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 ...
This commit is contained in:
commit
a455eda33f
|
@ -0,0 +1,33 @@
|
||||||
|
Amazon's Annapurna Labs Thermal Sensor
|
||||||
|
|
||||||
|
Simple thermal device that allows temperature reading by a single MMIO
|
||||||
|
transaction.
|
||||||
|
|
||||||
|
Required properties:
|
||||||
|
- compatible: "amazon,al-thermal".
|
||||||
|
- reg: The physical base address and length of the sensor's registers.
|
||||||
|
- #thermal-sensor-cells: Must be 1. See ./thermal.txt for a description.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
thermal: thermal {
|
||||||
|
compatible = "amazon,al-thermal";
|
||||||
|
reg = <0x0 0x05002860 0x0 0x1>;
|
||||||
|
#thermal-sensor-cells = <0x1>;
|
||||||
|
};
|
||||||
|
|
||||||
|
thermal-zones {
|
||||||
|
thermal-z0 {
|
||||||
|
polling-delay-passive = <250>;
|
||||||
|
polling-delay = <1000>;
|
||||||
|
thermal-sensors = <&thermal 0>;
|
||||||
|
trips {
|
||||||
|
critical {
|
||||||
|
temperature = <105000>;
|
||||||
|
hysteresis = <2000>;
|
||||||
|
type = "critical";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
@ -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 :
|
||||||
|
|
||||||
#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 :
|
||||||
* 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:
|
||||||
- "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 {
|
||||||
#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 @@
|
||||||
|
|
||||||
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.
|
||||||
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
|
||||||
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,
|
||||||
}
|
}
|
||||||
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[] = {
|
||||||
};
|
};
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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)
|
||||||
} 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)
|
||||||
|
|
||||||
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);
|
||||||
|
|
||||||
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
|
||||||
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
|
||||||
|
|
||||||
# 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 @@
|
||||||
* 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[] = {
|
||||||
};
|
};
|
||||||
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);
|
||||||
|
|
|
@ -1,26 +1,14 @@
|
||||||
|
// 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 {
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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)
|
||||||
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 @@
|
||||||
* 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>
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
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
|
||||||
|
|
|
@ -1,105 +0,0 @@
|
||||||
// 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 @@
|
||||||
#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)
|
||||||
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)
|
||||||
* 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, ®);
|
ret = regmap_read(priv->tm_map, CNTL_ADDR, ®);
|
||||||
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, ®_cntl);
|
ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_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)
|
||||||
* 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)
|
||||||
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)
|
||||||
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 = {
|
||||||
.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 @@
|
||||||
#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)
|
||||||
* 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,
|
||||||
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)
|
||||||
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 = &tmdev->sensor[id];
|
struct tsens_sensor *s = &priv->sensor[i];
|
||||||
u32 code;
|
u32 temp_idx = LAST_TEMP_0 + s->hw_id;
|
||||||
unsigned int status_reg;
|
u32 valid_idx = VALID_0 + s->hw_id;
|
||||||
int last_temp = 0, ret;
|
u32 last_temp = 0, valid, mask;
|
||||||
|
int ret;
|
||||||
|
|
||||||
status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET;
|
ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||||
ret = regmap_read(tmdev->tm_map, status_reg, &code);
|
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 = &priv->sensor[i];
|
||||||
|
int last_temp = 0, ret;
|
||||||
|
|
||||||
|
ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp);
|
||||||
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 = {
|
||||||
.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)
|
||||||
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,19 +205,47 @@ 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 (ret)
|
if (IS_ERR(priv->rf[TSENS_EN])) {
|
||||||
|
ret = PTR_ERR(priv->rf[TSENS_EN]);
|
||||||
|
goto err_put_device;
|
||||||
|
}
|
||||||
|
ret = regmap_field_read(priv->rf[TSENS_EN], &enabled);
|
||||||
|
if (ret)
|
||||||
|
goto err_put_device;
|
||||||
|
if (!enabled) {
|
||||||
|
dev_err(dev, "tsens device is not enabled\n");
|
||||||
|
ret = -ENODEV;
|
||||||
|
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;
|
goto err_put_device;
|
||||||
if (!(code & TSENS_EN)) {
|
}
|
||||||
dev_err(tmdev->dev, "tsens device is not enabled\n");
|
}
|
||||||
ret = -ENODEV;
|
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;
|
goto err_put_device;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 @@
|
||||||
|
|
||||||
#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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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,
|
||||||
};
|
};
|
|
@ -0,0 +1,193 @@
|
||||||
|
// 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 @@
|
||||||
* 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 @@
|
||||||
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[] = {
|
||||||
}, {
|
}, {
|
||||||
.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 = {
|
||||||
.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)
|
||||||
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)
|
||||||
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) {
|
||||||
dev_err(dev, "tsens calibration failed\n");
|
if (ret != -EPROBE_DEFER)
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,39 @@
|
||||||
#define ONE_PT_CALIB 0x1
|
#define ONE_PT_CALIB 0x1
|
||||||
#define ONE_PT_CALIB2 0x2
|
#define ONE_PT_CALIB2 0x2
|
||||||
#define TWO_PT_CALIB 0x3
|
#define TWO_PT_CALIB 0x3
|
||||||
|
#define CAL_DEGC_PT1 30
|
||||||
|
#define CAL_DEGC_PT2 120
|
||||||
|
#define SLOPE_FACTOR 1000
|
||||||
|
#define SLOPE_DEFAULT 3200
|
||||||
|
|
||||||
|
|
||||||
#include <linux/thermal.h>
|
#include <linux/thermal.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
struct tsens_device;
|
struct tsens_priv;
|
||||||
|
|
||||||
|
enum tsens_ver {
|
||||||
|
VER_0_1 = 0,
|
||||||
|
VER_1_X,
|
||||||
|
VER_2_X,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct tsens_sensor - data for each sensor connected to the tsens device
|
||||||
|
* @priv: tsens device instance that this sensor is connected to
|
||||||
|
* @tzd: pointer to the thermal zone that this sensor is in
|
||||||
|
* @offset: offset of temperature adjustment curve
|
||||||
|
* @id: Sensor ID
|
||||||
|
* @hw_id: HW ID can be used in case of platform-specific IDs
|
||||||
|
* @slope: slope of temperature adjustment curve
|
||||||
|
* @status: 8960-specific variable to track 8960 and 8660 status register offset
|
||||||
|
*/
|
||||||
struct tsens_sensor {
|
struct tsens_sensor {
|
||||||
struct tsens_device *tmdev;
|
struct tsens_priv *priv;
|
||||||
struct thermal_zone_device *tzd;
|
struct thermal_zone_device *tzd;
|
||||||
int offset;
|
int offset;
|
||||||
int id;
|
unsigned int id;
|
||||||
int hw_id;
|
unsigned int hw_id;
|
||||||
int slope;
|
int slope;
|
||||||
u32 status;
|
u32 status;
|
||||||
};
|
};
|
||||||
|
@ -37,63 +59,274 @@ struct tsens_sensor {
|
||||||
*/
|
*/
|
||||||
struct tsens_ops {
|
struct tsens_ops {
|
||||||
/* mandatory callbacks */
|
/* mandatory callbacks */
|
||||||
int (*init)(struct tsens_device *);
|
int (*init)(struct tsens_priv *priv);
|
||||||
int (*calibrate)(struct tsens_device *);
|
int (*calibrate)(struct tsens_priv *priv);
|
||||||
int (*get_temp)(struct tsens_device *, int, int *);
|
int (*get_temp)(struct tsens_priv *priv, int i, int *temp);
|
||||||
/* optional callbacks */
|
/* optional callbacks */
|
||||||
int (*enable)(struct tsens_device *, int);
|
int (*enable)(struct tsens_priv *priv, int i);
|
||||||
void (*disable)(struct tsens_device *);
|
void (*disable)(struct tsens_priv *priv);
|
||||||
int (*suspend)(struct tsens_device *);
|
int (*suspend)(struct tsens_priv *priv);
|
||||||
int (*resume)(struct tsens_device *);
|
int (*resume)(struct tsens_priv *priv);
|
||||||
int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
|
int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend);
|
||||||
};
|
};
|
||||||
|
|
||||||
enum reg_list {
|
#define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
|
||||||
SROT_CTRL_OFFSET,
|
[_name##_##0] = REG_FIELD(_offset, _startbit, _stopbit), \
|
||||||
|
[_name##_##1] = REG_FIELD(_offset + 4, _startbit, _stopbit), \
|
||||||
|
[_name##_##2] = REG_FIELD(_offset + 8, _startbit, _stopbit), \
|
||||||
|
[_name##_##3] = REG_FIELD(_offset + 12, _startbit, _stopbit), \
|
||||||
|
[_name##_##4] = REG_FIELD(_offset + 16, _startbit, _stopbit), \
|
||||||
|
[_name##_##5] = REG_FIELD(_offset + 20, _startbit, _stopbit), \
|
||||||
|
[_name##_##6] = REG_FIELD(_offset + 24, _startbit, _stopbit), \
|
||||||
|
[_name##_##7] = REG_FIELD(_offset + 28, _startbit, _stopbit), \
|
||||||
|
[_name##_##8] = REG_FIELD(_offset + 32, _startbit, _stopbit), \
|
||||||
|
[_name##_##9] = REG_FIELD(_offset + 36, _startbit, _stopbit), \
|
||||||
|
[_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit)
|
||||||
|
|
||||||
REG_ARRAY_SIZE,
|
#define REG_FIELD_FOR_EACH_SENSOR16(_name, _offset, _startbit, _stopbit) \
|
||||||
|
[_name##_##0] = REG_FIELD(_offset, _startbit, _stopbit), \
|
||||||
|
[_name##_##1] = REG_FIELD(_offset + 4, _startbit, _stopbit), \
|
||||||
|
[_name##_##2] = REG_FIELD(_offset + 8, _startbit, _stopbit), \
|
||||||
|
[_name##_##3] = REG_FIELD(_offset + 12, _startbit, _stopbit), \
|
||||||
|
[_name##_##4] = REG_FIELD(_offset + 16, _startbit, _stopbit), \
|
||||||
|
[_name##_##5] = REG_FIELD(_offset + 20, _startbit, _stopbit), \
|
||||||
|
[_name##_##6] = REG_FIELD(_offset + 24, _startbit, _stopbit), \
|
||||||
|
[_name##_##7] = REG_FIELD(_offset + 28, _startbit, _stopbit), \
|
||||||
|
[_name##_##8] = REG_FIELD(_offset + 32, _startbit, _stopbit), \
|
||||||
|
[_name##_##9] = REG_FIELD(_offset + 36, _startbit, _stopbit), \
|
||||||
|
[_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit), \
|
||||||
|
[_name##_##11] = REG_FIELD(_offset + 44, _startbit, _stopbit), \
|
||||||
|
[_name##_##12] = REG_FIELD(_offset + 48, _startbit, _stopbit), \
|
||||||
|
[_name##_##13] = REG_FIELD(_offset + 52, _startbit, _stopbit), \
|
||||||
|
[_name##_##14] = REG_FIELD(_offset + 56, _startbit, _stopbit), \
|
||||||
|
[_name##_##15] = REG_FIELD(_offset + 60, _startbit, _stopbit)
|
||||||
|
|
||||||
|
/* reg_field IDs to use as an index into an array */
|
||||||
|
enum regfield_ids {
|
||||||
|
/* ----- SROT ------ */
|
||||||
|
/* HW_VER */
|
||||||
|
VER_MAJOR = 0,
|
||||||
|
VER_MINOR,
|
||||||
|
VER_STEP,
|
||||||
|
/* CTRL_OFFSET */
|
||||||
|
TSENS_EN = 3,
|
||||||
|
TSENS_SW_RST,
|
||||||
|
SENSOR_EN,
|
||||||
|
CODE_OR_TEMP,
|
||||||
|
|
||||||
|
/* ----- TM ------ */
|
||||||
|
/* STATUS */
|
||||||
|
LAST_TEMP_0 = 7, /* Last temperature reading */
|
||||||
|
LAST_TEMP_1,
|
||||||
|
LAST_TEMP_2,
|
||||||
|
LAST_TEMP_3,
|
||||||
|
LAST_TEMP_4,
|
||||||
|
LAST_TEMP_5,
|
||||||
|
LAST_TEMP_6,
|
||||||
|
LAST_TEMP_7,
|
||||||
|
LAST_TEMP_8,
|
||||||
|
LAST_TEMP_9,
|
||||||
|
LAST_TEMP_10,
|
||||||
|
LAST_TEMP_11,
|
||||||
|
LAST_TEMP_12,
|
||||||
|
LAST_TEMP_13,
|
||||||
|
LAST_TEMP_14,
|
||||||
|
LAST_TEMP_15,
|
||||||
|
VALID_0 = 23, /* VALID reading or not */
|
||||||
|
VALID_1,
|
||||||
|
VALID_2,
|
||||||
|
VALID_3,
|
||||||
|
VALID_4,
|
||||||
|
VALID_5,
|
||||||
|
VALID_6,
|
||||||
|
VALID_7,
|
||||||
|
VALID_8,
|
||||||
|
VALID_9,
|
||||||
|
VALID_10,
|
||||||
|
VALID_11,
|
||||||
|
VALID_12,
|
||||||
|
VALID_13,
|
||||||
|
VALID_14,
|
||||||
|
VALID_15,
|
||||||
|
MIN_STATUS_0, /* MIN threshold violated */
|
||||||
|
MIN_STATUS_1,
|
||||||
|
MIN_STATUS_2,
|
||||||
|
MIN_STATUS_3,
|
||||||
|
MIN_STATUS_4,
|
||||||
|
MIN_STATUS_5,
|
||||||
|
MIN_STATUS_6,
|
||||||
|
MIN_STATUS_7,
|
||||||
|
MIN_STATUS_8,
|
||||||
|
MIN_STATUS_9,
|
||||||
|
MIN_STATUS_10,
|
||||||
|
MIN_STATUS_11,
|
||||||
|
MIN_STATUS_12,
|
||||||
|
MIN_STATUS_13,
|
||||||
|
MIN_STATUS_14,
|
||||||
|
MIN_STATUS_15,
|
||||||
|
MAX_STATUS_0, /* MAX threshold violated */
|
||||||
|
MAX_STATUS_1,
|
||||||
|
MAX_STATUS_2,
|
||||||
|
MAX_STATUS_3,
|
||||||
|
MAX_STATUS_4,
|
||||||
|
MAX_STATUS_5,
|
||||||
|
MAX_STATUS_6,
|
||||||
|
MAX_STATUS_7,
|
||||||
|
MAX_STATUS_8,
|
||||||
|
MAX_STATUS_9,
|
||||||
|
MAX_STATUS_10,
|
||||||
|
MAX_STATUS_11,
|
||||||
|
MAX_STATUS_12,
|
||||||
|
MAX_STATUS_13,
|
||||||
|
MAX_STATUS_14,
|
||||||
|
MAX_STATUS_15,
|
||||||
|
LOWER_STATUS_0, /* LOWER threshold violated */
|
||||||
|
LOWER_STATUS_1,
|
||||||
|
LOWER_STATUS_2,
|
||||||
|
LOWER_STATUS_3,
|
||||||
|
LOWER_STATUS_4,
|
||||||
|
LOWER_STATUS_5,
|
||||||
|
LOWER_STATUS_6,
|
||||||
|
LOWER_STATUS_7,
|
||||||
|
LOWER_STATUS_8,
|
||||||
|
LOWER_STATUS_9,
|
||||||
|
LOWER_STATUS_10,
|
||||||
|
LOWER_STATUS_11,
|
||||||
|
LOWER_STATUS_12,
|
||||||
|
LOWER_STATUS_13,
|
||||||
|
LOWER_STATUS_14,
|
||||||
|
LOWER_STATUS_15,
|
||||||
|
UPPER_STATUS_0, /* UPPER threshold violated */
|
||||||
|
UPPER_STATUS_1,
|
||||||
|
UPPER_STATUS_2,
|
||||||
|
UPPER_STATUS_3,
|
||||||
|
UPPER_STATUS_4,
|
||||||
|
UPPER_STATUS_5,
|
||||||
|
UPPER_STATUS_6,
|
||||||
|
UPPER_STATUS_7,
|
||||||
|
UPPER_STATUS_8,
|
||||||
|
UPPER_STATUS_9,
|
||||||
|
UPPER_STATUS_10,
|
||||||
|
UPPER_STATUS_11,
|
||||||
|
UPPER_STATUS_12,
|
||||||
|
UPPER_STATUS_13,
|
||||||
|
UPPER_STATUS_14,
|
||||||
|
UPPER_STATUS_15,
|
||||||
|
CRITICAL_STATUS_0, /* CRITICAL threshold violated */
|
||||||
|
CRITICAL_STATUS_1,
|
||||||
|
CRITICAL_STATUS_2,
|
||||||
|
CRITICAL_STATUS_3,
|
||||||
|
CRITICAL_STATUS_4,
|
||||||
|
CRITICAL_STATUS_5,
|
||||||
|
CRITICAL_STATUS_6,
|
||||||
|
CRITICAL_STATUS_7,
|
||||||
|
CRITICAL_STATUS_8,
|
||||||
|
CRITICAL_STATUS_9,
|
||||||
|
CRITICAL_STATUS_10,
|
||||||
|
CRITICAL_STATUS_11,
|
||||||
|
CRITICAL_STATUS_12,
|
||||||
|
CRITICAL_STATUS_13,
|
||||||
|
CRITICAL_STATUS_14,
|
||||||
|
CRITICAL_STATUS_15,
|
||||||
|
/* TRDY */
|
||||||
|
TRDY,
|
||||||
|
/* INTERRUPT ENABLE */
|
||||||
|
INT_EN, /* Pre-V1, V1.x */
|
||||||
|
LOW_INT_EN, /* V2.x */
|
||||||
|
UP_INT_EN, /* V2.x */
|
||||||
|
CRIT_INT_EN, /* V2.x */
|
||||||
|
|
||||||
|
/* Keep last */
|
||||||
|
MAX_REGFIELDS
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct tsens_data - tsens instance specific data
|
* struct tsens_features - Features supported by the IP
|
||||||
* @num_sensors: Max number of sensors supported by platform
|
* @ver_major: Major number of IP version
|
||||||
* @ops: operations the tsens instance supports
|
* @crit_int: does the IP support critical interrupts?
|
||||||
* @hw_ids: Subset of sensors ids supported by platform, if not the first n
|
* @adc: do the sensors only output adc code (instead of temperature)?
|
||||||
* @reg_offsets: Register offsets for commonly used registers
|
* @srot_split: does the IP neatly splits the register space into SROT and TM,
|
||||||
|
* with SROT only being available to secure boot firmware?
|
||||||
|
* @max_sensors: maximum sensors supported by this version of the IP
|
||||||
*/
|
*/
|
||||||
struct tsens_data {
|
struct tsens_features {
|
||||||
const u32 num_sensors;
|
unsigned int ver_major;
|
||||||
const struct tsens_ops *ops;
|
unsigned int crit_int:1;
|
||||||
const u16 reg_offsets[REG_ARRAY_SIZE];
|
unsigned int adc:1;
|
||||||
unsigned int *hw_ids;
|
unsigned int srot_split:1;
|
||||||
|
unsigned int max_sensors;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Registers to be saved/restored across a context loss */
|
/**
|
||||||
|
* struct tsens_plat_data - tsens compile-time platform data
|
||||||
|
* @num_sensors: Number of sensors supported by platform
|
||||||
|
* @ops: operations the tsens instance supports
|
||||||
|
* @hw_ids: Subset of sensors ids supported by platform, if not the first n
|
||||||
|
* @feat: features of the IP
|
||||||
|
* @fields: bitfield locations
|
||||||
|
*/
|
||||||
|
struct tsens_plat_data {
|
||||||
|
const u32 num_sensors;
|
||||||
|
const struct tsens_ops *ops;
|
||||||
|
unsigned int *hw_ids;
|
||||||
|
const struct tsens_features *feat;
|
||||||
|
const struct reg_field *fields;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct tsens_context - Registers to be saved/restored across a context loss
|
||||||
|
*/
|
||||||
struct tsens_context {
|
struct tsens_context {
|
||||||
int threshold;
|
int threshold;
|
||||||
int control;
|
int control;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tsens_device {
|
/**
|
||||||
|
* struct tsens_priv - private data for each instance of the tsens IP
|
||||||
|
* @dev: pointer to struct device
|
||||||
|
* @num_sensors: number of sensors enabled on this device
|
||||||
|
* @tm_map: pointer to TM register address space
|
||||||
|
* @srot_map: pointer to SROT register address space
|
||||||
|
* @tm_offset: deal with old device trees that don't address TM and SROT
|
||||||
|
* address space separately
|
||||||
|
* @rf: array of regmap_fields used to store value of the field
|
||||||
|
* @ctx: registers to be saved and restored during suspend/resume
|
||||||
|
* @feat: features of the IP
|
||||||
|
* @fields: bitfield locations
|
||||||
|
* @ops: pointer to list of callbacks supported by this device
|
||||||
|
* @sensor: list of sensors attached to this device
|
||||||
|
*/
|
||||||
|
struct tsens_priv {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
u32 num_sensors;
|
u32 num_sensors;
|
||||||
struct regmap *tm_map;
|
struct regmap *tm_map;
|
||||||
struct regmap *srot_map;
|
struct regmap *srot_map;
|
||||||
u32 tm_offset;
|
u32 tm_offset;
|
||||||
u16 reg_offsets[REG_ARRAY_SIZE];
|
struct regmap_field *rf[MAX_REGFIELDS];
|
||||||
struct tsens_context ctx;
|
struct tsens_context ctx;
|
||||||
|
const struct tsens_features *feat;
|
||||||
|
const struct reg_field *fields;
|
||||||
const struct tsens_ops *ops;
|
const struct tsens_ops *ops;
|
||||||
struct tsens_sensor sensor[0];
|
struct tsens_sensor sensor[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
char *qfprom_read(struct device *, const char *);
|
char *qfprom_read(struct device *dev, const char *cname);
|
||||||
void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
|
void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode);
|
||||||
int init_common(struct tsens_device *);
|
int init_common(struct tsens_priv *priv);
|
||||||
int get_temp_common(struct tsens_device *, int, int *);
|
int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp);
|
||||||
|
int get_temp_common(struct tsens_priv *priv, int i, int *temp);
|
||||||
|
bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id);
|
||||||
|
|
||||||
|
/* TSENS target */
|
||||||
|
extern const struct tsens_plat_data data_8960;
|
||||||
|
|
||||||
|
/* TSENS v0.1 targets */
|
||||||
|
extern const struct tsens_plat_data data_8916, data_8974;
|
||||||
|
|
||||||
/* TSENS v1 targets */
|
/* TSENS v1 targets */
|
||||||
extern const struct tsens_data data_8916, data_8974, data_8960;
|
extern const struct tsens_plat_data data_tsens_v1;
|
||||||
|
|
||||||
/* TSENS v2 targets */
|
/* TSENS v2 targets */
|
||||||
extern const struct tsens_data data_8996, data_tsens_v2;
|
extern const struct tsens_plat_data data_8996, data_tsens_v2;
|
||||||
|
|
||||||
#endif /* __QCOM_TSENS_H__ */
|
#endif /* __QCOM_TSENS_H__ */
|
||||||
|
|
|
@ -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 @@
|
||||||
#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 {
|
||||||
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,38 +230,16 @@ 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;
|
thermal_zone_device_update(priv->tscs[i]->zone,
|
||||||
|
THERMAL_EVENT_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == IRQ_WAKE_THREAD)
|
|
||||||
rcar_thermal_irq_set(priv, false);
|
|
||||||
|
|
||||||
spin_unlock(&priv->lock);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
|
|
||||||
{
|
|
||||||
struct rcar_gen3_thermal_priv *priv = data;
|
|
||||||
unsigned long flags;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for (i = 0; i < priv->num_tscs; i++)
|
|
||||||
thermal_zone_device_update(priv->tscs[i]->zone,
|
|
||||||
THERMAL_EVENT_UNSPECIFIED);
|
|
||||||
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
rcar_thermal_irq_set(priv, true);
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
}
|
}
|
||||||
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)
|
||||||
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 {
|
||||||
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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
* 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,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
mutex_lock(&priv->lock);
|
mutex_lock(&priv->lock);
|
||||||
tmp = MCELSIUS((priv->ctemp * 5) - 65);
|
if (priv->chip->ctemp_bands == 1)
|
||||||
|
tmp = MCELSIUS((priv->ctemp * 5) - 65);
|
||||||
|
else if (priv->ctemp < 24)
|
||||||
|
tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
|
||||||
|
else
|
||||||
|
tmp = MCELSIUS((priv->ctemp * 5) - 60);
|
||||||
mutex_unlock(&priv->lock);
|
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 {
|
||||||
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 {
|
||||||
#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,
|
||||||
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,
|
||||||
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 = {
|
||||||
};
|
};
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
config ST_THERMAL
|
config ST_THERMAL
|
||||||
tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
|
tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
|
||||||
help
|
help
|
||||||
Support for thermal sensors on STMicroelectronics STi series of SoCs.
|
Support for thermal sensors on STMicroelectronics STi series of SoCs.
|
||||||
|
|
||||||
config ST_THERMAL_SYSCFG
|
config ST_THERMAL_SYSCFG
|
||||||
select ST_THERMAL
|
select ST_THERMAL
|
||||||
|
@ -16,11 +16,11 @@ config ST_THERMAL_MEMMAP
|
||||||
tristate "STi series memory mapped access based thermal sensors"
|
tristate "STi series memory mapped access based thermal sensors"
|
||||||
|
|
||||||
config STM32_THERMAL
|
config STM32_THERMAL
|
||||||
tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
|
tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
|
||||||
depends on MACH_STM32MP157
|
depends on MACH_STM32MP157
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
Support for thermal framework on STMicroelectronics STM32 series of
|
Support for thermal framework on STMicroelectronics STM32 series of
|
||||||
SoCs. This thermal driver allows to access to general thermal framework
|
SoCs. This thermal driver allows to access to general thermal framework
|
||||||
functionalities and to acces to SoC sensor functionalities. This
|
functionalities and to acces to SoC sensor functionalities. This
|
||||||
configuration is fully dependent of MACH_STM32MP157.
|
configuration is fully dependent of MACH_STM32MP157.
|
||||||
|
|
|
@ -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)
|
||||||
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)
|
||||||
|
|
|
@ -14,7 +14,7 @@ config TEGRA_BPMP_THERMAL
|
||||||
tristate "Tegra BPMP thermal sensing"
|
tristate "Tegra BPMP thermal sensing"
|
||||||
depends on TEGRA_BPMP || COMPILE_TEST
|
depends on TEGRA_BPMP || COMPILE_TEST
|
||||||
help
|
help
|
||||||
Enable this option for support for sensing system temperature of NVIDIA
|
Enable this option for support for sensing system temperature of NVIDIA
|
||||||
Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
|
Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,4 @@
|
||||||
|
/* 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 @@
|
||||||
#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 {
|
||||||
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 {
|
||||||
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 {
|
||||||
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,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* 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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* 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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* This software is licensed under the terms of the GNU General Public
|
* 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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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 = {
|
||||||
.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)
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
}
|
}
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
// 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 @@
|
||||||
#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 *,
|
||||||
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 *
|
||||||
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)
|
||||||
{ }
|
{ }
|
||||||
|
|
Loading…
Reference in New Issue