diff mbox series

[4/6] thermal: renesas: rzg3s: Add thermal driver for the Renesas RZ/G3S SoC

Message ID 20250103163805.1775705-5-claudiu.beznea.uj@bp.renesas.com (mailing list archive)
State Under Review
Delegated to: Geert Uytterhoeven
Headers show
Series thermal: renesas: Add support for RZ/G3S | expand

Commit Message

Claudiu Beznea Jan. 3, 2025, 4:38 p.m. UTC
From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that reports
the junction temperature. The temperature is reported through a dedicated
ADC channel. Add a driver for the Renesas RZ/G3S TSU.

Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
---
 MAINTAINERS                             |   7 +
 drivers/thermal/renesas/Kconfig         |   8 +
 drivers/thermal/renesas/Makefile        |   1 +
 drivers/thermal/renesas/rzg3s_thermal.c | 301 ++++++++++++++++++++++++
 4 files changed, 317 insertions(+)
 create mode 100644 drivers/thermal/renesas/rzg3s_thermal.c

Comments

Geert Uytterhoeven Jan. 22, 2025, 10:29 a.m. UTC | #1
Hi Claudiu,

CC iio

On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>
> The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that reports
> the junction temperature. The temperature is reported through a dedicated
> ADC channel. Add a driver for the Renesas RZ/G3S TSU.
>
> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>

Thanks for your patch!

> --- /dev/null
> +++ b/drivers/thermal/renesas/rzg3s_thermal.c

> +static int rzg3s_thermal_probe(struct platform_device *pdev)
> +{
> +       struct rzg3s_thermal_priv *priv;
> +       struct device *dev = &pdev->dev;
> +       int ret;
> +
> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +       if (!priv)
> +               return -ENOMEM;
> +
> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> +       if (IS_ERR(priv->base))
> +               return PTR_ERR(priv->base);
> +
> +       priv->channel = devm_iio_channel_get(dev, "tsu");

Given there's only a single IIO channel, you could pass NULL instead
of the name, and drop "io-channel-names" from the DT bindings.
I don't know what's the IIO policy w.r.t. unnamed channels, though.

> +       if (IS_ERR(priv->channel))
> +               return dev_err_probe(dev, PTR_ERR(priv->channel), "Failed to get IIO channel!\n");
> +
> +       priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL);
> +       if (IS_ERR(priv->rstc))
> +               return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get reset!\n");
> +
> +       priv->dev = dev;
> +       priv->mode = THERMAL_DEVICE_DISABLED;
> +       platform_set_drvdata(pdev, priv);
> +
> +       pm_runtime_set_autosuspend_delay(dev, 300);
> +       pm_runtime_use_autosuspend(dev);
> +       pm_runtime_enable(dev);
> +
> +       ret = rzg3s_thermal_read_calib(priv);
> +       if (ret) {
> +               dev_err_probe(dev, ret, "Failed to read calibration data!\n");
> +               goto rpm_disable;
> +       }
> +
> +       priv->tz = thermal_of_zone_register(dev->of_node, 0, priv, &rzg3s_tz_of_ops);
> +       if (IS_ERR(priv->tz)) {
> +               dev_err_probe(dev, PTR_ERR(priv->tz), "Failed to register thermal zone!\n");
> +               goto rpm_disable;
> +       }
> +
> +       ret = thermal_add_hwmon_sysfs(priv->tz);
> +       if (ret) {
> +               dev_err_probe(dev, ret, "Failed to add hwmon sysfs!\n");
> +               goto tz_unregister;
> +       }
> +
> +       return 0;
> +
> +tz_unregister:
> +       thermal_of_zone_unregister(priv->tz);
> +rpm_disable:
> +       pm_runtime_disable(dev);
> +       pm_runtime_dont_use_autosuspend(dev);
> +       return ret;
> +}

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Jonathan Cameron Jan. 25, 2025, 12:18 p.m. UTC | #2
On Wed, 22 Jan 2025 11:29:19 +0100
Geert Uytterhoeven <geert@linux-m68k.org> wrote:

