From 7fd5257f11445e35257a80d186a1da0e9795068f Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 31 Jul 2018 11:59:13 -0700 Subject: [PATCH 01/41] dt-bindings: thermal: qcom-spmi-temp-alarm: Fix documentation of 'reg' The documentation claims that the 'reg' property consists of two values, the SPMI address and the length of the controller's registers. However the SPMI bus to which it is added specifies "#size-cells = <0>;". Remove the controller register length from the documentation of the field and the example. Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt index 290ec06fa33a..86fb41fe772f 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt @@ -6,8 +6,7 @@ interrupt signal and status register to identify high PMIC die temperature. Required properties: - compatible: Should contain "qcom,spmi-temp-alarm". -- reg: Specifies the SPMI address and length of the controller's - registers. +- reg: Specifies the SPMI address. - interrupts: PMIC temperature alarm interrupt. - #thermal-sensor-cells: Should be 0. See thermal.txt for a description. @@ -20,7 +19,7 @@ Example: pm8941_temp: thermal-alarm@2400 { compatible = "qcom,spmi-temp-alarm"; - reg = <0x2400 0x100>; + reg = <0x2400>; interrupts = <0 0x24 0 IRQ_TYPE_EDGE_RISING>; #thermal-sensor-cells = <0>; From 97b27dd33d592b14cfb9299d5c89167ec57a3b83 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 31 Jul 2018 11:59:14 -0700 Subject: [PATCH 02/41] dt-bindings: thermal: qcom-spmi-temp-alarm: Improve thermal zone in example MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current example for a thermal zone isn't very useful as reference since it would result in a hardware shutdown at 145°C, instead of allowing the system to try to shutdown gracefully. Without an ADC channel a maximum of two trip points is useful in practice for this sensor, with temperatures corresponding to the stage 1 and stage 2 'hardware trip points'. A critical trip point at stage 2 may allow the system to shutdown before a hardware shutdown at stage 3 kicks in. It should be noted though that by default the chip performs a 'partial shutdown' when the temperature reaches stage 2, which may prevent an orderly shutdown. The 'partial shutdown' can be disabled by software. Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../bindings/thermal/qcom-spmi-temp-alarm.txt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt index 86fb41fe772f..0273a92a2a84 100644 --- a/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt +++ b/Documentation/devicetree/bindings/thermal/qcom-spmi-temp-alarm.txt @@ -35,19 +35,14 @@ Example: thermal-sensors = <&pm8941_temp>; trips { - passive { - temperature = <1050000>; + stage1 { + temperature = <105000>; hysteresis = <2000>; type = "passive"; }; - alert { + stage2 { temperature = <125000>; hysteresis = <2000>; - type = "hot"; - }; - crit { - temperature = <145000>; - hysteresis = <2000>; type = "critical"; }; }; From f1599f9e4cd6f1dd0cad202853fb830854f4e944 Mon Sep 17 00:00:00 2001 From: Matthias Kaehlcke Date: Tue, 31 Jul 2018 11:59:15 -0700 Subject: [PATCH 03/41] thermal: qcom-spmi: Use PMIC thermal stage 2 for critical trip points MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are three thermal stages defined in the PMIC: stage 1: warning stage 2: system should shut down stage 3: emergency shut down By default the PMIC assumes that the OS isn't doing anything and thus at stage 2 it does a partial PMIC shutdown and at stage 3 it kills all power. When switching between thermal stages the PMIC generates an interrupt which is handled by the driver. The partial PMIC shutdown at stage 2 can be disabled by software, which allows the OS to initiate a shutdown at stage 2 with a thermal zone configured accordingly. If a critical trip point is configured in the thermal zone the driver adjusts the stage 1-3 temperature thresholds to (closely) match the critical temperature with a stage 2 threshold (125/130/135/140 °C). If a suitable match is found the partial shutdown at stage 2 is disabled. If for some reason the system doesn't shutdown at stage 2 the emergency shutdown at stage 3 kicks in. The partial shutdown at stage 2 remains enabled in these cases: - no critical trip point defined - the temperature of the critical trip point is < 125°C - the temperature of the critical trip point is > 140°C and no ADC channel is configured (thus the OS is not notified when the critical temperature is reached) Suggested-by: Douglas Anderson Signed-off-by: Matthias Kaehlcke Reviewed-by: Douglas Anderson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom-spmi-temp-alarm.c | 158 ++++++++++++++++++++++--- 1 file changed, 140 insertions(+), 18 deletions(-) diff --git a/drivers/thermal/qcom-spmi-temp-alarm.c b/drivers/thermal/qcom-spmi-temp-alarm.c index ad4f3a8d6560..b2d5d5bf4a9b 100644 --- a/drivers/thermal/qcom-spmi-temp-alarm.c +++ b/drivers/thermal/qcom-spmi-temp-alarm.c @@ -23,6 +23,8 @@ #include #include +#include "thermal_core.h" + #define QPNP_TM_REG_TYPE 0x04 #define QPNP_TM_REG_SUBTYPE 0x05 #define QPNP_TM_REG_STATUS 0x08 @@ -37,9 +39,11 @@ #define STATUS_GEN2_STATE_MASK GENMASK(6, 4) #define STATUS_GEN2_STATE_SHIFT 4 -#define SHUTDOWN_CTRL1_OVERRIDE_MASK GENMASK(7, 6) +#define SHUTDOWN_CTRL1_OVERRIDE_S2 BIT(6) #define SHUTDOWN_CTRL1_THRESHOLD_MASK GENMASK(1, 0) +#define SHUTDOWN_CTRL1_RATE_25HZ BIT(3) + #define ALARM_CTRL_FORCE_ENABLE BIT(7) /* @@ -56,12 +60,19 @@ #define TEMP_THRESH_STEP 5000 /* Threshold step: 5 C */ #define THRESH_MIN 0 +#define THRESH_MAX 3 + +/* Stage 2 Threshold Min: 125 C */ +#define STAGE2_THRESHOLD_MIN 125000 +/* Stage 2 Threshold Max: 140 C */ +#define STAGE2_THRESHOLD_MAX 140000 /* Temperature in Milli Celsius reported during stage 0 if no ADC is present */ #define DEFAULT_TEMP 37000 struct qpnp_tm_chip { struct regmap *map; + struct device *dev; struct thermal_zone_device *tz_dev; unsigned int subtype; long temp; @@ -69,6 +80,10 @@ struct qpnp_tm_chip { unsigned int stage; unsigned int prev_stage; unsigned int base; + /* protects .thresh, .stage and chip registers */ + struct mutex lock; + bool initialized; + struct iio_channel *adc; }; @@ -125,6 +140,8 @@ static int qpnp_tm_update_temp_no_adc(struct qpnp_tm_chip *chip) unsigned int stage, stage_new, stage_old; int ret; + WARN_ON(!mutex_is_locked(&chip->lock)); + ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) return ret; @@ -163,8 +180,15 @@ static int qpnp_tm_get_temp(void *data, int *temp) if (!temp) return -EINVAL; + if (!chip->initialized) { + *temp = DEFAULT_TEMP; + return 0; + } + if (!chip->adc) { + mutex_lock(&chip->lock); ret = qpnp_tm_update_temp_no_adc(chip); + mutex_unlock(&chip->lock); if (ret < 0) return ret; } else { @@ -180,8 +204,72 @@ static int qpnp_tm_get_temp(void *data, int *temp) return 0; } +static int qpnp_tm_update_critical_trip_temp(struct qpnp_tm_chip *chip, + int temp) +{ + u8 reg; + bool disable_s2_shutdown = false; + + WARN_ON(!mutex_is_locked(&chip->lock)); + + /* + * Default: S2 and S3 shutdown enabled, thresholds at + * 105C/125C/145C, monitoring at 25Hz + */ + reg = SHUTDOWN_CTRL1_RATE_25HZ; + + if (temp == THERMAL_TEMP_INVALID || + temp < STAGE2_THRESHOLD_MIN) { + chip->thresh = THRESH_MIN; + goto skip; + } + + if (temp <= STAGE2_THRESHOLD_MAX) { + chip->thresh = THRESH_MAX - + ((STAGE2_THRESHOLD_MAX - temp) / + TEMP_THRESH_STEP); + disable_s2_shutdown = true; + } else { + chip->thresh = THRESH_MAX; + + if (chip->adc) + disable_s2_shutdown = true; + else + dev_warn(chip->dev, + "No ADC is configured and critical temperature is above the maximum stage 2 threshold of 140 C! Configuring stage 2 shutdown at 140 C.\n"); + } + +skip: + reg |= chip->thresh; + if (disable_s2_shutdown) + reg |= SHUTDOWN_CTRL1_OVERRIDE_S2; + + return qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); +} + +static int qpnp_tm_set_trip_temp(void *data, int trip, int temp) +{ + struct qpnp_tm_chip *chip = data; + const struct thermal_trip *trip_points; + int ret; + + trip_points = of_thermal_get_trip_points(chip->tz_dev); + if (!trip_points) + return -EINVAL; + + if (trip_points[trip].type != THERMAL_TRIP_CRITICAL) + return 0; + + mutex_lock(&chip->lock); + ret = qpnp_tm_update_critical_trip_temp(chip, temp); + mutex_unlock(&chip->lock); + + return ret; +} + static const struct thermal_zone_of_device_ops qpnp_tm_sensor_ops = { .get_temp = qpnp_tm_get_temp, + .set_trip_temp = qpnp_tm_set_trip_temp, }; static irqreturn_t qpnp_tm_isr(int irq, void *data) @@ -193,6 +281,29 @@ static irqreturn_t qpnp_tm_isr(int irq, void *data) return IRQ_HANDLED; } +static int qpnp_tm_get_critical_trip_temp(struct qpnp_tm_chip *chip) +{ + int ntrips; + const struct thermal_trip *trips; + int i; + + ntrips = of_thermal_get_ntrips(chip->tz_dev); + if (ntrips <= 0) + return THERMAL_TEMP_INVALID; + + trips = of_thermal_get_trip_points(chip->tz_dev); + if (!trips) + return THERMAL_TEMP_INVALID; + + for (i = 0; i < ntrips; i++) { + if (of_thermal_is_trip_valid(chip->tz_dev, i) && + trips[i].type == THERMAL_TRIP_CRITICAL) + return trips[i].temperature; + } + + return THERMAL_TEMP_INVALID; +} + /* * This function initializes the internal temp value based on only the * current thermal stage and threshold. Setup threshold control and @@ -203,17 +314,20 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) unsigned int stage; int ret; u8 reg = 0; + int crit_temp; + + mutex_lock(&chip->lock); ret = qpnp_tm_read(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, ®); if (ret < 0) - return ret; + goto out; chip->thresh = reg & SHUTDOWN_CTRL1_THRESHOLD_MASK; chip->temp = DEFAULT_TEMP; ret = qpnp_tm_get_temp_stage(chip); if (ret < 0) - return ret; + goto out; chip->stage = ret; stage = chip->subtype == QPNP_TM_SUBTYPE_GEN1 @@ -224,21 +338,19 @@ static int qpnp_tm_init(struct qpnp_tm_chip *chip) (stage - 1) * TEMP_STAGE_STEP + TEMP_THRESH_MIN; - /* - * Set threshold and disable software override of stage 2 and 3 - * shutdowns. - */ - chip->thresh = THRESH_MIN; - reg &= ~(SHUTDOWN_CTRL1_OVERRIDE_MASK | SHUTDOWN_CTRL1_THRESHOLD_MASK); - reg |= chip->thresh & SHUTDOWN_CTRL1_THRESHOLD_MASK; - ret = qpnp_tm_write(chip, QPNP_TM_REG_SHUTDOWN_CTRL1, reg); + crit_temp = qpnp_tm_get_critical_trip_temp(chip); + ret = qpnp_tm_update_critical_trip_temp(chip, crit_temp); if (ret < 0) - return ret; + goto out; /* Enable the thermal alarm PMIC module in always-on mode. */ reg = ALARM_CTRL_FORCE_ENABLE; ret = qpnp_tm_write(chip, QPNP_TM_REG_ALARM_CTRL, reg); + chip->initialized = true; + +out: + mutex_unlock(&chip->lock); return ret; } @@ -257,6 +369,9 @@ static int qpnp_tm_probe(struct platform_device *pdev) return -ENOMEM; dev_set_drvdata(&pdev->dev, chip); + chip->dev = &pdev->dev; + + mutex_init(&chip->lock); chip->map = dev_get_regmap(pdev->dev.parent, NULL); if (!chip->map) @@ -302,6 +417,18 @@ static int qpnp_tm_probe(struct platform_device *pdev) chip->subtype = subtype; + /* + * Register the sensor before initializing the hardware to be able to + * read the trip points. get_temp() returns the default temperature + * before the hardware initialization is completed. + */ + chip->tz_dev = devm_thermal_zone_of_sensor_register( + &pdev->dev, 0, chip, &qpnp_tm_sensor_ops); + if (IS_ERR(chip->tz_dev)) { + dev_err(&pdev->dev, "failed to register sensor\n"); + return PTR_ERR(chip->tz_dev); + } + ret = qpnp_tm_init(chip); if (ret < 0) { dev_err(&pdev->dev, "init failed\n"); @@ -313,12 +440,7 @@ static int qpnp_tm_probe(struct platform_device *pdev) if (ret < 0) return ret; - chip->tz_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, chip, - &qpnp_tm_sensor_ops); - if (IS_ERR(chip->tz_dev)) { - dev_err(&pdev->dev, "failed to register sensor\n"); - return PTR_ERR(chip->tz_dev); - } + thermal_zone_device_update(chip->tz_dev, THERMAL_EVENT_UNSPECIFIED); return 0; } From a92bab8919e3fb0dfb58e79d9a452507b389fd77 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Aug 2018 12:38:14 +0530 Subject: [PATCH 04/41] of: thermal: Allow multiple devices to share cooling map A cooling map entry may now contain a list of phandles and their arguments representing multiple devices which share the trip point. This patch updates the thermal OF core to parse them properly. The trip point and contribution value is shared by multiple cooling devices now and so a new structure is created, struct __thermal_cooling_bind_param, which represents a cooling device and its min/max states and the existing struct __thermal_bind_params now contains an array of this new cooling device structure. Tested on Hikey960. Signed-off-by: Viresh Kumar Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 142 +++++++++++++++++++++++++---------- 1 file changed, 103 insertions(+), 39 deletions(-) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 977a8307fbb1..89267f42c597 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -19,22 +19,33 @@ /*** Private data structures to represent thermal device tree data ***/ /** - * struct __thermal_bind_param - a match between trip and cooling device + * struct __thermal_cooling_bind_param - a cooling device for a trip point * @cooling_device: a pointer to identify the referred cooling device - * @trip_id: the trip point index - * @usage: the percentage (from 0 to 100) of cooling contribution * @min: minimum cooling state used at this trip point * @max: maximum cooling state used at this trip point */ -struct __thermal_bind_params { +struct __thermal_cooling_bind_param { struct device_node *cooling_device; - unsigned int trip_id; - unsigned int usage; unsigned long min; unsigned long max; }; +/** + * struct __thermal_bind_param - a match between trip and cooling device + * @tcbp: a pointer to an array of cooling devices + * @count: number of elements in array + * @trip_id: the trip point index + * @usage: the percentage (from 0 to 100) of cooling contribution + */ + +struct __thermal_bind_params { + struct __thermal_cooling_bind_param *tcbp; + unsigned int count; + unsigned int trip_id; + unsigned int usage; +}; + /** * struct __thermal_zone - internal representation of a thermal zone * @mode: current thermal zone device mode (enabled/disabled) @@ -192,25 +203,31 @@ static int of_thermal_bind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { struct __thermal_zone *data = thermal->devdata; - int i; + struct __thermal_bind_params *tbp; + struct __thermal_cooling_bind_param *tcbp; + int i, j; if (!data || IS_ERR(data)) return -ENODEV; /* find where to bind */ for (i = 0; i < data->num_tbps; i++) { - struct __thermal_bind_params *tbp = data->tbps + i; + tbp = data->tbps + i; - if (tbp->cooling_device == cdev->np) { - int ret; + for (j = 0; j < tbp->count; j++) { + tcbp = tbp->tcbp + j; - ret = thermal_zone_bind_cooling_device(thermal, + if (tcbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_bind_cooling_device(thermal, tbp->trip_id, cdev, - tbp->max, - tbp->min, + tcbp->max, + tcbp->min, tbp->usage); - if (ret) - return ret; + if (ret) + return ret; + } } } @@ -221,22 +238,28 @@ static int of_thermal_unbind(struct thermal_zone_device *thermal, struct thermal_cooling_device *cdev) { struct __thermal_zone *data = thermal->devdata; - int i; + struct __thermal_bind_params *tbp; + struct __thermal_cooling_bind_param *tcbp; + int i, j; if (!data || IS_ERR(data)) return -ENODEV; /* find where to unbind */ for (i = 0; i < data->num_tbps; i++) { - struct __thermal_bind_params *tbp = data->tbps + i; + tbp = data->tbps + i; - if (tbp->cooling_device == cdev->np) { - int ret; + for (j = 0; j < tbp->count; j++) { + tcbp = tbp->tcbp + j; - ret = thermal_zone_unbind_cooling_device(thermal, - tbp->trip_id, cdev); - if (ret) - return ret; + if (tcbp->cooling_device == cdev->np) { + int ret; + + ret = thermal_zone_unbind_cooling_device(thermal, + tbp->trip_id, cdev); + if (ret) + return ret; + } } } @@ -652,8 +675,9 @@ static int thermal_of_populate_bind_params(struct device_node *np, int ntrips) { struct of_phandle_args cooling_spec; + struct __thermal_cooling_bind_param *__tcbp; struct device_node *trip; - int ret, i; + int ret, i, count; u32 prop; /* Default weight. Usage is optional */ @@ -680,20 +704,44 @@ static int thermal_of_populate_bind_params(struct device_node *np, goto end; } - ret = of_parse_phandle_with_args(np, "cooling-device", "#cooling-cells", - 0, &cooling_spec); - if (ret < 0) { - pr_err("missing cooling_device property\n"); + count = of_count_phandle_with_args(np, "cooling-device", + "#cooling-cells"); + if (!count) { + pr_err("Add a cooling_device property with at least one device\n"); goto end; } - __tbp->cooling_device = cooling_spec.np; - if (cooling_spec.args_count >= 2) { /* at least min and max */ - __tbp->min = cooling_spec.args[0]; - __tbp->max = cooling_spec.args[1]; - } else { - pr_err("wrong reference to cooling device, missing limits\n"); + + __tcbp = kcalloc(count, sizeof(*__tcbp), GFP_KERNEL); + if (!__tcbp) + goto end; + + for (i = 0; i < count; i++) { + ret = of_parse_phandle_with_args(np, "cooling-device", + "#cooling-cells", i, &cooling_spec); + if (ret < 0) { + pr_err("Invalid cooling-device entry\n"); + goto free_tcbp; + } + + __tcbp[i].cooling_device = cooling_spec.np; + + if (cooling_spec.args_count >= 2) { /* at least min and max */ + __tcbp[i].min = cooling_spec.args[0]; + __tcbp[i].max = cooling_spec.args[1]; + } else { + pr_err("wrong reference to cooling device, missing limits\n"); + } } + __tbp->tcbp = __tcbp; + __tbp->count = count; + + goto end; + +free_tcbp: + for (i = i - 1; i >= 0; i--) + of_node_put(__tcbp[i].cooling_device); + kfree(__tcbp); end: of_node_put(trip); @@ -900,8 +948,16 @@ finish: return tz; free_tbps: - for (i = i - 1; i >= 0; i--) - of_node_put(tz->tbps[i].cooling_device); + for (i = i - 1; i >= 0; i--) { + struct __thermal_bind_params *tbp = tz->tbps + i; + int j; + + for (j = 0; j < tbp->count; j++) + of_node_put(tbp->tcbp[j].cooling_device); + + kfree(tbp->tcbp); + } + kfree(tz->tbps); free_trips: for (i = 0; i < tz->ntrips; i++) @@ -917,10 +973,18 @@ free_tz: static inline void of_thermal_free_zone(struct __thermal_zone *tz) { - int i; + struct __thermal_bind_params *tbp; + int i, j; + + for (i = 0; i < tz->num_tbps; i++) { + tbp = tz->tbps + i; + + for (j = 0; j < tbp->count; j++) + of_node_put(tbp->tcbp[j].cooling_device); + + kfree(tbp->tcbp); + } - for (i = 0; i < tz->num_tbps; i++) - of_node_put(tz->tbps[i].cooling_device); kfree(tz->tbps); for (i = 0; i < tz->ntrips; i++) of_node_put(tz->trips[i].np); From 1d9e6cf3c8537c14ad979a9c02ce4e674e5f50e8 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 17 Aug 2018 15:53:03 +0100 Subject: [PATCH 05/41] thermal: rcar_gen3_thermal: Add r8a774a1 support Add r8a774a1 specific compatible string. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Simon Horman Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 766521eb7071..53904fbc66c6 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -327,6 +327,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) } static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { + { .compatible = "renesas,r8a774a1-thermal", }, { .compatible = "renesas,r8a7795-thermal", }, { .compatible = "renesas,r8a7796-thermal", }, { .compatible = "renesas,r8a77965-thermal", }, From be6af481f3b2d5084c4e70684eaa962602f94707 Mon Sep 17 00:00:00 2001 From: Fabrizio Castro Date: Fri, 17 Aug 2018 15:53:04 +0100 Subject: [PATCH 06/41] dt-bindings: thermal: rcar-gen3-thermal: Add r8a774a1 support Document RZ/G2M (R8A774A1) SoC bindings. Signed-off-by: Fabrizio Castro Reviewed-by: Biju Das Reviewed-by: Rob Herring Reviewed-by: Simon Horman Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt index cfa154bb0fa7..098bf9550748 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt @@ -7,6 +7,7 @@ inside the LSI. Required properties: - compatible : "renesas,-thermal", Examples with soctypes are: + - "renesas,r8a774a1-thermal" (RZ/G2M) - "renesas,r8a7795-thermal" (R-Car H3) - "renesas,r8a7796-thermal" (R-Car M3-W) - "renesas,r8a77965-thermal" (R-Car M3-N) From 9b96566063c5511982c33df747e239e77cb75f78 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Aug 2018 20:52:46 -0500 Subject: [PATCH 07/41] thermal: Convert to using %pOFn instead of device_node.name In preparation to remove the node name pointer from struct device_node, convert printf users to use the %pOFn format specifier. Cc: Zhang Rui Cc: Eduardo Valentin Cc: Daniel Lezcano Cc: linux-pm@vger.kernel.org Signed-off-by: Rob Herring Acked-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/of-thermal.c | 10 +++++----- drivers/thermal/qoriq_thermal.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c index 89267f42c597..217d25d7e325 100644 --- a/drivers/thermal/of-thermal.c +++ b/drivers/thermal/of-thermal.c @@ -506,8 +506,8 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data, if (sensor_specs.args_count >= 1) { id = sensor_specs.args[0]; WARN(sensor_specs.args_count > 1, - "%s: too many cells in sensor specifier %d\n", - sensor_specs.np->name, sensor_specs.args_count); + "%pOFn: too many cells in sensor specifier %d\n", + sensor_specs.np, sensor_specs.args_count); } else { id = 0; } @@ -1024,8 +1024,8 @@ int __init of_parse_thermal_zones(void) tz = thermal_of_build_thermal_zone(child); if (IS_ERR(tz)) { - pr_err("failed to build thermal zone %s: %ld\n", - child->name, + pr_err("failed to build thermal zone %pOFn: %ld\n", + child, PTR_ERR(tz)); continue; } @@ -1059,7 +1059,7 @@ int __init of_parse_thermal_zones(void) tz->passive_delay, tz->polling_delay); if (IS_ERR(zone)) { - pr_err("Failed to build %s zone %ld\n", child->name, + pr_err("Failed to build %pOFn zone %ld\n", child, PTR_ERR(zone)); kfree(tzp); kfree(ops); diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c index c866cc165960..1fa132fc316b 100644 --- a/drivers/thermal/qoriq_thermal.c +++ b/drivers/thermal/qoriq_thermal.c @@ -129,8 +129,8 @@ static int qoriq_tmu_get_sensor_id(void) if (sensor_specs.args_count >= 1) { id = sensor_specs.args[0]; WARN(sensor_specs.args_count > 1, - "%s: too many cells in sensor specifier %d\n", - sensor_specs.np->name, sensor_specs.args_count); + "%pOFn: too many cells in sensor specifier %d\n", + sensor_specs.np, sensor_specs.args_count); } else { id = 0; } From 6017e2a9d727809bfae9a4decfe8d00e2a0f0242 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 30 Aug 2018 10:14:46 +0800 Subject: [PATCH 08/41] thermal: qoriq: add i.mx8mq support Add i.mx8mq specific compatible string. Signed-off-by: Anson Huang Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/qoriq-thermal.txt | 6 +++--- drivers/thermal/qoriq_thermal.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt b/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt index 20ca4ef9d776..04cbb90a5d3e 100644 --- a/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/qoriq-thermal.txt @@ -1,9 +1,9 @@ * Thermal Monitoring Unit (TMU) on Freescale QorIQ SoCs Required properties: -- compatible : Must include "fsl,qoriq-tmu". The version of the device is - determined by the TMU IP Block Revision Register (IPBRR0) at - offset 0x0BF8. +- compatible : Must include "fsl,qoriq-tmu" or "fsl,imx8mq-tmu". The + version of the device is determined by the TMU IP Block Revision + Register (IPBRR0) at offset 0x0BF8. Table of correspondences between IPBRR0 values and example chips: Value Device ---------- ----- diff --git a/drivers/thermal/qoriq_thermal.c b/drivers/thermal/qoriq_thermal.c index 1fa132fc316b..d37a14bd872e 100644 --- a/drivers/thermal/qoriq_thermal.c +++ b/drivers/thermal/qoriq_thermal.c @@ -305,6 +305,7 @@ static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops, static const struct of_device_id qoriq_tmu_match[] = { { .compatible = "fsl,qoriq-tmu", }, + { .compatible = "fsl,imx8mq-tmu", }, {}, }; MODULE_DEVICE_TABLE(of, qoriq_tmu_match); From bd7557f55a4514bf277dcc80ed66985eadab5719 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:46 +0530 Subject: [PATCH 09/41] thermal: tsens: Prepare 8916 and 8974 tsens to use SROT and TM address space We've already converted over the devicetree of platforms using v2 version of the TSENS IP to use two address spaces. Now prepare to convert over the 8916 and 8974 platforms to use separate SROT and TM address spaces. This patch will work with device trees with one or two address spaces because we set the tm_offset in commit 5b1283984fa3 ("thermal: tsens: Add support to split up register address space into two"). Signed-off-by: Amit Kucheria Reviewed-by: Matthias Kaehlcke Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 6207d8d92351..478739543bbc 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -21,7 +21,7 @@ #include #include "tsens.h" -#define S0_ST_ADDR 0x1030 +#define STATUS_OFFSET 0x30 #define SN_ADDR_OFFSET 0x4 #define SN_ST_TEMP_MASK 0x3ff #define CAL_DEGC_PT1 30 @@ -107,8 +107,9 @@ int get_temp_common(struct tsens_device *tmdev, int id, int *temp) unsigned int status_reg; int last_temp = 0, ret; - status_reg = S0_ST_ADDR + s->hw_id * SN_ADDR_OFFSET; + status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; ret = regmap_read(tmdev->map, status_reg, &code); + if (ret) return ret; last_temp = code & SN_ST_TEMP_MASK; From 2d71d8ded5f48b23ae46fec44811fe33da639fc9 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:47 +0530 Subject: [PATCH 10/41] thermal: tsens: Add SPDX license identifiers The TSENS drivers use a GPL-2.0 license. Replace with equivalent SPDX tags and delete the full license text. Signed-off-by: Amit Kucheria Reviewed-by: Matthias Kaehlcke Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-8916.c | 11 +---------- drivers/thermal/qcom/tsens-8960.c | 11 +---------- drivers/thermal/qcom/tsens-8974.c | 11 +---------- drivers/thermal/qcom/tsens-common.c | 11 +---------- drivers/thermal/qcom/tsens.c | 11 +---------- drivers/thermal/qcom/tsens.h | 11 ++--------- 6 files changed, 7 insertions(+), 59 deletions(-) diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c index fdf561b8b81d..c4955c85e922 100644 --- a/drivers/thermal/qcom/tsens-8916.c +++ b/drivers/thermal/qcom/tsens-8916.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c index 0451277d3a8f..4af76de7dc2e 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/thermal/qcom/tsens-8974.c b/drivers/thermal/qcom/tsens-8974.c index 9baf77e8cbe3..7e149edbfeb6 100644 --- a/drivers/thermal/qcom/tsens-8974.c +++ b/drivers/thermal/qcom/tsens-8974.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 478739543bbc..303e3fdaca98 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index a2c9bfae3d86..90bb431cf740 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -1,15 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * */ #include diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 14331eb45a86..8207610f326a 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -1,15 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * Copyright (c) 2015, The Linux Foundation. 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 - * may be copied, distributed, and modified under those terms. - * - * 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. */ + #ifndef __QCOM_TSENS_H__ #define __QCOM_TSENS_H__ From caac52bce61116c4d645d80e38ed07e47a81a2e9 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:48 +0530 Subject: [PATCH 11/41] thermal: tsens: Get rid of dead code hw_id is dynamically allocated but not used anywhere. Get rid of dead code. Signed-off-by: Amit Kucheria Reviewed-by: Matthias Kaehlcke Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/thermal/qcom/tsens.c b/drivers/thermal/qcom/tsens.c index 90bb431cf740..9a8e8f7b4ae1 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -80,11 +80,6 @@ static int tsens_register(struct tsens_device *tmdev) { int i; struct thermal_zone_device *tzd; - u32 *hw_id, n = tmdev->num_sensors; - - hw_id = devm_kcalloc(tmdev->dev, n, sizeof(u32), GFP_KERNEL); - if (!hw_id) - return -ENOMEM; for (i = 0; i < tmdev->num_sensors; i++) { tmdev->sensor[i].tmdev = tmdev; From 67b0f5e064cd7fb3ac79c49dcbf7720fa5dc4acd Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:49 +0530 Subject: [PATCH 12/41] thermal: tsens: Rename map field in order to add a second address map The TSENS driver currently only uses a limited set of registers from the TM address space. So it was ok to map just that set of registers and call it "map". We'd now like to map a second set: SROT registers to introduce new functionality. Rename the "map" field to a more appropriate "tm_map". The 8960 doesn't have a clear split between TM and SROT registers. To avoid complicating the data structure, it will switchover to using tm_map for its maps. There is no functional change with this patch. Signed-off-by: Amit Kucheria Reviewed-by: Matthias Kaehlcke Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-8960.c | 30 ++++++++++++++--------------- drivers/thermal/qcom/tsens-common.c | 17 ++++++++-------- drivers/thermal/qcom/tsens-v2.c | 6 +++--- drivers/thermal/qcom/tsens.h | 2 +- 4 files changed, 27 insertions(+), 28 deletions(-) diff --git a/drivers/thermal/qcom/tsens-8960.c b/drivers/thermal/qcom/tsens-8960.c index 4af76de7dc2e..0f0adb302a7b 100644 --- a/drivers/thermal/qcom/tsens-8960.c +++ b/drivers/thermal/qcom/tsens-8960.c @@ -60,7 +60,7 @@ static int suspend_8960(struct tsens_device *tmdev) { int ret; unsigned int mask; - struct regmap *map = tmdev->map; + struct regmap *map = tmdev->tm_map; ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold); if (ret) @@ -85,7 +85,7 @@ static int suspend_8960(struct tsens_device *tmdev) static int resume_8960(struct tsens_device *tmdev) { int ret; - struct regmap *map = tmdev->map; + struct regmap *map = tmdev->tm_map; ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); if (ret) @@ -117,12 +117,12 @@ static int enable_8960(struct tsens_device *tmdev, int id) int ret; u32 reg, mask; - ret = regmap_read(tmdev->map, CNTL_ADDR, ®); + ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®); if (ret) return ret; mask = BIT(id + SENSOR0_SHIFT); - ret = regmap_write(tmdev->map, CNTL_ADDR, reg | SW_RST); + ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST); if (ret) return ret; @@ -131,7 +131,7 @@ static int enable_8960(struct tsens_device *tmdev, int id) else reg |= mask | SLP_CLK_ENA_8660 | EN; - ret = regmap_write(tmdev->map, CNTL_ADDR, reg); + ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg); if (ret) return ret; @@ -148,7 +148,7 @@ static void disable_8960(struct tsens_device *tmdev) mask <<= SENSOR0_SHIFT; mask |= EN; - ret = regmap_read(tmdev->map, CNTL_ADDR, ®_cntl); + ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®_cntl); if (ret) return; @@ -159,7 +159,7 @@ static void disable_8960(struct tsens_device *tmdev) else reg_cntl &= ~SLP_CLK_ENA_8660; - regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); + regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); } static int init_8960(struct tsens_device *tmdev) @@ -167,8 +167,8 @@ static int init_8960(struct tsens_device *tmdev) int ret, i; u32 reg_cntl; - tmdev->map = dev_get_regmap(tmdev->dev, NULL); - if (!tmdev->map) + tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL); + if (!tmdev->tm_map) return -ENODEV; /* @@ -184,14 +184,14 @@ static int init_8960(struct tsens_device *tmdev) } reg_cntl = SW_RST; - ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl); + ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl); if (ret) return ret; if (tmdev->num_sensors > 1) { reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); reg_cntl &= ~SW_RST; - ret = regmap_update_bits(tmdev->map, CONFIG_ADDR, + ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR, CONFIG_MASK, CONFIG); } else { reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); @@ -200,12 +200,12 @@ static int init_8960(struct tsens_device *tmdev) } reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT; - ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); + ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); if (ret) return ret; reg_cntl |= EN; - ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl); + ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); if (ret) return ret; @@ -252,12 +252,12 @@ static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp) timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); do { - ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy); + ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy); if (ret) return ret; if (!(trdy & TRDY_MASK)) continue; - ret = regmap_read(tmdev->map, s->status, &code); + ret = regmap_read(tmdev->tm_map, s->status, &code); if (ret) return ret; *temp = code_to_mdegC(code, s); diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 303e3fdaca98..0585084630b3 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -99,8 +99,7 @@ int get_temp_common(struct tsens_device *tmdev, int id, int *temp) int last_temp = 0, ret; status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; - ret = regmap_read(tmdev->map, status_reg, &code); - + ret = regmap_read(tmdev->tm_map, status_reg, &code); if (ret) return ret; last_temp = code & SN_ST_TEMP_MASK; @@ -118,7 +117,7 @@ static const struct regmap_config tsens_config = { int __init init_common(struct tsens_device *tmdev) { - void __iomem *base; + void __iomem *tm_base; struct resource *res; struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node); @@ -134,13 +133,13 @@ int __init init_common(struct tsens_device *tmdev) } res = platform_get_resource(op, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&op->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); + tm_base = devm_ioremap_resource(&op->dev, res); + if (IS_ERR(tm_base)) + return PTR_ERR(tm_base); - tmdev->map = devm_regmap_init_mmio(tmdev->dev, base, &tsens_config); - if (IS_ERR(tmdev->map)) - return PTR_ERR(tmdev->map); + tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config); + if (IS_ERR(tmdev->tm_map)) + return PTR_ERR(tmdev->tm_map); return 0; } diff --git a/drivers/thermal/qcom/tsens-v2.c b/drivers/thermal/qcom/tsens-v2.c index 44da02f594ac..1bdef92e4521 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -21,7 +21,7 @@ static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp) int ret; status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * 4; - ret = regmap_read(tmdev->map, status_reg, &code); + ret = regmap_read(tmdev->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_device *tmdev, int id, int *temp) goto done; /* Try a second time */ - ret = regmap_read(tmdev->map, status_reg, &code); + ret = regmap_read(tmdev->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_device *tmdev, int id, int *temp) } /* Try a third/last time */ - ret = regmap_read(tmdev->map, status_reg, &code); + ret = regmap_read(tmdev->tm_map, status_reg, &code); if (ret) return ret; if (code & STATUS_VALID_BIT) { diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 8207610f326a..58e98c4d3a8b 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -69,7 +69,7 @@ struct tsens_context { struct tsens_device { struct device *dev; u32 num_sensors; - struct regmap *map; + struct regmap *tm_map; u32 tm_offset; struct tsens_context ctx; const struct tsens_ops *ops; From a15525b5d9ac37fec559d140b2e24c4ce4defa54 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:50 +0530 Subject: [PATCH 13/41] thermal: tsens: Add the SROT address map On platforms whose device trees specify two address spaces for TSENS, the second one points to the SROT registers. Initialise the SROT map on those platforms. Signed-off-by: Amit Kucheria Reviewed-by: Matthias Kaehlcke Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 14 ++++++++++++-- drivers/thermal/qcom/tsens.h | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 0585084630b3..0b8a793f15f4 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -117,16 +117,26 @@ static const struct regmap_config tsens_config = { int __init init_common(struct tsens_device *tmdev) { - void __iomem *tm_base; + void __iomem *tm_base, *srot_base; struct resource *res; struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node); if (!op) return -EINVAL; - /* The driver only uses the TM register address space for now */ if (op->num_resources > 1) { + /* DT with separate SROT and TM address space */ tmdev->tm_offset = 0; + res = platform_get_resource(op, IORESOURCE_MEM, 1); + srot_base = devm_ioremap_resource(&op->dev, res); + if (IS_ERR(srot_base)) + return PTR_ERR(srot_base); + + tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, + srot_base, &tsens_config); + if (IS_ERR(tmdev->srot_map)) + return PTR_ERR(tmdev->srot_map); + } else { /* old DTs where SROT and TM were in a contiguous 2K block */ tmdev->tm_offset = 0x1000; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index 58e98c4d3a8b..b9c4bcf255fa 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -70,6 +70,7 @@ struct tsens_device { struct device *dev; u32 num_sensors; struct regmap *tm_map; + struct regmap *srot_map; u32 tm_offset; struct tsens_context ctx; const struct tsens_ops *ops; From c130a7602e3bc2c6fd896c1d56478fca47a38c02 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:52 +0530 Subject: [PATCH 14/41] thermal: tsens: Pass register offsets as private data Registers have moved around across TSENS generations. For example, the CTRL register was at offset 0x0 in the SROT region on msm8916 but is at offset 0x4 in newer v2 based TSENS HW blocks. Allow passing offsets of important registers so that we can continue to use common functions. Signed-off-by: Amit Kucheria Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-8916.c | 1 + drivers/thermal/qcom/tsens-8974.c | 1 + drivers/thermal/qcom/tsens-v2.c | 2 ++ drivers/thermal/qcom/tsens.c | 3 +++ drivers/thermal/qcom/tsens.h | 9 +++++++++ 5 files changed, 16 insertions(+) diff --git a/drivers/thermal/qcom/tsens-8916.c b/drivers/thermal/qcom/tsens-8916.c index c4955c85e922..c6dd620ac029 100644 --- a/drivers/thermal/qcom/tsens-8916.c +++ b/drivers/thermal/qcom/tsens-8916.c @@ -100,5 +100,6 @@ static const struct tsens_ops ops_8916 = { const struct tsens_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-8974.c b/drivers/thermal/qcom/tsens-8974.c index 7e149edbfeb6..3d3fda3d731b 100644 --- a/drivers/thermal/qcom/tsens-8974.c +++ b/drivers/thermal/qcom/tsens-8974.c @@ -232,4 +232,5 @@ static const struct tsens_ops ops_8974 = { const struct tsens_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 1bdef92e4521..381a212872bf 100644 --- a/drivers/thermal/qcom/tsens-v2.c +++ b/drivers/thermal/qcom/tsens-v2.c @@ -68,10 +68,12 @@ static const struct tsens_ops ops_generic_v2 = { const struct tsens_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 = { .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 9a8e8f7b4ae1..f1ec9bbe4717 100644 --- a/drivers/thermal/qcom/tsens.c +++ b/drivers/thermal/qcom/tsens.c @@ -144,6 +144,9 @@ static int tsens_probe(struct platform_device *pdev) else tmdev->sensor[i].hw_id = i; } + for (i = 0; i < REG_ARRAY_SIZE; i++) { + tmdev->reg_offsets[i] = data->reg_offsets[i]; + } if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp) return -EINVAL; diff --git a/drivers/thermal/qcom/tsens.h b/drivers/thermal/qcom/tsens.h index b9c4bcf255fa..7b7feee5dc46 100644 --- a/drivers/thermal/qcom/tsens.h +++ b/drivers/thermal/qcom/tsens.h @@ -48,15 +48,23 @@ struct tsens_ops { int (*get_trend)(struct tsens_device *, int, enum thermal_trend *); }; +enum reg_list { + SROT_CTRL_OFFSET, + + REG_ARRAY_SIZE, +}; + /** * struct tsens_data - tsens instance specific data * @num_sensors: Max 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 { const u32 num_sensors; const struct tsens_ops *ops; + const u16 reg_offsets[REG_ARRAY_SIZE]; unsigned int *hw_ids; }; @@ -72,6 +80,7 @@ struct tsens_device { struct regmap *tm_map; struct regmap *srot_map; u32 tm_offset; + u16 reg_offsets[REG_ARRAY_SIZE]; struct tsens_context ctx; const struct tsens_ops *ops; struct tsens_sensor sensor[0]; From c8c3b091b65c55ed950cb1601b21eea59c3117c0 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:53 +0530 Subject: [PATCH 15/41] thermal: tsens: Check if the IP is correctly enabled by firmware The SROT registers are initialised by the secure firmware at boot. We don't have write access to the registers. Check if the block is enabled before continuing. Signed-off-by: Amit Kucheria Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- drivers/thermal/qcom/tsens-common.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/thermal/qcom/tsens-common.c b/drivers/thermal/qcom/tsens-common.c index 0b8a793f15f4..3be4be2e0465 100644 --- a/drivers/thermal/qcom/tsens-common.c +++ b/drivers/thermal/qcom/tsens-common.c @@ -12,6 +12,10 @@ #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 @@ -119,7 +123,10 @@ int __init init_common(struct tsens_device *tmdev) { 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]; if (!op) return -EINVAL; @@ -151,5 +158,15 @@ int __init init_common(struct tsens_device *tmdev) if (IS_ERR(tmdev->tm_map)) return PTR_ERR(tmdev->tm_map); + if (tmdev->srot_map) { + ret = regmap_read(tmdev->srot_map, ctrl_offset, &code); + if (ret) + return ret; + if (!(code & TSENS_EN)) { + dev_err(tmdev->dev, "tsens device is not enabled\n"); + return -ENODEV; + } + } + return 0; } From 36d83c6662450e13a2fa5792b34afff6f8bdba50 Mon Sep 17 00:00:00 2001 From: Amit Kucheria Date: Wed, 12 Sep 2018 15:22:58 +0530 Subject: [PATCH 16/41] dt-bindings: thermal: Fix a typo in documentation c(1) + x(1) was actually meant to be c(1) * x(1). Signed-off-by: Amit Kucheria Reviewed-by: Matthias Kaehlcke Acked-by: Rob Herring Reviewed-by: Bjorn Andersson Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/thermal.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/thermal.txt b/Documentation/devicetree/bindings/thermal/thermal.txt index cc553f0952c5..3070049bf1fa 100644 --- a/Documentation/devicetree/bindings/thermal/thermal.txt +++ b/Documentation/devicetree/bindings/thermal/thermal.txt @@ -152,7 +152,7 @@ Optional property: Elem size: one cell the sensors listed in the thermal-sensors property. Elem type: signed Coefficients defaults to 1, in case this property is not specified. A simple linear polynomial is used: - Z = c0 * x0 + c1 + x1 + ... + c(n-1) * x(n-1) + cn. + Z = c0 * x0 + c1 * x1 + ... + c(n-1) * x(n-1) + cn. The coefficients are ordered and they match with sensors by means of sensor ID. Additional coefficients are From 337a4aecdaf8fa53b16fbf48a73d328fb44ffb75 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 13 Sep 2018 17:13:05 +0800 Subject: [PATCH 17/41] thermal: imx: improve error message Remove the duplicated "from" to improve the error message. Signed-off-by: Anson Huang Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/imx_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index aa452acb60b6..6cfa2a82209e 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -725,7 +725,7 @@ static int imx_thermal_probe(struct platform_device *pdev) } else { ret = imx_init_from_tempmon_data(pdev); if (ret) { - dev_err(&pdev->dev, "failed to init from from fsl,tempmon-data\n"); + dev_err(&pdev->dev, "failed to init from fsl,tempmon-data\n"); return ret; } } From b6ad3981ff94b415d48399e949db0bdfbe360736 Mon Sep 17 00:00:00 2001 From: Anson Huang Date: Thu, 13 Sep 2018 17:13:06 +0800 Subject: [PATCH 18/41] thermal: imx: handle error path in one place to save duplicated code During probe phase, the error path can be handled in one place and use goto method to save many duplicated code. Signed-off-by: Anson Huang Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/imx_thermal.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 6cfa2a82209e..15661549eb67 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c @@ -762,9 +762,7 @@ static int imx_thermal_probe(struct platform_device *pdev) if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "failed to get thermal clk: %d\n", ret); - cpufreq_cooling_unregister(data->cdev); - cpufreq_cpu_put(data->policy); - return ret; + goto cpufreq_put; } /* @@ -777,9 +775,7 @@ static int imx_thermal_probe(struct platform_device *pdev) ret = clk_prepare_enable(data->thermal_clk); if (ret) { dev_err(&pdev->dev, "failed to enable thermal clk: %d\n", ret); - cpufreq_cooling_unregister(data->cdev); - cpufreq_cpu_put(data->policy); - return ret; + goto cpufreq_put; } data->tz = thermal_zone_device_register("imx_thermal_zone", @@ -792,10 +788,7 @@ static int imx_thermal_probe(struct platform_device *pdev) ret = PTR_ERR(data->tz); dev_err(&pdev->dev, "failed to register thermal zone device %d\n", ret); - clk_disable_unprepare(data->thermal_clk); - cpufreq_cooling_unregister(data->cdev); - cpufreq_cpu_put(data->policy); - return ret; + goto clk_disable; } dev_info(&pdev->dev, "%s CPU temperature grade - max:%dC" @@ -827,14 +820,20 @@ static int imx_thermal_probe(struct platform_device *pdev) 0, "imx_thermal", data); if (ret < 0) { dev_err(&pdev->dev, "failed to request alarm irq: %d\n", ret); - clk_disable_unprepare(data->thermal_clk); - thermal_zone_device_unregister(data->tz); - cpufreq_cooling_unregister(data->cdev); - cpufreq_cpu_put(data->policy); - return ret; + goto thermal_zone_unregister; } return 0; + +thermal_zone_unregister: + thermal_zone_device_unregister(data->tz); +clk_disable: + clk_disable_unprepare(data->thermal_clk); +cpufreq_put: + cpufreq_cooling_unregister(data->cdev); + cpufreq_cpu_put(data->policy); + + return ret; } static int imx_thermal_remove(struct platform_device *pdev) From d1d2c290b3c04b65fa6132eeebe50a070746d8f6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 19 Sep 2018 13:35:00 +0300 Subject: [PATCH 19/41] thermal: armada: fix a test in probe() The platform_get_resource() function doesn't return error pointers, it returns NULL on error. Fixes: 3d4e51844a4e ("thermal: armada: convert driver to syscon register accesses") Signed-off-by: Dan Carpenter Reviewed-by: Miquel Raynal Signed-off-by: Eduardo Valentin --- drivers/thermal/armada_thermal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/armada_thermal.c b/drivers/thermal/armada_thermal.c index 2c2f6d93034e..92f67d40f2e9 100644 --- a/drivers/thermal/armada_thermal.c +++ b/drivers/thermal/armada_thermal.c @@ -526,8 +526,8 @@ static int armada_thermal_probe_legacy(struct platform_device *pdev, /* First memory region points towards the status register */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (IS_ERR(res)) - return PTR_ERR(res); + if (!res) + return -EIO; /* * Edit the resource start address and length to map over all the From c90aaeccc7c6a8967f3efd43048eeae51072251c Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:02:59 +0200 Subject: [PATCH 20/41] thermal/drivers/hisi: Change the platform data pointer to sensor ops Group the temperature sensor specific ops into a single structure and assign it to hisi thermal data structure. Change the platform data pointer to reference the specific sensor ops instead of the probe functions. Moving out those allow to split the code to self-encapsulate the sensor object. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 60 +++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 761d0559c268..9794cfe56a12 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -64,11 +64,18 @@ struct hisi_thermal_sensor { uint32_t thres_temp; }; -struct hisi_thermal_data { +struct hisi_thermal_data; + +struct hisi_thermal_ops { int (*get_temp)(struct hisi_thermal_data *data); int (*enable_sensor)(struct hisi_thermal_data *data); int (*disable_sensor)(struct hisi_thermal_data *data); int (*irq_handler)(struct hisi_thermal_data *data); + int (*probe)(struct hisi_thermal_data *data); +}; + +struct hisi_thermal_data { + const struct hisi_thermal_ops *ops; struct platform_device *pdev; struct clk *clk; struct hisi_thermal_sensor sensor; @@ -374,11 +381,6 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) struct resource *res; int ret; - data->get_temp = hi6220_thermal_get_temp; - data->enable_sensor = hi6220_thermal_enable_sensor; - data->disable_sensor = hi6220_thermal_disable_sensor; - data->irq_handler = hi6220_thermal_irq_handler; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->regs = devm_ioremap_resource(dev, res); if (IS_ERR(data->regs)) { @@ -409,11 +411,6 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data) struct device *dev = &pdev->dev; struct resource *res; - data->get_temp = hi3660_thermal_get_temp; - data->enable_sensor = hi3660_thermal_enable_sensor; - data->disable_sensor = hi3660_thermal_disable_sensor; - data->irq_handler = hi3660_thermal_irq_handler; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); data->regs = devm_ioremap_resource(dev, res); if (IS_ERR(data->regs)) { @@ -435,7 +432,7 @@ static int hisi_thermal_get_temp(void *__data, int *temp) struct hisi_thermal_data *data = __data; struct hisi_thermal_sensor *sensor = &data->sensor; - *temp = data->get_temp(data); + *temp = data->ops->get_temp(data); dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n", sensor->id, *temp, sensor->thres_temp); @@ -453,7 +450,7 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) struct hisi_thermal_sensor *sensor = &data->sensor; int temp = 0; - data->irq_handler(data); + data->ops->irq_handler(data); hisi_thermal_get_temp(data, &temp); @@ -502,14 +499,30 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev, return 0; } +static const struct hisi_thermal_ops hi6220_ops = { + .get_temp = hi6220_thermal_get_temp, + .enable_sensor = hi6220_thermal_enable_sensor, + .disable_sensor = hi6220_thermal_disable_sensor, + .irq_handler = hi6220_thermal_irq_handler, + .probe = hi6220_thermal_probe, +}; + +static const struct hisi_thermal_ops hi3660_ops = { + .get_temp = hi3660_thermal_get_temp, + .enable_sensor = hi3660_thermal_enable_sensor, + .disable_sensor = hi3660_thermal_disable_sensor, + .irq_handler = hi3660_thermal_irq_handler, + .probe = hi3660_thermal_probe, +}; + static const struct of_device_id of_hisi_thermal_match[] = { { .compatible = "hisilicon,tsensor", - .data = hi6220_thermal_probe + .data = &hi6220_ops, }, { .compatible = "hisilicon,hi3660-tsensor", - .data = hi3660_thermal_probe + .data = &hi3660_ops, }, { /* end */ } }; @@ -527,7 +540,6 @@ static void hisi_thermal_toggle_sensor(struct hisi_thermal_sensor *sensor, static int hisi_thermal_probe(struct platform_device *pdev) { struct hisi_thermal_data *data; - int (*platform_probe)(struct hisi_thermal_data *); struct device *dev = &pdev->dev; int ret; @@ -538,13 +550,9 @@ static int hisi_thermal_probe(struct platform_device *pdev) data->pdev = pdev; platform_set_drvdata(pdev, data); - platform_probe = of_device_get_match_data(dev); - if (!platform_probe) { - dev_err(dev, "failed to get probe func\n"); - return -EINVAL; - } + data->ops = of_device_get_match_data(dev); - ret = platform_probe(data); + ret = data->ops->probe(data); if (ret) return ret; @@ -555,7 +563,7 @@ static int hisi_thermal_probe(struct platform_device *pdev) return ret; } - ret = data->enable_sensor(data); + ret = data->ops->enable_sensor(data); if (ret) { dev_err(dev, "Failed to setup the sensor: %d\n", ret); return ret; @@ -583,7 +591,7 @@ static int hisi_thermal_remove(struct platform_device *pdev) hisi_thermal_toggle_sensor(sensor, false); - data->disable_sensor(data); + data->ops->disable_sensor(data); return 0; } @@ -593,7 +601,7 @@ static int hisi_thermal_suspend(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); - data->disable_sensor(data); + data->ops->disable_sensor(data); return 0; } @@ -602,7 +610,7 @@ static int hisi_thermal_resume(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); - return data->enable_sensor(data); + return data->ops->enable_sensor(data); } #endif From 9c9ae8da710639790f1d45b1a55d28ee70734c11 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:00 +0200 Subject: [PATCH 21/41] thermal/drivers/hisi: Change the driver to be sensor oriented In order to support multiple sensors, we have to change the code to deal with sensors and not the hisi thermal structure. Add a back pointer to the hisi thermal structure (containerof is not a good option because later we convert the sensor field to a pointer). Change the functions parameters to take a sensor instead of this hisi thermal 'data' structure. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 72 ++++++++++++++++++++-------------- 1 file changed, 42 insertions(+), 30 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 9794cfe56a12..1fdda55bd93b 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -58,27 +58,28 @@ #define HI6220_DEFAULT_SENSOR 2 #define HI3660_DEFAULT_SENSOR 1 +struct hisi_thermal_data; + struct hisi_thermal_sensor { + struct hisi_thermal_data *data; struct thermal_zone_device *tzd; uint32_t id; uint32_t thres_temp; }; -struct hisi_thermal_data; - struct hisi_thermal_ops { - int (*get_temp)(struct hisi_thermal_data *data); - int (*enable_sensor)(struct hisi_thermal_data *data); - int (*disable_sensor)(struct hisi_thermal_data *data); - int (*irq_handler)(struct hisi_thermal_data *data); + int (*get_temp)(struct hisi_thermal_sensor *sensor); + int (*enable_sensor)(struct hisi_thermal_sensor *sensor); + int (*disable_sensor)(struct hisi_thermal_sensor *sensor); + int (*irq_handler)(struct hisi_thermal_sensor *sensor); int (*probe)(struct hisi_thermal_data *data); }; struct hisi_thermal_data { const struct hisi_thermal_ops *ops; + struct hisi_thermal_sensor sensor; struct platform_device *pdev; struct clk *clk; - struct hisi_thermal_sensor sensor; void __iomem *regs; int irq; }; @@ -273,30 +274,40 @@ static inline void hi6220_thermal_hdak_set(void __iomem *addr, int value) (value << 4), addr + HI6220_TEMP0_CFG); } -static int hi6220_thermal_irq_handler(struct hisi_thermal_data *data) +static int hi6220_thermal_irq_handler(struct hisi_thermal_sensor *sensor) { + struct hisi_thermal_data *data = sensor->data; + hi6220_thermal_alarm_clear(data->regs, 1); return 0; } -static int hi3660_thermal_irq_handler(struct hisi_thermal_data *data) +static int hi3660_thermal_irq_handler(struct hisi_thermal_sensor *sensor) { - hi3660_thermal_alarm_clear(data->regs, data->sensor.id, 1); + struct hisi_thermal_data *data = sensor->data; + + hi3660_thermal_alarm_clear(data->regs, sensor->id, 1); return 0; } -static int hi6220_thermal_get_temp(struct hisi_thermal_data *data) +static int hi6220_thermal_get_temp(struct hisi_thermal_sensor *sensor) { + struct hisi_thermal_data *data = sensor->data; + return hi6220_thermal_get_temperature(data->regs); } -static int hi3660_thermal_get_temp(struct hisi_thermal_data *data) +static int hi3660_thermal_get_temp(struct hisi_thermal_sensor *sensor) { - return hi3660_thermal_get_temperature(data->regs, data->sensor.id); + struct hisi_thermal_data *data = sensor->data; + + return hi3660_thermal_get_temperature(data->regs, sensor->id); } -static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data) +static int hi6220_thermal_disable_sensor(struct hisi_thermal_sensor *sensor) { + struct hisi_thermal_data *data = sensor->data; + /* disable sensor module */ hi6220_thermal_enable(data->regs, 0); hi6220_thermal_alarm_enable(data->regs, 0); @@ -307,16 +318,18 @@ static int hi6220_thermal_disable_sensor(struct hisi_thermal_data *data) return 0; } -static int hi3660_thermal_disable_sensor(struct hisi_thermal_data *data) +static int hi3660_thermal_disable_sensor(struct hisi_thermal_sensor *sensor) { + struct hisi_thermal_data *data = sensor->data; + /* disable sensor module */ - hi3660_thermal_alarm_enable(data->regs, data->sensor.id, 0); + hi3660_thermal_alarm_enable(data->regs, sensor->id, 0); return 0; } -static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data) +static int hi6220_thermal_enable_sensor(struct hisi_thermal_sensor *sensor) { - struct hisi_thermal_sensor *sensor = &data->sensor; + struct hisi_thermal_data *data = sensor->data; int ret; /* enable clock for tsensor */ @@ -352,10 +365,10 @@ static int hi6220_thermal_enable_sensor(struct hisi_thermal_data *data) return 0; } -static int hi3660_thermal_enable_sensor(struct hisi_thermal_data *data) +static int hi3660_thermal_enable_sensor(struct hisi_thermal_sensor *sensor) { unsigned int value; - struct hisi_thermal_sensor *sensor = &data->sensor; + struct hisi_thermal_data *data = sensor->data; /* disable interrupt */ hi3660_thermal_alarm_enable(data->regs, sensor->id, 0); @@ -432,7 +445,7 @@ static int hisi_thermal_get_temp(void *__data, int *temp) struct hisi_thermal_data *data = __data; struct hisi_thermal_sensor *sensor = &data->sensor; - *temp = data->ops->get_temp(data); + *temp = data->ops->get_temp(sensor); dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n", sensor->id, *temp, sensor->thres_temp); @@ -450,7 +463,7 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) struct hisi_thermal_sensor *sensor = &data->sensor; int temp = 0; - data->ops->irq_handler(data); + data->ops->irq_handler(sensor); hisi_thermal_get_temp(data, &temp); @@ -470,10 +483,10 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) } static int hisi_thermal_register_sensor(struct platform_device *pdev, - struct hisi_thermal_data *data, struct hisi_thermal_sensor *sensor) { int ret, i; + struct hisi_thermal_data *data = sensor->data; const struct thermal_trip *trip; sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, @@ -549,21 +562,20 @@ static int hisi_thermal_probe(struct platform_device *pdev) data->pdev = pdev; platform_set_drvdata(pdev, data); - + data->sensor.data = data; data->ops = of_device_get_match_data(dev); ret = data->ops->probe(data); if (ret) return ret; - ret = hisi_thermal_register_sensor(pdev, data, - &data->sensor); + ret = hisi_thermal_register_sensor(pdev, &data->sensor); if (ret) { dev_err(dev, "failed to register thermal sensor: %d\n", ret); return ret; } - ret = data->ops->enable_sensor(data); + ret = data->ops->enable_sensor(&data->sensor); if (ret) { dev_err(dev, "Failed to setup the sensor: %d\n", ret); return ret; @@ -591,7 +603,7 @@ static int hisi_thermal_remove(struct platform_device *pdev) hisi_thermal_toggle_sensor(sensor, false); - data->ops->disable_sensor(data); + data->ops->disable_sensor(&data->sensor); return 0; } @@ -601,7 +613,7 @@ static int hisi_thermal_suspend(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); - data->ops->disable_sensor(data); + data->ops->disable_sensor(&data->sensor); return 0; } @@ -610,7 +622,7 @@ static int hisi_thermal_resume(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); - return data->ops->enable_sensor(data); + return data->ops->enable_sensor(&data->sensor); } #endif From 49e778d1c750d5b1f773edeb93dfef963bef3f21 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:01 +0200 Subject: [PATCH 22/41] thermal/drivers/hisi: Set the thermal zone private data to the sensor pointer Store the sensor pointer in the thermal zone private data and use it in the callback functions. That allows to continue the conversion to sensor oriented code where the pointers are the sensors. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 1fdda55bd93b..567fde6ea369 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -442,8 +442,8 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data) static int hisi_thermal_get_temp(void *__data, int *temp) { - struct hisi_thermal_data *data = __data; - struct hisi_thermal_sensor *sensor = &data->sensor; + struct hisi_thermal_sensor *sensor = __data; + struct hisi_thermal_data *data = sensor->data; *temp = data->ops->get_temp(sensor); @@ -465,7 +465,7 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) data->ops->irq_handler(sensor); - hisi_thermal_get_temp(data, &temp); + hisi_thermal_get_temp(sensor, &temp); if (temp >= sensor->thres_temp) { dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n", @@ -486,11 +486,10 @@ static int hisi_thermal_register_sensor(struct platform_device *pdev, struct hisi_thermal_sensor *sensor) { int ret, i; - struct hisi_thermal_data *data = sensor->data; const struct thermal_trip *trip; sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, - sensor->id, data, + sensor->id, sensor, &hisi_of_thermal_ops); if (IS_ERR(sensor->tzd)) { ret = PTR_ERR(sensor->tzd); From 9bb4ec8d9e93f0d1a94e8aa9100c5f42fd364078 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:02 +0200 Subject: [PATCH 23/41] thermal/drivers/hisi: Factor out the probe functions The hi6220 and the hi3660 probe functions are doing almost the same operations, they can share 90% of their code. Factor out the probe functions by moving the common code in the common probe function. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 39 +++++++++++----------------------- 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 567fde6ea369..7287818a66b6 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -391,16 +391,8 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) { struct platform_device *pdev = data->pdev; struct device *dev = &pdev->dev; - struct resource *res; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(data->regs)) { - dev_err(dev, "failed to get io address\n"); - return PTR_ERR(data->regs); - } - data->clk = devm_clk_get(dev, "thermal_clk"); if (IS_ERR(data->clk)) { ret = PTR_ERR(data->clk); @@ -409,10 +401,6 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) return ret; } - data->irq = platform_get_irq(pdev, 0); - if (data->irq < 0) - return data->irq; - data->sensor.id = HI6220_DEFAULT_SENSOR; return 0; @@ -420,21 +408,6 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) static int hi3660_thermal_probe(struct hisi_thermal_data *data) { - struct platform_device *pdev = data->pdev; - struct device *dev = &pdev->dev; - struct resource *res; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - data->regs = devm_ioremap_resource(dev, res); - if (IS_ERR(data->regs)) { - dev_err(dev, "failed to get io address\n"); - return PTR_ERR(data->regs); - } - - data->irq = platform_get_irq(pdev, 0); - if (data->irq < 0) - return data->irq; - data->sensor.id = HI3660_DEFAULT_SENSOR; return 0; @@ -553,6 +526,7 @@ static int hisi_thermal_probe(struct platform_device *pdev) { struct hisi_thermal_data *data; struct device *dev = &pdev->dev; + struct resource *res; int ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); @@ -564,6 +538,17 @@ static int hisi_thermal_probe(struct platform_device *pdev) data->sensor.data = data; data->ops = of_device_get_match_data(dev); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + data->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(data->regs)) { + dev_err(dev, "failed to get io address\n"); + return PTR_ERR(data->regs); + } + + data->irq = platform_get_irq(pdev, 0); + if (data->irq < 0) + return data->irq; + ret = data->ops->probe(data); if (ret) return ret; From 8c0ffc8f9a76b2007258f146a4ff22ef14e68590 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:03 +0200 Subject: [PATCH 24/41] thermal/drivers/hisi: Prepare to support multiple sensors Convert the 'sensor' field to a pointer and propagate the change in the file. Havintg a pointer, gives us the opportunity to define multiple sensors. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 41 +++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 7287818a66b6..87b82fb00b08 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -77,10 +77,11 @@ struct hisi_thermal_ops { struct hisi_thermal_data { const struct hisi_thermal_ops *ops; - struct hisi_thermal_sensor sensor; + struct hisi_thermal_sensor *sensor; struct platform_device *pdev; struct clk *clk; void __iomem *regs; + int nr_sensors; int irq; }; @@ -401,14 +402,29 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) return ret; } - data->sensor.id = HI6220_DEFAULT_SENSOR; + data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL); + if (!data->sensor) + return -ENOMEM; + + data->sensor[0].id = HI6220_DEFAULT_SENSOR; + data->sensor[0].data = data; + data->nr_sensors = 1; return 0; } static int hi3660_thermal_probe(struct hisi_thermal_data *data) { - data->sensor.id = HI3660_DEFAULT_SENSOR; + struct platform_device *pdev = data->pdev; + struct device *dev = &pdev->dev; + + data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL); + if (!data->sensor) + return -ENOMEM; + + data->sensor[0].id = HI3660_DEFAULT_SENSOR; + data->sensor[0].data = data; + data->nr_sensors = 1; return 0; } @@ -433,7 +449,7 @@ static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = { static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) { struct hisi_thermal_data *data = dev; - struct hisi_thermal_sensor *sensor = &data->sensor; + struct hisi_thermal_sensor *sensor = &data->sensor[0]; int temp = 0; data->ops->irq_handler(sensor); @@ -444,7 +460,7 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n", temp, sensor->thres_temp); - thermal_zone_device_update(data->sensor.tzd, + thermal_zone_device_update(data->sensor[0].tzd, THERMAL_EVENT_UNSPECIFIED); } else { @@ -535,7 +551,6 @@ static int hisi_thermal_probe(struct platform_device *pdev) data->pdev = pdev; platform_set_drvdata(pdev, data); - data->sensor.data = data; data->ops = of_device_get_match_data(dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -553,13 +568,13 @@ static int hisi_thermal_probe(struct platform_device *pdev) if (ret) return ret; - ret = hisi_thermal_register_sensor(pdev, &data->sensor); + ret = hisi_thermal_register_sensor(pdev, &data->sensor[0]); if (ret) { dev_err(dev, "failed to register thermal sensor: %d\n", ret); return ret; } - ret = data->ops->enable_sensor(&data->sensor); + ret = data->ops->enable_sensor(&data->sensor[0]); if (ret) { dev_err(dev, "Failed to setup the sensor: %d\n", ret); return ret; @@ -575,7 +590,7 @@ static int hisi_thermal_probe(struct platform_device *pdev) } } - hisi_thermal_toggle_sensor(&data->sensor, true); + hisi_thermal_toggle_sensor(&data->sensor[0], true); return 0; } @@ -583,11 +598,11 @@ static int hisi_thermal_probe(struct platform_device *pdev) static int hisi_thermal_remove(struct platform_device *pdev) { struct hisi_thermal_data *data = platform_get_drvdata(pdev); - struct hisi_thermal_sensor *sensor = &data->sensor; + struct hisi_thermal_sensor *sensor = &data->sensor[0]; hisi_thermal_toggle_sensor(sensor, false); - data->ops->disable_sensor(&data->sensor); + data->ops->disable_sensor(sensor); return 0; } @@ -597,7 +612,7 @@ static int hisi_thermal_suspend(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); - data->ops->disable_sensor(&data->sensor); + data->ops->disable_sensor(&data->sensor[0]); return 0; } @@ -606,7 +621,7 @@ static int hisi_thermal_resume(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); - return data->ops->enable_sensor(&data->sensor); + return data->ops->enable_sensor(&data->sensor[0]); } #endif From 7edc5e406f2637ba1f9c93b1e72e0e37f446304b Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:04 +0200 Subject: [PATCH 25/41] thermal/drivers/hisi: Add multiple sensors support Change the code as it is dealing with several sensors. For git-bisect compatibility (compilation and booting), assume the DT is not yet changed and we have a single interrupt. Next changes will support multiple interrupt sorted by their name. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 79 ++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 87b82fb00b08..a5756f6d13e4 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -448,8 +448,8 @@ static const struct thermal_zone_of_device_ops hisi_of_thermal_ops = { static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) { - struct hisi_thermal_data *data = dev; - struct hisi_thermal_sensor *sensor = &data->sensor[0]; + struct hisi_thermal_sensor *sensor = dev; + struct hisi_thermal_data *data = sensor->data; int temp = 0; data->ops->irq_handler(sensor); @@ -457,15 +457,17 @@ static irqreturn_t hisi_thermal_alarm_irq_thread(int irq, void *dev) hisi_thermal_get_temp(sensor, &temp); if (temp >= sensor->thres_temp) { - dev_crit(&data->pdev->dev, "THERMAL ALARM: %d > %d\n", - temp, sensor->thres_temp); + dev_crit(&data->pdev->dev, + "sensor <%d> THERMAL ALARM: %d > %d\n", + sensor->id, temp, sensor->thres_temp); - thermal_zone_device_update(data->sensor[0].tzd, + thermal_zone_device_update(sensor->tzd, THERMAL_EVENT_UNSPECIFIED); } else { - dev_crit(&data->pdev->dev, "THERMAL ALARM stopped: %d < %d\n", - temp, sensor->thres_temp); + dev_crit(&data->pdev->dev, + "sensor <%d> THERMAL ALARM stopped: %d < %d\n", + sensor->id, temp, sensor->thres_temp); } return IRQ_HANDLED; @@ -543,7 +545,7 @@ static int hisi_thermal_probe(struct platform_device *pdev) struct hisi_thermal_data *data; struct device *dev = &pdev->dev; struct resource *res; - int ret; + int i, ret; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) @@ -560,37 +562,41 @@ static int hisi_thermal_probe(struct platform_device *pdev) return PTR_ERR(data->regs); } - data->irq = platform_get_irq(pdev, 0); - if (data->irq < 0) - return data->irq; - ret = data->ops->probe(data); if (ret) return ret; - ret = hisi_thermal_register_sensor(pdev, &data->sensor[0]); - if (ret) { - dev_err(dev, "failed to register thermal sensor: %d\n", ret); - return ret; - } + for (i = 0; i < data->nr_sensors; i++) { + struct hisi_thermal_sensor *sensor = &data->sensor[i]; - ret = data->ops->enable_sensor(&data->sensor[0]); - if (ret) { - dev_err(dev, "Failed to setup the sensor: %d\n", ret); - return ret; - } + ret = hisi_thermal_register_sensor(pdev, sensor); + if (ret) { + dev_err(dev, "failed to register thermal sensor: %d\n", + ret); + return ret; + } + + data->irq = platform_get_irq(pdev, 0); + if (data->irq < 0) + return data->irq; - if (data->irq) { ret = devm_request_threaded_irq(dev, data->irq, NULL, - hisi_thermal_alarm_irq_thread, - IRQF_ONESHOT, "hisi_thermal", data); + hisi_thermal_alarm_irq_thread, + IRQF_ONESHOT, "hisi_thermal", + sensor); if (ret < 0) { dev_err(dev, "failed to request alarm irq: %d\n", ret); return ret; } - } - hisi_thermal_toggle_sensor(&data->sensor[0], true); + ret = data->ops->enable_sensor(sensor); + if (ret) { + dev_err(dev, "Failed to setup the sensor: %d\n", ret); + return ret; + } + + hisi_thermal_toggle_sensor(sensor, true); + } return 0; } @@ -598,11 +604,14 @@ static int hisi_thermal_probe(struct platform_device *pdev) static int hisi_thermal_remove(struct platform_device *pdev) { struct hisi_thermal_data *data = platform_get_drvdata(pdev); - struct hisi_thermal_sensor *sensor = &data->sensor[0]; + int i; - hisi_thermal_toggle_sensor(sensor, false); + for (i = 0; i < data->nr_sensors; i++) { + struct hisi_thermal_sensor *sensor = &data->sensor[i]; - data->ops->disable_sensor(sensor); + hisi_thermal_toggle_sensor(sensor, false); + data->ops->disable_sensor(sensor); + } return 0; } @@ -611,8 +620,10 @@ static int hisi_thermal_remove(struct platform_device *pdev) static int hisi_thermal_suspend(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); + int i; - data->ops->disable_sensor(&data->sensor[0]); + for (i = 0; i < data->nr_sensors; i++) + data->ops->disable_sensor(&data->sensor[i]); return 0; } @@ -620,8 +631,12 @@ static int hisi_thermal_suspend(struct device *dev) static int hisi_thermal_resume(struct device *dev) { struct hisi_thermal_data *data = dev_get_drvdata(dev); + int i, ret = 0; - return data->ops->enable_sensor(&data->sensor[0]); + for (i = 0; i < data->nr_sensors; i++) + ret |= data->ops->enable_sensor(&data->sensor[i]); + + return ret; } #endif From a849eecee7ee70db47c4f7e2976432ef16c081e1 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:05 +0200 Subject: [PATCH 26/41] thermal/drivers/hisi: Replace macro name with relevant sensor location Change the macro name in order to give a better indication of the sensor location. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index a5756f6d13e4..a542cb3b4028 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -55,8 +55,8 @@ #define HI3660_TEMP_STEP (205) #define HI3660_TEMP_LAG (4000) -#define HI6220_DEFAULT_SENSOR 2 -#define HI3660_DEFAULT_SENSOR 1 +#define HI6220_CLUSTER0_SENSOR 2 +#define HI3660_BIG_SENSOR 1 struct hisi_thermal_data; @@ -406,7 +406,7 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) if (!data->sensor) return -ENOMEM; - data->sensor[0].id = HI6220_DEFAULT_SENSOR; + data->sensor[0].id = HI6220_CLUSTER0_SENSOR; data->sensor[0].data = data; data->nr_sensors = 1; @@ -422,7 +422,7 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data) if (!data->sensor) return -ENOMEM; - data->sensor[0].id = HI3660_DEFAULT_SENSOR; + data->sensor[0].id = HI3660_BIG_SENSOR; data->sensor[0].data = data; data->nr_sensors = 1; From 2cffaeff083fafeefb1daee7b443f7381eca5b2f Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:07 +0200 Subject: [PATCH 27/41] thermal/drivers/hisi: Use platform_get_irq_byname As we have the interrupt names defines, replace platform_get_irq() by platform_get_irq_byname(), so no confusion can be made when getting the interrupt with the sensor id. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index a542cb3b4028..941c2c42ca79 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -63,6 +63,7 @@ struct hisi_thermal_data; struct hisi_thermal_sensor { struct hisi_thermal_data *data; struct thermal_zone_device *tzd; + const char *irq_name; uint32_t id; uint32_t thres_temp; }; @@ -407,6 +408,7 @@ static int hi6220_thermal_probe(struct hisi_thermal_data *data) return -ENOMEM; data->sensor[0].id = HI6220_CLUSTER0_SENSOR; + data->sensor[0].irq_name = "tsensor_intr"; data->sensor[0].data = data; data->nr_sensors = 1; @@ -423,6 +425,7 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data) return -ENOMEM; data->sensor[0].id = HI3660_BIG_SENSOR; + data->sensor[0].irq_name = "tsensor_a73"; data->sensor[0].data = data; data->nr_sensors = 1; @@ -576,13 +579,13 @@ static int hisi_thermal_probe(struct platform_device *pdev) return ret; } - data->irq = platform_get_irq(pdev, 0); + data->irq = platform_get_irq_byname(pdev, sensor->irq_name); if (data->irq < 0) return data->irq; ret = devm_request_threaded_irq(dev, data->irq, NULL, hisi_thermal_alarm_irq_thread, - IRQF_ONESHOT, "hisi_thermal", + IRQF_ONESHOT, sensor->irq_name, sensor); if (ret < 0) { dev_err(dev, "failed to request alarm irq: %d\n", ret); From a18e83e77217b63e4138470aa49d8269a201f76d Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:09 +0200 Subject: [PATCH 28/41] thermal/drivers/hisi: Remove pointless irq field The irq field in the data structure is pointless as the scope of its usage is just to request the interrupt. It can be replaced by a local variable. Use the 'ret' variable to get the interrupt number. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 941c2c42ca79..87d8a135ad38 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -83,7 +83,6 @@ struct hisi_thermal_data { struct clk *clk; void __iomem *regs; int nr_sensors; - int irq; }; /* @@ -579,16 +578,16 @@ static int hisi_thermal_probe(struct platform_device *pdev) return ret; } - data->irq = platform_get_irq_byname(pdev, sensor->irq_name); - if (data->irq < 0) - return data->irq; + ret = platform_get_irq_byname(pdev, sensor->irq_name); + if (ret < 0) + return ret; - ret = devm_request_threaded_irq(dev, data->irq, NULL, + ret = devm_request_threaded_irq(dev, ret, NULL, hisi_thermal_alarm_irq_thread, IRQF_ONESHOT, sensor->irq_name, sensor); if (ret < 0) { - dev_err(dev, "failed to request alarm irq: %d\n", ret); + dev_err(dev, "Failed to request alarm irq: %d\n", ret); return ret; } From ce8c0700dcf905333733f83a06cd956496e0a661 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:10 +0200 Subject: [PATCH 29/41] thermal/drivers/hisi: Add more sensors channel Add the sensor channels id for the little, g3d and modem. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index 87d8a135ad38..ba89cb9a6248 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -56,7 +56,12 @@ #define HI3660_TEMP_LAG (4000) #define HI6220_CLUSTER0_SENSOR 2 +#define HI6220_CLUSTER1_SENSOR 1 + +#define HI3660_LITTLE_SENSOR 0 #define HI3660_BIG_SENSOR 1 +#define HI3660_G3D_SENSOR 2 +#define HI3660_MODEM_SENSOR 3 struct hisi_thermal_data; From 8c6c36846f1174784bcf90627341ede7ce9a0b36 Mon Sep 17 00:00:00 2001 From: Daniel Lezcano Date: Tue, 25 Sep 2018 11:03:12 +0200 Subject: [PATCH 30/41] thermal/drivers/hisi: Add the dual clusters sensors for hi3660 The code is ready to support multiple sensors on the hi3660. The DT defines a thermal zone per cluster. Add the little cluster sensor and let it bind with the thermal zone. Signed-off-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/hisi_thermal.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/thermal/hisi_thermal.c b/drivers/thermal/hisi_thermal.c index ba89cb9a6248..c4111a98f1a7 100644 --- a/drivers/thermal/hisi_thermal.c +++ b/drivers/thermal/hisi_thermal.c @@ -424,14 +424,20 @@ static int hi3660_thermal_probe(struct hisi_thermal_data *data) struct platform_device *pdev = data->pdev; struct device *dev = &pdev->dev; - data->sensor = devm_kzalloc(dev, sizeof(*data->sensor), GFP_KERNEL); + data->nr_sensors = 2; + + data->sensor = devm_kzalloc(dev, sizeof(*data->sensor) * + data->nr_sensors, GFP_KERNEL); if (!data->sensor) return -ENOMEM; data->sensor[0].id = HI3660_BIG_SENSOR; data->sensor[0].irq_name = "tsensor_a73"; data->sensor[0].data = data; - data->nr_sensors = 1; + + data->sensor[1].id = HI3660_LITTLE_SENSOR; + data->sensor[1].irq_name = "tsensor_a53"; + data->sensor[1].data = data; return 0; } @@ -443,8 +449,8 @@ static int hisi_thermal_get_temp(void *__data, int *temp) *temp = data->ops->get_temp(sensor); - dev_dbg(&data->pdev->dev, "id=%d, temp=%d, thres=%d\n", - sensor->id, *temp, sensor->thres_temp); + dev_dbg(&data->pdev->dev, "tzd=%p, id=%d, temp=%d, thres=%d\n", + sensor->tzd, sensor->id, *temp, sensor->thres_temp); return 0; } From 304d9b486b3c6994c193b6693c601b463987e6ac Mon Sep 17 00:00:00 2001 From: Biju Das Date: Tue, 25 Sep 2018 18:01:04 +0100 Subject: [PATCH 31/41] dt-bindings: thermal: rcar: Add device tree support for r8a7744 Add thermal sensor support for r8a7744 SoC. The Renesas RZ/G1N (r8a7744) thermal sensor module is identical to the R-Car Gen2 family. No driver change is needed due to the fallback compatible value "renesas,rcar-gen2-thermal". Signed-off-by: Biju Das Reviewed-by: Chris Paterson Reviewed-by: Daniel Lezcano Reviewed-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/rcar-thermal.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index 67c563f1b4c4..01d30a972f0d 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt @@ -8,6 +8,7 @@ Required properties: Examples with soctypes are: - "renesas,thermal-r8a73a4" (R-Mobile APE6) - "renesas,thermal-r8a7743" (RZ/G1M) + - "renesas,thermal-r8a7744" (RZ/G1N) - "renesas,thermal-r8a7779" (R-Car H1) - "renesas,thermal-r8a7790" (R-Car H2) - "renesas,thermal-r8a7791" (R-Car M2-W) From df016bbba63743bbef9ff5c6c282561211dd72cc Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 3 Oct 2018 23:47:34 +0300 Subject: [PATCH 32/41] thermal: rcar_thermal: fix duplicate IRQ request The driver on R8A77995 requests the same IRQ twice since platform_get_resource() is always called for the 1st IRQ resource. Fixes: 1969d9dc2079 ("thermal: rcar_thermal: add r8a77995 support") Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Reviewed-by: Daniel Lezcano Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_thermal.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index e77e63070e99..39366cf69d7f 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -504,7 +504,7 @@ static int rcar_thermal_probe(struct platform_device *pdev) pm_runtime_get_sync(dev); for (i = 0; i < chip->nirqs; i++) { - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + irq = platform_get_resource(pdev, IORESOURCE_IRQ, i); if (!irq) continue; if (!common->base) { From a14404a9f04b904bd0c22f34e2119afbf1425abe Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 5 Oct 2018 00:01:38 +0300 Subject: [PATCH 33/41] dt-bindings: thermal: rcar-thermal: document R8A77970 bindings Document the R-Car V3M (R8A77970) SoC in the Renesas R-Car gen2 thermal bindings. The hardware is the same as in the R-Car D3 (R8A77995) plus an extra status register. Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- Documentation/devicetree/bindings/thermal/rcar-thermal.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt index 01d30a972f0d..73e1613d2cb0 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-thermal.txt @@ -4,7 +4,7 @@ Required properties: - compatible : "renesas,thermal-", "renesas,rcar-gen2-thermal" (with thermal-zone) or "renesas,rcar-thermal" (without thermal-zone) as - fallback except R-Car D3. + fallback except R-Car V3M/D3. Examples with soctypes are: - "renesas,thermal-r8a73a4" (R-Mobile APE6) - "renesas,thermal-r8a7743" (RZ/G1M) @@ -14,6 +14,7 @@ Required properties: - "renesas,thermal-r8a7791" (R-Car M2-W) - "renesas,thermal-r8a7792" (R-Car V2H) - "renesas,thermal-r8a7793" (R-Car M2-N) + - "renesas,thermal-r8a77970" (R-Car V3M) - "renesas,thermal-r8a77995" (R-Car D3) - reg : Address range of the thermal registers. The 1st reg will be recognized as common register @@ -22,7 +23,7 @@ Required properties: Option properties: - interrupts : If present should contain 3 interrupts for - R-Car D3 or 1 interrupt otherwise. + R-Car V3M/D3 or 1 interrupt otherwise. Example (non interrupt support): From 92ca366e9b835ada0bfe3c663da91ae44d7e8184 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 5 Oct 2018 00:03:13 +0300 Subject: [PATCH 34/41] thermal: rcar_thermal: add R8A77970 support Add the R-Car V3M (R8A77970) SoC support to the R-Car gen2 thermal driver. The hardware is the same as in the R-Car D3 (R8A77995) plus the CIVM status register (we don't use). Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Reviewed-by: Simon Horman Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_thermal.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 39366cf69d7f..98f951391dcb 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -124,6 +124,10 @@ static const struct of_device_id rcar_thermal_dt_ids[] = { .compatible = "renesas,rcar-gen2-thermal", .data = &rcar_gen2_thermal, }, + { + .compatible = "renesas,thermal-r8a77970", + .data = &rcar_gen3_thermal, + }, { .compatible = "renesas,thermal-r8a77995", .data = &rcar_gen3_thermal, From 7f1a22ce597c2d6410843628c7d240e7441a81a3 Mon Sep 17 00:00:00 2001 From: David HERNANDEZ SANCHEZ Date: Fri, 5 Oct 2018 10:08:45 +0000 Subject: [PATCH 35/41] dt-bindings: stm32-thermal: add binding documentation Add thermal binding documentation for STM32 DTS sensor Signed-off-by: David Hernandez Sanchez Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../bindings/thermal/stm32-thermal.txt | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 Documentation/devicetree/bindings/thermal/stm32-thermal.txt diff --git a/Documentation/devicetree/bindings/thermal/stm32-thermal.txt b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt new file mode 100644 index 000000000000..8c0d5a4d8031 --- /dev/null +++ b/Documentation/devicetree/bindings/thermal/stm32-thermal.txt @@ -0,0 +1,61 @@ +Binding for Thermal Sensor for STMicroelectronics STM32 series of SoCs. + +On STM32 SoCs, the Digital Temperature Sensor (DTS) is in charge of managing an +analog block which delivers a frequency depending on the internal SoC's +temperature. By using a reference frequency, DTS is able to provide a sample +number which can be translated into a temperature by the user. + +DTS provides interrupt notification mechanism by threshold. This mechanism +offers two temperature trip points: passive and critical. The first is intended +for passive cooling notification while the second is used for over-temperature +reset. + +Required parameters: +------------------- + +compatible: Should be "st,stm32-thermal" +reg: This should be the physical base address and length of the + sensor's registers. +clocks: Phandle of the clock used by the thermal sensor. + See: Documentation/devicetree/bindings/clock/clock-bindings.txt +clock-names: Should be "pclk" for register access clock and reference clock. + See: Documentation/devicetree/bindings/resource-names.txt +#thermal-sensor-cells: Should be 0. See ./thermal.txt for a description. +interrupts: Standard way to define interrupt number. + +Example: + + thermal-zones { + cpu_thermal: cpu-thermal { + polling-delay-passive = <0>; + polling-delay = <0>; + + thermal-sensors = <&thermal>; + + trips { + cpu_alert1: cpu-alert1 { + temperature = <85000>; + hysteresis = <0>; + type = "passive"; + }; + + cpu-crit: cpu-crit { + temperature = <120000>; + hysteresis = <0>; + type = "critical"; + }; + }; + + cooling-maps { + }; + }; + }; + + thermal: thermal@50028000 { + compatible = "st,stm32-thermal"; + reg = <0x50028000 0x100>; + clocks = <&rcc TMPSENS>; + clock-names = "pclk"; + #thermal-sensor-cells = <0>; + interrupts = ; + }; From 1d693155607329adff57f5307d35a3a8320d4e7f Mon Sep 17 00:00:00 2001 From: David HERNANDEZ SANCHEZ Date: Fri, 5 Oct 2018 10:08:46 +0000 Subject: [PATCH 36/41] thermal: add stm32 thermal driver Add support for DTS thermal sensor that can be found on some STM32 platforms. This driver is based on OF and works in interrupt mode. It offers two temperature trip points: passive and critical. The first is intended for passive cooling notification while the second is used for over-temperature reset. Signed-off-by: David Hernandez Sanchez Signed-off-by: Eduardo Valentin --- drivers/thermal/Kconfig | 2 +- drivers/thermal/Makefile | 2 +- drivers/thermal/st/Kconfig | 14 + drivers/thermal/st/Makefile | 1 + drivers/thermal/st/stm_thermal.c | 760 +++++++++++++++++++++++++++++++ 5 files changed, 777 insertions(+), 2 deletions(-) create mode 100644 drivers/thermal/st/stm_thermal.c diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 82979880f985..1775d4438a58 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -432,7 +432,7 @@ source "drivers/thermal/samsung/Kconfig" endmenu menu "STMicroelectronics thermal drivers" -depends on ARCH_STI && OF +depends on (ARCH_STI || ARCH_STM32) && OF source "drivers/thermal/st/Kconfig" endmenu diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile index 610344eb3e03..82bb50dc6423 100644 --- a/drivers/thermal/Makefile +++ b/drivers/thermal/Makefile @@ -53,7 +53,7 @@ obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/ obj-$(CONFIG_INTEL_BXT_PMIC_THERMAL) += intel_bxt_pmic_thermal.o obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o -obj-$(CONFIG_ST_THERMAL) += st/ +obj-y += st/ obj-$(CONFIG_QCOM_TSENS) += qcom/ obj-y += tegra/ obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o diff --git a/drivers/thermal/st/Kconfig b/drivers/thermal/st/Kconfig index 490fdbe22eea..b80f9a9e4f8f 100644 --- a/drivers/thermal/st/Kconfig +++ b/drivers/thermal/st/Kconfig @@ -1,3 +1,7 @@ +# +# STMicroelectronics thermal drivers configuration +# + config ST_THERMAL tristate "Thermal sensors on STMicroelectronics STi series of SoCs" help @@ -10,3 +14,13 @@ config ST_THERMAL_SYSCFG config ST_THERMAL_MEMMAP select ST_THERMAL 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. diff --git a/drivers/thermal/st/Makefile b/drivers/thermal/st/Makefile index b38878977bd8..b2b9e9b96296 100644 --- a/drivers/thermal/st/Makefile +++ b/drivers/thermal/st/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_ST_THERMAL) := st_thermal.o obj-$(CONFIG_ST_THERMAL_SYSCFG) += st_thermal_syscfg.o obj-$(CONFIG_ST_THERMAL_MEMMAP) += st_thermal_memmap.o +obj-$(CONFIG_STM32_THERMAL) := stm_thermal.o \ No newline at end of file diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c new file mode 100644 index 000000000000..47623da0f91b --- /dev/null +++ b/drivers/thermal/st/stm_thermal.c @@ -0,0 +1,760 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) STMicroelectronics 2018 - All Rights Reserved + * Author: David Hernandez Sanchez for + * STMicroelectronics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../thermal_core.h" +#include "../thermal_hwmon.h" + +/* DTS register offsets */ +#define DTS_CFGR1_OFFSET 0x0 +#define DTS_T0VALR1_OFFSET 0x8 +#define DTS_RAMPVALR_OFFSET 0X10 +#define DTS_ITR1_OFFSET 0x14 +#define DTS_DR_OFFSET 0x1C +#define DTS_SR_OFFSET 0x20 +#define DTS_ITENR_OFFSET 0x24 +#define DTS_CIFR_OFFSET 0x28 + +/* DTS_CFGR1 register mask definitions */ +#define HSREF_CLK_DIV_MASK GENMASK(30, 24) +#define TS1_SMP_TIME_MASK GENMASK(19, 16) +#define TS1_INTRIG_SEL_MASK GENMASK(11, 8) + +/* DTS_T0VALR1 register mask definitions */ +#define TS1_T0_MASK GENMASK(17, 16) +#define TS1_FMT0_MASK GENMASK(15, 0) + +/* DTS_RAMPVALR register mask definitions */ +#define TS1_RAMP_COEFF_MASK GENMASK(15, 0) + +/* DTS_ITR1 register mask definitions */ +#define TS1_HITTHD_MASK GENMASK(31, 16) +#define TS1_LITTHD_MASK GENMASK(15, 0) + +/* DTS_DR register mask definitions */ +#define TS1_MFREQ_MASK GENMASK(15, 0) + +/* Less significant bit position definitions */ +#define TS1_T0_POS 16 +#define TS1_SMP_TIME_POS 16 +#define TS1_HITTHD_POS 16 +#define HSREF_CLK_DIV_POS 24 + +/* DTS_CFGR1 bit definitions */ +#define TS1_EN BIT(0) +#define TS1_START BIT(4) +#define REFCLK_SEL BIT(20) +#define REFCLK_LSE REFCLK_SEL +#define Q_MEAS_OPT BIT(21) +#define CALIBRATION_CONTROL Q_MEAS_OPT + +/* DTS_SR bit definitions */ +#define TS_RDY BIT(15) +/* Bit definitions below are common for DTS_SR, DTS_ITENR and DTS_CIFR */ +#define HIGH_THRESHOLD BIT(2) +#define LOW_THRESHOLD BIT(1) + +/* Constants */ +#define ADJUST 100 +#define ONE_MHZ 1000000 +#define POLL_TIMEOUT 5000 +#define STARTUP_TIME 40 +#define TS1_T0_VAL0 30 +#define TS1_T0_VAL1 130 +#define NO_HW_TRIG 0 + +/* The Thermal Framework expects millidegrees */ +#define mcelsius(temp) ((temp) * 1000) + +/* The Sensor expects oC degrees */ +#define celsius(temp) ((temp) / 1000) + +struct stm_thermal_sensor { + struct device *dev; + struct thermal_zone_device *th_dev; + enum thermal_device_mode mode; + struct clk *clk; + int high_temp; + int low_temp; + int temp_critical; + int temp_passive; + unsigned int low_temp_enabled; + int num_trips; + int irq; + unsigned int irq_enabled; + void __iomem *base; + int t0, fmt0, ramp_coeff; +}; + +static irqreturn_t stm_thermal_alarm_irq(int irq, void *sdata) +{ + struct stm_thermal_sensor *sensor = sdata; + + disable_irq_nosync(irq); + sensor->irq_enabled = false; + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t stm_thermal_alarm_irq_thread(int irq, void *sdata) +{ + u32 value; + struct stm_thermal_sensor *sensor = sdata; + + /* read IT reason in SR and clear flags */ + value = readl_relaxed(sensor->base + DTS_SR_OFFSET); + + if ((value & LOW_THRESHOLD) == LOW_THRESHOLD) + writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); + + if ((value & HIGH_THRESHOLD) == HIGH_THRESHOLD) + writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); + + thermal_zone_device_update(sensor->th_dev, THERMAL_EVENT_UNSPECIFIED); + + return IRQ_HANDLED; +} + +static int stm_sensor_power_on(struct stm_thermal_sensor *sensor) +{ + int ret; + u32 value; + + /* Enable sensor */ + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + value |= TS1_EN; + writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); + + /* + * The DTS block can be enabled by setting TSx_EN bit in + * DTS_CFGRx register. It requires a startup time of + * 40μs. Use 5 ms as arbitrary timeout. + */ + ret = readl_poll_timeout(sensor->base + DTS_SR_OFFSET, + value, (value & TS_RDY), + STARTUP_TIME, POLL_TIMEOUT); + if (ret) + return ret; + + /* Start continuous measuring */ + value = readl_relaxed(sensor->base + + DTS_CFGR1_OFFSET); + value |= TS1_START; + writel_relaxed(value, sensor->base + + DTS_CFGR1_OFFSET); + + return 0; +} + +static int stm_sensor_power_off(struct stm_thermal_sensor *sensor) +{ + u32 value; + + /* Stop measuring */ + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + value &= ~TS1_START; + writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); + + /* Ensure stop is taken into account */ + usleep_range(STARTUP_TIME, POLL_TIMEOUT); + + /* Disable sensor */ + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + value &= ~TS1_EN; + writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); + + /* Ensure disable is taken into account */ + return readl_poll_timeout(sensor->base + DTS_SR_OFFSET, value, + !(value & TS_RDY), + STARTUP_TIME, POLL_TIMEOUT); +} + +static int stm_thermal_calibration(struct stm_thermal_sensor *sensor) +{ + u32 value, clk_freq; + u32 prescaler; + + /* Figure out prescaler value for PCLK during calibration */ + clk_freq = clk_get_rate(sensor->clk); + if (!clk_freq) + return -EINVAL; + + prescaler = 0; + clk_freq /= ONE_MHZ; + if (clk_freq) { + while (prescaler <= clk_freq) + prescaler++; + } + + value = readl_relaxed(sensor->base + DTS_CFGR1_OFFSET); + + /* Clear prescaler */ + value &= ~HSREF_CLK_DIV_MASK; + + /* Set prescaler. pclk_freq/prescaler < 1MHz */ + value |= (prescaler << HSREF_CLK_DIV_POS); + + /* Select PCLK as reference clock */ + value &= ~REFCLK_SEL; + + /* Set maximal sampling time for better precision */ + value |= TS1_SMP_TIME_MASK; + + /* Measure with calibration */ + value &= ~CALIBRATION_CONTROL; + + /* select trigger */ + value &= ~TS1_INTRIG_SEL_MASK; + value |= NO_HW_TRIG; + + writel_relaxed(value, sensor->base + DTS_CFGR1_OFFSET); + + return 0; +} + +/* Fill in DTS structure with factory sensor values */ +static int stm_thermal_read_factory_settings(struct stm_thermal_sensor *sensor) +{ + /* Retrieve engineering calibration temperature */ + sensor->t0 = readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) & + TS1_T0_MASK; + if (!sensor->t0) + sensor->t0 = TS1_T0_VAL0; + else + sensor->t0 = TS1_T0_VAL1; + + /* Retrieve fmt0 and put it on Hz */ + sensor->fmt0 = ADJUST * readl_relaxed(sensor->base + DTS_T0VALR1_OFFSET) + & TS1_FMT0_MASK; + + /* Retrieve ramp coefficient */ + sensor->ramp_coeff = readl_relaxed(sensor->base + DTS_RAMPVALR_OFFSET) & + TS1_RAMP_COEFF_MASK; + + if (!sensor->fmt0 || !sensor->ramp_coeff) { + dev_err(sensor->dev, "%s: wrong setting\n", __func__); + return -EINVAL; + } + + dev_dbg(sensor->dev, "%s: T0 = %doC, FMT0 = %dHz, RAMP_COEFF = %dHz/oC", + __func__, sensor->t0, sensor->fmt0, sensor->ramp_coeff); + + return 0; +} + +static int stm_thermal_calculate_threshold(struct stm_thermal_sensor *sensor, + int temp, u32 *th) +{ + int freqM; + u32 sampling_time; + + /* Retrieve the number of periods to sample */ + sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) & + TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS; + + /* Figure out the CLK_PTAT frequency for a given temperature */ + freqM = ((temp - sensor->t0) * sensor->ramp_coeff) + + sensor->fmt0; + + dev_dbg(sensor->dev, "%s: freqM for threshold = %d Hz", + __func__, freqM); + + /* Figure out the threshold sample number */ + *th = clk_get_rate(sensor->clk); + if (!*th) + return -EINVAL; + + *th = *th / freqM; + + *th *= sampling_time; + + return 0; +} + +static int stm_thermal_set_threshold(struct stm_thermal_sensor *sensor) +{ + u32 value, th; + int ret; + + value = readl_relaxed(sensor->base + DTS_ITR1_OFFSET); + + /* Erase threshold content */ + value &= ~(TS1_LITTHD_MASK | TS1_HITTHD_MASK); + + /* Retrieve the sample threshold number th for a given temperature */ + ret = stm_thermal_calculate_threshold(sensor, sensor->high_temp, &th); + if (ret) + return ret; + + value |= th & TS1_LITTHD_MASK; + + if (sensor->low_temp_enabled) { + /* Retrieve the sample threshold */ + ret = stm_thermal_calculate_threshold(sensor, sensor->low_temp, + &th); + if (ret) + return ret; + + value |= (TS1_HITTHD_MASK & (th << TS1_HITTHD_POS)); + } + + /* Write value on the Low interrupt threshold */ + writel_relaxed(value, sensor->base + DTS_ITR1_OFFSET); + + return 0; +} + +/* Disable temperature interrupt */ +static int stm_disable_irq(struct stm_thermal_sensor *sensor) +{ + u32 value; + + /* Disable IT generation for low and high thresholds */ + value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); + writel_relaxed(value & ~(LOW_THRESHOLD | HIGH_THRESHOLD), + sensor->base + DTS_ITENR_OFFSET); + + dev_dbg(sensor->dev, "%s: IT disabled on sensor side", __func__); + + return 0; +} + +/* Enable temperature interrupt */ +static int stm_enable_irq(struct stm_thermal_sensor *sensor) +{ + u32 value; + + /* + * Code below enables High temperature threshold using a low threshold + * sampling value + */ + + /* Make sure LOW_THRESHOLD IT is clear before enabling */ + writel_relaxed(LOW_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); + + /* Enable IT generation for low threshold */ + value = readl_relaxed(sensor->base + DTS_ITENR_OFFSET); + value |= LOW_THRESHOLD; + + /* Enable the low temperature threshold if needed */ + if (sensor->low_temp_enabled) { + /* Make sure HIGH_THRESHOLD IT is clear before enabling */ + writel_relaxed(HIGH_THRESHOLD, sensor->base + DTS_CIFR_OFFSET); + + /* Enable IT generation for high threshold */ + value |= HIGH_THRESHOLD; + } + + /* Enable thresholds */ + writel_relaxed(value, sensor->base + DTS_ITENR_OFFSET); + + dev_dbg(sensor->dev, "%s: IT enabled on sensor side", __func__); + + return 0; +} + +static int stm_thermal_update_threshold(struct stm_thermal_sensor *sensor) +{ + int ret; + + sensor->mode = THERMAL_DEVICE_DISABLED; + + ret = stm_sensor_power_off(sensor); + if (ret) + return ret; + + ret = stm_disable_irq(sensor); + if (ret) + return ret; + + ret = stm_thermal_set_threshold(sensor); + if (ret) + return ret; + + ret = stm_enable_irq(sensor); + if (ret) + return ret; + + ret = stm_sensor_power_on(sensor); + if (ret) + return ret; + + sensor->mode = THERMAL_DEVICE_ENABLED; + + return 0; +} + +/* Callback to get temperature from HW */ +static int stm_thermal_get_temp(void *data, int *temp) +{ + struct stm_thermal_sensor *sensor = data; + u32 sampling_time; + int freqM, ret; + + if (sensor->mode != THERMAL_DEVICE_ENABLED) + return -EAGAIN; + + /* Retrieve the number of samples */ + ret = readl_poll_timeout(sensor->base + DTS_DR_OFFSET, freqM, + (freqM & TS1_MFREQ_MASK), STARTUP_TIME, + POLL_TIMEOUT); + + if (ret) + return ret; + + if (!freqM) + return -ENODATA; + + /* Retrieve the number of periods sampled */ + sampling_time = (readl_relaxed(sensor->base + DTS_CFGR1_OFFSET) & + TS1_SMP_TIME_MASK) >> TS1_SMP_TIME_POS; + + /* Figure out the number of samples per period */ + freqM /= sampling_time; + + /* Figure out the CLK_PTAT frequency */ + freqM = clk_get_rate(sensor->clk) / freqM; + if (!freqM) + return -EINVAL; + + dev_dbg(sensor->dev, "%s: freqM=%d\n", __func__, freqM); + + /* Figure out the temperature in mili celsius */ + *temp = mcelsius(sensor->t0 + ((freqM - sensor->fmt0) / + sensor->ramp_coeff)); + + dev_dbg(sensor->dev, "%s: temperature = %d millicelsius", + __func__, *temp); + + /* Update thresholds */ + if (sensor->num_trips > 1) { + /* Update alarm threshold value to next higher trip point */ + if (sensor->high_temp == sensor->temp_passive && + celsius(*temp) >= sensor->temp_passive) { + sensor->high_temp = sensor->temp_critical; + sensor->low_temp = sensor->temp_passive; + sensor->low_temp_enabled = true; + ret = stm_thermal_update_threshold(sensor); + if (ret) + return ret; + } + + if (sensor->high_temp == sensor->temp_critical && + celsius(*temp) < sensor->temp_passive) { + sensor->high_temp = sensor->temp_passive; + sensor->low_temp_enabled = false; + ret = stm_thermal_update_threshold(sensor); + if (ret) + return ret; + } + + /* + * Re-enable alarm IRQ if temperature below critical + * temperature + */ + if (!sensor->irq_enabled && + (celsius(*temp) < sensor->temp_critical)) { + sensor->irq_enabled = true; + enable_irq(sensor->irq); + } + } + + return 0; +} + +/* Registers DTS irq to be visible by GIC */ +static int stm_register_irq(struct stm_thermal_sensor *sensor) +{ + struct device *dev = sensor->dev; + struct platform_device *pdev = to_platform_device(dev); + int ret; + + sensor->irq = platform_get_irq(pdev, 0); + if (sensor->irq < 0) { + dev_err(dev, "%s: Unable to find IRQ\n", __func__); + return sensor->irq; + } + + ret = devm_request_threaded_irq(dev, sensor->irq, + stm_thermal_alarm_irq, + stm_thermal_alarm_irq_thread, + IRQF_ONESHOT, + dev->driver->name, sensor); + if (ret) { + dev_err(dev, "%s: Failed to register IRQ %d\n", __func__, + sensor->irq); + return ret; + } + + sensor->irq_enabled = true; + + dev_dbg(dev, "%s: thermal IRQ registered", __func__); + + return 0; +} + +static int stm_thermal_sensor_off(struct stm_thermal_sensor *sensor) +{ + int ret; + + ret = stm_sensor_power_off(sensor); + if (ret) + return ret; + + clk_disable_unprepare(sensor->clk); + + return 0; +} + +static int stm_thermal_prepare(struct stm_thermal_sensor *sensor) +{ + int ret; + struct device *dev = sensor->dev; + + ret = clk_prepare_enable(sensor->clk); + if (ret) + return ret; + + ret = stm_thermal_calibration(sensor); + if (ret) + goto thermal_unprepare; + + /* Set threshold(s) for IRQ */ + ret = stm_thermal_set_threshold(sensor); + if (ret) + goto thermal_unprepare; + + ret = stm_enable_irq(sensor); + if (ret) + goto thermal_unprepare; + + ret = stm_sensor_power_on(sensor); + if (ret) { + dev_err(dev, "%s: failed to power on sensor\n", __func__); + goto irq_disable; + } + + return 0; + +irq_disable: + stm_disable_irq(sensor); + +thermal_unprepare: + clk_disable_unprepare(sensor->clk); + + return ret; +} + +#ifdef CONFIG_PM_SLEEP +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); + + ret = stm_thermal_sensor_off(sensor); + if (ret) + return ret; + + sensor->mode = THERMAL_DEVICE_DISABLED; + + return 0; +} + +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); + + ret = stm_thermal_prepare(sensor); + if (ret) + return ret; + + sensor->mode = THERMAL_DEVICE_ENABLED; + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +SIMPLE_DEV_PM_OPS(stm_thermal_pm_ops, stm_thermal_suspend, stm_thermal_resume); + +static const struct thermal_zone_of_device_ops stm_tz_ops = { + .get_temp = stm_thermal_get_temp, +}; + +static const struct of_device_id stm_thermal_of_match[] = { + { .compatible = "st,stm32-thermal"}, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, stm_thermal_of_match); + +static int stm_thermal_probe(struct platform_device *pdev) +{ + struct stm_thermal_sensor *sensor; + struct resource *res; + const struct thermal_trip *trip; + void __iomem *base; + int ret, i; + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, "%s: device tree node not found\n", + __func__); + return -EINVAL; + } + + sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return -ENOMEM; + + platform_set_drvdata(pdev, sensor); + + sensor->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + /* Populate sensor */ + sensor->base = base; + + ret = stm_thermal_read_factory_settings(sensor); + if (ret) + return ret; + + sensor->clk = devm_clk_get(&pdev->dev, "pclk"); + if (IS_ERR(sensor->clk)) { + dev_err(&pdev->dev, "%s: failed to fetch PCLK clock\n", + __func__); + return PTR_ERR(sensor->clk); + } + + /* Register IRQ into GIC */ + ret = stm_register_irq(sensor); + if (ret) + return ret; + + sensor->th_dev = devm_thermal_zone_of_sensor_register(&pdev->dev, 0, + sensor, + &stm_tz_ops); + + if (IS_ERR(sensor->th_dev)) { + dev_err(&pdev->dev, "%s: thermal zone sensor registering KO\n", + __func__); + ret = PTR_ERR(sensor->th_dev); + return ret; + } + + if (!sensor->th_dev->ops->get_crit_temp) { + /* Critical point must be provided */ + ret = -EINVAL; + goto err_tz; + } + + ret = sensor->th_dev->ops->get_crit_temp(sensor->th_dev, + &sensor->temp_critical); + if (ret) { + dev_err(&pdev->dev, + "Not able to read critical_temp: %d\n", ret); + goto err_tz; + } + + sensor->temp_critical = celsius(sensor->temp_critical); + + /* Set thresholds for IRQ */ + sensor->high_temp = sensor->temp_critical; + + trip = of_thermal_get_trip_points(sensor->th_dev); + sensor->num_trips = of_thermal_get_ntrips(sensor->th_dev); + + /* Find out passive temperature if it exists */ + for (i = (sensor->num_trips - 1); i >= 0; i--) { + if (trip[i].type == THERMAL_TRIP_PASSIVE) { + sensor->temp_passive = celsius(trip[i].temperature); + /* Update high temperature threshold */ + sensor->high_temp = sensor->temp_passive; + } + } + + /* + * Ensure low_temp_enabled flag is disabled. + * By disabling low_temp_enabled, low threshold IT will not be + * configured neither enabled because it is not needed as high + * threshold is set on the lowest temperature trip point after + * probe. + */ + sensor->low_temp_enabled = false; + + /* Configure and enable HW sensor */ + ret = stm_thermal_prepare(sensor); + if (ret) { + dev_err(&pdev->dev, + "Not able to enable sensor: %d\n", ret); + goto err_tz; + } + + /* + * Thermal_zone doesn't enable hwmon as default, + * enable it here + */ + sensor->th_dev->tzp->no_hwmon = false; + ret = thermal_add_hwmon_sysfs(sensor->th_dev); + if (ret) + goto err_tz; + + sensor->mode = THERMAL_DEVICE_ENABLED; + + dev_info(&pdev->dev, "%s: Driver initialized successfully\n", + __func__); + + return 0; + +err_tz: + thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev); + return ret; +} + +static int stm_thermal_remove(struct platform_device *pdev) +{ + struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev); + + stm_thermal_sensor_off(sensor); + thermal_remove_hwmon_sysfs(sensor->th_dev); + thermal_zone_of_sensor_unregister(&pdev->dev, sensor->th_dev); + + return 0; +} + +static struct platform_driver stm_thermal_driver = { + .driver = { + .name = "stm_thermal", + .pm = &stm_thermal_pm_ops, + .of_match_table = stm_thermal_of_match, + }, + .probe = stm_thermal_probe, + .remove = stm_thermal_remove, +}; +module_platform_driver(stm_thermal_driver); + +MODULE_DESCRIPTION("STMicroelectronics STM32 Thermal Sensor Driver"); +MODULE_AUTHOR("David Hernandez Sanchez "); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:stm_thermal"); From 8583d8d621eb7f38e388dfe53a45fff908ccf07d Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 9 Oct 2018 22:10:14 +0300 Subject: [PATCH 37/41] dt-bindings: thermal: rcar-gen3-thermal: document R8A77980 bindings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the R-Car V3H (R8A77980) SoC in the Renesas R-Car gen3 thermal bindings. Signed-off-by: Sergei Shtylyov Reviewed-by: Simon Horman Reviewed-by: Niklas Söderlund Reviewed-by: Rob Herring Signed-off-by: Eduardo Valentin --- .../devicetree/bindings/thermal/rcar-gen3-thermal.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt index 098bf9550748..ad9a435afef4 100644 --- a/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt +++ b/Documentation/devicetree/bindings/thermal/rcar-gen3-thermal.txt @@ -11,6 +11,7 @@ Required properties: - "renesas,r8a7795-thermal" (R-Car H3) - "renesas,r8a7796-thermal" (R-Car M3-W) - "renesas,r8a77965-thermal" (R-Car M3-N) + - "renesas,r8a77980-thermal" (R-Car V3H) - reg : Address ranges of the thermal registers. Each sensor needs one address range. Sorting must be done in increasing order according to datasheet, i.e. @@ -20,7 +21,8 @@ Required properties: Optional properties: -- interrupts : interrupts routed to the TSC (3 for H3, M3-W and M3-N) +- interrupts : interrupts routed to the TSC (3 for H3, M3-W, M3-N, + and V3H) - power-domain : Must contain a reference to the power domain. This property is mandatory if the thermal sensor instance is part of a controllable power domain. From 853cbc1f2d3a6ef9d5f6f99fe7c4b7595eae9d3a Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Tue, 9 Oct 2018 22:11:51 +0300 Subject: [PATCH 38/41] thermal: rcar_gen3_thermal: add R8A77980 support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add the R-Car V3H (R8A77980) SoC support to the R-Car gen3 thermal driver. Signed-off-by: Sergei Shtylyov Reviewed-by: Simon Horman Reviewed-by: Niklas Söderlund Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_gen3_thermal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/rcar_gen3_thermal.c b/drivers/thermal/rcar_gen3_thermal.c index 53904fbc66c6..b5f33d52c0ec 100644 --- a/drivers/thermal/rcar_gen3_thermal.c +++ b/drivers/thermal/rcar_gen3_thermal.c @@ -331,6 +331,7 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = { { .compatible = "renesas,r8a7795-thermal", }, { .compatible = "renesas,r8a7796-thermal", }, { .compatible = "renesas,r8a77965-thermal", }, + { .compatible = "renesas,r8a77980-thermal", }, {}, }; MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); From 3a31386217628ffe2491695be2db933c25dde785 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 12 Oct 2018 09:20:15 +0200 Subject: [PATCH 39/41] thermal: rcar_thermal: Prevent hardware access during system suspend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On r8a7791/koelsch, sometimes the following message is printed during system suspend: rcar_thermal e61f0000.thermal: thermal sensor was broken This happens if the workqueue runs while the device is already suspended. Fix this by using the freezable system workqueue instead, cfr. commit 51e20d0e3a60cf46 ("thermal: Prevent polling from happening during system suspend"). Fixes: e0a5172e9eec7f0d ("thermal: rcar: add interrupt support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_thermal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index 98f951391dcb..f0e385dd7a92 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -450,8 +450,8 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data) rcar_thermal_for_each_priv(priv, common) { if (rcar_thermal_had_changed(priv, status)) { rcar_thermal_irq_disable(priv); - schedule_delayed_work(&priv->work, - msecs_to_jiffies(300)); + queue_delayed_work(system_freezable_wq, &priv->work, + msecs_to_jiffies(300)); } } From 697ee786f15d7b65c7f3045d45fe3a05d28e0911 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 12 Oct 2018 09:20:16 +0200 Subject: [PATCH 40/41] thermal: rcar_thermal: Prevent doing work after unbind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When testing bind/unbind on r8a7791/koelsch: WARNING: CPU: 1 PID: 697 at lib/debugobjects.c:329 debug_print_object+0x8c/0xb4 ODEBUG: free active (active state 0) object type: timer_list hint: delayed_work_timer_fn+0x0/0x10 This happens if the workqueue runs after the device has been unbound. Fix this by cancelling any queued work during remove. Fixes: e0a5172e9eec7f0d ("thermal: rcar: add interrupt support") Signed-off-by: Geert Uytterhoeven Reviewed-by: Niklas Söderlund Signed-off-by: Eduardo Valentin --- drivers/thermal/rcar_thermal.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/thermal/rcar_thermal.c b/drivers/thermal/rcar_thermal.c index f0e385dd7a92..6d3205819da3 100644 --- a/drivers/thermal/rcar_thermal.c +++ b/drivers/thermal/rcar_thermal.c @@ -469,6 +469,7 @@ static int rcar_thermal_remove(struct platform_device *pdev) rcar_thermal_for_each_priv(priv, common) { rcar_thermal_irq_disable(priv); + cancel_delayed_work_sync(&priv->work); if (priv->chip->use_of_thermal) thermal_remove_hwmon_sysfs(priv->zone); else From 760eea43f8c6d48684f1f34b8a02fddc1456e849 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 12 Oct 2018 09:20:17 +0200 Subject: [PATCH 41/41] thermal: da9062/61: Prevent hardware access during system suspend The workqueue used for monitoring the hardware may run while the device is already suspended. Fix this by using the freezable system workqueue instead, cfr. commit 51e20d0e3a60cf46 ("thermal: Prevent polling from happening during system suspend"). Fixes: 608567aac3206ae8 ("thermal: da9062/61: Thermal junction temperature monitoring driver") Signed-off-by: Geert Uytterhoeven Acked-by: Steve Twiss Signed-off-by: Eduardo Valentin --- drivers/thermal/da9062-thermal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/thermal/da9062-thermal.c b/drivers/thermal/da9062-thermal.c index dd8dd947b7f0..01b0cb994457 100644 --- a/drivers/thermal/da9062-thermal.c +++ b/drivers/thermal/da9062-thermal.c @@ -106,7 +106,7 @@ static void da9062_thermal_poll_on(struct work_struct *work) THERMAL_EVENT_UNSPECIFIED); delay = msecs_to_jiffies(thermal->zone->passive_delay); - schedule_delayed_work(&thermal->work, delay); + queue_delayed_work(system_freezable_wq, &thermal->work, delay); return; } @@ -125,7 +125,7 @@ static irqreturn_t da9062_thermal_irq_handler(int irq, void *data) struct da9062_thermal *thermal = data; disable_irq_nosync(thermal->irq); - schedule_delayed_work(&thermal->work, 0); + queue_delayed_work(system_freezable_wq, &thermal->work, 0); return IRQ_HANDLED; }