Skip to content

Commit

Permalink
Merge branch 'imx-nvmem' into thermal-soc
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhang Rui committed Nov 2, 2017
2 parents b2fd708 + 531fcde commit fe9ba5b
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 30 deletions.
7 changes: 7 additions & 0 deletions Documentation/devicetree/bindings/thermal/imx-thermal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,17 @@ Required properties:
is higher than panic threshold, system will auto reboot by SRC module.
- fsl,tempmon : phandle pointer to system controller that contains TEMPMON
control registers, e.g. ANATOP on imx6q.
- nvmem-cells: A phandle to the calibration cells provided by ocotp.
- nvmem-cell-names: Should be "calib", "temp_grade".

Deprecated properties:
- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
calibration data, e.g. OCOTP on imx6q. The details about calibration data
can be found in SoC Reference Manual.

Direct access to OCOTP via fsl,tempmon-data is incorrect on some newer chips
because it does not handle OCOTP clock requirements.

Optional properties:
- clocks : thermal sensor's clock source.

Expand Down
1 change: 1 addition & 0 deletions drivers/thermal/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ config HISI_THERMAL
config IMX_THERMAL
tristate "Temperature sensor driver for Freescale i.MX SoCs"
depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST
depends on NVMEM || !NVMEM
depends on MFD_SYSCON
depends on OF
help
Expand Down
104 changes: 74 additions & 30 deletions drivers/thermal/imx_thermal.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <linux/slab.h>
#include <linux/thermal.h>
#include <linux/types.h>
#include <linux/nvmem-consumer.h>

#define REG_SET 0x4
#define REG_CLR 0x8
Expand Down Expand Up @@ -94,7 +95,7 @@ struct imx_thermal_data {
struct thermal_cooling_device *cdev;
enum thermal_device_mode mode;
struct regmap *tempmon;
u32 c1, c2; /* See formula in imx_get_sensor_data() */
u32 c1, c2; /* See formula in imx_init_calib() */
int temp_passive;
int temp_critical;
int temp_max;
Expand Down Expand Up @@ -177,7 +178,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)

n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;

/* See imx_get_sensor_data() for formula derivation */
/* See imx_init_calib() for formula derivation */
*temp = data->c2 - n_meas * data->c1;

/* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
Expand Down Expand Up @@ -346,29 +347,12 @@ static struct thermal_zone_device_ops imx_tz_ops = {
.set_trip_temp = imx_set_trip_temp,
};

static int imx_get_sensor_data(struct platform_device *pdev)
static int imx_init_calib(struct platform_device *pdev, u32 val)
{
struct imx_thermal_data *data = platform_get_drvdata(pdev);
struct regmap *map;
int t1, n1;
int ret;
u32 val;
u64 temp64;

map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"fsl,tempmon-data");
if (IS_ERR(map)) {
ret = PTR_ERR(map);
dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
return ret;
}

ret = regmap_read(map, OCOTP_ANA1, &val);
if (ret) {
dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
return ret;
}

if (val == 0 || val == ~0) {
dev_err(&pdev->dev, "invalid sensor calibration data\n");
return -EINVAL;
Expand Down Expand Up @@ -405,12 +389,12 @@ static int imx_get_sensor_data(struct platform_device *pdev)
data->c1 = temp64;
data->c2 = n1 * data->c1 + 1000 * t1;

/* use OTP for thermal grade */
ret = regmap_read(map, OCOTP_MEM0, &val);
if (ret) {
dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret);
return ret;
}
return 0;
}

static void imx_init_temp_grade(struct platform_device *pdev, u32 val)
{
struct imx_thermal_data *data = platform_get_drvdata(pdev);

/* The maximum die temp is specified by the Temperature Grade */
switch ((val >> 6) & 0x3) {
Expand Down Expand Up @@ -438,6 +422,55 @@ static int imx_get_sensor_data(struct platform_device *pdev)
*/
data->temp_critical = data->temp_max - (1000 * 5);
data->temp_passive = data->temp_max - (1000 * 10);
}

static int imx_init_from_tempmon_data(struct platform_device *pdev)
{
struct regmap *map;
int ret;
u32 val;

map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"fsl,tempmon-data");
if (IS_ERR(map)) {
ret = PTR_ERR(map);
dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
return ret;
}

ret = regmap_read(map, OCOTP_ANA1, &val);
if (ret) {
dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
return ret;
}
ret = imx_init_calib(pdev, val);
if (ret)
return ret;

ret = regmap_read(map, OCOTP_MEM0, &val);
if (ret) {
dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
return ret;
}
imx_init_temp_grade(pdev, val);

return 0;
}

static int imx_init_from_nvmem_cells(struct platform_device *pdev)
{
int ret;
u32 val;

ret = nvmem_cell_read_u32(&pdev->dev, "calib", &val);
if (ret)
return ret;
imx_init_calib(pdev, val);

ret = nvmem_cell_read_u32(&pdev->dev, "temp_grade", &val);
if (ret)
return ret;
imx_init_temp_grade(pdev, val);

return 0;
}
Expand Down Expand Up @@ -514,10 +547,21 @@ static int imx_thermal_probe(struct platform_device *pdev)

platform_set_drvdata(pdev, data);

ret = imx_get_sensor_data(pdev);
if (ret) {
dev_err(&pdev->dev, "failed to get sensor data\n");
return ret;
if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) {
ret = imx_init_from_nvmem_cells(pdev);
if (ret == -EPROBE_DEFER)
return ret;
if (ret) {
dev_err(&pdev->dev, "failed to init from nvmem: %d\n",
ret);
return ret;
}
} else {
ret = imx_init_from_tempmon_data(pdev);
if (ret) {
dev_err(&pdev->dev, "failed to init from from fsl,tempmon-data\n");
return ret;
}
}

/* Make sure sensor is in known good state for measurements */
Expand Down

0 comments on commit fe9ba5b

Please sign in to comment.