> Hi Claudiu,
> 
> CC iio
> 
> On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> > From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >
> > The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that reports
> > the junction temperature. The temperature is reported through a dedicated
> > ADC channel. Add a driver for the Renesas RZ/G3S TSU.
> >
> > Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>  
> 
> Thanks for your patch!
> 
> > --- /dev/null
> > +++ b/drivers/thermal/renesas/rzg3s_thermal.c  
> 
> > +static int rzg3s_thermal_probe(struct platform_device *pdev)
> > +{
> > +       struct rzg3s_thermal_priv *priv;
> > +       struct device *dev = &pdev->dev;
> > +       int ret;
> > +
> > +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > +       if (!priv)
> > +               return -ENOMEM;
> > +
> > +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> > +       if (IS_ERR(priv->base))
> > +               return PTR_ERR(priv->base);
> > +
> > +       priv->channel = devm_iio_channel_get(dev, "tsu");  
> 
> Given there's only a single IIO channel, you could pass NULL instead
> of the name, and drop "io-channel-names" from the DT bindings.
> I don't know what's the IIO policy w.r.t. unnamed channels, though.

It's supported, so fine as long as no future additional names show up.
Will just fallback to index 0 I think.

Jonathan

> 
> > +       if (IS_ERR(priv->channel))
> > +               return dev_err_probe(dev, PTR_ERR(priv->channel), "Failed to get IIO channel!\n");
> > +
> > +       priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL);
> > +       if (IS_ERR(priv->rstc))
> > +               return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get reset!\n");
> > +
> > +       priv->dev = dev;
> > +       priv->mode = THERMAL_DEVICE_DISABLED;
> > +       platform_set_drvdata(pdev, priv);
> > +
> > +       pm_runtime_set_autosuspend_delay(dev, 300);
> > +       pm_runtime_use_autosuspend(dev);
> > +       pm_runtime_enable(dev);
> > +
> > +       ret = rzg3s_thermal_read_calib(priv);
> > +       if (ret) {
> > +               dev_err_probe(dev, ret, "Failed to read calibration data!\n");
> > +               goto rpm_disable;
> > +       }
> > +
> > +       priv->tz = thermal_of_zone_register(dev->of_node, 0, priv, &rzg3s_tz_of_ops);
> > +       if (IS_ERR(priv->tz)) {
> > +               dev_err_probe(dev, PTR_ERR(priv->tz), "Failed to register thermal zone!\n");
> > +               goto rpm_disable;
> > +       }
> > +
> > +       ret = thermal_add_hwmon_sysfs(priv->tz);
> > +       if (ret) {
> > +               dev_err_probe(dev, ret, "Failed to add hwmon sysfs!\n");
> > +               goto tz_unregister;
> > +       }
> > +
> > +       return 0;
> > +
> > +tz_unregister:
> > +       thermal_of_zone_unregister(priv->tz);
> > +rpm_disable:
> > +       pm_runtime_disable(dev);
> > +       pm_runtime_dont_use_autosuspend(dev);
> > +       return ret;
> > +}  
> 
> Gr{oetje,eeting}s,
> 
>                         Geert
> 
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
> 
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
>                                 -- Linus Torvalds
>
Claudiu Beznea Jan. 27, 2025, 8:32 a.m. UTC | #3
On 25.01.2025 14:18, Jonathan Cameron wrote:
> On Wed, 22 Jan 2025 11:29:19 +0100
> Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> 
>> Hi Claudiu,
>>
>> CC iio
>>
>> On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>
>>> The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that reports
>>> the junction temperature. The temperature is reported through a dedicated
>>> ADC channel. Add a driver for the Renesas RZ/G3S TSU.
>>>
>>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>  
>>
>> Thanks for your patch!
>>
>>> --- /dev/null
>>> +++ b/drivers/thermal/renesas/rzg3s_thermal.c  
>>
>>> +static int rzg3s_thermal_probe(struct platform_device *pdev)
>>> +{
>>> +       struct rzg3s_thermal_priv *priv;
>>> +       struct device *dev = &pdev->dev;
>>> +       int ret;
>>> +
>>> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>> +       if (!priv)
>>> +               return -ENOMEM;
>>> +
>>> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
>>> +       if (IS_ERR(priv->base))
>>> +               return PTR_ERR(priv->base);
>>> +
>>> +       priv->channel = devm_iio_channel_get(dev, "tsu");  
>>
>> Given there's only a single IIO channel, you could pass NULL instead
>> of the name, and drop "io-channel-names" from the DT bindings.
>> I don't know what's the IIO policy w.r.t. unnamed channels, though.
> 
> It's supported, so fine as long as no future additional names show up.
> Will just fallback to index 0 I think.

If everyone agrees, I would keep the name, too, to avoid complications in
case this IP variant will be extended on future SoCs.

Thank you,
Claudiu

> 
> Jonathan
> 
>>
>>> +       if (IS_ERR(priv->channel))
>>> +               return dev_err_probe(dev, PTR_ERR(priv->channel), "Failed to get IIO channel!\n");
>>> +
>>> +       priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL);
>>> +       if (IS_ERR(priv->rstc))
>>> +               return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get reset!\n");
>>> +
>>> +       priv->dev = dev;
>>> +       priv->mode = THERMAL_DEVICE_DISABLED;
>>> +       platform_set_drvdata(pdev, priv);
>>> +
>>> +       pm_runtime_set_autosuspend_delay(dev, 300);
>>> +       pm_runtime_use_autosuspend(dev);
>>> +       pm_runtime_enable(dev);
>>> +
>>> +       ret = rzg3s_thermal_read_calib(priv);
>>> +       if (ret) {
>>> +               dev_err_probe(dev, ret, "Failed to read calibration data!\n");
>>> +               goto rpm_disable;
>>> +       }
>>> +
>>> +       priv->tz = thermal_of_zone_register(dev->of_node, 0, priv, &rzg3s_tz_of_ops);
>>> +       if (IS_ERR(priv->tz)) {
>>> +               dev_err_probe(dev, PTR_ERR(priv->tz), "Failed to register thermal zone!\n");
>>> +               goto rpm_disable;
>>> +       }
>>> +
>>> +       ret = thermal_add_hwmon_sysfs(priv->tz);
>>> +       if (ret) {
>>> +               dev_err_probe(dev, ret, "Failed to add hwmon sysfs!\n");
>>> +               goto tz_unregister;
>>> +       }
>>> +
>>> +       return 0;
>>> +
>>> +tz_unregister:
>>> +       thermal_of_zone_unregister(priv->tz);
>>> +rpm_disable:
>>> +       pm_runtime_disable(dev);
>>> +       pm_runtime_dont_use_autosuspend(dev);
>>> +       return ret;
>>> +}  
>>
>> Gr{oetje,eeting}s,
>>
>>                         Geert
>>
>> --
>> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
>>
>> In personal conversations with technical people, I call myself a hacker. But
>> when I'm talking to journalists I just say "programmer" or something like that.
>>                                 -- Linus Torvalds
>>
>
Geert Uytterhoeven Jan. 27, 2025, 8:54 a.m. UTC | #4
Hi Claudiu,

