GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
config DM_THERMAL
|
||||
bool "Driver support for thermal devices"
|
||||
help
|
||||
Enable support for temperature-sensing devices. Some SoCs have on-chip
|
||||
temperature sensors to permit warnings, speed throttling or even
|
||||
automatic power-off when the temperature gets too high or low. Other
|
||||
devices may be discrete but connected on a suitable bus.
|
||||
|
||||
if DM_THERMAL
|
||||
|
||||
config IMX_THERMAL
|
||||
bool "Temperature sensor driver for Freescale i.MX SoCs"
|
||||
depends on MX6 || MX7
|
||||
help
|
||||
Support for Temperature Monitor (TEMPMON) found on Freescale i.MX SoCs.
|
||||
It supports one critical trip point and one passive trip point. The
|
||||
cpufreq is used as the cooling device to throttle CPUs when the
|
||||
passive trip is crossed.
|
||||
|
||||
config IMX_SCU_THERMAL
|
||||
bool "Temperature sensor driver for NXP i.MX8"
|
||||
depends on ARCH_IMX8
|
||||
help
|
||||
Support for Temperature sensors on NXP i.MX8.
|
||||
It supports one critical trip point and one passive trip point. The
|
||||
boot is hold to the cool device to throttle CPUs when the passive
|
||||
trip is crossed
|
||||
|
||||
config TI_DRA7_THERMAL
|
||||
bool "Temperature sensor driver for TI dra7xx SOCs"
|
||||
help
|
||||
Enable thermal support for for the Texas Instruments DRA752 SoC family.
|
||||
The driver supports reading CPU temperature.
|
||||
|
||||
endif # if DM_THERMAL
|
||||
@@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# (C) Copyright 2014 Freescale Semiconductor, Inc.
|
||||
# Author: Nitin Garg <nitin.garg@freescale.com>
|
||||
|
||||
obj-$(CONFIG_DM_THERMAL) += thermal-uclass.o
|
||||
obj-$(CONFIG_IMX_THERMAL) += imx_thermal.o
|
||||
obj-$(CONFIG_IMX_SCU_THERMAL) += imx_scu_thermal.o
|
||||
obj-$(CONFIG_TI_DRA7_THERMAL) += ti-bandgap.o
|
||||
@@ -0,0 +1,203 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2019 NXP
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <thermal.h>
|
||||
#include <dm/device-internal.h>
|
||||
#include <dm/device.h>
|
||||
#include <asm/arch/sci/sci.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
struct imx_sc_thermal_plat {
|
||||
int critical;
|
||||
int alert;
|
||||
int polling_delay;
|
||||
int id;
|
||||
bool zone_node;
|
||||
};
|
||||
|
||||
static int read_temperature(struct udevice *dev, int *temp)
|
||||
{
|
||||
s16 celsius;
|
||||
s8 tenths;
|
||||
int ret;
|
||||
|
||||
sc_rsrc_t *sensor_rsrc = (sc_rsrc_t *)dev_get_driver_data(dev);
|
||||
|
||||
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
||||
|
||||
if (!temp)
|
||||
return -EINVAL;
|
||||
|
||||
ret = sc_misc_get_temp(-1, sensor_rsrc[pdata->id], SC_C_TEMP,
|
||||
&celsius, &tenths);
|
||||
if (ret) {
|
||||
printf("Error: get temperature failed! (error = %d)\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*temp = celsius * 1000 + tenths * 100;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int imx_sc_thermal_get_temp(struct udevice *dev, int *temp)
|
||||
{
|
||||
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
||||
int cpu_temp = 0;
|
||||
int ret;
|
||||
|
||||
ret = read_temperature(dev, &cpu_temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
while (cpu_temp >= pdata->alert) {
|
||||
printf("CPU Temperature (%dC) has beyond alert (%dC), close to critical (%dC)",
|
||||
cpu_temp, pdata->alert, pdata->critical);
|
||||
puts(" waiting...\n");
|
||||
mdelay(pdata->polling_delay);
|
||||
ret = read_temperature(dev, &cpu_temp);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
*temp = cpu_temp / 1000;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_thermal_ops imx_sc_thermal_ops = {
|
||||
.get_temp = imx_sc_thermal_get_temp,
|
||||
};
|
||||
|
||||
static int imx_sc_thermal_probe(struct udevice *dev)
|
||||
{
|
||||
debug("%s dev name %s\n", __func__, dev->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_sc_thermal_bind(struct udevice *dev)
|
||||
{
|
||||
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
||||
int reg, ret;
|
||||
int offset;
|
||||
const char *name;
|
||||
const void *prop;
|
||||
|
||||
debug("%s dev name %s\n", __func__, dev->name);
|
||||
|
||||
prop = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "compatible",
|
||||
NULL);
|
||||
if (!prop)
|
||||
return 0;
|
||||
|
||||
pdata->zone_node = 1;
|
||||
|
||||
reg = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "tsens-num", 0);
|
||||
if (reg == 0) {
|
||||
printf("%s: no temp sensor number provided!\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
offset = fdt_subnode_offset(gd->fdt_blob, 0, "thermal-zones");
|
||||
fdt_for_each_subnode(offset, gd->fdt_blob, offset) {
|
||||
/* Bind the subnode to this driver */
|
||||
name = fdt_get_name(gd->fdt_blob, offset, NULL);
|
||||
|
||||
ret = device_bind_with_driver_data(dev, dev->driver, name,
|
||||
dev->driver_data,
|
||||
offset_to_ofnode(offset),
|
||||
NULL);
|
||||
if (ret)
|
||||
printf("Error binding driver '%s': %d\n",
|
||||
dev->driver->name, ret);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx_sc_thermal_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct imx_sc_thermal_plat *pdata = dev_get_platdata(dev);
|
||||
struct fdtdec_phandle_args args;
|
||||
const char *type;
|
||||
int ret;
|
||||
int trips_np;
|
||||
|
||||
debug("%s dev name %s\n", __func__, dev->name);
|
||||
|
||||
if (pdata->zone_node)
|
||||
return 0;
|
||||
|
||||
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev_of_offset(dev),
|
||||
"thermal-sensors",
|
||||
"#thermal-sensor-cells",
|
||||
0, 0, &args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (args.node != dev_of_offset(dev->parent))
|
||||
return -EFAULT;
|
||||
|
||||
if (args.args_count >= 1)
|
||||
pdata->id = args.args[0];
|
||||
else
|
||||
pdata->id = 0;
|
||||
|
||||
debug("args.args_count %d, id %d\n", args.args_count, pdata->id);
|
||||
|
||||
pdata->polling_delay = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
|
||||
"polling-delay", 1000);
|
||||
|
||||
trips_np = fdt_subnode_offset(gd->fdt_blob, dev_of_offset(dev),
|
||||
"trips");
|
||||
fdt_for_each_subnode(trips_np, gd->fdt_blob, trips_np) {
|
||||
type = fdt_getprop(gd->fdt_blob, trips_np, "type", NULL);
|
||||
if (type) {
|
||||
if (strcmp(type, "critical") == 0) {
|
||||
pdata->critical = fdtdec_get_int(gd->fdt_blob,
|
||||
trips_np,
|
||||
"temperature",
|
||||
85);
|
||||
} else if (strcmp(type, "passive") == 0) {
|
||||
pdata->alert = fdtdec_get_int(gd->fdt_blob,
|
||||
trips_np,
|
||||
"temperature",
|
||||
80);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
debug("id %d polling_delay %d, critical %d, alert %d\n", pdata->id,
|
||||
pdata->polling_delay, pdata->critical, pdata->alert);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const sc_rsrc_t imx8qxp_sensor_rsrc[] = {
|
||||
SC_R_SYSTEM, SC_R_DRC_0, SC_R_PMIC_0,
|
||||
SC_R_PMIC_1, SC_R_PMIC_2,
|
||||
};
|
||||
|
||||
static const struct udevice_id imx_sc_thermal_ids[] = {
|
||||
{ .compatible = "nxp,imx8qxp-sc-tsens", .data =
|
||||
(ulong)&imx8qxp_sensor_rsrc, },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(imx_sc_thermal) = {
|
||||
.name = "imx_sc_thermal",
|
||||
.id = UCLASS_THERMAL,
|
||||
.ops = &imx_sc_thermal_ops,
|
||||
.of_match = imx_sc_thermal_ids,
|
||||
.bind = imx_sc_thermal_bind,
|
||||
.probe = imx_sc_thermal_probe,
|
||||
.ofdata_to_platdata = imx_sc_thermal_ofdata_to_platdata,
|
||||
.platdata_auto_alloc_size = sizeof(struct imx_sc_thermal_plat),
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,277 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2014 Freescale Semiconductor, Inc.
|
||||
* Author: Nitin Garg <nitin.garg@freescale.com>
|
||||
* Ye Li <Ye.Li@freescale.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <common.h>
|
||||
#include <div64.h>
|
||||
#include <fuse.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clock.h>
|
||||
#include <asm/arch/sys_proto.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
#include <malloc.h>
|
||||
#include <linux/math64.h>
|
||||
#include <thermal.h>
|
||||
#include <imx_thermal.h>
|
||||
|
||||
/* board will busyloop until this many degrees C below CPU max temperature */
|
||||
#define TEMPERATURE_HOT_DELTA 5 /* CPU maxT - 5C */
|
||||
#define FACTOR0 10000000
|
||||
#define FACTOR1 15423
|
||||
#define FACTOR2 4148468
|
||||
#define OFFSET 3580661
|
||||
#define MEASURE_FREQ 327
|
||||
#define TEMPERATURE_MIN -40
|
||||
#define TEMPERATURE_HOT 85
|
||||
#define TEMPERATURE_MAX 125
|
||||
|
||||
#define TEMPSENSE0_TEMP_CNT_SHIFT 8
|
||||
#define TEMPSENSE0_TEMP_CNT_MASK (0xfff << TEMPSENSE0_TEMP_CNT_SHIFT)
|
||||
#define TEMPSENSE0_FINISHED (1 << 2)
|
||||
#define TEMPSENSE0_MEASURE_TEMP (1 << 1)
|
||||
#define TEMPSENSE0_POWER_DOWN (1 << 0)
|
||||
#define MISC0_REFTOP_SELBIASOFF (1 << 3)
|
||||
#define TEMPSENSE1_MEASURE_FREQ 0xffff
|
||||
|
||||
struct thermal_data {
|
||||
unsigned int fuse;
|
||||
int critical;
|
||||
int minc;
|
||||
int maxc;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_MX6)
|
||||
static int read_cpu_temperature(struct udevice *dev)
|
||||
{
|
||||
int temperature;
|
||||
unsigned int reg, n_meas;
|
||||
const struct imx_thermal_plat *pdata = dev_get_platdata(dev);
|
||||
struct anatop_regs *anatop = (struct anatop_regs *)pdata->regs;
|
||||
struct thermal_data *priv = dev_get_priv(dev);
|
||||
u32 fuse = priv->fuse;
|
||||
int t1, n1;
|
||||
s64 c1, c2;
|
||||
s64 temp64;
|
||||
s32 rem;
|
||||
|
||||
/*
|
||||
* Sensor data layout:
|
||||
* [31:20] - sensor value @ 25C
|
||||
* We use universal formula now and only need sensor value @ 25C
|
||||
* slope = 0.4445388 - (0.0016549 * 25C fuse)
|
||||
*/
|
||||
n1 = fuse >> 20;
|
||||
t1 = 25; /* t1 always 25C */
|
||||
|
||||
/*
|
||||
* Derived from linear interpolation:
|
||||
* slope = 0.4445388 - (0.0016549 * 25C fuse)
|
||||
* slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
|
||||
* offset = 3.580661
|
||||
* offset = OFFSET / 1000000
|
||||
* (Nmeas - n1) / (Tmeas - t1 - offset) = slope
|
||||
* We want to reduce this down to the minimum computation necessary
|
||||
* for each temperature read. Also, we want Tmeas in millicelsius
|
||||
* and we don't want to lose precision from integer division. So...
|
||||
* Tmeas = (Nmeas - n1) / slope + t1 + offset
|
||||
* milli_Tmeas = 1000000 * (Nmeas - n1) / slope + 1000000 * t1 + OFFSET
|
||||
* milli_Tmeas = -1000000 * (n1 - Nmeas) / slope + 1000000 * t1 + OFFSET
|
||||
* Let constant c1 = (-1000000 / slope)
|
||||
* milli_Tmeas = (n1 - Nmeas) * c1 + 1000000 * t1 + OFFSET
|
||||
* Let constant c2 = n1 *c1 + 1000000 * t1
|
||||
* milli_Tmeas = (c2 - Nmeas * c1) + OFFSET
|
||||
* Tmeas = ((c2 - Nmeas * c1) + OFFSET) / 1000000
|
||||
*/
|
||||
temp64 = FACTOR0;
|
||||
temp64 *= 1000000;
|
||||
temp64 = div_s64_rem(temp64, FACTOR1 * n1 - FACTOR2, &rem);
|
||||
c1 = temp64;
|
||||
c2 = n1 * c1 + 1000000 * t1;
|
||||
|
||||
/*
|
||||
* now we only use single measure, every time we read
|
||||
* the temperature, we will power on/down anadig thermal
|
||||
* module
|
||||
*/
|
||||
writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_clr);
|
||||
writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_set);
|
||||
|
||||
/* setup measure freq */
|
||||
reg = readl(&anatop->tempsense1);
|
||||
reg &= ~TEMPSENSE1_MEASURE_FREQ;
|
||||
reg |= MEASURE_FREQ;
|
||||
writel(reg, &anatop->tempsense1);
|
||||
|
||||
/* start the measurement process */
|
||||
writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_clr);
|
||||
writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
|
||||
writel(TEMPSENSE0_MEASURE_TEMP, &anatop->tempsense0_set);
|
||||
|
||||
/* make sure that the latest temp is valid */
|
||||
while ((readl(&anatop->tempsense0) &
|
||||
TEMPSENSE0_FINISHED) == 0)
|
||||
udelay(10000);
|
||||
|
||||
/* read temperature count */
|
||||
reg = readl(&anatop->tempsense0);
|
||||
n_meas = (reg & TEMPSENSE0_TEMP_CNT_MASK)
|
||||
>> TEMPSENSE0_TEMP_CNT_SHIFT;
|
||||
writel(TEMPSENSE0_FINISHED, &anatop->tempsense0_clr);
|
||||
|
||||
/* Tmeas = (c2 - Nmeas * c1 + OFFSET) / 1000000 */
|
||||
temperature = div_s64_rem(c2 - n_meas * c1 + OFFSET, 1000000, &rem);
|
||||
|
||||
/* power down anatop thermal sensor */
|
||||
writel(TEMPSENSE0_POWER_DOWN, &anatop->tempsense0_set);
|
||||
writel(MISC0_REFTOP_SELBIASOFF, &anatop->ana_misc0_clr);
|
||||
|
||||
return temperature;
|
||||
}
|
||||
#elif defined(CONFIG_MX7)
|
||||
static int read_cpu_temperature(struct udevice *dev)
|
||||
{
|
||||
unsigned int reg, tmp;
|
||||
unsigned int raw_25c, te1;
|
||||
int temperature;
|
||||
unsigned int *priv = dev_get_priv(dev);
|
||||
u32 fuse = *priv;
|
||||
struct mxc_ccm_anatop_reg *ccm_anatop = (struct mxc_ccm_anatop_reg *)
|
||||
ANATOP_BASE_ADDR;
|
||||
/*
|
||||
* fuse data layout:
|
||||
* [31:21] sensor value @ 25C
|
||||
* [20:18] hot temperature value
|
||||
* [17:9] sensor value of room
|
||||
* [8:0] sensor value of hot
|
||||
*/
|
||||
|
||||
raw_25c = fuse >> 21;
|
||||
if (raw_25c == 0)
|
||||
raw_25c = 25;
|
||||
|
||||
te1 = (fuse >> 9) & 0x1ff;
|
||||
|
||||
/*
|
||||
* now we only use single measure, every time we read
|
||||
* the temperature, we will power on/down anadig thermal
|
||||
* module
|
||||
*/
|
||||
writel(TEMPMON_HW_ANADIG_TEMPSENSE1_POWER_DOWN_MASK, &ccm_anatop->tempsense1_clr);
|
||||
writel(PMU_REF_REFTOP_SELFBIASOFF_MASK, &ccm_anatop->ref_set);
|
||||
|
||||
/* write measure freq */
|
||||
reg = readl(&ccm_anatop->tempsense1);
|
||||
reg &= ~TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_FREQ_MASK;
|
||||
reg |= TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_FREQ(MEASURE_FREQ);
|
||||
writel(reg, &ccm_anatop->tempsense1);
|
||||
|
||||
writel(TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_TEMP_MASK, &ccm_anatop->tempsense1_clr);
|
||||
writel(TEMPMON_HW_ANADIG_TEMPSENSE1_FINISHED_MASK, &ccm_anatop->tempsense1_clr);
|
||||
writel(TEMPMON_HW_ANADIG_TEMPSENSE1_MEASURE_TEMP_MASK, &ccm_anatop->tempsense1_set);
|
||||
|
||||
if (soc_rev() >= CHIP_REV_1_1) {
|
||||
while ((readl(&ccm_anatop->tempsense1) &
|
||||
TEMPMON_HW_ANADIG_TEMPSENSE1_FINISHED_MASK) == 0)
|
||||
;
|
||||
reg = readl(&ccm_anatop->tempsense1);
|
||||
tmp = (reg & TEMPMON_HW_ANADIG_TEMPSENSE1_TEMP_VALUE_MASK)
|
||||
>> TEMPMON_HW_ANADIG_TEMPSENSE1_TEMP_VALUE_SHIFT;
|
||||
} else {
|
||||
/*
|
||||
* Since we can not rely on finish bit, use 10ms
|
||||
* delay to get temperature. From RM, 17us is
|
||||
* enough to get data, but to gurantee to get
|
||||
* the data, delay 10ms here.
|
||||
*/
|
||||
udelay(10000);
|
||||
reg = readl(&ccm_anatop->tempsense1);
|
||||
tmp = (reg & TEMPMON_HW_ANADIG_TEMPSENSE1_TEMP_VALUE_MASK)
|
||||
>> TEMPMON_HW_ANADIG_TEMPSENSE1_TEMP_VALUE_SHIFT;
|
||||
}
|
||||
|
||||
writel(TEMPMON_HW_ANADIG_TEMPSENSE1_FINISHED_MASK, &ccm_anatop->tempsense1_clr);
|
||||
|
||||
/* power down anatop thermal sensor */
|
||||
writel(TEMPMON_HW_ANADIG_TEMPSENSE1_POWER_DOWN_MASK, &ccm_anatop->tempsense1_set);
|
||||
writel(PMU_REF_REFTOP_SELFBIASOFF_MASK, &ccm_anatop->ref_clr);
|
||||
|
||||
/* Single point */
|
||||
temperature = tmp - (te1 - raw_25c);
|
||||
|
||||
return temperature;
|
||||
}
|
||||
#endif
|
||||
|
||||
int imx_thermal_get_temp(struct udevice *dev, int *temp)
|
||||
{
|
||||
struct thermal_data *priv = dev_get_priv(dev);
|
||||
int cpu_tmp = 0;
|
||||
|
||||
cpu_tmp = read_cpu_temperature(dev);
|
||||
|
||||
while (cpu_tmp >= priv->critical) {
|
||||
printf("CPU Temperature (%dC) too close to max (%dC)",
|
||||
cpu_tmp, priv->maxc);
|
||||
puts(" waiting...\n");
|
||||
udelay(5000000);
|
||||
cpu_tmp = read_cpu_temperature(dev);
|
||||
}
|
||||
|
||||
*temp = cpu_tmp;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dm_thermal_ops imx_thermal_ops = {
|
||||
.get_temp = imx_thermal_get_temp,
|
||||
};
|
||||
|
||||
static int imx_thermal_probe(struct udevice *dev)
|
||||
{
|
||||
unsigned int fuse = ~0;
|
||||
|
||||
const struct imx_thermal_plat *pdata = dev_get_platdata(dev);
|
||||
struct thermal_data *priv = dev_get_priv(dev);
|
||||
|
||||
/* Read Temperature calibration data fuse */
|
||||
fuse_read(pdata->fuse_bank, pdata->fuse_word, &fuse);
|
||||
|
||||
if (is_soc_type(MXC_SOC_MX6)) {
|
||||
/* Check for valid fuse */
|
||||
if (fuse == 0 || fuse == ~0) {
|
||||
debug("CPU: Thermal invalid data, fuse: 0x%x\n",
|
||||
fuse);
|
||||
return -EPERM;
|
||||
}
|
||||
} else if (is_soc_type(MXC_SOC_MX7)) {
|
||||
/* No Calibration data in FUSE? */
|
||||
if ((fuse & 0x3ffff) == 0)
|
||||
return -EPERM;
|
||||
/* We do not support 105C TE2 */
|
||||
if (((fuse & 0x1c0000) >> 18) == 0x6)
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
/* set critical cooling temp */
|
||||
get_cpu_temp_grade(&priv->minc, &priv->maxc);
|
||||
priv->critical = priv->maxc - TEMPERATURE_HOT_DELTA;
|
||||
priv->fuse = fuse;
|
||||
|
||||
enable_thermal_clk();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
U_BOOT_DRIVER(imx_thermal) = {
|
||||
.name = "imx_thermal",
|
||||
.id = UCLASS_THERMAL,
|
||||
.ops = &imx_thermal_ops,
|
||||
.probe = imx_thermal_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct thermal_data),
|
||||
.flags = DM_FLAG_PRE_RELOC,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* (C) Copyright 2014 Freescale Semiconductor, Inc
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <thermal.h>
|
||||
#include <errno.h>
|
||||
#include <fdtdec.h>
|
||||
#include <malloc.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
|
||||
int thermal_get_temp(struct udevice *dev, int *temp)
|
||||
{
|
||||
const struct dm_thermal_ops *ops = device_get_ops(dev);
|
||||
|
||||
if (!ops->get_temp)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->get_temp(dev, temp);
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(thermal) = {
|
||||
.id = UCLASS_THERMAL,
|
||||
.name = "thermal",
|
||||
};
|
||||
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* TI Bandgap temperature sensor driver
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Taken from Linux v4.9 (drivers/thermal/ti-soc-thermal/ti-bandgap.c)
|
||||
* and ported to uboot.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <dm.h>
|
||||
#include <thermal.h>
|
||||
|
||||
#define CTRL_CORE_TEMP_SENSOR_MPU 0
|
||||
#define DRA752_ADC_START_VALUE 540
|
||||
|
||||
struct ti_bandgap {
|
||||
ulong base;
|
||||
int temperature; /* in mili degree celsius */
|
||||
};
|
||||
|
||||
/*
|
||||
* DRA752 : Temperature values in milli degree celsius
|
||||
* ADC code values from 540 to 945
|
||||
*/
|
||||
static int dra752_adc_to_temp[] = {
|
||||
/* Index 540 - 549 */
|
||||
-40000, -40000, -40000, -40000, -39800, -39400, -39000, -38600, -38200,
|
||||
-37800,
|
||||
/* Index 550 - 559 */
|
||||
-37400, -37000, -36600, -36200, -35800, -35300, -34700, -34200, -33800,
|
||||
-33400,
|
||||
/* Index 560 - 569 */
|
||||
-33000, -32600, -32200, -31800, -31400, -31000, -30600, -30200, -29800,
|
||||
-29400,
|
||||
/* Index 570 - 579 */
|
||||
-29000, -28600, -28200, -27700, -27100, -26600, -26200, -25800, -25400,
|
||||
-25000,
|
||||
/* Index 580 - 589 */
|
||||
-24600, -24200, -23800, -23400, -23000, -22600, -22200, -21800, -21400,
|
||||
-21000,
|
||||
/* Index 590 - 599 */
|
||||
-20500, -19900, -19400, -19000, -18600, -18200, -17800, -17400, -17000,
|
||||
-16600,
|
||||
/* Index 600 - 609 */
|
||||
-16200, -15800, -15400, -15000, -14600, -14200, -13800, -13400, -13000,
|
||||
-12500,
|
||||
/* Index 610 - 619 */
|
||||
-11900, -11400, -11000, -10600, -10200, -9800, -9400, -9000, -8600,
|
||||
-8200,
|
||||
/* Index 620 - 629 */
|
||||
-7800, -7400, -7000, -6600, -6200, -5800, -5400, -5000, -4500,
|
||||
-3900,
|
||||
/* Index 630 - 639 */
|
||||
-3400, -3000, -2600, -2200, -1800, -1400, -1000, -600, -200,
|
||||
200,
|
||||
/* Index 640 - 649 */
|
||||
600, 1000, 1400, 1800, 2200, 2600, 3000, 3400, 3900,
|
||||
4500,
|
||||
/* Index 650 - 659 */
|
||||
5000, 5400, 5800, 6200, 6600, 7000, 7400, 7800, 8200,
|
||||
8600,
|
||||
/* Index 660 - 669 */
|
||||
9000, 9400, 9800, 10200, 10600, 11000, 11400, 11800, 12200,
|
||||
12700,
|
||||
/* Index 670 - 679 */
|
||||
13300, 13800, 14200, 14600, 15000, 15400, 15800, 16200, 16600,
|
||||
17000,
|
||||
/* Index 680 - 689 */
|
||||
17400, 17800, 18200, 18600, 19000, 19400, 19800, 20200, 20600,
|
||||
21000,
|
||||
/* Index 690 - 699 */
|
||||
21400, 21900, 22500, 23000, 23400, 23800, 24200, 24600, 25000,
|
||||
25400,
|
||||
/* Index 700 - 709 */
|
||||
25800, 26200, 26600, 27000, 27400, 27800, 28200, 28600, 29000,
|
||||
29400,
|
||||
/* Index 710 - 719 */
|
||||
29800, 30200, 30600, 31000, 31400, 31900, 32500, 33000, 33400,
|
||||
33800,
|
||||
/* Index 720 - 729 */
|
||||
34200, 34600, 35000, 35400, 35800, 36200, 36600, 37000, 37400,
|
||||
37800,
|
||||
/* Index 730 - 739 */
|
||||
38200, 38600, 39000, 39400, 39800, 40200, 40600, 41000, 41400,
|
||||
41800,
|
||||
/* Index 740 - 749 */
|
||||
42200, 42600, 43100, 43700, 44200, 44600, 45000, 45400, 45800,
|
||||
46200,
|
||||
/* Index 750 - 759 */
|
||||
46600, 47000, 47400, 47800, 48200, 48600, 49000, 49400, 49800,
|
||||
50200,
|
||||
/* Index 760 - 769 */
|
||||
50600, 51000, 51400, 51800, 52200, 52600, 53000, 53400, 53800,
|
||||
54200,
|
||||
/* Index 770 - 779 */
|
||||
54600, 55000, 55400, 55900, 56500, 57000, 57400, 57800, 58200,
|
||||
58600,
|
||||
/* Index 780 - 789 */
|
||||
59000, 59400, 59800, 60200, 60600, 61000, 61400, 61800, 62200,
|
||||
62600,
|
||||
/* Index 790 - 799 */
|
||||
63000, 63400, 63800, 64200, 64600, 65000, 65400, 65800, 66200,
|
||||
66600,
|
||||
/* Index 800 - 809 */
|
||||
67000, 67400, 67800, 68200, 68600, 69000, 69400, 69800, 70200,
|
||||
70600,
|
||||
/* Index 810 - 819 */
|
||||
71000, 71500, 72100, 72600, 73000, 73400, 73800, 74200, 74600,
|
||||
75000,
|
||||
/* Index 820 - 829 */
|
||||
75400, 75800, 76200, 76600, 77000, 77400, 77800, 78200, 78600,
|
||||
79000,
|
||||
/* Index 830 - 839 */
|
||||
79400, 79800, 80200, 80600, 81000, 81400, 81800, 82200, 82600,
|
||||
83000,
|
||||
/* Index 840 - 849 */
|
||||
83400, 83800, 84200, 84600, 85000, 85400, 85800, 86200, 86600,
|
||||
87000,
|
||||
/* Index 850 - 859 */
|
||||
87400, 87800, 88200, 88600, 89000, 89400, 89800, 90200, 90600,
|
||||
91000,
|
||||
/* Index 860 - 869 */
|
||||
91400, 91800, 92200, 92600, 93000, 93400, 93800, 94200, 94600,
|
||||
95000,
|
||||
/* Index 870 - 879 */
|
||||
95400, 95800, 96200, 96600, 97000, 97500, 98100, 98600, 99000,
|
||||
99400,
|
||||
/* Index 880 - 889 */
|
||||
99800, 100200, 100600, 101000, 101400, 101800, 102200, 102600, 103000,
|
||||
103400,
|
||||
/* Index 890 - 899 */
|
||||
103800, 104200, 104600, 105000, 105400, 105800, 106200, 106600, 107000,
|
||||
107400,
|
||||
/* Index 900 - 909 */
|
||||
107800, 108200, 108600, 109000, 109400, 109800, 110200, 110600, 111000,
|
||||
111400,
|
||||
/* Index 910 - 919 */
|
||||
111800, 112200, 112600, 113000, 113400, 113800, 114200, 114600, 115000,
|
||||
115400,
|
||||
/* Index 920 - 929 */
|
||||
115800, 116200, 116600, 117000, 117400, 117800, 118200, 118600, 119000,
|
||||
119400,
|
||||
/* Index 930 - 939 */
|
||||
119800, 120200, 120600, 121000, 121400, 121800, 122200, 122600, 123000,
|
||||
123400,
|
||||
/* Index 940 - 945 */
|
||||
123800, 124200, 124600, 124900, 125000, 125000,
|
||||
};
|
||||
|
||||
static int ti_bandgap_get_temp(struct udevice *dev, int *temp)
|
||||
{
|
||||
struct ti_bandgap *bgp = dev_get_priv(dev);
|
||||
|
||||
bgp->temperature = 0x3ff & readl(bgp->base + CTRL_CORE_TEMP_SENSOR_MPU);
|
||||
*temp = dra752_adc_to_temp[bgp->temperature - DRA752_ADC_START_VALUE];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dm_thermal_ops ti_thermal_ops = {
|
||||
.get_temp = ti_bandgap_get_temp,
|
||||
};
|
||||
|
||||
static int ti_bandgap_probe(struct udevice *dev)
|
||||
{
|
||||
struct ti_bandgap *bgp = dev_get_priv(dev);
|
||||
|
||||
bgp->base = devfdt_get_addr_index(dev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct udevice_id of_ti_bandgap_match[] = {
|
||||
{
|
||||
.compatible = "ti,dra752-bandgap",
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ti_bandgap_thermal) = {
|
||||
.name = "ti_bandgap_thermal",
|
||||
.id = UCLASS_THERMAL,
|
||||
.ops = &ti_thermal_ops,
|
||||
.probe = ti_bandgap_probe,
|
||||
.of_match = of_ti_bandgap_match,
|
||||
.priv_auto_alloc_size = sizeof(struct ti_bandgap),
|
||||
};
|
||||
Reference in New Issue
Block a user