Devicetree
 help / color / mirror / Atom feed
From: Sakari Ailus <sakari.ailus@linux.intel.com>
To: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Cc: Philippe Baetens <philippebaetens@gmail.com>,
	Mauro Carvalho Chehab <mchehab@kernel.org>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Kieran Bingham <kieran.bingham@ideasonboard.com>,
	Jai Luthra <jai.luthra@ideasonboard.com>,
	linux-media@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH v10 2/2] media: i2c: Add driver for AMS-OSRAM Mira220
Date: Mon, 3 Aug 2026 13:28:43 +0300	[thread overview]
Message-ID: <anBtWwyNVdKi90Zg@kekkonen.localdomain> (raw)
In-Reply-To: <amypEMpDvY47VkG5@zed>

Hi Jacopo,

On Fri, Jul 31, 2026 at 04:15:53PM +0200, Jacopo Mondi wrote:

...

> > > +	/* Sensor control mode */
> > > +	{ CCI_REG8(0x0043), 0x0 }, //  Sensor Control Mode.SLEEP_POWER_MODE(0)
> > > +	{ CCI_REG8(0x0043), 0x0 }, //  Sensor Control Mode.IDLE_POWER_MODE(0)
> > > +	{ CCI_REG8(0x0043), 0x4 }, //  Sensor Control Mode.SYSTEM_CLOCK_ENABLE(0)
> > > +	{ CCI_REG8(0x0043), 0xC }, //  Sensor Control Mode.SRAM_CLOCK_ENABLE(0)
> > > +	{ CCI_REG8(0x1001), 0x41 }, //  Sensor Control Mode.EXT_EVENT_SEL(0)
> > > +	{ CCI_REG8(0x10f2), 0x1 }, //  Sensor Control Mode.NB_OF_FRAMES_A(0)
> > > +	{ CCI_REG8(0x10f3), 0x0 }, //  Sensor Control Mode.NB_OF_FRAMES_A(1)
> > > +	{ CCI_REG8(0x0012), 0x0 }, //  IO Drive Strength.DIG_DRIVE_STRENGTH(0)
> > > +	{ CCI_REG8(0x0012), 0x0 }, //  IO Drive Strength.CCI_DRIVE_STRENGTH(0)
> > > +	{ CCI_REG8(0x1001), 0x41 }, //  Readout && Exposure.EXT_EXP_PW_SEL(0)
> > > +	{ CCI_REG8(0x10d0), 0x0 }, //  Readout && Exposure.EXT_EXP_PW_DELAY(0)
> > > +	{ CCI_REG8(0x10d1), 0x0 }, //  Readout && Exposure.EXT_EXP_PW_DELAY(1)
> > > +	/* MIPI */
> > > +	{ CCI_REG8(0x6006), 0x0 }, //  MIPI.TX_CTRL_EN(0)
> > > +	{ CCI_REG8(0x5004), 0x1 }, //  MIPI.datarate
> > > +	{ CCI_REG8(0x5086), 0x2 }, //  MIPI.datarate
> > > +	{ CCI_REG8(0x5087), 0x4e }, //  MIPI.datarate
> > > +	{ CCI_REG8(0x5088), 0x0 }, //  MIPI.datarate
> > > +	{ CCI_REG8(0x5090), 0x0 }, //  MIPI.datarate
> >
> > How many of these registers are actually 16 or 32 bits? Does the sensor
> > support wider than single-octet writes -- few don't?
> 
> The sensor is said to support both single read/write and burst read/write
> sequences.
> 
> There is room for improvements here, but as the startup latency is not
> a concern for the time being, I would leave this as an exercize for
> later

Related to the previous comment, it'd be nice to have human-readable names
also for these registers. I'm fine with that if you promise to address this
later. :-)

...

