[PATCH 5/6] drivers/thermal/exynos: add initial Exynos 850 support

Sam Protsenko semen.protsenko at linaro.org
Mon Jul 22 17:02:16 PDT 2024


On Fri, Jul 19, 2024 at 7:10 AM Mateusz Majewski
<m.majewski2 at samsung.com> wrote:
>
> This is loosely adapted from an implementation available at
> https://gitlab.com/Linaro/96boards/e850-96/kernel/-/blob/android-exynos-4.14-linaro/drivers/thermal/samsung/exynos_tmu.c

Not sure if it's going to be helpful to you, but we also uploaded the
downstream k5.10 a while back, and it features a bit different TMU
driver implementation [1].

[1] https://gitlab.com/Linaro/96boards/e850-96/kernel/-/tree/android-exynos-5.10-linaro/drivers/thermal/samsung?ref_type=heads

> Some differences from that implementation:
> - unlike that implementation, we do not use the ACPM mechanism, instead
>   we just access the registers, like we do for other SoCs,

Do you know what are the possible implications of not using ACPM? As I
understand, ACPM is a Samsung's downstream framework which uses APM
(Active Power Management) IP block internally to act as an IPC
mechanism, which makes it possible to offload any PM related
operations (which might get quite heavy, if we are to belive the TRM
description of APM) from CPU to APM. I'm not against the direct
registers access based implementation (in fact, I'm not sure how that
APM/ACPM thing can be implemented in upstreamable way and if it's
worth it at all). Just curious if we understand what we are
potentially missing out, and if at some point we'll be forced to
implement that ACPM thing anyway (for something else)?

> - the SoC is supposed to support multiple sensors inside one unit. The
>   vendor implementation uses one kernel device per sensor, we would
>   probably prefer to have one device for all sensors, have
>   #thermal-sensor-cells = <1> and so on. We implemented this, but we
>   could not get the extra sensors to work on our hardware so far. This
>   might be due to a misconfiguration and we will probably come back to
>   this, however our implementation only supports a single sensor for
>   now,
> - the vendor implementation supports disabling CPU cores as a cooling
>   device. We did not attempt to port this, and this would not really fit
>   this driver anyway.
>
> Additionally, some differences from the other SoCs supported by this
> driver:
> - this SoC does not require a clock to work correctly, so we need an
>   exception for data->clk,

Not sure if that's true, as already discussed in my comments for the
previous patches. Looks like one clock is still needed, which is the
PCLK bus clock (to interface registers) which might simultaneously act
as an operating (functional) clock.

> - we do not really constrain the e-fuse information like the other SoCs
>   do (data->{min,max}_efuse_value). In our tests, those values (as well
>   as the raw sensor values) were much higher than in the other SoCs, to
>   the degree that reusing the data->{min,max}_efuse_value from the other
>   SoCs would cause instant critical temperature reset on boot,
> - this SoC provides more information in the e-fuse data than other SoCs,
>   so we read some values inside exynos850_tmu_initialize instead of
>   hardcoding them in exynos_map_dt_data.
>
> Signed-off-by: Mateusz Majewski <m.majewski2 at samsung.com>
> ---
>  drivers/thermal/samsung/exynos_tmu.c | 214 +++++++++++++++++++++++++--
>  1 file changed, 202 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
> index f0de72a62fd7..bd52663f1a5a 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -116,6 +116,43 @@
>  #define EXYNOS7_EMUL_DATA_SHIFT                        7
>  #define EXYNOS7_EMUL_DATA_MASK                 0x1ff
>
> +/* Exynos850 specific registers */
> +#define EXYNOS850_TMU_REG_AVG_CON              0x58

Exynos850 TRM says AVG_CONTROL offset is 0x38, and 0x58 is actually
for THRESHOLD0_TEMP_RISE3_2 register.

