* [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings
@ 2015-01-27 5:48 Abhilash Kesavan
2015-01-27 5:48 ` [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC Abhilash Kesavan
` (2 more replies)
0 siblings, 3 replies; 10+ messages in thread
From: Abhilash Kesavan @ 2015-01-27 5:48 UTC (permalink / raw)
To: rui.zhang, edubezval, kgene.kim, linux-pm
Cc: linux-kernel, b.zolnierkie, l.majewski, amit.daniel,
kesavan.abhilash, linux-samsung-soc
Add documentation for exynos7 thermal bindings including compatible
name and special clock properties.
Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
---
.../devicetree/bindings/thermal/exynos-thermal.txt | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
index 0f44932..695150a 100644
--- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
@@ -12,6 +12,7 @@
"samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
Exynos5420 (Must pass triminfo base and triminfo clock)
"samsung,exynos5440-tmu"
+ "samsung,exynos7-tmu"
- interrupt-parent : The phandle for the interrupt controller
- reg : Address range of the thermal registers. For soc's which has multiple
instances of TMU and some registers are shared across all TMU's like
@@ -32,10 +33,13 @@
- clocks : The main clocks for TMU device
-- 1. operational clock for TMU channel
-- 2. optional clock to access the shared registers of TMU channel
+ -- 3. optional special clock for functional operation
- clock-names : Thermal system clock name
-- "tmu_apbif" operational clock for current TMU channel
-- "tmu_triminfo_apbif" clock to access the shared triminfo register
for current TMU channel
+ -- "tmu_sclk" clock for functional operation of the current TMU
+ channel
- vtmu-supply: This entry is optional and provides the regulator node supplying
voltage to TMU. If needed this entry can be placed inside
board/platform specific dts file.
--
1.7.9.5
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC
2015-01-27 5:48 [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
@ 2015-01-27 5:48 ` Abhilash Kesavan
2015-01-29 8:26 ` Lukasz Majewski
2015-01-31 19:24 ` Eduardo Valentin
2015-01-28 10:51 ` [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
2015-01-29 7:52 ` Lukasz Majewski
2 siblings, 2 replies; 10+ messages in thread
From: Abhilash Kesavan @ 2015-01-27 5:48 UTC (permalink / raw)
To: rui.zhang, edubezval, kgene.kim, linux-pm
Cc: linux-kernel, b.zolnierkie, l.majewski, amit.daniel,
kesavan.abhilash, linux-samsung-soc
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.kesavan@samsung.com>
---
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
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings
2015-01-27 5:48 [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
2015-01-27 5:48 ` [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC Abhilash Kesavan
@ 2015-01-28 10:51 ` Abhilash Kesavan
2015-01-28 17:23 ` Eduardo Valentin
2015-01-29 7:52 ` Lukasz Majewski
2 siblings, 1 reply; 10+ messages in thread
From: Abhilash Kesavan @ 2015-01-28 10:51 UTC (permalink / raw)
To: Zhang Rui, Eduardo Valentin, Kukjin Kim, linux-pm
Cc: linux-kernel, Bartlomiej Zolnierkiewicz, Lukasz Majewski,
Amit Kachhap, Me2, linux-samsung-soc
Hi Eduardo,
On Tue, Jan 27, 2015 at 11:18 AM, Abhilash Kesavan
<a.kesavan@samsung.com> wrote:
> Add documentation for exynos7 thermal bindings including compatible
> name and special clock properties.
>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> ---
> .../devicetree/bindings/thermal/exynos-thermal.txt | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> index 0f44932..695150a 100644
> --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> @@ -12,6 +12,7 @@
> "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
> Exynos5420 (Must pass triminfo base and triminfo clock)
> "samsung,exynos5440-tmu"
> + "samsung,exynos7-tmu"
> - interrupt-parent : The phandle for the interrupt controller
> - reg : Address range of the thermal registers. For soc's which has multiple
> instances of TMU and some registers are shared across all TMU's like
> @@ -32,10 +33,13 @@
> - clocks : The main clocks for TMU device
> -- 1. operational clock for TMU channel
> -- 2. optional clock to access the shared registers of TMU channel
> + -- 3. optional special clock for functional operation
> - clock-names : Thermal system clock name
> -- "tmu_apbif" operational clock for current TMU channel
> -- "tmu_triminfo_apbif" clock to access the shared triminfo register
> for current TMU channel
> + -- "tmu_sclk" clock for functional operation of the current TMU
> + channel
> - vtmu-supply: This entry is optional and provides the regulator node supplying
> voltage to TMU. If needed this entry can be placed inside
> board/platform specific dts file.
Can you kindly consider applying these two patches to your next tree
if they look OK ?
Regards,
Abhilash
> --
> 1.7.9.5
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings
2015-01-28 10:51 ` [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
@ 2015-01-28 17:23 ` Eduardo Valentin
2015-01-29 7:45 ` Lukasz Majewski
0 siblings, 1 reply; 10+ messages in thread
From: Eduardo Valentin @ 2015-01-28 17:23 UTC (permalink / raw)
To: Abhilash Kesavan
Cc: Zhang Rui, Kukjin Kim, linux-pm, linux-kernel,
Bartlomiej Zolnierkiewicz, Lukasz Majewski, Amit Kachhap,
linux-samsung-soc
[-- Attachment #1: Type: text/plain, Size: 2426 bytes --]
On Wed, Jan 28, 2015 at 04:21:49PM +0530, Abhilash Kesavan wrote:
> Hi Eduardo,
>
> On Tue, Jan 27, 2015 at 11:18 AM, Abhilash Kesavan
> <a.kesavan@samsung.com> wrote:
> > Add documentation for exynos7 thermal bindings including compatible
> > name and special clock properties.
> >
> > Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> > ---
> > .../devicetree/bindings/thermal/exynos-thermal.txt | 4 ++++
> > 1 file changed, 4 insertions(+)
> >
> > diff --git a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> > index 0f44932..695150a 100644
> > --- a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> > +++ b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> > @@ -12,6 +12,7 @@
> > "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
> > Exynos5420 (Must pass triminfo base and triminfo clock)
> > "samsung,exynos5440-tmu"
> > + "samsung,exynos7-tmu"
> > - interrupt-parent : The phandle for the interrupt controller
> > - reg : Address range of the thermal registers. For soc's which has multiple
> > instances of TMU and some registers are shared across all TMU's like
> > @@ -32,10 +33,13 @@
> > - clocks : The main clocks for TMU device
> > -- 1. operational clock for TMU channel
> > -- 2. optional clock to access the shared registers of TMU channel
> > + -- 3. optional special clock for functional operation
> > - clock-names : Thermal system clock name
> > -- "tmu_apbif" operational clock for current TMU channel
> > -- "tmu_triminfo_apbif" clock to access the shared triminfo register
> > for current TMU channel
> > + -- "tmu_sclk" clock for functional operation of the current TMU
> > + channel
> > - vtmu-supply: This entry is optional and provides the regulator node supplying
> > voltage to TMU. If needed this entry can be placed inside
> > board/platform specific dts file.
>
> Can you kindly consider applying these two patches to your next tree
> if they look OK ?
Abhilash, can you please get at least one Reviewed-by from one of the
active developers of exynos thermal driver?
>
> Regards,
> Abhilash
> > --
> > 1.7.9.5
> >
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings
2015-01-28 17:23 ` Eduardo Valentin
@ 2015-01-29 7:45 ` Lukasz Majewski
0 siblings, 0 replies; 10+ messages in thread
From: Lukasz Majewski @ 2015-01-29 7:45 UTC (permalink / raw)
To: Eduardo Valentin
Cc: Abhilash Kesavan, Zhang Rui, Kukjin Kim, linux-pm, linux-kernel,
Bartlomiej Zolnierkiewicz, Amit Kachhap, linux-samsung-soc
Hi Eduardo,
> On Wed, Jan 28, 2015 at 04:21:49PM +0530, Abhilash Kesavan wrote:
> > Hi Eduardo,
> >
> > On Tue, Jan 27, 2015 at 11:18 AM, Abhilash Kesavan
> > <a.kesavan@samsung.com> wrote:
> > > Add documentation for exynos7 thermal bindings including
> > > compatible name and special clock properties.
> > >
> > > Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> > > ---
> > > .../devicetree/bindings/thermal/exynos-thermal.txt | 4 ++++
> > > 1 file changed, 4 insertions(+)
> > >
> > > diff --git
> > > a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> > > b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> > > index 0f44932..695150a 100644 ---
> > > a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> > > +++
> > > b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt @@
> > > -12,6 +12,7 @@ "samsung,exynos5420-tmu-ext-triminfo" for TMU
> > > channels 2, 3 and 4 Exynos5420 (Must pass triminfo base and
> > > triminfo clock) "samsung,exynos5440-tmu"
> > > + "samsung,exynos7-tmu"
> > > - interrupt-parent : The phandle for the interrupt controller
> > > - reg : Address range of the thermal registers. For soc's which
> > > has multiple instances of TMU and some registers are shared
> > > across all TMU's like @@ -32,10 +33,13 @@
> > > - clocks : The main clocks for TMU device
> > > -- 1. operational clock for TMU channel
> > > -- 2. optional clock to access the shared registers of
> > > TMU channel
> > > + -- 3. optional special clock for functional operation
> > > - clock-names : Thermal system clock name
> > > -- "tmu_apbif" operational clock for current TMU channel
> > > -- "tmu_triminfo_apbif" clock to access the shared
> > > triminfo register for current TMU channel
> > > + -- "tmu_sclk" clock for functional operation of the
> > > current TMU
> > > + channel
> > > - vtmu-supply: This entry is optional and provides the regulator
> > > node supplying voltage to TMU. If needed this entry can be placed
> > > inside board/platform specific dts file.
> >
> > Can you kindly consider applying these two patches to your next tree
> > if they look OK ?
>
> Abhilash, can you please get at least one Reviewed-by from one of the
> active developers of exynos thermal driver?
I will review your patches. :-)
>
>
> >
> > Regards,
> > Abhilash
> > > --
> > > 1.7.9.5
> > >
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings
2015-01-27 5:48 [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
2015-01-27 5:48 ` [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC Abhilash Kesavan
2015-01-28 10:51 ` [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
@ 2015-01-29 7:52 ` Lukasz Majewski
2 siblings, 0 replies; 10+ messages in thread
From: Lukasz Majewski @ 2015-01-29 7:52 UTC (permalink / raw)
To: Abhilash Kesavan
Cc: rui.zhang, edubezval, kgene.kim, linux-pm, linux-kernel,
b.zolnierkie, amit.daniel, kesavan.abhilash, linux-samsung-soc
Hi Abhilash,
> Add documentation for exynos7 thermal bindings including compatible
> name and special clock properties.
>
> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com>
> ---
> .../devicetree/bindings/thermal/exynos-thermal.txt | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git
> a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt
> b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt index
> 0f44932..695150a 100644 ---
> a/Documentation/devicetree/bindings/thermal/exynos-thermal.txt +++
> b/Documentation/devicetree/bindings/thermal/exynos-thermal.txt @@
> -12,6 +12,7 @@ "samsung,exynos5420-tmu-ext-triminfo" for TMU channels
> 2, 3 and 4 Exynos5420 (Must pass triminfo base and triminfo clock)
> "samsung,exynos5440-tmu"
> + "samsung,exynos7-tmu"
> - interrupt-parent : The phandle for the interrupt controller
> - reg : Address range of the thermal registers. For soc's which has
> multiple instances of TMU and some registers are shared across all
> TMU's like @@ -32,10 +33,13 @@
> - clocks : The main clocks for TMU device
> -- 1. operational clock for TMU channel
> -- 2. optional clock to access the shared registers of TMU
> channel
> + -- 3. optional special clock for functional operation
> - clock-names : Thermal system clock name
> -- "tmu_apbif" operational clock for current TMU channel
> -- "tmu_triminfo_apbif" clock to access the shared triminfo
> register for current TMU channel
> + -- "tmu_sclk" clock for functional operation of the current
> TMU
> + channel
> - vtmu-supply: This entry is optional and provides the regulator
> node supplying voltage to TMU. If needed this entry can be placed
> inside board/platform specific dts file.
Acked-by: Lukasz Majewski <l.majewski@samsung.com>
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC
2015-01-27 5:48 ` [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC Abhilash Kesavan
@ 2015-01-29 8:26 ` Lukasz Majewski
2015-01-29 15:01 ` Abhilash Kesavan
2015-01-31 19:24 ` Eduardo Valentin
1 sibling, 1 reply; 10+ messages in thread
From: Lukasz Majewski @ 2015-01-29 8:26 UTC (permalink / raw)
To: Abhilash Kesavan
Cc: rui.zhang, edubezval, kgene.kim, linux-pm, linux-kernel,
b.zolnierkie, amit.daniel, kesavan.abhilash, linux-samsung-soc
Hi Abhilash,
> 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.kesavan@samsung.com>
> ---
> 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,
> };
>
> /**
Acked-by: Lukasz Majewski <l.majewski@samsung.com>
Tested-by: Lukasz Majewski <l.majewski@samsung.com>
Test HW: Odroid-U3 (Exynos4412)
linux-soc-thermal/fixes
SHA1: 252454f5cbda2c6b40c5d36f58cac2938437b85d
--
Best regards,
Lukasz Majewski
Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC
2015-01-29 8:26 ` Lukasz Majewski
@ 2015-01-29 15:01 ` Abhilash Kesavan
0 siblings, 0 replies; 10+ messages in thread
From: Abhilash Kesavan @ 2015-01-29 15:01 UTC (permalink / raw)
To: Lukasz Majewski
Cc: Zhang Rui, Eduardo Valentin, Kukjin Kim, linux-pm, linux-kernel,
Bartlomiej Zolnierkiewicz, Amit Kachhap, linux-samsung-soc
Hi Lukasz,
On Thu, Jan 29, 2015 at 1:56 PM, Lukasz Majewski <l.majewski@samsung.com> wrote:
> Hi Abhilash,
>
>> 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.kesavan@samsung.com>
>> ---
>> 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,
>> };
>>
>> /**
>
>
> Acked-by: Lukasz Majewski <l.majewski@samsung.com>
> Tested-by: Lukasz Majewski <l.majewski@samsung.com>
>
> Test HW: Odroid-U3 (Exynos4412)
>
> linux-soc-thermal/fixes
> SHA1: 252454f5cbda2c6b40c5d36f58cac2938437b85d
Thanks a lot for reviewing and testing these two patches.
Regards,
Abhilash
>
> --
> Best regards,
>
> Lukasz Majewski
>
> Samsung R&D Institute Poland (SRPOL) | Linux Platform Group
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC
2015-01-27 5:48 ` [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC Abhilash Kesavan
2015-01-29 8:26 ` Lukasz Majewski
@ 2015-01-31 19:24 ` Eduardo Valentin
2015-02-02 5:39 ` Abhilash Kesavan
1 sibling, 1 reply; 10+ messages in thread
From: Eduardo Valentin @ 2015-01-31 19:24 UTC (permalink / raw)
To: Abhilash Kesavan
Cc: rui.zhang, kgene.kim, linux-pm, linux-kernel, b.zolnierkie,
l.majewski, amit.daniel, kesavan.abhilash, linux-samsung-soc
[-- Attachment #1: Type: text/plain, Size: 15567 bytes --]
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.kesavan@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 #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 473 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC
2015-01-31 19:24 ` Eduardo Valentin
@ 2015-02-02 5:39 ` Abhilash Kesavan
0 siblings, 0 replies; 10+ messages in thread
From: Abhilash Kesavan @ 2015-02-02 5:39 UTC (permalink / raw)
To: Eduardo Valentin
Cc: Zhang Rui, Kukjin Kim, linux-pm, linux-kernel,
Bartlomiej Zolnierkiewicz, Lukasz Majewski, Amit Kachhap,
linux-samsung-soc
Hi Eduardo,
On Sun, Feb 1, 2015 at 12:54 AM, Eduardo Valentin <edubezval@gmail.com> wrote:
> 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.kesavan@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.
Thanks for applying these patches. As this is adding support for a new
SoC, should it not be part of your -next branch ?
I generally just run checkpatch without the "strict" option. Will
ensure that I run it with "strict" in the future.
Regards,
Abhilash
>
>
>> ---
>> 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
>>
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2015-02-02 5:39 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-27 5:48 [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
2015-01-27 5:48 ` [PATCH v4 2/2] thermal: exynos: Add TMU support for Exynos7 SoC Abhilash Kesavan
2015-01-29 8:26 ` Lukasz Majewski
2015-01-29 15:01 ` Abhilash Kesavan
2015-01-31 19:24 ` Eduardo Valentin
2015-02-02 5:39 ` Abhilash Kesavan
2015-01-28 10:51 ` [PATCH v4 1/2] dts: Documentation: Add documentation for Exynos7 SoC thermal bindings Abhilash Kesavan
2015-01-28 17:23 ` Eduardo Valentin
2015-01-29 7:45 ` Lukasz Majewski
2015-01-29 7:52 ` Lukasz Majewski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).