X-Git-Url: http://plrg.eecs.uci.edu/git/?p=firefly-linux-kernel-4.4.55.git;a=blobdiff_plain;f=drivers%2Fthermal%2Frockchip_thermal.c;h=0360d87d189e09ce84c80c21c64bba5bb65716ff;hp=b4e3639fba79aceb333e94d853af59ba5a78ac6d;hb=25e1c1c2865f7b91b8d60a16734100f3cb67722d;hpb=7a8bd6a860e186a7e42e19bbfc8cf124c355db11 diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index b4e3639fba79..0360d87d189e 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -1,7 +1,5 @@ /* - * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd - * - * Copyright (c) 2015, Fuzhou Rockchip Electronics Co., Ltd + * Copyright (c) 2014-2016, Fuzhou Rockchip Electronics Co., Ltd * Caesar Wang * * This program is free software; you can redistribute it and/or modify it @@ -75,7 +73,7 @@ enum adc_sort_mode { #define SOC_MAX_SENSORS 2 /** - * struct chip_tsadc_table: hold information about chip-specific differences + * struct chip_tsadc_table - hold information about chip-specific differences * @id: conversion table * @length: size of conversion table * @data_mask: mask to apply on data inputs @@ -88,6 +86,21 @@ struct chip_tsadc_table { enum adc_sort_mode mode; }; +/** + * struct rockchip_tsadc_chip - hold the private data of tsadc chip + * @chn_id[SOC_MAX_SENSORS]: the sensor id of chip correspond to the channel + * @chn_num: the channel number of tsadc chip + * @tshut_temp: the hardware-controlled shutdown temperature value + * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) + * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) + * @initialize: SoC special initialize tsadc controller method + * @irq_ack: clear the interrupt + * @get_temp: get the temperature + * @set_alarm_temp: set the high temperature interrupt + * @set_tshut_temp: set the hardware-controlled shutdown temperature + * @set_tshut_mode: set the hardware-controlled shutdown mode + * @table: the chip-specific conversion table + */ struct rockchip_tsadc_chip { /* The sensor id of chip correspond to the ADC channel */ int chn_id[SOC_MAX_SENSORS]; @@ -107,6 +120,8 @@ struct rockchip_tsadc_chip { /* Per-sensor methods */ int (*get_temp)(struct chip_tsadc_table table, int chn, void __iomem *reg, int *temp); + void (*set_alarm_temp)(struct chip_tsadc_table table, + int chn, void __iomem *reg, int temp); void (*set_tshut_temp)(struct chip_tsadc_table table, int chn, void __iomem *reg, int temp); void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); @@ -115,12 +130,32 @@ struct rockchip_tsadc_chip { struct chip_tsadc_table table; }; +/** + * struct rockchip_thermal_sensor - hold the information of thermal sensor + * @thermal: pointer to the platform/configuration data + * @tzd: pointer to a thermal zone + * @id: identifier of the thermal sensor + */ struct rockchip_thermal_sensor { struct rockchip_thermal_data *thermal; struct thermal_zone_device *tzd; int id; }; +/** + * struct rockchip_thermal_data - hold the private data of thermal driver + * @chip: pointer to the platform/configuration data + * @pdev: platform device of thermal + * @reset: the reset controller of tsadc + * @sensors[SOC_MAX_SENSORS]: the thermal sensor + * @clk: the controller clock is divided by the exteral 24MHz + * @pclk: the advanced peripherals bus clock + * @grf: the general register file will be used to do static set by software + * @regs: the base address of tsadc controller + * @tshut_temp: the hardware-controlled shutdown temperature value + * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) + * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) + */ struct rockchip_thermal_data { const struct rockchip_tsadc_chip *chip; struct platform_device *pdev; @@ -146,10 +181,12 @@ struct rockchip_thermal_data { * TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399) * */ +#define TSADCV2_USER_CON 0x00 #define TSADCV2_AUTO_CON 0x04 #define TSADCV2_INT_EN 0x08 #define TSADCV2_INT_PD 0x0c #define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) +#define TSADCV2_COMP_INT(chn) (0x30 + (chn) * 0x04) #define TSADCV2_COMP_SHUT(chn) (0x40 + (chn) * 0x04) #define TSADCV2_HIGHT_INT_DEBOUNCE 0x60 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE 0x64 @@ -159,12 +196,7 @@ struct rockchip_thermal_data { #define TSADCV2_AUTO_EN BIT(0) #define TSADCV2_AUTO_SRC_EN(chn) BIT(4 + (chn)) #define TSADCV2_AUTO_TSHUT_POLARITY_HIGH BIT(8) -/** - * TSADCV1_AUTO_Q_SEL_EN: - * whether select (1024 - tsadc_q) as output - * 1'b0:use tsadc_q as output(temperature-code is rising sequence) - * 1'b1:use(1024 - tsadc_q) as output (temperature-code is falling sequence) - */ + #define TSADCV3_AUTO_Q_SEL_EN BIT(1) #define TSADCV2_INT_SRC_EN(chn) BIT(chn) @@ -179,30 +211,37 @@ struct rockchip_thermal_data { #define TSADCV2_HIGHT_INT_DEBOUNCE_COUNT 4 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT 4 -#define TSADCV2_AUTO_PERIOD_TIME 250 /* msec */ -#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* msec */ +#define TSADCV2_AUTO_PERIOD_TIME 250 /* 250ms */ +#define TSADCV2_AUTO_PERIOD_HT_TIME 50 /* 50ms */ +#define TSADCV3_AUTO_PERIOD_TIME 1875 /* 2.5ms */ +#define TSADCV3_AUTO_PERIOD_HT_TIME 1875 /* 2.5ms */ + +#define TSADCV2_USER_INTER_PD_SOC 0x340 /* 13 clocks */ #define GRF_SARADC_TESTBIT 0x0e644 #define GRF_TSADC_TESTBIT_L 0x0e648 #define GRF_TSADC_TESTBIT_H 0x0e64c -#define GRF_TSADC_TSEN_PD_ON (0x30003 << 0) -#define GRF_TSADC_TSEN_PD_OFF (0x30000 << 0) #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) - -struct tsadc_table { - u32 code; - int temp; -}; +#define GRF_TSADC_VCM_EN_L (0x10001 << 7) +#define GRF_TSADC_VCM_EN_H (0x10001 << 7) /** + * struct tsadc_table - code to temperature conversion table + * @code: the value of adc channel + * @temp: the temperature * Note: - * Code to Temperature mapping of the Temperature sensor is a piece wise linear + * code to temperature mapping of the temperature sensor is a piece wise linear * curve.Any temperature, code faling between to 2 give temperatures can be * linearly interpolated. - * Code to Temperature mapping should be updated based on sillcon results. + * Code to Temperature mapping should be updated based on manufacturer results. */ +struct tsadc_table { + u32 code; + int temp; +}; + static const struct tsadc_table rk3228_code_table[] = { {0, -40000}, {588, -40000}, @@ -280,6 +319,44 @@ static const struct tsadc_table rk3288_code_table[] = { {3421, 125000}, }; +static const struct tsadc_table rk3328_code_table[] = { + {0, -40000}, + {296, -40000}, + {304, -35000}, + {313, -30000}, + {331, -20000}, + {340, -15000}, + {349, -10000}, + {359, -5000}, + {368, 0}, + {378, 5000}, + {388, 10000}, + {398, 15000}, + {408, 20000}, + {418, 25000}, + {429, 30000}, + {440, 35000}, + {451, 40000}, + {462, 45000}, + {473, 50000}, + {485, 55000}, + {496, 60000}, + {508, 65000}, + {521, 70000}, + {533, 75000}, + {546, 80000}, + {559, 85000}, + {572, 90000}, + {586, 95000}, + {600, 100000}, + {614, 105000}, + {629, 110000}, + {644, 115000}, + {659, 120000}, + {675, 125000}, + {TSADCV2_DATA_MASK, 125000}, +}; + static const struct tsadc_table rk3368_code_table[] = { {0, -40000}, {106, -40000}, @@ -362,13 +439,15 @@ static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, int temp) { int high, low, mid; + u32 error = table.data_mask; low = 0; high = table.length - 1; mid = (high + low) / 2; + /* Return mask code data when the temp is over table range */ if (temp < table.id[low].temp || temp > table.id[high].temp) - return 0; + goto exit; while (low <= high) { if (temp == table.id[mid].temp) @@ -380,7 +459,11 @@ static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, mid = (low + high) / 2; } - return 0; +exit: + pr_err("%s: Invalid conversion table: code=%d, temperature=%d\n", + __func__, error, temp); + + return error; } static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, @@ -418,8 +501,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, return -EAGAIN; /* Incorrect reading */ while (low <= high) { - if (code >= table.id[mid - 1].code && - code < table.id[mid].code) + if (code <= table.id[mid].code && + code > table.id[mid - 1].code) break; else if (code > table.id[mid].code) low = mid + 1; @@ -430,7 +513,8 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, } break; default: - pr_err("Invalid the conversion table\n"); + pr_err("%s: Invalid the conversion table mode=%d\n", + __func__, table.mode); } /* @@ -479,15 +563,11 @@ static void rk_tsadcv2_initialize(struct regmap *grf, void __iomem *regs, regs + TSADCV2_AUTO_PERIOD_HT); writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); - - if (IS_ERR(grf)) { - pr_warn("%s: Missing rockchip,grf property\n", __func__); - return; - } } /** * rk_tsadcv3_initialize - initialize TASDC Controller. + * * (1) The tsadc control power sequence. * * (2) Set TSADC_V2_AUTO_PERIOD: @@ -505,19 +585,38 @@ static void rk_tsadcv2_initialize(struct regmap *grf, void __iomem *regs, static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, enum tshut_polarity tshut_polarity) { + /* The tsadc control power sequence */ if (IS_ERR(grf)) { - pr_warn("%s: Missing rockchip,grf property\n", __func__); - return; - } + /* Set interleave value to workround ic time sync issue */ + writel_relaxed(TSADCV2_USER_INTER_PD_SOC, regs + + TSADCV2_USER_CON); + + writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_INT_DEBOUNCE); + writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, + regs + TSADCV2_AUTO_PERIOD_HT); + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); - /* The tsadc control power sequence */ - regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_ON); - mdelay(10); - regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_OFF); - udelay(100); /* The spec note says at least 15 us */ - regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON); - regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON); - udelay(200); /* The spec note says at least 90 us */ + } else { + /* Enable the voltage common mode feature */ + regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_VCM_EN_L); + regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_VCM_EN_H); + + udelay(100); /* The spec note says at least 15 us */ + regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON); + regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON); + udelay(200); /* The spec note says at least 90 us */ + + writel_relaxed(TSADCV3_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); + writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_INT_DEBOUNCE); + writel_relaxed(TSADCV3_AUTO_PERIOD_HT_TIME, + regs + TSADCV2_AUTO_PERIOD_HT); + writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, + regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); + } if (tshut_polarity == TSHUT_HIGH_ACTIVE) writel_relaxed(0U | TSADCV2_AUTO_TSHUT_POLARITY_HIGH, @@ -525,14 +624,6 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, else writel_relaxed(0U & ~TSADCV2_AUTO_TSHUT_POLARITY_HIGH, regs + TSADCV2_AUTO_CON); - - writel_relaxed(TSADCV2_AUTO_PERIOD_TIME, regs + TSADCV2_AUTO_PERIOD); - writel_relaxed(TSADCV2_HIGHT_INT_DEBOUNCE_COUNT, - regs + TSADCV2_HIGHT_INT_DEBOUNCE); - writel_relaxed(TSADCV2_AUTO_PERIOD_HT_TIME, - regs + TSADCV2_AUTO_PERIOD_HT); - writel_relaxed(TSADCV2_HIGHT_TSHUT_DEBOUNCE_COUNT, - regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); } static void rk_tsadcv2_irq_ack(void __iomem *regs) @@ -565,10 +656,11 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable) } /** - * @rk_tsadcv3_control: - * TSADC controller works at auto mode, and some SoCs need set the tsadc_q_sel - * bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output adc value if - * setting this bit to enable. + * rk_tsadcv3_control - the tsadc controller is enabled or disabled. + * + * NOTE: TSADC controller works at auto mode, and some SoCs need set the + * tsadc_q_sel bit on TSADCV2_AUTO_CON[1]. The (1024 - tsadc_q) as output + * adc value if setting this bit to enable. */ static void rk_tsadcv3_control(void __iomem *regs, bool enable) { @@ -593,12 +685,34 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, return rk_tsadcv2_code_to_temp(table, val, temp); } +static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table, + int chn, void __iomem *regs, int temp) +{ + u32 alarm_value, int_en; + + /* Make sure the value is valid */ + alarm_value = rk_tsadcv2_temp_to_code(table, temp); + if (alarm_value == table.data_mask) + return; + + writel_relaxed(alarm_value & table.data_mask, + regs + TSADCV2_COMP_INT(chn)); + + int_en = readl_relaxed(regs + TSADCV2_INT_EN); + int_en |= TSADCV2_INT_SRC_EN(chn); + writel_relaxed(int_en, regs + TSADCV2_INT_EN); +} + static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table, int chn, void __iomem *regs, int temp) { u32 tshut_value, val; + /* Make sure the value is valid */ tshut_value = rk_tsadcv2_temp_to_code(table, temp); + if (tshut_value == table.data_mask) + return; + writel_relaxed(tshut_value, regs + TSADCV2_COMP_SHUT(chn)); /* TSHUT will be valid */ @@ -635,6 +749,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = { .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -659,6 +774,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { .irq_ack = rk_tsadcv2_irq_ack, .control = rk_tsadcv2_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -670,6 +786,54 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { }, }; +static const struct rockchip_tsadc_chip rk3328_tsadc_data = { + .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ + .chn_num = 1, /* one channels for tsadc */ + + .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv2_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = { + .id = rk3328_code_table, + .length = ARRAY_SIZE(rk3328_code_table), + .data_mask = TSADCV2_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + +static const struct rockchip_tsadc_chip rk3366_tsadc_data = { + .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ + .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ + .chn_num = 2, /* two channels for tsadc */ + + .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ + .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv3_initialize, + .irq_ack = rk_tsadcv3_irq_ack, + .control = rk_tsadcv3_control, + .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, + .set_tshut_temp = rk_tsadcv2_tshut_temp, + .set_tshut_mode = rk_tsadcv2_tshut_mode, + + .table = { + .id = rk3228_code_table, + .length = ARRAY_SIZE(rk3228_code_table), + .data_mask = TSADCV3_DATA_MASK, + .mode = ADC_INCREMENT, + }, +}; + static const struct rockchip_tsadc_chip rk3368_tsadc_data = { .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ .chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */ @@ -683,6 +847,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = { .irq_ack = rk_tsadcv2_irq_ack, .control = rk_tsadcv2_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -707,6 +872,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, + .set_alarm_temp = rk_tsadcv2_alarm_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -727,6 +893,14 @@ static const struct of_device_id of_rockchip_thermal_match[] = { .compatible = "rockchip,rk3288-tsadc", .data = (void *)&rk3288_tsadc_data, }, + { + .compatible = "rockchip,rk3328-tsadc", + .data = (void *)&rk3328_tsadc_data, + }, + { + .compatible = "rockchip,rk3366-tsadc", + .data = (void *)&rk3366_tsadc_data, + }, { .compatible = "rockchip,rk3368-tsadc", .data = (void *)&rk3368_tsadc_data, @@ -763,6 +937,21 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev) return IRQ_HANDLED; } +static int rockchip_thermal_set_trips(void *_sensor, int low, int high) +{ + struct rockchip_thermal_sensor *sensor = _sensor; + struct rockchip_thermal_data *thermal = sensor->thermal; + const struct rockchip_tsadc_chip *tsadc = thermal->chip; + + dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n", + __func__, sensor->id, low, high); + + tsadc->set_alarm_temp(tsadc->table, + sensor->id, thermal->regs, high); + + return 0; +} + static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) { struct rockchip_thermal_sensor *sensor = _sensor; @@ -780,6 +969,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp) static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = { .get_temp = rockchip_thermal_get_temp, + .set_trips = rockchip_thermal_set_trips, }; static int rockchip_configure_from_dt(struct device *dev, @@ -839,6 +1029,8 @@ static int rockchip_configure_from_dt(struct device *dev, * need this property. */ thermal->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf"); + if (IS_ERR(thermal->grf)) + dev_warn(dev, "Missing rockchip,grf property\n"); return 0; } @@ -858,8 +1050,8 @@ rockchip_thermal_register_sensor(struct platform_device *pdev, sensor->thermal = thermal; sensor->id = id; - sensor->tzd = thermal_zone_of_sensor_register(&pdev->dev, id, sensor, - &rockchip_of_thermal_ops); + sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, id, + sensor, &rockchip_of_thermal_ops); if (IS_ERR(sensor->tzd)) { error = PTR_ERR(sensor->tzd); dev_err(&pdev->dev, "failed to register sensor %d: %d\n", @@ -880,6 +1072,48 @@ static void rockchip_thermal_reset_controller(struct reset_control *reset) reset_control_deassert(reset); } +static struct platform_device *thermal_device; + +void rockchip_dump_temperature(void) +{ + struct rockchip_thermal_data *thermal; + struct platform_device *pdev; + int i; + + if (!thermal_device) + return; + + pdev = thermal_device; + thermal = platform_get_drvdata(pdev); + + for (i = 0; i < thermal->chip->chn_num; i++) { + struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; + struct thermal_zone_device *tz = sensor->tzd; + + if (tz->temperature != THERMAL_TEMP_INVALID) + dev_warn(&pdev->dev, "channal %d: temperature(%d C)\n", + i, tz->temperature / 1000); + } + + if (thermal->regs) { + pr_warn("THERMAL REGS:\n"); + print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, + 32, 4, thermal->regs, 0x88, false); + } +} +EXPORT_SYMBOL_GPL(rockchip_dump_temperature); + +static int rockchip_thermal_panic(struct notifier_block *this, + unsigned long ev, void *ptr) +{ + rockchip_dump_temperature(); + return NOTIFY_DONE; +} + +static struct notifier_block rockchip_thermal_panic_block = { + .notifier_call = rockchip_thermal_panic, +}; + static int rockchip_thermal_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; @@ -887,7 +1121,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) const struct of_device_id *match; struct resource *res; int irq; - int i, j; + int i; int error; match = of_match_node(of_rockchip_thermal_match, np); @@ -971,9 +1205,6 @@ static int rockchip_thermal_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to register sensor[%d] : error = %d\n", i, error); - for (j = 0; j < i; j++) - thermal_zone_of_sensor_unregister(&pdev->dev, - thermal->sensors[j].tzd); goto err_disable_pclk; } } @@ -985,7 +1216,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev) if (error) { dev_err(&pdev->dev, "failed to request tsadc irq: %d\n", error); - goto err_unregister_sensor; + goto err_disable_pclk; } thermal->chip->control(thermal->regs, true); @@ -995,12 +1226,12 @@ static int rockchip_thermal_probe(struct platform_device *pdev) platform_set_drvdata(pdev, thermal); - return 0; + thermal_device = pdev; + + atomic_notifier_chain_register(&panic_notifier_list, + &rockchip_thermal_panic_block); -err_unregister_sensor: - while (i--) - thermal_zone_of_sensor_unregister(&pdev->dev, - thermal->sensors[i].tzd); + return 0; err_disable_pclk: clk_disable_unprepare(thermal->pclk); @@ -1019,7 +1250,6 @@ static int rockchip_thermal_remove(struct platform_device *pdev) struct rockchip_thermal_sensor *sensor = &thermal->sensors[i]; rockchip_thermal_toggle_sensor(sensor, false); - thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); } thermal->chip->control(thermal->regs, false); @@ -1061,8 +1291,10 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) return error; error = clk_enable(thermal->pclk); - if (error) + if (error) { + clk_disable(thermal->clk); return error; + } rockchip_thermal_reset_controller(thermal->reset);