Skip to content

Commit

Permalink
thermal: imx: Add support for reading OCOTP through nvmem
Browse files Browse the repository at this point in the history
On newer imx SOCs accessing OCOTP directly is wrong because the ocotp
clock needs to be enabled first. Add support for reading those same
values through the nvmem API instead.

The older path is preserved for compatibility with older dts and because
it works correctly on imx6qdl chips.

Signed-off-by: Leonard Crestez <leonard.crestez@nxp.com>
Acked-by: Shawn Guo <shawnguo@kernel.org>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
  • Loading branch information
Leonard Crestez authored and Zhang Rui committed Sep 20, 2017
1 parent 4633f7a commit ae62155
Showing 1 changed file with 74 additions and 30 deletions.
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 ae62155

Please sign in to comment.