mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-14 17:14:09 +00:00
Merge branch 'linus' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal into thermal-soc
This commit is contained in:
commit
ef1d75263f
@ -0,0 +1,56 @@
|
||||
* DT bindings for Renesas R-Car Gen3 Thermal Sensor driver
|
||||
|
||||
On R-Car Gen3 SoCs, the thermal sensor controllers (TSC) control the thermal
|
||||
sensors (THS) which are the analog circuits for measuring temperature (Tj)
|
||||
inside the LSI.
|
||||
|
||||
Required properties:
|
||||
- compatible : "renesas,<soctype>-thermal",
|
||||
Examples with soctypes are:
|
||||
- "renesas,r8a7795-thermal" (R-Car H3)
|
||||
- "renesas,r8a7796-thermal" (R-Car M3-W)
|
||||
- reg : Address ranges of the thermal registers. Each sensor
|
||||
needs one address range. Sorting must be done in
|
||||
increasing order according to datasheet, i.e.
|
||||
TSC1, TSC2, ...
|
||||
- clocks : Must contain a reference to the functional clock.
|
||||
- #thermal-sensor-cells : must be <1>.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- interrupts : interrupts routed to the TSC (3 for H3 and M3-W)
|
||||
- power-domain : Must contain a reference to the power domain. This
|
||||
property is mandatory if the thermal sensor instance
|
||||
is part of a controllable power domain.
|
||||
|
||||
Example:
|
||||
|
||||
tsc: thermal@e6198000 {
|
||||
compatible = "renesas,r8a7795-thermal";
|
||||
reg = <0 0xe6198000 0 0x68>,
|
||||
<0 0xe61a0000 0 0x5c>,
|
||||
<0 0xe61a8000 0 0x5c>;
|
||||
interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
|
||||
<GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 522>;
|
||||
power-domains = <&sysc R8A7795_PD_ALWAYS_ON>;
|
||||
#thermal-sensor-cells = <1>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
thermal-zones {
|
||||
sensor_thermal1: sensor-thermal1 {
|
||||
polling-delay-passive = <250>;
|
||||
polling-delay = <1000>;
|
||||
thermal-sensors = <&tsc 0>;
|
||||
|
||||
trips {
|
||||
sensor1_crit: sensor1-crit {
|
||||
temperature = <90000>;
|
||||
hysteresis = <2000>;
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
116
Documentation/devicetree/bindings/thermal/zx2967-thermal.txt
Normal file
116
Documentation/devicetree/bindings/thermal/zx2967-thermal.txt
Normal file
@ -0,0 +1,116 @@
|
||||
* ZTE zx2967 family Thermal
|
||||
|
||||
Required Properties:
|
||||
- compatible: should be one of the following.
|
||||
* zte,zx296718-thermal
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region.
|
||||
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
|
||||
- clock-names: "topcrm" for the topcrm clock.
|
||||
"apb" for the apb clock.
|
||||
- #thermal-sensor-cells: must be 0.
|
||||
|
||||
Please note: slope coefficient defined in thermal-zones section need to be
|
||||
multiplied by 1000.
|
||||
|
||||
Example for tempsensor:
|
||||
|
||||
tempsensor: tempsensor@148a000 {
|
||||
compatible = "zte,zx296718-thermal";
|
||||
reg = <0x0148a000 0x20>;
|
||||
clocks = <&topcrm TEMPSENSOR_GATE>, <&audiocrm AUDIO_TS_PCLK>;
|
||||
clock-names = "topcrm", "apb";
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
|
||||
Example for cooling device:
|
||||
|
||||
cooling_dev: cooling_dev {
|
||||
cluster0_cooling_dev: cluster0-cooling-dev {
|
||||
#cooling-cells = <2>;
|
||||
cpumask = <0xf>;
|
||||
capacitance = <1500>;
|
||||
};
|
||||
|
||||
cluster1_cooling_dev: cluster1-cooling-dev {
|
||||
#cooling-cells = <2>;
|
||||
cpumask = <0x30>;
|
||||
capacitance = <2000>;
|
||||
};
|
||||
};
|
||||
|
||||
Example for thermal zones:
|
||||
|
||||
thermal-zones {
|
||||
zx296718_thermal: zx296718_thermal {
|
||||
polling-delay-passive = <500>;
|
||||
polling-delay = <1000>;
|
||||
sustainable-power = <6500>;
|
||||
|
||||
thermal-sensors = <&tempsensor 0>;
|
||||
/*
|
||||
* slope need to be multiplied by 1000.
|
||||
*/
|
||||
coefficients = <1951 (-922)>;
|
||||
|
||||
trips {
|
||||
trip0: switch_on_temperature {
|
||||
temperature = <90000>;
|
||||
hysteresis = <2000>;
|
||||
type = "passive";
|
||||
};
|
||||
|
||||
trip1: desired_temperature {
|
||||
temperature = <100000>;
|
||||
hysteresis = <2000>;
|
||||
type = "passive";
|
||||
};
|
||||
|
||||
crit: critical_temperature {
|
||||
temperature = <110000>;
|
||||
hysteresis = <2000>;
|
||||
type = "critical";
|
||||
};
|
||||
};
|
||||
|
||||
cooling-maps {
|
||||
map0 {
|
||||
trip = <&trip0>;
|
||||
cooling-device = <&gpu 2 5>;
|
||||
};
|
||||
|
||||
map1 {
|
||||
trip = <&trip0>;
|
||||
cooling-device = <&cluster0_cooling_dev 1 2>;
|
||||
};
|
||||
|
||||
map2 {
|
||||
trip = <&trip1>;
|
||||
cooling-device = <&cluster0_cooling_dev 1 2>;
|
||||
};
|
||||
|
||||
map3 {
|
||||
trip = <&crit>;
|
||||
cooling-device = <&cluster0_cooling_dev 1 2>;
|
||||
};
|
||||
|
||||
map4 {
|
||||
trip = <&trip0>;
|
||||
cooling-device = <&cluster1_cooling_dev 1 2>;
|
||||
contribution = <9000>;
|
||||
};
|
||||
|
||||
map5 {
|
||||
trip = <&trip1>;
|
||||
cooling-device = <&cluster1_cooling_dev 1 2>;
|
||||
contribution = <4096>;
|
||||
};
|
||||
|
||||
map6 {
|
||||
trip = <&crit>;
|
||||
cooling-device = <&cluster1_cooling_dev 1 2>;
|
||||
contribution = <4096>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
@ -245,6 +245,15 @@ config RCAR_THERMAL
|
||||
Enable this to plug the R-Car thermal sensor driver into the Linux
|
||||
thermal framework.
|
||||
|
||||
config RCAR_GEN3_THERMAL
|
||||
tristate "Renesas R-Car Gen3 thermal driver"
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
depends on OF
|
||||
help
|
||||
Enable this to plug the R-Car Gen3 thermal sensor driver into the Linux
|
||||
thermal framework.
|
||||
|
||||
config KIRKWOOD_THERMAL
|
||||
tristate "Temperature sensor on Marvell Kirkwood SoCs"
|
||||
depends on MACH_KIRKWOOD || COMPILE_TEST
|
||||
@ -436,4 +445,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
|
||||
source "drivers/thermal/qcom/Kconfig"
|
||||
endmenu
|
||||
|
||||
config ZX2967_THERMAL
|
||||
tristate "Thermal sensors on zx2967 SoC"
|
||||
depends on ARCH_ZX || COMPILE_TEST
|
||||
help
|
||||
Enable the zx2967 thermal sensors driver, which supports
|
||||
the primitive temperature sensor embedded in zx2967 SoCs.
|
||||
This sensor generates the real time die temperature.
|
||||
|
||||
endif
|
||||
|
@ -31,6 +31,7 @@ obj-$(CONFIG_QCOM_SPMI_TEMP_ALARM) += qcom-spmi-temp-alarm.o
|
||||
obj-$(CONFIG_SPEAR_THERMAL) += spear_thermal.o
|
||||
obj-$(CONFIG_ROCKCHIP_THERMAL) += rockchip_thermal.o
|
||||
obj-$(CONFIG_RCAR_THERMAL) += rcar_thermal.o
|
||||
obj-$(CONFIG_RCAR_GEN3_THERMAL) += rcar_gen3_thermal.o
|
||||
obj-$(CONFIG_KIRKWOOD_THERMAL) += kirkwood_thermal.o
|
||||
obj-y += samsung/
|
||||
obj-$(CONFIG_DOVE_THERMAL) += dove_thermal.o
|
||||
@ -56,3 +57,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
|
||||
obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
|
||||
obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
|
||||
obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
|
||||
obj-$(CONFIG_ZX2967_THERMAL) += zx2967_thermal.o
|
||||
|
@ -489,6 +489,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
|
||||
data->tempmon = map;
|
||||
|
||||
data->socdata = of_device_get_match_data(&pdev->dev);
|
||||
if (!data->socdata) {
|
||||
dev_err(&pdev->dev, "no device match found\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
|
||||
if (data->socdata->version == TEMPMON_IMX6SX) {
|
||||
|
@ -183,37 +183,37 @@ struct mtk_thermal {
|
||||
};
|
||||
|
||||
/* MT8173 thermal sensor data */
|
||||
const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
|
||||
static const int mt8173_bank_data[MT8173_NUM_ZONES][3] = {
|
||||
{ MT8173_TS2, MT8173_TS3 },
|
||||
{ MT8173_TS2, MT8173_TS4 },
|
||||
{ MT8173_TS1, MT8173_TS2, MT8173_TSABB },
|
||||
{ MT8173_TS2 },
|
||||
};
|
||||
|
||||
const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
|
||||
static const int mt8173_msr[MT8173_NUM_SENSORS_PER_ZONE] = {
|
||||
TEMP_MSR0, TEMP_MSR1, TEMP_MSR2, TEMP_MSR2
|
||||
};
|
||||
|
||||
const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
|
||||
static const int mt8173_adcpnp[MT8173_NUM_SENSORS_PER_ZONE] = {
|
||||
TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2, TEMP_ADCPNP3
|
||||
};
|
||||
|
||||
const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
|
||||
static const int mt8173_mux_values[MT8173_NUM_SENSORS] = { 0, 1, 2, 3, 16 };
|
||||
|
||||
/* MT2701 thermal sensor data */
|
||||
const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
|
||||
static const int mt2701_bank_data[MT2701_NUM_SENSORS] = {
|
||||
MT2701_TS1, MT2701_TS2, MT2701_TSABB
|
||||
};
|
||||
|
||||
const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
|
||||
static const int mt2701_msr[MT2701_NUM_SENSORS_PER_ZONE] = {
|
||||
TEMP_MSR0, TEMP_MSR1, TEMP_MSR2
|
||||
};
|
||||
|
||||
const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
|
||||
static const int mt2701_adcpnp[MT2701_NUM_SENSORS_PER_ZONE] = {
|
||||
TEMP_ADCPNP0, TEMP_ADCPNP1, TEMP_ADCPNP2
|
||||
};
|
||||
|
||||
const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
|
||||
static const int mt2701_mux_values[MT2701_NUM_SENSORS] = { 0, 1, 16 };
|
||||
|
||||
/**
|
||||
* The MT8173 thermal controller has four banks. Each bank can read up to
|
||||
|
335
drivers/thermal/rcar_gen3_thermal.c
Normal file
335
drivers/thermal/rcar_gen3_thermal.c
Normal file
@ -0,0 +1,335 @@
|
||||
/*
|
||||
* R-Car Gen3 THS thermal sensor driver
|
||||
* Based on rcar_thermal.c and work from Hien Dang and Khiem Nguyen.
|
||||
*
|
||||
* Copyright (C) 2016 Renesas Electronics Corporation.
|
||||
* Copyright (C) 2016 Sang Engineering
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
*/
|
||||
#include <linux/delay.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
/* Register offsets */
|
||||
#define REG_GEN3_IRQSTR 0x04
|
||||
#define REG_GEN3_IRQMSK 0x08
|
||||
#define REG_GEN3_IRQCTL 0x0C
|
||||
#define REG_GEN3_IRQEN 0x10
|
||||
#define REG_GEN3_IRQTEMP1 0x14
|
||||
#define REG_GEN3_IRQTEMP2 0x18
|
||||
#define REG_GEN3_IRQTEMP3 0x1C
|
||||
#define REG_GEN3_CTSR 0x20
|
||||
#define REG_GEN3_THCTR 0x20
|
||||
#define REG_GEN3_TEMP 0x28
|
||||
#define REG_GEN3_THCODE1 0x50
|
||||
#define REG_GEN3_THCODE2 0x54
|
||||
#define REG_GEN3_THCODE3 0x58
|
||||
|
||||
/* CTSR bits */
|
||||
#define CTSR_PONM BIT(8)
|
||||
#define CTSR_AOUT BIT(7)
|
||||
#define CTSR_THBGR BIT(5)
|
||||
#define CTSR_VMEN BIT(4)
|
||||
#define CTSR_VMST BIT(1)
|
||||
#define CTSR_THSST BIT(0)
|
||||
|
||||
/* THCTR bits */
|
||||
#define THCTR_PONM BIT(6)
|
||||
#define THCTR_THSST BIT(0)
|
||||
|
||||
#define CTEMP_MASK 0xFFF
|
||||
|
||||
#define MCELSIUS(temp) ((temp) * 1000)
|
||||
#define GEN3_FUSE_MASK 0xFFF
|
||||
|
||||
#define TSC_MAX_NUM 3
|
||||
|
||||
/* Structure for thermal temperature calculation */
|
||||
struct equation_coefs {
|
||||
int a1;
|
||||
int b1;
|
||||
int a2;
|
||||
int b2;
|
||||
};
|
||||
|
||||
struct rcar_gen3_thermal_tsc {
|
||||
void __iomem *base;
|
||||
struct thermal_zone_device *zone;
|
||||
struct equation_coefs coef;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct rcar_gen3_thermal_priv {
|
||||
struct rcar_gen3_thermal_tsc *tscs[TSC_MAX_NUM];
|
||||
};
|
||||
|
||||
struct rcar_gen3_thermal_data {
|
||||
void (*thermal_init)(struct rcar_gen3_thermal_tsc *tsc);
|
||||
};
|
||||
|
||||
static inline u32 rcar_gen3_thermal_read(struct rcar_gen3_thermal_tsc *tsc,
|
||||
u32 reg)
|
||||
{
|
||||
return ioread32(tsc->base + reg);
|
||||
}
|
||||
|
||||
static inline void rcar_gen3_thermal_write(struct rcar_gen3_thermal_tsc *tsc,
|
||||
u32 reg, u32 data)
|
||||
{
|
||||
iowrite32(data, tsc->base + reg);
|
||||
}
|
||||
|
||||
/*
|
||||
* Linear approximation for temperature
|
||||
*
|
||||
* [reg] = [temp] * a + b => [temp] = ([reg] - b) / a
|
||||
*
|
||||
* The constants a and b are calculated using two triplets of int values PTAT
|
||||
* and THCODE. PTAT and THCODE can either be read from hardware or use hard
|
||||
* coded values from driver. The formula to calculate a and b are taken from
|
||||
* BSP and sparsely documented and understood.
|
||||
*
|
||||
* Examining the linear formula and the formula used to calculate constants a
|
||||
* and b while knowing that the span for PTAT and THCODE values are between
|
||||
* 0x000 and 0xfff the largest integer possible is 0xfff * 0xfff == 0xffe001.
|
||||
* Integer also needs to be signed so that leaves 7 bits for binary
|
||||
* fixed point scaling.
|
||||
*/
|
||||
|
||||
#define FIXPT_SHIFT 7
|
||||
#define FIXPT_INT(_x) ((_x) << FIXPT_SHIFT)
|
||||
#define FIXPT_DIV(_a, _b) DIV_ROUND_CLOSEST(((_a) << FIXPT_SHIFT), (_b))
|
||||
#define FIXPT_TO_MCELSIUS(_x) ((_x) * 1000 >> FIXPT_SHIFT)
|
||||
|
||||
#define RCAR3_THERMAL_GRAN 500 /* mili Celsius */
|
||||
|
||||
/* no idea where these constants come from */
|
||||
#define TJ_1 96
|
||||
#define TJ_3 -41
|
||||
|
||||
static void rcar_gen3_thermal_calc_coefs(struct equation_coefs *coef,
|
||||
int *ptat, int *thcode)
|
||||
{
|
||||
int tj_2;
|
||||
|
||||
/* TODO: Find documentation and document constant calculation formula */
|
||||
|
||||
/*
|
||||
* Division is not scaled in BSP and if scaled it might overflow
|
||||
* the dividend (4095 * 4095 << 14 > INT_MAX) so keep it unscaled
|
||||
*/
|
||||
tj_2 = (FIXPT_INT((ptat[1] - ptat[2]) * 137)
|
||||
/ (ptat[0] - ptat[2])) - FIXPT_INT(41);
|
||||
|
||||
coef->a1 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[2]),
|
||||
tj_2 - FIXPT_INT(TJ_3));
|
||||
coef->b1 = FIXPT_INT(thcode[2]) - coef->a1 * TJ_3;
|
||||
|
||||
coef->a2 = FIXPT_DIV(FIXPT_INT(thcode[1] - thcode[0]),
|
||||
tj_2 - FIXPT_INT(TJ_1));
|
||||
coef->b2 = FIXPT_INT(thcode[0]) - coef->a2 * TJ_1;
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_round(int temp)
|
||||
{
|
||||
int result, round_offs;
|
||||
|
||||
round_offs = temp >= 0 ? RCAR3_THERMAL_GRAN / 2 :
|
||||
-RCAR3_THERMAL_GRAN / 2;
|
||||
result = (temp + round_offs) / RCAR3_THERMAL_GRAN;
|
||||
return result * RCAR3_THERMAL_GRAN;
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
|
||||
{
|
||||
struct rcar_gen3_thermal_tsc *tsc = devdata;
|
||||
int mcelsius, val1, val2;
|
||||
u32 reg;
|
||||
|
||||
/* Read register and convert to mili Celsius */
|
||||
mutex_lock(&tsc->lock);
|
||||
|
||||
reg = rcar_gen3_thermal_read(tsc, REG_GEN3_TEMP) & CTEMP_MASK;
|
||||
|
||||
val1 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b1, tsc->coef.a1);
|
||||
val2 = FIXPT_DIV(FIXPT_INT(reg) - tsc->coef.b2, tsc->coef.a2);
|
||||
mcelsius = FIXPT_TO_MCELSIUS((val1 + val2) / 2);
|
||||
|
||||
mutex_unlock(&tsc->lock);
|
||||
|
||||
/* Make sure we are inside specifications */
|
||||
if ((mcelsius < MCELSIUS(-40)) || (mcelsius > MCELSIUS(125)))
|
||||
return -EIO;
|
||||
|
||||
/* Round value to device granularity setting */
|
||||
*temp = rcar_gen3_thermal_round(mcelsius);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
|
||||
.get_temp = rcar_gen3_thermal_get_temp,
|
||||
};
|
||||
|
||||
static void r8a7795_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||
{
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_THBGR);
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, 0x0);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR, CTSR_PONM);
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
|
||||
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
|
||||
|
||||
usleep_range(100, 200);
|
||||
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
|
||||
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN |
|
||||
CTSR_VMST | CTSR_THSST);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
}
|
||||
|
||||
static void r8a7796_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
|
||||
{
|
||||
u32 reg_val;
|
||||
|
||||
reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
|
||||
reg_val &= ~THCTR_PONM;
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
|
||||
|
||||
usleep_range(1000, 2000);
|
||||
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
|
||||
reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
|
||||
reg_val |= THCTR_THSST;
|
||||
rcar_gen3_thermal_write(tsc, REG_GEN3_THCTR, reg_val);
|
||||
}
|
||||
|
||||
static const struct rcar_gen3_thermal_data r8a7795_data = {
|
||||
.thermal_init = r8a7795_thermal_init,
|
||||
};
|
||||
|
||||
static const struct rcar_gen3_thermal_data r8a7796_data = {
|
||||
.thermal_init = r8a7796_thermal_init,
|
||||
};
|
||||
|
||||
static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
|
||||
{ .compatible = "renesas,r8a7795-thermal", .data = &r8a7795_data},
|
||||
{ .compatible = "renesas,r8a7796-thermal", .data = &r8a7796_data},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
||||
|
||||
static int rcar_gen3_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_gen3_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_gen3_thermal_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
struct thermal_zone_device *zone;
|
||||
int ret, i;
|
||||
const struct rcar_gen3_thermal_data *match_data =
|
||||
of_device_get_match_data(dev);
|
||||
|
||||
/* default values if FUSEs are missing */
|
||||
/* TODO: Read values from hardware on supported platforms */
|
||||
int ptat[3] = { 2351, 1509, 435 };
|
||||
int thcode[TSC_MAX_NUM][3] = {
|
||||
{ 3248, 2800, 2221 },
|
||||
{ 3245, 2795, 2216 },
|
||||
{ 3250, 2805, 2237 },
|
||||
};
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
|
||||
for (i = 0; i < TSC_MAX_NUM; i++) {
|
||||
struct rcar_gen3_thermal_tsc *tsc;
|
||||
|
||||
tsc = devm_kzalloc(dev, sizeof(*tsc), GFP_KERNEL);
|
||||
if (!tsc) {
|
||||
ret = -ENOMEM;
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, i);
|
||||
if (!res)
|
||||
break;
|
||||
|
||||
tsc->base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(tsc->base)) {
|
||||
ret = PTR_ERR(tsc->base);
|
||||
goto error_unregister;
|
||||
}
|
||||
|
||||
priv->tscs[i] = tsc;
|
||||
mutex_init(&tsc->lock);
|
||||
|
||||
match_data->thermal_init(tsc);
|
||||
rcar_gen3_thermal_calc_coefs(&tsc->coef, ptat, thcode[i]);
|
||||
|
||||
zone = devm_thermal_zone_of_sensor_register(dev, i, tsc,
|
||||
&rcar_gen3_tz_of_ops);
|
||||
if (IS_ERR(zone)) {
|
||||
dev_err(dev, "Can't register thermal zone\n");
|
||||
ret = PTR_ERR(zone);
|
||||
goto error_unregister;
|
||||
}
|
||||
tsc->zone = zone;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_unregister:
|
||||
rcar_gen3_thermal_remove(pdev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver rcar_gen3_thermal_driver = {
|
||||
.driver = {
|
||||
.name = "rcar_gen3_thermal",
|
||||
.of_match_table = rcar_gen3_thermal_dt_ids,
|
||||
},
|
||||
.probe = rcar_gen3_thermal_probe,
|
||||
.remove = rcar_gen3_thermal_remove,
|
||||
};
|
||||
module_platform_driver(rcar_gen3_thermal_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("R-Car Gen3 THS thermal sensor driver");
|
||||
MODULE_AUTHOR("Wolfram Sang <wsa+renesas@sang-engineering.com>");
|
@ -1168,7 +1168,6 @@ static int exynos_of_sensor_conf(struct device_node *np,
|
||||
pdata->default_temp_offset = (u8)value;
|
||||
|
||||
of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
|
||||
of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode);
|
||||
|
||||
of_node_put(np);
|
||||
return 0;
|
||||
|
@ -70,7 +70,6 @@ struct exynos_tmu_platform_data {
|
||||
|
||||
enum soc_type type;
|
||||
u32 cal_type;
|
||||
u32 cal_mode;
|
||||
};
|
||||
|
||||
#endif /* _EXYNOS_TMU_H */
|
||||
|
@ -11,7 +11,6 @@ config TI_SOC_THERMAL
|
||||
config TI_THERMAL
|
||||
bool "Texas Instruments SoCs thermal framework support"
|
||||
depends on TI_SOC_THERMAL
|
||||
depends on CPU_THERMAL
|
||||
help
|
||||
If you say yes here you want to get support for generic thermal
|
||||
framework for the Texas Instruments on die bandgap temperature sensor.
|
||||
|
@ -54,7 +54,6 @@
|
||||
#define DRA752_STD_FUSE_OPP_BGAP_CORE_OFFSET 0x8
|
||||
#define DRA752_TEMP_SENSOR_CORE_OFFSET 0x154
|
||||
#define DRA752_BANDGAP_THRESHOLD_CORE_OFFSET 0x1ac
|
||||
#define DRA752_BANDGAP_TSHUT_CORE_OFFSET 0x1b8
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_OFFSET 0x1c4
|
||||
#define DRA752_DTEMP_CORE_0_OFFSET 0x208
|
||||
#define DRA752_DTEMP_CORE_1_OFFSET 0x20c
|
||||
@ -66,7 +65,6 @@
|
||||
#define DRA752_STD_FUSE_OPP_BGAP_IVA_OFFSET 0x388
|
||||
#define DRA752_TEMP_SENSOR_IVA_OFFSET 0x398
|
||||
#define DRA752_BANDGAP_THRESHOLD_IVA_OFFSET 0x3a4
|
||||
#define DRA752_BANDGAP_TSHUT_IVA_OFFSET 0x3ac
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_IVA_OFFSET 0x3b4
|
||||
#define DRA752_DTEMP_IVA_0_OFFSET 0x3d0
|
||||
#define DRA752_DTEMP_IVA_1_OFFSET 0x3d4
|
||||
@ -78,7 +76,6 @@
|
||||
#define DRA752_STD_FUSE_OPP_BGAP_MPU_OFFSET 0x4
|
||||
#define DRA752_TEMP_SENSOR_MPU_OFFSET 0x14c
|
||||
#define DRA752_BANDGAP_THRESHOLD_MPU_OFFSET 0x1a4
|
||||
#define DRA752_BANDGAP_TSHUT_MPU_OFFSET 0x1b0
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_MPU_OFFSET 0x1bc
|
||||
#define DRA752_DTEMP_MPU_0_OFFSET 0x1e0
|
||||
#define DRA752_DTEMP_MPU_1_OFFSET 0x1e4
|
||||
@ -90,7 +87,6 @@
|
||||
#define DRA752_STD_FUSE_OPP_BGAP_DSPEVE_OFFSET 0x384
|
||||
#define DRA752_TEMP_SENSOR_DSPEVE_OFFSET 0x394
|
||||
#define DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET 0x3a0
|
||||
#define DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET 0x3a8
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_DSPEVE_OFFSET 0x3b0
|
||||
#define DRA752_DTEMP_DSPEVE_0_OFFSET 0x3bc
|
||||
#define DRA752_DTEMP_DSPEVE_1_OFFSET 0x3c0
|
||||
@ -102,7 +98,6 @@
|
||||
#define DRA752_STD_FUSE_OPP_BGAP_GPU_OFFSET 0x0
|
||||
#define DRA752_TEMP_SENSOR_GPU_OFFSET 0x150
|
||||
#define DRA752_BANDGAP_THRESHOLD_GPU_OFFSET 0x1a8
|
||||
#define DRA752_BANDGAP_TSHUT_GPU_OFFSET 0x1b4
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_GPU_OFFSET 0x1c0
|
||||
#define DRA752_DTEMP_GPU_0_OFFSET 0x1f4
|
||||
#define DRA752_DTEMP_GPU_1_OFFSET 0x1f8
|
||||
@ -173,10 +168,6 @@
|
||||
#define DRA752_BANDGAP_THRESHOLD_HOT_MASK (0x3ff << 16)
|
||||
#define DRA752_BANDGAP_THRESHOLD_COLD_MASK (0x3ff << 0)
|
||||
|
||||
/* DRA752.TSHUT_THRESHOLD */
|
||||
#define DRA752_TSHUT_THRESHOLD_MUXCTRL_MASK BIT(31)
|
||||
#define DRA752_TSHUT_THRESHOLD_HOT_MASK (0x3ff << 16)
|
||||
#define DRA752_TSHUT_THRESHOLD_COLD_MASK (0x3ff << 0)
|
||||
|
||||
/* DRA752.BANDGAP_CUMUL_DTEMP_CORE */
|
||||
#define DRA752_BANDGAP_CUMUL_DTEMP_CORE_MASK (0xffffffff << 0)
|
||||
@ -216,8 +207,6 @@
|
||||
#define DRA752_GPU_MAX_TEMP 125000
|
||||
#define DRA752_GPU_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_GPU_TSHUT_HOT 915
|
||||
#define DRA752_GPU_TSHUT_COLD 900
|
||||
#define DRA752_GPU_T_HOT 800
|
||||
#define DRA752_GPU_T_COLD 795
|
||||
|
||||
@ -230,8 +219,6 @@
|
||||
#define DRA752_MPU_MAX_TEMP 125000
|
||||
#define DRA752_MPU_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_MPU_TSHUT_HOT 915
|
||||
#define DRA752_MPU_TSHUT_COLD 900
|
||||
#define DRA752_MPU_T_HOT 800
|
||||
#define DRA752_MPU_T_COLD 795
|
||||
|
||||
@ -244,8 +231,6 @@
|
||||
#define DRA752_CORE_MAX_TEMP 125000
|
||||
#define DRA752_CORE_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_CORE_TSHUT_HOT 915
|
||||
#define DRA752_CORE_TSHUT_COLD 900
|
||||
#define DRA752_CORE_T_HOT 800
|
||||
#define DRA752_CORE_T_COLD 795
|
||||
|
||||
@ -258,8 +243,6 @@
|
||||
#define DRA752_DSPEVE_MAX_TEMP 125000
|
||||
#define DRA752_DSPEVE_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_DSPEVE_TSHUT_HOT 915
|
||||
#define DRA752_DSPEVE_TSHUT_COLD 900
|
||||
#define DRA752_DSPEVE_T_HOT 800
|
||||
#define DRA752_DSPEVE_T_COLD 795
|
||||
|
||||
@ -272,8 +255,6 @@
|
||||
#define DRA752_IVA_MAX_TEMP 125000
|
||||
#define DRA752_IVA_HYST_VAL 5000
|
||||
/* interrupts thresholds */
|
||||
#define DRA752_IVA_TSHUT_HOT 915
|
||||
#define DRA752_IVA_TSHUT_COLD 900
|
||||
#define DRA752_IVA_T_HOT 800
|
||||
#define DRA752_IVA_T_COLD 795
|
||||
|
||||
|
@ -49,9 +49,6 @@ dra752_core_temp_sensor_registers = {
|
||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_CORE_OFFSET,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_CORE_OFFSET,
|
||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
||||
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_CORE_MASK,
|
||||
@ -85,9 +82,6 @@ dra752_iva_temp_sensor_registers = {
|
||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_IVA_OFFSET,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_IVA_OFFSET,
|
||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
||||
.bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||
.status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_IVA_MASK,
|
||||
@ -121,9 +115,6 @@ dra752_mpu_temp_sensor_registers = {
|
||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_MPU_OFFSET,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_MPU_OFFSET,
|
||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
||||
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_MPU_MASK,
|
||||
@ -157,9 +148,6 @@ dra752_dspeve_temp_sensor_registers = {
|
||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_DSPEVE_OFFSET,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_DSPEVE_OFFSET,
|
||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
||||
.bgap_status = DRA752_BANDGAP_STATUS_2_OFFSET,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||
.status_hot_mask = DRA752_BANDGAP_STATUS_2_HOT_DSPEVE_MASK,
|
||||
@ -193,9 +181,6 @@ dra752_gpu_temp_sensor_registers = {
|
||||
.bgap_threshold = DRA752_BANDGAP_THRESHOLD_GPU_OFFSET,
|
||||
.threshold_thot_mask = DRA752_BANDGAP_THRESHOLD_HOT_MASK,
|
||||
.threshold_tcold_mask = DRA752_BANDGAP_THRESHOLD_COLD_MASK,
|
||||
.tshut_threshold = DRA752_BANDGAP_TSHUT_GPU_OFFSET,
|
||||
.tshut_hot_mask = DRA752_TSHUT_THRESHOLD_HOT_MASK,
|
||||
.tshut_cold_mask = DRA752_TSHUT_THRESHOLD_COLD_MASK,
|
||||
.bgap_status = DRA752_BANDGAP_STATUS_1_OFFSET,
|
||||
.status_bgap_alert_mask = DRA752_BANDGAP_STATUS_1_ALERT_MASK,
|
||||
.status_hot_mask = DRA752_BANDGAP_STATUS_1_HOT_GPU_MASK,
|
||||
@ -211,8 +196,6 @@ dra752_gpu_temp_sensor_registers = {
|
||||
|
||||
/* Thresholds and limits for DRA752 MPU temperature sensor */
|
||||
static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
|
||||
.tshut_hot = DRA752_MPU_TSHUT_HOT,
|
||||
.tshut_cold = DRA752_MPU_TSHUT_COLD,
|
||||
.t_hot = DRA752_MPU_T_HOT,
|
||||
.t_cold = DRA752_MPU_T_COLD,
|
||||
.min_freq = DRA752_MPU_MIN_FREQ,
|
||||
@ -226,8 +209,6 @@ static struct temp_sensor_data dra752_mpu_temp_sensor_data = {
|
||||
|
||||
/* Thresholds and limits for DRA752 GPU temperature sensor */
|
||||
static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
|
||||
.tshut_hot = DRA752_GPU_TSHUT_HOT,
|
||||
.tshut_cold = DRA752_GPU_TSHUT_COLD,
|
||||
.t_hot = DRA752_GPU_T_HOT,
|
||||
.t_cold = DRA752_GPU_T_COLD,
|
||||
.min_freq = DRA752_GPU_MIN_FREQ,
|
||||
@ -241,8 +222,6 @@ static struct temp_sensor_data dra752_gpu_temp_sensor_data = {
|
||||
|
||||
/* Thresholds and limits for DRA752 CORE temperature sensor */
|
||||
static struct temp_sensor_data dra752_core_temp_sensor_data = {
|
||||
.tshut_hot = DRA752_CORE_TSHUT_HOT,
|
||||
.tshut_cold = DRA752_CORE_TSHUT_COLD,
|
||||
.t_hot = DRA752_CORE_T_HOT,
|
||||
.t_cold = DRA752_CORE_T_COLD,
|
||||
.min_freq = DRA752_CORE_MIN_FREQ,
|
||||
@ -256,8 +235,6 @@ static struct temp_sensor_data dra752_core_temp_sensor_data = {
|
||||
|
||||
/* Thresholds and limits for DRA752 DSPEVE temperature sensor */
|
||||
static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
|
||||
.tshut_hot = DRA752_DSPEVE_TSHUT_HOT,
|
||||
.tshut_cold = DRA752_DSPEVE_TSHUT_COLD,
|
||||
.t_hot = DRA752_DSPEVE_T_HOT,
|
||||
.t_cold = DRA752_DSPEVE_T_COLD,
|
||||
.min_freq = DRA752_DSPEVE_MIN_FREQ,
|
||||
@ -271,8 +248,6 @@ static struct temp_sensor_data dra752_dspeve_temp_sensor_data = {
|
||||
|
||||
/* Thresholds and limits for DRA752 IVA temperature sensor */
|
||||
static struct temp_sensor_data dra752_iva_temp_sensor_data = {
|
||||
.tshut_hot = DRA752_IVA_TSHUT_HOT,
|
||||
.tshut_cold = DRA752_IVA_TSHUT_COLD,
|
||||
.t_hot = DRA752_IVA_T_HOT,
|
||||
.t_cold = DRA752_IVA_T_COLD,
|
||||
.min_freq = DRA752_IVA_MIN_FREQ,
|
||||
@ -416,8 +391,7 @@ int dra752_adc_to_temp[DRA752_ADC_END_VALUE - DRA752_ADC_START_VALUE + 1] = {
|
||||
|
||||
/* DRA752 data */
|
||||
const struct ti_bandgap_data dra752_data = {
|
||||
.features = TI_BANDGAP_FEATURE_TSHUT_CONFIG |
|
||||
TI_BANDGAP_FEATURE_FREEZE_BIT |
|
||||
.features = TI_BANDGAP_FEATURE_FREEZE_BIT |
|
||||
TI_BANDGAP_FEATURE_TALERT |
|
||||
TI_BANDGAP_FEATURE_COUNTER_DELAY |
|
||||
TI_BANDGAP_FEATURE_HISTORY_BUFFER |
|
||||
|
258
drivers/thermal/zx2967_thermal.c
Normal file
258
drivers/thermal/zx2967_thermal.c
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* ZTE's zx2967 family thermal sensor driver
|
||||
*
|
||||
* Copyright (C) 2017 ZTE Ltd.
|
||||
*
|
||||
* Author: Baoyou Xie <baoyou.xie@linaro.org>
|
||||
*
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/thermal.h>
|
||||
|
||||
/* Power Mode: 0->low 1->high */
|
||||
#define ZX2967_THERMAL_POWER_MODE 0
|
||||
#define ZX2967_POWER_MODE_LOW 0
|
||||
#define ZX2967_POWER_MODE_HIGH 1
|
||||
|
||||
/* DCF Control Register */
|
||||
#define ZX2967_THERMAL_DCF 0x4
|
||||
#define ZX2967_DCF_EN BIT(1)
|
||||
#define ZX2967_DCF_FREEZE BIT(0)
|
||||
|
||||
/* Selection Register */
|
||||
#define ZX2967_THERMAL_SEL 0x8
|
||||
|
||||
/* Control Register */
|
||||
#define ZX2967_THERMAL_CTRL 0x10
|
||||
|
||||
#define ZX2967_THERMAL_READY BIT(12)
|
||||
#define ZX2967_THERMAL_TEMP_MASK GENMASK(11, 0)
|
||||
#define ZX2967_THERMAL_ID_MASK 0x18
|
||||
#define ZX2967_THERMAL_ID 0x10
|
||||
|
||||
#define ZX2967_GET_TEMP_TIMEOUT_US (100 * 1024)
|
||||
|
||||
/**
|
||||
* struct zx2967_thermal_priv - zx2967 thermal sensor private structure
|
||||
* @tzd: struct thermal_zone_device where the sensor is registered
|
||||
* @lock: prevents read sensor in parallel
|
||||
* @clk_topcrm: topcrm clk structure
|
||||
* @clk_apb: apb clk structure
|
||||
* @regs: pointer to base address of the thermal sensor
|
||||
*/
|
||||
|
||||
struct zx2967_thermal_priv {
|
||||
struct thermal_zone_device *tzd;
|
||||
struct mutex lock;
|
||||
struct clk *clk_topcrm;
|
||||
struct clk *clk_apb;
|
||||
void __iomem *regs;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static int zx2967_thermal_get_temp(void *data, int *temp)
|
||||
{
|
||||
void __iomem *regs;
|
||||
struct zx2967_thermal_priv *priv = data;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (!priv->tzd)
|
||||
return -EAGAIN;
|
||||
|
||||
regs = priv->regs;
|
||||
mutex_lock(&priv->lock);
|
||||
writel_relaxed(ZX2967_POWER_MODE_LOW,
|
||||
regs + ZX2967_THERMAL_POWER_MODE);
|
||||
writel_relaxed(ZX2967_DCF_EN, regs + ZX2967_THERMAL_DCF);
|
||||
|
||||
val = readl_relaxed(regs + ZX2967_THERMAL_SEL);
|
||||
val &= ~ZX2967_THERMAL_ID_MASK;
|
||||
val |= ZX2967_THERMAL_ID;
|
||||
writel_relaxed(val, regs + ZX2967_THERMAL_SEL);
|
||||
|
||||
/*
|
||||
* Must wait for a while, surely it's a bit odd.
|
||||
* otherwise temperature value we got has a few deviation, even if
|
||||
* the THERMAL_READY bit is set.
|
||||
*/
|
||||
usleep_range(100, 300);
|
||||
ret = readx_poll_timeout(readl, regs + ZX2967_THERMAL_CTRL,
|
||||
val, val & ZX2967_THERMAL_READY, 300,
|
||||
ZX2967_GET_TEMP_TIMEOUT_US);
|
||||
if (ret) {
|
||||
dev_err(priv->dev, "Thermal sensor data timeout\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
writel_relaxed(ZX2967_DCF_FREEZE | ZX2967_DCF_EN,
|
||||
regs + ZX2967_THERMAL_DCF);
|
||||
val = readl_relaxed(regs + ZX2967_THERMAL_CTRL)
|
||||
& ZX2967_THERMAL_TEMP_MASK;
|
||||
writel_relaxed(ZX2967_POWER_MODE_HIGH,
|
||||
regs + ZX2967_THERMAL_POWER_MODE);
|
||||
|
||||
/*
|
||||
* Calculate temperature
|
||||
* In dts, slope is multiplied by 1000.
|
||||
*/
|
||||
*temp = DIV_ROUND_CLOSEST(((s32)val + priv->tzd->tzp->offset) * 1000,
|
||||
priv->tzd->tzp->slope);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&priv->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct thermal_zone_of_device_ops zx2967_of_thermal_ops = {
|
||||
.get_temp = zx2967_thermal_get_temp,
|
||||
};
|
||||
|
||||
static int zx2967_thermal_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct zx2967_thermal_priv *priv;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
priv->regs = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(priv->regs))
|
||||
return PTR_ERR(priv->regs);
|
||||
|
||||
priv->clk_topcrm = devm_clk_get(&pdev->dev, "topcrm");
|
||||
if (IS_ERR(priv->clk_topcrm)) {
|
||||
ret = PTR_ERR(priv->clk_topcrm);
|
||||
dev_err(&pdev->dev, "failed to get topcrm clock: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->clk_topcrm);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable topcrm clock: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
priv->clk_apb = devm_clk_get(&pdev->dev, "apb");
|
||||
if (IS_ERR(priv->clk_apb)) {
|
||||
ret = PTR_ERR(priv->clk_apb);
|
||||
dev_err(&pdev->dev, "failed to get apb clock: %d\n", ret);
|
||||
goto disable_clk_topcrm;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(priv->clk_apb);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to enable apb clock: %d\n",
|
||||
ret);
|
||||
goto disable_clk_topcrm;
|
||||
}
|
||||
|
||||
mutex_init(&priv->lock);
|
||||
priv->tzd = thermal_zone_of_sensor_register(&pdev->dev,
|
||||
0, priv, &zx2967_of_thermal_ops);
|
||||
|
||||
if (IS_ERR(priv->tzd)) {
|
||||
ret = PTR_ERR(priv->tzd);
|
||||
dev_err(&pdev->dev, "failed to register sensor: %d\n", ret);
|
||||
goto disable_clk_all;
|
||||
}
|
||||
|
||||
if (priv->tzd->tzp->slope == 0) {
|
||||
thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
|
||||
dev_err(&pdev->dev, "coefficients of sensor is invalid\n");
|
||||
ret = -EINVAL;
|
||||
goto disable_clk_all;
|
||||
}
|
||||
|
||||
priv->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, priv);
|
||||
|
||||
return 0;
|
||||
|
||||
disable_clk_all:
|
||||
clk_disable_unprepare(priv->clk_apb);
|
||||
disable_clk_topcrm:
|
||||
clk_disable_unprepare(priv->clk_topcrm);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int zx2967_thermal_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
thermal_zone_of_sensor_unregister(&pdev->dev, priv->tzd);
|
||||
clk_disable_unprepare(priv->clk_topcrm);
|
||||
clk_disable_unprepare(priv->clk_apb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id zx2967_thermal_id_table[] = {
|
||||
{ .compatible = "zte,zx296718-thermal" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, zx2967_thermal_id_table);
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int zx2967_thermal_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
if (priv && priv->clk_topcrm)
|
||||
clk_disable_unprepare(priv->clk_topcrm);
|
||||
|
||||
if (priv && priv->clk_apb)
|
||||
clk_disable_unprepare(priv->clk_apb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int zx2967_thermal_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct zx2967_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||
int error;
|
||||
|
||||
error = clk_prepare_enable(priv->clk_topcrm);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
error = clk_prepare_enable(priv->clk_apb);
|
||||
if (error) {
|
||||
clk_disable_unprepare(priv->clk_topcrm);
|
||||
return error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(zx2967_thermal_pm_ops,
|
||||
zx2967_thermal_suspend, zx2967_thermal_resume);
|
||||
|
||||
static struct platform_driver zx2967_thermal_driver = {
|
||||
.probe = zx2967_thermal_probe,
|
||||
.remove = zx2967_thermal_exit,
|
||||
.driver = {
|
||||
.name = "zx2967_thermal",
|
||||
.of_match_table = zx2967_thermal_id_table,
|
||||
.pm = &zx2967_thermal_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(zx2967_thermal_driver);
|
||||
|
||||
MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
|
||||
MODULE_DESCRIPTION("ZTE zx2967 thermal driver");
|
||||
MODULE_LICENSE("GPL v2");
|
Loading…
x
Reference in New Issue
Block a user