> > > +	ret = pm_runtime_resume_and_get(&client->dev);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	/*
> > > +	 * Apply default values of current mode. Stop streaming before
> > > +	 * uploading register sequence.
> > > +	 */
> > > +	ret = mira220_write_stop_streaming_regs(mira220);
> > > +	if (ret)
> > > +		goto err_rpm_put;
> > > +
> > > +	ret = cci_multi_reg_write(mira220->regmap, mira220_init_reg_list,
> > > +				  ARRAY_SIZE(mira220_init_reg_list), NULL);
> > > +	if (ret)
> > > +		goto err_rpm_put;
> > > +
> > > +	ret = mira220_otp_restore(mira220);
> > > +	if (ret)
> > > +		goto err_rpm_put;
> > > +
> > > +	ret = mira220_set_bus_config(mira220);
> > > +	if (ret)
> > > +		goto err_rpm_put;
> > > +
> > > +	ret = mira220_set_framefmt(mira220, state);
> > > +	if (ret)
> > > +		goto err_rpm_put;
> >
> > Instead of a series of ifs and gotos, you could do
> >
> > 	if (!ret)
> > 		...;
> >
> > Up to you.
> >
> 
> 	ret = pm_runtime_resume_and_get(&client->dev);
> 	if (ret < 0)
> 		return ret;
> 
> 	/*
> 	 * Apply default values of current mode. Stop streaming before
> 	 * uploading register sequence.
> 	 */
> 	if (!ret)
> 		ret = mira220_write_stop_streaming_regs(mira220);
> 	if (!ret)
> 		ret = cci_multi_reg_write(mira220->regmap, mira220_init_reg_list,
> 					  ARRAY_SIZE(mira220_init_reg_list), NULL);
> 	if (!ret)
> 		ret = mira220_otp_restore(mira220);
> 	if (!ret)
> 		ret = mira220_set_bus_config(mira220);
> 	if (!ret)
> 		ret = mira220_set_framefmt(mira220, state);
> 
> 	/* Apply customized values from user */
> 	if (!ret)
> 		ret = __v4l2_ctrl_handler_setup(mira220->sd.ctrl_handler);
> 	if (!ret)
> 		ret = mira220_write_start_streaming_regs(mira220);
> 
> 	if (ret)
> 		goto err_rpm_put;
> 
> 	/* vflip and hflip cannot change during streaming */
> 	__v4l2_ctrl_grab(mira220->hflip, true);
> 	__v4l2_ctrl_grab(mira220->vflip, true);
> 
> 	return 0;
> 
> Looks a bit unusual, but I think I can do that

Such a pattern is used in quite a few sensor drivers.

...

> > > +	/* By default, PIXEL_RATE is read only */
> > > +	v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops, V4L2_CID_PIXEL_RATE,
> > > +			  MIRA220_PIXEL_RATE, MIRA220_PIXEL_RATE, 1,
> > > +			  MIRA220_PIXEL_RATE);
> > > +
> > > +	min_vblank = mira220_calc_min_vblank(mira220);
> > > +	mira220->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
> > > +					    V4L2_CID_VBLANK,
> > > +					    min_vblank, MIRA220_MAX_VBLANK, 1,
> > > +					    min_vblank);
> > > +
> > > +	ctrl = v4l2_ctrl_new_int_menu(ctrl_hdlr, NULL, V4L2_CID_LINK_FREQ,
> > > +				      0, 0, &mira220_link_freqs[0]);
> > > +	if (ctrl)
> > > +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > > +
> > > +	/*
> > > +	 * Scale hblank according to the number of enabled data lanes to match
> > > +	 * row_length.
> > > +	 */
> > > +	hblank_val = MIRA220_LLP_1600x1400_304 * (2 / mira220->lanes)
> > > +		   - MIRA220_PIXEL_ARRAY_WIDTH;
> > > +	ctrl = v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_HBLANK, hblank_val,
> > > +				 hblank_val, 1, hblank_val);
> > > +	if (ctrl)
> > > +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > > +
> > > +	/* Max exposure is determined by vblank + vsize and Tglob. */
> > > +	max_exposure = mira220_calc_exposure(mira220,
> > > +					     MIRA220_PIXEL_ARRAY_HEIGHT,
> > > +					     min_vblank);
> > > +
> > > +	mira220->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
> > > +					      V4L2_CID_EXPOSURE,
> > > +					      MIRA220_EXPOSURE_MIN,
> > > +					      max_exposure, 1,
> > > +					      MIRA220_DEFAULT_EXPOSURE);
> > > +
> > > +	v4l2_ctrl_new_std(ctrl_hdlr, NULL, V4L2_CID_ANALOGUE_GAIN,
> > > +			  MIRA220_ANALOG_GAIN_MIN, MIRA220_ANALOG_GAIN_MAX,
> > > +			  MIRA220_ANALOG_GAIN_STEP,
> > > +			  MIRA220_ANALOG_GAIN_DEFAULT);
> > > +
> > > +	mira220->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &mira220_ctrl_ops,
> > > +					   V4L2_CID_HFLIP, 0, 1, 1, 0);
> > > +	if (mira220->hflip)
> > > +		mira220->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
> >
> > You can omit these checks if you move setting the control flags after
> 
> ah yes
> 
> > checking for the handler's error state. I'd use different variables for the
> > hblank and vblank controls for this reason.
> 
> vblank is writable and stored in the driver structure
> 
> link_freq and hblank are RO and re-use the local 'ctrl' variable.

I indeed meant link_freq indeed, not vblank.

> 
> if I move everything below, I'll have to use 2 different variables for
> sure

Yes, that'd be nice.

...

