aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhilash Kesavan <a.kesavan@samsung.com>2015-01-27 00:48:22 -0500
committerEduardo Valentin <edubezval@gmail.com>2015-01-31 14:20:45 -0500
commit6c247393cfdd6695717f80ff31f9fd9af8c2c525 (patch)
tree15133debdf0ce9d9b8fdacd650b6b52899d29434
parent14ccc17a37c291172c557070f4faf77445494aff (diff)
thermal: exynos: Add TMU support for Exynos7 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. Acked-by: Lukasz Majewski <l.majewski@samsung.com> Tested-by: Lukasz Majewski <l.majewski@samsung.com> Signed-off-by: Abhilash Kesavan <a.kesavan@samsung.com> Signed-off-by: Eduardo Valentin <edubezval@gmail.com>
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c205
-rw-r--r--drivers/thermal/samsung/exynos_tmu.h1
2 files changed, 198 insertions, 8 deletions
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index b6a6e90ba340..fbeedc072cc2 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -119,6 +119,26 @@
119#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24 119#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
120#define EXYNOS5440_EFUSE_SWAP_OFFSET 8 120#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
121 121
122/* Exynos7 specific registers */
123#define EXYNOS7_THD_TEMP_RISE7_6 0x50
124#define EXYNOS7_THD_TEMP_FALL7_6 0x60
125#define EXYNOS7_TMU_REG_INTEN 0x110
126#define EXYNOS7_TMU_REG_INTPEND 0x118
127#define EXYNOS7_TMU_REG_EMUL_CON 0x160
128
129#define EXYNOS7_TMU_TEMP_MASK 0x1ff
130#define EXYNOS7_PD_DET_EN_SHIFT 23
131#define EXYNOS7_TMU_INTEN_RISE0_SHIFT 0
132#define EXYNOS7_TMU_INTEN_RISE1_SHIFT 1
133#define EXYNOS7_TMU_INTEN_RISE2_SHIFT 2
134#define EXYNOS7_TMU_INTEN_RISE3_SHIFT 3
135#define EXYNOS7_TMU_INTEN_RISE4_SHIFT 4
136#define EXYNOS7_TMU_INTEN_RISE5_SHIFT 5
137#define EXYNOS7_TMU_INTEN_RISE6_SHIFT 6
138#define EXYNOS7_TMU_INTEN_RISE7_SHIFT 7
139#define EXYNOS7_EMUL_DATA_SHIFT 7
140#define EXYNOS7_EMUL_DATA_MASK 0x1ff
141
122#define MCELSIUS 1000 142#define MCELSIUS 1000
123/** 143/**
124 * struct exynos_tmu_data : A structure to hold the private data of the TMU 144 * struct exynos_tmu_data : A structure to hold the private data of the TMU
@@ -133,6 +153,7 @@
133 * @lock: lock to implement synchronization. 153 * @lock: lock to implement synchronization.
134 * @clk: pointer to the clock structure. 154 * @clk: pointer to the clock structure.
135 * @clk_sec: pointer to the clock structure for accessing the base_second. 155 * @clk_sec: pointer to the clock structure for accessing the base_second.
156 * @sclk: pointer to the clock structure for accessing the tmu special clk.
136 * @temp_error1: fused value of the first point trim. 157 * @temp_error1: fused value of the first point trim.
137 * @temp_error2: fused value of the second point trim. 158 * @temp_error2: fused value of the second point trim.
138 * @regulator: pointer to the TMU regulator structure. 159 * @regulator: pointer to the TMU regulator structure.
@@ -152,8 +173,8 @@ struct exynos_tmu_data {
152 enum soc_type soc; 173 enum soc_type soc;
153 struct work_struct irq_work; 174 struct work_struct irq_work;
154 struct mutex lock; 175 struct mutex lock;
155 struct clk *clk, *clk_sec; 176 struct clk *clk, *clk_sec, *sclk;
156 u8 temp_error1, temp_error2; 177 u16 temp_error1, temp_error2;
157 struct regulator *regulator; 178 struct regulator *regulator;
158 struct thermal_zone_device *tzd; 179 struct thermal_zone_device *tzd;
159 180
@@ -223,7 +244,7 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
223 * Calculate a temperature value from a temperature code. 244 * Calculate a temperature value from a temperature code.
224 * The unit of the temperature is degree Celsius. 245 * The unit of the temperature is degree Celsius.
225 */ 246 */
226static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code) 247static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code)
227{ 248{
228 struct exynos_tmu_platform_data *pdata = data->pdata; 249 struct exynos_tmu_platform_data *pdata = data->pdata;
229 int temp; 250 int temp;
@@ -513,6 +534,84 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
513 return ret; 534 return ret;
514} 535}
515 536
537static int exynos7_tmu_initialize(struct platform_device *pdev)
538{
539 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
540 struct thermal_zone_device *tz = data->tzd;
541 struct exynos_tmu_platform_data *pdata = data->pdata;
542 unsigned int status, trim_info;
543 unsigned int rising_threshold = 0, falling_threshold = 0;
544 int ret = 0, threshold_code, i;
545 unsigned long temp, temp_hist;
546 unsigned int reg_off, bit_off;
547
548 status = readb(data->base + EXYNOS_TMU_REG_STATUS);
549 if (!status) {
550 ret = -EBUSY;
551 goto out;
552 }
553
554 trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
555
556 data->temp_error1 = trim_info & EXYNOS7_TMU_TEMP_MASK;
557 if (!data->temp_error1 ||
558 (pdata->min_efuse_value > data->temp_error1) ||
559 (data->temp_error1 > pdata->max_efuse_value))
560 data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
561
562 /* Write temperature code for rising and falling threshold */
563 for (i = (of_thermal_get_ntrips(tz) - 1); i >= 0; i--) {
564 /*
565 * On exynos7 there are 4 rising and 4 falling threshold
566 * registers (0x50-0x5c and 0x60-0x6c respectively). Each
567 * register holds the value of two threshold levels (at bit
568 * offsets 0 and 16). Based on the fact that there are atmost
569 * eight possible trigger levels, calculate the register and
570 * bit offsets where the threshold levels are to be written.
571 *
572 * e.g. EXYNOS7_THD_TEMP_RISE7_6 (0x50)
573 * [24:16] - Threshold level 7
574 * [8:0] - Threshold level 6
575 * e.g. EXYNOS7_THD_TEMP_RISE5_4 (0x54)
576 * [24:16] - Threshold level 5
577 * [8:0] - Threshold level 4
578 *
579 * and similarly for falling thresholds.
580 *
581 * Based on the above, calculate the register and bit offsets
582 * for rising/falling threshold levels and populate them.
583 */
584 reg_off = ((7 - i) / 2) * 4;
585 bit_off = ((8 - i) % 2);
586
587 tz->ops->get_trip_temp(tz, i, &temp);
588 temp /= MCELSIUS;
589
590 tz->ops->get_trip_hyst(tz, i, &temp_hist);
591 temp_hist = temp - (temp_hist / MCELSIUS);
592
593 /* Set 9-bit temperature code for rising threshold levels */
594 threshold_code = temp_to_code(data, temp);
595 rising_threshold = readl(data->base +
596 EXYNOS7_THD_TEMP_RISE7_6 + reg_off);
597 rising_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off));
598 rising_threshold |= threshold_code << (16 * bit_off);
599 writel(rising_threshold,
600 data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off);
601
602 /* Set 9-bit temperature code for falling threshold levels */
603 threshold_code = temp_to_code(data, temp_hist);
604 falling_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off));
605 falling_threshold |= threshold_code << (16 * bit_off);
606 writel(falling_threshold,
607 data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off);
608 }
609
610 data->tmu_clear_irqs(data);
611out:
612 return ret;
613}
614
516static void exynos4210_tmu_control(struct platform_device *pdev, bool on) 615static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
517{ 616{
518 struct exynos_tmu_data *data = platform_get_drvdata(pdev); 617 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
@@ -573,6 +672,46 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
573 writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL); 672 writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL);
574} 673}
575 674
675static void exynos7_tmu_control(struct platform_device *pdev, bool on)
676{
677 struct exynos_tmu_data *data = platform_get_drvdata(pdev);
678 struct thermal_zone_device *tz = data->tzd;
679 unsigned int con, interrupt_en;
680
681 con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
682
683 if (on) {
684 con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
685 interrupt_en =
686 (of_thermal_is_trip_valid(tz, 7)
687 << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
688 (of_thermal_is_trip_valid(tz, 6)
689 << EXYNOS7_TMU_INTEN_RISE6_SHIFT) |
690 (of_thermal_is_trip_valid(tz, 5)
691 << EXYNOS7_TMU_INTEN_RISE5_SHIFT) |
692 (of_thermal_is_trip_valid(tz, 4)
693 << EXYNOS7_TMU_INTEN_RISE4_SHIFT) |
694 (of_thermal_is_trip_valid(tz, 3)
695 << EXYNOS7_TMU_INTEN_RISE3_SHIFT) |
696 (of_thermal_is_trip_valid(tz, 2)
697 << EXYNOS7_TMU_INTEN_RISE2_SHIFT) |
698 (of_thermal_is_trip_valid(tz, 1)
699 << EXYNOS7_TMU_INTEN_RISE1_SHIFT) |
700 (of_thermal_is_trip_valid(tz, 0)
701 << EXYNOS7_TMU_INTEN_RISE0_SHIFT);
702
703 interrupt_en |=
704 interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
705 } else {
706 con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
707 interrupt_en = 0; /* Disable all interrupts */
708 }
709 con |= 1 << EXYNOS7_PD_DET_EN_SHIFT;
710
711 writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN);
712 writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
713}
714
576static int exynos_get_temp(void *p, long *temp) 715static int exynos_get_temp(void *p, long *temp)
577{ 716{
578 struct exynos_tmu_data *data = p; 717 struct exynos_tmu_data *data = p;
@@ -602,9 +741,19 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
602 val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT); 741 val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT);
603 val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT); 742 val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT);
604 } 743 }
605 val &= ~(EXYNOS_EMUL_DATA_MASK << EXYNOS_EMUL_DATA_SHIFT); 744 if (data->soc == SOC_ARCH_EXYNOS7) {
606 val |= (temp_to_code(data, temp) << EXYNOS_EMUL_DATA_SHIFT) | 745 val &= ~(EXYNOS7_EMUL_DATA_MASK <<
607 EXYNOS_EMUL_ENABLE; 746 EXYNOS7_EMUL_DATA_SHIFT);
747 val |= (temp_to_code(data, temp) <<
748 EXYNOS7_EMUL_DATA_SHIFT) |
749 EXYNOS_EMUL_ENABLE;
750 } else {
751 val &= ~(EXYNOS_EMUL_DATA_MASK <<
752 EXYNOS_EMUL_DATA_SHIFT);
753 val |= (temp_to_code(data, temp) <<
754 EXYNOS_EMUL_DATA_SHIFT) |
755 EXYNOS_EMUL_ENABLE;
756 }
608 } else { 757 } else {
609 val &= ~EXYNOS_EMUL_ENABLE; 758 val &= ~EXYNOS_EMUL_ENABLE;
610 } 759 }
@@ -620,6 +769,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
620 769
621 if (data->soc == SOC_ARCH_EXYNOS5260) 770 if (data->soc == SOC_ARCH_EXYNOS5260)
622 emul_con = EXYNOS5260_EMUL_CON; 771 emul_con = EXYNOS5260_EMUL_CON;
772 else if (data->soc == SOC_ARCH_EXYNOS7)
773 emul_con = EXYNOS7_TMU_REG_EMUL_CON;
623 else 774 else
624 emul_con = EXYNOS_EMUL_CON; 775 emul_con = EXYNOS_EMUL_CON;
625 776
@@ -683,6 +834,12 @@ static int exynos5440_tmu_read(struct exynos_tmu_data *data)
683 return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP); 834 return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP);
684} 835}
685 836
837static int exynos7_tmu_read(struct exynos_tmu_data *data)
838{
839 return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) &
840 EXYNOS7_TMU_TEMP_MASK;
841}
842
686static void exynos_tmu_work(struct work_struct *work) 843static void exynos_tmu_work(struct work_struct *work)
687{ 844{
688 struct exynos_tmu_data *data = container_of(work, 845 struct exynos_tmu_data *data = container_of(work,
@@ -721,6 +878,9 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
721 if (data->soc == SOC_ARCH_EXYNOS5260) { 878 if (data->soc == SOC_ARCH_EXYNOS5260) {
722 tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT; 879 tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT;
723 tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR; 880 tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR;
881 } else if (data->soc == SOC_ARCH_EXYNOS7) {
882 tmu_intstat = EXYNOS7_TMU_REG_INTPEND;
883 tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
724 } else { 884 } else {
725 tmu_intstat = EXYNOS_TMU_REG_INTSTAT; 885 tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
726 tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; 886 tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;
@@ -782,6 +942,9 @@ static const struct of_device_id exynos_tmu_match[] = {
782 { 942 {
783 .compatible = "samsung,exynos5440-tmu", 943 .compatible = "samsung,exynos5440-tmu",
784 }, 944 },
945 {
946 .compatible = "samsung,exynos7-tmu",
947 },
785 {}, 948 {},
786}; 949};
787MODULE_DEVICE_TABLE(of, exynos_tmu_match); 950MODULE_DEVICE_TABLE(of, exynos_tmu_match);
@@ -805,6 +968,8 @@ static int exynos_of_get_soc_type(struct device_node *np)
805 return SOC_ARCH_EXYNOS5420_TRIMINFO; 968 return SOC_ARCH_EXYNOS5420_TRIMINFO;
806 else if (of_device_is_compatible(np, "samsung,exynos5440-tmu")) 969 else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
807 return SOC_ARCH_EXYNOS5440; 970 return SOC_ARCH_EXYNOS5440;
971 else if (of_device_is_compatible(np, "samsung,exynos7-tmu"))
972 return SOC_ARCH_EXYNOS7;
808 973
809 return -EINVAL; 974 return -EINVAL;
810} 975}
@@ -928,6 +1093,13 @@ static int exynos_map_dt_data(struct platform_device *pdev)
928 data->tmu_set_emulation = exynos5440_tmu_set_emulation; 1093 data->tmu_set_emulation = exynos5440_tmu_set_emulation;
929 data->tmu_clear_irqs = exynos5440_tmu_clear_irqs; 1094 data->tmu_clear_irqs = exynos5440_tmu_clear_irqs;
930 break; 1095 break;
1096 case SOC_ARCH_EXYNOS7:
1097 data->tmu_initialize = exynos7_tmu_initialize;
1098 data->tmu_control = exynos7_tmu_control;
1099 data->tmu_read = exynos7_tmu_read;
1100 data->tmu_set_emulation = exynos4412_tmu_set_emulation;
1101 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
1102 break;
931 default: 1103 default:
932 dev_err(&pdev->dev, "Platform not supported\n"); 1104 dev_err(&pdev->dev, "Platform not supported\n");
933 return -EINVAL; 1105 return -EINVAL;
@@ -1017,21 +1189,37 @@ static int exynos_tmu_probe(struct platform_device *pdev)
1017 goto err_clk_sec; 1189 goto err_clk_sec;
1018 } 1190 }
1019 1191
1192 if (data->soc == SOC_ARCH_EXYNOS7) {
1193 data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk");
1194 if (IS_ERR(data->sclk)) {
1195 dev_err(&pdev->dev, "Failed to get sclk\n");
1196 goto err_clk;
1197 } else {
1198 ret = clk_prepare_enable(data->sclk);
1199 if (ret) {
1200 dev_err(&pdev->dev, "Failed to enable sclk\n");
1201 goto err_clk;
1202 }
1203 }
1204 }
1205
1020 ret = exynos_tmu_initialize(pdev); 1206 ret = exynos_tmu_initialize(pdev);
1021 if (ret) { 1207 if (ret) {
1022 dev_err(&pdev->dev, "Failed to initialize TMU\n"); 1208 dev_err(&pdev->dev, "Failed to initialize TMU\n");
1023 goto err_clk; 1209 goto err_sclk;
1024 } 1210 }
1025 1211
1026 ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq, 1212 ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
1027 IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data); 1213 IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
1028 if (ret) { 1214 if (ret) {
1029 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq); 1215 dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
1030 goto err_clk; 1216 goto err_sclk;
1031 } 1217 }
1032 1218
1033 exynos_tmu_control(pdev, true); 1219 exynos_tmu_control(pdev, true);
1034 return 0; 1220 return 0;
1221err_sclk:
1222 clk_disable_unprepare(data->sclk);
1035err_clk: 1223err_clk:
1036 clk_unprepare(data->clk); 1224 clk_unprepare(data->clk);
1037err_clk_sec: 1225err_clk_sec:
@@ -1051,6 +1239,7 @@ static int exynos_tmu_remove(struct platform_device *pdev)
1051 thermal_zone_of_sensor_unregister(&pdev->dev, tzd); 1239 thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
1052 exynos_tmu_control(pdev, false); 1240 exynos_tmu_control(pdev, false);
1053 1241
1242 clk_disable_unprepare(data->sclk);
1054 clk_unprepare(data->clk); 1243 clk_unprepare(data->clk);
1055 if (!IS_ERR(data->clk_sec)) 1244 if (!IS_ERR(data->clk_sec))
1056 clk_unprepare(data->clk_sec); 1245 clk_unprepare(data->clk_sec);
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index 9f9b1b810269..4d71ec6c9aa0 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -34,6 +34,7 @@ enum soc_type {
34 SOC_ARCH_EXYNOS5420, 34 SOC_ARCH_EXYNOS5420,
35 SOC_ARCH_EXYNOS5420_TRIMINFO, 35 SOC_ARCH_EXYNOS5420_TRIMINFO,
36 SOC_ARCH_EXYNOS5440, 36 SOC_ARCH_EXYNOS5440,
37 SOC_ARCH_EXYNOS7,
37}; 38};
38 39
39/** 40/**