Commit a455eda3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal

Pull thermal soc updates from Eduardo Valentin:

 - thermal core has a new devm_* API for registering cooling devices. I
   took the entire series, that is why you see changes on drivers/hwmon
   in this pull (Guenter Roeck)

 - rockchip thermal driver gains support to PX30 SoC (Elaine Zhang)

 - the generic-adc thermal driver now considers the lookup table DT
   property as optional (Jean-Francois Dagenais)

 - Refactoring of tsens thermal driver (Amit Kucheria)

 - Cleanups on cpu cooling driver (Daniel Lezcano)

 - broadcom thermal driver dropped support to ACPI (Srinath Mannam)

 - tegra thermal driver gains support to OC hw throttle and GPU throtle
   (Wei Ni)

 - Fixes in several thermal drivers.

* 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal: (59 commits)
  hwmon: (pwm-fan) Use devm_thermal_of_cooling_device_register
  hwmon: (npcm750-pwm-fan) Use devm_thermal_of_cooling_device_register
  hwmon: (mlxreg-fan) Use devm_thermal_of_cooling_device_register
  hwmon: (gpio-fan) Use devm_thermal_of_cooling_device_register
  hwmon: (aspeed-pwm-tacho) Use devm_thermal_of_cooling_device_register
  thermal: rcar_gen3_thermal: Fix to show correct trip points number
  thermal: rcar_thermal: update calculation formula for R-Car Gen3 SoCs
  thermal: cpu_cooling: Actually trace CPU load in thermal_power_cpu_get_power
  thermal: rockchip: Support the PX30 SoC in thermal driver
  dt-bindings: rockchip-thermal: Support the PX30 SoC compatible
  thermal: rockchip: fix up the tsadc pinctrl setting error
  thermal: broadcom: Remove ACPI support
  thermal: Fix build error of missing devm_ioremap_resource on UM
  thermal/drivers/cpu_cooling: Remove pointless field
  thermal/drivers/cpu_cooling: Add Software Package Data Exchange (SPDX)
  thermal/drivers/cpu_cooling: Fixup the header and copyright
  thermal/drivers/cpu_cooling: Remove pointless test in power2state()
  thermal: rcar_gen3_thermal: disable interrupt in .remove
  thermal: rcar_gen3_thermal: fix interrupt type
  thermal: Introduce devm_thermal_of_cooling_device_register
  ...
