On Tue, Jan 27, 2015 at 11:18:22AM +0530, Abhilash Kesavan wrote:
> Add registers, bit fields and compatible strings for Exynos7 TMU
> (Thermal Management Unit). Following are a few of the differences
> in the Exynos7 TMU from earlier SoCs:
>         - 8 trigger levels
>         - Different bit offsets and more registers for the rising
>         and falling thresholds.
>         - New power down detection bit in the TMU_CONTROL register
>         which does not update the CURRENT_TEMP0 when tmu power down
>         is detected.
>         - Change in bit offset for the NEXT_DATA field of EMUL_CON
>         register. EMUL_CON register address has also changed.
>         - INTSTAT and INTCLEAR registers present in earlier SoCs
>         have been combined into one INTPEND register. The register
>         address for INTCLEAR and INTPEND is also different.
>         - Since there are 8 rising/falling interrupts as against
>         at most 4 in earlier SoCs the INTEN bit offsets are different.
>         - Multiple probe support which is handled by a TMU_CONTROL1
>         register (No support for this in the current patch).
> 
> This patch adds special clock support required only for Exynos7. It
> also updates the "code_to_temp" prototype as Exynos7 has 9 bit
> code-temp mapping.
> 
> Signed-off-by: Abhilash Kesavan <a.kesa...@samsung.com>

