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.c486
1 files changed, 250 insertions, 236 deletions
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index a22402b7acff..378f4e6af12c 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -5,6 +5,7 @@
* Copyright (C) 2013 Cogent Embedded, Inc.
* Copyright (C) 2013 Renesas Solutions Corp.
*/
+#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
@@ -194,6 +195,7 @@ struct adv7180_state;
#define ADV7180_FLAG_V2 BIT(1)
#define ADV7180_FLAG_MIPI_CSI2 BIT(2)
#define ADV7180_FLAG_I2P BIT(3)
+#define ADV7180_FLAG_TEST_PATTERN BIT(4)
struct adv7180_chip_info {
unsigned int flags;
@@ -212,7 +214,6 @@ struct adv7180_state {
struct gpio_desc *pwdn_gpio;
struct gpio_desc *rst_gpio;
v4l2_std_id curr_norm;
- bool powered;
bool streaming;
u8 input;
@@ -272,6 +273,38 @@ static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg,
return i2c_smbus_write_byte_data(state->vpp_client, reg, value);
}
+static int adv7180_set_power(struct adv7180_state *state, bool on)
+{
+ u8 val;
+ int ret;
+
+ if (on)
+ val = ADV7180_PWR_MAN_ON;
+ else
+ val = ADV7180_PWR_MAN_OFF;
+
+ ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val);
+ if (ret)
+ return ret;
+
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ if (on) {
+ adv7180_csi_write(state, 0xDE, 0x02);
+ adv7180_csi_write(state, 0xD2, 0xF7);
+ adv7180_csi_write(state, 0xD8, 0x65);
+ adv7180_csi_write(state, 0xE0, 0x09);
+ adv7180_csi_write(state, 0x2C, 0x00);
+ if (state->field == V4L2_FIELD_NONE)
+ adv7180_csi_write(state, 0x1D, 0x80);
+ adv7180_csi_write(state, 0x00, 0x00);
+ } else {
+ adv7180_csi_write(state, 0x00, 0x80);
+ }
+ }
+
+ return 0;
+}
+
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
{
/* in case V4L2_IN_ST_NO_SIGNAL */
@@ -355,32 +388,27 @@ static inline struct adv7180_state *to_state(struct v4l2_subdev *sd)
static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
{
struct adv7180_state *state = to_state(sd);
- int err = mutex_lock_interruptible(&state->mutex);
- if (err)
- return err;
-
- if (state->streaming) {
- err = -EBUSY;
- goto unlock;
- }
+ int ret;
- err = adv7180_set_video_standard(state,
- ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
- if (err)
- goto unlock;
+ guard(mutex)(&state->mutex);
- msleep(100);
- __adv7180_status(state, NULL, std);
+ /*
+ * We can't sample the standard if the device is streaming as that would
+ * interfere with the capture session as the VID_SEL reg is touched.
+ */
+ if (state->streaming)
+ return -EBUSY;
- err = v4l2_std_to_adv7180(state->curr_norm);
- if (err < 0)
- goto unlock;
+ /* Set the standard to autodetect PAL B/G/H/I/D, NTSC J or SECAM */
+ ret = adv7180_set_video_standard(state,
+ ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
+ if (ret)
+ return ret;
- err = adv7180_set_video_standard(state, err);
+ /* Allow some time for the autodetection to run. */
+ msleep(100);
-unlock:
- mutex_unlock(&state->mutex);
- return err;
+ return __adv7180_status(state, NULL, std);
}
static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
@@ -435,22 +463,18 @@ static int adv7180_program_std(struct adv7180_state *state)
static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7180_state *state = to_state(sd);
- int ret = mutex_lock_interruptible(&state->mutex);
+ int ret;
- if (ret)
- return ret;
+ guard(mutex)(&state->mutex);
/* Make sure we can support this std */
ret = v4l2_std_to_adv7180(std);
if (ret < 0)
- goto out;
+ return ret;
state->curr_norm = std;
- ret = adv7180_program_std(state);
-out:
- mutex_unlock(&state->mutex);
- return ret;
+ return 0;
}
static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
@@ -462,11 +486,19 @@ static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
return 0;
}
-static int adv7180_g_frame_interval(struct v4l2_subdev *sd,
- struct v4l2_subdev_frame_interval *fi)
+static int adv7180_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_interval *fi)
{
struct adv7180_state *state = to_state(sd);
+ /*
+ * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
+ * subdev active state API.
+ */
+ if (fi->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return -EINVAL;
+
if (state->curr_norm & V4L2_STD_525_60) {
fi->interval.numerator = 1001;
fi->interval.denominator = 30000;
@@ -504,55 +536,6 @@ static void adv7180_set_reset_pin(struct adv7180_state *state, bool on)
}
}
-static int adv7180_set_power(struct adv7180_state *state, bool on)
-{
- u8 val;
- int ret;
-
- if (on)
- val = ADV7180_PWR_MAN_ON;
- else
- val = ADV7180_PWR_MAN_OFF;
-
- ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val);
- if (ret)
- return ret;
-
- if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
- if (on) {
- adv7180_csi_write(state, 0xDE, 0x02);
- adv7180_csi_write(state, 0xD2, 0xF7);
- adv7180_csi_write(state, 0xD8, 0x65);
- adv7180_csi_write(state, 0xE0, 0x09);
- adv7180_csi_write(state, 0x2C, 0x00);
- if (state->field == V4L2_FIELD_NONE)
- adv7180_csi_write(state, 0x1D, 0x80);
- adv7180_csi_write(state, 0x00, 0x00);
- } else {
- adv7180_csi_write(state, 0x00, 0x80);
- }
- }
-
- return 0;
-}
-
-static int adv7180_s_power(struct v4l2_subdev *sd, int on)
-{
- struct adv7180_state *state = to_state(sd);
- int ret;
-
- ret = mutex_lock_interruptible(&state->mutex);
- if (ret)
- return ret;
-
- ret = adv7180_set_power(state, on);
- if (ret == 0)
- state->powered = on;
-
- mutex_unlock(&state->mutex);
- return ret;
-}
-
static const char * const test_pattern_menu[] = {
"Single color",
"Color bars",
@@ -591,11 +574,11 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
struct adv7180_state *state = to_state(sd);
- int ret = mutex_lock_interruptible(&state->mutex);
+ int ret = 0;
int val;
- if (ret)
- return ret;
+ lockdep_assert_held(&state->mutex);
+
val = ctrl->val;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
@@ -637,7 +620,6 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
ret = -EINVAL;
}
- mutex_unlock(&state->mutex);
return ret;
}
@@ -658,6 +640,7 @@ static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
static int adv7180_init_controls(struct adv7180_state *state)
{
v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
+ state->ctrl_hdl.lock = &state->mutex;
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
V4L2_CID_BRIGHTNESS, ADV7180_BRI_MIN,
@@ -673,11 +656,15 @@ static int adv7180_init_controls(struct adv7180_state *state)
ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
- v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl, &adv7180_ctrl_ops,
- V4L2_CID_TEST_PATTERN,
- ARRAY_SIZE(test_pattern_menu) - 1,
- 0, ARRAY_SIZE(test_pattern_menu) - 1,
- test_pattern_menu);
+ if (state->chip_info->flags & ADV7180_FLAG_TEST_PATTERN) {
+ v4l2_ctrl_new_std_menu_items(&state->ctrl_hdl,
+ &adv7180_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(test_pattern_menu) - 1,
+ 0,
+ ARRAY_SIZE(test_pattern_menu) - 1,
+ test_pattern_menu);
+ }
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
@@ -686,7 +673,6 @@ static int adv7180_init_controls(struct adv7180_state *state)
v4l2_ctrl_handler_free(&state->ctrl_hdl);
return err;
}
- v4l2_ctrl_handler_setup(&state->ctrl_hdl);
return 0;
}
@@ -768,7 +754,7 @@ static int adv7180_get_pad_format(struct v4l2_subdev *sd,
struct adv7180_state *state = to_state(sd);
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
- format->format = *v4l2_subdev_get_try_format(sd, sd_state, 0);
+ format->format = *v4l2_subdev_state_get_format(sd_state, 0);
} else {
adv7180_mbus_fmt(sd, &format->format);
format->format.field = state->field;
@@ -798,22 +784,17 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
ret = adv7180_mbus_fmt(sd, &format->format);
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- if (state->field != format->format.field) {
- state->field = format->format.field;
- adv7180_set_power(state, false);
- adv7180_set_field_mode(state);
- adv7180_set_power(state, true);
- }
+ state->field = format->format.field;
} else {
- framefmt = v4l2_subdev_get_try_format(sd, sd_state, 0);
+ framefmt = v4l2_subdev_state_get_format(sd_state, 0);
*framefmt = format->format;
}
return ret;
}
-static int adv7180_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int adv7180_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state)
{
struct v4l2_subdev_format fmt = {
.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY
@@ -854,24 +835,92 @@ static int adv7180_get_skip_frames(struct v4l2_subdev *sd, u32 *frames)
return 0;
}
-static int adv7180_g_pixelaspect(struct v4l2_subdev *sd, struct v4l2_fract *aspect)
+static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
{
- struct adv7180_state *state = to_state(sd);
+ *norm = V4L2_STD_ALL;
+ return 0;
+}
- if (state->curr_norm & V4L2_STD_525_60) {
- aspect->numerator = 11;
- aspect->denominator = 10;
- } else {
- aspect->numerator = 54;
- aspect->denominator = 59;
- }
+static int init_device(struct adv7180_state *state)
+{
+ int ret;
- return 0;
+ lockdep_assert_held(&state->mutex);
+
+ ret = adv7180_program_std(state);
+ if (ret)
+ return ret;
+
+ adv7180_set_field_mode(state);
+
+ __v4l2_ctrl_handler_setup(&state->ctrl_hdl);
+
+ return ret;
}
-static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
+static int adv7180_reset_device(struct adv7180_state *state)
{
- *norm = V4L2_STD_ALL;
+ int ret;
+
+ lockdep_assert_held(&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);
+
+ /*
+ * If the devices decoder is power on after reset, power off so the
+ * device can be configured.
+ */
+ if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
+ adv7180_set_power(state, false);
+
+ ret = state->chip_info->init(state);
+ if (ret)
+ return ret;
+
+ ret = init_device(state);
+ if (ret)
+ return ret;
+
+ /* register for interrupts */
+ if (state->irq > 0) {
+ /* config the Interrupt pin to be active low */
+ ret = adv7180_write(state, ADV7180_REG_ICONF1,
+ ADV7180_ICONF1_ACTIVE_LOW |
+ ADV7180_ICONF1_PSYNC_ONLY);
+ if (ret < 0)
+ return ret;
+
+ ret = adv7180_write(state, ADV7180_REG_IMR1, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = adv7180_write(state, ADV7180_REG_IMR2, 0);
+ if (ret < 0)
+ return ret;
+
+ /* enable AD change interrupts */
+ ret = adv7180_write(state, ADV7180_REG_IMR3,
+ ADV7180_IRQ3_AD_CHANGE);
+ if (ret < 0)
+ return ret;
+
+ ret = adv7180_write(state, ADV7180_REG_IMR4, 0);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * If the devices decoder is power on after reset, restore the power
+ * after configuration. This is to preserve the behavior of the driver,
+ * not doing this result in the first 35+ frames captured being garbage.
+ */
+ if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
+ adv7180_set_power(state, true);
+
return 0;
}
@@ -880,18 +929,29 @@ static int adv7180_s_stream(struct v4l2_subdev *sd, int enable)
struct adv7180_state *state = to_state(sd);
int ret;
- /* It's always safe to stop streaming, no need to take the lock */
- if (!enable) {
- state->streaming = enable;
- return 0;
- }
-
/* Must wait until querystd released the lock */
- ret = mutex_lock_interruptible(&state->mutex);
+ guard(mutex)(&state->mutex);
+
+ /*
+ * Always power off the decoder even if streaming is to be enabled, the
+ * decoder needs to be off for the device to be configured.
+ */
+ ret = adv7180_set_power(state, false);
if (ret)
return ret;
+
+ if (enable) {
+ ret = init_device(state);
+ if (ret)
+ return ret;
+
+ ret = adv7180_set_power(state, true);
+ if (ret)
+ return ret;
+ }
+
state->streaming = enable;
- mutex_unlock(&state->mutex);
+
return 0;
}
@@ -912,26 +972,23 @@ static int adv7180_subscribe_event(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.s_std = adv7180_s_std,
.g_std = adv7180_g_std,
- .g_frame_interval = adv7180_g_frame_interval,
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
- .g_pixelaspect = adv7180_g_pixelaspect,
.g_tvnorms = adv7180_g_tvnorms,
.s_stream = adv7180_s_stream,
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
- .s_power = adv7180_s_power,
.subscribe_event = adv7180_subscribe_event,
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
- .init_cfg = adv7180_init_cfg,
.enum_mbus_code = adv7180_enum_mbus_code,
.set_fmt = adv7180_set_pad_format,
.get_fmt = adv7180_get_pad_format,
+ .get_frame_interval = adv7180_get_frame_interval,
.get_mbus_config = adv7180_get_mbus_config,
};
@@ -946,6 +1003,10 @@ static const struct v4l2_subdev_ops adv7180_ops = {
.sensor = &adv7180_sensor_ops,
};
+static const struct v4l2_subdev_internal_ops adv7180_internal_ops = {
+ .init_state = adv7180_init_state,
+};
+
static irqreturn_t adv7180_irq(int irq, void *devid)
{
struct adv7180_state *state = devid;
@@ -1045,11 +1106,11 @@ static int adv7182_init(struct adv7180_state *state)
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
0x17);
}
- }
- else
+ } else {
adv7180_write(state,
ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
0x07);
+ }
adv7180_write(state, ADV7180_REG_OUTPUT_CONTROL, 0x0c);
adv7180_write(state, ADV7180_REG_CTRL_2, 0x40);
}
@@ -1209,7 +1270,7 @@ static const struct adv7180_chip_info adv7182_info = {
};
static const struct adv7180_chip_info adv7280_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -1223,7 +1284,8 @@ static const struct adv7180_chip_info adv7280_info = {
};
static const struct adv7180_chip_info adv7280_m_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P |
+ ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -1244,7 +1306,8 @@ static const struct adv7180_chip_info adv7280_m_info = {
};
static const struct adv7180_chip_info adv7281_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 |
+ ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN7) |
@@ -1259,7 +1322,8 @@ static const struct adv7180_chip_info adv7281_info = {
};
static const struct adv7180_chip_info adv7281_m_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 |
+ ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -1279,7 +1343,8 @@ static const struct adv7180_chip_info adv7281_m_info = {
};
static const struct adv7180_chip_info adv7281_ma_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 |
+ ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -1304,7 +1369,7 @@ static const struct adv7180_chip_info adv7281_ma_info = {
};
static const struct adv7180_chip_info adv7282_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P | ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN7) |
@@ -1319,7 +1384,8 @@ static const struct adv7180_chip_info adv7282_info = {
};
static const struct adv7180_chip_info adv7282_m_info = {
- .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P |
+ ADV7180_FLAG_TEST_PATTERN,
.valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
BIT(ADV7182_INPUT_CVBS_AIN2) |
BIT(ADV7182_INPUT_CVBS_AIN3) |
@@ -1337,65 +1403,8 @@ static const struct adv7180_chip_info adv7282_m_info = {
.select_input = adv7182_select_input,
};
-static int init_device(struct adv7180_state *state)
-{
- int ret;
-
- 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);
-
- ret = state->chip_info->init(state);
- if (ret)
- goto out_unlock;
-
- ret = adv7180_program_std(state);
- if (ret)
- goto out_unlock;
-
- adv7180_set_field_mode(state);
-
- /* register for interrupts */
- if (state->irq > 0) {
- /* config the Interrupt pin to be active low */
- ret = adv7180_write(state, ADV7180_REG_ICONF1,
- ADV7180_ICONF1_ACTIVE_LOW |
- ADV7180_ICONF1_PSYNC_ONLY);
- if (ret < 0)
- goto out_unlock;
-
- ret = adv7180_write(state, ADV7180_REG_IMR1, 0);
- if (ret < 0)
- goto out_unlock;
-
- ret = adv7180_write(state, ADV7180_REG_IMR2, 0);
- if (ret < 0)
- goto out_unlock;
-
- /* enable AD change interrupts interrupts */
- ret = adv7180_write(state, ADV7180_REG_IMR3,
- ADV7180_IRQ3_AD_CHANGE);
- if (ret < 0)
- goto out_unlock;
-
- ret = adv7180_write(state, ADV7180_REG_IMR4, 0);
- if (ret < 0)
- goto out_unlock;
- }
-
-out_unlock:
- mutex_unlock(&state->mutex);
-
- return ret;
-}
-
static int adv7180_probe(struct i2c_client *client)
{
- const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct device_node *np = client->dev.of_node;
struct adv7180_state *state;
struct v4l2_subdev *sd;
@@ -1411,7 +1420,7 @@ static int adv7180_probe(struct i2c_client *client)
state->client = client;
state->field = V4L2_FIELD_ALTERNATE;
- state->chip_info = (struct adv7180_chip_info *)id->driver_data;
+ state->chip_info = i2c_get_match_data(client);
state->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown",
GPIOD_OUT_HIGH);
@@ -1429,7 +1438,8 @@ static int adv7180_probe(struct i2c_client *client)
return ret;
}
- if (of_property_read_bool(np, "adv,force-bt656-4"))
+ if (of_property_read_bool(np, "adv,force-bt656-4") ||
+ of_property_read_bool(np, "adi,force-bt656-4"))
state->force_bt656_4 = true;
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
@@ -1451,13 +1461,11 @@ static int adv7180_probe(struct i2c_client *client)
state->irq = client->irq;
mutex_init(&state->mutex);
state->curr_norm = V4L2_STD_NTSC;
- if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
- state->powered = true;
- else
- state->powered = false;
+
state->input = 0;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+ sd->internal_ops = &adv7180_internal_ops;
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
ret = adv7180_init_controls(state);
@@ -1470,11 +1478,13 @@ static int adv7180_probe(struct i2c_client *client)
if (ret)
goto err_free_ctrl;
- ret = init_device(state);
+ mutex_lock(&state->mutex);
+ ret = adv7180_reset_device(state);
+ mutex_unlock(&state->mutex);
if (ret)
goto err_media_entity_cleanup;
- if (state->irq) {
+ if (state->irq > 0) {
ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
KBUILD_MODNAME, state);
@@ -1536,28 +1546,14 @@ static void adv7180_remove(struct i2c_client *client)
mutex_destroy(&state->mutex);
}
-static const struct i2c_device_id adv7180_id[] = {
- { "adv7180", (kernel_ulong_t)&adv7180_info },
- { "adv7180cp", (kernel_ulong_t)&adv7180_info },
- { "adv7180st", (kernel_ulong_t)&adv7180_info },
- { "adv7182", (kernel_ulong_t)&adv7182_info },
- { "adv7280", (kernel_ulong_t)&adv7280_info },
- { "adv7280-m", (kernel_ulong_t)&adv7280_m_info },
- { "adv7281", (kernel_ulong_t)&adv7281_info },
- { "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
- { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
- { "adv7282", (kernel_ulong_t)&adv7282_info },
- { "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
- {},
-};
-MODULE_DEVICE_TABLE(i2c, adv7180_id);
-
#ifdef CONFIG_PM_SLEEP
static int adv7180_suspend(struct device *dev)
{
struct v4l2_subdev *sd = dev_get_drvdata(dev);
struct adv7180_state *state = to_state(sd);
+ guard(mutex)(&state->mutex);
+
return adv7180_set_power(state, false);
}
@@ -1567,13 +1563,18 @@ static int adv7180_resume(struct device *dev)
struct adv7180_state *state = to_state(sd);
int ret;
- ret = init_device(state);
+ guard(mutex)(&state->mutex);
+
+ ret = adv7180_reset_device(state);
if (ret < 0)
return ret;
- ret = adv7180_set_power(state, state->powered);
- if (ret)
- return ret;
+ /* If we were streaming when suspending, start decoder. */
+ if (state->streaming) {
+ ret = adv7180_set_power(state, true);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -1585,32 +1586,45 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
#define ADV7180_PM_OPS NULL
#endif
-#ifdef CONFIG_OF
-static const struct of_device_id adv7180_of_id[] = {
- { .compatible = "adi,adv7180", },
- { .compatible = "adi,adv7180cp", },
- { .compatible = "adi,adv7180st", },
- { .compatible = "adi,adv7182", },
- { .compatible = "adi,adv7280", },
- { .compatible = "adi,adv7280-m", },
- { .compatible = "adi,adv7281", },
- { .compatible = "adi,adv7281-m", },
- { .compatible = "adi,adv7281-ma", },
- { .compatible = "adi,adv7282", },
- { .compatible = "adi,adv7282-m", },
- { },
+static const struct i2c_device_id adv7180_id[] = {
+ { "adv7180", (kernel_ulong_t)&adv7180_info },
+ { "adv7180cp", (kernel_ulong_t)&adv7180_info },
+ { "adv7180st", (kernel_ulong_t)&adv7180_info },
+ { "adv7182", (kernel_ulong_t)&adv7182_info },
+ { "adv7280", (kernel_ulong_t)&adv7280_info },
+ { "adv7280-m", (kernel_ulong_t)&adv7280_m_info },
+ { "adv7281", (kernel_ulong_t)&adv7281_info },
+ { "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
+ { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
+ { "adv7282", (kernel_ulong_t)&adv7282_info },
+ { "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
+ {}
};
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
+static const struct of_device_id adv7180_of_id[] = {
+ { .compatible = "adi,adv7180", &adv7180_info },
+ { .compatible = "adi,adv7180cp", &adv7180_info },
+ { .compatible = "adi,adv7180st", &adv7180_info },
+ { .compatible = "adi,adv7182", &adv7182_info },
+ { .compatible = "adi,adv7280", &adv7280_info },
+ { .compatible = "adi,adv7280-m", &adv7280_m_info },
+ { .compatible = "adi,adv7281", &adv7281_info },
+ { .compatible = "adi,adv7281-m", &adv7281_m_info },
+ { .compatible = "adi,adv7281-ma", &adv7281_ma_info },
+ { .compatible = "adi,adv7282", &adv7282_info },
+ { .compatible = "adi,adv7282-m", &adv7282_m_info },
+ {}
+};
MODULE_DEVICE_TABLE(of, adv7180_of_id);
-#endif
static struct i2c_driver adv7180_driver = {
.driver = {
.name = KBUILD_MODNAME,
.pm = ADV7180_PM_OPS,
- .of_match_table = of_match_ptr(adv7180_of_id),
+ .of_match_table = adv7180_of_id,
},
- .probe_new = adv7180_probe,
+ .probe = adv7180_probe,
.remove = adv7180_remove,
.id_table = adv7180_id,
};