> > > +	ret = v4l2_async_register_subdev_sensor(&mira220->sd);
> > > +	if (ret < 0) {
> > > +		dev_err_probe(dev, ret,
> > > +			      "failed to register sensor sub-device\n");
> > > +		goto error_subdev_cleanup;
> > > +	}
> > > +
> > > +	pm_runtime_idle(dev);
> >
> > You probably want to call pm_runtime_idle() after setting autosuspend
> > delay.
> >
> To be honest I copied this from imx219 but I can certainly change it.

That could be fixed as well. I'll write a patch for it. :-)

> 
> 
> 
> > > +	pm_runtime_set_autosuspend_delay(dev, 1000);
> > > +	pm_runtime_use_autosuspend(dev);
> > > +
> > > +	return 0;
> > > +
> > > +error_subdev_cleanup:
> > > +	v4l2_subdev_cleanup(&mira220->sd);
> > > +error_media_entity:
> > > +	media_entity_cleanup(&mira220->sd.entity);
> > > +error_handler_free:
> > > +	v4l2_ctrl_handler_free(mira220->sd.ctrl_handler);
> > > +error_power_off:
> > > +	pm_runtime_disable(dev);
> > > +	mira220_power_off(dev);
> > > +	pm_runtime_set_suspended(dev);
> >
> > A newline here perhaps?
> >
> 
> Usually I like to keep error path returns compact
> 
> Thanks, I'll send a new version soon.
> It's mostly minor stuff, do you think I can get this in for this cycle
> (a bit last minute, I know)
> 
> Thanks
>   j
> 
> 
> > > +	return ret;
> > > +}
> > > +
> > > +static void mira220_remove(struct i2c_client *client)
> > > +{
> > > +	struct v4l2_subdev *sd = i2c_get_clientdata(client);
> > > +	struct mira220 *mira220 = to_mira220(sd);
> > > +
> > > +	v4l2_async_unregister_subdev(sd);
> > > +	v4l2_subdev_cleanup(&mira220->sd);
> > > +	media_entity_cleanup(&sd->entity);
> > > +
> > > +	v4l2_ctrl_handler_free(mira220->sd.ctrl_handler);
> > > +
> > > +	pm_runtime_disable(&client->dev);
> > > +	if (!pm_runtime_status_suspended(&client->dev))
> > > +		mira220_power_off(&client->dev);
> > > +	pm_runtime_set_suspended(&client->dev);
> > > +}
> > > +
> > > +static const struct dev_pm_ops mira220_pm_ops = {
> > > +	SET_RUNTIME_PM_OPS(mira220_power_off, mira220_power_on, NULL)
> > > +};
> > > +
> > > +static const struct of_device_id mira220_dt_ids[] = {
> > > +	{ .compatible = "ams,mira220" },
> > > +	{ /* sentinel */ }
> > > +};
> > > +MODULE_DEVICE_TABLE(of, mira220_dt_ids);
> > > +
> > > +static struct i2c_driver mira220_i2c_driver = {
> > > +	.driver = {
> > > +		.name = "mira220",
> > > +		.of_match_table	= mira220_dt_ids,
> > > +		.pm = pm_ptr(&mira220_pm_ops),

If CONFIG_PM isn't defined, mira220_pm_ops needs to use __maybe_unused. I'd
just drop pm_ops() here.

-- 
Regards,

Sakari Ailus

  reply	other threads:[~2026-08-03 10:33 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-27  8:56 [PATCH v10 0/2] media: i2c: Add driver for Mira220 Jacopo Mondi
2026-07-27  8:56 ` [PATCH v10 1/2] dt-bindings: media: i2c: Add mira220 image sensor Jacopo Mondi
2026-07-28 14:43   ` Sakari Ailus
2026-07-31 14:31     ` Jacopo Mondi
2026-08-03 10:19       ` Sakari Ailus
2026-07-27  8:56 ` [PATCH v10 2/2] media: i2c: Add driver for AMS-OSRAM Mira220 Jacopo Mondi
2026-07-27  9:10   ` sashiko-bot
2026-07-28 14:45   ` Sakari Ailus
2026-07-31 14:15     ` Jacopo Mondi
2026-08-03 10:28       ` Sakari Ailus [this message]
2026-08-03 10:59         ` Jacopo Mondi
2026-08-03 20:27           ` Sakari Ailus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=anBtWwyNVdKi90Zg@kekkonen.localdomain \
    --to=sakari.ailus@linux.intel.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=jacopo.mondi@ideasonboard.com \
    --cc=jai.luthra@ideasonboard.com \
    --cc=kieran.bingham@ideasonboard.com \
    --cc=krzk+dt@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=mchehab@kernel.org \
    --cc=philippebaetens@gmail.com \
    --cc=robh@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox