From a92db1c8089e82b7524545d15b6d6ee6cee67965 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 30 Nov 2015 12:42:32 +0100 Subject: thermal: Add Mediatek thermal controller support This adds support for the Mediatek thermal controller found on MT8173 and likely other SoCs. The controller is a bit special. It does not have its own ADC, instead it controls the on-SoC AUXADC via AHB bus accesses. For this reason we need the physical address of the AUXADC. Also it controls a mux using AHB bus accesses, so we need the APMIXEDSYS physical address aswell. Signed-off-by: Sascha Hauer Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 8 + drivers/thermal/Makefile | 1 + drivers/thermal/mtk_thermal.c | 623 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 632 insertions(+) create mode 100644 drivers/thermal/mtk_thermal.c (limited to 'drivers/thermal') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 7c92c09be213..5e7c97a3f1d8 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -365,6 +365,14 @@ config INTEL_PCH_THERMAL Thermal reporting device will provide temperature reading, programmable trip points and other information. +config MTK_THERMAL + tristate "Temperature sensor driver for mediatek SoCs" + depends on ARCH_MEDIATEK || COMPILE_TEST + default y + help + Enable this option if you want to have support for thermal management + controller present in Mediatek SoCs + menu "Texas Instruments thermal drivers" depends on ARCH_HAS_BANDGAP || COMPILE_TEST source "drivers/thermal/ti-soc-thermal/Kconfig" diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index cfae6a654793..8e9cbc3b5679 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o obj-$(CONFIG_ST_THERMAL) += st/ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra_soctherm.o obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o +obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c new file mode 100644 index 000000000000..589a138368ee --- /dev/null +++ b/drivers/thermal/mtk_thermal.c @@ -0,0 +1,623 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Hanyi Wu + * Sascha Hauer + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* AUXADC Registers */ +#define AUXADC_CON0_V 0x000 +#define AUXADC_CON1_V 0x004 +#define AUXADC_CON1_SET_V 0x008 +#define AUXADC_CON1_CLR_V 0x00c +#define AUXADC_CON2_V 0x010 +#define AUXADC_DATA(channel) (0x14 + (channel) * 4) +#define AUXADC_MISC_V 0x094 + +#define AUXADC_CON1_CHANNEL(x) BIT(x) + +#define APMIXED_SYS_TS_CON1 0x604 + +/* Thermal Controller Registers */ +#define TEMP_MONCTL0 0x000 +#define TEMP_MONCTL1 0x004 +#define TEMP_MONCTL2 0x008 +#define TEMP_MONIDET0 0x014 +#define TEMP_MONIDET1 0x018 +#define TEMP_MSRCTL0 0x038 +#define TEMP_AHBPOLL 0x040 +#define TEMP_AHBTO 0x044 +#define TEMP_ADCPNP0 0x048 +#define TEMP_ADCPNP1 0x04c +#define TEMP_ADCPNP2 0x050 +#define TEMP_ADCPNP3 0x0b4 + +#define TEMP_ADCMUX 0x054 +#define TEMP_ADCEN 0x060 +#define TEMP_PNPMUXADDR 0x064 +#define TEMP_ADCMUXADDR 0x068 +#define TEMP_ADCENADDR 0x074 +#define TEMP_ADCVALIDADDR 0x078 +#define TEMP_ADCVOLTADDR 0x07c +#define TEMP_RDCTRL 0x080 +#define TEMP_ADCVALIDMASK 0x084 +#define TEMP_ADCVOLTAGESHIFT 0x088 +#define TEMP_ADCWRITECTRL 0x08c +#define TEMP_MSR0 0x090 +#define TEMP_MSR1 0x094 +#define TEMP_MSR2 0x098 +#define TEMP_MSR3 0x0B8 + +#define TEMP_SPARE0 0x0f0 + +#define PTPCORESEL 0x400 + +#define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff) + +#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff)) << 16 +#define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff) + +#define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x) + +#define TEMP_ADCWRITECTRL_ADC_PNP_WRITE BIT(0) +#define TEMP_ADCWRITECTRL_ADC_MUX_WRITE BIT(1) + +#define TEMP_ADCVALIDMASK_VALID_HIGH BIT(5) +#define TEMP_ADCVALIDMASK_VALID_POS(bit) (bit) + +#define MT8173_TS1 0 +#define MT8173_TS2 1 +#define MT8173_TS3 2 +#define MT8173_TS4 3 +#define MT8173_TSABB 4 + +/* AUXADC channel 11 is used for the temperature sensors */ +#define MT8173_TEMP_AUXADC_CHANNEL 11 + +/* The total number of temperature sensors in the MT8173 */ +#define MT8173_NUM_SENSORS 5 + +/* The number of banks in the MT8173 */ +#define MT8173_NUM_ZONES 4 + +/* The number of sensing points per bank */ +#define MT8173_NUM_SENSORS_PER_ZONE 4 + +/* Layout of the fuses providing the calibration data */ +#define MT8173_CALIB_BUF0_VALID (1 << 0) +#define MT8173_CALIB_BUF1_ADC_GE(x) (((x) >> 22 ) & 0x3ff) +#define MT8173_CALIB_BUF0_VTS_TS1(x) (((x) >> 17 ) & 0x1ff) +#define MT8173_CALIB_BUF0_VTS_TS2(x) (((x) >> 8 ) & 0x1ff) +#define MT8173_CALIB_BUF1_VTS_TS3(x) (((x) >> 0 ) & 0x1ff) +#define MT8173_CALIB_BUF2_VTS_TS4(x) (((x) >> 23 ) & 0x1ff) +#define MT8173_CALIB_BUF2_VTS_TSABB(x) (((x) >> 14 ) & 0x1ff) +#define MT8173_CALIB_BUF0_DEGC_CALI(x) (((x) >> 1 ) & 0x3f) +#define MT8173_CALIB_BUF0_O_SLOPE(x) (((x) >> 26 ) & 0x3f) + +#define THERMAL_NAME "mtk-thermal" + +struct mtk_thermal; + +struct mtk_thermal_bank { + struct mtk_thermal *mt; + int id; +}; + +struct mtk_thermal { + struct device *dev; + void __iomem *thermal_base; + + struct clk *clk_peri_therm; + struct clk *clk_auxadc; + + struct mtk_thermal_bank banks[MT8173_NUM_ZONES]; + + struct mutex lock; + + /* Calibration values */ + s32 adc_ge; + s32 degc_cali; + s32 o_slope; + s32 vts[MT8173_NUM_SENSORS]; + + struct thermal_zone_device *tzd; +}; + +struct mtk_thermal_bank_cfg { + unsigned int num_sensors; + unsigned int sensors[MT8173_NUM_SENSORS_PER_ZONE]; +}; + +static const int sensor_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 }; + +/* + * The MT8173 thermal controller has four banks. Each bank can read up to + * four temperature sensors simultaneously. The MT8173 has a total of 5 + * temperature sensors. We use each bank to measure a certain area of the + * SoC. Since TS2 is located centrally in the SoC it is influenced by multiple + * areas, hence is used in different banks. + * + * The thermal core only gets the maximum temperature of all banks, so + * the bank concept wouldn't be necessary here. However, the SVS (Smart + * Voltage Scaling) unit makes its decisions based on the same bank + * data, and this indeed needs the temperatures of the individual banks + * for making better decisions. + */ +static const struct mtk_thermal_bank_cfg bank_data[] = { + { + .num_sensors = 2, + .sensors = { MT8173_TS2, MT8173_TS3 }, + }, { + .num_sensors = 2, + .sensors = { MT8173_TS2, MT8173_TS4 }, + }, { + .num_sensors = 3, + .sensors = { MT8173_TS1, MT8173_TS2, MT8173_TSABB }, + }, { + .num_sensors = 1, + .sensors = { MT8173_TS2 }, + }, +}; + +struct mtk_thermal_sense_point { + int msr; + int adcpnp; +}; + +static const struct mtk_thermal_sense_point + sensing_points[MT8173_NUM_SENSORS_PER_ZONE] = { + { + .msr = TEMP_MSR0, + .adcpnp = TEMP_ADCPNP0, + }, { + .msr = TEMP_MSR1, + .adcpnp = TEMP_ADCPNP1, + }, { + .msr = TEMP_MSR2, + .adcpnp = TEMP_ADCPNP2, + }, { + .msr = TEMP_MSR3, + .adcpnp = TEMP_ADCPNP3, + }, +}; + +/** + * raw_to_mcelsius - convert a raw ADC value to mcelsius + * @mt: The thermal controller + * @raw: raw ADC value + * + * This converts the raw ADC value to mcelsius using the SoC specific + * calibration constants + */ +static int raw_to_mcelsius(struct mtk_thermal *mt, int sensno, s32 raw) +{ + s32 tmp; + + raw &= 0xfff; + + tmp = 203450520 << 3; + tmp /= 165 + mt->o_slope; + tmp /= 10000 + mt->adc_ge; + tmp *= raw - mt->vts[sensno] - 3350; + tmp >>= 3; + + return mt->degc_cali * 500 - tmp; +} + +/** + * mtk_thermal_get_bank - get bank + * @bank: The bank + * + * The bank registers are banked, we have to select a bank in the + * PTPCORESEL register to access it. + */ +static void mtk_thermal_get_bank(struct mtk_thermal_bank *bank) +{ + struct mtk_thermal *mt = bank->mt; + u32 val; + + mutex_lock(&mt->lock); + + val = readl(mt->thermal_base + PTPCORESEL); + val &= ~0xf; + val |= bank->id; + writel(val, mt->thermal_base + PTPCORESEL); +} + +/** + * mtk_thermal_put_bank - release bank + * @bank: The bank + * + * release a bank previously taken with mtk_thermal_get_bank, + */ +static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank) +{ + struct mtk_thermal *mt = bank->mt; + + mutex_unlock(&mt->lock); +} + +/** + * mtk_thermal_bank_temperature - get the temperature of a bank + * @bank: The bank + * + * The temperature of a bank is considered the maximum temperature of + * the sensors associated to the bank. + */ +static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) +{ + struct mtk_thermal *mt = bank->mt; + int temp, i, max; + u32 raw; + + temp = max = INT_MIN; + + for (i = 0; i < bank_data[bank->id].num_sensors; i++) { + raw = readl(mt->thermal_base + sensing_points[i].msr); + + temp = raw_to_mcelsius(mt, bank_data[bank->id].sensors[i], raw); + + /* + * The first read of a sensor often contains very high bogus + * temperature value. Filter these out so that the system does + * not immediately shut down. + */ + if (temp > 200000) + temp = 0; + + if (temp > max) + max = temp; + } + + return max; +} + +static int mtk_read_temp(void *data, int *temperature) +{ + struct mtk_thermal *mt = data; + int i; + int tempmax = INT_MIN; + + for (i = 0; i < MT8173_NUM_ZONES; i++) { + struct mtk_thermal_bank *bank = &mt->banks[i]; + + mtk_thermal_get_bank(bank); + + tempmax = max(tempmax, mtk_thermal_bank_temperature(bank)); + + mtk_thermal_put_bank(bank); + } + + *temperature = tempmax; + + return 0; +} + +static const struct thermal_zone_of_device_ops mtk_thermal_ops = { + .get_temp = mtk_read_temp, +}; + +static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, + u32 apmixed_phys_base, u32 auxadc_phys_base) +{ + struct mtk_thermal_bank *bank = &mt->banks[num]; + const struct mtk_thermal_bank_cfg *cfg = &bank_data[num]; + int i; + + bank->id = num; + bank->mt = mt; + + mtk_thermal_get_bank(bank); + + /* bus clock 66M counting unit is 12 * 15.15ns * 256 = 46.540us */ + writel(TEMP_MONCTL1_PERIOD_UNIT(12), mt->thermal_base + TEMP_MONCTL1); + + /* + * filt interval is 1 * 46.540us = 46.54us, + * sen interval is 429 * 46.540us = 19.96ms + */ + writel(TEMP_MONCTL2_FILTER_INTERVAL(1) | + TEMP_MONCTL2_SENSOR_INTERVAL(429), + mt->thermal_base + TEMP_MONCTL2); + + /* poll is set to 10u */ + writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768), + mt->thermal_base + TEMP_AHBPOLL); + + /* temperature sampling control, 1 sample */ + writel(0x0, mt->thermal_base + TEMP_MSRCTL0); + + /* exceed this polling time, IRQ would be inserted */ + writel(0xffffffff, mt->thermal_base + TEMP_AHBTO); + + /* number of interrupts per event, 1 is enough */ + writel(0x0, mt->thermal_base + TEMP_MONIDET0); + writel(0x0, mt->thermal_base + TEMP_MONIDET1); + + /* + * The MT8173 thermal controller does not have its own ADC. Instead it + * uses AHB bus accesses to control the AUXADC. To do this the thermal + * controller has to be programmed with the physical addresses of the + * AUXADC registers and with the various bit positions in the AUXADC. + * Also the thermal controller controls a mux in the APMIXEDSYS register + * space. + */ + + /* + * this value will be stored to TEMP_PNPMUXADDR (TEMP_SPARE0) + * automatically by hw + */ + writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCMUX); + + /* AHB address for auxadc mux selection */ + writel(auxadc_phys_base + AUXADC_CON1_CLR_V, + mt->thermal_base + TEMP_ADCMUXADDR); + + /* AHB address for pnp sensor mux selection */ + writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, + mt->thermal_base + TEMP_PNPMUXADDR); + + /* AHB value for auxadc enable */ + writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN); + + /* AHB address for auxadc enable (channel 0 immediate mode selected) */ + writel(auxadc_phys_base + AUXADC_CON1_SET_V, + mt->thermal_base + TEMP_ADCENADDR); + + /* AHB address for auxadc valid bit */ + writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL), + mt->thermal_base + TEMP_ADCVALIDADDR); + + /* AHB address for auxadc voltage output */ + writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL), + mt->thermal_base + TEMP_ADCVOLTADDR); + + /* read valid & voltage are at the same register */ + writel(0x0, mt->thermal_base + TEMP_RDCTRL); + + /* indicate where the valid bit is */ + writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12), + mt->thermal_base + TEMP_ADCVALIDMASK); + + /* no shift */ + writel(0x0, mt->thermal_base + TEMP_ADCVOLTAGESHIFT); + + /* enable auxadc mux write transaction */ + writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE, + mt->thermal_base + TEMP_ADCWRITECTRL); + + for (i = 0; i < cfg->num_sensors; i++) + writel(sensor_mux_values[cfg->sensors[i]], + mt->thermal_base + sensing_points[i].adcpnp); + + writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0); + + writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE | TEMP_ADCWRITECTRL_ADC_MUX_WRITE, + mt->thermal_base + TEMP_ADCWRITECTRL); + + mtk_thermal_put_bank(bank); +} + +static u64 of_get_phys_base(struct device_node *np) +{ + u64 size64; + const __be32 *regaddr_p; + + regaddr_p = of_get_address(np, 0, &size64, NULL); + if (!regaddr_p) + return OF_BAD_ADDR; + + return of_translate_address(np, regaddr_p); +} + +static int mtk_thermal_get_calibration_data(struct device *dev, struct mtk_thermal *mt) +{ + struct nvmem_cell *cell; + u32 *buf; + size_t len; + int i, ret = 0; + + /* Start with default values */ + mt->adc_ge = 512; + for (i = 0; i < MT8173_NUM_SENSORS; i++) + mt->vts[i] = 260; + mt->degc_cali = 40; + mt->o_slope = 0; + + cell = nvmem_cell_get(dev, "calibration-data"); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) + return PTR_ERR(cell); + return 0; + } + + buf = (u32 *)nvmem_cell_read(cell, &len); + + nvmem_cell_put(cell); + + if (IS_ERR(buf)) + return PTR_ERR(buf); + + if (len < 3 * sizeof(u32)) { + dev_warn(dev, "invalid calibration data\n"); + ret = -EINVAL; + goto out; + } + + if (buf[0] & MT8173_CALIB_BUF0_VALID) { + mt->adc_ge = MT8173_CALIB_BUF1_ADC_GE(buf[1]); + mt->vts[MT8173_TS1] = MT8173_CALIB_BUF0_VTS_TS1(buf[0]); + mt->vts[MT8173_TS2] = MT8173_CALIB_BUF0_VTS_TS2(buf[0]); + mt->vts[MT8173_TS3] = MT8173_CALIB_BUF1_VTS_TS3(buf[1]); + mt->vts[MT8173_TS4] = MT8173_CALIB_BUF2_VTS_TS4(buf[2]); + mt->vts[MT8173_TSABB] = MT8173_CALIB_BUF2_VTS_TSABB(buf[2]); + mt->degc_cali = MT8173_CALIB_BUF0_DEGC_CALI(buf[0]); + mt->o_slope = MT8173_CALIB_BUF0_O_SLOPE(buf[0]); + } else { + dev_info(dev, "Device not calibrated, using default calibration values\n"); + } + +out: + kfree(buf); + + return ret; +} + +static int mtk_thermal_probe(struct platform_device *pdev) +{ + int ret, i; + struct device_node *auxadc, *apmixedsys, *np = pdev->dev.of_node; + struct mtk_thermal *mt; + struct resource *res; + u64 auxadc_phys_base, apmixed_phys_base; + + mt = devm_kzalloc(&pdev->dev, sizeof(*mt), GFP_KERNEL); + if (!mt) + return -ENOMEM; + + mt->clk_peri_therm = devm_clk_get(&pdev->dev, "therm"); + if (IS_ERR(mt->clk_peri_therm)) + return PTR_ERR(mt->clk_peri_therm); + + mt->clk_auxadc = devm_clk_get(&pdev->dev, "auxadc"); + if (IS_ERR(mt->clk_auxadc)) + return PTR_ERR(mt->clk_auxadc); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mt->thermal_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mt->thermal_base)) + return PTR_ERR(mt->thermal_base); + + ret = mtk_thermal_get_calibration_data(&pdev->dev, mt); + if (ret) + return ret; + + mutex_init(&mt->lock); + + mt->dev = &pdev->dev; + + auxadc = of_parse_phandle(np, "mediatek,auxadc", 0); + if (!auxadc) { + dev_err(&pdev->dev, "missing auxadc node\n"); + return -ENODEV; + } + + auxadc_phys_base = of_get_phys_base(auxadc); + + of_node_put(auxadc); + + if (auxadc_phys_base == OF_BAD_ADDR) { + dev_err(&pdev->dev, "Can't get auxadc phys address\n"); + return -EINVAL; + } + + apmixedsys = of_parse_phandle(np, "mediatek,apmixedsys", 0); + if (!apmixedsys) { + dev_err(&pdev->dev, "missing apmixedsys node\n"); + return -ENODEV; + } + + apmixed_phys_base = of_get_phys_base(apmixedsys); + + of_node_put(apmixedsys); + + if (apmixed_phys_base == OF_BAD_ADDR) { + dev_err(&pdev->dev, "Can't get auxadc phys address\n"); + return -EINVAL; + } + + ret = clk_prepare_enable(mt->clk_auxadc); + if (ret) { + dev_err(&pdev->dev, "Can't enable auxadc clk: %d\n", ret); + return ret; + } + + ret = device_reset(&pdev->dev); + if (ret) + goto err_disable_clk_auxadc; + + ret = clk_prepare_enable(mt->clk_peri_therm); + if (ret) { + dev_err(&pdev->dev, "Can't enable peri clk: %d\n", ret); + goto err_disable_clk_auxadc; + } + + for (i = 0; i < MT8173_NUM_ZONES; i++) + mtk_thermal_init_bank(mt, i, apmixed_phys_base, auxadc_phys_base); + + platform_set_drvdata(pdev, mt); + + mt->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, mt, + &mtk_thermal_ops); + if (IS_ERR(mt->tzd)) + goto err_register; + + return 0; + +err_register: + clk_disable_unprepare(mt->clk_peri_therm); + +err_disable_clk_auxadc: + clk_disable_unprepare(mt->clk_auxadc); + + return ret; +} + +static int mtk_thermal_remove(struct platform_device *pdev) +{ + struct mtk_thermal *mt = platform_get_drvdata(pdev); + + thermal_zone_of_sensor_unregister(&pdev->dev, mt->tzd); + + clk_disable_unprepare(mt->clk_peri_therm); + clk_disable_unprepare(mt->clk_auxadc); + + return 0; +} + +static const struct of_device_id mtk_thermal_of_match[] = { + { + .compatible = "mediatek,mt8173-thermal", + }, { + }, +}; + +static struct platform_driver mtk_thermal_driver = { + .probe = mtk_thermal_probe, + .remove = mtk_thermal_remove, + .driver = { + .name = THERMAL_NAME, + .of_match_table = mtk_thermal_of_match, + }, +}; + +module_platform_driver(mtk_thermal_driver); + +MODULE_AUTHOR("Sascha Hauer "); +MODULE_DESCRIPTION("Mediatek thermal driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-59-g8ed1b From eb4fc33eb2680750e6dc06bd40bf6a203e7ad312 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Thu, 18 Feb 2016 07:43:57 -0800 Subject: thermal: small style cleanup in mtk_thermal Remove all checkpatch.pl --strict errors, checks, and warnings. Cc: Zhang Rui Cc: Matthias Brugger Cc: linux-pm@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Eduardo Valentin --- drivers/thermal/mtk_thermal.c | 56 ++++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 27 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/mtk_thermal.c b/drivers/thermal/mtk_thermal.c index 589a138368ee..3d93b1c07cee 100644 --- a/drivers/thermal/mtk_thermal.c +++ b/drivers/thermal/mtk_thermal.c @@ -78,7 +78,7 @@ #define TEMP_MONCTL1_PERIOD_UNIT(x) ((x) & 0x3ff) -#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff)) << 16 +#define TEMP_MONCTL2_FILTER_INTERVAL(x) (((x) & 0x3ff) << 16) #define TEMP_MONCTL2_SENSOR_INTERVAL(x) ((x) & 0x3ff) #define TEMP_AHBPOLL_ADC_POLL_INTERVAL(x) (x) @@ -108,15 +108,15 @@ #define MT8173_NUM_SENSORS_PER_ZONE 4 /* Layout of the fuses providing the calibration data */ -#define MT8173_CALIB_BUF0_VALID (1 << 0) -#define MT8173_CALIB_BUF1_ADC_GE(x) (((x) >> 22 ) & 0x3ff) -#define MT8173_CALIB_BUF0_VTS_TS1(x) (((x) >> 17 ) & 0x1ff) -#define MT8173_CALIB_BUF0_VTS_TS2(x) (((x) >> 8 ) & 0x1ff) -#define MT8173_CALIB_BUF1_VTS_TS3(x) (((x) >> 0 ) & 0x1ff) -#define MT8173_CALIB_BUF2_VTS_TS4(x) (((x) >> 23 ) & 0x1ff) -#define MT8173_CALIB_BUF2_VTS_TSABB(x) (((x) >> 14 ) & 0x1ff) -#define MT8173_CALIB_BUF0_DEGC_CALI(x) (((x) >> 1 ) & 0x3f) -#define MT8173_CALIB_BUF0_O_SLOPE(x) (((x) >> 26 ) & 0x3f) +#define MT8173_CALIB_BUF0_VALID BIT(0) +#define MT8173_CALIB_BUF1_ADC_GE(x) (((x) >> 22) & 0x3ff) +#define MT8173_CALIB_BUF0_VTS_TS1(x) (((x) >> 17) & 0x1ff) +#define MT8173_CALIB_BUF0_VTS_TS2(x) (((x) >> 8) & 0x1ff) +#define MT8173_CALIB_BUF1_VTS_TS3(x) (((x) >> 0) & 0x1ff) +#define MT8173_CALIB_BUF2_VTS_TS4(x) (((x) >> 23) & 0x1ff) +#define MT8173_CALIB_BUF2_VTS_TSABB(x) (((x) >> 14) & 0x1ff) +#define MT8173_CALIB_BUF0_DEGC_CALI(x) (((x) >> 1) & 0x3f) +#define MT8173_CALIB_BUF0_O_SLOPE(x) (((x) >> 26) & 0x3f) #define THERMAL_NAME "mtk-thermal" @@ -136,6 +136,7 @@ struct mtk_thermal { struct mtk_thermal_bank banks[MT8173_NUM_ZONES]; + /* lock: for getting and putting banks */ struct mutex lock; /* Calibration values */ @@ -271,11 +272,9 @@ static void mtk_thermal_put_bank(struct mtk_thermal_bank *bank) static int mtk_thermal_bank_temperature(struct mtk_thermal_bank *bank) { struct mtk_thermal *mt = bank->mt; - int temp, i, max; + int i, temp = INT_MIN, max = INT_MIN; u32 raw; - temp = max = INT_MIN; - for (i = 0; i < bank_data[bank->id].num_sensors; i++) { raw = readl(mt->thermal_base + sensing_points[i].msr); @@ -322,7 +321,7 @@ static const struct thermal_zone_of_device_ops mtk_thermal_ops = { }; static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, - u32 apmixed_phys_base, u32 auxadc_phys_base) + u32 apmixed_phys_base, u32 auxadc_phys_base) { struct mtk_thermal_bank *bank = &mt->banks[num]; const struct mtk_thermal_bank_cfg *cfg = &bank_data[num]; @@ -346,7 +345,7 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, /* poll is set to 10u */ writel(TEMP_AHBPOLL_ADC_POLL_INTERVAL(768), - mt->thermal_base + TEMP_AHBPOLL); + mt->thermal_base + TEMP_AHBPOLL); /* temperature sampling control, 1 sample */ writel(0x0, mt->thermal_base + TEMP_MSRCTL0); @@ -375,49 +374,50 @@ static void mtk_thermal_init_bank(struct mtk_thermal *mt, int num, /* AHB address for auxadc mux selection */ writel(auxadc_phys_base + AUXADC_CON1_CLR_V, - mt->thermal_base + TEMP_ADCMUXADDR); + mt->thermal_base + TEMP_ADCMUXADDR); /* AHB address for pnp sensor mux selection */ writel(apmixed_phys_base + APMIXED_SYS_TS_CON1, - mt->thermal_base + TEMP_PNPMUXADDR); + mt->thermal_base + TEMP_PNPMUXADDR); /* AHB value for auxadc enable */ writel(BIT(MT8173_TEMP_AUXADC_CHANNEL), mt->thermal_base + TEMP_ADCEN); /* AHB address for auxadc enable (channel 0 immediate mode selected) */ writel(auxadc_phys_base + AUXADC_CON1_SET_V, - mt->thermal_base + TEMP_ADCENADDR); + mt->thermal_base + TEMP_ADCENADDR); /* AHB address for auxadc valid bit */ writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL), - mt->thermal_base + TEMP_ADCVALIDADDR); + mt->thermal_base + TEMP_ADCVALIDADDR); /* AHB address for auxadc voltage output */ writel(auxadc_phys_base + AUXADC_DATA(MT8173_TEMP_AUXADC_CHANNEL), - mt->thermal_base + TEMP_ADCVOLTADDR); + mt->thermal_base + TEMP_ADCVOLTADDR); /* read valid & voltage are at the same register */ writel(0x0, mt->thermal_base + TEMP_RDCTRL); /* indicate where the valid bit is */ writel(TEMP_ADCVALIDMASK_VALID_HIGH | TEMP_ADCVALIDMASK_VALID_POS(12), - mt->thermal_base + TEMP_ADCVALIDMASK); + mt->thermal_base + TEMP_ADCVALIDMASK); /* no shift */ writel(0x0, mt->thermal_base + TEMP_ADCVOLTAGESHIFT); /* enable auxadc mux write transaction */ writel(TEMP_ADCWRITECTRL_ADC_MUX_WRITE, - mt->thermal_base + TEMP_ADCWRITECTRL); + mt->thermal_base + TEMP_ADCWRITECTRL); for (i = 0; i < cfg->num_sensors; i++) writel(sensor_mux_values[cfg->sensors[i]], - mt->thermal_base + sensing_points[i].adcpnp); + mt->thermal_base + sensing_points[i].adcpnp); writel((1 << cfg->num_sensors) - 1, mt->thermal_base + TEMP_MONCTL0); - writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE | TEMP_ADCWRITECTRL_ADC_MUX_WRITE, - mt->thermal_base + TEMP_ADCWRITECTRL); + writel(TEMP_ADCWRITECTRL_ADC_PNP_WRITE | + TEMP_ADCWRITECTRL_ADC_MUX_WRITE, + mt->thermal_base + TEMP_ADCWRITECTRL); mtk_thermal_put_bank(bank); } @@ -434,7 +434,8 @@ static u64 of_get_phys_base(struct device_node *np) return of_translate_address(np, regaddr_p); } -static int mtk_thermal_get_calibration_data(struct device *dev, struct mtk_thermal *mt) +static int mtk_thermal_get_calibration_data(struct device *dev, + struct mtk_thermal *mt) { struct nvmem_cell *cell; u32 *buf; @@ -567,7 +568,8 @@ static int mtk_thermal_probe(struct platform_device *pdev) } for (i = 0; i < MT8173_NUM_ZONES; i++) - mtk_thermal_init_bank(mt, i, apmixed_phys_base, auxadc_phys_base); + mtk_thermal_init_bank(mt, i, apmixed_phys_base, + auxadc_phys_base); platform_set_drvdata(pdev, mt); -- cgit v1.2.3-59-g8ed1b From 43b4eb9fe719b107c8e5d49d1edbff0c135a42cb Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 15 Feb 2016 15:33:28 +0800 Subject: thermal: rockchip: fix a impossible condition caused by the warning As the Dan report the smatch check the thermal driver warning: drivers/thermal/rockchip_thermal.c:551 rockchip_configure_from_dt() warn: impossible condition '(thermal->tshut_temp > ((~0 >> 1))) => (s32min-s32max > s32max)' Although The shut_temp read from DT is u32,the temperature is currently represented as int not long in the thermal driver. Let's change to make shut_temp instead of the thermal->tshut_temp for the condition. Fixes: commit 437df2172e8d ("thermal: rockchip: consistently use int for temperatures") Reported-by: Dan Carpenter Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin --- drivers/thermal/rockchip_thermal.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index b58e3fb9b311..433085a97626 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -693,15 +693,14 @@ static int rockchip_configure_from_dt(struct device *dev, thermal->chip->tshut_temp); thermal->tshut_temp = thermal->chip->tshut_temp; } else { + if (shut_temp > INT_MAX) { + dev_err(dev, "Invalid tshut temperature specified: %d\n", + shut_temp); + return -ERANGE; + } thermal->tshut_temp = shut_temp; } - if (thermal->tshut_temp > INT_MAX) { - dev_err(dev, "Invalid tshut temperature specified: %d\n", - thermal->tshut_temp); - return -ERANGE; - } - if (of_property_read_u32(np, "rockchip,hw-tshut-mode", &tshut_mode)) { dev_warn(dev, "Missing tshut mode property, using default (%s)\n", -- cgit v1.2.3-59-g8ed1b From 1d37a037dd9527df55db68aee80afa73ce40c733 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Mon, 15 Feb 2016 15:33:29 +0800 Subject: thermal: rockchip: fix calculation error for code_to_temp the calculation use a global table, not their own table. so adapt the table to the correct one. Signed-off-by: Elaine Zhang Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin --- drivers/thermal/rockchip_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 433085a97626..5c58d489eaf8 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -411,7 +411,7 @@ static int rk_tsadcv2_code_to_temp(struct chip_tsadc_table table, u32 code, * temperature between 2 table entries is linear and interpolate * to produce less granular result. */ - num = table.id[mid].temp - v2_code_table[mid - 1].temp; + num = table.id[mid].temp - table.id[mid - 1].temp; num *= abs(table.id[mid - 1].code - code); denom = abs(table.id[mid - 1].code - table.id[mid].code); *temp = table.id[mid - 1].temp + (num / denom); -- cgit v1.2.3-59-g8ed1b From 952418a34f26f252cd0afbca8c33a8506a03cab7 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 15 Feb 2016 15:33:30 +0800 Subject: thermal: rockchip: the rename compatibles for rockchip SoCs This patch renames to be more adapter compatibles since more and more SoCs are supported in thermal driver. Reported-by: Huang,Tao Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin --- drivers/thermal/rockchip_thermal.c | 50 +++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 22 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 5c58d489eaf8..9cdef62abcae 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -58,8 +58,8 @@ enum sensor_id { /** * The conversion table has the adc value and temperature. - * ADC_DECREMENT: the adc value is of diminishing.(e.g. v2_code_table) - * ADC_INCREMENT: the adc value is incremental.(e.g. v3_code_table) + * ADC_DECREMENT: the adc value is of diminishing.(e.g. rk3288_code_table) + * ADC_INCREMENT: the adc value is incremental.(e.g. rk3368_code_table) */ enum adc_sort_mode { ADC_DECREMENT = 0, @@ -135,7 +135,13 @@ struct rockchip_thermal_data { enum tshut_polarity tshut_polarity; }; -/* TSADC Sensor info define: */ +/** + * TSADC Sensor Register description: + * + * TSADCV2_* are used for RK3288 SoCs, the other chips can reuse it. + * TSADCV3_* are used for newer SoCs than RK3288. (e.g: RK3228, RK3399) + * + */ #define TSADCV2_AUTO_CON 0x04 #define TSADCV2_INT_EN 0x08 #define TSADCV2_INT_PD 0x0c @@ -154,8 +160,8 @@ struct rockchip_thermal_data { #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) #define TSADCV2_SHUT_2CRU_SRC_EN(chn) BIT(8 + (chn)) -#define TSADCV1_INT_PD_CLEAR_MASK ~BIT(16) #define TSADCV2_INT_PD_CLEAR_MASK ~BIT(8) +#define TSADCV3_INT_PD_CLEAR_MASK ~BIT(16) #define TSADCV2_DATA_MASK 0xfff #define TSADCV3_DATA_MASK 0x3ff @@ -177,7 +183,7 @@ struct tsadc_table { * linearly interpolated. * Code to Temperature mapping should be updated based on sillcon results. */ -static const struct tsadc_table v1_code_table[] = { +static const struct tsadc_table rk3228_code_table[] = { {TSADCV3_DATA_MASK, -40000}, {436, -40000}, {431, -35000}, @@ -215,7 +221,7 @@ static const struct tsadc_table v1_code_table[] = { {264, 125000}, }; -static const struct tsadc_table v2_code_table[] = { +static const struct tsadc_table rk3288_code_table[] = { {TSADCV2_DATA_MASK, -40000}, {3800, -40000}, {3792, -35000}, @@ -253,7 +259,7 @@ static const struct tsadc_table v2_code_table[] = { {3421, 125000}, }; -static const struct tsadc_table v3_code_table[] = { +static const struct tsadc_table rk3368_code_table[] = { {0, -40000}, {106, -40000}, {108, -35000}, @@ -292,7 +298,7 @@ static const struct tsadc_table v3_code_table[] = { {TSADCV3_DATA_MASK, 125000}, }; -static const struct tsadc_table v4_code_table[] = { +static const struct tsadc_table rk3399_code_table[] = { {TSADCV3_DATA_MASK, -40000}, {431, -40000}, {426, -35000}, @@ -453,20 +459,20 @@ static void rk_tsadcv2_initialize(void __iomem *regs, regs + TSADCV2_HIGHT_TSHUT_DEBOUNCE); } -static void rk_tsadcv1_irq_ack(void __iomem *regs) +static void rk_tsadcv2_irq_ack(void __iomem *regs) { u32 val; val = readl_relaxed(regs + TSADCV2_INT_PD); - writel_relaxed(val & TSADCV1_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); + writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); } -static void rk_tsadcv2_irq_ack(void __iomem *regs) +static void rk_tsadcv3_irq_ack(void __iomem *regs) { u32 val; val = readl_relaxed(regs + TSADCV2_INT_PD); - writel_relaxed(val & TSADCV2_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); + writel_relaxed(val & TSADCV3_INT_PD_CLEAR_MASK, regs + TSADCV2_INT_PD); } static void rk_tsadcv2_control(void __iomem *regs, bool enable) @@ -531,15 +537,15 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = { .tshut_temp = 95000, .initialize = rk_tsadcv2_initialize, - .irq_ack = rk_tsadcv1_irq_ack, + .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv2_control, .get_temp = rk_tsadcv2_get_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, .table = { - .id = v1_code_table, - .length = ARRAY_SIZE(v1_code_table), + .id = rk3228_code_table, + .length = ARRAY_SIZE(rk3228_code_table), .data_mask = TSADCV3_DATA_MASK, .mode = ADC_DECREMENT, }, @@ -562,8 +568,8 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = { .set_tshut_mode = rk_tsadcv2_tshut_mode, .table = { - .id = v2_code_table, - .length = ARRAY_SIZE(v2_code_table), + .id = rk3288_code_table, + .length = ARRAY_SIZE(rk3288_code_table), .data_mask = TSADCV2_DATA_MASK, .mode = ADC_DECREMENT, }, @@ -586,8 +592,8 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = { .set_tshut_mode = rk_tsadcv2_tshut_mode, .table = { - .id = v3_code_table, - .length = ARRAY_SIZE(v3_code_table), + .id = rk3368_code_table, + .length = ARRAY_SIZE(rk3368_code_table), .data_mask = TSADCV3_DATA_MASK, .mode = ADC_INCREMENT, }, @@ -603,15 +609,15 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { .tshut_temp = 95000, .initialize = rk_tsadcv2_initialize, - .irq_ack = rk_tsadcv1_irq_ack, + .irq_ack = rk_tsadcv3_irq_ack, .control = rk_tsadcv2_control, .get_temp = rk_tsadcv2_get_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, .table = { - .id = v4_code_table, - .length = ARRAY_SIZE(v4_code_table), + .id = rk3399_code_table, + .length = ARRAY_SIZE(rk3399_code_table), .data_mask = TSADCV3_DATA_MASK, .mode = ADC_DECREMENT, }, -- cgit v1.2.3-59-g8ed1b From 7ea38c6c3622bc65279dc6a1fecd28227027fbb5 Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Mon, 15 Feb 2016 15:33:31 +0800 Subject: thermal: rockchip: fix the tsadc sequence output on rk3228/rk3399 As the TRM says, add the tsadc_q_sel to control the temperature-code sequence since the rk3228/rk3399 need set this bit (1024 - tsadc_q) as output. Fixes: commit b0d7033 "thermal: rockchip: Support the RK3399 SoCs in thermal driver" 7b02a5e "thermal: rockchip: Support the RK3228 SoCs in thermal driver" Reported-by: Elaine Zhang Signed-off-by: Caesar Wang Signed-off-by: Eduardo Valentin --- drivers/thermal/rockchip_thermal.c | 176 +++++++++++++++++++++---------------- 1 file changed, 102 insertions(+), 74 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 9cdef62abcae..233a564442a0 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -155,6 +155,13 @@ 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) #define TSADCV2_SHUT_2GPIO_SRC_EN(chn) BIT(4 + (chn)) @@ -184,41 +191,42 @@ struct tsadc_table { * Code to Temperature mapping should be updated based on sillcon results. */ static const struct tsadc_table rk3228_code_table[] = { - {TSADCV3_DATA_MASK, -40000}, - {436, -40000}, - {431, -35000}, - {426, -30000}, - {421, -25000}, - {416, -20000}, - {411, -15000}, - {406, -10000}, - {401, -5000}, - {395, 0}, - {390, 5000}, - {385, 10000}, - {380, 15000}, - {375, 20000}, - {370, 25000}, - {364, 30000}, - {359, 35000}, - {354, 40000}, - {349, 45000}, - {343, 50000}, - {338, 55000}, - {333, 60000}, - {328, 65000}, - {322, 70000}, - {317, 75000}, - {312, 80000}, - {307, 85000}, - {301, 90000}, - {296, 95000}, - {291, 100000}, - {286, 105000}, - {280, 110000}, - {275, 115000}, - {270, 120000}, - {264, 125000}, + {0, -40000}, + {588, -40000}, + {593, -35000}, + {598, -30000}, + {603, -25000}, + {608, -20000}, + {613, -15000}, + {618, -10000}, + {623, -5000}, + {629, 0}, + {634, 5000}, + {639, 10000}, + {644, 15000}, + {649, 20000}, + {654, 25000}, + {660, 30000}, + {665, 35000}, + {670, 40000}, + {675, 45000}, + {681, 50000}, + {686, 55000}, + {691, 60000}, + {696, 65000}, + {702, 70000}, + {707, 75000}, + {712, 80000}, + {717, 85000}, + {723, 90000}, + {728, 95000}, + {733, 100000}, + {738, 105000}, + {744, 110000}, + {749, 115000}, + {754, 120000}, + {760, 125000}, + {TSADCV2_DATA_MASK, 125000}, }; static const struct tsadc_table rk3288_code_table[] = { @@ -299,41 +307,42 @@ static const struct tsadc_table rk3368_code_table[] = { }; static const struct tsadc_table rk3399_code_table[] = { - {TSADCV3_DATA_MASK, -40000}, - {431, -40000}, - {426, -35000}, - {421, -30000}, - {415, -25000}, - {410, -20000}, - {405, -15000}, - {399, -10000}, - {394, -5000}, - {389, 0}, - {383, 5000}, - {378, 10000}, - {373, 15000}, - {367, 20000}, - {362, 25000}, - {357, 30000}, - {351, 35000}, - {346, 40000}, - {340, 45000}, - {335, 50000}, - {330, 55000}, - {324, 60000}, - {319, 65000}, - {313, 70000}, - {308, 75000}, - {302, 80000}, - {297, 85000}, - {291, 90000}, - {286, 95000}, - {281, 100000}, - {275, 105000}, - {270, 110000}, - {264, 115000}, - {259, 120000}, - {253, 125000}, + {0, -40000}, + {593, -40000}, + {598, -35000}, + {603, -30000}, + {609, -25000}, + {614, -20000}, + {619, -15000}, + {625, -10000}, + {630, -5000}, + {635, 0}, + {641, 5000}, + {646, 10000}, + {651, 15000}, + {657, 20000}, + {662, 25000}, + {667, 30000}, + {673, 35000}, + {678, 40000}, + {684, 45000}, + {689, 50000}, + {694, 55000}, + {700, 60000}, + {705, 65000}, + {711, 70000}, + {716, 75000}, + {722, 80000}, + {727, 85000}, + {733, 90000}, + {738, 95000}, + {743, 100000}, + {749, 105000}, + {754, 110000}, + {760, 115000}, + {765, 120000}, + {771, 125000}, + {TSADCV3_DATA_MASK, 125000}, }; static u32 rk_tsadcv2_temp_to_code(struct chip_tsadc_table table, @@ -488,6 +497,25 @@ static void rk_tsadcv2_control(void __iomem *regs, bool enable) writel_relaxed(val, regs + TSADCV2_AUTO_CON); } +/** + * @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. + */ +static void rk_tsadcv3_control(void __iomem *regs, bool enable) +{ + u32 val; + + val = readl_relaxed(regs + TSADCV2_AUTO_CON); + if (enable) + val |= TSADCV2_AUTO_EN | TSADCV3_AUTO_Q_SEL_EN; + else + val &= ~TSADCV2_AUTO_EN; + + writel_relaxed(val, regs + TSADCV2_AUTO_CON); +} + static int rk_tsadcv2_get_temp(struct chip_tsadc_table table, int chn, void __iomem *regs, int *temp) { @@ -538,7 +566,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = { .initialize = rk_tsadcv2_initialize, .irq_ack = rk_tsadcv3_irq_ack, - .control = rk_tsadcv2_control, + .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -547,7 +575,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = { .id = rk3228_code_table, .length = ARRAY_SIZE(rk3228_code_table), .data_mask = TSADCV3_DATA_MASK, - .mode = ADC_DECREMENT, + .mode = ADC_INCREMENT, }, }; @@ -610,7 +638,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { .initialize = rk_tsadcv2_initialize, .irq_ack = rk_tsadcv3_irq_ack, - .control = rk_tsadcv2_control, + .control = rk_tsadcv3_control, .get_temp = rk_tsadcv2_get_temp, .set_tshut_temp = rk_tsadcv2_tshut_temp, .set_tshut_mode = rk_tsadcv2_tshut_mode, @@ -619,7 +647,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { .id = rk3399_code_table, .length = ARRAY_SIZE(rk3399_code_table), .data_mask = TSADCV3_DATA_MASK, - .mode = ADC_DECREMENT, + .mode = ADC_INCREMENT, }, }; -- cgit v1.2.3-59-g8ed1b From 527860fe4684bf69281d7479c5034243dd6c36c4 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Wed, 14 Oct 2015 19:43:29 +0100 Subject: thermal: db8500_cpufreq_cooling: Compile with COMPILE_TEST This driver only has runtime but no build time dependencies, so it can be built for testing purposes if the Kconfig COMPILE_TEST option is enabled. This is useful to have more build coverage and make sure that drivers are not affected by changes that could cause build regressions. Signed-off-by: Luis de Bethencourt Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 7c92c09be213..5670d2652514 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -266,7 +266,7 @@ config TEGRA_SOCTHERM config DB8500_CPUFREQ_COOLING tristate "DB8500 cpufreq cooling" - depends on ARCH_U8500 + depends on ARCH_U8500 || COMPILE_TEST depends on CPU_THERMAL default y help -- cgit v1.2.3-59-g8ed1b From 67bc3f4226c1d29ee820eff98fcaf8a9283938fe Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 1 Mar 2016 17:38:31 +0100 Subject: thermal: rcar_thermal: don't open code of_device_get_match_data() This change will also make Coverity happy by avoiding a theoretical NULL pointer dereference; yet another reason is to use the above helper function to tighten the code and make it more readable. Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_thermal.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 0e735acea33a..82daba09e150 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -430,8 +430,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) struct rcar_thermal_priv *priv; struct device *dev = &pdev->dev; struct resource *res, *irq; - const struct of_device_id *of_id = of_match_device(rcar_thermal_dt_ids, dev); - unsigned long of_data = (unsigned long)of_id->data; + unsigned long of_data = (unsigned long)of_device_get_match_data(dev); int mres = 0; int i; int ret = -ENODEV; -- cgit v1.2.3-59-g8ed1b From 8255e4e2376189c497cb722fd6aea36b540f7125 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 2 Mar 2016 11:04:26 +0900 Subject: thermal: rcar: Use ARCH_RENESAS Make use of ARCH_RENESAS in place of ARCH_SHMOBILE. This is part of an ongoing process to migrate from ARCH_SHMOBILE to ARCH_RENESAS the motivation for which being that RENESAS seems to be a more appropriate name than SHMOBILE for the majority of Renesas ARM based SoCs. Acked-by: Geert Uytterhoeven Signed-off-by: Simon Horman Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5670d2652514..962ddaf39cae 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -214,7 +214,7 @@ config ROCKCHIP_THERMAL config RCAR_THERMAL tristate "Renesas R-Car thermal driver" - depends on ARCH_SHMOBILE || COMPILE_TEST + depends on ARCH_RENESAS || COMPILE_TEST depends on HAS_IOMEM help Enable this to plug the R-Car thermal sensor driver into the Linux -- cgit v1.2.3-59-g8ed1b From 13369194256a95c5fd63472b0f5abcfd58a284c1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 2 Mar 2016 13:00:55 +0300 Subject: thermal: ti-soc-thermal: clean up the error handling a bit We don't need to initialize "ret". We can move the IS_ERR() checks into the if condition instead of doing an assignment first. Also there is a check for "ret" when we know it is zero so we can remove that. Signed-off-by: Dan Carpenter Signed-off-by: Eduardo Valentin --- drivers/thermal/ti-soc-thermal/ti-bandgap.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/ti-soc-thermal/ti-bandgap.c b/drivers/thermal/ti-soc-thermal/ti-bandgap.c index 1e34a1efc554..06ea9766a70a 100644 --- a/drivers/thermal/ti-soc-thermal/ti-bandgap.c +++ b/drivers/thermal/ti-soc-thermal/ti-bandgap.c @@ -1265,7 +1265,7 @@ static int ti_bandgap_probe(struct platform_device *pdev) { struct ti_bandgap *bgp; - int clk_rate, ret = 0, i; + int clk_rate, ret, i; bgp = ti_bandgap_build(pdev); if (IS_ERR(bgp)) { @@ -1288,16 +1288,14 @@ int ti_bandgap_probe(struct platform_device *pdev) } bgp->fclock = clk_get(NULL, bgp->conf->fclock_name); - ret = IS_ERR(bgp->fclock); - if (ret) { + if (IS_ERR(bgp->fclock)) { dev_err(&pdev->dev, "failed to request fclock reference\n"); ret = PTR_ERR(bgp->fclock); goto free_irqs; } bgp->div_clk = clk_get(NULL, bgp->conf->div_ck_name); - ret = IS_ERR(bgp->div_clk); - if (ret) { + if (IS_ERR(bgp->div_clk)) { dev_err(&pdev->dev, "failed to request div_ts_ck clock ref\n"); ret = PTR_ERR(bgp->div_clk); goto free_irqs; @@ -1314,7 +1312,7 @@ int ti_bandgap_probe(struct platform_device *pdev) * may not be accurate */ val = ti_bandgap_readl(bgp, tsr->bgap_efuse); - if (ret || !val) + if (!val) dev_info(&pdev->dev, "Non-trimmed BGAP, Temp not accurate\n"); } -- cgit v1.2.3-59-g8ed1b From bf82c350e940f5ee3508a94165a99eda81298d5f Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 4 Mar 2016 10:03:59 +0900 Subject: thermal: Fix build error of missing devm_ioremap_resource on UM The devres.o gets linked if HAS_IOMEM is present so on ARCH=um allyesconfig (COMPILE_TEST) failed on many files with: drivers/built-in.o: In function `kirkwood_thermal_probe': kirkwood_thermal.c:(.text+0x390a25): undefined reference to `devm_ioremap_resource' drivers/built-in.o: In function `exynos_tmu_probe': exynos_tmu.c:(.text+0x39246b): undefined reference to `devm_ioremap' The users of devm_ioremap_resource() which are compile-testable should depend on HAS_IOMEM. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 8 ++++++++ drivers/thermal/samsung/Kconfig | 1 + 2 files changed, 9 insertions(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 962ddaf39cae..d1fd2e5d25e2 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -178,6 +178,7 @@ config THERMAL_EMULATION config HISI_THERMAL tristate "Hisilicon thermal driver" depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST + depends on HAS_IOMEM help Enable this to plug hisilicon's thermal sensor driver into the Linux thermal framework. cpufreq is used as the cooling device to throttle @@ -197,6 +198,7 @@ config IMX_THERMAL config SPEAR_THERMAL tristate "SPEAr thermal sensor driver" depends on PLAT_SPEAR || COMPILE_TEST + depends on HAS_IOMEM depends on OF help Enable this to plug the SPEAr thermal sensor driver into the Linux @@ -206,6 +208,7 @@ config ROCKCHIP_THERMAL tristate "Rockchip thermal driver" depends on ARCH_ROCKCHIP || COMPILE_TEST depends on RESET_CONTROLLER + depends on HAS_IOMEM help Rockchip thermal driver provides support for Temperature sensor ADC (TS-ADC) found on Rockchip SoCs. It supports one critical @@ -223,6 +226,7 @@ config RCAR_THERMAL config KIRKWOOD_THERMAL tristate "Temperature sensor on Marvell Kirkwood SoCs" depends on MACH_KIRKWOOD || COMPILE_TEST + depends on HAS_IOMEM depends on OF help Support for the Kirkwood thermal sensor driver into the Linux thermal @@ -231,6 +235,7 @@ config KIRKWOOD_THERMAL config DOVE_THERMAL tristate "Temperature sensor on Marvell Dove SoCs" depends on ARCH_DOVE || MACH_DOVE || COMPILE_TEST + depends on HAS_IOMEM depends on OF help Support for the Dove thermal sensor driver in the Linux thermal @@ -249,6 +254,7 @@ config DB8500_THERMAL config ARMADA_THERMAL tristate "Armada 370/XP thermal management" depends on ARCH_MVEBU || COMPILE_TEST + depends on HAS_IOMEM depends on OF help Enable this option if you want to have support for thermal management @@ -267,6 +273,7 @@ config TEGRA_SOCTHERM config DB8500_CPUFREQ_COOLING tristate "DB8500 cpufreq cooling" depends on ARCH_U8500 || COMPILE_TEST + depends on HAS_IOMEM depends on CPU_THERMAL default y help @@ -367,6 +374,7 @@ config INTEL_PCH_THERMAL menu "Texas Instruments thermal drivers" depends on ARCH_HAS_BANDGAP || COMPILE_TEST +depends on HAS_IOMEM source "drivers/thermal/ti-soc-thermal/Kconfig" endmenu diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig index e0da3865e060..222e644169f0 100644 --- a/drivers/thermal/samsung/Kconfig +++ b/drivers/thermal/samsung/Kconfig @@ -1,6 +1,7 @@ config EXYNOS_THERMAL tristate "Exynos thermal management unit driver" depends on THERMAL_OF + depends on HAS_IOMEM help If you say yes here you get support for the TMU (Thermal Management Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises -- cgit v1.2.3-59-g8ed1b From 5e25166f32e7364422e2c413b5667713d6fa0f85 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Tue, 8 Mar 2016 11:19:01 +0800 Subject: thermal: tegra_soctherm: fix sign bit of temperature The sign bit of temperature readback is bit 0, not bit 1. Change to BIT(0) to fix it. Signed-off-by: Wei Ni Reviewed-by: Matt Longnecker Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra_soctherm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/tegra_soctherm.c b/drivers/thermal/tegra_soctherm.c index 74ea5765938b..136975220c92 100644 --- a/drivers/thermal/tegra_soctherm.c +++ b/drivers/thermal/tegra_soctherm.c @@ -57,7 +57,7 @@ #define READBACK_VALUE_MASK 0xff00 #define READBACK_VALUE_SHIFT 8 #define READBACK_ADD_HALF BIT(7) -#define READBACK_NEGATE BIT(1) +#define READBACK_NEGATE BIT(0) #define FUSE_TSENSOR8_CALIB 0x180 #define FUSE_SPARE_REALIGNMENT_REG_0 0x1fc -- cgit v1.2.3-59-g8ed1b From 74e5053cd71bdfe9b390000edb5a63dcf1607305 Mon Sep 17 00:00:00 2001 From: Eduardo Valentin Date: Tue, 8 Mar 2016 13:32:48 -0800 Subject: thermal: mtk: allow compile testing on UM Following the fix on thermal Kconfig, this patch adds dependency on HAS_IOMEM so driver properly compile test on UM arch. Cc: Krzysztof Kozlowski Cc: Zhang Rui Cc: Matthias Brugger Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 5e7c97a3f1d8..462d0149460d 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -368,6 +368,7 @@ config INTEL_PCH_THERMAL config MTK_THERMAL tristate "Temperature sensor driver for mediatek SoCs" depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_IOMEM default y help Enable this option if you want to have support for thermal management -- cgit v1.2.3-59-g8ed1b From 3a3a5f15869fa74472c377a556c3d00453403854 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 18 Feb 2016 14:14:20 +0900 Subject: thermal: exynos: Print a message about exceeded number of supported trip-points When DeviveTree contains more trip-points than SoC can configure (usually more than four) and polling mode is not enabled, then the remaining trip-points will be silently ignored. No interrupts will be generated for them. This might be quite dangerous when one provides DTB with a non-configurable critical trip-point, like (assuming four supported thresholds in TMU): - alert @50 C (type: active), - alert @60 C (type: active), - alert @70 C (type: active), - alert @80 C (type: active), - critical @120 C (type: critical) <- no interrupts generated. This is a mistake in DTB so print a message in such case. Reviewed-by: Chanwoo Choi Signed-off-by: Krzysztof Kozlowski Signed-off-by: Eduardo Valentin --- drivers/thermal/samsung/exynos_tmu.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index fa61eff88496..6c6f59ba7423 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -184,6 +184,7 @@ * @temp_error2: fused value of the second point trim. * @regulator: pointer to the TMU regulator structure. * @reg_conf: pointer to structure to register with core thermal. + * @ntrip: number of supported trip points. * @tmu_initialize: SoC specific TMU initialization method * @tmu_control: SoC specific TMU control method * @tmu_read: SoC specific TMU temperature read method @@ -203,6 +204,7 @@ struct exynos_tmu_data { u16 temp_error1, temp_error2; struct regulator *regulator; struct thermal_zone_device *tzd; + unsigned int ntrip; int (*tmu_initialize)(struct platform_device *pdev); void (*tmu_control)(struct platform_device *pdev, bool on); @@ -346,6 +348,14 @@ static int exynos_tmu_initialize(struct platform_device *pdev) struct exynos_tmu_data *data = platform_get_drvdata(pdev); int ret; + if (of_thermal_get_ntrips(data->tzd) > data->ntrip) { + dev_info(&pdev->dev, + "More trip points than supported by this TMU.\n"); + dev_info(&pdev->dev, + "%d trip points should be configured in polling mode.\n", + (of_thermal_get_ntrips(data->tzd) - data->ntrip)); + } + mutex_lock(&data->lock); clk_enable(data->clk); if (!IS_ERR(data->clk_sec)) @@ -1210,6 +1220,7 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->tmu_control = exynos4210_tmu_control; data->tmu_read = exynos4210_tmu_read; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; + data->ntrip = 4; break; case SOC_ARCH_EXYNOS3250: case SOC_ARCH_EXYNOS4412: @@ -1222,6 +1233,7 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->tmu_read = exynos4412_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; + data->ntrip = 4; break; case SOC_ARCH_EXYNOS5433: data->tmu_initialize = exynos5433_tmu_initialize; @@ -1229,6 +1241,7 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->tmu_read = exynos4412_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; + data->ntrip = 8; break; case SOC_ARCH_EXYNOS5440: data->tmu_initialize = exynos5440_tmu_initialize; @@ -1236,6 +1249,7 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->tmu_read = exynos5440_tmu_read; data->tmu_set_emulation = exynos5440_tmu_set_emulation; data->tmu_clear_irqs = exynos5440_tmu_clear_irqs; + data->ntrip = 4; break; case SOC_ARCH_EXYNOS7: data->tmu_initialize = exynos7_tmu_initialize; @@ -1243,6 +1257,7 @@ static int exynos_map_dt_data(struct platform_device *pdev) data->tmu_read = exynos7_tmu_read; data->tmu_set_emulation = exynos4412_tmu_set_emulation; data->tmu_clear_irqs = exynos4210_tmu_clear_irqs; + data->ntrip = 8; break; default: dev_err(&pdev->dev, "Platform not supported\n"); -- cgit v1.2.3-59-g8ed1b From 4d3583cd1cb1a51825f195b2cfe8b855827803eb Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 18 Feb 2016 15:19:10 -0300 Subject: thermal: exynos: Use devm_regulator_get_optional() for vtmu The Exynos TMU DT binding says that the vtmu-supply is optional but the driver uses devm_regulator_get() that creates a dummy regulator if it's not defined in the DT. For example the following message is in the log: 10060000.tmu supply vtmu not found, using dummy regulator Use the optional version of regulator_get() that doesn't create a dummy regulator and instead returns a -ENODEV errno code. Since it's expected that a regulator may not be defined and the driver will inform about it: exynos-tmu 10060000.tmu: Regulator node (vtmu) not found Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Signed-off-by: Javier Martinez Canillas Signed-off-by: Eduardo Valentin --- drivers/thermal/samsung/exynos_tmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/thermal') diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index 6c6f59ba7423..f4f36bba7be9 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1310,7 +1310,7 @@ static int exynos_tmu_probe(struct platform_device *pdev) * TODO: Add regulator as an SOC feature, so that regulator enable * is a compulsory call. */ - data->regulator = devm_regulator_get(&pdev->dev, "vtmu"); + data->regulator = devm_regulator_get_optional(&pdev->dev, "vtmu"); if (!IS_ERR(data->regulator)) { ret = regulator_enable(data->regulator); if (ret) { -- cgit v1.2.3-59-g8ed1b From ccb361d2fdda8975c8bbc8a1749c31dbd62dd276 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 18 Feb 2016 15:19:11 -0300 Subject: thermal: exynos: Defer probe if vtmu is present but not registered The driver doesn't check if the regulator_get_optional return value is -EPROBE_DEFER so it will wrongly assume that the regulator couldn't be found just because the regulator driver wasn't registered yet, i.e: exynos-tmu 10060000.tmu: Regulator node (vtmu) not found In this case the return value should be propagated to allow the driver probe function to be deferred until the regulator driver is registered. Reviewed-by: Krzysztof Kozlowski Reviewed-by: Andi Shyti Signed-off-by: Javier Martinez Canillas Signed-off-by: Eduardo Valentin --- drivers/thermal/samsung/exynos_tmu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index f4f36bba7be9..f3ce94ec73b5 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c @@ -1318,6 +1318,8 @@ static int exynos_tmu_probe(struct platform_device *pdev) return ret; } } else { + if (PTR_ERR(data->regulator) == -EPROBE_DEFER) + return -EPROBE_DEFER; dev_info(&pdev->dev, "Regulator node (vtmu) not found\n"); } -- cgit v1.2.3-59-g8ed1b From e498b4984db82b4ba3ceea7dba813222a31e9c2e Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Wed, 9 Mar 2016 18:40:06 +0530 Subject: thermal: of-thermal: Add devm version of thermal_zone_of_sensor_register Add resource managed version of thermal_zone_of_sensor_register() and thermal_zone_of_sensor_unregister(). This helps in reducing the code size in error path, remove of driver remove callbacks and making proper sequence for deallocations. Signed-off-by: Laxman Dewangan Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 81 ++++++++++++++++++++++++++++++++++++++++++++ include/linux/thermal.h | 18 ++++++++++ 2 files changed, 99 insertions(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 9043f8f91852..49ac23d3e776 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -555,6 +555,87 @@ void thermal_zone_of_sensor_unregister(struct device *dev, } EXPORT_SYMBOL_GPL(thermal_zone_of_sensor_unregister); +static void devm_thermal_zone_of_sensor_release(struct device *dev, void *res) +{ + thermal_zone_of_sensor_unregister(dev, + *(struct thermal_zone_device **)res); +} + +static int devm_thermal_zone_of_sensor_match(struct device *dev, void *res, + void *data) +{ + struct thermal_zone_device **r = res; + + if (WARN_ON(!r || !*r)) + return 0; + + return *r == data; +} + +/** + * devm_thermal_zone_of_sensor_register - Resource managed version of + * thermal_zone_of_sensor_register() + * @dev: a valid struct device pointer of a sensor device. Must contain + * a valid .of_node, for the sensor node. + * @sensor_id: a sensor identifier, in case the sensor IP has more + * than one sensors + * @data: a private pointer (owned by the caller) that will be passed + * back, when a temperature reading is needed. + * @ops: struct thermal_zone_of_device_ops *. Must contain at least .get_temp. + * + * Refer thermal_zone_of_sensor_register() for more details. + * + * Return: On success returns a valid struct thermal_zone_device, + * otherwise, it returns a corresponding ERR_PTR(). Caller must + * check the return value with help of IS_ERR() helper. + * Registered hermal_zone_device device will automatically be + * released when device is unbounded. + */ +struct thermal_zone_device *devm_thermal_zone_of_sensor_register( + struct device *dev, int sensor_id, + void *data, const struct thermal_zone_of_device_ops *ops) +{ + struct thermal_zone_device **ptr, *tzd; + + ptr = devres_alloc(devm_thermal_zone_of_sensor_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + tzd = thermal_zone_of_sensor_register(dev, sensor_id, data, ops); + if (IS_ERR(tzd)) { + devres_free(ptr); + return tzd; + } + + *ptr = tzd; + devres_add(dev, ptr); + + return tzd; +} +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_register); + +/** + * devm_thermal_zone_of_sensor_unregister - Resource managed version of + * thermal_zone_of_sensor_unregister(). + * @dev: Device for which which resource was allocated. + * @tzd: a pointer to struct thermal_zone_device where the sensor is registered. + * + * This function removes the sensor callbacks and private data from the + * thermal zone device registered with devm_thermal_zone_of_sensor_register() + * API. It will also silent the zone by remove the .get_temp() and .get_trend() + * thermal zone device callbacks. + * Normally this function will not need to be called and the resource + * management code will ensure that the resource is freed. + */ +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tzd) +{ + WARN_ON(devres_release(dev, devm_thermal_zone_of_sensor_release, + devm_thermal_zone_of_sensor_match, tzd)); +} +EXPORT_SYMBOL_GPL(devm_thermal_zone_of_sensor_unregister); + /*** functions parsing device tree nodes ***/ /** diff --git a/include/linux/thermal.h b/include/linux/thermal.h index e13a1ace50e9..9c481991fdc7 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -362,6 +362,11 @@ thermal_zone_of_sensor_register(struct device *dev, int id, void *data, const struct thermal_zone_of_device_ops *ops); void thermal_zone_of_sensor_unregister(struct device *dev, struct thermal_zone_device *tz); +struct thermal_zone_device *devm_thermal_zone_of_sensor_register( + struct device *dev, int id, void *data, + const struct thermal_zone_of_device_ops *ops); +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz); #else static inline struct thermal_zone_device * thermal_zone_of_sensor_register(struct device *dev, int id, void *data, @@ -376,6 +381,19 @@ void thermal_zone_of_sensor_unregister(struct device *dev, { } +static inline struct thermal_zone_device *devm_thermal_zone_of_sensor_register( + struct device *dev, int id, void *data, + const struct thermal_zone_of_device_ops *ops) +{ + return ERR_PTR(-ENODEV); +} + +static inline +void devm_thermal_zone_of_sensor_unregister(struct device *dev, + struct thermal_zone_device *tz) +{ +} + #endif #if IS_ENABLED(CONFIG_THERMAL) -- cgit v1.2.3-59-g8ed1b From 4cba7d23633c8ecb55460f0c614c3d57af0d8c08 Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Tue, 2 Feb 2016 00:03:41 -0800 Subject: thermal: intel_pch_thermal: Enable Skylake PCH thermal Enabled temperature reporting device of Skylake Platform Controller hub. The register map is same as the wildcat point thermal currently implemented in this driver. Signed-off-by: Srinivas Pandruvada Signed-off-by: Zhang Rui --- drivers/thermal/intel_pch_thermal.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/thermal') diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c index 00d81af648b8..6a6ec1c95a7a 100644 --- a/drivers/thermal/intel_pch_thermal.c +++ b/drivers/thermal/intel_pch_thermal.c @@ -24,6 +24,7 @@ /* Intel PCH thermal Device IDs */ #define PCH_THERMAL_DID_WPT 0x9CA4 /* Wildcat Point */ +#define PCH_THERMAL_DID_SKL 0x9D31 /* Skylake PCH */ /* Wildcat Point-LP PCH Thermal registers */ #define WPT_TEMP 0x0000 /* Temperature */ @@ -201,6 +202,10 @@ static int intel_pch_thermal_probe(struct pci_dev *pdev, ptd->ops = &pch_dev_ops_wpt; dev_name = "pch_wildcat_point"; break; + case PCH_THERMAL_DID_SKL: + ptd->ops = &pch_dev_ops_wpt; + dev_name = "pch_skylake"; + break; default: dev_err(&pdev->dev, "unknown pch thermal device\n"); return -ENODEV; @@ -266,6 +271,7 @@ static void intel_pch_thermal_remove(struct pci_dev *pdev) static struct pci_device_id intel_pch_thermal_id[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_WPT) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_SKL) }, { 0, }, }; MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id); -- cgit v1.2.3-59-g8ed1b