parents cc7ce901 37bcec5d
Amazon's Annapurna Labs Thermal Sensor
Simple thermal device that allows temperature reading by a single MMIO
transaction.
Required properties:
- compatible: "amazon,al-thermal".
- reg: The physical base address and length of the sensor's registers.
- #thermal-sensor-cells: Must be 1. See ./thermal.txt for a description.
Example:
thermal: thermal {
compatible = "amazon,al-thermal";
reg = <0x0 0x05002860 0x0 0x1>;
#thermal-sensor-cells = <0x1>;
};
thermal-zones {
thermal-z0 {
polling-delay-passive = <250>;
polling-delay = <1000>;
thermal-sensors = <&thermal 0>;
trips {
critical {
temperature = <105000>;
hysteresis = <2000>;
type = "critical";
};
};
};
};
...@@ -52,13 +52,47 @@ Required properties : ...@@ -52,13 +52,47 @@ Required properties :
Must set as following values: Must set as following values:
TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
- nvidia,gpu-throt-level: This property is for Tegra124 and Tegra210.
It is the level of pulse skippers, which used to throttle clock
frequencies. It indicates gpu clock throttling depth and can be
programmed to any of the following values which represent a throttling
percentage:
TEGRA_SOCTHERM_THROT_LEVEL_NONE (0%)
TEGRA_SOCTHERM_THROT_LEVEL_LOW (50%),
TEGRA_SOCTHERM_THROT_LEVEL_MED (75%),
TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%).
- #cooling-cells: Should be 1. This cooling device only support on/off state. - #cooling-cells: Should be 1. This cooling device only support on/off state.
See ./thermal.txt for a description of this property. See ./thermal.txt for a description of this property.
Optional properties: The following properties are T210 specific and
valid only for OCx throttle events.
- nvidia,count-threshold: Specifies the number of OC events that are
required for triggering an interrupt. Interrupts are not triggered if
the property is missing. A value of 0 will interrupt on every OC alarm.
- nvidia,polarity-active-low: Configures the polarity of the OC alaram
signal. If present, this means assert low, otherwise assert high.
- nvidia,alarm-filter: Number of clocks to filter event. When the filter
expires (which means the OC event has not occurred for a long time),
the counter is cleared and filter is rearmed. Default value is 0.
- nvidia,throttle-period-us: Specifies the number of uSec for which
throttling is engaged after the OC event is deasserted. Default value
is 0.
Optional properties:
- nvidia,thermtrips : When present, this property specifies the temperature at
which the soctherm hardware will assert the thermal trigger signal to the
Power Management IC, which can be configured to reset or shutdown the device.
It is an array of pairs where each pair represents a tsensor id followed by a
temperature in milli Celcius. In the absence of this property the critical
trip point will be used for thermtrip temperature.
Note: Note:
- the "critical" type trip points will be set to SOC_THERM hardware as the - the "critical" type trip points will be used to set the temperature at which
shut down temperature. Once the temperature of this thermal zone is higher the SOC_THERM hardware will assert a thermal trigger if the "nvidia,thermtrips"
than it, the system will be shutdown or reset by hardware. property is missing. When the thermtrips property is present, the breach of a
critical trip point is reported back to the thermal framework to implement
software shutdown.
- the "hot" type trip points will be set to SOC_THERM hardware as the throttle - the "hot" type trip points will be set to SOC_THERM hardware as the throttle
temperature. Once the the temperature of this thermal zone is higher temperature. Once the the temperature of this thermal zone is higher
than it, it will trigger the HW throttle event. than it, it will trigger the HW throttle event.
...@@ -79,25 +113,32 @@ Example : ...@@ -79,25 +113,32 @@ Example :
#thermal-sensor-cells = <1>; #thermal-sensor-cells = <1>;
nvidia,thermtrips = <TEGRA124_SOCTHERM_SENSOR_CPU 102500
TEGRA124_SOCTHERM_SENSOR_GPU 103000>;
throttle-cfgs { throttle-cfgs {
/* /*
* When the "heavy" cooling device triggered, * When the "heavy" cooling device triggered,
* the HW will skip cpu clock's pulse in 85% depth * the HW will skip cpu clock's pulse in 85% depth,
* skip gpu clock's pulse in 85% level
*/ */
throttle_heavy: heavy { throttle_heavy: heavy {
nvidia,priority = <100>; nvidia,priority = <100>;
nvidia,cpu-throt-percent = <85>; nvidia,cpu-throt-percent = <85>;
nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
#cooling-cells = <1>; #cooling-cells = <1>;
}; };
/* /*
* When the "light" cooling device triggered, * When the "light" cooling device triggered,
* the HW will skip cpu clock's pulse in 50% depth * the HW will skip cpu clock's pulse in 50% depth,
* skip gpu clock's pulse in 50% level
*/ */
throttle_light: light { throttle_light: light {
nvidia,priority = <80>; nvidia,priority = <80>;
nvidia,cpu-throt-percent = <50>; nvidia,cpu-throt-percent = <50>;
nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_LOW>;
#cooling-cells = <1>; #cooling-cells = <1>;
}; };
...@@ -107,6 +148,17 @@ Example : ...@@ -107,6 +148,17 @@ Example :
* arbiter will select the highest priority as the final throttle * arbiter will select the highest priority as the final throttle
* settings to skip cpu pulse. * settings to skip cpu pulse.
*/ */
throttle_oc1: oc1 {
nvidia,priority = <50>;
nvidia,polarity-active-low;
nvidia,count-threshold = <100>;
nvidia,alarm-filter = <5100000>;
nvidia,throttle-period-us = <0>;
nvidia,cpu-throt-percent = <75>;
nvidia,gpu-throt-level =
<TEGRA_SOCTHERM_THROT_LEVEL_MED>;
};
}; };
}; };
......
...@@ -6,11 +6,14 @@ Required properties: ...@@ -6,11 +6,14 @@ Required properties:
- "qcom,msm8916-tsens" (MSM8916) - "qcom,msm8916-tsens" (MSM8916)
- "qcom,msm8974-tsens" (MSM8974) - "qcom,msm8974-tsens" (MSM8974)
- "qcom,msm8996-tsens" (MSM8996) - "qcom,msm8996-tsens" (MSM8996)
- "qcom,qcs404-tsens", "qcom,tsens-v1" (QCS404)
- "qcom,msm8998-tsens", "qcom,tsens-v2" (MSM8998) - "qcom,msm8998-tsens", "qcom,tsens-v2" (MSM8998)
- "qcom,sdm845-tsens", "qcom,tsens-v2" (SDM845) - "qcom,sdm845-tsens", "qcom,tsens-v2" (SDM845)
The generic "qcom,tsens-v2" property must be used as a fallback for any SoC The generic "qcom,tsens-v2" property must be used as a fallback for any SoC
with version 2 of the TSENS IP. MSM8996 is the only exception because the with version 2 of the TSENS IP. MSM8996 is the only exception because the
generic property did not exist when support was added. generic property did not exist when support was added.
Similarly, the generic "qcom,tsens-v1" property must be used as a fallback for
any SoC with version 1 of the TSENS IP.
- reg: Address range of the thermal registers. - reg: Address range of the thermal registers.
New platforms containing v2.x.y of the TSENS IP must specify the SROT and TM New platforms containing v2.x.y of the TSENS IP must specify the SROT and TM
...@@ -39,3 +42,14 @@ tsens0: thermal-sensor@c263000 { ...@@ -39,3 +42,14 @@ tsens0: thermal-sensor@c263000 {
#qcom,sensors = <13>; #qcom,sensors = <13>;
#thermal-sensor-cells = <1>; #thermal-sensor-cells = <1>;
}; };
Example 3 (for any platform containing v1 of the TSENS IP):
tsens: thermal-sensor@4a9000 {
compatible = "qcom,qcs404-tsens", "qcom,tsens-v1";
reg = <0x004a9000 0x1000>, /* TM */
<0x004a8000 0x1000>; /* SROT */
nvmem-cells = <&tsens_caldata>;
nvmem-cell-names = "calib";
#qcom,sensors = <10>;
#thermal-sensor-cells = <1>;
};
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
Required properties: Required properties:
- compatible : should be "rockchip,<name>-tsadc" - compatible : should be "rockchip,<name>-tsadc"
"rockchip,px30-tsadc": found on PX30 SoCs
"rockchip,rv1108-tsadc": found on RV1108 SoCs "rockchip,rv1108-tsadc": found on RV1108 SoCs
"rockchip,rk3228-tsadc": found on RK3228 SoCs "rockchip,rk3228-tsadc": found on RK3228 SoCs
"rockchip,rk3288-tsadc": found on RK3288 SoCs "rockchip,rk3288-tsadc": found on RK3288 SoCs
......
...@@ -8,16 +8,22 @@ temperature using voltage-temperature lookup table. ...@@ -8,16 +8,22 @@ temperature using voltage-temperature lookup table.
Required properties: Required properties:
=================== ===================
- compatible: Must be "generic-adc-thermal". - compatible: Must be "generic-adc-thermal".
- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description
of this property.
Optional properties:
===================
- temperature-lookup-table: Two dimensional array of Integer; lookup table - temperature-lookup-table: Two dimensional array of Integer; lookup table
to map the relation between ADC value and to map the relation between ADC value and
temperature. When ADC is read, the value is temperature. When ADC is read, the value is
looked up on the table to get the equivalent looked up on the table to get the equivalent
temperature. temperature.
The first value of the each row of array is the The first value of the each row of array is the
temperature in milliCelsius and second value of temperature in milliCelsius and second value of
the each row of array is the ADC read value. the each row of array is the ADC read value.
- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description
of this property. If not specified, driver assumes the ADC channel
gives milliCelsius directly.
Example : Example :
#include <dt-bindings/thermal/thermal.h> #include <dt-bindings/thermal/thermal.h>
......
...@@ -742,6 +742,12 @@ F: drivers/tty/serial/altera_jtaguart.c ...@@ -742,6 +742,12 @@ F: drivers/tty/serial/altera_jtaguart.c
F: include/linux/altera_uart.h F: include/linux/altera_uart.h
F: include/linux/altera_jtaguart.h F: include/linux/altera_jtaguart.h
AMAZON ANNAPURNA LABS THERMAL MMIO DRIVER
M: Talel Shenhar <talel@amazon.com>
S: Maintained
F: Documentation/devicetree/bindings/thermal/amazon,al-thermal.txt
F: drivers/thermal/thermal_mmio.c
AMAZON ETHERNET DRIVERS AMAZON ETHERNET DRIVERS
M: Netanel Belgazal <netanel@amazon.com> M: Netanel Belgazal <netanel@amazon.com>
R: Saeed Bishara <saeedb@amazon.com> R: Saeed Bishara <saeedb@amazon.com>
......
...@@ -830,10 +830,8 @@ static int aspeed_create_pwm_cooling(struct device *dev, ...@@ -830,10 +830,8 @@ static int aspeed_create_pwm_cooling(struct device *dev,
} }
snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port); snprintf(cdev->name, MAX_CDEV_NAME_LEN, "%pOFn%d", child, pwm_port);
cdev->tcdev = thermal_of_cooling_device_register(child, cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
cdev->name, cdev->name, cdev, &aspeed_pwm_cool_ops);
cdev,
&aspeed_pwm_cool_ops);
if (IS_ERR(cdev->tcdev)) if (IS_ERR(cdev->tcdev))
return PTR_ERR(cdev->tcdev); return PTR_ERR(cdev->tcdev);
......
...@@ -498,6 +498,11 @@ static const struct of_device_id of_gpio_fan_match[] = { ...@@ -498,6 +498,11 @@ static const struct of_device_id of_gpio_fan_match[] = {
}; };
MODULE_DEVICE_TABLE(of, of_gpio_fan_match); MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
static void gpio_fan_stop(void *data)
{
set_fan_speed(data, 0);
}
static int gpio_fan_probe(struct platform_device *pdev) static int gpio_fan_probe(struct platform_device *pdev)
{ {
int err; int err;
...@@ -532,6 +537,7 @@ static int gpio_fan_probe(struct platform_device *pdev) ...@@ -532,6 +537,7 @@ static int gpio_fan_probe(struct platform_device *pdev)
err = fan_ctrl_init(fan_data); err = fan_ctrl_init(fan_data);
if (err) if (err)
return err; return err;
devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
} }
/* Make this driver part of hwmon class. */ /* Make this driver part of hwmon class. */
...@@ -543,32 +549,20 @@ static int gpio_fan_probe(struct platform_device *pdev) ...@@ -543,32 +549,20 @@ static int gpio_fan_probe(struct platform_device *pdev)
return PTR_ERR(fan_data->hwmon_dev); return PTR_ERR(fan_data->hwmon_dev);
/* Optional cooling device register for Device tree platforms */ /* Optional cooling device register for Device tree platforms */
fan_data->cdev = thermal_of_cooling_device_register(np, fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
"gpio-fan", "gpio-fan", fan_data, &gpio_fan_cool_ops);
fan_data,
&gpio_fan_cool_ops);
dev_info(dev, "GPIO fan initialized\n"); dev_info(dev, "GPIO fan initialized\n");
return 0; return 0;
} }
static int gpio_fan_remove(struct platform_device *pdev) static void gpio_fan_shutdown(struct platform_device *pdev)
{ {
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev); struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
if (!IS_ERR(fan_data->cdev))
thermal_cooling_device_unregister(fan_data->cdev);
if (fan_data->gpios) if (fan_data->gpios)
set_fan_speed(fan_data, 0); set_fan_speed(fan_data, 0);
return 0;
}
static void gpio_fan_shutdown(struct platform_device *pdev)
{
gpio_fan_remove(pdev);
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -602,7 +596,6 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume); ...@@ -602,7 +596,6 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
static struct platform_driver gpio_fan_driver = { static struct platform_driver gpio_fan_driver = {
.probe = gpio_fan_probe, .probe = gpio_fan_probe,
.remove = gpio_fan_remove,
.shutdown = gpio_fan_shutdown, .shutdown = gpio_fan_shutdown,
.driver = { .driver = {
.name = "gpio-fan", .name = "gpio-fan",
......
...@@ -465,42 +465,42 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan, ...@@ -465,42 +465,42 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
static int mlxreg_fan_probe(struct platform_device *pdev) static int mlxreg_fan_probe(struct platform_device *pdev)
{ {
struct mlxreg_core_platform_data *pdata; struct mlxreg_core_platform_data *pdata;
struct device *dev = &pdev->dev;
struct mlxreg_fan *fan; struct mlxreg_fan *fan;
struct device *hwm; struct device *hwm;
int err; int err;
pdata = dev_get_platdata(&pdev->dev); pdata = dev_get_platdata(dev);
if (!pdata) { if (!pdata) {
dev_err(&pdev->dev, "Failed to get platform data.\n"); dev_err(dev, "Failed to get platform data.\n");
return -EINVAL; return -EINVAL;
} }
fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL); fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL);
if (!fan) if (!fan)
return -ENOMEM; return -ENOMEM;
fan->dev = &pdev->dev; fan->dev = dev;
fan->regmap = pdata->regmap; fan->regmap = pdata->regmap;
platform_set_drvdata(pdev, fan);
err = mlxreg_fan_config(fan, pdata); err = mlxreg_fan_config(fan, pdata);
if (err) if (err)
return err; return err;
hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan", hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan",
fan, fan,
&mlxreg_fan_hwmon_chip_info, &mlxreg_fan_hwmon_chip_info,
NULL); NULL);
if (IS_ERR(hwm)) { if (IS_ERR(hwm)) {
dev_err(&pdev->dev, "Failed to register hwmon device\n"); dev_err(dev, "Failed to register hwmon device\n");
return PTR_ERR(hwm); return PTR_ERR(hwm);
} }
if (IS_REACHABLE(CONFIG_THERMAL)) { if (IS_REACHABLE(CONFIG_THERMAL)) {
fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan, fan->cdev = devm_thermal_of_cooling_device_register(dev,
&mlxreg_fan_cooling_ops); NULL, "mlxreg_fan", fan, &mlxreg_fan_cooling_ops);
if (IS_ERR(fan->cdev)) { if (IS_ERR(fan->cdev)) {
dev_err(&pdev->dev, "Failed to register cooling device\n"); dev_err(dev, "Failed to register cooling device\n");
return PTR_ERR(fan->cdev); return PTR_ERR(fan->cdev);
} }
} }
...@@ -508,22 +508,11 @@ static int mlxreg_fan_probe(struct platform_device *pdev) ...@@ -508,22 +508,11 @@ static int mlxreg_fan_probe(struct platform_device *pdev)
return 0; return 0;
} }
static int mlxreg_fan_remove(struct platform_device *pdev)
{
struct mlxreg_fan *fan = platform_get_drvdata(pdev);
if (IS_REACHABLE(CONFIG_THERMAL))
thermal_cooling_device_unregister(fan->cdev);
return 0;
}
static struct platform_driver mlxreg_fan_driver = { static struct platform_driver mlxreg_fan_driver = {
.driver = { .driver = {
.name = "mlxreg-fan", .name = "mlxreg-fan",
}, },
.probe = mlxreg_fan_probe, .probe = mlxreg_fan_probe,
.remove = mlxreg_fan_remove,
}; };
module_platform_driver(mlxreg_fan_driver); module_platform_driver(mlxreg_fan_driver);
......
...@@ -846,10 +846,8 @@ static int npcm7xx_create_pwm_cooling(struct device *dev, ...@@ -846,10 +846,8 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child, snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
pwm_port); pwm_port);
cdev->tcdev = thermal_of_cooling_device_register(child, cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
cdev->name, cdev->name, cdev, &npcm7xx_pwm_cool_ops);
cdev,
&npcm7xx_pwm_cool_ops);
if (IS_ERR(cdev->tcdev)) if (IS_ERR(cdev->tcdev))
return PTR_ERR(cdev->tcdev); return PTR_ERR(cdev->tcdev);
......
...@@ -273,27 +273,40 @@ static int pwm_fan_of_get_cooling_data(struct device *dev, ...@@ -273,27 +273,40 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
return 0; return 0;
} }
static void pwm_fan_regulator_disable(void *data)
{
regulator_disable(data);
}
static void pwm_fan_pwm_disable(void *__ctx)
{
struct pwm_fan_ctx *ctx = __ctx;
pwm_disable(ctx->pwm);
del_timer_sync(&ctx->rpm_timer);
}
static int pwm_fan_probe(struct platform_device *pdev) static int pwm_fan_probe(struct platform_device *pdev)
{ {
struct thermal_cooling_device *cdev; struct thermal_cooling_device *cdev;
struct device *dev = &pdev->dev;
struct pwm_fan_ctx *ctx; struct pwm_fan_ctx *ctx;
struct device *hwmon; struct device *hwmon;
int ret; int ret;
struct pwm_state state = { }; struct pwm_state state = { };
u32 ppr = 2; u32 ppr = 2;
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
mutex_init(&ctx->lock); mutex_init(&ctx->lock);
ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL); ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL);
if (IS_ERR(ctx->pwm)) { if (IS_ERR(ctx->pwm)) {
ret = PTR_ERR(ctx->pwm); ret = PTR_ERR(ctx->pwm);
if (ret != -EPROBE_DEFER) if (ret != -EPROBE_DEFER)
dev_err(&pdev->dev, "Could not get PWM: %d\n", ret); dev_err(dev, "Could not get PWM: %d\n", ret);
return ret; return ret;
} }
...@@ -304,7 +317,7 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -304,7 +317,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
if (ctx->irq == -EPROBE_DEFER) if (ctx->irq == -EPROBE_DEFER)
return ctx->irq; return ctx->irq;
ctx->reg_en = devm_regulator_get_optional(&pdev->dev, "fan"); ctx->reg_en = devm_regulator_get_optional(dev, "fan");
if (IS_ERR(ctx->reg_en)) { if (IS_ERR(ctx->reg_en)) {
if (PTR_ERR(ctx->reg_en) != -ENODEV) if (PTR_ERR(ctx->reg_en) != -ENODEV)
return PTR_ERR(ctx->reg_en); return PTR_ERR(ctx->reg_en);
...@@ -313,10 +326,11 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -313,10 +326,11 @@ static int pwm_fan_probe(struct platform_device *pdev)
} else { } else {
ret = regulator_enable(ctx->reg_en); ret = regulator_enable(ctx->reg_en);
if (ret) { if (ret) {
dev_err(&pdev->dev, dev_err(dev, "Failed to enable fan supply: %d\n", ret);
"Failed to enable fan supply: %d\n", ret);
return ret; return ret;
} }
devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
ctx->reg_en);
} }
ctx->pwm_value = MAX_PWM; ctx->pwm_value = MAX_PWM;
...@@ -328,91 +342,57 @@ static int pwm_fan_probe(struct platform_device *pdev) ...@@ -328,91 +342,57 @@ static int pwm_fan_probe(struct platform_device *pdev)
ret = pwm_apply_state(ctx->pwm, &state); ret = pwm_apply_state(ctx->pwm, &state);
if (ret) { if (ret) {
dev_err(&pdev->dev, "Failed to configure PWM: %d\n", ret); dev_err(dev, "Failed to configure PWM: %d\n", ret);
goto err_reg_disable; return ret;
} }
timer_setup(&ctx->rpm_timer, sample_timer, 0); timer_setup(&ctx->rpm_timer, sample_timer, 0);
devm_add_action_or_reset(dev, pwm_fan_pwm_disable, ctx);
of_property_read_u32(pdev->dev.of_node, "pulses-per-revolution", &ppr); of_property_read_u32(dev->of_node, "pulses-per-revolution", &ppr);
ctx->pulses_per_revolution = ppr; ctx->pulses_per_revolution = ppr;
if (!ctx->pulses_per_revolution) { if (!ctx->pulses_per_revolution) {
dev_err(&pdev->dev, "pulses-per-revolution can't be zero.\n"); dev_err(dev, "pulses-per-revolution can't be zero.\n");
ret = -EINVAL; return -EINVAL;
goto err_pwm_disable;
} }
if (ctx->irq > 0) { if (ctx->irq > 0) {
ret = devm_request_irq(&pdev->dev, ctx->irq, pulse_handler, 0, ret = devm_request_irq(dev, ctx->irq, pulse_handler, 0,
pdev->name, ctx); pdev->name, ctx);
if (ret) { if (ret) {
dev_err(&pdev->dev, dev_err(dev, "Failed to request interrupt: %d\n", ret);
"Failed to request interrupt: %d\n", ret); return ret;
goto err_pwm_disable;
} }
ctx->sample_start = ktime_get(); ctx->sample_start = ktime_get();
mod_timer(&ctx->rpm_timer, jiffies + HZ); mod_timer(&ctx->rpm_timer, jiffies + HZ);
} }
hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, "pwmfan", hwmon = devm_hwmon_device_register_with_groups(dev, "pwmfan",
ctx, pwm_fan_groups); ctx, pwm_fan_groups);
if (IS_ERR(hwmon)) { if (IS_ERR(hwmon)) {
ret = PTR_ERR(hwmon); dev_err(dev, "Failed to register hwmon device\n");
dev_err(&pdev->dev, return PTR_ERR(hwmon);
"Failed to register hwmon device: %d\n", ret);
goto err_del_timer;
} }
ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx); ret = pwm_fan_of_get_cooling_data(dev, ctx);
if (ret) if (ret)
goto err_del_timer; return ret;
ctx->pwm_fan_state = ctx->pwm_fan_max_state; ctx->pwm_fan_state = ctx->pwm_fan_max_state;
if (IS_ENABLED(CONFIG_THERMAL)) { if (IS_ENABLED(CONFIG_THERMAL)) {
cdev = thermal_of_cooling_device_register(pdev->dev.of_node, cdev = devm_thermal_of_cooling_device_register(dev,
"pwm-fan", ctx, dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops);
&pwm_fan_cooling_ops);
if (IS_ERR(cdev)) { if (IS_ERR(cdev)) {
ret = PTR_ERR(cdev); ret = PTR_ERR(cdev);
dev_err(&pdev->dev, dev_err(dev,
"Failed to register pwm-fan as cooling device: %d\n", "Failed to register pwm-fan as cooling device: %d\n",
ret); ret);
goto err_del_timer; return ret;
} }
ctx->cdev = cdev; ctx->cdev = cdev;
thermal_cdev_update(cdev); thermal_cdev_update(cdev);
} }
return 0; return 0;
err_del_timer:
del_timer_sync(&ctx->rpm_timer);
err_pwm_disable:
state.enabled = false;
pwm_apply_state(ctx->pwm, &state);
err_reg_disable:
if (ctx->reg_en)
regulator_disable(ctx->reg_en);
return ret;
}
static int pwm_fan_remove(struct platform_device *pdev)
{
struct pwm_fan_ctx *ctx = platform_get_drvdata(pdev);
thermal_cooling_device_unregister(ctx->cdev);
del_timer_sync(&ctx->rpm_timer);
if (ctx->pwm_value)
pwm_disable(ctx->pwm);
if (ctx->reg_en)
regulator_disable(ctx->reg_en);
return 0;
} }
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
...@@ -480,7 +460,6 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match); ...@@ -480,7 +460,6 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match);
static struct platform_driver pwm_fan_driver = { static struct platform_driver pwm_fan_driver = {
.probe = pwm_fan_probe, .probe = pwm_fan_probe,
.remove = pwm_fan_remove,
.driver = { .driver = {
.name = "pwm-fan", .name = "pwm-fan",
.pm = &pwm_fan_pm, .pm = &pwm_fan_pm,
......
...@@ -200,6 +200,17 @@ config THERMAL_EMULATION ...@@ -200,6 +200,17 @@ config THERMAL_EMULATION
because userland can easily disable the thermal policy by simply because userland can easily disable the thermal policy by simply
flooding this sysfs node with low temperature values. flooding this sysfs node with low temperature values.
config THERMAL_MMIO
tristate "Generic Thermal MMIO driver"
depends on OF || COMPILE_TEST
depends on HAS_IOMEM
help
This option enables the generic thermal MMIO driver that will use
memory-mapped reads to get the temperature. Any HW/System that
allows temperature reading by a single memory-mapped reading, be it
register or shared memory, is a potential candidate to work with this
driver.
config HISI_THERMAL config HISI_THERMAL
tristate "Hisilicon thermal driver" tristate "Hisilicon thermal driver"
depends on ARCH_HISI || COMPILE_TEST depends on ARCH_HISI || COMPILE_TEST
......
...@@ -29,6 +29,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o ...@@ -29,6 +29,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
# platform thermal drivers # platform thermal drivers
obj-y += broadcom/ obj-y += broadcom/
obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
* Copyright (C) 2018 Broadcom * Copyright (C) 2018 Broadcom
*/ */
#include <linux/acpi.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -100,18 +99,11 @@ static const struct of_device_id sr_thermal_of_match[] = { ...@@ -100,18 +99,11 @@ static const struct of_device_id sr_thermal_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, sr_thermal_of_match); MODULE_DEVICE_TABLE(of, sr_thermal_of_match);
static const struct acpi_device_id sr_thermal_acpi_ids[] = {
{ .id = "BRCM0500" },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(acpi, sr_thermal_acpi_ids);
static struct platform_driver sr_thermal_driver = { static struct platform_driver sr_thermal_driver = {
.probe = sr_thermal_probe, .probe = sr_thermal_probe,
.driver = { .driver = {
.name = "sr-thermal", .name = "sr-thermal",
.of_match_table = sr_thermal_of_match, .of_match_table = sr_thermal_of_match,
.acpi_match_table = ACPI_PTR(sr_thermal_acpi_ids),
}, },
}; };
module_platform_driver(sr_thermal_driver); module_platform_driver(sr_thermal_driver);
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* linux/drivers/thermal/cpu_cooling.c * linux/drivers/thermal/cpu_cooling.c
* *
* Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com)
* Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org>
* *
* Copyright (C) 2014 Viresh Kumar <viresh.kumar@linaro.org> * Copyright (C) 2012-2018 Linaro Limited.
* *
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Authors: Amit Daniel <amit.kachhap@linaro.org>
* This program is free software; you can redistribute it and/or modify * Viresh Kumar <viresh.kumar@linaro.org>
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
* *
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/thermal.h> #include <linux/thermal.h>
...@@ -99,7 +87,6 @@ struct cpufreq_cooling_device { ...@@ -99,7 +87,6 @@ struct cpufreq_cooling_device {
unsigned int clipped_freq; unsigned int clipped_freq;
unsigned int max_level; unsigned int max_level;
struct freq_table *freq_table; /* In descending order */ struct freq_table *freq_table; /* In descending order */
struct thermal_cooling_device *cdev;
struct cpufreq_policy *policy; struct cpufreq_policy *policy;
struct list_head node; struct list_head node;
struct time_in_idle *idle_time; struct time_in_idle *idle_time;
...@@ -207,8 +194,7 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev, ...@@ -207,8 +194,7 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev,
dev = get_cpu_device(cpu); dev = get_cpu_device(cpu);
if (unlikely(!dev)) { if (unlikely(!dev)) {
dev_warn(&cpufreq_cdev->cdev->device, pr_warn("No cpu device for cpu %d\n", cpu);
"No cpu device for cpu %d\n", cpu);
return -ENODEV; return -ENODEV;
} }
...@@ -458,7 +444,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev, ...@@ -458,7 +444,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
load = 0; load = 0;
total_load += load; total_load += load;
if (trace_thermal_power_cpu_limit_enabled() && load_cpu) if (load_cpu)
load_cpu[i] = load; load_cpu[i] = load;
i++; i++;
...@@ -541,7 +527,6 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev, ...@@ -541,7 +527,6 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata; struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
struct cpufreq_policy *policy = cpufreq_cdev->policy; struct cpufreq_policy *policy = cpufreq_cdev->policy;
power = power > 0 ? power : 0;
last_load = cpufreq_cdev->last_load ?: 1; last_load = cpufreq_cdev->last_load ?: 1;
normalised_power = (power * 100) / last_load; normalised_power = (power * 100) / last_load;
target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power); target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
...@@ -692,7 +677,6 @@ __cpufreq_cooling_register(struct device_node *np, ...@@ -692,7 +677,6 @@ __cpufreq_cooling_register(struct device_node *np,
goto remove_ida; goto remove_ida;
cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency; cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
cpufreq_cdev->cdev = cdev;
mutex_lock(&cooling_list_lock); mutex_lock(&cooling_list_lock);
/* Register the notifier for first cpufreq cooling device */ /* Register the notifier for first cpufreq cooling device */
...@@ -810,7 +794,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) ...@@ -810,7 +794,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
CPUFREQ_POLICY_NOTIFIER); CPUFREQ_POLICY_NOTIFIER);
thermal_cooling_device_unregister(cpufreq_cdev->cdev); thermal_cooling_device_unregister(cdev);
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id); ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
kfree(cpufreq_cdev->idle_time); kfree(cpufreq_cdev->idle_time);
kfree(cpufreq_cdev->freq_table); kfree(cpufreq_cdev->freq_table);
......
...@@ -5,6 +5,9 @@ ...@@ -5,6 +5,9 @@
* Copyright (C) 2013 Texas Instruments * Copyright (C) 2013 Texas Instruments
* Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com> * Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/types.h> #include <linux/types.h>
......
obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o obj-$(CONFIG_QCOM_TSENS) += qcom_tsens.o
qcom_tsens-y += tsens.o tsens-common.o tsens-8916.o tsens-8974.o tsens-8960.o tsens-v2.o
qcom_tsens-y += tsens.o tsens-common.o tsens-v0_1.o \
tsens-8960.o tsens-v2.o tsens-v1.o
obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*/
#include <linux/platform_device.h>
#include "tsens.h"
/* eeprom layout data for 8916 */
#define BASE0_MASK 0x0000007f
#define BASE1_MASK 0xfe000000
#define BASE0_SHIFT 0
#define BASE1_SHIFT 25
#define S0_P1_MASK 0x00000f80
#define S1_P1_MASK 0x003e0000
#define S2_P1_MASK 0xf8000000
#define S3_P1_MASK 0x000003e0
#define S4_P1_MASK 0x000f8000
#define S0_P2_MASK 0x0001f000
#define S1_P2_MASK 0x07c00000
#define S2_P2_MASK 0x0000001f
#define S3_P2_MASK 0x00007c00
#define S4_P2_MASK 0x01f00000
#define S0_P1_SHIFT 7
#define S1_P1_SHIFT 17
#define S2_P1_SHIFT 27
#define S3_P1_SHIFT 5
#define S4_P1_SHIFT 15
#define S0_P2_SHIFT 12
#define S1_P2_SHIFT 22
#define S2_P2_SHIFT 0
#define S3_P2_SHIFT 10
#define S4_P2_SHIFT 20
#define CAL_SEL_MASK 0xe0000000
#define CAL_SEL_SHIFT 29
static int calibrate_8916(struct tsens_device *tmdev)
{
int base0 = 0, base1 = 0, i;
u32 p1[5], p2[5];
int mode = 0;
u32 *qfprom_cdata, *qfprom_csel;
qfprom_cdata = (u32 *)qfprom_read(tmdev->dev, "calib");
if (IS_ERR(qfprom_cdata))
return PTR_ERR(qfprom_cdata);
qfprom_csel = (u32 *)qfprom_read(tmdev->dev, "calib_sel");
if (IS_ERR(qfprom_csel))
return PTR_ERR(qfprom_csel);
mode = (qfprom_csel[0] & CAL_SEL_MASK) >> CAL_SEL_SHIFT;
dev_dbg(tmdev->dev, "calibration mode is %d\n", mode);
switch (mode) {
case TWO_PT_CALIB:
base1 = (qfprom_cdata[1] & BASE1_MASK) >> BASE1_SHIFT;
p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT;
p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT;
p2[2] = (qfprom_cdata[1] & S2_P2_MASK) >> S2_P2_SHIFT;
p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT;
p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT;
for (i = 0; i < tmdev->num_sensors; i++)
p2[i] = ((base1 + p2[i]) << 3);
/* Fall through */
case ONE_PT_CALIB2:
base0 = (qfprom_cdata[0] & BASE0_MASK);
p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT;
p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT;
p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT;
p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT;
p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT;
for (i = 0; i < tmdev->num_sensors; i++)
p1[i] = (((base0) + p1[i]) << 3);
break;
default:
for (i = 0; i < tmdev->num_sensors; i++) {
p1[i] = 500;
p2[i] = 780;
}
break;
}
compute_intercept_slope(tmdev, p1, p2, mode);
return 0;
}
static const struct tsens_ops ops_8916 = {
.init = init_common,
.calibrate = calibrate_8916,
.get_temp = get_temp_common,
};
const struct tsens_data data_8916 = {
.num_sensors = 5,
.ops = &ops_8916,
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 },
.hw_ids = (unsigned int []){0, 1, 2, 4, 5 },
};
...@@ -56,21 +56,21 @@ ...@@ -56,21 +56,21 @@
#define TRDY_MASK BIT(7) #define TRDY_MASK BIT(7)
#define TIMEOUT_US 100 #define TIMEOUT_US 100
static int suspend_8960(struct tsens_device *tmdev) static int suspend_8960(struct tsens_priv *priv)
{ {
int ret; int ret;
unsigned int mask; unsigned int mask;
struct regmap *map = tmdev->tm_map; struct regmap *map = priv->tm_map;
ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold); ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold);
if (ret) if (ret)
return ret; return ret;
ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control); ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control);
if (ret) if (ret)
return ret; return ret;
if (tmdev->num_sensors > 1) if (priv->num_sensors > 1)
mask = SLP_CLK_ENA | EN; mask = SLP_CLK_ENA | EN;
else else
mask = SLP_CLK_ENA_8660 | EN; mask = SLP_CLK_ENA_8660 | EN;
...@@ -82,10 +82,10 @@ static int suspend_8960(struct tsens_device *tmdev) ...@@ -82,10 +82,10 @@ static int suspend_8960(struct tsens_device *tmdev)
return 0; return 0;
} }
static int resume_8960(struct tsens_device *tmdev) static int resume_8960(struct tsens_priv *priv)
{ {
int ret; int ret;
struct regmap *map = tmdev->tm_map; struct regmap *map = priv->tm_map;
ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
if (ret) if (ret)
...@@ -95,80 +95,80 @@ static int resume_8960(struct tsens_device *tmdev) ...@@ -95,80 +95,80 @@ static int resume_8960(struct tsens_device *tmdev)
* Separate CONFIG restore is not needed only for 8660 as * Separate CONFIG restore is not needed only for 8660 as
* config is part of CTRL Addr and its restored as such * config is part of CTRL Addr and its restored as such
*/ */
if (tmdev->num_sensors > 1) { if (priv->num_sensors > 1) {
ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
if (ret) if (ret)
return ret; return ret;
} }
ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold); ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold);
if (ret) if (ret)
return ret; return ret;
ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control); ret = regmap_write(map, CNTL_ADDR, priv->ctx.control);
if (ret) if (ret)
return ret; return ret;
return 0; return 0;
} }
static int enable_8960(struct tsens_device *tmdev, int id) static int enable_8960(struct tsens_priv *priv, int id)
{ {
int ret; int ret;
u32 reg, mask; u32 reg, mask;
ret = regmap_read(tmdev->tm_map, CNTL_ADDR, &reg); ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg);
if (ret) if (ret)
return ret; return ret;
mask = BIT(id + SENSOR0_SHIFT); mask = BIT(id + SENSOR0_SHIFT);
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST); ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
if (ret) if (ret)
return ret; return ret;
if (tmdev->num_sensors > 1) if (priv->num_sensors > 1)
reg |= mask | SLP_CLK_ENA | EN; reg |= mask | SLP_CLK_ENA | EN;
else else
reg |= mask | SLP_CLK_ENA_8660 | EN; reg |= mask | SLP_CLK_ENA_8660 | EN;
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg); ret = regmap_write(priv->tm_map, CNTL_ADDR, reg);
if (ret) if (ret)
return ret; return ret;
return 0; return 0;
} }
static void disable_8960(struct tsens_device *tmdev) static void disable_8960(struct tsens_priv *priv)
{ {
int ret; int ret;
u32 reg_cntl; u32 reg_cntl;
u32 mask; u32 mask;
mask = GENMASK(tmdev->num_sensors - 1, 0); mask = GENMASK(priv->num_sensors - 1, 0);
mask <<= SENSOR0_SHIFT; mask <<= SENSOR0_SHIFT;
mask |= EN; mask |= EN;
ret = regmap_read(tmdev->tm_map, CNTL_ADDR, &reg_cntl); ret = regmap_read(priv->tm_map, CNTL_ADDR, &reg_cntl);
if (ret) if (ret)
return; return;
reg_cntl &= ~mask; reg_cntl &= ~mask;
if (tmdev->num_sensors > 1) if (priv->num_sensors > 1)
reg_cntl &= ~SLP_CLK_ENA; reg_cntl &= ~SLP_CLK_ENA;
else else
reg_cntl &= ~SLP_CLK_ENA_8660; reg_cntl &= ~SLP_CLK_ENA_8660;
regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
} }
static int init_8960(struct tsens_device *tmdev) static int init_8960(struct tsens_priv *priv)
{ {
int ret, i; int ret, i;
u32 reg_cntl; u32 reg_cntl;
tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL); priv->tm_map = dev_get_regmap(priv->dev, NULL);
if (!tmdev->tm_map) if (!priv->tm_map)
return -ENODEV; return -ENODEV;
/* /*
...@@ -177,21 +177,21 @@ static int init_8960(struct tsens_device *tmdev) ...@@ -177,21 +177,21 @@ static int init_8960(struct tsens_device *tmdev)
* but the control registers stay in the same place, i.e * but the control registers stay in the same place, i.e
* directly after the first 5 status registers. * directly after the first 5 status registers.
*/ */
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < priv->num_sensors; i++) {
if (i >= 5) if (i >= 5)
tmdev->sensor[i].status = S0_STATUS_ADDR + 40; priv->sensor[i].status = S0_STATUS_ADDR + 40;
tmdev->sensor[i].status += i * 4; priv->sensor[i].status += i * 4;
} }
reg_cntl = SW_RST; reg_cntl = SW_RST;
ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl); ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
if (ret) if (ret)
return ret; return ret;
if (tmdev->num_sensors > 1) { if (priv->num_sensors > 1) {
reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
reg_cntl &= ~SW_RST; reg_cntl &= ~SW_RST;
ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR, ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
CONFIG_MASK, CONFIG); CONFIG_MASK, CONFIG);
} else { } else {
reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
...@@ -199,30 +199,30 @@ static int init_8960(struct tsens_device *tmdev) ...@@ -199,30 +199,30 @@ static int init_8960(struct tsens_device *tmdev)
reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
} }
reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT; reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
if (ret) if (ret)
return ret; return ret;
reg_cntl |= EN; reg_cntl |= EN;
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
if (ret) if (ret)
return ret; return ret;
return 0; return 0;
} }
static int calibrate_8960(struct tsens_device *tmdev) static int calibrate_8960(struct tsens_priv *priv)
{ {
int i; int i;
char *data; char *data;
ssize_t num_read = tmdev->num_sensors; ssize_t num_read = priv->num_sensors;
struct tsens_sensor *s = tmdev->sensor; struct tsens_sensor *s = priv->sensor;
data = qfprom_read(tmdev->dev, "calib"); data = qfprom_read(priv->dev, "calib");
if (IS_ERR(data)) if (IS_ERR(data))
data = qfprom_read(tmdev->dev, "calib_backup"); data = qfprom_read(priv->dev, "calib_backup");
if (IS_ERR(data)) if (IS_ERR(data))
return PTR_ERR(data); return PTR_ERR(data);
...@@ -243,21 +243,21 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) ...@@ -243,21 +243,21 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
return adc_code * slope + offset; return adc_code * slope + offset;
} }
static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp) static int get_temp_8960(struct tsens_priv *priv, int id, int *temp)
{ {
int ret; int ret;
u32 code, trdy; u32 code, trdy;
const struct tsens_sensor *s = &tmdev->sensor[id]; const struct tsens_sensor *s = &priv->sensor[id];
unsigned long timeout; unsigned long timeout;
timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
do { do {
ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy); ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
if (ret) if (ret)
return ret; return ret;
if (!(trdy & TRDY_MASK)) if (!(trdy & TRDY_MASK))
continue; continue;
ret = regmap_read(tmdev->tm_map, s->status, &code); ret = regmap_read(priv->tm_map, s->status, &code);
if (ret) if (ret)
return ret; return ret;
*temp = code_to_mdegC(code, s); *temp = code_to_mdegC(code, s);
...@@ -277,7 +277,7 @@ static const struct tsens_ops ops_8960 = { ...@@ -277,7 +277,7 @@ static const struct tsens_ops ops_8960 = {
.resume = resume_8960, .resume = resume_8960,
}; };
const struct tsens_data data_8960 = { const struct tsens_plat_data data_8960 = {
.num_sensors = 11, .num_sensors = 11,
.ops = &ops_8960, .ops = &ops_8960,
}; };
...@@ -12,18 +12,6 @@ ...@@ -12,18 +12,6 @@
#include <linux/regmap.h> #include <linux/regmap.h>
#include "tsens.h" #include "tsens.h"
/* SROT */
#define TSENS_EN BIT(0)
/* TM */
#define STATUS_OFFSET 0x30
#define SN_ADDR_OFFSET 0x4
#define SN_ST_TEMP_MASK 0x3ff
#define CAL_DEGC_PT1 30
#define CAL_DEGC_PT2 120
#define SLOPE_FACTOR 1000
#define SLOPE_DEFAULT 3200
char *qfprom_read(struct device *dev, const char *cname) char *qfprom_read(struct device *dev, const char *cname)
{ {
struct nvmem_cell *cell; struct nvmem_cell *cell;
...@@ -46,18 +34,18 @@ char *qfprom_read(struct device *dev, const char *cname) ...@@ -46,18 +34,18 @@ char *qfprom_read(struct device *dev, const char *cname)
* and offset values are derived from tz->tzp->slope and tz->tzp->offset * and offset values are derived from tz->tzp->slope and tz->tzp->offset
* resp. * resp.
*/ */
void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, void compute_intercept_slope(struct tsens_priv *priv, u32 *p1,
u32 *p2, u32 mode) u32 *p2, u32 mode)
{ {
int i; int i;
int num, den; int num, den;
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < priv->num_sensors; i++) {
dev_dbg(tmdev->dev, dev_dbg(priv->dev,
"sensor%d - data_point1:%#x data_point2:%#x\n", "sensor%d - data_point1:%#x data_point2:%#x\n",
i, p1[i], p2[i]); i, p1[i], p2[i]);
tmdev->sensor[i].slope = SLOPE_DEFAULT; priv->sensor[i].slope = SLOPE_DEFAULT;
if (mode == TWO_PT_CALIB) { if (mode == TWO_PT_CALIB) {
/* /*
* slope (m) = adc_code2 - adc_code1 (y2 - y1)/ * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
...@@ -66,16 +54,30 @@ void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1, ...@@ -66,16 +54,30 @@ void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
num = p2[i] - p1[i]; num = p2[i] - p1[i];
num *= SLOPE_FACTOR; num *= SLOPE_FACTOR;
den = CAL_DEGC_PT2 - CAL_DEGC_PT1; den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
tmdev->sensor[i].slope = num / den; priv->sensor[i].slope = num / den;
} }
tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) - priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
(CAL_DEGC_PT1 * (CAL_DEGC_PT1 *
tmdev->sensor[i].slope); priv->sensor[i].slope);
dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset); dev_dbg(priv->dev, "offset:%d\n", priv->sensor[i].offset);
} }
} }
bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id)
{
u32 val;
int ret;
if ((hw_id > (priv->num_sensors - 1)) || (hw_id < 0))
return -EINVAL;
ret = regmap_field_read(priv->rf[SENSOR_EN], &val);
if (ret)
return ret;
return val & (1 << hw_id);
}
static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
{ {
int degc, num, den; int degc, num, den;
...@@ -95,18 +97,54 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s) ...@@ -95,18 +97,54 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
return degc; return degc;
} }
int get_temp_common(struct tsens_device *tmdev, int id, int *temp) int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp)
{
struct tsens_sensor *s = &priv->sensor[i];
u32 temp_idx = LAST_TEMP_0 + s->hw_id;
u32 valid_idx = VALID_0 + s->hw_id;
u32 last_temp = 0, valid, mask;
int ret;
ret = regmap_field_read(priv->rf[valid_idx], &valid);
if (ret)
return ret;
while (!valid) {
/* Valid bit is 0 for 6 AHB clock cycles.
* At 19.2MHz, 1 AHB clock is ~60ns.
* We should enter this loop very, very rarely.
*/
ndelay(400);
ret = regmap_field_read(priv->rf[valid_idx], &valid);
if (ret)
return ret;
}
/* Valid bit is set, OK to read the temperature */
ret = regmap_field_read(priv->rf[temp_idx], &last_temp);
if (ret)
return ret;
if (priv->feat->adc) {
/* Convert temperature from ADC code to milliCelsius */
*temp = code_to_degc(last_temp, s) * 1000;
} else {
mask = GENMASK(priv->fields[LAST_TEMP_0].msb,
priv->fields[LAST_TEMP_0].lsb);
/* Convert temperature from deciCelsius to milliCelsius */
*temp = sign_extend32(last_temp, fls(mask) - 1) * 100;
}
return 0;
}
int get_temp_common(struct tsens_priv *priv, int i, int *temp)
{ {
struct tsens_sensor *s = &tmdev->sensor[id]; struct tsens_sensor *s = &priv->sensor[i];
u32 code;
unsigned int status_reg;
int last_temp = 0, ret; int last_temp = 0, ret;
status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET; ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp);
ret = regmap_read(tmdev->tm_map, status_reg, &code);
if (ret) if (ret)
return ret; return ret;
last_temp = code & SN_ST_TEMP_MASK;
*temp = code_to_degc(last_temp, s) * 1000; *temp = code_to_degc(last_temp, s) * 1000;
...@@ -127,21 +165,21 @@ static const struct regmap_config tsens_srot_config = { ...@@ -127,21 +165,21 @@ static const struct regmap_config tsens_srot_config = {
.reg_stride = 4, .reg_stride = 4,
}; };
int __init init_common(struct tsens_device *tmdev) int __init init_common(struct tsens_priv *priv)
{ {
void __iomem *tm_base, *srot_base; void __iomem *tm_base, *srot_base;
struct device *dev = priv->dev;
struct resource *res; struct resource *res;
u32 code; u32 enabled;
int ret; int ret, i, j;
struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node); struct platform_device *op = of_find_device_by_node(priv->dev->of_node);
u16 ctrl_offset = tmdev->reg_offsets[SROT_CTRL_OFFSET];
if (!op) if (!op)
return -EINVAL; return -EINVAL;
if (op->num_resources > 1) { if (op->num_resources > 1) {
/* DT with separate SROT and TM address space */ /* DT with separate SROT and TM address space */
tmdev->tm_offset = 0; priv->tm_offset = 0;
res = platform_get_resource(op, IORESOURCE_MEM, 1); res = platform_get_resource(op, IORESOURCE_MEM, 1);
srot_base = devm_ioremap_resource(&op->dev, res); srot_base = devm_ioremap_resource(&op->dev, res);
if (IS_ERR(srot_base)) { if (IS_ERR(srot_base)) {
...@@ -149,16 +187,15 @@ int __init init_common(struct tsens_device *tmdev) ...@@ -149,16 +187,15 @@ int __init init_common(struct tsens_device *tmdev)
goto err_put_device; goto err_put_device;
} }
tmdev->srot_map = devm_regmap_init_mmio(tmdev->dev, srot_base, priv->srot_map = devm_regmap_init_mmio(dev, srot_base,
&tsens_srot_config); &tsens_srot_config);
if (IS_ERR(tmdev->srot_map)) { if (IS_ERR(priv->srot_map)) {
ret = PTR_ERR(tmdev->srot_map); ret = PTR_ERR(priv->srot_map);
goto err_put_device; goto err_put_device;
} }
} else { } else {
/* old DTs where SROT and TM were in a contiguous 2K block */ /* old DTs where SROT and TM were in a contiguous 2K block */
tmdev->tm_offset = 0x1000; priv->tm_offset = 0x1000;
} }
res = platform_get_resource(op, IORESOURCE_MEM, 0); res = platform_get_resource(op, IORESOURCE_MEM, 0);
...@@ -168,21 +205,49 @@ int __init init_common(struct tsens_device *tmdev) ...@@ -168,21 +205,49 @@ int __init init_common(struct tsens_device *tmdev)
goto err_put_device; goto err_put_device;
} }
tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config); priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
if (IS_ERR(tmdev->tm_map)) { if (IS_ERR(priv->tm_map)) {
ret = PTR_ERR(tmdev->tm_map); ret = PTR_ERR(priv->tm_map);
goto err_put_device; goto err_put_device;
} }
if (tmdev->srot_map) { priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
ret = regmap_read(tmdev->srot_map, ctrl_offset, &code); priv->fields[TSENS_EN]);
if (IS_ERR(priv->rf[TSENS_EN])) {
ret = PTR_ERR(priv->rf[TSENS_EN]);
goto err_put_device;
}
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
if (ret) if (ret)
goto err_put_device; goto err_put_device;
if (!(code & TSENS_EN)) { if (!enabled) {
dev_err(tmdev->dev, "tsens device is not enabled\n"); dev_err(dev, "tsens device is not enabled\n");
ret = -ENODEV; ret = -ENODEV;
goto err_put_device; goto err_put_device;
} }
priv->rf[SENSOR_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
priv->fields[SENSOR_EN]);
if (IS_ERR(priv->rf[SENSOR_EN])) {
ret = PTR_ERR(priv->rf[SENSOR_EN]);
goto err_put_device;
}
/* now alloc regmap_fields in tm_map */
for (i = 0, j = LAST_TEMP_0; i < priv->feat->max_sensors; i++, j++) {
priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
priv->fields[j]);
if (IS_ERR(priv->rf[j])) {
ret = PTR_ERR(priv->rf[j]);
goto err_put_device;
}
}
for (i = 0, j = VALID_0; i < priv->feat->max_sensors; i++, j++) {
priv->rf[j] = devm_regmap_field_alloc(dev, priv->tm_map,
priv->fields[j]);
if (IS_ERR(priv->rf[j])) {
ret = PTR_ERR(priv->rf[j]);
goto err_put_device;
}
} }
return 0; return 0;
......
...@@ -6,6 +6,48 @@ ...@@ -6,6 +6,48 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include "tsens.h" #include "tsens.h"
/* ----- SROT ------ */
#define SROT_CTRL_OFF 0x0000
/* ----- TM ------ */
#define TM_INT_EN_OFF 0x0000
#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF 0x0004
#define TM_Sn_STATUS_OFF 0x0030
#define TM_TRDY_OFF 0x005c
/* eeprom layout data for 8916 */
#define MSM8916_BASE0_MASK 0x0000007f
#define MSM8916_BASE1_MASK 0xfe000000
#define MSM8916_BASE0_SHIFT 0
#define MSM8916_BASE1_SHIFT 25
#define MSM8916_S0_P1_MASK 0x00000f80
#define MSM8916_S1_P1_MASK 0x003e0000
#define MSM8916_S2_P1_MASK 0xf8000000
#define MSM8916_S3_P1_MASK 0x000003e0
#define MSM8916_S4_P1_MASK 0x000f8000
#define MSM8916_S0_P2_MASK 0x0001f000
#define MSM8916_S1_P2_MASK 0x07c00000
#define MSM8916_S2_P2_MASK 0x0000001f
#define MSM8916_S3_P2_MASK 0x00007c00
#define MSM8916_S4_P2_MASK 0x01f00000
#define MSM8916_S0_P1_SHIFT 7
#define MSM8916_S1_P1_SHIFT 17
#define MSM8916_S2_P1_SHIFT 27
#define MSM8916_S3_P1_SHIFT 5
#define MSM8916_S4_P1_SHIFT 15
#define MSM8916_S0_P2_SHIFT 12
#define MSM8916_S1_P2_SHIFT 22
#define MSM8916_S2_P2_SHIFT 0
#define MSM8916_S3_P2_SHIFT 10
#define MSM8916_S4_P2_SHIFT 20
#define MSM8916_CAL_SEL_MASK 0xe0000000
#define MSM8916_CAL_SEL_SHIFT 29
/* eeprom layout data for 8974 */ /* eeprom layout data for 8974 */
#define BASE1_MASK 0xff #define BASE1_MASK 0xff
#define S0_P1_MASK 0x3f00 #define S0_P1_MASK 0x3f00
...@@ -91,7 +133,59 @@ ...@@ -91,7 +133,59 @@
#define BIT_APPEND 0x3 #define BIT_APPEND 0x3
static int calibrate_8974(struct tsens_device *tmdev) static int calibrate_8916(struct tsens_priv *priv)
{
int base0 = 0, base1 = 0, i;
u32 p1[5], p2[5];
int mode = 0;
u32 *qfprom_cdata, *qfprom_csel;
qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
if (IS_ERR(qfprom_cdata))
return PTR_ERR(qfprom_cdata);
qfprom_csel = (u32 *)qfprom_read(priv->dev, "calib_sel");
if (IS_ERR(qfprom_csel))
return PTR_ERR(qfprom_csel);
mode = (qfprom_csel[0] & MSM8916_CAL_SEL_MASK) >> MSM8916_CAL_SEL_SHIFT;
dev_dbg(priv->dev, "calibration mode is %d\n", mode);
switch (mode) {
case TWO_PT_CALIB:
base1 = (qfprom_cdata[1] & MSM8916_BASE1_MASK) >> MSM8916_BASE1_SHIFT;
p2[0] = (qfprom_cdata[0] & MSM8916_S0_P2_MASK) >> MSM8916_S0_P2_SHIFT;
p2[1] = (qfprom_cdata[0] & MSM8916_S1_P2_MASK) >> MSM8916_S1_P2_SHIFT;
p2[2] = (qfprom_cdata[1] & MSM8916_S2_P2_MASK) >> MSM8916_S2_P2_SHIFT;
p2[3] = (qfprom_cdata[1] & MSM8916_S3_P2_MASK) >> MSM8916_S3_P2_SHIFT;
p2[4] = (qfprom_cdata[1] & MSM8916_S4_P2_MASK) >> MSM8916_S4_P2_SHIFT;
for (i = 0; i < priv->num_sensors; i++)
p2[i] = ((base1 + p2[i]) << 3);
/* Fall through */
case ONE_PT_CALIB2:
base0 = (qfprom_cdata[0] & MSM8916_BASE0_MASK);
p1[0] = (qfprom_cdata[0] & MSM8916_S0_P1_MASK) >> MSM8916_S0_P1_SHIFT;
p1[1] = (qfprom_cdata[0] & MSM8916_S1_P1_MASK) >> MSM8916_S1_P1_SHIFT;
p1[2] = (qfprom_cdata[0] & MSM8916_S2_P1_MASK) >> MSM8916_S2_P1_SHIFT;
p1[3] = (qfprom_cdata[1] & MSM8916_S3_P1_MASK) >> MSM8916_S3_P1_SHIFT;
p1[4] = (qfprom_cdata[1] & MSM8916_S4_P1_MASK) >> MSM8916_S4_P1_SHIFT;
for (i = 0; i < priv->num_sensors; i++)
p1[i] = (((base0) + p1[i]) << 3);
break;
default:
for (i = 0; i < priv->num_sensors; i++) {
p1[i] = 500;
p2[i] = 780;
}
break;
}
compute_intercept_slope(priv, p1, p2, mode);
return 0;
}
static int calibrate_8974(struct tsens_priv *priv)
{ {
int base1 = 0, base2 = 0, i; int base1 = 0, base2 = 0, i;
u32 p1[11], p2[11]; u32 p1[11], p2[11];
...@@ -99,11 +193,11 @@ static int calibrate_8974(struct tsens_device *tmdev) ...@@ -99,11 +193,11 @@ static int calibrate_8974(struct tsens_device *tmdev)
u32 *calib, *bkp; u32 *calib, *bkp;
u32 calib_redun_sel; u32 calib_redun_sel;
calib = (u32 *)qfprom_read(tmdev->dev, "calib"); calib = (u32 *)qfprom_read(priv->dev, "calib");
if (IS_ERR(calib)) if (IS_ERR(calib))
return PTR_ERR(calib); return PTR_ERR(calib);
bkp = (u32 *)qfprom_read(tmdev->dev, "calib_backup"); bkp = (u32 *)qfprom_read(priv->dev, "calib_backup");
if (IS_ERR(bkp)) if (IS_ERR(bkp))
return PTR_ERR(bkp); return PTR_ERR(bkp);
...@@ -184,25 +278,25 @@ static int calibrate_8974(struct tsens_device *tmdev) ...@@ -184,25 +278,25 @@ static int calibrate_8974(struct tsens_device *tmdev)
switch (mode) { switch (mode) {
case ONE_PT_CALIB: case ONE_PT_CALIB:
for (i = 0; i < tmdev->num_sensors; i++) for (i = 0; i < priv->num_sensors; i++)
p1[i] += (base1 << 2) | BIT_APPEND; p1[i] += (base1 << 2) | BIT_APPEND;
break; break;
case TWO_PT_CALIB: case TWO_PT_CALIB:
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < priv->num_sensors; i++) {
p2[i] += base2; p2[i] += base2;
p2[i] <<= 2; p2[i] <<= 2;
p2[i] |= BIT_APPEND; p2[i] |= BIT_APPEND;
} }
/* Fall through */ /* Fall through */
case ONE_PT_CALIB2: case ONE_PT_CALIB2:
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < priv->num_sensors; i++) {
p1[i] += base1; p1[i] += base1;
p1[i] <<= 2; p1[i] <<= 2;
p1[i] |= BIT_APPEND; p1[i] |= BIT_APPEND;
} }
break; break;
default: default:
for (i = 0; i < tmdev->num_sensors; i++) for (i = 0; i < priv->num_sensors; i++)
p2[i] = 780; p2[i] = 780;
p1[0] = 502; p1[0] = 502;
p1[1] = 509; p1[1] = 509;
...@@ -218,19 +312,71 @@ static int calibrate_8974(struct tsens_device *tmdev) ...@@ -218,19 +312,71 @@ static int calibrate_8974(struct tsens_device *tmdev)
break; break;
} }
compute_intercept_slope(tmdev, p1, p2, mode); compute_intercept_slope(priv, p1, p2, mode);
return 0; return 0;
} }
/* v0.1: 8916, 8974 */
static const struct tsens_features tsens_v0_1_feat = {
.ver_major = VER_0_1,
.crit_int = 0,
.adc = 1,
.srot_split = 1,
.max_sensors = 11,
};
static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
/* ----- SROT ------ */
/* No VERSION information */
/* CTRL_OFFSET */
[TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0),
[TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1),
[SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 13),
/* ----- TM ------ */
/* INTERRUPT ENABLE */
[INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0),
/* Sn_STATUS */
REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 9),
/* No VALID field on v0.1 */
REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS, TM_Sn_STATUS_OFF, 10, 10),
REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11),
REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12),
/* No CRITICAL field on v0.1 */
REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS, TM_Sn_STATUS_OFF, 13, 13),
/* TRDY: 1=ready, 0=in progress */
[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
};
static const struct tsens_ops ops_8916 = {
.init = init_common,
.calibrate = calibrate_8916,
.get_temp = get_temp_common,
};
const struct tsens_plat_data data_8916 = {
.num_sensors = 5,
.ops = &ops_8916,
.hw_ids = (unsigned int []){0, 1, 2, 4, 5 },
.feat = &tsens_v0_1_feat,
.fields = tsens_v0_1_regfields,
};
static const struct tsens_ops ops_8974 = { static const struct tsens_ops ops_8974 = {
.init = init_common, .init = init_common,
.calibrate = calibrate_8974, .calibrate = calibrate_8974,
.get_temp = get_temp_common, .get_temp = get_temp_common,
}; };
const struct tsens_data data_8974 = { const struct tsens_plat_data data_8974 = {
.num_sensors = 11, .num_sensors = 11,
.ops = &ops_8974, .ops = &ops_8974,
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 }, .feat = &tsens_v0_1_feat,
.fields = tsens_v0_1_regfields,
}; };
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019, Linaro Limited
*/
#include <linux/bitops.h>
#include <linux/regmap.h>
#include <linux/delay.h>
#include "tsens.h"
/* ----- SROT ------ */
#define SROT_HW_VER_OFF 0x0000
#define SROT_CTRL_OFF 0x0004
/* ----- TM ------ */
#define TM_INT_EN_OFF 0x0000
#define TM_Sn_UPPER_LOWER_STATUS_CTRL_OFF 0x0004
#define TM_Sn_STATUS_OFF 0x0044
#define TM_TRDY_OFF 0x0084
/* eeprom layout data for qcs404/405 (v1) */
#define BASE0_MASK 0x000007f8
#define BASE1_MASK 0x0007f800
#define BASE0_SHIFT 3
#define BASE1_SHIFT 11
#define S0_P1_MASK 0x0000003f
#define S1_P1_MASK 0x0003f000
#define S2_P1_MASK 0x3f000000
#define S3_P1_MASK 0x000003f0
#define S4_P1_MASK 0x003f0000
#define S5_P1_MASK 0x0000003f
#define S6_P1_MASK 0x0003f000
#define S7_P1_MASK 0x3f000000
#define S8_P1_MASK 0x000003f0
#define S9_P1_MASK 0x003f0000
#define S0_P2_MASK 0x00000fc0
#define S1_P2_MASK 0x00fc0000
#define S2_P2_MASK_1_0 0xc0000000
#define S2_P2_MASK_5_2 0x0000000f
#define S3_P2_MASK 0x0000fc00
#define S4_P2_MASK 0x0fc00000
#define S5_P2_MASK 0x00000fc0
#define S6_P2_MASK 0x00fc0000
#define S7_P2_MASK_1_0 0xc0000000
#define S7_P2_MASK_5_2 0x0000000f
#define S8_P2_MASK 0x0000fc00
#define S9_P2_MASK 0x0fc00000
#define S0_P1_SHIFT 0
#define S0_P2_SHIFT 6
#define S1_P1_SHIFT 12
#define S1_P2_SHIFT 18
#define S2_P1_SHIFT 24
#define S2_P2_SHIFT_1_0 30
#define S2_P2_SHIFT_5_2 0
#define S3_P1_SHIFT 4
#define S3_P2_SHIFT 10
#define S4_P1_SHIFT 16
#define S4_P2_SHIFT 22
#define S5_P1_SHIFT 0
#define S5_P2_SHIFT 6
#define S6_P1_SHIFT 12
#define S6_P2_SHIFT 18
#define S7_P1_SHIFT 24
#define S7_P2_SHIFT_1_0 30
#define S7_P2_SHIFT_5_2 0
#define S8_P1_SHIFT 4
#define S8_P2_SHIFT 10
#define S9_P1_SHIFT 16
#define S9_P2_SHIFT 22
#define CAL_SEL_MASK 7
#define CAL_SEL_SHIFT 0
static int calibrate_v1(struct tsens_priv *priv)
{
u32 base0 = 0, base1 = 0;
u32 p1[10], p2[10];
u32 mode = 0, lsb = 0, msb = 0;
u32 *qfprom_cdata;
int i;
qfprom_cdata = (u32 *)qfprom_read(priv->dev, "calib");
if (IS_ERR(qfprom_cdata))
return PTR_ERR(qfprom_cdata);
mode = (qfprom_cdata[4] & CAL_SEL_MASK) >> CAL_SEL_SHIFT;
dev_dbg(priv->dev, "calibration mode is %d\n", mode);
switch (mode) {
case TWO_PT_CALIB:
base1 = (qfprom_cdata[4] & BASE1_MASK) >> BASE1_SHIFT;
p2[0] = (qfprom_cdata[0] & S0_P2_MASK) >> S0_P2_SHIFT;
p2[1] = (qfprom_cdata[0] & S1_P2_MASK) >> S1_P2_SHIFT;
/* This value is split over two registers, 2 bits and 4 bits */
lsb = (qfprom_cdata[0] & S2_P2_MASK_1_0) >> S2_P2_SHIFT_1_0;
msb = (qfprom_cdata[1] & S2_P2_MASK_5_2) >> S2_P2_SHIFT_5_2;
p2[2] = msb << 2 | lsb;
p2[3] = (qfprom_cdata[1] & S3_P2_MASK) >> S3_P2_SHIFT;
p2[4] = (qfprom_cdata[1] & S4_P2_MASK) >> S4_P2_SHIFT;
p2[5] = (qfprom_cdata[2] & S5_P2_MASK) >> S5_P2_SHIFT;
p2[6] = (qfprom_cdata[2] & S6_P2_MASK) >> S6_P2_SHIFT;
/* This value is split over two registers, 2 bits and 4 bits */
lsb = (qfprom_cdata[2] & S7_P2_MASK_1_0) >> S7_P2_SHIFT_1_0;
msb = (qfprom_cdata[3] & S7_P2_MASK_5_2) >> S7_P2_SHIFT_5_2;
p2[7] = msb << 2 | lsb;
p2[8] = (qfprom_cdata[3] & S8_P2_MASK) >> S8_P2_SHIFT;
p2[9] = (qfprom_cdata[3] & S9_P2_MASK) >> S9_P2_SHIFT;
for (i = 0; i < priv->num_sensors; i++)
p2[i] = ((base1 + p2[i]) << 2);
/* Fall through */
case ONE_PT_CALIB2:
base0 = (qfprom_cdata[4] & BASE0_MASK) >> BASE0_SHIFT;
p1[0] = (qfprom_cdata[0] & S0_P1_MASK) >> S0_P1_SHIFT;
p1[1] = (qfprom_cdata[0] & S1_P1_MASK) >> S1_P1_SHIFT;
p1[2] = (qfprom_cdata[0] & S2_P1_MASK) >> S2_P1_SHIFT;
p1[3] = (qfprom_cdata[1] & S3_P1_MASK) >> S3_P1_SHIFT;
p1[4] = (qfprom_cdata[1] & S4_P1_MASK) >> S4_P1_SHIFT;
p1[5] = (qfprom_cdata[2] & S5_P1_MASK) >> S5_P1_SHIFT;
p1[6] = (qfprom_cdata[2] & S6_P1_MASK) >> S6_P1_SHIFT;
p1[7] = (qfprom_cdata[2] & S7_P1_MASK) >> S7_P1_SHIFT;
p1[8] = (qfprom_cdata[3] & S8_P1_MASK) >> S8_P1_SHIFT;
p1[9] = (qfprom_cdata[3] & S9_P1_MASK) >> S9_P1_SHIFT;
for (i = 0; i < priv->num_sensors; i++)
p1[i] = (((base0) + p1[i]) << 2);
break;
default:
for (i = 0; i < priv->num_sensors; i++) {
p1[i] = 500;
p2[i] = 780;
}
break;
}
compute_intercept_slope(priv, p1, p2, mode);
return 0;
}
/* v1.x: qcs404,405 */
static const struct tsens_features tsens_v1_feat = {
.ver_major = VER_1_X,
.crit_int = 0,
.adc = 1,
.srot_split = 1,
.max_sensors = 11,
};
static const struct reg_field tsens_v1_regfields[MAX_REGFIELDS] = {
/* ----- SROT ------ */
/* VERSION */
[VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31),
[VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27),
[VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15),
/* CTRL_OFFSET */
[TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0),
[TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1),
[SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 13),
/* ----- TM ------ */
/* INTERRUPT ENABLE */
[INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 0),
/* Sn_STATUS */
REG_FIELD_FOR_EACH_SENSOR11(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 9),
REG_FIELD_FOR_EACH_SENSOR11(VALID, TM_Sn_STATUS_OFF, 14, 14),
REG_FIELD_FOR_EACH_SENSOR11(MIN_STATUS, TM_Sn_STATUS_OFF, 10, 10),
REG_FIELD_FOR_EACH_SENSOR11(LOWER_STATUS, TM_Sn_STATUS_OFF, 11, 11),
REG_FIELD_FOR_EACH_SENSOR11(UPPER_STATUS, TM_Sn_STATUS_OFF, 12, 12),
/* No CRITICAL field on v1.x */
REG_FIELD_FOR_EACH_SENSOR11(MAX_STATUS, TM_Sn_STATUS_OFF, 13, 13),
/* TRDY: 1=ready, 0=in progress */
[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
};
static const struct tsens_ops ops_generic_v1 = {
.init = init_common,
.calibrate = calibrate_v1,
.get_temp = get_temp_tsens_valid,
};
const struct tsens_plat_data data_tsens_v1 = {
.ops = &ops_generic_v1,
.feat = &tsens_v1_feat,
.fields = tsens_v1_regfields,
};
...@@ -4,76 +4,81 @@ ...@@ -4,76 +4,81 @@
* Copyright (c) 2018, Linaro Limited * Copyright (c) 2018, Linaro Limited
*/ */
#include <linux/regmap.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/regmap.h>
#include "tsens.h" #include "tsens.h"
#define STATUS_OFFSET 0xa0 /* ----- SROT ------ */
#define LAST_TEMP_MASK 0xfff #define SROT_HW_VER_OFF 0x0000
#define STATUS_VALID_BIT BIT(21) #define SROT_CTRL_OFF 0x0004
static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp) /* ----- TM ------ */
{ #define TM_INT_EN_OFF 0x0004
struct tsens_sensor *s = &tmdev->sensor[id]; #define TM_UPPER_LOWER_INT_STATUS_OFF 0x0008
u32 code; #define TM_UPPER_LOWER_INT_CLEAR_OFF 0x000c
unsigned int status_reg; #define TM_UPPER_LOWER_INT_MASK_OFF 0x0010
u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0; #define TM_CRITICAL_INT_STATUS_OFF 0x0014
int ret; #define TM_CRITICAL_INT_CLEAR_OFF 0x0018
#define TM_CRITICAL_INT_MASK_OFF 0x001c
#define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020
#define TM_Sn_CRITICAL_THRESHOLD_OFF 0x0060
#define TM_Sn_STATUS_OFF 0x00a0
#define TM_TRDY_OFF 0x00e4
status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * 4; /* v2.x: 8996, 8998, sdm845 */
ret = regmap_read(tmdev->tm_map, status_reg, &code);
if (ret)
return ret;
last_temp = code & LAST_TEMP_MASK;
if (code & STATUS_VALID_BIT)
goto done;
/* Try a second time */ static const struct tsens_features tsens_v2_feat = {
ret = regmap_read(tmdev->tm_map, status_reg, &code); .ver_major = VER_2_X,
if (ret) .crit_int = 1,
return ret; .adc = 0,
if (code & STATUS_VALID_BIT) { .srot_split = 1,
last_temp = code & LAST_TEMP_MASK; .max_sensors = 16,
goto done; };
} else {
last_temp2 = code & LAST_TEMP_MASK;
}
/* Try a third/last time */ static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
ret = regmap_read(tmdev->tm_map, status_reg, &code); /* ----- SROT ------ */
if (ret) /* VERSION */
return ret; [VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31),
if (code & STATUS_VALID_BIT) { [VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27),
last_temp = code & LAST_TEMP_MASK; [VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15),
goto done; /* CTRL_OFF */
} else { [TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0),
last_temp3 = code & LAST_TEMP_MASK; [TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1),
} [SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 18),
if (last_temp == last_temp2) /* ----- TM ------ */
last_temp = last_temp2; /* INTERRUPT ENABLE */
else if (last_temp2 == last_temp3) /* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */
last_temp = last_temp3; [INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 2),
done:
/* Convert temperature from deciCelsius to milliCelsius */
*temp = sign_extend32(last_temp, fls(LAST_TEMP_MASK) - 1) * 100;
return 0; /* Sn_STATUS */
} REG_FIELD_FOR_EACH_SENSOR16(LAST_TEMP, TM_Sn_STATUS_OFF, 0, 11),
REG_FIELD_FOR_EACH_SENSOR16(VALID, TM_Sn_STATUS_OFF, 21, 21),
REG_FIELD_FOR_EACH_SENSOR16(MIN_STATUS, TM_Sn_STATUS_OFF, 16, 16),
REG_FIELD_FOR_EACH_SENSOR16(LOWER_STATUS, TM_Sn_STATUS_OFF, 17, 17),
REG_FIELD_FOR_EACH_SENSOR16(UPPER_STATUS, TM_Sn_STATUS_OFF, 18, 18),
REG_FIELD_FOR_EACH_SENSOR16(CRITICAL_STATUS, TM_Sn_STATUS_OFF, 19, 19),
REG_FIELD_FOR_EACH_SENSOR16(MAX_STATUS, TM_Sn_STATUS_OFF, 20, 20),
/* TRDY: 1=ready, 0=in progress */
[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
};
static const struct tsens_ops ops_generic_v2 = { static const struct tsens_ops ops_generic_v2 = {
.init = init_common, .init = init_common,
.get_temp = get_temp_tsens_v2, .get_temp = get_temp_tsens_valid,
}; };
const struct tsens_data data_tsens_v2 = { const struct tsens_plat_data data_tsens_v2 = {
.ops = &ops_generic_v2, .ops = &ops_generic_v2,
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 }, .feat = &tsens_v2_feat,
.fields = tsens_v2_regfields,
}; };
/* Kept around for backward compatibility with old msm8996.dtsi */ /* Kept around for backward compatibility with old msm8996.dtsi */
const struct tsens_data data_8996 = { const struct tsens_plat_data data_8996 = {
.num_sensors = 13, .num_sensors = 13,
.ops = &ops_generic_v2, .ops = &ops_generic_v2,
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 }, .feat = &tsens_v2_feat,
.fields = tsens_v2_regfields,
}; };
...@@ -15,38 +15,38 @@ ...@@ -15,38 +15,38 @@
static int tsens_get_temp(void *data, int *temp) static int tsens_get_temp(void *data, int *temp)
{ {
const struct tsens_sensor *s = data; const struct tsens_sensor *s = data;
struct tsens_device *tmdev = s->tmdev; struct tsens_priv *priv = s->priv;
return tmdev->ops->get_temp(tmdev, s->id, temp); return priv->ops->get_temp(priv, s->id, temp);
} }
static int tsens_get_trend(void *p, int trip, enum thermal_trend *trend) static int tsens_get_trend(void *data, int trip, enum thermal_trend *trend)
{ {
const struct tsens_sensor *s = p; const struct tsens_sensor *s = data;
struct tsens_device *tmdev = s->tmdev; struct tsens_priv *priv = s->priv;
if (tmdev->ops->get_trend) if (priv->ops->get_trend)
return tmdev->ops->get_trend(tmdev, s->id, trend); return priv->ops->get_trend(priv, s->id, trend);
return -ENOTSUPP; return -ENOTSUPP;
} }
static int __maybe_unused tsens_suspend(struct device *dev) static int __maybe_unused tsens_suspend(struct device *dev)
{ {
struct tsens_device *tmdev = dev_get_drvdata(dev); struct tsens_priv *priv = dev_get_drvdata(dev);
if (tmdev->ops && tmdev->ops->suspend) if (priv->ops && priv->ops->suspend)
return tmdev->ops->suspend(tmdev); return priv->ops->suspend(priv);
return 0; return 0;
} }
static int __maybe_unused tsens_resume(struct device *dev) static int __maybe_unused tsens_resume(struct device *dev)
{ {
struct tsens_device *tmdev = dev_get_drvdata(dev); struct tsens_priv *priv = dev_get_drvdata(dev);
if (tmdev->ops && tmdev->ops->resume) if (priv->ops && priv->ops->resume)
return tmdev->ops->resume(tmdev); return priv->ops->resume(priv);
return 0; return 0;
} }
...@@ -63,6 +63,9 @@ static const struct of_device_id tsens_table[] = { ...@@ -63,6 +63,9 @@ static const struct of_device_id tsens_table[] = {
}, { }, {
.compatible = "qcom,msm8996-tsens", .compatible = "qcom,msm8996-tsens",
.data = &data_8996, .data = &data_8996,
}, {
.compatible = "qcom,tsens-v1",
.data = &data_tsens_v1,
}, { }, {
.compatible = "qcom,tsens-v2", .compatible = "qcom,tsens-v2",
.data = &data_tsens_v2, .data = &data_tsens_v2,
...@@ -76,22 +79,27 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = { ...@@ -76,22 +79,27 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
.get_trend = tsens_get_trend, .get_trend = tsens_get_trend,
}; };
static int tsens_register(struct tsens_device *tmdev) static int tsens_register(struct tsens_priv *priv)
{ {
int i; int i;
struct thermal_zone_device *tzd; struct thermal_zone_device *tzd;
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < priv->num_sensors; i++) {
tmdev->sensor[i].tmdev = tmdev; if (!is_sensor_enabled(priv, priv->sensor[i].hw_id)) {
tmdev->sensor[i].id = i; dev_err(priv->dev, "sensor %d: disabled\n",
tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i, priv->sensor[i].hw_id);
&tmdev->sensor[i], continue;
}
priv->sensor[i].priv = priv;
priv->sensor[i].id = i;
tzd = devm_thermal_zone_of_sensor_register(priv->dev, i,
&priv->sensor[i],
&tsens_of_ops); &tsens_of_ops);
if (IS_ERR(tzd)) if (IS_ERR(tzd))
continue; continue;
tmdev->sensor[i].tzd = tzd; priv->sensor[i].tzd = tzd;
if (tmdev->ops->enable) if (priv->ops->enable)
tmdev->ops->enable(tmdev, i); priv->ops->enable(priv, i);
} }
return 0; return 0;
} }
...@@ -101,8 +109,8 @@ static int tsens_probe(struct platform_device *pdev) ...@@ -101,8 +109,8 @@ static int tsens_probe(struct platform_device *pdev)
int ret, i; int ret, i;
struct device *dev; struct device *dev;
struct device_node *np; struct device_node *np;
struct tsens_device *tmdev; struct tsens_priv *priv;
const struct tsens_data *data; const struct tsens_plat_data *data;
const struct of_device_id *id; const struct of_device_id *id;
u32 num_sensors; u32 num_sensors;
...@@ -129,55 +137,55 @@ static int tsens_probe(struct platform_device *pdev) ...@@ -129,55 +137,55 @@ static int tsens_probe(struct platform_device *pdev)
return -EINVAL; return -EINVAL;
} }
tmdev = devm_kzalloc(dev, priv = devm_kzalloc(dev,
struct_size(tmdev, sensor, num_sensors), struct_size(priv, sensor, num_sensors),
GFP_KERNEL); GFP_KERNEL);
if (!tmdev) if (!priv)
return -ENOMEM; return -ENOMEM;
tmdev->dev = dev; priv->dev = dev;
tmdev->num_sensors = num_sensors; priv->num_sensors = num_sensors;
tmdev->ops = data->ops; priv->ops = data->ops;
for (i = 0; i < tmdev->num_sensors; i++) { for (i = 0; i < priv->num_sensors; i++) {
if (data->hw_ids) if (data->hw_ids)
tmdev->sensor[i].hw_id = data->hw_ids[i]; priv->sensor[i].hw_id = data->hw_ids[i];
else else
tmdev->sensor[i].hw_id = i; priv->sensor[i].hw_id = i;
}
for (i = 0; i < REG_ARRAY_SIZE; i++) {
tmdev->reg_offsets[i] = data->reg_offsets[i];
} }
priv->feat = data->feat;
priv->fields = data->fields;
if (!tmdev->ops || !tmdev->ops->init || !tmdev->ops->get_temp) if (!priv->ops || !priv->ops->init || !priv->ops->get_temp)
return -EINVAL; return -EINVAL;
ret = tmdev->ops->init(tmdev); ret = priv->ops->init(priv);
if (ret < 0) { if (ret < 0) {
dev_err(dev, "tsens init failed\n"); dev_err(dev, "tsens init failed\n");
return ret; return ret;
} }
if (tmdev->ops->calibrate) { if (priv->ops->calibrate) {
ret = tmdev->ops->calibrate(tmdev); ret = priv->ops->calibrate(priv);
if (ret < 0) { if (ret < 0) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "tsens calibration failed\n"); dev_err(dev, "tsens calibration failed\n");
return ret; return ret;
} }
} }
ret = tsens_register(tmdev); ret = tsens_register(priv);
platform_set_drvdata(pdev, tmdev); platform_set_drvdata(pdev, priv);
return ret; return ret;
} }
static int tsens_remove(struct platform_device *pdev) static int tsens_remove(struct platform_device *pdev)
{ {
struct tsens_device *tmdev = platform_get_drvdata(pdev); struct tsens_priv *priv = platform_get_drvdata(pdev);
if (tmdev->ops->disable) if (priv->ops->disable)
tmdev->ops->disable(tmdev); priv->ops->disable(priv);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -193,11 +193,6 @@ static int qoriq_tmu_probe(struct platform_device *pdev) ...@@ -193,11 +193,6 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
struct qoriq_tmu_data *data; struct qoriq_tmu_data *data;
struct device_node *np = pdev->dev.of_node; struct device_node *np = pdev->dev.of_node;
if (!np) {
dev_err(&pdev->dev, "Device OF-Node is NULL");
return -ENODEV;
}
data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data), data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
GFP_KERNEL); GFP_KERNEL);
if (!data) if (!data)
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/spinlock.h>
#include <linux/sys_soc.h> #include <linux/sys_soc.h>
#include <linux/thermal.h> #include <linux/thermal.h>
...@@ -82,7 +81,6 @@ struct rcar_gen3_thermal_tsc { ...@@ -82,7 +81,6 @@ struct rcar_gen3_thermal_tsc {
struct rcar_gen3_thermal_priv { struct rcar_gen3_thermal_priv {
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM]; struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
unsigned int num_tscs; unsigned int num_tscs;
spinlock_t lock; /* Protect interrupts on and off */
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc); void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
}; };
...@@ -232,37 +230,15 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data) ...@@ -232,37 +230,15 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
{ {
struct rcar_gen3_thermal_priv *priv = data; struct rcar_gen3_thermal_priv *priv = data;
u32 status; u32 status;
int i, ret = IRQ_HANDLED; int i;
spin_lock(&priv->lock);
for (i = 0; i < priv->num_tscs; i++) { for (i = 0; i < priv->num_tscs; i++) {
status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR); status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0); rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
if (status) if (status)
ret = IRQ_WAKE_THREAD;
}
if (ret == IRQ_WAKE_THREAD)
rcar_thermal_irq_set(priv, false);
spin_unlock(&priv->lock);
return ret;
}
static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
{
struct rcar_gen3_thermal_priv *priv = data;
unsigned long flags;
int i;
for (i = 0; i < priv->num_tscs; i++)
thermal_zone_device_update(priv->tscs[i]->zone, thermal_zone_device_update(priv->tscs[i]->zone,
THERMAL_EVENT_UNSPECIFIED); THERMAL_EVENT_UNSPECIFIED);
}
spin_lock_irqsave(&priv->lock, flags);
rcar_thermal_irq_set(priv, true);
spin_unlock_irqrestore(&priv->lock, flags);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -307,7 +283,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc) ...@@ -307,7 +283,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
usleep_range(1000, 2000); usleep_range(1000, 2000);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2); rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
...@@ -331,6 +307,9 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids); ...@@ -331,6 +307,9 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
static int rcar_gen3_thermal_remove(struct platform_device *pdev) static int rcar_gen3_thermal_remove(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
rcar_thermal_irq_set(priv, false);
pm_runtime_put(dev); pm_runtime_put(dev);
pm_runtime_disable(dev); pm_runtime_disable(dev);
...@@ -371,8 +350,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ...@@ -371,8 +350,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
if (soc_device_match(r8a7795es1)) if (soc_device_match(r8a7795es1))
priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1; priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1;
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
/* /*
...@@ -390,9 +367,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ...@@ -390,9 +367,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
if (!irqname) if (!irqname)
return -ENOMEM; return -ENOMEM;
ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq, ret = devm_request_threaded_irq(dev, irq, NULL,
rcar_gen3_thermal_irq_thread, rcar_gen3_thermal_irq,
IRQF_SHARED, irqname, priv); IRQF_ONESHOT, irqname, priv);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -433,10 +410,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ...@@ -433,10 +410,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
} }
tsc->zone = zone; tsc->zone = zone;
ret = of_thermal_get_ntrips(tsc->zone);
if (ret < 0)
goto error_unregister;
tsc->zone->tzp->no_hwmon = false; tsc->zone->tzp->no_hwmon = false;
ret = thermal_add_hwmon_sysfs(tsc->zone); ret = thermal_add_hwmon_sysfs(tsc->zone);
if (ret) if (ret)
...@@ -448,6 +421,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev) ...@@ -448,6 +421,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
goto error_unregister; goto error_unregister;
} }
ret = of_thermal_get_ntrips(tsc->zone);
if (ret < 0)
goto error_unregister;
dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret); dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
} }
......
...@@ -52,6 +52,7 @@ struct rcar_thermal_chip { ...@@ -52,6 +52,7 @@ struct rcar_thermal_chip {
unsigned int irq_per_ch : 1; unsigned int irq_per_ch : 1;
unsigned int needs_suspend_resume : 1; unsigned int needs_suspend_resume : 1;
unsigned int nirqs; unsigned int nirqs;
unsigned int ctemp_bands;
}; };
static const struct rcar_thermal_chip rcar_thermal = { static const struct rcar_thermal_chip rcar_thermal = {
...@@ -60,6 +61,7 @@ static const struct rcar_thermal_chip rcar_thermal = { ...@@ -60,6 +61,7 @@ static const struct rcar_thermal_chip rcar_thermal = {
.irq_per_ch = 0, .irq_per_ch = 0,
.needs_suspend_resume = 0, .needs_suspend_resume = 0,
.nirqs = 1, .nirqs = 1,
.ctemp_bands = 1,
}; };
static const struct rcar_thermal_chip rcar_gen2_thermal = { static const struct rcar_thermal_chip rcar_gen2_thermal = {
...@@ -68,6 +70,7 @@ static const struct rcar_thermal_chip rcar_gen2_thermal = { ...@@ -68,6 +70,7 @@ static const struct rcar_thermal_chip rcar_gen2_thermal = {
.irq_per_ch = 0, .irq_per_ch = 0,
.needs_suspend_resume = 0, .needs_suspend_resume = 0,
.nirqs = 1, .nirqs = 1,
.ctemp_bands = 1,
}; };
static const struct rcar_thermal_chip rcar_gen3_thermal = { static const struct rcar_thermal_chip rcar_gen3_thermal = {
...@@ -80,6 +83,7 @@ static const struct rcar_thermal_chip rcar_gen3_thermal = { ...@@ -80,6 +83,7 @@ static const struct rcar_thermal_chip rcar_gen3_thermal = {
* interrupts to detect a temperature change, rise or fall. * interrupts to detect a temperature change, rise or fall.
*/ */
.nirqs = 2, .nirqs = 2,
.ctemp_bands = 2,
}; };
struct rcar_thermal_priv { struct rcar_thermal_priv {
...@@ -263,7 +267,12 @@ static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv, ...@@ -263,7 +267,12 @@ static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
return ret; return ret;
mutex_lock(&priv->lock); mutex_lock(&priv->lock);
if (priv->chip->ctemp_bands == 1)
tmp = MCELSIUS((priv->ctemp * 5) - 65); tmp = MCELSIUS((priv->ctemp * 5) - 65);
else if (priv->ctemp < 24)
tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
else
tmp = MCELSIUS((priv->ctemp * 5) - 60);
mutex_unlock(&priv->lock); mutex_unlock(&priv->lock);
if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) { if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) {
......
...@@ -172,6 +172,9 @@ struct rockchip_thermal_data { ...@@ -172,6 +172,9 @@ struct rockchip_thermal_data {
int tshut_temp; int tshut_temp;
enum tshut_mode tshut_mode; enum tshut_mode tshut_mode;
enum tshut_polarity tshut_polarity; enum tshut_polarity tshut_polarity;
struct pinctrl *pinctrl;
struct pinctrl_state *gpio_state;
struct pinctrl_state *otp_state;
}; };
/** /**
...@@ -222,11 +225,15 @@ struct rockchip_thermal_data { ...@@ -222,11 +225,15 @@ struct rockchip_thermal_data {
#define GRF_TSADC_TESTBIT_L 0x0e648 #define GRF_TSADC_TESTBIT_L 0x0e648
#define GRF_TSADC_TESTBIT_H 0x0e64c #define GRF_TSADC_TESTBIT_H 0x0e64c
#define PX30_GRF_SOC_CON2 0x0408
#define GRF_SARADC_TESTBIT_ON (0x10001 << 2) #define GRF_SARADC_TESTBIT_ON (0x10001 << 2)
#define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2) #define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
#define GRF_TSADC_VCM_EN_L (0x10001 << 7) #define GRF_TSADC_VCM_EN_L (0x10001 << 7)
#define GRF_TSADC_VCM_EN_H (0x10001 << 7) #define GRF_TSADC_VCM_EN_H (0x10001 << 7)
#define GRF_CON_TSADC_CH_INV (0x10001 << 1)
/** /**
* struct tsadc_table - code to temperature conversion table * struct tsadc_table - code to temperature conversion table
* @code: the value of adc channel * @code: the value of adc channel
...@@ -689,6 +696,13 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs, ...@@ -689,6 +696,13 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs,
regs + TSADCV2_AUTO_CON); regs + TSADCV2_AUTO_CON);
} }
static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs,
enum tshut_polarity tshut_polarity)
{
rk_tsadcv2_initialize(grf, regs, tshut_polarity);
regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV);
}
static void rk_tsadcv2_irq_ack(void __iomem *regs) static void rk_tsadcv2_irq_ack(void __iomem *regs)
{ {
u32 val; u32 val;
...@@ -818,6 +832,30 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs, ...@@ -818,6 +832,30 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
writel_relaxed(val, regs + TSADCV2_INT_EN); writel_relaxed(val, regs + TSADCV2_INT_EN);
} }
static const struct rockchip_tsadc_chip px30_tsadc_data = {
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
.chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
.chn_num = 2, /* 2 channels for tsadc */
.tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */
.tshut_temp = 95000,
.initialize = rk_tsadcv4_initialize,
.irq_ack = rk_tsadcv3_irq_ack,
.control = rk_tsadcv3_control,
.get_temp = rk_tsadcv2_get_temp,
.set_alarm_temp = rk_tsadcv2_alarm_temp,
.set_tshut_temp = rk_tsadcv2_tshut_temp,
.set_tshut_mode = rk_tsadcv2_tshut_mode,
.table = {
.id = rk3328_code_table,
.length = ARRAY_SIZE(rk3328_code_table),
.data_mask = TSADCV2_DATA_MASK,
.mode = ADC_INCREMENT,
},
};
static const struct rockchip_tsadc_chip rv1108_tsadc_data = { static const struct rockchip_tsadc_chip rv1108_tsadc_data = {
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */ .chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
.chn_num = 1, /* one channel for tsadc */ .chn_num = 1, /* one channel for tsadc */
...@@ -990,6 +1028,9 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = { ...@@ -990,6 +1028,9 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
}; };
static const struct of_device_id of_rockchip_thermal_match[] = { static const struct of_device_id of_rockchip_thermal_match[] = {
{ .compatible = "rockchip,px30-tsadc",
.data = (void *)&px30_tsadc_data,
},
{ {
.compatible = "rockchip,rv1108-tsadc", .compatible = "rockchip,rv1108-tsadc",
.data = (void *)&rv1108_tsadc_data, .data = (void *)&rv1108_tsadc_data,
...@@ -1242,6 +1283,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev) ...@@ -1242,6 +1283,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
return error; return error;
} }
thermal->chip->control(thermal->regs, false);
error = clk_prepare_enable(thermal->clk); error = clk_prepare_enable(thermal->clk);
if (error) { if (error) {
dev_err(&pdev->dev, "failed to enable converter clock: %d\n", dev_err(&pdev->dev, "failed to enable converter clock: %d\n",
...@@ -1267,6 +1310,30 @@ static int rockchip_thermal_probe(struct platform_device *pdev) ...@@ -1267,6 +1310,30 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
thermal->chip->initialize(thermal->grf, thermal->regs, thermal->chip->initialize(thermal->grf, thermal->regs,
thermal->tshut_polarity); thermal->tshut_polarity);
if (thermal->tshut_mode == TSHUT_MODE_GPIO) {
thermal->pinctrl = devm_pinctrl_get(&pdev->dev);
if (IS_ERR(thermal->pinctrl)) {
dev_err(&pdev->dev, "failed to find thermal pinctrl\n");
return PTR_ERR(thermal->pinctrl);
}
thermal->gpio_state = pinctrl_lookup_state(thermal->pinctrl,
"gpio");
if (IS_ERR_OR_NULL(thermal->gpio_state)) {
dev_err(&pdev->dev, "failed to find thermal gpio state\n");
return -EINVAL;
}
thermal->otp_state = pinctrl_lookup_state(thermal->pinctrl,
"otpout");
if (IS_ERR_OR_NULL(thermal->otp_state)) {
dev_err(&pdev->dev, "failed to find thermal otpout state\n");
return -EINVAL;
}
pinctrl_select_state(thermal->pinctrl, thermal->otp_state);
}
for (i = 0; i < thermal->chip->chn_num; i++) { for (i = 0; i < thermal->chip->chn_num; i++) {
error = rockchip_thermal_register_sensor(pdev, thermal, error = rockchip_thermal_register_sensor(pdev, thermal,
&thermal->sensors[i], &thermal->sensors[i],
...@@ -1337,8 +1404,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev) ...@@ -1337,8 +1404,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
clk_disable(thermal->pclk); clk_disable(thermal->pclk);
clk_disable(thermal->clk); clk_disable(thermal->clk);
if (thermal->tshut_mode == TSHUT_MODE_GPIO)
pinctrl_pm_select_sleep_state(dev); pinctrl_select_state(thermal->pinctrl, thermal->gpio_state);
return 0; return 0;
} }
...@@ -1383,7 +1450,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev) ...@@ -1383,7 +1450,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
for (i = 0; i < thermal->chip->chn_num; i++) for (i = 0; i < thermal->chip->chn_num; i++)
rockchip_thermal_toggle_sensor(&thermal->sensors[i], true); rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
pinctrl_pm_select_default_state(dev); if (thermal->tshut_mode == TSHUT_MODE_GPIO)
pinctrl_select_state(thermal->pinctrl, thermal->otp_state);
return 0; return 0;
} }
......
...@@ -570,8 +570,7 @@ static int stm_thermal_prepare(struct stm_thermal_sensor *sensor) ...@@ -570,8 +570,7 @@ static int stm_thermal_prepare(struct stm_thermal_sensor *sensor)
static int stm_thermal_suspend(struct device *dev) static int stm_thermal_suspend(struct device *dev)
{ {
int ret; int ret;
struct platform_device *pdev = to_platform_device(dev); struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
ret = stm_thermal_sensor_off(sensor); ret = stm_thermal_sensor_off(sensor);
if (ret) if (ret)
...@@ -585,8 +584,7 @@ static int stm_thermal_suspend(struct device *dev) ...@@ -585,8 +584,7 @@ static int stm_thermal_suspend(struct device *dev)
static int stm_thermal_resume(struct device *dev) static int stm_thermal_resume(struct device *dev)
{ {
int ret; int ret;
struct platform_device *pdev = to_platform_device(dev); struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
ret = stm_thermal_prepare(sensor); ret = stm_thermal_prepare(sensor);
if (ret) if (ret)
......
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
* *
...@@ -29,6 +30,14 @@ ...@@ -29,6 +30,14 @@
#define THERMCTL_THERMTRIP_CTL 0x80 #define THERMCTL_THERMTRIP_CTL 0x80
/* BITs are defined in device file */ /* BITs are defined in device file */
#define THERMCTL_INTR_ENABLE 0x88
#define THERMCTL_INTR_DISABLE 0x8c
#define TH_INTR_UP_DN_EN 0x3
#define THERM_IRQ_MEM_MASK (TH_INTR_UP_DN_EN << 24)
#define THERM_IRQ_GPU_MASK (TH_INTR_UP_DN_EN << 16)
#define THERM_IRQ_CPU_MASK (TH_INTR_UP_DN_EN << 8)
#define THERM_IRQ_TSENSE_MASK (TH_INTR_UP_DN_EN << 0)
#define SENSOR_PDIV 0x1c0 #define SENSOR_PDIV 0x1c0
#define SENSOR_PDIV_CPU_MASK (0xf << 12) #define SENSOR_PDIV_CPU_MASK (0xf << 12)
#define SENSOR_PDIV_GPU_MASK (0xf << 8) #define SENSOR_PDIV_GPU_MASK (0xf << 8)
...@@ -70,6 +79,7 @@ struct tegra_tsensor_group { ...@@ -70,6 +79,7 @@ struct tegra_tsensor_group {
u32 thermtrip_enable_mask; u32 thermtrip_enable_mask;
u32 thermtrip_any_en_mask; u32 thermtrip_any_en_mask;
u32 thermtrip_threshold_mask; u32 thermtrip_threshold_mask;
u32 thermctl_isr_mask;
u16 thermctl_lvl0_offset; u16 thermctl_lvl0_offset;
u32 thermctl_lvl0_up_thresh_mask; u32 thermctl_lvl0_up_thresh_mask;
u32 thermctl_lvl0_dn_thresh_mask; u32 thermctl_lvl0_dn_thresh_mask;
...@@ -92,6 +102,11 @@ struct tegra_tsensor { ...@@ -92,6 +102,11 @@ struct tegra_tsensor {
const struct tegra_tsensor_group *group; const struct tegra_tsensor_group *group;
}; };
struct tsensor_group_thermtrips {
u8 id;
u32 temp;
};
struct tegra_soctherm_fuse { struct tegra_soctherm_fuse {
u32 fuse_base_cp_mask, fuse_base_cp_shift; u32 fuse_base_cp_mask, fuse_base_cp_shift;
u32 fuse_base_ft_mask, fuse_base_ft_shift; u32 fuse_base_ft_mask, fuse_base_ft_shift;
...@@ -113,6 +128,7 @@ struct tegra_soctherm_soc { ...@@ -113,6 +128,7 @@ struct tegra_soctherm_soc {
const int thresh_grain; const int thresh_grain;
const unsigned int bptt; const unsigned int bptt;
const bool use_ccroc; const bool use_ccroc;
struct tsensor_group_thermtrips *thermtrips;
}; };
int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse, int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
...@@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = { ...@@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_CPU_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = { ...@@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_GPU_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = { ...@@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = { ...@@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK, .thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK,
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK, .thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_MEM_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
...@@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = { ...@@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_CPU_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = { ...@@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_GPU_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = { ...@@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = { ...@@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK, .thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK,
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK, .thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_MEM_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
......
// SPDX-License-Identifier: GPL-2.0
/* /*
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
* *
* This software is licensed under the terms of the GNU General Public * This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and * License version 2, as published by the Free Software Foundation, and
...@@ -56,6 +57,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = { ...@@ -56,6 +57,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_CPU_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -74,6 +76,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = { ...@@ -74,6 +76,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_GPU_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -90,6 +93,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = { ...@@ -90,6 +93,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -108,6 +112,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = { ...@@ -108,6 +112,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK, .thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
.thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK, .thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK,
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK, .thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
.thermctl_isr_mask = THERM_IRQ_MEM_MASK,
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM, .thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK, .thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK, .thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
...@@ -203,6 +208,13 @@ static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = { ...@@ -203,6 +208,13 @@ static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = {
.fuse_spare_realignment = 0, .fuse_spare_realignment = 0,
}; };
struct tsensor_group_thermtrips tegra210_tsensor_thermtrips[] = {
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
};
const struct tegra_soctherm_soc tegra210_soctherm = { const struct tegra_soctherm_soc tegra210_soctherm = {
.tsensors = tegra210_tsensors, .tsensors = tegra210_tsensors,
.num_tsensors = ARRAY_SIZE(tegra210_tsensors), .num_tsensors = ARRAY_SIZE(tegra210_tsensors),
...@@ -212,4 +224,5 @@ const struct tegra_soctherm_soc tegra210_soctherm = { ...@@ -212,4 +224,5 @@ const struct tegra_soctherm_soc tegra210_soctherm = {
.thresh_grain = TEGRA210_THRESH_GRAIN, .thresh_grain = TEGRA210_THRESH_GRAIN,
.bptt = TEGRA210_BPTT, .bptt = TEGRA210_BPTT,
.use_ccroc = false, .use_ccroc = false,
.thermtrips = tegra210_tsensor_thermtrips,
}; };
...@@ -29,6 +29,9 @@ static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val) ...@@ -29,6 +29,9 @@ static int gadc_thermal_adc_to_temp(struct gadc_thermal_info *gti, int val)
int temp, temp_hi, temp_lo, adc_hi, adc_lo; int temp, temp_hi, temp_lo, adc_hi, adc_lo;
int i; int i;
if (!gti->lookup_table)
return val;
for (i = 0; i < gti->nlookup_table; i++) { for (i = 0; i < gti->nlookup_table; i++) {
if (val >= gti->lookup_table[2 * i + 1]) if (val >= gti->lookup_table[2 * i + 1])
break; break;
...@@ -81,9 +84,9 @@ static int gadc_thermal_read_linear_lookup_table(struct device *dev, ...@@ -81,9 +84,9 @@ static int gadc_thermal_read_linear_lookup_table(struct device *dev,
ntable = of_property_count_elems_of_size(np, "temperature-lookup-table", ntable = of_property_count_elems_of_size(np, "temperature-lookup-table",
sizeof(u32)); sizeof(u32));
if (ntable < 0) { if (ntable <= 0) {
dev_err(dev, "Lookup table is not provided\n"); dev_notice(dev, "no lookup table, assuming DAC channel returns milliCelcius\n");
return ntable; return 0;
} }
if (ntable % 2) { if (ntable % 2) {
......
...@@ -1046,6 +1046,55 @@ thermal_of_cooling_device_register(struct device_node *np, ...@@ -1046,6 +1046,55 @@ thermal_of_cooling_device_register(struct device_node *np,
} }
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register); EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
static void thermal_cooling_device_release(struct device *dev, void *res)
{
thermal_cooling_device_unregister(
*(struct thermal_cooling_device **)res);
}
/**
* devm_thermal_of_cooling_device_register() - register an OF thermal cooling
* device
* @dev: a valid struct device pointer of a sensor device.
* @np: a pointer to a device tree node.
* @type: the thermal cooling device type.
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
*
* This function will register a cooling device with device tree node reference.
* This interface function adds a new thermal cooling device (fan/processor/...)
* to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
* to all the thermal zone devices registered at the same time.
*
* Return: a pointer to the created struct thermal_cooling_device or an
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
*/
struct thermal_cooling_device *
devm_thermal_of_cooling_device_register(struct device *dev,
struct device_node *np,
char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device **ptr, *tcd;
ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
GFP_KERNEL);
if (!ptr)
return ERR_PTR(-ENOMEM);
tcd = __thermal_cooling_device_register(np, type, devdata, ops);
if (IS_ERR(tcd)) {
devres_free(ptr);
return tcd;
}
*ptr = tcd;
devres_add(dev, ptr);
return tcd;
}
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
static void __unbind(struct thermal_zone_device *tz, int mask, static void __unbind(struct thermal_zone_device *tz, int mask,
struct thermal_cooling_device *cdev) struct thermal_cooling_device *cdev)
{ {
......
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*/
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/platform_device.h>
#include <linux/thermal.h>
struct thermal_mmio {
void __iomem *mmio_base;
u32 (*read_mmio)(void __iomem *mmio_base);
u32 mask;
int factor;
};
static u32 thermal_mmio_readb(void __iomem *mmio_base)
{
return readb(mmio_base);
}
static int thermal_mmio_get_temperature(void *private, int *temp)
{
int t;
struct thermal_mmio *sensor =
(struct thermal_mmio *)private;
t = sensor->read_mmio(sensor->mmio_base) & sensor->mask;
t *= sensor->factor;
*temp = t;
return 0;
}
static struct thermal_zone_of_device_ops thermal_mmio_ops = {
.get_temp = thermal_mmio_get_temperature,
};
static int thermal_mmio_probe(struct platform_device *pdev)
{
struct resource *resource;
struct thermal_mmio *sensor;
int (*sensor_init_func)(struct platform_device *pdev,
struct thermal_mmio *sensor);
struct thermal_zone_device *thermal_zone;
int ret;
int temperature;
sensor = devm_kzalloc(&pdev->dev, sizeof(*sensor), GFP_KERNEL);
if (!sensor)
return -ENOMEM;
resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (IS_ERR(resource)) {
dev_err(&pdev->dev,
"fail to get platform memory resource (%ld)\n",
PTR_ERR(resource));
return PTR_ERR(resource);
}
sensor->mmio_base = devm_ioremap_resource(&pdev->dev, resource);
if (IS_ERR(sensor->mmio_base)) {
dev_err(&pdev->dev, "failed to ioremap memory (%ld)\n",
PTR_ERR(sensor->mmio_base));
return PTR_ERR(sensor->mmio_base);
}
sensor_init_func = device_get_match_data(&pdev->dev);
if (sensor_init_func) {
ret = sensor_init_func(pdev, sensor);
if (ret) {
dev_err(&pdev->dev,
"failed to initialize sensor (%d)\n",
ret);
return ret;
}
}
thermal_zone = devm_thermal_zone_of_sensor_register(&pdev->dev,
0,
sensor,
&thermal_mmio_ops);
if (IS_ERR(thermal_zone)) {
dev_err(&pdev->dev,
"failed to register sensor (%ld)\n",
PTR_ERR(thermal_zone));
return PTR_ERR(thermal_zone);
}
thermal_mmio_get_temperature(sensor, &temperature);
dev_info(&pdev->dev,
"thermal mmio sensor %s registered, current temperature: %d\n",
pdev->name, temperature);
return 0;
}
static int al_thermal_init(struct platform_device *pdev,
struct thermal_mmio *sensor)
{
sensor->read_mmio = thermal_mmio_readb;
sensor->mask = 0xff;
sensor->factor = 1000;
return 0;
}
static const struct of_device_id thermal_mmio_id_table[] = {
{ .compatible = "amazon,al-thermal", .data = al_thermal_init},
{}
};
MODULE_DEVICE_TABLE(of, thermal_mmio_id_table);
static struct platform_driver thermal_mmio_driver = {
.probe = thermal_mmio_probe,
.driver = {
.name = "thermal-mmio",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(thermal_mmio_id_table),
},
};
module_platform_driver(thermal_mmio_driver);
MODULE_AUTHOR("Talel Shenhar <talel@amazon.com>");
MODULE_DESCRIPTION("Thermal MMIO Driver");
MODULE_LICENSE("GPL v2");
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
#define TEGRA124_SOCTHERM_SENSOR_PLLX 3 #define TEGRA124_SOCTHERM_SENSOR_PLLX 3
#define TEGRA124_SOCTHERM_SENSOR_NUM 4 #define TEGRA124_SOCTHERM_SENSOR_NUM 4
#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 0 #define TEGRA_SOCTHERM_THROT_LEVEL_NONE 0
#define TEGRA_SOCTHERM_THROT_LEVEL_MED 1 #define TEGRA_SOCTHERM_THROT_LEVEL_LOW 1
#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2 #define TEGRA_SOCTHERM_THROT_LEVEL_MED 2
#define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1 #define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 3
#endif #endif
...@@ -447,6 +447,11 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, ...@@ -447,6 +447,11 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
struct thermal_cooling_device * struct thermal_cooling_device *
thermal_of_cooling_device_register(struct device_node *np, char *, void *, thermal_of_cooling_device_register(struct device_node *np, char *, void *,
const struct thermal_cooling_device_ops *); const struct thermal_cooling_device_ops *);
struct thermal_cooling_device *
devm_thermal_of_cooling_device_register(struct device *dev,
struct device_node *np,
char *type, void *devdata,
const struct thermal_cooling_device_ops *ops);
void thermal_cooling_device_unregister(struct thermal_cooling_device *); void thermal_cooling_device_unregister(struct thermal_cooling_device *);
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
...@@ -503,6 +508,14 @@ static inline struct thermal_cooling_device * ...@@ -503,6 +508,14 @@ static inline struct thermal_cooling_device *
thermal_of_cooling_device_register(struct device_node *np, thermal_of_cooling_device_register(struct device_node *np,
char *type, void *devdata, const struct thermal_cooling_device_ops *ops) char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
{ return ERR_PTR(-ENODEV); } { return ERR_PTR(-ENODEV); }
static inline struct thermal_cooling_device *
devm_thermal_of_cooling_device_register(struct device *dev,
struct device_node *np,
char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
return ERR_PTR(-ENODEV);
}
static inline void thermal_cooling_device_unregister( static inline void thermal_cooling_device_unregister(
struct thermal_cooling_device *cdev) struct thermal_cooling_device *cdev)
{ } { }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment