diff options
Diffstat (limited to 'drivers/media/i2c')
107 files changed, 5121 insertions, 2946 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6237fe804a5c..cdd7ba5da0d5 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -27,7 +27,7 @@ config VIDEO_IR_I2C menuconfig VIDEO_CAMERA_SENSOR bool "Camera sensor devices" - depends on MEDIA_CAMERA_SUPPORT && I2C + depends on MEDIA_CAMERA_SUPPORT && I2C && HAVE_CLK select MEDIA_CONTROLLER select V4L2_FWNODE select VIDEO_V4L2_SUBDEV_API @@ -70,6 +70,16 @@ config VIDEO_GC0308 To compile this driver as a module, choose M here: the module will be called gc0308. +config VIDEO_GC0310 + tristate "GalaxyCore GC0310 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor-level driver for the Galaxycore + GC0310 0.3MP sensor. + + To compile this driver as a module, choose M here: the + module will be called gc0310. + config VIDEO_GC05A2 tristate "GalaxyCore gc05a2 sensor support" select V4L2_CCI_I2C @@ -317,6 +327,7 @@ config VIDEO_MT9V011 config VIDEO_MT9V032 tristate "Micron MT9V032 sensor support" + depends on OF select REGMAP_I2C help This is a Video4Linux2 sensor driver for the Micron @@ -340,6 +351,16 @@ config VIDEO_OG01A1B To compile this driver as a module, choose M here: the module will be called og01a1b. +config VIDEO_OG0VE1B + tristate "OmniVision OG0VE1B sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the OmniVision + OG0VE1B camera. + + To compile this driver as a module, choose M here: the + module will be called og0ve1b. + config VIDEO_OV01A10 tristate "OmniVision OV01A10 sensor support" help @@ -446,6 +467,16 @@ config VIDEO_OV2685 To compile this driver as a module, choose M here: the module will be called ov2685. +config VIDEO_OV2735 + tristate "OmniVision OV2735 sensor support" + select V4L2_CCI_I2C + help + This is a Video4Linux2 sensor driver for the Sony + OV2735 camera. + + To compile this driver as a module, choose M here: the + module will be called ov2735. + config VIDEO_OV2740 tristate "OmniVision OV2740 sensor support" depends on ACPI || COMPILE_TEST @@ -542,24 +573,25 @@ config VIDEO_OV5695 To compile this driver as a module, choose M here: the module will be called ov5695. -config VIDEO_OV64A40 - tristate "OmniVision OV64A40 sensor support" +config VIDEO_OV6211 + tristate "OmniVision OV6211 sensor support" select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the OmniVision - OV64A40 camera. + OV6211 camera. To compile this driver as a module, choose M here: the - module will be called ov64a40. + module will be called ov6211. -config VIDEO_OV6650 - tristate "OmniVision OV6650 sensor support" +config VIDEO_OV64A40 + tristate "OmniVision OV64A40 sensor support" + select V4L2_CCI_I2C help This is a Video4Linux2 sensor driver for the OmniVision - OV6650 camera. + OV64A40 camera. To compile this driver as a module, choose M here: the - module will be called ov6650. + module will be called ov64a40. config VIDEO_OV7251 tristate "OmniVision OV7251 sensor support" diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index 5873d29433ee..57cdd8dc96f6 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ obj-$(CONFIG_VIDEO_GC0308) += gc0308.o +obj-$(CONFIG_VIDEO_GC0310) += gc0310.o obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o obj-$(CONFIG_VIDEO_GC08A3) += gc08a3.o obj-$(CONFIG_VIDEO_GC2145) += gc2145.o @@ -81,6 +82,7 @@ obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o obj-$(CONFIG_VIDEO_MT9V111) += mt9v111.o obj-$(CONFIG_VIDEO_OG01A1B) += og01a1b.o +obj-$(CONFIG_VIDEO_OG0VE1B) += og0ve1b.o obj-$(CONFIG_VIDEO_OV01A10) += ov01a10.o obj-$(CONFIG_VIDEO_OV02A10) += ov02a10.o obj-$(CONFIG_VIDEO_OV02C10) += ov02c10.o @@ -93,6 +95,7 @@ obj-$(CONFIG_VIDEO_OV2640) += ov2640.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o obj-$(CONFIG_VIDEO_OV2680) += ov2680.o obj-$(CONFIG_VIDEO_OV2685) += ov2685.o +obj-$(CONFIG_VIDEO_OV2735) += ov2735.o obj-$(CONFIG_VIDEO_OV2740) += ov2740.o obj-$(CONFIG_VIDEO_OV4689) += ov4689.o obj-$(CONFIG_VIDEO_OV5640) += ov5640.o @@ -103,8 +106,8 @@ obj-$(CONFIG_VIDEO_OV5670) += ov5670.o obj-$(CONFIG_VIDEO_OV5675) += ov5675.o obj-$(CONFIG_VIDEO_OV5693) += ov5693.o obj-$(CONFIG_VIDEO_OV5695) += ov5695.o +obj-$(CONFIG_VIDEO_OV6211) += ov6211.o obj-$(CONFIG_VIDEO_OV64A40) += ov64a40.o -obj-$(CONFIG_VIDEO_OV6650) += ov6650.o obj-$(CONFIG_VIDEO_OV7251) += ov7251.o obj-$(CONFIG_VIDEO_OV7640) += ov7640.o obj-$(CONFIG_VIDEO_OV7670) += ov7670.o diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index 5d90b8ab9b6d..378f4e6af12c 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -214,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; @@ -274,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 */ @@ -357,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, @@ -437,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) @@ -514,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", @@ -601,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: @@ -647,7 +620,6 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl) ret = -EINVAL; } - mutex_unlock(&state->mutex); return ret; } @@ -668,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, @@ -700,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; } @@ -812,12 +784,7 @@ 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_state_get_format(sd_state, 0); *framefmt = format->format; @@ -874,23 +841,117 @@ static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm) return 0; } -static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) +static int init_device(struct adv7180_state *state) { - 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; + 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_reset_device(struct adv7180_state *state) +{ + 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; +} + +static int adv7180_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct adv7180_state *state = to_state(sd); + int ret; + /* 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; } @@ -919,7 +980,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = { }; 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, }; @@ -1343,62 +1403,6 @@ 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) { struct device_node *np = client->dev.of_node; @@ -1457,10 +1461,7 @@ 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); @@ -1477,7 +1478,9 @@ 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; @@ -1549,6 +1552,8 @@ 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); } @@ -1558,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; } diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index afed38596362..8fe7c2f72883 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -42,7 +42,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_DESCRIPTION("Analog Devices ADV7604/10/11/12 video decoder driver"); -MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 5545cd23e113..9780082db841 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -38,7 +38,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (0-2)"); MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver"); -MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@kernel.org>"); MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c index 05b708bd0a64..1f088acecf36 100644 --- a/drivers/media/i2c/alvium-csi2.c +++ b/drivers/media/i2c/alvium-csi2.c @@ -1841,7 +1841,6 @@ static int alvium_s_stream(struct v4l2_subdev *sd, int enable) } else { alvium_set_stream_mipi(alvium, enable); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c index 24873149096c..939bf590d4b2 100644 --- a/drivers/media/i2c/ar0521.c +++ b/drivers/media/i2c/ar0521.c @@ -1077,11 +1077,10 @@ static int ar0521_probe(struct i2c_client *client) } /* Get master clock (extclk) */ - sensor->extclk = devm_clk_get(dev, "extclk"); - if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get extclk\n"); - return PTR_ERR(sensor->extclk); - } + sensor->extclk = devm_v4l2_sensor_clk_get(dev, "extclk"); + if (IS_ERR(sensor->extclk)) + return dev_err_probe(dev, PTR_ERR(sensor->extclk), + "failed to get extclk\n"); sensor->extclk_freq = clk_get_rate(sensor->extclk); diff --git a/drivers/media/i2c/ccs/ccs-core.c b/drivers/media/i2c/ccs/ccs-core.c index 487bcabb4a19..1c889c878abd 100644 --- a/drivers/media/i2c/ccs/ccs-core.c +++ b/drivers/media/i2c/ccs/ccs-core.c @@ -787,10 +787,8 @@ static int ccs_set_ctrl(struct v4l2_ctrl *ctrl) rval = -EINVAL; } - if (pm_status > 0) { - pm_runtime_mark_last_busy(&client->dev); + if (pm_status > 0) pm_runtime_put_autosuspend(&client->dev); - } return rval; } @@ -1914,7 +1912,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) if (!enable) { ccs_stop_streaming(sensor); sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; @@ -1929,7 +1926,6 @@ static int ccs_set_stream(struct v4l2_subdev *subdev, int enable) rval = ccs_start_streaming(sensor); if (rval < 0) { sensor->streaming = false; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } @@ -2677,7 +2673,6 @@ nvm_show(struct device *dev, struct device_attribute *attr, char *buf) return -ENODEV; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); /* diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index a90a9e5705a0..a86306304330 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -9,10 +9,10 @@ * Changes by Tyler Trafford <tatrafford@comcast.net> * - cleanup/rewrite for V4L2 API (2005) * - * VBI support by Hans Verkuil <hverkuil@xs4all.nl>. + * VBI support by Hans Verkuil <hverkuil@kernel.org>. * * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> - * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. + * with additional fixes by Hans Verkuil <hverkuil@kernel.org>. * * CX23885 support by Steven Toth <stoth@linuxtv.org>. * diff --git a/drivers/media/i2c/ds90ub913.c b/drivers/media/i2c/ds90ub913.c index a80da2b4a8fa..73150061ea45 100644 --- a/drivers/media/i2c/ds90ub913.c +++ b/drivers/media/i2c/ds90ub913.c @@ -333,8 +333,7 @@ static int _ub913_set_routing(struct v4l2_subdev *sd, .quantization = V4L2_QUANTIZATION_LIM_RANGE, .xfer_func = V4L2_XFER_FUNC_SRGB, }; - struct v4l2_subdev_stream_configs *stream_configs; - unsigned int i; + struct v4l2_subdev_route *route; int ret; ret = v4l2_subdev_routing_validate(sd, routing, @@ -346,13 +345,15 @@ static int _ub913_set_routing(struct v4l2_subdev *sd, if (ret) return ret; - stream_configs = &state->stream_configs; + for_each_active_route(&state->routing, route) { + struct v4l2_mbus_framefmt *fmt; - for (i = 0; i < stream_configs->num_configs; i++) { - if (stream_configs->configs[i].pad == UB913_PAD_SINK) - stream_configs->configs[i].fmt = in_format; - else - stream_configs->configs[i].fmt = out_format; + fmt = v4l2_subdev_state_get_format(state, route->sink_pad, + route->sink_stream); + *fmt = in_format; + fmt = v4l2_subdev_state_get_format(state, route->source_pad, + route->source_stream); + *fmt = out_format; } return 0; diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c index 3a4d100b9199..d434721ba8ed 100644 --- a/drivers/media/i2c/dw9768.c +++ b/drivers/media/i2c/dw9768.c @@ -374,7 +374,6 @@ static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_autosuspend(sd->dev); return 0; diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c index 7519863d77b1..2cb7b718782b 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c @@ -816,7 +816,6 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor) { struct v4l2_subdev *subdev = &sensor->subdev; struct i2c_client *client = v4l2_get_subdevdata(subdev); - unsigned int xclk_freq; int val, rval; rval = regulator_enable(sensor->vana); @@ -825,17 +824,6 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor) return rval; } - if (sensor->current_reglist) - xclk_freq = sensor->current_reglist->mode.ext_clock; - else - xclk_freq = sensor->xclk_freq; - - rval = clk_set_rate(sensor->ext_clk, xclk_freq); - if (rval < 0) { - dev_err(&client->dev, "unable to set extclk clock freq to %u\n", - xclk_freq); - goto out; - } rval = clk_prepare_enable(sensor->ext_clk); if (rval < 0) { dev_err(&client->dev, "failed to enable extclk\n"); @@ -849,7 +837,7 @@ static int et8ek8_power_on(struct et8ek8_sensor *sensor) gpiod_set_value(sensor->reset, 1); - msleep(5000 * 1000 / xclk_freq + 1); /* Wait 5000 cycles */ + msleep(5000 * 1000 / sensor->xclk_freq + 1); /* Wait 5000 cycles */ rval = et8ek8_i2c_reglist_find_write(client, &meta_reglist, ET8EK8_REGLIST_POWERON); @@ -1085,9 +1073,6 @@ static int et8ek8_set_frame_interval(struct v4l2_subdev *subdev, if (!reglist) return -EINVAL; - if (sensor->current_reglist->mode.ext_clock != reglist->mode.ext_clock) - return -EINVAL; - sensor->current_reglist = reglist; et8ek8_update_controls(sensor); @@ -1433,18 +1418,13 @@ static int et8ek8_probe(struct i2c_client *client) return PTR_ERR(sensor->vana); } - sensor->ext_clk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock\n"); - return PTR_ERR(sensor->ext_clk); - } + sensor->ext_clk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true, + 9600000); + if (IS_ERR(sensor->ext_clk)) + return dev_err_probe(&client->dev, PTR_ERR(sensor->ext_clk), + "could not get clock\n"); - ret = of_property_read_u32(dev->of_node, "clock-frequency", - &sensor->xclk_freq); - if (ret) { - dev_warn(dev, "can't get clock-frequency\n"); - return ret; - } + sensor->xclk_freq = clk_get_rate(sensor->ext_clk); mutex_init(&sensor->power_lock); diff --git a/drivers/media/i2c/et8ek8/et8ek8_mode.c b/drivers/media/i2c/et8ek8/et8ek8_mode.c index c9088eb0a812..914be1007099 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_mode.c +++ b/drivers/media/i2c/et8ek8/et8ek8_mode.c @@ -44,7 +44,6 @@ static struct et8ek8_reglist mode1_poweron_mode2_16vga_2592x1968_12_07fps = { .window_width = 2592, .window_height = 1968, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 1207 @@ -145,7 +144,6 @@ static struct et8ek8_reglist mode1_16vga_2592x1968_13_12fps_dpcm10_8 = { .window_width = 2592, .window_height = 1968, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 1292 @@ -201,7 +199,6 @@ static struct et8ek8_reglist mode3_4vga_1296x984_29_99fps_dpcm10_8 = { .window_width = 1296, .window_height = 984, .pixel_clock = 96533333, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 3000 @@ -257,7 +254,6 @@ static struct et8ek8_reglist mode4_svga_864x656_29_88fps = { .window_width = 864, .window_height = 656, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 2988 @@ -313,7 +309,6 @@ static struct et8ek8_reglist mode5_vga_648x492_29_93fps = { .window_width = 648, .window_height = 492, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 2993 @@ -369,7 +364,6 @@ static struct et8ek8_reglist mode2_16vga_2592x1968_3_99fps = { .window_width = 2592, .window_height = 1968, .pixel_clock = 80000000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 399 @@ -424,7 +418,6 @@ static struct et8ek8_reglist mode_648x492_5fps = { .window_width = 648, .window_height = 492, .pixel_clock = 13333333, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 499 @@ -480,7 +473,6 @@ static struct et8ek8_reglist mode3_4vga_1296x984_5fps = { .window_width = 1296, .window_height = 984, .pixel_clock = 49400000, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 501 @@ -536,7 +528,6 @@ static struct et8ek8_reglist mode_4vga_1296x984_25fps_dpcm10_8 = { .window_width = 1296, .window_height = 984, .pixel_clock = 84266667, - .ext_clock = 9600000, .timeperframe = { .numerator = 100, .denominator = 2500 diff --git a/drivers/media/i2c/et8ek8/et8ek8_reg.h b/drivers/media/i2c/et8ek8/et8ek8_reg.h index c90e74935f12..3305986c7c9c 100644 --- a/drivers/media/i2c/et8ek8/et8ek8_reg.h +++ b/drivers/media/i2c/et8ek8/et8ek8_reg.h @@ -37,7 +37,6 @@ struct et8ek8_mode { u16 window_height; u32 pixel_clock; /* in Hz */ - u32 ext_clock; /* in Hz */ struct v4l2_fract timeperframe; u32 max_exp; /* Maximum exposure value */ u32 bus_format; /* MEDIA_BUS_FMT_ */ diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c index 069f42785b3c..cbcda0e18ff1 100644 --- a/drivers/media/i2c/gc0308.c +++ b/drivers/media/i2c/gc0308.c @@ -974,7 +974,6 @@ static int gc0308_s_ctrl(struct v4l2_ctrl *ctrl) if (ret) dev_err(gc0308->dev, "failed to set control: %d\n", ret); - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return ret; @@ -1157,14 +1156,12 @@ static int gc0308_start_stream(struct gc0308 *gc0308) return 0; disable_pm: - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return ret; } static int gc0308_stop_stream(struct gc0308 *gc0308) { - pm_runtime_mark_last_busy(gc0308->dev); pm_runtime_put_autosuspend(gc0308->dev); return 0; } diff --git a/drivers/media/i2c/gc0310.c b/drivers/media/i2c/gc0310.c new file mode 100644 index 000000000000..7af4d66f42a0 --- /dev/null +++ b/drivers/media/i2c/gc0310.c @@ -0,0 +1,783 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for GalaxyCore GC0310 VGA camera sensor. + * + * Copyright (c) 2013 Intel Corporation. All Rights Reserved. + * Copyright (c) 2023-2025 Hans de Goede <hansg@kernel.org> + */ + +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/string.h> +#include <linux/types.h> + +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define GC0310_NATIVE_WIDTH 656 +#define GC0310_NATIVE_HEIGHT 496 + +/* + * The actual PLL output rate is unknown, the datasheet + * says that the formula for the frame-time in pixels is: + * rowtime = win-width + hblank + sh-delay + 4 + * frametime = rowtime * (win-height + vblank) + * Filling this in and multiplying by 30 fps gives: + * pixelrate = (660 + 178 + 42 + 4) * (498 + 27) * 30 = 13923000 + */ +#define GC0310_PIXELRATE 13923000 +/* single lane, bus-format is 8 bpp, CSI-2 is double data rate */ +#define GC0310_LINK_FREQ (GC0310_PIXELRATE * 8 / 2) +#define GC0310_MCLK_FREQ 19200000 +#define GC0310_FPS 30 +#define GC0310_SKIP_FRAMES 3 + +#define GC0310_ID 0xa310 + +#define GC0310_RESET_RELATED_REG CCI_REG8(0xfe) +#define GC0310_REGISTER_PAGE_0 0x0 +#define GC0310_REGISTER_PAGE_3 0x3 + +/* + * GC0310 System control registers + */ +#define GC0310_SW_STREAM_REG CCI_REG8(0x10) + +#define GC0310_START_STREAMING 0x94 /* 8-bit enable */ +#define GC0310_STOP_STREAMING 0x0 /* 8-bit disable */ + +#define GC0310_SC_CMMN_CHIP_ID_REG CCI_REG16(0xf0) + +#define GC0310_AEC_PK_EXPO_REG CCI_REG16(0x03) +#define GC0310_AGC_ADJ_REG CCI_REG8(0x48) +#define GC0310_DGC_ADJ_REG CCI_REG8(0x71) + +#define GC0310_H_CROP_START_REG CCI_REG16(0x09) +#define GC0310_V_CROP_START_REG CCI_REG16(0x0b) +#define GC0310_H_OUTSIZE_REG CCI_REG16(0x0f) +#define GC0310_V_OUTSIZE_REG CCI_REG16(0x0d) + +#define GC0310_H_BLANKING_REG CCI_REG16(0x05) +/* Hblank-register + sh-delay + H-crop + 4 (from hw) */ +#define GC0310_H_BLANK_DEFAULT (178 + 42 + 4 + 4) + +#define GC0310_V_BLANKING_REG CCI_REG16(0x07) +/* Vblank needs an offset compensate for the small V-crop done */ +#define GC0310_V_BLANK_OFFSET 2 +/* Vsync start time + 1 row vsync + vsync end time + offset */ +#define GC0310_V_BLANK_MIN (9 + 1 + 4 + GC0310_V_BLANK_OFFSET) +#define GC0310_V_BLANK_DEFAULT (27 + GC0310_V_BLANK_OFFSET) +#define GC0310_V_BLANK_MAX (4095 - GC0310_NATIVE_HEIGHT) + +#define GC0310_SH_DELAY_REG CCI_REG8(0x11) +#define GC0310_VS_START_TIME_REG CCI_REG8(0x12) +#define GC0310_VS_END_TIME_REG CCI_REG8(0x13) + +#define to_gc0310_sensor(x) container_of(x, struct gc0310_device, sd) + +struct gc0310_device { + struct v4l2_subdev sd; + struct media_pad pad; + + struct regmap *regmap; + struct gpio_desc *reset; + struct gpio_desc *powerdown; + + struct gc0310_ctrls { + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *hblank; + } ctrls; +}; + +struct gc0310_reg { + u8 reg; + u8 val; +}; + +static const struct reg_sequence gc0310_reset_register[] = { + /* System registers */ + { 0xfe, 0xf0 }, + { 0xfe, 0xf0 }, + { 0xfe, 0x00 }, + + { 0xfc, 0x0e }, /* 4e */ + { 0xfc, 0x0e }, /* 16//4e // [0]apwd [6]regf_clk_gate */ + { 0xf2, 0x80 }, /* sync output */ + { 0xf3, 0x00 }, /* 1f//01 data output */ + { 0xf7, 0x33 }, /* f9 */ + { 0xf8, 0x05 }, /* 00 */ + { 0xf9, 0x0e }, /* 0x8e //0f */ + { 0xfa, 0x11 }, + + /* MIPI */ + { 0xfe, 0x03 }, + { 0x01, 0x03 }, /* mipi 1lane */ + { 0x02, 0x22 }, /* 0x33 */ + { 0x03, 0x94 }, + { 0x04, 0x01 }, /* fifo_prog */ + { 0x05, 0x00 }, /* fifo_prog */ + { 0x06, 0x80 }, /* b0 //YUV ISP data */ + { 0x11, 0x2a }, /* 1e //LDI set YUV422 */ + { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */ + { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */ + { 0x15, 0x12 }, /* 0x10 //DPHYY_MODE read_ready */ + { 0x17, 0x01 }, + { 0x40, 0x08 }, + { 0x41, 0x00 }, + { 0x42, 0x00 }, + { 0x43, 0x00 }, + { 0x21, 0x02 }, /* 0x01 */ + { 0x22, 0x02 }, /* 0x01 */ + { 0x23, 0x01 }, /* 0x05 //Nor:0x05 DOU:0x06 */ + { 0x29, 0x00 }, + { 0x2A, 0x25 }, /* 0x05 //data zero 0x7a de */ + { 0x2B, 0x02 }, + + { 0xfe, 0x00 }, + + /* CISCTL */ + { 0x00, 0x2f }, /* 2f//0f//02//01 */ + { 0x01, 0x0f }, /* 06 */ + { 0x02, 0x04 }, + { 0x4f, 0x00 }, /* AEC 0FF */ + { 0x03, 0x01 }, /* 0x03 //04 */ + { 0x04, 0xc0 }, /* 0xe8 //58 */ + { 0x05, 0x00 }, + { 0x06, 0xb2 }, /* 0x0a //HB */ + /* Vblank (reg 0x07 + 0x08) gets set by the vblank ctrl */ + { 0x09, 0x00 }, /* row start */ + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, /* col start */ + { 0x0c, 0x00 }, + { 0x0d, 0x01 }, /* height */ + { 0x0e, 0xf2 }, /* 0xf7 //height */ + { 0x0f, 0x02 }, /* width */ + { 0x10, 0x94 }, /* 0xa0 //height */ + { 0x17, 0x14 }, + { 0x18, 0x1a }, /* 0a//[4]double reset */ + { 0x19, 0x14 }, /* AD pipeline */ + { 0x1b, 0x48 }, + { 0x1e, 0x6b }, /* 3b//col bias */ + { 0x1f, 0x28 }, /* 20//00//08//txlow */ + { 0x20, 0x89 }, /* 88//0c//[3:2]DA15 */ + { 0x21, 0x49 }, /* 48//[3] txhigh */ + { 0x22, 0xb0 }, + { 0x23, 0x04 }, /* [1:0]vcm_r */ + { 0x24, 0x16 }, /* 15 */ + { 0x34, 0x20 }, /* [6:4] rsg high//range */ + + /* BLK */ + { 0x26, 0x23 }, /* [1]dark_current_en [0]offset_en */ + { 0x28, 0xff }, /* BLK_limie_value */ + { 0x29, 0x00 }, /* global offset */ + { 0x33, 0x18 }, /* offset_ratio */ + { 0x37, 0x20 }, /* dark_current_ratio */ + { 0x2a, 0x00 }, + { 0x2b, 0x00 }, + { 0x2c, 0x00 }, + { 0x2d, 0x00 }, + { 0x2e, 0x00 }, + { 0x2f, 0x00 }, + { 0x30, 0x00 }, + { 0x31, 0x00 }, + { 0x47, 0x80 }, /* a7 */ + { 0x4e, 0x66 }, /* select_row */ + { 0xa8, 0x02 }, /* win_width_dark, same with crop_win_width */ + { 0xa9, 0x80 }, + + /* ISP */ + { 0x40, 0x06 }, /* 0xff //ff //48 */ + { 0x41, 0x00 }, /* 0x21 //00//[0]curve_en */ + { 0x42, 0x04 }, /* 0xcf //0a//[1]awn_en */ + { 0x44, 0x18 }, /* 0x18 //02 */ + { 0x46, 0x02 }, /* 0x03 //sync */ + { 0x49, 0x03 }, + { 0x4c, 0x20 }, /* 00[5]pretect exp */ + { 0x50, 0x01 }, /* crop enable */ + { 0x51, 0x00 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x01 }, + { 0x55, 0x01 }, /* crop window height */ + { 0x56, 0xf0 }, + { 0x57, 0x02 }, /* crop window width */ + { 0x58, 0x90 }, + + /* Gain */ + { 0x70, 0x70 }, /* 70 //80//global gain */ + { 0x71, 0x20 }, /* pregain gain */ + { 0x72, 0x40 }, /* post gain */ + { 0x5a, 0x84 }, /* 84//analog gain 0 */ + { 0x5b, 0xc9 }, /* c9 */ + { 0x5c, 0xed }, /* ed//not use pga gain highest level */ + { 0x77, 0x40 }, /* R gain 0x74 //awb gain */ + { 0x78, 0x40 }, /* G gain */ + { 0x79, 0x40 }, /* B gain 0x5f */ + + { 0x48, 0x00 }, + { 0xfe, 0x01 }, + { 0x0a, 0x45 }, /* [7]col gain mode */ + + { 0x3e, 0x40 }, + { 0x3f, 0x5c }, + { 0x40, 0x7b }, + { 0x41, 0xbd }, + { 0x42, 0xf6 }, + { 0x43, 0x63 }, + { 0x03, 0x60 }, + { 0x44, 0x03 }, + + /* Dark / Sun mode related */ + { 0xfe, 0x01 }, + { 0x45, 0xa4 }, /* 0xf7 */ + { 0x46, 0xf0 }, /* 0xff //f0//sun value th */ + { 0x48, 0x03 }, /* sun mode */ + { 0x4f, 0x60 }, /* sun_clamp */ + { 0xfe, 0x00 }, +}; + +static const struct reg_sequence gc0310_VGA_30fps[] = { + { 0xfe, 0x00 }, + { 0x0d, 0x01 }, /* height */ + { 0x0e, 0xf2 }, /* 0xf7 //height */ + { 0x0f, 0x02 }, /* width */ + { 0x10, 0x94 }, /* 0xa0 //height */ + + { 0x50, 0x01 }, /* crop enable */ + { 0x51, 0x00 }, + { 0x52, 0x00 }, + { 0x53, 0x00 }, + { 0x54, 0x01 }, + { 0x55, 0x01 }, /* crop window height */ + { 0x56, 0xf0 }, + { 0x57, 0x02 }, /* crop window width */ + { 0x58, 0x90 }, + + { 0xfe, 0x03 }, + { 0x12, 0x90 }, /* 00 //04 //00 //04//00 //LWC[7:0] */ + { 0x13, 0x02 }, /* 05 //05 //LWC[15:8] */ + + { 0xfe, 0x00 }, +}; + +static const s64 link_freq_menu_items[] = { + GC0310_LINK_FREQ, +}; + +static int gc0310_gain_set(struct gc0310_device *sensor, u32 gain) +{ + u8 again, dgain; + int ret = 0; + + /* Taken from original driver, this never sets dgain lower then 32? */ + + /* Change 0 - 95 to 32 - 127 */ + gain += 32; + + if (gain < 64) { + again = 0x0; /* sqrt(2) */ + dgain = gain; + } else { + again = 0x2; /* 2 * sqrt(2) */ + dgain = gain / 2; + } + + cci_write(sensor->regmap, GC0310_AGC_ADJ_REG, again, &ret); + cci_write(sensor->regmap, GC0310_DGC_ADJ_REG, dgain, &ret); + return ret; +} + +static int gc0310_exposure_update_range(struct gc0310_device *sensor) +{ + int exp_max = GC0310_NATIVE_HEIGHT + sensor->ctrls.vblank->val; + + return __v4l2_ctrl_modify_range(sensor->ctrls.exposure, 0, exp_max, + 1, exp_max); +} + +static int gc0310_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gc0310_device *sensor = + container_of(ctrl->handler, struct gc0310_device, ctrls.handler); + int ret; + + /* Update exposure range on vblank changes */ + if (ctrl->id == V4L2_CID_VBLANK) { + ret = gc0310_exposure_update_range(sensor); + if (ret) + return ret; + } + + /* Only apply changes to the controls if the device is powered up */ + if (!pm_runtime_get_if_in_use(sensor->sd.dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ret = cci_write(sensor->regmap, GC0310_AEC_PK_EXPO_REG, + ctrl->val, NULL); + break; + case V4L2_CID_ANALOGUE_GAIN: + ret = gc0310_gain_set(sensor, ctrl->val); + break; + case V4L2_CID_VBLANK: + ret = cci_write(sensor->regmap, GC0310_V_BLANKING_REG, + ctrl->val - GC0310_V_BLANK_OFFSET, + NULL); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(sensor->sd.dev); + return ret; +} + +static const struct v4l2_ctrl_ops ctrl_ops = { + .s_ctrl = gc0310_s_ctrl, +}; + +/* The GC0310 currently only supports 1 fixed fmt */ +static void gc0310_fill_format(struct v4l2_mbus_framefmt *fmt) +{ + memset(fmt, 0, sizeof(*fmt)); + fmt->width = GC0310_NATIVE_WIDTH; + fmt->height = GC0310_NATIVE_HEIGHT; + fmt->field = V4L2_FIELD_NONE; + fmt->code = MEDIA_BUS_FMT_SGRBG8_1X8; +} + +static int gc0310_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_selection *sel) +{ + /* Only the single fixed 656x496 mode is supported, without croping */ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r.top = 0; + sel->r.left = 0; + sel->r.width = GC0310_NATIVE_WIDTH; + sel->r.height = GC0310_NATIVE_HEIGHT; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int gc0310_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + gpiod_set_value_cansleep(sensor->powerdown, 1); + gpiod_set_value_cansleep(sensor->reset, 1); + return 0; +} + +static int gc0310_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + fsleep(10 * USEC_PER_MSEC); + gpiod_set_value_cansleep(sensor->reset, 0); + fsleep(10 * USEC_PER_MSEC); + gpiod_set_value_cansleep(sensor->powerdown, 0); + fsleep(10 * USEC_PER_MSEC); + + return 0; +} + +static int gc0310_detect(struct gc0310_device *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + u64 val; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -ENODEV; + + ret = cci_read(sensor->regmap, GC0310_SC_CMMN_CHIP_ID_REG, &val, NULL); + if (ret < 0) { + dev_err(&client->dev, "read sensor_id failed: %d\n", ret); + return -ENODEV; + } + + dev_dbg(&client->dev, "sensor ID = 0x%llx\n", val); + + if (val != GC0310_ID) { + dev_err(&client->dev, "sensor ID error, read id = 0x%llx, target id = 0x%x\n", + val, GC0310_ID); + return -ENODEV; + } + + dev_dbg(&client->dev, "detect gc0310 success\n"); + + return 0; +} + +static int gc0310_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct gc0310_device *sensor = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret; + + ret = pm_runtime_resume_and_get(&client->dev); + if (ret) + return ret; + + ret = regmap_multi_reg_write(sensor->regmap, + gc0310_reset_register, + ARRAY_SIZE(gc0310_reset_register)); + if (ret) + goto error_power_down; + + ret = regmap_multi_reg_write(sensor->regmap, + gc0310_VGA_30fps, + ARRAY_SIZE(gc0310_VGA_30fps)); + if (ret) + goto error_power_down; + + /* restore value of all ctrls */ + ret = __v4l2_ctrl_handler_setup(&sensor->ctrls.handler); + + /* enable per frame MIPI and sensor ctrl reset */ + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, 0x30, &ret); + + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_3, &ret); + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, + GC0310_START_STREAMING, &ret); + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_0, &ret); + +error_power_down: + if (ret) + pm_runtime_put(&client->dev); + + return ret; +} + +static int gc0310_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct gc0310_device *sensor = to_gc0310_sensor(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); + int ret = 0; + + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_3, &ret); + cci_write(sensor->regmap, GC0310_SW_STREAM_REG, + GC0310_STOP_STREAMING, &ret); + cci_write(sensor->regmap, GC0310_RESET_RELATED_REG, + GC0310_REGISTER_PAGE_0, &ret); + + pm_runtime_put(&client->dev); + return ret; +} + +static int gc0310_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* We support only a single format */ + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG8_1X8; + return 0; +} + +static int gc0310_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + /* We support only a single resolution */ + if (fse->index) + return -EINVAL; + + fse->min_width = GC0310_NATIVE_WIDTH; + fse->max_width = GC0310_NATIVE_WIDTH; + fse->min_height = GC0310_NATIVE_HEIGHT; + fse->max_height = GC0310_NATIVE_HEIGHT; + + return 0; +} + +static const struct v4l2_subdev_video_ops gc0310_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops gc0310_pad_ops = { + .enum_mbus_code = gc0310_enum_mbus_code, + .enum_frame_size = gc0310_enum_frame_size, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = v4l2_subdev_get_fmt, /* Only 1 fixed mode supported */ + .get_selection = gc0310_get_selection, + .set_selection = gc0310_get_selection, + .enable_streams = gc0310_enable_streams, + .disable_streams = gc0310_disable_streams, +}; + +static const struct v4l2_subdev_ops gc0310_ops = { + .video = &gc0310_video_ops, + .pad = &gc0310_pad_ops, +}; + +static int gc0310_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + gc0310_fill_format(v4l2_subdev_state_get_format(sd_state, 0)); + return 0; +} + +static const struct v4l2_subdev_internal_ops gc0310_internal_ops = { + .init_state = gc0310_init_state, +}; + +static int gc0310_init_controls(struct gc0310_device *sensor) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->sd); + struct v4l2_ctrl_handler *hdl = &sensor->ctrls.handler; + struct v4l2_fwnode_device_properties props; + int exp_max, ret; + + v4l2_ctrl_handler_init(hdl, 8); + + /* Use the same lock for controls as for everything else */ + sensor->sd.ctrl_handler = hdl; + + exp_max = GC0310_NATIVE_HEIGHT + GC0310_V_BLANK_DEFAULT; + sensor->ctrls.exposure = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_EXPOSURE, 0, + exp_max, 1, exp_max); + + /* 32 steps at base gain 1 + 64 half steps at base gain 2 */ + sensor->ctrls.gain = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_ANALOGUE_GAIN, 0, 95, 1, 31); + + sensor->ctrls.link_freq = + v4l2_ctrl_new_int_menu(hdl, NULL, V4L2_CID_LINK_FREQ, + 0, 0, link_freq_menu_items); + sensor->ctrls.pixel_rate = + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_PIXEL_RATE, 0, + GC0310_PIXELRATE, 1, GC0310_PIXELRATE); + + sensor->ctrls.vblank = + v4l2_ctrl_new_std(hdl, &ctrl_ops, V4L2_CID_VBLANK, + GC0310_V_BLANK_MIN, + GC0310_V_BLANK_MAX, 1, + GC0310_V_BLANK_DEFAULT); + + sensor->ctrls.hblank = + v4l2_ctrl_new_std(hdl, NULL, V4L2_CID_HBLANK, + GC0310_H_BLANK_DEFAULT, + GC0310_H_BLANK_DEFAULT, 1, + GC0310_H_BLANK_DEFAULT); + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + return ret; + + v4l2_ctrl_new_fwnode_properties(hdl, &ctrl_ops, &props); + + if (hdl->error) + return hdl->error; + + sensor->ctrls.pixel_rate->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->ctrls.link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + sensor->ctrls.hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; + return 0; +} + +static void gc0310_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct gc0310_device *sensor = to_gc0310_sensor(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sensor->sd.entity); + v4l2_ctrl_handler_free(&sensor->ctrls.handler); + pm_runtime_disable(&client->dev); + if (!pm_runtime_status_suspended(&client->dev)) { + gc0310_power_off(&client->dev); + pm_runtime_set_suspended(&client->dev); + } +} + +static int gc0310_check_hwcfg(struct device *dev) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep_fwnode; + unsigned long link_freq_bitmap; + u32 mclk; + int ret; + + /* + * Sometimes the fwnode graph is initialized by the bridge driver. + * Bridge drivers doing this may also add GPIO mappings, wait for this. + */ + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, 0); + if (!ep_fwnode) + return dev_err_probe(dev, -EPROBE_DEFER, + "waiting for fwnode graph endpoint\n"); + + ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", + &mclk); + if (ret) { + fwnode_handle_put(ep_fwnode); + return dev_err_probe(dev, ret, + "reading clock-frequency property\n"); + } + + if (mclk != GC0310_MCLK_FREQ) { + fwnode_handle_put(ep_fwnode); + return dev_err_probe(dev, -EINVAL, + "external clock %u is not supported\n", + mclk); + } + + ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &bus_cfg); + fwnode_handle_put(ep_fwnode); + if (ret) + return dev_err_probe(dev, ret, "parsing endpoint failed\n"); + + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + + if (ret == 0 && bus_cfg.bus.mipi_csi2.num_data_lanes != 1) + ret = dev_err_probe(dev, -EINVAL, + "number of CSI2 data lanes %u is not supported\n", + bus_cfg.bus.mipi_csi2.num_data_lanes); + + v4l2_fwnode_endpoint_free(&bus_cfg); + return ret; +} + +static int gc0310_probe(struct i2c_client *client) +{ + struct gc0310_device *sensor; + int ret; + + ret = gc0310_check_hwcfg(&client->dev); + if (ret) + return ret; + + sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + sensor->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->reset)) { + return dev_err_probe(&client->dev, PTR_ERR(sensor->reset), + "getting reset GPIO\n"); + } + + sensor->powerdown = devm_gpiod_get(&client->dev, "powerdown", GPIOD_OUT_HIGH); + if (IS_ERR(sensor->powerdown)) { + return dev_err_probe(&client->dev, PTR_ERR(sensor->powerdown), + "getting powerdown GPIO\n"); + } + + v4l2_i2c_subdev_init(&sensor->sd, client, &gc0310_ops); + + sensor->regmap = devm_cci_regmap_init_i2c(client, 8); + if (IS_ERR(sensor->regmap)) + return PTR_ERR(sensor->regmap); + + gc0310_power_on(&client->dev); + + pm_runtime_set_active(&client->dev); + pm_runtime_get_noresume(&client->dev); + pm_runtime_enable(&client->dev); + + ret = gc0310_detect(sensor); + if (ret) + goto err_power_down; + + sensor->sd.internal_ops = &gc0310_internal_ops; + sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sensor->pad.flags = MEDIA_PAD_FL_SOURCE; + sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + ret = gc0310_init_controls(sensor); + if (ret) + goto err_power_down; + + ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad); + if (ret) + goto err_power_down; + + sensor->sd.state_lock = sensor->ctrls.handler.lock; + ret = v4l2_subdev_init_finalize(&sensor->sd); + if (ret) + goto err_power_down; + + ret = v4l2_async_register_subdev_sensor(&sensor->sd); + if (ret) + goto err_power_down; + + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); + + return 0; + +err_power_down: + pm_runtime_put_noidle(&client->dev); + gc0310_remove(client); + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(gc0310_pm_ops, + gc0310_power_off, gc0310_power_on, NULL); + +static const struct acpi_device_id gc0310_acpi_match[] = { + {"INT0310"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, gc0310_acpi_match); + +static struct i2c_driver gc0310_driver = { + .driver = { + .name = "gc0310", + .pm = pm_sleep_ptr(&gc0310_pm_ops), + .acpi_match_table = gc0310_acpi_match, + }, + .probe = gc0310_probe, + .remove = gc0310_remove, +}; +module_i2c_driver(gc0310_driver); + +MODULE_AUTHOR("Lai, Angie <angie.lai@intel.com>"); +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); +MODULE_DESCRIPTION("A low-level driver for GalaxyCore GC0310 sensors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c index 3f7f3d5abeeb..8ba17f80fffe 100644 --- a/drivers/media/i2c/gc05a2.c +++ b/drivers/media/i2c/gc05a2.c @@ -1235,16 +1235,12 @@ static int gc05a2_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(gc05a2->regmap), "failed to init CCI\n"); - gc05a2->xclk = devm_clk_get(dev, NULL); + gc05a2->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true, + GC05A2_DEFAULT_CLK_FREQ); if (IS_ERR(gc05a2->xclk)) return dev_err_probe(dev, PTR_ERR(gc05a2->xclk), "failed to get xclk\n"); - ret = clk_set_rate(gc05a2->xclk, GC05A2_DEFAULT_CLK_FREQ); - if (ret) - return dev_err_probe(dev, ret, - "failed to set xclk frequency\n"); - ret = gc05a2_get_regulators(dev, gc05a2); if (ret < 0) return dev_err_probe(dev, ret, diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c index 938709a677b6..11fd936db9c3 100644 --- a/drivers/media/i2c/gc08a3.c +++ b/drivers/media/i2c/gc08a3.c @@ -1199,16 +1199,12 @@ static int gc08a3_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(gc08a3->regmap), "failed to init CCI\n"); - gc08a3->xclk = devm_clk_get(dev, NULL); + gc08a3->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, true, + GC08A3_DEFAULT_CLK_FREQ); if (IS_ERR(gc08a3->xclk)) return dev_err_probe(dev, PTR_ERR(gc08a3->xclk), "failed to get xclk\n"); - ret = clk_set_rate(gc08a3->xclk, GC08A3_DEFAULT_CLK_FREQ); - if (ret) - return dev_err_probe(dev, ret, - "failed to set xclk frequency\n"); - ret = gc08a3_get_regulators(dev, gc08a3); if (ret < 0) return dev_err_probe(dev, ret, diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c index ba02161d46e7..b215963a2648 100644 --- a/drivers/media/i2c/gc2145.c +++ b/drivers/media/i2c/gc2145.c @@ -963,7 +963,6 @@ static int gc2145_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -985,7 +984,6 @@ static int gc2145_disable_streams(struct v4l2_subdev *sd, if (ret) dev_err(&client->dev, "%s failed to write regs\n", __func__); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -1193,7 +1191,6 @@ static int gc2145_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -1334,7 +1331,7 @@ static int gc2145_probe(struct i2c_client *client) return -EINVAL; /* Get system clock (xclk) */ - gc2145->xclk = devm_clk_get(dev, NULL); + gc2145->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(gc2145->xclk)) return dev_err_probe(dev, PTR_ERR(gc2145->xclk), "failed to get xclk\n"); diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c index 076c19fcf99c..de573cee4451 100644 --- a/drivers/media/i2c/hi556.c +++ b/drivers/media/i2c/hi556.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -631,6 +632,8 @@ static const char * const hi556_supply_names[] = { }; struct hi556 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -715,7 +718,6 @@ static int hi556_write_reg(struct hi556 *hi556, u16 reg, u16 len, u32 val) static int hi556_write_reg_list(struct hi556 *hi556, const struct hi556_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); unsigned int i; int ret; @@ -724,7 +726,7 @@ static int hi556_write_reg_list(struct hi556 *hi556, HI556_REG_VALUE_16BIT, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(hi556->dev, "failed to write reg 0x%4.4x. error = %d\n", r_list->regs[i].address, ret); return ret; @@ -785,7 +787,6 @@ static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) { struct hi556 *hi556 = container_of(ctrl->handler, struct hi556, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); s64 exposure_max; int ret = 0; @@ -801,7 +802,7 @@ static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(hi556->dev)) return 0; switch (ctrl->id) { @@ -835,7 +836,7 @@ static int hi556_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(hi556->dev); return ret; } @@ -921,7 +922,6 @@ static void hi556_assign_pad_format(const struct hi556_mode *mode, static int hi556_identify_module(struct hi556 *hi556) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); int ret; u32 val; @@ -934,7 +934,7 @@ static int hi556_identify_module(struct hi556 *hi556) return ret; if (val != HI556_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(hi556->dev, "chip id mismatch: %x!=%x\n", HI556_CHIP_ID, val); return -ENXIO; } @@ -998,7 +998,6 @@ static int hi556_get_selection(struct v4l2_subdev *sd, static int hi556_start_streaming(struct hi556 *hi556) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); const struct hi556_reg_list *reg_list; int link_freq_index, ret; @@ -1010,14 +1009,14 @@ static int hi556_start_streaming(struct hi556 *hi556) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = hi556_write_reg_list(hi556, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls\n"); + dev_err(hi556->dev, "failed to set plls\n"); return ret; } reg_list = &hi556->cur_mode->reg_list; ret = hi556_write_reg_list(hi556, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(hi556->dev, "failed to set mode\n"); return ret; } @@ -1029,7 +1028,7 @@ static int hi556_start_streaming(struct hi556 *hi556) HI556_REG_VALUE_16BIT, HI556_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream\n"); + dev_err(hi556->dev, "failed to set stream\n"); return ret; } @@ -1038,22 +1037,19 @@ static int hi556_start_streaming(struct hi556 *hi556) static void hi556_stop_streaming(struct hi556 *hi556) { - struct i2c_client *client = v4l2_get_subdevdata(&hi556->sd); - if (hi556_write_reg(hi556, HI556_REG_MODE_SELECT, HI556_REG_VALUE_16BIT, HI556_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream\n"); + dev_err(hi556->dev, "failed to set stream\n"); } static int hi556_set_stream(struct v4l2_subdev *sd, int enable) { struct hi556 *hi556 = to_hi556(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&hi556->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(hi556->dev); if (ret < 0) { mutex_unlock(&hi556->mutex); return ret; @@ -1062,11 +1058,11 @@ static int hi556_set_stream(struct v4l2_subdev *sd, int enable) ret = hi556_start_streaming(hi556); if (ret) { hi556_stop_streaming(hi556); - pm_runtime_put(&client->dev); + pm_runtime_put(hi556->dev); } } else { hi556_stop_streaming(hi556); - pm_runtime_put(&client->dev); + pm_runtime_put(hi556->dev); } mutex_unlock(&hi556->mutex); @@ -1217,7 +1213,6 @@ static int hi556_check_hwcfg(struct device *dev) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret = 0; unsigned int i, j; @@ -1235,18 +1230,6 @@ static int hi556_check_hwcfg(struct device *dev) if (ret) return dev_err_probe(dev, ret, "parsing endpoint failed\n"); - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - dev_err(dev, "can't get clock frequency\n"); - goto check_hwcfg_error; - } - - if (mclk != HI556_MCLK) { - dev_err(dev, "external clock %d is not supported\n", mclk); - ret = -EINVAL; - goto check_hwcfg_error; - } - if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { dev_err(dev, "number of CSI2 data lanes %d is not supported\n", bus_cfg.bus.mipi_csi2.num_data_lanes); @@ -1289,7 +1272,7 @@ static void hi556_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(hi556->dev); mutex_destroy(&hi556->mutex); } @@ -1336,6 +1319,7 @@ static int hi556_resume(struct device *dev) static int hi556_probe(struct i2c_client *client) { struct hi556 *hi556; + unsigned long freq; bool full_power; int i, ret; @@ -1347,40 +1331,48 @@ static int hi556_probe(struct i2c_client *client) if (!hi556) return -ENOMEM; + hi556->dev = &client->dev; + v4l2_i2c_subdev_init(&hi556->sd, client, &hi556_subdev_ops); - hi556->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + hi556->reset_gpio = devm_gpiod_get_optional(hi556->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hi556->reset_gpio)) - return dev_err_probe(&client->dev, PTR_ERR(hi556->reset_gpio), + return dev_err_probe(hi556->dev, PTR_ERR(hi556->reset_gpio), "failed to get reset GPIO\n"); - hi556->clk = devm_clk_get_optional(&client->dev, "clk"); + hi556->clk = devm_v4l2_sensor_clk_get(hi556->dev, "clk"); if (IS_ERR(hi556->clk)) - return dev_err_probe(&client->dev, PTR_ERR(hi556->clk), + return dev_err_probe(hi556->dev, PTR_ERR(hi556->clk), "failed to get clock\n"); + freq = clk_get_rate(hi556->clk); + if (freq != HI556_MCLK) + return dev_err_probe(hi556->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + for (i = 0; i < ARRAY_SIZE(hi556_supply_names); i++) hi556->supplies[i].supply = hi556_supply_names[i]; - ret = devm_regulator_bulk_get(&client->dev, + ret = devm_regulator_bulk_get(hi556->dev, ARRAY_SIZE(hi556_supply_names), hi556->supplies); if (ret) - return dev_err_probe(&client->dev, ret, + return dev_err_probe(hi556->dev, ret, "failed to get regulators\n"); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(hi556->dev); if (full_power) { /* Ensure non ACPI managed resources are enabled */ - ret = hi556_resume(&client->dev); + ret = hi556_resume(hi556->dev); if (ret) - return dev_err_probe(&client->dev, ret, + return dev_err_probe(hi556->dev, ret, "failed to power on sensor\n"); ret = hi556_identify_module(hi556); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(hi556->dev, "failed to find sensor: %d\n", ret); goto probe_error_power_off; } } @@ -1389,7 +1381,7 @@ static int hi556_probe(struct i2c_client *client) hi556->cur_mode = &supported_modes[0]; ret = hi556_init_controls(hi556); if (ret) { - dev_err(&client->dev, "failed to init controls: %d\n", ret); + dev_err(hi556->dev, "failed to init controls: %d\n", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1400,22 +1392,22 @@ static int hi556_probe(struct i2c_client *client) hi556->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&hi556->sd.entity, 1, &hi556->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d\n", ret); + dev_err(hi556->dev, "failed to init entity pads: %d\n", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&hi556->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d\n", + dev_err(hi556->dev, "failed to register V4L2 subdev: %d\n", ret); goto probe_error_media_entity_cleanup; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(hi556->dev); + pm_runtime_enable(hi556->dev); + pm_runtime_idle(hi556->dev); return 0; @@ -1428,7 +1420,7 @@ probe_error_v4l2_ctrl_handler_free: probe_error_power_off: if (full_power) - hi556_suspend(&client->dev); + hi556_suspend(hi556->dev); return ret; } diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c index 172772decd3d..a3f77b8434ca 100644 --- a/drivers/media/i2c/hi846.c +++ b/drivers/media/i2c/hi846.c @@ -2052,12 +2052,11 @@ static int hi846_probe(struct i2c_client *client) return ret; } - hi846->clock = devm_clk_get(&client->dev, NULL); - if (IS_ERR(hi846->clock)) { - dev_err(&client->dev, "failed to get clock: %pe\n", - hi846->clock); - return PTR_ERR(hi846->clock); - } + hi846->clock = devm_v4l2_sensor_clk_get(&client->dev, NULL); + if (IS_ERR(hi846->clock)) + return dev_err_probe(&client->dev, PTR_ERR(hi846->clock), + "failed to get clock: %pe\n", + hi846->clock); mclk_freq = clk_get_rate(hi846->clock); if (mclk_freq != 25000000) diff --git a/drivers/media/i2c/hi847.c b/drivers/media/i2c/hi847.c index 546833f5b5f5..def01aa07b2f 100644 --- a/drivers/media/i2c/hi847.c +++ b/drivers/media/i2c/hi847.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -2166,6 +2168,9 @@ static const struct hi847_mode supported_modes[] = { }; struct hi847 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -2244,7 +2249,6 @@ static int hi847_write_reg(struct hi847 *hi847, u16 reg, u16 len, u32 val) static int hi847_write_reg_list(struct hi847 *hi847, const struct hi847_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); unsigned int i; int ret; @@ -2253,7 +2257,7 @@ static int hi847_write_reg_list(struct hi847 *hi847, HI847_REG_VALUE_16BIT, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(hi847->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -2408,7 +2412,6 @@ static int hi847_set_ctrl(struct v4l2_ctrl *ctrl) { struct hi847 *hi847 = container_of(ctrl->handler, struct hi847, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); s64 exposure_max; int ret = 0; @@ -2424,7 +2427,7 @@ static int hi847_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(hi847->dev)) return 0; switch (ctrl->id) { @@ -2466,7 +2469,7 @@ static int hi847_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(hi847->dev); return ret; } @@ -2557,7 +2560,6 @@ static void hi847_assign_pad_format(const struct hi847_mode *mode, static int hi847_start_streaming(struct hi847 *hi847) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); const struct hi847_reg_list *reg_list; int link_freq_index, ret; @@ -2565,14 +2567,14 @@ static int hi847_start_streaming(struct hi847 *hi847) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = hi847_write_reg_list(hi847, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(hi847->dev, "failed to set plls"); return ret; } reg_list = &hi847->cur_mode->reg_list; ret = hi847_write_reg_list(hi847, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(hi847->dev, "failed to set mode"); return ret; } @@ -2587,7 +2589,7 @@ static int hi847_start_streaming(struct hi847 *hi847) HI847_REG_VALUE_16BIT, HI847_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(hi847->dev, "failed to set stream"); return ret; } @@ -2596,28 +2598,25 @@ static int hi847_start_streaming(struct hi847 *hi847) static void hi847_stop_streaming(struct hi847 *hi847) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); - if (hi847_write_reg(hi847, HI847_REG_MODE_TG, HI847_REG_VALUE_16BIT, HI847_REG_MODE_TG_DISABLE)) - dev_err(&client->dev, "failed to set stream 0x%x", + dev_err(hi847->dev, "failed to set stream 0x%x", HI847_REG_MODE_TG); if (hi847_write_reg(hi847, HI847_REG_MODE_SELECT, HI847_REG_VALUE_16BIT, HI847_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream 0x%x", + dev_err(hi847->dev, "failed to set stream 0x%x", HI847_REG_MODE_SELECT); } static int hi847_set_stream(struct v4l2_subdev *sd, int enable) { struct hi847 *hi847 = to_hi847(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&hi847->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(hi847->dev); if (ret) { mutex_unlock(&hi847->mutex); return ret; @@ -2627,11 +2626,11 @@ static int hi847_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; hi847_stop_streaming(hi847); - pm_runtime_put(&client->dev); + pm_runtime_put(hi847->dev); } } else { hi847_stop_streaming(hi847); - pm_runtime_put(&client->dev); + pm_runtime_put(hi847->dev); } mutex_unlock(&hi847->mutex); @@ -2768,7 +2767,6 @@ static const struct v4l2_subdev_internal_ops hi847_internal_ops = { static int hi847_identify_module(struct hi847 *hi847) { - struct i2c_client *client = v4l2_get_subdevdata(&hi847->sd); int ret; u32 val; @@ -2778,7 +2776,7 @@ static int hi847_identify_module(struct hi847 *hi847) return ret; if (val != HI847_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(hi847->dev, "chip id mismatch: %x!=%x", HI847_CHIP_ID, val); return -ENXIO; } @@ -2793,24 +2791,12 @@ static int hi847_check_hwcfg(struct device *dev) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - - if (mclk != HI847_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -2862,22 +2848,36 @@ static void hi847_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(hi847->dev); mutex_destroy(&hi847->mutex); } static int hi847_probe(struct i2c_client *client) { struct hi847 *hi847; + unsigned long freq; int ret; hi847 = devm_kzalloc(&client->dev, sizeof(*hi847), GFP_KERNEL); if (!hi847) return -ENOMEM; - ret = hi847_check_hwcfg(&client->dev); + hi847->dev = &client->dev; + + hi847->clk = devm_v4l2_sensor_clk_get(hi847->dev, NULL); + if (IS_ERR(hi847->clk)) + return dev_err_probe(hi847->dev, PTR_ERR(hi847->clk), + "failed to get clock\n"); + + freq = clk_get_rate(hi847->clk); + if (freq != HI847_MCLK) + return dev_err_probe(hi847->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + + ret = hi847_check_hwcfg(hi847->dev); if (ret) { - dev_err(&client->dev, "failed to get HW configuration: %d", + dev_err(hi847->dev, "failed to get HW configuration: %d", ret); return ret; } @@ -2885,7 +2885,7 @@ static int hi847_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&hi847->sd, client, &hi847_subdev_ops); ret = hi847_identify_module(hi847); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(hi847->dev, "failed to find sensor: %d", ret); return ret; } @@ -2893,7 +2893,7 @@ static int hi847_probe(struct i2c_client *client) hi847->cur_mode = &supported_modes[0]; ret = hi847_init_controls(hi847); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(hi847->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -2904,20 +2904,20 @@ static int hi847_probe(struct i2c_client *client) hi847->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&hi847->sd.entity, 1, &hi847->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(hi847->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&hi847->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(hi847->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(hi847->dev); + pm_runtime_enable(hi847->dev); + pm_runtime_idle(hi847->dev); return 0; diff --git a/drivers/media/i2c/imx208.c b/drivers/media/i2c/imx208.c index 2b5a6ce7b1ae..d5350bb46f14 100644 --- a/drivers/media/i2c/imx208.c +++ b/drivers/media/i2c/imx208.c @@ -2,13 +2,15 @@ // Copyright (C) 2021 Intel Corporation #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> -#include <linux/unaligned.h> #define IMX208_REG_MODE_SELECT 0x0100 #define IMX208_MODE_STANDBY 0x00 @@ -268,6 +270,9 @@ static const struct imx208_mode supported_modes[] = { }; struct imx208 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -372,7 +377,6 @@ static int imx208_write_reg(struct imx208 *imx208, u16 reg, u32 len, u32 val) static int imx208_write_regs(struct imx208 *imx208, const struct imx208_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); unsigned int i; int ret; @@ -380,7 +384,7 @@ static int imx208_write_regs(struct imx208 *imx208, ret = imx208_write_reg(imx208, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(imx208->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -431,14 +435,13 @@ static int imx208_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx208 *imx208 = container_of(ctrl->handler, struct imx208, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); int ret; /* * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(imx208->dev)) return 0; switch (ctrl->id) { @@ -471,13 +474,13 @@ static int imx208_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_err(&client->dev, + dev_err(imx208->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); return ret; } @@ -620,7 +623,6 @@ static int imx208_set_pad_format(struct v4l2_subdev *sd, static int imx208_identify_module(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); int ret; u32 val; @@ -630,13 +632,13 @@ static int imx208_identify_module(struct imx208 *imx208) ret = imx208_read_reg(imx208, IMX208_REG_CHIP_ID, 2, &val); if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", + dev_err(imx208->dev, "failed to read chip id %x\n", IMX208_CHIP_ID); return ret; } if (val != IMX208_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(imx208->dev, "chip id mismatch: %x!=%x\n", IMX208_CHIP_ID, val); return -EIO; } @@ -649,7 +651,6 @@ static int imx208_identify_module(struct imx208 *imx208) /* Start streaming */ static int imx208_start_streaming(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); const struct imx208_reg_list *reg_list; int ret, link_freq_index; @@ -662,7 +663,7 @@ static int imx208_start_streaming(struct imx208 *imx208) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(imx208->dev, "%s failed to set plls\n", __func__); return ret; } @@ -670,7 +671,7 @@ static int imx208_start_streaming(struct imx208 *imx208) reg_list = &imx208->cur_mode->reg_list; ret = imx208_write_regs(imx208, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(imx208->dev, "%s failed to set mode\n", __func__); return ret; } @@ -687,14 +688,13 @@ static int imx208_start_streaming(struct imx208 *imx208) /* Stop streaming */ static int imx208_stop_streaming(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); int ret; /* set stream off register */ ret = imx208_write_reg(imx208, IMX208_REG_MODE_SELECT, 1, IMX208_MODE_STANDBY); if (ret) - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(imx208->dev, "%s failed to set stream\n", __func__); /* * Return success even if it was an error, as there is nothing the @@ -706,13 +706,12 @@ static int imx208_stop_streaming(struct imx208 *imx208) static int imx208_set_stream(struct v4l2_subdev *sd, int enable) { struct imx208 *imx208 = to_imx208(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx208->imx208_mx); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx208->dev); if (ret) { mutex_unlock(&imx208->imx208_mx); return ret; @@ -727,7 +726,7 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx208_stop_streaming(imx208); - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); } mutex_unlock(&imx208->imx208_mx); @@ -739,7 +738,7 @@ static int imx208_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); mutex_unlock(&imx208->imx208_mx); return ret; @@ -778,7 +777,7 @@ static int imx208_read_otp(struct imx208 *imx208) if (imx208->otp_read) goto out_unlock; - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx208->dev); if (ret) goto out_unlock; @@ -805,7 +804,7 @@ static int imx208_read_otp(struct imx208 *imx208) } out_pm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx208->dev); out_unlock: mutex_unlock(&imx208->imx208_mx); @@ -835,7 +834,6 @@ static const BIN_ATTR_RO(otp, IMX208_OTP_SIZE); /* Initialize control handlers */ static int imx208_init_controls(struct imx208 *imx208) { - struct i2c_client *client = v4l2_get_subdevdata(&imx208->sd); struct v4l2_ctrl_handler *ctrl_hdlr = &imx208->ctrl_handler; s64 exposure_max; s64 vblank_def; @@ -914,7 +912,7 @@ static int imx208_init_controls(struct imx208 *imx208) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(imx208->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } @@ -938,31 +936,36 @@ static void imx208_free_controls(struct imx208 *imx208) static int imx208_probe(struct i2c_client *client) { struct imx208 *imx208; + unsigned long freq; int ret; bool full_power; - u32 val = 0; - - device_property_read_u32(&client->dev, "clock-frequency", &val); - if (val != 19200000) { - dev_err(&client->dev, - "Unsupported clock-frequency %u. Expected 19200000.\n", - val); - return -EINVAL; - } imx208 = devm_kzalloc(&client->dev, sizeof(*imx208), GFP_KERNEL); if (!imx208) return -ENOMEM; + imx208->dev = &client->dev; + + imx208->clk = devm_v4l2_sensor_clk_get(imx208->dev, NULL); + if (IS_ERR(imx208->clk)) + return dev_err_probe(imx208->dev, PTR_ERR(imx208->clk), + "failed to get clock\n"); + + freq = clk_get_rate(imx208->clk); + if (freq != 19200000) + return dev_err_probe(imx208->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx208->sd, client, &imx208_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(imx208->dev); if (full_power) { /* Check module identity */ ret = imx208_identify_module(imx208); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(imx208->dev, "failed to find sensor: %d", ret); goto error_probe; } } @@ -972,7 +975,7 @@ static int imx208_probe(struct i2c_client *client) ret = imx208_init_controls(imx208); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(imx208->dev, "failed to init controls: %d", ret); goto error_probe; } @@ -985,7 +988,7 @@ static int imx208_probe(struct i2c_client *client) imx208->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx208->sd.entity, 1, &imx208->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(imx208->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -993,17 +996,17 @@ static int imx208_probe(struct i2c_client *client) if (ret < 0) goto error_media_entity; - ret = device_create_bin_file(&client->dev, &bin_attr_otp); + ret = device_create_bin_file(imx208->dev, &bin_attr_otp); if (ret) { - dev_err(&client->dev, "sysfs otp creation failed\n"); + dev_err(imx208->dev, "sysfs otp creation failed\n"); goto error_async_subdev; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(imx208->dev); + pm_runtime_enable(imx208->dev); + pm_runtime_idle(imx208->dev); return 0; @@ -1027,13 +1030,13 @@ static void imx208_remove(struct i2c_client *client) struct v4l2_subdev *sd = i2c_get_clientdata(client); struct imx208 *imx208 = to_imx208(sd); - device_remove_bin_file(&client->dev, &bin_attr_otp); + device_remove_bin_file(imx208->dev, &bin_attr_otp); v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); imx208_free_controls(imx208); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx208->dev); + pm_runtime_set_suspended(imx208->dev); mutex_destroy(&imx208->imx208_mx); } diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index a0cef9e61b41..94ebe625c9e6 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -881,6 +881,109 @@ static const struct v4l2_ctrl_ops imx214_ctrl_ops = { .s_ctrl = imx214_set_ctrl, }; +static int imx214_pll_calculate(struct imx214 *imx214, struct ccs_pll *pll, + unsigned int link_freq) +{ + struct ccs_pll_limits limits = { + .min_ext_clk_freq_hz = 6000000, + .max_ext_clk_freq_hz = 27000000, + + .vt_fr = { + .min_pre_pll_clk_div = 1, + .max_pre_pll_clk_div = 15, + /* Value is educated guess as we don't have a spec */ + .min_pll_ip_clk_freq_hz = 6000000, + /* Value is educated guess as we don't have a spec */ + .max_pll_ip_clk_freq_hz = 12000000, + .min_pll_multiplier = 12, + .max_pll_multiplier = 1200, + .min_pll_op_clk_freq_hz = 338000000, + .max_pll_op_clk_freq_hz = 1200000000, + }, + .vt_bk = { + .min_sys_clk_div = 2, + .max_sys_clk_div = 4, + .min_pix_clk_div = 5, + .max_pix_clk_div = 10, + .min_pix_clk_freq_hz = 30000000, + .max_pix_clk_freq_hz = 120000000, + }, + .op_bk = { + .min_sys_clk_div = 1, + .max_sys_clk_div = 2, + .min_pix_clk_div = 6, + .max_pix_clk_div = 10, + .min_pix_clk_freq_hz = 30000000, + .max_pix_clk_freq_hz = 120000000, + }, + + .min_line_length_pck_bin = IMX214_PPL_DEFAULT, + .min_line_length_pck = IMX214_PPL_DEFAULT, + }; + unsigned int num_lanes = imx214->bus_cfg.bus.mipi_csi2.num_data_lanes; + + /* + * There are no documented constraints on the sys clock frequency, for + * either branch. Recover them based on the PLL output clock frequency + * and sys_clk_div limits on one hand, and the pix clock frequency and + * the pix_clk_div limits on the other hand. + */ + limits.vt_bk.min_sys_clk_freq_hz = + max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.vt_bk.max_sys_clk_div, + limits.vt_bk.min_pix_clk_freq_hz * limits.vt_bk.min_pix_clk_div); + limits.vt_bk.max_sys_clk_freq_hz = + min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.vt_bk.min_sys_clk_div, + limits.vt_bk.max_pix_clk_freq_hz * limits.vt_bk.max_pix_clk_div); + + limits.op_bk.min_sys_clk_freq_hz = + max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.op_bk.max_sys_clk_div, + limits.op_bk.min_pix_clk_freq_hz * limits.op_bk.min_pix_clk_div); + limits.op_bk.max_sys_clk_freq_hz = + min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.op_bk.min_sys_clk_div, + limits.op_bk.max_pix_clk_freq_hz * limits.op_bk.max_pix_clk_div); + + memset(pll, 0, sizeof(*pll)); + + pll->bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; + pll->op_lanes = num_lanes; + pll->vt_lanes = num_lanes; + pll->csi2.lanes = num_lanes; + + pll->binning_horizontal = 1; + pll->binning_vertical = 1; + pll->scale_m = 1; + pll->scale_n = 1; + pll->bits_per_pixel = + IMX214_CSI_DATA_FORMAT_RAW10 & IMX214_BITS_PER_PIXEL_MASK; + pll->flags = CCS_PLL_FLAG_LANE_SPEED_MODEL; + pll->link_freq = link_freq; + pll->ext_clk_freq_hz = clk_get_rate(imx214->xclk); + + return ccs_pll_calculate(imx214->dev, &limits, pll); +} + +static int imx214_pll_update(struct imx214 *imx214) +{ + u64 link_freq; + int ret; + + link_freq = imx214->bus_cfg.link_frequencies[imx214->link_freq->val]; + ret = imx214_pll_calculate(imx214, &imx214->pll, link_freq); + if (ret) { + dev_err(imx214->dev, "PLL calculations failed: %d\n", ret); + return ret; + } + + ret = v4l2_ctrl_s_ctrl_int64(imx214->pixel_rate, + imx214->pll.pixel_rate_pixel_array); + if (ret) { + dev_err(imx214->dev, "failed to set pixel rate\n"); + return ret; + } + + return 0; +} + static int imx214_ctrls_init(struct imx214 *imx214) { static const struct v4l2_area unit_size = { @@ -1003,6 +1106,13 @@ static int imx214_ctrls_init(struct imx214 *imx214) return ret; } + ret = imx214_pll_update(imx214); + if (ret < 0) { + v4l2_ctrl_handler_free(ctrl_hdlr); + dev_err(imx214->dev, "failed to update PLL\n"); + return ret; + } + imx214->sd.ctrl_handler = ctrl_hdlr; return 0; @@ -1029,8 +1139,8 @@ static int imx214_start_streaming(struct imx214 *imx214) return ret; } - bit_rate_mbps = (imx214->pll.pixel_rate_csi / 1000000) - * imx214->pll.bits_per_pixel; + bit_rate_mbps = imx214->pll.pixel_rate_csi / 1000000 + * imx214->pll.bits_per_pixel; ret = cci_write(imx214->regmap, IMX214_REG_REQ_LINK_BIT_RATE, IMX214_LINK_BIT_RATE_MBPS(bit_rate_mbps), NULL); if (ret) { @@ -1115,109 +1225,6 @@ err_rpm_put: return ret; } -static int imx214_pll_calculate(struct imx214 *imx214, struct ccs_pll *pll, - unsigned int link_freq) -{ - struct ccs_pll_limits limits = { - .min_ext_clk_freq_hz = 6000000, - .max_ext_clk_freq_hz = 27000000, - - .vt_fr = { - .min_pre_pll_clk_div = 1, - .max_pre_pll_clk_div = 15, - /* Value is educated guess as we don't have a spec */ - .min_pll_ip_clk_freq_hz = 6000000, - /* Value is educated guess as we don't have a spec */ - .max_pll_ip_clk_freq_hz = 12000000, - .min_pll_multiplier = 12, - .max_pll_multiplier = 1200, - .min_pll_op_clk_freq_hz = 338000000, - .max_pll_op_clk_freq_hz = 1200000000, - }, - .vt_bk = { - .min_sys_clk_div = 2, - .max_sys_clk_div = 4, - .min_pix_clk_div = 5, - .max_pix_clk_div = 10, - .min_pix_clk_freq_hz = 30000000, - .max_pix_clk_freq_hz = 120000000, - }, - .op_bk = { - .min_sys_clk_div = 1, - .max_sys_clk_div = 2, - .min_pix_clk_div = 6, - .max_pix_clk_div = 10, - .min_pix_clk_freq_hz = 30000000, - .max_pix_clk_freq_hz = 120000000, - }, - - .min_line_length_pck_bin = IMX214_PPL_DEFAULT, - .min_line_length_pck = IMX214_PPL_DEFAULT, - }; - unsigned int num_lanes = imx214->bus_cfg.bus.mipi_csi2.num_data_lanes; - - /* - * There are no documented constraints on the sys clock frequency, for - * either branch. Recover them based on the PLL output clock frequency - * and sys_clk_div limits on one hand, and the pix clock frequency and - * the pix_clk_div limits on the other hand. - */ - limits.vt_bk.min_sys_clk_freq_hz = - max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.vt_bk.max_sys_clk_div, - limits.vt_bk.min_pix_clk_freq_hz * limits.vt_bk.min_pix_clk_div); - limits.vt_bk.max_sys_clk_freq_hz = - min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.vt_bk.min_sys_clk_div, - limits.vt_bk.max_pix_clk_freq_hz * limits.vt_bk.max_pix_clk_div); - - limits.op_bk.min_sys_clk_freq_hz = - max(limits.vt_fr.min_pll_op_clk_freq_hz / limits.op_bk.max_sys_clk_div, - limits.op_bk.min_pix_clk_freq_hz * limits.op_bk.min_pix_clk_div); - limits.op_bk.max_sys_clk_freq_hz = - min(limits.vt_fr.max_pll_op_clk_freq_hz / limits.op_bk.min_sys_clk_div, - limits.op_bk.max_pix_clk_freq_hz * limits.op_bk.max_pix_clk_div); - - memset(pll, 0, sizeof(*pll)); - - pll->bus_type = CCS_PLL_BUS_TYPE_CSI2_DPHY; - pll->op_lanes = num_lanes; - pll->vt_lanes = num_lanes; - pll->csi2.lanes = num_lanes; - - pll->binning_horizontal = 1; - pll->binning_vertical = 1; - pll->scale_m = 1; - pll->scale_n = 1; - pll->bits_per_pixel = - IMX214_CSI_DATA_FORMAT_RAW10 & IMX214_BITS_PER_PIXEL_MASK; - pll->flags = CCS_PLL_FLAG_LANE_SPEED_MODEL; - pll->link_freq = link_freq; - pll->ext_clk_freq_hz = clk_get_rate(imx214->xclk); - - return ccs_pll_calculate(imx214->dev, &limits, pll); -} - -static int imx214_pll_update(struct imx214 *imx214) -{ - u64 link_freq; - int ret; - - link_freq = imx214->bus_cfg.link_frequencies[imx214->link_freq->val]; - ret = imx214_pll_calculate(imx214, &imx214->pll, link_freq); - if (ret) { - dev_err(imx214->dev, "PLL calculations failed: %d\n", ret); - return ret; - } - - ret = v4l2_ctrl_s_ctrl_int64(imx214->pixel_rate, - imx214->pll.pixel_rate_pixel_array); - if (ret) { - dev_err(imx214->dev, "failed to set pixel rate\n"); - return ret; - } - - return 0; -} - static int imx214_get_frame_interval(struct v4l2_subdev *subdev, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_frame_interval *fival) @@ -1324,10 +1331,11 @@ static int imx214_identify_module(struct imx214 *imx214) return 0; } -static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) +static int imx214_parse_fwnode(struct imx214 *imx214) { + struct fwnode_handle *endpoint __free(fwnode_handle) = NULL; struct v4l2_fwnode_endpoint *bus_cfg = &imx214->bus_cfg; - struct fwnode_handle *endpoint; + struct device *dev = imx214->dev; unsigned int i; int ret; @@ -1337,11 +1345,8 @@ static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) bus_cfg->bus_type = V4L2_MBUS_CSI2_DPHY; ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, bus_cfg); - fwnode_handle_put(endpoint); - if (ret) { - dev_err_probe(dev, ret, "parsing endpoint node failed\n"); - goto error; - } + if (ret) + return dev_err_probe(dev, ret, "parsing endpoint node failed\n"); /* Check the number of MIPI CSI2 data lanes */ if (bus_cfg->bus.mipi_csi2.num_data_lanes != 4) { @@ -1357,18 +1362,16 @@ static int imx214_parse_fwnode(struct device *dev, struct imx214 *imx214) u64 freq = bus_cfg->link_frequencies[i]; struct ccs_pll pll; - if (!imx214_pll_calculate(imx214, &pll, freq)) - break; if (freq == IMX214_DEFAULT_LINK_FREQ_LEGACY) { dev_warn(dev, "link-frequencies %d not supported, please review your DT. Continuing anyway\n", IMX214_DEFAULT_LINK_FREQ); freq = IMX214_DEFAULT_LINK_FREQ; - if (imx214_pll_calculate(imx214, &pll, freq)) - continue; bus_cfg->link_frequencies[i] = freq; - break; } + + if (!imx214_pll_calculate(imx214, &pll, freq)) + break; } if (i == bus_cfg->nr_of_link_frequencies) @@ -1396,7 +1399,7 @@ static int imx214_probe(struct i2c_client *client) imx214->dev = dev; - imx214->xclk = devm_clk_get(dev, NULL); + imx214->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(imx214->xclk)) return dev_err_probe(dev, PTR_ERR(imx214->xclk), "failed to get xclk\n"); @@ -1415,7 +1418,7 @@ static int imx214_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(imx214->regmap), "failed to initialize CCI\n"); - ret = imx214_parse_fwnode(dev, imx214); + ret = imx214_parse_fwnode(imx214); if (ret) return ret; @@ -1459,12 +1462,6 @@ static int imx214_probe(struct i2c_client *client) pm_runtime_set_active(imx214->dev); pm_runtime_enable(imx214->dev); - ret = imx214_pll_update(imx214); - if (ret < 0) { - dev_err_probe(dev, ret, "failed to update PLL\n"); - goto error_subdev_cleanup; - } - ret = v4l2_async_register_subdev_sensor(&imx214->sd); if (ret < 0) { dev_err_probe(dev, ret, diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index 3b4f68543342..c680aa6c3a55 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -771,7 +771,6 @@ static int imx219_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } @@ -793,7 +792,6 @@ static int imx219_disable_streams(struct v4l2_subdev *sd, __v4l2_ctrl_grab(imx219->vflip, false); __v4l2_ctrl_grab(imx219->hflip, false); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; @@ -1034,6 +1032,10 @@ static int imx219_power_on(struct device *dev) goto reg_off; } + /* + * Note: Misinterpretation of reset assertion - do not re-use this code. + * XCLR pin is using incorrect (for reset signal) logical level. + */ gpiod_set_value_cansleep(imx219->reset_gpio, 1); usleep_range(IMX219_XCLR_MIN_DELAY_US, IMX219_XCLR_MIN_DELAY_US + IMX219_XCLR_DELAY_RANGE_US); @@ -1188,7 +1190,7 @@ static int imx219_probe(struct i2c_client *client) "failed to initialize CCI\n"); /* Get system clock (xclk) */ - imx219->xclk = devm_clk_get(dev, NULL); + imx219->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(imx219->xclk)) return dev_err_probe(dev, PTR_ERR(imx219->xclk), "failed to get xclk\n"); diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c index 9e30fce1f223..e50dcfd830f5 100644 --- a/drivers/media/i2c/imx258.c +++ b/drivers/media/i2c/imx258.c @@ -8,11 +8,12 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> -#include <linux/unaligned.h> #define IMX258_REG_MODE_SELECT CCI_REG8(0x0100) #define IMX258_MODE_STANDBY 0x00 @@ -645,6 +646,8 @@ static const struct imx258_mode supported_modes[] = { }; struct imx258 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct regmap *regmap; @@ -751,7 +754,6 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx258 *imx258 = container_of(ctrl->handler, struct imx258, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); int ret = 0; /* @@ -765,7 +767,7 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (pm_runtime_get_if_in_use(&client->dev) == 0) + if (pm_runtime_get_if_in_use(imx258->dev) == 0) return 0; switch (ctrl->id) { @@ -811,14 +813,14 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) NULL); break; default: - dev_info(&client->dev, + dev_info(imx258->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); ret = -EINVAL; break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx258->dev); return ret; } @@ -1013,14 +1015,13 @@ static int imx258_get_selection(struct v4l2_subdev *sd, /* Start streaming */ static int imx258_start_streaming(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); const struct imx258_reg_list *reg_list; const struct imx258_link_freq_config *link_freq_cfg; int ret, link_freq_index; ret = cci_write(imx258->regmap, IMX258_REG_RESET, 0x01, NULL); if (ret) { - dev_err(&client->dev, "%s failed to reset sensor\n", __func__); + dev_err(imx258->dev, "%s failed to reset sensor\n", __func__); return ret; } @@ -1034,21 +1035,21 @@ static int imx258_start_streaming(struct imx258 *imx258) reg_list = &link_freq_cfg->link_cfg[imx258->lane_mode_idx].reg_list; ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(imx258->dev, "%s failed to set plls\n", __func__); return ret; } ret = cci_multi_reg_write(imx258->regmap, mode_common_regs, ARRAY_SIZE(mode_common_regs), NULL); if (ret) { - dev_err(&client->dev, "%s failed to set common regs\n", __func__); + dev_err(imx258->dev, "%s failed to set common regs\n", __func__); return ret; } ret = cci_multi_reg_write(imx258->regmap, imx258->variant_cfg->regs, imx258->variant_cfg->num_regs, NULL); if (ret) { - dev_err(&client->dev, "%s failed to set variant config\n", + dev_err(imx258->dev, "%s failed to set variant config\n", __func__); return ret; } @@ -1057,7 +1058,7 @@ static int imx258_start_streaming(struct imx258 *imx258) !!(imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK), NULL); if (ret) { - dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__); + dev_err(imx258->dev, "%s failed to set clock lane mode\n", __func__); return ret; } @@ -1065,7 +1066,7 @@ static int imx258_start_streaming(struct imx258 *imx258) reg_list = &imx258->cur_mode->reg_list; ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(imx258->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1082,14 +1083,13 @@ static int imx258_start_streaming(struct imx258 *imx258) /* Stop streaming */ static int imx258_stop_streaming(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); int ret; /* set stream off register */ ret = cci_write(imx258->regmap, IMX258_REG_MODE_SELECT, IMX258_MODE_STANDBY, NULL); if (ret) - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(imx258->dev, "%s failed to set stream\n", __func__); /* * Return success even if it was an error, as there is nothing the @@ -1135,13 +1135,12 @@ static int imx258_power_off(struct device *dev) static int imx258_set_stream(struct v4l2_subdev *sd, int enable) { struct imx258 *imx258 = to_imx258(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx258->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx258->dev); if (ret < 0) goto err_unlock; @@ -1154,7 +1153,7 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx258_stop_streaming(imx258); - pm_runtime_put(&client->dev); + pm_runtime_put(imx258->dev); } mutex_unlock(&imx258->mutex); @@ -1162,7 +1161,7 @@ static int imx258_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx258->dev); err_unlock: mutex_unlock(&imx258->mutex); @@ -1172,20 +1171,19 @@ err_unlock: /* Verify chip ID */ static int imx258_identify_module(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); int ret; u64 val; ret = cci_read(imx258->regmap, IMX258_REG_CHIP_ID, &val, NULL); if (ret) { - dev_err(&client->dev, "failed to read chip id %x\n", + dev_err(imx258->dev, "failed to read chip id %x\n", IMX258_CHIP_ID); return ret; } if (val != IMX258_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", + dev_err(imx258->dev, "chip id mismatch: %x!=%llx\n", IMX258_CHIP_ID, val); return -EIO; } @@ -1217,7 +1215,6 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = { /* Initialize control handlers */ static int imx258_init_controls(struct imx258 *imx258) { - struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); const struct imx258_link_freq_config *link_freq_cfgs; struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; @@ -1308,12 +1305,12 @@ static int imx258_init_controls(struct imx258 *imx258) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(imx258->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(imx258->dev, &props); if (ret) goto error; @@ -1339,15 +1336,14 @@ static void imx258_free_controls(struct imx258 *imx258) mutex_destroy(&imx258->mutex); } -static int imx258_get_regulators(struct imx258 *imx258, - struct i2c_client *client) +static int imx258_get_regulators(struct imx258 *imx258) { unsigned int i; for (i = 0; i < IMX258_NUM_SUPPLIES; i++) imx258->supplies[i].supply = imx258_supply_name[i]; - return devm_regulator_bulk_get(&client->dev, + return devm_regulator_bulk_get(imx258->dev, IMX258_NUM_SUPPLIES, imx258->supplies); } @@ -1365,30 +1361,27 @@ static int imx258_probe(struct i2c_client *client) if (!imx258) return -ENOMEM; + imx258->dev = &client->dev; + imx258->regmap = devm_cci_regmap_init_i2c(client, 16); if (IS_ERR(imx258->regmap)) { ret = PTR_ERR(imx258->regmap); - dev_err(&client->dev, "failed to initialize CCI: %d\n", ret); + dev_err(imx258->dev, "failed to initialize CCI: %d\n", ret); return ret; } - ret = imx258_get_regulators(imx258, client); + ret = imx258_get_regulators(imx258); if (ret) - return dev_err_probe(&client->dev, ret, + return dev_err_probe(imx258->dev, ret, "failed to get regulators\n"); - imx258->clk = devm_clk_get_optional(&client->dev, NULL); + imx258->clk = devm_v4l2_sensor_clk_get_legacy(imx258->dev, NULL, false, + 0); if (IS_ERR(imx258->clk)) - return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), + return dev_err_probe(imx258->dev, PTR_ERR(imx258->clk), "error getting clock\n"); - if (!imx258->clk) { - dev_dbg(&client->dev, - "no clock provided, using clock-frequency property\n"); - device_property_read_u32(&client->dev, "clock-frequency", &val); - } else { - val = clk_get_rate(imx258->clk); - } + val = clk_get_rate(imx258->clk); switch (val) { case 19200000: @@ -1400,32 +1393,32 @@ static int imx258_probe(struct i2c_client *client) imx258->link_freq_menu_items = link_freq_menu_items_24; break; default: - dev_err(&client->dev, "input clock frequency of %u not supported\n", + dev_err(imx258->dev, "input clock frequency of %u not supported\n", val); return -EINVAL; } - endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(imx258->dev), NULL); if (!endpoint) { - dev_err(&client->dev, "Endpoint node not found\n"); + dev_err(imx258->dev, "Endpoint node not found\n"); return -EINVAL; } ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); fwnode_handle_put(endpoint); if (ret) { - dev_err(&client->dev, "Parsing endpoint node failed\n"); + dev_err(imx258->dev, "Parsing endpoint node failed\n"); return ret; } - ret = v4l2_link_freq_to_bitmap(&client->dev, + ret = v4l2_link_freq_to_bitmap(imx258->dev, ep.link_frequencies, ep.nr_of_link_frequencies, imx258->link_freq_menu_items, ARRAY_SIZE(link_freq_menu_items_19_2), &imx258->link_freq_bitmap); if (ret) { - dev_err(&client->dev, "Link frequency not supported\n"); + dev_err(imx258->dev, "Link frequency not supported\n"); goto error_endpoint_free; } @@ -1438,7 +1431,7 @@ static int imx258_probe(struct i2c_client *client) imx258->lane_mode_idx = IMX258_4_LANE_MODE; break; default: - dev_err(&client->dev, "Invalid data lanes: %u\n", + dev_err(imx258->dev, "Invalid data lanes: %u\n", ep.bus.mipi_csi2.num_data_lanes); ret = -EINVAL; goto error_endpoint_free; @@ -1446,7 +1439,7 @@ static int imx258_probe(struct i2c_client *client) imx258->csi2_flags = ep.bus.mipi_csi2.flags; - imx258->variant_cfg = device_get_match_data(&client->dev); + imx258->variant_cfg = device_get_match_data(imx258->dev); if (!imx258->variant_cfg) imx258->variant_cfg = &imx258_cfg; @@ -1454,7 +1447,7 @@ static int imx258_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); /* Will be powered off via pm_runtime_idle */ - ret = imx258_power_on(&client->dev); + ret = imx258_power_on(imx258->dev); if (ret) goto error_endpoint_free; @@ -1486,9 +1479,9 @@ static int imx258_probe(struct i2c_client *client) if (ret < 0) goto error_media_entity; - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(imx258->dev); + pm_runtime_enable(imx258->dev); + pm_runtime_idle(imx258->dev); v4l2_fwnode_endpoint_free(&ep); return 0; @@ -1500,7 +1493,7 @@ error_handler_free: imx258_free_controls(imx258); error_identify: - imx258_power_off(&client->dev); + imx258_power_off(imx258->dev); error_endpoint_free: v4l2_fwnode_endpoint_free(&ep); @@ -1517,10 +1510,10 @@ static void imx258_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); imx258_free_controls(imx258); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - imx258_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx258->dev); + if (!pm_runtime_status_suspended(imx258->dev)) + imx258_power_off(imx258->dev); + pm_runtime_set_suspended(imx258->dev); } static const struct dev_pm_ops imx258_pm_ops = { diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c index a2b824986027..d86d08c29174 100644 --- a/drivers/media/i2c/imx274.c +++ b/drivers/media/i2c/imx274.c @@ -826,6 +826,8 @@ static int imx274_start_stream(struct stimx274 *priv) * if rst = 0, keep it in reset; * if rst = 1, bring it out of reset. * + * Note: Misinterpretation of reset assertion - do not re-use this code. + * XCLR pin is using incorrect (for reset signal) logical level. */ static void imx274_reset(struct stimx274 *priv, int rst) { diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c index da618c8cbadc..8ab63ad8f385 100644 --- a/drivers/media/i2c/imx283.c +++ b/drivers/media/i2c/imx283.c @@ -1143,7 +1143,6 @@ static int imx283_enable_streams(struct v4l2_subdev *sd, return 0; err_rpm_put: - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return ret; @@ -1163,7 +1162,6 @@ static int imx283_disable_streams(struct v4l2_subdev *sd, if (ret) dev_err(imx283->dev, "Failed to stop stream\n"); - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return ret; @@ -1462,11 +1460,10 @@ static int imx283_probe(struct i2c_client *client) } /* Get system clock (xclk) */ - imx283->xclk = devm_clk_get(imx283->dev, NULL); - if (IS_ERR(imx283->xclk)) { + imx283->xclk = devm_v4l2_sensor_clk_get(imx283->dev, NULL); + if (IS_ERR(imx283->xclk)) return dev_err_probe(imx283->dev, PTR_ERR(imx283->xclk), "failed to get xclk\n"); - } xclk_freq = clk_get_rate(imx283->xclk); for (i = 0; i < ARRAY_SIZE(imx283_frequencies); i++) { @@ -1558,7 +1555,6 @@ static int imx283_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(imx283->dev); pm_runtime_put_autosuspend(imx283->dev); return 0; diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c index 4f3f386c5353..21cbc81cb2ed 100644 --- a/drivers/media/i2c/imx290.c +++ b/drivers/media/i2c/imx290.c @@ -869,7 +869,6 @@ static int imx290_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); return ret; @@ -1099,7 +1098,6 @@ static int imx290_set_stream(struct v4l2_subdev *sd, int enable) } } else { imx290_stop_streaming(imx290); - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); } @@ -1294,7 +1292,6 @@ static int imx290_subdev_init(struct imx290 *imx290) * will already be prevented even before the delay. */ v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops); - pm_runtime_mark_last_busy(imx290->dev); pm_runtime_put_autosuspend(imx290->dev); imx290->sd.internal_ops = &imx290_internal_ops; @@ -1425,14 +1422,14 @@ static int imx290_get_regulators(struct device *dev, struct imx290 *imx290) static int imx290_init_clk(struct imx290 *imx290) { u32 xclk_freq; - int ret; - ret = device_property_read_u32(imx290->dev, "clock-frequency", - &xclk_freq); - if (ret) { - dev_err(imx290->dev, "Could not get xclk frequency\n"); - return ret; - } + imx290->xclk = devm_v4l2_sensor_clk_get_legacy(imx290->dev, "xclk", + false, 0); + if (IS_ERR(imx290->xclk)) + return dev_err_probe(imx290->dev, PTR_ERR(imx290->xclk), + "Could not get xclk\n"); + + xclk_freq = clk_get_rate(imx290->xclk); /* external clock must be 37.125 MHz or 74.25MHz */ switch (xclk_freq) { @@ -1448,12 +1445,6 @@ static int imx290_init_clk(struct imx290 *imx290) return -EINVAL; } - ret = clk_set_rate(imx290->xclk, xclk_freq); - if (ret) { - dev_err(imx290->dev, "Could not set xclk frequency\n"); - return ret; - } - return 0; } @@ -1599,11 +1590,6 @@ static int imx290_probe(struct i2c_client *client) return ret; /* Acquire resources. */ - imx290->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(imx290->xclk)) - return dev_err_probe(dev, PTR_ERR(imx290->xclk), - "Could not get xclk\n"); - ret = imx290_get_regulators(dev, imx290); if (ret < 0) return dev_err_probe(dev, ret, "Cannot get regulators\n"); @@ -1614,7 +1600,7 @@ static int imx290_probe(struct i2c_client *client) return dev_err_probe(dev, PTR_ERR(imx290->rst_gpio), "Cannot get reset gpio\n"); - /* Initialize external clock frequency. */ + /* Initialize external clock. */ ret = imx290_init_clk(imx290); if (ret) return ret; diff --git a/drivers/media/i2c/imx296.c b/drivers/media/i2c/imx296.c index f3bec16b527c..69636db11a2b 100644 --- a/drivers/media/i2c/imx296.c +++ b/drivers/media/i2c/imx296.c @@ -604,7 +604,6 @@ static int imx296_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { ret = imx296_stream_off(sensor); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); goto unlock; @@ -922,7 +921,7 @@ static int imx296_read_temperature(struct imx296 *sensor, int *temp) tmdout &= IMX296_TMDOUT_MASK; - /* T(°C) = 246.312 - 0.304 * TMDOUT */; + /* T(°C) = 246.312 - 0.304 * TMDOUT */ *temp = 246312 - 304 * tmdout; return imx296_write(sensor, IMX296_TMDCTRL, 0, NULL); @@ -1044,7 +1043,7 @@ static int imx296_probe(struct i2c_client *client) return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), "failed to get reset GPIO\n"); - sensor->clk = devm_clk_get(sensor->dev, "inck"); + sensor->clk = devm_v4l2_sensor_clk_get(sensor->dev, "inck"); if (IS_ERR(sensor->clk)) return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), "failed to get clock\n"); diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 701840f4a5cc..953310ef3046 100644 --- a/drivers/media/i2c/imx319.c +++ b/drivers/media/i2c/imx319.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Intel Corporation -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -106,11 +108,12 @@ struct imx319_mode { }; struct imx319_hwcfg { - u32 ext_clk; /* sensor external clk */ unsigned long link_freq_bitmap; }; struct imx319 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -1839,14 +1842,13 @@ static int imx319_write_reg(struct imx319 *imx319, u16 reg, u32 len, u32 val) static int imx319_write_regs(struct imx319 *imx319, const struct imx319_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); int ret; u32 i; for (i = 0; i < len; i++) { ret = imx319_write_reg(imx319, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(imx319->dev, "write reg 0x%4.4x return err %d", regs[i].address, ret); return ret; @@ -1880,7 +1882,6 @@ static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx319 *imx319 = container_of(ctrl->handler, struct imx319, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); s64 max; int ret; @@ -1899,7 +1900,7 @@ static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(imx319->dev)) return 0; switch (ctrl->id) { @@ -1933,12 +1934,12 @@ static int imx319_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", + dev_info(imx319->dev, "ctrl(id:0x%x,val:0x%x) is not handled", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx319->dev); return ret; } @@ -2087,7 +2088,6 @@ imx319_set_pad_format(struct v4l2_subdev *sd, /* Verify chip ID */ static int imx319_identify_module(struct imx319 *imx319) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); int ret; u32 val; @@ -2099,7 +2099,7 @@ static int imx319_identify_module(struct imx319 *imx319) return ret; if (val != IMX319_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(imx319->dev, "chip id mismatch: %x!=%x", IMX319_CHIP_ID, val); return -EIO; } @@ -2112,7 +2112,6 @@ static int imx319_identify_module(struct imx319 *imx319) /* Start streaming */ static int imx319_start_streaming(struct imx319 *imx319) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); const struct imx319_reg_list *reg_list; int ret; @@ -2124,7 +2123,7 @@ static int imx319_start_streaming(struct imx319 *imx319) reg_list = &imx319_global_setting; ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set global settings"); + dev_err(imx319->dev, "failed to set global settings"); return ret; } @@ -2132,7 +2131,7 @@ static int imx319_start_streaming(struct imx319 *imx319) reg_list = &imx319->cur_mode->reg_list; ret = imx319_write_regs(imx319, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(imx319->dev, "failed to set mode"); return ret; } @@ -2160,13 +2159,12 @@ static int imx319_stop_streaming(struct imx319 *imx319) static int imx319_set_stream(struct v4l2_subdev *sd, int enable) { struct imx319 *imx319 = to_imx319(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx319->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx319->dev); if (ret < 0) goto err_unlock; @@ -2179,7 +2177,7 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx319_stop_streaming(imx319); - pm_runtime_put(&client->dev); + pm_runtime_put(imx319->dev); } /* vflip and hflip cannot change during streaming */ @@ -2191,7 +2189,7 @@ static int imx319_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx319->dev); err_unlock: mutex_unlock(&imx319->mutex); @@ -2231,7 +2229,6 @@ static const struct v4l2_subdev_internal_ops imx319_internal_ops = { /* Initialize control handlers */ static int imx319_init_controls(struct imx319 *imx319) { - struct i2c_client *client = v4l2_get_subdevdata(&imx319->sd); struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; s64 vblank_def; @@ -2311,7 +2308,7 @@ static int imx319_init_controls(struct imx319 *imx319) 0, 0, imx319_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "control init failed: %d", ret); + dev_err(imx319->dev, "control init failed: %d", ret); goto error; } @@ -2350,20 +2347,6 @@ static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev) if (!cfg) goto out_err; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &cfg->ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - goto out_err; - } - - dev_dbg(dev, "ext clk: %d", cfg->ext_clk); - if (cfg->ext_clk != IMX319_EXT_CLK) { - dev_err(dev, "external clock %d is not supported", - cfg->ext_clk); - goto out_err; - } - ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, link_freq_menu_items, @@ -2385,6 +2368,8 @@ out_err: static int imx319_probe(struct i2c_client *client) { struct imx319 *imx319; + unsigned long freq; + struct clk *clk; bool full_power; int ret; @@ -2392,24 +2377,37 @@ static int imx319_probe(struct i2c_client *client) if (!imx319) return -ENOMEM; + imx319->dev = &client->dev; + mutex_init(&imx319->mutex); + clk = devm_v4l2_sensor_clk_get(imx319->dev, NULL); + if (IS_ERR(clk)) + return dev_err_probe(imx319->dev, PTR_ERR(clk), + "failed to acquire clock\n"); + + freq = clk_get_rate(clk); + if (freq != IMX319_EXT_CLK) + return dev_err_probe(imx319->dev, -EINVAL, + "external clock %lu is not supported", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx319->sd, client, &imx319_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(imx319->dev); if (full_power) { /* Check module identity */ ret = imx319_identify_module(imx319); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(imx319->dev, "failed to find sensor: %d", ret); goto error_probe; } } - imx319->hwcfg = imx319_get_hwcfg(&client->dev); + imx319->hwcfg = imx319_get_hwcfg(imx319->dev); if (!imx319->hwcfg) { - dev_err(&client->dev, "failed to get hwcfg"); + dev_err(imx319->dev, "failed to get hwcfg"); ret = -ENODEV; goto error_probe; } @@ -2419,7 +2417,7 @@ static int imx319_probe(struct i2c_client *client) ret = imx319_init_controls(imx319); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(imx319->dev, "failed to init controls: %d", ret); goto error_probe; } @@ -2434,27 +2432,27 @@ static int imx319_probe(struct i2c_client *client) imx319->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx319->sd.entity, 1, &imx319->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(imx319->dev, "failed to init entity pads: %d", ret); goto error_handler_free; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(imx319->dev); + pm_runtime_enable(imx319->dev); ret = v4l2_async_register_subdev_sensor(&imx319->sd); if (ret < 0) goto error_media_entity_pm; - pm_runtime_idle(&client->dev); + pm_runtime_idle(imx319->dev); return 0; error_media_entity_pm: - pm_runtime_disable(&client->dev); + pm_runtime_disable(imx319->dev); if (full_power) - pm_runtime_set_suspended(&client->dev); + pm_runtime_set_suspended(imx319->dev); media_entity_cleanup(&imx319->sd.entity); error_handler_free: @@ -2475,9 +2473,9 @@ static void imx319_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx319->dev); + if (!pm_runtime_status_suspended(imx319->dev)) + pm_runtime_set_suspended(imx319->dev); mutex_destroy(&imx319->mutex); } diff --git a/drivers/media/i2c/imx334.c b/drivers/media/i2c/imx334.c index 846b9928d4e8..9654f9268056 100644 --- a/drivers/media/i2c/imx334.c +++ b/drivers/media/i2c/imx334.c @@ -118,6 +118,9 @@ #define IMX334_REG_TP CCI_REG8(0x329e) #define IMX334_TP_COLOR_HBARS 0xa #define IMX334_TP_COLOR_VBARS 0xb +#define IMX334_TP_BLACK 0x0 +#define IMX334_TP_WHITE 0x1 +#define IMX334_TP_BLACK_GREY 0xc #define IMX334_TPG_EN_DOUT CCI_REG8(0x329c) #define IMX334_TP_ENABLE 0x1 @@ -398,12 +401,18 @@ static const char * const imx334_test_pattern_menu[] = { "Disabled", "Vertical Color Bars", "Horizontal Color Bars", + "Black and Grey Bars", + "Black Color", + "White Color", }; static const int imx334_test_pattern_val[] = { IMX334_TP_DISABLE, IMX334_TP_COLOR_HBARS, IMX334_TP_COLOR_VBARS, + IMX334_TP_BLACK_GREY, + IMX334_TP_BLACK, + IMX334_TP_WHITE, }; static const struct cci_reg_sequence raw10_framefmt_regs[] = { @@ -997,7 +1006,7 @@ static int imx334_parse_hw_config(struct imx334 *imx334) "failed to get reset gpio\n"); /* Get sensor input clock */ - imx334->inclk = devm_clk_get(imx334->dev, NULL); + imx334->inclk = devm_v4l2_sensor_clk_get(imx334->dev, NULL); if (IS_ERR(imx334->inclk)) return dev_err_probe(imx334->dev, PTR_ERR(imx334->inclk), "could not get inclk\n"); @@ -1070,6 +1079,10 @@ static int imx334_power_on(struct device *dev) struct imx334 *imx334 = to_imx334(sd); int ret; + /* + * Note: Misinterpretation of reset assertion - do not re-use this code. + * XCLR pin is using incorrect (for reset signal) logical level. + */ gpiod_set_value_cansleep(imx334->reset_gpio, 1); ret = clk_prepare_enable(imx334->inclk); diff --git a/drivers/media/i2c/imx335.c b/drivers/media/i2c/imx335.c index 9b4db4cd4929..c043df2f15fb 100644 --- a/drivers/media/i2c/imx335.c +++ b/drivers/media/i2c/imx335.c @@ -1026,11 +1026,10 @@ static int imx335_parse_hw_config(struct imx335 *imx335) } /* Get sensor input clock */ - imx335->inclk = devm_clk_get(imx335->dev, NULL); - if (IS_ERR(imx335->inclk)) { - dev_err(imx335->dev, "could not get inclk\n"); - return PTR_ERR(imx335->inclk); - } + imx335->inclk = devm_v4l2_sensor_clk_get(imx335->dev, NULL); + if (IS_ERR(imx335->inclk)) + return dev_err_probe(imx335->dev, PTR_ERR(imx335->inclk), + "could not get inclk\n"); rate = clk_get_rate(imx335->inclk); if (rate != IMX335_INCLK_RATE) { diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index b2dce67c0b6b..776107efe386 100644 --- a/drivers/media/i2c/imx355.c +++ b/drivers/media/i2c/imx355.c @@ -1,11 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Intel Corporation -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -92,11 +94,13 @@ struct imx355_mode { }; struct imx355_hwcfg { - u32 ext_clk; /* sensor external clk */ unsigned long link_freq_bitmap; }; struct imx355 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -1136,14 +1140,13 @@ static int imx355_write_reg(struct imx355 *imx355, u16 reg, u32 len, u32 val) static int imx355_write_regs(struct imx355 *imx355, const struct imx355_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); int ret; u32 i; for (i = 0; i < len; i++) { ret = imx355_write_reg(imx355, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(imx355->dev, "write reg 0x%4.4x return err %d", regs[i].address, ret); @@ -1178,7 +1181,6 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) { struct imx355 *imx355 = container_of(ctrl->handler, struct imx355, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); s64 max; int ret; @@ -1197,7 +1199,7 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(imx355->dev)) return 0; switch (ctrl->id) { @@ -1231,12 +1233,12 @@ static int imx355_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_info(&client->dev, "ctrl(id:0x%x,val:0x%x) is not handled", + dev_info(imx355->dev, "ctrl(id:0x%x,val:0x%x) is not handled", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(imx355->dev); return ret; } @@ -1385,7 +1387,6 @@ imx355_set_pad_format(struct v4l2_subdev *sd, /* Start streaming */ static int imx355_start_streaming(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); const struct imx355_reg_list *reg_list; int ret; @@ -1393,7 +1394,7 @@ static int imx355_start_streaming(struct imx355 *imx355) reg_list = &imx355_global_setting; ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set global settings"); + dev_err(imx355->dev, "failed to set global settings"); return ret; } @@ -1401,7 +1402,7 @@ static int imx355_start_streaming(struct imx355 *imx355) reg_list = &imx355->cur_mode->reg_list; ret = imx355_write_regs(imx355, reg_list->regs, reg_list->num_of_regs); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(imx355->dev, "failed to set mode"); return ret; } @@ -1429,13 +1430,12 @@ static int imx355_stop_streaming(struct imx355 *imx355) static int imx355_set_stream(struct v4l2_subdev *sd, int enable) { struct imx355 *imx355 = to_imx355(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&imx355->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx355->dev); if (ret < 0) goto err_unlock; @@ -1448,7 +1448,7 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { imx355_stop_streaming(imx355); - pm_runtime_put(&client->dev); + pm_runtime_put(imx355->dev); } /* vflip and hflip cannot change during streaming */ @@ -1460,7 +1460,7 @@ static int imx355_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(imx355->dev); err_unlock: mutex_unlock(&imx355->mutex); @@ -1470,7 +1470,6 @@ err_unlock: /* Verify chip ID */ static int imx355_identify_module(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); int ret; u32 val; @@ -1479,7 +1478,7 @@ static int imx355_identify_module(struct imx355 *imx355) return ret; if (val != IMX355_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(imx355->dev, "chip id mismatch: %x!=%x", IMX355_CHIP_ID, val); return -EIO; } @@ -1519,7 +1518,6 @@ static const struct v4l2_subdev_internal_ops imx355_internal_ops = { /* Initialize control handlers */ static int imx355_init_controls(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -1600,11 +1598,11 @@ static int imx355_init_controls(struct imx355 *imx355) 0, 0, imx355_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "control init failed: %d", ret); + dev_err(imx355->dev, "control init failed: %d", ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(imx355->dev, &props); if (ret) goto error; @@ -1648,20 +1646,6 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) if (!cfg) goto out_err; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &cfg->ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - goto out_err; - } - - dev_dbg(dev, "ext clk: %d", cfg->ext_clk); - if (cfg->ext_clk != IMX355_EXT_CLK) { - dev_err(dev, "external clock %d is not supported", - cfg->ext_clk); - goto out_err; - } - ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, bus_cfg.nr_of_link_frequencies, link_freq_menu_items, @@ -1683,27 +1667,41 @@ out_err: static int imx355_probe(struct i2c_client *client) { struct imx355 *imx355; + unsigned long freq; int ret; imx355 = devm_kzalloc(&client->dev, sizeof(*imx355), GFP_KERNEL); if (!imx355) return -ENOMEM; + imx355->dev = &client->dev; + mutex_init(&imx355->mutex); + imx355->clk = devm_v4l2_sensor_clk_get(imx355->dev, NULL); + if (IS_ERR(imx355->clk)) + return dev_err_probe(imx355->dev, PTR_ERR(imx355->clk), + "failed to get clock\n"); + + freq = clk_get_rate(imx355->clk); + if (freq != IMX355_EXT_CLK) + return dev_err_probe(imx355->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&imx355->sd, client, &imx355_subdev_ops); /* Check module identity */ ret = imx355_identify_module(imx355); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(imx355->dev, "failed to find sensor: %d", ret); goto error_probe; } - imx355->hwcfg = imx355_get_hwcfg(&client->dev); + imx355->hwcfg = imx355_get_hwcfg(imx355->dev); if (!imx355->hwcfg) { - dev_err(&client->dev, "failed to get hwcfg"); + dev_err(imx355->dev, "failed to get hwcfg"); ret = -ENODEV; goto error_probe; } @@ -1713,7 +1711,7 @@ static int imx355_probe(struct i2c_client *client) ret = imx355_init_controls(imx355); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(imx355->dev, "failed to init controls: %d", ret); goto error_probe; } @@ -1728,7 +1726,7 @@ static int imx355_probe(struct i2c_client *client) imx355->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&imx355->sd.entity, 1, &imx355->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(imx355->dev, "failed to init entity pads: %d", ret); goto error_handler_free; } @@ -1736,9 +1734,9 @@ static int imx355_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(imx355->dev); + pm_runtime_enable(imx355->dev); + pm_runtime_idle(imx355->dev); ret = v4l2_async_register_subdev_sensor(&imx355->sd); if (ret < 0) @@ -1747,8 +1745,8 @@ static int imx355_probe(struct i2c_client *client) return 0; error_media_entity_runtime_pm: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx355->dev); + pm_runtime_set_suspended(imx355->dev); media_entity_cleanup(&imx355->sd.entity); error_handler_free: @@ -1769,8 +1767,8 @@ static void imx355_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(imx355->dev); + pm_runtime_set_suspended(imx355->dev); mutex_destroy(&imx355->mutex); } diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c index c74097a59c42..7bbd639a9ddf 100644 --- a/drivers/media/i2c/imx412.c +++ b/drivers/media/i2c/imx412.c @@ -933,11 +933,10 @@ static int imx412_parse_hw_config(struct imx412 *imx412) } /* Get sensor input clock */ - imx412->inclk = devm_clk_get(imx412->dev, NULL); - if (IS_ERR(imx412->inclk)) { - dev_err(imx412->dev, "could not get inclk\n"); - return PTR_ERR(imx412->inclk); - } + imx412->inclk = devm_v4l2_sensor_clk_get(imx412->dev, NULL); + if (IS_ERR(imx412->inclk)) + return dev_err_probe(imx412->dev, PTR_ERR(imx412->inclk), + "could not get inclk\n"); rate = clk_get_rate(imx412->inclk); if (rate != IMX412_INCLK_RATE) { diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c index 278e743646ea..0b424c17e880 100644 --- a/drivers/media/i2c/imx415.c +++ b/drivers/media/i2c/imx415.c @@ -952,7 +952,6 @@ static int imx415_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { ret = imx415_stream_off(sensor); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); goto unlock; @@ -1251,7 +1250,7 @@ static int imx415_parse_hw_config(struct imx415 *sensor) return dev_err_probe(sensor->dev, PTR_ERR(sensor->reset), "failed to get reset GPIO\n"); - sensor->clk = devm_clk_get(sensor->dev, NULL); + sensor->clk = devm_v4l2_sensor_clk_get(sensor->dev, NULL); if (IS_ERR(sensor->clk)) return dev_err_probe(sensor->dev, PTR_ERR(sensor->clk), "failed to get clock\n"); diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c index c84e1e0e6109..5588cdd7ec20 100644 --- a/drivers/media/i2c/ir-kbd-i2c.c +++ b/drivers/media/i2c/ir-kbd-i2c.c @@ -321,9 +321,9 @@ static int get_key_avermedia_cardbus(struct IR_i2c *ir, enum rc_proto *protocol, static int ir_key_poll(struct IR_i2c *ir) { - enum rc_proto protocol; - u32 scancode; - u8 toggle; + enum rc_proto protocol = 0; + u32 scancode = 0; + u8 toggle = 0; int rc; dev_dbg(&ir->rc->dev, "%s\n", __func__); diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c index 12d3e86bdc0f..7a6114d18dfc 100644 --- a/drivers/media/i2c/mt9m001.c +++ b/drivers/media/i2c/mt9m001.c @@ -743,9 +743,10 @@ static int mt9m001_probe(struct i2c_client *client) if (!mt9m001) return -ENOMEM; - mt9m001->clk = devm_clk_get(&client->dev, NULL); + mt9m001->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9m001->clk)) - return PTR_ERR(mt9m001->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9m001->clk), + "failed to get the clock\n"); mt9m001->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_LOW); diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c index 9aa5dcda3805..05dcf37c6f01 100644 --- a/drivers/media/i2c/mt9m111.c +++ b/drivers/media/i2c/mt9m111.c @@ -1279,9 +1279,10 @@ static int mt9m111_probe(struct i2c_client *client) return ret; } - mt9m111->clk = devm_clk_get(&client->dev, "mclk"); + mt9m111->clk = devm_v4l2_sensor_clk_get(&client->dev, "mclk"); if (IS_ERR(mt9m111->clk)) - return PTR_ERR(mt9m111->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9m111->clk), + "failed to get mclk\n"); mt9m111->regulator = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(mt9m111->regulator)) { diff --git a/drivers/media/i2c/mt9m114.c b/drivers/media/i2c/mt9m114.c index 3f540ca40f3c..51ebbe7ae996 100644 --- a/drivers/media/i2c/mt9m114.c +++ b/drivers/media/i2c/mt9m114.c @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/mutex.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/types.h> @@ -42,6 +43,9 @@ #define MT9M114_RESET_AND_MISC_CONTROL CCI_REG16(0x001a) #define MT9M114_RESET_SOC BIT(0) #define MT9M114_PAD_SLEW CCI_REG16(0x001e) +#define MT9M114_PAD_SLEW_MIN 0 +#define MT9M114_PAD_SLEW_MAX 7 +#define MT9M114_PAD_SLEW_DEFAULT 7 #define MT9M114_PAD_CONTROL CCI_REG16(0x0032) /* XDMA registers */ @@ -388,6 +392,7 @@ struct mt9m114 { unsigned int pixrate; bool streaming; + u32 pad_slew_rate; /* Pixel Array */ struct { @@ -645,9 +650,6 @@ static const struct cci_reg_sequence mt9m114_init[] = { { MT9M114_CAM_SENSOR_CFG_FINE_INTEG_TIME_MAX, 1459 }, { MT9M114_CAM_SENSOR_CFG_FINE_CORRECTION, 96 }, { MT9M114_CAM_SENSOR_CFG_REG_0_DATA, 32 }, - - /* Miscellaneous settings */ - { MT9M114_PAD_SLEW, 0x0777 }, }; /* ----------------------------------------------------------------------------- @@ -779,6 +781,13 @@ static int mt9m114_initialize(struct mt9m114 *sensor) if (ret < 0) return ret; + value = sensor->pad_slew_rate + | sensor->pad_slew_rate << 4 + | sensor->pad_slew_rate << 8; + cci_write(sensor->regmap, MT9M114_PAD_SLEW, value, &ret); + if (ret < 0) + return ret; + ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); if (ret < 0) return ret; @@ -974,7 +983,6 @@ static int mt9m114_start_streaming(struct mt9m114 *sensor, return 0; error: - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -988,7 +996,6 @@ static int mt9m114_stop_streaming(struct mt9m114 *sensor) ret = mt9m114_set_state(sensor, MT9M114_SYS_STATE_ENTER_SUSPEND); - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1046,7 +1053,6 @@ static int mt9m114_pa_g_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1113,7 +1119,6 @@ static int mt9m114_pa_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -1287,6 +1292,7 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, struct mt9m114 *sensor = pa_to_mt9m114(sd); struct v4l2_mbus_framefmt *format; struct v4l2_rect *crop; + int ret = 0; if (sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; @@ -1302,25 +1308,41 @@ static int mt9m114_pa_set_selection(struct v4l2_subdev *sd, * binning, but binning is configured after setting the selection, so * we can't know tell here if it will be used. */ - crop->left = ALIGN(sel->r.left, 4); - crop->top = ALIGN(sel->r.top, 2); - crop->width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), - MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, - MT9M114_PIXEL_ARRAY_WIDTH - crop->left); - crop->height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), - MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, - MT9M114_PIXEL_ARRAY_HEIGHT - crop->top); - - sel->r = *crop; + sel->r.left = ALIGN(sel->r.left, 4); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = clamp_t(unsigned int, ALIGN(sel->r.width, 4), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_WIDTH, + MT9M114_PIXEL_ARRAY_WIDTH - sel->r.left); + sel->r.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2), + MT9M114_PIXEL_ARRAY_MIN_OUTPUT_HEIGHT, + MT9M114_PIXEL_ARRAY_HEIGHT - sel->r.top); + + /* Changing the selection size is not allowed in streaming state. */ + if (sensor->streaming && + (sel->r.height != crop->height || sel->r.width != crop->width)) + return -EBUSY; + + *crop = sel->r; /* Reset the format. */ format->width = crop->width; format->height = crop->height; - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) - mt9m114_pa_ctrl_update_blanking(sensor, format); + if (sel->which != V4L2_SUBDEV_FORMAT_ACTIVE) + return ret; - return 0; + mt9m114_pa_ctrl_update_blanking(sensor, format); + + /* Apply values immediately if streaming. */ + if (sensor->streaming) { + ret = mt9m114_configure_pa(sensor, state); + if (ret) + return ret; + /* Changing the cropping config requires a CONFIG_CHANGE. */ + ret = mt9m114_set_state(sensor, + MT9M114_SYS_STATE_ENTER_CONFIG_CHANGE); + } + return ret; } static const struct v4l2_subdev_pad_ops mt9m114_pa_pad_ops = { @@ -1565,7 +1587,6 @@ static int mt9m114_ifp_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->client->dev); pm_runtime_put_autosuspend(&sensor->client->dev); return ret; @@ -2365,6 +2386,17 @@ static int mt9m114_parse_dt(struct mt9m114 *sensor) goto error; } + sensor->pad_slew_rate = MT9M114_PAD_SLEW_DEFAULT; + device_property_read_u32(&sensor->client->dev, "slew-rate", + &sensor->pad_slew_rate); + + if (sensor->pad_slew_rate < MT9M114_PAD_SLEW_MIN || + sensor->pad_slew_rate > MT9M114_PAD_SLEW_MAX) { + dev_err(&sensor->client->dev, "Invalid slew-rate %u\n", + sensor->pad_slew_rate); + return -EINVAL; + } + return 0; error: @@ -2395,10 +2427,10 @@ static int mt9m114_probe(struct i2c_client *client) return ret; /* Acquire clocks, GPIOs and regulators. */ - sensor->clk = devm_clk_get(dev, NULL); + sensor->clk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->clk)) { - ret = PTR_ERR(sensor->clk); - dev_err_probe(dev, ret, "Failed to get clock\n"); + ret = dev_err_probe(dev, PTR_ERR(sensor->clk), + "Failed to get clock\n"); goto error_ep_free; } @@ -2472,7 +2504,6 @@ static int mt9m114_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c index 4ef5fb06131d..1500ee4db47e 100644 --- a/drivers/media/i2c/mt9p031.c +++ b/drivers/media/i2c/mt9p031.c @@ -233,9 +233,10 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031) unsigned long ext_freq; int ret; - mt9p031->clk = devm_clk_get(&client->dev, NULL); + mt9p031->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9p031->clk)) - return PTR_ERR(mt9p031->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9p031->clk), + "failed to get the clock\n"); ret = clk_set_rate(mt9p031->clk, mt9p031->ext_freq); if (ret < 0) @@ -1092,6 +1093,7 @@ static int mt9p031_parse_properties(struct mt9p031 *mt9p031, struct device *dev) static int mt9p031_probe(struct i2c_client *client) { struct i2c_adapter *adapter = client->adapter; + const struct mt9p031_model_info *info; struct mt9p031 *mt9p031; unsigned int i; int ret; @@ -1112,7 +1114,8 @@ static int mt9p031_probe(struct i2c_client *client) mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF; mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC; - mt9p031->code = (uintptr_t)device_get_match_data(&client->dev); + info = device_get_match_data(&client->dev); + mt9p031->code = info->code; mt9p031->regulators[0].supply = "vdd"; mt9p031->regulators[1].supply = "vdd_io"; diff --git a/drivers/media/i2c/mt9t112.c b/drivers/media/i2c/mt9t112.c index 878dff9b7577..2d2c840fc002 100644 --- a/drivers/media/i2c/mt9t112.c +++ b/drivers/media/i2c/mt9t112.c @@ -1078,13 +1078,12 @@ static int mt9t112_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&priv->subdev, client, &mt9t112_subdev_ops); - priv->clk = devm_clk_get(&client->dev, "extclk"); - if (PTR_ERR(priv->clk) == -ENOENT) { + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "extclk"); + if (PTR_ERR(priv->clk) == -ENOENT) priv->clk = NULL; - } else if (IS_ERR(priv->clk)) { - dev_err(&client->dev, "Unable to get clock \"extclk\"\n"); - return PTR_ERR(priv->clk); - } + else if (IS_ERR(priv->clk)) + return dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "Unable to get clock \"extclk\"\n"); priv->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", GPIOD_OUT_HIGH); diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c index 302120ff125e..d4359d5b92bb 100644 --- a/drivers/media/i2c/mt9v032.c +++ b/drivers/media/i2c/mt9v032.c @@ -15,16 +15,15 @@ #include <linux/i2c.h> #include <linux/log2.h> #include <linux/mod_devicetable.h> +#include <linux/module.h> #include <linux/mutex.h> #include <linux/of.h> #include <linux/of_graph.h> #include <linux/regmap.h> #include <linux/slab.h> -#include <linux/videodev2.h> #include <linux/v4l2-mediabus.h> -#include <linux/module.h> +#include <linux/videodev2.h> -#include <media/i2c/mt9v032.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -182,7 +181,16 @@ static const struct mt9v032_model_version mt9v032_versions[] = { { MT9V034_CHIP_ID_REV1, "MT9V024/MT9V034 rev1" }, }; +struct mt9v032_platform_data { + unsigned int clk_pol:1; + + const s64 *link_freqs; + s64 link_def_freq; +}; + struct mt9v032 { + struct device *dev; + struct v4l2_subdev subdev; struct media_pad pad; @@ -205,7 +213,7 @@ struct mt9v032 { struct gpio_desc *reset_gpio; struct gpio_desc *standby_gpio; - struct mt9v032_platform_data *pdata; + struct mt9v032_platform_data pdata; const struct mt9v032_model_info *model; const struct mt9v032_model_version *version; @@ -330,7 +338,7 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on) return ret; /* Configure the pixel clock polarity */ - if (mt9v032->pdata && mt9v032->pdata->clk_pol) { + if (mt9v032->pdata.clk_pol) { ret = regmap_write(map, mt9v032->model->data->pclk_reg, MT9V032_PIXEL_CLOCK_INV_PXL_CLK); if (ret < 0) @@ -473,13 +481,12 @@ static int mt9v032_get_format(struct v4l2_subdev *subdev, static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032) { - struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev); int ret; ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate, mt9v032->sysclk / mt9v032->hratio); if (ret < 0) - dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret); + dev_warn(mt9v032->dev, "failed to set pixel rate (%d)\n", ret); } static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output) @@ -682,7 +689,7 @@ static int mt9v032_s_ctrl(struct v4l2_ctrl *ctrl) if (mt9v032->link_freq == NULL) break; - freq = mt9v032->pdata->link_freqs[mt9v032->link_freq->val]; + freq = mt9v032->pdata.link_freqs[mt9v032->link_freq->val]; *mt9v032->pixel_rate->p_new.p_s64 = freq; mt9v032->sysclk = freq; break; @@ -883,12 +890,12 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) u32 version; int ret; - dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n", + dev_info(mt9v032->dev, "Probing MT9V032 at address 0x%02x\n", client->addr); ret = mt9v032_power_on(mt9v032); if (ret < 0) { - dev_err(&client->dev, "MT9V032 power up failed\n"); + dev_err(mt9v032->dev, "MT9V032 power up failed\n"); return ret; } @@ -898,7 +905,7 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) mt9v032_power_off(mt9v032); if (ret < 0) { - dev_err(&client->dev, "Failed reading chip version\n"); + dev_err(mt9v032->dev, "Failed reading chip version\n"); return ret; } @@ -910,12 +917,12 @@ static int mt9v032_registered(struct v4l2_subdev *subdev) } if (mt9v032->version == NULL) { - dev_err(&client->dev, "Unsupported chip version 0x%04x\n", + dev_err(mt9v032->dev, "Unsupported chip version 0x%04x\n", version); return -ENODEV; } - dev_info(&client->dev, "%s detected at address 0x%02x\n", + dev_info(mt9v032->dev, "%s detected at address 0x%02x\n", mt9v032->version->name, client->addr); mt9v032_configure_pixel_rate(mt9v032); @@ -995,41 +1002,33 @@ static const struct regmap_config mt9v032_regmap_config = { * Driver initialization and probing */ -static struct mt9v032_platform_data * -mt9v032_get_pdata(struct i2c_client *client) +static int mt9v032_get_pdata(struct mt9v032 *mt9v032) { - struct mt9v032_platform_data *pdata = NULL; + struct mt9v032_platform_data *pdata = &mt9v032->pdata; struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 }; - struct device_node *np; + struct device_node *np __free(device_node) = NULL; struct property *prop; - if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) - return client->dev.platform_data; - - np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1); + np = of_graph_get_endpoint_by_regs(mt9v032->dev->of_node, 0, -1); if (!np) - return NULL; + return -EINVAL; if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0) - goto done; - - pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - goto done; + return -EINVAL; prop = of_find_property(np, "link-frequencies", NULL); if (prop) { u64 *link_freqs; size_t size = prop->length / sizeof(*link_freqs); - link_freqs = devm_kcalloc(&client->dev, size, + link_freqs = devm_kcalloc(mt9v032->dev, size, sizeof(*link_freqs), GFP_KERNEL); if (!link_freqs) - goto done; + return -EINVAL; if (of_property_read_u64_array(np, "link-frequencies", link_freqs, size) < 0) - goto done; + return -EINVAL; pdata->link_freqs = link_freqs; pdata->link_def_freq = link_freqs[0]; @@ -1038,14 +1037,11 @@ mt9v032_get_pdata(struct i2c_client *client) pdata->clk_pol = !!(endpoint.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING); -done: - of_node_put(np); - return pdata; + return 0; } static int mt9v032_probe(struct i2c_client *client) { - struct mt9v032_platform_data *pdata = mt9v032_get_pdata(client); struct mt9v032 *mt9v032; unsigned int i; int ret; @@ -1054,27 +1050,35 @@ static int mt9v032_probe(struct i2c_client *client) if (!mt9v032) return -ENOMEM; + mt9v032->dev = &client->dev; + mt9v032->regmap = devm_regmap_init_i2c(client, &mt9v032_regmap_config); if (IS_ERR(mt9v032->regmap)) return PTR_ERR(mt9v032->regmap); - mt9v032->clk = devm_clk_get(&client->dev, NULL); + mt9v032->clk = devm_v4l2_sensor_clk_get(mt9v032->dev, NULL); if (IS_ERR(mt9v032->clk)) - return PTR_ERR(mt9v032->clk); + return dev_err_probe(mt9v032->dev, PTR_ERR(mt9v032->clk), + "failed to get the clock\n"); - mt9v032->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + mt9v032->reset_gpio = devm_gpiod_get_optional(mt9v032->dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(mt9v032->reset_gpio)) return PTR_ERR(mt9v032->reset_gpio); - mt9v032->standby_gpio = devm_gpiod_get_optional(&client->dev, "standby", + mt9v032->standby_gpio = devm_gpiod_get_optional(mt9v032->dev, "standby", GPIOD_OUT_LOW); if (IS_ERR(mt9v032->standby_gpio)) return PTR_ERR(mt9v032->standby_gpio); mutex_init(&mt9v032->power_lock); - mt9v032->pdata = pdata; - mt9v032->model = i2c_get_match_data(client); + + ret = mt9v032_get_pdata(mt9v032); + if (ret) + return dev_err_probe(mt9v032->dev, -EINVAL, + "Failed to parse DT properties\n"); + + mt9v032->model = device_get_match_data(mt9v032->dev); v4l2_ctrl_handler_init(&mt9v032->ctrls, 11 + ARRAY_SIZE(mt9v032_aegc_controls)); @@ -1119,7 +1123,8 @@ static int mt9v032_probe(struct i2c_client *client) v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops, V4L2_CID_PIXEL_RATE, 1, INT_MAX, 1, 1); - if (pdata && pdata->link_freqs) { + if (mt9v032->pdata.link_freqs) { + const struct mt9v032_platform_data *pdata = &mt9v032->pdata; unsigned int def = 0; for (i = 0; pdata->link_freqs[i]; ++i) { @@ -1139,7 +1144,7 @@ static int mt9v032_probe(struct i2c_client *client) mt9v032->subdev.ctrl_handler = &mt9v032->ctrls; if (mt9v032->ctrls.error) { - dev_err(&client->dev, "control initialization error %d\n", + dev_err(mt9v032->dev, "control initialization error %d\n", mt9v032->ctrls.error); ret = mt9v032->ctrls.error; goto err; @@ -1177,7 +1182,7 @@ static int mt9v032_probe(struct i2c_client *client) if (ret < 0) goto err; - mt9v032->subdev.dev = &client->dev; + mt9v032->subdev.dev = mt9v032->dev; ret = v4l2_async_register_subdev(&mt9v032->subdev); if (ret < 0) goto err; @@ -1261,19 +1266,6 @@ static const struct mt9v032_model_info mt9v032_models[] = { }, }; -static const struct i2c_device_id mt9v032_id[] = { - { "mt9v022", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_COLOR] }, - { "mt9v022m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V022_MONO] }, - { "mt9v024", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_COLOR] }, - { "mt9v024m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V024_MONO] }, - { "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] }, - { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] }, - { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] }, - { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] }, - { /* Sentinel */ } -}; -MODULE_DEVICE_TABLE(i2c, mt9v032_id); - static const struct of_device_id mt9v032_of_match[] = { { .compatible = "aptina,mt9v022", .data = &mt9v032_models[MT9V032_MODEL_V022_COLOR] }, { .compatible = "aptina,mt9v022m", .data = &mt9v032_models[MT9V032_MODEL_V022_MONO] }, @@ -1294,7 +1286,6 @@ static struct i2c_driver mt9v032_driver = { }, .probe = mt9v032_probe, .remove = mt9v032_remove, - .id_table = mt9v032_id, }; module_i2c_driver(mt9v032_driver); diff --git a/drivers/media/i2c/mt9v111.c b/drivers/media/i2c/mt9v111.c index 723fe138e7bc..b4f2703faa18 100644 --- a/drivers/media/i2c/mt9v111.c +++ b/drivers/media/i2c/mt9v111.c @@ -365,8 +365,6 @@ static int __mt9v111_power_on(struct v4l2_subdev *sd) if (ret) return ret; - clk_set_rate(mt9v111->clk, mt9v111->sysclk); - gpiod_set_value(mt9v111->standby, 0); usleep_range(500, 1000); @@ -532,8 +530,8 @@ static int mt9v111_calc_frame_rate(struct mt9v111_dev *mt9v111, static int mt9v111_hw_config(struct mt9v111_dev *mt9v111) { struct i2c_client *c = mt9v111->client; - unsigned int ret; u16 outfmtctrl2; + int ret; /* Force device reset. */ ret = __mt9v111_hw_reset(mt9v111); @@ -1129,9 +1127,10 @@ static int mt9v111_probe(struct i2c_client *client) mt9v111->dev = &client->dev; mt9v111->client = client; - mt9v111->clk = devm_clk_get(&client->dev, NULL); + mt9v111->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(mt9v111->clk)) - return PTR_ERR(mt9v111->clk); + return dev_err_probe(&client->dev, PTR_ERR(mt9v111->clk), + "failed to get the clock\n"); mt9v111->sysclk = clk_get_rate(mt9v111->clk); if (mt9v111->sysclk > MT9V111_MAX_CLKIN) diff --git a/drivers/media/i2c/og01a1b.c b/drivers/media/i2c/og01a1b.c index 78d5d406e4b7..c7184de6251a 100644 --- a/drivers/media/i2c/og01a1b.c +++ b/drivers/media/i2c/og01a1b.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -421,6 +422,7 @@ static const struct og01a1b_mode supported_modes[] = { }; struct og01a1b { + struct device *dev; struct clk *xvclk; struct gpio_desc *reset_gpio; struct regulator *avdd; @@ -512,7 +514,6 @@ static int og01a1b_write_reg(struct og01a1b *og01a1b, u16 reg, u16 len, u32 val) static int og01a1b_write_reg_list(struct og01a1b *og01a1b, const struct og01a1b_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); unsigned int i; int ret; @@ -520,7 +521,7 @@ static int og01a1b_write_reg_list(struct og01a1b *og01a1b, ret = og01a1b_write_reg(og01a1b, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(og01a1b->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -544,7 +545,6 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) { struct og01a1b *og01a1b = container_of(ctrl->handler, struct og01a1b, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); s64 exposure_max; int ret = 0; @@ -560,7 +560,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(og01a1b->dev)) return 0; switch (ctrl->id) { @@ -596,7 +596,7 @@ static int og01a1b_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); return ret; } @@ -682,13 +682,12 @@ static void og01a1b_update_pad_format(const struct og01a1b_mode *mode, { fmt->width = mode->width; fmt->height = mode->height; - fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; + fmt->code = MEDIA_BUS_FMT_Y10_1X10; fmt->field = V4L2_FIELD_NONE; } static int og01a1b_start_streaming(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); const struct og01a1b_reg_list *reg_list; int link_freq_index, ret; @@ -697,14 +696,14 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) ret = og01a1b_write_reg_list(og01a1b, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(og01a1b->dev, "failed to set plls"); return ret; } reg_list = &og01a1b->cur_mode->reg_list; ret = og01a1b_write_reg_list(og01a1b, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(og01a1b->dev, "failed to set mode"); return ret; } @@ -716,7 +715,7 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(og01a1b->dev, "failed to set stream"); return ret; } @@ -725,22 +724,19 @@ static int og01a1b_start_streaming(struct og01a1b *og01a1b) static void og01a1b_stop_streaming(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); - if (og01a1b_write_reg(og01a1b, OG01A1B_REG_MODE_SELECT, OG01A1B_REG_VALUE_08BIT, OG01A1B_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(og01a1b->dev, "failed to set stream"); } static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) { struct og01a1b *og01a1b = to_og01a1b(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&og01a1b->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(og01a1b->dev); if (ret) { mutex_unlock(&og01a1b->mutex); return ret; @@ -750,11 +746,11 @@ static int og01a1b_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; og01a1b_stop_streaming(og01a1b); - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); } } else { og01a1b_stop_streaming(og01a1b); - pm_runtime_put(&client->dev); + pm_runtime_put(og01a1b->dev); } mutex_unlock(&og01a1b->mutex); @@ -828,7 +824,7 @@ static int og01a1b_enum_mbus_code(struct v4l2_subdev *sd, if (code->index > 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + code->code = MEDIA_BUS_FMT_Y10_1X10; return 0; } @@ -840,7 +836,7 @@ static int og01a1b_enum_frame_size(struct v4l2_subdev *sd, if (fse->index >= ARRAY_SIZE(supported_modes)) return -EINVAL; - if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + if (fse->code != MEDIA_BUS_FMT_Y10_1X10) return -EINVAL; fse->min_width = supported_modes[fse->index].width; @@ -889,7 +885,6 @@ static const struct v4l2_subdev_internal_ops og01a1b_internal_ops = { static int og01a1b_identify_module(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); int ret; u32 val; @@ -899,7 +894,7 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) return ret; if (val != OG01A1B_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(og01a1b->dev, "chip id mismatch: %x!=%x", OG01A1B_CHIP_ID, val); return -ENXIO; } @@ -909,35 +904,18 @@ static int og01a1b_identify_module(struct og01a1b *og01a1b) static int og01a1b_check_hwcfg(struct og01a1b *og01a1b) { - struct i2c_client *client = v4l2_get_subdevdata(&og01a1b->sd); - struct device *dev = &client->dev; + struct device *dev = og01a1b->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - if (!og01a1b->xvclk) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - - mclk = clk_get_rate(og01a1b->xvclk); - } - - if (mclk != OG01A1B_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1066,47 +1044,54 @@ static void og01a1b_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(og01a1b->dev); mutex_destroy(&og01a1b->mutex); } static int og01a1b_probe(struct i2c_client *client) { struct og01a1b *og01a1b; + unsigned long freq; int ret; og01a1b = devm_kzalloc(&client->dev, sizeof(*og01a1b), GFP_KERNEL); if (!og01a1b) return -ENOMEM; + og01a1b->dev = &client->dev; + v4l2_i2c_subdev_init(&og01a1b->sd, client, &og01a1b_subdev_ops); - og01a1b->xvclk = devm_clk_get_optional(&client->dev, NULL); - if (IS_ERR(og01a1b->xvclk)) { - ret = PTR_ERR(og01a1b->xvclk); - dev_err(&client->dev, "failed to get xvclk clock: %d\n", ret); - return ret; - } + og01a1b->xvclk = devm_v4l2_sensor_clk_get(og01a1b->dev, NULL); + if (IS_ERR(og01a1b->xvclk)) + return dev_err_probe(og01a1b->dev, PTR_ERR(og01a1b->xvclk), + "failed to get xvclk clock\n"); + + freq = clk_get_rate(og01a1b->xvclk); + if (freq != OG01A1B_MCLK) + return dev_err_probe(og01a1b->dev, -EINVAL, + "external clock %lu is not supported", + freq); ret = og01a1b_check_hwcfg(og01a1b); if (ret) { - dev_err(&client->dev, "failed to check HW configuration: %d", + dev_err(og01a1b->dev, "failed to check HW configuration: %d", ret); return ret; } - og01a1b->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + og01a1b->reset_gpio = devm_gpiod_get_optional(og01a1b->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(og01a1b->reset_gpio)) { - dev_err(&client->dev, "cannot get reset GPIO\n"); + dev_err(og01a1b->dev, "cannot get reset GPIO\n"); return PTR_ERR(og01a1b->reset_gpio); } - og01a1b->avdd = devm_regulator_get_optional(&client->dev, "avdd"); + og01a1b->avdd = devm_regulator_get_optional(og01a1b->dev, "avdd"); if (IS_ERR(og01a1b->avdd)) { ret = PTR_ERR(og01a1b->avdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'avdd' regulator\n"); return ret; } @@ -1114,11 +1099,11 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->avdd = NULL; } - og01a1b->dovdd = devm_regulator_get_optional(&client->dev, "dovdd"); + og01a1b->dovdd = devm_regulator_get_optional(og01a1b->dev, "dovdd"); if (IS_ERR(og01a1b->dovdd)) { ret = PTR_ERR(og01a1b->dovdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'dovdd' regulator\n"); return ret; } @@ -1126,11 +1111,11 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->dovdd = NULL; } - og01a1b->dvdd = devm_regulator_get_optional(&client->dev, "dvdd"); + og01a1b->dvdd = devm_regulator_get_optional(og01a1b->dev, "dvdd"); if (IS_ERR(og01a1b->dvdd)) { ret = PTR_ERR(og01a1b->dvdd); if (ret != -ENODEV) { - dev_err_probe(&client->dev, ret, + dev_err_probe(og01a1b->dev, ret, "Failed to get 'dvdd' regulator\n"); return ret; } @@ -1139,13 +1124,13 @@ static int og01a1b_probe(struct i2c_client *client) } /* The sensor must be powered on to read the CHIP_ID register */ - ret = og01a1b_power_on(&client->dev); + ret = og01a1b_power_on(og01a1b->dev); if (ret) return ret; ret = og01a1b_identify_module(og01a1b); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(og01a1b->dev, "failed to find sensor: %d", ret); goto power_off; } @@ -1153,7 +1138,7 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->cur_mode = &supported_modes[0]; ret = og01a1b_init_controls(og01a1b); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(og01a1b->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1164,21 +1149,21 @@ static int og01a1b_probe(struct i2c_client *client) og01a1b->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&og01a1b->sd.entity, 1, &og01a1b->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(og01a1b->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&og01a1b->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(og01a1b->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Enable runtime PM and turn off the device */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(og01a1b->dev); + pm_runtime_enable(og01a1b->dev); + pm_runtime_idle(og01a1b->dev); return 0; @@ -1190,7 +1175,7 @@ probe_error_v4l2_ctrl_handler_free: mutex_destroy(&og01a1b->mutex); power_off: - og01a1b_power_off(&client->dev); + og01a1b_power_off(og01a1b->dev); return ret; } diff --git a/drivers/media/i2c/og0ve1b.c b/drivers/media/i2c/og0ve1b.c new file mode 100644 index 000000000000..262d9df766fe --- /dev/null +++ b/drivers/media/i2c/og0ve1b.c @@ -0,0 +1,816 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024-2025 Linaro Ltd + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OG0VE1B_LINK_FREQ_500MHZ (500 * HZ_PER_MHZ) +#define OG0VE1B_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) + +#define OG0VE1B_REG_CHIP_ID CCI_REG24(0x300a) +#define OG0VE1B_CHIP_ID 0xc75645 + +#define OG0VE1B_REG_MODE_SELECT CCI_REG8(0x0100) +#define OG0VE1B_MODE_STANDBY 0x00 +#define OG0VE1B_MODE_STREAMING BIT(0) + +#define OG0VE1B_REG_SOFTWARE_RST CCI_REG8(0x0103) +#define OG0VE1B_SOFTWARE_RST BIT(0) + +/* Exposure controls from sensor */ +#define OG0VE1B_REG_EXPOSURE CCI_REG24(0x3500) +#define OG0VE1B_EXPOSURE_MIN 1 +#define OG0VE1B_EXPOSURE_MAX_MARGIN 14 +#define OG0VE1B_EXPOSURE_STEP 1 +#define OG0VE1B_EXPOSURE_DEFAULT 554 + +/* Analogue gain controls from sensor */ +#define OG0VE1B_REG_ANALOGUE_GAIN CCI_REG16(0x350a) +#define OG0VE1B_ANALOGUE_GAIN_MIN 1 +#define OG0VE1B_ANALOGUE_GAIN_MAX 0x1ff +#define OG0VE1B_ANALOGUE_GAIN_STEP 1 +#define OG0VE1B_ANALOGUE_GAIN_DEFAULT 16 + +/* Test pattern */ +#define OG0VE1B_REG_PRE_ISP CCI_REG8(0x5e00) +#define OG0VE1B_TEST_PATTERN_ENABLE BIT(7) + +#define to_og0ve1b(_sd) container_of(_sd, struct og0ve1b, sd) + +static const s64 og0ve1b_link_freq_menu[] = { + OG0VE1B_LINK_FREQ_500MHZ, +}; + +struct og0ve1b_reg_list { + const struct cci_reg_sequence *regs; + unsigned int num_regs; +}; + +struct og0ve1b_mode { + u32 width; /* Frame width in pixels */ + u32 height; /* Frame height in pixels */ + u32 hts; /* Horizontal timing size */ + u32 vts; /* Default vertical timing size */ + u32 bpp; /* Bits per pixel */ + + const struct og0ve1b_reg_list reg_list; /* Sensor register setting */ +}; + +static const char * const og0ve1b_test_pattern_menu[] = { + "Disabled", + "Vertical Colour Bars", +}; + +static const char * const og0ve1b_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OG0VE1B_NUM_SUPPLIES ARRAY_SIZE(og0ve1b_supply_names) + +struct og0ve1b { + struct device *dev; + struct regmap *regmap; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OG0VE1B_NUM_SUPPLIES]; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + + /* Saved register value */ + u64 pre_isp; +}; + +static const struct cci_reg_sequence og0ve1b_640x480_120fps_mode[] = { + { CCI_REG8(0x30a0), 0x02 }, + { CCI_REG8(0x30a1), 0x00 }, + { CCI_REG8(0x30a2), 0x48 }, + { CCI_REG8(0x30a3), 0x34 }, + { CCI_REG8(0x30a4), 0xf7 }, + { CCI_REG8(0x30a5), 0x00 }, + { CCI_REG8(0x3082), 0x32 }, + { CCI_REG8(0x3083), 0x01 }, + { CCI_REG8(0x301c), 0xf0 }, + { CCI_REG8(0x301e), 0x0b }, + { CCI_REG8(0x3106), 0x10 }, + { CCI_REG8(0x3708), 0x77 }, + { CCI_REG8(0x3709), 0xf8 }, + { CCI_REG8(0x3717), 0x00 }, + { CCI_REG8(0x3782), 0x00 }, + { CCI_REG8(0x3783), 0x47 }, + { CCI_REG8(0x37a2), 0x00 }, + { CCI_REG8(0x3503), 0x07 }, + { CCI_REG8(0x3509), 0x10 }, + { CCI_REG8(0x3600), 0x83 }, + { CCI_REG8(0x3601), 0x21 }, + { CCI_REG8(0x3602), 0xf1 }, + { CCI_REG8(0x360a), 0x18 }, + { CCI_REG8(0x360e), 0xb3 }, + { CCI_REG8(0x3613), 0x20 }, + { CCI_REG8(0x366a), 0x78 }, + { CCI_REG8(0x3706), 0x63 }, + { CCI_REG8(0x3713), 0x00 }, + { CCI_REG8(0x3716), 0xb0 }, + { CCI_REG8(0x37a1), 0x38 }, + { CCI_REG8(0x3800), 0x00 }, + { CCI_REG8(0x3801), 0x04 }, + { CCI_REG8(0x3802), 0x00 }, + { CCI_REG8(0x3803), 0x04 }, + { CCI_REG8(0x3804), 0x02 }, + { CCI_REG8(0x3805), 0x8b }, + { CCI_REG8(0x3806), 0x01 }, + { CCI_REG8(0x3807), 0xeb }, + { CCI_REG8(0x3808), 0x02 }, /* output width */ + { CCI_REG8(0x3809), 0x80 }, + { CCI_REG8(0x380a), 0x01 }, /* output height */ + { CCI_REG8(0x380b), 0xe0 }, + { CCI_REG8(0x380c), 0x03 }, /* horizontal timing size */ + { CCI_REG8(0x380d), 0x18 }, + { CCI_REG8(0x380e), 0x02 }, /* vertical timing size */ + { CCI_REG8(0x380f), 0x38 }, + { CCI_REG8(0x3811), 0x04 }, + { CCI_REG8(0x3813), 0x04 }, + { CCI_REG8(0x3814), 0x11 }, + { CCI_REG8(0x3815), 0x11 }, + { CCI_REG8(0x3820), 0x00 }, + { CCI_REG8(0x3821), 0x00 }, + { CCI_REG8(0x3823), 0x04 }, + { CCI_REG8(0x382a), 0x00 }, + { CCI_REG8(0x382b), 0x03 }, + { CCI_REG8(0x3840), 0x00 }, + { CCI_REG8(0x389e), 0x00 }, + { CCI_REG8(0x3c05), 0x08 }, + { CCI_REG8(0x3c26), 0x02 }, + { CCI_REG8(0x3c27), 0xc0 }, + { CCI_REG8(0x3c28), 0x00 }, + { CCI_REG8(0x3c29), 0x40 }, + { CCI_REG8(0x3c2c), 0x00 }, + { CCI_REG8(0x3c2d), 0x50 }, + { CCI_REG8(0x3c2e), 0x02 }, + { CCI_REG8(0x3c2f), 0x66 }, + { CCI_REG8(0x3c33), 0x08 }, + { CCI_REG8(0x3c35), 0x00 }, + { CCI_REG8(0x3c36), 0x00 }, + { CCI_REG8(0x3c37), 0x00 }, + { CCI_REG8(0x3f52), 0x9b }, + { CCI_REG8(0x4001), 0x42 }, + { CCI_REG8(0x4004), 0x08 }, + { CCI_REG8(0x4005), 0x00 }, + { CCI_REG8(0x4007), 0x28 }, + { CCI_REG8(0x4009), 0x40 }, + { CCI_REG8(0x4307), 0x30 }, + { CCI_REG8(0x4500), 0x80 }, + { CCI_REG8(0x4501), 0x02 }, + { CCI_REG8(0x4502), 0x47 }, + { CCI_REG8(0x4504), 0x7f }, + { CCI_REG8(0x4601), 0x48 }, + { CCI_REG8(0x4800), 0x64 }, + { CCI_REG8(0x4801), 0x0f }, + { CCI_REG8(0x4806), 0x2f }, + { CCI_REG8(0x4819), 0xaa }, + { CCI_REG8(0x4823), 0x3e }, + { CCI_REG8(0x5000), 0x85 }, + { CCI_REG8(0x5e00), 0x0c }, + { CCI_REG8(0x3899), 0x09 }, + { CCI_REG8(0x4f00), 0x64 }, + { CCI_REG8(0x4f02), 0x0a }, + { CCI_REG8(0x4f05), 0x0e }, + { CCI_REG8(0x4f06), 0x11 }, + { CCI_REG8(0x4f08), 0x0b }, + { CCI_REG8(0x4f0a), 0xc4 }, + { CCI_REG8(0x4f20), 0x1f }, + { CCI_REG8(0x4f25), 0x10 }, + { CCI_REG8(0x3016), 0x10 }, + { CCI_REG8(0x3017), 0x00 }, + { CCI_REG8(0x3018), 0x00 }, + { CCI_REG8(0x3019), 0x00 }, + { CCI_REG8(0x301a), 0x00 }, + { CCI_REG8(0x301b), 0x00 }, + { CCI_REG8(0x301c), 0x72 }, + { CCI_REG8(0x3037), 0x40 }, + { CCI_REG8(0x4f2c), 0x00 }, + { CCI_REG8(0x4f21), 0x00 }, + { CCI_REG8(0x4f23), 0x00 }, + { CCI_REG8(0x4f2a), 0x00 }, + { CCI_REG8(0x3665), 0xe7 }, + { CCI_REG8(0x3668), 0x48 }, + { CCI_REG8(0x3671), 0x3c }, + { CCI_REG8(0x389a), 0x02 }, + { CCI_REG8(0x389b), 0x00 }, + { CCI_REG8(0x303c), 0xa0 }, + { CCI_REG8(0x300f), 0xf0 }, + { CCI_REG8(0x304b), 0x0f }, + { CCI_REG8(0x3662), 0x24 }, + { CCI_REG8(0x3006), 0x40 }, + { CCI_REG8(0x4f26), 0x45 }, + { CCI_REG8(0x3607), 0x34 }, + { CCI_REG8(0x3608), 0x01 }, + { CCI_REG8(0x360a), 0x0c }, + { CCI_REG8(0x360b), 0x86 }, + { CCI_REG8(0x360c), 0xcc }, + { CCI_REG8(0x3013), 0x00 }, + { CCI_REG8(0x3083), 0x02 }, + { CCI_REG8(0x3084), 0x12 }, + { CCI_REG8(0x4601), 0x38 }, + { CCI_REG8(0x366f), 0x3a }, + { CCI_REG8(0x3713), 0x19 }, + { CCI_REG8(0x37a2), 0x00 }, + { CCI_REG8(0x3f43), 0x27 }, + { CCI_REG8(0x3f45), 0x27 }, + { CCI_REG8(0x3f47), 0x32 }, + { CCI_REG8(0x3f49), 0x3e }, + { CCI_REG8(0x3f4b), 0x20 }, + { CCI_REG8(0x3f4d), 0x30 }, + { CCI_REG8(0x4300), 0x3f }, + { CCI_REG8(0x4009), 0x10 }, + { CCI_REG8(0x3f02), 0x68 }, + { CCI_REG8(0x3700), 0x8c }, + { CCI_REG8(0x370b), 0x7e }, + { CCI_REG8(0x3f47), 0x35 }, +}; + +static const struct og0ve1b_mode supported_modes[] = { + { + .width = 640, + .height = 480, + .hts = 792, + .vts = 568, + .bpp = 8, + .reg_list = { + .regs = og0ve1b_640x480_120fps_mode, + .num_regs = ARRAY_SIZE(og0ve1b_640x480_120fps_mode), + }, + }, +}; + +static int og0ve1b_enable_test_pattern(struct og0ve1b *og0ve1b, u32 pattern) +{ + u64 val = og0ve1b->pre_isp; + + if (pattern) + val |= OG0VE1B_TEST_PATTERN_ENABLE; + else + val &= ~OG0VE1B_TEST_PATTERN_ENABLE; + + return cci_write(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, val, NULL); +} + +static int og0ve1b_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct og0ve1b *og0ve1b = container_of(ctrl->handler, struct og0ve1b, + ctrl_handler); + int ret; + + /* V4L2 controls are applied, when sensor is powered up for streaming */ + if (!pm_runtime_get_if_active(og0ve1b->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_ANALOGUE_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_EXPOSURE: + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_EXPOSURE, + ctrl->val << 4, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = og0ve1b_enable_test_pattern(og0ve1b, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(og0ve1b->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops og0ve1b_ctrl_ops = { + .s_ctrl = og0ve1b_set_ctrl, +}; + +static int og0ve1b_init_controls(struct og0ve1b *og0ve1b) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &og0ve1b->ctrl_handler; + const struct og0ve1b_mode *mode = &supported_modes[0]; + struct v4l2_fwnode_device_properties props; + s64 exposure_max, pixel_rate, h_blank; + struct v4l2_ctrl *ctrl; + int ret; + + v4l2_ctrl_handler_init(ctrl_hdlr, 9); + + ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &og0ve1b_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(og0ve1b_link_freq_menu) - 1, + 0, og0ve1b_link_freq_menu); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = og0ve1b_link_freq_menu[0] / mode->bpp; + v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts - mode->width; + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_VBLANK, + mode->vts - mode->height, + mode->vts - mode->height, 1, + mode->vts - mode->height); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OG0VE1B_ANALOGUE_GAIN_MIN, OG0VE1B_ANALOGUE_GAIN_MAX, + OG0VE1B_ANALOGUE_GAIN_STEP, + OG0VE1B_ANALOGUE_GAIN_DEFAULT); + + exposure_max = (mode->vts - OG0VE1B_EXPOSURE_MAX_MARGIN); + v4l2_ctrl_new_std(ctrl_hdlr, &og0ve1b_ctrl_ops, + V4L2_CID_EXPOSURE, + OG0VE1B_EXPOSURE_MIN, exposure_max, + OG0VE1B_EXPOSURE_STEP, + OG0VE1B_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &og0ve1b_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(og0ve1b_test_pattern_menu) - 1, + 0, 0, og0ve1b_test_pattern_menu); + + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ret = v4l2_fwnode_device_parse(og0ve1b->dev, &props); + if (ret) + goto error_free_hdlr; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &og0ve1b_ctrl_ops, + &props); + if (ret) + goto error_free_hdlr; + + og0ve1b->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error_free_hdlr: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static void og0ve1b_update_pad_format(const struct og0ve1b_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_Y8_1X8; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; +} + +static int og0ve1b_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + const struct og0ve1b_reg_list *reg_list = &supported_modes[0].reg_list; + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + int ret; + + ret = pm_runtime_resume_and_get(og0ve1b->dev); + if (ret) + return ret; + + /* Skip a step of explicit entering into the standby mode */ + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_SOFTWARE_RST, + OG0VE1B_SOFTWARE_RST, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to software reset: %d\n", ret); + goto error; + } + + ret = cci_multi_reg_write(og0ve1b->regmap, reg_list->regs, + reg_list->num_regs, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to set mode: %d\n", ret); + goto error; + } + + ret = __v4l2_ctrl_handler_setup(og0ve1b->sd.ctrl_handler); + if (ret) + goto error; + + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_MODE_SELECT, + OG0VE1B_MODE_STREAMING, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to start streaming: %d\n", ret); + goto error; + } + + return 0; + +error: + pm_runtime_put_autosuspend(og0ve1b->dev); + + return ret; +} + +static int og0ve1b_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + int ret; + + ret = cci_write(og0ve1b->regmap, OG0VE1B_REG_MODE_SELECT, + OG0VE1B_MODE_STANDBY, NULL); + if (ret) + dev_err(og0ve1b->dev, "failed to stop streaming: %d\n", ret); + + pm_runtime_put_autosuspend(og0ve1b->dev); + + return ret; +} + +static int og0ve1b_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + const struct og0ve1b_mode *mode; + + format = v4l2_subdev_state_get_format(state, 0); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, + fmt->format.height); + + og0ve1b_update_pad_format(mode, &fmt->format); + *format = fmt->format; + + return 0; +} + +static int og0ve1b_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_Y8_1X8; + + return 0; +} + +static int og0ve1b_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_Y8_1X8) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int og0ve1b_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_Y8_1X8, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + og0ve1b_set_pad_format(sd, state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_video_ops og0ve1b_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops og0ve1b_pad_ops = { + .set_fmt = og0ve1b_set_pad_format, + .get_fmt = v4l2_subdev_get_fmt, + .enum_mbus_code = og0ve1b_enum_mbus_code, + .enum_frame_size = og0ve1b_enum_frame_size, + .enable_streams = og0ve1b_enable_streams, + .disable_streams = og0ve1b_disable_streams, +}; + +static const struct v4l2_subdev_ops og0ve1b_subdev_ops = { + .video = &og0ve1b_video_ops, + .pad = &og0ve1b_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops og0ve1b_internal_ops = { + .init_state = og0ve1b_init_state, +}; + +static const struct media_entity_operations og0ve1b_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int og0ve1b_identify_sensor(struct og0ve1b *og0ve1b) +{ + u64 val; + int ret; + + ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_CHIP_ID, &val, NULL); + if (ret) { + dev_err(og0ve1b->dev, "failed to read chip id: %d\n", ret); + return ret; + } + + if (val != OG0VE1B_CHIP_ID) { + dev_err(og0ve1b->dev, "chip id mismatch: %x!=%llx\n", + OG0VE1B_CHIP_ID, val); + return -ENODEV; + } + + ret = cci_read(og0ve1b->regmap, OG0VE1B_REG_PRE_ISP, + &og0ve1b->pre_isp, NULL); + if (ret) + dev_err(og0ve1b->dev, "failed to read pre_isp: %d\n", ret); + + return ret; +} + +static int og0ve1b_check_hwcfg(struct og0ve1b *og0ve1b) +{ + struct fwnode_handle *fwnode = dev_fwnode(og0ve1b->dev), *ep; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + unsigned long freq_bitmap; + int ret; + + if (!fwnode) + return -ENODEV; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + ret = v4l2_link_freq_to_bitmap(og0ve1b->dev, + bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + og0ve1b_link_freq_menu, + ARRAY_SIZE(og0ve1b_link_freq_menu), + &freq_bitmap); + + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int og0ve1b_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + int ret; + + ret = regulator_bulk_enable(OG0VE1B_NUM_SUPPLIES, og0ve1b->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(og0ve1b->reset_gpio, 0); + usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC); + + ret = clk_prepare_enable(og0ve1b->xvclk); + if (ret) + goto reset_gpio; + + return 0; + +reset_gpio: + gpiod_set_value_cansleep(og0ve1b->reset_gpio, 1); + + regulator_bulk_disable(OG0VE1B_NUM_SUPPLIES, og0ve1b->supplies); + + return ret; +} + +static int og0ve1b_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + + clk_disable_unprepare(og0ve1b->xvclk); + + gpiod_set_value_cansleep(og0ve1b->reset_gpio, 1); + + regulator_bulk_disable(OG0VE1B_NUM_SUPPLIES, og0ve1b->supplies); + + return 0; +} + +static int og0ve1b_probe(struct i2c_client *client) +{ + struct og0ve1b *og0ve1b; + unsigned long freq; + unsigned int i; + int ret; + + og0ve1b = devm_kzalloc(&client->dev, sizeof(*og0ve1b), GFP_KERNEL); + if (!og0ve1b) + return -ENOMEM; + + og0ve1b->dev = &client->dev; + + v4l2_i2c_subdev_init(&og0ve1b->sd, client, &og0ve1b_subdev_ops); + + og0ve1b->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(og0ve1b->regmap)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->regmap), + "failed to init CCI\n"); + + og0ve1b->xvclk = devm_v4l2_sensor_clk_get(og0ve1b->dev, NULL); + if (IS_ERR(og0ve1b->xvclk)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->xvclk), + "failed to get XVCLK clock\n"); + + freq = clk_get_rate(og0ve1b->xvclk); + if (freq && freq != OG0VE1B_MCLK_FREQ_24MHZ) + return dev_err_probe(og0ve1b->dev, -EINVAL, + "XVCLK clock frequency %lu is not supported\n", + freq); + + ret = og0ve1b_check_hwcfg(og0ve1b); + if (ret) + return dev_err_probe(og0ve1b->dev, ret, + "failed to check HW configuration\n"); + + og0ve1b->reset_gpio = devm_gpiod_get_optional(og0ve1b->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(og0ve1b->reset_gpio)) + return dev_err_probe(og0ve1b->dev, PTR_ERR(og0ve1b->reset_gpio), + "cannot get reset GPIO\n"); + + for (i = 0; i < OG0VE1B_NUM_SUPPLIES; i++) + og0ve1b->supplies[i].supply = og0ve1b_supply_names[i]; + + ret = devm_regulator_bulk_get(og0ve1b->dev, OG0VE1B_NUM_SUPPLIES, + og0ve1b->supplies); + if (ret) + return dev_err_probe(og0ve1b->dev, ret, + "failed to get supply regulators\n"); + + /* The sensor must be powered on to read the CHIP_ID register */ + ret = og0ve1b_power_on(og0ve1b->dev); + if (ret) + return ret; + + ret = og0ve1b_identify_sensor(og0ve1b); + if (ret) { + dev_err_probe(og0ve1b->dev, ret, "failed to find sensor\n"); + goto power_off; + } + + ret = og0ve1b_init_controls(og0ve1b); + if (ret) { + dev_err_probe(og0ve1b->dev, ret, "failed to init controls\n"); + goto power_off; + } + + og0ve1b->sd.state_lock = og0ve1b->ctrl_handler.lock; + og0ve1b->sd.internal_ops = &og0ve1b_internal_ops; + og0ve1b->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + og0ve1b->sd.entity.ops = &og0ve1b_subdev_entity_ops; + og0ve1b->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + og0ve1b->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&og0ve1b->sd.entity, 1, &og0ve1b->pad); + if (ret) { + dev_err_probe(og0ve1b->dev, ret, + "failed to init media entity pads\n"); + goto v4l2_ctrl_handler_free; + } + + ret = v4l2_subdev_init_finalize(&og0ve1b->sd); + if (ret < 0) { + dev_err_probe(og0ve1b->dev, ret, + "failed to init media entity pads\n"); + goto media_entity_cleanup; + } + + pm_runtime_set_active(og0ve1b->dev); + pm_runtime_enable(og0ve1b->dev); + + ret = v4l2_async_register_subdev_sensor(&og0ve1b->sd); + if (ret < 0) { + dev_err_probe(og0ve1b->dev, ret, + "failed to register V4L2 subdev\n"); + goto subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ + pm_runtime_idle(og0ve1b->dev); + pm_runtime_set_autosuspend_delay(og0ve1b->dev, 1000); + pm_runtime_use_autosuspend(og0ve1b->dev); + + return 0; + +subdev_cleanup: + v4l2_subdev_cleanup(&og0ve1b->sd); + pm_runtime_disable(og0ve1b->dev); + pm_runtime_set_suspended(og0ve1b->dev); + +media_entity_cleanup: + media_entity_cleanup(&og0ve1b->sd.entity); + +v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(og0ve1b->sd.ctrl_handler); + +power_off: + og0ve1b_power_off(og0ve1b->dev); + + return ret; +} + +static void og0ve1b_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct og0ve1b *og0ve1b = to_og0ve1b(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(og0ve1b->dev); + + if (!pm_runtime_status_suspended(og0ve1b->dev)) { + og0ve1b_power_off(og0ve1b->dev); + pm_runtime_set_suspended(og0ve1b->dev); + } +} + +static const struct dev_pm_ops og0ve1b_pm_ops = { + SET_RUNTIME_PM_OPS(og0ve1b_power_off, og0ve1b_power_on, NULL) +}; + +static const struct of_device_id og0ve1b_of_match[] = { + { .compatible = "ovti,og0ve1b" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, og0ve1b_of_match); + +static struct i2c_driver og0ve1b_i2c_driver = { + .driver = { + .name = "og0ve1b", + .pm = &og0ve1b_pm_ops, + .of_match_table = og0ve1b_of_match, + }, + .probe = og0ve1b_probe, + .remove = og0ve1b_remove, +}; + +module_i2c_driver(og0ve1b_i2c_driver); + +MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>"); +MODULE_DESCRIPTION("OmniVision OG0VE1B sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov02a10.c b/drivers/media/i2c/ov02a10.c index 6c30e1a0d814..70d9d7c43f18 100644 --- a/drivers/media/i2c/ov02a10.c +++ b/drivers/media/i2c/ov02a10.c @@ -100,7 +100,8 @@ struct ov02a10_mode { }; struct ov02a10 { - u32 eclk_freq; + struct device *dev; + /* Indication of MIPI transmission speed select */ u32 mipi_clock_voltage; @@ -392,7 +393,7 @@ static int ov02a10_check_sensor_id(struct ov02a10 *ov02a10) chip_id = le16_to_cpu((__force __le16)ret); if ((chip_id & OV02A10_ID_MASK) != OV02A10_ID) { - dev_err(&client->dev, "unexpected sensor id(0x%04x)\n", chip_id); + dev_err(ov02a10->dev, "unexpected sensor id(0x%04x)\n", chip_id); return -EINVAL; } @@ -481,7 +482,7 @@ static int __ov02a10_start_stream(struct ov02a10 *ov02a10) ret = i2c_smbus_write_byte_data(client, REG_MIRROR_FLIP_CONTROL, REG_MIRROR_FLIP_ENABLE); if (ret < 0) { - dev_err(&client->dev, "failed to set orientation\n"); + dev_err(ov02a10->dev, "failed to set orientation\n"); return ret; } ret = i2c_smbus_write_byte_data(client, REG_GLOBAL_EFFECTIVE, @@ -530,7 +531,6 @@ static int ov02a10_init_state(struct v4l2_subdev *sd, static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) { struct ov02a10 *ov02a10 = to_ov02a10(sd); - struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); int ret; mutex_lock(&ov02a10->mutex); @@ -541,7 +541,7 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) } if (on) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov02a10->dev); if (ret < 0) goto unlock_and_return; @@ -553,7 +553,7 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) } } else { __ov02a10_stop_stream(ov02a10); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02a10->dev); } ov02a10->streaming = on; @@ -562,7 +562,7 @@ static int ov02a10_s_stream(struct v4l2_subdev *sd, int on) return 0; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov02a10->dev); unlock_and_return: mutex_unlock(&ov02a10->mutex); @@ -662,7 +662,6 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov02a10 *ov02a10 = container_of(ctrl->handler, struct ov02a10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); s64 max_expo; int ret; @@ -678,7 +677,7 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov02a10->dev)) return 0; switch (ctrl->id) { @@ -699,7 +698,7 @@ static int ov02a10_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov02a10->dev); return ret; } @@ -734,7 +733,6 @@ static const struct v4l2_ctrl_ops ov02a10_ctrl_ops = { static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02a10->subdev); const struct ov02a10_mode *mode; struct v4l2_ctrl_handler *handler; struct v4l2_ctrl *ctrl; @@ -790,7 +788,7 @@ static int ov02a10_initialize_controls(struct ov02a10 *ov02a10) if (handler->error) { ret = handler->error; - dev_err(&client->dev, "failed to init controls(%d)\n", ret); + dev_err(ov02a10->dev, "failed to init controls(%d)\n", ret); goto err_free_handler; } @@ -866,6 +864,8 @@ static int ov02a10_probe(struct i2c_client *client) if (!ov02a10) return -ENOMEM; + ov02a10->dev = dev; + ret = ov02a10_check_hwcfg(dev, ov02a10); if (ret) return dev_err_probe(dev, ret, @@ -885,22 +885,11 @@ static int ov02a10_probe(struct i2c_client *client) ov02a10->fmt.code = MEDIA_BUS_FMT_SRGGB10_1X10; } - ov02a10->eclk = devm_clk_get(dev, "eclk"); + ov02a10->eclk = devm_v4l2_sensor_clk_get_legacy(dev, "eclk", false, 0); if (IS_ERR(ov02a10->eclk)) return dev_err_probe(dev, PTR_ERR(ov02a10->eclk), "failed to get eclk\n"); - ret = device_property_read_u32(dev, "clock-frequency", - &ov02a10->eclk_freq); - if (ret < 0) - return dev_err_probe(dev, ret, - "failed to get eclk frequency\n"); - - ret = clk_set_rate(ov02a10->eclk, ov02a10->eclk_freq); - if (ret < 0) - return dev_err_probe(dev, ret, - "failed to set eclk frequency (24MHz)\n"); - if (clk_get_rate(ov02a10->eclk) != OV02A10_ECLK_FREQ) dev_warn(dev, "eclk mismatched, mode is based on 24MHz\n"); @@ -985,10 +974,10 @@ static void ov02a10_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - ov02a10_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02a10->dev); + if (!pm_runtime_status_suspended(ov02a10->dev)) + ov02a10_power_off(ov02a10->dev); + pm_runtime_set_suspended(ov02a10->dev); mutex_destroy(&ov02a10->mutex); } diff --git a/drivers/media/i2c/ov02c10.c b/drivers/media/i2c/ov02c10.c index 089a4fd9627c..8c4d85dc7922 100644 --- a/drivers/media/i2c/ov02c10.c +++ b/drivers/media/i2c/ov02c10.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> -#include <linux/version.h> #include <media/v4l2-cci.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -373,6 +372,8 @@ static const char * const ov02c10_supply_names[] = { }; struct ov02c10 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -418,7 +419,6 @@ static int ov02c10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov02c10 *ov02c10 = container_of(ctrl->handler, struct ov02c10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); const u32 height = supported_modes[0].height; s64 exposure_max; int ret = 0; @@ -434,7 +434,7 @@ static int ov02c10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov02c10->dev)) return 0; switch (ctrl->id) { @@ -467,7 +467,7 @@ static int ov02c10_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov02c10->dev); return ret; } @@ -478,7 +478,6 @@ static const struct v4l2_ctrl_ops ov02c10_ctrl_ops = { static int ov02c10_init_controls(struct ov02c10 *ov02c10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); struct v4l2_ctrl_handler *ctrl_hdlr = &ov02c10->ctrl_handler; const struct ov02c10_mode *mode = &supported_modes[0]; u32 vblank_min, vblank_max, vblank_default, vts_def; @@ -542,7 +541,7 @@ static int ov02c10_init_controls(struct ov02c10 *ov02c10) ARRAY_SIZE(ov02c10_test_pattern_menu) - 1, 0, 0, ov02c10_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov02c10->dev, &props); if (ret) return ret; @@ -570,12 +569,11 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, u32 pad, u64 streams_mask) { const struct ov02c10_mode *mode = &supported_modes[0]; - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02c10 *ov02c10 = to_ov02c10(sd); const struct reg_sequence *reg_sequence; int ret, sequence_length; - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov02c10->dev); if (ret) return ret; @@ -584,7 +582,7 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, ret = regmap_multi_reg_write(ov02c10->regmap, reg_sequence, sequence_length); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(ov02c10->dev, "failed to set mode\n"); goto out; } @@ -593,7 +591,7 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, ret = regmap_multi_reg_write(ov02c10->regmap, reg_sequence, sequence_length); if (ret) { - dev_err(&client->dev, "failed to write lane settings\n"); + dev_err(ov02c10->dev, "failed to write lane settings\n"); goto out; } @@ -604,7 +602,7 @@ static int ov02c10_enable_streams(struct v4l2_subdev *sd, ret = cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 1, NULL); out: if (ret) - pm_runtime_put(&client->dev); + pm_runtime_put(ov02c10->dev); return ret; } @@ -613,11 +611,10 @@ static int ov02c10_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02c10 *ov02c10 = to_ov02c10(sd); cci_write(ov02c10->regmap, OV02C10_REG_STREAM_CONTROL, 0, NULL); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02c10->dev); return 0; } @@ -778,7 +775,6 @@ static const struct v4l2_subdev_internal_ops ov02c10_internal_ops = { static int ov02c10_identify_module(struct ov02c10 *ov02c10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02c10->sd); u64 chip_id; int ret; @@ -787,7 +783,7 @@ static int ov02c10_identify_module(struct ov02c10 *ov02c10) return ret; if (chip_id != OV02C10_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%llx", + dev_err(ov02c10->dev, "chip id mismatch: %x!=%llx", OV02C10_CHIP_ID, chip_id); return -ENXIO; } @@ -795,14 +791,14 @@ static int ov02c10_identify_module(struct ov02c10 *ov02c10) return 0; } -static int ov02c10_check_hwcfg(struct device *dev, struct ov02c10 *ov02c10) +static int ov02c10_check_hwcfg(struct ov02c10 *ov02c10) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov02c10->dev; struct fwnode_handle *ep, *fwnode = dev_fwnode(dev); unsigned long link_freq_bitmap; - u32 mclk; int ret; /* @@ -814,31 +810,6 @@ static int ov02c10_check_hwcfg(struct device *dev, struct ov02c10 *ov02c10) return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); - ov02c10->img_clk = devm_clk_get_optional(dev, NULL); - if (IS_ERR(ov02c10->img_clk)) { - fwnode_handle_put(ep); - return dev_err_probe(dev, PTR_ERR(ov02c10->img_clk), - "failed to get imaging clock\n"); - } - - if (ov02c10->img_clk) { - mclk = clk_get_rate(ov02c10->img_clk); - } else { - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - fwnode_handle_put(ep); - return dev_err_probe(dev, ret, - "reading clock-frequency property\n"); - } - } - - if (mclk != OV02C10_MCLK) { - fwnode_handle_put(ep); - return dev_err_probe(dev, -EINVAL, - "external clock %u is not supported\n", - mclk); - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -873,35 +844,50 @@ check_hwcfg_error: static void ov02c10_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02c10 *ov02c10 = to_ov02c10(sd); v4l2_async_unregister_subdev(sd); v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) { - ov02c10_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02c10->dev); + if (!pm_runtime_status_suspended(ov02c10->dev)) { + ov02c10_power_off(ov02c10->dev); + pm_runtime_set_suspended(ov02c10->dev); } } static int ov02c10_probe(struct i2c_client *client) { struct ov02c10 *ov02c10; + unsigned long freq; int ret; ov02c10 = devm_kzalloc(&client->dev, sizeof(*ov02c10), GFP_KERNEL); if (!ov02c10) return -ENOMEM; + ov02c10->dev = &client->dev; + + ov02c10->img_clk = devm_v4l2_sensor_clk_get(ov02c10->dev, NULL); + if (IS_ERR(ov02c10->img_clk)) + return dev_err_probe(ov02c10->dev, PTR_ERR(ov02c10->img_clk), + "failed to get imaging clock\n"); + + freq = clk_get_rate(ov02c10->img_clk); + if (freq != OV02C10_MCLK) + return dev_err_probe(ov02c10->dev, -EINVAL, + "external clock %lu is not supported", + freq); + v4l2_i2c_subdev_init(&ov02c10->sd, client, &ov02c10_subdev_ops); /* Check HW config */ - ret = ov02c10_check_hwcfg(&client->dev, ov02c10); + ret = ov02c10_check_hwcfg(ov02c10); if (ret) return ret; - ret = ov02c10_get_pm_resources(&client->dev); + ret = ov02c10_get_pm_resources(ov02c10->dev); if (ret) return ret; @@ -909,21 +895,21 @@ static int ov02c10_probe(struct i2c_client *client) if (IS_ERR(ov02c10->regmap)) return PTR_ERR(ov02c10->regmap); - ret = ov02c10_power_on(&client->dev); + ret = ov02c10_power_on(ov02c10->dev); if (ret) { - dev_err_probe(&client->dev, ret, "failed to power on\n"); + dev_err_probe(ov02c10->dev, ret, "failed to power on\n"); return ret; } ret = ov02c10_identify_module(ov02c10); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov02c10->dev, "failed to find sensor: %d", ret); goto probe_error_power_off; } ret = ov02c10_init_controls(ov02c10); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov02c10->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -934,33 +920,33 @@ static int ov02c10_probe(struct i2c_client *client) ov02c10->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov02c10->sd.entity, 1, &ov02c10->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov02c10->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ov02c10->sd.state_lock = ov02c10->ctrl_handler.lock; ret = v4l2_subdev_init_finalize(&ov02c10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to init subdev: %d", ret); + dev_err(ov02c10->dev, "failed to init subdev: %d", ret); goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(ov02c10->dev); + pm_runtime_enable(ov02c10->dev); ret = v4l2_async_register_subdev_sensor(&ov02c10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov02c10->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_v4l2_subdev_cleanup; } - pm_runtime_idle(&client->dev); + pm_runtime_idle(ov02c10->dev); return 0; probe_error_v4l2_subdev_cleanup: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02c10->dev); + pm_runtime_set_suspended(ov02c10->dev); v4l2_subdev_cleanup(&ov02c10->sd); probe_error_media_entity_cleanup: @@ -970,7 +956,7 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov02c10->sd.ctrl_handler); probe_error_power_off: - ov02c10_power_off(&client->dev); + ov02c10_power_off(ov02c10->dev); return ret; } diff --git a/drivers/media/i2c/ov02e10.c b/drivers/media/i2c/ov02e10.c index d74dc62e189d..4a64cba99991 100644 --- a/drivers/media/i2c/ov02e10.c +++ b/drivers/media/i2c/ov02e10.c @@ -226,6 +226,8 @@ static const char * const ov02e10_supply_names[] = { }; struct ov02e10 { + struct device *dev; + struct regmap *regmap; struct v4l2_subdev sd; struct media_pad pad; @@ -288,7 +290,6 @@ static int ov02e10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov02e10 *ov02e10 = container_of(ctrl->handler, struct ov02e10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov02e10->sd); s64 exposure_max; int ret; @@ -307,7 +308,7 @@ static int ov02e10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov02e10->dev)) return 0; ret = cci_write(ov02e10->regmap, OV02E10_REG_COMMAND_UPDATE, @@ -363,7 +364,7 @@ static int ov02e10_set_ctrl(struct v4l2_ctrl *ctrl) cci_write(ov02e10->regmap, OV02E10_REG_COMMAND_UPDATE, OV02E10_COMMAND_UPDATE, &ret); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02e10->dev); return ret; } @@ -374,7 +375,6 @@ static const struct v4l2_ctrl_ops ov02e10_ctrl_ops = { static int ov02e10_init_controls(struct ov02e10 *ov02e10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02e10->sd); struct v4l2_ctrl_handler *ctrl_hdlr = &ov02e10->ctrl_handler; const struct ov02e10_mode *mode = ov02e10->cur_mode; u32 vblank_min, vblank_max, vblank_def; @@ -442,7 +442,7 @@ static int ov02e10_init_controls(struct ov02e10 *ov02e10) ARRAY_SIZE(ov02e10_test_pattern_menu) - 1, 0, 0, ov02e10_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov02e10->dev, &props); if (ret) return ret; @@ -481,12 +481,11 @@ static int ov02e10_enable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02e10 *ov02e10 = to_ov02e10(sd); const struct reg_sequence_list *reg_list; int ret; - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov02e10->dev); if (ret) return ret; @@ -494,7 +493,7 @@ static int ov02e10_enable_streams(struct v4l2_subdev *sd, ret = regmap_multi_reg_write(ov02e10->regmap, reg_list->regs, reg_list->num_regs); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(ov02e10->dev, "failed to set mode\n"); goto out; } @@ -506,7 +505,7 @@ static int ov02e10_enable_streams(struct v4l2_subdev *sd, out: if (ret) - pm_runtime_put(&client->dev); + pm_runtime_put(ov02e10->dev); return ret; } @@ -515,11 +514,10 @@ static int ov02e10_disable_streams(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, u32 pad, u64 streams_mask) { - struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov02e10 *ov02e10 = to_ov02e10(sd); ov02e10_set_stream_mode(ov02e10, 0); - pm_runtime_put(&client->dev); + pm_runtime_put(ov02e10->dev); return 0; } @@ -724,7 +722,6 @@ static const struct v4l2_subdev_internal_ops ov02e10_internal_ops = { static int ov02e10_identify_module(struct ov02e10 *ov02e10) { - struct i2c_client *client = v4l2_get_subdevdata(&ov02e10->sd); int ret; u64 val; @@ -735,7 +732,7 @@ static int ov02e10_identify_module(struct ov02e10 *ov02e10) return ret; if (val != OV02E10_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov02e10->dev, "chip id mismatch: %x!=%x\n", OV02E10_CHIP_ID, (u32)val); return -ENXIO; } @@ -743,15 +740,15 @@ static int ov02e10_identify_module(struct ov02e10 *ov02e10) return 0; } -static int ov02e10_check_hwcfg(struct device *dev, struct ov02e10 *ov02e10) +static int ov02e10_check_hwcfg(struct ov02e10 *ov02e10) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov02e10->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned long link_freq_bitmap; - u32 ext_clk; int ret; ep = fwnode_graph_get_next_endpoint(fwnode, NULL); @@ -764,31 +761,6 @@ static int ov02e10_check_hwcfg(struct device *dev, struct ov02e10 *ov02e10) if (ret) return dev_err_probe(dev, ret, "parsing endpoint failed\n"); - ov02e10->img_clk = devm_clk_get_optional(dev, NULL); - if (IS_ERR(ov02e10->img_clk)) { - ret = dev_err_probe(dev, PTR_ERR(ov02e10->img_clk), - "failed to get imaging clock\n"); - goto out_err; - } - - if (ov02e10->img_clk) { - ext_clk = clk_get_rate(ov02e10->img_clk); - } else { - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency\n"); - goto out_err; - } - } - - if (ext_clk != OV02E10_MCLK) { - dev_err(dev, "external clock %d is not supported\n", - ext_clk); - ret = -EINVAL; - goto out_err; - } - if (bus_cfg.bus.mipi_csi2.num_data_lanes != OV02E10_DATA_LANES) { dev_err(dev, "number of CSI2 data lanes %d is not supported\n", bus_cfg.bus.mipi_csi2.num_data_lanes); @@ -823,32 +795,47 @@ out_err: static void ov02e10_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov02e10 *ov02e10 = to_ov02e10(sd); v4l2_async_unregister_subdev(sd); v4l2_subdev_cleanup(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov02e10->dev); - if (!pm_runtime_status_suspended(&client->dev)) { - ov02e10_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + if (!pm_runtime_status_suspended(ov02e10->dev)) { + ov02e10_power_off(ov02e10->dev); + pm_runtime_set_suspended(ov02e10->dev); } } static int ov02e10_probe(struct i2c_client *client) { struct ov02e10 *ov02e10; + unsigned long freq; int ret; ov02e10 = devm_kzalloc(&client->dev, sizeof(*ov02e10), GFP_KERNEL); if (!ov02e10) return -ENOMEM; + ov02e10->dev = &client->dev; + + ov02e10->img_clk = devm_v4l2_sensor_clk_get(ov02e10->dev, NULL); + if (IS_ERR(ov02e10->img_clk)) + return dev_err_probe(ov02e10->dev, PTR_ERR(ov02e10->img_clk), + "failed to get imaging clock\n"); + + freq = clk_get_rate(ov02e10->img_clk); + if (freq != OV02E10_MCLK) + return dev_err_probe(ov02e10->dev, -EINVAL, + "external clock %lu is not supported", + freq); + v4l2_i2c_subdev_init(&ov02e10->sd, client, &ov02e10_subdev_ops); /* Check HW config */ - ret = ov02e10_check_hwcfg(&client->dev, ov02e10); + ret = ov02e10_check_hwcfg(ov02e10); if (ret) return ret; @@ -857,27 +844,27 @@ static int ov02e10_probe(struct i2c_client *client) if (IS_ERR(ov02e10->regmap)) return PTR_ERR(ov02e10->regmap); - ret = ov02e10_get_pm_resources(&client->dev); + ret = ov02e10_get_pm_resources(ov02e10->dev); if (ret) return ret; - ret = ov02e10_power_on(&client->dev); + ret = ov02e10_power_on(ov02e10->dev); if (ret) { - dev_err_probe(&client->dev, ret, "failed to power on\n"); + dev_err_probe(ov02e10->dev, ret, "failed to power on\n"); return ret; } /* Check module identity */ ret = ov02e10_identify_module(ov02e10); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(ov02e10->dev, "failed to find sensor: %d\n", ret); goto probe_error_power_off; } ov02e10->cur_mode = &supported_modes[0]; ret = ov02e10_init_controls(ov02e10); if (ret) { - dev_err(&client->dev, "failed to init controls: %d\n", ret); + dev_err(ov02e10->dev, "failed to init controls: %d\n", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -891,33 +878,33 @@ static int ov02e10_probe(struct i2c_client *client) ov02e10->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov02e10->sd.entity, 1, &ov02e10->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov02e10->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ov02e10->sd.state_lock = ov02e10->ctrl_handler.lock; ret = v4l2_subdev_init_finalize(&ov02e10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to init subdev: %d", ret); + dev_err(ov02e10->dev, "failed to init subdev: %d", ret); goto probe_error_media_entity_cleanup; } - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(ov02e10->dev); + pm_runtime_enable(ov02e10->dev); ret = v4l2_async_register_subdev_sensor(&ov02e10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov02e10->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_v4l2_subdev_cleanup; } - pm_runtime_idle(&client->dev); + pm_runtime_idle(ov02e10->dev); return 0; probe_error_v4l2_subdev_cleanup: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov02e10->dev); + pm_runtime_set_suspended(ov02e10->dev); v4l2_subdev_cleanup(&ov02e10->sd); probe_error_media_entity_cleanup: @@ -927,7 +914,7 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov02e10->sd.ctrl_handler); probe_error_power_off: - ov02e10_power_off(&client->dev); + ov02e10_power_off(ov02e10->dev); return ret; } @@ -961,7 +948,7 @@ static struct i2c_driver ov02e10_i2c_driver = { module_i2c_driver(ov02e10_i2c_driver); -MODULE_AUTHOR("Jingjing Xiong <jingjing.xiong@intel.com>"); +MODULE_AUTHOR("Jingjing Xiong"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_AUTHOR("Alan Stern <stern@rowland.harvard.edu>"); MODULE_AUTHOR("Bryan O'Donoghue <bryan.odonoghue@linaro.org>"); diff --git a/drivers/media/i2c/ov08d10.c b/drivers/media/i2c/ov08d10.c index 1bacbdfa4298..43ec2a1f2fcf 100644 --- a/drivers/media/i2c/ov08d10.c +++ b/drivers/media/i2c/ov08d10.c @@ -515,12 +515,13 @@ static const char * const ov08d10_test_pattern_menu[] = { }; struct ov08d10 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; - struct clk *xvclk; - /* V4L2 Controls */ struct v4l2_ctrl *link_freq; struct v4l2_ctrl *pixel_rate; @@ -663,7 +664,7 @@ static int ov08d10_write_reg_list(struct ov08d10 *ov08d10, ret = i2c_smbus_write_byte_data(client, r_list->regs[i].address, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov08d10->dev, "failed to write reg 0x%2.2x. error = %d", r_list->regs[i].address, ret); return ret; @@ -849,7 +850,6 @@ static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov08d10 *ov08d10 = container_of(ctrl->handler, struct ov08d10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov08d10->sd); s64 exposure_max; int ret; @@ -865,7 +865,7 @@ static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov08d10->dev)) return 0; switch (ctrl->id) { @@ -901,7 +901,7 @@ static int ov08d10_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov08d10->dev); return ret; } @@ -1025,32 +1025,32 @@ static int ov08d10_start_streaming(struct ov08d10 *ov08d10) /* soft reset */ ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, 0x00); if (ret < 0) { - dev_err(&client->dev, "failed to reset sensor"); + dev_err(ov08d10->dev, "failed to reset sensor"); return ret; } ret = i2c_smbus_write_byte_data(client, 0x20, 0x0e); if (ret < 0) { - dev_err(&client->dev, "failed to reset sensor"); + dev_err(ov08d10->dev, "failed to reset sensor"); return ret; } usleep_range(3000, 4000); ret = i2c_smbus_write_byte_data(client, 0x20, 0x0b); if (ret < 0) { - dev_err(&client->dev, "failed to reset sensor"); + dev_err(ov08d10->dev, "failed to reset sensor"); return ret; } /* update sensor setting */ ret = ov08d10_write_reg_list(ov08d10, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov08d10->dev, "failed to set plls"); return ret; } reg_list = &ov08d10->cur_mode->reg_list; ret = ov08d10_write_reg_list(ov08d10, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov08d10->dev, "failed to set mode"); return ret; } @@ -1077,19 +1077,19 @@ static void ov08d10_stop_streaming(struct ov08d10 *ov08d10) ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, 0x00); if (ret < 0) { - dev_err(&client->dev, "failed to stop streaming"); + dev_err(ov08d10->dev, "failed to stop streaming"); return; } ret = i2c_smbus_write_byte_data(client, OV08D10_REG_MODE_SELECT, OV08D10_MODE_STANDBY); if (ret < 0) { - dev_err(&client->dev, "failed to stop streaming"); + dev_err(ov08d10->dev, "failed to stop streaming"); return; } ret = i2c_smbus_write_byte_data(client, OV08D10_REG_PAGE, 0x01); if (ret < 0) { - dev_err(&client->dev, "failed to stop streaming"); + dev_err(ov08d10->dev, "failed to stop streaming"); return; } } @@ -1097,12 +1097,11 @@ static void ov08d10_stop_streaming(struct ov08d10 *ov08d10) static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) { struct ov08d10 *ov08d10 = to_ov08d10(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov08d10->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov08d10->dev); if (ret < 0) { mutex_unlock(&ov08d10->mutex); return ret; @@ -1112,11 +1111,11 @@ static int ov08d10_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov08d10_stop_streaming(ov08d10); - pm_runtime_put(&client->dev); + pm_runtime_put(ov08d10->dev); } } else { ov08d10_stop_streaming(ov08d10); - pm_runtime_put(&client->dev); + pm_runtime_put(ov08d10->dev); } /* vflip and hflip cannot change during streaming */ @@ -1293,7 +1292,7 @@ static int ov08d10_identify_module(struct ov08d10 *ov08d10) chip_id = val | ret; if ((chip_id & OV08D10_ID_MASK) != OV08D10_CHIP_ID) { - dev_err(&client->dev, "unexpected sensor id(0x%04x)\n", + dev_err(ov08d10->dev, "unexpected sensor id(0x%04x)\n", chip_id); return -EINVAL; } @@ -1301,28 +1300,20 @@ static int ov08d10_identify_module(struct ov08d10 *ov08d10) return 0; } -static int ov08d10_get_hwcfg(struct ov08d10 *ov08d10, struct device *dev) +static int ov08d10_get_hwcfg(struct ov08d10 *ov08d10) { + struct device *dev = ov08d10->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 xvclk_rate; unsigned int i, j; int ret; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &xvclk_rate); - if (ret) - return ret; - - if (xvclk_rate != OV08D10_XVCLK_19_2) - dev_warn(dev, "external clock rate %u is unsupported", - xvclk_rate); - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -1380,22 +1371,35 @@ static void ov08d10_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov08d10->dev); mutex_destroy(&ov08d10->mutex); } static int ov08d10_probe(struct i2c_client *client) { struct ov08d10 *ov08d10; + unsigned long freq; int ret; ov08d10 = devm_kzalloc(&client->dev, sizeof(*ov08d10), GFP_KERNEL); if (!ov08d10) return -ENOMEM; - ret = ov08d10_get_hwcfg(ov08d10, &client->dev); + ov08d10->dev = &client->dev; + + ov08d10->clk = devm_v4l2_sensor_clk_get(ov08d10->dev, NULL); + if (IS_ERR(ov08d10->clk)) + return dev_err_probe(ov08d10->dev, PTR_ERR(ov08d10->clk), + "failed to get clock\n"); + + freq = clk_get_rate(ov08d10->clk); + if (freq != OV08D10_XVCLK_19_2) + dev_warn(ov08d10->dev, + "external clock rate %lu is not supported\n", freq); + + ret = ov08d10_get_hwcfg(ov08d10); if (ret) { - dev_err(&client->dev, "failed to get HW configuration: %d", + dev_err(ov08d10->dev, "failed to get HW configuration: %d", ret); return ret; } @@ -1404,7 +1408,7 @@ static int ov08d10_probe(struct i2c_client *client) ret = ov08d10_identify_module(ov08d10); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov08d10->dev, "failed to find sensor: %d", ret); return ret; } @@ -1412,7 +1416,7 @@ static int ov08d10_probe(struct i2c_client *client) ov08d10->cur_mode = &ov08d10->priv_lane->sp_modes[0]; ret = ov08d10_init_controls(ov08d10); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov08d10->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1422,13 +1426,13 @@ static int ov08d10_probe(struct i2c_client *client) ov08d10->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov08d10->sd.entity, 1, &ov08d10->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov08d10->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&ov08d10->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov08d10->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } @@ -1437,9 +1441,9 @@ static int ov08d10_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov08d10->dev); + pm_runtime_enable(ov08d10->dev); + pm_runtime_idle(ov08d10->dev); return 0; diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c index e0094305ca2a..5eaf454f4763 100644 --- a/drivers/media/i2c/ov08x40.c +++ b/drivers/media/i2c/ov08x40.c @@ -1,15 +1,16 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2022 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> -#include <linux/i2c.h> +#include <linux/delay.h> #include <linux/gpio/consumer.h> +#include <linux/i2c.h> #include <linux/module.h> -#include <linux/delay.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-common.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> @@ -1305,6 +1306,8 @@ static const char * const ov08x40_supply_names[] = { }; struct ov08x40 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -1513,7 +1516,6 @@ static int ov08x40_write_reg(struct ov08x40 *ov08x, static int ov08x40_write_regs(struct ov08x40 *ov08x, const struct ov08x40_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); int ret; u32 i; @@ -1522,7 +1524,7 @@ static int ov08x40_write_regs(struct ov08x40 *ov08x, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov08x->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -1648,7 +1650,7 @@ static int ov08x40_set_ctrl_hflip(struct ov08x40 *ov08x, u32 ctrl_val) return ov08x40_write_reg(ov08x, OV08X40_REG_MIRROR, OV08X40_REG_VALUE_08BIT, - ctrl_val ? val | BIT(2) : val & ~BIT(2)); + ctrl_val ? val & ~BIT(2) : val | BIT(2)); } static int ov08x40_set_ctrl_vflip(struct ov08x40 *ov08x, u32 ctrl_val) @@ -1670,7 +1672,6 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov08x40 *ov08x = container_of(ctrl->handler, struct ov08x40, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); s64 max; int exp; int fll; @@ -1699,7 +1700,7 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov08x->dev)) return 0; switch (ctrl->id) { @@ -1737,13 +1738,13 @@ static int ov08x40_set_ctrl(struct v4l2_ctrl *ctrl) ov08x40_set_ctrl_vflip(ov08x, ctrl->val); break; default: - dev_info(&client->dev, + dev_info(ov08x->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov08x->dev); return ret; } @@ -1912,7 +1913,6 @@ ov08x40_set_pad_format(struct v4l2_subdev *sd, static int ov08x40_start_streaming(struct ov08x40 *ov08x) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); const struct ov08x40_reg_list *reg_list; int ret, link_freq_index; @@ -1920,7 +1920,7 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) ret = ov08x40_write_reg(ov08x, OV08X40_REG_SOFTWARE_RST, OV08X40_REG_VALUE_08BIT, OV08X40_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov08x->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -1930,14 +1930,14 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) ret = ov08x40_write_reg_list(ov08x, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov08x->dev, "%s failed to set plls\n", __func__); return ret; } reg_list = &ov08x40_global_setting; ret = ov08x40_write_reg_list(ov08x, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set global setting\n", + dev_err(ov08x->dev, "%s failed to set global setting\n", __func__); return ret; } @@ -1946,7 +1946,7 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) reg_list = &ov08x->cur_mode->reg_list; ret = ov08x40_write_reg_list(ov08x, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov08x->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1962,7 +1962,7 @@ static int ov08x40_start_streaming(struct ov08x40 *ov08x) } if (ret) { - dev_err(&client->dev, "%s failed to set regs\n", __func__); + dev_err(ov08x->dev, "%s failed to set regs\n", __func__); return ret; } @@ -1986,7 +1986,6 @@ static int ov08x40_stop_streaming(struct ov08x40 *ov08x) /* Verify chip ID */ static int ov08x40_identify_module(struct ov08x40 *ov08x) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); int ret; u32 val; @@ -1996,17 +1995,17 @@ static int ov08x40_identify_module(struct ov08x40 *ov08x) ret = ov08x40_read_reg(ov08x, OV08X40_REG_CHIP_ID, OV08X40_REG_VALUE_24BIT, &val); if (ret) { - dev_err(&client->dev, "error reading chip-id register: %d\n", ret); + dev_err(ov08x->dev, "error reading chip-id register: %d\n", ret); return ret; } if (val != OV08X40_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov08x->dev, "chip id mismatch: %x!=%x\n", OV08X40_CHIP_ID, val); return -ENXIO; } - dev_dbg(&client->dev, "chip id 0x%x\n", val); + dev_dbg(ov08x->dev, "chip id 0x%x\n", val); ov08x->identified = true; return 0; @@ -2015,13 +2014,12 @@ static int ov08x40_identify_module(struct ov08x40 *ov08x) static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) { struct ov08x40 *ov08x = to_ov08x40(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov08x->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov08x->dev); if (ret < 0) goto err_unlock; @@ -2038,7 +2036,7 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { ov08x40_stop_streaming(ov08x); - pm_runtime_put(&client->dev); + pm_runtime_put(ov08x->dev); } mutex_unlock(&ov08x->mutex); @@ -2046,7 +2044,7 @@ static int ov08x40_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov08x->dev); err_unlock: mutex_unlock(&ov08x->mutex); @@ -2079,7 +2077,6 @@ static const struct v4l2_subdev_internal_ops ov08x40_internal_ops = { static int ov08x40_init_controls(struct ov08x40 *ov08x) { - struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -2160,12 +2157,12 @@ static int ov08x40_init_controls(struct ov08x40 *ov08x) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(ov08x->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov08x->dev, &props); if (ret) goto error; @@ -2191,11 +2188,12 @@ static void ov08x40_free_controls(struct ov08x40 *ov08x) mutex_destroy(&ov08x->mutex); } -static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) +static int ov08x40_check_hwcfg(struct ov08x40 *ov08x) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov08x->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned int i; @@ -2232,23 +2230,14 @@ static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev) if (ret) goto out_err; - ov08x->xvclk = devm_clk_get_optional(dev, NULL); + ov08x->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov08x->xvclk)) { ret = dev_err_probe(dev, PTR_ERR(ov08x->xvclk), "getting xvclk\n"); goto out_err; } - if (ov08x->xvclk) { - xvclk_rate = clk_get_rate(ov08x->xvclk); - } else { - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &xvclk_rate); - if (ret) { - dev_err(dev, "can't get clock frequency\n"); - goto out_err; - } - } + xvclk_rate = clk_get_rate(ov08x->xvclk); if (xvclk_rate != OV08X40_XVCLK) { dev_err(dev, "external clock %d is not supported\n", xvclk_rate); @@ -2294,19 +2283,21 @@ static int ov08x40_probe(struct i2c_client *client) if (!ov08x) return -ENOMEM; + ov08x->dev = &client->dev; + /* Check HW config */ - ret = ov08x40_check_hwcfg(ov08x, &client->dev); + ret = ov08x40_check_hwcfg(ov08x); if (ret) return ret; /* Initialize subdev */ v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov08x->dev); if (full_power) { - ret = ov08x40_power_on(&client->dev); + ret = ov08x40_power_on(ov08x->dev); if (ret) { - dev_err(&client->dev, "failed to power on\n"); + dev_err(ov08x->dev, "failed to power on\n"); return ret; } @@ -2333,7 +2324,7 @@ static int ov08x40_probe(struct i2c_client *client) ov08x->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov08x->sd.entity, 1, &ov08x->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov08x->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -2342,9 +2333,9 @@ static int ov08x40_probe(struct i2c_client *client) goto error_media_entity; if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov08x->dev); + pm_runtime_enable(ov08x->dev); + pm_runtime_idle(ov08x->dev); return 0; @@ -2355,7 +2346,7 @@ error_handler_free: ov08x40_free_controls(ov08x); probe_power_off: - ov08x40_power_off(&client->dev); + ov08x40_power_off(ov08x->dev); return ret; } @@ -2369,10 +2360,10 @@ static void ov08x40_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov08x40_free_controls(ov08x); - pm_runtime_disable(&client->dev); - if (!pm_runtime_status_suspended(&client->dev)) - ov08x40_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov08x->dev); + if (!pm_runtime_status_suspended(ov08x->dev)) + ov08x40_power_off(ov08x->dev); + pm_runtime_set_suspended(ov08x->dev); } static DEFINE_RUNTIME_DEV_PM_OPS(ov08x40_pm_ops, ov08x40_power_off, diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c index 7a3fc1d28514..162b49046990 100644 --- a/drivers/media/i2c/ov13858.c +++ b/drivers/media/i2c/ov13858.c @@ -2,6 +2,7 @@ // Copyright (c) 2017 Intel Corporation. #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> @@ -1028,6 +1029,9 @@ static const struct ov13858_mode supported_modes[] = { }; struct ov13858 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -1117,7 +1121,6 @@ static int ov13858_write_reg(struct ov13858 *ov13858, u16 reg, u32 len, static int ov13858_write_regs(struct ov13858 *ov13858, const struct ov13858_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); int ret; u32 i; @@ -1126,7 +1129,7 @@ static int ov13858_write_regs(struct ov13858 *ov13858, regs[i].val); if (ret) { dev_err_ratelimited( - &client->dev, + ov13858->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -1209,7 +1212,6 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov13858 *ov13858 = container_of(ctrl->handler, struct ov13858, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); s64 max; int ret; @@ -1228,7 +1230,7 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov13858->dev)) return 0; ret = 0; @@ -1256,13 +1258,13 @@ static int ov13858_set_ctrl(struct v4l2_ctrl *ctrl) ret = ov13858_enable_test_pattern(ov13858, ctrl->val); break; default: - dev_info(&client->dev, + dev_info(ov13858->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov13858->dev); return ret; } @@ -1408,7 +1410,6 @@ static int ov13858_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) /* Start streaming */ static int ov13858_start_streaming(struct ov13858 *ov13858) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); const struct ov13858_reg_list *reg_list; int ret, link_freq_index; @@ -1416,7 +1417,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) ret = ov13858_write_reg(ov13858, OV13858_REG_SOFTWARE_RST, OV13858_REG_VALUE_08BIT, OV13858_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov13858->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -1426,7 +1427,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov13858_write_reg_list(ov13858, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov13858->dev, "%s failed to set plls\n", __func__); return ret; } @@ -1434,7 +1435,7 @@ static int ov13858_start_streaming(struct ov13858 *ov13858) reg_list = &ov13858->cur_mode->reg_list; ret = ov13858_write_reg_list(ov13858, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov13858->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1458,13 +1459,12 @@ static int ov13858_stop_streaming(struct ov13858 *ov13858) static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) { struct ov13858 *ov13858 = to_ov13858(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov13858->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov13858->dev); if (ret < 0) goto err_unlock; @@ -1477,7 +1477,7 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { ov13858_stop_streaming(ov13858); - pm_runtime_put(&client->dev); + pm_runtime_put(ov13858->dev); } mutex_unlock(&ov13858->mutex); @@ -1485,7 +1485,7 @@ static int ov13858_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov13858->dev); err_unlock: mutex_unlock(&ov13858->mutex); @@ -1495,7 +1495,6 @@ err_unlock: /* Verify chip ID */ static int ov13858_identify_module(struct ov13858 *ov13858) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); int ret; u32 val; @@ -1505,7 +1504,7 @@ static int ov13858_identify_module(struct ov13858 *ov13858) return ret; if (val != OV13858_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov13858->dev, "chip id mismatch: %x!=%x\n", OV13858_CHIP_ID, val); return -EIO; } @@ -1552,7 +1551,6 @@ static const struct v4l2_subdev_internal_ops ov13858_internal_ops = { /* Initialize control handlers */ static int ov13858_init_controls(struct ov13858 *ov13858) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13858->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -1626,12 +1624,12 @@ static int ov13858_init_controls(struct ov13858 *ov13858) 0, 0, ov13858_test_pattern_menu); if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(ov13858->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov13858->dev, &props); if (ret) goto error; @@ -1660,24 +1658,33 @@ static void ov13858_free_controls(struct ov13858 *ov13858) static int ov13858_probe(struct i2c_client *client) { struct ov13858 *ov13858; + unsigned long freq; int ret; - u32 val = 0; - - device_property_read_u32(&client->dev, "clock-frequency", &val); - if (val != 19200000) - return -EINVAL; ov13858 = devm_kzalloc(&client->dev, sizeof(*ov13858), GFP_KERNEL); if (!ov13858) return -ENOMEM; + ov13858->dev = &client->dev; + + ov13858->clk = devm_v4l2_sensor_clk_get(ov13858->dev, NULL); + if (IS_ERR(ov13858->clk)) + return dev_err_probe(ov13858->dev, PTR_ERR(ov13858->clk), + "failed to get clock\n"); + + freq = clk_get_rate(ov13858->clk); + if (freq != 19200000) + return dev_err_probe(ov13858->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + /* Initialize subdev */ v4l2_i2c_subdev_init(&ov13858->sd, client, &ov13858_subdev_ops); /* Check module identity */ ret = ov13858_identify_module(ov13858); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(ov13858->dev, "failed to find sensor: %d\n", ret); return ret; } @@ -1699,7 +1706,7 @@ static int ov13858_probe(struct i2c_client *client) ov13858->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov13858->sd.entity, 1, &ov13858->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -1711,9 +1718,9 @@ static int ov13858_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov13858->dev); + pm_runtime_enable(ov13858->dev); + pm_runtime_idle(ov13858->dev); return 0; @@ -1722,7 +1729,7 @@ error_media_entity: error_handler_free: ov13858_free_controls(ov13858); - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13858->dev, "%s failed:%d\n", __func__, ret); return ret; } @@ -1736,7 +1743,7 @@ static void ov13858_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov13858_free_controls(ov13858); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov13858->dev); } static const struct i2c_device_id ov13858_id_table[] = { diff --git a/drivers/media/i2c/ov13b10.c b/drivers/media/i2c/ov13b10.c index e85c7d33a670..869bc78ed792 100644 --- a/drivers/media/i2c/ov13b10.c +++ b/drivers/media/i2c/ov13b10.c @@ -700,6 +700,8 @@ static const struct ov13b10_mode supported_2_lanes_modes[] = { }; struct ov13b10 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -805,7 +807,6 @@ static int ov13b10_write_reg(struct ov13b10 *ov13b, static int ov13b10_write_regs(struct ov13b10 *ov13b, const struct ov13b10_reg *regs, u32 len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); int ret; u32 i; @@ -813,7 +814,7 @@ static int ov13b10_write_regs(struct ov13b10 *ov13b, ret = ov13b10_write_reg(ov13b, regs[i].address, 1, regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov13b->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -968,7 +969,6 @@ static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov13b10 *ov13b = container_of(ctrl->handler, struct ov13b10, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); s64 max; int ret; @@ -987,7 +987,7 @@ static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) * Applying V4L2 control value only happens * when power is up for streaming */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov13b->dev)) return 0; ret = 0; @@ -1021,13 +1021,13 @@ static int ov13b10_set_ctrl(struct v4l2_ctrl *ctrl) ov13b10_set_ctrl_vflip(ov13b, ctrl->val); break; default: - dev_info(&client->dev, + dev_info(ov13b->dev, "ctrl(id:0x%x,val:0x%x) is not handled\n", ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov13b->dev); return ret; } @@ -1166,7 +1166,6 @@ ov13b10_set_pad_format(struct v4l2_subdev *sd, /* Verify chip ID */ static int ov13b10_identify_module(struct ov13b10 *ov13b) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); int ret; u32 val; @@ -1179,7 +1178,7 @@ static int ov13b10_identify_module(struct ov13b10 *ov13b) return ret; if (val != OV13B10_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov13b->dev, "chip id mismatch: %x!=%x\n", OV13B10_CHIP_ID, val); return -EIO; } @@ -1234,7 +1233,6 @@ static int ov13b10_power_on(struct device *dev) static int ov13b10_start_streaming(struct ov13b10 *ov13b) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); const struct ov13b10_reg_list *reg_list; int ret, link_freq_index; @@ -1246,7 +1244,7 @@ static int ov13b10_start_streaming(struct ov13b10 *ov13b) ret = ov13b10_write_reg(ov13b, OV13B10_REG_SOFTWARE_RST, OV13B10_REG_VALUE_08BIT, OV13B10_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov13b->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -1255,7 +1253,7 @@ static int ov13b10_start_streaming(struct ov13b10 *ov13b) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov13b10_write_reg_list(ov13b, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov13b->dev, "%s failed to set plls\n", __func__); return ret; } @@ -1263,7 +1261,7 @@ static int ov13b10_start_streaming(struct ov13b10 *ov13b) reg_list = &ov13b->cur_mode->reg_list; ret = ov13b10_write_reg_list(ov13b, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov13b->dev, "%s failed to set mode\n", __func__); return ret; } @@ -1287,13 +1285,12 @@ static int ov13b10_stop_streaming(struct ov13b10 *ov13b) static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) { struct ov13b10 *ov13b = to_ov13b10(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov13b->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov13b->dev); if (ret < 0) goto err_unlock; @@ -1306,7 +1303,7 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) goto err_rpm_put; } else { ov13b10_stop_streaming(ov13b); - pm_runtime_put(&client->dev); + pm_runtime_put(ov13b->dev); } mutex_unlock(&ov13b->mutex); @@ -1314,7 +1311,7 @@ static int ov13b10_set_stream(struct v4l2_subdev *sd, int enable) return ret; err_rpm_put: - pm_runtime_put(&client->dev); + pm_runtime_put(ov13b->dev); err_unlock: mutex_unlock(&ov13b->mutex); @@ -1360,7 +1357,6 @@ static const struct v4l2_subdev_internal_ops ov13b10_internal_ops = { /* Initialize control handlers */ static int ov13b10_init_controls(struct ov13b10 *ov13b) { - struct i2c_client *client = v4l2_get_subdevdata(&ov13b->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max; @@ -1443,12 +1439,12 @@ static int ov13b10_init_controls(struct ov13b10 *ov13b) if (ctrl_hdlr->error) { ret = ctrl_hdlr->error; - dev_err(&client->dev, "%s control init failed (%d)\n", + dev_err(ov13b->dev, "%s control init failed (%d)\n", __func__, ret); goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov13b->dev, &props); if (ret) goto error; @@ -1474,44 +1470,49 @@ static void ov13b10_free_controls(struct ov13b10 *ov13b) mutex_destroy(&ov13b->mutex); } -static int ov13b10_get_pm_resources(struct device *dev) +static int ov13b10_get_pm_resources(struct ov13b10 *ov13b) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov13b10 *ov13b = to_ov13b10(sd); + unsigned long freq; int ret; - ov13b->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); + ov13b->reset = devm_gpiod_get_optional(ov13b->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov13b->reset)) - return dev_err_probe(dev, PTR_ERR(ov13b->reset), + return dev_err_probe(ov13b->dev, PTR_ERR(ov13b->reset), "failed to get reset gpio\n"); - ov13b->img_clk = devm_clk_get_optional(dev, NULL); + ov13b->img_clk = devm_v4l2_sensor_clk_get(ov13b->dev, NULL); if (IS_ERR(ov13b->img_clk)) - return dev_err_probe(dev, PTR_ERR(ov13b->img_clk), + return dev_err_probe(ov13b->dev, PTR_ERR(ov13b->img_clk), "failed to get imaging clock\n"); - ov13b->avdd = devm_regulator_get_optional(dev, "avdd"); + freq = clk_get_rate(ov13b->img_clk); + if (freq != OV13B10_EXT_CLK) + return dev_err_probe(ov13b->dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + + ov13b->avdd = devm_regulator_get_optional(ov13b->dev, "avdd"); if (IS_ERR(ov13b->avdd)) { ret = PTR_ERR(ov13b->avdd); ov13b->avdd = NULL; if (ret != -ENODEV) - return dev_err_probe(dev, ret, + return dev_err_probe(ov13b->dev, ret, "failed to get avdd regulator\n"); } return 0; } -static int ov13b10_check_hwcfg(struct device *dev, struct ov13b10 *ov13b) +static int ov13b10_check_hwcfg(struct ov13b10 *ov13b) { struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct device *dev = ov13b->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); unsigned int i, j; int ret; - u32 ext_clk; u8 dlane; if (!fwnode) @@ -1521,19 +1522,6 @@ static int ov13b10_check_hwcfg(struct device *dev, struct ov13b10 *ov13b) if (!ep) return -EPROBE_DEFER; - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &ext_clk); - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - - if (ext_clk != OV13B10_EXT_CLK) { - dev_err(dev, "external clock %d is not supported", - ext_clk); - return -EINVAL; - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -1602,32 +1590,34 @@ static int ov13b10_probe(struct i2c_client *client) if (!ov13b) return -ENOMEM; + ov13b->dev = &client->dev; + /* Check HW config */ - ret = ov13b10_check_hwcfg(&client->dev, ov13b); + ret = ov13b10_check_hwcfg(ov13b); if (ret) { - dev_err(&client->dev, "failed to check hwcfg: %d", ret); + dev_err(ov13b->dev, "failed to check hwcfg: %d", ret); return ret; } /* Initialize subdev */ v4l2_i2c_subdev_init(&ov13b->sd, client, &ov13b10_subdev_ops); - ret = ov13b10_get_pm_resources(&client->dev); + ret = ov13b10_get_pm_resources(ov13b); if (ret) return ret; - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov13b->dev); if (full_power) { - ret = ov13b10_power_on(&client->dev); + ret = ov13b10_power_on(ov13b->dev); if (ret) { - dev_err(&client->dev, "failed to power on\n"); + dev_err(ov13b->dev, "failed to power on\n"); return ret; } /* Check module identity */ ret = ov13b10_identify_module(ov13b); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d\n", ret); + dev_err(ov13b->dev, "failed to find sensor: %d\n", ret); goto error_power_off; } } @@ -1646,7 +1636,7 @@ static int ov13b10_probe(struct i2c_client *client) ov13b->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov13b->sd.entity, 1, &ov13b->pad); if (ret) { - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13b->dev, "%s failed:%d\n", __func__, ret); goto error_handler_free; } @@ -1657,9 +1647,9 @@ static int ov13b10_probe(struct i2c_client *client) */ /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov13b->dev); + pm_runtime_enable(ov13b->dev); + pm_runtime_idle(ov13b->dev); ret = v4l2_async_register_subdev_sensor(&ov13b->sd); if (ret < 0) @@ -1668,17 +1658,17 @@ static int ov13b10_probe(struct i2c_client *client) return 0; error_media_entity_runtime_pm: - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov13b->dev); if (full_power) - pm_runtime_set_suspended(&client->dev); + pm_runtime_set_suspended(ov13b->dev); media_entity_cleanup(&ov13b->sd.entity); error_handler_free: ov13b10_free_controls(ov13b); - dev_err(&client->dev, "%s failed:%d\n", __func__, ret); + dev_err(ov13b->dev, "%s failed:%d\n", __func__, ret); error_power_off: - ov13b10_power_off(&client->dev); + ov13b10_power_off(ov13b->dev); return ret; } @@ -1692,8 +1682,8 @@ static void ov13b10_remove(struct i2c_client *client) media_entity_cleanup(&sd->entity); ov13b10_free_controls(ov13b); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov13b->dev); + pm_runtime_set_suspended(ov13b->dev); } static DEFINE_RUNTIME_DEV_PM_OPS(ov13b10_pm_ops, ov13b10_suspend, diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 586b31ba076b..061401b020fc 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1437,9 +1437,10 @@ static int ov2659_probe(struct i2c_client *client) ov2659->pdata = pdata; ov2659->client = client; - ov2659->clk = devm_clk_get(&client->dev, "xvclk"); + ov2659->clk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); if (IS_ERR(ov2659->clk)) - return PTR_ERR(ov2659->clk); + return dev_err_probe(&client->dev, PTR_ERR(ov2659->clk), + "failed to get xvclk\n"); ov2659->xvclk_frequency = clk_get_rate(ov2659->clk); if (ov2659->xvclk_frequency < 6000000 || diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c index 7237fb27ecd0..78e63bd1b35b 100644 --- a/drivers/media/i2c/ov2680.c +++ b/drivers/media/i2c/ov2680.c @@ -1079,7 +1079,6 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) struct device *dev = sensor->dev; struct fwnode_handle *ep_fwnode; struct gpio_desc *gpio; - unsigned int rate = 0; int i, ret; /* @@ -1114,38 +1113,14 @@ static int ov2680_parse_dt(struct ov2680_dev *sensor) sensor->pwdn_gpio = gpio; - sensor->xvclk = devm_clk_get_optional(dev, "xvclk"); + sensor->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); if (IS_ERR(sensor->xvclk)) { ret = dev_err_probe(dev, PTR_ERR(sensor->xvclk), "xvclk clock missing or invalid\n"); goto out_free_bus_cfg; } - /* - * We could have either a 24MHz or 19.2MHz clock rate from either DT or - * ACPI... but we also need to support the weird IPU3 case which will - * have an external clock AND a clock-frequency property. Check for the - * clock-frequency property and if found, set that rate if we managed - * to acquire a clock. This should cover the ACPI case. If the system - * uses devicetree then the configured rate should already be set, so - * we can just read it. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (ret && !sensor->xvclk) { - dev_err_probe(dev, ret, "invalid clock config\n"); - goto out_free_bus_cfg; - } - - if (!ret && sensor->xvclk) { - ret = clk_set_rate(sensor->xvclk, rate); - if (ret) { - dev_err_probe(dev, ret, "failed to set clock rate\n"); - goto out_free_bus_cfg; - } - } - - sensor->xvclk_freq = rate ?: clk_get_rate(sensor->xvclk); + sensor->xvclk_freq = clk_get_rate(sensor->xvclk); for (i = 0; i < ARRAY_SIZE(ov2680_xvclk_freqs); i++) { if (sensor->xvclk_freq == ov2680_xvclk_freqs[i]) diff --git a/drivers/media/i2c/ov2685.c b/drivers/media/i2c/ov2685.c index 9b8481b8dcd4..4911a4eea126 100644 --- a/drivers/media/i2c/ov2685.c +++ b/drivers/media/i2c/ov2685.c @@ -783,16 +783,12 @@ static int ov2685_probe(struct i2c_client *client) ov2685->client = client; ov2685->cur_mode = &supported_modes[0]; - ov2685->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov2685->xvclk)) { - dev_err(dev, "Failed to get xvclk\n"); - return -EINVAL; - } - ret = clk_set_rate(ov2685->xvclk, OV2685_XVCLK_FREQ); - if (ret < 0) { - dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); - return ret; - } + ov2685->xvclk = devm_v4l2_sensor_clk_get_legacy(dev, "xvclk", true, + OV2685_XVCLK_FREQ); + if (IS_ERR(ov2685->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov2685->xvclk), + "Failed to get xvclk\n"); + if (clk_get_rate(ov2685->xvclk) != OV2685_XVCLK_FREQ) dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); diff --git a/drivers/media/i2c/ov2735.c b/drivers/media/i2c/ov2735.c new file mode 100644 index 000000000000..b96600204141 --- /dev/null +++ b/drivers/media/i2c/ov2735.c @@ -0,0 +1,1109 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 Support for the OV2735 + * + * Copyright (C) 2025 Silicon Signals Pvt. Ltd. + * + * Based on Rockchip ov2735 Camera Driver + * Copyright (C) 2017 Fuzhou Rockchip Electronics Co., Ltd. + * + * Inspired from ov8858, imx219, imx283 camera drivers. + */ + +#include <linux/array_size.h> +#include <linux/bitops.h> +#include <linux/cleanup.h> +#include <linux/clk.h> +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/device/devres.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> +#include <linux/types.h> +#include <linux/time.h> + +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-mediabus.h> + +#define OV2735_XCLK_FREQ (24 * HZ_PER_MHZ) + +/* Add page number in CCI private bits [31:28] of the register address */ +#define OV2735_PAGE_REG8(p, x) (((p) << CCI_REG_PRIVATE_SHIFT) | CCI_REG8(x)) +#define OV2735_PAGE_REG16(p, x) (((p) << CCI_REG_PRIVATE_SHIFT) | CCI_REG16(x)) + +#define OV2735_REG_PAGE_SELECT CCI_REG8(0xfd) + +/* Page 0 */ +#define OV2735_REG_CHIPID OV2735_PAGE_REG16(0x00, 0x02) +#define OV2735_CHIPID 0x2735 + +#define OV2735_REG_SOFT_RESET OV2735_PAGE_REG8(0x00, 0x20) + +/* Clock Settings */ +#define OV2735_REG_PLL_CTRL OV2735_PAGE_REG8(0x00, 0x2f) +#define OV2735_PLL_CTRL_ENABLE 0x7f +#define OV2735_REG_PLL_OUTDIV OV2735_PAGE_REG8(0x00, 0x34) +#define OV2735_REG_CLK_MODE OV2735_PAGE_REG8(0x00, 0x30) +#define OV2735_REG_CLOCK_REG1 OV2735_PAGE_REG8(0x00, 0x33) +#define OV2735_REG_CLOCK_REG2 OV2735_PAGE_REG8(0x00, 0x35) + +/* Page 1 */ +#define OV2735_REG_STREAM_CTRL OV2735_PAGE_REG8(0x01, 0xa0) +#define OV2735_STREAM_CTRL_ON 0x01 +#define OV2735_STREAM_CTRL_OFF 0x00 + +#define OV2735_REG_UPDOWN_MIRROR OV2735_PAGE_REG8(0x01, 0x3f) +#define OV2735_REG_BINNING_DAC_CODE_MODE OV2735_PAGE_REG8(0x01, 0x30) +#define OV2735_REG_FRAME_LENGTH OV2735_PAGE_REG16(0x01, 0x0e) +#define OV2735_FRAME_LENGTH_MAX 0x0fff +#define OV2735_REG_FRAME_EXP_SEPERATE_EN OV2735_PAGE_REG8(0x01, 0x0d) +#define OV2735_FRAME_EXP_SEPERATE_EN 0x10 +#define OV2735_REG_FRAME_SYNC OV2735_PAGE_REG8(0x01, 0x01) + +#define OV2735_REG_HBLANK OV2735_PAGE_REG16(0x01, 0x09) + +#define OV2735_REG_HS_MIPI OV2735_PAGE_REG8(0x01, 0xb1) +#define OV2735_REG_MIPI_CTRL1 OV2735_PAGE_REG8(0x01, 0x92) +#define OV2735_REG_MIPI_CTRL2 OV2735_PAGE_REG8(0x01, 0x94) +#define OV2735_REG_MIPI_CTRL3 OV2735_PAGE_REG8(0x01, 0xa1) +#define OV2735_REG_MIPI_CTRL4 OV2735_PAGE_REG8(0x01, 0xb2) +#define OV2735_REG_MIPI_CTRL5 OV2735_PAGE_REG8(0x01, 0xb3) +#define OV2735_REG_MIPI_CTRL6 OV2735_PAGE_REG8(0x01, 0xb4) +#define OV2735_REG_MIPI_CTRL7 OV2735_PAGE_REG8(0x01, 0xb5) +#define OV2735_REG_HIGH_SPEED OV2735_PAGE_REG8(0x01, 0x9d) +#define OV2735_REG_PREPARE OV2735_PAGE_REG8(0x01, 0x95) +#define OV2735_REG_R_HS_ZERO OV2735_PAGE_REG8(0x01, 0x96) +#define OV2735_REG_TRAIL OV2735_PAGE_REG8(0x01, 0x98) +#define OV2735_REG_R_CLK_ZERO OV2735_PAGE_REG8(0x01, 0x9c) +#define OV2735_REG_MIPI_COLOMN_NUMBER OV2735_PAGE_REG16(0x01, 0x8e) +#define OV2735_REG_MIPI_LINE_NUMBER OV2735_PAGE_REG16(0x01, 0x90) + +/* Timing control registers */ +#define OV2735_REG_TIMING_CTRL2 OV2735_PAGE_REG8(0x01, 0x1a) +#define OV2735_REG_TIMING_CTRL3 OV2735_PAGE_REG8(0x01, 0x1c) +#define OV2735_REG_TIMING_CTRL1 OV2735_PAGE_REG8(0x01, 0x16) +#define OV2735_REG_RST_NUM OV2735_PAGE_REG16(0x01, 0x10) +#define OV2735_REG_RST_NUM2 OV2735_PAGE_REG16(0x01, 0x32) +#define OV2735_REG_BOOST_EN OV2735_PAGE_REG8(0x01, 0xd0) +#define OV2735_REG_B2_NUM OV2735_PAGE_REG16(0x01, 0xd1) +#define OV2735_REG_B4_NUM OV2735_PAGE_REG16(0x01, 0xd3) +#define OV2735_REG_PIXEL_CYCLE_P0 OV2735_PAGE_REG8(0x01, 0x50) +#define OV2735_REG_PIXEL_CYCLE_P1 OV2735_PAGE_REG8(0x01, 0x51) +#define OV2735_REG_PIXEL_CYCLE_P2 OV2735_PAGE_REG8(0x01, 0x52) +#define OV2735_REG_PIXEL_CYCLE_P3 OV2735_PAGE_REG8(0x01, 0x53) +#define OV2735_REG_PIXEL_CYCLE_P5 OV2735_PAGE_REG8(0x01, 0x55) +#define OV2735_REG_PIXEL_CYCLE_P7 OV2735_PAGE_REG16(0x01, 0x57) +#define OV2735_REG_PIXEL_CYCLE_P9 OV2735_PAGE_REG8(0x01, 0x5a) +#define OV2735_REG_PIXEL_CYCLE_P10 OV2735_PAGE_REG8(0x01, 0x5b) +#define OV2735_REG_PIXEL_CYCLE_P12 OV2735_PAGE_REG8(0x01, 0x5d) +#define OV2735_REG_PIXEL_CYCLE_P18 OV2735_PAGE_REG8(0x01, 0x64) +#define OV2735_REG_PIXEL_CYCLE_P20 OV2735_PAGE_REG8(0x01, 0x66) +#define OV2735_REG_PIXEL_CYCLE_P22 OV2735_PAGE_REG8(0x01, 0x68) +#define OV2735_REG_PIXEL_CYCLE_P33 OV2735_PAGE_REG16(0x01, 0x74) +#define OV2735_REG_PIXEL_CYCLE_P34 OV2735_PAGE_REG8(0x01, 0x76) +#define OV2735_REG_PIXEL_CYCLE_P35_P36 OV2735_PAGE_REG8(0x01, 0x77) +#define OV2735_REG_PIXEL_CYCLE_P37_P38 OV2735_PAGE_REG8(0x01, 0x78) +#define OV2735_REG_PIXEL_CYCLE_P31 OV2735_PAGE_REG8(0x01, 0x72) +#define OV2735_REG_PIXEL_CYCLE_P32 OV2735_PAGE_REG8(0x01, 0x73) +#define OV2735_REG_PIXEL_CYCLE_P44 OV2735_PAGE_REG8(0x01, 0x7d) +#define OV2735_REG_PIXEL_CYCLE_P45 OV2735_PAGE_REG8(0x01, 0x7e) +#define OV2735_REG_PIXEL_BIAS_CTRL_RH_RL OV2735_PAGE_REG8(0x01, 0x8a) +#define OV2735_REG_PIXEL_BIAS_CTRL_SH_SL OV2735_PAGE_REG8(0x01, 0x8b) + +/* Analog Control registers */ +#define OV2735_REG_ICOMP OV2735_PAGE_REG8(0x01, 0x19) +#define OV2735_REG_PCP_RST_SEL OV2735_PAGE_REG8(0x01, 0x21) +#define OV2735_REG_VNCP OV2735_PAGE_REG8(0x01, 0x20) +#define OV2735_REG_ANALOG_CTRL3 OV2735_PAGE_REG8(0x01, 0x25) +#define OV2735_REG_ANALOG_CTRL4 OV2735_PAGE_REG8(0x01, 0x26) +#define OV2735_REG_ANALOG_CTRL5 OV2735_PAGE_REG8(0x01, 0x29) +#define OV2735_REG_ANALOG_CTRL6 OV2735_PAGE_REG8(0x01, 0x2a) +#define OV2735_REG_ANALOG_CTRL8 OV2735_PAGE_REG8(0x01, 0x2c) + +/* BLC registers */ +#define OV2735_REG_BLC_GAIN_BLUE OV2735_PAGE_REG8(0x01, 0x86) +#define OV2735_REG_BLC_GAIN_RED OV2735_PAGE_REG8(0x01, 0x87) +#define OV2735_REG_BLC_GAIN_GR OV2735_PAGE_REG8(0x01, 0x88) +#define OV2735_REG_BLC_GAIN_GB OV2735_PAGE_REG8(0x01, 0x89) +#define OV2735_REG_GB_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf0) +#define OV2735_REG_BLUE_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf1) +#define OV2735_REG_RED_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf2) +#define OV2735_REG_GR_SUBOFFSET OV2735_PAGE_REG8(0x01, 0xf3) +#define OV2735_REG_BLC_BPC_TH_P OV2735_PAGE_REG8(0x01, 0xfc) +#define OV2735_REG_BLC_BPC_TH_N OV2735_PAGE_REG8(0x01, 0xfe) +#define OV2735_REG_ABL OV2735_PAGE_REG8(0x01, 0xfb) + +#define OV2735_REG_TEST_PATTERN OV2735_PAGE_REG8(0x01, 0xb2) +#define OV2735_TEST_PATTERN_ENABLE 0x01 +#define OV2735_TEST_PATTERN_DISABLE 0xfe + +#define OV2735_REG_LONG_EXPOSURE OV2735_PAGE_REG16(0x01, 0x03) +#define OV2735_EXPOSURE_MIN 4 +#define OV2735_EXPOSURE_STEP 1 +#define OV2735_EXPOSURE_MARGIN 4 + +#define OV2735_REG_ANALOG_GAIN OV2735_PAGE_REG8(0x01, 0x24) +#define OV2735_ANALOG_GAIN_MIN 0x10 +#define OV2735_ANALOG_GAIN_MAX 0xff +#define OV2735_ANALOG_GAIN_STEP 1 +#define OV2735_ANALOG_GAIN_DEFAULT 0x10 + +/* Page 2 */ +#define OV2735_REG_V_START OV2735_PAGE_REG16(0x02, 0xa0) +#define OV2735_REG_V_SIZE OV2735_PAGE_REG16(0x02, 0xa2) +#define OV2735_REG_H_START OV2735_PAGE_REG16(0x02, 0xa4) +#define OV2735_REG_H_SIZE OV2735_PAGE_REG16(0x02, 0xa6) + +#define OV2735_LINK_FREQ_420MHZ (420 * HZ_PER_MHZ) +#define OV2735_PIXEL_RATE (168 * HZ_PER_MHZ) + +/* OV2735 native and active pixel array size */ +static const struct v4l2_rect ov2735_native_area = { + .top = 0, + .left = 0, + .width = 1936, + .height = 1096, +}; + +static const struct v4l2_rect ov2735_active_area = { + .top = 8, + .left = 8, + .width = 1920, + .height = 1080, +}; + +static const char * const ov2735_supply_name[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +/* PLL_OUT = [PLL_IN * (pll_nc +3)] / [(pll_mc + 1) * (pll_outdiv + 1)] */ +struct ov2735_pll_parameters { + u8 pll_nc; + u8 pll_mc; + u8 pll_outdiv; +}; + +struct ov2735 { + struct device *dev; + struct regmap *cci; + struct v4l2_subdev sd; + struct media_pad pad; + struct clk *xclk; + struct gpio_desc *reset_gpio; + struct gpio_desc *enable_gpio; + struct regulator_bulk_data supplies[ARRAY_SIZE(ov2735_supply_name)]; + + /* V4L2 Controls */ + struct v4l2_ctrl_handler handler; + struct v4l2_ctrl *link_freq; + struct v4l2_ctrl *pixel_rate; + struct v4l2_ctrl *hblank; + struct v4l2_ctrl *vblank; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *test_pattern; + + u32 link_freq_index; + + u8 current_page; + struct mutex page_lock; +}; + +struct ov2735_mode { + u32 width; + u32 height; + u32 hts_def; + u32 vts_def; + u32 exp_def; + struct v4l2_rect crop; +}; + +static const struct cci_reg_sequence ov2735_common_regs[] = { + { OV2735_REG_CLK_MODE, 0x15 }, + { OV2735_REG_CLOCK_REG1, 0x01 }, + { OV2735_REG_CLOCK_REG2, 0x20 }, + { OV2735_REG_BINNING_DAC_CODE_MODE, 0x00 }, + { OV2735_REG_ABL, 0x73 }, + { OV2735_REG_FRAME_SYNC, 0x01 }, + + /* Timing ctrl */ + { OV2735_REG_TIMING_CTRL2, 0x6b }, + { OV2735_REG_TIMING_CTRL3, 0xea }, + { OV2735_REG_TIMING_CTRL1, 0x0c }, + { OV2735_REG_RST_NUM, 0x0063 }, + { OV2735_REG_RST_NUM2, 0x006f }, + { OV2735_REG_BOOST_EN, 0x02 }, + { OV2735_REG_B2_NUM, 0x0120 }, + { OV2735_REG_B4_NUM, 0x042a }, + { OV2735_REG_PIXEL_CYCLE_P0, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P1, 0x2c }, + { OV2735_REG_PIXEL_CYCLE_P2, 0x29 }, + { OV2735_REG_PIXEL_CYCLE_P3, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P5, 0x44 }, + { OV2735_REG_PIXEL_CYCLE_P7, 0x0029 }, + { OV2735_REG_PIXEL_CYCLE_P9, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P10, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P12, 0x00 }, + { OV2735_REG_PIXEL_CYCLE_P18, 0x2f }, + { OV2735_REG_PIXEL_CYCLE_P20, 0x62 }, + { OV2735_REG_PIXEL_CYCLE_P22, 0x5b }, + { OV2735_REG_PIXEL_CYCLE_P33, 0x0046 }, + { OV2735_REG_PIXEL_CYCLE_P34, 0x36 }, + { OV2735_REG_PIXEL_CYCLE_P35_P36, 0x4f }, + { OV2735_REG_PIXEL_CYCLE_P37_P38, 0xef }, + { OV2735_REG_PIXEL_CYCLE_P31, 0xcf }, + { OV2735_REG_PIXEL_CYCLE_P32, 0x36 }, + { OV2735_REG_PIXEL_CYCLE_P44, 0x0d }, + { OV2735_REG_PIXEL_CYCLE_P45, 0x0d }, + { OV2735_REG_PIXEL_BIAS_CTRL_RH_RL, 0x77 }, + { OV2735_REG_PIXEL_BIAS_CTRL_SH_SL, 0x77 }, + + /* Analog ctrl */ + { OV2735_REG_ANALOG_CTRL4, 0x5a }, + { OV2735_REG_ANALOG_CTRL5, 0x01 }, + { OV2735_REG_ANALOG_CTRL6, 0xd2 }, + { OV2735_REG_ANALOG_CTRL8, 0x40 }, + { OV2735_REG_PCP_RST_SEL, 0x00 }, + { OV2735_REG_ICOMP, 0xc3 }, + + { OV2735_REG_HS_MIPI, 0x83 }, + { OV2735_REG_MIPI_CTRL5, 0x0b }, + { OV2735_REG_MIPI_CTRL6, 0x14 }, + { OV2735_REG_HIGH_SPEED, 0x40 }, + { OV2735_REG_MIPI_CTRL3, 0x05 }, + { OV2735_REG_MIPI_CTRL2, 0x44 }, + { OV2735_REG_PREPARE, 0x33 }, + { OV2735_REG_R_HS_ZERO, 0x1f }, + { OV2735_REG_TRAIL, 0x45 }, + { OV2735_REG_R_CLK_ZERO, 0x10 }, + { OV2735_REG_MIPI_CTRL7, 0x70 }, + { OV2735_REG_ANALOG_CTRL3, 0xe0 }, + { OV2735_REG_VNCP, 0x7b }, + + /* BLC */ + { OV2735_REG_BLC_GAIN_BLUE, 0x77 }, + { OV2735_REG_BLC_GAIN_GB, 0x77 }, + { OV2735_REG_BLC_GAIN_RED, 0x74 }, + { OV2735_REG_BLC_GAIN_GR, 0x74 }, + { OV2735_REG_BLC_BPC_TH_P, 0xe0 }, + { OV2735_REG_BLC_BPC_TH_N, 0xe0 }, + { OV2735_REG_GB_SUBOFFSET, 0x40 }, + { OV2735_REG_BLUE_SUBOFFSET, 0x40 }, + { OV2735_REG_RED_SUBOFFSET, 0x40 }, + { OV2735_REG_GR_SUBOFFSET, 0x40 }, +}; + +static const struct ov2735_mode supported_modes[] = { + { + .width = 1920, + .height = 1080, + .exp_def = 399, + .hts_def = 2200, + .vts_def = 2545, + .crop = { + .top = 8, + .left = 8, + .width = 1920, + .height = 1080, + }, + }, +}; + +static const s64 link_freq_menu_items[] = { + OV2735_LINK_FREQ_420MHZ, +}; + +static const struct ov2735_pll_parameters pll_configs[] = { + /* For 420MHz pll_configs */ + { + .pll_nc = 4, + .pll_mc = 0, + .pll_outdiv = 1, + }, +}; + +static const char * const ov2735_test_pattern_menu[] = { + "Disabled", + "Vertical Color", +}; + +static int ov2735_page_access(struct ov2735 *ov2735, u32 reg, int *err) +{ + u8 page = reg >> CCI_REG_PRIVATE_SHIFT; + int ret = 0; + + if (err && *err) + return *err; + + guard(mutex)(&ov2735->page_lock); + + /* Perform page access before read/write */ + if (ov2735->current_page == page) + return ret; + + ret = cci_write(ov2735->cci, OV2735_REG_PAGE_SELECT, page, err); + if (!ret) + ov2735->current_page = page; + + return ret; +} + +static int ov2735_read(struct ov2735 *ov2735, u32 reg, u64 *val, int *err) +{ + u32 addr = reg & ~CCI_REG_PRIVATE_MASK; + int ret; + + ret = ov2735_page_access(ov2735, reg, err); + if (ret) + return ret; + + return cci_read(ov2735->cci, addr, val, err); +} + +static int ov2735_write(struct ov2735 *ov2735, u32 reg, u64 val, int *err) +{ + u32 addr = reg & ~CCI_REG_PRIVATE_MASK; + int ret; + + ret = ov2735_page_access(ov2735, reg, err); + if (ret) + return ret; + + return cci_write(ov2735->cci, addr, val, err); +} + +static int ov2735_multi_reg_write(struct ov2735 *ov2735, + const struct cci_reg_sequence *regs, + unsigned int num_regs, int *err) +{ + unsigned int i; + int ret; + + for (i = 0; i < num_regs; i++) { + ret = ov2735_write(ov2735, regs[i].reg, regs[i].val, err); + if (ret) + return ret; + } + + return 0; +} + +static inline struct ov2735 *to_ov2735(struct v4l2_subdev *_sd) +{ + return container_of_const(_sd, struct ov2735, sd); +} + +static int ov2735_enable_test_pattern(struct ov2735 *ov2735, u32 pattern) +{ + int ret; + u64 val; + + ret = ov2735_read(ov2735, OV2735_REG_TEST_PATTERN, &val, NULL); + if (ret) + return ret; + + switch (pattern) { + case 0: + val &= ~OV2735_TEST_PATTERN_ENABLE; + break; + case 1: + val |= OV2735_TEST_PATTERN_ENABLE; + break; + } + + return ov2735_write(ov2735, OV2735_REG_TEST_PATTERN, val, NULL); +} + +static int ov2735_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov2735 *ov2735 = + container_of_const(ctrl->handler, struct ov2735, handler); + struct v4l2_mbus_framefmt *fmt; + struct v4l2_subdev_state *state; + u64 vts; + int ret = 0; + + state = v4l2_subdev_get_locked_active_state(&ov2735->sd); + fmt = v4l2_subdev_state_get_format(state, 0); + + if (ctrl->id == V4L2_CID_VBLANK) { + /* Honour the VBLANK limits when setting exposure */ + s64 max = fmt->height + ctrl->val - OV2735_EXPOSURE_MARGIN; + + ret = __v4l2_ctrl_modify_range(ov2735->exposure, + ov2735->exposure->minimum, max, + ov2735->exposure->step, + ov2735->exposure->default_value); + if (ret) + return ret; + } + + if (pm_runtime_get_if_in_use(ov2735->dev) == 0) + return 0; + + switch (ctrl->id) { + case V4L2_CID_EXPOSURE: + ov2735_write(ov2735, OV2735_REG_LONG_EXPOSURE, ctrl->val, &ret); + break; + case V4L2_CID_ANALOGUE_GAIN: + ov2735_write(ov2735, OV2735_REG_ANALOG_GAIN, ctrl->val, &ret); + break; + case V4L2_CID_HBLANK: + ov2735_write(ov2735, OV2735_REG_HBLANK, ctrl->val, &ret); + break; + case V4L2_CID_VBLANK: + vts = ctrl->val + fmt->height; + ov2735_write(ov2735, OV2735_REG_FRAME_EXP_SEPERATE_EN, + OV2735_FRAME_EXP_SEPERATE_EN, &ret); + ov2735_write(ov2735, OV2735_REG_FRAME_LENGTH, vts, &ret); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov2735_enable_test_pattern(ov2735, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + ov2735_write(ov2735, OV2735_REG_FRAME_SYNC, 0x01, &ret); + + pm_runtime_put(ov2735->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov2735_ctrl_ops = { + .s_ctrl = ov2735_set_ctrl, +}; + +static int ov2735_init_controls(struct ov2735 *ov2735) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_fwnode_device_properties props; + const struct ov2735_mode *mode = &supported_modes[0]; + u64 hblank_def, vblank_def, exp_max; + int ret; + + ctrl_hdlr = &ov2735->handler; + v4l2_ctrl_handler_init(ctrl_hdlr, 9); + + ov2735->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_PIXEL_RATE, 0, + OV2735_PIXEL_RATE, 1, + OV2735_PIXEL_RATE); + + ov2735->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_LINK_FREQ, + ov2735->link_freq_index, + 0, link_freq_menu_items); + if (ov2735->link_freq) + ov2735->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + hblank_def = mode->hts_def - mode->width; + ov2735->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_HBLANK, hblank_def, + hblank_def, 1, hblank_def); + + vblank_def = mode->vts_def - mode->height; + ov2735->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_VBLANK, vblank_def, + OV2735_FRAME_LENGTH_MAX - mode->height, + 1, vblank_def); + + exp_max = mode->vts_def - OV2735_EXPOSURE_MARGIN; + ov2735->exposure = + v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_EXPOSURE, + OV2735_EXPOSURE_MIN, exp_max, + OV2735_EXPOSURE_STEP, mode->exp_def); + + ov2735->gain = + v4l2_ctrl_new_std(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_ANALOGUE_GAIN, OV2735_ANALOG_GAIN_MIN, + OV2735_ANALOG_GAIN_MAX, OV2735_ANALOG_GAIN_STEP, + OV2735_ANALOG_GAIN_DEFAULT); + + ov2735->test_pattern = + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov2735_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov2735_test_pattern_menu) - 1, + 0, 0, ov2735_test_pattern_menu); + + if (ctrl_hdlr->error) { + ret = ctrl_hdlr->error; + dev_err(ov2735->dev, "control init failed (%d)\n", ret); + goto err_handler_free; + } + + ret = v4l2_fwnode_device_parse(ov2735->dev, &props); + if (ret) + goto err_handler_free; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, + &ov2735_ctrl_ops, &props); + if (ret) + goto err_handler_free; + + ov2735->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +err_handler_free: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static int ov2735_set_pll_ctrl(struct ov2735 *ov2735) +{ + const struct ov2735_pll_parameters *pll_parameters; + u8 pll_ctrl; + u8 pll_outdiv; + int ret = 0; + + pll_parameters = &pll_configs[ov2735->link_freq_index]; + + /* BIT[7]: pll_clk_sel, BIT[6:2]: pll_nc, BIT[1:0]: pll_mc */ + pll_ctrl = ((pll_parameters->pll_nc << 2) | (pll_parameters->pll_mc << 0)) & + OV2735_PLL_CTRL_ENABLE; + + pll_outdiv = pll_parameters->pll_outdiv; + + ov2735_write(ov2735, OV2735_REG_PLL_CTRL, pll_ctrl, &ret); + ov2735_write(ov2735, OV2735_REG_PLL_OUTDIV, pll_outdiv, &ret); + + return ret; +} + +static int ov2735_set_framefmt(struct ov2735 *ov2735, + struct v4l2_subdev_state *state) +{ + const struct v4l2_mbus_framefmt *format; + const struct v4l2_rect *crop; + int ret = 0; + + format = v4l2_subdev_state_get_format(state, 0); + crop = v4l2_subdev_state_get_crop(state, 0); + + ov2735_write(ov2735, OV2735_REG_V_START, crop->top, &ret); + ov2735_write(ov2735, OV2735_REG_V_SIZE, format->height, &ret); + ov2735_write(ov2735, OV2735_REG_MIPI_LINE_NUMBER, format->height, &ret); + ov2735_write(ov2735, OV2735_REG_H_START, crop->left, &ret); + /* OV2735_REG_H_SIZE: Image half horizontal size */ + ov2735_write(ov2735, OV2735_REG_H_SIZE, (format->width / 2), &ret); + ov2735_write(ov2735, OV2735_REG_MIPI_COLOMN_NUMBER, format->width, &ret); + + return ret; +} + +static int ov2735_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + ret = pm_runtime_resume_and_get(ov2735->dev); + if (ret < 0) + return ret; + + /* Apply pll settings */ + ret = ov2735_set_pll_ctrl(ov2735); + if (ret) { + dev_err(ov2735->dev, "failed to set frame format: %d\n", ret); + goto err_rpm_put; + } + + ret = ov2735_multi_reg_write(ov2735, ov2735_common_regs, + ARRAY_SIZE(ov2735_common_regs), NULL); + if (ret) { + dev_err(ov2735->dev, "failed to write common registers\n"); + goto err_rpm_put; + } + + /* Apply format settings */ + ret = ov2735_set_framefmt(ov2735, state); + if (ret) { + dev_err(ov2735->dev, "failed to set frame format: %d\n", ret); + goto err_rpm_put; + } + + /* Apply customized values from user */ + ret = __v4l2_ctrl_handler_setup(ov2735->sd.ctrl_handler); + if (ret) + goto err_rpm_put; + + ret = ov2735_write(ov2735, OV2735_REG_STREAM_CTRL, + OV2735_STREAM_CTRL_ON, NULL); + if (ret) + goto err_rpm_put; + + return 0; + +err_rpm_put: + pm_runtime_put(ov2735->dev); + return ret; +} + +static int ov2735_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + ret = ov2735_write(ov2735, OV2735_REG_STREAM_CTRL, + OV2735_STREAM_CTRL_OFF, NULL); + if (ret) + dev_err(ov2735->dev, "%s failed to set stream\n", __func__); + + pm_runtime_put(ov2735->dev); + + return ret; +} + +static int ov2735_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); + return 0; + case V4L2_SEL_TGT_NATIVE_SIZE: + sel->r = ov2735_native_area; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r = ov2735_active_area; + return 0; + default: + return -EINVAL; + } +} + +static int ov2735_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_SGRBG10_1X10; + + return 0; +} + +static int ov2735_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov2735_set_framing_limits(struct ov2735 *ov2735, + const struct ov2735_mode *mode) +{ + u32 hblank, vblank_def; + int ret; + + hblank = mode->hts_def - mode->width; + ret = __v4l2_ctrl_modify_range(ov2735->hblank, hblank, hblank, 1, + hblank); + if (ret) + return ret; + + vblank_def = mode->vts_def - mode->height; + return __v4l2_ctrl_modify_range(ov2735->vblank, vblank_def, + OV2735_FRAME_LENGTH_MAX - mode->height, + 1, vblank_def); +} + +static int ov2735_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + const struct ov2735_mode *mode; + struct v4l2_rect *crop; + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + format = v4l2_subdev_state_get_format(sd_state, 0); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, fmt->format.height); + + fmt->format.width = mode->width; + fmt->format.height = mode->height; + fmt->format.field = V4L2_FIELD_NONE; + fmt->format.colorspace = V4L2_COLORSPACE_RAW; + fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + ret = ov2735_set_framing_limits(ov2735, mode); + if (ret) + return ret; + } + + *format = fmt->format; + + /* Initialize crop rectangle */ + crop = v4l2_subdev_state_get_crop(sd_state, 0); + *crop = mode->crop; + + return 0; +} + +static int ov2735_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .format = { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + ov2735_set_pad_format(sd, state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov2735_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops ov2735_pad_ops = { + .enum_mbus_code = ov2735_enum_mbus_code, + .get_fmt = v4l2_subdev_get_fmt, + .set_fmt = ov2735_set_pad_format, + .get_selection = ov2735_get_selection, + .enum_frame_size = ov2735_enum_frame_size, + .enable_streams = ov2735_enable_streams, + .disable_streams = ov2735_disable_streams, +}; + +static const struct v4l2_subdev_ops ov2735_subdev_ops = { + .video = &ov2735_video_ops, + .pad = &ov2735_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ov2735_internal_ops = { + .init_state = ov2735_init_state, +}; + +static int ov2735_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2735 *ov2735 = to_ov2735(sd); + int ret; + + ret = regulator_bulk_enable(ARRAY_SIZE(ov2735_supply_name), + ov2735->supplies); + if (ret) { + dev_err(ov2735->dev, "failed to enable regulators\n"); + return ret; + } + + gpiod_set_value_cansleep(ov2735->enable_gpio, 1); + /* T4: delay from PWDN pulling low to RSTB pulling high */ + fsleep(4 * USEC_PER_MSEC); + + ret = clk_prepare_enable(ov2735->xclk); + if (ret) { + dev_err(ov2735->dev, "failed to enable clock\n"); + goto err_regulator_off; + } + + gpiod_set_value_cansleep(ov2735->reset_gpio, 0); + /* T5: delay from RSTB pulling high to first I2C command */ + fsleep(5 * USEC_PER_MSEC); + + return 0; + +err_regulator_off: + regulator_bulk_disable(ARRAY_SIZE(ov2735_supply_name), ov2735->supplies); + return ret; +} + +static int ov2735_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov2735 *ov2735 = to_ov2735(sd); + + gpiod_set_value_cansleep(ov2735->enable_gpio, 0); + clk_disable_unprepare(ov2735->xclk); + gpiod_set_value_cansleep(ov2735->reset_gpio, 1); + regulator_bulk_disable(ARRAY_SIZE(ov2735_supply_name), ov2735->supplies); + + return 0; +} + +static int ov2735_get_regulators(struct ov2735 *ov2735) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(ov2735_supply_name); i++) + ov2735->supplies[i].supply = ov2735_supply_name[i]; + + return devm_regulator_bulk_get(ov2735->dev, + ARRAY_SIZE(ov2735_supply_name), + ov2735->supplies); +} + +static int ov2735_identify_module(struct ov2735 *ov2735) +{ + u64 chip_id; + int ret; + + ret = ov2735_read(ov2735, OV2735_REG_CHIPID, &chip_id, NULL); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "failed to read chip id %x\n", + OV2735_CHIPID); + + if (chip_id != OV2735_CHIPID) + return dev_err_probe(ov2735->dev, -EIO, + "chip id mismatch: %x!=%llx\n", + OV2735_CHIPID, chip_id); + + return 0; +} + +static int ov2735_parse_endpoint(struct ov2735 *ov2735) +{ + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + struct fwnode_handle *ep; + unsigned long link_freq_bitmap; + int ret; + + ep = fwnode_graph_get_next_endpoint(dev_fwnode(ov2735->dev), NULL); + if (!ep) + return dev_err_probe(ov2735->dev, -ENXIO, + "Failed to get next endpoint\n"); + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 2) { + ret = dev_err_probe(ov2735->dev, -EINVAL, + "only 2 data lanes are supported\n"); + goto error_out; + } + + ret = v4l2_link_freq_to_bitmap(ov2735->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + link_freq_menu_items, + ARRAY_SIZE(link_freq_menu_items), + &link_freq_bitmap); + if (ret) { + ret = dev_err_probe(ov2735->dev, -EINVAL, + "only 420MHz frequency is available\n"); + goto error_out; + } + + ov2735->link_freq_index = __ffs(link_freq_bitmap); + +error_out: + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +}; + +static int ov2735_probe(struct i2c_client *client) +{ + struct ov2735 *ov2735; + unsigned int xclk_freq; + int ret; + + ov2735 = devm_kzalloc(&client->dev, sizeof(*ov2735), GFP_KERNEL); + if (!ov2735) + return -ENOMEM; + + ov2735->dev = &client->dev; + + v4l2_i2c_subdev_init(&ov2735->sd, client, &ov2735_subdev_ops); + ov2735->sd.internal_ops = &ov2735_internal_ops; + + ov2735->cci = devm_cci_regmap_init_i2c(client, 8); + if (IS_ERR(ov2735->cci)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->cci), + "failed to initialize CCI\n"); + + /* Set Current page to 0 */ + ov2735->current_page = 0; + + ret = devm_mutex_init(ov2735->dev, &ov2735->page_lock); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "Failed to initialize lock\n"); + + /* Get system clock (xvclk) */ + ov2735->xclk = devm_v4l2_sensor_clk_get(ov2735->dev, NULL); + if (IS_ERR(ov2735->xclk)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->xclk), + "failed to get xclk\n"); + + xclk_freq = clk_get_rate(ov2735->xclk); + if (xclk_freq != OV2735_XCLK_FREQ) + return dev_err_probe(ov2735->dev, -EINVAL, + "xclk frequency not supported: %u Hz\n", + xclk_freq); + + ret = ov2735_get_regulators(ov2735); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "failed to get regulators\n"); + + ret = ov2735_parse_endpoint(ov2735); + if (ret) + return dev_err_probe(ov2735->dev, ret, + "failed to parse endpoint configuration\n"); + + ov2735->reset_gpio = devm_gpiod_get_optional(ov2735->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(ov2735->reset_gpio)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->reset_gpio), + "failed to get reset GPIO\n"); + + ov2735->enable_gpio = devm_gpiod_get_optional(ov2735->dev, + "enable", GPIOD_OUT_LOW); + if (IS_ERR(ov2735->enable_gpio)) + return dev_err_probe(ov2735->dev, PTR_ERR(ov2735->enable_gpio), + "failed to get enable GPIO\n"); + + ret = ov2735_power_on(ov2735->dev); + if (ret) + return ret; + + ret = ov2735_identify_module(ov2735); + if (ret) + goto error_power_off; + + ret = ov2735_init_controls(ov2735); + if (ret) + goto error_power_off; + + /* Initialize subdev */ + ov2735->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov2735->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov2735->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&ov2735->sd.entity, 1, &ov2735->pad); + if (ret) { + dev_err_probe(ov2735->dev, ret, "failed to init entity pads\n"); + goto error_handler_free; + } + + ov2735->sd.state_lock = ov2735->handler.lock; + ret = v4l2_subdev_init_finalize(&ov2735->sd); + if (ret) { + dev_err_probe(ov2735->dev, ret, "subdev init error\n"); + goto error_media_entity; + } + + ret = devm_pm_runtime_get_noresume(ov2735->dev); + if (ret) { + dev_err_probe(ov2735->dev, ret, + "failed to get runtime PM noresume\n"); + goto error_subdev_cleanup; + } + + ret = devm_pm_runtime_set_active_enabled(ov2735->dev); + if (ret) { + dev_err_probe(ov2735->dev, ret, + "failed to set runtime PM active+enabled\n"); + goto error_subdev_cleanup; + } + + ret = v4l2_async_register_subdev_sensor(&ov2735->sd); + if (ret) { + dev_err_probe(ov2735->dev, ret, + "failed to register ov2735 sub-device\n"); + goto error_subdev_cleanup; + } + + return 0; + +error_subdev_cleanup: + v4l2_subdev_cleanup(&ov2735->sd); + +error_media_entity: + media_entity_cleanup(&ov2735->sd.entity); + +error_handler_free: + v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); + +error_power_off: + ov2735_power_off(ov2735->dev); + + return ret; +} + +static void ov2735_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov2735 *ov2735 = to_ov2735(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(&ov2735->sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(ov2735->sd.ctrl_handler); +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ov2735_pm_ops, + ov2735_power_off, ov2735_power_on, NULL); + +static const struct of_device_id ov2735_id[] = { + { .compatible = "ovti,ov2735" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov2735_id); + +static struct i2c_driver ov2735_driver = { + .driver = { + .name = "ov2735", + .pm = pm_ptr(&ov2735_pm_ops), + .of_match_table = ov2735_id, + }, + .probe = ov2735_probe, + .remove = ov2735_remove, +}; +module_i2c_driver(ov2735_driver); + +MODULE_DESCRIPTION("OV2735 Camera Sensor Driver"); +MODULE_AUTHOR("Hardevsinh Palaniya <hardevsinh.palaniya@siliconsignals.io>"); +MODULE_AUTHOR("Himanshu Bhavani <himanshu.bhavani@siliconsignals.io>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c index 4e959534e6e7..fb590dfadda1 100644 --- a/drivers/media/i2c/ov2740.c +++ b/drivers/media/i2c/ov2740.c @@ -1,17 +1,17 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/pm_runtime.h> #include <linux/nvmem-provider.h> +#include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -519,6 +519,8 @@ static const struct ov2740_mode supported_modes_180mhz[] = { }; struct ov2740 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -616,7 +618,6 @@ static int ov2740_write_reg(struct ov2740 *ov2740, u16 reg, u16 len, u32 val) static int ov2740_write_reg_list(struct ov2740 *ov2740, const struct ov2740_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); unsigned int i; int ret; @@ -624,7 +625,7 @@ static int ov2740_write_reg_list(struct ov2740 *ov2740, ret = ov2740_write_reg(ov2740, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov2740->dev, "write reg 0x%4.4x return err = %d\n", r_list->regs[i].address, ret); return ret; @@ -636,7 +637,6 @@ static int ov2740_write_reg_list(struct ov2740 *ov2740, static int ov2740_identify_module(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); int ret; u32 val; @@ -648,12 +648,12 @@ static int ov2740_identify_module(struct ov2740 *ov2740) return ret; if (val != OV2740_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x != %x\n", + dev_err(ov2740->dev, "chip id mismatch: %x != %x\n", OV2740_CHIP_ID, val); return -ENXIO; } - dev_dbg(&client->dev, "chip id: 0x%x\n", val); + dev_dbg(ov2740->dev, "chip id: 0x%x\n", val); ov2740->identified = true; @@ -704,7 +704,6 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov2740 *ov2740 = container_of(ctrl->handler, struct ov2740, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); s64 exposure_max; int ret; @@ -720,7 +719,7 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov2740->dev)) return 0; switch (ctrl->id) { @@ -753,7 +752,7 @@ static int ov2740_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov2740->dev); return ret; } @@ -764,7 +763,6 @@ static const struct v4l2_ctrl_ops ov2740_ctrl_ops = { static int ov2740_init_controls(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max, h_blank, pixel_rate; u32 vblank_min, vblank_max, vblank_default; @@ -821,7 +819,7 @@ static int ov2740_init_controls(struct ov2740 *ov2740) ARRAY_SIZE(ov2740_test_pattern_menu) - 1, 0, 0, ov2740_test_pattern_menu); - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov2740->dev, &props); if (ret) { v4l2_ctrl_handler_free(ctrl_hdlr); return ret; @@ -940,7 +938,6 @@ err: static int ov2740_start_streaming(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); const struct ov2740_reg_list *reg_list; int link_freq_index; int ret; @@ -955,7 +952,7 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) /* Reset the sensor */ ret = ov2740_write_reg(ov2740, 0x0103, 1, 0x01); if (ret) { - dev_err(&client->dev, "failed to reset\n"); + dev_err(ov2740->dev, "failed to reset\n"); return ret; } @@ -965,14 +962,14 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov2740_write_reg_list(ov2740, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls\n"); + dev_err(ov2740->dev, "failed to set plls\n"); return ret; } reg_list = &ov2740->cur_mode->reg_list; ret = ov2740_write_reg_list(ov2740, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode\n"); + dev_err(ov2740->dev, "failed to set mode\n"); return ret; } @@ -983,31 +980,28 @@ static int ov2740_start_streaming(struct ov2740 *ov2740) ret = ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, OV2740_MODE_STREAMING); if (ret) - dev_err(&client->dev, "failed to start streaming\n"); + dev_err(ov2740->dev, "failed to start streaming\n"); return ret; } static void ov2740_stop_streaming(struct ov2740 *ov2740) { - struct i2c_client *client = v4l2_get_subdevdata(&ov2740->sd); - if (ov2740_write_reg(ov2740, OV2740_REG_MODE_SELECT, 1, OV2740_MODE_STANDBY)) - dev_err(&client->dev, "failed to stop streaming\n"); + dev_err(ov2740->dev, "failed to stop streaming\n"); } static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) { struct ov2740 *ov2740 = to_ov2740(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); struct v4l2_subdev_state *sd_state; int ret = 0; sd_state = v4l2_subdev_lock_and_get_active_state(&ov2740->sd); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov2740->dev); if (ret < 0) goto out_unlock; @@ -1015,11 +1009,11 @@ static int ov2740_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov2740_stop_streaming(ov2740); - pm_runtime_put(&client->dev); + pm_runtime_put(ov2740->dev); } } else { ov2740_stop_streaming(ov2740); - pm_runtime_put(&client->dev); + pm_runtime_put(ov2740->dev); } out_unlock: @@ -1131,16 +1125,14 @@ static const struct media_entity_operations ov2740_subdev_entity_ops = { .link_validate = v4l2_subdev_link_validate, }; -static int ov2740_check_hwcfg(struct device *dev) +static int ov2740_check_hwcfg(struct ov2740 *ov2740) { - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct ov2740 *ov2740 = to_ov2740(sd); + struct device *dev = ov2740->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; @@ -1153,20 +1145,6 @@ static int ov2740_check_hwcfg(struct device *dev) return dev_err_probe(dev, -EPROBE_DEFER, "waiting for fwnode graph endpoint\n"); - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) { - fwnode_handle_put(ep); - return dev_err_probe(dev, ret, - "reading clock-frequency property\n"); - } - - if (mclk != OV2740_MCLK) { - fwnode_handle_put(ep); - return dev_err_probe(dev, -EINVAL, - "external clock %d is not supported\n", - mclk); - } - ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); fwnode_handle_put(ep); if (ret) @@ -1270,7 +1248,7 @@ static int ov2740_register_nvmem(struct i2c_client *client, struct regmap_config regmap_config = { }; struct nvmem_config nvmem_config = { }; struct regmap *regmap; - struct device *dev = &client->dev; + struct device *dev = ov2740->dev; nvm = devm_kzalloc(dev, sizeof(*nvm), GFP_KERNEL); if (!nvm) @@ -1349,6 +1327,7 @@ static int ov2740_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov2740 *ov2740; + unsigned long freq; bool full_power; unsigned int i; int ret; @@ -1357,10 +1336,12 @@ static int ov2740_probe(struct i2c_client *client) if (!ov2740) return -ENOMEM; + ov2740->dev = &client->dev; + v4l2_i2c_subdev_init(&ov2740->sd, client, &ov2740_subdev_ops); ov2740->sd.internal_ops = &ov2740_internal_ops; - ret = ov2740_check_hwcfg(dev); + ret = ov2740_check_hwcfg(ov2740); if (ret) return ret; @@ -1384,11 +1365,17 @@ static int ov2740_probe(struct i2c_client *client) msleep(20); } - ov2740->clk = devm_clk_get_optional(dev, "clk"); + ov2740->clk = devm_v4l2_sensor_clk_get(dev, "clk"); if (IS_ERR(ov2740->clk)) return dev_err_probe(dev, PTR_ERR(ov2740->clk), "failed to get clock\n"); + freq = clk_get_rate(ov2740->clk); + if (freq != OV2740_MCLK) + return dev_err_probe(dev, -EINVAL, + "external clock %lu is not supported\n", + freq); + for (i = 0; i < ARRAY_SIZE(ov2740_supply_name); i++) ov2740->supplies[i].supply = ov2740_supply_name[i]; @@ -1397,7 +1384,7 @@ static int ov2740_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "failed to get regulators\n"); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov2740->dev); if (full_power) { /* ACPI does not always clear the reset GPIO / enable the clock */ ret = ov2740_resume(dev); @@ -1435,9 +1422,9 @@ static int ov2740_probe(struct i2c_client *client) /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov2740->dev); + pm_runtime_enable(ov2740->dev); + pm_runtime_idle(ov2740->dev); ret = v4l2_async_register_subdev_sensor(&ov2740->sd); if (ret < 0) { @@ -1447,13 +1434,13 @@ static int ov2740_probe(struct i2c_client *client) ret = ov2740_register_nvmem(client, ov2740); if (ret) - dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret); + dev_warn(ov2740->dev, "register nvmem failed, ret %d\n", ret); return 0; probe_error_v4l2_subdev_cleanup: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov2740->dev); + pm_runtime_set_suspended(ov2740->dev); v4l2_subdev_cleanup(&ov2740->sd); probe_error_media_entity_cleanup: diff --git a/drivers/media/i2c/ov4689.c b/drivers/media/i2c/ov4689.c index 1c3a449f9354..a59d25b09b5b 100644 --- a/drivers/media/i2c/ov4689.c +++ b/drivers/media/i2c/ov4689.c @@ -497,7 +497,6 @@ static int ov4689_s_stream(struct v4l2_subdev *sd, int on) } else { cci_write(ov4689->regmap, OV4689_REG_CTRL_MODE, OV4689_MODE_SW_STANDBY, NULL); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); } @@ -702,7 +701,6 @@ static int ov4689_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -909,20 +907,12 @@ static int ov4689_probe(struct i2c_client *client) ov4689->cur_mode = &supported_modes[OV4689_MODE_2688_1520]; - ov4689->xvclk = devm_clk_get_optional(dev, NULL); + ov4689->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov4689->xvclk)) return dev_err_probe(dev, PTR_ERR(ov4689->xvclk), "Failed to get external clock\n"); - if (!ov4689->xvclk) { - dev_dbg(dev, - "No clock provided, using clock-frequency property\n"); - device_property_read_u32(dev, "clock-frequency", - &ov4689->clock_rate); - } else { - ov4689->clock_rate = clk_get_rate(ov4689->xvclk); - } - + ov4689->clock_rate = clk_get_rate(ov4689->xvclk); if (ov4689->clock_rate != OV4689_XVCLK_FREQ) { dev_err(dev, "External clock rate mismatch: got %d Hz, expected %d Hz\n", @@ -999,7 +989,6 @@ static int ov4689_probe(struct i2c_client *client) goto err_clean_subdev_pm; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c index 0dae0438aa80..85ecc23b3587 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -3341,7 +3341,6 @@ static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return 0; @@ -3417,7 +3416,6 @@ static int ov5640_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); return ret; @@ -3754,7 +3752,6 @@ out: mutex_unlock(&sensor->lock); if (!enable || ret) { - pm_runtime_mark_last_busy(&sensor->i2c_client->dev); pm_runtime_put_autosuspend(&sensor->i2c_client->dev); } @@ -3898,11 +3895,10 @@ static int ov5640_probe(struct i2c_client *client) ov5640_dvp_default_fmt; /* get system clock (xclk) */ - sensor->xclk = devm_clk_get(dev, "xclk"); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, "xclk"); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "failed to get xclk\n"); sensor->xclk_freq = clk_get_rate(sensor->xclk); if (sensor->xclk_freq < OV5640_XCLK_MIN || @@ -3965,7 +3961,6 @@ static int ov5640_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c index 004d0ee5c3f5..b10d408034a1 100644 --- a/drivers/media/i2c/ov5645.c +++ b/drivers/media/i2c/ov5645.c @@ -808,7 +808,6 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); return ret; @@ -979,7 +978,6 @@ static int ov5645_disable_streams(struct v4l2_subdev *sd, OV5645_SYSTEM_CTRL0_STOP); rpm_put: - pm_runtime_mark_last_busy(ov5645->dev); pm_runtime_put_autosuspend(ov5645->dev); return ret; @@ -1044,27 +1042,18 @@ static int ov5645_probe(struct i2c_client *client) "invalid bus type, must be CSI2\n"); /* get system clock (xclk) */ - ov5645->xclk = devm_clk_get(dev, NULL); + ov5645->xclk = devm_v4l2_sensor_clk_get_legacy(dev, NULL, false, 0); if (IS_ERR(ov5645->xclk)) return dev_err_probe(dev, PTR_ERR(ov5645->xclk), "could not get xclk"); - ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq); - if (ret) - return dev_err_probe(dev, ret, - "could not get xclk frequency\n"); - /* external clock must be 24MHz, allow 1% tolerance */ + xclk_freq = clk_get_rate(ov5645->xclk); if (xclk_freq < 23760000 || xclk_freq > 24240000) return dev_err_probe(dev, -EINVAL, "unsupported xclk frequency %u\n", xclk_freq); - ret = clk_set_rate(ov5645->xclk, xclk_freq); - if (ret) - return dev_err_probe(dev, ret, - "could not set xclk frequency\n"); - for (i = 0; i < OV5645_NUM_SUPPLIES; i++) ov5645->supplies[i].supply = ov5645_supply_name[i]; @@ -1196,7 +1185,6 @@ static int ov5645_probe(struct i2c_client *client) pm_runtime_set_autosuspend_delay(dev, 1000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index a727beb9d57e..e193fef4fced 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -1398,11 +1398,10 @@ static int ov5647_probe(struct i2c_client *client) } } - sensor->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "could not get xclk"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "could not get xclk\n"); xclk_freq = clk_get_rate(sensor->xclk); if (xclk_freq != 25000000) { diff --git a/drivers/media/i2c/ov5648.c b/drivers/media/i2c/ov5648.c index 4b86d2631bd1..f0b839cd65f1 100644 --- a/drivers/media/i2c/ov5648.c +++ b/drivers/media/i2c/ov5648.c @@ -1061,8 +1061,8 @@ static int ov5648_sw_standby(struct ov5648_sensor *sensor, int standby) static int ov5648_chip_id_check(struct ov5648_sensor *sensor) { - u16 regs[] = { OV5648_CHIP_ID_H_REG, OV5648_CHIP_ID_L_REG }; - u8 values[] = { OV5648_CHIP_ID_H_VALUE, OV5648_CHIP_ID_L_VALUE }; + static const u16 regs[] = { OV5648_CHIP_ID_H_REG, OV5648_CHIP_ID_L_REG }; + static const u8 values[] = { OV5648_CHIP_ID_H_VALUE, OV5648_CHIP_ID_L_VALUE }; unsigned int i; u8 value; int ret; @@ -2521,10 +2521,10 @@ static int ov5648_probe(struct i2c_client *client) /* External Clock */ - sensor->xvclk = devm_clk_get(dev, NULL); + sensor->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xvclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->xvclk); + ret = dev_err_probe(dev, PTR_ERR(sensor->xvclk), + "failed to get external clock\n"); goto error_endpoint; } diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c index b9efb2d2276a..04b3183b7bcb 100644 --- a/drivers/media/i2c/ov5670.c +++ b/drivers/media/i2c/ov5670.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -12,6 +11,8 @@ #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-event.h> @@ -1854,6 +1855,8 @@ static const struct ov5670_mode supported_modes[] = { }; struct ov5670 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_fwnode_endpoint endpoint; @@ -1959,7 +1962,6 @@ static int ov5670_write_reg(struct ov5670 *ov5670, u16 reg, unsigned int len, static int ov5670_write_regs(struct ov5670 *ov5670, const struct ov5670_reg *regs, unsigned int len) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); unsigned int i; int ret; @@ -1967,7 +1969,7 @@ static int ov5670_write_regs(struct ov5670 *ov5670, ret = ov5670_write_reg(ov5670, regs[i].address, 1, regs[i].val); if (ret) { dev_err_ratelimited( - &client->dev, + ov5670->dev, "Failed to write reg 0x%4.4x. error = %d\n", regs[i].address, ret); @@ -2032,7 +2034,6 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov5670 *ov5670 = container_of(ctrl->handler, struct ov5670, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); s64 max; int ret; @@ -2048,7 +2049,7 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov5670->dev)) return 0; switch (ctrl->id) { @@ -2080,12 +2081,12 @@ static int ov5670_set_ctrl(struct v4l2_ctrl *ctrl) break; default: ret = -EINVAL; - dev_info(&client->dev, "%s Unhandled id:0x%x, val:0x%x\n", + dev_info(ov5670->dev, "%s Unhandled id:0x%x, val:0x%x\n", __func__, ctrl->id, ctrl->val); break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov5670->dev); return ret; } @@ -2099,7 +2100,6 @@ static int ov5670_init_controls(struct ov5670 *ov5670) { struct v4l2_mbus_config_mipi_csi2 *bus_mipi_csi2 = &ov5670->endpoint.bus.mipi_csi2; - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; unsigned int lanes_count; @@ -2177,7 +2177,7 @@ static int ov5670_init_controls(struct ov5670 *ov5670) goto error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov5670->dev, &props); if (ret) goto error; @@ -2350,7 +2350,6 @@ static int ov5670_get_skip_frames(struct v4l2_subdev *sd, u32 *frames) /* Verify chip ID */ static int ov5670_identify_module(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); int ret; u32 val; @@ -2363,7 +2362,7 @@ static int ov5670_identify_module(struct ov5670 *ov5670) return ret; if (val != OV5670_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x\n", + dev_err(ov5670->dev, "chip id mismatch: %x!=%x\n", OV5670_CHIP_ID, val); return -ENXIO; } @@ -2389,7 +2388,6 @@ static int ov5670_mipi_configure(struct ov5670 *ov5670) /* Prepare streaming by writing default values and customized values */ static int ov5670_start_streaming(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); const struct ov5670_reg_list *reg_list; int link_freq_index; int ret; @@ -2402,7 +2400,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) ret = ov5670_write_reg(ov5670, OV5670_REG_SOFTWARE_RST, OV5670_REG_VALUE_08BIT, OV5670_SOFTWARE_RST); if (ret) { - dev_err(&client->dev, "%s failed to set powerup registers\n", + dev_err(ov5670->dev, "%s failed to set powerup registers\n", __func__); return ret; } @@ -2412,7 +2410,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov5670_write_reg_list(ov5670, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set plls\n", __func__); + dev_err(ov5670->dev, "%s failed to set plls\n", __func__); return ret; } @@ -2420,13 +2418,13 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) reg_list = &ov5670->cur_mode->reg_list; ret = ov5670_write_reg_list(ov5670, reg_list); if (ret) { - dev_err(&client->dev, "%s failed to set mode\n", __func__); + dev_err(ov5670->dev, "%s failed to set mode\n", __func__); return ret; } ret = ov5670_mipi_configure(ov5670); if (ret) { - dev_err(&client->dev, "%s failed to configure MIPI\n", __func__); + dev_err(ov5670->dev, "%s failed to configure MIPI\n", __func__); return ret; } @@ -2438,7 +2436,7 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT, OV5670_REG_VALUE_08BIT, OV5670_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(ov5670->dev, "%s failed to set stream\n", __func__); return ret; } @@ -2447,13 +2445,12 @@ static int ov5670_start_streaming(struct ov5670 *ov5670) static int ov5670_stop_streaming(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); int ret; ret = ov5670_write_reg(ov5670, OV5670_REG_MODE_SELECT, OV5670_REG_VALUE_08BIT, OV5670_MODE_STANDBY); if (ret) - dev_err(&client->dev, "%s failed to set stream\n", __func__); + dev_err(ov5670->dev, "%s failed to set stream\n", __func__); /* Return success even if it was an error, as there is nothing the * caller can do about it. @@ -2464,13 +2461,12 @@ static int ov5670_stop_streaming(struct ov5670 *ov5670) static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) { struct ov5670 *ov5670 = to_ov5670(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov5670->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov5670->dev); if (ret < 0) goto unlock_and_return; @@ -2479,12 +2475,12 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable) goto error; } else { ret = ov5670_stop_streaming(ov5670); - pm_runtime_put(&client->dev); + pm_runtime_put(ov5670->dev); } goto unlock_and_return; error: - pm_runtime_put(&client->dev); + pm_runtime_put(ov5670->dev); unlock_and_return: mutex_unlock(&ov5670->mutex); @@ -2621,26 +2617,23 @@ static const struct media_entity_operations ov5670_subdev_entity_ops = { static int ov5670_regulators_probe(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); unsigned int i; for (i = 0; i < OV5670_NUM_SUPPLIES; i++) ov5670->supplies[i].supply = ov5670_supply_names[i]; - return devm_regulator_bulk_get(&client->dev, OV5670_NUM_SUPPLIES, + return devm_regulator_bulk_get(ov5670->dev, OV5670_NUM_SUPPLIES, ov5670->supplies); } static int ov5670_gpio_probe(struct ov5670 *ov5670) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5670->sd); - - ov5670->pwdn_gpio = devm_gpiod_get_optional(&client->dev, "powerdown", + ov5670->pwdn_gpio = devm_gpiod_get_optional(ov5670->dev, "powerdown", GPIOD_OUT_LOW); if (IS_ERR(ov5670->pwdn_gpio)) return PTR_ERR(ov5670->pwdn_gpio); - ov5670->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", + ov5670->reset_gpio = devm_gpiod_get_optional(ov5670->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov5670->reset_gpio)) return PTR_ERR(ov5670->reset_gpio); @@ -2660,18 +2653,16 @@ static int ov5670_probe(struct i2c_client *client) if (!ov5670) return -ENOMEM; - ov5670->xvclk = devm_clk_get_optional(&client->dev, NULL); - if (!IS_ERR_OR_NULL(ov5670->xvclk)) - input_clk = clk_get_rate(ov5670->xvclk); - else if (!ov5670->xvclk || PTR_ERR(ov5670->xvclk) == -ENOENT) - device_property_read_u32(&client->dev, "clock-frequency", - &input_clk); - else - return dev_err_probe(&client->dev, PTR_ERR(ov5670->xvclk), + ov5670->dev = &client->dev; + + ov5670->xvclk = devm_v4l2_sensor_clk_get(ov5670->dev, NULL); + if (IS_ERR(ov5670->xvclk)) + return dev_err_probe(ov5670->dev, PTR_ERR(ov5670->xvclk), "error getting clock\n"); + input_clk = clk_get_rate(ov5670->xvclk); if (input_clk != OV5670_XVCLK_FREQ) { - dev_err(&client->dev, + dev_err(ov5670->dev, "Unsupported clock frequency %u\n", input_clk); return -EINVAL; } @@ -2682,20 +2673,20 @@ static int ov5670_probe(struct i2c_client *client) ret = ov5670_regulators_probe(ov5670); if (ret) - return dev_err_probe(&client->dev, ret, "Regulators probe failed\n"); + return dev_err_probe(ov5670->dev, ret, "Regulators probe failed\n"); ret = ov5670_gpio_probe(ov5670); if (ret) - return dev_err_probe(&client->dev, ret, "GPIO probe failed\n"); + return dev_err_probe(ov5670->dev, ret, "GPIO probe failed\n"); /* * Graph Endpoint. If it's missing we defer rather than fail, as this * sensor is known to co-exist on systems with the IPU3 and so it might * be created by the ipu-bridge. */ - handle = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); + handle = fwnode_graph_get_next_endpoint(dev_fwnode(ov5670->dev), NULL); if (!handle) - return dev_err_probe(&client->dev, -EPROBE_DEFER, + return dev_err_probe(ov5670->dev, -EPROBE_DEFER, "Endpoint for node get failed\n"); ov5670->endpoint.bus_type = V4L2_MBUS_CSI2_DPHY; @@ -2704,20 +2695,20 @@ static int ov5670_probe(struct i2c_client *client) ret = v4l2_fwnode_endpoint_alloc_parse(handle, &ov5670->endpoint); fwnode_handle_put(handle); if (ret) - return dev_err_probe(&client->dev, ret, "Endpoint parse failed\n"); + return dev_err_probe(ov5670->dev, ret, "Endpoint parse failed\n"); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov5670->dev); if (full_power) { - ret = ov5670_runtime_resume(&client->dev); + ret = ov5670_runtime_resume(ov5670->dev); if (ret) { - dev_err_probe(&client->dev, ret, "Power up failed\n"); + dev_err_probe(ov5670->dev, ret, "Power up failed\n"); goto error_endpoint; } /* Check module identity */ ret = ov5670_identify_module(ov5670); if (ret) { - dev_err_probe(&client->dev, ret, "ov5670_identify_module() error\n"); + dev_err_probe(ov5670->dev, ret, "ov5670_identify_module() error\n"); goto error_power_off; } } @@ -2729,7 +2720,7 @@ static int ov5670_probe(struct i2c_client *client) ret = ov5670_init_controls(ov5670); if (ret) { - dev_err_probe(&client->dev, ret, "ov5670_init_controls() error\n"); + dev_err_probe(ov5670->dev, ret, "ov5670_init_controls() error\n"); goto error_mutex_destroy; } @@ -2742,28 +2733,28 @@ static int ov5670_probe(struct i2c_client *client) ov5670->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov5670->sd.entity, 1, &ov5670->pad); if (ret) { - dev_err_probe(&client->dev, ret, "media_entity_pads_init() error\n"); + dev_err_probe(ov5670->dev, ret, "media_entity_pads_init() error\n"); goto error_handler_free; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + pm_runtime_set_active(ov5670->dev); + pm_runtime_enable(ov5670->dev); /* Async register for subdev */ ret = v4l2_async_register_subdev_sensor(&ov5670->sd); if (ret < 0) { - dev_err_probe(&client->dev, ret, "v4l2_async_register_subdev() error\n"); + dev_err_probe(ov5670->dev, ret, "v4l2_async_register_subdev() error\n"); goto error_pm_disable; } - pm_runtime_idle(&client->dev); + pm_runtime_idle(ov5670->dev); return 0; error_pm_disable: - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov5670->dev); media_entity_cleanup(&ov5670->sd.entity); @@ -2775,7 +2766,7 @@ error_mutex_destroy: error_power_off: if (full_power) - ov5670_runtime_suspend(&client->dev); + ov5670_runtime_suspend(ov5670->dev); error_endpoint: v4l2_fwnode_endpoint_free(&ov5670->endpoint); @@ -2793,8 +2784,8 @@ static void ov5670_remove(struct i2c_client *client) v4l2_ctrl_handler_free(sd->ctrl_handler); mutex_destroy(&ov5670->mutex); - pm_runtime_disable(&client->dev); - ov5670_runtime_suspend(&client->dev); + pm_runtime_disable(ov5670->dev); + ov5670_runtime_suspend(ov5670->dev); v4l2_fwnode_endpoint_free(&ov5670->endpoint); } diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c index e7aec281e9a4..30e27d39ee44 100644 --- a/drivers/media/i2c/ov5675.c +++ b/drivers/media/i2c/ov5675.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -11,6 +10,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -493,6 +494,8 @@ static const struct ov5675_mode supported_modes[] = { }; struct ov5675 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -584,7 +587,6 @@ static int ov5675_write_reg(struct ov5675 *ov5675, u16 reg, u16 len, u32 val) static int ov5675_write_reg_list(struct ov5675 *ov5675, const struct ov5675_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); unsigned int i; int ret; @@ -592,7 +594,7 @@ static int ov5675_write_reg_list(struct ov5675 *ov5675, ret = ov5675_write_reg(ov5675, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov5675->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -700,7 +702,6 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov5675 *ov5675 = container_of(ctrl->handler, struct ov5675, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); s64 exposure_max; int ret = 0; @@ -716,7 +717,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov5675->dev)) return 0; switch (ctrl->id) { @@ -765,7 +766,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov5675->dev); return ret; } @@ -776,7 +777,6 @@ static const struct v4l2_ctrl_ops ov5675_ctrl_ops = { static int ov5675_init_controls(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); struct v4l2_fwnode_device_properties props; struct v4l2_ctrl_handler *ctrl_hdlr; s64 exposure_max, h_blank; @@ -839,7 +839,7 @@ static int ov5675_init_controls(struct ov5675 *ov5675) return ctrl_hdlr->error; } - ret = v4l2_fwnode_device_parse(&client->dev, &props); + ret = v4l2_fwnode_device_parse(ov5675->dev, &props); if (ret) goto error; @@ -869,7 +869,6 @@ static void ov5675_update_pad_format(const struct ov5675_mode *mode, static int ov5675_identify_module(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); int ret; u32 val; @@ -882,7 +881,7 @@ static int ov5675_identify_module(struct ov5675 *ov5675) return ret; if (val != OV5675_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(ov5675->dev, "chip id mismatch: %x!=%x", OV5675_CHIP_ID, val); return -ENXIO; } @@ -894,7 +893,6 @@ static int ov5675_identify_module(struct ov5675 *ov5675) static int ov5675_start_streaming(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); const struct ov5675_reg_list *reg_list; int link_freq_index, ret; @@ -906,14 +904,14 @@ static int ov5675_start_streaming(struct ov5675 *ov5675) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov5675_write_reg_list(ov5675, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov5675->dev, "failed to set plls"); return ret; } reg_list = &ov5675->cur_mode->reg_list; ret = ov5675_write_reg_list(ov5675, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov5675->dev, "failed to set mode"); return ret; } @@ -924,7 +922,7 @@ static int ov5675_start_streaming(struct ov5675 *ov5675) ret = ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, OV5675_REG_VALUE_08BIT, OV5675_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(ov5675->dev, "failed to set stream"); return ret; } @@ -933,22 +931,19 @@ static int ov5675_start_streaming(struct ov5675 *ov5675) static void ov5675_stop_streaming(struct ov5675 *ov5675) { - struct i2c_client *client = v4l2_get_subdevdata(&ov5675->sd); - if (ov5675_write_reg(ov5675, OV5675_REG_MODE_SELECT, OV5675_REG_VALUE_08BIT, OV5675_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(ov5675->dev, "failed to set stream"); } static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) { struct ov5675 *ov5675 = to_ov5675(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov5675->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov5675->dev); if (ret < 0) { mutex_unlock(&ov5675->mutex); return ret; @@ -958,11 +953,11 @@ static int ov5675_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov5675_stop_streaming(ov5675); - pm_runtime_put(&client->dev); + pm_runtime_put(ov5675->dev); } } else { ov5675_stop_streaming(ov5675); - pm_runtime_put(&client->dev); + pm_runtime_put(ov5675->dev); } mutex_unlock(&ov5675->mutex); @@ -1171,8 +1166,9 @@ static const struct v4l2_subdev_internal_ops ov5675_internal_ops = { .open = ov5675_open, }; -static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev) +static int ov5675_get_hwcfg(struct ov5675 *ov5675) { + struct device *dev = ov5675->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { @@ -1185,24 +1181,13 @@ static int ov5675_get_hwcfg(struct ov5675 *ov5675, struct device *dev) if (!fwnode) return -ENXIO; - ov5675->xvclk = devm_clk_get_optional(dev, NULL); + ov5675->xvclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov5675->xvclk)) return dev_err_probe(dev, PTR_ERR(ov5675->xvclk), "failed to get xvclk: %ld\n", PTR_ERR(ov5675->xvclk)); - if (ov5675->xvclk) { - xvclk_rate = clk_get_rate(ov5675->xvclk); - } else { - ret = fwnode_property_read_u32(fwnode, "clock-frequency", - &xvclk_rate); - - if (ret) { - dev_err(dev, "can't get clock frequency"); - return ret; - } - } - + xvclk_rate = clk_get_rate(ov5675->xvclk); if (xvclk_rate != OV5675_XVCLK_19_2) { dev_err(dev, "external clock rate %u is unsupported", xvclk_rate); @@ -1276,12 +1261,12 @@ static void ov5675_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov5675->dev); mutex_destroy(&ov5675->mutex); - if (!pm_runtime_status_suspended(&client->dev)) - ov5675_power_off(&client->dev); - pm_runtime_set_suspended(&client->dev); + if (!pm_runtime_status_suspended(ov5675->dev)) + ov5675_power_off(ov5675->dev); + pm_runtime_set_suspended(ov5675->dev); } static int ov5675_probe(struct i2c_client *client) @@ -1294,23 +1279,25 @@ static int ov5675_probe(struct i2c_client *client) if (!ov5675) return -ENOMEM; - ret = ov5675_get_hwcfg(ov5675, &client->dev); + ov5675->dev = &client->dev; + + ret = ov5675_get_hwcfg(ov5675); if (ret) return ret; v4l2_i2c_subdev_init(&ov5675->sd, client, &ov5675_subdev_ops); - ret = ov5675_power_on(&client->dev); + ret = ov5675_power_on(ov5675->dev); if (ret) { - dev_err(&client->dev, "failed to power on: %d\n", ret); + dev_err(ov5675->dev, "failed to power on: %d\n", ret); return ret; } - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov5675->dev); if (full_power) { ret = ov5675_identify_module(ov5675); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov5675->dev, "failed to find sensor: %d", ret); goto probe_power_off; } } @@ -1319,7 +1306,7 @@ static int ov5675_probe(struct i2c_client *client) ov5675->cur_mode = &supported_modes[0]; ret = ov5675_init_controls(ov5675); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov5675->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -1330,22 +1317,22 @@ static int ov5675_probe(struct i2c_client *client) ov5675->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov5675->sd.entity, 1, &ov5675->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov5675->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&ov5675->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov5675->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov5675->dev); + pm_runtime_enable(ov5675->dev); + pm_runtime_idle(ov5675->dev); return 0; @@ -1356,7 +1343,7 @@ probe_error_v4l2_ctrl_handler_free: v4l2_ctrl_handler_free(ov5675->sd.ctrl_handler); mutex_destroy(&ov5675->mutex); probe_power_off: - ov5675_power_off(&client->dev); + ov5675_power_off(ov5675->dev); return ret; } diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c index 485efd15257e..d294477f9dd3 100644 --- a/drivers/media/i2c/ov5693.c +++ b/drivers/media/i2c/ov5693.c @@ -1289,25 +1289,13 @@ static int ov5693_probe(struct i2c_client *client) v4l2_i2c_subdev_init(&ov5693->sd, client, &ov5693_ops); - ov5693->xvclk = devm_clk_get_optional(&client->dev, "xvclk"); + ov5693->xvclk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); if (IS_ERR(ov5693->xvclk)) return dev_err_probe(&client->dev, PTR_ERR(ov5693->xvclk), "failed to get xvclk: %ld\n", PTR_ERR(ov5693->xvclk)); - if (ov5693->xvclk) { - xvclk_rate = clk_get_rate(ov5693->xvclk); - } else { - ret = fwnode_property_read_u32(dev_fwnode(&client->dev), - "clock-frequency", - &xvclk_rate); - - if (ret) { - dev_err(&client->dev, "can't get clock frequency"); - return ret; - } - } - + xvclk_rate = clk_get_rate(ov5693->xvclk); if (xvclk_rate != OV5693_XVCLK_FREQ) dev_warn(&client->dev, "Found clk freq %u, expected %u\n", xvclk_rate, OV5693_XVCLK_FREQ); diff --git a/drivers/media/i2c/ov5695.c b/drivers/media/i2c/ov5695.c index 663eccdfea6a..5bb6ce7b3237 100644 --- a/drivers/media/i2c/ov5695.c +++ b/drivers/media/i2c/ov5695.c @@ -1264,16 +1264,12 @@ static int ov5695_probe(struct i2c_client *client) ov5695->client = client; ov5695->cur_mode = &supported_modes[0]; - ov5695->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov5695->xvclk)) { - dev_err(dev, "Failed to get xvclk\n"); - return -EINVAL; - } - ret = clk_set_rate(ov5695->xvclk, OV5695_XVCLK_FREQ); - if (ret < 0) { - dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); - return ret; - } + ov5695->xvclk = devm_v4l2_sensor_clk_get_legacy(dev, "xvclk", true, + OV5695_XVCLK_FREQ); + if (IS_ERR(ov5695->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov5695->xvclk), + "Failed to get xvclk\n"); + if (clk_get_rate(ov5695->xvclk) != OV5695_XVCLK_FREQ) dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n"); diff --git a/drivers/media/i2c/ov6211.c b/drivers/media/i2c/ov6211.c new file mode 100644 index 000000000000..e3ac5ecf27d1 --- /dev/null +++ b/drivers/media/i2c/ov6211.c @@ -0,0 +1,793 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024-2025 Linaro Ltd + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/regulator/consumer.h> +#include <linux/units.h> +#include <media/v4l2-cci.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> + +#define OV6211_LINK_FREQ_480MHZ (480 * HZ_PER_MHZ) +#define OV6211_MCLK_FREQ_24MHZ (24 * HZ_PER_MHZ) + +#define OV6211_REG_CHIP_ID CCI_REG16(0x300a) +#define OV6211_CHIP_ID 0x6710 + +#define OV6211_REG_MODE_SELECT CCI_REG8(0x0100) +#define OV6211_MODE_STANDBY 0x00 +#define OV6211_MODE_STREAMING BIT(0) + +#define OV6211_REG_SOFTWARE_RST CCI_REG8(0x0103) +#define OV6211_SOFTWARE_RST BIT(0) + +/* Exposure controls from sensor */ +#define OV6211_REG_EXPOSURE CCI_REG24(0x3500) +#define OV6211_EXPOSURE_MIN 1 +#define OV6211_EXPOSURE_MAX_MARGIN 4 +#define OV6211_EXPOSURE_STEP 1 +#define OV6211_EXPOSURE_DEFAULT 210 + +/* Analogue gain controls from sensor */ +#define OV6211_REG_ANALOGUE_GAIN CCI_REG16(0x350a) +#define OV6211_ANALOGUE_GAIN_MIN 1 +#define OV6211_ANALOGUE_GAIN_MAX 0x3ff +#define OV6211_ANALOGUE_GAIN_STEP 1 +#define OV6211_ANALOGUE_GAIN_DEFAULT 160 + +/* Test pattern */ +#define OV6211_REG_PRE_ISP CCI_REG8(0x5e00) +#define OV6211_TEST_PATTERN_ENABLE BIT(7) + +#define to_ov6211(_sd) container_of(_sd, struct ov6211, sd) + +static const s64 ov6211_link_freq_menu[] = { + OV6211_LINK_FREQ_480MHZ, +}; + +struct ov6211_reg_list { + const struct cci_reg_sequence *regs; + unsigned int num_regs; +}; + +struct ov6211_mode { + u32 width; /* Frame width in pixels */ + u32 height; /* Frame height in pixels */ + u32 hts; /* Horizontal timing size */ + u32 vts; /* Default vertical timing size */ + u32 bpp; /* Bits per pixel */ + + const struct ov6211_reg_list reg_list; /* Sensor register setting */ +}; + +static const char * const ov6211_test_pattern_menu[] = { + "Disabled", + "Vertical Colour Bars", +}; + +static const char * const ov6211_supply_names[] = { + "avdd", /* Analog power */ + "dovdd", /* Digital I/O power */ + "dvdd", /* Digital core power */ +}; + +#define OV6211_NUM_SUPPLIES ARRAY_SIZE(ov6211_supply_names) + +struct ov6211 { + struct device *dev; + struct regmap *regmap; + struct clk *xvclk; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data supplies[OV6211_NUM_SUPPLIES]; + + struct v4l2_subdev sd; + struct media_pad pad; + + struct v4l2_ctrl_handler ctrl_handler; + + /* Saved register values */ + u64 pre_isp; +}; + +static const struct cci_reg_sequence ov6211_400x400_120fps_mode[] = { + { CCI_REG8(0x3005), 0x00 }, + { CCI_REG8(0x3013), 0x12 }, + { CCI_REG8(0x3014), 0x04 }, + { CCI_REG8(0x3016), 0x10 }, + { CCI_REG8(0x3017), 0x00 }, + { CCI_REG8(0x3018), 0x00 }, + { CCI_REG8(0x301a), 0x00 }, + { CCI_REG8(0x301b), 0x00 }, + { CCI_REG8(0x301c), 0x00 }, + { CCI_REG8(0x3037), 0xf0 }, + { CCI_REG8(0x3080), 0x01 }, + { CCI_REG8(0x3081), 0x00 }, + { CCI_REG8(0x3082), 0x01 }, + { CCI_REG8(0x3098), 0x04 }, + { CCI_REG8(0x3099), 0x28 }, + { CCI_REG8(0x309a), 0x06 }, + { CCI_REG8(0x309b), 0x04 }, + { CCI_REG8(0x309c), 0x00 }, + { CCI_REG8(0x309d), 0x00 }, + { CCI_REG8(0x309e), 0x01 }, + { CCI_REG8(0x309f), 0x00 }, + { CCI_REG8(0x30b0), 0x08 }, + { CCI_REG8(0x30b1), 0x02 }, + { CCI_REG8(0x30b2), 0x00 }, + { CCI_REG8(0x30b3), 0x28 }, + { CCI_REG8(0x30b4), 0x02 }, + { CCI_REG8(0x30b5), 0x00 }, + { CCI_REG8(0x3106), 0xd9 }, + { CCI_REG8(0x3503), 0x07 }, + { CCI_REG8(0x3509), 0x10 }, + { CCI_REG8(0x3600), 0xfc }, + { CCI_REG8(0x3620), 0xb7 }, + { CCI_REG8(0x3621), 0x05 }, + { CCI_REG8(0x3626), 0x31 }, + { CCI_REG8(0x3627), 0x40 }, + { CCI_REG8(0x3632), 0xa3 }, + { CCI_REG8(0x3633), 0x34 }, + { CCI_REG8(0x3634), 0x40 }, + { CCI_REG8(0x3636), 0x00 }, + { CCI_REG8(0x3660), 0x80 }, + { CCI_REG8(0x3662), 0x03 }, + { CCI_REG8(0x3664), 0xf0 }, + { CCI_REG8(0x366a), 0x10 }, + { CCI_REG8(0x366b), 0x06 }, + { CCI_REG8(0x3680), 0xf4 }, + { CCI_REG8(0x3681), 0x50 }, + { CCI_REG8(0x3682), 0x00 }, + { CCI_REG8(0x3708), 0x20 }, + { CCI_REG8(0x3709), 0x40 }, + { CCI_REG8(0x370d), 0x03 }, + { CCI_REG8(0x373b), 0x02 }, + { CCI_REG8(0x373c), 0x08 }, + { CCI_REG8(0x3742), 0x00 }, + { CCI_REG8(0x3744), 0x16 }, + { CCI_REG8(0x3745), 0x08 }, + { CCI_REG8(0x3781), 0xfc }, + { CCI_REG8(0x3788), 0x00 }, + { CCI_REG8(0x3800), 0x00 }, + { CCI_REG8(0x3801), 0x04 }, + { CCI_REG8(0x3802), 0x00 }, + { CCI_REG8(0x3803), 0x04 }, + { CCI_REG8(0x3804), 0x01 }, + { CCI_REG8(0x3805), 0x9b }, + { CCI_REG8(0x3806), 0x01 }, + { CCI_REG8(0x3807), 0x9b }, + { CCI_REG8(0x3808), 0x01 }, /* output width */ + { CCI_REG8(0x3809), 0x90 }, + { CCI_REG8(0x380a), 0x01 }, /* output height */ + { CCI_REG8(0x380b), 0x90 }, + { CCI_REG8(0x380c), 0x05 }, /* horizontal timing size */ + { CCI_REG8(0x380d), 0xf2 }, + { CCI_REG8(0x380e), 0x01 }, /* vertical timing size */ + { CCI_REG8(0x380f), 0xb6 }, + { CCI_REG8(0x3810), 0x00 }, + { CCI_REG8(0x3811), 0x04 }, + { CCI_REG8(0x3812), 0x00 }, + { CCI_REG8(0x3813), 0x04 }, + { CCI_REG8(0x3814), 0x11 }, + { CCI_REG8(0x3815), 0x11 }, + { CCI_REG8(0x3820), 0x00 }, + { CCI_REG8(0x3821), 0x00 }, + { CCI_REG8(0x382b), 0xfa }, + { CCI_REG8(0x382f), 0x04 }, + { CCI_REG8(0x3832), 0x00 }, + { CCI_REG8(0x3833), 0x05 }, + { CCI_REG8(0x3834), 0x00 }, + { CCI_REG8(0x3835), 0x05 }, + { CCI_REG8(0x3882), 0x04 }, + { CCI_REG8(0x3883), 0x00 }, + { CCI_REG8(0x38a4), 0x10 }, + { CCI_REG8(0x38a5), 0x00 }, + { CCI_REG8(0x38b1), 0x03 }, + { CCI_REG8(0x3b80), 0x00 }, + { CCI_REG8(0x3b81), 0xff }, + { CCI_REG8(0x3b82), 0x10 }, + { CCI_REG8(0x3b83), 0x00 }, + { CCI_REG8(0x3b84), 0x08 }, + { CCI_REG8(0x3b85), 0x00 }, + { CCI_REG8(0x3b86), 0x01 }, + { CCI_REG8(0x3b87), 0x00 }, + { CCI_REG8(0x3b88), 0x00 }, + { CCI_REG8(0x3b89), 0x00 }, + { CCI_REG8(0x3b8a), 0x00 }, + { CCI_REG8(0x3b8b), 0x05 }, + { CCI_REG8(0x3b8c), 0x00 }, + { CCI_REG8(0x3b8d), 0x00 }, + { CCI_REG8(0x3b8e), 0x01 }, + { CCI_REG8(0x3b8f), 0xb2 }, + { CCI_REG8(0x3b94), 0x05 }, + { CCI_REG8(0x3b95), 0xf2 }, + { CCI_REG8(0x3b96), 0xc0 }, + { CCI_REG8(0x4004), 0x04 }, + { CCI_REG8(0x404e), 0x01 }, + { CCI_REG8(0x4801), 0x0f }, + { CCI_REG8(0x4806), 0x0f }, + { CCI_REG8(0x4837), 0x43 }, + { CCI_REG8(0x5a08), 0x00 }, + { CCI_REG8(0x5a01), 0x00 }, + { CCI_REG8(0x5a03), 0x00 }, + { CCI_REG8(0x5a04), 0x10 }, + { CCI_REG8(0x5a05), 0xa0 }, + { CCI_REG8(0x5a06), 0x0c }, + { CCI_REG8(0x5a07), 0x78 }, +}; + +static const struct ov6211_mode supported_modes[] = { + { + .width = 400, + .height = 400, + .hts = 1522, + .vts = 438, + .bpp = 8, + .reg_list = { + .regs = ov6211_400x400_120fps_mode, + .num_regs = ARRAY_SIZE(ov6211_400x400_120fps_mode), + }, + }, +}; + +static int ov6211_set_test_pattern(struct ov6211 *ov6211, u32 pattern) +{ + u64 val = ov6211->pre_isp; + + if (pattern) + val |= OV6211_TEST_PATTERN_ENABLE; + else + val &= ~OV6211_TEST_PATTERN_ENABLE; + + return cci_write(ov6211->regmap, OV6211_REG_PRE_ISP, val, NULL); +} + +static int ov6211_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct ov6211 *ov6211 = container_of(ctrl->handler, struct ov6211, + ctrl_handler); + int ret; + + /* V4L2 controls are applied, when sensor is powered up for streaming */ + if (!pm_runtime_get_if_active(ov6211->dev)) + return 0; + + switch (ctrl->id) { + case V4L2_CID_ANALOGUE_GAIN: + ret = cci_write(ov6211->regmap, OV6211_REG_ANALOGUE_GAIN, + ctrl->val, NULL); + break; + case V4L2_CID_EXPOSURE: + ret = cci_write(ov6211->regmap, OV6211_REG_EXPOSURE, + ctrl->val << 4, NULL); + break; + case V4L2_CID_TEST_PATTERN: + ret = ov6211_set_test_pattern(ov6211, ctrl->val); + break; + default: + ret = -EINVAL; + break; + } + + pm_runtime_put(ov6211->dev); + + return ret; +} + +static const struct v4l2_ctrl_ops ov6211_ctrl_ops = { + .s_ctrl = ov6211_set_ctrl, +}; + +static int ov6211_init_controls(struct ov6211 *ov6211) +{ + struct v4l2_ctrl_handler *ctrl_hdlr = &ov6211->ctrl_handler; + const struct ov6211_mode *mode = &supported_modes[0]; + struct v4l2_fwnode_device_properties props; + s64 exposure_max, pixel_rate, h_blank; + struct v4l2_ctrl *ctrl; + int ret; + + v4l2_ctrl_handler_init(ctrl_hdlr, 9); + + ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, &ov6211_ctrl_ops, + V4L2_CID_LINK_FREQ, + ARRAY_SIZE(ov6211_link_freq_menu) - 1, + 0, ov6211_link_freq_menu); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + pixel_rate = ov6211_link_freq_menu[0] / mode->bpp; + v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_PIXEL_RATE, + 0, pixel_rate, 1, pixel_rate); + + h_blank = mode->hts - mode->width; + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_HBLANK, + h_blank, h_blank, 1, h_blank); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + ctrl = v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_VBLANK, + mode->vts - mode->height, + mode->vts - mode->height, 1, + mode->vts - mode->height); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; + + v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, + OV6211_ANALOGUE_GAIN_MIN, OV6211_ANALOGUE_GAIN_MAX, + OV6211_ANALOGUE_GAIN_STEP, + OV6211_ANALOGUE_GAIN_DEFAULT); + + exposure_max = (mode->vts - OV6211_EXPOSURE_MAX_MARGIN); + v4l2_ctrl_new_std(ctrl_hdlr, &ov6211_ctrl_ops, + V4L2_CID_EXPOSURE, + OV6211_EXPOSURE_MIN, exposure_max, + OV6211_EXPOSURE_STEP, + OV6211_EXPOSURE_DEFAULT); + + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &ov6211_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(ov6211_test_pattern_menu) - 1, + 0, 0, ov6211_test_pattern_menu); + + if (ctrl_hdlr->error) + return ctrl_hdlr->error; + + ret = v4l2_fwnode_device_parse(ov6211->dev, &props); + if (ret) + goto error_free_hdlr; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &ov6211_ctrl_ops, + &props); + if (ret) + goto error_free_hdlr; + + ov6211->sd.ctrl_handler = ctrl_hdlr; + + return 0; + +error_free_hdlr: + v4l2_ctrl_handler_free(ctrl_hdlr); + + return ret; +} + +static void ov6211_update_pad_format(const struct ov6211_mode *mode, + struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_Y8_1X8; + fmt->width = mode->width; + fmt->height = mode->height; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_RAW; + fmt->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_XFER_FUNC_NONE; +} + +static int ov6211_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + const struct ov6211_reg_list *reg_list = &supported_modes[0].reg_list; + struct ov6211 *ov6211 = to_ov6211(sd); + int ret; + + ret = pm_runtime_resume_and_get(ov6211->dev); + if (ret) + return ret; + + /* Skip a step of explicit entering into the standby mode */ + ret = cci_write(ov6211->regmap, OV6211_REG_SOFTWARE_RST, + OV6211_SOFTWARE_RST, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to software reset: %d\n", ret); + goto error; + } + + ret = cci_multi_reg_write(ov6211->regmap, reg_list->regs, + reg_list->num_regs, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to set mode: %d\n", ret); + goto error; + } + + ret = __v4l2_ctrl_handler_setup(ov6211->sd.ctrl_handler); + if (ret) + goto error; + + ret = cci_write(ov6211->regmap, OV6211_REG_MODE_SELECT, + OV6211_MODE_STREAMING, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to start streaming: %d\n", ret); + goto error; + } + + return 0; + +error: + pm_runtime_put_autosuspend(ov6211->dev); + + return ret; +} + +static int ov6211_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, u32 pad, + u64 streams_mask) +{ + struct ov6211 *ov6211 = to_ov6211(sd); + int ret; + + ret = cci_write(ov6211->regmap, OV6211_REG_MODE_SELECT, + OV6211_MODE_STANDBY, NULL); + if (ret) + dev_err(ov6211->dev, "failed to stop streaming: %d\n", ret); + + pm_runtime_put_autosuspend(ov6211->dev); + + return ret; +} + +static int ov6211_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_format *fmt) +{ + struct v4l2_mbus_framefmt *format; + const struct ov6211_mode *mode; + + format = v4l2_subdev_state_get_format(state, 0); + + mode = v4l2_find_nearest_size(supported_modes, + ARRAY_SIZE(supported_modes), + width, height, + fmt->format.width, + fmt->format.height); + + ov6211_update_pad_format(mode, &fmt->format); + *format = fmt->format; + + return 0; +} + +static int ov6211_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_mbus_code_enum *code) +{ + if (code->index > 0) + return -EINVAL; + + code->code = MEDIA_BUS_FMT_Y8_1X8; + + return 0; +} + +static int ov6211_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_frame_size_enum *fse) +{ + if (fse->index >= ARRAY_SIZE(supported_modes)) + return -EINVAL; + + if (fse->code != MEDIA_BUS_FMT_Y8_1X8) + return -EINVAL; + + fse->min_width = supported_modes[fse->index].width; + fse->max_width = fse->min_width; + fse->min_height = supported_modes[fse->index].height; + fse->max_height = fse->min_height; + + return 0; +} + +static int ov6211_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_format fmt = { + .which = V4L2_SUBDEV_FORMAT_TRY, + .pad = 0, + .format = { + .code = MEDIA_BUS_FMT_Y8_1X8, + .width = supported_modes[0].width, + .height = supported_modes[0].height, + }, + }; + + ov6211_set_pad_format(sd, state, &fmt); + + return 0; +} + +static const struct v4l2_subdev_video_ops ov6211_video_ops = { + .s_stream = v4l2_subdev_s_stream_helper, +}; + +static const struct v4l2_subdev_pad_ops ov6211_pad_ops = { + .set_fmt = ov6211_set_pad_format, + .get_fmt = v4l2_subdev_get_fmt, + .enum_mbus_code = ov6211_enum_mbus_code, + .enum_frame_size = ov6211_enum_frame_size, + .enable_streams = ov6211_enable_streams, + .disable_streams = ov6211_disable_streams, +}; + +static const struct v4l2_subdev_ops ov6211_subdev_ops = { + .video = &ov6211_video_ops, + .pad = &ov6211_pad_ops, +}; + +static const struct v4l2_subdev_internal_ops ov6211_internal_ops = { + .init_state = ov6211_init_state, +}; + +static const struct media_entity_operations ov6211_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int ov6211_identify_sensor(struct ov6211 *ov6211) +{ + u64 val; + int ret; + + ret = cci_read(ov6211->regmap, OV6211_REG_CHIP_ID, &val, NULL); + if (ret) { + dev_err(ov6211->dev, "failed to read chip id: %d\n", ret); + return ret; + } + + if (val != OV6211_CHIP_ID) { + dev_err(ov6211->dev, "chip id mismatch: %x!=%llx\n", + OV6211_CHIP_ID, val); + return -ENODEV; + } + + ret = cci_read(ov6211->regmap, OV6211_REG_PRE_ISP, + &ov6211->pre_isp, NULL); + if (ret) + dev_err(ov6211->dev, "failed to read pre_isp: %d\n", ret); + + return ret; +} + +static int ov6211_check_hwcfg(struct ov6211 *ov6211) +{ + struct fwnode_handle *fwnode = dev_fwnode(ov6211->dev), *ep; + struct v4l2_fwnode_endpoint bus_cfg = { + .bus_type = V4L2_MBUS_CSI2_DPHY, + }; + unsigned long freq_bitmap; + int ret; + + if (!fwnode) + return -ENODEV; + + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); + if (!ep) + return -EINVAL; + + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); + fwnode_handle_put(ep); + if (ret) + return ret; + + ret = v4l2_link_freq_to_bitmap(ov6211->dev, bus_cfg.link_frequencies, + bus_cfg.nr_of_link_frequencies, + ov6211_link_freq_menu, + ARRAY_SIZE(ov6211_link_freq_menu), + &freq_bitmap); + + v4l2_fwnode_endpoint_free(&bus_cfg); + + return ret; +} + +static int ov6211_power_on(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov6211 *ov6211 = to_ov6211(sd); + int ret; + + ret = regulator_bulk_enable(OV6211_NUM_SUPPLIES, ov6211->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(ov6211->reset_gpio, 0); + usleep_range(10 * USEC_PER_MSEC, 15 * USEC_PER_MSEC); + + ret = clk_prepare_enable(ov6211->xvclk); + if (ret) + goto reset_gpio; + + return 0; + +reset_gpio: + gpiod_set_value_cansleep(ov6211->reset_gpio, 1); + + regulator_bulk_disable(OV6211_NUM_SUPPLIES, ov6211->supplies); + + return ret; +} + +static int ov6211_power_off(struct device *dev) +{ + struct v4l2_subdev *sd = dev_get_drvdata(dev); + struct ov6211 *ov6211 = to_ov6211(sd); + + clk_disable_unprepare(ov6211->xvclk); + + gpiod_set_value_cansleep(ov6211->reset_gpio, 1); + + regulator_bulk_disable(OV6211_NUM_SUPPLIES, ov6211->supplies); + + return 0; +} + +static int ov6211_probe(struct i2c_client *client) +{ + struct ov6211 *ov6211; + unsigned long freq; + unsigned int i; + int ret; + + ov6211 = devm_kzalloc(&client->dev, sizeof(*ov6211), GFP_KERNEL); + if (!ov6211) + return -ENOMEM; + + ov6211->dev = &client->dev; + + v4l2_i2c_subdev_init(&ov6211->sd, client, &ov6211_subdev_ops); + + ov6211->regmap = devm_cci_regmap_init_i2c(client, 16); + if (IS_ERR(ov6211->regmap)) + return dev_err_probe(ov6211->dev, PTR_ERR(ov6211->regmap), + "failed to init CCI\n"); + + ov6211->xvclk = devm_v4l2_sensor_clk_get(ov6211->dev, NULL); + if (IS_ERR(ov6211->xvclk)) + return dev_err_probe(ov6211->dev, PTR_ERR(ov6211->xvclk), + "failed to get XVCLK clock\n"); + + freq = clk_get_rate(ov6211->xvclk); + if (freq && freq != OV6211_MCLK_FREQ_24MHZ) + return dev_err_probe(ov6211->dev, -EINVAL, + "XVCLK clock frequency %lu is not supported\n", + freq); + + ret = ov6211_check_hwcfg(ov6211); + if (ret) + return dev_err_probe(ov6211->dev, ret, + "failed to check HW configuration\n"); + + ov6211->reset_gpio = devm_gpiod_get_optional(ov6211->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ov6211->reset_gpio)) + return dev_err_probe(ov6211->dev, PTR_ERR(ov6211->reset_gpio), + "cannot get reset GPIO\n"); + + for (i = 0; i < OV6211_NUM_SUPPLIES; i++) + ov6211->supplies[i].supply = ov6211_supply_names[i]; + + ret = devm_regulator_bulk_get(ov6211->dev, OV6211_NUM_SUPPLIES, + ov6211->supplies); + if (ret) + return dev_err_probe(ov6211->dev, ret, + "failed to get supply regulators\n"); + + /* The sensor must be powered on to read the CHIP_ID register */ + ret = ov6211_power_on(ov6211->dev); + if (ret) + return ret; + + ret = ov6211_identify_sensor(ov6211); + if (ret) { + dev_err_probe(ov6211->dev, ret, "failed to find sensor\n"); + goto power_off; + } + + ret = ov6211_init_controls(ov6211); + if (ret) { + dev_err_probe(ov6211->dev, ret, "failed to init controls\n"); + goto power_off; + } + + ov6211->sd.state_lock = ov6211->ctrl_handler.lock; + ov6211->sd.internal_ops = &ov6211_internal_ops; + ov6211->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ov6211->sd.entity.ops = &ov6211_subdev_entity_ops; + ov6211->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + ov6211->pad.flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&ov6211->sd.entity, 1, &ov6211->pad); + if (ret) { + dev_err_probe(ov6211->dev, ret, + "failed to init media entity pads\n"); + goto v4l2_ctrl_handler_free; + } + + ret = v4l2_subdev_init_finalize(&ov6211->sd); + if (ret < 0) { + dev_err_probe(ov6211->dev, ret, + "failed to init media entity pads\n"); + goto media_entity_cleanup; + } + + pm_runtime_set_active(ov6211->dev); + pm_runtime_enable(ov6211->dev); + + ret = v4l2_async_register_subdev_sensor(&ov6211->sd); + if (ret < 0) { + dev_err_probe(ov6211->dev, ret, + "failed to register V4L2 subdev\n"); + goto subdev_cleanup; + } + + /* Enable runtime PM and turn off the device */ + pm_runtime_idle(ov6211->dev); + pm_runtime_set_autosuspend_delay(ov6211->dev, 1000); + pm_runtime_use_autosuspend(ov6211->dev); + + return 0; + +subdev_cleanup: + v4l2_subdev_cleanup(&ov6211->sd); + pm_runtime_disable(ov6211->dev); + pm_runtime_set_suspended(ov6211->dev); + +media_entity_cleanup: + media_entity_cleanup(&ov6211->sd.entity); + +v4l2_ctrl_handler_free: + v4l2_ctrl_handler_free(ov6211->sd.ctrl_handler); + +power_off: + ov6211_power_off(ov6211->dev); + + return ret; +} + +static void ov6211_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct ov6211 *ov6211 = to_ov6211(sd); + + v4l2_async_unregister_subdev(sd); + v4l2_subdev_cleanup(sd); + media_entity_cleanup(&sd->entity); + v4l2_ctrl_handler_free(sd->ctrl_handler); + pm_runtime_disable(ov6211->dev); + + if (!pm_runtime_status_suspended(ov6211->dev)) { + ov6211_power_off(ov6211->dev); + pm_runtime_set_suspended(ov6211->dev); + } +} + +static const struct dev_pm_ops ov6211_pm_ops = { + SET_RUNTIME_PM_OPS(ov6211_power_off, ov6211_power_on, NULL) +}; + +static const struct of_device_id ov6211_of_match[] = { + { .compatible = "ovti,ov6211" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ov6211_of_match); + +static struct i2c_driver ov6211_i2c_driver = { + .driver = { + .name = "ov6211", + .pm = &ov6211_pm_ops, + .of_match_table = ov6211_of_match, + }, + .probe = ov6211_probe, + .remove = ov6211_remove, +}; + +module_i2c_driver(ov6211_i2c_driver); + +MODULE_AUTHOR("Vladimir Zapolskiy <vladimir.zapolskiy@linaro.org>"); +MODULE_DESCRIPTION("OmniVision OV6211 sensor driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c index a5da4fe47e0b..78b62c169b99 100644 --- a/drivers/media/i2c/ov64a40.c +++ b/drivers/media/i2c/ov64a40.c @@ -2990,7 +2990,6 @@ static int ov64a40_start_streaming(struct ov64a40 *ov64a40, return 0; error_power_off: - pm_runtime_mark_last_busy(ov64a40->dev); pm_runtime_put_autosuspend(ov64a40->dev); return ret; @@ -3000,7 +2999,6 @@ static int ov64a40_stop_streaming(struct ov64a40 *ov64a40, struct v4l2_subdev_state *state) { cci_update_bits(ov64a40->cci, OV64A40_REG_SMIA, BIT(0), 0, NULL); - pm_runtime_mark_last_busy(ov64a40->dev); pm_runtime_put_autosuspend(ov64a40->dev); __v4l2_ctrl_grab(ov64a40->link_freq, false); @@ -3329,10 +3327,8 @@ static int ov64a40_set_ctrl(struct v4l2_ctrl *ctrl) break; } - if (pm_status > 0) { - pm_runtime_mark_last_busy(ov64a40->dev); + if (pm_status > 0) pm_runtime_put_autosuspend(ov64a40->dev); - } return ret; } @@ -3550,7 +3546,7 @@ static int ov64a40_probe(struct i2c_client *client) return PTR_ERR(ov64a40->cci); } - ov64a40->xclk = devm_clk_get(&client->dev, NULL); + ov64a40->xclk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(ov64a40->xclk)) return dev_err_probe(&client->dev, PTR_ERR(ov64a40->xclk), "Failed to get clock\n"); @@ -3622,7 +3618,6 @@ static int ov64a40_probe(struct i2c_client *client) goto error_subdev_cleanup; } - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c deleted file mode 100644 index 9c7627161142..000000000000 --- a/drivers/media/i2c/ov6650.c +++ /dev/null @@ -1,1149 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * V4L2 subdevice driver for OmniVision OV6650 Camera Sensor - * - * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl> - * - * Based on OmniVision OV96xx Camera Driver - * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com> - * - * Based on ov772x camera driver: - * Copyright (C) 2008 Renesas Solutions Corp. - * Kuninori Morimoto <morimoto.kuninori@renesas.com> - * - * Based on ov7670 and soc_camera_platform driver, - * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net> - * Copyright (C) 2008 Magnus Damm - * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de> - * - * Hardware specific bits initially based on former work by Matt Callow - * drivers/media/video/omap/sensor_ov6650.c - * Copyright (C) 2006 Matt Callow - */ - -#include <linux/bitops.h> -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/slab.h> -#include <linux/v4l2-mediabus.h> -#include <linux/module.h> - -#include <media/v4l2-ctrls.h> -#include <media/v4l2-device.h> - -/* Register definitions */ -#define REG_GAIN 0x00 /* range 00 - 3F */ -#define REG_BLUE 0x01 -#define REG_RED 0x02 -#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */ -#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */ - -#define REG_BRT 0x06 - -#define REG_PIDH 0x0a -#define REG_PIDL 0x0b - -#define REG_AECH 0x10 -#define REG_CLKRC 0x11 /* Data Format and Internal Clock */ - /* [7:6] Input system clock (MHz)*/ - /* 00=8, 01=12, 10=16, 11=24 */ - /* [5:0]: Internal Clock Pre-Scaler */ -#define REG_COMA 0x12 /* [7] Reset */ -#define REG_COMB 0x13 -#define REG_COMC 0x14 -#define REG_COMD 0x15 -#define REG_COML 0x16 -#define REG_HSTRT 0x17 -#define REG_HSTOP 0x18 -#define REG_VSTRT 0x19 -#define REG_VSTOP 0x1a -#define REG_PSHFT 0x1b -#define REG_MIDH 0x1c -#define REG_MIDL 0x1d -#define REG_HSYNS 0x1e -#define REG_HSYNE 0x1f -#define REG_COME 0x20 -#define REG_YOFF 0x21 -#define REG_UOFF 0x22 -#define REG_VOFF 0x23 -#define REG_AEW 0x24 -#define REG_AEB 0x25 -#define REG_COMF 0x26 -#define REG_COMG 0x27 -#define REG_COMH 0x28 -#define REG_COMI 0x29 - -#define REG_FRARL 0x2b -#define REG_COMJ 0x2c -#define REG_COMK 0x2d -#define REG_AVGY 0x2e -#define REG_REF0 0x2f -#define REG_REF1 0x30 -#define REG_REF2 0x31 -#define REG_FRAJH 0x32 -#define REG_FRAJL 0x33 -#define REG_FACT 0x34 -#define REG_L1AEC 0x35 -#define REG_AVGU 0x36 -#define REG_AVGV 0x37 - -#define REG_SPCB 0x60 -#define REG_SPCC 0x61 -#define REG_GAM1 0x62 -#define REG_GAM2 0x63 -#define REG_GAM3 0x64 -#define REG_SPCD 0x65 - -#define REG_SPCE 0x68 -#define REG_ADCL 0x69 - -#define REG_RMCO 0x6c -#define REG_GMCO 0x6d -#define REG_BMCO 0x6e - - -/* Register bits, values, etc. */ -#define OV6650_PIDH 0x66 /* high byte of product ID number */ -#define OV6650_PIDL 0x50 /* low byte of product ID number */ -#define OV6650_MIDH 0x7F /* high byte of mfg ID */ -#define OV6650_MIDL 0xA2 /* low byte of mfg ID */ - -#define DEF_GAIN 0x00 -#define DEF_BLUE 0x80 -#define DEF_RED 0x80 - -#define SAT_SHIFT 4 -#define SAT_MASK (0xf << SAT_SHIFT) -#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK) - -#define HUE_EN BIT(5) -#define HUE_MASK 0x1f -#define DEF_HUE 0x10 -#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK)) - -#define DEF_AECH 0x4D - -#define CLKRC_8MHz 0x00 -#define CLKRC_12MHz 0x40 -#define CLKRC_16MHz 0x80 -#define CLKRC_24MHz 0xc0 -#define CLKRC_DIV_MASK 0x3f -#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1) -#define DEF_CLKRC 0x00 - -#define COMA_RESET BIT(7) -#define COMA_QCIF BIT(5) -#define COMA_RAW_RGB BIT(4) -#define COMA_RGB BIT(3) -#define COMA_BW BIT(2) -#define COMA_WORD_SWAP BIT(1) -#define COMA_BYTE_SWAP BIT(0) -#define DEF_COMA 0x00 - -#define COMB_FLIP_V BIT(7) -#define COMB_FLIP_H BIT(5) -#define COMB_BAND_FILTER BIT(4) -#define COMB_AWB BIT(2) -#define COMB_AGC BIT(1) -#define COMB_AEC BIT(0) -#define DEF_COMB 0x5f - -#define COML_ONE_CHANNEL BIT(7) - -#define DEF_HSTRT 0x24 -#define DEF_HSTOP 0xd4 -#define DEF_VSTRT 0x04 -#define DEF_VSTOP 0x94 - -#define COMF_HREF_LOW BIT(4) - -#define COMJ_PCLK_RISING BIT(4) -#define COMJ_VSYNC_HIGH BIT(0) - -/* supported resolutions */ -#define W_QCIF (DEF_HSTOP - DEF_HSTRT) -#define W_CIF (W_QCIF << 1) -#define H_QCIF (DEF_VSTOP - DEF_VSTRT) -#define H_CIF (H_QCIF << 1) - -#define FRAME_RATE_MAX 30 - - -struct ov6650_reg { - u8 reg; - u8 val; -}; - -struct ov6650 { - struct v4l2_subdev subdev; - struct v4l2_ctrl_handler hdl; - struct { - /* exposure/autoexposure cluster */ - struct v4l2_ctrl *autoexposure; - struct v4l2_ctrl *exposure; - }; - struct { - /* gain/autogain cluster */ - struct v4l2_ctrl *autogain; - struct v4l2_ctrl *gain; - }; - struct { - /* blue/red/autowhitebalance cluster */ - struct v4l2_ctrl *autowb; - struct v4l2_ctrl *blue; - struct v4l2_ctrl *red; - }; - struct clk *clk; - bool half_scale; /* scale down output by 2 */ - struct v4l2_rect rect; /* sensor cropping window */ - struct v4l2_fract tpf; /* as requested with set_frame_interval */ - u32 code; -}; - -struct ov6650_xclk { - unsigned long rate; - u8 clkrc; -}; - -static const struct ov6650_xclk ov6650_xclk[] = { -{ - .rate = 8000000, - .clkrc = CLKRC_8MHz, -}, -{ - .rate = 12000000, - .clkrc = CLKRC_12MHz, -}, -{ - .rate = 16000000, - .clkrc = CLKRC_16MHz, -}, -{ - .rate = 24000000, - .clkrc = CLKRC_24MHz, -}, -}; - -static u32 ov6650_codes[] = { - MEDIA_BUS_FMT_YUYV8_2X8, - MEDIA_BUS_FMT_UYVY8_2X8, - MEDIA_BUS_FMT_YVYU8_2X8, - MEDIA_BUS_FMT_VYUY8_2X8, - MEDIA_BUS_FMT_SBGGR8_1X8, - MEDIA_BUS_FMT_Y8_1X8, -}; - -static const struct v4l2_mbus_framefmt ov6650_def_fmt = { - .width = W_CIF, - .height = H_CIF, - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .colorspace = V4L2_COLORSPACE_SRGB, - .field = V4L2_FIELD_NONE, - .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, - .quantization = V4L2_QUANTIZATION_DEFAULT, - .xfer_func = V4L2_XFER_FUNC_DEFAULT, -}; - -/* read a register */ -static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val) -{ - int ret; - u8 data = reg; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - msg.flags = I2C_M_RD; - ret = i2c_transfer(client->adapter, &msg, 1); - if (ret < 0) - goto err; - - *val = data; - return 0; - -err: - dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg); - return ret; -} - -/* write a register */ -static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val) -{ - int ret; - unsigned char data[2] = { reg, val }; - struct i2c_msg msg = { - .addr = client->addr, - .flags = 0, - .len = 2, - .buf = data, - }; - - ret = i2c_transfer(client->adapter, &msg, 1); - udelay(100); - - if (ret < 0) { - dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg); - return ret; - } - return 0; -} - - -/* Read a register, alter its bits, write it back */ -static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask) -{ - u8 val; - int ret; - - ret = ov6650_reg_read(client, reg, &val); - if (ret) { - dev_err(&client->dev, - "[Read]-Modify-Write of register 0x%02x failed!\n", - reg); - return ret; - } - - val &= ~mask; - val |= set; - - ret = ov6650_reg_write(client, reg, val); - if (ret) - dev_err(&client->dev, - "Read-Modify-[Write] of register 0x%02x failed!\n", - reg); - - return ret; -} - -static struct ov6650 *to_ov6650(const struct i2c_client *client) -{ - return container_of(i2c_get_clientdata(client), struct ov6650, subdev); -} - -/* Start/Stop streaming from the device */ -static int ov6650_s_stream(struct v4l2_subdev *sd, int enable) -{ - return 0; -} - -/* Get status of additional camera capabilities */ -static int ov6550_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); - struct v4l2_subdev *sd = &priv->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - uint8_t reg, reg2; - int ret; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - ret = ov6650_reg_read(client, REG_GAIN, ®); - if (!ret) - priv->gain->val = reg; - return ret; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = ov6650_reg_read(client, REG_BLUE, ®); - if (!ret) - ret = ov6650_reg_read(client, REG_RED, ®2); - if (!ret) { - priv->blue->val = reg; - priv->red->val = reg2; - } - return ret; - case V4L2_CID_EXPOSURE_AUTO: - ret = ov6650_reg_read(client, REG_AECH, ®); - if (!ret) - priv->exposure->val = reg; - return ret; - } - return -EINVAL; -} - -/* Set status of additional camera capabilities */ -static int ov6550_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct ov6650 *priv = container_of(ctrl->handler, struct ov6650, hdl); - struct v4l2_subdev *sd = &priv->subdev; - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_AGC : 0, COMB_AGC); - if (!ret && !ctrl->val) - ret = ov6650_reg_write(client, REG_GAIN, priv->gain->val); - return ret; - case V4L2_CID_AUTO_WHITE_BALANCE: - ret = ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_AWB : 0, COMB_AWB); - if (!ret && !ctrl->val) { - ret = ov6650_reg_write(client, REG_BLUE, priv->blue->val); - if (!ret) - ret = ov6650_reg_write(client, REG_RED, - priv->red->val); - } - return ret; - case V4L2_CID_SATURATION: - return ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->val), - SAT_MASK); - case V4L2_CID_HUE: - return ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->val), - HUE_MASK); - case V4L2_CID_BRIGHTNESS: - return ov6650_reg_write(client, REG_BRT, ctrl->val); - case V4L2_CID_EXPOSURE_AUTO: - ret = ov6650_reg_rmw(client, REG_COMB, ctrl->val == - V4L2_EXPOSURE_AUTO ? COMB_AEC : 0, COMB_AEC); - if (!ret && ctrl->val == V4L2_EXPOSURE_MANUAL) - ret = ov6650_reg_write(client, REG_AECH, - priv->exposure->val); - return ret; - case V4L2_CID_GAMMA: - return ov6650_reg_write(client, REG_GAM1, ctrl->val); - case V4L2_CID_VFLIP: - return ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_FLIP_V : 0, COMB_FLIP_V); - case V4L2_CID_HFLIP: - return ov6650_reg_rmw(client, REG_COMB, - ctrl->val ? COMB_FLIP_H : 0, COMB_FLIP_H); - } - - return -EINVAL; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int ov6650_get_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - int ret; - u8 val; - - if (reg->reg & ~0xff) - return -EINVAL; - - reg->size = 1; - - ret = ov6650_reg_read(client, reg->reg, &val); - if (!ret) - reg->val = (__u64)val; - - return ret; -} - -static int ov6650_set_register(struct v4l2_subdev *sd, - const struct v4l2_dbg_register *reg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - - if (reg->reg & ~0xff || reg->val & ~0xff) - return -EINVAL; - - return ov6650_reg_write(client, reg->reg, reg->val); -} -#endif - -static int ov6650_s_power(struct v4l2_subdev *sd, int on) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - int ret = 0; - - if (on) - ret = clk_prepare_enable(priv->clk); - else - clk_disable_unprepare(priv->clk); - - return ret; -} - -static int ov6650_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect *rect; - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - /* pre-select try crop rectangle */ - rect = v4l2_subdev_state_get_crop(sd_state, 0); - - } else { - /* pre-select active crop rectangle */ - rect = &priv->rect; - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.left = DEF_HSTRT << 1; - sel->r.top = DEF_VSTRT << 1; - sel->r.width = W_CIF; - sel->r.height = H_CIF; - return 0; - - case V4L2_SEL_TGT_CROP: - /* use selected crop rectangle */ - sel->r = *rect; - return 0; - - default: - return -EINVAL; - } -} - -static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect) -{ - return width > rect->width >> 1 || height > rect->height >> 1; -} - -static void ov6650_bind_align_crop_rectangle(struct v4l2_rect *rect) -{ - v4l_bound_align_image(&rect->width, 2, W_CIF, 1, - &rect->height, 2, H_CIF, 1, 0); - v4l_bound_align_image(&rect->left, DEF_HSTRT << 1, - (DEF_HSTRT << 1) + W_CIF - (__s32)rect->width, 1, - &rect->top, DEF_VSTRT << 1, - (DEF_VSTRT << 1) + H_CIF - (__s32)rect->height, - 1, 0); -} - -static int ov6650_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_selection *sel) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - int ret; - - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - ov6650_bind_align_crop_rectangle(&sel->r); - - if (sel->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_rect *crop = - v4l2_subdev_state_get_crop(sd_state, 0); - struct v4l2_mbus_framefmt *mf = - v4l2_subdev_state_get_format(sd_state, 0); - /* detect current pad config scaling factor */ - bool half_scale = !is_unscaled_ok(mf->width, mf->height, crop); - - /* store new crop rectangle */ - *crop = sel->r; - - /* adjust frame size */ - mf->width = crop->width >> half_scale; - mf->height = crop->height >> half_scale; - - return 0; - } - - /* V4L2_SUBDEV_FORMAT_ACTIVE */ - - /* apply new crop rectangle */ - ret = ov6650_reg_write(client, REG_HSTRT, sel->r.left >> 1); - if (!ret) { - priv->rect.width += priv->rect.left - sel->r.left; - priv->rect.left = sel->r.left; - ret = ov6650_reg_write(client, REG_HSTOP, - (sel->r.left + sel->r.width) >> 1); - } - if (!ret) { - priv->rect.width = sel->r.width; - ret = ov6650_reg_write(client, REG_VSTRT, sel->r.top >> 1); - } - if (!ret) { - priv->rect.height += priv->rect.top - sel->r.top; - priv->rect.top = sel->r.top; - ret = ov6650_reg_write(client, REG_VSTOP, - (sel->r.top + sel->r.height) >> 1); - } - if (!ret) - priv->rect.height = sel->r.height; - - return ret; -} - -static int ov6650_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - if (format->pad) - return -EINVAL; - - /* initialize response with default media bus frame format */ - *mf = ov6650_def_fmt; - - /* update media bus format code and frame size */ - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_state_get_format(sd_state, 0); - - mf->width = try_fmt->width; - mf->height = try_fmt->height; - mf->code = try_fmt->code; - - } else { - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - } - return 0; -} - -#define to_clkrc(div) ((div) - 1) - -/* set the format we will capture in */ -static int ov6650_s_fmt(struct v4l2_subdev *sd, u32 code, bool half_scale) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask; - int ret; - - /* select color matrix configuration for given color encoding */ - switch (code) { - case MEDIA_BUS_FMT_Y8_1X8: - dev_dbg(&client->dev, "pixel format GREY8_1X8\n"); - coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP; - coma_set |= COMA_BW; - break; - case MEDIA_BUS_FMT_YUYV8_2X8: - dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n"); - coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP; - coma_set |= COMA_WORD_SWAP; - break; - case MEDIA_BUS_FMT_YVYU8_2X8: - dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n"); - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP | - COMA_BYTE_SWAP; - break; - case MEDIA_BUS_FMT_UYVY8_2X8: - dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n"); - if (half_scale) { - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; - coma_set |= COMA_BYTE_SWAP; - } else { - coma_mask |= COMA_RGB | COMA_BW; - coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; - } - break; - case MEDIA_BUS_FMT_VYUY8_2X8: - dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n"); - if (half_scale) { - coma_mask |= COMA_RGB | COMA_BW; - coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP; - } else { - coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP; - coma_set |= COMA_BYTE_SWAP; - } - break; - case MEDIA_BUS_FMT_SBGGR8_1X8: - dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n"); - coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP; - coma_set |= COMA_RAW_RGB | COMA_RGB; - break; - default: - dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code); - return -EINVAL; - } - - if (code == MEDIA_BUS_FMT_Y8_1X8 || - code == MEDIA_BUS_FMT_SBGGR8_1X8) { - coml_mask = COML_ONE_CHANNEL; - coml_set = 0; - } else { - coml_mask = 0; - coml_set = COML_ONE_CHANNEL; - } - - if (half_scale) { - dev_dbg(&client->dev, "max resolution: QCIF\n"); - coma_set |= COMA_QCIF; - } else { - dev_dbg(&client->dev, "max resolution: CIF\n"); - coma_mask |= COMA_QCIF; - } - - ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask); - if (!ret) { - priv->half_scale = half_scale; - - ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask); - } - if (!ret) - priv->code = code; - - return ret; -} - -static int ov6650_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct v4l2_mbus_framefmt *mf = &format->format; - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_rect *crop; - bool half_scale; - - if (format->pad) - return -EINVAL; - - switch (mf->code) { - case MEDIA_BUS_FMT_Y10_1X10: - mf->code = MEDIA_BUS_FMT_Y8_1X8; - fallthrough; - case MEDIA_BUS_FMT_Y8_1X8: - case MEDIA_BUS_FMT_YVYU8_2X8: - case MEDIA_BUS_FMT_YUYV8_2X8: - case MEDIA_BUS_FMT_VYUY8_2X8: - case MEDIA_BUS_FMT_UYVY8_2X8: - break; - default: - mf->code = MEDIA_BUS_FMT_SBGGR8_1X8; - fallthrough; - case MEDIA_BUS_FMT_SBGGR8_1X8: - break; - } - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) - crop = v4l2_subdev_state_get_crop(sd_state, 0); - else - crop = &priv->rect; - - half_scale = !is_unscaled_ok(mf->width, mf->height, crop); - - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_state_get_format(sd_state, 0); - - /* store new mbus frame format code and size in pad config */ - try_fmt->width = crop->width >> half_scale; - try_fmt->height = crop->height >> half_scale; - try_fmt->code = mf->code; - - /* return default mbus frame format updated with pad config */ - *mf = ov6650_def_fmt; - mf->width = try_fmt->width; - mf->height = try_fmt->height; - mf->code = try_fmt->code; - - } else { - int ret = 0; - - /* apply new media bus frame format and scaling if changed */ - if (mf->code != priv->code || half_scale != priv->half_scale) - ret = ov6650_s_fmt(sd, mf->code, half_scale); - if (ret) - return ret; - - /* return default format updated with active size and code */ - *mf = ov6650_def_fmt; - mf->width = priv->rect.width >> priv->half_scale; - mf->height = priv->rect.height >> priv->half_scale; - mf->code = priv->code; - } - return 0; -} - -static int ov6650_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_mbus_code_enum *code) -{ - if (code->pad || code->index >= ARRAY_SIZE(ov6650_codes)) - return -EINVAL; - - code->code = ov6650_codes[code->index]; - return 0; -} - -static int ov6650_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval_enum *fie) -{ - int i; - - /* enumerate supported frame intervals not exceeding 1 second */ - if (fie->index > CLKRC_DIV_MASK || - GET_CLKRC_DIV(fie->index) > FRAME_RATE_MAX) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(ov6650_codes); i++) - if (fie->code == ov6650_codes[i]) - break; - if (i == ARRAY_SIZE(ov6650_codes)) - return -EINVAL; - - if (!fie->width || fie->width > W_CIF || - !fie->height || fie->height > H_CIF) - return -EINVAL; - - fie->interval.numerator = GET_CLKRC_DIV(fie->index); - fie->interval.denominator = FRAME_RATE_MAX; - - return 0; -} - -static int ov6650_get_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval *ival) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ - if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - ival->interval = priv->tpf; - - dev_dbg(&client->dev, "Frame interval: %u/%u s\n", - ival->interval.numerator, ival->interval.denominator); - - return 0; -} - -static int ov6650_set_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_frame_interval *ival) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - struct v4l2_fract *tpf = &ival->interval; - int div, ret; - - /* - * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 - * subdev active state API. - */ - if (ival->which != V4L2_SUBDEV_FORMAT_ACTIVE) - return -EINVAL; - - if (tpf->numerator == 0 || tpf->denominator == 0) - div = 1; /* Reset to full rate */ - else - div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator; - - if (div == 0) - div = 1; - else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK)) - div = GET_CLKRC_DIV(CLKRC_DIV_MASK); - - ret = ov6650_reg_rmw(client, REG_CLKRC, to_clkrc(div), CLKRC_DIV_MASK); - if (!ret) { - priv->tpf.numerator = div; - priv->tpf.denominator = FRAME_RATE_MAX; - - *tpf = priv->tpf; - } - - return ret; -} - -/* Soft reset the camera. This has nothing to do with the RESET pin! */ -static int ov6650_reset(struct i2c_client *client) -{ - int ret; - - dev_dbg(&client->dev, "reset\n"); - - ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0); - if (ret) - dev_err(&client->dev, - "An error occurred while entering soft reset!\n"); - - return ret; -} - -/* program default register values */ -static int ov6650_prog_dflt(struct i2c_client *client, u8 clkrc) -{ - int ret; - - dev_dbg(&client->dev, "initializing\n"); - - ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */ - if (!ret) - ret = ov6650_reg_write(client, REG_CLKRC, clkrc); - if (!ret) - ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER); - - return ret; -} - -static int ov6650_video_probe(struct v4l2_subdev *sd) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - struct ov6650 *priv = to_ov6650(client); - const struct ov6650_xclk *xclk = NULL; - unsigned long rate; - u8 pidh, pidl, midh, midl; - int i, ret = 0; - - priv->clk = devm_clk_get(&client->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - dev_err(&client->dev, "clk request err: %d\n", ret); - return ret; - } - - rate = clk_get_rate(priv->clk); - for (i = 0; rate && i < ARRAY_SIZE(ov6650_xclk); i++) { - if (rate != ov6650_xclk[i].rate) - continue; - - xclk = &ov6650_xclk[i]; - dev_info(&client->dev, "using host default clock rate %lukHz\n", - rate / 1000); - break; - } - for (i = 0; !xclk && i < ARRAY_SIZE(ov6650_xclk); i++) { - ret = clk_set_rate(priv->clk, ov6650_xclk[i].rate); - if (ret || clk_get_rate(priv->clk) != ov6650_xclk[i].rate) - continue; - - xclk = &ov6650_xclk[i]; - dev_info(&client->dev, "using negotiated clock rate %lukHz\n", - xclk->rate / 1000); - break; - } - if (!xclk) { - dev_err(&client->dev, "unable to get supported clock rate\n"); - if (!ret) - ret = -EINVAL; - return ret; - } - - ret = ov6650_s_power(sd, 1); - if (ret < 0) - return ret; - - msleep(20); - - /* - * check and show product ID and manufacturer ID - */ - ret = ov6650_reg_read(client, REG_PIDH, &pidh); - if (!ret) - ret = ov6650_reg_read(client, REG_PIDL, &pidl); - if (!ret) - ret = ov6650_reg_read(client, REG_MIDH, &midh); - if (!ret) - ret = ov6650_reg_read(client, REG_MIDL, &midl); - - if (ret) - goto done; - - if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) { - dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n", - pidh, pidl); - ret = -ENODEV; - goto done; - } - - dev_info(&client->dev, - "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n", - pidh, pidl, midh, midl); - - ret = ov6650_reset(client); - if (!ret) - ret = ov6650_prog_dflt(client, xclk->clkrc); - if (!ret) { - /* driver default frame format, no scaling */ - ret = ov6650_s_fmt(sd, ov6650_def_fmt.code, false); - } - if (!ret) - ret = v4l2_ctrl_handler_setup(&priv->hdl); - -done: - ov6650_s_power(sd, 0); - return ret; -} - -static const struct v4l2_ctrl_ops ov6550_ctrl_ops = { - .g_volatile_ctrl = ov6550_g_volatile_ctrl, - .s_ctrl = ov6550_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops ov6650_core_ops = { -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = ov6650_get_register, - .s_register = ov6650_set_register, -#endif - .s_power = ov6650_s_power, -}; - -/* Request bus settings on camera side */ -static int ov6650_get_mbus_config(struct v4l2_subdev *sd, - unsigned int pad, - struct v4l2_mbus_config *cfg) -{ - struct i2c_client *client = v4l2_get_subdevdata(sd); - u8 comj, comf; - int ret; - - ret = ov6650_reg_read(client, REG_COMJ, &comj); - if (ret) - return ret; - - ret = ov6650_reg_read(client, REG_COMF, &comf); - if (ret) - return ret; - - cfg->type = V4L2_MBUS_PARALLEL; - - cfg->bus.parallel.flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH - | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH - : V4L2_MBUS_VSYNC_ACTIVE_LOW) - | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW - : V4L2_MBUS_HSYNC_ACTIVE_HIGH) - | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING - : V4L2_MBUS_PCLK_SAMPLE_FALLING); - return 0; -} - -static const struct v4l2_subdev_video_ops ov6650_video_ops = { - .s_stream = ov6650_s_stream, -}; - -static const struct v4l2_subdev_pad_ops ov6650_pad_ops = { - .enum_mbus_code = ov6650_enum_mbus_code, - .enum_frame_interval = ov6650_enum_frame_interval, - .get_selection = ov6650_get_selection, - .set_selection = ov6650_set_selection, - .get_fmt = ov6650_get_fmt, - .set_fmt = ov6650_set_fmt, - .get_frame_interval = ov6650_get_frame_interval, - .set_frame_interval = ov6650_set_frame_interval, - .get_mbus_config = ov6650_get_mbus_config, -}; - -static const struct v4l2_subdev_ops ov6650_subdev_ops = { - .core = &ov6650_core_ops, - .video = &ov6650_video_ops, - .pad = &ov6650_pad_ops, -}; - -static const struct v4l2_subdev_internal_ops ov6650_internal_ops = { - .registered = ov6650_video_probe, -}; - -/* - * i2c_driver function - */ -static int ov6650_probe(struct i2c_client *client) -{ - struct ov6650 *priv; - int ret; - - priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops); - v4l2_ctrl_handler_init(&priv->hdl, 13); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - priv->autogain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - priv->gain = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_GAIN, 0, 0x3f, 1, DEF_GAIN); - priv->autowb = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - priv->blue = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_BLUE_BALANCE, 0, 0xff, 1, DEF_BLUE); - priv->red = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_RED_BALANCE, 0, 0xff, 1, DEF_RED); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_SATURATION, 0, 0xf, 1, 0x8); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_HUE, 0, HUE_MASK, 1, DEF_HUE); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 0xff, 1, 0x80); - priv->autoexposure = v4l2_ctrl_new_std_menu(&priv->hdl, - &ov6550_ctrl_ops, V4L2_CID_EXPOSURE_AUTO, - V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO); - priv->exposure = v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_EXPOSURE, 0, 0xff, 1, DEF_AECH); - v4l2_ctrl_new_std(&priv->hdl, &ov6550_ctrl_ops, - V4L2_CID_GAMMA, 0, 0xff, 1, 0x12); - - priv->subdev.ctrl_handler = &priv->hdl; - if (priv->hdl.error) { - ret = priv->hdl.error; - goto ectlhdlfree; - } - - v4l2_ctrl_auto_cluster(2, &priv->autogain, 0, true); - v4l2_ctrl_auto_cluster(3, &priv->autowb, 0, true); - v4l2_ctrl_auto_cluster(2, &priv->autoexposure, - V4L2_EXPOSURE_MANUAL, true); - - priv->rect.left = DEF_HSTRT << 1; - priv->rect.top = DEF_VSTRT << 1; - priv->rect.width = W_CIF; - priv->rect.height = H_CIF; - - /* Hardware default frame interval */ - priv->tpf.numerator = GET_CLKRC_DIV(DEF_CLKRC); - priv->tpf.denominator = FRAME_RATE_MAX; - - priv->subdev.internal_ops = &ov6650_internal_ops; - - ret = v4l2_async_register_subdev(&priv->subdev); - if (!ret) - return 0; -ectlhdlfree: - v4l2_ctrl_handler_free(&priv->hdl); - - return ret; -} - -static void ov6650_remove(struct i2c_client *client) -{ - struct ov6650 *priv = to_ov6650(client); - - v4l2_async_unregister_subdev(&priv->subdev); - v4l2_ctrl_handler_free(&priv->hdl); -} - -static const struct i2c_device_id ov6650_id[] = { - { "ov6650" }, - { } -}; -MODULE_DEVICE_TABLE(i2c, ov6650_id); - -static struct i2c_driver ov6650_i2c_driver = { - .driver = { - .name = "ov6650", - }, - .probe = ov6650_probe, - .remove = ov6650_remove, - .id_table = ov6650_id, -}; - -module_i2c_driver(ov6650_i2c_driver); - -MODULE_DESCRIPTION("V4L2 subdevice driver for OmniVision OV6650 camera sensor"); -MODULE_AUTHOR("Janusz Krzysztofik <jmkrzyszt@gmail.com"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/i2c/ov7251.c b/drivers/media/i2c/ov7251.c index 31a42d81e970..27afc3fc0175 100644 --- a/drivers/media/i2c/ov7251.c +++ b/drivers/media/i2c/ov7251.c @@ -1630,7 +1630,6 @@ static int ov7251_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct ov7251 *ov7251; - unsigned int rate = 0, clk_rate = 0; int ret; int i; @@ -1646,33 +1645,12 @@ static int ov7251_probe(struct i2c_client *client) return ret; /* get system clock (xclk) */ - ov7251->xclk = devm_clk_get_optional(dev, NULL); + ov7251->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(ov7251->xclk)) return dev_err_probe(dev, PTR_ERR(ov7251->xclk), "could not get xclk"); - /* - * We could have either a 24MHz or 19.2MHz clock rate from either DT or - * ACPI. We also need to support the IPU3 case which will have both an - * external clock AND a clock-frequency property. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (ret && !ov7251->xclk) - return dev_err_probe(dev, ret, "invalid clock config\n"); - - clk_rate = clk_get_rate(ov7251->xclk); - ov7251->xclk_freq = clk_rate ? clk_rate : rate; - - if (ov7251->xclk_freq == 0) - return dev_err_probe(dev, -EINVAL, "invalid clock frequency\n"); - - if (!ret && ov7251->xclk) { - ret = clk_set_rate(ov7251->xclk, rate); - if (ret) - return dev_err_probe(dev, ret, - "failed to set clock rate\n"); - } + ov7251->xclk_freq = clk_get_rate(ov7251->xclk); for (i = 0; i < ARRAY_SIZE(supported_xclk_rates); i++) if (ov7251->xclk_freq == supported_xclk_rates[i]) diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index 1f1c0de8e510..632fb80469be 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -1036,13 +1036,10 @@ static int ov7740_probe(struct i2c_client *client) if (!ov7740) return -ENOMEM; - ov7740->xvclk = devm_clk_get(&client->dev, "xvclk"); - if (IS_ERR(ov7740->xvclk)) { - ret = PTR_ERR(ov7740->xvclk); - dev_err(&client->dev, - "OV7740: fail to get xvclk: %d\n", ret); - return ret; - } + ov7740->xvclk = devm_v4l2_sensor_clk_get(&client->dev, "xvclk"); + if (IS_ERR(ov7740->xvclk)) + return dev_err_probe(&client->dev, PTR_ERR(ov7740->xvclk), + "OV7740: fail to get xvclk\n"); ret = ov7740_probe_dt(client, ov7740); if (ret) diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c index 4b6874d2a104..e2998cfa0d18 100644 --- a/drivers/media/i2c/ov8856.c +++ b/drivers/media/i2c/ov8856.c @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2019 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -10,6 +9,8 @@ #include <linux/module.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -1414,6 +1415,8 @@ static const struct ov8856_reg_list bayer_offset_configs[] = { }; struct ov8856 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -1668,7 +1671,6 @@ static int ov8856_write_reg(struct ov8856 *ov8856, u16 reg, u16 len, u32 val) static int ov8856_write_reg_list(struct ov8856 *ov8856, const struct ov8856_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); unsigned int i; int ret; @@ -1676,7 +1678,7 @@ static int ov8856_write_reg_list(struct ov8856 *ov8856, ret = ov8856_write_reg(ov8856, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov8856->dev, "failed to write reg 0x%4.4x. error = %d", r_list->regs[i].address, ret); return ret; @@ -1688,7 +1690,6 @@ static int ov8856_write_reg_list(struct ov8856 *ov8856, static int ov8856_identify_module(struct ov8856 *ov8856) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); int ret; u32 val; @@ -1701,7 +1702,7 @@ static int ov8856_identify_module(struct ov8856 *ov8856) return ret; if (val != OV8856_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(ov8856->dev, "chip id mismatch: %x!=%x", OV8856_CHIP_ID, val); return -ENXIO; } @@ -1818,7 +1819,6 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov8856 *ov8856 = container_of(ctrl->handler, struct ov8856, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); s64 exposure_max; int ret = 0; @@ -1834,7 +1834,7 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov8856->dev)) return 0; switch (ctrl->id) { @@ -1876,7 +1876,7 @@ static int ov8856_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov8856->dev); return ret; } @@ -1979,7 +1979,6 @@ static void ov8856_update_pad_format(struct ov8856 *ov8856, static int ov8856_start_streaming(struct ov8856 *ov8856) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); const struct ov8856_reg_list *reg_list; int link_freq_index, ret; @@ -1992,21 +1991,21 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) ret = ov8856_write_reg_list(ov8856, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov8856->dev, "failed to set plls"); return ret; } reg_list = &ov8856->cur_mode->reg_list; ret = ov8856_write_reg_list(ov8856, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov8856->dev, "failed to set mode"); return ret; } reg_list = &bayer_offset_configs[ov8856->cur_mbus_index]; ret = ov8856_write_reg_list(ov8856, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mbus format"); + dev_err(ov8856->dev, "failed to set mbus format"); return ret; } @@ -2017,7 +2016,7 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) ret = ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, OV8856_REG_VALUE_08BIT, OV8856_MODE_STREAMING); if (ret) { - dev_err(&client->dev, "failed to set stream"); + dev_err(ov8856->dev, "failed to set stream"); return ret; } @@ -2026,22 +2025,19 @@ static int ov8856_start_streaming(struct ov8856 *ov8856) static void ov8856_stop_streaming(struct ov8856 *ov8856) { - struct i2c_client *client = v4l2_get_subdevdata(&ov8856->sd); - if (ov8856_write_reg(ov8856, OV8856_REG_MODE_SELECT, OV8856_REG_VALUE_08BIT, OV8856_MODE_STANDBY)) - dev_err(&client->dev, "failed to set stream"); + dev_err(ov8856->dev, "failed to set stream"); } static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) { struct ov8856 *ov8856 = to_ov8856(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov8856->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov8856->dev); if (ret < 0) { mutex_unlock(&ov8856->mutex); return ret; @@ -2051,11 +2047,11 @@ static int ov8856_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov8856_stop_streaming(ov8856); - pm_runtime_put(&client->dev); + pm_runtime_put(ov8856->dev); } } else { ov8856_stop_streaming(ov8856); - pm_runtime_put(&client->dev); + pm_runtime_put(ov8856->dev); } mutex_unlock(&ov8856->mutex); @@ -2255,8 +2251,9 @@ static const struct v4l2_subdev_internal_ops ov8856_internal_ops = { }; -static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) +static int ov8856_get_hwcfg(struct ov8856 *ov8856) { + struct device *dev = ov8856->dev; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); struct v4l2_fwnode_endpoint bus_cfg = { @@ -2269,21 +2266,17 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &xvclk_rate); - if (ret) - return ret; - - if (!is_acpi_node(fwnode)) { - ov8856->xvclk = devm_clk_get(dev, "xvclk"); - if (IS_ERR(ov8856->xvclk)) { - dev_err_probe(dev, PTR_ERR(ov8856->xvclk), - "could not get xvclk clock\n"); - return PTR_ERR(ov8856->xvclk); - } + ov8856->xvclk = devm_v4l2_sensor_clk_get_legacy(dev, "xvclk", false, 0); + if (IS_ERR(ov8856->xvclk)) + return dev_err_probe(dev, PTR_ERR(ov8856->xvclk), + "could not get xvclk clock\n"); - clk_set_rate(ov8856->xvclk, xvclk_rate); - xvclk_rate = clk_get_rate(ov8856->xvclk); + xvclk_rate = clk_get_rate(ov8856->xvclk); + if (xvclk_rate != OV8856_XVCLK_19_2) + dev_warn(dev, "external clock rate %u is unsupported", + xvclk_rate); + if (!is_acpi_node(fwnode)) { ov8856->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ov8856->reset_gpio)) @@ -2299,10 +2292,6 @@ static int ov8856_get_hwcfg(struct ov8856 *ov8856, struct device *dev) return ret; } - if (xvclk_rate != OV8856_XVCLK_19_2) - dev_warn(dev, "external clock rate %u is unsupported", - xvclk_rate); - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -2365,10 +2354,10 @@ static void ov8856_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); + pm_runtime_disable(ov8856->dev); mutex_destroy(&ov8856->mutex); - ov8856_power_off(&client->dev); + ov8856_power_off(ov8856->dev); } static int ov8856_probe(struct i2c_client *client) @@ -2381,23 +2370,25 @@ static int ov8856_probe(struct i2c_client *client) if (!ov8856) return -ENOMEM; - ret = ov8856_get_hwcfg(ov8856, &client->dev); + ov8856->dev = &client->dev; + + ret = ov8856_get_hwcfg(ov8856); if (ret) return ret; v4l2_i2c_subdev_init(&ov8856->sd, client, &ov8856_subdev_ops); - full_power = acpi_dev_state_d0(&client->dev); + full_power = acpi_dev_state_d0(ov8856->dev); if (full_power) { - ret = ov8856_power_on(&client->dev); + ret = ov8856_power_on(ov8856->dev); if (ret) { - dev_err(&client->dev, "failed to power on\n"); + dev_err(ov8856->dev, "failed to power on\n"); return ret; } ret = ov8856_identify_module(ov8856); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov8856->dev, "failed to find sensor: %d", ret); goto probe_power_off; } } @@ -2407,7 +2398,7 @@ static int ov8856_probe(struct i2c_client *client) ov8856->cur_mbus_index = ov8856->cur_mode->default_mbus_index; ret = ov8856_init_controls(ov8856); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov8856->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -2418,22 +2409,22 @@ static int ov8856_probe(struct i2c_client *client) ov8856->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov8856->sd.entity, 1, &ov8856->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov8856->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } ret = v4l2_async_register_subdev_sensor(&ov8856->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov8856->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup; } /* Set the device's state to active if it's in D0 state. */ if (full_power) - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov8856->dev); + pm_runtime_enable(ov8856->dev); + pm_runtime_idle(ov8856->dev); return 0; @@ -2445,7 +2436,7 @@ probe_error_v4l2_ctrl_handler_free: mutex_destroy(&ov8856->mutex); probe_power_off: - ov8856_power_off(&client->dev); + ov8856_power_off(ov8856->dev); return ret; } diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c index 95f9ae794846..3f45f7fab833 100644 --- a/drivers/media/i2c/ov8858.c +++ b/drivers/media/i2c/ov8858.c @@ -1391,7 +1391,6 @@ static int ov8858_s_stream(struct v4l2_subdev *sd, int on) } } else { ov8858_stop_stream(ov8858); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); } @@ -1877,7 +1876,7 @@ static int ov8858_probe(struct i2c_client *client) if (!ov8858) return -ENOMEM; - ov8858->xvclk = devm_clk_get(dev, "xvclk"); + ov8858->xvclk = devm_v4l2_sensor_clk_get(dev, "xvclk"); if (IS_ERR(ov8858->xvclk)) return dev_err_probe(dev, PTR_ERR(ov8858->xvclk), "Failed to get xvclk\n"); @@ -1945,7 +1944,6 @@ static int ov8858_probe(struct i2c_client *client) goto err_power_off; } - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return 0; diff --git a/drivers/media/i2c/ov8865.c b/drivers/media/i2c/ov8865.c index a2138f7988aa..a8586df14f77 100644 --- a/drivers/media/i2c/ov8865.c +++ b/drivers/media/i2c/ov8865.c @@ -2304,14 +2304,6 @@ static int ov8865_state_configure(struct ov8865_sensor *sensor, if (sensor->state.streaming) return -EBUSY; - /* State will be configured at first power on otherwise. */ - if (pm_runtime_enabled(sensor->dev) && - !pm_runtime_suspended(sensor->dev)) { - ret = ov8865_mode_configure(sensor, mode, mbus_code); - if (ret) - return ret; - } - ret = ov8865_state_mipi_configure(sensor, mode, mbus_code); if (ret) return ret; @@ -2384,10 +2376,10 @@ static int ov8865_sensor_init(struct ov8865_sensor *sensor) } /* Configure current mode. */ - ret = ov8865_state_configure(sensor, sensor->state.mode, - sensor->state.mbus_code); + ret = ov8865_mode_configure(sensor, sensor->state.mode, + sensor->state.mbus_code); if (ret) { - dev_err(sensor->dev, "failed to configure state\n"); + dev_err(sensor->dev, "failed to configure mode\n"); return ret; } @@ -2956,7 +2948,6 @@ static int ov8865_probe(struct i2c_client *client) struct ov8865_sensor *sensor; struct v4l2_subdev *subdev; struct media_pad *pad; - unsigned int rate = 0; unsigned int i; int ret; @@ -3020,39 +3011,14 @@ static int ov8865_probe(struct i2c_client *client) /* External Clock */ - sensor->extclk = devm_clk_get(dev, NULL); - if (PTR_ERR(sensor->extclk) == -ENOENT) { - dev_info(dev, "no external clock found, continuing...\n"); - sensor->extclk = NULL; - } else if (IS_ERR(sensor->extclk)) { - dev_err(dev, "failed to get external clock\n"); - ret = PTR_ERR(sensor->extclk); - goto error_endpoint; - } - - /* - * We could have either a 24MHz or 19.2MHz clock rate from either dt or - * ACPI...but we also need to support the weird IPU3 case which will - * have an external clock AND a clock-frequency property. Check for the - * clock-frequency property and if found, set that rate if we managed - * to acquire a clock. This should cover the ACPI case. If the system - * uses devicetree then the configured rate should already be set, so - * we can just read it. - */ - ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency", - &rate); - if (!ret && sensor->extclk) { - ret = clk_set_rate(sensor->extclk, rate); - if (ret) { - dev_err_probe(dev, ret, "failed to set clock rate\n"); - goto error_endpoint; - } - } else if (ret && !sensor->extclk) { - dev_err_probe(dev, ret, "invalid clock config\n"); + sensor->extclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->extclk)) { + ret = dev_err_probe(dev, PTR_ERR(sensor->extclk), + "failed to get external clock\n"); goto error_endpoint; } - sensor->extclk_rate = rate ? rate : clk_get_rate(sensor->extclk); + sensor->extclk_rate = clk_get_rate(sensor->extclk); for (i = 0; i < ARRAY_SIZE(supported_extclk_rates); i++) { if (sensor->extclk_rate == supported_extclk_rates[i]) diff --git a/drivers/media/i2c/ov9282.c b/drivers/media/i2c/ov9282.c index c882a021cf18..a9f6176e9729 100644 --- a/drivers/media/i2c/ov9282.c +++ b/drivers/media/i2c/ov9282.c @@ -1135,11 +1135,10 @@ static int ov9282_parse_hw_config(struct ov9282 *ov9282) } /* Get sensor input clock */ - ov9282->inclk = devm_clk_get(ov9282->dev, NULL); - if (IS_ERR(ov9282->inclk)) { - dev_err(ov9282->dev, "could not get inclk"); - return PTR_ERR(ov9282->inclk); - } + ov9282->inclk = devm_v4l2_sensor_clk_get(ov9282->dev, NULL); + if (IS_ERR(ov9282->inclk)) + return dev_err_probe(ov9282->dev, PTR_ERR(ov9282->inclk), + "could not get inclk\n"); ret = ov9282_configure_regulators(ov9282); if (ret) diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c index 01dbc0ba89c8..2190c52b1433 100644 --- a/drivers/media/i2c/ov9640.c +++ b/drivers/media/i2c/ov9640.c @@ -718,9 +718,10 @@ static int ov9640_probe(struct i2c_client *client) priv->subdev.ctrl_handler = &priv->hdl; - priv->clk = devm_clk_get(&client->dev, "mclk"); + priv->clk = devm_v4l2_sensor_clk_get(&client->dev, "mclk"); if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); + ret = dev_err_probe(&client->dev, PTR_ERR(priv->clk), + "failed to get mclk\n"); goto ectrlinit; } diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c index 026ea34d6291..c94e8fe29f22 100644 --- a/drivers/media/i2c/ov9650.c +++ b/drivers/media/i2c/ov9650.c @@ -1494,9 +1494,10 @@ static int ov965x_probe(struct i2c_client *client) } if (dev_fwnode(&client->dev)) { - ov965x->clk = devm_clk_get(&client->dev, NULL); + ov965x->clk = devm_v4l2_sensor_clk_get(&client->dev, NULL); if (IS_ERR(ov965x->clk)) - return PTR_ERR(ov965x->clk); + return dev_err_probe(&client->dev, PTR_ERR(ov965x->clk), + "failed to get the clock\n"); ov965x->mclk_frequency = clk_get_rate(ov965x->clk); ret = ov965x_configure_gpios(ov965x); diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c index cae3aeefb616..0eaf33807fc9 100644 --- a/drivers/media/i2c/ov9734.c +++ b/drivers/media/i2c/ov9734.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2020 Intel Corporation. -#include <linux/unaligned.h> #include <linux/acpi.h> +#include <linux/clk.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/pm_runtime.h> +#include <linux/unaligned.h> + #include <media/v4l2-ctrls.h> #include <media/v4l2-device.h> #include <media/v4l2-fwnode.h> @@ -321,6 +323,9 @@ static const struct ov9734_mode supported_modes[] = { }; struct ov9734 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler ctrl_handler; @@ -414,7 +419,6 @@ static int ov9734_write_reg(struct ov9734 *ov9734, u16 reg, u16 len, u32 val) static int ov9734_write_reg_list(struct ov9734 *ov9734, const struct ov9734_reg_list *r_list) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); unsigned int i; int ret; @@ -422,7 +426,7 @@ static int ov9734_write_reg_list(struct ov9734 *ov9734, ret = ov9734_write_reg(ov9734, r_list->regs[i].address, 1, r_list->regs[i].val); if (ret) { - dev_err_ratelimited(&client->dev, + dev_err_ratelimited(ov9734->dev, "write reg 0x%4.4x return err = %d", r_list->regs[i].address, ret); return ret; @@ -476,7 +480,6 @@ static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) { struct ov9734 *ov9734 = container_of(ctrl->handler, struct ov9734, ctrl_handler); - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); s64 exposure_max; int ret = 0; @@ -492,7 +495,7 @@ static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) } /* V4L2 controls values will be applied only when power is already up */ - if (!pm_runtime_get_if_in_use(&client->dev)) + if (!pm_runtime_get_if_in_use(ov9734->dev)) return 0; switch (ctrl->id) { @@ -525,7 +528,7 @@ static int ov9734_set_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_put(&client->dev); + pm_runtime_put(ov9734->dev); return ret; } @@ -610,7 +613,6 @@ static void ov9734_update_pad_format(const struct ov9734_mode *mode, static int ov9734_start_streaming(struct ov9734 *ov9734) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); const struct ov9734_reg_list *reg_list; int link_freq_index, ret; @@ -618,14 +620,14 @@ static int ov9734_start_streaming(struct ov9734 *ov9734) reg_list = &link_freq_configs[link_freq_index].reg_list; ret = ov9734_write_reg_list(ov9734, reg_list); if (ret) { - dev_err(&client->dev, "failed to set plls"); + dev_err(ov9734->dev, "failed to set plls"); return ret; } reg_list = &ov9734->cur_mode->reg_list; ret = ov9734_write_reg_list(ov9734, reg_list); if (ret) { - dev_err(&client->dev, "failed to set mode"); + dev_err(ov9734->dev, "failed to set mode"); return ret; } @@ -636,30 +638,27 @@ static int ov9734_start_streaming(struct ov9734 *ov9734) ret = ov9734_write_reg(ov9734, OV9734_REG_MODE_SELECT, 1, OV9734_MODE_STREAMING); if (ret) - dev_err(&client->dev, "failed to start stream"); + dev_err(ov9734->dev, "failed to start stream"); return ret; } static void ov9734_stop_streaming(struct ov9734 *ov9734) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); - if (ov9734_write_reg(ov9734, OV9734_REG_MODE_SELECT, 1, OV9734_MODE_STANDBY)) - dev_err(&client->dev, "failed to stop stream"); + dev_err(ov9734->dev, "failed to stop stream"); } static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) { struct ov9734 *ov9734 = to_ov9734(sd); - struct i2c_client *client = v4l2_get_subdevdata(sd); int ret = 0; mutex_lock(&ov9734->mutex); if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(ov9734->dev); if (ret < 0) { mutex_unlock(&ov9734->mutex); return ret; @@ -669,11 +668,11 @@ static int ov9734_set_stream(struct v4l2_subdev *sd, int enable) if (ret) { enable = 0; ov9734_stop_streaming(ov9734); - pm_runtime_put(&client->dev); + pm_runtime_put(ov9734->dev); } } else { ov9734_stop_streaming(ov9734); - pm_runtime_put(&client->dev); + pm_runtime_put(ov9734->dev); } mutex_unlock(&ov9734->mutex); @@ -808,7 +807,6 @@ static const struct v4l2_subdev_internal_ops ov9734_internal_ops = { static int ov9734_identify_module(struct ov9734 *ov9734) { - struct i2c_client *client = v4l2_get_subdevdata(&ov9734->sd); int ret; u32 val; @@ -817,7 +815,7 @@ static int ov9734_identify_module(struct ov9734 *ov9734) return ret; if (val != OV9734_CHIP_ID) { - dev_err(&client->dev, "chip id mismatch: %x!=%x", + dev_err(ov9734->dev, "chip id mismatch: %x!=%x", OV9734_CHIP_ID, val); return -ENXIO; } @@ -832,22 +830,12 @@ static int ov9734_check_hwcfg(struct device *dev) struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = V4L2_MBUS_CSI2_DPHY }; - u32 mclk; int ret; unsigned int i, j; if (!fwnode) return -ENXIO; - ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk); - if (ret) - return ret; - - if (mclk != OV9734_MCLK) { - dev_err(dev, "external clock %d is not supported", mclk); - return -EINVAL; - } - ep = fwnode_graph_get_next_endpoint(fwnode, NULL); if (!ep) return -ENXIO; @@ -892,14 +880,15 @@ static void ov9734_remove(struct i2c_client *client) v4l2_async_unregister_subdev(sd); media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(sd->ctrl_handler); - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov9734->dev); + pm_runtime_set_suspended(ov9734->dev); mutex_destroy(&ov9734->mutex); } static int ov9734_probe(struct i2c_client *client) { struct ov9734 *ov9734; + unsigned long freq; int ret; ret = ov9734_check_hwcfg(&client->dev); @@ -913,10 +902,23 @@ static int ov9734_probe(struct i2c_client *client) if (!ov9734) return -ENOMEM; + ov9734->dev = &client->dev; + + ov9734->clk = devm_v4l2_sensor_clk_get(ov9734->dev, NULL); + if (IS_ERR(ov9734->clk)) + return dev_err_probe(ov9734->dev, PTR_ERR(ov9734->clk), + "failed to get clock\n"); + + freq = clk_get_rate(ov9734->clk); + if (freq != OV9734_MCLK) + return dev_err_probe(ov9734->dev, -EINVAL, + "external clock %lu is not supported", + freq); + v4l2_i2c_subdev_init(&ov9734->sd, client, &ov9734_subdev_ops); ret = ov9734_identify_module(ov9734); if (ret) { - dev_err(&client->dev, "failed to find sensor: %d", ret); + dev_err(ov9734->dev, "failed to find sensor: %d", ret); return ret; } @@ -924,7 +926,7 @@ static int ov9734_probe(struct i2c_client *client) ov9734->cur_mode = &supported_modes[0]; ret = ov9734_init_controls(ov9734); if (ret) { - dev_err(&client->dev, "failed to init controls: %d", ret); + dev_err(ov9734->dev, "failed to init controls: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -935,7 +937,7 @@ static int ov9734_probe(struct i2c_client *client) ov9734->pad.flags = MEDIA_PAD_FL_SOURCE; ret = media_entity_pads_init(&ov9734->sd.entity, 1, &ov9734->pad); if (ret) { - dev_err(&client->dev, "failed to init entity pads: %d", ret); + dev_err(ov9734->dev, "failed to init entity pads: %d", ret); goto probe_error_v4l2_ctrl_handler_free; } @@ -943,13 +945,13 @@ static int ov9734_probe(struct i2c_client *client) * Device is already turned on by i2c-core with ACPI domain PM. * Enable runtime PM and turn off the device. */ - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); - pm_runtime_idle(&client->dev); + pm_runtime_set_active(ov9734->dev); + pm_runtime_enable(ov9734->dev); + pm_runtime_idle(ov9734->dev); ret = v4l2_async_register_subdev_sensor(&ov9734->sd); if (ret < 0) { - dev_err(&client->dev, "failed to register V4L2 subdev: %d", + dev_err(ov9734->dev, "failed to register V4L2 subdev: %d", ret); goto probe_error_media_entity_cleanup_pm; } @@ -957,8 +959,8 @@ static int ov9734_probe(struct i2c_client *client) return 0; probe_error_media_entity_cleanup_pm: - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + pm_runtime_disable(ov9734->dev); + pm_runtime_set_suspended(ov9734->dev); media_entity_cleanup(&ov9734->sd.entity); probe_error_v4l2_ctrl_handler_free: diff --git a/drivers/media/i2c/rj54n1cb0c.c b/drivers/media/i2c/rj54n1cb0c.c index b7ca39f63dba..6dfc91216851 100644 --- a/drivers/media/i2c/rj54n1cb0c.c +++ b/drivers/media/i2c/rj54n1cb0c.c @@ -1329,10 +1329,13 @@ static int rj54n1_probe(struct i2c_client *client) V4L2_CID_GAIN, 0, 127, 1, 66); v4l2_ctrl_new_std(&rj54n1->hdl, &rj54n1_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); - rj54n1->subdev.ctrl_handler = &rj54n1->hdl; - if (rj54n1->hdl.error) - return rj54n1->hdl.error; + if (rj54n1->hdl.error) { + ret = rj54n1->hdl.error; + goto err_free_ctrl; + } + + rj54n1->subdev.ctrl_handler = &rj54n1->hdl; rj54n1->clk_div = clk_div; rj54n1->rect.left = RJ54N1_COLUMN_SKIP; rj54n1->rect.top = RJ54N1_ROW_SKIP; diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-core.c b/drivers/media/i2c/s5c73m3/s5c73m3-core.c index 7716dfe2b8c9..ab31ee2b596b 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3-core.c +++ b/drivers/media/i2c/s5c73m3/s5c73m3-core.c @@ -1368,10 +1368,6 @@ static int __s5c73m3_power_on(struct s5c73m3 *state) goto err_reg_dis; } - ret = clk_set_rate(state->clock, state->mclk_frequency); - if (ret < 0) - goto err_reg_dis; - ret = clk_prepare_enable(state->clock); if (ret < 0) goto err_reg_dis; @@ -1556,16 +1552,13 @@ static int s5c73m3_get_dt_data(struct s5c73m3 *state) if (!node) return -EINVAL; - state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); + state->clock = devm_v4l2_sensor_clk_get_legacy(dev, S5C73M3_CLK_NAME, + false, + S5C73M3_DEFAULT_MCLK_FREQ); if (IS_ERR(state->clock)) - return PTR_ERR(state->clock); - - if (of_property_read_u32(node, "clock-frequency", - &state->mclk_frequency)) { - state->mclk_frequency = S5C73M3_DEFAULT_MCLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - state->mclk_frequency); - } + return dev_err_probe(dev, PTR_ERR(state->clock), + "Failed to get the clock %s\n", + S5C73M3_CLK_NAME); /* Request GPIO lines asserted */ state->stby = devm_gpiod_get(dev, "standby", GPIOD_OUT_HIGH); diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h index 627e80cf5b72..68a19c2c8db8 100644 --- a/drivers/media/i2c/s5c73m3/s5c73m3.h +++ b/drivers/media/i2c/s5c73m3/s5c73m3.h @@ -382,8 +382,6 @@ struct s5c73m3 { struct clk *clock; - /* External master clock frequency */ - u32 mclk_frequency; /* Video bus type - MIPI-CSI2/parallel */ enum v4l2_mbus_type bus_type; diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c index 24f399cd2124..d1d00eca8708 100644 --- a/drivers/media/i2c/s5k5baf.c +++ b/drivers/media/i2c/s5k5baf.c @@ -284,7 +284,6 @@ struct s5k5baf { struct regulator_bulk_data supplies[S5K5BAF_NUM_SUPPLIES]; struct clk *clock; - u32 mclk_frequency; struct s5k5baf_fw *fw; @@ -576,7 +575,7 @@ static void s5k5baf_hw_patch(struct s5k5baf *state) static void s5k5baf_hw_set_clocks(struct s5k5baf *state) { - unsigned long mclk = state->mclk_frequency / 1000; + unsigned long mclk = clk_get_rate(state->clock) / 1000; u16 status; static const u16 nseq_clk_cfg[] = { NSEQ(REG_I_USE_NPVI_CLOCKS, @@ -946,10 +945,6 @@ static int s5k5baf_power_on(struct s5k5baf *state) if (ret < 0) goto err; - ret = clk_set_rate(state->clock, state->mclk_frequency); - if (ret < 0) - goto err_reg_dis; - ret = clk_prepare_enable(state->clock); if (ret < 0) goto err_reg_dis; @@ -1841,14 +1836,6 @@ static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev) return -EINVAL; } - ret = of_property_read_u32(node, "clock-frequency", - &state->mclk_frequency); - if (ret < 0) { - state->mclk_frequency = S5K5BAF_DEFAULT_MCLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - state->mclk_frequency); - } - node_ep = of_graph_get_endpoint_by_regs(node, 0, -1); if (!node_ep) { dev_err(dev, "no endpoint defined at node %pOF\n", node); @@ -1967,9 +1954,11 @@ static int s5k5baf_probe(struct i2c_client *c) if (ret < 0) goto err_me; - state->clock = devm_clk_get(state->sd.dev, S5K5BAF_CLK_NAME); + state->clock = devm_v4l2_sensor_clk_get_legacy(state->sd.dev, + S5K5BAF_CLK_NAME, false, + S5K5BAF_DEFAULT_MCLK_FREQ); if (IS_ERR(state->clock)) { - ret = -EPROBE_DEFER; + ret = PTR_ERR(state->clock); goto err_me; } diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c index 0c2674115b7b..ba6477e88da3 100644 --- a/drivers/media/i2c/s5k6a3.c +++ b/drivers/media/i2c/s5k6a3.c @@ -51,7 +51,6 @@ enum { * @lock: mutex protecting the structure's members below * @format: media bus format at the sensor's source pad * @clock: pointer to &struct clk. - * @clock_frequency: clock frequency * @power_count: stores state if device is powered */ struct s5k6a3 { @@ -63,7 +62,6 @@ struct s5k6a3 { struct mutex lock; struct v4l2_mbus_framefmt format; struct clk *clock; - u32 clock_frequency; int power_count; }; @@ -192,10 +190,6 @@ static int __s5k6a3_power_on(struct s5k6a3 *sensor) int i = S5K6A3_SUPP_VDDA; int ret; - ret = clk_set_rate(sensor->clock, sensor->clock_frequency); - if (ret < 0) - return ret; - ret = pm_runtime_get(sensor->dev); if (ret < 0) goto error_rpm_put; @@ -292,22 +286,18 @@ static int s5k6a3_probe(struct i2c_client *client) mutex_init(&sensor->lock); sensor->dev = dev; - sensor->clock = devm_clk_get(sensor->dev, S5K6A3_CLK_NAME); + sensor->clock = devm_v4l2_sensor_clk_get_legacy(sensor->dev, + S5K6A3_CLK_NAME, false, + S5K6A3_DEFAULT_CLK_FREQ); if (IS_ERR(sensor->clock)) - return PTR_ERR(sensor->clock); + return dev_err_probe(sensor->dev, PTR_ERR(sensor->clock), + "failed to get extclk\n"); sensor->gpio_reset = devm_gpiod_get(dev, NULL, GPIOD_OUT_HIGH); ret = PTR_ERR_OR_ZERO(sensor->gpio_reset); if (ret) return ret; - if (of_property_read_u32(dev->of_node, "clock-frequency", - &sensor->clock_frequency)) { - sensor->clock_frequency = S5K6A3_DEFAULT_CLK_FREQ; - dev_info(dev, "using default %u Hz clock frequency\n", - sensor->clock_frequency); - } - for (i = 0; i < S5K6A3_NUM_SUPPLIES; i++) sensor->supplies[i].supply = s5k6a3_supply_names[i]; diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c index 1ed8b5edb3fb..1c0031ba43b4 100644 --- a/drivers/media/i2c/saa6752hs.c +++ b/drivers/media/i2c/saa6752hs.c @@ -6,7 +6,7 @@ AC-3 support: - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c index b8b8f206ec3a..48d6730d9271 100644 --- a/drivers/media/i2c/saa7115.c +++ b/drivers/media/i2c/saa7115.c @@ -18,7 +18,7 @@ // Added saa7115 support by Kevin Thayer <nufan_wfk at yahoo.com> // (2/17/2003) // -// VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> +// VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@kernel.org> // // Copyright (c) 2005-2006 Mauro Carvalho Chehab <mchehab@kernel.org> // SAA7111, SAA7113 and SAA7118 support diff --git a/drivers/media/i2c/saa7127.c b/drivers/media/i2c/saa7127.c index 818ed19cf37b..a42a7ffe3768 100644 --- a/drivers/media/i2c/saa7127.c +++ b/drivers/media/i2c/saa7127.c @@ -25,7 +25,7 @@ * Copyright (C) 2004 Chris Kennedy <c@groovy.org> * * VBI additions & cleanup: - * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2004, 2005 Hans Verkuil <hverkuil@kernel.org> * * Note: the saa7126 is identical to the saa7127, and the saa7128 is * identical to the saa7129, except that the saa7126 and saa7128 have diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index b0793bb0c02a..713331be947c 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -10,7 +10,7 @@ * Changes by T.Adachi (tadachi@tadachi-net.com) * - support audio, video scaler etc, and checked the initialize sequence. * - * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl> + * Cleaned up by Hans Verkuil <hverkuil@kernel.org> * * Note: this is a reversed engineered driver based on captures from * the I2C bus under Windows. This chip is very similar to the saa7134, diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c index f4568e87f018..41ae25b0911f 100644 --- a/drivers/media/i2c/st-mipid02.c +++ b/drivers/media/i2c/st-mipid02.c @@ -465,7 +465,6 @@ static int mipid02_disable_streams(struct v4l2_subdev *sd, if (ret) goto error; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); error: @@ -542,7 +541,6 @@ error: cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret); cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret); - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return ret; } diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 1cc7636e446d..a0ca19359c43 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -38,7 +38,21 @@ static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-3)"); +MODULE_PARM_DESC(debug, " debug level (0-3)"); + +static int packet_type = 0x87; +module_param(packet_type, int, 0644); +MODULE_PARM_DESC(packet_type, + " Programmable Packet Type. Possible values:\n" + "\t\t 0x87: DRM InfoFrame (Default).\n" + "\t\t 0x01: Audio Clock Regeneration Packet\n" + "\t\t 0x02: Audio Sample Packet\n" + "\t\t 0x03: General Control Packet\n" + "\t\t 0x04: ACP Packet\n" + "\t\t 0x07: One Bit Audio Sample Packet\n" + "\t\t 0x08: DST Audio Packet\n" + "\t\t 0x09: High Bitrate Audio Stream Packet\n" + "\t\t 0x0a: Gamut Metadata Packet\n"); MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); MODULE_AUTHOR("Ramakrishnan Muthukrishnan <ram@rkrishnan.org>"); @@ -466,10 +480,29 @@ tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, if (!is_hdmi(sd)) return 0; - if (type != V4L2_DEBUGFS_IF_AVI) + switch (type) { + case V4L2_DEBUGFS_IF_AVI: + i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_LEN); + break; + case V4L2_DEBUGFS_IF_AUDIO: + i2c_rd(sd, PK_AUD_0HEAD, buf, PK_AUD_LEN); + break; + case V4L2_DEBUGFS_IF_SPD: + i2c_rd(sd, PK_SPD_0HEAD, buf, PK_SPD_LEN); + break; + case V4L2_DEBUGFS_IF_HDMI: + i2c_rd(sd, PK_VS_0HEAD, buf, PK_VS_LEN); + break; + case V4L2_DEBUGFS_IF_DRM: + i2c_rd(sd, PK_ACP_0HEAD, buf, PK_ACP_LEN); + break; + default: return 0; + } + + if (!buf[2]) + return -ENOENT; - i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1); len = buf[2] + 4; if (len > V4L2_DEBUGFS_IF_MAX_LEN) len = -ENOENT; @@ -478,26 +511,69 @@ tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp, return len < 0 ? 0 : len; } -static void print_avi_infoframe(struct v4l2_subdev *sd) +static void print_infoframes(struct v4l2_subdev *sd) { struct i2c_client *client = v4l2_get_subdevdata(sd); struct device *dev = &client->dev; union hdmi_infoframe frame; - u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {}; + u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {}; + + /* + * Updating the ACP TYPE here allows for dynamically + * changing the type you want to monitor, without having + * to reload the driver with a new packet_type module option value. + * + * Instead you can set it with the new value, then call + * VIDIOC_LOG_STATUS. + */ + i2c_wr8(sd, TYP_ACP_SET, packet_type); if (!is_hdmi(sd)) { - v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); + v4l2_info(sd, "DVI-D signal - InfoFrames not supported\n"); return; } - i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); + i2c_rd(sd, PK_AVI_0HEAD, buffer, PK_AVI_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); - if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) < 0) { - v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); - return; + i2c_rd(sd, PK_VS_0HEAD, buffer, PK_VS_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); + + i2c_rd(sd, PK_AUD_0HEAD, buffer, PK_AUD_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); + + i2c_rd(sd, PK_SPD_0HEAD, buffer, PK_SPD_LEN); + if (hdmi_infoframe_unpack(&frame, buffer, sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); + + i2c_rd(sd, PK_ACP_0HEAD, buffer, PK_ACP_LEN); + if (buffer[0] == packet_type) { + if (packet_type < 0x80) + v4l2_info(sd, "Packet: %*ph\n", PK_ACP_LEN, buffer); + else if (packet_type != 0x87) + v4l2_info(sd, "InfoFrame: %*ph\n", PK_ACP_LEN, buffer); + else if (hdmi_infoframe_unpack(&frame, buffer, + sizeof(buffer)) >= 0) + hdmi_infoframe_log(KERN_INFO, dev, &frame); } - hdmi_infoframe_log(KERN_INFO, dev, &frame); + i2c_rd(sd, PK_MS_0HEAD, buffer, PK_MS_LEN); + if (buffer[2] && buffer[2] + 3 <= PK_MS_LEN) + v4l2_info(sd, "MPEG Source InfoFrame: %*ph\n", + buffer[2] + 3, buffer); + + i2c_rd(sd, PK_ISRC1_0HEAD, buffer, PK_ISRC1_LEN); + if (buffer[0] == 0x05) + v4l2_info(sd, "ISRC1 Packet: %*ph\n", + PK_ISRC1_LEN, buffer); + + i2c_rd(sd, PK_ISRC2_0HEAD, buffer, PK_ISRC2_LEN); + if (buffer[0] == 0x06) + v4l2_info(sd, "ISRC2 Packet: %*ph\n", + PK_ISRC2_LEN, buffer); } /* --------------- CTRLS --------------- */ @@ -1375,7 +1451,7 @@ static int tc358743_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "Deep color mode: %d-bits per channel\n", deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & MASK_S_DEEPCOLOR) >> 2]); - print_avi_infoframe(sd); + print_infoframes(sd); return 0; } @@ -2232,10 +2308,15 @@ static int tc358743_probe(struct i2c_client *client) if (err < 0) goto err_work_queues; + i2c_wr8(sd, TYP_ACP_SET, packet_type); + i2c_wr8(sd, PK_AUTO_CLR, 0xff); + i2c_wr8(sd, NO_PKT_CLR, MASK_NO_ACP_CLR); + state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root()); state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir, - V4L2_DEBUGFS_IF_AVI, sd, - tc358743_debugfs_if_read); + V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO | + V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI | + V4L2_DEBUGFS_IF_DRM, sd, tc358743_debugfs_if_read); v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, client->addr << 1, client->adapter->name); @@ -2245,10 +2326,10 @@ static int tc358743_probe(struct i2c_client *client) err_work_queues: cec_unregister_adapter(state->cec_adap); if (!state->i2c_client->irq) { - timer_delete(&state->timer); + timer_delete_sync(&state->timer); flush_work(&state->work_i2c_poll); } - cancel_delayed_work(&state->delayed_work_enable_hotplug); + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); mutex_destroy(&state->confctl_mutex); err_hdl: media_entity_cleanup(&sd->entity); diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h index 2495878dc358..aae288f8add3 100644 --- a/drivers/media/i2c/tc358743_regs.h +++ b/drivers/media/i2c/tc358743_regs.h @@ -692,6 +692,8 @@ #define MASK_NCO_F0_MOD_42MHZ 0x00 #define MASK_NCO_F0_MOD_27MHZ 0x01 +#define TYP_ACP_SET 0x8706 + #define PK_INT_MODE 0x8709 #define MASK_ISRC2_INT_MODE 0x80 #define MASK_ISRC_INT_MODE 0x40 @@ -702,6 +704,8 @@ #define MASK_AUD_INT_MODE 0x02 #define MASK_AVI_INT_MODE 0x01 +#define PK_AUTO_CLR 0x870a + #define NO_PKT_LIMIT 0x870B #define MASK_NO_ACP_LIMIT 0xf0 #define SET_NO_ACP_LIMIT_MS(milliseconds) ((((milliseconds) / 80) << 4) & \ @@ -720,25 +724,44 @@ #define ERR_PK_LIMIT 0x870D #define NO_PKT_LIMIT2 0x870E #define PK_AVI_0HEAD 0x8710 -#define PK_AVI_1HEAD 0x8711 -#define PK_AVI_2HEAD 0x8712 #define PK_AVI_0BYTE 0x8713 -#define PK_AVI_1BYTE 0x8714 -#define PK_AVI_2BYTE 0x8715 -#define PK_AVI_3BYTE 0x8716 -#define PK_AVI_4BYTE 0x8717 -#define PK_AVI_5BYTE 0x8718 -#define PK_AVI_6BYTE 0x8719 -#define PK_AVI_7BYTE 0x871A -#define PK_AVI_8BYTE 0x871B -#define PK_AVI_9BYTE 0x871C -#define PK_AVI_10BYTE 0x871D -#define PK_AVI_11BYTE 0x871E -#define PK_AVI_12BYTE 0x871F -#define PK_AVI_13BYTE 0x8720 -#define PK_AVI_14BYTE 0x8721 -#define PK_AVI_15BYTE 0x8722 #define PK_AVI_16BYTE 0x8723 +#define PK_AVI_LEN (PK_AVI_16BYTE - PK_AVI_0HEAD + 1) + +#define PK_AUD_0HEAD 0x8730 +#define PK_AUD_0BYTE 0x8733 +#define PK_AUD_10BYTE 0x873d +#define PK_AUD_LEN (PK_AUD_10BYTE - PK_AUD_0HEAD + 1) + +#define PK_MS_0HEAD 0x8740 +#define PK_MS_0BYTE 0x8743 +#define PK_MS_10BYTE 0x874d +#define PK_MS_LEN (PK_MS_10BYTE - PK_MS_0HEAD + 1) + +#define PK_SPD_0HEAD 0x8750 +#define PK_SPD_0BYTE 0x8753 +#define PK_SPD_27BYTE 0x876e +#define PK_SPD_LEN (PK_SPD_27BYTE - PK_SPD_0HEAD + 1) + +#define PK_VS_0HEAD 0x8770 +#define PK_VS_0BYTE 0x8773 +#define PK_VS_27BYTE 0x878e +#define PK_VS_LEN (PK_VS_27BYTE - PK_VS_0HEAD + 1) + +#define PK_ACP_0HEAD 0x8790 +#define PK_ACP_0BYTE 0x8793 +#define PK_ACP_27BYTE 0x87ae +#define PK_ACP_LEN (PK_ACP_27BYTE - PK_ACP_0HEAD + 1) + +#define PK_ISRC1_0HEAD 0x87b0 +#define PK_ISRC1_0BYTE 0x87b3 +#define PK_ISRC1_27BYTE 0x87c2 +#define PK_ISRC1_LEN (PK_ISRC1_27BYTE - PK_ISRC1_0HEAD + 1) + +#define PK_ISRC2_0HEAD 0x87d0 +#define PK_ISRC2_0BYTE 0x87d3 +#define PK_ISRC2_27BYTE 0x87ee +#define PK_ISRC2_LEN (PK_ISRC2_27BYTE - PK_ISRC2_0HEAD + 1) #define BKSV 0x8800 diff --git a/drivers/media/i2c/tc358746.c b/drivers/media/i2c/tc358746.c index 143aa1359aba..bcfc274cf891 100644 --- a/drivers/media/i2c/tc358746.c +++ b/drivers/media/i2c/tc358746.c @@ -816,7 +816,6 @@ static int tc358746_s_stream(struct v4l2_subdev *sd, int enable) return 0; err_out: - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return err; @@ -838,7 +837,6 @@ err_out: if (err) return err; - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return v4l2_subdev_call(src, video, s_stream, 0); @@ -1016,7 +1014,6 @@ tc358746_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg) err = tc358746_read(tc358746, reg->reg, &val); reg->val = val; - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return err; @@ -1032,7 +1029,6 @@ tc358746_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg) tc358746_write(tc358746, (u32)reg->reg, (u32)reg->val); - pm_runtime_mark_last_busy(sd->dev); pm_runtime_put_sync_autosuspend(sd->dev); return 0; @@ -1395,7 +1391,6 @@ static int tc358746_init_hw(struct tc358746 *tc358746) } err = tc358746_read(tc358746, CHIPID_REG, &val); - pm_runtime_mark_last_busy(dev); pm_runtime_put_sync_autosuspend(dev); if (err) return -ENODEV; diff --git a/drivers/media/i2c/tda9840.c b/drivers/media/i2c/tda9840.c index d61da811c9da..e3b266db571f 100644 --- a/drivers/media/i2c/tda9840.c +++ b/drivers/media/i2c/tda9840.c @@ -3,7 +3,7 @@ tda9840 - i2c-driver for the tda9840 by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> The tda9840 is a stereo/dual sound processor with digital identification. It can be found at address 0x84 on the i2c-bus. diff --git a/drivers/media/i2c/tea6415c.c b/drivers/media/i2c/tea6415c.c index 4aaf66353610..0cd2e6c52e20 100644 --- a/drivers/media/i2c/tea6415c.c +++ b/drivers/media/i2c/tea6415c.c @@ -3,7 +3,7 @@ tea6415c - i2c-driver for the tea6415c by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> The tea6415c is a bus controlled video-matrix-switch with 8 inputs and 6 outputs. diff --git a/drivers/media/i2c/tea6420.c b/drivers/media/i2c/tea6420.c index 5c5ea3973251..400883fc0c0f 100644 --- a/drivers/media/i2c/tea6420.c +++ b/drivers/media/i2c/tea6420.c @@ -3,7 +3,7 @@ tea6420 - i2c-driver for the tea6420 by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> - Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + Copyright (C) 2008 Hans Verkuil <hverkuil@kernel.org> The tea6420 is a bus controlled audio-matrix with 5 stereo inputs, 4 stereo outputs and gain control for each output. diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c index 8852c56431fe..775cfba188d8 100644 --- a/drivers/media/i2c/thp7312.c +++ b/drivers/media/i2c/thp7312.c @@ -808,7 +808,6 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) if (!enable) { thp7312_stream_enable(thp7312, false); - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); v4l2_subdev_unlock_state(sd_state); @@ -839,7 +838,6 @@ static int thp7312_s_stream(struct v4l2_subdev *sd, int enable) goto finish_unlock; finish_pm: - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); finish_unlock: v4l2_subdev_unlock_state(sd_state); @@ -1147,7 +1145,6 @@ static int thp7312_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(thp7312->dev); pm_runtime_put_autosuspend(thp7312->dev); return ret; @@ -2183,7 +2180,6 @@ static int thp7312_probe(struct i2c_client *client) * Decrease the PM usage count. The device will get suspended after the * autosuspend delay, turning the power off. */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); dev_info(dev, "THP7312 firmware version %02u.%02u\n", diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c index b7cedc5b3e8e..ff268ebeb4d9 100644 --- a/drivers/media/i2c/ths7303.c +++ b/drivers/media/i2c/ths7303.c @@ -7,7 +7,7 @@ * Author: Chaithrika U S <chaithrika@ti.com> * * Contributors: - * Hans Verkuil <hansverk@cisco.com> + * Hans Verkuil <hverkuil@kernel.org> * Lad, Prabhakar <prabhakar.lad@ti.com> * Martin Bugge <marbugge@cisco.com> * diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index b7b31b6192af..6f6bc5236565 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c @@ -7,7 +7,7 @@ * Based on wm8775 driver * * Copyright (C) 2004 Ulf Eklund <ivtv at eklund.to> - * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2005 Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/i2c/upd64031a.c b/drivers/media/i2c/upd64031a.c index 9d0b72a213be..a178af46e695 100644 --- a/drivers/media/i2c/upd64031a.c +++ b/drivers/media/i2c/upd64031a.c @@ -4,7 +4,7 @@ * * 2003 by T.Adachi <tadachi@tadachi-net.com> * 2003 by Takeru KOMORIYA <komoriya@paken.org> - * 2006 by Hans Verkuil <hverkuil@xs4all.nl> + * 2006 by Hans Verkuil <hverkuil@kernel.org> */ diff --git a/drivers/media/i2c/upd64083.c b/drivers/media/i2c/upd64083.c index 2e99ed5da42c..5421dc5e32c9 100644 --- a/drivers/media/i2c/upd64083.c +++ b/drivers/media/i2c/upd64083.c @@ -4,7 +4,7 @@ * * 2003 by T.Adachi (tadachi@tadachi-net.com) * 2003 by Takeru KOMORIYA <komoriya@paken.org> - * 2006 by Hans Verkuil <hverkuil@xs4all.nl> + * 2006 by Hans Verkuil <hverkuil@kernel.org> */ #include <linux/module.h> diff --git a/drivers/media/i2c/vd55g1.c b/drivers/media/i2c/vd55g1.c index c0754fd03b1d..f09d6bf32641 100644 --- a/drivers/media/i2c/vd55g1.c +++ b/drivers/media/i2c/vd55g1.c @@ -66,7 +66,7 @@ #define VD55G1_REG_READOUT_CTRL CCI_REG8(0x052e) #define VD55G1_READOUT_CTRL_BIN_MODE_NORMAL 0 #define VD55G1_READOUT_CTRL_BIN_MODE_DIGITAL_X2 1 -#define VD55G1_REG_DUSTER_CTRL CCI_REG8(0x03ea) +#define VD55G1_REG_DUSTER_CTRL CCI_REG8(0x03ae) #define VD55G1_DUSTER_ENABLE BIT(0) #define VD55G1_DUSTER_DISABLE 0 #define VD55G1_DUSTER_DYN_ENABLE BIT(1) @@ -1104,7 +1104,6 @@ static int vd55g1_disable_streams(struct v4l2_subdev *sd, vd55g1_grab_ctrls(sensor, false); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1338,7 +1337,6 @@ static int vd55g1_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1433,7 +1431,6 @@ static int vd55g1_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1863,7 +1860,7 @@ static int vd55g1_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Failed to get regulators\n"); - sensor->xclk = devm_clk_get(dev, NULL); + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xclk)) return dev_err_probe(dev, PTR_ERR(sensor->xclk), "Failed to get xclk\n"); @@ -1895,7 +1892,6 @@ static int vd55g1_probe(struct i2c_client *client) pm_runtime_enable(dev); pm_runtime_set_autosuspend_delay(dev, 4000); pm_runtime_use_autosuspend(dev); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); ret = vd55g1_subdev_init(sensor); diff --git a/drivers/media/i2c/vd56g3.c b/drivers/media/i2c/vd56g3.c index 5d951ad0b478..157acea9e286 100644 --- a/drivers/media/i2c/vd56g3.c +++ b/drivers/media/i2c/vd56g3.c @@ -493,7 +493,6 @@ static int vd56g3_g_volatile_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -577,7 +576,6 @@ static int vd56g3_s_ctrl(struct v4l2_ctrl *ctrl) break; } - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1021,7 +1019,6 @@ static int vd56g3_disable_streams(struct v4l2_subdev *sd, __v4l2_ctrl_grab(sensor->vflip_ctrl, false); __v4l2_ctrl_grab(sensor->patgen_ctrl, false); - pm_runtime_mark_last_busy(sensor->dev); pm_runtime_put_autosuspend(sensor->dev); return ret; @@ -1474,7 +1471,7 @@ static int vd56g3_probe(struct i2c_client *client) if (ret) return dev_err_probe(dev, ret, "Failed to get regulators\n"); - sensor->xclk = devm_clk_get(dev, NULL); + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); if (IS_ERR(sensor->xclk)) return dev_err_probe(dev, PTR_ERR(sensor->xclk), "Failed to get xclk\n"); @@ -1527,7 +1524,6 @@ static int vd56g3_probe(struct i2c_client *client) } /* Sensor could now be powered off (after the autosuspend delay) */ - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); dev_dbg(dev, "Successfully probe %s sensor\n", diff --git a/drivers/media/i2c/vgxy61.c b/drivers/media/i2c/vgxy61.c index 5b0479f3a3c0..d64d0099e6fe 100644 --- a/drivers/media/i2c/vgxy61.c +++ b/drivers/media/i2c/vgxy61.c @@ -1181,6 +1181,21 @@ static int vgxy61_s_stream(struct v4l2_subdev *sd, int enable) return ret; } +static int vgxy61_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad, + struct v4l2_mbus_frame_desc *fd) +{ + struct vgxy61_dev *sensor = to_vgxy61_dev(sd); + + fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2; + fd->num_entries = 1; + fd->entry[0].pixelcode = sensor->fmt.code; + fd->entry[0].stream = 0; + fd->entry[0].bus.csi2.vc = 0; + fd->entry[0].bus.csi2.dt = get_data_type_by_code(sensor->fmt.code); + + return 0; +} + static int vgxy61_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) @@ -1402,6 +1417,7 @@ static const struct v4l2_subdev_pad_ops vgxy61_pad_ops = { .set_fmt = vgxy61_set_fmt, .get_selection = vgxy61_get_selection, .enum_frame_size = vgxy61_enum_frame_size, + .get_frame_desc = vgxy61_get_frame_desc, }; static const struct v4l2_subdev_ops vgxy61_subdev_ops = { @@ -1761,11 +1777,11 @@ static int vgxy61_probe(struct i2c_client *client) return ret; } - sensor->xclk = devm_clk_get(dev, NULL); - if (IS_ERR(sensor->xclk)) { - dev_err(dev, "failed to get xclk\n"); - return PTR_ERR(sensor->xclk); - } + sensor->xclk = devm_v4l2_sensor_clk_get(dev, NULL); + if (IS_ERR(sensor->xclk)) + return dev_err_probe(dev, PTR_ERR(sensor->xclk), + "failed to get xclk\n"); + sensor->clk_freq = clk_get_rate(sensor->xclk); if (sensor->clk_freq < 6 * HZ_PER_MHZ || sensor->clk_freq > 27 * HZ_PER_MHZ) { diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c index 0dd991d70d53..1eee2d4f5b40 100644 --- a/drivers/media/i2c/video-i2c.c +++ b/drivers/media/i2c/video-i2c.c @@ -288,7 +288,6 @@ static int amg88xx_read(struct device *dev, enum hwmon_sensor_types type, return tmp; tmp = regmap_bulk_read(data->regmap, AMG88XX_REG_TTHL, &buf, 2); - pm_runtime_mark_last_busy(regmap_get_device(data->regmap)); pm_runtime_put_autosuspend(regmap_get_device(data->regmap)); if (tmp) return tmp; @@ -527,7 +526,6 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) return 0; error_rpm_put: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); error_del_list: video_i2c_del_list(vq, VB2_BUF_STATE_QUEUED); @@ -544,7 +542,6 @@ static void stop_streaming(struct vb2_queue *vq) kthread_stop(data->kthread_vid_cap); data->kthread_vid_cap = NULL; - pm_runtime_mark_last_busy(regmap_get_device(data->regmap)); pm_runtime_put_autosuspend(regmap_get_device(data->regmap)); video_i2c_del_list(vq, VB2_BUF_STATE_ERROR); @@ -853,7 +850,6 @@ static int video_i2c_probe(struct i2c_client *client) if (ret < 0) goto error_pm_disable; - pm_runtime_mark_last_busy(&client->dev); pm_runtime_put_autosuspend(&client->dev); return 0; diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c index 06fd46a63c72..df21950be24f 100644 --- a/drivers/media/i2c/vp27smpx.c +++ b/drivers/media/i2c/vp27smpx.c @@ -2,7 +2,7 @@ /* * vp27smpx - driver version 0.0.1 * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2007 Hans Verkuil <hverkuil@kernel.org> * * Based on a tvaudio patch from Takahiro Adachi <tadachi@tadachi-net.com> * and Kazuhiko Kawakami <kazz-0@mail.goo.ne.jp> diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c index c091b78a5b41..72eb10339d06 100644 --- a/drivers/media/i2c/wm8739.c +++ b/drivers/media/i2c/wm8739.c @@ -4,7 +4,7 @@ * * Copyright (C) 2005 T. Adachi <tadachi@tadachi-net.com> * - * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2005 Hans Verkuil <hverkuil@kernel.org> * - Cleanup */ diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index 619b2988577c..56778d3bc28a 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -6,7 +6,7 @@ * * Based on saa7115 driver * - * Copyright (C) 2005 Hans Verkuil <hverkuil@xs4all.nl> + * Copyright (C) 2005 Hans Verkuil <hverkuil@kernel.org> * - Cleanup * - V4L2 API update * - sound fixes |