Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thermal: exynos: Add the support for Exynos5433 TMU

This patch adds the support for Exynos5433's TMU (Thermal Management Unit).
Exynos5433 has a little different register bit fields as following description:
- Support the eight trip points for rising/falling interrupt by using two registers
- Read the calibration type (1-point or 2-point) and sensor id from TRIMINFO register
- Use a little different register address

Cc: Zhang Rui <rui.zhang@intel.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
Cc: Lukasz Majewski <l.majewski@samsung.com>
Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
Signed-off-by: Eduardo Valentin <edubezval@gmail.com>

authored by

Chanwoo Choi and committed by
Eduardo Valentin
488c7455 dd658e02

+186 -2
+185 -2
drivers/thermal/samsung/exynos_tmu.c
··· 97 97 #define EXYNOS4412_MUX_ADDR_VALUE 6 98 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 126 /*exynos5440 specific registers*/ 101 127 #define EXYNOS5440_TMU_S0_7_TRIM 0x000 102 128 #define EXYNOS5440_TMU_S0_7_CTRL 0x020 ··· 510 484 return ret; 511 485 } 512 486 487 + static int exynos5433_tmu_initialize(struct platform_device *pdev) 488 + { 489 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 490 + struct exynos_tmu_platform_data *pdata = data->pdata; 491 + struct thermal_zone_device *tz = data->tzd; 492 + unsigned int status, trim_info; 493 + unsigned int rising_threshold = 0, falling_threshold = 0; 494 + unsigned long temp, temp_hist; 495 + int ret = 0, threshold_code, i, sensor_id, cal_type; 496 + 497 + status = readb(data->base + EXYNOS_TMU_REG_STATUS); 498 + if (!status) { 499 + ret = -EBUSY; 500 + goto out; 501 + } 502 + 503 + trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO); 504 + sanitize_temp_error(data, trim_info); 505 + 506 + /* Read the temperature sensor id */ 507 + sensor_id = (trim_info & EXYNOS5433_TRIMINFO_SENSOR_ID_MASK) 508 + >> EXYNOS5433_TRIMINFO_SENSOR_ID_SHIFT; 509 + dev_info(&pdev->dev, "Temperature sensor ID: 0x%x\n", sensor_id); 510 + 511 + /* Read the calibration mode */ 512 + writel(trim_info, data->base + EXYNOS_TMU_REG_TRIMINFO); 513 + cal_type = (trim_info & EXYNOS5433_TRIMINFO_CALIB_SEL_MASK) 514 + >> EXYNOS5433_TRIMINFO_CALIB_SEL_SHIFT; 515 + 516 + switch (cal_type) { 517 + case EXYNOS5433_TRIMINFO_ONE_POINT_TRIMMING: 518 + pdata->cal_type = TYPE_ONE_POINT_TRIMMING; 519 + break; 520 + case EXYNOS5433_TRIMINFO_TWO_POINT_TRIMMING: 521 + pdata->cal_type = TYPE_TWO_POINT_TRIMMING; 522 + break; 523 + default: 524 + pdata->cal_type = TYPE_ONE_POINT_TRIMMING; 525 + break; 526 + }; 527 + 528 + dev_info(&pdev->dev, "Calibration type is %d-point calibration\n", 529 + cal_type ? 2 : 1); 530 + 531 + /* Write temperature code for rising and falling threshold */ 532 + for (i = 0; i < of_thermal_get_ntrips(tz); i++) { 533 + int rising_reg_offset, falling_reg_offset; 534 + int j = 0; 535 + 536 + switch (i) { 537 + case 0: 538 + case 1: 539 + case 2: 540 + case 3: 541 + rising_reg_offset = EXYNOS5433_THD_TEMP_RISE3_0; 542 + falling_reg_offset = EXYNOS5433_THD_TEMP_FALL3_0; 543 + j = i; 544 + break; 545 + case 4: 546 + case 5: 547 + case 6: 548 + case 7: 549 + rising_reg_offset = EXYNOS5433_THD_TEMP_RISE7_4; 550 + falling_reg_offset = EXYNOS5433_THD_TEMP_FALL7_4; 551 + j = i - 4; 552 + break; 553 + default: 554 + continue; 555 + } 556 + 557 + /* Write temperature code for rising threshold */ 558 + tz->ops->get_trip_temp(tz, i, &temp); 559 + temp /= MCELSIUS; 560 + threshold_code = temp_to_code(data, temp); 561 + 562 + rising_threshold = readl(data->base + rising_reg_offset); 563 + rising_threshold |= (threshold_code << j * 8); 564 + writel(rising_threshold, data->base + rising_reg_offset); 565 + 566 + /* Write temperature code for falling threshold */ 567 + tz->ops->get_trip_hyst(tz, i, &temp_hist); 568 + temp_hist = temp - (temp_hist / MCELSIUS); 569 + threshold_code = temp_to_code(data, temp_hist); 570 + 571 + falling_threshold = readl(data->base + falling_reg_offset); 572 + falling_threshold &= ~(0xff << j * 8); 573 + falling_threshold |= (threshold_code << j * 8); 574 + writel(falling_threshold, data->base + falling_reg_offset); 575 + } 576 + 577 + data->tmu_clear_irqs(data); 578 + out: 579 + return ret; 580 + } 581 + 513 582 static int exynos5440_tmu_initialize(struct platform_device *pdev) 514 583 { 515 584 struct exynos_tmu_data *data = platform_get_drvdata(pdev); ··· 764 643 writel(con, data->base + EXYNOS_TMU_REG_CONTROL); 765 644 } 766 645 646 + static void exynos5433_tmu_control(struct platform_device *pdev, bool on) 647 + { 648 + struct exynos_tmu_data *data = platform_get_drvdata(pdev); 649 + struct thermal_zone_device *tz = data->tzd; 650 + unsigned int con, interrupt_en, pd_det_en; 651 + 652 + con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL)); 653 + 654 + if (on) { 655 + con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT); 656 + interrupt_en = 657 + (of_thermal_is_trip_valid(tz, 7) 658 + << EXYNOS7_TMU_INTEN_RISE7_SHIFT) | 659 + (of_thermal_is_trip_valid(tz, 6) 660 + << EXYNOS7_TMU_INTEN_RISE6_SHIFT) | 661 + (of_thermal_is_trip_valid(tz, 5) 662 + << EXYNOS7_TMU_INTEN_RISE5_SHIFT) | 663 + (of_thermal_is_trip_valid(tz, 4) 664 + << EXYNOS7_TMU_INTEN_RISE4_SHIFT) | 665 + (of_thermal_is_trip_valid(tz, 3) 666 + << EXYNOS7_TMU_INTEN_RISE3_SHIFT) | 667 + (of_thermal_is_trip_valid(tz, 2) 668 + << EXYNOS7_TMU_INTEN_RISE2_SHIFT) | 669 + (of_thermal_is_trip_valid(tz, 1) 670 + << EXYNOS7_TMU_INTEN_RISE1_SHIFT) | 671 + (of_thermal_is_trip_valid(tz, 0) 672 + << EXYNOS7_TMU_INTEN_RISE0_SHIFT); 673 + 674 + interrupt_en |= 675 + interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT; 676 + } else { 677 + con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT); 678 + interrupt_en = 0; /* Disable all interrupts */ 679 + } 680 + 681 + pd_det_en = on ? EXYNOS5433_PD_DET_EN : 0; 682 + 683 + writel(pd_det_en, data->base + EXYNOS5433_TMU_PD_DET_EN); 684 + writel(interrupt_en, data->base + EXYNOS5433_TMU_REG_INTEN); 685 + writel(con, data->base + EXYNOS_TMU_REG_CONTROL); 686 + } 687 + 767 688 static void exynos5440_tmu_control(struct platform_device *pdev, bool on) 768 689 { 769 690 struct exynos_tmu_data *data = platform_get_drvdata(pdev); ··· 933 770 934 771 if (data->soc == SOC_ARCH_EXYNOS5260) 935 772 emul_con = EXYNOS5260_EMUL_CON; 773 + if (data->soc == SOC_ARCH_EXYNOS5433) 774 + emul_con = EXYNOS5433_TMU_EMUL_CON; 936 775 else if (data->soc == SOC_ARCH_EXYNOS7) 937 776 emul_con = EXYNOS7_TMU_REG_EMUL_CON; 938 777 else ··· 1047 882 } else if (data->soc == SOC_ARCH_EXYNOS7) { 1048 883 tmu_intstat = EXYNOS7_TMU_REG_INTPEND; 1049 884 tmu_intclear = EXYNOS7_TMU_REG_INTPEND; 885 + } else if (data->soc == SOC_ARCH_EXYNOS5433) { 886 + tmu_intstat = EXYNOS5433_TMU_REG_INTPEND; 887 + tmu_intclear = EXYNOS5433_TMU_REG_INTPEND; 1050 888 } else { 1051 889 tmu_intstat = EXYNOS_TMU_REG_INTSTAT; 1052 890 tmu_intclear = EXYNOS_TMU_REG_INTCLEAR; ··· 1094 926 { .compatible = "samsung,exynos5260-tmu", }, 1095 927 { .compatible = "samsung,exynos5420-tmu", }, 1096 928 { .compatible = "samsung,exynos5420-tmu-ext-triminfo", }, 929 + { .compatible = "samsung,exynos5433-tmu", }, 1097 930 { .compatible = "samsung,exynos5440-tmu", }, 1098 931 { .compatible = "samsung,exynos7-tmu", }, 1099 932 { /* sentinel */ }, ··· 1118 949 else if (of_device_is_compatible(np, 1119 950 "samsung,exynos5420-tmu-ext-triminfo")) 1120 951 return SOC_ARCH_EXYNOS5420_TRIMINFO; 952 + else if (of_device_is_compatible(np, "samsung,exynos5433-tmu")) 953 + return SOC_ARCH_EXYNOS5433; 1121 954 else if (of_device_is_compatible(np, "samsung,exynos5440-tmu")) 1122 955 return SOC_ARCH_EXYNOS5440; 1123 956 else if (of_device_is_compatible(np, "samsung,exynos7-tmu")) ··· 1240 1069 data->tmu_set_emulation = exynos4412_tmu_set_emulation; 1241 1070 data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; 1242 1071 break; 1072 + case SOC_ARCH_EXYNOS5433: 1073 + data->tmu_initialize = exynos5433_tmu_initialize; 1074 + data->tmu_control = exynos5433_tmu_control; 1075 + data->tmu_read = exynos4412_tmu_read; 1076 + data->tmu_set_emulation = exynos4412_tmu_set_emulation; 1077 + data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; 1078 + break; 1243 1079 case SOC_ARCH_EXYNOS5440: 1244 1080 data->tmu_initialize = exynos5440_tmu_initialize; 1245 1081 data->tmu_control = exynos5440_tmu_control; ··· 1350 1172 goto err_clk_sec; 1351 1173 } 1352 1174 1353 - if (data->soc == SOC_ARCH_EXYNOS7) { 1175 + switch (data->soc) { 1176 + case SOC_ARCH_EXYNOS5433: 1177 + case SOC_ARCH_EXYNOS7: 1354 1178 data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk"); 1355 1179 if (IS_ERR(data->sclk)) { 1356 1180 dev_err(&pdev->dev, "Failed to get sclk\n"); ··· 1364 1184 goto err_clk; 1365 1185 } 1366 1186 } 1367 - } 1187 + break; 1188 + default: 1189 + break; 1190 + }; 1368 1191 1369 1192 ret = exynos_tmu_initialize(pdev); 1370 1193 if (ret) {
+1
drivers/thermal/samsung/exynos_tmu.h
··· 33 33 SOC_ARCH_EXYNOS5260, 34 34 SOC_ARCH_EXYNOS5420, 35 35 SOC_ARCH_EXYNOS5420_TRIMINFO, 36 + SOC_ARCH_EXYNOS5433, 36 37 SOC_ARCH_EXYNOS5440, 37 38 SOC_ARCH_EXYNOS7, 38 39 };