Applied to my -fixes branch. However, I had to amend it myself to make
checkpatch.pl --strict silent. In this version, it still outputs:
CHECK: Alignment should match open parenthesis
#209: FILE: drivers/thermal/samsung/exynos_tmu.c:558:
+       if (!data->temp_error1 ||
+          (pdata->min_efuse_value > data->temp_error1) ||

CHECK: multiple assignments should be avoided
#366: FILE: drivers/thermal/samsung/exynos_tmu.c:882:
+               tmu_intstat = tmu_intclear = EXYNOS7_TMU_REG_INTPEND;

total: 0 errors, 0 warnings, 2 checks, 314 lines checked

next, make sure you run checkpatch.pl --strict before sending patches.


> ---
> This patch set has been tested on linux next-20150123 with Eduardo's
> thermal-next branch merged along with the arch-side exynos7 related
> dts changes applied.
> 
> Changes since v3:
> Addressed comments from Lukasz Majewski:
>       - Added more comments in the code setting the thresholds.
>       - Split the documentation out into another patch.
> Changes since v2:
>       - Rebased on top of Lukasz' latest exynos tmu series (v4).
>       - Added new exynos7 soc_type.
> Changes since v1:
>       - Rebased on top of Lukasz' latest exynos tmu series (v2).
>       - Added sclk support to patch adding Exynos7 tmu support.
>       Previously, it was a separate patch.
>       - Used the SOC type to decide if sclk is present.
> 
>  drivers/thermal/samsung/exynos_tmu.c |  204 
> ++++++++++++++++++++++++++++++++--
>  drivers/thermal/samsung/exynos_tmu.h |    1 +
>  2 files changed, 197 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/thermal/samsung/exynos_tmu.c 
> b/drivers/thermal/samsung/exynos_tmu.c
> index 852e622..660ff69 100644
> --- a/drivers/thermal/samsung/exynos_tmu.c
> +++ b/drivers/thermal/samsung/exynos_tmu.c
> @@ -119,6 +119,26 @@
>  #define EXYNOS5440_TMU_TH_RISE4_SHIFT                24
>  #define EXYNOS5440_EFUSE_SWAP_OFFSET         8
>  
> +/* Exynos7 specific registers */
> +#define EXYNOS7_THD_TEMP_RISE7_6             0x50
> +#define EXYNOS7_THD_TEMP_FALL7_6             0x60
> +#define EXYNOS7_TMU_REG_INTEN                        0x110
> +#define EXYNOS7_TMU_REG_INTPEND                      0x118
> +#define EXYNOS7_TMU_REG_EMUL_CON             0x160
> +
> +#define EXYNOS7_TMU_TEMP_MASK                        0x1ff
> +#define EXYNOS7_PD_DET_EN_SHIFT                      23
> +#define EXYNOS7_TMU_INTEN_RISE0_SHIFT                0
> +#define EXYNOS7_TMU_INTEN_RISE1_SHIFT                1
> +#define EXYNOS7_TMU_INTEN_RISE2_SHIFT                2
> +#define EXYNOS7_TMU_INTEN_RISE3_SHIFT                3
> +#define EXYNOS7_TMU_INTEN_RISE4_SHIFT                4
> +#define EXYNOS7_TMU_INTEN_RISE5_SHIFT                5
> +#define EXYNOS7_TMU_INTEN_RISE6_SHIFT                6
> +#define EXYNOS7_TMU_INTEN_RISE7_SHIFT                7
> +#define EXYNOS7_EMUL_DATA_SHIFT                      7
> +#define EXYNOS7_EMUL_DATA_MASK                       0x1ff
> +
>  #define MCELSIUS     1000
>  /**
>   * struct exynos_tmu_data : A structure to hold the private data of the TMU
> @@ -133,6 +153,7 @@
>   * @lock: lock to implement synchronization.
>   * @clk: pointer to the clock structure.
>   * @clk_sec: pointer to the clock structure for accessing the base_second.
> + * @sclk: pointer to the clock structure for accessing the tmu special clk.
>   * @temp_error1: fused value of the first point trim.
>   * @temp_error2: fused value of the second point trim.
>   * @regulator: pointer to the TMU regulator structure.
> @@ -152,8 +173,8 @@ struct exynos_tmu_data {
>       enum soc_type soc;
>       struct work_struct irq_work;
>       struct mutex lock;
> -     struct clk *clk, *clk_sec;
> -     u8 temp_error1, temp_error2;
> +     struct clk *clk, *clk_sec, *sclk;
> +     u16 temp_error1, temp_error2;
>       struct regulator *regulator;
>       struct thermal_zone_device *tzd;
>  
> @@ -223,7 +244,7 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 
> temp)
>   * Calculate a temperature value from a temperature code.
>   * The unit of the temperature is degree Celsius.
>   */
> -static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
> +static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code)
>  {
>       struct exynos_tmu_platform_data *pdata = data->pdata;
>       int temp;
> @@ -513,6 +534,84 @@ static int exynos5440_tmu_initialize(struct 
> platform_device *pdev)
>       return ret;
>  }
>  
> +static int exynos7_tmu_initialize(struct platform_device *pdev)
> +{
> +     struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> +     struct thermal_zone_device *tz = data->tzd;
> +     struct exynos_tmu_platform_data *pdata = data->pdata;
> +     unsigned int status, trim_info;
> +     unsigned int rising_threshold = 0, falling_threshold = 0;
> +     int ret = 0, threshold_code, i;
> +     unsigned long temp, temp_hist;
> +     unsigned int reg_off, bit_off;
> +
> +     status = readb(data->base + EXYNOS_TMU_REG_STATUS);
> +     if (!status) {
> +             ret = -EBUSY;
> +             goto out;
> +     }
> +
> +     trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
> +
> +     data->temp_error1 = trim_info & EXYNOS7_TMU_TEMP_MASK;
> +     if (!data->temp_error1 ||
> +        (pdata->min_efuse_value > data->temp_error1) ||
> +        (data->temp_error1 > pdata->max_efuse_value))
> +             data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
> +
> +     /* Write temperature code for rising and falling threshold */
> +     for (i = (of_thermal_get_ntrips(tz) - 1); i >= 0; i--) {
> +             /*
> +              * On exynos7 there are 4 rising and 4 falling threshold
> +              * registers (0x50-0x5c and 0x60-0x6c respectively). Each
> +              * register holds the value of two threshold levels (at bit
> +              * offsets 0 and 16). Based on the fact that there are atmost
> +              * eight possible trigger levels, calculate the register and
> +              * bit offsets where the threshold levels are to be written.
> +              *
> +              * e.g. EXYNOS7_THD_TEMP_RISE7_6 (0x50)
> +              * [24:16] - Threshold level 7
> +              * [8:0] - Threshold level 6
> +              * e.g. EXYNOS7_THD_TEMP_RISE5_4 (0x54)
> +              * [24:16] - Threshold level 5
> +              * [8:0] - Threshold level 4
> +              *
> +              * and similarly for falling thresholds.
> +              *
> +              * Based on the above, calculate the register and bit offsets
> +              * for rising/falling threshold levels and populate them.
> +              */
> +             reg_off = ((7 - i) / 2) * 4;
> +             bit_off = ((8 - i) % 2);
> +
> +             tz->ops->get_trip_temp(tz, i, &temp);
> +             temp /= MCELSIUS;
> +
> +             tz->ops->get_trip_hyst(tz, i, &temp_hist);
> +             temp_hist = temp - (temp_hist / MCELSIUS);
> +
> +             /* Set 9-bit temperature code for rising threshold levels */
> +             threshold_code = temp_to_code(data, temp);
> +             rising_threshold = readl(data->base +
> +                     EXYNOS7_THD_TEMP_RISE7_6 + reg_off);
> +             rising_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off));
> +             rising_threshold |= threshold_code << (16 * bit_off);
> +             writel(rising_threshold,
> +                    data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off);
> +
> +             /* Set 9-bit temperature code for falling threshold levels */
> +             threshold_code = temp_to_code(data, temp_hist);
> +             falling_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off));
> +             falling_threshold |= threshold_code << (16 * bit_off);
> +             writel(falling_threshold,
> +                    data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off);
> +     }
> +
> +     data->tmu_clear_irqs(data);
> +out:
> +     return ret;
> +}
> +
>  static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
>  {
>       struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> @@ -573,6 +672,46 @@ static void exynos5440_tmu_control(struct 
> platform_device *pdev, bool on)
>       writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL);
>  }
>  
> +static void exynos7_tmu_control(struct platform_device *pdev, bool on)
> +{
> +     struct exynos_tmu_data *data = platform_get_drvdata(pdev);
> +     struct thermal_zone_device *tz = data->tzd;
> +     unsigned int con, interrupt_en;
> +
> +     con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
> +
> +     if (on) {
> +             con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
> +             interrupt_en =
> +                     (of_thermal_is_trip_valid(tz, 7)
> +                     << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 6)
> +                     << EXYNOS7_TMU_INTEN_RISE6_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 5)
> +                     << EXYNOS7_TMU_INTEN_RISE5_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 4)
> +                     << EXYNOS7_TMU_INTEN_RISE4_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 3)
> +                     << EXYNOS7_TMU_INTEN_RISE3_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 2)
> +                     << EXYNOS7_TMU_INTEN_RISE2_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 1)
> +                     << EXYNOS7_TMU_INTEN_RISE1_SHIFT) |
> +                     (of_thermal_is_trip_valid(tz, 0)
> +                     << EXYNOS7_TMU_INTEN_RISE0_SHIFT);
> +
> +             interrupt_en |=
> +                     interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
> +     } else {
> +             con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
> +             interrupt_en = 0; /* Disable all interrupts */
> +     }
> +     con |= 1 << EXYNOS7_PD_DET_EN_SHIFT;
> +
> +     writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN);
> +     writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
> +}
> +
>  static int exynos_get_temp(void *p, long *temp)
>  {
>       struct exynos_tmu_data *data = p;
> @@ -602,9 +741,19 @@ 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);
>               }
> -             val &= ~(EXYNOS_EMUL_DATA_MASK << EXYNOS_EMUL_DATA_SHIFT);
> -             val |= (temp_to_code(data, temp) << EXYNOS_EMUL_DATA_SHIFT) |
> -                     EXYNOS_EMUL_ENABLE;
> +             if (data->soc == SOC_ARCH_EXYNOS7) {
> +                     val &= ~(EXYNOS7_EMUL_DATA_MASK <<
> +                             EXYNOS7_EMUL_DATA_SHIFT);
> +                     val |= (temp_to_code(data, temp) <<
> +                             EXYNOS7_EMUL_DATA_SHIFT) |
> +                             EXYNOS_EMUL_ENABLE;
> +             } else {
> +                     val &= ~(EXYNOS_EMUL_DATA_MASK <<
> +                             EXYNOS_EMUL_DATA_SHIFT);
> +                     val |= (temp_to_code(data, temp) <<
> +                             EXYNOS_EMUL_DATA_SHIFT) |
> +                             EXYNOS_EMUL_ENABLE;
> +             }
>       } else {
>               val &= ~EXYNOS_EMUL_ENABLE;
>       }
> @@ -620,6 +769,8 @@ static void exynos4412_tmu_set_emulation(struct 
> exynos_tmu_data *data,
>  
>       if (data->soc == SOC_ARCH_EXYNOS5260)
>               emul_con = EXYNOS5260_EMUL_CON;
> +     else if (data->soc == SOC_ARCH_EXYNOS7)
> +             emul_con = EXYNOS7_TMU_REG_EMUL_CON;
>       else
>               emul_con = EXYNOS_EMUL_CON;
>  
> @@ -683,6 +834,12 @@ static int exynos5440_tmu_read(struct exynos_tmu_data 
> *data)
>       return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP);
>  }
>  
> +static int exynos7_tmu_read(struct exynos_tmu_data *data)
> +{
> +     return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) &
> +             EXYNOS7_TMU_TEMP_MASK;
> +}
> +
>  static void exynos_tmu_work(struct work_struct *work)
>  {
>       struct exynos_tmu_data *data = container_of(work,
> @@ -721,6 +878,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) {
> +             tmu_intstat = tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
>       } else {
>               tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
>               tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;
> @@ -782,6 +941,9 @@ static const struct of_device_id exynos_tmu_match[] = {
>       {
>               .compatible = "samsung,exynos5440-tmu",
>       },
> +     {
> +             .compatible = "samsung,exynos7-tmu",
> +     },
>       {},
>  };
>  MODULE_DEVICE_TABLE(of, exynos_tmu_match);
> @@ -805,6 +967,8 @@ static int exynos_of_get_soc_type(struct device_node *np)
>               return SOC_ARCH_EXYNOS5420_TRIMINFO;
>       else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
>               return SOC_ARCH_EXYNOS5440;
> +     else if (of_device_is_compatible(np, "samsung,exynos7-tmu"))
> +             return SOC_ARCH_EXYNOS7;
>  
>       return -EINVAL;
>  }
> @@ -928,6 +1092,13 @@ static int exynos_map_dt_data(struct platform_device 
> *pdev)
>               data->tmu_set_emulation = exynos5440_tmu_set_emulation;
>               data->tmu_clear_irqs = exynos5440_tmu_clear_irqs;
>               break;
> +     case SOC_ARCH_EXYNOS7:
> +             data->tmu_initialize = exynos7_tmu_initialize;
> +             data->tmu_control = exynos7_tmu_control;
> +             data->tmu_read = exynos7_tmu_read;
> +             data->tmu_set_emulation = exynos4412_tmu_set_emulation;
> +             data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
> +             break;
>       default:
>               dev_err(&pdev->dev, "Platform not supported\n");
>               return -EINVAL;
> @@ -1018,21 +1189,37 @@ static int exynos_tmu_probe(struct platform_device 
> *pdev)
>               goto err_clk_sec;
>       }
>  
> +     if (data->soc == SOC_ARCH_EXYNOS7) {
> +             data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk");
> +             if (IS_ERR(data->sclk)) {
> +                     dev_err(&pdev->dev, "Failed to get sclk\n");
> +                     goto err_clk;
> +             } else {
> +                     ret = clk_prepare_enable(data->sclk);
> +                     if (ret) {
> +                             dev_err(&pdev->dev, "Failed to enable sclk\n");
> +                             goto err_clk;
> +                     }
> +             }
> +     }
> +
>       ret = exynos_tmu_initialize(pdev);
>       if (ret) {
>               dev_err(&pdev->dev, "Failed to initialize TMU\n");
> -             goto err_clk;
> +             goto err_sclk;
>       }
>  
>       ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
>               IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
>       if (ret) {
>               dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
> -             goto err_clk;
> +             goto err_sclk;
>       }
>  
>       exynos_tmu_control(pdev, true);
>       return 0;
> +err_sclk:
> +     clk_disable_unprepare(data->sclk);
>  err_clk:
>       clk_unprepare(data->clk);
>  err_clk_sec:
> @@ -1052,6 +1239,7 @@ static int exynos_tmu_remove(struct platform_device 
> *pdev)
>       thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
>       exynos_tmu_control(pdev, false);
>  
> +     clk_disable_unprepare(data->sclk);
>       clk_unprepare(data->clk);
>       if (!IS_ERR(data->clk_sec))
>               clk_unprepare(data->clk_sec);
> diff --git a/drivers/thermal/samsung/exynos_tmu.h 
> b/drivers/thermal/samsung/exynos_tmu.h
> index 9f9b1b8..4d71ec6 100644
> --- a/drivers/thermal/samsung/exynos_tmu.h
> +++ b/drivers/thermal/samsung/exynos_tmu.h
> @@ -34,6 +34,7 @@ enum soc_type {
>       SOC_ARCH_EXYNOS5420,
>       SOC_ARCH_EXYNOS5420_TRIMINFO,
>       SOC_ARCH_EXYNOS5440,
> +     SOC_ARCH_EXYNOS7,
>  };
>  
>  /**
> -- 
> 1.7.9.5
> 

Attachment: signature.asc
Description: Digital signature

Reply via email to