diff options
Diffstat (limited to 'drivers/media/i2c/imx319.c')
| -rw-r--r-- | drivers/media/i2c/imx319.c | 207 |
1 files changed, 70 insertions, 137 deletions
diff --git a/drivers/media/i2c/imx319.c b/drivers/media/i2c/imx319.c index 45b1b61b2880..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 <asm/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> @@ -70,7 +72,7 @@ #define IMX319_REG_ORIENTATION 0x0101 /* default link frequency and external clock */ -#define IMX319_LINK_FREQ_DEFAULT 482400000 +#define IMX319_LINK_FREQ_DEFAULT 482400000LL #define IMX319_EXT_CLK 19200000 #define IMX319_LINK_FREQ_INDEX 0 @@ -106,12 +108,12 @@ struct imx319_mode { }; struct imx319_hwcfg { - u32 ext_clk; /* sensor external clk */ - s64 *link_freqs; /* CSI-2 link frequencies */ - unsigned int nr_of_link_freqs; + unsigned long link_freq_bitmap; }; struct imx319 { + struct device *dev; + struct v4l2_subdev sd; struct media_pad pad; @@ -129,7 +131,6 @@ struct imx319 { const struct imx319_mode *cur_mode; struct imx319_hwcfg *hwcfg; - s64 link_def_freq; /* CSI-2 link default frequency */ /* * Mutex for serialized access: @@ -138,8 +139,6 @@ struct imx319 { */ struct mutex mutex; - /* Streaming on/off */ - bool streaming; /* True if the device has been identified */ bool identified; }; @@ -1656,7 +1655,10 @@ static const char * const imx319_test_pattern_menu[] = { "Pseudorandom Sequence (PN9)", }; -/* supported link frequencies */ +/* + * When adding more than the one below, make sure the disallowed ones will + * actually be disabled in the LINK_FREQ control. + */ static const s64 link_freq_menu_items[] = { IMX319_LINK_FREQ_DEFAULT, }; @@ -1840,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; @@ -1862,7 +1863,7 @@ static int imx319_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct imx319 *imx319 = to_imx319(sd); struct v4l2_mbus_framefmt *try_fmt = - v4l2_subdev_get_try_format(sd, fh->state, 0); + v4l2_subdev_state_get_format(fh->state, 0); mutex_lock(&imx319->mutex); @@ -1881,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; @@ -1900,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) { @@ -1934,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; } @@ -2003,10 +2003,9 @@ static int imx319_do_get_pad_format(struct imx319 *imx319, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &imx319->sd; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); fmt->format = *framefmt; } else { imx319_update_pad_format(imx319, imx319->cur_mode, fmt); @@ -2057,11 +2056,11 @@ imx319_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx319_update_pad_format(imx319, mode, fmt); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - framefmt = v4l2_subdev_get_try_format(sd, sd_state, fmt->pad); + framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); *framefmt = fmt->format; } else { imx319->cur_mode = mode; - pixel_rate = imx319->link_def_freq * 2 * 4; + pixel_rate = IMX319_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); __v4l2_ctrl_s_ctrl_int64(imx319->pixel_rate, pixel_rate); /* Update limits and set FPS to default */ @@ -2089,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; @@ -2101,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; } @@ -2114,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; @@ -2126,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; } @@ -2134,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; } @@ -2162,17 +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 (imx319->streaming == enable) { - mutex_unlock(&imx319->mutex); - return 0; - } if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx319->dev); if (ret < 0) goto err_unlock; @@ -2185,11 +2177,9 @@ 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); } - imx319->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx319->vflip, enable); __v4l2_ctrl_grab(imx319->hflip, enable); @@ -2199,44 +2189,13 @@ 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); return ret; } -static int __maybe_unused imx319_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx319 *imx319 = to_imx319(sd); - - if (imx319->streaming) - imx319_stop_streaming(imx319); - - return 0; -} - -static int __maybe_unused imx319_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx319 *imx319 = to_imx319(sd); - int ret; - - if (imx319->streaming) { - ret = imx319_start_streaming(imx319); - if (ret) - goto error; - } - - return 0; - -error: - imx319_stop_streaming(imx319); - imx319->streaming = 0; - return ret; -} - static const struct v4l2_subdev_core_ops imx319_subdev_core_ops = { .subscribe_event = v4l2_ctrl_subdev_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, @@ -2270,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; @@ -2295,7 +2253,7 @@ static int imx319_init_controls(struct imx319 *imx319) imx319->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = imx319->link_def_freq * 2 * 4; + pixel_rate = IMX319_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); /* By default, PIXEL_RATE is read only */ imx319->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx319_ctrl_ops, @@ -2350,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; } @@ -2372,7 +2330,6 @@ static struct imx319_hwcfg *imx319_get_hwcfg(struct device *dev) }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); - unsigned int i; int ret; if (!fwnode) @@ -2390,38 +2347,14 @@ 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; - } - - dev_dbg(dev, "num of link freqs: %d", bus_cfg.nr_of_link_frequencies); - if (!bus_cfg.nr_of_link_frequencies) { - dev_warn(dev, "no link frequencies defined"); - goto out_err; - } - - cfg->nr_of_link_freqs = bus_cfg.nr_of_link_frequencies; - cfg->link_freqs = devm_kcalloc(dev, - bus_cfg.nr_of_link_frequencies + 1, - sizeof(*cfg->link_freqs), GFP_KERNEL); - if (!cfg->link_freqs) + 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), + &cfg->link_freq_bitmap); + if (ret) goto out_err; - for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) { - cfg->link_freqs[i] = bus_cfg.link_frequencies[i]; - dev_dbg(dev, "link_freq[%d] = %lld", i, cfg->link_freqs[i]); - } - v4l2_fwnode_endpoint_free(&bus_cfg); fwnode_handle_put(ep); return cfg; @@ -2435,56 +2368,56 @@ out_err: static int imx319_probe(struct i2c_client *client) { struct imx319 *imx319; + unsigned long freq; + struct clk *clk; bool full_power; int ret; - u32 i; imx319 = devm_kzalloc(&client->dev, sizeof(*imx319), GFP_KERNEL); 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; } - imx319->link_def_freq = link_freq_menu_items[IMX319_LINK_FREQ_INDEX]; - for (i = 0; i < imx319->hwcfg->nr_of_link_freqs; i++) { - if (imx319->hwcfg->link_freqs[i] == imx319->link_def_freq) { - dev_dbg(&client->dev, "link freq index %d matched", i); - break; - } - } - - if (i == imx319->hwcfg->nr_of_link_freqs) { - dev_err(&client->dev, "no link frequency supported"); - ret = -EINVAL; - goto error_probe; - } - /* Set default mode to max resolution */ imx319->cur_mode = &supported_modes[0]; 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; } @@ -2499,23 +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(imx319->dev); + pm_runtime_enable(imx319->dev); + ret = v4l2_async_register_subdev_sensor(&imx319->sd); if (ret < 0) - goto error_media_entity; + goto error_media_entity_pm; - /* 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_idle(imx319->dev); return 0; -error_media_entity: +error_media_entity_pm: + pm_runtime_disable(imx319->dev); + if (full_power) + pm_runtime_set_suspended(imx319->dev); media_entity_cleanup(&imx319->sd.entity); error_handler_free: @@ -2536,16 +2473,13 @@ 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); - 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); } -static const struct dev_pm_ops imx319_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx319_suspend, imx319_resume) -}; - static const struct acpi_device_id imx319_acpi_ids[] __maybe_unused = { { "SONY319A" }, { /* sentinel */ } @@ -2555,17 +2489,16 @@ MODULE_DEVICE_TABLE(acpi, imx319_acpi_ids); static struct i2c_driver imx319_i2c_driver = { .driver = { .name = "imx319", - .pm = &imx319_pm_ops, .acpi_match_table = ACPI_PTR(imx319_acpi_ids), }, - .probe_new = imx319_probe, + .probe = imx319_probe, .remove = imx319_remove, .flags = I2C_DRV_ACPI_WAIVE_D0_PROBE, }; module_i2c_driver(imx319_i2c_driver); MODULE_AUTHOR("Qiu, Tianshu <tian.shu.qiu@intel.com>"); -MODULE_AUTHOR("Rapolu, Chiranjeevi <chiranjeevi.rapolu@intel.com>"); +MODULE_AUTHOR("Rapolu, Chiranjeevi"); MODULE_AUTHOR("Bingbu Cao <bingbu.cao@intel.com>"); MODULE_AUTHOR("Yang, Hyungwoo"); MODULE_DESCRIPTION("Sony imx319 sensor driver"); |