On Mon, 27 Jan 2025 at 09:33, Claudiu Beznea <claudiu.beznea@tuxon.dev> wrote:
> On 25.01.2025 14:18, Jonathan Cameron wrote:
> > On Wed, 22 Jan 2025 11:29:19 +0100
> > Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >> On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> >>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>>
> >>> The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that reports
> >>> the junction temperature. The temperature is reported through a dedicated
> >>> ADC channel. Add a driver for the Renesas RZ/G3S TSU.
> >>>
> >>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>
> >> Thanks for your patch!
> >>
> >>> --- /dev/null
> >>> +++ b/drivers/thermal/renesas/rzg3s_thermal.c
> >>
> >>> +static int rzg3s_thermal_probe(struct platform_device *pdev)
> >>> +{
> >>> +       struct rzg3s_thermal_priv *priv;
> >>> +       struct device *dev = &pdev->dev;
> >>> +       int ret;
> >>> +
> >>> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >>> +       if (!priv)
> >>> +               return -ENOMEM;
> >>> +
> >>> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> >>> +       if (IS_ERR(priv->base))
> >>> +               return PTR_ERR(priv->base);
> >>> +
> >>> +       priv->channel = devm_iio_channel_get(dev, "tsu");
> >>
> >> Given there's only a single IIO channel, you could pass NULL instead
> >> of the name, and drop "io-channel-names" from the DT bindings.
> >> I don't know what's the IIO policy w.r.t. unnamed channels, though.
> >
> > It's supported, so fine as long as no future additional names show up.
> > Will just fallback to index 0 I think.
>
> If everyone agrees, I would keep the name, too, to avoid complications in
> case this IP variant will be extended on future SoCs.

Fine for me.

Gr{oetje,eeting}s,

                        Geert
Biju Das Jan. 27, 2025, 9:11 a.m. UTC | #5
Hi Claudiu,

> -----Original Message-----
> From: Geert Uytterhoeven <geert@linux-m68k.org>
> Sent: 27 January 2025 08:55
> Subject: Re: [PATCH 4/6] thermal: renesas: rzg3s: Add thermal driver for the Renesas RZ/G3S SoC
> 
> Hi Claudiu,
> 
> On Mon, 27 Jan 2025 at 09:33, Claudiu Beznea <claudiu.beznea@tuxon.dev> wrote:
> > On 25.01.2025 14:18, Jonathan Cameron wrote:
> > > On Wed, 22 Jan 2025 11:29:19 +0100
> > > Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> > >> On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> > >>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > >>>
> > >>> The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that
> > >>> reports the junction temperature. The temperature is reported
> > >>> through a dedicated ADC channel. Add a driver for the Renesas RZ/G3S TSU.
> > >>>
> > >>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> > >>
> > >> Thanks for your patch!
> > >>
> > >>> --- /dev/null
> > >>> +++ b/drivers/thermal/renesas/rzg3s_thermal.c
> > >>
> > >>> +static int rzg3s_thermal_probe(struct platform_device *pdev) {
> > >>> +       struct rzg3s_thermal_priv *priv;
> > >>> +       struct device *dev = &pdev->dev;
> > >>> +       int ret;
> > >>> +
> > >>> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> > >>> +       if (!priv)
> > >>> +               return -ENOMEM;
> > >>> +
> > >>> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> > >>> +       if (IS_ERR(priv->base))
> > >>> +               return PTR_ERR(priv->base);
> > >>> +
> > >>> +       priv->channel = devm_iio_channel_get(dev, "tsu");
> > >>
> > >> Given there's only a single IIO channel, you could pass NULL
> > >> instead of the name, and drop "io-channel-names" from the DT bindings.
> > >> I don't know what's the IIO policy w.r.t. unnamed channels, though.
> > >
> > > It's supported, so fine as long as no future additional names show up.
> > > Will just fallback to index 0 I think.
> >
> > If everyone agrees, I would keep the name, too, to avoid complications
> > in case this IP variant will be extended on future SoCs.

If you are planning to extend this driver to other SoCs then may be update
KConfig with dependency on ARCH_RENESAS? see [1]

[1] https://lore.kernel.org/linux-renesas-soc/20250118-trout-of-luxurious-inquire-aae9aa@krzk-bin/

Cheers,
Biju
Claudiu Beznea Jan. 27, 2025, 9:15 a.m. UTC | #6
Hi, Biju,

On 27.01.2025 11:11, Biju Das wrote:
> Hi Claudiu,
> 
>> -----Original Message-----
>> From: Geert Uytterhoeven <geert@linux-m68k.org>
>> Sent: 27 January 2025 08:55
>> Subject: Re: [PATCH 4/6] thermal: renesas: rzg3s: Add thermal driver for the Renesas RZ/G3S SoC
>>
>> Hi Claudiu,
>>
>> On Mon, 27 Jan 2025 at 09:33, Claudiu Beznea <claudiu.beznea@tuxon.dev> wrote:
>>> On 25.01.2025 14:18, Jonathan Cameron wrote:
>>>> On Wed, 22 Jan 2025 11:29:19 +0100
>>>> Geert Uytterhoeven <geert@linux-m68k.org> wrote:
>>>>> On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
>>>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>>>
>>>>>> The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that
>>>>>> reports the junction temperature. The temperature is reported
>>>>>> through a dedicated ADC channel. Add a driver for the Renesas RZ/G3S TSU.
>>>>>>
>>>>>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
>>>>>
>>>>> Thanks for your patch!
>>>>>
>>>>>> --- /dev/null
>>>>>> +++ b/drivers/thermal/renesas/rzg3s_thermal.c
>>>>>
>>>>>> +static int rzg3s_thermal_probe(struct platform_device *pdev) {
>>>>>> +       struct rzg3s_thermal_priv *priv;
>>>>>> +       struct device *dev = &pdev->dev;
>>>>>> +       int ret;
>>>>>> +
>>>>>> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>>>>>> +       if (!priv)
>>>>>> +               return -ENOMEM;
>>>>>> +
>>>>>> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
>>>>>> +       if (IS_ERR(priv->base))
>>>>>> +               return PTR_ERR(priv->base);
>>>>>> +
>>>>>> +       priv->channel = devm_iio_channel_get(dev, "tsu");
>>>>>
>>>>> Given there's only a single IIO channel, you could pass NULL
>>>>> instead of the name, and drop "io-channel-names" from the DT bindings.
>>>>> I don't know what's the IIO policy w.r.t. unnamed channels, though.
>>>>
>>>> It's supported, so fine as long as no future additional names show up.
>>>> Will just fallback to index 0 I think.
>>>
>>> If everyone agrees, I would keep the name, too, to avoid complications
>>> in case this IP variant will be extended on future SoCs.
> 
> If you are planning to extend this driver to other SoCs then may be update

I don't plan to extend it. My point here was to keep the driver as is for
any possible future extensions that might arise.

Thank you,
Claudiu

> KConfig with dependency on ARCH_RENESAS? see [1]
> 
> [1] https://lore.kernel.org/linux-renesas-soc/20250118-trout-of-luxurious-inquire-aae9aa@krzk-bin/
> 
> Cheers,
> Biju
Biju Das Jan. 27, 2025, 9:17 a.m. UTC | #7
Hi Claudiu,

> -----Original Message-----
> From: Claudiu Beznea <claudiu.beznea@tuxon.dev>
> Sent: 27 January 2025 09:16
> Subject: Re: [PATCH 4/6] thermal: renesas: rzg3s: Add thermal driver for the Renesas RZ/G3S SoC
> 
> Hi, Biju,
> 
> On 27.01.2025 11:11, Biju Das wrote:
> > Hi Claudiu,
> >
> >> -----Original Message-----
> >> From: Geert Uytterhoeven <geert@linux-m68k.org>
> >> Sent: 27 January 2025 08:55
> >> Subject: Re: [PATCH 4/6] thermal: renesas: rzg3s: Add thermal driver
> >> for the Renesas RZ/G3S SoC
> >>
> >> Hi Claudiu,
> >>
> >> On Mon, 27 Jan 2025 at 09:33, Claudiu Beznea <claudiu.beznea@tuxon.dev> wrote:
> >>> On 25.01.2025 14:18, Jonathan Cameron wrote:
> >>>> On Wed, 22 Jan 2025 11:29:19 +0100
> >>>> Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >>>>> On Fri, Jan 3, 2025 at 5:38 PM Claudiu <claudiu.beznea@tuxon.dev> wrote:
> >>>>>> From: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>>>>>
> >>>>>> The Renesas RZ/G3S SoC features a Thermal Sensor Unit (TSU) that
> >>>>>> reports the junction temperature. The temperature is reported
> >>>>>> through a dedicated ADC channel. Add a driver for the Renesas RZ/G3S TSU.
> >>>>>>
> >>>>>> Signed-off-by: Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
> >>>>>
> >>>>> Thanks for your patch!
> >>>>>
> >>>>>> --- /dev/null
> >>>>>> +++ b/drivers/thermal/renesas/rzg3s_thermal.c
> >>>>>
> >>>>>> +static int rzg3s_thermal_probe(struct platform_device *pdev) {
> >>>>>> +       struct rzg3s_thermal_priv *priv;
> >>>>>> +       struct device *dev = &pdev->dev;
> >>>>>> +       int ret;
> >>>>>> +
> >>>>>> +       priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> >>>>>> +       if (!priv)
> >>>>>> +               return -ENOMEM;
> >>>>>> +
> >>>>>> +       priv->base = devm_platform_ioremap_resource(pdev, 0);
> >>>>>> +       if (IS_ERR(priv->base))
> >>>>>> +               return PTR_ERR(priv->base);
> >>>>>> +
> >>>>>> +       priv->channel = devm_iio_channel_get(dev, "tsu");
> >>>>>
> >>>>> Given there's only a single IIO channel, you could pass NULL
> >>>>> instead of the name, and drop "io-channel-names" from the DT bindings.
> >>>>> I don't know what's the IIO policy w.r.t. unnamed channels, though.
> >>>>
> >>>> It's supported, so fine as long as no future additional names show up.
> >>>> Will just fallback to index 0 I think.
> >>>
> >>> If everyone agrees, I would keep the name, too, to avoid
> >>> complications in case this IP variant will be extended on future SoCs.
> >
> > If you are planning to extend this driver to other SoCs then may be
> > update
> 
> I don't plan to extend it. My point here was to keep the driver as is for any possible future
> extensions that might arise.

OK, then it is fine as the driver is only for RZ/G3S SoC.

Cheers,
Biju
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index d2ab799a0659..0b5854dc2d5d 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20131,6 +20131,13 @@  S:	Maintained
 F:	Documentation/devicetree/bindings/iio/potentiometer/renesas,x9250.yaml
 F:	drivers/iio/potentiometer/x9250.c
 
+RENESAS RZ/G3S THERMAL SENSOR UNIT DRIVER
+M:	Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>
+L:	linux-pm@vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/thermal/renesas,r9a08g045-tsu.yaml
+F:	drivers/thermal/renesas/rzg3s_thermal.c
+
 RESET CONTROLLER FRAMEWORK
 M:	Philipp Zabel <p.zabel@pengutronix.de>
 S:	Maintained
diff --git a/drivers/thermal/renesas/Kconfig b/drivers/thermal/renesas/Kconfig
index dcf5fc5ae08e..566478797095 100644
--- a/drivers/thermal/renesas/Kconfig
+++ b/drivers/thermal/renesas/Kconfig
@@ -26,3 +26,11 @@  config RZG2L_THERMAL
 	help
 	  Enable this to plug the RZ/G2L thermal sensor driver into the Linux
 	  thermal framework.
+
+config RZG3S_THERMAL
+	tristate "Renesas RZ/G3S thermal driver"
+	depends on ARCH_R9A08G045 || COMPILE_TEST
+	depends on OF && IIO && RZG2L_ADC
+	help
+	  Enable this to plug the RZ/G3S thermal sensor driver into the Linux
+	  thermal framework.
diff --git a/drivers/thermal/renesas/Makefile b/drivers/thermal/renesas/Makefile
index bf9cb3cb94d6..1feb5ab78827 100644
--- a/drivers/thermal/renesas/Makefile
+++ b/drivers/thermal/renesas/Makefile
@@ -3,3 +3,4 @@ 
 obj-$(CONFIG_RCAR_GEN3_THERMAL)	+= rcar_gen3_thermal.o
 obj-$(CONFIG_RCAR_THERMAL)	+= rcar_thermal.o
 obj-$(CONFIG_RZG2L_THERMAL)	+= rzg2l_thermal.o
+obj-$(CONFIG_RZG3S_THERMAL)	+= rzg3s_thermal.o
diff --git a/drivers/thermal/renesas/rzg3s_thermal.c b/drivers/thermal/renesas/rzg3s_thermal.c
new file mode 100644
index 000000000000..6719f9ca05eb
--- /dev/null
+++ b/drivers/thermal/renesas/rzg3s_thermal.c
@@ -0,0 +1,301 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Renesas RZ/G3S TSU Thermal Sensor Driver
+ *
+ * Copyright (C) 2024 Renesas Electronics Corporation
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/iio/consumer.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/reset.h>
+#include <linux/thermal.h>
+#include <linux/units.h>
+
+#include "../thermal_hwmon.h"
+
+#define TSU_SM			0x0
+#define TSU_SM_EN		BIT(0)
+#define TSU_SM_OE		BIT(1)
+#define OTPTSUTRIM_REG(n)	(0x18 + (n) * 0x4)
+#define OTPTSUTRIM_EN_MASK	BIT(31)
+#define OTPTSUTRIM_MASK		GENMASK(11, 0)
+
+#define TSU_READ_STEPS		8
+
+/* Default calibration values, if FUSE values are missing. */
+#define SW_CALIB0_VAL		1297
+#define SW_CALIB1_VAL		751
+
+#define MCELSIUS(temp)		((temp) * MILLIDEGREE_PER_DEGREE)
+
+/**
+ * struct rzg3s_thermal_priv - RZ/G3S thermal private data structure
+ * @base: TSU base address
+ * @dev: device pointer
+ * @tz: thermal zone pointer
+ * @rstc: reset control
+ * @channel: IIO channel to read the TSU
+ * @mode: current device mode
+ * @calib0: calibration value
+ * @calib1: calibration value
+ */
+struct rzg3s_thermal_priv {
+	void __iomem *base;
+	struct device *dev;
+	struct thermal_zone_device *tz;
+	struct reset_control *rstc;
+	struct iio_channel *channel;
+	enum thermal_device_mode mode;
+	u16 calib0;
+	u16 calib1;
+};
+
+static int rzg3s_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
+{
+	struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz);
+	struct device *dev = priv->dev;
+	u32 ts_code_ave = 0;
+	int ret, val;
+
+	if (priv->mode != THERMAL_DEVICE_ENABLED)
+		return -EAGAIN;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
+
+	for (u8 i = 0; i < TSU_READ_STEPS; i++) {
+		ret = iio_read_channel_raw(priv->channel, &val);
+		if (ret < 0)
+			goto rpm_put;
+
+		ts_code_ave += val;
+		/*
+		 * According to the HW manual (section 40.4.4 Procedure for Measuring the
+		 * Temperature) we need to wait here at leat 3us.
+		 */
+		usleep_range(5, 10);
+	}
+
+	ret = 0;
+	ts_code_ave = DIV_ROUND_CLOSEST(ts_code_ave, TSU_READ_STEPS);
+
+	/*
+	 * According to the HW manual (section 40.4.4 Procedure for Measuring the Temperature)
+	 * the computation formula is as follows:
+	 *
+	 * Tj = (ts_code_ave - priv->calib1) * 165 / (priv->calib0 - priv->calib1) - 40
+	 */
+	*temp = DIV_ROUND_CLOSEST((ts_code_ave - priv->calib1) * 165,
+				  (priv->calib0 - priv->calib1)) - 40;
+
+	/* Report it in mili degrees Celsius and round it up to 0.5 degrees Celsius. */
+	*temp = roundup(MCELSIUS(*temp), 500);
+
+rpm_put:
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return ret;
+}
+
+static void rzg3s_thermal_set_mode(struct rzg3s_thermal_priv *priv,
+				   enum thermal_device_mode mode)
+{
+	struct device *dev = priv->dev;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return;
+
+	if (mode == THERMAL_DEVICE_DISABLED) {
+		writel(0, priv->base + TSU_SM);
+	} else {
+		writel(TSU_SM_EN, priv->base + TSU_SM);
+		/*
+		 * According to the HW manual (section 40.4.1 Procedure for
+		 * Starting the TSU) we need to wait here 30us or more.
+		 */
+		usleep_range(30, 40);
+
+		writel(TSU_SM_OE | TSU_SM_EN, priv->base + TSU_SM);
+		/*
+		 * According to the HW manual (section 40.4.1 Procedure for
+		 * Starting the TSU) we need to wait here 50us or more.
+		 */
+		usleep_range(50, 60);
+	}
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+}
+
+static int rzg3s_thermal_change_mode(struct thermal_zone_device *tz,
+				     enum thermal_device_mode mode)
+{
+	struct rzg3s_thermal_priv *priv = thermal_zone_device_priv(tz);
+
+	if (priv->mode == mode)
+		return 0;
+
+	rzg3s_thermal_set_mode(priv, mode);
+	priv->mode = mode;
+
+	return 0;
+}
+
+static const struct thermal_zone_device_ops rzg3s_tz_of_ops = {
+	.get_temp = rzg3s_thermal_get_temp,
+	.change_mode = rzg3s_thermal_change_mode,
+};
+
+static int rzg3s_thermal_read_calib(struct rzg3s_thermal_priv *priv)
+{
+	struct device *dev = priv->dev;
+	u32 val;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret)
+		return ret;
+
+	val = readl(priv->base + OTPTSUTRIM_REG(0));
+	if (val & OTPTSUTRIM_EN_MASK)
+		priv->calib0 = FIELD_GET(OTPTSUTRIM_MASK, val);
+	else
+		priv->calib0 = SW_CALIB0_VAL;
+
+	val = readl(priv->base + OTPTSUTRIM_REG(1));
+	if (val & OTPTSUTRIM_EN_MASK)
+		priv->calib1 = FIELD_GET(OTPTSUTRIM_MASK, val);
+	else
+		priv->calib1 = SW_CALIB1_VAL;
+
+	pm_runtime_mark_last_busy(dev);
+	pm_runtime_put_autosuspend(dev);
+
+	return 0;
+}
+
+static int rzg3s_thermal_probe(struct platform_device *pdev)
+{
+	struct rzg3s_thermal_priv *priv;
+	struct device *dev = &pdev->dev;
+	int ret;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(priv->base))
+		return PTR_ERR(priv->base);
+
+	priv->channel = devm_iio_channel_get(dev, "tsu");
+	if (IS_ERR(priv->channel))
+		return dev_err_probe(dev, PTR_ERR(priv->channel), "Failed to get IIO channel!\n");
+
+	priv->rstc = devm_reset_control_get_exclusive_deasserted(dev, NULL);
+	if (IS_ERR(priv->rstc))
+		return dev_err_probe(dev, PTR_ERR(priv->rstc), "Failed to get reset!\n");
+
+	priv->dev = dev;
+	priv->mode = THERMAL_DEVICE_DISABLED;
+	platform_set_drvdata(pdev, priv);
+
+	pm_runtime_set_autosuspend_delay(dev, 300);
+	pm_runtime_use_autosuspend(dev);
+	pm_runtime_enable(dev);
+
+	ret = rzg3s_thermal_read_calib(priv);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to read calibration data!\n");
+		goto rpm_disable;
+	}
+
+	priv->tz = thermal_of_zone_register(dev->of_node, 0, priv, &rzg3s_tz_of_ops);
+	if (IS_ERR(priv->tz)) {
+		dev_err_probe(dev, PTR_ERR(priv->tz), "Failed to register thermal zone!\n");
+		goto rpm_disable;
+	}
+
+	ret = thermal_add_hwmon_sysfs(priv->tz);
+	if (ret) {
+		dev_err_probe(dev, ret, "Failed to add hwmon sysfs!\n");
+		goto tz_unregister;
+	}
+
+	return 0;
+
+tz_unregister:
+	thermal_of_zone_unregister(priv->tz);
+rpm_disable:
+	pm_runtime_disable(dev);
+	pm_runtime_dont_use_autosuspend(dev);
+	return ret;
+}
+
+static void rzg3s_thermal_remove(struct platform_device *pdev)
+{
+	struct rzg3s_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
+
+	thermal_remove_hwmon_sysfs(priv->tz);
+	thermal_of_zone_unregister(priv->tz);
+	pm_runtime_disable(priv->dev);
+	pm_runtime_dont_use_autosuspend(priv->dev);
+}
+
+static int rzg3s_thermal_suspend(struct device *dev)
+{
+	struct rzg3s_thermal_priv *priv = dev_get_drvdata(dev);
+
+	rzg3s_thermal_set_mode(priv, THERMAL_DEVICE_DISABLED);
+
+	return reset_control_assert(priv->rstc);
+}
+
+static int rzg3s_thermal_resume(struct device *dev)
+{
+	struct rzg3s_thermal_priv *priv = dev_get_drvdata(dev);
+	int ret;
+
+	ret = reset_control_deassert(priv->rstc);
+	if (ret)
+		return ret;
+
+	if (priv->mode != THERMAL_DEVICE_DISABLED)
+		rzg3s_thermal_set_mode(priv, priv->mode);
+
+	return 0;
+}
+
+static const struct dev_pm_ops rzg3s_thermal_pm_ops = {
+	SYSTEM_SLEEP_PM_OPS(rzg3s_thermal_suspend, rzg3s_thermal_resume)
+};
+
+static const struct of_device_id rzg3s_thermal_dt_ids[] = {
+	{ .compatible = "renesas,r9a08g045-tsu" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rzg3s_thermal_dt_ids);
+
+static struct platform_driver rzg3s_thermal_driver = {
+	.driver = {
+		.name = "rzg3s_thermal",
+		.of_match_table = rzg3s_thermal_dt_ids,
+		.pm = pm_ptr(&rzg3s_thermal_pm_ops),
+	},
+	.probe = rzg3s_thermal_probe,
+	.remove = rzg3s_thermal_remove,
+};
+module_platform_driver(rzg3s_thermal_driver);
+
+MODULE_DESCRIPTION("Renesas RZ/G3S Thermal Sensor Unit Driver");
+MODULE_AUTHOR("Claudiu Beznea <claudiu.beznea.uj@bp.renesas.com>");
+MODULE_LICENSE("GPL");