diff mbox series

[v2,1/3] media: mt9m111: add V4L2_CID_LINK_FREQ support

Message ID 20220916135713.143890-1-m.felsch@pengutronix.de (mailing list archive)
State New, archived
Headers show
Series [v2,1/3] media: mt9m111: add V4L2_CID_LINK_FREQ support | expand

Commit Message

Marco Felsch Sept. 16, 2022, 1:57 p.m. UTC
Add support to report the link frequency.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
The v1 of this small series can be found here:
https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/

Thanks a lot to Jacopo for the review feedback on my v1.

Changelog:

v2:
- use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
---
 drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

Comments

Sakari Ailus Sept. 19, 2022, 12:42 p.m. UTC | #1
Hi Marco,

On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> Add support to report the link frequency.
> 
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> The v1 of this small series can be found here:
> https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
> 
> Thanks a lot to Jacopo for the review feedback on my v1.
> 
> Changelog:
> 
> v2:
> - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> ---
>  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
>  1 file changed, 20 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> index afc86efa9e3e..52be1c310455 100644
> --- a/drivers/media/i2c/mt9m111.c
> +++ b/drivers/media/i2c/mt9m111.c
> @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
>  {
>  	struct mt9m111 *mt9m111;
>  	struct i2c_adapter *adapter = client->adapter;
> +	static s64 extclk_rate;
> +	struct v4l2_ctrl *ctrl;
>  	int ret;
>  
>  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
>  	if (IS_ERR(mt9m111->clk))
>  		return PTR_ERR(mt9m111->clk);
>  
> +	ret = clk_prepare_enable(mt9m111->clk);
> +	if (ret < 0)
> +		return ret;
> +
> +	extclk_rate = clk_get_rate(mt9m111->clk);
> +	clk_disable_unprepare(mt9m111->clk);

I don't think you'll need to enable a clock to just get its frequency.

> +
>  	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
>  	if (IS_ERR(mt9m111->regulator)) {
>  		dev_err(&client->dev, "regulator not found: %ld\n",
> @@ -1285,7 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
>  	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
>  				 V4L2_SUBDEV_FL_HAS_EVENTS;
>  
> -	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
> +	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
>  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
>  			V4L2_CID_VFLIP, 0, 1, 1, 0);
>  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> @@ -1309,6 +1318,16 @@ static int mt9m111_probe(struct i2c_client *client)
>  				BIT(V4L2_COLORFX_NEGATIVE) |
>  				BIT(V4L2_COLORFX_SOLARIZATION)),
>  			V4L2_COLORFX_NONE);
> +	/*
> +	 * The extclk rate equals the link freq. if reg default values are used,
> +	 * which is the case. This must be adapted as soon as we don't use the
> +	 * default values anymore.
> +	 */
> +	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
> +				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
> +	if (ctrl)
> +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +
>  	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
>  	if (mt9m111->hdl.error) {
>  		ret = mt9m111->hdl.error;
Laurent Pinchart Sept. 19, 2022, 12:55 p.m. UTC | #2
On Mon, Sep 19, 2022 at 12:42:15PM +0000, Sakari Ailus wrote:
> Hi Marco,
> 
> On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> > Add support to report the link frequency.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > The v1 of this small series can be found here:
> > https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
> > 
> > Thanks a lot to Jacopo for the review feedback on my v1.
> > 
> > Changelog:
> > 
> > v2:
> > - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> > ---
> >  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
> >  1 file changed, 20 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> > index afc86efa9e3e..52be1c310455 100644
> > --- a/drivers/media/i2c/mt9m111.c
> > +++ b/drivers/media/i2c/mt9m111.c
> > @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
> >  {
> >  	struct mt9m111 *mt9m111;
> >  	struct i2c_adapter *adapter = client->adapter;
> > +	static s64 extclk_rate;
> > +	struct v4l2_ctrl *ctrl;
> >  	int ret;
> >  
> >  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> > @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
> >  	if (IS_ERR(mt9m111->clk))
> >  		return PTR_ERR(mt9m111->clk);
> >  
> > +	ret = clk_prepare_enable(mt9m111->clk);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > +	clk_disable_unprepare(mt9m111->clk);
> 
> I don't think you'll need to enable a clock to just get its frequency.
> 
> > +
> >  	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
> >  	if (IS_ERR(mt9m111->regulator)) {
> >  		dev_err(&client->dev, "regulator not found: %ld\n",
> > @@ -1285,7 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
> >  	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> >  				 V4L2_SUBDEV_FL_HAS_EVENTS;
> >  
> > -	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
> > +	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
> >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> >  			V4L2_CID_VFLIP, 0, 1, 1, 0);
> >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > @@ -1309,6 +1318,16 @@ static int mt9m111_probe(struct i2c_client *client)
> >  				BIT(V4L2_COLORFX_NEGATIVE) |
> >  				BIT(V4L2_COLORFX_SOLARIZATION)),
> >  			V4L2_COLORFX_NONE);
> > +	/*
> > +	 * The extclk rate equals the link freq. if reg default values are used,

s/freq./frequency/

> > +	 * which is the case. This must be adapted as soon as we don't use the
> > +	 * default values anymore.
> > +	 */
> > +	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > +				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
> > +	if (ctrl)
> > +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > +
> >  	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
> >  	if (mt9m111->hdl.error) {
> >  		ret = mt9m111->hdl.error;
Marco Felsch Sept. 19, 2022, 1:08 p.m. UTC | #3
Hi Sakari,

On 22-09-19, Sakari Ailus wrote:
> Hi Marco,
> 
> On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> > Add support to report the link frequency.
> > 
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > The v1 of this small series can be found here:
> > https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
> > 
> > Thanks a lot to Jacopo for the review feedback on my v1.
> > 
> > Changelog:
> > 
> > v2:
> > - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> > ---
> >  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
> >  1 file changed, 20 insertions(+), 1 deletion(-)
> > 
> > diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> > index afc86efa9e3e..52be1c310455 100644
> > --- a/drivers/media/i2c/mt9m111.c
> > +++ b/drivers/media/i2c/mt9m111.c
> > @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
> >  {
> >  	struct mt9m111 *mt9m111;
> >  	struct i2c_adapter *adapter = client->adapter;
> > +	static s64 extclk_rate;
> > +	struct v4l2_ctrl *ctrl;
> >  	int ret;
> >  
> >  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> > @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
> >  	if (IS_ERR(mt9m111->clk))
> >  		return PTR_ERR(mt9m111->clk);
> >  
> > +	ret = clk_prepare_enable(mt9m111->clk);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > +	clk_disable_unprepare(mt9m111->clk);
> 
> I don't think you'll need to enable a clock to just get its frequency.

The official API states that you need to turn on the clk before
requesting it and it makes sense. Also there is a new helper
devm_clk_get_enabled() which addresses simple clk usage since most of
drivers don't enable it before requesting the rate.

Regards,
  Marco

> > +
> >  	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
> >  	if (IS_ERR(mt9m111->regulator)) {
> >  		dev_err(&client->dev, "regulator not found: %ld\n",
> > @@ -1285,7 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
> >  	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> >  				 V4L2_SUBDEV_FL_HAS_EVENTS;
> >  
> > -	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
> > +	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
> >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> >  			V4L2_CID_VFLIP, 0, 1, 1, 0);
> >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > @@ -1309,6 +1318,16 @@ static int mt9m111_probe(struct i2c_client *client)
> >  				BIT(V4L2_COLORFX_NEGATIVE) |
> >  				BIT(V4L2_COLORFX_SOLARIZATION)),
> >  			V4L2_COLORFX_NONE);
> > +	/*
> > +	 * The extclk rate equals the link freq. if reg default values are used,
> > +	 * which is the case. This must be adapted as soon as we don't use the
> > +	 * default values anymore.
> > +	 */
> > +	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > +				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
> > +	if (ctrl)
> > +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > +
> >  	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
> >  	if (mt9m111->hdl.error) {
> >  		ret = mt9m111->hdl.error;
> 
> -- 
> Regards,
> 
> Sakari Ailus
>
Sakari Ailus Sept. 19, 2022, 1:18 p.m. UTC | #4
Hi Marco,

On Mon, Sep 19, 2022 at 03:08:29PM +0200, Marco Felsch wrote:
> Hi Sakari,
> 
> On 22-09-19, Sakari Ailus wrote:
> > Hi Marco,
> > 
> > On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> > > Add support to report the link frequency.
> > > 
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > > The v1 of this small series can be found here:
> > > https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
> > > 
> > > Thanks a lot to Jacopo for the review feedback on my v1.
> > > 
> > > Changelog:
> > > 
> > > v2:
> > > - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> > > ---
> > >  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
> > >  1 file changed, 20 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> > > index afc86efa9e3e..52be1c310455 100644
> > > --- a/drivers/media/i2c/mt9m111.c
> > > +++ b/drivers/media/i2c/mt9m111.c
> > > @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
> > >  {
> > >  	struct mt9m111 *mt9m111;
> > >  	struct i2c_adapter *adapter = client->adapter;
> > > +	static s64 extclk_rate;
> > > +	struct v4l2_ctrl *ctrl;
> > >  	int ret;
> > >  
> > >  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> > > @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
> > >  	if (IS_ERR(mt9m111->clk))
> > >  		return PTR_ERR(mt9m111->clk);
> > >  
> > > +	ret = clk_prepare_enable(mt9m111->clk);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > > +	clk_disable_unprepare(mt9m111->clk);
> > 
> > I don't think you'll need to enable a clock to just get its frequency.
> 
> The official API states that you need to turn on the clk before
> requesting it and it makes sense. Also there is a new helper
> devm_clk_get_enabled() which addresses simple clk usage since most of
> drivers don't enable it before requesting the rate.

I guess the rate could change in the meantime, unless exclusive access is
requested. The clock framework currently doesn't offer a way to set the
assigned rate and prevent changing it. But above, couldn't the clock
frequency be changed again once the clock has been disabled?
Marco Felsch Sept. 20, 2022, 8:56 a.m. UTC | #5
Hi Sakari,

On 22-09-19, Sakari Ailus wrote:

...

> > > > +	ret = clk_prepare_enable(mt9m111->clk);
> > > > +	if (ret < 0)
> > > > +		return ret;
> > > > +
> > > > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > > > +	clk_disable_unprepare(mt9m111->clk);
> > > 
> > > I don't think you'll need to enable a clock to just get its frequency.
> > 
> > The official API states that you need to turn on the clk before
> > requesting it and it makes sense. Also there is a new helper
> > devm_clk_get_enabled() which addresses simple clk usage since most of
> > drivers don't enable it before requesting the rate.
> 
> I guess the rate could change in the meantime, unless exclusive access is
> requested. 

Not only that, there are a bunch of clk provider hw around which may
need to turned on first. Anyway, I really don't care on this topic. As
I said I wanted to fullfil the API and if drop clk_prepare_enable() I
don't. So if this okay for you I will go that way.

> The clock framework currently doesn't offer a way to set the assigned
> rate and prevent changing it. But above, couldn't the clock frequency
> be changed again once the clock has been disabled?

Yes it could.

Regards,
  Marco
Jacopo Mondi Sept. 20, 2022, 9:19 a.m. UTC | #6
Hello

On Tue, Sep 20, 2022 at 10:56:17AM +0200, Marco Felsch wrote:
> Hi Sakari,
>
> On 22-09-19, Sakari Ailus wrote:
>
> ...
>
> > > > > +	ret = clk_prepare_enable(mt9m111->clk);
> > > > > +	if (ret < 0)
> > > > > +		return ret;
> > > > > +
> > > > > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > > > > +	clk_disable_unprepare(mt9m111->clk);
> > > >
> > > > I don't think you'll need to enable a clock to just get its frequency.
> > >
> > > The official API states that you need to turn on the clk before
> > > requesting it and it makes sense. Also there is a new helper
> > > devm_clk_get_enabled() which addresses simple clk usage since most of
> > > drivers don't enable it before requesting the rate.

Had the same question on v1 and Marco pointed me to the clk_get_rate()
documentation
https://elixir.bootlin.com/linux/v6.0-rc1/source/include/linux/clk.h#L682

which indeed specifies
"This is only valid once the clock source has been enabled."

However none (or very few) of the linux-media i2c drivers actually do
that.

I have added in cc the clk framework maintainer to see if he can help
shed some light on this


> >
> > I guess the rate could change in the meantime, unless exclusive access is
> > requested.
>
> Not only that, there are a bunch of clk provider hw around which may
> need to turned on first. Anyway, I really don't care on this topic. As
> I said I wanted to fullfil the API and if drop clk_prepare_enable() I
> don't. So if this okay for you I will go that way.
>
> > The clock framework currently doesn't offer a way to set the assigned
> > rate and prevent changing it. But above, couldn't the clock frequency
> > be changed again once the clock has been disabled?
>
> Yes it could.
>
> Regards,
>   Marco
Jacopo Mondi Sept. 20, 2022, 9:43 a.m. UTC | #7
Hi Marco

On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> Add support to report the link frequency.
>
> Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> ---
> The v1 of this small series can be found here:
> https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
>
> Thanks a lot to Jacopo for the review feedback on my v1.
>
> Changelog:
>
> v2:
> - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> ---
>  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
>  1 file changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> index afc86efa9e3e..52be1c310455 100644
> --- a/drivers/media/i2c/mt9m111.c
> +++ b/drivers/media/i2c/mt9m111.c
> @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
>  {
>  	struct mt9m111 *mt9m111;
>  	struct i2c_adapter *adapter = client->adapter;
> +	static s64 extclk_rate;

Why static ?
Also clk_get_rate() returns an unsigned long


> +	struct v4l2_ctrl *ctrl;
>  	int ret;
>
>  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
>  	if (IS_ERR(mt9m111->clk))
>  		return PTR_ERR(mt9m111->clk);
>
> +	ret = clk_prepare_enable(mt9m111->clk);
> +	if (ret < 0)
> +		return ret;
> +
> +	extclk_rate = clk_get_rate(mt9m111->clk);
> +	clk_disable_unprepare(mt9m111->clk);
> +
>  	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
>  	if (IS_ERR(mt9m111->regulator)) {
>  		dev_err(&client->dev, "regulator not found: %ld\n",
> @@ -1285,7 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
>  	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
>  				 V4L2_SUBDEV_FL_HAS_EVENTS;
>
> -	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
> +	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
>  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
>  			V4L2_CID_VFLIP, 0, 1, 1, 0);
>  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> @@ -1309,6 +1318,16 @@ static int mt9m111_probe(struct i2c_client *client)
>  				BIT(V4L2_COLORFX_NEGATIVE) |
>  				BIT(V4L2_COLORFX_SOLARIZATION)),
>  			V4L2_COLORFX_NONE);

Empty line maybe ?

> +	/*
> +	 * The extclk rate equals the link freq. if reg default values are used,
> +	 * which is the case. This must be adapted as soon as we don't use the
> +	 * default values anymore.
> +	 */
> +	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
> +				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
> +	if (ctrl)
> +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> +

I'm sorry I have not replied to your previous email about using
LINK_FREQ for parallel busses.. I see it mentioned in ext-ctrls-image-process.rst
as you said:

``V4L2_CID_LINK_FREQ (integer menu)``
    The frequency of the data bus (e.g. parallel or CSI-2).

I still have a bit of troubles seeing it apply nicely on a parallel
bus. Isn't PIXEL_RATE more appropriate ? You said you need to know the
overall bus bandwidth in bytes , and pixel_rate * bpp / 8 is equally
valid and easy as link_freq / num_lanes, which requires the receiver
to fetch the remote subdev media bus configuration instead of relying
on the input format. Also LINK_FREQ is a menu control, something nasty
already for CSI-2 busses, which requires to pre-calculate the link
freqs based on the input mclk. It is also meant to be changed by
userspace, while PIXEL_RATE is RO by default.

Sakari, Laurent, what's your take here ?



>  	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
>  	if (mt9m111->hdl.error) {
>  		ret = mt9m111->hdl.error;
> --
> 2.30.2
>
Laurent Pinchart Sept. 20, 2022, 9:48 a.m. UTC | #8
On Tue, Sep 20, 2022 at 11:43:37AM +0200, Jacopo Mondi wrote:
> On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> > Add support to report the link frequency.
> >
> > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > ---
> > The v1 of this small series can be found here:
> > https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
> >
> > Thanks a lot to Jacopo for the review feedback on my v1.
> >
> > Changelog:
> >
> > v2:
> > - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> > ---
> >  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
> >  1 file changed, 20 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> > index afc86efa9e3e..52be1c310455 100644
> > --- a/drivers/media/i2c/mt9m111.c
> > +++ b/drivers/media/i2c/mt9m111.c
> > @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
> >  {
> >  	struct mt9m111 *mt9m111;
> >  	struct i2c_adapter *adapter = client->adapter;
> > +	static s64 extclk_rate;
> 
> Why static ?

I missed that one indeed. I assume it's static because the pointer is
stored in the v4l2_ctrl structure by v4l2_ctrl_new_int_menu(), but
that's wrong. The data should be in the mt9m111 structure instead,
otherwise it won't work right when using multiple sensors.

> Also clk_get_rate() returns an unsigned long

v4l2_ctrl_new_int_menu() requires an s64 pointer.

> > +	struct v4l2_ctrl *ctrl;
> >  	int ret;
> >
> >  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> > @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
> >  	if (IS_ERR(mt9m111->clk))
> >  		return PTR_ERR(mt9m111->clk);
> >
> > +	ret = clk_prepare_enable(mt9m111->clk);
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > +	clk_disable_unprepare(mt9m111->clk);
> > +
> >  	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
> >  	if (IS_ERR(mt9m111->regulator)) {
> >  		dev_err(&client->dev, "regulator not found: %ld\n",
> > @@ -1285,7 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
> >  	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> >  				 V4L2_SUBDEV_FL_HAS_EVENTS;
> >
> > -	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
> > +	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
> >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> >  			V4L2_CID_VFLIP, 0, 1, 1, 0);
> >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > @@ -1309,6 +1318,16 @@ static int mt9m111_probe(struct i2c_client *client)
> >  				BIT(V4L2_COLORFX_NEGATIVE) |
> >  				BIT(V4L2_COLORFX_SOLARIZATION)),
> >  			V4L2_COLORFX_NONE);
> 
> Empty line maybe ?
> 
> > +	/*
> > +	 * The extclk rate equals the link freq. if reg default values are used,
> > +	 * which is the case. This must be adapted as soon as we don't use the
> > +	 * default values anymore.
> > +	 */
> > +	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > +				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
> > +	if (ctrl)
> > +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > +
> 
> I'm sorry I have not replied to your previous email about using
> LINK_FREQ for parallel busses.. I see it mentioned in ext-ctrls-image-process.rst
> as you said:
> 
> ``V4L2_CID_LINK_FREQ (integer menu)``
>     The frequency of the data bus (e.g. parallel or CSI-2).
> 
> I still have a bit of troubles seeing it apply nicely on a parallel
> bus. Isn't PIXEL_RATE more appropriate ?

They are different. When transmitting YUYV_2X8 for instance, the link
frequency is twice the pixel clock rate.

> You said you need to know the
> overall bus bandwidth in bytes , and pixel_rate * bpp / 8 is equally
> valid and easy as link_freq / num_lanes, which requires the receiver
> to fetch the remote subdev media bus configuration instead of relying
> on the input format. Also LINK_FREQ is a menu control, something nasty
> already for CSI-2 busses, which requires to pre-calculate the link
> freqs based on the input mclk. It is also meant to be changed by
> userspace, while PIXEL_RATE is RO by default.
> 
> Sakari, Laurent, what's your take here ?

Ideally both should be implemented by the driver.

> >  	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
> >  	if (mt9m111->hdl.error) {
> >  		ret = mt9m111->hdl.error;
Sakari Ailus Sept. 20, 2022, 10:36 a.m. UTC | #9
Hi Jacopo,

On Tue, Sep 20, 2022 at 11:19:33AM +0200, Jacopo Mondi wrote:
> Hello
> 
> On Tue, Sep 20, 2022 at 10:56:17AM +0200, Marco Felsch wrote:
> > Hi Sakari,
> >
> > On 22-09-19, Sakari Ailus wrote:
> >
> > ...
> >
> > > > > > +	ret = clk_prepare_enable(mt9m111->clk);
> > > > > > +	if (ret < 0)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > > > > > +	clk_disable_unprepare(mt9m111->clk);
> > > > >
> > > > > I don't think you'll need to enable a clock to just get its frequency.
> > > >
> > > > The official API states that you need to turn on the clk before
> > > > requesting it and it makes sense. Also there is a new helper
> > > > devm_clk_get_enabled() which addresses simple clk usage since most of
> > > > drivers don't enable it before requesting the rate.
> 
> Had the same question on v1 and Marco pointed me to the clk_get_rate()
> documentation
> https://elixir.bootlin.com/linux/v6.0-rc1/source/include/linux/clk.h#L682
> 
> which indeed specifies
> "This is only valid once the clock source has been enabled."
> 
> However none (or very few) of the linux-media i2c drivers actually do
> that.

I'm not aware of any. That's indeed what the documentation says. Also
clk_enable() documentation says that "If the clock can not be
enabled/disabled, this should return success". So I wonder how much can
you trust it. ;-)

> 
> I have added in cc the clk framework maintainer to see if he can help
> shed some light on this

Thanks.

But yes, to make this work in general case, one would need a way to ensure
the frequency is the one assigned in DT and that it won't change.

Getting the frequency (in an unreliable way?) isn't perfect but better than
nothing. So far I haven't heard of issues in practice though.
Marco Felsch Sept. 20, 2022, 2:37 p.m. UTC | #10
On 22-09-20, Laurent Pinchart wrote:
> On Tue, Sep 20, 2022 at 11:43:37AM +0200, Jacopo Mondi wrote:
> > On Fri, Sep 16, 2022 at 03:57:11PM +0200, Marco Felsch wrote:
> > > Add support to report the link frequency.
> > >
> > > Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
> > > ---
> > > The v1 of this small series can be found here:
> > > https://lore.kernel.org/all/20220818144712.997477-1-m.felsch@pengutronix.de/
> > >
> > > Thanks a lot to Jacopo for the review feedback on my v1.
> > >
> > > Changelog:
> > >
> > > v2:
> > > - use V4L2_CID_LINK_FREQ instead of V4L2_CID_PIXEL_RATE
> > > ---
> > >  drivers/media/i2c/mt9m111.c | 21 ++++++++++++++++++++-
> > >  1 file changed, 20 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
> > > index afc86efa9e3e..52be1c310455 100644
> > > --- a/drivers/media/i2c/mt9m111.c
> > > +++ b/drivers/media/i2c/mt9m111.c
> > > @@ -1249,6 +1249,8 @@ static int mt9m111_probe(struct i2c_client *client)
> > >  {
> > >  	struct mt9m111 *mt9m111;
> > >  	struct i2c_adapter *adapter = client->adapter;
> > > +	static s64 extclk_rate;
> > 
> > Why static ?
> 
> I missed that one indeed. I assume it's static because the pointer is
> stored in the v4l2_ctrl structure by v4l2_ctrl_new_int_menu(), but
> that's wrong. The data should be in the mt9m111 structure instead,
> otherwise it won't work right when using multiple sensors.

Yes, thats the reason. Didn't had in mind, the fact of using multiple
sensor of the same type. Sry. I will move it to the driver struct of
course.

> > Also clk_get_rate() returns an unsigned long
> 
> v4l2_ctrl_new_int_menu() requires an s64 pointer.

Yes.

Regards,
  Marco

> > > +	struct v4l2_ctrl *ctrl;
> > >  	int ret;
> > >
> > >  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
> > > @@ -1271,6 +1273,13 @@ static int mt9m111_probe(struct i2c_client *client)
> > >  	if (IS_ERR(mt9m111->clk))
> > >  		return PTR_ERR(mt9m111->clk);
> > >
> > > +	ret = clk_prepare_enable(mt9m111->clk);
> > > +	if (ret < 0)
> > > +		return ret;
> > > +
> > > +	extclk_rate = clk_get_rate(mt9m111->clk);
> > > +	clk_disable_unprepare(mt9m111->clk);
> > > +
> > >  	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
> > >  	if (IS_ERR(mt9m111->regulator)) {
> > >  		dev_err(&client->dev, "regulator not found: %ld\n",
> > > @@ -1285,7 +1294,7 @@ static int mt9m111_probe(struct i2c_client *client)
> > >  	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
> > >  				 V4L2_SUBDEV_FL_HAS_EVENTS;
> > >
> > > -	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
> > > +	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
> > >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > >  			V4L2_CID_VFLIP, 0, 1, 1, 0);
> > >  	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > > @@ -1309,6 +1318,16 @@ static int mt9m111_probe(struct i2c_client *client)
> > >  				BIT(V4L2_COLORFX_NEGATIVE) |
> > >  				BIT(V4L2_COLORFX_SOLARIZATION)),
> > >  			V4L2_COLORFX_NONE);
> > 
> > Empty line maybe ?
> > 
> > > +	/*
> > > +	 * The extclk rate equals the link freq. if reg default values are used,
> > > +	 * which is the case. This must be adapted as soon as we don't use the
> > > +	 * default values anymore.
> > > +	 */
> > > +	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
> > > +				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
> > > +	if (ctrl)
> > > +		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
> > > +
> > 
> > I'm sorry I have not replied to your previous email about using
> > LINK_FREQ for parallel busses.. I see it mentioned in ext-ctrls-image-process.rst
> > as you said:
> > 
> > ``V4L2_CID_LINK_FREQ (integer menu)``
> >     The frequency of the data bus (e.g. parallel or CSI-2).
> > 
> > I still have a bit of troubles seeing it apply nicely on a parallel
> > bus. Isn't PIXEL_RATE more appropriate ?
> 
> They are different. When transmitting YUYV_2X8 for instance, the link
> frequency is twice the pixel clock rate.
> 
> > You said you need to know the
> > overall bus bandwidth in bytes , and pixel_rate * bpp / 8 is equally
> > valid and easy as link_freq / num_lanes, which requires the receiver
> > to fetch the remote subdev media bus configuration instead of relying
> > on the input format. Also LINK_FREQ is a menu control, something nasty
> > already for CSI-2 busses, which requires to pre-calculate the link
> > freqs based on the input mclk. It is also meant to be changed by
> > userspace, while PIXEL_RATE is RO by default.
> > 
> > Sakari, Laurent, what's your take here ?
> 
> Ideally both should be implemented by the driver.
> 
> > >  	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
> > >  	if (mt9m111->hdl.error) {
> > >  		ret = mt9m111->hdl.error;
> 
> -- 
> Regards,
> 
> Laurent Pinchart
>
diff mbox series

Patch

diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index afc86efa9e3e..52be1c310455 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -1249,6 +1249,8 @@  static int mt9m111_probe(struct i2c_client *client)
 {
 	struct mt9m111 *mt9m111;
 	struct i2c_adapter *adapter = client->adapter;
+	static s64 extclk_rate;
+	struct v4l2_ctrl *ctrl;
 	int ret;
 
 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
@@ -1271,6 +1273,13 @@  static int mt9m111_probe(struct i2c_client *client)
 	if (IS_ERR(mt9m111->clk))
 		return PTR_ERR(mt9m111->clk);
 
+	ret = clk_prepare_enable(mt9m111->clk);
+	if (ret < 0)
+		return ret;
+
+	extclk_rate = clk_get_rate(mt9m111->clk);
+	clk_disable_unprepare(mt9m111->clk);
+
 	mt9m111->regulator = devm_regulator_get(&client->dev, "vdd");
 	if (IS_ERR(mt9m111->regulator)) {
 		dev_err(&client->dev, "regulator not found: %ld\n",
@@ -1285,7 +1294,7 @@  static int mt9m111_probe(struct i2c_client *client)
 	mt9m111->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
 				 V4L2_SUBDEV_FL_HAS_EVENTS;
 
-	v4l2_ctrl_handler_init(&mt9m111->hdl, 7);
+	v4l2_ctrl_handler_init(&mt9m111->hdl, 8);
 	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
 			V4L2_CID_VFLIP, 0, 1, 1, 0);
 	v4l2_ctrl_new_std(&mt9m111->hdl, &mt9m111_ctrl_ops,
@@ -1309,6 +1318,16 @@  static int mt9m111_probe(struct i2c_client *client)
 				BIT(V4L2_COLORFX_NEGATIVE) |
 				BIT(V4L2_COLORFX_SOLARIZATION)),
 			V4L2_COLORFX_NONE);
+	/*
+	 * The extclk rate equals the link freq. if reg default values are used,
+	 * which is the case. This must be adapted as soon as we don't use the
+	 * default values anymore.
+	 */
+	ctrl = v4l2_ctrl_new_int_menu(&mt9m111->hdl, &mt9m111_ctrl_ops,
+				      V4L2_CID_LINK_FREQ, 0, 0, &extclk_rate);
+	if (ctrl)
+		ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
 	mt9m111->subdev.ctrl_handler = &mt9m111->hdl;
 	if (mt9m111->hdl.error) {
 		ret = mt9m111->hdl.error;