summaryrefslogtreecommitdiff
path: root/drivers/media/i2c/adv7180.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c/adv7180.c')
-rw-r--r--drivers/media/i2c/adv7180.c66
1 files changed, 60 insertions, 6 deletions
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index fa5bc55bc944..d9a99fcfacb1 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -94,6 +94,7 @@
#define ADV7180_REG_SHAP_FILTER_CTL_1 0x0017
#define ADV7180_REG_CTRL_2 0x001d
#define ADV7180_REG_VSYNC_FIELD_CTL_1 0x0031
+#define ADV7180_VSYNC_FIELD_CTL_1_NEWAV 0x12
#define ADV7180_REG_MANUAL_WIN_CTL_1 0x003d
#define ADV7180_REG_MANUAL_WIN_CTL_2 0x003e
#define ADV7180_REG_MANUAL_WIN_CTL_3 0x003f
@@ -205,6 +206,7 @@ struct adv7180_state {
struct mutex mutex; /* mutual excl. when accessing chip */
int irq;
struct gpio_desc *pwdn_gpio;
+ struct gpio_desc *rst_gpio;
v4l2_std_id curr_norm;
bool powered;
bool streaming;
@@ -216,6 +218,7 @@ struct adv7180_state {
struct i2c_client *vpp_client;
const struct adv7180_chip_info *chip_info;
enum v4l2_field field;
+ bool force_bt656_4;
};
#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
struct adv7180_state, \
@@ -484,6 +487,19 @@ static void adv7180_set_power_pin(struct adv7180_state *state, bool on)
}
}
+static void adv7180_set_reset_pin(struct adv7180_state *state, bool on)
+{
+ if (!state->rst_gpio)
+ return;
+
+ if (on) {
+ gpiod_set_value_cansleep(state->rst_gpio, 1);
+ } else {
+ gpiod_set_value_cansleep(state->rst_gpio, 0);
+ usleep_range(5000, 10000);
+ }
+}
+
static int adv7180_set_power(struct adv7180_state *state, bool on)
{
u8 val;
@@ -963,10 +979,26 @@ static int adv7182_init(struct adv7180_state *state)
adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL, 0x57);
adv7180_write(state, ADV7180_REG_CTRL_2, 0xc0);
} else {
- if (state->chip_info->flags & ADV7180_FLAG_V2)
- adv7180_write(state,
- ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
- 0x17);
+ if (state->chip_info->flags & ADV7180_FLAG_V2) {
+ if (state->force_bt656_4) {
+ /* ITU-R BT.656-4 compatible */
+ adv7180_write(state,
+ ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
+ ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
+ /* Manually set NEWAVMODE */
+ adv7180_write(state,
+ ADV7180_REG_VSYNC_FIELD_CTL_1,
+ ADV7180_VSYNC_FIELD_CTL_1_NEWAV);
+ /* Manually set V bit end position in NTSC mode */
+ adv7180_write(state,
+ ADV7180_REG_NTSC_V_BIT_END,
+ ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+ } else {
+ adv7180_write(state,
+ ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
+ 0x17);
+ }
+ }
else
adv7180_write(state,
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
@@ -1263,6 +1295,7 @@ static int init_device(struct adv7180_state *state)
mutex_lock(&state->mutex);
adv7180_set_power_pin(state, true);
+ adv7180_set_reset_pin(state, false);
adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
usleep_range(5000, 10000);
@@ -1314,6 +1347,7 @@ out_unlock:
static int adv7180_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct device_node *np = client->dev.of_node;
struct adv7180_state *state;
struct v4l2_subdev *sd;
int ret;
@@ -1338,6 +1372,17 @@ static int adv7180_probe(struct i2c_client *client,
return ret;
}
+ state->rst_gpio = devm_gpiod_get_optional(&client->dev, "reset",
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(state->rst_gpio)) {
+ ret = PTR_ERR(state->rst_gpio);
+ v4l_err(client, "request for reset pin failed: %d\n", ret);
+ return ret;
+ }
+
+ if (of_property_read_bool(np, "adv,force-bt656-4"))
+ state->force_bt656_4 = true;
+
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
state->csi_client = i2c_new_dummy_device(client->adapter,
ADV7180_DEFAULT_CSI_I2C_ADDR);
@@ -1392,11 +1437,19 @@ static int adv7180_probe(struct i2c_client *client,
if (ret)
goto err_free_irq;
- v4l_info(client, "chip found @ 0x%02x (%s)\n",
- client->addr, client->adapter->name);
+ mutex_lock(&state->mutex);
+ ret = adv7180_read(state, ADV7180_REG_IDENT);
+ mutex_unlock(&state->mutex);
+ if (ret < 0)
+ goto err_v4l2_async_unregister;
+
+ v4l_info(client, "chip id 0x%x found @ 0x%02x (%s)\n",
+ ret, client->addr, client->adapter->name);
return 0;
+err_v4l2_async_unregister:
+ v4l2_async_unregister_subdev(sd);
err_free_irq:
if (state->irq > 0)
free_irq(client->irq, state);
@@ -1428,6 +1481,7 @@ static int adv7180_remove(struct i2c_client *client)
i2c_unregister_device(state->vpp_client);
i2c_unregister_device(state->csi_client);
+ adv7180_set_reset_pin(state, true);
adv7180_set_power_pin(state, false);
mutex_destroy(&state->mutex);