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:
Коммит
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:
|
||||
TEGRA_SOCTHERM_THROT_LEVEL_LOW, TEGRA_SOCTHERM_THROT_LEVEL_MED
|
||||
TEGRA_SOCTHERM_THROT_LEVEL_HIGH, TEGRA_SOCTHERM_THROT_LEVEL_NONE
|
||||
- nvidia,gpu-throt-level: This property is for Tegra124 and Tegra210.
|
||||
It is the level of pulse skippers, which used to throttle clock
|
||||
frequencies. It indicates gpu clock throttling depth and can be
|
||||
programmed to any of the following values which represent a throttling
|
||||
percentage:
|
||||
TEGRA_SOCTHERM_THROT_LEVEL_NONE (0%)
|
||||
TEGRA_SOCTHERM_THROT_LEVEL_LOW (50%),
|
||||
TEGRA_SOCTHERM_THROT_LEVEL_MED (75%),
|
||||
TEGRA_SOCTHERM_THROT_LEVEL_HIGH (85%).
|
||||
- #cooling-cells: Should be 1. This cooling device only support on/off state.
|
||||
See ./thermal.txt for a description of this property.
|
||||
|
||||
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:
|
||||
- the "critical" type trip points will be set to SOC_THERM hardware as the
|
||||
shut down temperature. Once the temperature of this thermal zone is higher
|
||||
than it, the system will be shutdown or reset by hardware.
|
||||
- the "critical" type trip points will be used to set the temperature at which
|
||||
the SOC_THERM hardware will assert a thermal trigger if the "nvidia,thermtrips"
|
||||
property is missing. When the thermtrips property is present, the breach of a
|
||||
critical trip point is reported back to the thermal framework to implement
|
||||
software shutdown.
|
||||
|
||||
- the "hot" type trip points will be set to SOC_THERM hardware as the throttle
|
||||
temperature. Once the the temperature of this thermal zone is higher
|
||||
than it, it will trigger the HW throttle event.
|
||||
|
@ -79,25 +113,32 @@ Example :
|
|||
|
||||
#thermal-sensor-cells = <1>;
|
||||
|
||||
nvidia,thermtrips = <TEGRA124_SOCTHERM_SENSOR_CPU 102500
|
||||
TEGRA124_SOCTHERM_SENSOR_GPU 103000>;
|
||||
|
||||
throttle-cfgs {
|
||||
/*
|
||||
* When the "heavy" cooling device triggered,
|
||||
* the HW will skip cpu clock's pulse in 85% depth
|
||||
* the HW will skip cpu clock's pulse in 85% depth,
|
||||
* skip gpu clock's pulse in 85% level
|
||||
*/
|
||||
throttle_heavy: heavy {
|
||||
nvidia,priority = <100>;
|
||||
nvidia,cpu-throt-percent = <85>;
|
||||
nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_HIGH>;
|
||||
|
||||
#cooling-cells = <1>;
|
||||
};
|
||||
|
||||
/*
|
||||
* When the "light" cooling device triggered,
|
||||
* the HW will skip cpu clock's pulse in 50% depth
|
||||
* the HW will skip cpu clock's pulse in 50% depth,
|
||||
* skip gpu clock's pulse in 50% level
|
||||
*/
|
||||
throttle_light: light {
|
||||
nvidia,priority = <80>;
|
||||
nvidia,cpu-throt-percent = <50>;
|
||||
nvidia,gpu-throt-level = <TEGRA_SOCTHERM_THROT_LEVEL_LOW>;
|
||||
|
||||
#cooling-cells = <1>;
|
||||
};
|
||||
|
@ -107,6 +148,17 @@ Example :
|
|||
* arbiter will select the highest priority as the final throttle
|
||||
* settings to skip cpu pulse.
|
||||
*/
|
||||
|
||||
throttle_oc1: oc1 {
|
||||
nvidia,priority = <50>;
|
||||
nvidia,polarity-active-low;
|
||||
nvidia,count-threshold = <100>;
|
||||
nvidia,alarm-filter = <5100000>;
|
||||
nvidia,throttle-period-us = <0>;
|
||||
nvidia,cpu-throt-percent = <75>;
|
||||
nvidia,gpu-throt-level =
|
||||
<TEGRA_SOCTHERM_THROT_LEVEL_MED>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -6,11 +6,14 @@ Required properties:
|
|||
- "qcom,msm8916-tsens" (MSM8916)
|
||||
- "qcom,msm8974-tsens" (MSM8974)
|
||||
- "qcom,msm8996-tsens" (MSM8996)
|
||||
- "qcom,qcs404-tsens", "qcom,tsens-v1" (QCS404)
|
||||
- "qcom,msm8998-tsens", "qcom,tsens-v2" (MSM8998)
|
||||
- "qcom,sdm845-tsens", "qcom,tsens-v2" (SDM845)
|
||||
The generic "qcom,tsens-v2" property must be used as a fallback for any SoC
|
||||
with version 2 of the TSENS IP. MSM8996 is the only exception because the
|
||||
generic property did not exist when support was added.
|
||||
Similarly, the generic "qcom,tsens-v1" property must be used as a fallback for
|
||||
any SoC with version 1 of the TSENS IP.
|
||||
|
||||
- reg: Address range of the thermal registers.
|
||||
New platforms containing v2.x.y of the TSENS IP must specify the SROT and TM
|
||||
|
@ -39,3 +42,14 @@ tsens0: thermal-sensor@c263000 {
|
|||
#qcom,sensors = <13>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
||||
Example 3 (for any platform containing v1 of the TSENS IP):
|
||||
tsens: thermal-sensor@4a9000 {
|
||||
compatible = "qcom,qcs404-tsens", "qcom,tsens-v1";
|
||||
reg = <0x004a9000 0x1000>, /* TM */
|
||||
<0x004a8000 0x1000>; /* SROT */
|
||||
nvmem-cells = <&tsens_caldata>;
|
||||
nvmem-cell-names = "calib";
|
||||
#qcom,sensors = <10>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
Required properties:
|
||||
- compatible : should be "rockchip,<name>-tsadc"
|
||||
"rockchip,px30-tsadc": found on PX30 SoCs
|
||||
"rockchip,rv1108-tsadc": found on RV1108 SoCs
|
||||
"rockchip,rk3228-tsadc": found on RK3228 SoCs
|
||||
"rockchip,rk3288-tsadc": found on RK3288 SoCs
|
||||
|
|
|
@ -8,16 +8,22 @@ temperature using voltage-temperature lookup table.
|
|||
Required properties:
|
||||
===================
|
||||
- compatible: Must be "generic-adc-thermal".
|
||||
- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description
|
||||
of this property.
|
||||
Optional properties:
|
||||
===================
|
||||
- temperature-lookup-table: Two dimensional array of Integer; lookup table
|
||||
to map the relation between ADC value and
|
||||
temperature. When ADC is read, the value is
|
||||
looked up on the table to get the equivalent
|
||||
temperature.
|
||||
|
||||
The first value of the each row of array is the
|
||||
temperature in milliCelsius and second value of
|
||||
the each row of array is the ADC read value.
|
||||
- #thermal-sensor-cells: Should be 1. See ./thermal.txt for a description
|
||||
of this property.
|
||||
|
||||
If not specified, driver assumes the ADC channel
|
||||
gives milliCelsius directly.
|
||||
|
||||
Example :
|
||||
#include <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_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
|
||||
M: Netanel Belgazal <netanel@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);
|
||||
|
||||
cdev->tcdev = thermal_of_cooling_device_register(child,
|
||||
cdev->name,
|
||||
cdev,
|
||||
&aspeed_pwm_cool_ops);
|
||||
cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
|
||||
cdev->name, cdev, &aspeed_pwm_cool_ops);
|
||||
if (IS_ERR(cdev->tcdev))
|
||||
return PTR_ERR(cdev->tcdev);
|
||||
|
||||
|
|
|
@ -498,6 +498,11 @@ static const struct of_device_id of_gpio_fan_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, of_gpio_fan_match);
|
||||
|
||||
static void gpio_fan_stop(void *data)
|
||||
{
|
||||
set_fan_speed(data, 0);
|
||||
}
|
||||
|
||||
static int gpio_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
int err;
|
||||
|
@ -532,6 +537,7 @@ static int gpio_fan_probe(struct platform_device *pdev)
|
|||
err = fan_ctrl_init(fan_data);
|
||||
if (err)
|
||||
return err;
|
||||
devm_add_action_or_reset(dev, gpio_fan_stop, fan_data);
|
||||
}
|
||||
|
||||
/* Make this driver part of hwmon class. */
|
||||
|
@ -543,32 +549,20 @@ static int gpio_fan_probe(struct platform_device *pdev)
|
|||
return PTR_ERR(fan_data->hwmon_dev);
|
||||
|
||||
/* Optional cooling device register for Device tree platforms */
|
||||
fan_data->cdev = thermal_of_cooling_device_register(np,
|
||||
"gpio-fan",
|
||||
fan_data,
|
||||
&gpio_fan_cool_ops);
|
||||
fan_data->cdev = devm_thermal_of_cooling_device_register(dev, np,
|
||||
"gpio-fan", fan_data, &gpio_fan_cool_ops);
|
||||
|
||||
dev_info(dev, "GPIO fan initialized\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gpio_fan_remove(struct platform_device *pdev)
|
||||
static void gpio_fan_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
|
||||
|
||||
if (!IS_ERR(fan_data->cdev))
|
||||
thermal_cooling_device_unregister(fan_data->cdev);
|
||||
|
||||
if (fan_data->gpios)
|
||||
set_fan_speed(fan_data, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void gpio_fan_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
gpio_fan_remove(pdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -602,7 +596,6 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
|
|||
|
||||
static struct platform_driver gpio_fan_driver = {
|
||||
.probe = gpio_fan_probe,
|
||||
.remove = gpio_fan_remove,
|
||||
.shutdown = gpio_fan_shutdown,
|
||||
.driver = {
|
||||
.name = "gpio-fan",
|
||||
|
|
|
@ -465,42 +465,42 @@ static int mlxreg_fan_config(struct mlxreg_fan *fan,
|
|||
static int mlxreg_fan_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxreg_core_platform_data *pdata;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct mlxreg_fan *fan;
|
||||
struct device *hwm;
|
||||
int err;
|
||||
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
pdata = dev_get_platdata(dev);
|
||||
if (!pdata) {
|
||||
dev_err(&pdev->dev, "Failed to get platform data.\n");
|
||||
dev_err(dev, "Failed to get platform data.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
|
||||
fan = devm_kzalloc(dev, sizeof(*fan), GFP_KERNEL);
|
||||
if (!fan)
|
||||
return -ENOMEM;
|
||||
|
||||
fan->dev = &pdev->dev;
|
||||
fan->dev = dev;
|
||||
fan->regmap = pdata->regmap;
|
||||
platform_set_drvdata(pdev, fan);
|
||||
|
||||
err = mlxreg_fan_config(fan, pdata);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
hwm = devm_hwmon_device_register_with_info(&pdev->dev, "mlxreg_fan",
|
||||
hwm = devm_hwmon_device_register_with_info(dev, "mlxreg_fan",
|
||||
fan,
|
||||
&mlxreg_fan_hwmon_chip_info,
|
||||
NULL);
|
||||
if (IS_ERR(hwm)) {
|
||||
dev_err(&pdev->dev, "Failed to register hwmon device\n");
|
||||
dev_err(dev, "Failed to register hwmon device\n");
|
||||
return PTR_ERR(hwm);
|
||||
}
|
||||
|
||||
if (IS_REACHABLE(CONFIG_THERMAL)) {
|
||||
fan->cdev = thermal_cooling_device_register("mlxreg_fan", fan,
|
||||
&mlxreg_fan_cooling_ops);
|
||||
fan->cdev = devm_thermal_of_cooling_device_register(dev,
|
||||
NULL, "mlxreg_fan", fan, &mlxreg_fan_cooling_ops);
|
||||
if (IS_ERR(fan->cdev)) {
|
||||
dev_err(&pdev->dev, "Failed to register cooling device\n");
|
||||
dev_err(dev, "Failed to register cooling device\n");
|
||||
return PTR_ERR(fan->cdev);
|
||||
}
|
||||
}
|
||||
|
@ -508,22 +508,11 @@ static int mlxreg_fan_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mlxreg_fan_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct mlxreg_fan *fan = platform_get_drvdata(pdev);
|
||||
|
||||
if (IS_REACHABLE(CONFIG_THERMAL))
|
||||
thermal_cooling_device_unregister(fan->cdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver mlxreg_fan_driver = {
|
||||
.driver = {
|
||||
.name = "mlxreg-fan",
|
||||
},
|
||||
.probe = mlxreg_fan_probe,
|
||||
.remove = mlxreg_fan_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(mlxreg_fan_driver);
|
||||
|
|
|
@ -846,10 +846,8 @@ static int npcm7xx_create_pwm_cooling(struct device *dev,
|
|||
snprintf(cdev->name, THERMAL_NAME_LENGTH, "%pOFn%d", child,
|
||||
pwm_port);
|
||||
|
||||
cdev->tcdev = thermal_of_cooling_device_register(child,
|
||||
cdev->name,
|
||||
cdev,
|
||||
&npcm7xx_pwm_cool_ops);
|
||||
cdev->tcdev = devm_thermal_of_cooling_device_register(dev, child,
|
||||
cdev->name, cdev, &npcm7xx_pwm_cool_ops);
|
||||
if (IS_ERR(cdev->tcdev))
|
||||
return PTR_ERR(cdev->tcdev);
|
||||
|
||||
|
|
|
@ -273,27 +273,40 @@ static int pwm_fan_of_get_cooling_data(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void pwm_fan_regulator_disable(void *data)
|
||||
{
|
||||
regulator_disable(data);
|
||||
}
|
||||
|
||||
static void pwm_fan_pwm_disable(void *__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)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct pwm_fan_ctx *ctx;
|
||||
struct device *hwmon;
|
||||
int ret;
|
||||
struct pwm_state state = { };
|
||||
u32 ppr = 2;
|
||||
|
||||
ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
|
||||
ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ctx->lock);
|
||||
|
||||
ctx->pwm = devm_of_pwm_get(&pdev->dev, pdev->dev.of_node, NULL);
|
||||
ctx->pwm = devm_of_pwm_get(dev, dev->of_node, NULL);
|
||||
if (IS_ERR(ctx->pwm)) {
|
||||
ret = PTR_ERR(ctx->pwm);
|
||||
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "Could not get PWM: %d\n", ret);
|
||||
dev_err(dev, "Could not get PWM: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -304,7 +317,7 @@ static int pwm_fan_probe(struct platform_device *pdev)
|
|||
if (ctx->irq == -EPROBE_DEFER)
|
||||
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 (PTR_ERR(ctx->reg_en) != -ENODEV)
|
||||
return PTR_ERR(ctx->reg_en);
|
||||
|
@ -313,10 +326,11 @@ static int pwm_fan_probe(struct platform_device *pdev)
|
|||
} else {
|
||||
ret = regulator_enable(ctx->reg_en);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to enable fan supply: %d\n", ret);
|
||||
dev_err(dev, "Failed to enable fan supply: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
devm_add_action_or_reset(dev, pwm_fan_regulator_disable,
|
||||
ctx->reg_en);
|
||||
}
|
||||
|
||||
ctx->pwm_value = MAX_PWM;
|
||||
|
@ -328,91 +342,57 @@ static int pwm_fan_probe(struct platform_device *pdev)
|
|||
|
||||
ret = pwm_apply_state(ctx->pwm, &state);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to configure PWM: %d\n", ret);
|
||||
goto err_reg_disable;
|
||||
dev_err(dev, "Failed to configure PWM: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
if (!ctx->pulses_per_revolution) {
|
||||
dev_err(&pdev->dev, "pulses-per-revolution can't be zero.\n");
|
||||
ret = -EINVAL;
|
||||
goto err_pwm_disable;
|
||||
dev_err(dev, "pulses-per-revolution can't be zero.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
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);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to request interrupt: %d\n", ret);
|
||||
goto err_pwm_disable;
|
||||
dev_err(dev, "Failed to request interrupt: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ctx->sample_start = ktime_get();
|
||||
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);
|
||||
if (IS_ERR(hwmon)) {
|
||||
ret = PTR_ERR(hwmon);
|
||||
dev_err(&pdev->dev,
|
||||
"Failed to register hwmon device: %d\n", ret);
|
||||
goto err_del_timer;
|
||||
dev_err(dev, "Failed to register hwmon device\n");
|
||||
return PTR_ERR(hwmon);
|
||||
}
|
||||
|
||||
ret = pwm_fan_of_get_cooling_data(&pdev->dev, ctx);
|
||||
ret = pwm_fan_of_get_cooling_data(dev, ctx);
|
||||
if (ret)
|
||||
goto err_del_timer;
|
||||
return ret;
|
||||
|
||||
ctx->pwm_fan_state = ctx->pwm_fan_max_state;
|
||||
if (IS_ENABLED(CONFIG_THERMAL)) {
|
||||
cdev = thermal_of_cooling_device_register(pdev->dev.of_node,
|
||||
"pwm-fan", ctx,
|
||||
&pwm_fan_cooling_ops);
|
||||
cdev = devm_thermal_of_cooling_device_register(dev,
|
||||
dev->of_node, "pwm-fan", ctx, &pwm_fan_cooling_ops);
|
||||
if (IS_ERR(cdev)) {
|
||||
ret = PTR_ERR(cdev);
|
||||
dev_err(&pdev->dev,
|
||||
dev_err(dev,
|
||||
"Failed to register pwm-fan as cooling device: %d\n",
|
||||
ret);
|
||||
goto err_del_timer;
|
||||
return ret;
|
||||
}
|
||||
ctx->cdev = cdev;
|
||||
thermal_cdev_update(cdev);
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -480,7 +460,6 @@ MODULE_DEVICE_TABLE(of, of_pwm_fan_match);
|
|||
|
||||
static struct platform_driver pwm_fan_driver = {
|
||||
.probe = pwm_fan_probe,
|
||||
.remove = pwm_fan_remove,
|
||||
.driver = {
|
||||
.name = "pwm-fan",
|
||||
.pm = &pwm_fan_pm,
|
||||
|
|
|
@ -200,6 +200,17 @@ config THERMAL_EMULATION
|
|||
because userland can easily disable the thermal policy by simply
|
||||
flooding this sysfs node with low temperature values.
|
||||
|
||||
config THERMAL_MMIO
|
||||
tristate "Generic Thermal MMIO driver"
|
||||
depends on OF || COMPILE_TEST
|
||||
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
|
||||
tristate "Hisilicon thermal driver"
|
||||
depends on ARCH_HISI || COMPILE_TEST
|
||||
|
|
|
@ -29,6 +29,7 @@ thermal_sys-$(CONFIG_DEVFREQ_THERMAL) += devfreq_cooling.o
|
|||
|
||||
# platform thermal drivers
|
||||
obj-y += broadcom/
|
||||
obj-$(CONFIG_THERMAL_MMIO) += thermal_mmio.o
|
||||
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
||||
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
|
||||
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
* Copyright (C) 2018 Broadcom
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_address.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);
|
||||
|
||||
static const struct acpi_device_id sr_thermal_acpi_ids[] = {
|
||||
{ .id = "BRCM0500" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, sr_thermal_acpi_ids);
|
||||
|
||||
static struct platform_driver sr_thermal_driver = {
|
||||
.probe = sr_thermal_probe,
|
||||
.driver = {
|
||||
.name = "sr-thermal",
|
||||
.of_match_table = sr_thermal_of_match,
|
||||
.acpi_match_table = ACPI_PTR(sr_thermal_acpi_ids),
|
||||
},
|
||||
};
|
||||
module_platform_driver(sr_thermal_driver);
|
||||
|
|
|
@ -1,26 +1,14 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* linux/drivers/thermal/cpu_cooling.c
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
* Authors: Amit Daniel <amit.kachhap@linaro.org>
|
||||
* Viresh Kumar <viresh.kumar@linaro.org>
|
||||
*
|
||||
* 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/thermal.h>
|
||||
|
@ -99,7 +87,6 @@ struct cpufreq_cooling_device {
|
|||
unsigned int clipped_freq;
|
||||
unsigned int max_level;
|
||||
struct freq_table *freq_table; /* In descending order */
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct cpufreq_policy *policy;
|
||||
struct list_head node;
|
||||
struct time_in_idle *idle_time;
|
||||
|
@ -207,8 +194,7 @@ static int update_freq_table(struct cpufreq_cooling_device *cpufreq_cdev,
|
|||
|
||||
dev = get_cpu_device(cpu);
|
||||
if (unlikely(!dev)) {
|
||||
dev_warn(&cpufreq_cdev->cdev->device,
|
||||
"No cpu device for cpu %d\n", cpu);
|
||||
pr_warn("No cpu device for cpu %d\n", cpu);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
@ -458,7 +444,7 @@ static int cpufreq_get_requested_power(struct thermal_cooling_device *cdev,
|
|||
load = 0;
|
||||
|
||||
total_load += load;
|
||||
if (trace_thermal_power_cpu_limit_enabled() && load_cpu)
|
||||
if (load_cpu)
|
||||
load_cpu[i] = load;
|
||||
|
||||
i++;
|
||||
|
@ -541,7 +527,6 @@ static int cpufreq_power2state(struct thermal_cooling_device *cdev,
|
|||
struct cpufreq_cooling_device *cpufreq_cdev = cdev->devdata;
|
||||
struct cpufreq_policy *policy = cpufreq_cdev->policy;
|
||||
|
||||
power = power > 0 ? power : 0;
|
||||
last_load = cpufreq_cdev->last_load ?: 1;
|
||||
normalised_power = (power * 100) / last_load;
|
||||
target_freq = cpu_power_to_freq(cpufreq_cdev, normalised_power);
|
||||
|
@ -692,7 +677,6 @@ __cpufreq_cooling_register(struct device_node *np,
|
|||
goto remove_ida;
|
||||
|
||||
cpufreq_cdev->clipped_freq = cpufreq_cdev->freq_table[0].frequency;
|
||||
cpufreq_cdev->cdev = cdev;
|
||||
|
||||
mutex_lock(&cooling_list_lock);
|
||||
/* Register the notifier for first cpufreq cooling device */
|
||||
|
@ -810,7 +794,7 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev)
|
|||
cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
|
||||
thermal_cooling_device_unregister(cpufreq_cdev->cdev);
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
ida_simple_remove(&cpufreq_ida, cpufreq_cdev->id);
|
||||
kfree(cpufreq_cdev->idle_time);
|
||||
kfree(cpufreq_cdev->freq_table);
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
* Copyright (C) 2013 Texas Instruments
|
||||
* Copyright (C) 2013 Eduardo Valentin <eduardo.valentin@ti.com>
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
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
|
||||
|
|
|
@ -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 TIMEOUT_US 100
|
||||
|
||||
static int suspend_8960(struct tsens_device *tmdev)
|
||||
static int suspend_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
unsigned int mask;
|
||||
struct regmap *map = tmdev->tm_map;
|
||||
struct regmap *map = priv->tm_map;
|
||||
|
||||
ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
|
||||
ret = regmap_read(map, THRESHOLD_ADDR, &priv->ctx.threshold);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
|
||||
ret = regmap_read(map, CNTL_ADDR, &priv->ctx.control);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tmdev->num_sensors > 1)
|
||||
if (priv->num_sensors > 1)
|
||||
mask = SLP_CLK_ENA | EN;
|
||||
else
|
||||
mask = SLP_CLK_ENA_8660 | EN;
|
||||
|
@ -82,10 +82,10 @@ static int suspend_8960(struct tsens_device *tmdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int resume_8960(struct tsens_device *tmdev)
|
||||
static int resume_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
struct regmap *map = tmdev->tm_map;
|
||||
struct regmap *map = priv->tm_map;
|
||||
|
||||
ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
|
||||
if (ret)
|
||||
|
@ -95,80 +95,80 @@ static int resume_8960(struct tsens_device *tmdev)
|
|||
* Separate CONFIG restore is not needed only for 8660 as
|
||||
* config is part of CTRL Addr and its restored as such
|
||||
*/
|
||||
if (tmdev->num_sensors > 1) {
|
||||
if (priv->num_sensors > 1) {
|
||||
ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
|
||||
ret = regmap_write(map, THRESHOLD_ADDR, priv->ctx.threshold);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
|
||||
ret = regmap_write(map, CNTL_ADDR, priv->ctx.control);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int enable_8960(struct tsens_device *tmdev, int id)
|
||||
static int enable_8960(struct tsens_priv *priv, int id)
|
||||
{
|
||||
int ret;
|
||||
u32 reg, mask;
|
||||
|
||||
ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®);
|
||||
ret = regmap_read(priv->tm_map, CNTL_ADDR, ®);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mask = BIT(id + SENSOR0_SHIFT);
|
||||
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST);
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg | SW_RST);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tmdev->num_sensors > 1)
|
||||
if (priv->num_sensors > 1)
|
||||
reg |= mask | SLP_CLK_ENA | EN;
|
||||
else
|
||||
reg |= mask | SLP_CLK_ENA_8660 | EN;
|
||||
|
||||
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg);
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void disable_8960(struct tsens_device *tmdev)
|
||||
static void disable_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
u32 reg_cntl;
|
||||
u32 mask;
|
||||
|
||||
mask = GENMASK(tmdev->num_sensors - 1, 0);
|
||||
mask = GENMASK(priv->num_sensors - 1, 0);
|
||||
mask <<= SENSOR0_SHIFT;
|
||||
mask |= EN;
|
||||
|
||||
ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®_cntl);
|
||||
ret = regmap_read(priv->tm_map, CNTL_ADDR, ®_cntl);
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
reg_cntl &= ~mask;
|
||||
|
||||
if (tmdev->num_sensors > 1)
|
||||
if (priv->num_sensors > 1)
|
||||
reg_cntl &= ~SLP_CLK_ENA;
|
||||
else
|
||||
reg_cntl &= ~SLP_CLK_ENA_8660;
|
||||
|
||||
regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
|
||||
regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||
}
|
||||
|
||||
static int init_8960(struct tsens_device *tmdev)
|
||||
static int init_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int ret, i;
|
||||
u32 reg_cntl;
|
||||
|
||||
tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL);
|
||||
if (!tmdev->tm_map)
|
||||
priv->tm_map = dev_get_regmap(priv->dev, NULL);
|
||||
if (!priv->tm_map)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
|
@ -177,21 +177,21 @@ static int init_8960(struct tsens_device *tmdev)
|
|||
* but the control registers stay in the same place, i.e
|
||||
* directly after the first 5 status registers.
|
||||
*/
|
||||
for (i = 0; i < tmdev->num_sensors; i++) {
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
if (i >= 5)
|
||||
tmdev->sensor[i].status = S0_STATUS_ADDR + 40;
|
||||
tmdev->sensor[i].status += i * 4;
|
||||
priv->sensor[i].status = S0_STATUS_ADDR + 40;
|
||||
priv->sensor[i].status += i * 4;
|
||||
}
|
||||
|
||||
reg_cntl = SW_RST;
|
||||
ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
|
||||
ret = regmap_update_bits(priv->tm_map, CNTL_ADDR, SW_RST, reg_cntl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tmdev->num_sensors > 1) {
|
||||
if (priv->num_sensors > 1) {
|
||||
reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
|
||||
reg_cntl &= ~SW_RST;
|
||||
ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR,
|
||||
ret = regmap_update_bits(priv->tm_map, CONFIG_ADDR,
|
||||
CONFIG_MASK, CONFIG);
|
||||
} else {
|
||||
reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
|
||||
|
@ -199,30 +199,30 @@ static int init_8960(struct tsens_device *tmdev)
|
|||
reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
|
||||
}
|
||||
|
||||
reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
|
||||
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
|
||||
reg_cntl |= GENMASK(priv->num_sensors - 1, 0) << SENSOR0_SHIFT;
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
reg_cntl |= EN;
|
||||
ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl);
|
||||
ret = regmap_write(priv->tm_map, CNTL_ADDR, reg_cntl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int calibrate_8960(struct tsens_device *tmdev)
|
||||
static int calibrate_8960(struct tsens_priv *priv)
|
||||
{
|
||||
int i;
|
||||
char *data;
|
||||
|
||||
ssize_t num_read = tmdev->num_sensors;
|
||||
struct tsens_sensor *s = tmdev->sensor;
|
||||
ssize_t num_read = priv->num_sensors;
|
||||
struct tsens_sensor *s = priv->sensor;
|
||||
|
||||
data = qfprom_read(tmdev->dev, "calib");
|
||||
data = qfprom_read(priv->dev, "calib");
|
||||
if (IS_ERR(data))
|
||||
data = qfprom_read(tmdev->dev, "calib_backup");
|
||||
data = qfprom_read(priv->dev, "calib_backup");
|
||||
if (IS_ERR(data))
|
||||
return PTR_ERR(data);
|
||||
|
||||
|
@ -243,21 +243,21 @@ static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
|
|||
return adc_code * slope + offset;
|
||||
}
|
||||
|
||||
static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp)
|
||||
static int get_temp_8960(struct tsens_priv *priv, int id, int *temp)
|
||||
{
|
||||
int ret;
|
||||
u32 code, trdy;
|
||||
const struct tsens_sensor *s = &tmdev->sensor[id];
|
||||
const struct tsens_sensor *s = &priv->sensor[id];
|
||||
unsigned long timeout;
|
||||
|
||||
timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
|
||||
do {
|
||||
ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy);
|
||||
ret = regmap_read(priv->tm_map, INT_STATUS_ADDR, &trdy);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (!(trdy & TRDY_MASK))
|
||||
continue;
|
||||
ret = regmap_read(tmdev->tm_map, s->status, &code);
|
||||
ret = regmap_read(priv->tm_map, s->status, &code);
|
||||
if (ret)
|
||||
return ret;
|
||||
*temp = code_to_mdegC(code, s);
|
||||
|
@ -277,7 +277,7 @@ static const struct tsens_ops ops_8960 = {
|
|||
.resume = resume_8960,
|
||||
};
|
||||
|
||||
const struct tsens_data data_8960 = {
|
||||
const struct tsens_plat_data data_8960 = {
|
||||
.num_sensors = 11,
|
||||
.ops = &ops_8960,
|
||||
};
|
||||
|
|
|
@ -12,18 +12,6 @@
|
|||
#include <linux/regmap.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)
|
||||
{
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
int i;
|
||||
int num, den;
|
||||
|
||||
for (i = 0; i < tmdev->num_sensors; i++) {
|
||||
dev_dbg(tmdev->dev,
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
dev_dbg(priv->dev,
|
||||
"sensor%d - data_point1:%#x data_point2:%#x\n",
|
||||
i, p1[i], p2[i]);
|
||||
|
||||
tmdev->sensor[i].slope = SLOPE_DEFAULT;
|
||||
priv->sensor[i].slope = SLOPE_DEFAULT;
|
||||
if (mode == TWO_PT_CALIB) {
|
||||
/*
|
||||
* slope (m) = adc_code2 - adc_code1 (y2 - y1)/
|
||||
|
@ -66,16 +54,30 @@ void compute_intercept_slope(struct tsens_device *tmdev, u32 *p1,
|
|||
num = p2[i] - p1[i];
|
||||
num *= SLOPE_FACTOR;
|
||||
den = CAL_DEGC_PT2 - CAL_DEGC_PT1;
|
||||
tmdev->sensor[i].slope = num / den;
|
||||
priv->sensor[i].slope = num / den;
|
||||
}
|
||||
|
||||
tmdev->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
|
||||
priv->sensor[i].offset = (p1[i] * SLOPE_FACTOR) -
|
||||
(CAL_DEGC_PT1 *
|
||||
tmdev->sensor[i].slope);
|
||||
dev_dbg(tmdev->dev, "offset:%d\n", tmdev->sensor[i].offset);
|
||||
priv->sensor[i].slope);
|
||||
dev_dbg(priv->dev, "offset:%d\n", priv->sensor[i].offset);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if ((hw_id > (priv->num_sensors - 1)) || (hw_id < 0))
|
||||
return -EINVAL;
|
||||
ret = regmap_field_read(priv->rf[SENSOR_EN], &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return val & (1 << hw_id);
|
||||
}
|
||||
|
||||
static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
|
||||
{
|
||||
int degc, num, den;
|
||||
|
@ -95,18 +97,54 @@ static inline int code_to_degc(u32 adc_code, const struct tsens_sensor *s)
|
|||
return degc;
|
||||
}
|
||||
|
||||
int get_temp_common(struct tsens_device *tmdev, int id, int *temp)
|
||||
int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp)
|
||||
{
|
||||
struct tsens_sensor *s = &tmdev->sensor[id];
|
||||
u32 code;
|
||||
unsigned int status_reg;
|
||||
int last_temp = 0, ret;
|
||||
struct tsens_sensor *s = &priv->sensor[i];
|
||||
u32 temp_idx = LAST_TEMP_0 + s->hw_id;
|
||||
u32 valid_idx = VALID_0 + s->hw_id;
|
||||
u32 last_temp = 0, valid, mask;
|
||||
int ret;
|
||||
|
||||
status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * SN_ADDR_OFFSET;
|
||||
ret = regmap_read(tmdev->tm_map, status_reg, &code);
|
||||
ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||
if (ret)
|
||||
return ret;
|
||||
while (!valid) {
|
||||
/* Valid bit is 0 for 6 AHB clock cycles.
|
||||
* At 19.2MHz, 1 AHB clock is ~60ns.
|
||||
* We should enter this loop very, very rarely.
|
||||
*/
|
||||
ndelay(400);
|
||||
ret = regmap_field_read(priv->rf[valid_idx], &valid);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Valid bit is set, OK to read the temperature */
|
||||
ret = regmap_field_read(priv->rf[temp_idx], &last_temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (priv->feat->adc) {
|
||||
/* Convert temperature from ADC code to milliCelsius */
|
||||
*temp = code_to_degc(last_temp, s) * 1000;
|
||||
} else {
|
||||
mask = GENMASK(priv->fields[LAST_TEMP_0].msb,
|
||||
priv->fields[LAST_TEMP_0].lsb);
|
||||
/* Convert temperature from deciCelsius to milliCelsius */
|
||||
*temp = sign_extend32(last_temp, fls(mask) - 1) * 100;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_temp_common(struct tsens_priv *priv, int i, int *temp)
|
||||
{
|
||||
struct tsens_sensor *s = &priv->sensor[i];
|
||||
int last_temp = 0, ret;
|
||||
|
||||
ret = regmap_field_read(priv->rf[LAST_TEMP_0 + s->hw_id], &last_temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
last_temp = code & SN_ST_TEMP_MASK;
|
||||
|
||||
*temp = code_to_degc(last_temp, s) * 1000;
|
||||
|
||||
|
@ -127,21 +165,21 @@ static const struct regmap_config tsens_srot_config = {
|
|||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
int __init init_common(struct tsens_device *tmdev)
|
||||
int __init init_common(struct tsens_priv *priv)
|
||||
{
|
||||
void __iomem *tm_base, *srot_base;
|
||||
struct device *dev = priv->dev;
|
||||
struct resource *res;
|
||||
u32 code;
|
||||
int ret;
|
||||
struct platform_device *op = of_find_device_by_node(tmdev->dev->of_node);
|
||||
u16 ctrl_offset = tmdev->reg_offsets[SROT_CTRL_OFFSET];
|
||||
u32 enabled;
|
||||
int ret, i, j;
|
||||
struct platform_device *op = of_find_device_by_node(priv->dev->of_node);
|
||||
|
||||
if (!op)
|
||||
return -EINVAL;
|
||||
|
||||
if (op->num_resources > 1) {
|
||||
/* DT with separate SROT and TM address space */
|
||||
tmdev->tm_offset = 0;
|
||||
priv->tm_offset = 0;
|
||||
res = platform_get_resource(op, IORESOURCE_MEM, 1);
|
||||
srot_base = devm_ioremap_resource(&op->dev, res);
|
||||
if (IS_ERR(srot_base)) {
|
||||
|
@ -149,16 +187,15 @@ int __init init_common(struct tsens_device *tmdev)
|
|||
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);
|
||||
if (IS_ERR(tmdev->srot_map)) {
|
||||
ret = PTR_ERR(tmdev->srot_map);
|
||||
if (IS_ERR(priv->srot_map)) {
|
||||
ret = PTR_ERR(priv->srot_map);
|
||||
goto err_put_device;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* old DTs where SROT and TM were in a contiguous 2K block */
|
||||
tmdev->tm_offset = 0x1000;
|
||||
priv->tm_offset = 0x1000;
|
||||
}
|
||||
|
||||
res = platform_get_resource(op, IORESOURCE_MEM, 0);
|
||||
|
@ -168,19 +205,47 @@ int __init init_common(struct tsens_device *tmdev)
|
|||
goto err_put_device;
|
||||
}
|
||||
|
||||
tmdev->tm_map = devm_regmap_init_mmio(tmdev->dev, tm_base, &tsens_config);
|
||||
if (IS_ERR(tmdev->tm_map)) {
|
||||
ret = PTR_ERR(tmdev->tm_map);
|
||||
priv->tm_map = devm_regmap_init_mmio(dev, tm_base, &tsens_config);
|
||||
if (IS_ERR(priv->tm_map)) {
|
||||
ret = PTR_ERR(priv->tm_map);
|
||||
goto err_put_device;
|
||||
}
|
||||
|
||||
if (tmdev->srot_map) {
|
||||
ret = regmap_read(tmdev->srot_map, ctrl_offset, &code);
|
||||
if (ret)
|
||||
priv->rf[TSENS_EN] = devm_regmap_field_alloc(dev, priv->srot_map,
|
||||
priv->fields[TSENS_EN]);
|
||||
if (IS_ERR(priv->rf[TSENS_EN])) {
|
||||
ret = PTR_ERR(priv->rf[TSENS_EN]);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,48 @@
|
|||
#include <linux/platform_device.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 */
|
||||
#define BASE1_MASK 0xff
|
||||
#define S0_P1_MASK 0x3f00
|
||||
|
@ -91,7 +133,59 @@
|
|||
|
||||
#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;
|
||||
u32 p1[11], p2[11];
|
||||
|
@ -99,11 +193,11 @@ static int calibrate_8974(struct tsens_device *tmdev)
|
|||
u32 *calib, *bkp;
|
||||
u32 calib_redun_sel;
|
||||
|
||||
calib = (u32 *)qfprom_read(tmdev->dev, "calib");
|
||||
calib = (u32 *)qfprom_read(priv->dev, "calib");
|
||||
if (IS_ERR(calib))
|
||||
return PTR_ERR(calib);
|
||||
|
||||
bkp = (u32 *)qfprom_read(tmdev->dev, "calib_backup");
|
||||
bkp = (u32 *)qfprom_read(priv->dev, "calib_backup");
|
||||
if (IS_ERR(bkp))
|
||||
return PTR_ERR(bkp);
|
||||
|
||||
|
@ -184,25 +278,25 @@ static int calibrate_8974(struct tsens_device *tmdev)
|
|||
|
||||
switch (mode) {
|
||||
case ONE_PT_CALIB:
|
||||
for (i = 0; i < tmdev->num_sensors; i++)
|
||||
for (i = 0; i < priv->num_sensors; i++)
|
||||
p1[i] += (base1 << 2) | BIT_APPEND;
|
||||
break;
|
||||
case TWO_PT_CALIB:
|
||||
for (i = 0; i < tmdev->num_sensors; i++) {
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
p2[i] += base2;
|
||||
p2[i] <<= 2;
|
||||
p2[i] |= BIT_APPEND;
|
||||
}
|
||||
/* Fall through */
|
||||
case ONE_PT_CALIB2:
|
||||
for (i = 0; i < tmdev->num_sensors; i++) {
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
p1[i] += base1;
|
||||
p1[i] <<= 2;
|
||||
p1[i] |= BIT_APPEND;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (i = 0; i < tmdev->num_sensors; i++)
|
||||
for (i = 0; i < priv->num_sensors; i++)
|
||||
p2[i] = 780;
|
||||
p1[0] = 502;
|
||||
p1[1] = 509;
|
||||
|
@ -218,19 +312,71 @@ static int calibrate_8974(struct tsens_device *tmdev)
|
|||
break;
|
||||
}
|
||||
|
||||
compute_intercept_slope(tmdev, p1, p2, mode);
|
||||
compute_intercept_slope(priv, p1, p2, mode);
|
||||
|
||||
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 = {
|
||||
.init = init_common,
|
||||
.calibrate = calibrate_8974,
|
||||
.get_temp = get_temp_common,
|
||||
};
|
||||
|
||||
const struct tsens_data data_8974 = {
|
||||
const struct tsens_plat_data data_8974 = {
|
||||
.num_sensors = 11,
|
||||
.ops = &ops_8974,
|
||||
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x0 },
|
||||
.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
|
||||
*/
|
||||
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/regmap.h>
|
||||
#include "tsens.h"
|
||||
|
||||
#define STATUS_OFFSET 0xa0
|
||||
#define LAST_TEMP_MASK 0xfff
|
||||
#define STATUS_VALID_BIT BIT(21)
|
||||
/* ----- SROT ------ */
|
||||
#define SROT_HW_VER_OFF 0x0000
|
||||
#define SROT_CTRL_OFF 0x0004
|
||||
|
||||
static int get_temp_tsens_v2(struct tsens_device *tmdev, int id, int *temp)
|
||||
{
|
||||
struct tsens_sensor *s = &tmdev->sensor[id];
|
||||
u32 code;
|
||||
unsigned int status_reg;
|
||||
u32 last_temp = 0, last_temp2 = 0, last_temp3 = 0;
|
||||
int ret;
|
||||
/* ----- TM ------ */
|
||||
#define TM_INT_EN_OFF 0x0004
|
||||
#define TM_UPPER_LOWER_INT_STATUS_OFF 0x0008
|
||||
#define TM_UPPER_LOWER_INT_CLEAR_OFF 0x000c
|
||||
#define TM_UPPER_LOWER_INT_MASK_OFF 0x0010
|
||||
#define TM_CRITICAL_INT_STATUS_OFF 0x0014
|
||||
#define TM_CRITICAL_INT_CLEAR_OFF 0x0018
|
||||
#define TM_CRITICAL_INT_MASK_OFF 0x001c
|
||||
#define TM_Sn_UPPER_LOWER_THRESHOLD_OFF 0x0020
|
||||
#define TM_Sn_CRITICAL_THRESHOLD_OFF 0x0060
|
||||
#define TM_Sn_STATUS_OFF 0x00a0
|
||||
#define TM_TRDY_OFF 0x00e4
|
||||
|
||||
status_reg = tmdev->tm_offset + STATUS_OFFSET + s->hw_id * 4;
|
||||
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;
|
||||
/* v2.x: 8996, 8998, sdm845 */
|
||||
|
||||
/* Try a second time */
|
||||
ret = regmap_read(tmdev->tm_map, status_reg, &code);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (code & STATUS_VALID_BIT) {
|
||||
last_temp = code & LAST_TEMP_MASK;
|
||||
goto done;
|
||||
} else {
|
||||
last_temp2 = code & LAST_TEMP_MASK;
|
||||
}
|
||||
static const struct tsens_features tsens_v2_feat = {
|
||||
.ver_major = VER_2_X,
|
||||
.crit_int = 1,
|
||||
.adc = 0,
|
||||
.srot_split = 1,
|
||||
.max_sensors = 16,
|
||||
};
|
||||
|
||||
/* Try a third/last time */
|
||||
ret = regmap_read(tmdev->tm_map, status_reg, &code);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (code & STATUS_VALID_BIT) {
|
||||
last_temp = code & LAST_TEMP_MASK;
|
||||
goto done;
|
||||
} else {
|
||||
last_temp3 = code & LAST_TEMP_MASK;
|
||||
}
|
||||
static const struct reg_field tsens_v2_regfields[MAX_REGFIELDS] = {
|
||||
/* ----- SROT ------ */
|
||||
/* VERSION */
|
||||
[VER_MAJOR] = REG_FIELD(SROT_HW_VER_OFF, 28, 31),
|
||||
[VER_MINOR] = REG_FIELD(SROT_HW_VER_OFF, 16, 27),
|
||||
[VER_STEP] = REG_FIELD(SROT_HW_VER_OFF, 0, 15),
|
||||
/* CTRL_OFF */
|
||||
[TSENS_EN] = REG_FIELD(SROT_CTRL_OFF, 0, 0),
|
||||
[TSENS_SW_RST] = REG_FIELD(SROT_CTRL_OFF, 1, 1),
|
||||
[SENSOR_EN] = REG_FIELD(SROT_CTRL_OFF, 3, 18),
|
||||
|
||||
if (last_temp == last_temp2)
|
||||
last_temp = last_temp2;
|
||||
else if (last_temp2 == last_temp3)
|
||||
last_temp = last_temp3;
|
||||
done:
|
||||
/* Convert temperature from deciCelsius to milliCelsius */
|
||||
*temp = sign_extend32(last_temp, fls(LAST_TEMP_MASK) - 1) * 100;
|
||||
/* ----- TM ------ */
|
||||
/* INTERRUPT ENABLE */
|
||||
/* v2 has separate enables for UPPER/LOWER/CRITICAL interrupts */
|
||||
[INT_EN] = REG_FIELD(TM_INT_EN_OFF, 0, 2),
|
||||
|
||||
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 = {
|
||||
.init = init_common,
|
||||
.get_temp = get_temp_tsens_v2,
|
||||
.get_temp = get_temp_tsens_valid,
|
||||
};
|
||||
|
||||
const struct tsens_data data_tsens_v2 = {
|
||||
.ops = &ops_generic_v2,
|
||||
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 },
|
||||
const struct tsens_plat_data data_tsens_v2 = {
|
||||
.ops = &ops_generic_v2,
|
||||
.feat = &tsens_v2_feat,
|
||||
.fields = tsens_v2_regfields,
|
||||
};
|
||||
|
||||
/* Kept around for backward compatibility with old msm8996.dtsi */
|
||||
const struct tsens_data data_8996 = {
|
||||
const struct tsens_plat_data data_8996 = {
|
||||
.num_sensors = 13,
|
||||
.ops = &ops_generic_v2,
|
||||
.reg_offsets = { [SROT_CTRL_OFFSET] = 0x4 },
|
||||
.feat = &tsens_v2_feat,
|
||||
.fields = tsens_v2_regfields,
|
||||
};
|
||||
|
|
|
@ -15,38 +15,38 @@
|
|||
static int tsens_get_temp(void *data, int *temp)
|
||||
{
|
||||
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;
|
||||
struct tsens_device *tmdev = s->tmdev;
|
||||
const struct tsens_sensor *s = data;
|
||||
struct tsens_priv *priv = s->priv;
|
||||
|
||||
if (tmdev->ops->get_trend)
|
||||
return tmdev->ops->get_trend(tmdev, s->id, trend);
|
||||
if (priv->ops->get_trend)
|
||||
return priv->ops->get_trend(priv, s->id, trend);
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static int __maybe_unused tsens_suspend(struct device *dev)
|
||||
{
|
||||
struct tsens_device *tmdev = dev_get_drvdata(dev);
|
||||
struct tsens_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (tmdev->ops && tmdev->ops->suspend)
|
||||
return tmdev->ops->suspend(tmdev);
|
||||
if (priv->ops && priv->ops->suspend)
|
||||
return priv->ops->suspend(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused tsens_resume(struct device *dev)
|
||||
{
|
||||
struct tsens_device *tmdev = dev_get_drvdata(dev);
|
||||
struct tsens_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
if (tmdev->ops && tmdev->ops->resume)
|
||||
return tmdev->ops->resume(tmdev);
|
||||
if (priv->ops && priv->ops->resume)
|
||||
return priv->ops->resume(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -63,6 +63,9 @@ static const struct of_device_id tsens_table[] = {
|
|||
}, {
|
||||
.compatible = "qcom,msm8996-tsens",
|
||||
.data = &data_8996,
|
||||
}, {
|
||||
.compatible = "qcom,tsens-v1",
|
||||
.data = &data_tsens_v1,
|
||||
}, {
|
||||
.compatible = "qcom,tsens-v2",
|
||||
.data = &data_tsens_v2,
|
||||
|
@ -76,22 +79,27 @@ static const struct thermal_zone_of_device_ops tsens_of_ops = {
|
|||
.get_trend = tsens_get_trend,
|
||||
};
|
||||
|
||||
static int tsens_register(struct tsens_device *tmdev)
|
||||
static int tsens_register(struct tsens_priv *priv)
|
||||
{
|
||||
int i;
|
||||
struct thermal_zone_device *tzd;
|
||||
|
||||
for (i = 0; i < tmdev->num_sensors; i++) {
|
||||
tmdev->sensor[i].tmdev = tmdev;
|
||||
tmdev->sensor[i].id = i;
|
||||
tzd = devm_thermal_zone_of_sensor_register(tmdev->dev, i,
|
||||
&tmdev->sensor[i],
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
if (!is_sensor_enabled(priv, priv->sensor[i].hw_id)) {
|
||||
dev_err(priv->dev, "sensor %d: disabled\n",
|
||||
priv->sensor[i].hw_id);
|
||||
continue;
|
||||
}
|
||||
priv->sensor[i].priv = priv;
|
||||
priv->sensor[i].id = i;
|
||||
tzd = devm_thermal_zone_of_sensor_register(priv->dev, i,
|
||||
&priv->sensor[i],
|
||||
&tsens_of_ops);
|
||||
if (IS_ERR(tzd))
|
||||
continue;
|
||||
tmdev->sensor[i].tzd = tzd;
|
||||
if (tmdev->ops->enable)
|
||||
tmdev->ops->enable(tmdev, i);
|
||||
priv->sensor[i].tzd = tzd;
|
||||
if (priv->ops->enable)
|
||||
priv->ops->enable(priv, i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -101,8 +109,8 @@ static int tsens_probe(struct platform_device *pdev)
|
|||
int ret, i;
|
||||
struct device *dev;
|
||||
struct device_node *np;
|
||||
struct tsens_device *tmdev;
|
||||
const struct tsens_data *data;
|
||||
struct tsens_priv *priv;
|
||||
const struct tsens_plat_data *data;
|
||||
const struct of_device_id *id;
|
||||
u32 num_sensors;
|
||||
|
||||
|
@ -129,55 +137,55 @@ static int tsens_probe(struct platform_device *pdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
tmdev = devm_kzalloc(dev,
|
||||
struct_size(tmdev, sensor, num_sensors),
|
||||
priv = devm_kzalloc(dev,
|
||||
struct_size(priv, sensor, num_sensors),
|
||||
GFP_KERNEL);
|
||||
if (!tmdev)
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
tmdev->dev = dev;
|
||||
tmdev->num_sensors = num_sensors;
|
||||
tmdev->ops = data->ops;
|
||||
for (i = 0; i < tmdev->num_sensors; i++) {
|
||||
priv->dev = dev;
|
||||
priv->num_sensors = num_sensors;
|
||||
priv->ops = data->ops;
|
||||
for (i = 0; i < priv->num_sensors; i++) {
|
||||
if (data->hw_ids)
|
||||
tmdev->sensor[i].hw_id = data->hw_ids[i];
|
||||
priv->sensor[i].hw_id = data->hw_ids[i];
|
||||
else
|
||||
tmdev->sensor[i].hw_id = i;
|
||||
}
|
||||
for (i = 0; i < REG_ARRAY_SIZE; i++) {
|
||||
tmdev->reg_offsets[i] = data->reg_offsets[i];
|
||||
priv->sensor[i].hw_id = 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;
|
||||
|
||||
ret = tmdev->ops->init(tmdev);
|
||||
ret = priv->ops->init(priv);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "tsens init failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (tmdev->ops->calibrate) {
|
||||
ret = tmdev->ops->calibrate(tmdev);
|
||||
if (priv->ops->calibrate) {
|
||||
ret = priv->ops->calibrate(priv);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "tsens calibration failed\n");
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "tsens calibration failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ret = tsens_register(tmdev);
|
||||
ret = tsens_register(priv);
|
||||
|
||||
platform_set_drvdata(pdev, tmdev);
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tsens_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tsens_device *tmdev = platform_get_drvdata(pdev);
|
||||
struct tsens_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
if (tmdev->ops->disable)
|
||||
tmdev->ops->disable(tmdev);
|
||||
if (priv->ops->disable)
|
||||
priv->ops->disable(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -9,17 +9,39 @@
|
|||
#define ONE_PT_CALIB 0x1
|
||||
#define ONE_PT_CALIB2 0x2
|
||||
#define TWO_PT_CALIB 0x3
|
||||
#define CAL_DEGC_PT1 30
|
||||
#define CAL_DEGC_PT2 120
|
||||
#define SLOPE_FACTOR 1000
|
||||
#define SLOPE_DEFAULT 3200
|
||||
|
||||
|
||||
#include <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_device *tmdev;
|
||||
struct tsens_priv *priv;
|
||||
struct thermal_zone_device *tzd;
|
||||
int offset;
|
||||
int id;
|
||||
int hw_id;
|
||||
unsigned int id;
|
||||
unsigned int hw_id;
|
||||
int slope;
|
||||
u32 status;
|
||||
};
|
||||
|
@ -37,63 +59,274 @@ struct tsens_sensor {
|
|||
*/
|
||||
struct tsens_ops {
|
||||
/* mandatory callbacks */
|
||||
int (*init)(struct tsens_device *);
|
||||
int (*calibrate)(struct tsens_device *);
|
||||
int (*get_temp)(struct tsens_device *, int, int *);
|
||||
int (*init)(struct tsens_priv *priv);
|
||||
int (*calibrate)(struct tsens_priv *priv);
|
||||
int (*get_temp)(struct tsens_priv *priv, int i, int *temp);
|
||||
/* optional callbacks */
|
||||
int (*enable)(struct tsens_device *, int);
|
||||
void (*disable)(struct tsens_device *);
|
||||
int (*suspend)(struct tsens_device *);
|
||||
int (*resume)(struct tsens_device *);
|
||||
int (*get_trend)(struct tsens_device *, int, enum thermal_trend *);
|
||||
int (*enable)(struct tsens_priv *priv, int i);
|
||||
void (*disable)(struct tsens_priv *priv);
|
||||
int (*suspend)(struct tsens_priv *priv);
|
||||
int (*resume)(struct tsens_priv *priv);
|
||||
int (*get_trend)(struct tsens_priv *priv, int i, enum thermal_trend *trend);
|
||||
};
|
||||
|
||||
enum reg_list {
|
||||
SROT_CTRL_OFFSET,
|
||||
#define REG_FIELD_FOR_EACH_SENSOR11(_name, _offset, _startbit, _stopbit) \
|
||||
[_name##_##0] = REG_FIELD(_offset, _startbit, _stopbit), \
|
||||
[_name##_##1] = REG_FIELD(_offset + 4, _startbit, _stopbit), \
|
||||
[_name##_##2] = REG_FIELD(_offset + 8, _startbit, _stopbit), \
|
||||
[_name##_##3] = REG_FIELD(_offset + 12, _startbit, _stopbit), \
|
||||
[_name##_##4] = REG_FIELD(_offset + 16, _startbit, _stopbit), \
|
||||
[_name##_##5] = REG_FIELD(_offset + 20, _startbit, _stopbit), \
|
||||
[_name##_##6] = REG_FIELD(_offset + 24, _startbit, _stopbit), \
|
||||
[_name##_##7] = REG_FIELD(_offset + 28, _startbit, _stopbit), \
|
||||
[_name##_##8] = REG_FIELD(_offset + 32, _startbit, _stopbit), \
|
||||
[_name##_##9] = REG_FIELD(_offset + 36, _startbit, _stopbit), \
|
||||
[_name##_##10] = REG_FIELD(_offset + 40, _startbit, _stopbit)
|
||||
|
||||
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
|
||||
* @num_sensors: Max number of sensors supported by platform
|
||||
* @ops: operations the tsens instance supports
|
||||
* @hw_ids: Subset of sensors ids supported by platform, if not the first n
|
||||
* @reg_offsets: Register offsets for commonly used registers
|
||||
* struct tsens_features - Features supported by the IP
|
||||
* @ver_major: Major number of IP version
|
||||
* @crit_int: does the IP support critical interrupts?
|
||||
* @adc: do the sensors only output adc code (instead of temperature)?
|
||||
* @srot_split: does the IP neatly splits the register space into SROT and TM,
|
||||
* with SROT only being available to secure boot firmware?
|
||||
* @max_sensors: maximum sensors supported by this version of the IP
|
||||
*/
|
||||
struct tsens_data {
|
||||
const u32 num_sensors;
|
||||
const struct tsens_ops *ops;
|
||||
const u16 reg_offsets[REG_ARRAY_SIZE];
|
||||
unsigned int *hw_ids;
|
||||
struct tsens_features {
|
||||
unsigned int ver_major;
|
||||
unsigned int crit_int:1;
|
||||
unsigned int adc:1;
|
||||
unsigned int srot_split:1;
|
||||
unsigned int max_sensors;
|
||||
};
|
||||
|
||||
/* 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 {
|
||||
int threshold;
|
||||
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;
|
||||
u32 num_sensors;
|
||||
struct regmap *tm_map;
|
||||
struct regmap *srot_map;
|
||||
u32 tm_offset;
|
||||
u16 reg_offsets[REG_ARRAY_SIZE];
|
||||
struct regmap_field *rf[MAX_REGFIELDS];
|
||||
struct tsens_context ctx;
|
||||
const struct tsens_features *feat;
|
||||
const struct reg_field *fields;
|
||||
const struct tsens_ops *ops;
|
||||
struct tsens_sensor sensor[0];
|
||||
};
|
||||
|
||||
char *qfprom_read(struct device *, const char *);
|
||||
void compute_intercept_slope(struct tsens_device *, u32 *, u32 *, u32);
|
||||
int init_common(struct tsens_device *);
|
||||
int get_temp_common(struct tsens_device *, int, int *);
|
||||
char *qfprom_read(struct device *dev, const char *cname);
|
||||
void compute_intercept_slope(struct tsens_priv *priv, u32 *pt1, u32 *pt2, u32 mode);
|
||||
int init_common(struct tsens_priv *priv);
|
||||
int get_temp_tsens_valid(struct tsens_priv *priv, int i, int *temp);
|
||||
int get_temp_common(struct tsens_priv *priv, int i, int *temp);
|
||||
bool is_sensor_enabled(struct tsens_priv *priv, u32 hw_id);
|
||||
|
||||
/* 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 */
|
||||
extern const struct tsens_data data_8916, data_8974, data_8960;
|
||||
extern const struct tsens_plat_data data_tsens_v1;
|
||||
|
||||
/* 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__ */
|
||||
|
|
|
@ -193,11 +193,6 @@ static int qoriq_tmu_probe(struct platform_device *pdev)
|
|||
struct qoriq_tmu_data *data;
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
|
||||
if (!np) {
|
||||
dev_err(&pdev->dev, "Device OF-Node is NULL");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
data = devm_kzalloc(&pdev->dev, sizeof(struct qoriq_tmu_data),
|
||||
GFP_KERNEL);
|
||||
if (!data)
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
|
@ -82,7 +81,6 @@ struct rcar_gen3_thermal_tsc {
|
|||
struct rcar_gen3_thermal_priv {
|
||||
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
|
||||
unsigned int num_tscs;
|
||||
spinlock_t lock; /* Protect interrupts on and off */
|
||||
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
|
||||
};
|
||||
|
||||
|
@ -232,38 +230,16 @@ static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
|
|||
{
|
||||
struct rcar_gen3_thermal_priv *priv = data;
|
||||
u32 status;
|
||||
int i, ret = IRQ_HANDLED;
|
||||
int i;
|
||||
|
||||
spin_lock(&priv->lock);
|
||||
for (i = 0; i < priv->num_tscs; i++) {
|
||||
status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
|
||||
rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
|
||||
if (status)
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
thermal_zone_device_update(priv->tscs[i]->zone,
|
||||
THERMAL_EVENT_UNSPECIFIED);
|
||||
}
|
||||
|
||||
if (ret == IRQ_WAKE_THREAD)
|
||||
rcar_thermal_irq_set(priv, false);
|
||||
|
||||
spin_unlock(&priv->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rcar_gen3_thermal_irq_thread(int irq, void *data)
|
||||
{
|
||||
struct rcar_gen3_thermal_priv *priv = data;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < priv->num_tscs; i++)
|
||||
thermal_zone_device_update(priv->tscs[i]->zone,
|
||||
THERMAL_EVENT_UNSPECIFIED);
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
rcar_thermal_irq_set(priv, true);
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -307,7 +283,7 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
|||
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
|
||||
|
||||
|
@ -331,6 +307,9 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
|||
static int rcar_gen3_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
|
||||
|
||||
rcar_thermal_irq_set(priv, false);
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
@ -371,8 +350,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
if (soc_device_match(r8a7795es1))
|
||||
priv->thermal_init = rcar_gen3_thermal_init_r8a7795es1;
|
||||
|
||||
spin_lock_init(&priv->lock);
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
/*
|
||||
|
@ -390,9 +367,9 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
if (!irqname)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq, rcar_gen3_thermal_irq,
|
||||
rcar_gen3_thermal_irq_thread,
|
||||
IRQF_SHARED, irqname, priv);
|
||||
ret = devm_request_threaded_irq(dev, irq, NULL,
|
||||
rcar_gen3_thermal_irq,
|
||||
IRQF_ONESHOT, irqname, priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -433,10 +410,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
}
|
||||
tsc->zone = zone;
|
||||
|
||||
ret = of_thermal_get_ntrips(tsc->zone);
|
||||
if (ret < 0)
|
||||
goto error_unregister;
|
||||
|
||||
tsc->zone->tzp->no_hwmon = false;
|
||||
ret = thermal_add_hwmon_sysfs(tsc->zone);
|
||||
if (ret)
|
||||
|
@ -448,6 +421,10 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
|||
goto error_unregister;
|
||||
}
|
||||
|
||||
ret = of_thermal_get_ntrips(tsc->zone);
|
||||
if (ret < 0)
|
||||
goto error_unregister;
|
||||
|
||||
dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ struct rcar_thermal_chip {
|
|||
unsigned int irq_per_ch : 1;
|
||||
unsigned int needs_suspend_resume : 1;
|
||||
unsigned int nirqs;
|
||||
unsigned int ctemp_bands;
|
||||
};
|
||||
|
||||
static const struct rcar_thermal_chip rcar_thermal = {
|
||||
|
@ -60,6 +61,7 @@ static const struct rcar_thermal_chip rcar_thermal = {
|
|||
.irq_per_ch = 0,
|
||||
.needs_suspend_resume = 0,
|
||||
.nirqs = 1,
|
||||
.ctemp_bands = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_thermal_chip rcar_gen2_thermal = {
|
||||
|
@ -68,6 +70,7 @@ static const struct rcar_thermal_chip rcar_gen2_thermal = {
|
|||
.irq_per_ch = 0,
|
||||
.needs_suspend_resume = 0,
|
||||
.nirqs = 1,
|
||||
.ctemp_bands = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_thermal_chip rcar_gen3_thermal = {
|
||||
|
@ -80,6 +83,7 @@ static const struct rcar_thermal_chip rcar_gen3_thermal = {
|
|||
* interrupts to detect a temperature change, rise or fall.
|
||||
*/
|
||||
.nirqs = 2,
|
||||
.ctemp_bands = 2,
|
||||
};
|
||||
|
||||
struct rcar_thermal_priv {
|
||||
|
@ -263,7 +267,12 @@ static int rcar_thermal_get_current_temp(struct rcar_thermal_priv *priv,
|
|||
return ret;
|
||||
|
||||
mutex_lock(&priv->lock);
|
||||
tmp = MCELSIUS((priv->ctemp * 5) - 65);
|
||||
if (priv->chip->ctemp_bands == 1)
|
||||
tmp = MCELSIUS((priv->ctemp * 5) - 65);
|
||||
else if (priv->ctemp < 24)
|
||||
tmp = MCELSIUS(((priv->ctemp * 55) - 720) / 10);
|
||||
else
|
||||
tmp = MCELSIUS((priv->ctemp * 5) - 60);
|
||||
mutex_unlock(&priv->lock);
|
||||
|
||||
if ((tmp < MCELSIUS(-45)) || (tmp > MCELSIUS(125))) {
|
||||
|
|
|
@ -172,6 +172,9 @@ struct rockchip_thermal_data {
|
|||
int tshut_temp;
|
||||
enum tshut_mode tshut_mode;
|
||||
enum tshut_polarity tshut_polarity;
|
||||
struct pinctrl *pinctrl;
|
||||
struct pinctrl_state *gpio_state;
|
||||
struct pinctrl_state *otp_state;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -222,11 +225,15 @@ struct rockchip_thermal_data {
|
|||
#define GRF_TSADC_TESTBIT_L 0x0e648
|
||||
#define GRF_TSADC_TESTBIT_H 0x0e64c
|
||||
|
||||
#define PX30_GRF_SOC_CON2 0x0408
|
||||
|
||||
#define GRF_SARADC_TESTBIT_ON (0x10001 << 2)
|
||||
#define GRF_TSADC_TESTBIT_H_ON (0x10001 << 2)
|
||||
#define GRF_TSADC_VCM_EN_L (0x10001 << 7)
|
||||
#define GRF_TSADC_VCM_EN_H (0x10001 << 7)
|
||||
|
||||
#define GRF_CON_TSADC_CH_INV (0x10001 << 1)
|
||||
|
||||
/**
|
||||
* struct tsadc_table - code to temperature conversion table
|
||||
* @code: the value of adc channel
|
||||
|
@ -689,6 +696,13 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs,
|
|||
regs + TSADCV2_AUTO_CON);
|
||||
}
|
||||
|
||||
static void rk_tsadcv4_initialize(struct regmap *grf, void __iomem *regs,
|
||||
enum tshut_polarity tshut_polarity)
|
||||
{
|
||||
rk_tsadcv2_initialize(grf, regs, tshut_polarity);
|
||||
regmap_write(grf, PX30_GRF_SOC_CON2, GRF_CON_TSADC_CH_INV);
|
||||
}
|
||||
|
||||
static void rk_tsadcv2_irq_ack(void __iomem *regs)
|
||||
{
|
||||
u32 val;
|
||||
|
@ -818,6 +832,30 @@ static void rk_tsadcv2_tshut_mode(int chn, void __iomem *regs,
|
|||
writel_relaxed(val, regs + TSADCV2_INT_EN);
|
||||
}
|
||||
|
||||
static const struct rockchip_tsadc_chip px30_tsadc_data = {
|
||||
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
|
||||
.chn_id[SENSOR_GPU] = 1, /* gpu sensor is channel 1 */
|
||||
.chn_num = 2, /* 2 channels for tsadc */
|
||||
|
||||
.tshut_mode = TSHUT_MODE_CRU, /* default TSHUT via CRU */
|
||||
.tshut_temp = 95000,
|
||||
|
||||
.initialize = rk_tsadcv4_initialize,
|
||||
.irq_ack = rk_tsadcv3_irq_ack,
|
||||
.control = rk_tsadcv3_control,
|
||||
.get_temp = rk_tsadcv2_get_temp,
|
||||
.set_alarm_temp = rk_tsadcv2_alarm_temp,
|
||||
.set_tshut_temp = rk_tsadcv2_tshut_temp,
|
||||
.set_tshut_mode = rk_tsadcv2_tshut_mode,
|
||||
|
||||
.table = {
|
||||
.id = rk3328_code_table,
|
||||
.length = ARRAY_SIZE(rk3328_code_table),
|
||||
.data_mask = TSADCV2_DATA_MASK,
|
||||
.mode = ADC_INCREMENT,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct rockchip_tsadc_chip rv1108_tsadc_data = {
|
||||
.chn_id[SENSOR_CPU] = 0, /* cpu sensor is channel 0 */
|
||||
.chn_num = 1, /* one channel for tsadc */
|
||||
|
@ -990,6 +1028,9 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
|
|||
};
|
||||
|
||||
static const struct of_device_id of_rockchip_thermal_match[] = {
|
||||
{ .compatible = "rockchip,px30-tsadc",
|
||||
.data = (void *)&px30_tsadc_data,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rv1108-tsadc",
|
||||
.data = (void *)&rv1108_tsadc_data,
|
||||
|
@ -1242,6 +1283,8 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
|
|||
return error;
|
||||
}
|
||||
|
||||
thermal->chip->control(thermal->regs, false);
|
||||
|
||||
error = clk_prepare_enable(thermal->clk);
|
||||
if (error) {
|
||||
dev_err(&pdev->dev, "failed to enable converter clock: %d\n",
|
||||
|
@ -1267,6 +1310,30 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
|
|||
thermal->chip->initialize(thermal->grf, thermal->regs,
|
||||
thermal->tshut_polarity);
|
||||
|
||||
if (thermal->tshut_mode == TSHUT_MODE_GPIO) {
|
||||
thermal->pinctrl = devm_pinctrl_get(&pdev->dev);
|
||||
if (IS_ERR(thermal->pinctrl)) {
|
||||
dev_err(&pdev->dev, "failed to find thermal pinctrl\n");
|
||||
return PTR_ERR(thermal->pinctrl);
|
||||
}
|
||||
|
||||
thermal->gpio_state = pinctrl_lookup_state(thermal->pinctrl,
|
||||
"gpio");
|
||||
if (IS_ERR_OR_NULL(thermal->gpio_state)) {
|
||||
dev_err(&pdev->dev, "failed to find thermal gpio state\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
thermal->otp_state = pinctrl_lookup_state(thermal->pinctrl,
|
||||
"otpout");
|
||||
if (IS_ERR_OR_NULL(thermal->otp_state)) {
|
||||
dev_err(&pdev->dev, "failed to find thermal otpout state\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pinctrl_select_state(thermal->pinctrl, thermal->otp_state);
|
||||
}
|
||||
|
||||
for (i = 0; i < thermal->chip->chn_num; i++) {
|
||||
error = rockchip_thermal_register_sensor(pdev, thermal,
|
||||
&thermal->sensors[i],
|
||||
|
@ -1337,8 +1404,8 @@ static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
|
|||
|
||||
clk_disable(thermal->pclk);
|
||||
clk_disable(thermal->clk);
|
||||
|
||||
pinctrl_pm_select_sleep_state(dev);
|
||||
if (thermal->tshut_mode == TSHUT_MODE_GPIO)
|
||||
pinctrl_select_state(thermal->pinctrl, thermal->gpio_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1383,7 +1450,8 @@ static int __maybe_unused rockchip_thermal_resume(struct device *dev)
|
|||
for (i = 0; i < thermal->chip->chn_num; i++)
|
||||
rockchip_thermal_toggle_sensor(&thermal->sensors[i], true);
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
if (thermal->tshut_mode == TSHUT_MODE_GPIO)
|
||||
pinctrl_select_state(thermal->pinctrl, thermal->otp_state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
#
|
||||
|
||||
config ST_THERMAL
|
||||
tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
|
||||
help
|
||||
Support for thermal sensors on STMicroelectronics STi series of SoCs.
|
||||
tristate "Thermal sensors on STMicroelectronics STi series of SoCs"
|
||||
help
|
||||
Support for thermal sensors on STMicroelectronics STi series of SoCs.
|
||||
|
||||
config ST_THERMAL_SYSCFG
|
||||
select ST_THERMAL
|
||||
|
@ -16,11 +16,11 @@ config ST_THERMAL_MEMMAP
|
|||
tristate "STi series memory mapped access based thermal sensors"
|
||||
|
||||
config STM32_THERMAL
|
||||
tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
|
||||
depends on MACH_STM32MP157
|
||||
default y
|
||||
help
|
||||
Support for thermal framework on STMicroelectronics STM32 series of
|
||||
SoCs. This thermal driver allows to access to general thermal framework
|
||||
functionalities and to acces to SoC sensor functionalities. This
|
||||
configuration is fully dependent of MACH_STM32MP157.
|
||||
tristate "Thermal framework support on STMicroelectronics STM32 series of SoCs"
|
||||
depends on MACH_STM32MP157
|
||||
default y
|
||||
help
|
||||
Support for thermal framework on STMicroelectronics STM32 series of
|
||||
SoCs. This thermal driver allows to access to general thermal framework
|
||||
functionalities and to acces to SoC sensor functionalities. This
|
||||
configuration is fully dependent of MACH_STM32MP157.
|
||||
|
|
|
@ -570,8 +570,7 @@ thermal_unprepare:
|
|||
static int stm_thermal_suspend(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
|
||||
struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
|
||||
|
||||
ret = stm_thermal_sensor_off(sensor);
|
||||
if (ret)
|
||||
|
@ -585,8 +584,7 @@ static int stm_thermal_suspend(struct device *dev)
|
|||
static int stm_thermal_resume(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
|
||||
struct stm_thermal_sensor *sensor = dev_get_drvdata(dev);
|
||||
|
||||
ret = stm_thermal_prepare(sensor);
|
||||
if (ret)
|
||||
|
|
|
@ -14,7 +14,7 @@ config TEGRA_BPMP_THERMAL
|
|||
tristate "Tegra BPMP thermal sensing"
|
||||
depends on TEGRA_BPMP || COMPILE_TEST
|
||||
help
|
||||
Enable this option for support for sensing system temperature of NVIDIA
|
||||
Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
|
||||
Enable this option for support for sensing system temperature of NVIDIA
|
||||
Tegra systems-on-chip with the BPMP coprocessor (Tegra186).
|
||||
|
||||
endmenu
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
|
@ -29,6 +30,14 @@
|
|||
#define THERMCTL_THERMTRIP_CTL 0x80
|
||||
/* BITs are defined in device file */
|
||||
|
||||
#define THERMCTL_INTR_ENABLE 0x88
|
||||
#define THERMCTL_INTR_DISABLE 0x8c
|
||||
#define TH_INTR_UP_DN_EN 0x3
|
||||
#define THERM_IRQ_MEM_MASK (TH_INTR_UP_DN_EN << 24)
|
||||
#define THERM_IRQ_GPU_MASK (TH_INTR_UP_DN_EN << 16)
|
||||
#define THERM_IRQ_CPU_MASK (TH_INTR_UP_DN_EN << 8)
|
||||
#define THERM_IRQ_TSENSE_MASK (TH_INTR_UP_DN_EN << 0)
|
||||
|
||||
#define SENSOR_PDIV 0x1c0
|
||||
#define SENSOR_PDIV_CPU_MASK (0xf << 12)
|
||||
#define SENSOR_PDIV_GPU_MASK (0xf << 8)
|
||||
|
@ -70,6 +79,7 @@ struct tegra_tsensor_group {
|
|||
u32 thermtrip_enable_mask;
|
||||
u32 thermtrip_any_en_mask;
|
||||
u32 thermtrip_threshold_mask;
|
||||
u32 thermctl_isr_mask;
|
||||
u16 thermctl_lvl0_offset;
|
||||
u32 thermctl_lvl0_up_thresh_mask;
|
||||
u32 thermctl_lvl0_dn_thresh_mask;
|
||||
|
@ -92,6 +102,11 @@ struct tegra_tsensor {
|
|||
const struct tegra_tsensor_group *group;
|
||||
};
|
||||
|
||||
struct tsensor_group_thermtrips {
|
||||
u8 id;
|
||||
u32 temp;
|
||||
};
|
||||
|
||||
struct tegra_soctherm_fuse {
|
||||
u32 fuse_base_cp_mask, fuse_base_cp_shift;
|
||||
u32 fuse_base_ft_mask, fuse_base_ft_shift;
|
||||
|
@ -113,6 +128,7 @@ struct tegra_soctherm_soc {
|
|||
const int thresh_grain;
|
||||
const unsigned int bptt;
|
||||
const bool use_ccroc;
|
||||
struct tsensor_group_thermtrips *thermtrips;
|
||||
};
|
||||
|
||||
int tegra_calc_shared_calib(const struct tegra_soctherm_fuse *tfuse,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_cpu = {
|
|||
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA124_THERMTRIP_CPU_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_CPU_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_CPU_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_gpu = {
|
|||
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA124_THERMTRIP_GPU_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_GPU_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_pll = {
|
|||
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA124_THERMTRIP_TSENSE_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_TSENSE_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra124_tsensor_group_mem = {
|
|||
.thermtrip_any_en_mask = TEGRA124_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA124_THERMTRIP_MEM_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA124_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_MEM_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA124_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA124_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -55,6 +56,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_cpu = {
|
|||
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA132_THERMTRIP_CPU_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_CPU_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_CPU_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -73,6 +75,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_gpu = {
|
|||
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA132_THERMTRIP_GPU_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_GPU_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -89,6 +92,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_pll = {
|
|||
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA132_THERMTRIP_TSENSE_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_TSENSE_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -107,6 +111,7 @@ static const struct tegra_tsensor_group tegra132_tsensor_group_mem = {
|
|||
.thermtrip_any_en_mask = TEGRA132_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA132_THERMTRIP_MEM_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA132_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_MEM_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA132_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA132_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
||||
* Copyright (c) 2014-2018, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
|
@ -56,6 +57,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_cpu = {
|
|||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_CPU_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_CPU_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_CPU_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_CPU,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -74,6 +76,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_gpu = {
|
|||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_GPU_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_GPU_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_GPU,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -90,6 +93,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_pll = {
|
|||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_TSENSE_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_TSENSE_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_TSENSE_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_TSENSE,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -108,6 +112,7 @@ static const struct tegra_tsensor_group tegra210_tsensor_group_mem = {
|
|||
.thermtrip_any_en_mask = TEGRA210_THERMTRIP_ANY_EN_MASK,
|
||||
.thermtrip_enable_mask = TEGRA210_THERMTRIP_MEM_EN_MASK,
|
||||
.thermtrip_threshold_mask = TEGRA210_THERMTRIP_GPUMEM_THRESH_MASK,
|
||||
.thermctl_isr_mask = THERM_IRQ_MEM_MASK,
|
||||
.thermctl_lvl0_offset = THERMCTL_LEVEL0_GROUP_MEM,
|
||||
.thermctl_lvl0_up_thresh_mask = TEGRA210_THERMCTL_LVL0_UP_THRESH_MASK,
|
||||
.thermctl_lvl0_dn_thresh_mask = TEGRA210_THERMCTL_LVL0_DN_THRESH_MASK,
|
||||
|
@ -203,6 +208,13 @@ static const struct tegra_soctherm_fuse tegra210_soctherm_fuse = {
|
|||
.fuse_spare_realignment = 0,
|
||||
};
|
||||
|
||||
struct tsensor_group_thermtrips tegra210_tsensor_thermtrips[] = {
|
||||
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
|
||||
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
|
||||
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
|
||||
{.id = TEGRA124_SOCTHERM_SENSOR_NUM},
|
||||
};
|
||||
|
||||
const struct tegra_soctherm_soc tegra210_soctherm = {
|
||||
.tsensors = tegra210_tsensors,
|
||||
.num_tsensors = ARRAY_SIZE(tegra210_tsensors),
|
||||
|
@ -212,4 +224,5 @@ const struct tegra_soctherm_soc tegra210_soctherm = {
|
|||
.thresh_grain = TEGRA210_THRESH_GRAIN,
|
||||
.bptt = TEGRA210_BPTT,
|
||||
.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 i;
|
||||
|
||||
if (!gti->lookup_table)
|
||||
return val;
|
||||
|
||||
for (i = 0; i < gti->nlookup_table; i++) {
|
||||
if (val >= gti->lookup_table[2 * i + 1])
|
||||
break;
|
||||
|
@ -81,9 +84,9 @@ static int gadc_thermal_read_linear_lookup_table(struct device *dev,
|
|||
|
||||
ntable = of_property_count_elems_of_size(np, "temperature-lookup-table",
|
||||
sizeof(u32));
|
||||
if (ntable < 0) {
|
||||
dev_err(dev, "Lookup table is not provided\n");
|
||||
return ntable;
|
||||
if (ntable <= 0) {
|
||||
dev_notice(dev, "no lookup table, assuming DAC channel returns milliCelcius\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ntable % 2) {
|
||||
|
|
|
@ -1046,6 +1046,55 @@ thermal_of_cooling_device_register(struct device_node *np,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
|
||||
|
||||
static void thermal_cooling_device_release(struct device *dev, void *res)
|
||||
{
|
||||
thermal_cooling_device_unregister(
|
||||
*(struct thermal_cooling_device **)res);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_thermal_of_cooling_device_register() - register an OF thermal cooling
|
||||
* device
|
||||
* @dev: a valid struct device pointer of a sensor device.
|
||||
* @np: a pointer to a device tree node.
|
||||
* @type: the thermal cooling device type.
|
||||
* @devdata: device private data.
|
||||
* @ops: standard thermal cooling devices callbacks.
|
||||
*
|
||||
* This function will register a cooling device with device tree node reference.
|
||||
* This interface function adds a new thermal cooling device (fan/processor/...)
|
||||
* to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
|
||||
* to all the thermal zone devices registered at the same time.
|
||||
*
|
||||
* Return: a pointer to the created struct thermal_cooling_device or an
|
||||
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
|
||||
*/
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
struct thermal_cooling_device **ptr, *tcd;
|
||||
|
||||
ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
|
||||
GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
tcd = __thermal_cooling_device_register(np, type, devdata, ops);
|
||||
if (IS_ERR(tcd)) {
|
||||
devres_free(ptr);
|
||||
return tcd;
|
||||
}
|
||||
|
||||
*ptr = tcd;
|
||||
devres_add(dev, ptr);
|
||||
|
||||
return tcd;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
|
||||
|
||||
static void __unbind(struct thermal_zone_device *tz, int mask,
|
||||
struct thermal_cooling_device *cdev)
|
||||
{
|
||||
|
|
|
@ -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_NUM 4
|
||||
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 0
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_MED 1
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 2
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_NONE -1
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_NONE 0
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_LOW 1
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_MED 2
|
||||
#define TEGRA_SOCTHERM_THROT_LEVEL_HIGH 3
|
||||
|
||||
#endif
|
||||
|
|
|
@ -447,6 +447,11 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
|
|||
struct thermal_cooling_device *
|
||||
thermal_of_cooling_device_register(struct device_node *np, char *, void *,
|
||||
const struct thermal_cooling_device_ops *);
|
||||
struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops);
|
||||
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
|
||||
struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name);
|
||||
int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
|
||||
|
@ -503,6 +508,14 @@ static inline struct thermal_cooling_device *
|
|||
thermal_of_cooling_device_register(struct device_node *np,
|
||||
char *type, void *devdata, const struct thermal_cooling_device_ops *ops)
|
||||
{ return ERR_PTR(-ENODEV); }
|
||||
static inline struct thermal_cooling_device *
|
||||
devm_thermal_of_cooling_device_register(struct device *dev,
|
||||
struct device_node *np,
|
||||
char *type, void *devdata,
|
||||
const struct thermal_cooling_device_ops *ops)
|
||||
{
|
||||
return ERR_PTR(-ENODEV);
|
||||
}
|
||||
static inline void thermal_cooling_device_unregister(
|
||||
struct thermal_cooling_device *cdev)
|
||||
{ }
|
||||
|
|
Загрузка…
Ссылка в новой задаче