[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAHp75Vcvvadd6EeTWk2ZDrmtCQzWBV8rOoxNCotzYRRPwecaEA@mail.gmail.com>
Date: Fri, 8 Mar 2024 01:11:42 +0200
From: Andy Shevchenko <andy.shevchenko@...il.com>
To: Umang Jain <umang.jain@...asonboard.com>
Cc: linux-media@...r.kernel.org, Sakari Ailus <sakari.ailus@...ux.intel.com>,
Kieran Bingham <kieran.bingham@...asonboard.com>,
Laurent Pinchart <laurent.pinchart@...asonboard.com>, willl will <will@...lwhang.com>,
Mauro Carvalho Chehab <mchehab@...nel.org>, Hans Verkuil <hverkuil-cisco@...all.nl>,
Hans de Goede <hdegoede@...hat.com>, Tomi Valkeinen <tomi.valkeinen@...asonboard.com>,
Alain Volmat <alain.volmat@...s.st.com>, Paul Elder <paul.elder@...asonboard.com>,
Mehdi Djait <mehdi.djait@...tlin.com>, Bingbu Cao <bingbu.cao@...el.com>,
Sebastian Reichel <sre@...nel.org>, Jacopo Mondi <jacopo.mondi@...asonboard.com>,
open list <linux-kernel@...r.kernel.org>
Subject: Re: [PATCH v2 2/2] media: i2c: Add imx283 camera sensor driver
On Thu, Mar 7, 2024 at 11:41 PM Umang Jain <umang.jain@...asonboardcom> wrote:
>
> From: Kieran Bingham <kieran.bingham@...asonboard.com>
>
> Add a v4l2 subdevice driver for the Sony IMX283 image sensor.
>
> The IMX283 is a 20MP Diagonal 15.86 mm (Type 1) CMOS Image Sensor with
> Square Pixel for Color Cameras.
>
> The following features are supported:
> - Manual exposure an gain control support
> - vblank/hblank/link freq control support
> - Test pattern support control
> - Arbitrary horizontal and vertical cropping
> - Supported resolution:
> - 5472x3648 @ 20fps (SRGGB12)
> - 5472x3648 @ 25fps (SRGGB10)
> - 2736x1824 @ 50fps (SRGGB12)
..
+ array_size.h
+ bitops.h
+ container_of.h
> +#include <linux/clk.h>
> +#include <linux/delay.h>
+ errno.h
> +#include <linux/gpio/consumer.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
+ mutex.h
> +#include <linux/of.h>
How is this being used, please?
> +#include <linux/pm_runtime.h>
+ property.h
> +#include <linux/regulator/consumer.h>
+ types.h
> +#include <linux/units.h>
..
> +#define IMX283_HMAX_MAX 0xffff
I would rather use the form of (BIT(16) - 1) to imply that this is
limited by bit field in the HW.
..
> +#define IMX283_VMAX_MAX 0xfffff
Ditto.
..
> +#define IMX283_XCLR_MIN_DELAY_US 1000
> +#define IMX283_XCLR_DELAY_RANGE_US 1000
Perhaps (1 * USEC_PER_MSEC) ?
..
> + /* Veritcal 2/9 subsampling, horizontal 3 binning cropping */
Vertical
..
> +static const s64 link_frequencies[] = {
> + 720 * MEGA, /* 1440 Mbps lane data rate */
> + 360 * MEGA, /* 720 Mbps data lane rate */
HZ_PER_MHZ
> +};
..
> +/* regulator supplies */
> +static const char *const imx283_supply_name[] = {
> + "vadd", /* Analog (2.9V) supply */
> + "vdd1", /* Supply Voltage 2 (1.8V) supply */
> + "vdd2", /* Supply Voltage 3 (1.2V) supply */
> +};
> +
> +
One blank line is enough.
..
> + default:
> + *mode_list = NULL;
> + *num_modes = 0;
break;
..
> + u64 link_frequency = link_frequencies[__ffs(imx283->link_freq_bitmap)];
> +
> + return link_frequency * ddr * lanes / bpp;
No overflow on 32-bit?
..
> +static u64 imx283_internal_clock(unsigned int pixel_rate, unsigned int pixels)
> +{
> + /*
> + * Determine the following operation without overflow:
> + * pixels = 72 * MEGA / pixel_rate
Use proper units in the comments, I believe you want MHz here.
> + * The internal clock at 72MHz and Pixel Rate (between 240 and 576MHz)
> + * can easily overflow this calculation, so pre-divide to simplify.
> + */
> + const u32 iclk_pre = 72 * MEGA / 1000000;
HZ_PER_MHZ
MEGA
(But why? wouldn't simply 72 be enough here?)
> + const u32 pclk_pre = pixel_rate / 1000000;
MEGA
> + return pixels * iclk_pre / pclk_pre;
> +}
..
> +static u64 imx283_iclk_to_pix(unsigned int pixel_rate, unsigned int cycles)
Same comments as per above function.
..
> + do_div(numerator, hmax);
> + numerator = clamp_t(u32, numerator, 0, 0xFFFFFFFF);
Please, avoid _t variant, better to use proper types.
Also the last should be U32_MAX, no?
> + return numerator;
return clamp(...);
..
> + max_shr = min_t(u64, max_shr, 0xFFFF);
No min_t() please. You probably wanted clamp() here.
..
> +/*
> + * Integration Time [s] = [{VMAX x (SVR + 1) – (SHR)} x HMAX + offset]
> + * / (72 x 10^6)
Indent better, so we can read easily.
> + */
..
> + shr = (u32)(vmax * (svr + 1) - temp);
> +
> + return shr;
Unneeded casting, simply
return vmas * ...;
..
> + current_exposure = clamp_t(u32, current_exposure, min_exposure,
> + max_exposure);
Can it be clamp()?
..
> + case V4L2_CID_VBLANK:
> + imx283->vmax = mode->height + ctrl->val;
> + dev_dbg(imx283->dev, "V4L2_CID_VBLANK : %d VMAX : %d\n",
> + ctrl->val, imx283->vmax);
%d or %u? Check ALL specifiers to have proper signedness.
> + ret = cci_write(imx283->cci, IMX283_REG_VMAX, imx283->vmax, NULL);
> + break;
..
> + usleep_range(1000, 2000); /* 1st Stabilisation period of 1 ms or more */
fsleep()
..
> + /* Apply customized values from controls (HMAX/VMAX/SHR) */
> + ret = __v4l2_ctrl_handler_setup(imx283->sd.ctrl_handler);
> +
> + return ret;
return __v4l2_ctrl_handler_setup(...);
..
> + ret = cci_write(imx283->cci, IMX283_REG_STANDBY, IMX283_STBLOGIC, NULL);
> + if (ret)
> + dev_err(imx283->dev, "%s failed to set stream\n", __func__);
Why __func__?
..
> + ret = regulator_bulk_enable(ARRAY_SIZE(imx283_supply_name),
> + imx283->supplies);
> + if (ret) {
> + dev_err(imx283->dev, "%s: failed to enable regulators\n",
> + __func__);
> + return ret;
Ditto.
> + }
> +
> + ret = clk_prepare_enable(imx283->xclk);
> + if (ret) {
> + dev_err(imx283->dev, "%s: failed to enable clock\n",
> + __func__);
Ditto.
> + goto reg_off;
> + }
This Q applies to all error messages.
..
> +static int __maybe_unused imx283_power_off(struct device *dev)
No __maybe_unused in a new code.
..
> + 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 = imx283_native_area;
> + return 0;
> +
> + case V4L2_SEL_TGT_CROP_DEFAULT:
> + case V4L2_SEL_TGT_CROP_BOUNDS:
> + sel->r = imx283_active_area;
> + return 0;
> + }
> +
> + return -EINVAL;
Instead use default: case.
..
> + mutex_lock(imx283->ctrl_handler.lock);
> + mutex_unlock(imx283->ctrl_handler.lock);
Can you use cleanup.h?
..
> +static int imx283_parse_endpoint(struct imx283 *imx283)
> +{
> + struct fwnode_handle *fwnode = dev_fwnode(imx283->dev);
Split this assignment that it will be easier to understand at the
first use where it came from.
> + struct v4l2_fwnode_endpoint bus_cfg = {
> + .bus_type = V4L2_MBUS_CSI2_DPHY
> + };
> + struct fwnode_handle *ep;
> + int ret;
fwnode = ...
> + if (!fwnode)
> + return -ENXIO;
> +
> + ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
> + if (!ep) {
> + dev_err(imx283->dev, "Failed to get next endpoint\n");
> + return -ENXIO;
> + }
> +
> + 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 != 4) {
> + dev_err(imx283->dev,
> + "number of CSI2 data lanes %d is not supported\n",
> + bus_cfg.bus.mipi_csi2.num_data_lanes);
> + ret = -EINVAL;
> + goto done_endpoint_free;
> + }
> +
> + ret = v4l2_link_freq_to_bitmap(imx283->dev, bus_cfg.link_frequencies,
> + bus_cfg.nr_of_link_frequencies,
> + link_frequencies, ARRAY_SIZE(link_frequencies),
> + &imx283->link_freq_bitmap);
> +
> +done_endpoint_free:
> + v4l2_fwnode_endpoint_free(&bus_cfg);
> +
> + return ret;
> +};
..
> + imx283->cci = devm_cci_regmap_init_i2c(client, 16);
> + if (IS_ERR(imx283->cci)) {
> + ret = PTR_ERR(imx283->cci);
> + dev_err(imx283->dev, "failed to initialize CCI: %d\n", ret);
> + return ret;
What's wrong with
return dev_err_probe(...);
?
> + }
..
> + if (!imx283->freq) {
> + dev_err(imx283->dev, "xclk frequency unsupported: %d Hz\n", xclk_freq);
> + return -EINVAL;
return dev_err_probe(...);
> + }
..
> + ret = imx283_parse_endpoint(imx283);
> + if (ret) {
> + dev_err(imx283->dev, "failed to parse endpoint configuration\n");
> + return ret;
Ditto.
Make all messages in ->probe() stage to use the same pattern.
> + }
..
> + /* Request optional enable pin */
> + imx283->reset_gpio = devm_gpiod_get_optional(imx283->dev, "reset",
> + GPIOD_OUT_LOW);
No error check?! Why?
..
> + ret = media_entity_pads_init(&imx283->sd.entity, 1, &imx283->pad);
> + if (ret) {
> + dev_err(imx283->dev, "failed to init entity pads: %d\n", ret);
dev_err_probe(...);
> + goto error_handler_free;
> + }
> +
> + imx283->sd.state_lock = imx283->ctrl_handler.lock;
> + ret = v4l2_subdev_init_finalize(&imx283->sd);
> + if (ret < 0) {
> + dev_err(imx283->dev, "subdev init error: %d\n", ret);
Ditto.
> + goto error_media_entity;
> + }
> +
> + ret = v4l2_async_register_subdev_sensor(&imx283->sd);
> + if (ret < 0) {
> + dev_err(imx283->dev, "failed to register sensor sub-device: %d\n", ret);
Ditto.
> + goto error_subdev_cleanup;
> + }
..
> +static const struct dev_pm_ops imx283_pm_ops = {
> + SET_RUNTIME_PM_OPS(imx283_power_off, imx283_power_on, NULL)
> +};
Use the respective DEFINE_* PM macro.
..
> +static const struct of_device_id imx283_dt_ids[] = {
> + { .compatible = "sony,imx283", },
Inner comma is not needed.
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, imx283_dt_ids);
> +
> +static struct i2c_driver imx283_i2c_driver = {
> + .driver = {
> + .name = "imx283",
> + .of_match_table = imx283_dt_ids,
> + .pm = &imx283_pm_ops,
Missing respective PM macro.
> + },
> + .probe = imx283_probe,
> + .remove = imx283_remove,
> +};
> +
Unneeded blank line.
> +module_i2c_driver(imx283_i2c_driver);
--
With Best Regards,
Andy Shevchenko
Powered by blists - more mailing lists