diff options
Diffstat (limited to 'drivers/media/i2c/imx355.c')
| -rw-r--r-- | drivers/media/i2c/imx355.c | 217 |
1 files changed, 78 insertions, 139 deletions
diff --git a/drivers/media/i2c/imx355.c b/drivers/media/i2c/imx355.c index 25d4dbb6041e..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 <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> @@ -56,7 +58,7 @@ #define IMX355_REG_ORIENTATION 0x0101 /* default link frequency and external clock */ -#define IMX355_LINK_FREQ_DEFAULT 360000000 +#define IMX355_LINK_FREQ_DEFAULT 360000000LL #define IMX355_EXT_CLK 19200000 #define IMX355_LINK_FREQ_INDEX 0 @@ -92,12 +94,13 @@ struct imx355_mode { }; struct imx355_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 imx355 { + struct device *dev; + struct clk *clk; + struct v4l2_subdev sd; struct media_pad pad; @@ -115,7 +118,6 @@ struct imx355 { const struct imx355_mode *cur_mode; struct imx355_hwcfg *hwcfg; - s64 link_def_freq; /* CSI-2 link default frequency */ /* * Mutex for serialized access: @@ -123,9 +125,6 @@ struct imx355 { * Protect access to sensor v4l2 controls. */ struct mutex mutex; - - /* Streaming on/off */ - bool streaming; }; static const struct imx355_reg imx355_global_regs[] = { @@ -882,7 +881,10 @@ static const char * const imx355_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[] = { IMX355_LINK_FREQ_DEFAULT, }; @@ -1138,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); @@ -1161,7 +1162,7 @@ static int imx355_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct imx355 *imx355 = to_imx355(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(&imx355->mutex); @@ -1180,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; @@ -1199,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) { @@ -1233,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; } @@ -1302,10 +1302,9 @@ static int imx355_do_get_pad_format(struct imx355 *imx355, struct v4l2_subdev_format *fmt) { struct v4l2_mbus_framefmt *framefmt; - struct v4l2_subdev *sd = &imx355->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 { imx355_update_pad_format(imx355, imx355->cur_mode, fmt); @@ -1356,11 +1355,11 @@ imx355_set_pad_format(struct v4l2_subdev *sd, fmt->format.width, fmt->format.height); imx355_update_pad_format(imx355, 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 { imx355->cur_mode = mode; - pixel_rate = imx355->link_def_freq * 2 * 4; + pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); __v4l2_ctrl_s_ctrl_int64(imx355->pixel_rate, pixel_rate); /* Update limits and set FPS to default */ @@ -1388,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; @@ -1396,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; } @@ -1404,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; } @@ -1432,17 +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 (imx355->streaming == enable) { - mutex_unlock(&imx355->mutex); - return 0; - } if (enable) { - ret = pm_runtime_resume_and_get(&client->dev); + ret = pm_runtime_resume_and_get(imx355->dev); if (ret < 0) goto err_unlock; @@ -1455,11 +1448,9 @@ 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); } - imx355->streaming = enable; - /* vflip and hflip cannot change during streaming */ __v4l2_ctrl_grab(imx355->vflip, enable); __v4l2_ctrl_grab(imx355->hflip, enable); @@ -1469,48 +1460,16 @@ 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); return ret; } -static int __maybe_unused imx355_suspend(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx355 *imx355 = to_imx355(sd); - - if (imx355->streaming) - imx355_stop_streaming(imx355); - - return 0; -} - -static int __maybe_unused imx355_resume(struct device *dev) -{ - struct v4l2_subdev *sd = dev_get_drvdata(dev); - struct imx355 *imx355 = to_imx355(sd); - int ret; - - if (imx355->streaming) { - ret = imx355_start_streaming(imx355); - if (ret) - goto error; - } - - return 0; - -error: - imx355_stop_streaming(imx355); - imx355->streaming = 0; - return ret; -} - /* Verify chip ID */ static int imx355_identify_module(struct imx355 *imx355) { - struct i2c_client *client = v4l2_get_subdevdata(&imx355->sd); int ret; u32 val; @@ -1519,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; } @@ -1559,7 +1518,7 @@ 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; s64 vblank_def; @@ -1571,7 +1530,7 @@ static int imx355_init_controls(struct imx355 *imx355) int ret; ctrl_hdlr = &imx355->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 10); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 12); if (ret) return ret; @@ -1584,7 +1543,7 @@ static int imx355_init_controls(struct imx355 *imx355) imx355->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; /* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */ - pixel_rate = imx355->link_def_freq * 2 * 4; + pixel_rate = IMX355_LINK_FREQ_DEFAULT * 2 * 4; do_div(pixel_rate, 10); /* By default, PIXEL_RATE is read only */ imx355->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx355_ctrl_ops, @@ -1639,10 +1598,19 @@ 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(imx355->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx355_ctrl_ops, + &props); + if (ret) + goto error; + imx355->sd.ctrl_handler = ctrl_hdlr; return 0; @@ -1661,7 +1629,6 @@ static struct imx355_hwcfg *imx355_get_hwcfg(struct device *dev) }; struct fwnode_handle *ep; struct fwnode_handle *fwnode = dev_fwnode(dev); - unsigned int i; int ret; if (!fwnode) @@ -1679,38 +1646,14 @@ 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; - } - - 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; @@ -1724,52 +1667,51 @@ out_err: static int imx355_probe(struct i2c_client *client) { struct imx355 *imx355; + unsigned long freq; int ret; - u32 i; 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; } - imx355->link_def_freq = link_freq_menu_items[IMX355_LINK_FREQ_INDEX]; - for (i = 0; i < imx355->hwcfg->nr_of_link_freqs; i++) { - if (imx355->hwcfg->link_freqs[i] == imx355->link_def_freq) { - dev_dbg(&client->dev, "link freq index %d matched", i); - break; - } - } - - if (i == imx355->hwcfg->nr_of_link_freqs) { - dev_err(&client->dev, "no link frequency supported"); - ret = -EINVAL; - goto error_probe; - } - /* Set default mode to max resolution */ imx355->cur_mode = &supported_modes[0]; 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; } @@ -1784,25 +1726,27 @@ 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; } - ret = v4l2_async_register_subdev_sensor(&imx355->sd); - if (ret < 0) - goto error_media_entity; - /* * 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) + goto error_media_entity_runtime_pm; return 0; -error_media_entity: +error_media_entity_runtime_pm: + pm_runtime_disable(imx355->dev); + pm_runtime_set_suspended(imx355->dev); media_entity_cleanup(&imx355->sd.entity); error_handler_free: @@ -1823,16 +1767,12 @@ 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); } -static const struct dev_pm_ops imx355_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(imx355_suspend, imx355_resume) -}; - static const struct acpi_device_id imx355_acpi_ids[] __maybe_unused = { { "SONY355A" }, { /* sentinel */ } @@ -1842,16 +1782,15 @@ MODULE_DEVICE_TABLE(acpi, imx355_acpi_ids); static struct i2c_driver imx355_i2c_driver = { .driver = { .name = "imx355", - .pm = &imx355_pm_ops, .acpi_match_table = ACPI_PTR(imx355_acpi_ids), }, - .probe_new = imx355_probe, + .probe = imx355_probe, .remove = imx355_remove, }; module_i2c_driver(imx355_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 imx355 sensor driver"); |
