diff options
Diffstat (limited to 'drivers/thermal/samsung/exynos_tmu.c')
-rw-r--r-- | drivers/thermal/samsung/exynos_tmu.c | 187 |
1 files changed, 185 insertions, 2 deletions
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 1d30b0975651..531f4b179871 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c | |||
@@ -97,6 +97,32 @@ | |||
97 | #define EXYNOS4412_MUX_ADDR_VALUE 6 | 97 | #define EXYNOS4412_MUX_ADDR_VALUE 6 |
98 | #define EXYNOS4412_MUX_ADDR_SHIFT 20 | 98 | #define EXYNOS4412_MUX_ADDR_SHIFT 20 |
99 | 99 | ||
100 | /* Exynos5433 specific registers */ | ||
101 | #define EXYNOS5433_TMU_REG_CONTROL1 0x024 | ||
102 | #define EXYNOS5433_TMU_SAMPLING_INTERVAL 0x02c | ||
103 | #define EXYNOS5433_TMU_COUNTER_VALUE0 0x030 | ||
104 | #define EXYNOS5433_TMU_COUNTER_VALUE1 0x034 | ||
105 | #define EXYNOS5433_TMU_REG_CURRENT_TEMP1 0x044 | ||
106 | #define EXYNOS5433_THD_TEMP_RISE3_0 0x050 | ||
107 | #define EXYNOS5433_THD_TEMP_RISE7_4 0x054 | ||
108 | #define EXYNOS5433_THD_TEMP_FALL3_0 0x060 | ||
109 | #define EXYNOS5433_THD_TEMP_FALL7_4 0x064 | ||
110 | #define EXYNOS5433_TMU_REG_INTEN 0x0c0 | ||
111 | #define EXYNOS5433_TMU_REG_INTPEND 0x0c8 | ||
112 | #define EXYNOS5433_TMU_EMUL_CON 0x110 | ||
113 | #define EXYNOS5433_TMU_PD_DET_EN 0x130 | ||
114 | |||
115 | #define EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT 16 | ||
116 | #define EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT 23 | ||
117 | #define EXYNOS5433_TRIMINFO_SENSOR_ID_MASK \ | ||
118 | (0xf << EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT) | ||
119 | #define EXYNOS5433_TRIMINFO_CALIB_SEL_MASK BIT(23) | ||
120 | |||
121 | #define EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING 0 | ||
122 | #define EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING 1 | ||
123 | |||
124 | #define EXYNOS5433_PD_DET_EN 1 | ||
125 | |||
100 | /*exynos5440 specific registers*/ | 126 | /*exynos5440 specific registers*/ |
101 | #define EXYNOS5440_TMU_S0_7_TRIM 0x000 | 127 | #define EXYNOS5440_TMU_S0_7_TRIM 0x000 |
102 | #define EXYNOS5440_TMU_S0_7_CTRL 0x020 | 128 | #define EXYNOS5440_TMU_S0_7_CTRL 0x020 |
@@ -484,6 +510,101 @@ out: | |||
484 | return ret; | 510 | return ret; |
485 | } | 511 | } |
486 | 512 | ||
513 | static int exynos5433_tmu_initialize(struct platform_device *pdev) | ||
514 | { | ||
515 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | ||
516 | struct exynos_tmu_platform_data *pdata = data->pdata; | ||
517 | struct thermal_zone_device *tz = data->tzd; | ||
518 | unsigned int status, trim_info; | ||
519 | unsigned int rising_threshold = 0, falling_threshold = 0; | ||
520 | unsigned long temp, temp_hist; | ||
521 | int ret = 0, threshold_code, i, sensor_id, cal_type; | ||
522 | |||
523 | status = readb(data->base + EXYNOS_TMU_REG_STATUS); | ||
524 | if (!status) { | ||
525 | ret = -EBUSY; | ||
526 | goto out; | ||
527 | } | ||
528 | |||
529 | trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); | ||
530 | sanitize_temp_error(data, trim_info); | ||
531 | |||
532 | /* Read the temperature sensor id */ | ||
533 | sensor_id = (trim_info & EXYNOS5433_TRIMINFO_SENSOR_ID_MASK) | ||
534 | >> EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT; | ||
535 | dev_info(&pdev->dev, "Temperature sensor ID: 0x%x\n", sensor_id); | ||
536 | |||
537 | /* Read the calibration mode */ | ||
538 | writel(trim_info, data->base + EXYNOS_TMU_REG_TRIMINFO); | ||
539 | cal_type = (trim_info & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK) | ||
540 | >> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT; | ||
541 | |||
542 | switch (cal_type) { | ||
543 | case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING: | ||
544 | pdata->cal_type = TYPE_ONE_POINT_TRIMMING; | ||
545 | break; | ||
546 | case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING: | ||
547 | pdata->cal_type = TYPE_TWO_POINT_TRIMMING; | ||
548 | break; | ||
549 | default: | ||
550 | pdata->cal_type = TYPE_ONE_POINT_TRIMMING; | ||
551 | break; | ||
552 | }; | ||
553 | |||
554 | dev_info(&pdev->dev, "Calibration type is %d-point calibration\n", | ||
555 | cal_type ? 2 : 1); | ||
556 | |||
557 | /* Write temperature code for rising and falling threshold */ | ||
558 | for (i = 0; i < of_thermal_get_ntrips(tz); i++) { | ||
559 | int rising_reg_offset, falling_reg_offset; | ||
560 | int j = 0; | ||
561 | |||
562 | switch (i) { | ||
563 | case 0: | ||
564 | case 1: | ||
565 | case 2: | ||
566 | case 3: | ||
567 | rising_reg_offset = EXYNOS5433_THD_TEMP_RISE3_0; | ||
568 | falling_reg_offset = EXYNOS5433_THD_TEMP_FALL3_0; | ||
569 | j = i; | ||
570 | break; | ||
571 | case 4: | ||
572 | case 5: | ||
573 | case 6: | ||
574 | case 7: | ||
575 | rising_reg_offset = EXYNOS5433_THD_TEMP_RISE7_4; | ||
576 | falling_reg_offset = EXYNOS5433_THD_TEMP_FALL7_4; | ||
577 | j = i - 4; | ||
578 | break; | ||
579 | default: | ||
580 | continue; | ||
581 | } | ||
582 | |||
583 | /* Write temperature code for rising threshold */ | ||
584 | tz->ops->get_trip_temp(tz, i, &temp); | ||
585 | temp /= MCELSIUS; | ||
586 | threshold_code = temp_to_code(data, temp); | ||
587 | |||
588 | rising_threshold = readl(data->base + rising_reg_offset); | ||
589 | rising_threshold |= (threshold_code << j * 8); | ||
590 | writel(rising_threshold, data->base + rising_reg_offset); | ||
591 | |||
592 | /* Write temperature code for falling threshold */ | ||
593 | tz->ops->get_trip_hyst(tz, i, &temp_hist); | ||
594 | temp_hist = temp - (temp_hist / MCELSIUS); | ||
595 | threshold_code = temp_to_code(data, temp_hist); | ||
596 | |||
597 | falling_threshold = readl(data->base + falling_reg_offset); | ||
598 | falling_threshold &= ~(0xff << j * 8); | ||
599 | falling_threshold |= (threshold_code << j * 8); | ||
600 | writel(falling_threshold, data->base + falling_reg_offset); | ||
601 | } | ||
602 | |||
603 | data->tmu_clear_irqs(data); | ||
604 | out: | ||
605 | return ret; | ||
606 | } | ||
607 | |||
487 | static int exynos5440_tmu_initialize(struct platform_device *pdev) | 608 | static int exynos5440_tmu_initialize(struct platform_device *pdev) |
488 | { | 609 | { |
489 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 610 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
@@ -643,6 +764,48 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on) | |||
643 | writel(con, data->base + EXYNOS_TMU_REG_CONTROL); | 764 | writel(con, data->base + EXYNOS_TMU_REG_CONTROL); |
644 | } | 765 | } |
645 | 766 | ||
767 | static void exynos5433_tmu_control(struct platform_device *pdev, bool on) | ||
768 | { | ||
769 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | ||
770 | struct thermal_zone_device *tz = data->tzd; | ||
771 | unsigned int con, interrupt_en, pd_det_en; | ||
772 | |||
773 | con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); | ||
774 | |||
775 | if (on) { | ||
776 | con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); | ||
777 | interrupt_en = | ||
778 | (of_thermal_is_trip_valid(tz, 7) | ||
779 | << EXYNOS7_TMU_INTEN_RISE7_SHIFT) | | ||
780 | (of_thermal_is_trip_valid(tz, 6) | ||
781 | << EXYNOS7_TMU_INTEN_RISE6_SHIFT) | | ||
782 | (of_thermal_is_trip_valid(tz, 5) | ||
783 | << EXYNOS7_TMU_INTEN_RISE5_SHIFT) | | ||
784 | (of_thermal_is_trip_valid(tz, 4) | ||
785 | << EXYNOS7_TMU_INTEN_RISE4_SHIFT) | | ||
786 | (of_thermal_is_trip_valid(tz, 3) | ||
787 | << EXYNOS7_TMU_INTEN_RISE3_SHIFT) | | ||
788 | (of_thermal_is_trip_valid(tz, 2) | ||
789 | << EXYNOS7_TMU_INTEN_RISE2_SHIFT) | | ||
790 | (of_thermal_is_trip_valid(tz, 1) | ||
791 | << EXYNOS7_TMU_INTEN_RISE1_SHIFT) | | ||
792 | (of_thermal_is_trip_valid(tz, 0) | ||
793 | << EXYNOS7_TMU_INTEN_RISE0_SHIFT); | ||
794 | |||
795 | interrupt_en |= | ||
796 | interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; | ||
797 | } else { | ||
798 | con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); | ||
799 | interrupt_en = 0; /* Disable all interrupts */ | ||
800 | } | ||
801 | |||
802 | pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0; | ||
803 | |||
804 | writel(pd_det_en, data->base + EXYNOS5433_TMU_PD_DET_EN); | ||
805 | writel(interrupt_en, data->base + EXYNOS5433_TMU_REG_INTEN); | ||
806 | writel(con, data->base + EXYNOS_TMU_REG_CONTROL); | ||
807 | } | ||
808 | |||
646 | static void exynos5440_tmu_control(struct platform_device *pdev, bool on) | 809 | static void exynos5440_tmu_control(struct platform_device *pdev, bool on) |
647 | { | 810 | { |
648 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); | 811 | struct exynos_tmu_data *data = platform_get_drvdata(pdev); |
@@ -770,6 +933,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data, | |||
770 | 933 | ||
771 | if (data->soc == SOC_ARCH_EXYNOS5260) | 934 | if (data->soc == SOC_ARCH_EXYNOS5260) |
772 | emul_con = EXYNOS5260_EMUL_CON; | 935 | emul_con = EXYNOS5260_EMUL_CON; |
936 | if (data->soc == SOC_ARCH_EXYNOS5433) | ||
937 | emul_con = EXYNOS5433_TMU_EMUL_CON; | ||
773 | else if (data->soc == SOC_ARCH_EXYNOS7) | 938 | else if (data->soc == SOC_ARCH_EXYNOS7) |
774 | emul_con = EXYNOS7_TMU_REG_EMUL_CON; | 939 | emul_con = EXYNOS7_TMU_REG_EMUL_CON; |
775 | else | 940 | else |
@@ -882,6 +1047,9 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data) | |||
882 | } else if (data->soc == SOC_ARCH_EXYNOS7) { | 1047 | } else if (data->soc == SOC_ARCH_EXYNOS7) { |
883 | tmu_intstat = EXYNOS7_TMU_REG_INTPEND; | 1048 | tmu_intstat = EXYNOS7_TMU_REG_INTPEND; |
884 | tmu_intclear = EXYNOS7_TMU_REG_INTPEND; | 1049 | tmu_intclear = EXYNOS7_TMU_REG_INTPEND; |
1050 | } else if (data->soc == SOC_ARCH_EXYNOS5433) { | ||
1051 | tmu_intstat = EXYNOS5433_TMU_REG_INTPEND; | ||
1052 | tmu_intclear = EXYNOS5433_TMU_REG_INTPEND; | ||
885 | } else { | 1053 | } else { |
886 | tmu_intstat = EXYNOS_TMU_REG_INTSTAT; | 1054 | tmu_intstat = EXYNOS_TMU_REG_INTSTAT; |
887 | tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; | 1055 | tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; |
@@ -926,6 +1094,7 @@ static const struct of_device_id exynos_tmu_match[] = { | |||
926 | { .compatible = "samsung,exynos5260-tmu", }, | 1094 | { .compatible = "samsung,exynos5260-tmu", }, |
927 | { .compatible = "samsung,exynos5420-tmu", }, | 1095 | { .compatible = "samsung,exynos5420-tmu", }, |
928 | { .compatible = "samsung,exynos5420-tmu-ext-triminfo", }, | 1096 | { .compatible = "samsung,exynos5420-tmu-ext-triminfo", }, |
1097 | { .compatible = "samsung,exynos5433-tmu", }, | ||
929 | { .compatible = "samsung,exynos5440-tmu", }, | 1098 | { .compatible = "samsung,exynos5440-tmu", }, |
930 | { .compatible = "samsung,exynos7-tmu", }, | 1099 | { .compatible = "samsung,exynos7-tmu", }, |
931 | { /* sentinel */ }, | 1100 | { /* sentinel */ }, |
@@ -949,6 +1118,8 @@ static int exynos_of_get_soc_type(struct device_node *np) | |||
949 | else if (of_device_is_compatible(np, | 1118 | else if (of_device_is_compatible(np, |
950 | "samsung,exynos5420-tmu-ext-triminfo")) | 1119 | "samsung,exynos5420-tmu-ext-triminfo")) |
951 | return SOC_ARCH_EXYNOS5420_TRIMINFO; | 1120 | return SOC_ARCH_EXYNOS5420_TRIMINFO; |
1121 | else if (of_device_is_compatible(np, "samsung,exynos5433-tmu")) | ||
1122 | return SOC_ARCH_EXYNOS5433; | ||
952 | else if (of_device_is_compatible(np, "samsung,exynos5440-tmu")) | 1123 | else if (of_device_is_compatible(np, "samsung,exynos5440-tmu")) |
953 | return SOC_ARCH_EXYNOS5440; | 1124 | return SOC_ARCH_EXYNOS5440; |
954 | else if (of_device_is_compatible(np, "samsung,exynos7-tmu")) | 1125 | else if (of_device_is_compatible(np, "samsung,exynos7-tmu")) |
@@ -1069,6 +1240,13 @@ static int exynos_map_dt_data(struct platform_device *pdev) | |||
1069 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; | 1240 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; |
1070 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; | 1241 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; |
1071 | break; | 1242 | break; |
1243 | case SOC_ARCH_EXYNOS5433: | ||
1244 | data->tmu_initialize = exynos5433_tmu_initialize; | ||
1245 | data->tmu_control = exynos5433_tmu_control; | ||
1246 | data->tmu_read = exynos4412_tmu_read; | ||
1247 | data->tmu_set_emulation = exynos4412_tmu_set_emulation; | ||
1248 | data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; | ||
1249 | break; | ||
1072 | case SOC_ARCH_EXYNOS5440: | 1250 | case SOC_ARCH_EXYNOS5440: |
1073 | data->tmu_initialize = exynos5440_tmu_initialize; | 1251 | data->tmu_initialize = exynos5440_tmu_initialize; |
1074 | data->tmu_control = exynos5440_tmu_control; | 1252 | data->tmu_control = exynos5440_tmu_control; |
@@ -1172,7 +1350,9 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
1172 | goto err_clk_sec; | 1350 | goto err_clk_sec; |
1173 | } | 1351 | } |
1174 | 1352 | ||
1175 | if (data->soc == SOC_ARCH_EXYNOS7) { | 1353 | switch (data->soc) { |
1354 | case SOC_ARCH_EXYNOS5433: | ||
1355 | case SOC_ARCH_EXYNOS7: | ||
1176 | data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk"); | 1356 | data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk"); |
1177 | if (IS_ERR(data->sclk)) { | 1357 | if (IS_ERR(data->sclk)) { |
1178 | dev_err(&pdev->dev, "Failed to get sclk\n"); | 1358 | dev_err(&pdev->dev, "Failed to get sclk\n"); |
@@ -1184,7 +1364,10 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
1184 | goto err_clk; | 1364 | goto err_clk; |
1185 | } | 1365 | } |
1186 | } | 1366 | } |
1187 | } | 1367 | break; |
1368 | default: | ||
1369 | break; | ||
1370 | }; | ||
1188 | 1371 | ||
1189 | ret = exynos_tmu_initialize(pdev); | 1372 | ret = exynos_tmu_initialize(pdev); |
1190 | if (ret) { | 1373 | if (ret) { |