> +#define EXYNOS850_TMU_REG_CONTROL1             0x24
> +#define EXYNOS850_TMU_REG_COUNTER_VALUE0       0x30
> +#define EXYNOS850_TMU_REG_COUNTER_VALUE1       0x34
> +#define EXYNOS850_TMU_REG_CURRENT_TEMP1_0      0x40

In TRM, this register is called CURRENT_TEMP0_1. Maybe change 1_0 -> 0_1?

> +#define EXYNOS850_TMU_REG_THD_TEMP0_RISE       0x50
> +#define EXYNOS850_TMU_REG_THD_TEMP0_FALL       0x60
> +#define EXYNOS850_TMU_REG_TRIM0                        0x3C
> +
> +#define EXYNOS850_TMU_AVG_CON_SHIFT            18

Maybe rename it to something like EXYNOS850_TMU_T_AVG_MODE_SHIFT, to
avoid confusion with AVG_CONTROL register? That belongs to TRIMINFO2
register, if I understand it correctly, not to AVG_CONTROL.

> +#define EXYNOS850_TMU_AVG_MODE_MASK            0x7

I'd suggest to group all the definitions here as such:

#define REG1_OFFSET
#define REG1_FIELD1_OFFSET
#define REG1_FIELD2_OFFSET
...empty line...
#define REG2_OFFSET
#define REG2_FIELD1_OFFSET
#define REG2_FIELD2_OFFSET
...etc...

Or otherwise each shift/mask constant should contain its register name
as a prefix, to avoid confusion. But right now it's kinda hard to
understand what belongs to what :) But that's just a nitpick.

> +#define EXYNOS850_TMU_BGRI_TRIM_MASK           0xF

Suggest using GENMASK() macro whenever possible.

> +#define EXYNOS850_TMU_BGRI_TRIM_SHIFT          20
> +#define EXYNOS850_TMU_CLK_SENSE_ON_MASK                0xffff
> +#define EXYNOS850_TMU_CLK_SENSE_ON_SHIFT       16
> +#define EXYNOS850_TMU_DEM_ENABLE               1
> +#define EXYNOS850_TMU_DEM_SHIFT                        4

Instead of above two values, it could be just BIT(4) for
EXYNOS850_TMU_DEM_ENABLE?

> +#define EXYNOS850_TMU_EN_TEMP_SEN_OFF_MASK     0xffff
> +#define EXYNOS850_TMU_EN_TEMP_SEN_OFF_SHIFT    0
> +#define EXYNOS850_TMU_LPI_MODE_MASK            1
> +#define EXYNOS850_TMU_LPI_MODE_SHIFT           10
> +#define EXYNOS850_TMU_T_BUF_SLOPE_SEL_MASK     0xF
> +#define EXYNOS850_TMU_T_BUF_SLOPE_SEL_SHIFT    18
> +#define EXYNOS850_TMU_T_BUF_VREF_SEL_MASK      0x1F
> +#define EXYNOS850_TMU_T_BUF_VREF_SEL_SHIFT     18
> +#define EXYNOS850_TMU_TEM1051X_SENSE_VALUE     0x028A
> +#define EXYNOS850_TMU_TEM1456X_SENSE_VALUE     0x0A28

I'd pull those two values under shift/mask definitions. Also, please
use lowercase characters for hex values, here and in all other places.

> +#define EXYNOS850_TMU_TEMP_SHIFT               9
> +#define EXYNOS850_TMU_TRIMINFO_SHIFT           4
> +#define EXYNOS850_TMU_T_TRIM0_MASK             0xF
> +#define EXYNOS850_TMU_T_TRIM0_SHIFT            18
> +#define EXYNOS850_TMU_VBEI_TRIM_MASK           0xF
> +#define EXYNOS850_TMU_VBEI_TRIM_SHIFT          8
> +#define EXYNOS850_TMU_VREF_TRIM_MASK           0xF
> +#define EXYNOS850_TMU_VREF_TRIM_SHIFT          12
> +
>  #define EXYNOS_FIRST_POINT_TRIM                        25
>  #define EXYNOS_SECOND_POINT_TRIM               85
>
> @@ -133,6 +170,7 @@ enum soc_type {
>         SOC_ARCH_EXYNOS5420_TRIMINFO,
>         SOC_ARCH_EXYNOS5433,
>         SOC_ARCH_EXYNOS7,
> +       SOC_ARCH_EXYNOS850,
>  };
>
>  /**
> @@ -231,13 +269,16 @@ static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code)
>
>  static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
>  {
> -       u16 tmu_temp_mask =
> -               (data->soc == SOC_ARCH_EXYNOS7) ? EXYNOS7_TMU_TEMP_MASK
> -                                               : EXYNOS_TMU_TEMP_MASK;
> +       u16 tmu_temp_mask = (data->soc == SOC_ARCH_EXYNOS7 ||
> +                            data->soc == SOC_ARCH_EXYNOS850) ?
> +                                   EXYNOS7_TMU_TEMP_MASK :
> +                                   EXYNOS_TMU_TEMP_MASK;
> +       int tmu_85_shift = (data->soc == SOC_ARCH_EXYNOS850) ?
> +                                  EXYNOS850_TMU_TEMP_SHIFT :
> +                                  EXYNOS_TRIMINFO_85_SHIFT;

Something seems off to me here. How come the shift value for EXYNOS7
case is 8, but the mask is actually 9 bits long? Does it mean the
first error field is 8 bits long, and the second error field is 9 bits
long for EXYNOS7? I don't have the Exynos7 manual, so it's just a
hunch. But if it's true, maybe this shift value has to be added in
your [PATCH 2/6] to fix Exynos7 case?

Also, just an idea: those values (and other similar values) could be
pre-calculated somewhere during the probe, stored in some struct (e.g.
_variant or _chip) and then just used here. Stylistically, instead of
the ternary operator, maybe switch one would easier to read? Again,
those are very minor nitpicks.

>
>         data->temp_error1 = trim_info & tmu_temp_mask;
> -       data->temp_error2 = ((trim_info >> EXYNOS_TRIMINFO_85_SHIFT) &
> -                               tmu_temp_mask);
> +       data->temp_error2 = ((trim_info >> tmu_85_shift) & tmu_temp_mask);
>

No need for the left-most and right-most brackets.

>         if (!data->temp_error1 ||
>             (data->min_efuse_value > data->temp_error1) ||
> @@ -245,9 +286,8 @@ static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
>                 data->temp_error1 = data->efuse_value & tmu_temp_mask;
>
>         if (!data->temp_error2)
> -               data->temp_error2 =
> -                       (data->efuse_value >> EXYNOS_TRIMINFO_85_SHIFT) &
> -                       tmu_temp_mask;
> +               data->temp_error2 = (data->efuse_value >> tmu_85_shift) &
> +                                   tmu_temp_mask;
>  }
>
>  static int exynos_tmu_initialize(struct platform_device *pdev)
> @@ -588,6 +628,129 @@ static void exynos7_tmu_initialize(struct platform_device *pdev)
>         sanitize_temp_error(data, trim_info);
>  }
>
> +static void exynos850_tmu_set_low_temp(struct exynos_tmu_data *data, u8 temp)
> +{
> +       exynos_tmu_update_temp(data, EXYNOS850_TMU_REG_THD_TEMP0_FALL + 12, 0,
> +                              temp);
> +       exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
> +                             EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, true);
> +}
> +
> +static void exynos850_tmu_set_high_temp(struct exynos_tmu_data *data, u8 temp)
> +{
> +       exynos_tmu_update_temp(data, EXYNOS850_TMU_REG_THD_TEMP0_RISE + 12, 16,
> +                              temp);
> +       exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
> +                             EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, true);
> +}
> +
> +static void exynos850_tmu_disable_low(struct exynos_tmu_data *data)
> +{
> +       exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
> +                             EXYNOS_TMU_INTEN_FALL0_SHIFT + 0, false);
> +}
> +
> +static void exynos850_tmu_disable_high(struct exynos_tmu_data *data)
> +{
> +       exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
> +                             EXYNOS7_TMU_INTEN_RISE0_SHIFT + 1, false);
> +}
> +
> +static void exynos850_tmu_set_crit_temp(struct exynos_tmu_data *data, u8 temp)
> +{
> +       exynos_tmu_update_temp(data, EXYNOS850_TMU_REG_THD_TEMP0_RISE + 0, 16,
> +                              temp);
> +       exynos_tmu_update_bit(data, EXYNOS_TMU_REG_CONTROL,
> +                             EXYNOS_TMU_THERM_TRIP_EN_SHIFT, true);
> +       exynos_tmu_update_bit(data, EXYNOS7_TMU_REG_INTEN,
> +                             EXYNOS7_TMU_INTEN_RISE0_SHIFT + 7, true);
> +}
> +
> +static void exynos850_tmu_initialize(struct platform_device *pdev)
> +{
> +       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> +       int cal_type;

Please make it u32.

> +       unsigned int avg_mode, buf, bgri, vref, vbei;

Suggest renaming buf -> reg, and maybe make it u32.

> +
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
> +       cal_type = (buf & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK) >>
> +                  EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT;
> +       data->reference_voltage = (buf >> EXYNOS850_TMU_T_BUF_VREF_SEL_SHIFT) &
> +                                 EXYNOS850_TMU_T_BUF_VREF_SEL_MASK;
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO +
> +                   EXYNOS850_TMU_TRIMINFO_SHIFT);
> +       data->gain = (buf >> EXYNOS850_TMU_T_BUF_SLOPE_SEL_SHIFT) &
> +                    EXYNOS850_TMU_T_BUF_SLOPE_SEL_MASK;
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO +
> +                   2 * EXYNOS850_TMU_TRIMINFO_SHIFT);
> +       avg_mode = (buf >> EXYNOS850_TMU_AVG_CON_SHIFT) &
> +                  EXYNOS850_TMU_AVG_MODE_MASK;
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO +
> +                   3 * EXYNOS850_TMU_TRIMINFO_SHIFT);
> +       bgri = (buf >> EXYNOS850_TMU_T_TRIM0_SHIFT) &
> +              EXYNOS850_TMU_T_TRIM0_MASK;
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO +
> +                   4 * EXYNOS850_TMU_TRIMINFO_SHIFT);
> +       vref = (buf >> EXYNOS850_TMU_T_TRIM0_SHIFT) &
> +              EXYNOS850_TMU_T_TRIM0_MASK;
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO +
> +                   5 * EXYNOS850_TMU_TRIMINFO_SHIFT);

For cases like that, maybe introduce some macro like:

    #define EXYNOS850_TRIMINFO_OFFSET(n)    (EXYNOS_TMU_REG_TRIMINFO +
(n) * EXYNOS850_TMU_TRIMINFO_SHIFT)

and use it everywhere?

> +       vbei = (buf >> EXYNOS850_TMU_T_TRIM0_SHIFT) &
> +              EXYNOS850_TMU_T_TRIM0_MASK;
> +
> +       buf = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
> +       sanitize_temp_error(data, buf);
> +
> +       switch (cal_type) {
> +       case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING:
> +               data->cal_type = TYPE_TWO_POINT_TRIMMING;
> +               break;
> +       case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING:

Add "fallthrough;" here? Or maybe just remove above line at all?

> +       default:
> +               data->cal_type = TYPE_ONE_POINT_TRIMMING;
> +               break;
> +       }
> +
> +       dev_info(&pdev->dev, "Calibration type is %d-point calibration\n",
> +                cal_type ? 2 : 1);
> +
> +       buf = readl(data->base + EXYNOS850_TMU_REG_AVG_CON);
> +       buf &= ~(EXYNOS850_TMU_AVG_MODE_MASK);

No need for brackets.

> +       buf &= ~(EXYNOS850_TMU_DEM_ENABLE << EXYNOS850_TMU_DEM_SHIFT);
> +       if (avg_mode) {
> +               buf |= avg_mode;
> +               buf |= (EXYNOS850_TMU_DEM_ENABLE << EXYNOS850_TMU_DEM_SHIFT);
> +       }
> +       writel(buf, data->base + EXYNOS850_TMU_REG_AVG_CON);
> +
> +       buf = readl(data->base + EXYNOS850_TMU_REG_COUNTER_VALUE0);
> +       buf &= ~(EXYNOS850_TMU_EN_TEMP_SEN_OFF_MASK
> +                << EXYNOS850_TMU_EN_TEMP_SEN_OFF_SHIFT);
> +       buf |= EXYNOS850_TMU_TEM1051X_SENSE_VALUE
> +              << EXYNOS850_TMU_EN_TEMP_SEN_OFF_SHIFT;
> +       writel(buf, data->base + EXYNOS850_TMU_REG_COUNTER_VALUE0);
> +
> +       buf = readl(data->base + EXYNOS850_TMU_REG_COUNTER_VALUE1);
> +       buf &= ~(EXYNOS850_TMU_CLK_SENSE_ON_MASK
> +                << EXYNOS850_TMU_CLK_SENSE_ON_SHIFT);
> +       buf |= EXYNOS850_TMU_TEM1051X_SENSE_VALUE
> +              << EXYNOS850_TMU_CLK_SENSE_ON_SHIFT;
> +       writel(buf, data->base + EXYNOS850_TMU_REG_COUNTER_VALUE1);
> +
> +       buf = readl(data->base + EXYNOS850_TMU_REG_TRIM0);
> +       buf &= ~(EXYNOS850_TMU_BGRI_TRIM_MASK << EXYNOS850_TMU_BGRI_TRIM_SHIFT);
> +       buf &= ~(EXYNOS850_TMU_VREF_TRIM_MASK << EXYNOS850_TMU_VREF_TRIM_SHIFT);
> +       buf &= ~(EXYNOS850_TMU_VBEI_TRIM_MASK << EXYNOS850_TMU_VBEI_TRIM_SHIFT);

Why not define this mask value like this instead:

    #define EXYNOS850_TMU_VBEI_TRIM_MASK        GENMASK(11,8)

And then you'll be able to do just:

    buf &= ~EXYNOS850_TMU_VBEI_TRIM_MASK;

The same goes for all similar cases.

> +       buf |= (bgri << EXYNOS850_TMU_BGRI_TRIM_SHIFT);
> +       buf |= (vref << EXYNOS850_TMU_VREF_TRIM_SHIFT);
> +       buf |= (vbei << EXYNOS850_TMU_VBEI_TRIM_SHIFT);

Brackets are not needed.

> +       writel(buf, data->base + EXYNOS850_TMU_REG_TRIM0);
> +
> +       buf = readl(data->base + EXYNOS850_TMU_REG_CONTROL1);
> +       buf &= ~(EXYNOS850_TMU_LPI_MODE_MASK << EXYNOS850_TMU_LPI_MODE_SHIFT);
> +       writel(buf, data->base + EXYNOS850_TMU_REG_CONTROL1);
> +}
> +
>  static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
>  {
>         struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> @@ -679,7 +842,8 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
>
>                 val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT);
>                 val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT);
> -               if (data->soc == SOC_ARCH_EXYNOS7) {
> +               if (data->soc == SOC_ARCH_EXYNOS7 ||
> +                   data->soc == SOC_ARCH_EXYNOS850) {
>                         val &= ~(EXYNOS7_EMUL_DATA_MASK <<
>                                 EXYNOS7_EMUL_DATA_SHIFT);
>                         val |= (temp_to_code(data, temp) <<
> @@ -709,7 +873,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
>                 emul_con = EXYNOS5260_EMUL_CON;
>         else if (data->soc == SOC_ARCH_EXYNOS5433)
>                 emul_con = EXYNOS5433_TMU_EMUL_CON;
> -       else if (data->soc == SOC_ARCH_EXYNOS7)
> +       else if (data->soc == SOC_ARCH_EXYNOS7 ||
> +                data->soc == SOC_ARCH_EXYNOS850)
>                 emul_con = EXYNOS7_TMU_REG_EMUL_CON;
>         else
>                 emul_con = EXYNOS_EMUL_CON;
> @@ -766,6 +931,12 @@ static int exynos7_tmu_read(struct exynos_tmu_data *data)
>                 EXYNOS7_TMU_TEMP_MASK;
>  }
>
> +static int exynos850_tmu_read(struct exynos_tmu_data *data)
> +{
> +       return readw(data->base + EXYNOS850_TMU_REG_CURRENT_TEMP1_0) &
> +              EXYNOS7_TMU_TEMP_MASK;
> +}
> +
>  static irqreturn_t exynos_tmu_threaded_irq(int irq, void *id)
>  {
>         struct exynos_tmu_data *data = id;
> @@ -794,7 +965,8 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
>         if (data->soc == SOC_ARCH_EXYNOS5260) {
>                 tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT;
>                 tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR;
> -       } else if (data->soc == SOC_ARCH_EXYNOS7) {
> +       } else if (data->soc == SOC_ARCH_EXYNOS7 ||
> +                  data->soc == SOC_ARCH_EXYNOS850) {
>                 tmu_intstat = EXYNOS7_TMU_REG_INTPEND;
>                 tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
>         } else if (data->soc == SOC_ARCH_EXYNOS5433) {
> @@ -845,6 +1017,9 @@ static const struct of_device_id exynos_tmu_match[] = {
>         }, {
>                 .compatible = "samsung,exynos7-tmu",
>                 .data = (const void *)SOC_ARCH_EXYNOS7,
> +       }, {
> +               .compatible = "samsung,exynos850-tmu",
> +               .data = (const void *)SOC_ARCH_EXYNOS850,
>         },
>         { },
>  };
> @@ -957,6 +1132,21 @@ static int exynos_map_dt_data(struct platform_device *pdev)
>                 data->min_efuse_value = 15;
>                 data->max_efuse_value = 100;
>                 break;
> +       case SOC_ARCH_EXYNOS850:
> +               data->tmu_set_low_temp = exynos850_tmu_set_low_temp;
> +               data->tmu_set_high_temp = exynos850_tmu_set_high_temp;
> +               data->tmu_disable_low = exynos850_tmu_disable_low;
> +               data->tmu_disable_high = exynos850_tmu_disable_high;
> +               data->tmu_set_crit_temp = exynos850_tmu_set_crit_temp;
> +               data->tmu_initialize = exynos850_tmu_initialize;
> +               data->tmu_control = exynos4210_tmu_control;
> +               data->tmu_read = exynos850_tmu_read;
> +               data->tmu_set_emulation = exynos4412_tmu_set_emulation;
> +               data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
> +               data->efuse_value = 55;
> +               data->min_efuse_value = 0;
> +               data->max_efuse_value = 511;
> +               break;
>         default:
>                 dev_err(&pdev->dev, "Platform not supported\n");
>                 return -EINVAL;
> @@ -1051,7 +1241,7 @@ static int exynos_tmu_probe(struct platform_device *pdev)
>                 return ret;
>
>         data->clk = devm_clk_get(dev, "tmu_apbif");
> -       if (IS_ERR(data->clk))
> +       if (IS_ERR(data->clk) && data->soc != SOC_ARCH_EXYNOS850)
>                 return dev_err_probe(dev, PTR_ERR(data->clk), "Failed to get clock\n");
>
>         data->clk_sec = devm_clk_get(dev, "tmu_triminfo_apbif");
> --
> 2.45.1
>
>



More information about the linux-arm-kernel mailing list