From 9967a1bc8122e50cb2bb330b41bd982392314375 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:36 +0800 Subject: of: Add bindings of thermtrip for Tegra soctherm Add optional property "nvidia,thermtrips". If present, these trips will be used as HW shutdown trips, and critical trips will be used as SW shutdown trips. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- .../bindings/thermal/nvidia,tegra124-soctherm.txt | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt index b6c0ae53d4dc..ab66d6feab4b 100644 --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt @@ -55,10 +55,21 @@ Required properties : - #cooling-cells: Should be 1. This cooling device only support on/off state. See ./thermal.txt for a description of this property. +Optional properties: +- nvidia,thermtrips : When present, this property specifies the temperature at + which the soctherm hardware will assert the thermal trigger signal to the + Power Management IC, which can be configured to reset or shutdown the device. + It is an array of pairs where each pair represents a tsensor id followed by a + temperature in milli Celcius. In the absence of this property the critical + trip point will be used for thermtrip temperature. + Note: -- the "critical" type trip points will be set to SOC_THERM hardware as the -shut down temperature. Once the temperature of this thermal zone is higher -than it, the system will be shutdown or reset by hardware. +- the "critical" type trip points will be used to set the temperature at which +the SOC_THERM hardware will assert a thermal trigger if the "nvidia,thermtrips" +property is missing. When the thermtrips property is present, the breach of a +critical trip point is reported back to the thermal framework to implement +software shutdown. + - the "hot" type trip points will be set to SOC_THERM hardware as the throttle temperature. Once the the temperature of this thermal zone is higher than it, it will trigger the HW throttle event. @@ -79,6 +90,9 @@ Example : #thermal-sensor-cells = <1>; + nvidia,thermtrips = ; + throttle-cfgs { /* * When the "heavy" cooling device triggered, -- cgit From 2510aa56ab8795e541386c4f662d40c6c4e98ba9 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:37 +0800 Subject: thermal: tegra: support hw and sw shutdown Currently the critical trip points in thermal framework are the only way to specify a temperature at which HW should shutdown. This is insufficient for certain platforms which would want an orderly software shutdown in addition to HW shutdown. This change support to parse "nvidia, thermtrips" property, it allows soctherm DT to specify thermtrip temperatures so that critical trip points framework can be used for doing software shutdown. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra/soctherm.c | 99 ++++++++++++++++++++++++++----- drivers/thermal/tegra/soctherm.h | 6 ++ drivers/thermal/tegra/tegra210-soctherm.c | 8 +++ 3 files changed, 98 insertions(+), 15 deletions(-) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 70043a28eb7a..5797d2122a2b 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -446,6 +446,24 @@ find_throttle_cfg_by_name(struct tegra_soctherm *ts, const char *name) return NULL; } +static int tsensor_group_thermtrip_get(struct tegra_soctherm *ts, int id) +{ + int i, temp = min_low_temp; + struct tsensor_group_thermtrips *tt = ts->soc->thermtrips; + + if (id >= TEGRA124_SOCTHERM_SENSOR_NUM) + return temp; + + if (tt) { + for (i = 0; i < ts->soc->num_ttgs; i++) { + if (tt[i].id == id) + return tt[i].temp; + } + } + + return temp; +} + static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp) { struct tegra_thermctl_zone *zone = data; @@ -464,7 +482,16 @@ static int tegra_thermctl_set_trip_temp(void *data, int trip, int temp) return ret; if (type == THERMAL_TRIP_CRITICAL) { - return thermtrip_program(dev, sg, temp); + /* + * If thermtrips property is set in DT, + * doesn't need to program critical type trip to HW, + * if not, program critical trip to HW. + */ + if (min_low_temp == tsensor_group_thermtrip_get(ts, sg->id)) + return thermtrip_program(dev, sg, temp); + else + return 0; + } else if (type == THERMAL_TRIP_HOT) { int i; @@ -555,7 +582,8 @@ static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp) * @dev: struct device * of the SOC_THERM instance * * Configure the SOC_THERM HW trip points, setting "THERMTRIP" - * "THROTTLE" trip points , using "critical" or "hot" type trip_temp + * "THROTTLE" trip points , using "thermtrips", "critical" or "hot" + * type trip_temp * from thermal zone. * After they have been configured, THERMTRIP or THROTTLE will take * action when the configured SoC thermal sensor group reaches a @@ -577,28 +605,23 @@ static int tegra_soctherm_set_hwtrips(struct device *dev, { struct tegra_soctherm *ts = dev_get_drvdata(dev); struct soctherm_throt_cfg *stc; - int i, trip, temperature; - int ret; + int i, trip, temperature, ret; - ret = tz->ops->get_crit_temp(tz, &temperature); - if (ret) { - dev_warn(dev, "thermtrip: %s: missing critical temperature\n", - sg->name); - goto set_throttle; - } + /* Get thermtrips. If missing, try to get critical trips. */ + temperature = tsensor_group_thermtrip_get(ts, sg->id); + if (min_low_temp == temperature) + if (tz->ops->get_crit_temp(tz, &temperature)) + temperature = max_high_temp; ret = thermtrip_program(dev, sg, temperature); if (ret) { - dev_err(dev, "thermtrip: %s: error during enable\n", - sg->name); + dev_err(dev, "thermtrip: %s: error during enable\n", sg->name); return ret; } - dev_info(dev, - "thermtrip: will shut down when %s reaches %d mC\n", + dev_info(dev, "thermtrip: will shut down when %s reaches %d mC\n", sg->name, temperature); -set_throttle: ret = get_hot_temp(tz, &trip, &temperature); if (ret) { dev_info(dev, "throttrip: %s: missing hot temperature\n", @@ -929,6 +952,50 @@ static const struct thermal_cooling_device_ops throt_cooling_ops = { .set_cur_state = throt_set_cdev_state, }; +static int soctherm_thermtrips_parse(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_soctherm *ts = dev_get_drvdata(dev); + struct tsensor_group_thermtrips *tt = ts->soc->thermtrips; + const int max_num_prop = ts->soc->num_ttgs * 2; + u32 *tlb; + int i, j, n, ret; + + if (!tt) + return -ENOMEM; + + n = of_property_count_u32_elems(dev->of_node, "nvidia,thermtrips"); + if (n <= 0) { + dev_info(dev, + "missing thermtrips, will use critical trips as shut down temp\n"); + return n; + } + + n = min(max_num_prop, n); + + tlb = devm_kcalloc(&pdev->dev, max_num_prop, sizeof(u32), GFP_KERNEL); + if (!tlb) + return -ENOMEM; + ret = of_property_read_u32_array(dev->of_node, "nvidia,thermtrips", + tlb, n); + if (ret) { + dev_err(dev, "invalid num ele: thermtrips:%d\n", ret); + return ret; + } + + i = 0; + for (j = 0; j < n; j = j + 2) { + if (tlb[j] >= TEGRA124_SOCTHERM_SENSOR_NUM) + continue; + + tt[i].id = tlb[j]; + tt[i].temp = tlb[j + 1]; + i++; + } + + return 0; +} + /** * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations * and register them as cooling devices. @@ -1370,6 +1437,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev) if (err) return err; + soctherm_thermtrips_parse(pdev); + soctherm_init_hw_throt_cdev(pdev); soctherm_init(pdev); diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h index e96ca73fd780..c05c7e37e968 100644 --- a/drivers/thermal/tegra/soctherm.h +++ b/drivers/thermal/tegra/soctherm.h @@ -92,6 +92,11 @@ struct tegra_tsensor { const struct tegra_tsensor_group *group; }; +struct tsensor_group_thermtrips { + u8 id; + u32 temp; +}; + struct tegra_soctherm_fuse { u32 fuse_base_cp_mask, fuse_base_cp_shift; u32 fuse_base_ft_mask, fuse_base_ft_shift; @@ -113,6 +118,7 @@ struct tegra_soctherm_soc { const int thresh_grain; const unsigned int bptt; const bool use_ccroc; + struct tsensor_group_thermtrips *thermtrips; }; int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse, diff --git a/drivers/thermal/tegra/tegra210-soctherm.c b/drivers/thermal/tegra/tegra210-soctherm.c index ad53169a8e95..0a0c3cec7134 100644 --- a/drivers/thermal/tegra/tegra210-soctherm.c +++ b/drivers/thermal/tegra/tegra210-soctherm.c @@ -203,6 +203,13 @@ static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = { .fuse_spare_realignment = 0, }; +struct tsensor_group_thermtrips tegra210_tsensor_thermtrips[] = { + {.id = TEGRA124_SOCTHERM_SENSOR_NUM}, + {.id = TEGRA124_SOCTHERM_SENSOR_NUM}, + {.id = TEGRA124_SOCTHERM_SENSOR_NUM}, + {.id = TEGRA124_SOCTHERM_SENSOR_NUM}, +}; + const struct tegra_soctherm_soc tegra210_soctherm = { .tsensors = tegra210_tsensors, .num_tsensors = ARRAY_SIZE(tegra210_tsensors), @@ -212,4 +219,5 @@ const struct tegra_soctherm_soc tegra210_soctherm = { .thresh_grain = TEGRA210_THRESH_GRAIN, .bptt = TEGRA210_BPTT, .use_ccroc = false, + .thermtrips = tegra210_tsensor_thermtrips, }; -- cgit From 7d8ac6b282ad4a2914f480ab80bf81dd5b77038c Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:39 +0800 Subject: of: Add bindings of gpu hw throttle for Tegra soctherm Add "nvidia,gpu-throt-level" property to set gpu hw throttle level. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- .../bindings/thermal/nvidia,tegra124-soctherm.txt | 17 +++++++++++++++-- include/dt-bindings/thermal/tegra124-soctherm.h | 8 ++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt index ab66d6feab4b..cf6d0be56b7a 100644 --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt @@ -52,6 +52,15 @@ Required properties : Must set as following values: TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE + - nvidia,gpu-throt-level: This property is for Tegra124 and Tegra210. + It is the level of pulse skippers, which used to throttle clock + frequencies. It indicates gpu clock throttling depth and can be + programmed to any of the following values which represent a throttling + percentage: + TEGRA_SOCTHERM_THROT_LEVEL_NONE (0%) + TEGRA_SOCTHERM_THROT_LEVEL_LOW (50%), + TEGRA_SOCTHERM_THROT_LEVEL_MED (75%), + TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%). - #cooling-cells: Should be 1. This cooling device only support on/off state. See ./thermal.txt for a description of this property. @@ -96,22 +105,26 @@ Example : throttle-cfgs { /* * When the "heavy" cooling device triggered, - * the HW will skip cpu clock's pulse in 85% depth + * the HW will skip cpu clock's pulse in 85% depth, + * skip gpu clock's pulse in 85% level */ throttle_heavy: heavy { nvidia,priority = <100>; nvidia,cpu-throt-percent = <85>; + nvidia,gpu-throt-level = ; #cooling-cells = <1>; }; /* * When the "light" cooling device triggered, - * the HW will skip cpu clock's pulse in 50% depth + * the HW will skip cpu clock's pulse in 50% depth, + * skip gpu clock's pulse in 50% level */ throttle_light: light { nvidia,priority = <80>; nvidia,cpu-throt-percent = <50>; + nvidia,gpu-throt-level = ; #cooling-cells = <1>; }; diff --git a/include/dt-bindings/thermal/tegra124-soctherm.h b/include/dt-bindings/thermal/tegra124-soctherm.h index c15e8b709a0d..444c7bdde146 100644 --- a/include/dt-bindings/thermal/tegra124-soctherm.h +++ b/include/dt-bindings/thermal/tegra124-soctherm.h @@ -12,9 +12,9 @@ #define TEGRA124_SOCTHERM_SENSOR_PLLX 3 #define TEGRA124_SOCTHERM_SENSOR_NUM 4 -#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 0 -#define TEGRA_SOCTHERM_THROT_LEVEL_MED 1 -#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2 -#define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1 +#define TEGRA_SOCTHERM_THROT_LEVEL_NONE 0 +#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 1 +#define TEGRA_SOCTHERM_THROT_LEVEL_MED 2 +#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 3 #endif -- cgit From 6ca29b7e824c758bc29968e5153f39eb56a265fc Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:40 +0800 Subject: thermal: tegra: add support for gpu hw-throttle Add support to trigger pulse skippers on the GPU when a HOT trip point is triggered. The pulse skippers can be signalled to throttle at low, medium and high depths\levels. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra/soctherm.c | 118 ++++++++++++++++++++++++++++----------- 1 file changed, 85 insertions(+), 33 deletions(-) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 5797d2122a2b..b7dc93c1a050 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014 - 2018, NVIDIA CORPORATION. All rights reserved. * * Author: * Mikko Perttunen @@ -160,6 +161,15 @@ /* get dividend from the depth */ #define THROT_DEPTH_DIVIDEND(depth) ((256 * (100 - (depth)) / 100) - 1) +/* gk20a nv_therm interface N:3 Mapping. Levels defined in tegra124-sochterm.h + * level vector + * NONE 3'b000 + * LOW 3'b001 + * MED 3'b011 + * HIGH 3'b111 + */ +#define THROT_LEVEL_TO_DEPTH(level) ((0x1 << (level)) - 1) + /* get THROT_PSKIP_xxx offset per LIGHT/HEAVY throt and CPU/GPU dev */ #define THROT_OFFSET 0x30 #define THROT_PSKIP_CTRL(throt, dev) (THROT_PSKIP_CTRL_LITE_CPU + \ @@ -219,6 +229,7 @@ struct soctherm_throt_cfg { u8 priority; u8 cpu_throt_level; u32 cpu_throt_depth; + u32 gpu_throt_level; struct thermal_cooling_device *cdev; bool init; }; @@ -996,6 +1007,50 @@ static int soctherm_thermtrips_parse(struct platform_device *pdev) return 0; } +static int soctherm_throt_cfg_parse(struct device *dev, + struct device_node *np, + struct soctherm_throt_cfg *stc) +{ + struct tegra_soctherm *ts = dev_get_drvdata(dev); + int ret; + u32 val; + + ret = of_property_read_u32(np, "nvidia,priority", &val); + if (ret) { + dev_err(dev, "throttle-cfg: %s: invalid priority\n", stc->name); + return -EINVAL; + } + stc->priority = val; + + ret = of_property_read_u32(np, ts->soc->use_ccroc ? + "nvidia,cpu-throt-level" : + "nvidia,cpu-throt-percent", &val); + if (!ret) { + if (ts->soc->use_ccroc && + val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH) + stc->cpu_throt_level = val; + else if (!ts->soc->use_ccroc && val <= 100) + stc->cpu_throt_depth = val; + else + goto err; + } else { + goto err; + } + + ret = of_property_read_u32(np, "nvidia,gpu-throt-level", &val); + if (!ret && val <= TEGRA_SOCTHERM_THROT_LEVEL_HIGH) + stc->gpu_throt_level = val; + else + goto err; + + return 0; + +err: + dev_err(dev, "throttle-cfg: %s: no throt prop or invalid prop\n", + stc->name); + return -EINVAL; +} + /** * soctherm_init_hw_throt_cdev() - Parse the HW throttle configurations * and register them as cooling devices. @@ -1006,8 +1061,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) struct tegra_soctherm *ts = dev_get_drvdata(dev); struct device_node *np_stc, *np_stcc; const char *name; - u32 val; - int i, r; + int i; for (i = 0; i < THROTTLE_SIZE; i++) { ts->throt_cfgs[i].name = throt_names[i]; @@ -1025,6 +1079,7 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) for_each_child_of_node(np_stc, np_stcc) { struct soctherm_throt_cfg *stc; struct thermal_cooling_device *tcd; + int err; name = np_stcc->name; stc = find_throttle_cfg_by_name(ts, name); @@ -1034,37 +1089,10 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) continue; } - r = of_property_read_u32(np_stcc, "nvidia,priority", &val); - if (r) { - dev_info(dev, - "throttle-cfg: %s: missing priority\n", name); + + err = soctherm_throt_cfg_parse(dev, np_stcc, stc); + if (err) continue; - } - stc->priority = val; - - if (ts->soc->use_ccroc) { - r = of_property_read_u32(np_stcc, - "nvidia,cpu-throt-level", - &val); - if (r) { - dev_info(dev, - "throttle-cfg: %s: missing cpu-throt-level\n", - name); - continue; - } - stc->cpu_throt_level = val; - } else { - r = of_property_read_u32(np_stcc, - "nvidia,cpu-throt-percent", - &val); - if (r) { - dev_info(dev, - "throttle-cfg: %s: missing cpu-throt-percent\n", - name); - continue; - } - stc->cpu_throt_depth = val; - } tcd = thermal_of_cooling_device_register(np_stcc, (char *)name, ts, @@ -1207,6 +1235,28 @@ static void throttlectl_cpu_mn(struct tegra_soctherm *ts, writel(r, ts->regs + THROT_PSKIP_RAMP(throt, THROTTLE_DEV_CPU)); } +/** + * throttlectl_gpu_level_select() - selects throttling level for GPU + * @throt: the LIGHT/HEAVY of throttle event id + * + * This function programs soctherm's interface to GK20a NV_THERM to select + * pre-configured "Low", "Medium" or "Heavy" throttle levels. + * + * Return: boolean true if HW was programmed + */ +static void throttlectl_gpu_level_select(struct tegra_soctherm *ts, + enum soctherm_throttle_id throt) +{ + u32 r, level, throt_vect; + + level = ts->throt_cfgs[throt].gpu_throt_level; + throt_vect = THROT_LEVEL_TO_DEPTH(level); + r = readl(ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU)); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_ENABLE_MASK, 1); + r = REG_SET_MASK(r, THROT_PSKIP_CTRL_VECT_GPU_MASK, throt_vect); + writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU)); +} + /** * soctherm_throttle_program() - programs pulse skippers' configuration * @throt: the LIGHT/HEAVY of the throttle event id. @@ -1229,6 +1279,8 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts, else throttlectl_cpu_mn(ts, throt); + throttlectl_gpu_level_select(ts, throt); + r = REG_SET_MASK(0, THROT_PRIORITY_LITE_PRIO_MASK, stc.priority); writel(r, ts->regs + THROT_PRIORITY_CTRL(throt)); -- cgit From d7180be0d580ffc721da873dfa006680a9f14e63 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:42 +0800 Subject: thermal: tegra: add support for thermal IRQ Support to generate an interrupt when the temperature crosses a programmed threshold and notify the thermal framework. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra/soctherm.c | 136 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index b7dc93c1a050..6301b9e160e0 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -86,6 +86,20 @@ #define THERMCTL_LVL0_UP_STATS 0x10 #define THERMCTL_LVL0_DN_STATS 0x14 +#define THERMCTL_INTR_STATUS 0x84 +#define THERMCTL_INTR_ENABLE 0x88 +#define THERMCTL_INTR_DISABLE 0x8c + +#define TH_INTR_MD0_MASK BIT(25) +#define TH_INTR_MU0_MASK BIT(24) +#define TH_INTR_GD0_MASK BIT(17) +#define TH_INTR_GU0_MASK BIT(16) +#define TH_INTR_CD0_MASK BIT(9) +#define TH_INTR_CU0_MASK BIT(8) +#define TH_INTR_PD0_MASK BIT(1) +#define TH_INTR_PU0_MASK BIT(0) +#define TH_INTR_IGNORE_MASK 0xFCFCFCFC + #define THERMCTL_STATS_CTL 0x94 #define STATS_CTL_CLR_DN 0x8 #define STATS_CTL_EN_DN 0x4 @@ -242,6 +256,8 @@ struct tegra_soctherm { void __iomem *clk_regs; void __iomem *ccroc_regs; + int thermal_irq; + u32 *calib; struct thermal_zone_device **thermctl_tzs; struct tegra_soctherm_soc *soc; @@ -672,6 +688,98 @@ static int tegra_soctherm_set_hwtrips(struct device *dev, return 0; } +static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id) +{ + struct tegra_soctherm *ts = dev_id; + u32 r; + + r = readl(ts->regs + THERMCTL_INTR_STATUS); + writel(r, ts->regs + THERMCTL_INTR_DISABLE); + + return IRQ_WAKE_THREAD; +} + +/** + * soctherm_thermal_isr_thread() - Handles a thermal interrupt request + * @irq: The interrupt number being requested; not used + * @dev_id: Opaque pointer to tegra_soctherm; + * + * Clears the interrupt status register if there are expected + * interrupt bits set. + * The interrupt(s) are then handled by updating the corresponding + * thermal zones. + * + * An error is logged if any unexpected interrupt bits are set. + * + * Disabled interrupts are re-enabled. + * + * Return: %IRQ_HANDLED. Interrupt was handled and no further processing + * is needed. + */ +static irqreturn_t soctherm_thermal_isr_thread(int irq, void *dev_id) +{ + struct tegra_soctherm *ts = dev_id; + struct thermal_zone_device *tz; + u32 st, ex = 0, cp = 0, gp = 0, pl = 0, me = 0; + + st = readl(ts->regs + THERMCTL_INTR_STATUS); + + /* deliberately clear expected interrupts handled in SW */ + cp |= st & TH_INTR_CD0_MASK; + cp |= st & TH_INTR_CU0_MASK; + + gp |= st & TH_INTR_GD0_MASK; + gp |= st & TH_INTR_GU0_MASK; + + pl |= st & TH_INTR_PD0_MASK; + pl |= st & TH_INTR_PU0_MASK; + + me |= st & TH_INTR_MD0_MASK; + me |= st & TH_INTR_MU0_MASK; + + ex |= cp | gp | pl | me; + if (ex) { + writel(ex, ts->regs + THERMCTL_INTR_STATUS); + st &= ~ex; + + if (cp) { + tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_CPU]; + thermal_zone_device_update(tz, + THERMAL_EVENT_UNSPECIFIED); + } + + if (gp) { + tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_GPU]; + thermal_zone_device_update(tz, + THERMAL_EVENT_UNSPECIFIED); + } + + if (pl) { + tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_PLLX]; + thermal_zone_device_update(tz, + THERMAL_EVENT_UNSPECIFIED); + } + + if (me) { + tz = ts->thermctl_tzs[TEGRA124_SOCTHERM_SENSOR_MEM]; + thermal_zone_device_update(tz, + THERMAL_EVENT_UNSPECIFIED); + } + } + + /* deliberately ignore expected interrupts NOT handled in SW */ + ex |= TH_INTR_IGNORE_MASK; + st &= ~ex; + + if (st) { + /* Whine about any other unexpected INTR bits still set */ + pr_err("soctherm: Ignored unexpected INTRs 0x%08x\n", st); + writel(st, ts->regs + THERMCTL_INTR_STATUS); + } + + return IRQ_HANDLED; +} + #ifdef CONFIG_DEBUG_FS static int regs_show(struct seq_file *s, void *data) { @@ -1334,6 +1442,32 @@ static void tegra_soctherm_throttle(struct device *dev) writel(v, ts->regs + THERMCTL_STATS_CTL); } +static int soctherm_interrupts_init(struct platform_device *pdev, + struct tegra_soctherm *tegra) +{ + int ret; + + tegra->thermal_irq = platform_get_irq(pdev, 0); + if (tegra->thermal_irq < 0) { + dev_dbg(&pdev->dev, "get 'thermal_irq' failed.\n"); + return 0; + } + + ret = devm_request_threaded_irq(&pdev->dev, + tegra->thermal_irq, + soctherm_thermal_isr, + soctherm_thermal_isr_thread, + IRQF_ONESHOT, + dev_name(&pdev->dev), + tegra); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq 'thermal_irq' failed.\n"); + return ret; + } + + return 0; +} + static void soctherm_init(struct platform_device *pdev) { struct tegra_soctherm *tegra = platform_get_drvdata(pdev); @@ -1527,6 +1661,8 @@ static int tegra_soctherm_probe(struct platform_device *pdev) goto disable_clocks; } + err = soctherm_interrupts_init(pdev, tegra); + soctherm_debug_init(pdev); return 0; -- cgit From 5c9d6ac23170e672101bce965a8180af24c40adb Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:43 +0800 Subject: thermal: tegra: add set_trips functionality Implement set_trips ops to set passive trip points. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra/soctherm.c | 64 ++++++++++++++++++++++++++++++- drivers/thermal/tegra/soctherm.h | 10 +++++ drivers/thermal/tegra/tegra124-soctherm.c | 7 +++- drivers/thermal/tegra/tegra132-soctherm.c | 7 +++- drivers/thermal/tegra/tegra210-soctherm.c | 7 +++- 5 files changed, 90 insertions(+), 5 deletions(-) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 6301b9e160e0..9e66ea730098 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -87,8 +87,6 @@ #define THERMCTL_LVL0_DN_STATS 0x14 #define THERMCTL_INTR_STATUS 0x84 -#define THERMCTL_INTR_ENABLE 0x88 -#define THERMCTL_INTR_DISABLE 0x8c #define TH_INTR_MD0_MASK BIT(25) #define TH_INTR_MU0_MASK BIT(24) @@ -265,6 +263,8 @@ struct tegra_soctherm { struct soctherm_throt_cfg throt_cfgs[THROTTLE_SIZE]; struct dentry *debugfs_dir; + + struct mutex thermctl_lock; }; /** @@ -573,10 +573,60 @@ static int tegra_thermctl_get_trend(void *data, int trip, return 0; } +static void thermal_irq_enable(struct tegra_thermctl_zone *zn) +{ + u32 r; + + /* multiple zones could be handling and setting trips at once */ + mutex_lock(&zn->ts->thermctl_lock); + r = readl(zn->ts->regs + THERMCTL_INTR_ENABLE); + r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, TH_INTR_UP_DN_EN); + writel(r, zn->ts->regs + THERMCTL_INTR_ENABLE); + mutex_unlock(&zn->ts->thermctl_lock); +} + +static void thermal_irq_disable(struct tegra_thermctl_zone *zn) +{ + u32 r; + + /* multiple zones could be handling and setting trips at once */ + mutex_lock(&zn->ts->thermctl_lock); + r = readl(zn->ts->regs + THERMCTL_INTR_DISABLE); + r = REG_SET_MASK(r, zn->sg->thermctl_isr_mask, 0); + writel(r, zn->ts->regs + THERMCTL_INTR_DISABLE); + mutex_unlock(&zn->ts->thermctl_lock); +} + +static int tegra_thermctl_set_trips(void *data, int lo, int hi) +{ + struct tegra_thermctl_zone *zone = data; + u32 r; + + thermal_irq_disable(zone); + + r = readl(zone->ts->regs + zone->sg->thermctl_lvl0_offset); + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 0); + writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset); + + lo = enforce_temp_range(zone->dev, lo) / zone->ts->soc->thresh_grain; + hi = enforce_temp_range(zone->dev, hi) / zone->ts->soc->thresh_grain; + dev_dbg(zone->dev, "%s hi:%d, lo:%d\n", __func__, hi, lo); + + r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_up_thresh_mask, hi); + r = REG_SET_MASK(r, zone->sg->thermctl_lvl0_dn_thresh_mask, lo); + r = REG_SET_MASK(r, THERMCTL_LVL0_CPU0_EN_MASK, 1); + writel(r, zone->ts->regs + zone->sg->thermctl_lvl0_offset); + + thermal_irq_enable(zone); + + return 0; +} + static const struct thermal_zone_of_device_ops tegra_of_thermal_ops = { .get_temp = tegra_thermctl_get_temp, .set_trip_temp = tegra_thermctl_set_trip_temp, .get_trend = tegra_thermctl_get_trend, + .set_trips = tegra_thermctl_set_trips, }; static int get_hot_temp(struct thermal_zone_device *tz, int *trip, int *temp) @@ -693,6 +743,15 @@ static irqreturn_t soctherm_thermal_isr(int irq, void *dev_id) struct tegra_soctherm *ts = dev_id; u32 r; + /* Case for no lock: + * Although interrupts are enabled in set_trips, there is still no need + * to lock here because the interrupts are disabled before programming + * new trip points. Hence there cant be a interrupt on the same sensor. + * An interrupt can however occur on a sensor while trips are being + * programmed on a different one. This beign a LEVEL interrupt won't + * cause a new interrupt but this is taken care of by the re-reading of + * the STATUS register in the thread function. + */ r = readl(ts->regs + THERMCTL_INTR_STATUS); writel(r, ts->regs + THERMCTL_INTR_DISABLE); @@ -1545,6 +1604,7 @@ static int tegra_soctherm_probe(struct platform_device *pdev) if (!tegra) return -ENOMEM; + mutex_init(&tegra->thermctl_lock); dev_set_drvdata(&pdev->dev, tegra); tegra->soc = soc; diff --git a/drivers/thermal/tegra/soctherm.h b/drivers/thermal/tegra/soctherm.h index c05c7e37e968..70501e73d586 100644 --- a/drivers/thermal/tegra/soctherm.h +++ b/drivers/thermal/tegra/soctherm.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * @@ -29,6 +30,14 @@ #define THERMCTL_THERMTRIP_CTL 0x80 /* BITs are defined in device file */ +#define THERMCTL_INTR_ENABLE 0x88 +#define THERMCTL_INTR_DISABLE 0x8c +#define TH_INTR_UP_DN_EN 0x3 +#define THERM_IRQ_MEM_MASK (TH_INTR_UP_DN_EN << 24) +#define THERM_IRQ_GPU_MASK (TH_INTR_UP_DN_EN << 16) +#define THERM_IRQ_CPU_MASK (TH_INTR_UP_DN_EN << 8) +#define THERM_IRQ_TSENSE_MASK (TH_INTR_UP_DN_EN << 0) + #define SENSOR_PDIV 0x1c0 #define SENSOR_PDIV_CPU_MASK (0xf << 12) #define SENSOR_PDIV_GPU_MASK (0xf << 8) @@ -70,6 +79,7 @@ struct tegra_tsensor_group { u32 thermtrip_enable_mask; u32 thermtrip_any_en_mask; u32 thermtrip_threshold_mask; + u32 thermctl_isr_mask; u16 thermctl_lvl0_offset; u32 thermctl_lvl0_up_thresh_mask; u32 thermctl_lvl0_dn_thresh_mask; diff --git a/drivers/thermal/tegra/tegra124-soctherm.c b/drivers/thermal/tegra/tegra124-soctherm.c index 36768630f78c..20ad27f4d1a1 100644 --- a/drivers/thermal/tegra/tegra124-soctherm.c +++ b/drivers/thermal/tegra/tegra124-soctherm.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_CPU_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, @@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_GPU_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, @@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, @@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_MEM_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, diff --git a/drivers/thermal/tegra/tegra132-soctherm.c b/drivers/thermal/tegra/tegra132-soctherm.c index 97fa30501eb1..b76308fdad9e 100644 --- a/drivers/thermal/tegra/tegra132-soctherm.c +++ b/drivers/thermal/tegra/tegra132-soctherm.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_CPU_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, @@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_GPU_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, @@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, @@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_MEM_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, diff --git a/drivers/thermal/tegra/tegra210-soctherm.c b/drivers/thermal/tegra/tegra210-soctherm.c index 0a0c3cec7134..d31b50050faa 100644 --- a/drivers/thermal/tegra/tegra210-soctherm.c +++ b/drivers/thermal/tegra/tegra210-soctherm.c @@ -1,5 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -56,6 +57,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_CPU_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, @@ -74,6 +76,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_GPU_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, @@ -90,6 +93,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_TSENSE_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, @@ -108,6 +112,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = { .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, + .thermctl_isr_mask = THERM_IRQ_MEM_MASK, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, -- cgit From 4a04beb1bf2ef75945f293bb65ac46f41e818497 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:44 +0800 Subject: thermal: tegra: add support for EDP IRQ Add support to generate OC (over-current) interrupts to indicate the OC event and print out alarm messages. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra/soctherm.c | 420 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 9e66ea730098..35a9f1ef9d85 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -104,6 +106,16 @@ #define STATS_CTL_CLR_UP 0x2 #define STATS_CTL_EN_UP 0x1 +#define OC_INTR_STATUS 0x39c +#define OC_INTR_ENABLE 0x3a0 +#define OC_INTR_DISABLE 0x3a4 + +#define OC_INTR_OC1_MASK BIT(0) +#define OC_INTR_OC2_MASK BIT(1) +#define OC_INTR_OC3_MASK BIT(2) +#define OC_INTR_OC4_MASK BIT(3) +#define OC_INTR_OC5_MASK BIT(4) + #define THROT_GLOBAL_CFG 0x400 #define THROT_GLOBAL_ENB_MASK BIT(0) @@ -212,9 +224,23 @@ static const int max_high_temp = 127000; enum soctherm_throttle_id { THROTTLE_LIGHT = 0, THROTTLE_HEAVY, + THROTTLE_OC1, + THROTTLE_OC2, + THROTTLE_OC3, + THROTTLE_OC4, + THROTTLE_OC5, /* OC5 is reserved */ THROTTLE_SIZE, }; +enum soctherm_oc_irq_id { + TEGRA_SOC_OC_IRQ_1, + TEGRA_SOC_OC_IRQ_2, + TEGRA_SOC_OC_IRQ_3, + TEGRA_SOC_OC_IRQ_4, + TEGRA_SOC_OC_IRQ_5, + TEGRA_SOC_OC_IRQ_MAX, +}; + enum soctherm_throttle_dev_id { THROTTLE_DEV_CPU = 0, THROTTLE_DEV_GPU, @@ -224,6 +250,11 @@ enum soctherm_throttle_dev_id { static const char *const throt_names[] = { [THROTTLE_LIGHT] = "light", [THROTTLE_HEAVY] = "heavy", + [THROTTLE_OC1] = "oc1", + [THROTTLE_OC2] = "oc2", + [THROTTLE_OC3] = "oc3", + [THROTTLE_OC4] = "oc4", + [THROTTLE_OC5] = "oc5", }; struct tegra_soctherm; @@ -255,6 +286,7 @@ struct tegra_soctherm { void __iomem *ccroc_regs; int thermal_irq; + int edp_irq; u32 *calib; struct thermal_zone_device **thermctl_tzs; @@ -267,6 +299,15 @@ struct tegra_soctherm { struct mutex thermctl_lock; }; +struct soctherm_oc_irq_chip_data { + struct mutex irq_lock; /* serialize OC IRQs */ + struct irq_chip irq_chip; + struct irq_domain *domain; + int irq_enable; +}; + +static struct soctherm_oc_irq_chip_data soc_irq_cdata; + /** * ccroc_writel() - writes a value to a CCROC register * @ts: pointer to a struct tegra_soctherm @@ -839,6 +880,360 @@ static irqreturn_t soctherm_thermal_isr_thread(int irq, void *dev_id) return IRQ_HANDLED; } +/** + * soctherm_oc_intr_enable() - Enables the soctherm over-current interrupt + * @alarm: The soctherm throttle id + * @enable: Flag indicating enable the soctherm over-current + * interrupt or disable it + * + * Enables a specific over-current pins @alarm to raise an interrupt if the flag + * is set and the alarm corresponds to OC1, OC2, OC3, or OC4. + */ +static void soctherm_oc_intr_enable(struct tegra_soctherm *ts, + enum soctherm_throttle_id alarm, + bool enable) +{ + u32 r; + + if (!enable) + return; + + r = readl(ts->regs + OC_INTR_ENABLE); + switch (alarm) { + case THROTTLE_OC1: + r = REG_SET_MASK(r, OC_INTR_OC1_MASK, 1); + break; + case THROTTLE_OC2: + r = REG_SET_MASK(r, OC_INTR_OC2_MASK, 1); + break; + case THROTTLE_OC3: + r = REG_SET_MASK(r, OC_INTR_OC3_MASK, 1); + break; + case THROTTLE_OC4: + r = REG_SET_MASK(r, OC_INTR_OC4_MASK, 1); + break; + default: + r = 0; + break; + } + writel(r, ts->regs + OC_INTR_ENABLE); +} + +/** + * soctherm_handle_alarm() - Handles soctherm alarms + * @alarm: The soctherm throttle id + * + * "Handles" over-current alarms (OC1, OC2, OC3, and OC4) by printing + * a warning or informative message. + * + * Return: -EINVAL for @alarm = THROTTLE_OC3, otherwise 0 (success). + */ +static int soctherm_handle_alarm(enum soctherm_throttle_id alarm) +{ + int rv = -EINVAL; + + switch (alarm) { + case THROTTLE_OC1: + pr_debug("soctherm: Successfully handled OC1 alarm\n"); + rv = 0; + break; + + case THROTTLE_OC2: + pr_debug("soctherm: Successfully handled OC2 alarm\n"); + rv = 0; + break; + + case THROTTLE_OC3: + pr_debug("soctherm: Successfully handled OC3 alarm\n"); + rv = 0; + break; + + case THROTTLE_OC4: + pr_debug("soctherm: Successfully handled OC4 alarm\n"); + rv = 0; + break; + + default: + break; + } + + if (rv) + pr_err("soctherm: ERROR in handling %s alarm\n", + throt_names[alarm]); + + return rv; +} + +/** + * soctherm_edp_isr_thread() - log an over-current interrupt request + * @irq: OC irq number. Currently not being used. See description + * @arg: a void pointer for callback, currently not being used + * + * Over-current events are handled in hardware. This function is called to log + * and handle any OC events that happened. Additionally, it checks every + * over-current interrupt registers for registers are set but + * was not expected (i.e. any discrepancy in interrupt status) by the function, + * the discrepancy will logged. + * + * Return: %IRQ_HANDLED + */ +static irqreturn_t soctherm_edp_isr_thread(int irq, void *arg) +{ + struct tegra_soctherm *ts = arg; + u32 st, ex, oc1, oc2, oc3, oc4; + + st = readl(ts->regs + OC_INTR_STATUS); + + /* deliberately clear expected interrupts handled in SW */ + oc1 = st & OC_INTR_OC1_MASK; + oc2 = st & OC_INTR_OC2_MASK; + oc3 = st & OC_INTR_OC3_MASK; + oc4 = st & OC_INTR_OC4_MASK; + ex = oc1 | oc2 | oc3 | oc4; + + pr_err("soctherm: OC ALARM 0x%08x\n", ex); + if (ex) { + writel(st, ts->regs + OC_INTR_STATUS); + st &= ~ex; + + if (oc1 && !soctherm_handle_alarm(THROTTLE_OC1)) + soctherm_oc_intr_enable(ts, THROTTLE_OC1, true); + + if (oc2 && !soctherm_handle_alarm(THROTTLE_OC2)) + soctherm_oc_intr_enable(ts, THROTTLE_OC2, true); + + if (oc3 && !soctherm_handle_alarm(THROTTLE_OC3)) + soctherm_oc_intr_enable(ts, THROTTLE_OC3, true); + + if (oc4 && !soctherm_handle_alarm(THROTTLE_OC4)) + soctherm_oc_intr_enable(ts, THROTTLE_OC4, true); + + if (oc1 && soc_irq_cdata.irq_enable & BIT(0)) + handle_nested_irq( + irq_find_mapping(soc_irq_cdata.domain, 0)); + + if (oc2 && soc_irq_cdata.irq_enable & BIT(1)) + handle_nested_irq( + irq_find_mapping(soc_irq_cdata.domain, 1)); + + if (oc3 && soc_irq_cdata.irq_enable & BIT(2)) + handle_nested_irq( + irq_find_mapping(soc_irq_cdata.domain, 2)); + + if (oc4 && soc_irq_cdata.irq_enable & BIT(3)) + handle_nested_irq( + irq_find_mapping(soc_irq_cdata.domain, 3)); + } + + if (st) { + pr_err("soctherm: Ignored unexpected OC ALARM 0x%08x\n", st); + writel(st, ts->regs + OC_INTR_STATUS); + } + + return IRQ_HANDLED; +} + +/** + * soctherm_edp_isr() - Disables any active interrupts + * @irq: The interrupt request number + * @arg: Opaque pointer to an argument + * + * Writes to the OC_INTR_DISABLE register the over current interrupt status, + * masking any asserted interrupts. Doing this prevents the same interrupts + * from triggering this isr repeatedly. The thread woken by this isr will + * handle asserted interrupts and subsequently unmask/re-enable them. + * + * The OC_INTR_DISABLE register indicates which OC interrupts + * have been disabled. + * + * Return: %IRQ_WAKE_THREAD, handler requests to wake the handler thread + */ +static irqreturn_t soctherm_edp_isr(int irq, void *arg) +{ + struct tegra_soctherm *ts = arg; + u32 r; + + if (!ts) + return IRQ_NONE; + + r = readl(ts->regs + OC_INTR_STATUS); + writel(r, ts->regs + OC_INTR_DISABLE); + + return IRQ_WAKE_THREAD; +} + +/** + * soctherm_oc_irq_lock() - locks the over-current interrupt request + * @data: Interrupt request data + * + * Looks up the chip data from @data and locks the mutex associated with + * a particular over-current interrupt request. + */ +static void soctherm_oc_irq_lock(struct irq_data *data) +{ + struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data); + + mutex_lock(&d->irq_lock); +} + +/** + * soctherm_oc_irq_sync_unlock() - Unlocks the OC interrupt request + * @data: Interrupt request data + * + * Looks up the interrupt request data @data and unlocks the mutex associated + * with a particular over-current interrupt request. + */ +static void soctherm_oc_irq_sync_unlock(struct irq_data *data) +{ + struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data); + + mutex_unlock(&d->irq_lock); +} + +/** + * soctherm_oc_irq_enable() - Enables the SOC_THERM over-current interrupt queue + * @data: irq_data structure of the chip + * + * Sets the irq_enable bit of SOC_THERM allowing SOC_THERM + * to respond to over-current interrupts. + * + */ +static void soctherm_oc_irq_enable(struct irq_data *data) +{ + struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data); + + d->irq_enable |= BIT(data->hwirq); +} + +/** + * soctherm_oc_irq_disable() - Disables overcurrent interrupt requests + * @irq_data: The interrupt request information + * + * Clears the interrupt request enable bit of the overcurrent + * interrupt request chip data. + * + * Return: Nothing is returned (void) + */ +static void soctherm_oc_irq_disable(struct irq_data *data) +{ + struct soctherm_oc_irq_chip_data *d = irq_data_get_irq_chip_data(data); + + d->irq_enable &= ~BIT(data->hwirq); +} + +static int soctherm_oc_irq_set_type(struct irq_data *data, unsigned int type) +{ + return 0; +} + +/** + * soctherm_oc_irq_map() - SOC_THERM interrupt request domain mapper + * @h: Interrupt request domain + * @virq: Virtual interrupt request number + * @hw: Hardware interrupt request number + * + * Mapping callback function for SOC_THERM's irq_domain. When a SOC_THERM + * interrupt request is called, the irq_domain takes the request's virtual + * request number (much like a virtual memory address) and maps it to a + * physical hardware request number. + * + * When a mapping doesn't already exist for a virtual request number, the + * irq_domain calls this function to associate the virtual request number with + * a hardware request number. + * + * Return: 0 + */ +static int soctherm_oc_irq_map(struct irq_domain *h, unsigned int virq, + irq_hw_number_t hw) +{ + struct soctherm_oc_irq_chip_data *data = h->host_data; + + irq_set_chip_data(virq, data); + irq_set_chip(virq, &data->irq_chip); + irq_set_nested_thread(virq, 1); + return 0; +} + +/** + * soctherm_irq_domain_xlate_twocell() - xlate for soctherm interrupts + * @d: Interrupt request domain + * @intspec: Array of u32s from DTs "interrupt" property + * @intsize: Number of values inside the intspec array + * @out_hwirq: HW IRQ value associated with this interrupt + * @out_type: The IRQ SENSE type for this interrupt. + * + * This Device Tree IRQ specifier translation function will translate a + * specific "interrupt" as defined by 2 DT values where the cell values map + * the hwirq number + 1 and linux irq flags. Since the output is the hwirq + * number, this function will subtract 1 from the value listed in DT. + * + * Return: 0 + */ +static int soctherm_irq_domain_xlate_twocell(struct irq_domain *d, + struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, + irq_hw_number_t *out_hwirq, unsigned int *out_type) +{ + if (WARN_ON(intsize < 2)) + return -EINVAL; + + /* + * The HW value is 1 index less than the DT IRQ values. + * i.e. OC4 goes to HW index 3. + */ + *out_hwirq = intspec[0] - 1; + *out_type = intspec[1] & IRQ_TYPE_SENSE_MASK; + return 0; +} + +static const struct irq_domain_ops soctherm_oc_domain_ops = { + .map = soctherm_oc_irq_map, + .xlate = soctherm_irq_domain_xlate_twocell, +}; + +/** + * soctherm_oc_int_init() - Initial enabling of the over + * current interrupts + * @np: The devicetree node for soctherm + * @num_irqs: The number of new interrupt requests + * + * Sets the over current interrupt request chip data + * + * Return: 0 on success or if overcurrent interrupts are not enabled, + * -ENOMEM (out of memory), or irq_base if the function failed to + * allocate the irqs + */ +static int soctherm_oc_int_init(struct device_node *np, int num_irqs) +{ + if (!num_irqs) { + pr_info("%s(): OC interrupts are not enabled\n", __func__); + return 0; + } + + mutex_init(&soc_irq_cdata.irq_lock); + soc_irq_cdata.irq_enable = 0; + + soc_irq_cdata.irq_chip.name = "soc_therm_oc"; + soc_irq_cdata.irq_chip.irq_bus_lock = soctherm_oc_irq_lock; + soc_irq_cdata.irq_chip.irq_bus_sync_unlock = + soctherm_oc_irq_sync_unlock; + soc_irq_cdata.irq_chip.irq_disable = soctherm_oc_irq_disable; + soc_irq_cdata.irq_chip.irq_enable = soctherm_oc_irq_enable; + soc_irq_cdata.irq_chip.irq_set_type = soctherm_oc_irq_set_type; + soc_irq_cdata.irq_chip.irq_set_wake = NULL; + + soc_irq_cdata.domain = irq_domain_add_linear(np, num_irqs, + &soctherm_oc_domain_ops, + &soc_irq_cdata); + + if (!soc_irq_cdata.domain) { + pr_err("%s: Failed to create IRQ domain\n", __func__); + return -ENOMEM; + } + + pr_debug("%s(): OC interrupts enabled successful\n", __func__); + return 0; +} + #ifdef CONFIG_DEBUG_FS static int regs_show(struct seq_file *s, void *data) { @@ -1504,14 +1899,27 @@ static void tegra_soctherm_throttle(struct device *dev) static int soctherm_interrupts_init(struct platform_device *pdev, struct tegra_soctherm *tegra) { + struct device_node *np = pdev->dev.of_node; int ret; + ret = soctherm_oc_int_init(np, TEGRA_SOC_OC_IRQ_MAX); + if (ret < 0) { + dev_err(&pdev->dev, "soctherm_oc_int_init failed\n"); + return ret; + } + tegra->thermal_irq = platform_get_irq(pdev, 0); if (tegra->thermal_irq < 0) { dev_dbg(&pdev->dev, "get 'thermal_irq' failed.\n"); return 0; } + tegra->edp_irq = platform_get_irq(pdev, 1); + if (tegra->edp_irq < 0) { + dev_dbg(&pdev->dev, "get 'edp_irq' failed.\n"); + return 0; + } + ret = devm_request_threaded_irq(&pdev->dev, tegra->thermal_irq, soctherm_thermal_isr, @@ -1524,6 +1932,18 @@ static int soctherm_interrupts_init(struct platform_device *pdev, return ret; } + ret = devm_request_threaded_irq(&pdev->dev, + tegra->edp_irq, + soctherm_edp_isr, + soctherm_edp_isr_thread, + IRQF_ONESHOT, + "soctherm_edp", + tegra); + if (ret < 0) { + dev_err(&pdev->dev, "request_irq 'edp_irq' failed.\n"); + return ret; + } + return 0; } -- cgit From 8d3d462b684a064a45e68b64d40e9937966802d9 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:46 +0800 Subject: of: Add bindings of OC hw throttle for Tegra soctherm Add OC HW throttle configuration for soctherm in DT. It is used to describe the OCx throttle events. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- .../bindings/thermal/nvidia,tegra124-soctherm.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt index cf6d0be56b7a..f02f38527a6b 100644 --- a/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt +++ b/Documentation/devicetree/bindings/thermal/nvidia,tegra124-soctherm.txt @@ -64,6 +64,20 @@ Required properties : - #cooling-cells: Should be 1. This cooling device only support on/off state. See ./thermal.txt for a description of this property. + Optional properties: The following properties are T210 specific and + valid only for OCx throttle events. + - nvidia,count-threshold: Specifies the number of OC events that are + required for triggering an interrupt. Interrupts are not triggered if + the property is missing. A value of 0 will interrupt on every OC alarm. + - nvidia,polarity-active-low: Configures the polarity of the OC alaram + signal. If present, this means assert low, otherwise assert high. + - nvidia,alarm-filter: Number of clocks to filter event. When the filter + expires (which means the OC event has not occurred for a long time), + the counter is cleared and filter is rearmed. Default value is 0. + - nvidia,throttle-period-us: Specifies the number of uSec for which + throttling is engaged after the OC event is deasserted. Default value + is 0. + Optional properties: - nvidia,thermtrips : When present, this property specifies the temperature at which the soctherm hardware will assert the thermal trigger signal to the @@ -134,6 +148,17 @@ Example : * arbiter will select the highest priority as the final throttle * settings to skip cpu pulse. */ + + throttle_oc1: oc1 { + nvidia,priority = <50>; + nvidia,polarity-active-low; + nvidia,count-threshold = <100>; + nvidia,alarm-filter = <5100000>; + nvidia,throttle-period-us = <0>; + nvidia,cpu-throt-percent = <75>; + nvidia,gpu-throt-level = + ; + }; }; }; -- cgit From 1dcc242c7c75897bf0dfbcd1f563b7ab71cb4bb4 Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Thu, 21 Feb 2019 18:18:47 +0800 Subject: thermal: tegra: enable OC hw throttle Parse Over Current settings from DT and program them to generate interrupts. Also enable hw throttling whenever there are OC events. Log the OC events as debug messages. Signed-off-by: Wei Ni Signed-off-by: Eduardo Valentin --- drivers/thermal/tegra/soctherm.c | 130 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 120 insertions(+), 10 deletions(-) diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c index 35a9f1ef9d85..fcf70a3728b6 100644 --- a/drivers/thermal/tegra/soctherm.c +++ b/drivers/thermal/tegra/soctherm.c @@ -106,9 +106,26 @@ #define STATS_CTL_CLR_UP 0x2 #define STATS_CTL_EN_UP 0x1 +#define OC1_CFG 0x310 +#define OC1_CFG_LONG_LATENCY_MASK BIT(6) +#define OC1_CFG_HW_RESTORE_MASK BIT(5) +#define OC1_CFG_PWR_GOOD_MASK_MASK BIT(4) +#define OC1_CFG_THROTTLE_MODE_MASK (0x3 << 2) +#define OC1_CFG_ALARM_POLARITY_MASK BIT(1) +#define OC1_CFG_EN_THROTTLE_MASK BIT(0) + +#define OC1_CNT_THRESHOLD 0x314 +#define OC1_THROTTLE_PERIOD 0x318 +#define OC1_ALARM_COUNT 0x31c +#define OC1_FILTER 0x320 +#define OC1_STATS 0x3a8 + #define OC_INTR_STATUS 0x39c #define OC_INTR_ENABLE 0x3a0 #define OC_INTR_DISABLE 0x3a4 +#define OC_STATS_CTL 0x3c4 +#define OC_STATS_CTL_CLR_ALL 0x2 +#define OC_STATS_CTL_EN_ALL 0x1 #define OC_INTR_OC1_MASK BIT(0) #define OC_INTR_OC2_MASK BIT(1) @@ -207,6 +224,25 @@ #define THROT_DELAY_CTRL(throt) (THROT_DELAY_LITE + \ (THROT_OFFSET * throt)) +#define ALARM_OFFSET 0x14 +#define ALARM_CFG(throt) (OC1_CFG + \ + (ALARM_OFFSET * (throt - THROTTLE_OC1))) + +#define ALARM_CNT_THRESHOLD(throt) (OC1_CNT_THRESHOLD + \ + (ALARM_OFFSET * (throt - THROTTLE_OC1))) + +#define ALARM_THROTTLE_PERIOD(throt) (OC1_THROTTLE_PERIOD + \ + (ALARM_OFFSET * (throt - THROTTLE_OC1))) + +#define ALARM_ALARM_COUNT(throt) (OC1_ALARM_COUNT + \ + (ALARM_OFFSET * (throt - THROTTLE_OC1))) + +#define ALARM_FILTER(throt) (OC1_FILTER + \ + (ALARM_OFFSET * (throt - THROTTLE_OC1))) + +#define ALARM_STATS(throt) (OC1_STATS + \ + (4 * (throt - THROTTLE_OC1))) + /* get CCROC_THROT_PSKIP_xxx offset per HIGH/MED/LOW vect*/ #define CCROC_THROT_OFFSET 0x0c #define CCROC_THROT_PSKIP_CTRL_CPU_REG(vect) (CCROC_THROT_PSKIP_CTRL_CPU + \ @@ -218,6 +254,9 @@ #define THERMCTL_LVL_REGS_SIZE 0x20 #define THERMCTL_LVL_REG(rg, lv) ((rg) + ((lv) * THERMCTL_LVL_REGS_SIZE)) +#define OC_THROTTLE_MODE_DISABLED 0 +#define OC_THROTTLE_MODE_BRIEF 2 + static const int min_low_temp = -127000; static const int max_high_temp = 127000; @@ -266,6 +305,15 @@ struct tegra_thermctl_zone { const struct tegra_tsensor_group *sg; }; +struct soctherm_oc_cfg { + u32 active_low; + u32 throt_period; + u32 alarm_cnt_thresh; + u32 alarm_filter; + u32 mode; + bool intr_en; +}; + struct soctherm_throt_cfg { const char *name; unsigned int id; @@ -273,6 +321,7 @@ struct soctherm_throt_cfg { u8 cpu_throt_level; u32 cpu_throt_depth; u32 gpu_throt_level; + struct soctherm_oc_cfg oc_cfg; struct thermal_cooling_device *cdev; bool init; }; @@ -747,7 +796,7 @@ static int tegra_soctherm_set_hwtrips(struct device *dev, return 0; } - for (i = 0; i < THROTTLE_SIZE; i++) { + for (i = 0; i < THROTTLE_OC1; i++) { struct thermal_cooling_device *cdev; if (!ts->throt_cfgs[i].init) @@ -1569,6 +1618,32 @@ static int soctherm_thermtrips_parse(struct platform_device *pdev) return 0; } +static void soctherm_oc_cfg_parse(struct device *dev, + struct device_node *np_oc, + struct soctherm_throt_cfg *stc) +{ + u32 val; + + if (of_property_read_bool(np_oc, "nvidia,polarity-active-low")) + stc->oc_cfg.active_low = 1; + else + stc->oc_cfg.active_low = 0; + + if (!of_property_read_u32(np_oc, "nvidia,count-threshold", &val)) { + stc->oc_cfg.intr_en = 1; + stc->oc_cfg.alarm_cnt_thresh = val; + } + + if (!of_property_read_u32(np_oc, "nvidia,throttle-period-us", &val)) + stc->oc_cfg.throt_period = val; + + if (!of_property_read_u32(np_oc, "nvidia,alarm-filter", &val)) + stc->oc_cfg.alarm_filter = val; + + /* BRIEF throttling by default, do not support STICKY */ + stc->oc_cfg.mode = OC_THROTTLE_MODE_BRIEF; +} + static int soctherm_throt_cfg_parse(struct device *dev, struct device_node *np, struct soctherm_throt_cfg *stc) @@ -1651,24 +1726,34 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev) continue; } + if (stc->init) { + dev_err(dev, "throttle-cfg: %s: redefined!\n", name); + of_node_put(np_stcc); + break; + } err = soctherm_throt_cfg_parse(dev, np_stcc, stc); if (err) continue; - tcd = thermal_of_cooling_device_register(np_stcc, + if (stc->id >= THROTTLE_OC1) { + soctherm_oc_cfg_parse(dev, np_stcc, stc); + stc->init = true; + } else { + + tcd = thermal_of_cooling_device_register(np_stcc, (char *)name, ts, &throt_cooling_ops); - of_node_put(np_stcc); - if (IS_ERR_OR_NULL(tcd)) { - dev_err(dev, - "throttle-cfg: %s: failed to register cooling device\n", - name); - continue; + if (IS_ERR_OR_NULL(tcd)) { + dev_err(dev, + "throttle-cfg: %s: failed to register cooling device\n", + name); + continue; + } + stc->cdev = tcd; + stc->init = true; } - stc->cdev = tcd; - stc->init = true; } of_node_put(np_stc); @@ -1819,6 +1904,28 @@ static void throttlectl_gpu_level_select(struct tegra_soctherm *ts, writel(r, ts->regs + THROT_PSKIP_CTRL(throt, THROTTLE_DEV_GPU)); } +static int soctherm_oc_cfg_program(struct tegra_soctherm *ts, + enum soctherm_throttle_id throt) +{ + u32 r; + struct soctherm_oc_cfg *oc = &ts->throt_cfgs[throt].oc_cfg; + + if (oc->mode == OC_THROTTLE_MODE_DISABLED) + return -EINVAL; + + r = REG_SET_MASK(0, OC1_CFG_HW_RESTORE_MASK, 1); + r = REG_SET_MASK(r, OC1_CFG_THROTTLE_MODE_MASK, oc->mode); + r = REG_SET_MASK(r, OC1_CFG_ALARM_POLARITY_MASK, oc->active_low); + r = REG_SET_MASK(r, OC1_CFG_EN_THROTTLE_MASK, 1); + writel(r, ts->regs + ALARM_CFG(throt)); + writel(oc->throt_period, ts->regs + ALARM_THROTTLE_PERIOD(throt)); + writel(oc->alarm_cnt_thresh, ts->regs + ALARM_CNT_THRESHOLD(throt)); + writel(oc->alarm_filter, ts->regs + ALARM_FILTER(throt)); + soctherm_oc_intr_enable(ts, throt, oc->intr_en); + + return 0; +} + /** * soctherm_throttle_program() - programs pulse skippers' configuration * @throt: the LIGHT/HEAVY of the throttle event id. @@ -1835,6 +1942,9 @@ static void soctherm_throttle_program(struct tegra_soctherm *ts, if (!stc.init) return; + if ((throt >= THROTTLE_OC1) && (soctherm_oc_cfg_program(ts, throt))) + return; + /* Setup PSKIP parameters */ if (ts->soc->use_ccroc) throttlectl_cpu_level_select(ts, throt); -- cgit From 7ffd87c63d36b28109c0d7898a1f44fea7d9dac8 Mon Sep 17 00:00:00 2001 From: Yangtao Li Date: Sun, 24 Feb 2019 02:10:58 -0500 Subject: of: thermal: Improve print information Define pr_fmt macro to add a prefix to the message, this can make the thermal log better recognized. Before: [ 0.602672] nfc: nfc_init: NFC Core ver 0.1 [ 0.602828] NET: Registered protocol family 39 [ 0.603435] clocksource: Switched to clocksource mct-frc [ 0.746216] failed to build thermal zone cpu-thermal: -22 [ 0.746451] NET: Registered protocol family 2 After: [ 0.602804] NET: Registered protocol family 39 [ 0.603463] clocksource: Switched to clocksource mct-frc [ 0.746309] thermal_sys: failed to build thermal zone cpu-thermal: -22 [ 0.746545] NET: Registered protocol family 2 Signed-off-by: Yangtao Li Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 2df059cc07e2..dc5093be553e 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -5,6 +5,9 @@ * Copyright (C) 2013 Texas Instruments * Copyright (C) 2013 Eduardo Valentin */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include -- cgit From 0f54aa5cafbe8434e2938c1cc64ac2e4fe60f0c0 Mon Sep 17 00:00:00 2001 From: "Enrico Weigelt, metux IT consult" Date: Wed, 6 Mar 2019 23:05:24 +0100 Subject: drivers: thermal: Kconfig: pedantic cleanups Formatting of Kconfig files doesn't look so pretty, so just take damp cloth and clean it up. Signed-off-by: Enrico Weigelt, metux IT consult Signed-off-by: Eduardo Valentin --- drivers/thermal/st/Kconfig | 22 +++++++++++----------- drivers/thermal/tegra/Kconfig | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig index b80f9a9e4f8f..d8b1a4586d0b 100644 --- a/drivers/thermal/st/Kconfig +++ b/drivers/thermal/st/Kconfig @@ -3,9 +3,9 @@ # config ST_THERMAL - tristate "Thermal sensors on STMicroelectronics STi series of SoCs" - help - Support for thermal sensors on STMicroelectronics STi series of SoCs. + tristate "Thermal sensors on STMicroelectronics STi series of SoCs" + help + Support for thermal sensors on STMicroelectronics STi series of SoCs. config ST_THERMAL_SYSCFG select ST_THERMAL @@ -16,11 +16,11 @@ config ST_THERMAL_MEMMAP tristate "STi series memory mapped access based thermal sensors" config STM32_THERMAL - tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs" - depends on MACH_STM32MP157 - default y - help - Support for thermal framework on STMicroelectronics STM32 series of - SoCs. This thermal driver allows to access to general thermal framework - functionalities and to acces to SoC sensor functionalities. This - configuration is fully dependent of MACH_STM32MP157. + tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs" + depends on MACH_STM32MP157 + default y + help + Support for thermal framework on STMicroelectronics STM32 series of + SoCs. This thermal driver allows to access to general thermal framework + functionalities and to acces to SoC sensor functionalities. This + configuration is fully dependent of MACH_STM32MP157. diff --git a/drivers/thermal/tegra/Kconfig b/drivers/thermal/tegra/Kconfig index f8740f7852e3..fc0b33b3f26b 100644 --- a/drivers/thermal/tegra/Kconfig +++ b/drivers/thermal/tegra/Kconfig @@ -14,7 +14,7 @@ config TEGRA_BPMP_THERMAL tristate "Tegra BPMP thermal sensing" depends on TEGRA_BPMP || COMPILE_TEST help - Enable this option for support for sensing system temperature of NVIDIA - Tegra systems-on-chip with the BPMP coprocessor (Tegra186). + Enable this option for support for sensing system temperature of NVIDIA + Tegra systems-on-chip with the BPMP coprocessor (Tegra186). endmenu -- cgit From df535485bb74aa4bb25f2715d776ccea807a7809 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 Mar 2019 17:36:35 +0100 Subject: thermal: stm32: simplify getting .driver_data We should get 'driver_data' from 'struct device' directly. Going via platform_device is an unneeded step back and forth. Signed-off-by: Wolfram Sang Reviewed-by: Simon Horman Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/st/stm_thermal.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c index bbd73c5a4a4e..cf9ddc52f30e 100644 --- a/drivers/thermal/st/stm_thermal.c +++ b/drivers/thermal/st/stm_thermal.c @@ -570,8 +570,7 @@ thermal_unprepare: static int stm_thermal_suspend(struct device *dev) { int ret; - struct platform_device *pdev = to_platform_device(dev); - struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); + struct stm_thermal_sensor *sensor = dev_get_drvdata(dev); ret = stm_thermal_sensor_off(sensor); if (ret) @@ -585,8 +584,7 @@ static int stm_thermal_suspend(struct device *dev) static int stm_thermal_resume(struct device *dev) { int ret; - struct platform_device *pdev = to_platform_device(dev); - struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); + struct stm_thermal_sensor *sensor = dev_get_drvdata(dev); ret = stm_thermal_prepare(sensor); if (ret) -- cgit From 20a7a2db19dfaec4518c60d51e612d961d68a5f6 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:41 +0530 Subject: drivers: thermal: tsens: Document the data structures Describe how the TSENS device and the various sensors connected to it are described in the driver Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens.h | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 7b7feee5dc46..89318523c848 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -14,6 +14,16 @@ struct tsens_device; +/** + * struct tsens_sensor - data for each sensor connected to the tsens device + * @tmdev: tsens device instance that this sensor is connected to + * @tzd: pointer to the thermal zone that this sensor is in + * @offset: offset of temperature adjustment curve + * @id: Sensor ID + * @hw_id: HW ID can be used in case of platform-specific IDs + * @slope: slope of temperature adjustment curve + * @status: 8960-specific variable to track 8960 and 8660 status register offset + */ struct tsens_sensor { struct tsens_device *tmdev; struct thermal_zone_device *tzd; @@ -55,8 +65,8 @@ enum reg_list { }; /** - * struct tsens_data - tsens instance specific data - * @num_sensors: Max number of sensors supported by platform + * struct tsens_data - tsens platform data + * @num_sensors: Number of sensors supported by platform * @ops: operations the tsens instance supports * @hw_ids: Subset of sensors ids supported by platform, if not the first n * @reg_offsets: Register offsets for commonly used registers @@ -68,12 +78,27 @@ struct tsens_data { unsigned int *hw_ids; }; -/* Registers to be saved/restored across a context loss */ +/** + * struct tsens_context - Registers to be saved/restored across a context loss + */ struct tsens_context { int threshold; int control; }; +/** + * struct tsens_device - private data for each instance of the tsens IP + * @dev: pointer to struct device + * @num_sensors: number of sensors enabled on this device + * @tm_map: pointer to TM register address space + * @srot_map: pointer to SROT register address space + * @tm_offset: deal with old device trees that don't address TM and SROT + * address space separately + * @reg_offsets: array of offsets to important regs for this version of IP + * @ctx: registers to be saved and restored during suspend/resume + * @ops: pointer to list of callbacks supported by this device + * @sensor: list of sensors attached to this device + */ struct tsens_device { struct device *dev; u32 num_sensors; -- cgit From 3c040ce087a2e841998804c077aa72818f004d1e Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:42 +0530 Subject: drivers: thermal: tsens: Rename tsens_data Rename to tsens_plat_data to denote that it is platform-data passed in at compile-time. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-8916.c | 2 +- drivers/thermal/qcom/tsens-8960.c | 2 +- drivers/thermal/qcom/tsens-8974.c | 2 +- drivers/thermal/qcom/tsens-v2.c | 4 ++-- drivers/thermal/qcom/tsens.c | 2 +- drivers/thermal/qcom/tsens.h | 8 ++++---- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c index c6dd620ac029..66edcfca1526 100644 --- a/drivers/thermal/qcom/tsens-8916.c +++ b/drivers/thermal/qcom/tsens-8916.c @@ -97,7 +97,7 @@ static const struct tsens_ops ops_8916 = { .get_temp = get_temp_common, }; -const struct tsens_data data_8916 = { +const struct tsens_plat_data data_8916 = { .num_sensors = 5, .ops = &ops_8916, .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c index 0f0adb302a7b..f3c3820e6e8e 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -277,7 +277,7 @@ static const struct tsens_ops ops_8960 = { .resume = resume_8960, }; -const struct tsens_data data_8960 = { +const struct tsens_plat_data data_8960 = { .num_sensors = 11, .ops = &ops_8960, }; diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c index 3d3fda3d731b..5023f20afc14 100644 --- a/drivers/thermal/qcom/tsens-8974.c +++ b/drivers/thermal/qcom/tsens-8974.c @@ -229,7 +229,7 @@ static const struct tsens_ops ops_8974 = { .get_temp = get_temp_common, }; -const struct tsens_data data_8974 = { +const struct tsens_plat_data data_8974 = { .num_sensors = 11, .ops = &ops_8974, .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 381a212872bf..cc98a61e093b 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -66,13 +66,13 @@ static const struct tsens_ops ops_generic_v2 = { .get_temp = get_temp_tsens_v2, }; -const struct tsens_data data_tsens_v2 = { +const struct tsens_plat_data data_tsens_v2 = { .ops = &ops_generic_v2, .reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 }, }; /* Kept around for backward compatibility with old msm8996.dtsi */ -const struct tsens_data data_8996 = { +const struct tsens_plat_data data_8996 = { .num_sensors = 13, .ops = &ops_generic_v2, .reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 }, diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index f1ec9bbe4717..065ec2189bd3 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -102,7 +102,7 @@ static int tsens_probe(struct platform_device *pdev) struct device *dev; struct device_node *np; struct tsens_device *tmdev; - const struct tsens_data *data; + const struct tsens_plat_data *data; const struct of_device_id *id; u32 num_sensors; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 89318523c848..232376c690cc 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -65,13 +65,13 @@ enum reg_list { }; /** - * struct tsens_data - tsens platform data + * struct tsens_plat_data - tsens compile-time platform data * @num_sensors: Number of sensors supported by platform * @ops: operations the tsens instance supports * @hw_ids: Subset of sensors ids supported by platform, if not the first n * @reg_offsets: Register offsets for commonly used registers */ -struct tsens_data { +struct tsens_plat_data { const u32 num_sensors; const struct tsens_ops *ops; const u16 reg_offsets[REG_ARRAY_SIZE]; @@ -117,8 +117,8 @@ int init_common(struct tsens_device *); int get_temp_common(struct tsens_device *, int, int *); /* TSENS v1 targets */ -extern const struct tsens_data data_8916, data_8974, data_8960; +extern const struct tsens_plat_data data_8916, data_8974, data_8960; /* TSENS v2 targets */ -extern const struct tsens_data data_8996, data_tsens_v2; +extern const struct tsens_plat_data data_8996, data_tsens_v2; #endif /* __QCOM_TSENS_H__ */ -- cgit From 24ae447291bb4bdb860a88f55184cf92632a7a36 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:43 +0530 Subject: drivers: thermal: tsens: Rename tsens_device Rename to tsens_priv to denote that it is private data for each tsens instance. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-8916.c | 2 +- drivers/thermal/qcom/tsens-8960.c | 14 +++++++------- drivers/thermal/qcom/tsens-8974.c | 2 +- drivers/thermal/qcom/tsens-common.c | 6 +++--- drivers/thermal/qcom/tsens-v2.c | 2 +- drivers/thermal/qcom/tsens.c | 14 +++++++------- drivers/thermal/qcom/tsens.h | 30 +++++++++++++++--------------- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c index 66edcfca1526..7b8f83c9a033 100644 --- a/drivers/thermal/qcom/tsens-8916.c +++ b/drivers/thermal/qcom/tsens-8916.c @@ -39,7 +39,7 @@ #define CAL_SEL_MASK 0xe0000000 #define CAL_SEL_SHIFT 29 -static int calibrate_8916(struct tsens_device *tmdev) +static int calibrate_8916(struct tsens_priv *tmdev) { int base0 = 0, base1 = 0, i; u32 p1[5], p2[5]; diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c index f3c3820e6e8e..7e340eea48da 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -56,7 +56,7 @@ #define TRDY_MASK BIT(7) #define TIMEOUT_US 100 -static int suspend_8960(struct tsens_device *tmdev) +static int suspend_8960(struct tsens_priv *tmdev) { int ret; unsigned int mask; @@ -82,7 +82,7 @@ static int suspend_8960(struct tsens_device *tmdev) return 0; } -static int resume_8960(struct tsens_device *tmdev) +static int resume_8960(struct tsens_priv *tmdev) { int ret; struct regmap *map = tmdev->tm_map; @@ -112,7 +112,7 @@ static int resume_8960(struct tsens_device *tmdev) return 0; } -static int enable_8960(struct tsens_device *tmdev, int id) +static int enable_8960(struct tsens_priv *tmdev, int id) { int ret; u32 reg, mask; @@ -138,7 +138,7 @@ static int enable_8960(struct tsens_device *tmdev, int id) return 0; } -static void disable_8960(struct tsens_device *tmdev) +static void disable_8960(struct tsens_priv *tmdev) { int ret; u32 reg_cntl; @@ -162,7 +162,7 @@ static void disable_8960(struct tsens_device *tmdev) regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); } -static int init_8960(struct tsens_device *tmdev) +static int init_8960(struct tsens_priv *tmdev) { int ret, i; u32 reg_cntl; @@ -212,7 +212,7 @@ static int init_8960(struct tsens_device *tmdev) return 0; } -static int calibrate_8960(struct tsens_device *tmdev) +static int calibrate_8960(struct tsens_priv *tmdev) { int i; char *data; @@ -243,7 +243,7 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) return adc_code * slope + offset; } -static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp) +static int get_temp_8960(struct tsens_priv *tmdev, int id, int *temp) { int ret; u32 code, trdy; diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c index 5023f20afc14..f983f98f2176 100644 --- a/drivers/thermal/qcom/tsens-8974.c +++ b/drivers/thermal/qcom/tsens-8974.c @@ -91,7 +91,7 @@ #define BIT_APPEND 0x3 -static int calibrate_8974(struct tsens_device *tmdev) +static int calibrate_8974(struct tsens_priv *tmdev) { int base1 = 0, base2 = 0, i; u32 p1[11], p2[11]; diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index f80c73f11740..46f8c68c70f5 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -46,7 +46,7 @@ char *qfprom_read(struct device *dev, const char *cname) * and offset values are derived from tz->tzp->slope and tz->tzp->offset * resp. */ -void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, +void compute_intercept_slope(struct tsens_priv *tmdev, u32 *p1, u32 *p2, u32 mode) { int i; @@ -95,7 +95,7 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) return degc; } -int get_temp_common(struct tsens_device *tmdev, int id, int *temp) +int get_temp_common(struct tsens_priv *tmdev, int id, int *temp) { struct tsens_sensor *s = &tmdev->sensor[id]; u32 code; @@ -127,7 +127,7 @@ static const struct regmap_config tsens_srot_config = { .reg_stride = 4, }; -int __init init_common(struct tsens_device *tmdev) +int __init init_common(struct tsens_priv *tmdev) { void __iomem *tm_base, *srot_base; struct resource *res; diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index cc98a61e093b..d812fd3f4567 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -12,7 +12,7 @@ #define LAST_TEMP_MASK 0xfff #define STATUS_VALID_BIT BIT(21) -static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp) +static int get_temp_tsens_v2(struct tsens_priv *tmdev, int id, int *temp) { struct tsens_sensor *s = &tmdev->sensor[id]; u32 code; diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 065ec2189bd3..074fbb4d70f2 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -15,7 +15,7 @@ static int tsens_get_temp(void *data, int *temp) { const struct tsens_sensor *s = data; - struct tsens_device *tmdev = s->tmdev; + struct tsens_priv *tmdev = s->tmdev; return tmdev->ops->get_temp(tmdev, s->id, temp); } @@ -23,7 +23,7 @@ static int tsens_get_temp(void *data, int *temp) static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) { const struct tsens_sensor *s = p; - struct tsens_device *tmdev = s->tmdev; + struct tsens_priv *tmdev = s->tmdev; if (tmdev->ops->get_trend) return tmdev->ops->get_trend(tmdev, s->id, trend); @@ -33,7 +33,7 @@ static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) static int __maybe_unused tsens_suspend(struct device *dev) { - struct tsens_device *tmdev = dev_get_drvdata(dev); + struct tsens_priv *tmdev = dev_get_drvdata(dev); if (tmdev->ops && tmdev->ops->suspend) return tmdev->ops->suspend(tmdev); @@ -43,7 +43,7 @@ static int __maybe_unused tsens_suspend(struct device *dev) static int __maybe_unused tsens_resume(struct device *dev) { - struct tsens_device *tmdev = dev_get_drvdata(dev); + struct tsens_priv *tmdev = dev_get_drvdata(dev); if (tmdev->ops && tmdev->ops->resume) return tmdev->ops->resume(tmdev); @@ -76,7 +76,7 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = { .get_trend = tsens_get_trend, }; -static int tsens_register(struct tsens_device *tmdev) +static int tsens_register(struct tsens_priv *tmdev) { int i; struct thermal_zone_device *tzd; @@ -101,7 +101,7 @@ static int tsens_probe(struct platform_device *pdev) int ret, i; struct device *dev; struct device_node *np; - struct tsens_device *tmdev; + struct tsens_priv *tmdev; const struct tsens_plat_data *data; const struct of_device_id *id; u32 num_sensors; @@ -174,7 +174,7 @@ static int tsens_probe(struct platform_device *pdev) static int tsens_remove(struct platform_device *pdev) { - struct tsens_device *tmdev = platform_get_drvdata(pdev); + struct tsens_priv *tmdev = platform_get_drvdata(pdev); if (tmdev->ops->disable) tmdev->ops->disable(tmdev); diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 232376c690cc..936bdc7b1bc2 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -12,7 +12,7 @@ #include -struct tsens_device; +struct tsens_priv; /** * struct tsens_sensor - data for each sensor connected to the tsens device @@ -25,7 +25,7 @@ struct tsens_device; * @status: 8960-specific variable to track 8960 and 8660 status register offset */ struct tsens_sensor { - struct tsens_device *tmdev; + struct tsens_priv *tmdev; struct thermal_zone_device *tzd; int offset; int id; @@ -47,15 +47,15 @@ struct tsens_sensor { */ struct tsens_ops { /* mandatory callbacks */ - int (*init)(struct tsens_device *); - int (*calibrate)(struct tsens_device *); - int (*get_temp)(struct tsens_device *, int, int *); + int (*init)(struct tsens_priv *); + int (*calibrate)(struct tsens_priv *); + int (*get_temp)(struct tsens_priv *, int, int *); /* optional callbacks */ - int (*enable)(struct tsens_device *, int); - void (*disable)(struct tsens_device *); - int (*suspend)(struct tsens_device *); - int (*resume)(struct tsens_device *); - int (*get_trend)(struct tsens_device *, int, enum thermal_trend *); + int (*enable)(struct tsens_priv *, int); + void (*disable)(struct tsens_priv *); + int (*suspend)(struct tsens_priv *); + int (*resume)(struct tsens_priv *); + int (*get_trend)(struct tsens_priv *, int, enum thermal_trend *); }; enum reg_list { @@ -87,7 +87,7 @@ struct tsens_context { }; /** - * struct tsens_device - private data for each instance of the tsens IP + * struct tsens_priv - private data for each instance of the tsens IP * @dev: pointer to struct device * @num_sensors: number of sensors enabled on this device * @tm_map: pointer to TM register address space @@ -99,7 +99,7 @@ struct tsens_context { * @ops: pointer to list of callbacks supported by this device * @sensor: list of sensors attached to this device */ -struct tsens_device { +struct tsens_priv { struct device *dev; u32 num_sensors; struct regmap *tm_map; @@ -112,9 +112,9 @@ struct tsens_device { }; char *qfprom_read(struct device *, const char *); -void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32); -int init_common(struct tsens_device *); -int get_temp_common(struct tsens_device *, int, int *); +void compute_intercept_slope(struct tsens_priv *, u32 *, u32 *, u32); +int init_common(struct tsens_priv *); +int get_temp_common(struct tsens_priv *, int, int *); /* TSENS v1 targets */ extern const struct tsens_plat_data data_8916, data_8974, data_8960; -- cgit From 69b628ac71f07d667d09393d1f597f543ccd5240 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:44 +0530 Subject: drivers: thermal: tsens: Rename variable tmdev tmdev seems to imply that this is a device pointer when in fact it is just private platform data for each tsens device. Rename it to priv improve code readability. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-8916.c | 16 ++++---- drivers/thermal/qcom/tsens-8960.c | 82 ++++++++++++++++++------------------- drivers/thermal/qcom/tsens-8974.c | 16 ++++---- drivers/thermal/qcom/tsens-common.c | 53 ++++++++++++------------ drivers/thermal/qcom/tsens-v2.c | 12 +++--- drivers/thermal/qcom/tsens.c | 80 ++++++++++++++++++------------------ drivers/thermal/qcom/tsens.h | 4 +- 7 files changed, 131 insertions(+), 132 deletions(-) diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c index 7b8f83c9a033..d4ad4082c800 100644 --- a/drivers/thermal/qcom/tsens-8916.c +++ b/drivers/thermal/qcom/tsens-8916.c @@ -39,23 +39,23 @@ #define CAL_SEL_MASK 0xe0000000 #define CAL_SEL_SHIFT 29 -static int calibrate_8916(struct tsens_priv *tmdev) +static int calibrate_8916(struct tsens_priv *priv) { int base0 = 0, base1 = 0, i; u32 p1[5], p2[5]; int mode = 0; u32 *qfprom_cdata, *qfprom_csel; - qfprom_cdata = (u32 *)qfprom_read(tmdev->dev, "calib"); + qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); if (IS_ERR(qfprom_cdata)) return PTR_ERR(qfprom_cdata); - qfprom_csel = (u32 *)qfprom_read(tmdev->dev, "calib_sel"); + qfprom_csel = (u32 *)qfprom_read(priv->dev, "calib_sel"); if (IS_ERR(qfprom_csel)) return PTR_ERR(qfprom_csel); mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; - dev_dbg(tmdev->dev, "calibration mode is %d\n", mode); + dev_dbg(priv->dev, "calibration mode is %d\n", mode); switch (mode) { case TWO_PT_CALIB: @@ -65,7 +65,7 @@ static int calibrate_8916(struct tsens_priv *tmdev) p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT; p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; - for (i = 0; i < tmdev->num_sensors; i++) + for (i = 0; i < priv->num_sensors; i++) p2[i] = ((base1 + p2[i]) << 3); /* Fall through */ case ONE_PT_CALIB2: @@ -75,18 +75,18 @@ static int calibrate_8916(struct tsens_priv *tmdev) p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; - for (i = 0; i < tmdev->num_sensors; i++) + for (i = 0; i < priv->num_sensors; i++) p1[i] = (((base0) + p1[i]) << 3); break; default: - for (i = 0; i < tmdev->num_sensors; i++) { + for (i = 0; i < priv->num_sensors; i++) { p1[i] = 500; p2[i] = 780; } break; } - compute_intercept_slope(tmdev, p1, p2, mode); + compute_intercept_slope(priv, p1, p2, mode); return 0; } diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c index 7e340eea48da..8d9b721dadb6 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -56,21 +56,21 @@ #define TRDY_MASK BIT(7) #define TIMEOUT_US 100 -static int suspend_8960(struct tsens_priv *tmdev) +static int suspend_8960(struct tsens_priv *priv) { int ret; unsigned int mask; - struct regmap *map = tmdev->tm_map; + struct regmap *map = priv->tm_map; - ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold); + ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold); if (ret) return ret; - ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control); + ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control); if (ret) return ret; - if (tmdev->num_sensors > 1) + if (priv->num_sensors > 1) mask = SLP_CLK_ENA | EN; else mask = SLP_CLK_ENA_8660 | EN; @@ -82,10 +82,10 @@ static int suspend_8960(struct tsens_priv *tmdev) return 0; } -static int resume_8960(struct tsens_priv *tmdev) +static int resume_8960(struct tsens_priv *priv) { int ret; - struct regmap *map = tmdev->tm_map; + struct regmap *map = priv->tm_map; ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); if (ret) @@ -95,80 +95,80 @@ static int resume_8960(struct tsens_priv *tmdev) * Separate CONFIG restore is not needed only for 8660 as * config is part of CTRL Addr and its restored as such */ - if (tmdev->num_sensors > 1) { + if (priv->num_sensors > 1) { ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); if (ret) return ret; } - ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold); + ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold); if (ret) return ret; - ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control); + ret = regmap_write(map, CNTL_ADDR, priv->ctx.control); if (ret) return ret; return 0; } -static int enable_8960(struct tsens_priv *tmdev, int id) +static int enable_8960(struct tsens_priv *priv, int id) { int ret; u32 reg, mask; - ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®); + ret = regmap_read(priv->tm_map, CNTL_ADDR, ®); if (ret) return ret; mask = BIT(id + SENSOR0_SHIFT); - ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST); + ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST); if (ret) return ret; - if (tmdev->num_sensors > 1) + if (priv->num_sensors > 1) reg |= mask | SLP_CLK_ENA | EN; else reg |= mask | SLP_CLK_ENA_8660 | EN; - ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg); + ret = regmap_write(priv->tm_map, CNTL_ADDR, reg); if (ret) return ret; return 0; } -static void disable_8960(struct tsens_priv *tmdev) +static void disable_8960(struct tsens_priv *priv) { int ret; u32 reg_cntl; u32 mask; - mask = GENMASK(tmdev->num_sensors - 1, 0); + mask = GENMASK(priv->num_sensors - 1, 0); mask <<= SENSOR0_SHIFT; mask |= EN; - ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®_cntl); + ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl); if (ret) return; reg_cntl &= ~mask; - if (tmdev->num_sensors > 1) + if (priv->num_sensors > 1) reg_cntl &= ~SLP_CLK_ENA; else reg_cntl &= ~SLP_CLK_ENA_8660; - regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); + regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); } -static int init_8960(struct tsens_priv *tmdev) +static int init_8960(struct tsens_priv *priv) { int ret, i; u32 reg_cntl; - tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL); - if (!tmdev->tm_map) + priv->tm_map = dev_get_regmap(priv->dev, NULL); + if (!priv->tm_map) return -ENODEV; /* @@ -177,21 +177,21 @@ static int init_8960(struct tsens_priv *tmdev) * but the control registers stay in the same place, i.e * directly after the first 5 status registers. */ - for (i = 0; i < tmdev->num_sensors; i++) { + for (i = 0; i < priv->num_sensors; i++) { if (i >= 5) - tmdev->sensor[i].status = S0_STATUS_ADDR + 40; - tmdev->sensor[i].status += i * 4; + priv->sensor[i].status = S0_STATUS_ADDR + 40; + priv->sensor[i].status += i * 4; } reg_cntl = SW_RST; - ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl); + ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl); if (ret) return ret; - if (tmdev->num_sensors > 1) { + if (priv->num_sensors > 1) { reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); reg_cntl &= ~SW_RST; - ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR, + ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR, CONFIG_MASK, CONFIG); } else { reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); @@ -199,30 +199,30 @@ static int init_8960(struct tsens_priv *tmdev) reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; } - reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT; - ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); + reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT; + ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); if (ret) return ret; reg_cntl |= EN; - ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); + ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl); if (ret) return ret; return 0; } -static int calibrate_8960(struct tsens_priv *tmdev) +static int calibrate_8960(struct tsens_priv *priv) { int i; char *data; - ssize_t num_read = tmdev->num_sensors; - struct tsens_sensor *s = tmdev->sensor; + ssize_t num_read = priv->num_sensors; + struct tsens_sensor *s = priv->sensor; - data = qfprom_read(tmdev->dev, "calib"); + data = qfprom_read(priv->dev, "calib"); if (IS_ERR(data)) - data = qfprom_read(tmdev->dev, "calib_backup"); + data = qfprom_read(priv->dev, "calib_backup"); if (IS_ERR(data)) return PTR_ERR(data); @@ -243,21 +243,21 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) return adc_code * slope + offset; } -static int get_temp_8960(struct tsens_priv *tmdev, int id, int *temp) +static int get_temp_8960(struct tsens_priv *priv, int id, int *temp) { int ret; u32 code, trdy; - const struct tsens_sensor *s = &tmdev->sensor[id]; + const struct tsens_sensor *s = &priv->sensor[id]; unsigned long timeout; timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); do { - ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy); + ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy); if (ret) return ret; if (!(trdy & TRDY_MASK)) continue; - ret = regmap_read(tmdev->tm_map, s->status, &code); + ret = regmap_read(priv->tm_map, s->status, &code); if (ret) return ret; *temp = code_to_mdegC(code, s); diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c index f983f98f2176..303157fd00be 100644 --- a/drivers/thermal/qcom/tsens-8974.c +++ b/drivers/thermal/qcom/tsens-8974.c @@ -91,7 +91,7 @@ #define BIT_APPEND 0x3 -static int calibrate_8974(struct tsens_priv *tmdev) +static int calibrate_8974(struct tsens_priv *priv) { int base1 = 0, base2 = 0, i; u32 p1[11], p2[11]; @@ -99,11 +99,11 @@ static int calibrate_8974(struct tsens_priv *tmdev) u32 *calib, *bkp; u32 calib_redun_sel; - calib = (u32 *)qfprom_read(tmdev->dev, "calib"); + calib = (u32 *)qfprom_read(priv->dev, "calib"); if (IS_ERR(calib)) return PTR_ERR(calib); - bkp = (u32 *)qfprom_read(tmdev->dev, "calib_backup"); + bkp = (u32 *)qfprom_read(priv->dev, "calib_backup"); if (IS_ERR(bkp)) return PTR_ERR(bkp); @@ -184,25 +184,25 @@ static int calibrate_8974(struct tsens_priv *tmdev) switch (mode) { case ONE_PT_CALIB: - for (i = 0; i < tmdev->num_sensors; i++) + for (i = 0; i < priv->num_sensors; i++) p1[i] += (base1 << 2) | BIT_APPEND; break; case TWO_PT_CALIB: - for (i = 0; i < tmdev->num_sensors; i++) { + for (i = 0; i < priv->num_sensors; i++) { p2[i] += base2; p2[i] <<= 2; p2[i] |= BIT_APPEND; } /* Fall through */ case ONE_PT_CALIB2: - for (i = 0; i < tmdev->num_sensors; i++) { + for (i = 0; i < priv->num_sensors; i++) { p1[i] += base1; p1[i] <<= 2; p1[i] |= BIT_APPEND; } break; default: - for (i = 0; i < tmdev->num_sensors; i++) + for (i = 0; i < priv->num_sensors; i++) p2[i] = 780; p1[0] = 502; p1[1] = 509; @@ -218,7 +218,7 @@ static int calibrate_8974(struct tsens_priv *tmdev) break; } - compute_intercept_slope(tmdev, p1, p2, mode); + compute_intercept_slope(priv, p1, p2, mode); return 0; } diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 46f8c68c70f5..f0ef4e3cf7f9 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -46,18 +46,18 @@ char *qfprom_read(struct device *dev, const char *cname) * and offset values are derived from tz->tzp->slope and tz->tzp->offset * resp. */ -void compute_intercept_slope(struct tsens_priv *tmdev, u32 *p1, +void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, u32 *p2, u32 mode) { int i; int num, den; - for (i = 0; i < tmdev->num_sensors; i++) { - dev_dbg(tmdev->dev, + for (i = 0; i < priv->num_sensors; i++) { + dev_dbg(priv->dev, "sensor%d - data_point1:%#x data_point2:%#x\n", i, p1[i], p2[i]); - tmdev->sensor[i].slope = SLOPE_DEFAULT; + priv->sensor[i].slope = SLOPE_DEFAULT; if (mode == TWO_PT_CALIB) { /* * slope (m) = adc_code2 - adc_code1 (y2 - y1)/ @@ -66,13 +66,13 @@ void compute_intercept_slope(struct tsens_priv *tmdev, u32 *p1, num = p2[i] - p1[i]; num *= SLOPE_FACTOR; den = CAL_DEGC_PT2 - CAL_DEGC_PT1; - tmdev->sensor[i].slope = num / den; + priv->sensor[i].slope = num / den; } - tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - + priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - (CAL_DEGC_PT1 * - tmdev->sensor[i].slope); - dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset); + priv->sensor[i].slope); + dev_dbg(priv->dev, "offset:%d\n", priv->sensor[i].offset); } } @@ -95,15 +95,15 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) return degc; } -int get_temp_common(struct tsens_priv *tmdev, int id, int *temp) +int get_temp_common(struct tsens_priv *priv, int id, int *temp) { - struct tsens_sensor *s = &tmdev->sensor[id]; + struct tsens_sensor *s = &priv->sensor[id]; u32 code; unsigned int status_reg; int last_temp = 0, ret; - status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; - ret = regmap_read(tmdev->tm_map, status_reg, &code); + status_reg = priv->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; + ret = regmap_read(priv->tm_map, status_reg, &code); if (ret) return ret; last_temp = code & SN_ST_TEMP_MASK; @@ -127,21 +127,21 @@ static const struct regmap_config tsens_srot_config = { .reg_stride = 4, }; -int __init init_common(struct tsens_priv *tmdev) +int __init init_common(struct tsens_priv *priv) { void __iomem *tm_base, *srot_base; struct resource *res; u32 code; int ret; - struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node); - u16 ctrl_offset = tmdev->reg_offsets[SROT_CTRL_OFFSET]; + struct platform_device *op = of_find_device_by_node(priv->dev->of_node); + u16 ctrl_offset = priv->reg_offsets[SROT_CTRL_OFFSET]; if (!op) return -EINVAL; if (op->num_resources > 1) { /* DT with separate SROT and TM address space */ - tmdev->tm_offset = 0; + priv->tm_offset = 0; res = platform_get_resource(op, IORESOURCE_MEM, 1); srot_base = devm_ioremap_resource(&op->dev, res); if (IS_ERR(srot_base)) { @@ -149,16 +149,15 @@ int __init init_common(struct tsens_priv *tmdev) goto err_put_device; } - tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, srot_base, + priv->srot_map = devm_regmap_init_mmio(priv->dev, srot_base, &tsens_srot_config); - if (IS_ERR(tmdev->srot_map)) { - ret = PTR_ERR(tmdev->srot_map); + if (IS_ERR(priv->srot_map)) { + ret = PTR_ERR(priv->srot_map); goto err_put_device; } - } else { /* old DTs where SROT and TM were in a contiguous 2K block */ - tmdev->tm_offset = 0x1000; + priv->tm_offset = 0x1000; } res = platform_get_resource(op, IORESOURCE_MEM, 0); @@ -168,18 +167,18 @@ int __init init_common(struct tsens_priv *tmdev) goto err_put_device; } - tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config); - if (IS_ERR(tmdev->tm_map)) { - ret = PTR_ERR(tmdev->tm_map); + priv->tm_map = devm_regmap_init_mmio(priv->dev, tm_base, &tsens_config); + if (IS_ERR(priv->tm_map)) { + ret = PTR_ERR(priv->tm_map); goto err_put_device; } - if (tmdev->srot_map) { - ret = regmap_read(tmdev->srot_map, ctrl_offset, &code); + if (priv->srot_map) { + ret = regmap_read(priv->srot_map, ctrl_offset, &code); if (ret) goto err_put_device; if (!(code & TSENS_EN)) { - dev_err(tmdev->dev, "tsens device is not enabled\n"); + dev_err(priv->dev, "tsens device is not enabled\n"); ret = -ENODEV; goto err_put_device; } diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index d812fd3f4567..8b700772d903 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -12,16 +12,16 @@ #define LAST_TEMP_MASK 0xfff #define STATUS_VALID_BIT BIT(21) -static int get_temp_tsens_v2(struct tsens_priv *tmdev, int id, int *temp) +static int get_temp_tsens_v2(struct tsens_priv *priv, int id, int *temp) { - struct tsens_sensor *s = &tmdev->sensor[id]; + struct tsens_sensor *s = &priv->sensor[id]; u32 code; unsigned int status_reg; u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0; int ret; - status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * 4; - ret = regmap_read(tmdev->tm_map, status_reg, &code); + status_reg = priv->tm_offset + STATUS_OFFSET + s->hw_id * 4; + ret = regmap_read(priv->tm_map, status_reg, &code); if (ret) return ret; last_temp = code & LAST_TEMP_MASK; @@ -29,7 +29,7 @@ static int get_temp_tsens_v2(struct tsens_priv *tmdev, int id, int *temp) goto done; /* Try a second time */ - ret = regmap_read(tmdev->tm_map, status_reg, &code); + ret = regmap_read(priv->tm_map, status_reg, &code); if (ret) return ret; if (code & STATUS_VALID_BIT) { @@ -40,7 +40,7 @@ static int get_temp_tsens_v2(struct tsens_priv *tmdev, int id, int *temp) } /* Try a third/last time */ - ret = regmap_read(tmdev->tm_map, status_reg, &code); + ret = regmap_read(priv->tm_map, status_reg, &code); if (ret) return ret; if (code & STATUS_VALID_BIT) { diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 074fbb4d70f2..4582d2b30e94 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -15,38 +15,38 @@ static int tsens_get_temp(void *data, int *temp) { const struct tsens_sensor *s = data; - struct tsens_priv *tmdev = s->tmdev; + struct tsens_priv *priv = s->priv; - return tmdev->ops->get_temp(tmdev, s->id, temp); + return priv->ops->get_temp(priv, s->id, temp); } static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) { const struct tsens_sensor *s = p; - struct tsens_priv *tmdev = s->tmdev; + struct tsens_priv *priv = s->priv; - if (tmdev->ops->get_trend) - return tmdev->ops->get_trend(tmdev, s->id, trend); + if (priv->ops->get_trend) + return priv->ops->get_trend(priv, s->id, trend); return -ENOTSUPP; } static int __maybe_unused tsens_suspend(struct device *dev) { - struct tsens_priv *tmdev = dev_get_drvdata(dev); + struct tsens_priv *priv = dev_get_drvdata(dev); - if (tmdev->ops && tmdev->ops->suspend) - return tmdev->ops->suspend(tmdev); + if (priv->ops && priv->ops->suspend) + return priv->ops->suspend(priv); return 0; } static int __maybe_unused tsens_resume(struct device *dev) { - struct tsens_priv *tmdev = dev_get_drvdata(dev); + struct tsens_priv *priv = dev_get_drvdata(dev); - if (tmdev->ops && tmdev->ops->resume) - return tmdev->ops->resume(tmdev); + if (priv->ops && priv->ops->resume) + return priv->ops->resume(priv); return 0; } @@ -76,22 +76,22 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = { .get_trend = tsens_get_trend, }; -static int tsens_register(struct tsens_priv *tmdev) +static int tsens_register(struct tsens_priv *priv) { int i; struct thermal_zone_device *tzd; - for (i = 0; i < tmdev->num_sensors; i++) { - tmdev->sensor[i].tmdev = tmdev; - tmdev->sensor[i].id = i; - tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i, - &tmdev->sensor[i], + for (i = 0; i < priv->num_sensors; i++) { + priv->sensor[i].priv = priv; + priv->sensor[i].id = i; + tzd = devm_thermal_zone_of_sensor_register(priv->dev, i, + &priv->sensor[i], &tsens_of_ops); if (IS_ERR(tzd)) continue; - tmdev->sensor[i].tzd = tzd; - if (tmdev->ops->enable) - tmdev->ops->enable(tmdev, i); + priv->sensor[i].tzd = tzd; + if (priv->ops->enable) + priv->ops->enable(priv, i); } return 0; } @@ -101,7 +101,7 @@ static int tsens_probe(struct platform_device *pdev) int ret, i; struct device *dev; struct device_node *np; - struct tsens_priv *tmdev; + struct tsens_priv *priv; const struct tsens_plat_data *data; const struct of_device_id *id; u32 num_sensors; @@ -129,55 +129,55 @@ static int tsens_probe(struct platform_device *pdev) return -EINVAL; } - tmdev = devm_kzalloc(dev, - struct_size(tmdev, sensor, num_sensors), + priv = devm_kzalloc(dev, + struct_size(priv, sensor, num_sensors), GFP_KERNEL); - if (!tmdev) + if (!priv) return -ENOMEM; - tmdev->dev = dev; - tmdev->num_sensors = num_sensors; - tmdev->ops = data->ops; - for (i = 0; i < tmdev->num_sensors; i++) { + priv->dev = dev; + priv->num_sensors = num_sensors; + priv->ops = data->ops; + for (i = 0; i < priv->num_sensors; i++) { if (data->hw_ids) - tmdev->sensor[i].hw_id = data->hw_ids[i]; + priv->sensor[i].hw_id = data->hw_ids[i]; else - tmdev->sensor[i].hw_id = i; + priv->sensor[i].hw_id = i; } for (i = 0; i < REG_ARRAY_SIZE; i++) { - tmdev->reg_offsets[i] = data->reg_offsets[i]; + priv->reg_offsets[i] = data->reg_offsets[i]; } - if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp) + if (!priv->ops || !priv->ops->init || !priv->ops->get_temp) return -EINVAL; - ret = tmdev->ops->init(tmdev); + ret = priv->ops->init(priv); if (ret < 0) { dev_err(dev, "tsens init failed\n"); return ret; } - if (tmdev->ops->calibrate) { - ret = tmdev->ops->calibrate(tmdev); + if (priv->ops->calibrate) { + ret = priv->ops->calibrate(priv); if (ret < 0) { dev_err(dev, "tsens calibration failed\n"); return ret; } } - ret = tsens_register(tmdev); + ret = tsens_register(priv); - platform_set_drvdata(pdev, tmdev); + platform_set_drvdata(pdev, priv); return ret; } static int tsens_remove(struct platform_device *pdev) { - struct tsens_priv *tmdev = platform_get_drvdata(pdev); + struct tsens_priv *priv = platform_get_drvdata(pdev); - if (tmdev->ops->disable) - tmdev->ops->disable(tmdev); + if (priv->ops->disable) + priv->ops->disable(priv); return 0; } diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 936bdc7b1bc2..61ca2905ee7a 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -16,7 +16,7 @@ struct tsens_priv; /** * struct tsens_sensor - data for each sensor connected to the tsens device - * @tmdev: tsens device instance that this sensor is connected to + * @priv: tsens device instance that this sensor is connected to * @tzd: pointer to the thermal zone that this sensor is in * @offset: offset of temperature adjustment curve * @id: Sensor ID @@ -25,7 +25,7 @@ struct tsens_priv; * @status: 8960-specific variable to track 8960 and 8660 status register offset */ struct tsens_sensor { - struct tsens_priv *tmdev; + struct tsens_priv *priv; struct thermal_zone_device *tzd; int offset; int id; -- cgit From 2cbcd2eab01b28148ebc21c1821a7f8187a923f4 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:45 +0530 Subject: drivers: thermal: tsens: Use consistent names for variables tsens_get_temp() uses the name 'data' for the void pointer, use the same in tsens_get_trend() for consistency. Remove a stray space while we're at it. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 4582d2b30e94..0b5be08d515f 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -20,13 +20,13 @@ static int tsens_get_temp(void *data, int *temp) return priv->ops->get_temp(priv, s->id, temp); } -static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) +static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend) { - const struct tsens_sensor *s = p; + const struct tsens_sensor *s = data; struct tsens_priv *priv = s->priv; if (priv->ops->get_trend) - return priv->ops->get_trend(priv, s->id, trend); + return priv->ops->get_trend(priv, s->id, trend); return -ENOTSUPP; } -- cgit From 68b3314d7c77b52f67a912e1a37096ca672978da Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:46 +0530 Subject: drivers: thermal: tsens: Function prototypes should have argument names check_patch complains a lot as follows: WARNING: function definition argument 'struct tsens_priv *' should also have an identifier name + int (*init)(struct tsens_priv *); Fix it. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 61ca2905ee7a..4d6a406f8dca 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -47,15 +47,15 @@ struct tsens_sensor { */ struct tsens_ops { /* mandatory callbacks */ - int (*init)(struct tsens_priv *); - int (*calibrate)(struct tsens_priv *); - int (*get_temp)(struct tsens_priv *, int, int *); + int (*init)(struct tsens_priv *priv); + int (*calibrate)(struct tsens_priv *priv); + int (*get_temp)(struct tsens_priv *priv, int i, int *temp); /* optional callbacks */ - int (*enable)(struct tsens_priv *, int); - void (*disable)(struct tsens_priv *); - int (*suspend)(struct tsens_priv *); - int (*resume)(struct tsens_priv *); - int (*get_trend)(struct tsens_priv *, int, enum thermal_trend *); + int (*enable)(struct tsens_priv *priv, int i); + void (*disable)(struct tsens_priv *priv); + int (*suspend)(struct tsens_priv *priv); + int (*resume)(struct tsens_priv *priv); + int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend); }; enum reg_list { @@ -111,10 +111,10 @@ struct tsens_priv { struct tsens_sensor sensor[0]; }; -char *qfprom_read(struct device *, const char *); -void compute_intercept_slope(struct tsens_priv *, u32 *, u32 *, u32); -int init_common(struct tsens_priv *); -int get_temp_common(struct tsens_priv *, int, int *); +char *qfprom_read(struct device *dev, const char *cname); +void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode); +int init_common(struct tsens_priv *priv); +int get_temp_common(struct tsens_priv *priv, int i, int *temp); /* TSENS v1 targets */ extern const struct tsens_plat_data data_8916, data_8974, data_8960; -- cgit From 2be20763031bcd15b4908afda931a99ecfc1417c Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:47 +0530 Subject: drivers: thermal: tsens: Rename tsens-8916 to prepare to merge with tsens-8974 8916 and 8974 use v0.1.0 of the TSENS IP. Rename tsens-8916 to prepare it for merging with tsens-8974 in a later commit. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/Makefile | 2 +- drivers/thermal/qcom/tsens-8916.c | 105 -------------------------------------- drivers/thermal/qcom/tsens-v0_1.c | 105 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 106 deletions(-) delete mode 100644 drivers/thermal/qcom/tsens-8916.c create mode 100644 drivers/thermal/qcom/tsens-v0_1.c diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 717a08600bb5..1f2fafd43dff 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o -qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-v2.o +qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o tsens-8974.o tsens-8960.o tsens-v2.o obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c deleted file mode 100644 index d4ad4082c800..000000000000 --- a/drivers/thermal/qcom/tsens-8916.c +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. - */ - -#include -#include "tsens.h" - -/* eeprom layout data for 8916 */ -#define BASE0_MASK 0x0000007f -#define BASE1_MASK 0xfe000000 -#define BASE0_SHIFT 0 -#define BASE1_SHIFT 25 - -#define S0_P1_MASK 0x00000f80 -#define S1_P1_MASK 0x003e0000 -#define S2_P1_MASK 0xf8000000 -#define S3_P1_MASK 0x000003e0 -#define S4_P1_MASK 0x000f8000 - -#define S0_P2_MASK 0x0001f000 -#define S1_P2_MASK 0x07c00000 -#define S2_P2_MASK 0x0000001f -#define S3_P2_MASK 0x00007c00 -#define S4_P2_MASK 0x01f00000 - -#define S0_P1_SHIFT 7 -#define S1_P1_SHIFT 17 -#define S2_P1_SHIFT 27 -#define S3_P1_SHIFT 5 -#define S4_P1_SHIFT 15 - -#define S0_P2_SHIFT 12 -#define S1_P2_SHIFT 22 -#define S2_P2_SHIFT 0 -#define S3_P2_SHIFT 10 -#define S4_P2_SHIFT 20 - -#define CAL_SEL_MASK 0xe0000000 -#define CAL_SEL_SHIFT 29 - -static int calibrate_8916(struct tsens_priv *priv) -{ - int base0 = 0, base1 = 0, i; - u32 p1[5], p2[5]; - int mode = 0; - u32 *qfprom_cdata, *qfprom_csel; - - qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); - if (IS_ERR(qfprom_cdata)) - return PTR_ERR(qfprom_cdata); - - qfprom_csel = (u32 *)qfprom_read(priv->dev, "calib_sel"); - if (IS_ERR(qfprom_csel)) - return PTR_ERR(qfprom_csel); - - mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; - dev_dbg(priv->dev, "calibration mode is %d\n", mode); - - switch (mode) { - case TWO_PT_CALIB: - base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT; - p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT; - p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT; - p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT; - p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; - p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; - for (i = 0; i < priv->num_sensors; i++) - p2[i] = ((base1 + p2[i]) << 3); - /* Fall through */ - case ONE_PT_CALIB2: - base0 = (qfprom_cdata[0] & BASE0_MASK); - p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT; - p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT; - p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; - p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; - p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; - for (i = 0; i < priv->num_sensors; i++) - p1[i] = (((base0) + p1[i]) << 3); - break; - default: - for (i = 0; i < priv->num_sensors; i++) { - p1[i] = 500; - p2[i] = 780; - } - break; - } - - compute_intercept_slope(priv, p1, p2, mode); - - return 0; -} - -static const struct tsens_ops ops_8916 = { - .init = init_common, - .calibrate = calibrate_8916, - .get_temp = get_temp_common, -}; - -const struct tsens_plat_data data_8916 = { - .num_sensors = 5, - .ops = &ops_8916, - .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, - .hw_ids = (unsigned int []){0, 1, 2, 4, 5 }, -}; diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c new file mode 100644 index 000000000000..d4ad4082c800 --- /dev/null +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + */ + +#include +#include "tsens.h" + +/* eeprom layout data for 8916 */ +#define BASE0_MASK 0x0000007f +#define BASE1_MASK 0xfe000000 +#define BASE0_SHIFT 0 +#define BASE1_SHIFT 25 + +#define S0_P1_MASK 0x00000f80 +#define S1_P1_MASK 0x003e0000 +#define S2_P1_MASK 0xf8000000 +#define S3_P1_MASK 0x000003e0 +#define S4_P1_MASK 0x000f8000 + +#define S0_P2_MASK 0x0001f000 +#define S1_P2_MASK 0x07c00000 +#define S2_P2_MASK 0x0000001f +#define S3_P2_MASK 0x00007c00 +#define S4_P2_MASK 0x01f00000 + +#define S0_P1_SHIFT 7 +#define S1_P1_SHIFT 17 +#define S2_P1_SHIFT 27 +#define S3_P1_SHIFT 5 +#define S4_P1_SHIFT 15 + +#define S0_P2_SHIFT 12 +#define S1_P2_SHIFT 22 +#define S2_P2_SHIFT 0 +#define S3_P2_SHIFT 10 +#define S4_P2_SHIFT 20 + +#define CAL_SEL_MASK 0xe0000000 +#define CAL_SEL_SHIFT 29 + +static int calibrate_8916(struct tsens_priv *priv) +{ + int base0 = 0, base1 = 0, i; + u32 p1[5], p2[5]; + int mode = 0; + u32 *qfprom_cdata, *qfprom_csel; + + qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); + if (IS_ERR(qfprom_cdata)) + return PTR_ERR(qfprom_cdata); + + qfprom_csel = (u32 *)qfprom_read(priv->dev, "calib_sel"); + if (IS_ERR(qfprom_csel)) + return PTR_ERR(qfprom_csel); + + mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; + dev_dbg(priv->dev, "calibration mode is %d\n", mode); + + switch (mode) { + case TWO_PT_CALIB: + base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT; + p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT; + p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT; + p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT; + p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; + p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; + for (i = 0; i < priv->num_sensors; i++) + p2[i] = ((base1 + p2[i]) << 3); + /* Fall through */ + case ONE_PT_CALIB2: + base0 = (qfprom_cdata[0] & BASE0_MASK); + p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; + for (i = 0; i < priv->num_sensors; i++) + p1[i] = (((base0) + p1[i]) << 3); + break; + default: + for (i = 0; i < priv->num_sensors; i++) { + p1[i] = 500; + p2[i] = 780; + } + break; + } + + compute_intercept_slope(priv, p1, p2, mode); + + return 0; +} + +static const struct tsens_ops ops_8916 = { + .init = init_common, + .calibrate = calibrate_8916, + .get_temp = get_temp_common, +}; + +const struct tsens_plat_data data_8916 = { + .num_sensors = 5, + .ops = &ops_8916, + .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, + .hw_ids = (unsigned int []){0, 1, 2, 4, 5 }, +}; -- cgit From 774ccb08194754817f7bb6131dfa2a3842fe00aa Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:48 +0530 Subject: drivers: thermal: tsens: Rename constants to prepare to merge with tsens-8974 Some #defines in tsens-v_0_1.c clash with those in tsens-8974.c. Prefix them with 8916 to avoid the clash so we can merge the two files. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-v0_1.c | 88 +++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c index d4ad4082c800..30909594b1cf 100644 --- a/drivers/thermal/qcom/tsens-v0_1.c +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -7,37 +7,37 @@ #include "tsens.h" /* eeprom layout data for 8916 */ -#define BASE0_MASK 0x0000007f -#define BASE1_MASK 0xfe000000 -#define BASE0_SHIFT 0 -#define BASE1_SHIFT 25 - -#define S0_P1_MASK 0x00000f80 -#define S1_P1_MASK 0x003e0000 -#define S2_P1_MASK 0xf8000000 -#define S3_P1_MASK 0x000003e0 -#define S4_P1_MASK 0x000f8000 - -#define S0_P2_MASK 0x0001f000 -#define S1_P2_MASK 0x07c00000 -#define S2_P2_MASK 0x0000001f -#define S3_P2_MASK 0x00007c00 -#define S4_P2_MASK 0x01f00000 - -#define S0_P1_SHIFT 7 -#define S1_P1_SHIFT 17 -#define S2_P1_SHIFT 27 -#define S3_P1_SHIFT 5 -#define S4_P1_SHIFT 15 - -#define S0_P2_SHIFT 12 -#define S1_P2_SHIFT 22 -#define S2_P2_SHIFT 0 -#define S3_P2_SHIFT 10 -#define S4_P2_SHIFT 20 - -#define CAL_SEL_MASK 0xe0000000 -#define CAL_SEL_SHIFT 29 +#define MSM8916_BASE0_MASK 0x0000007f +#define MSM8916_BASE1_MASK 0xfe000000 +#define MSM8916_BASE0_SHIFT 0 +#define MSM8916_BASE1_SHIFT 25 + +#define MSM8916_S0_P1_MASK 0x00000f80 +#define MSM8916_S1_P1_MASK 0x003e0000 +#define MSM8916_S2_P1_MASK 0xf8000000 +#define MSM8916_S3_P1_MASK 0x000003e0 +#define MSM8916_S4_P1_MASK 0x000f8000 + +#define MSM8916_S0_P2_MASK 0x0001f000 +#define MSM8916_S1_P2_MASK 0x07c00000 +#define MSM8916_S2_P2_MASK 0x0000001f +#define MSM8916_S3_P2_MASK 0x00007c00 +#define MSM8916_S4_P2_MASK 0x01f00000 + +#define MSM8916_S0_P1_SHIFT 7 +#define MSM8916_S1_P1_SHIFT 17 +#define MSM8916_S2_P1_SHIFT 27 +#define MSM8916_S3_P1_SHIFT 5 +#define MSM8916_S4_P1_SHIFT 15 + +#define MSM8916_S0_P2_SHIFT 12 +#define MSM8916_S1_P2_SHIFT 22 +#define MSM8916_S2_P2_SHIFT 0 +#define MSM8916_S3_P2_SHIFT 10 +#define MSM8916_S4_P2_SHIFT 20 + +#define MSM8916_CAL_SEL_MASK 0xe0000000 +#define MSM8916_CAL_SEL_SHIFT 29 static int calibrate_8916(struct tsens_priv *priv) { @@ -54,27 +54,27 @@ static int calibrate_8916(struct tsens_priv *priv) if (IS_ERR(qfprom_csel)) return PTR_ERR(qfprom_csel); - mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; + mode = (qfprom_csel[0] & MSM8916_CAL_SEL_MASK) >> MSM8916_CAL_SEL_SHIFT; dev_dbg(priv->dev, "calibration mode is %d\n", mode); switch (mode) { case TWO_PT_CALIB: - base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT; - p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT; - p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT; - p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT; - p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; - p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; + base1 = (qfprom_cdata[1] & MSM8916_BASE1_MASK) >> MSM8916_BASE1_SHIFT; + p2[0] = (qfprom_cdata[0] & MSM8916_S0_P2_MASK) >> MSM8916_S0_P2_SHIFT; + p2[1] = (qfprom_cdata[0] & MSM8916_S1_P2_MASK) >> MSM8916_S1_P2_SHIFT; + p2[2] = (qfprom_cdata[1] & MSM8916_S2_P2_MASK) >> MSM8916_S2_P2_SHIFT; + p2[3] = (qfprom_cdata[1] & MSM8916_S3_P2_MASK) >> MSM8916_S3_P2_SHIFT; + p2[4] = (qfprom_cdata[1] & MSM8916_S4_P2_MASK) >> MSM8916_S4_P2_SHIFT; for (i = 0; i < priv->num_sensors; i++) p2[i] = ((base1 + p2[i]) << 3); /* Fall through */ case ONE_PT_CALIB2: - base0 = (qfprom_cdata[0] & BASE0_MASK); - p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT; - p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT; - p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; - p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; - p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; + base0 = (qfprom_cdata[0] & MSM8916_BASE0_MASK); + p1[0] = (qfprom_cdata[0] & MSM8916_S0_P1_MASK) >> MSM8916_S0_P1_SHIFT; + p1[1] = (qfprom_cdata[0] & MSM8916_S1_P1_MASK) >> MSM8916_S1_P1_SHIFT; + p1[2] = (qfprom_cdata[0] & MSM8916_S2_P1_MASK) >> MSM8916_S2_P1_SHIFT; + p1[3] = (qfprom_cdata[1] & MSM8916_S3_P1_MASK) >> MSM8916_S3_P1_SHIFT; + p1[4] = (qfprom_cdata[1] & MSM8916_S4_P1_MASK) >> MSM8916_S4_P1_SHIFT; for (i = 0; i < priv->num_sensors; i++) p1[i] = (((base0) + p1[i]) << 3); break; -- cgit From 582a0c4194a528d435bf0d638605c05c755d41df Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:49 +0530 Subject: drivers: thermal: tsens: Merge tsens-8974 into tsens-v0_1 8974 and 8916 have the same version of the TSENS IP. Merge the files to allow for better code reuse. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/Makefile | 2 +- drivers/thermal/qcom/tsens-8974.c | 236 -------------------------------------- drivers/thermal/qcom/tsens-v0_1.c | 229 ++++++++++++++++++++++++++++++++++++ drivers/thermal/qcom/tsens.h | 8 +- 4 files changed, 236 insertions(+), 239 deletions(-) delete mode 100644 drivers/thermal/qcom/tsens-8974.c diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 1f2fafd43dff..7fa3cadce760 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -1,3 +1,3 @@ obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o -qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o tsens-8974.o tsens-8960.o tsens-v2.o +qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o tsens-8960.o tsens-v2.o obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c deleted file mode 100644 index 303157fd00be..000000000000 --- a/drivers/thermal/qcom/tsens-8974.c +++ /dev/null @@ -1,236 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (c) 2015, The Linux Foundation. All rights reserved. - */ - -#include -#include "tsens.h" - -/* eeprom layout data for 8974 */ -#define BASE1_MASK 0xff -#define S0_P1_MASK 0x3f00 -#define S1_P1_MASK 0xfc000 -#define S2_P1_MASK 0x3f00000 -#define S3_P1_MASK 0xfc000000 -#define S4_P1_MASK 0x3f -#define S5_P1_MASK 0xfc0 -#define S6_P1_MASK 0x3f000 -#define S7_P1_MASK 0xfc0000 -#define S8_P1_MASK 0x3f000000 -#define S8_P1_MASK_BKP 0x3f -#define S9_P1_MASK 0x3f -#define S9_P1_MASK_BKP 0xfc0 -#define S10_P1_MASK 0xfc0 -#define S10_P1_MASK_BKP 0x3f000 -#define CAL_SEL_0_1 0xc0000000 -#define CAL_SEL_2 0x40000000 -#define CAL_SEL_SHIFT 30 -#define CAL_SEL_SHIFT_2 28 - -#define S0_P1_SHIFT 8 -#define S1_P1_SHIFT 14 -#define S2_P1_SHIFT 20 -#define S3_P1_SHIFT 26 -#define S5_P1_SHIFT 6 -#define S6_P1_SHIFT 12 -#define S7_P1_SHIFT 18 -#define S8_P1_SHIFT 24 -#define S9_P1_BKP_SHIFT 6 -#define S10_P1_SHIFT 6 -#define S10_P1_BKP_SHIFT 12 - -#define BASE2_SHIFT 12 -#define BASE2_BKP_SHIFT 18 -#define S0_P2_SHIFT 20 -#define S0_P2_BKP_SHIFT 26 -#define S1_P2_SHIFT 26 -#define S2_P2_BKP_SHIFT 6 -#define S3_P2_SHIFT 6 -#define S3_P2_BKP_SHIFT 12 -#define S4_P2_SHIFT 12 -#define S4_P2_BKP_SHIFT 18 -#define S5_P2_SHIFT 18 -#define S5_P2_BKP_SHIFT 24 -#define S6_P2_SHIFT 24 -#define S7_P2_BKP_SHIFT 6 -#define S8_P2_SHIFT 6 -#define S8_P2_BKP_SHIFT 12 -#define S9_P2_SHIFT 12 -#define S9_P2_BKP_SHIFT 18 -#define S10_P2_SHIFT 18 -#define S10_P2_BKP_SHIFT 24 - -#define BASE2_MASK 0xff000 -#define BASE2_BKP_MASK 0xfc0000 -#define S0_P2_MASK 0x3f00000 -#define S0_P2_BKP_MASK 0xfc000000 -#define S1_P2_MASK 0xfc000000 -#define S1_P2_BKP_MASK 0x3f -#define S2_P2_MASK 0x3f -#define S2_P2_BKP_MASK 0xfc0 -#define S3_P2_MASK 0xfc0 -#define S3_P2_BKP_MASK 0x3f000 -#define S4_P2_MASK 0x3f000 -#define S4_P2_BKP_MASK 0xfc0000 -#define S5_P2_MASK 0xfc0000 -#define S5_P2_BKP_MASK 0x3f000000 -#define S6_P2_MASK 0x3f000000 -#define S6_P2_BKP_MASK 0x3f -#define S7_P2_MASK 0x3f -#define S7_P2_BKP_MASK 0xfc0 -#define S8_P2_MASK 0xfc0 -#define S8_P2_BKP_MASK 0x3f000 -#define S9_P2_MASK 0x3f000 -#define S9_P2_BKP_MASK 0xfc0000 -#define S10_P2_MASK 0xfc0000 -#define S10_P2_BKP_MASK 0x3f000000 - -#define BKP_SEL 0x3 -#define BKP_REDUN_SEL 0xe0000000 -#define BKP_REDUN_SHIFT 29 - -#define BIT_APPEND 0x3 - -static int calibrate_8974(struct tsens_priv *priv) -{ - int base1 = 0, base2 = 0, i; - u32 p1[11], p2[11]; - int mode = 0; - u32 *calib, *bkp; - u32 calib_redun_sel; - - calib = (u32 *)qfprom_read(priv->dev, "calib"); - if (IS_ERR(calib)) - return PTR_ERR(calib); - - bkp = (u32 *)qfprom_read(priv->dev, "calib_backup"); - if (IS_ERR(bkp)) - return PTR_ERR(bkp); - - calib_redun_sel = bkp[1] & BKP_REDUN_SEL; - calib_redun_sel >>= BKP_REDUN_SHIFT; - - if (calib_redun_sel == BKP_SEL) { - mode = (calib[4] & CAL_SEL_0_1) >> CAL_SEL_SHIFT; - mode |= (calib[5] & CAL_SEL_2) >> CAL_SEL_SHIFT_2; - - switch (mode) { - case TWO_PT_CALIB: - base2 = (bkp[2] & BASE2_BKP_MASK) >> BASE2_BKP_SHIFT; - p2[0] = (bkp[2] & S0_P2_BKP_MASK) >> S0_P2_BKP_SHIFT; - p2[1] = (bkp[3] & S1_P2_BKP_MASK); - p2[2] = (bkp[3] & S2_P2_BKP_MASK) >> S2_P2_BKP_SHIFT; - p2[3] = (bkp[3] & S3_P2_BKP_MASK) >> S3_P2_BKP_SHIFT; - p2[4] = (bkp[3] & S4_P2_BKP_MASK) >> S4_P2_BKP_SHIFT; - p2[5] = (calib[4] & S5_P2_BKP_MASK) >> S5_P2_BKP_SHIFT; - p2[6] = (calib[5] & S6_P2_BKP_MASK); - p2[7] = (calib[5] & S7_P2_BKP_MASK) >> S7_P2_BKP_SHIFT; - p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT; - p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT; - p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT; - /* Fall through */ - case ONE_PT_CALIB: - case ONE_PT_CALIB2: - base1 = bkp[0] & BASE1_MASK; - p1[0] = (bkp[0] & S0_P1_MASK) >> S0_P1_SHIFT; - p1[1] = (bkp[0] & S1_P1_MASK) >> S1_P1_SHIFT; - p1[2] = (bkp[0] & S2_P1_MASK) >> S2_P1_SHIFT; - p1[3] = (bkp[0] & S3_P1_MASK) >> S3_P1_SHIFT; - p1[4] = (bkp[1] & S4_P1_MASK); - p1[5] = (bkp[1] & S5_P1_MASK) >> S5_P1_SHIFT; - p1[6] = (bkp[1] & S6_P1_MASK) >> S6_P1_SHIFT; - p1[7] = (bkp[1] & S7_P1_MASK) >> S7_P1_SHIFT; - p1[8] = (bkp[2] & S8_P1_MASK_BKP) >> S8_P1_SHIFT; - p1[9] = (bkp[2] & S9_P1_MASK_BKP) >> S9_P1_BKP_SHIFT; - p1[10] = (bkp[2] & S10_P1_MASK_BKP) >> S10_P1_BKP_SHIFT; - break; - } - } else { - mode = (calib[1] & CAL_SEL_0_1) >> CAL_SEL_SHIFT; - mode |= (calib[3] & CAL_SEL_2) >> CAL_SEL_SHIFT_2; - - switch (mode) { - case TWO_PT_CALIB: - base2 = (calib[2] & BASE2_MASK) >> BASE2_SHIFT; - p2[0] = (calib[2] & S0_P2_MASK) >> S0_P2_SHIFT; - p2[1] = (calib[2] & S1_P2_MASK) >> S1_P2_SHIFT; - p2[2] = (calib[3] & S2_P2_MASK); - p2[3] = (calib[3] & S3_P2_MASK) >> S3_P2_SHIFT; - p2[4] = (calib[3] & S4_P2_MASK) >> S4_P2_SHIFT; - p2[5] = (calib[3] & S5_P2_MASK) >> S5_P2_SHIFT; - p2[6] = (calib[3] & S6_P2_MASK) >> S6_P2_SHIFT; - p2[7] = (calib[4] & S7_P2_MASK); - p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT; - p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT; - p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT; - /* Fall through */ - case ONE_PT_CALIB: - case ONE_PT_CALIB2: - base1 = calib[0] & BASE1_MASK; - p1[0] = (calib[0] & S0_P1_MASK) >> S0_P1_SHIFT; - p1[1] = (calib[0] & S1_P1_MASK) >> S1_P1_SHIFT; - p1[2] = (calib[0] & S2_P1_MASK) >> S2_P1_SHIFT; - p1[3] = (calib[0] & S3_P1_MASK) >> S3_P1_SHIFT; - p1[4] = (calib[1] & S4_P1_MASK); - p1[5] = (calib[1] & S5_P1_MASK) >> S5_P1_SHIFT; - p1[6] = (calib[1] & S6_P1_MASK) >> S6_P1_SHIFT; - p1[7] = (calib[1] & S7_P1_MASK) >> S7_P1_SHIFT; - p1[8] = (calib[1] & S8_P1_MASK) >> S8_P1_SHIFT; - p1[9] = (calib[2] & S9_P1_MASK); - p1[10] = (calib[2] & S10_P1_MASK) >> S10_P1_SHIFT; - break; - } - } - - switch (mode) { - case ONE_PT_CALIB: - for (i = 0; i < priv->num_sensors; i++) - p1[i] += (base1 << 2) | BIT_APPEND; - break; - case TWO_PT_CALIB: - for (i = 0; i < priv->num_sensors; i++) { - p2[i] += base2; - p2[i] <<= 2; - p2[i] |= BIT_APPEND; - } - /* Fall through */ - case ONE_PT_CALIB2: - for (i = 0; i < priv->num_sensors; i++) { - p1[i] += base1; - p1[i] <<= 2; - p1[i] |= BIT_APPEND; - } - break; - default: - for (i = 0; i < priv->num_sensors; i++) - p2[i] = 780; - p1[0] = 502; - p1[1] = 509; - p1[2] = 503; - p1[3] = 509; - p1[4] = 505; - p1[5] = 509; - p1[6] = 507; - p1[7] = 510; - p1[8] = 508; - p1[9] = 509; - p1[10] = 508; - break; - } - - compute_intercept_slope(priv, p1, p2, mode); - - return 0; -} - -static const struct tsens_ops ops_8974 = { - .init = init_common, - .calibrate = calibrate_8974, - .get_temp = get_temp_common, -}; - -const struct tsens_plat_data data_8974 = { - .num_sensors = 11, - .ops = &ops_8974, - .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, -}; diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c index 30909594b1cf..a6e26be1234f 100644 --- a/drivers/thermal/qcom/tsens-v0_1.c +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -39,6 +39,91 @@ #define MSM8916_CAL_SEL_MASK 0xe0000000 #define MSM8916_CAL_SEL_SHIFT 29 +/* eeprom layout data for 8974 */ +#define BASE1_MASK 0xff +#define S0_P1_MASK 0x3f00 +#define S1_P1_MASK 0xfc000 +#define S2_P1_MASK 0x3f00000 +#define S3_P1_MASK 0xfc000000 +#define S4_P1_MASK 0x3f +#define S5_P1_MASK 0xfc0 +#define S6_P1_MASK 0x3f000 +#define S7_P1_MASK 0xfc0000 +#define S8_P1_MASK 0x3f000000 +#define S8_P1_MASK_BKP 0x3f +#define S9_P1_MASK 0x3f +#define S9_P1_MASK_BKP 0xfc0 +#define S10_P1_MASK 0xfc0 +#define S10_P1_MASK_BKP 0x3f000 +#define CAL_SEL_0_1 0xc0000000 +#define CAL_SEL_2 0x40000000 +#define CAL_SEL_SHIFT 30 +#define CAL_SEL_SHIFT_2 28 + +#define S0_P1_SHIFT 8 +#define S1_P1_SHIFT 14 +#define S2_P1_SHIFT 20 +#define S3_P1_SHIFT 26 +#define S5_P1_SHIFT 6 +#define S6_P1_SHIFT 12 +#define S7_P1_SHIFT 18 +#define S8_P1_SHIFT 24 +#define S9_P1_BKP_SHIFT 6 +#define S10_P1_SHIFT 6 +#define S10_P1_BKP_SHIFT 12 + +#define BASE2_SHIFT 12 +#define BASE2_BKP_SHIFT 18 +#define S0_P2_SHIFT 20 +#define S0_P2_BKP_SHIFT 26 +#define S1_P2_SHIFT 26 +#define S2_P2_BKP_SHIFT 6 +#define S3_P2_SHIFT 6 +#define S3_P2_BKP_SHIFT 12 +#define S4_P2_SHIFT 12 +#define S4_P2_BKP_SHIFT 18 +#define S5_P2_SHIFT 18 +#define S5_P2_BKP_SHIFT 24 +#define S6_P2_SHIFT 24 +#define S7_P2_BKP_SHIFT 6 +#define S8_P2_SHIFT 6 +#define S8_P2_BKP_SHIFT 12 +#define S9_P2_SHIFT 12 +#define S9_P2_BKP_SHIFT 18 +#define S10_P2_SHIFT 18 +#define S10_P2_BKP_SHIFT 24 + +#define BASE2_MASK 0xff000 +#define BASE2_BKP_MASK 0xfc0000 +#define S0_P2_MASK 0x3f00000 +#define S0_P2_BKP_MASK 0xfc000000 +#define S1_P2_MASK 0xfc000000 +#define S1_P2_BKP_MASK 0x3f +#define S2_P2_MASK 0x3f +#define S2_P2_BKP_MASK 0xfc0 +#define S3_P2_MASK 0xfc0 +#define S3_P2_BKP_MASK 0x3f000 +#define S4_P2_MASK 0x3f000 +#define S4_P2_BKP_MASK 0xfc0000 +#define S5_P2_MASK 0xfc0000 +#define S5_P2_BKP_MASK 0x3f000000 +#define S6_P2_MASK 0x3f000000 +#define S6_P2_BKP_MASK 0x3f +#define S7_P2_MASK 0x3f +#define S7_P2_BKP_MASK 0xfc0 +#define S8_P2_MASK 0xfc0 +#define S8_P2_BKP_MASK 0x3f000 +#define S9_P2_MASK 0x3f000 +#define S9_P2_BKP_MASK 0xfc0000 +#define S10_P2_MASK 0xfc0000 +#define S10_P2_BKP_MASK 0x3f000000 + +#define BKP_SEL 0x3 +#define BKP_REDUN_SEL 0xe0000000 +#define BKP_REDUN_SHIFT 29 + +#define BIT_APPEND 0x3 + static int calibrate_8916(struct tsens_priv *priv) { int base0 = 0, base1 = 0, i; @@ -91,6 +176,138 @@ static int calibrate_8916(struct tsens_priv *priv) return 0; } +static int calibrate_8974(struct tsens_priv *priv) +{ + int base1 = 0, base2 = 0, i; + u32 p1[11], p2[11]; + int mode = 0; + u32 *calib, *bkp; + u32 calib_redun_sel; + + calib = (u32 *)qfprom_read(priv->dev, "calib"); + if (IS_ERR(calib)) + return PTR_ERR(calib); + + bkp = (u32 *)qfprom_read(priv->dev, "calib_backup"); + if (IS_ERR(bkp)) + return PTR_ERR(bkp); + + calib_redun_sel = bkp[1] & BKP_REDUN_SEL; + calib_redun_sel >>= BKP_REDUN_SHIFT; + + if (calib_redun_sel == BKP_SEL) { + mode = (calib[4] & CAL_SEL_0_1) >> CAL_SEL_SHIFT; + mode |= (calib[5] & CAL_SEL_2) >> CAL_SEL_SHIFT_2; + + switch (mode) { + case TWO_PT_CALIB: + base2 = (bkp[2] & BASE2_BKP_MASK) >> BASE2_BKP_SHIFT; + p2[0] = (bkp[2] & S0_P2_BKP_MASK) >> S0_P2_BKP_SHIFT; + p2[1] = (bkp[3] & S1_P2_BKP_MASK); + p2[2] = (bkp[3] & S2_P2_BKP_MASK) >> S2_P2_BKP_SHIFT; + p2[3] = (bkp[3] & S3_P2_BKP_MASK) >> S3_P2_BKP_SHIFT; + p2[4] = (bkp[3] & S4_P2_BKP_MASK) >> S4_P2_BKP_SHIFT; + p2[5] = (calib[4] & S5_P2_BKP_MASK) >> S5_P2_BKP_SHIFT; + p2[6] = (calib[5] & S6_P2_BKP_MASK); + p2[7] = (calib[5] & S7_P2_BKP_MASK) >> S7_P2_BKP_SHIFT; + p2[8] = (calib[5] & S8_P2_BKP_MASK) >> S8_P2_BKP_SHIFT; + p2[9] = (calib[5] & S9_P2_BKP_MASK) >> S9_P2_BKP_SHIFT; + p2[10] = (calib[5] & S10_P2_BKP_MASK) >> S10_P2_BKP_SHIFT; + /* Fall through */ + case ONE_PT_CALIB: + case ONE_PT_CALIB2: + base1 = bkp[0] & BASE1_MASK; + p1[0] = (bkp[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (bkp[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (bkp[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (bkp[0] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (bkp[1] & S4_P1_MASK); + p1[5] = (bkp[1] & S5_P1_MASK) >> S5_P1_SHIFT; + p1[6] = (bkp[1] & S6_P1_MASK) >> S6_P1_SHIFT; + p1[7] = (bkp[1] & S7_P1_MASK) >> S7_P1_SHIFT; + p1[8] = (bkp[2] & S8_P1_MASK_BKP) >> S8_P1_SHIFT; + p1[9] = (bkp[2] & S9_P1_MASK_BKP) >> S9_P1_BKP_SHIFT; + p1[10] = (bkp[2] & S10_P1_MASK_BKP) >> S10_P1_BKP_SHIFT; + break; + } + } else { + mode = (calib[1] & CAL_SEL_0_1) >> CAL_SEL_SHIFT; + mode |= (calib[3] & CAL_SEL_2) >> CAL_SEL_SHIFT_2; + + switch (mode) { + case TWO_PT_CALIB: + base2 = (calib[2] & BASE2_MASK) >> BASE2_SHIFT; + p2[0] = (calib[2] & S0_P2_MASK) >> S0_P2_SHIFT; + p2[1] = (calib[2] & S1_P2_MASK) >> S1_P2_SHIFT; + p2[2] = (calib[3] & S2_P2_MASK); + p2[3] = (calib[3] & S3_P2_MASK) >> S3_P2_SHIFT; + p2[4] = (calib[3] & S4_P2_MASK) >> S4_P2_SHIFT; + p2[5] = (calib[3] & S5_P2_MASK) >> S5_P2_SHIFT; + p2[6] = (calib[3] & S6_P2_MASK) >> S6_P2_SHIFT; + p2[7] = (calib[4] & S7_P2_MASK); + p2[8] = (calib[4] & S8_P2_MASK) >> S8_P2_SHIFT; + p2[9] = (calib[4] & S9_P2_MASK) >> S9_P2_SHIFT; + p2[10] = (calib[4] & S10_P2_MASK) >> S10_P2_SHIFT; + /* Fall through */ + case ONE_PT_CALIB: + case ONE_PT_CALIB2: + base1 = calib[0] & BASE1_MASK; + p1[0] = (calib[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (calib[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (calib[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (calib[0] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (calib[1] & S4_P1_MASK); + p1[5] = (calib[1] & S5_P1_MASK) >> S5_P1_SHIFT; + p1[6] = (calib[1] & S6_P1_MASK) >> S6_P1_SHIFT; + p1[7] = (calib[1] & S7_P1_MASK) >> S7_P1_SHIFT; + p1[8] = (calib[1] & S8_P1_MASK) >> S8_P1_SHIFT; + p1[9] = (calib[2] & S9_P1_MASK); + p1[10] = (calib[2] & S10_P1_MASK) >> S10_P1_SHIFT; + break; + } + } + + switch (mode) { + case ONE_PT_CALIB: + for (i = 0; i < priv->num_sensors; i++) + p1[i] += (base1 << 2) | BIT_APPEND; + break; + case TWO_PT_CALIB: + for (i = 0; i < priv->num_sensors; i++) { + p2[i] += base2; + p2[i] <<= 2; + p2[i] |= BIT_APPEND; + } + /* Fall through */ + case ONE_PT_CALIB2: + for (i = 0; i < priv->num_sensors; i++) { + p1[i] += base1; + p1[i] <<= 2; + p1[i] |= BIT_APPEND; + } + break; + default: + for (i = 0; i < priv->num_sensors; i++) + p2[i] = 780; + p1[0] = 502; + p1[1] = 509; + p1[2] = 503; + p1[3] = 509; + p1[4] = 505; + p1[5] = 509; + p1[6] = 507; + p1[7] = 510; + p1[8] = 508; + p1[9] = 509; + p1[10] = 508; + break; + } + + compute_intercept_slope(priv, p1, p2, mode); + + return 0; +} + static const struct tsens_ops ops_8916 = { .init = init_common, .calibrate = calibrate_8916, @@ -103,3 +320,15 @@ const struct tsens_plat_data data_8916 = { .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, .hw_ids = (unsigned int []){0, 1, 2, 4, 5 }, }; + +static const struct tsens_ops ops_8974 = { + .init = init_common, + .calibrate = calibrate_8974, + .get_temp = get_temp_common, +}; + +const struct tsens_plat_data data_8974 = { + .num_sensors = 11, + .ops = &ops_8974, + .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, +}; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 4d6a406f8dca..27b8f74829d9 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -116,8 +116,12 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mo int init_common(struct tsens_priv *priv); int get_temp_common(struct tsens_priv *priv, int i, int *temp); -/* TSENS v1 targets */ -extern const struct tsens_plat_data data_8916, data_8974, data_8960; +/* TSENS target */ +extern const struct tsens_plat_data data_8960; + +/* TSENS v0.1 targets */ +extern const struct tsens_plat_data data_8916, data_8974; + /* TSENS v2 targets */ extern const struct tsens_plat_data data_8996, data_tsens_v2; -- cgit From c19970548edc35921ed7606951d203d7887e2ea9 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:50 +0530 Subject: drivers: thermal: tsens: Introduce reg_fields to deal with register description As we add support for newer versions of the TSENS IP, the current approach isn't scaling because registers and bitfields get moved around, requiring platform-specific hacks in the code. By moving to regmap, we can hide the register level differences away from the code. Define a common set of registers and bit-fields that we care about across the various tsens IP versions. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 62 +++++++---- drivers/thermal/qcom/tsens-v0_1.c | 50 ++++++++- drivers/thermal/qcom/tsens-v2.c | 105 ++++++++++++++---- drivers/thermal/qcom/tsens.c | 5 +- drivers/thermal/qcom/tsens.h | 206 ++++++++++++++++++++++++++++++++++-- 5 files changed, 370 insertions(+), 58 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index f0ef4e3cf7f9..0f9deec2517a 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -12,13 +12,6 @@ #include #include "tsens.h" -/* SROT */ -#define TSENS_EN BIT(0) - -/* TM */ -#define STATUS_OFFSET 0x30 -#define SN_ADDR_OFFSET 0x4 -#define SN_ST_TEMP_MASK 0x3ff #define CAL_DEGC_PT1 30 #define CAL_DEGC_PT2 120 #define SLOPE_FACTOR 1000 @@ -95,18 +88,14 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) return degc; } -int get_temp_common(struct tsens_priv *priv, int id, int *temp) +int get_temp_common(struct tsens_priv *priv, int i, int *temp) { - struct tsens_sensor *s = &priv->sensor[id]; - u32 code; - unsigned int status_reg; + struct tsens_sensor *s = &priv->sensor[i]; int last_temp = 0, ret; - status_reg = priv->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; - ret = regmap_read(priv->tm_map, status_reg, &code); + ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp); if (ret) return ret; - last_temp = code & SN_ST_TEMP_MASK; *temp = code_to_degc(last_temp, s) * 1000; @@ -131,10 +120,9 @@ int __init init_common(struct tsens_priv *priv) { void __iomem *tm_base, *srot_base; struct resource *res; - u32 code; - int ret; + u32 enabled; + int ret, i, j; struct platform_device *op = of_find_device_by_node(priv->dev->of_node); - u16 ctrl_offset = priv->reg_offsets[SROT_CTRL_OFFSET]; if (!op) return -EINVAL; @@ -173,13 +161,41 @@ int __init init_common(struct tsens_priv *priv) goto err_put_device; } - if (priv->srot_map) { - ret = regmap_read(priv->srot_map, ctrl_offset, &code); - if (ret) + priv->rf[TSENS_EN] = devm_regmap_field_alloc(priv->dev, priv->srot_map, + priv->fields[TSENS_EN]); + if (IS_ERR(priv->rf[TSENS_EN])) { + ret = PTR_ERR(priv->rf[TSENS_EN]); + goto err_put_device; + } + ret = regmap_field_read(priv->rf[TSENS_EN], &enabled); + if (ret) + goto err_put_device; + if (!enabled) { + dev_err(priv->dev, "tsens device is not enabled\n"); + ret = -ENODEV; + goto err_put_device; + } + + priv->rf[SENSOR_EN] = devm_regmap_field_alloc(priv->dev, priv->srot_map, + priv->fields[SENSOR_EN]); + if (IS_ERR(priv->rf[SENSOR_EN])) { + ret = PTR_ERR(priv->rf[SENSOR_EN]); + goto err_put_device; + } + /* now alloc regmap_fields in tm_map */ + for (i = 0, j = LAST_TEMP_0; i < priv->num_sensors; i++, j++) { + priv->rf[j] = devm_regmap_field_alloc(priv->dev, priv->tm_map, + priv->fields[j]); + if (IS_ERR(priv->rf[j])) { + ret = PTR_ERR(priv->rf[j]); goto err_put_device; - if (!(code & TSENS_EN)) { - dev_err(priv->dev, "tsens device is not enabled\n"); - ret = -ENODEV; + } + } + for (i = 0, j = VALID_0; i < priv->num_sensors; i++, j++) { + priv->rf[j] = devm_regmap_field_alloc(priv->dev, priv->tm_map, + priv->fields[j]); + if (IS_ERR(priv->rf[j])) { + ret = PTR_ERR(priv->rf[j]); goto err_put_device; } } diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c index a6e26be1234f..a7560e9a7c10 100644 --- a/drivers/thermal/qcom/tsens-v0_1.c +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -6,6 +6,15 @@ #include #include "tsens.h" +/* ----- SROT ------ */ +#define SROT_CTRL_OFF 0x0000 + +/* ----- TM ------ */ +#define TM_INT_EN_OFF 0x0000 +#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF 0x0004 +#define TM_Sn_STATUS_OFF 0x0030 +#define TM_TRDY_OFF 0x005c + /* eeprom layout data for 8916 */ #define MSM8916_BASE0_MASK 0x0000007f #define MSM8916_BASE1_MASK 0xfe000000 @@ -308,6 +317,40 @@ static int calibrate_8974(struct tsens_priv *priv) return 0; } +/* v0.1: 8916, 8974 */ + +static const struct tsens_features tsens_v0_1_feat = { + .ver_major = VER_0_1, + .crit_int = 0, + .adc = 1, + .srot_split = 1, +}; + +static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = { + /* ----- SROT ------ */ + /* No VERSION information */ + + /* CTRL_OFFSET */ + [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), + [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), + + /* ----- TM ------ */ + /* INTERRUPT ENABLE */ + [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0), + + /* Sn_STATUS */ + REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 9), + /* No VALID field on v0.1 */ + REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS, TM_Sn_STATUS_OFF, 10, 10), + REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11), + REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12), + /* No CRITICAL field on v0.1 */ + REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS, TM_Sn_STATUS_OFF, 13, 13), + + /* TRDY: 1=ready, 0=in progress */ + [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), +}; + static const struct tsens_ops ops_8916 = { .init = init_common, .calibrate = calibrate_8916, @@ -317,8 +360,10 @@ static const struct tsens_ops ops_8916 = { const struct tsens_plat_data data_8916 = { .num_sensors = 5, .ops = &ops_8916, - .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, .hw_ids = (unsigned int []){0, 1, 2, 4, 5 }, + + .feat = &tsens_v0_1_feat, + .fields = tsens_v0_1_regfields, }; static const struct tsens_ops ops_8974 = { @@ -330,5 +375,6 @@ static const struct tsens_ops ops_8974 = { const struct tsens_plat_data data_8974 = { .num_sensors = 11, .ops = &ops_8974, - .reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, + .feat = &tsens_v0_1_feat, + .fields = tsens_v0_1_regfields, }; diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 8b700772d903..b58f5af2fea7 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -4,50 +4,70 @@ * Copyright (c) 2018, Linaro Limited */ -#include #include +#include #include "tsens.h" -#define STATUS_OFFSET 0xa0 +/* ----- SROT ------ */ +#define SROT_HW_VER_OFF 0x0000 +#define SROT_CTRL_OFF 0x0004 + +/* ----- TM ------ */ +#define TM_INT_EN_OFF 0x0004 +#define TM_UPPER_LOWER_INT_STATUS_OFF 0x0008 +#define TM_UPPER_LOWER_INT_CLEAR_OFF 0x000c +#define TM_UPPER_LOWER_INT_MASK_OFF 0x0010 +#define TM_CRITICAL_INT_STATUS_OFF 0x0014 +#define TM_CRITICAL_INT_CLEAR_OFF 0x0018 +#define TM_CRITICAL_INT_MASK_OFF 0x001c +#define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020 +#define TM_Sn_CRITICAL_THRESHOLD_OFF 0x0060 +#define TM_Sn_STATUS_OFF 0x00a0 +#define TM_TRDY_OFF 0x00e4 + #define LAST_TEMP_MASK 0xfff -#define STATUS_VALID_BIT BIT(21) static int get_temp_tsens_v2(struct tsens_priv *priv, int id, int *temp) { struct tsens_sensor *s = &priv->sensor[id]; - u32 code; - unsigned int status_reg; - u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0; + u32 temp_idx = LAST_TEMP_0 + s->hw_id; + u32 valid_idx = VALID_0 + s->hw_id; + u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0, valid; int ret; - status_reg = priv->tm_offset + STATUS_OFFSET + s->hw_id * 4; - ret = regmap_read(priv->tm_map, status_reg, &code); + ret = regmap_field_read(priv->rf[temp_idx], &last_temp); + if (ret) + return ret; + + ret = regmap_field_read(priv->rf[valid_idx], &valid); if (ret) return ret; - last_temp = code & LAST_TEMP_MASK; - if (code & STATUS_VALID_BIT) + + if (valid) goto done; /* Try a second time */ - ret = regmap_read(priv->tm_map, status_reg, &code); + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; + ret = regmap_field_read(priv->rf[temp_idx], &last_temp2); if (ret) return ret; - if (code & STATUS_VALID_BIT) { - last_temp = code & LAST_TEMP_MASK; + if (valid) { + last_temp = last_temp2; goto done; - } else { - last_temp2 = code & LAST_TEMP_MASK; } /* Try a third/last time */ - ret = regmap_read(priv->tm_map, status_reg, &code); + ret = regmap_field_read(priv->rf[valid_idx], &valid); if (ret) return ret; - if (code & STATUS_VALID_BIT) { - last_temp = code & LAST_TEMP_MASK; + ret = regmap_field_read(priv->rf[temp_idx], &last_temp3); + if (ret) + return ret; + if (valid) { + last_temp = last_temp3; goto done; - } else { - last_temp3 = code & LAST_TEMP_MASK; } if (last_temp == last_temp2) @@ -61,19 +81,58 @@ done: return 0; } +/* v2.x: 8996, 8998, sdm845 */ + +static const struct tsens_features tsens_v2_feat = { + .ver_major = VER_2_X, + .crit_int = 1, + .adc = 0, + .srot_split = 1, +}; + +static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { + /* ----- SROT ------ */ + /* VERSION */ + [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31), + [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27), + [VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15), + /* CTRL_OFF */ + [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), + [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), + + /* ----- TM ------ */ + /* INTERRUPT ENABLE */ + /* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */ + [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 2), + + /* Sn_STATUS */ + REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 11), + REG_FIELD_FOR_EACH_SENSOR16(VALID, TM_Sn_STATUS_OFF, 21, 21), + REG_FIELD_FOR_EACH_SENSOR16(MIN_STATUS, TM_Sn_STATUS_OFF, 16, 16), + REG_FIELD_FOR_EACH_SENSOR16(LOWER_STATUS, TM_Sn_STATUS_OFF, 17, 17), + REG_FIELD_FOR_EACH_SENSOR16(UPPER_STATUS, TM_Sn_STATUS_OFF, 18, 18), + REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19, 19), + REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS, TM_Sn_STATUS_OFF, 20, 20), + + /* TRDY: 1=ready, 0=in progress */ + [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), +}; + static const struct tsens_ops ops_generic_v2 = { .init = init_common, .get_temp = get_temp_tsens_v2, }; const struct tsens_plat_data data_tsens_v2 = { - .ops = &ops_generic_v2, - .reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 }, + .ops = &ops_generic_v2, + .feat = &tsens_v2_feat, + .fields = tsens_v2_regfields, }; /* Kept around for backward compatibility with old msm8996.dtsi */ const struct tsens_plat_data data_8996 = { .num_sensors = 13, .ops = &ops_generic_v2, - .reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 }, + .feat = &tsens_v2_feat, + .fields = tsens_v2_regfields, }; diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 0b5be08d515f..b91a0b88d33c 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -144,9 +144,8 @@ static int tsens_probe(struct platform_device *pdev) else priv->sensor[i].hw_id = i; } - for (i = 0; i < REG_ARRAY_SIZE; i++) { - priv->reg_offsets[i] = data->reg_offsets[i]; - } + priv->feat = data->feat; + priv->fields = data->fields; if (!priv->ops || !priv->ops->init || !priv->ops->get_temp) return -EINVAL; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 27b8f74829d9..a9390e06b4dd 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -11,9 +11,16 @@ #define TWO_PT_CALIB 0x3 #include +#include struct tsens_priv; +enum tsens_ver { + VER_0_1 = 0, + VER_1_X, + VER_2_X, +}; + /** * struct tsens_sensor - data for each sensor connected to the tsens device * @priv: tsens device instance that this sensor is connected to @@ -58,10 +65,189 @@ struct tsens_ops { int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend); }; -enum reg_list { - SROT_CTRL_OFFSET, +#define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \ + [_name##_##0] = REG_FIELD(_offset, _startbit, _stopbit), \ + [_name##_##1] = REG_FIELD(_offset + 4, _startbit, _stopbit), \ + [_name##_##2] = REG_FIELD(_offset + 8, _startbit, _stopbit), \ + [_name##_##3] = REG_FIELD(_offset + 12, _startbit, _stopbit), \ + [_name##_##4] = REG_FIELD(_offset + 16, _startbit, _stopbit), \ + [_name##_##5] = REG_FIELD(_offset + 20, _startbit, _stopbit), \ + [_name##_##6] = REG_FIELD(_offset + 24, _startbit, _stopbit), \ + [_name##_##7] = REG_FIELD(_offset + 28, _startbit, _stopbit), \ + [_name##_##8] = REG_FIELD(_offset + 32, _startbit, _stopbit), \ + [_name##_##9] = REG_FIELD(_offset + 36, _startbit, _stopbit), \ + [_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit) + +#define REG_FIELD_FOR_EACH_SENSOR16(_name, _offset, _startbit, _stopbit) \ + [_name##_##0] = REG_FIELD(_offset, _startbit, _stopbit), \ + [_name##_##1] = REG_FIELD(_offset + 4, _startbit, _stopbit), \ + [_name##_##2] = REG_FIELD(_offset + 8, _startbit, _stopbit), \ + [_name##_##3] = REG_FIELD(_offset + 12, _startbit, _stopbit), \ + [_name##_##4] = REG_FIELD(_offset + 16, _startbit, _stopbit), \ + [_name##_##5] = REG_FIELD(_offset + 20, _startbit, _stopbit), \ + [_name##_##6] = REG_FIELD(_offset + 24, _startbit, _stopbit), \ + [_name##_##7] = REG_FIELD(_offset + 28, _startbit, _stopbit), \ + [_name##_##8] = REG_FIELD(_offset + 32, _startbit, _stopbit), \ + [_name##_##9] = REG_FIELD(_offset + 36, _startbit, _stopbit), \ + [_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit), \ + [_name##_##11] = REG_FIELD(_offset + 44, _startbit, _stopbit), \ + [_name##_##12] = REG_FIELD(_offset + 48, _startbit, _stopbit), \ + [_name##_##13] = REG_FIELD(_offset + 52, _startbit, _stopbit), \ + [_name##_##14] = REG_FIELD(_offset + 56, _startbit, _stopbit), \ + [_name##_##15] = REG_FIELD(_offset + 60, _startbit, _stopbit) + +/* reg_field IDs to use as an index into an array */ +enum regfield_ids { + /* ----- SROT ------ */ + /* HW_VER */ + VER_MAJOR = 0, + VER_MINOR, + VER_STEP, + /* CTRL_OFFSET */ + TSENS_EN = 3, + TSENS_SW_RST, + SENSOR_EN, + CODE_OR_TEMP, + + /* ----- TM ------ */ + /* STATUS */ + LAST_TEMP_0 = 7, /* Last temperature reading */ + LAST_TEMP_1, + LAST_TEMP_2, + LAST_TEMP_3, + LAST_TEMP_4, + LAST_TEMP_5, + LAST_TEMP_6, + LAST_TEMP_7, + LAST_TEMP_8, + LAST_TEMP_9, + LAST_TEMP_10, + LAST_TEMP_11, + LAST_TEMP_12, + LAST_TEMP_13, + LAST_TEMP_14, + LAST_TEMP_15, + VALID_0 = 23, /* VALID reading or not */ + VALID_1, + VALID_2, + VALID_3, + VALID_4, + VALID_5, + VALID_6, + VALID_7, + VALID_8, + VALID_9, + VALID_10, + VALID_11, + VALID_12, + VALID_13, + VALID_14, + VALID_15, + MIN_STATUS_0, /* MIN threshold violated */ + MIN_STATUS_1, + MIN_STATUS_2, + MIN_STATUS_3, + MIN_STATUS_4, + MIN_STATUS_5, + MIN_STATUS_6, + MIN_STATUS_7, + MIN_STATUS_8, + MIN_STATUS_9, + MIN_STATUS_10, + MIN_STATUS_11, + MIN_STATUS_12, + MIN_STATUS_13, + MIN_STATUS_14, + MIN_STATUS_15, + MAX_STATUS_0, /* MAX threshold violated */ + MAX_STATUS_1, + MAX_STATUS_2, + MAX_STATUS_3, + MAX_STATUS_4, + MAX_STATUS_5, + MAX_STATUS_6, + MAX_STATUS_7, + MAX_STATUS_8, + MAX_STATUS_9, + MAX_STATUS_10, + MAX_STATUS_11, + MAX_STATUS_12, + MAX_STATUS_13, + MAX_STATUS_14, + MAX_STATUS_15, + LOWER_STATUS_0, /* LOWER threshold violated */ + LOWER_STATUS_1, + LOWER_STATUS_2, + LOWER_STATUS_3, + LOWER_STATUS_4, + LOWER_STATUS_5, + LOWER_STATUS_6, + LOWER_STATUS_7, + LOWER_STATUS_8, + LOWER_STATUS_9, + LOWER_STATUS_10, + LOWER_STATUS_11, + LOWER_STATUS_12, + LOWER_STATUS_13, + LOWER_STATUS_14, + LOWER_STATUS_15, + UPPER_STATUS_0, /* UPPER threshold violated */ + UPPER_STATUS_1, + UPPER_STATUS_2, + UPPER_STATUS_3, + UPPER_STATUS_4, + UPPER_STATUS_5, + UPPER_STATUS_6, + UPPER_STATUS_7, + UPPER_STATUS_8, + UPPER_STATUS_9, + UPPER_STATUS_10, + UPPER_STATUS_11, + UPPER_STATUS_12, + UPPER_STATUS_13, + UPPER_STATUS_14, + UPPER_STATUS_15, + CRITICAL_STATUS_0, /* CRITICAL threshold violated */ + CRITICAL_STATUS_1, + CRITICAL_STATUS_2, + CRITICAL_STATUS_3, + CRITICAL_STATUS_4, + CRITICAL_STATUS_5, + CRITICAL_STATUS_6, + CRITICAL_STATUS_7, + CRITICAL_STATUS_8, + CRITICAL_STATUS_9, + CRITICAL_STATUS_10, + CRITICAL_STATUS_11, + CRITICAL_STATUS_12, + CRITICAL_STATUS_13, + CRITICAL_STATUS_14, + CRITICAL_STATUS_15, + /* TRDY */ + TRDY, + /* INTERRUPT ENABLE */ + INT_EN, /* Pre-V1, V1.x */ + LOW_INT_EN, /* V2.x */ + UP_INT_EN, /* V2.x */ + CRIT_INT_EN, /* V2.x */ - REG_ARRAY_SIZE, + /* Keep last */ + MAX_REGFIELDS +}; + +/** + * struct tsens_features - Features supported by the IP + * @ver_major: Major number of IP version + * @crit_int: does the IP support critical interrupts? + * @adc: do the sensors only output adc code (instead of temperature)? + * @srot_split: does the IP neatly splits the register space into SROT and TM, + * with SROT only being available to secure boot firmware? + */ +struct tsens_features { + unsigned int ver_major; + unsigned int crit_int:1; + unsigned int adc:1; + unsigned int srot_split:1; }; /** @@ -69,13 +255,15 @@ enum reg_list { * @num_sensors: Number of sensors supported by platform * @ops: operations the tsens instance supports * @hw_ids: Subset of sensors ids supported by platform, if not the first n - * @reg_offsets: Register offsets for commonly used registers + * @feat: features of the IP + * @fields: bitfield locations */ struct tsens_plat_data { const u32 num_sensors; const struct tsens_ops *ops; - const u16 reg_offsets[REG_ARRAY_SIZE]; unsigned int *hw_ids; + const struct tsens_features *feat; + const struct reg_field *fields; }; /** @@ -94,8 +282,10 @@ struct tsens_context { * @srot_map: pointer to SROT register address space * @tm_offset: deal with old device trees that don't address TM and SROT * address space separately - * @reg_offsets: array of offsets to important regs for this version of IP + * @rf: array of regmap_fields used to store value of the field * @ctx: registers to be saved and restored during suspend/resume + * @feat: features of the IP + * @fields: bitfield locations * @ops: pointer to list of callbacks supported by this device * @sensor: list of sensors attached to this device */ @@ -105,8 +295,10 @@ struct tsens_priv { struct regmap *tm_map; struct regmap *srot_map; u32 tm_offset; - u16 reg_offsets[REG_ARRAY_SIZE]; + struct regmap_field *rf[MAX_REGFIELDS]; struct tsens_context ctx; + const struct tsens_features *feat; + const struct reg_field *fields; const struct tsens_ops *ops; struct tsens_sensor sensor[0]; }; -- cgit From 52eafd66ef764022b3cd2ee62a053d39e2809120 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:51 +0530 Subject: drivers: thermal: tsens: Save reference to the device pointer and use it Code cleanup making it easier to read Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 0f9deec2517a..9d7a6c328ae0 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -119,6 +119,7 @@ static const struct regmap_config tsens_srot_config = { int __init init_common(struct tsens_priv *priv) { void __iomem *tm_base, *srot_base; + struct device *dev = priv->dev; struct resource *res; u32 enabled; int ret, i, j; @@ -137,7 +138,7 @@ int __init init_common(struct tsens_priv *priv) goto err_put_device; } - priv->srot_map = devm_regmap_init_mmio(priv->dev, srot_base, + priv->srot_map = devm_regmap_init_mmio(dev, srot_base, &tsens_srot_config); if (IS_ERR(priv->srot_map)) { ret = PTR_ERR(priv->srot_map); @@ -155,13 +156,13 @@ int __init init_common(struct tsens_priv *priv) goto err_put_device; } - priv->tm_map = devm_regmap_init_mmio(priv->dev, tm_base, &tsens_config); + priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config); if (IS_ERR(priv->tm_map)) { ret = PTR_ERR(priv->tm_map); goto err_put_device; } - priv->rf[TSENS_EN] = devm_regmap_field_alloc(priv->dev, priv->srot_map, + priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[TSENS_EN]); if (IS_ERR(priv->rf[TSENS_EN])) { ret = PTR_ERR(priv->rf[TSENS_EN]); @@ -171,12 +172,12 @@ int __init init_common(struct tsens_priv *priv) if (ret) goto err_put_device; if (!enabled) { - dev_err(priv->dev, "tsens device is not enabled\n"); + dev_err(dev, "tsens device is not enabled\n"); ret = -ENODEV; goto err_put_device; } - priv->rf[SENSOR_EN] = devm_regmap_field_alloc(priv->dev, priv->srot_map, + priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map, priv->fields[SENSOR_EN]); if (IS_ERR(priv->rf[SENSOR_EN])) { ret = PTR_ERR(priv->rf[SENSOR_EN]); @@ -184,7 +185,7 @@ int __init init_common(struct tsens_priv *priv) } /* now alloc regmap_fields in tm_map */ for (i = 0, j = LAST_TEMP_0; i < priv->num_sensors; i++, j++) { - priv->rf[j] = devm_regmap_field_alloc(priv->dev, priv->tm_map, + priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[j]); if (IS_ERR(priv->rf[j])) { ret = PTR_ERR(priv->rf[j]); @@ -192,7 +193,7 @@ int __init init_common(struct tsens_priv *priv) } } for (i = 0, j = VALID_0; i < priv->num_sensors; i++, j++) { - priv->rf[j] = devm_regmap_field_alloc(priv->dev, priv->tm_map, + priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[j]); if (IS_ERR(priv->rf[j])) { ret = PTR_ERR(priv->rf[j]); -- cgit From fc7d18cf6a923cde7f5e7ba2c1105bb106d3e29a Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:52 +0530 Subject: drivers: thermal: tsens: Don't print error message on -EPROBE_DEFER We print a calibration failure message on -EPROBE_DEFER from nvmem/qfprom as follows: [ 3.003090] qcom-tsens 4a9000.thermal-sensor: version: 1.4 [ 3.005376] qcom-tsens 4a9000.thermal-sensor: tsens calibration failed [ 3.113248] qcom-tsens 4a9000.thermal-sensor: version: 1.4 This confuses people when, in fact, calibration succeeds later when nvmem/qfprom device is available. Don't print this message on a -EPROBE_DEFER. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index b91a0b88d33c..057b33353ba3 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -159,7 +159,8 @@ static int tsens_probe(struct platform_device *pdev) if (priv->ops->calibrate) { ret = priv->ops->calibrate(priv); if (ret < 0) { - dev_err(dev, "tsens calibration failed\n"); + if (ret != -EPROBE_DEFER) + dev_err(dev, "tsens calibration failed\n"); return ret; } } -- cgit From 3e6a8fb3308419129c7a52de6eb42feef5a919a0 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:53 +0530 Subject: drivers: thermal: tsens: Add new operation to check if a sensor is enabled is_sensor_enabled() checks if the sensors are enabled on this platform. It is possible that the SoC might choose not to enable all the sensors that the IP block is capable of supporting. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 14 ++++++++++++++ drivers/thermal/qcom/tsens-v0_1.c | 1 + drivers/thermal/qcom/tsens-v2.c | 1 + drivers/thermal/qcom/tsens.c | 5 +++++ drivers/thermal/qcom/tsens.h | 1 + 5 files changed, 22 insertions(+) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 9d7a6c328ae0..c76f8cfb25a2 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -69,6 +69,20 @@ void compute_intercept_slope(struct tsens_priv *priv, u32 *p1, } } +bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id) +{ + u32 val; + int ret; + + if ((hw_id > (priv->num_sensors - 1)) || (hw_id < 0)) + return -EINVAL; + ret = regmap_field_read(priv->rf[SENSOR_EN], &val); + if (ret) + return ret; + + return val & (1 << hw_id); +} + static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) { int degc, num, den; diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c index a7560e9a7c10..c0476bfdc0d5 100644 --- a/drivers/thermal/qcom/tsens-v0_1.c +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -333,6 +333,7 @@ static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = { /* CTRL_OFFSET */ [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), + [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 13), /* ----- TM ------ */ /* INTERRUPT ENABLE */ diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index b58f5af2fea7..788d5886cd1c 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -99,6 +99,7 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { /* CTRL_OFF */ [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), + [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 18), /* ----- TM ------ */ /* INTERRUPT ENABLE */ diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 057b33353ba3..fc44cac31fa5 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -82,6 +82,11 @@ static int tsens_register(struct tsens_priv *priv) struct thermal_zone_device *tzd; for (i = 0; i < priv->num_sensors; i++) { + if (!is_sensor_enabled(priv, priv->sensor[i].hw_id)) { + dev_err(priv->dev, "sensor %d: disabled\n", + priv->sensor[i].hw_id); + continue; + } priv->sensor[i].priv = priv; priv->sensor[i].id = i; tzd = devm_thermal_zone_of_sensor_register(priv->dev, i, diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index a9390e06b4dd..a3bf7de88ae8 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -307,6 +307,7 @@ char *qfprom_read(struct device *dev, const char *cname); void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode); int init_common(struct tsens_priv *priv); int get_temp_common(struct tsens_priv *priv, int i, int *temp); +bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id); /* TSENS target */ extern const struct tsens_plat_data data_8960; -- cgit From 66ad8a100953dc1433c3ead8c473746d60c05693 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:54 +0530 Subject: drivers: thermal: tsens: change data type for sensor IDs The IDs cannot be negative, fix the data type. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index a3bf7de88ae8..527c42cfd2d5 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -35,8 +35,8 @@ struct tsens_sensor { struct tsens_priv *priv; struct thermal_zone_device *tzd; int offset; - int id; - int hw_id; + unsigned int id; + unsigned int hw_id; int slope; u32 status; }; -- cgit From 1b6e3e517fadcfbbe0f88eb676ebffafc20fd49c Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:55 +0530 Subject: drivers: thermal: tsens: Introduce IP-specific max_sensor count The IP can support 'm' sensors while the platform can enable 'n' sensors of the 'm' where n <= m. Track maximum sensors supported by the IP so that we can correctly track what subset of the sensors are supported on the platform. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 4 ++-- drivers/thermal/qcom/tsens-v0_1.c | 1 + drivers/thermal/qcom/tsens-v2.c | 1 + drivers/thermal/qcom/tsens.h | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index c76f8cfb25a2..5607c5cc635c 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -198,7 +198,7 @@ int __init init_common(struct tsens_priv *priv) goto err_put_device; } /* now alloc regmap_fields in tm_map */ - for (i = 0, j = LAST_TEMP_0; i < priv->num_sensors; i++, j++) { + for (i = 0, j = LAST_TEMP_0; i < priv->feat->max_sensors; i++, j++) { priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[j]); if (IS_ERR(priv->rf[j])) { @@ -206,7 +206,7 @@ int __init init_common(struct tsens_priv *priv) goto err_put_device; } } - for (i = 0, j = VALID_0; i < priv->num_sensors; i++, j++) { + for (i = 0, j = VALID_0; i < priv->feat->max_sensors; i++, j++) { priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map, priv->fields[j]); if (IS_ERR(priv->rf[j])) { diff --git a/drivers/thermal/qcom/tsens-v0_1.c b/drivers/thermal/qcom/tsens-v0_1.c index c0476bfdc0d5..a319283c223f 100644 --- a/drivers/thermal/qcom/tsens-v0_1.c +++ b/drivers/thermal/qcom/tsens-v0_1.c @@ -324,6 +324,7 @@ static const struct tsens_features tsens_v0_1_feat = { .crit_int = 0, .adc = 1, .srot_split = 1, + .max_sensors = 11, }; static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = { diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 788d5886cd1c..01ec1b2681f2 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -88,6 +88,7 @@ static const struct tsens_features tsens_v2_feat = { .crit_int = 1, .adc = 0, .srot_split = 1, + .max_sensors = 16, }; static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 527c42cfd2d5..080e15a09ac2 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -242,12 +242,14 @@ enum regfield_ids { * @adc: do the sensors only output adc code (instead of temperature)? * @srot_split: does the IP neatly splits the register space into SROT and TM, * with SROT only being available to secure boot firmware? + * @max_sensors: maximum sensors supported by this version of the IP */ struct tsens_features { unsigned int ver_major; unsigned int crit_int:1; unsigned int adc:1; unsigned int srot_split:1; + unsigned int max_sensors; }; /** -- cgit From dbdaa582e4ee38c9e2c2d500ebb102a350b7e1fc Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:56 +0530 Subject: drivers: thermal: tsens: simplify get_temp_tsens_v2 routine The current implementation is based on an algorithm published in the docs. Instead of reading the temperature thrice w/o any explanation, improve the algorithm. This will become the basis for a common get_temp routine in the future. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-v2.c | 55 +++++++++++++---------------------------- 1 file changed, 17 insertions(+), 38 deletions(-) diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 01ec1b2681f2..780e16b09b28 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -25,58 +25,37 @@ #define TM_Sn_STATUS_OFF 0x00a0 #define TM_TRDY_OFF 0x00e4 -#define LAST_TEMP_MASK 0xfff - -static int get_temp_tsens_v2(struct tsens_priv *priv, int id, int *temp) +static int get_temp_tsens_v2(struct tsens_priv *priv, int i, int *temp) { - struct tsens_sensor *s = &priv->sensor[id]; + struct tsens_sensor *s = &priv->sensor[i]; u32 temp_idx = LAST_TEMP_0 + s->hw_id; u32 valid_idx = VALID_0 + s->hw_id; - u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0, valid; + u32 last_temp = 0, valid, mask; int ret; - ret = regmap_field_read(priv->rf[temp_idx], &last_temp); - if (ret) - return ret; - ret = regmap_field_read(priv->rf[valid_idx], &valid); if (ret) return ret; - - if (valid) - goto done; - - /* Try a second time */ - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; - ret = regmap_field_read(priv->rf[temp_idx], &last_temp2); - if (ret) - return ret; - if (valid) { - last_temp = last_temp2; - goto done; + while (!valid) { + /* Valid bit is 0 for 6 AHB clock cycles. + * At 19.2MHz, 1 AHB clock is ~60ns. + * We should enter this loop very, very rarely. + */ + ndelay(400); + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; } - /* Try a third/last time */ - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; - ret = regmap_field_read(priv->rf[temp_idx], &last_temp3); + /* Valid bit is set, OK to read the temperature */ + ret = regmap_field_read(priv->rf[temp_idx], &last_temp); if (ret) return ret; - if (valid) { - last_temp = last_temp3; - goto done; - } - if (last_temp == last_temp2) - last_temp = last_temp2; - else if (last_temp2 == last_temp3) - last_temp = last_temp3; -done: + mask = GENMASK(priv->fields[LAST_TEMP_0].msb, + priv->fields[LAST_TEMP_0].lsb); /* Convert temperature from deciCelsius to milliCelsius */ - *temp = sign_extend32(last_temp, fls(LAST_TEMP_MASK) - 1) * 100; + *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; return 0; } -- cgit From c8b6169093f66e9bae6eb5157ccc4ad426402caf Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:57 +0530 Subject: drivers: thermal: tsens: Move get_temp_tsens_v2 to allow sharing Just rename the function and move it to allow code sharing with future versions of TSENS IP Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 35 +++++++++++++++++++++++++++++++++++ drivers/thermal/qcom/tsens-v2.c | 37 +------------------------------------ drivers/thermal/qcom/tsens.h | 1 + 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 5607c5cc635c..5adbf1a2e0fb 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -102,6 +102,41 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) return degc; } +int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp) +{ + struct tsens_sensor *s = &priv->sensor[i]; + u32 temp_idx = LAST_TEMP_0 + s->hw_id; + u32 valid_idx = VALID_0 + s->hw_id; + u32 last_temp = 0, valid, mask; + int ret; + + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; + while (!valid) { + /* Valid bit is 0 for 6 AHB clock cycles. + * At 19.2MHz, 1 AHB clock is ~60ns. + * We should enter this loop very, very rarely. + */ + ndelay(400); + ret = regmap_field_read(priv->rf[valid_idx], &valid); + if (ret) + return ret; + } + + /* Valid bit is set, OK to read the temperature */ + ret = regmap_field_read(priv->rf[temp_idx], &last_temp); + if (ret) + return ret; + + mask = GENMASK(priv->fields[LAST_TEMP_0].msb, + priv->fields[LAST_TEMP_0].lsb); + /* Convert temperature from deciCelsius to milliCelsius */ + *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; + + return 0; +} + int get_temp_common(struct tsens_priv *priv, int i, int *temp) { struct tsens_sensor *s = &priv->sensor[i]; diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 780e16b09b28..1099069f2aa3 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -25,41 +25,6 @@ #define TM_Sn_STATUS_OFF 0x00a0 #define TM_TRDY_OFF 0x00e4 -static int get_temp_tsens_v2(struct tsens_priv *priv, int i, int *temp) -{ - struct tsens_sensor *s = &priv->sensor[i]; - u32 temp_idx = LAST_TEMP_0 + s->hw_id; - u32 valid_idx = VALID_0 + s->hw_id; - u32 last_temp = 0, valid, mask; - int ret; - - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; - while (!valid) { - /* Valid bit is 0 for 6 AHB clock cycles. - * At 19.2MHz, 1 AHB clock is ~60ns. - * We should enter this loop very, very rarely. - */ - ndelay(400); - ret = regmap_field_read(priv->rf[valid_idx], &valid); - if (ret) - return ret; - } - - /* Valid bit is set, OK to read the temperature */ - ret = regmap_field_read(priv->rf[temp_idx], &last_temp); - if (ret) - return ret; - - mask = GENMASK(priv->fields[LAST_TEMP_0].msb, - priv->fields[LAST_TEMP_0].lsb); - /* Convert temperature from deciCelsius to milliCelsius */ - *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; - - return 0; -} - /* v2.x: 8996, 8998, sdm845 */ static const struct tsens_features tsens_v2_feat = { @@ -101,7 +66,7 @@ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = { static const struct tsens_ops ops_generic_v2 = { .init = init_common, - .get_temp = get_temp_tsens_v2, + .get_temp = get_temp_tsens_valid, }; const struct tsens_plat_data data_tsens_v2 = { diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 080e15a09ac2..f14a87aa1a47 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -308,6 +308,7 @@ struct tsens_priv { char *qfprom_read(struct device *dev, const char *cname); void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode); int init_common(struct tsens_priv *priv); +int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp); int get_temp_common(struct tsens_priv *priv, int i, int *temp); bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id); -- cgit From 14bbe98811209f3fb3f8143285ddcf1f6108aae4 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:58 +0530 Subject: drivers: thermal: tsens: Common get_temp() learns to do ADC conversion get_temp() learns to return temperature regardless of whether it is returned as ADC code or direct temperature. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 5adbf1a2e0fb..92747ccb2850 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -129,10 +129,15 @@ int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp) if (ret) return ret; - mask = GENMASK(priv->fields[LAST_TEMP_0].msb, - priv->fields[LAST_TEMP_0].lsb); - /* Convert temperature from deciCelsius to milliCelsius */ - *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; + if (priv->feat->adc) { + /* Convert temperature from ADC code to milliCelsius */ + *temp = code_to_degc(last_temp, s) * 1000; + } else { + mask = GENMASK(priv->fields[LAST_TEMP_0].msb, + priv->fields[LAST_TEMP_0].lsb); + /* Convert temperature from deciCelsius to milliCelsius */ + *temp = sign_extend32(last_temp, fls(mask) - 1) * 100; + } return 0; } -- cgit From a9604f28087f3641bed923b455c7392cdf432cbf Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:47:59 +0530 Subject: dt: thermal: tsens: Add bindings for qcs404 qcs404 uses v1 of the TSENS IP block. Create a fallback DT property "qcom,tsens-v1" to gather common code Signed-off-by: Amit Kucheria Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/qcom-tsens.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt index 1d9e8cf61018..673cc1831ee9 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-tsens.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-tsens.txt @@ -6,11 +6,14 @@ Required properties: - "qcom,msm8916-tsens" (MSM8916) - "qcom,msm8974-tsens" (MSM8974) - "qcom,msm8996-tsens" (MSM8996) + - "qcom,qcs404-tsens", "qcom,tsens-v1" (QCS404) - "qcom,msm8998-tsens", "qcom,tsens-v2" (MSM8998) - "qcom,sdm845-tsens", "qcom,tsens-v2" (SDM845) The generic "qcom,tsens-v2" property must be used as a fallback for any SoC with version 2 of the TSENS IP. MSM8996 is the only exception because the generic property did not exist when support was added. + Similarly, the generic "qcom,tsens-v1" property must be used as a fallback for + any SoC with version 1 of the TSENS IP. - reg: Address range of the thermal registers. New platforms containing v2.x.y of the TSENS IP must specify the SROT and TM @@ -39,3 +42,14 @@ tsens0: thermal-sensor@c263000 { #qcom,sensors = <13>; #thermal-sensor-cells = <1>; }; + +Example 3 (for any platform containing v1 of the TSENS IP): +tsens: thermal-sensor@4a9000 { + compatible = "qcom,qcs404-tsens", "qcom,tsens-v1"; + reg = <0x004a9000 0x1000>, /* TM */ + <0x004a8000 0x1000>; /* SROT */ + nvmem-cells = <&tsens_caldata>; + nvmem-cell-names = "calib"; + #qcom,sensors = <10>; + #thermal-sensor-cells = <1>; + }; -- cgit From e8c24c6f5d1c7a8e124d41e1c8f27dd494937320 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:48:00 +0530 Subject: drivers: thermal: tsens: Add generic support for TSENS v1 IP qcs404 has a single TSENS IP block with 10 sensors. It uses version 1.4 of the TSENS IP, functionality for which is encapsulated inside the qcom,tsens-v1 compatible. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/Makefile | 4 +- drivers/thermal/qcom/tsens-v1.c | 193 ++++++++++++++++++++++++++++++++++++++++ drivers/thermal/qcom/tsens.c | 3 + drivers/thermal/qcom/tsens.h | 3 + 4 files changed, 202 insertions(+), 1 deletion(-) create mode 100644 drivers/thermal/qcom/tsens-v1.c diff --git a/drivers/thermal/qcom/Makefile b/drivers/thermal/qcom/Makefile index 7fa3cadce760..fc6fe50cdde4 100644 --- a/drivers/thermal/qcom/Makefile +++ b/drivers/thermal/qcom/Makefile @@ -1,3 +1,5 @@ obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o -qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o tsens-8960.o tsens-v2.o + +qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o \ + tsens-8960.o tsens-v2.o tsens-v1.o obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o diff --git a/drivers/thermal/qcom/tsens-v1.c b/drivers/thermal/qcom/tsens-v1.c new file mode 100644 index 000000000000..10b595d4f619 --- /dev/null +++ b/drivers/thermal/qcom/tsens-v1.c @@ -0,0 +1,193 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2019, Linaro Limited + */ + +#include +#include +#include +#include "tsens.h" + +/* ----- SROT ------ */ +#define SROT_HW_VER_OFF 0x0000 +#define SROT_CTRL_OFF 0x0004 + +/* ----- TM ------ */ +#define TM_INT_EN_OFF 0x0000 +#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF 0x0004 +#define TM_Sn_STATUS_OFF 0x0044 +#define TM_TRDY_OFF 0x0084 + +/* eeprom layout data for qcs404/405 (v1) */ +#define BASE0_MASK 0x000007f8 +#define BASE1_MASK 0x0007f800 +#define BASE0_SHIFT 3 +#define BASE1_SHIFT 11 + +#define S0_P1_MASK 0x0000003f +#define S1_P1_MASK 0x0003f000 +#define S2_P1_MASK 0x3f000000 +#define S3_P1_MASK 0x000003f0 +#define S4_P1_MASK 0x003f0000 +#define S5_P1_MASK 0x0000003f +#define S6_P1_MASK 0x0003f000 +#define S7_P1_MASK 0x3f000000 +#define S8_P1_MASK 0x000003f0 +#define S9_P1_MASK 0x003f0000 + +#define S0_P2_MASK 0x00000fc0 +#define S1_P2_MASK 0x00fc0000 +#define S2_P2_MASK_1_0 0xc0000000 +#define S2_P2_MASK_5_2 0x0000000f +#define S3_P2_MASK 0x0000fc00 +#define S4_P2_MASK 0x0fc00000 +#define S5_P2_MASK 0x00000fc0 +#define S6_P2_MASK 0x00fc0000 +#define S7_P2_MASK_1_0 0xc0000000 +#define S7_P2_MASK_5_2 0x0000000f +#define S8_P2_MASK 0x0000fc00 +#define S9_P2_MASK 0x0fc00000 + +#define S0_P1_SHIFT 0 +#define S0_P2_SHIFT 6 +#define S1_P1_SHIFT 12 +#define S1_P2_SHIFT 18 +#define S2_P1_SHIFT 24 +#define S2_P2_SHIFT_1_0 30 + +#define S2_P2_SHIFT_5_2 0 +#define S3_P1_SHIFT 4 +#define S3_P2_SHIFT 10 +#define S4_P1_SHIFT 16 +#define S4_P2_SHIFT 22 + +#define S5_P1_SHIFT 0 +#define S5_P2_SHIFT 6 +#define S6_P1_SHIFT 12 +#define S6_P2_SHIFT 18 +#define S7_P1_SHIFT 24 +#define S7_P2_SHIFT_1_0 30 + +#define S7_P2_SHIFT_5_2 0 +#define S8_P1_SHIFT 4 +#define S8_P2_SHIFT 10 +#define S9_P1_SHIFT 16 +#define S9_P2_SHIFT 22 + +#define CAL_SEL_MASK 7 +#define CAL_SEL_SHIFT 0 + +static int calibrate_v1(struct tsens_priv *priv) +{ + u32 base0 = 0, base1 = 0; + u32 p1[10], p2[10]; + u32 mode = 0, lsb = 0, msb = 0; + u32 *qfprom_cdata; + int i; + + qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib"); + if (IS_ERR(qfprom_cdata)) + return PTR_ERR(qfprom_cdata); + + mode = (qfprom_cdata[4] & CAL_SEL_MASK) >> CAL_SEL_SHIFT; + dev_dbg(priv->dev, "calibration mode is %d\n", mode); + + switch (mode) { + case TWO_PT_CALIB: + base1 = (qfprom_cdata[4] & BASE1_MASK) >> BASE1_SHIFT; + p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT; + p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT; + /* This value is split over two registers, 2 bits and 4 bits */ + lsb = (qfprom_cdata[0] & S2_P2_MASK_1_0) >> S2_P2_SHIFT_1_0; + msb = (qfprom_cdata[1] & S2_P2_MASK_5_2) >> S2_P2_SHIFT_5_2; + p2[2] = msb << 2 | lsb; + p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT; + p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT; + p2[5] = (qfprom_cdata[2] & S5_P2_MASK) >> S5_P2_SHIFT; + p2[6] = (qfprom_cdata[2] & S6_P2_MASK) >> S6_P2_SHIFT; + /* This value is split over two registers, 2 bits and 4 bits */ + lsb = (qfprom_cdata[2] & S7_P2_MASK_1_0) >> S7_P2_SHIFT_1_0; + msb = (qfprom_cdata[3] & S7_P2_MASK_5_2) >> S7_P2_SHIFT_5_2; + p2[7] = msb << 2 | lsb; + p2[8] = (qfprom_cdata[3] & S8_P2_MASK) >> S8_P2_SHIFT; + p2[9] = (qfprom_cdata[3] & S9_P2_MASK) >> S9_P2_SHIFT; + for (i = 0; i < priv->num_sensors; i++) + p2[i] = ((base1 + p2[i]) << 2); + /* Fall through */ + case ONE_PT_CALIB2: + base0 = (qfprom_cdata[4] & BASE0_MASK) >> BASE0_SHIFT; + p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT; + p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT; + p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT; + p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT; + p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT; + p1[5] = (qfprom_cdata[2] & S5_P1_MASK) >> S5_P1_SHIFT; + p1[6] = (qfprom_cdata[2] & S6_P1_MASK) >> S6_P1_SHIFT; + p1[7] = (qfprom_cdata[2] & S7_P1_MASK) >> S7_P1_SHIFT; + p1[8] = (qfprom_cdata[3] & S8_P1_MASK) >> S8_P1_SHIFT; + p1[9] = (qfprom_cdata[3] & S9_P1_MASK) >> S9_P1_SHIFT; + for (i = 0; i < priv->num_sensors; i++) + p1[i] = (((base0) + p1[i]) << 2); + break; + default: + for (i = 0; i < priv->num_sensors; i++) { + p1[i] = 500; + p2[i] = 780; + } + break; + } + + compute_intercept_slope(priv, p1, p2, mode); + + return 0; +} + +/* v1.x: qcs404,405 */ + +static const struct tsens_features tsens_v1_feat = { + .ver_major = VER_1_X, + .crit_int = 0, + .adc = 1, + .srot_split = 1, + .max_sensors = 11, +}; + +static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = { + /* ----- SROT ------ */ + /* VERSION */ + [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31), + [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27), + [VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15), + /* CTRL_OFFSET */ + [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0), + [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1), + [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 13), + + /* ----- TM ------ */ + /* INTERRUPT ENABLE */ + [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0), + + /* Sn_STATUS */ + REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 9), + REG_FIELD_FOR_EACH_SENSOR11(VALID, TM_Sn_STATUS_OFF, 14, 14), + REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS, TM_Sn_STATUS_OFF, 10, 10), + REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11), + REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12), + /* No CRITICAL field on v1.x */ + REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS, TM_Sn_STATUS_OFF, 13, 13), + + /* TRDY: 1=ready, 0=in progress */ + [TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0), +}; + +static const struct tsens_ops ops_generic_v1 = { + .init = init_common, + .calibrate = calibrate_v1, + .get_temp = get_temp_tsens_valid, +}; + +const struct tsens_plat_data data_tsens_v1 = { + .ops = &ops_generic_v1, + .feat = &tsens_v1_feat, + .fields = tsens_v1_regfields, +}; diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index fc44cac31fa5..36b0b52db524 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -63,6 +63,9 @@ static const struct of_device_id tsens_table[] = { }, { .compatible = "qcom,msm8996-tsens", .data = &data_8996, + }, { + .compatible = "qcom,tsens-v1", + .data = &data_tsens_v1, }, { .compatible = "qcom,tsens-v2", .data = &data_tsens_v2, diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index f14a87aa1a47..d648fba235cf 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -318,6 +318,9 @@ extern const struct tsens_plat_data data_8960; /* TSENS v0.1 targets */ extern const struct tsens_plat_data data_8916, data_8974; +/* TSENS v1 targets */ +extern const struct tsens_plat_data data_tsens_v1; + /* TSENS v2 targets */ extern const struct tsens_plat_data data_8996, data_tsens_v2; -- cgit From e52bbd2f10adf708b8a706bc8b89fbad53445c79 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 20 Mar 2019 18:48:03 +0530 Subject: drivers: thermal: tsens: Move calibration constants to header file This will allow calibration routines to correctly include the constants from anywhere and allow more code sharing. Signed-off-by: Amit Kucheria Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 5 ----- drivers/thermal/qcom/tsens.h | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 92747ccb2850..928e8e81ba69 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -12,11 +12,6 @@ #include #include "tsens.h" -#define CAL_DEGC_PT1 30 -#define CAL_DEGC_PT2 120 -#define SLOPE_FACTOR 1000 -#define SLOPE_DEFAULT 3200 - char *qfprom_read(struct device *dev, const char *cname) { struct nvmem_cell *cell; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index d648fba235cf..eefe3844fb4e 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -9,6 +9,11 @@ #define ONE_PT_CALIB 0x1 #define ONE_PT_CALIB2 0x2 #define TWO_PT_CALIB 0x3 +#define CAL_DEGC_PT1 30 +#define CAL_DEGC_PT2 120 +#define SLOPE_FACTOR 1000 +#define SLOPE_DEFAULT 3200 + #include #include -- cgit From ed1b1ac1425b3d4399553411f305ce12fb3a6c54 Mon Sep 17 00:00:00 2001 From: Hoan Nguyen An Date: Wed, 27 Mar 2019 18:03:18 +0900 Subject: thermal: rcar_gen3_thermal: Fix init value of IRQCTL register Fix setting value for IRQCTL register. We are setting the last 6 bits of (IRQCTL) to be 1 (0x3f), this is only suitable for H3ES1.*, according to Hardware manual values 1 are "setting prohibited" for Gen3. Signed-off-by: Hoan Nguyen An Acked-by: Wolfram Sang Reviewed-by: Geert Uytterhoeven Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 88fa41cf16e8..248279539428 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -307,7 +307,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) usleep_range(1000, 2000); - rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); + rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2); -- cgit From c8044b918b2bd9e6ad93b4f14b42bcbb61dd544b Mon Sep 17 00:00:00 2001 From: Talel Shenhar Date: Thu, 11 Apr 2019 13:22:47 +0300 Subject: dt-bindings: thermal: al-thermal: Add binding documentation Add thermal binding documentation for Amazon's Annapurna Labs Thermal Sensor. Signed-off-by: Talel Shenhar Reviewed-by: David Woodhouse Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../bindings/thermal/amazon,al-thermal.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt diff --git a/Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt b/Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt new file mode 100644 index 000000000000..703979dbd577 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt @@ -0,0 +1,33 @@ +Amazon's Annapurna Labs Thermal Sensor + +Simple thermal device that allows temperature reading by a single MMIO +transaction. + +Required properties: +- compatible: "amazon,al-thermal". +- reg: The physical base address and length of the sensor's registers. +- #thermal-sensor-cells: Must be 1. See ./thermal.txt for a description. + +Example: + thermal: thermal { + compatible = "amazon,al-thermal"; + reg = <0x0 0x05002860 0x0 0x1>; + #thermal-sensor-cells = <0x1>; + }; + + thermal-zones { + thermal-z0 { + polling-delay-passive = <250>; + polling-delay = <1000>; + thermal-sensors = <&thermal 0>; + trips { + critical { + temperature = <105000>; + hysteresis = <2000>; + type = "critical"; + }; + }; + + }; + }; + -- cgit From 71aa3693493d5f51822d88cdd26bc5a51ae5544f Mon Sep 17 00:00:00 2001 From: Talel Shenhar Date: Thu, 11 Apr 2019 13:22:48 +0300 Subject: thermal: Introduce Amazon's Annapurna Labs Thermal Driver This is a generic thermal driver for simple MMIO sensors, of which amazon,al-thermal is one. This device uses a single MMIO transaction to read the temperature and report it to the thermal subsystem. Signed-off-by: Talel Shenhar Reviewed-by: David Woodhouse Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- MAINTAINERS | 6 ++ drivers/thermal/Kconfig | 10 ++++ drivers/thermal/Makefile | 1 + drivers/thermal/thermal_mmio.c | 129 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 drivers/thermal/thermal_mmio.c diff --git a/MAINTAINERS b/MAINTAINERS index 5c38f21aee78..4d08f59bdc3e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -744,6 +744,12 @@ S: Supported F: Documentation/networking/device_drivers/amazon/ena.txt F: drivers/net/ethernet/amazon/ +AMAZON ANNAPURNA LABS THERMAL MMIO DRIVER +M: Talel Shenhar +S: Maintained +F: Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt +F: drivers/thermal/thermal_mmio.c + AMD CRYPTOGRAPHIC COPROCESSOR (CCP) DRIVER M: Tom Lendacky M: Gary Hook diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 653aa27a25a4..41f3943bfe96 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -200,6 +200,16 @@ config THERMAL_EMULATION because userland can easily disable the thermal policy by simply flooding this sysfs node with low temperature values. +config THERMAL_MMIO + tristate "Generic Thermal MMIO driver" + depends on OF || COMPILE_TEST + help + This option enables the generic thermal MMIO driver that will use + memory-mapped reads to get the temperature. Any HW/System that + allows temperature reading by a single memory-mapped reading, be it + register or shared memory, is a potential candidate to work with this + driver. + config HISI_THERMAL tristate "Hisilicon thermal driver" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 486d682be047..74a37c7f847a 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -29,6 +29,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o # platform thermal drivers obj-y += broadcom/ +obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o diff --git a/drivers/thermal/thermal_mmio.c b/drivers/thermal/thermal_mmio.c new file mode 100644 index 000000000000..de3cceea23bc --- /dev/null +++ b/drivers/thermal/thermal_mmio.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + */ + +#include +#include +#include +#include + +struct thermal_mmio { + void __iomem *mmio_base; + u32 (*read_mmio)(void __iomem *mmio_base); + u32 mask; + int factor; +}; + +static u32 thermal_mmio_readb(void __iomem *mmio_base) +{ + return readb(mmio_base); +} + +static int thermal_mmio_get_temperature(void *private, int *temp) +{ + int t; + struct thermal_mmio *sensor = + (struct thermal_mmio *)private; + + t = sensor->read_mmio(sensor->mmio_base) & sensor->mask; + t *= sensor->factor; + + *temp = t; + + return 0; +} + +static struct thermal_zone_of_device_ops thermal_mmio_ops = { + .get_temp = thermal_mmio_get_temperature, +}; + +static int thermal_mmio_probe(struct platform_device *pdev) +{ + struct resource *resource; + struct thermal_mmio *sensor; + int (*sensor_init_func)(struct platform_device *pdev, + struct thermal_mmio *sensor); + struct thermal_zone_device *thermal_zone; + int ret; + int temperature; + + sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (IS_ERR(resource)) { + dev_err(&pdev->dev, + "fail to get platform memory resource (%ld)\n", + PTR_ERR(resource)); + return PTR_ERR(resource); + } + + sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource); + if (IS_ERR(sensor->mmio_base)) { + dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n", + PTR_ERR(sensor->mmio_base)); + return PTR_ERR(sensor->mmio_base); + } + + sensor_init_func = device_get_match_data(&pdev->dev); + if (sensor_init_func) { + ret = sensor_init_func(pdev, sensor); + if (ret) { + dev_err(&pdev->dev, + "failed to initialize sensor (%d)\n", + ret); + return ret; + } + } + + thermal_zone = devm_thermal_zone_of_sensor_register(&pdev->dev, + 0, + sensor, + &thermal_mmio_ops); + if (IS_ERR(thermal_zone)) { + dev_err(&pdev->dev, + "failed to register sensor (%ld)\n", + PTR_ERR(thermal_zone)); + return PTR_ERR(thermal_zone); + } + + thermal_mmio_get_temperature(sensor, &temperature); + dev_info(&pdev->dev, + "thermal mmio sensor %s registered, current temperature: %d\n", + pdev->name, temperature); + + return 0; +} + +static int al_thermal_init(struct platform_device *pdev, + struct thermal_mmio *sensor) +{ + sensor->read_mmio = thermal_mmio_readb; + sensor->mask = 0xff; + sensor->factor = 1000; + + return 0; +} + +static const struct of_device_id thermal_mmio_id_table[] = { + { .compatible = "amazon,al-thermal", .data = al_thermal_init}, + {} +}; +MODULE_DEVICE_TABLE(of, thermal_mmio_id_table); + +static struct platform_driver thermal_mmio_driver = { + .probe = thermal_mmio_probe, + .driver = { + .name = "thermal-mmio", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(thermal_mmio_id_table), + }, +}; + +module_platform_driver(thermal_mmio_driver); + +MODULE_AUTHOR("Talel Shenhar "); +MODULE_DESCRIPTION("Thermal MMIO Driver"); +MODULE_LICENSE("GPL v2"); -- cgit From f86a7a847ca39e613985b7419ce3970af91486b1 Mon Sep 17 00:00:00 2001 From: Andrey Smirnov Date: Sat, 13 Apr 2019 01:27:37 -0700 Subject: thermal: qoriq: Remove unnecessary DT node is NULL check It's impossible to use this driver outside of Device Tree, so if the probe function is called, the dev.of_node is guaranteed to not be NULL and guarding against that is pointless. Drop it. Signed-off-by: Andrey Smirnov Acked-by: Daniel Lezcano Cc: Chris Healy Cc: Lucas Stach Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: Angus Ainslie (Purism) Cc: linux-imx@nxp.com Cc: linux-pm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Eduardo Valentin --- drivers/thermal/qoriq_thermal.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c index 3b5f5b3fb1bc..7b364933bfb1 100644 --- a/drivers/thermal/qoriq_thermal.c +++ b/drivers/thermal/qoriq_thermal.c @@ -193,11 +193,6 @@ static int qoriq_tmu_probe(struct platform_device *pdev) struct qoriq_tmu_data *data; struct device_node *np = pdev->dev.of_node; - if (!np) { - dev_err(&pdev->dev, "Device OF-Node is NULL"); - return -ENODEV; - } - data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), GFP_KERNEL); if (!data) -- cgit From d36e2fa025387567710df740fd4dce1d5001b226 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dagenais Date: Thu, 18 Apr 2019 12:37:32 -0400 Subject: thermal: generic-adc: make lookup table optional Certain ADC channels, such as the xilinx-ams temperature channels, give milliCelcius already when read with iio_read_channel_processed. Rather than having to provide a 1:1 dummy lookup table, simply allow to bypass the mechanism. Signed-off-by: Jean-Francois Dagenais Signed-off-by: Eduardo Valentin --- drivers/thermal/thermal-generic-adc.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/thermal-generic-adc.c b/drivers/thermal/thermal-generic-adc.c index e22fc60ad36d..deb244f12de4 100644 --- a/drivers/thermal/thermal-generic-adc.c +++ b/drivers/thermal/thermal-generic-adc.c @@ -29,6 +29,9 @@ static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) int temp, temp_hi, temp_lo, adc_hi, adc_lo; int i; + if (!gti->lookup_table) + return val; + for (i = 0; i < gti->nlookup_table; i++) { if (val >= gti->lookup_table[2 * i + 1]) break; @@ -81,9 +84,9 @@ static int gadc_thermal_read_linear_lookup_table(struct device *dev, ntable = of_property_count_elems_of_size(np, "temperature-lookup-table", sizeof(u32)); - if (ntable < 0) { - dev_err(dev, "Lookup table is not provided\n"); - return ntable; + if (ntable <= 0) { + dev_notice(dev, "no lookup table, assuming DAC channel returns milliCelcius\n"); + return 0; } if (ntable % 2) { -- cgit From 80d95930dcdf06315cfde408c18783c811bf3db9 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dagenais Date: Thu, 18 Apr 2019 12:37:33 -0400 Subject: dt-bindings: thermal: generic-adc: make lookup-table optional Update binding description making lookup-table optional. Signed-off-by: Jean-Francois Dagenais Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/thermal-generic-adc.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt b/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt index d72355502b78..691a09db2fef 100644 --- a/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt +++ b/Documentation/devicetree/bindings/thermal/thermal-generic-adc.txt @@ -8,16 +8,22 @@ temperature using voltage-temperature lookup table. Required properties: =================== - compatible: Must be "generic-adc-thermal". +- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description + of this property. +Optional properties: +=================== - temperature-lookup-table: Two dimensional array of Integer; lookup table to map the relation between ADC value and temperature. When ADC is read, the value is looked up on the table to get the equivalent temperature. + The first value of the each row of array is the temperature in milliCelsius and second value of the each row of array is the ADC read value. -- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description - of this property. + + If not specified, driver assumes the ADC channel + gives milliCelsius directly. Example : #include -- cgit From b4ab114cc6a1bbf8ca1d9a2339f2b5b43374029b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 18 Apr 2019 12:58:15 -0700 Subject: thermal: Introduce devm_thermal_of_cooling_device_register thermal_of_cooling_device_register() and thermal_cooling_device_register() are typically called from driver probe functions, and thermal_cooling_device_unregister() is called from remove functions. This makes both a perfect candidate for device managed functions. Introduce devm_thermal_of_cooling_device_register(). This function can also be used to replace thermal_cooling_device_register() by passing a NULL pointer as device node. The new function requires both struct device * and struct device_node * as parameters since the struct device_node * parameter is not always identical to dev->of_node. Don't introduce a device managed remove function since it is not needed at this point. Signed-off-by: Guenter Roeck Signed-off-by: Eduardo Valentin --- drivers/thermal/thermal_core.c | 49 ++++++++++++++++++++++++++++++++++++++++++ include/linux/thermal.h | 13 +++++++++++ 2 files changed, 62 insertions(+) diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 6590bb5cb688..e0b530603db6 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -1046,6 +1046,55 @@ thermal_of_cooling_device_register(struct device_node *np, } EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register); +static void thermal_cooling_device_release(struct device *dev, void *res) +{ + thermal_cooling_device_unregister( + *(struct thermal_cooling_device **)res); +} + +/** + * devm_thermal_of_cooling_device_register() - register an OF thermal cooling + * device + * @dev: a valid struct device pointer of a sensor device. + * @np: a pointer to a device tree node. + * @type: the thermal cooling device type. + * @devdata: device private data. + * @ops: standard thermal cooling devices callbacks. + * + * This function will register a cooling device with device tree node reference. + * This interface function adds a new thermal cooling device (fan/processor/...) + * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself + * to all the thermal zone devices registered at the same time. + * + * Return: a pointer to the created struct thermal_cooling_device or an + * ERR_PTR. Caller must check return value with IS_ERR*() helpers. + */ +struct thermal_cooling_device * +devm_thermal_of_cooling_device_register(struct device *dev, + struct device_node *np, + char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ + struct thermal_cooling_device **ptr, *tcd; + + ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + + tcd = __thermal_cooling_device_register(np, type, devdata, ops); + if (IS_ERR(tcd)) { + devres_free(ptr); + return tcd; + } + + *ptr = tcd; + devres_add(dev, ptr); + + return tcd; +} +EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register); + static void __unbind(struct thermal_zone_device *tz, int mask, struct thermal_cooling_device *cdev) { diff --git a/include/linux/thermal.h b/include/linux/thermal.h index 5f4705f46c2f..4a22099ed8c0 100644 --- a/include/linux/thermal.h +++ b/include/linux/thermal.h @@ -447,6 +447,11 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, struct thermal_cooling_device * thermal_of_cooling_device_register(struct device_node *np, char *, void *, const struct thermal_cooling_device_ops *); +struct thermal_cooling_device * +devm_thermal_of_cooling_device_register(struct device *dev, + struct device_node *np, + char *type, void *devdata, + const struct thermal_cooling_device_ops *ops); void thermal_cooling_device_unregister(struct thermal_cooling_device *); struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); @@ -503,6 +508,14 @@ static inline struct thermal_cooling_device * thermal_of_cooling_device_register(struct device_node *np, char *type, void *devdata, const struct thermal_cooling_device_ops *ops) { return ERR_PTR(-ENODEV); } +static inline struct thermal_cooling_device * +devm_thermal_of_cooling_device_register(struct device *dev, + struct device_node *np, + char *type, void *devdata, + const struct thermal_cooling_device_ops *ops) +{ + return ERR_PTR(-ENODEV); +} static inline void thermal_cooling_device_unregister( struct thermal_cooling_device *cdev) { } -- cgit From 2c0928c9e004589dc9e7672c40a38d6c4ca12701 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Wed, 24 Apr 2019 14:11:44 +0900 Subject: thermal: rcar_gen3_thermal: fix interrupt type Currently IRQF_SHARED type interrupt line is allocated, but it is not appropriate, as the interrupt line isn't shared between different devices, instead IRQF_ONESHOT is the proper type. By changing interrupt type to IRQF_ONESHOT, now irq handler is no longer needed, as clear of interrupt status can be done in threaded interrupt context. Because IRQF_ONESHOT type interrupt line is kept disabled until the threaded handler has been run, so there is no need to protect read/write of REG_GEN3_IRQSTR with lock. Fixes: 7d4b269776ec6 ("enable hardware interrupts for trip points") Signed-off-by: Jiada Wang Reviewed-by: Simon Horman Tested-by: Simon Horman Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 38 ++++++------------------------------- 1 file changed, 6 insertions(+), 32 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 248279539428..cf5ae8f6e8ed 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -82,7 +81,6 @@ struct rcar_gen3_thermal_tsc { struct rcar_gen3_thermal_priv { struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM]; unsigned int num_tscs; - spinlock_t lock; /* Protect interrupts on and off */ void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc); }; @@ -232,38 +230,16 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data) { struct rcar_gen3_thermal_priv *priv = data; u32 status; - int i, ret = IRQ_HANDLED; + int i; - spin_lock(&priv->lock); for (i = 0; i < priv->num_tscs; i++) { status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); if (status) - ret = IRQ_WAKE_THREAD; + thermal_zone_device_update(priv->tscs[i]->zone, + THERMAL_EVENT_UNSPECIFIED); } - if (ret == IRQ_WAKE_THREAD) - rcar_thermal_irq_set(priv, false); - - spin_unlock(&priv->lock); - - return ret; -} - -static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data) -{ - struct rcar_gen3_thermal_priv *priv = data; - unsigned long flags; - int i; - - for (i = 0; i < priv->num_tscs; i++) - thermal_zone_device_update(priv->tscs[i]->zone, - THERMAL_EVENT_UNSPECIFIED); - - spin_lock_irqsave(&priv->lock, flags); - rcar_thermal_irq_set(priv, true); - spin_unlock_irqrestore(&priv->lock, flags); - return IRQ_HANDLED; } @@ -371,8 +347,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (soc_device_match(r8a7795es1)) priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1; - spin_lock_init(&priv->lock); - platform_set_drvdata(pdev, priv); /* @@ -390,9 +364,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) if (!irqname) return -ENOMEM; - ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq, - rcar_gen3_thermal_irq_thread, - IRQF_SHARED, irqname, priv); + ret = devm_request_threaded_irq(dev, irq, NULL, + rcar_gen3_thermal_irq, + IRQF_ONESHOT, irqname, priv); if (ret) return ret; } -- cgit From 63f55fcea50c25ae5ad45af92d08dae3b84534c2 Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Wed, 24 Apr 2019 14:11:45 +0900 Subject: thermal: rcar_gen3_thermal: disable interrupt in .remove Currently IRQ remains enabled after .remove, later if device is probed, IRQ is requested before .thermal_init, this may cause IRQ function be called before device is initialized. this patch disables interrupt in .remove, to ensure irq function only be called after device is fully initialized. Signed-off-by: Jiada Wang Reviewed-by: Simon Horman Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index cf5ae8f6e8ed..e6727bd09f86 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -307,6 +307,9 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); static int rcar_gen3_thermal_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev); + + rcar_thermal_irq_set(priv, false); pm_runtime_put(dev); pm_runtime_disable(dev); -- cgit From 3c74cbb8d0013f6ec7cdee0812247dae35edd757 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Wed, 24 Apr 2019 22:56:09 +0200 Subject: thermal/drivers/cpu_cooling: Remove pointless test in power2state() When the static power computation was removed, the test with the power being negative was not removed. However, the substraction which was responsible of the negative value was removed and the variable is now an u32. A double reason to remove the test which does not make sense. Fixes: 84fe2cab48590 ("cpu_cooling: Drop static-power related stuff") Cc: Viresh Kumar Signed-off-by: Daniel Lezcano Acked-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- drivers/thermal/cpu_cooling.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index f7c1f49ec87f..ee8419a6390c 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -541,7 +541,6 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev, struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata; struct cpufreq_policy *policy = cpufreq_cdev->policy; - power = power > 0 ? power : 0; last_load = cpufreq_cdev->last_load ?: 1; normalised_power = (power * 100) / last_load; target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power); -- cgit From 42cd9b049829d7facbd45ab503d763a86251e81b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sun, 28 Apr 2019 11:51:03 +0200 Subject: thermal/drivers/cpu_cooling: Fixup the header and copyright The copyright format does not conform to the format requested by Linaro: https://wiki.linaro.org/Copyright Fix it. Signed-off-by: Daniel Lezcano Acked-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- drivers/thermal/cpu_cooling.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index ee8419a6390c..42aeb9087cab 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -2,9 +2,11 @@ * linux/drivers/thermal/cpu_cooling.c * * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) - * Copyright (C) 2012 Amit Daniel * - * Copyright (C) 2014 Viresh Kumar + * Copyright (C) 2012-2018 Linaro Limited. + * + * Authors: Amit Daniel + * Viresh Kumar * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * This program is free software; you can redistribute it and/or modify -- cgit From 0fac9e2f1452ffb6f43926609a569372204262eb Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sun, 28 Apr 2019 11:51:04 +0200 Subject: thermal/drivers/cpu_cooling: Add Software Package Data Exchange (SPDX) For license auditing purpose, let's add the SPDX tag. Signed-off-by: Daniel Lezcano Acked-by: Viresh Kumar Acked-by: Philippe Ombredanne Signed-off-by: Eduardo Valentin --- drivers/thermal/cpu_cooling.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 42aeb9087cab..b9d152a5f7ba 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * linux/drivers/thermal/cpu_cooling.c * @@ -8,21 +9,6 @@ * Authors: Amit Daniel * Viresh Kumar * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * 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. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include #include -- cgit From 72554a7509aeb3fe94d9cf6746c9cb056622784f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Sun, 28 Apr 2019 11:51:05 +0200 Subject: thermal/drivers/cpu_cooling: Remove pointless field The structure cpufreq_cooling_device provides a backpointer to the thermal device but this one is used for a trace and to unregister. For the trace, we don't really need this field and the unregister function as the same pointer passed as parameter. Remove it. Acked-by: Viresh Kumar Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/cpu_cooling.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index b9d152a5f7ba..9b014d0e8e70 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -87,7 +87,6 @@ struct cpufreq_cooling_device { unsigned int clipped_freq; unsigned int max_level; struct freq_table *freq_table; /* In descending order */ - struct thermal_cooling_device *cdev; struct cpufreq_policy *policy; struct list_head node; struct time_in_idle *idle_time; @@ -195,8 +194,7 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev, dev = get_cpu_device(cpu); if (unlikely(!dev)) { - dev_warn(&cpufreq_cdev->cdev->device, - "No cpu device for cpu %d\n", cpu); + pr_warn("No cpu device for cpu %d\n", cpu); return -ENODEV; } @@ -679,7 +677,6 @@ __cpufreq_cooling_register(struct device_node *np, goto remove_ida; cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency; - cpufreq_cdev->cdev = cdev; mutex_lock(&cooling_list_lock); /* Register the notifier for first cpufreq cooling device */ @@ -797,7 +794,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); - thermal_cooling_device_unregister(cpufreq_cdev->cdev); + thermal_cooling_device_unregister(cdev); ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); kfree(cpufreq_cdev->idle_time); kfree(cpufreq_cdev->freq_table); -- cgit From 6ec8070b9d48294fbe865535c167a79527eaf357 Mon Sep 17 00:00:00 2001 From: Talel Shenhar Date: Mon, 29 Apr 2019 12:47:36 +0300 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/thermal/thermal_mmio.o: In function 'thermal_mmio_probe':thermal_mmio.c:(.text+0xe1): undefined reference to `devm_ioremap_resource' The users of devm_ioremap_resource() which are compile-testable should depend on HAS_IOMEM. Reported-by: kbuild test robot Signed-off-by: Talel Shenhar Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 41f3943bfe96..66a709d5d6b9 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -203,6 +203,7 @@ config THERMAL_EMULATION config THERMAL_MMIO tristate "Generic Thermal MMIO driver" depends on OF || COMPILE_TEST + depends on HAS_IOMEM help This option enables the generic thermal MMIO driver that will use memory-mapped reads to get the temperature. Any HW/System that -- cgit From fcc6d4cadadcc977911c6bfcdd95d379f4082c74 Mon Sep 17 00:00:00 2001 From: Srinath Mannam Date: Mon, 29 Apr 2019 22:25:29 +0530 Subject: thermal: broadcom: Remove ACPI support Unlike DT framework, thermal-zones and its parameters can't be parsed using ACPI framework. So that ACPI support is removed in this driver. Signed-off-by: Srinath Mannam Reported-by: David Woodhouse Signed-off-by: Eduardo Valentin --- drivers/thermal/broadcom/sr-thermal.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/thermal/broadcom/sr-thermal.c b/drivers/thermal/broadcom/sr-thermal.c index 2284cbecedf3..475ce2900771 100644 --- a/drivers/thermal/broadcom/sr-thermal.c +++ b/drivers/thermal/broadcom/sr-thermal.c @@ -3,7 +3,6 @@ * Copyright (C) 2018 Broadcom */ -#include #include #include #include @@ -100,18 +99,11 @@ static const struct of_device_id sr_thermal_of_match[] = { }; MODULE_DEVICE_TABLE(of, sr_thermal_of_match); -static const struct acpi_device_id sr_thermal_acpi_ids[] = { - { .id = "BRCM0500" }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(acpi, sr_thermal_acpi_ids); - static struct platform_driver sr_thermal_driver = { .probe = sr_thermal_probe, .driver = { .name = "sr-thermal", .of_match_table = sr_thermal_of_match, - .acpi_match_table = ACPI_PTR(sr_thermal_acpi_ids), }, }; module_platform_driver(sr_thermal_driver); -- cgit From 28694e009e512451ead5519dd801f9869acb1f60 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Tue, 30 Apr 2019 18:09:44 +0800 Subject: thermal: rockchip: fix up the tsadc pinctrl setting error Explicitly use the pinctrl to set/unset the right mode instead of relying on the pinctrl init mode. And it requires setting the tshut polarity before select pinctrl. When the temperature sensor mode is set to 0, it will automatically reset the board via the Clock-Reset-Unit (CRU) if the over temperature threshold is reached. However, when the pinctrl initializes, it does a transition to "otp_out" which may lead the SoC restart all the time. "otp_out" IO may be connected to the RESET circuit on the hardware. If the IO is in the wrong state, it will trigger RESET. (similar to the effect of pressing the RESET button) which will cause the soc to restart all the time. Signed-off-by: Elaine Zhang Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/rockchip_thermal.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 9c7643d62ed7..6dc7fc516abf 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -172,6 +172,9 @@ struct rockchip_thermal_data { int tshut_temp; enum tshut_mode tshut_mode; enum tshut_polarity tshut_polarity; + struct pinctrl *pinctrl; + struct pinctrl_state *gpio_state; + struct pinctrl_state *otp_state; }; /** @@ -1242,6 +1245,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev) return error; } + thermal->chip->control(thermal->regs, false); + error = clk_prepare_enable(thermal->clk); if (error) { dev_err(&pdev->dev, "failed to enable converter clock: %d\n", @@ -1267,6 +1272,30 @@ static int rockchip_thermal_probe(struct platform_device *pdev) thermal->chip->initialize(thermal->grf, thermal->regs, thermal->tshut_polarity); + if (thermal->tshut_mode == TSHUT_MODE_GPIO) { + thermal->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(thermal->pinctrl)) { + dev_err(&pdev->dev, "failed to find thermal pinctrl\n"); + return PTR_ERR(thermal->pinctrl); + } + + thermal->gpio_state = pinctrl_lookup_state(thermal->pinctrl, + "gpio"); + if (IS_ERR_OR_NULL(thermal->gpio_state)) { + dev_err(&pdev->dev, "failed to find thermal gpio state\n"); + return -EINVAL; + } + + thermal->otp_state = pinctrl_lookup_state(thermal->pinctrl, + "otpout"); + if (IS_ERR_OR_NULL(thermal->otp_state)) { + dev_err(&pdev->dev, "failed to find thermal otpout state\n"); + return -EINVAL; + } + + pinctrl_select_state(thermal->pinctrl, thermal->otp_state); + } + for (i = 0; i < thermal->chip->chn_num; i++) { error = rockchip_thermal_register_sensor(pdev, thermal, &thermal->sensors[i], @@ -1337,8 +1366,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev) clk_disable(thermal->pclk); clk_disable(thermal->clk); - - pinctrl_pm_select_sleep_state(dev); + if (thermal->tshut_mode == TSHUT_MODE_GPIO) + pinctrl_select_state(thermal->pinctrl, thermal->gpio_state); return 0; } @@ -1383,7 +1412,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) for (i = 0; i < thermal->chip->chn_num; i++) rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); - pinctrl_pm_select_default_state(dev); + if (thermal->tshut_mode == TSHUT_MODE_GPIO) + pinctrl_select_state(thermal->pinctrl, thermal->otp_state); return 0; } -- cgit From 4b984e7bfb6d8e4209838a55af4ae5fbba878867 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Tue, 30 Apr 2019 18:09:45 +0800 Subject: dt-bindings: rockchip-thermal: Support the PX30 SoC compatible Add a new compatible for thermal founding on PX30 SoCs. Signed-off-by: Elaine Zhang Acked-by: Daniel Lezcano Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/rockchip-thermal.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt index 43d744e5305e..c6aac9bcacf1 100644 --- a/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rockchip-thermal.txt @@ -2,6 +2,7 @@ Required properties: - compatible : should be "rockchip,-tsadc" + "rockchip,px30-tsadc": found on PX30 SoCs "rockchip,rv1108-tsadc": found on RV1108 SoCs "rockchip,rk3228-tsadc": found on RK3228 SoCs "rockchip,rk3288-tsadc": found on RK3288 SoCs -- cgit From ffd1b122d3a17783b68cfd03b0479dffedf0d960 Mon Sep 17 00:00:00 2001 From: Elaine Zhang Date: Tue, 30 Apr 2019 18:09:46 +0800 Subject: thermal: rockchip: Support the PX30 SoC in thermal driver PX30 SOC has two Temperature Sensors for CPU and GPU. Signed-off-by: Elaine Zhang Signed-off-by: Eduardo Valentin --- drivers/thermal/rockchip_thermal.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 6dc7fc516abf..bda1ca199abd 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c @@ -225,11 +225,15 @@ struct rockchip_thermal_data { #define GRF_TSADC_TESTBIT_L 0x0e648 #define GRF_TSADC_TESTBIT_H 0x0e64c +#define PX30_GRF_SOC_CON2 0x0408 + #define GRF_SARADC_TESTBIT_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) #define GRF_TSADC_VCM_EN_L (0x10001 << 7) #define GRF_TSADC_VCM_EN_H (0x10001 << 7) +#define GRF_CON_TSADC_CH_INV (0x10001 << 1) + /** * struct tsadc_table - code to temperature conversion table * @code: the value of adc channel @@ -692,6 +696,13 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, regs + TSADCV2_AUTO_CON); } +static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs, + enum tshut_polarity tshut_polarity) +{ + rk_tsadcv2_initialize(grf, regs, tshut_polarity); + regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV); +} + static void rk_tsadcv2_irq_ack(void __iomem *regs) { u32 val; @@ -821,6 +832,30 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, writel_relaxed(val, regs + TSADCV2_INT_EN); } +static const struct rockchip_tsadc_chip px30_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, /* 2 channels for tsadc */ + + .tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */ + .tshut_temp = 95000, + + .initialize = rk_tsadcv4_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 rv1108_tsadc_data = { .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ .chn_num = 1, /* one channel for tsadc */ @@ -993,6 +1028,9 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { }; static const struct of_device_id of_rockchip_thermal_match[] = { + { .compatible = "rockchip,px30-tsadc", + .data = (void *)&px30_tsadc_data, + }, { .compatible = "rockchip,rv1108-tsadc", .data = (void *)&rv1108_tsadc_data, -- cgit From bf45ac18b78038e43af3c1a273cae4ab5704d2ce Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Thu, 2 May 2019 11:32:38 -0700 Subject: thermal: cpu_cooling: Actually trace CPU load in thermal_power_cpu_get_power The CPU load values passed to the thermal_power_cpu_get_power tracepoint are zero for all CPUs, unless, unless the thermal_power_cpu_limit tracepoint is enabled too: irq/41-rockchip-98 [000] .... 290.972410: thermal_power_cpu_get_power: cpus=0000000f freq=1800000 load={{0x0,0x0,0x0,0x0}} dynamic_power=4815 vs irq/41-rockchip-96 [000] .... 95.773585: thermal_power_cpu_get_power: cpus=0000000f freq=1800000 load={{0x56,0x64,0x64,0x5e}} dynamic_power=4959 irq/41-rockchip-96 [000] .... 95.773596: thermal_power_cpu_limit: cpus=0000000f freq=408000 cdev_state=10 power=416 There seems to be no good reason for omitting the CPU load information depending on another tracepoint. My guess is that the intention was to check whether thermal_power_cpu_get_power is (still) enabled, however 'load_cpu != NULL' already indicates that it was at least enabled when cpufreq_get_requested_power() was entered, there seems little gain from omitting the assignment if the tracepoint was just disabled, so just remove the check. Fixes: 6828a4711f99 ("thermal: add trace events to the power allocator governor") Signed-off-by: Matthias Kaehlcke Reviewed-by: Daniel Lezcano Acked-by: Javi Merino Acked-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- drivers/thermal/cpu_cooling.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 9b014d0e8e70..4c5db59a619b 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -444,7 +444,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, load = 0; total_load += load; - if (trace_thermal_power_cpu_limit_enabled() && load_cpu) + if (load_cpu) load_cpu[i] = load; i++; -- cgit From 20386f0d84a22214d1f037dedfffb6709dd0117a Mon Sep 17 00:00:00 2001 From: Yoshihiro Kaneko Date: Wed, 8 May 2019 13:08:45 +0200 Subject: thermal: rcar_thermal: update calculation formula for R-Car Gen3 SoCs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update calculation for the R-Car Gen3 and RZ/G2 SoCs which have a thermal IP block controlled by this driver. That is the: * R-Car D3 (r8a77995) * R-Car E2 (r8a77990) * R-Car V3M (r8a77970) * RZ/G2E (r8a774c0) The calculation update is as documented in the R-Car Gen3 User's Manual, v1.50 Nov 2018: - When CTEMP is less than 24 T = CTEMP[5:0] * 5.5 - 72 - When CTEMP is equal to/greater than 24 T = CTEMP[5:0] * 5 - 60 This was inspired by a patch in the BSP by Van Do Signed-off-by: Yoshihiro Kaneko Tested-by: Simon Horman Acked-by: Wolfram Sang Reviewed-by: Niklas Söderlund Signed-off-by: Simon Horman Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_thermal.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 97462e9b40d8..d0873de718da 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -52,6 +52,7 @@ struct rcar_thermal_chip { unsigned int irq_per_ch : 1; unsigned int needs_suspend_resume : 1; unsigned int nirqs; + unsigned int ctemp_bands; }; static const struct rcar_thermal_chip rcar_thermal = { @@ -60,6 +61,7 @@ static const struct rcar_thermal_chip rcar_thermal = { .irq_per_ch = 0, .needs_suspend_resume = 0, .nirqs = 1, + .ctemp_bands = 1, }; static const struct rcar_thermal_chip rcar_gen2_thermal = { @@ -68,6 +70,7 @@ static const struct rcar_thermal_chip rcar_gen2_thermal = { .irq_per_ch = 0, .needs_suspend_resume = 0, .nirqs = 1, + .ctemp_bands = 1, }; static const struct rcar_thermal_chip rcar_gen3_thermal = { @@ -80,6 +83,7 @@ static const struct rcar_thermal_chip rcar_gen3_thermal = { * interrupts to detect a temperature change, rise or fall. */ .nirqs = 2, + .ctemp_bands = 2, }; struct rcar_thermal_priv { @@ -263,7 +267,12 @@ static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv, return ret; mutex_lock(&priv->lock); - tmp = MCELSIUS((priv->ctemp * 5) - 65); + if (priv->chip->ctemp_bands == 1) + tmp = MCELSIUS((priv->ctemp * 5) - 65); + else if (priv->ctemp < 24) + tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10); + else + tmp = MCELSIUS((priv->ctemp * 5) - 60); mutex_unlock(&priv->lock); if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) { -- cgit From e380ea8117ce8c83c5da7063a3587a728132de0b Mon Sep 17 00:00:00 2001 From: Jiada Wang Date: Thu, 9 May 2019 18:09:17 +0900 Subject: thermal: rcar_gen3_thermal: Fix to show correct trip points number Currently after store trip points number in 'ret', it is overwritten afterwards, this cause incorrect trip point number always be shown in the debug information after register of each thermal zone. This patch fix this issue by moving get of trip number to end of thermal zone registration. Fixes: 6269e9f790e8d ("thermal: rcar_gen3_thermal: Register hwmon sysfs interface") Signed-off-by: Jiada Wang Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index e6727bd09f86..83f306265ee1 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -410,10 +410,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) } tsc->zone = zone; - ret = of_thermal_get_ntrips(tsc->zone); - if (ret < 0) - goto error_unregister; - tsc->zone->tzp->no_hwmon = false; ret = thermal_add_hwmon_sysfs(tsc->zone); if (ret) @@ -425,6 +421,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) goto error_unregister; } + ret = of_thermal_get_ntrips(tsc->zone); + if (ret < 0) + goto error_unregister; + dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret); } -- cgit From 389c0ad1d61ec5790174ecb0f01eac13423a18e1 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 18 Apr 2019 12:58:16 -0700 Subject: hwmon: (aspeed-pwm-tacho) Use devm_thermal_of_cooling_device_register Use devm_thermal_of_cooling_device_register() to register the cooling device. As a side effect, this fixes a driver bug: thermal_cooling_device_unregister() was not called on removal. Fixes: f198907d2ff6d ("hwmon: (aspeed-pwm-tacho) cooling device support.") Cc: Mykola Kostenok Cc: Joel Stanley Signed-off-by: Guenter Roeck Reviewed-by: Patrick Venture Signed-off-by: Eduardo Valentin --- drivers/hwmon/aspeed-pwm-tacho.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c index c4dd6301e7c8..0daf0b32aa4a 100644 --- a/drivers/hwmon/aspeed-pwm-tacho.c +++ b/drivers/hwmon/aspeed-pwm-tacho.c @@ -830,10 +830,8 @@ static int aspeed_create_pwm_cooling(struct device *dev, } snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port); - cdev->tcdev = thermal_of_cooling_device_register(child, - cdev->name, - cdev, - &aspeed_pwm_cool_ops); + cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child, + cdev->name, cdev, &aspeed_pwm_cool_ops); if (IS_ERR(cdev->tcdev)) return PTR_ERR(cdev->tcdev); -- cgit From 9534784550ab02a4394f499ff60765e89bc88f22 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 18 Apr 2019 12:58:17 -0700 Subject: hwmon: (gpio-fan) Use devm_thermal_of_cooling_device_register Call devm_thermal_of_cooling_device_register() to register the cooling device. Also use devm_add_action_or_reset() to stop the fan on device removal. This fixes a race condition since the fan was stopped before the hwmon device was removed. Signed-off-by: Guenter Roeck Signed-off-by: Eduardo Valentin --- drivers/hwmon/gpio-fan.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c index f1bf67aca9e8..3f6e5b4e3997 100644 --- a/drivers/hwmon/gpio-fan.c +++ b/drivers/hwmon/gpio-fan.c @@ -498,6 +498,11 @@ static const struct of_device_id of_gpio_fan_match[] = { }; MODULE_DEVICE_TABLE(of, of_gpio_fan_match); +static void gpio_fan_stop(void *data) +{ + set_fan_speed(data, 0); +} + static int gpio_fan_probe(struct platform_device *pdev) { int err; @@ -532,6 +537,7 @@ static int gpio_fan_probe(struct platform_device *pdev) err = fan_ctrl_init(fan_data); if (err) return err; + devm_add_action_or_reset(dev, gpio_fan_stop, fan_data); } /* Make this driver part of hwmon class. */ @@ -543,32 +549,20 @@ static int gpio_fan_probe(struct platform_device *pdev) return PTR_ERR(fan_data->hwmon_dev); /* Optional cooling device register for Device tree platforms */ - fan_data->cdev = thermal_of_cooling_device_register(np, - "gpio-fan", - fan_data, - &gpio_fan_cool_ops); + fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np, + "gpio-fan", fan_data, &gpio_fan_cool_ops); dev_info(dev, "GPIO fan initialized\n"); return 0; } -static int gpio_fan_remove(struct platform_device *pdev) +static void gpio_fan_shutdown(struct platform_device *pdev) { struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); - if (!IS_ERR(fan_data->cdev)) - thermal_cooling_device_unregister(fan_data->cdev); - if (fan_data->gpios) set_fan_speed(fan_data, 0); - - return 0; -} - -static void gpio_fan_shutdown(struct platform_device *pdev) -{ - gpio_fan_remove(pdev); } #ifdef CONFIG_PM_SLEEP @@ -602,7 +596,6 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); static struct platform_driver gpio_fan_driver = { .probe = gpio_fan_probe, - .remove = gpio_fan_remove, .shutdown = gpio_fan_shutdown, .driver = { .name = "gpio-fan", -- cgit From 9ebe010e566e9300bf3a7bb4ebfeb3f4deb72aa6 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 18 Apr 2019 12:58:18 -0700 Subject: hwmon: (mlxreg-fan) Use devm_thermal_of_cooling_device_register Call devm_thermal_of_cooling_device_register() to register the cooling device. Also introduce struct device *dev = &pdev->dev; to make the code easier to read. Signed-off-by: Guenter Roeck Signed-off-by: Eduardo Valentin --- drivers/hwmon/mlxreg-fan.c | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/drivers/hwmon/mlxreg-fan.c b/drivers/hwmon/mlxreg-fan.c index db8c6de0b6a0..a14347ea0d77 100644 --- a/drivers/hwmon/mlxreg-fan.c +++ b/drivers/hwmon/mlxreg-fan.c @@ -420,42 +420,42 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, static int mlxreg_fan_probe(struct platform_device *pdev) { struct mlxreg_core_platform_data *pdata; + struct device *dev = &pdev->dev; struct mlxreg_fan *fan; struct device *hwm; int err; - pdata = dev_get_platdata(&pdev->dev); + pdata = dev_get_platdata(dev); if (!pdata) { - dev_err(&pdev->dev, "Failed to get platform data.\n"); + dev_err(dev, "Failed to get platform data.\n"); return -EINVAL; } - fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); + fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL); if (!fan) return -ENOMEM; - fan->dev = &pdev->dev; + fan->dev = dev; fan->regmap = pdata->regmap; - platform_set_drvdata(pdev, fan); err = mlxreg_fan_config(fan, pdata); if (err) return err; - hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", + hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan", fan, &mlxreg_fan_hwmon_chip_info, NULL); if (IS_ERR(hwm)) { - dev_err(&pdev->dev, "Failed to register hwmon device\n"); + dev_err(dev, "Failed to register hwmon device\n"); return PTR_ERR(hwm); } if (IS_REACHABLE(CONFIG_THERMAL)) { - fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, - &mlxreg_fan_cooling_ops); + fan->cdev = devm_thermal_of_cooling_device_register(dev, + NULL, "mlxreg_fan", fan, &mlxreg_fan_cooling_ops); if (IS_ERR(fan->cdev)) { - dev_err(&pdev->dev, "Failed to register cooling device\n"); + dev_err(dev, "Failed to register cooling device\n"); return PTR_ERR(fan->cdev); } } @@ -463,22 +463,11 @@ static int mlxreg_fan_probe(struct platform_device *pdev) return 0; } -static int mlxreg_fan_remove(struct platform_device *pdev) -{ - struct mlxreg_fan *fan = platform_get_drvdata(pdev); - - if (IS_REACHABLE(CONFIG_THERMAL)) - thermal_cooling_device_unregister(fan->cdev); - - return 0; -} - static struct platform_driver mlxreg_fan_driver = { .driver = { .name = "mlxreg-fan", }, .probe = mlxreg_fan_probe, - .remove = mlxreg_fan_remove, }; module_platform_driver(mlxreg_fan_driver); -- cgit From 0b2a785db8797db08181f71395a412c8eedbc614 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 18 Apr 2019 12:58:19 -0700 Subject: hwmon: (npcm750-pwm-fan) Use devm_thermal_of_cooling_device_register Use devm_thermal_of_cooling_device_register() to register the cooling device. As a side effect, this fixes a driver bug: thermal_cooling_device_unregister() was not called on device removal. Fixes: f1fd4a4db777 ("hwmon: Add NPCM7xx PWM and Fan driver") Cc: Tomer Maimon Signed-off-by: Guenter Roeck Signed-off-by: Eduardo Valentin --- drivers/hwmon/npcm750-pwm-fan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hwmon/npcm750-pwm-fan.c b/drivers/hwmon/npcm750-pwm-fan.c index b3b907bdfb63..f24cc00caba9 100644 --- a/drivers/hwmon/npcm750-pwm-fan.c +++ b/drivers/hwmon/npcm750-pwm-fan.c @@ -864,10 +864,8 @@ static int npcm7xx_create_pwm_cooling(struct device *dev, snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child, pwm_port); - cdev->tcdev = thermal_of_cooling_device_register(child, - cdev->name, - cdev, - &npcm7xx_pwm_cool_ops); + cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child, + cdev->name, cdev, &npcm7xx_pwm_cool_ops); if (IS_ERR(cdev->tcdev)) return PTR_ERR(cdev->tcdev); -- cgit From 37bcec5d9f71bd13142a97d2196b293c9ac23823 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 18 Apr 2019 12:58:20 -0700 Subject: hwmon: (pwm-fan) Use devm_thermal_of_cooling_device_register Use devm_thermal_of_cooling_device_register() to register the cooling device. Also use devm_add_action_or_reset() to stop the fan on device removal, and to disable the pwm. Introduce a local 'dev' variable in the probe function to make the code easier to read. As a side effect, this fixes a bug seen if pwm_fan_of_get_cooling_data() returned an error. In that situation, the pwm was not disabled, and the fan was not stopped. Using devm functions also ensures that the pwm is disabled and that the fan is stopped only after the hwmon device has been unregistered. Cc: Lukasz Majewski Signed-off-by: Guenter Roeck Signed-off-by: Eduardo Valentin --- drivers/hwmon/pwm-fan.c | 73 ++++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/drivers/hwmon/pwm-fan.c b/drivers/hwmon/pwm-fan.c index 167221c7628a..0243ba70107e 100644 --- a/drivers/hwmon/pwm-fan.c +++ b/drivers/hwmon/pwm-fan.c @@ -207,33 +207,44 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, return 0; } +static void pwm_fan_regulator_disable(void *data) +{ + regulator_disable(data); +} + +static void pwm_fan_pwm_disable(void *data) +{ + pwm_disable(data); +} + static int pwm_fan_probe(struct platform_device *pdev) { struct thermal_cooling_device *cdev; + struct device *dev = &pdev->dev; struct pwm_fan_ctx *ctx; struct device *hwmon; int ret; struct pwm_state state = { }; - ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) return -ENOMEM; mutex_init(&ctx->lock); - ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); + ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL); if (IS_ERR(ctx->pwm)) { ret = PTR_ERR(ctx->pwm); if (ret != -EPROBE_DEFER) - dev_err(&pdev->dev, "Could not get PWM: %d\n", ret); + dev_err(dev, "Could not get PWM: %d\n", ret); return ret; } platform_set_drvdata(pdev, ctx); - ctx->reg_en = devm_regulator_get_optional(&pdev->dev, "fan"); + ctx->reg_en = devm_regulator_get_optional(dev, "fan"); if (IS_ERR(ctx->reg_en)) { if (PTR_ERR(ctx->reg_en) != -ENODEV) return PTR_ERR(ctx->reg_en); @@ -242,10 +253,11 @@ static int pwm_fan_probe(struct platform_device *pdev) } else { ret = regulator_enable(ctx->reg_en); if (ret) { - dev_err(&pdev->dev, - "Failed to enable fan supply: %d\n", ret); + dev_err(dev, "Failed to enable fan supply: %d\n", ret); return ret; } + devm_add_action_or_reset(dev, pwm_fan_regulator_disable, + ctx->reg_en); } ctx->pwm_value = MAX_PWM; @@ -257,62 +269,36 @@ static int pwm_fan_probe(struct platform_device *pdev) ret = pwm_apply_state(ctx->pwm, &state); if (ret) { - dev_err(&pdev->dev, "Failed to configure PWM\n"); - goto err_reg_disable; + dev_err(dev, "Failed to configure PWM\n"); + return ret; } + devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx->pwm); - hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan", + hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan", ctx, pwm_fan_groups); if (IS_ERR(hwmon)) { - dev_err(&pdev->dev, "Failed to register hwmon device\n"); - ret = PTR_ERR(hwmon); - goto err_pwm_disable; + dev_err(dev, "Failed to register hwmon device\n"); + return PTR_ERR(hwmon); } - ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx); + ret = pwm_fan_of_get_cooling_data(dev, ctx); if (ret) return ret; ctx->pwm_fan_state = ctx->pwm_fan_max_state; if (IS_ENABLED(CONFIG_THERMAL)) { - cdev = thermal_of_cooling_device_register(pdev->dev.of_node, - "pwm-fan", ctx, - &pwm_fan_cooling_ops); + cdev = devm_thermal_of_cooling_device_register(dev, + dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops); if (IS_ERR(cdev)) { - dev_err(&pdev->dev, + dev_err(dev, "Failed to register pwm-fan as cooling device"); - ret = PTR_ERR(cdev); - goto err_pwm_disable; + return PTR_ERR(cdev); } ctx->cdev = cdev; thermal_cdev_update(cdev); } return 0; - -err_pwm_disable: - state.enabled = false; - pwm_apply_state(ctx->pwm, &state); - -err_reg_disable: - if (ctx->reg_en) - regulator_disable(ctx->reg_en); - - return ret; -} - -static int pwm_fan_remove(struct platform_device *pdev) -{ - struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev); - - thermal_cooling_device_unregister(ctx->cdev); - if (ctx->pwm_value) - pwm_disable(ctx->pwm); - - if (ctx->reg_en) - regulator_disable(ctx->reg_en); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -380,7 +366,6 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match); static struct platform_driver pwm_fan_driver = { .probe = pwm_fan_probe, - .remove = pwm_fan_remove, .driver = { .name = "pwm-fan", .pm = &pwm_fan_pm, -- cgit