aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeonard Crestez <leonard.crestez@nxp.com>2017-07-14 10:11:08 -0400
committerZhang Rui <rui.zhang@intel.com>2017-09-19 21:36:18 -0400
commitae6215576d6b2251ab8c6bbeaf1c4cea99f0481b (patch)
treebd429fb2cc5c7b3a63629bd48cde00455690f00d
parent4633f7a156bf41003b1527f88ddf843ce0bb7d68 (diff)
thermal: imx: Add support for reading OCOTP through nvmem
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>
-rw-r--r--drivers/thermal/imx_thermal.c104
1 files changed, 74 insertions, 30 deletions
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 4798b4b1fd77..e7d4ffc3de7f 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -25,6 +25,7 @@
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/thermal.h> 26#include <linux/thermal.h>
27#include <linux/types.h> 27#include <linux/types.h>
28#include <linux/nvmem-consumer.h>
28 29
29#define REG_SET 0x4 30#define REG_SET 0x4
30#define REG_CLR 0x8 31#define REG_CLR 0x8
@@ -94,7 +95,7 @@ struct imx_thermal_data {
94 struct thermal_cooling_device *cdev; 95 struct thermal_cooling_device *cdev;
95 enum thermal_device_mode mode; 96 enum thermal_device_mode mode;
96 struct regmap *tempmon; 97 struct regmap *tempmon;
97 u32 c1, c2; /* See formula in imx_get_sensor_data() */ 98 u32 c1, c2; /* See formula in imx_init_calib() */
98 int temp_passive; 99 int temp_passive;
99 int temp_critical; 100 int temp_critical;
100 int temp_max; 101 int temp_max;
@@ -177,7 +178,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, int *temp)
177 178
178 n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT; 179 n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
179 180
180 /* See imx_get_sensor_data() for formula derivation */ 181 /* See imx_init_calib() for formula derivation */
181 *temp = data->c2 - n_meas * data->c1; 182 *temp = data->c2 - n_meas * data->c1;
182 183
183 /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */ 184 /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
@@ -346,29 +347,12 @@ static struct thermal_zone_device_ops imx_tz_ops = {
346 .set_trip_temp = imx_set_trip_temp, 347 .set_trip_temp = imx_set_trip_temp,
347}; 348};
348 349
349static int imx_get_sensor_data(struct platform_device *pdev) 350static int imx_init_calib(struct platform_device *pdev, u32 val)
350{ 351{
351 struct imx_thermal_data *data = platform_get_drvdata(pdev); 352 struct imx_thermal_data *data = platform_get_drvdata(pdev);
352 struct regmap *map;
353 int t1, n1; 353 int t1, n1;
354 int ret;
355 u32 val;
356 u64 temp64; 354 u64 temp64;
357 355
358 map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
359 "fsl,tempmon-data");
360 if (IS_ERR(map)) {
361 ret = PTR_ERR(map);
362 dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
363 return ret;
364 }
365
366 ret = regmap_read(map, OCOTP_ANA1, &val);
367 if (ret) {
368 dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
369 return ret;
370 }
371
372 if (val == 0 || val == ~0) { 356 if (val == 0 || val == ~0) {
373 dev_err(&pdev->dev, "invalid sensor calibration data\n"); 357 dev_err(&pdev->dev, "invalid sensor calibration data\n");
374 return -EINVAL; 358 return -EINVAL;
@@ -405,12 +389,12 @@ static int imx_get_sensor_data(struct platform_device *pdev)
405 data->c1 = temp64; 389 data->c1 = temp64;
406 data->c2 = n1 * data->c1 + 1000 * t1; 390 data->c2 = n1 * data->c1 + 1000 * t1;
407 391
408 /* use OTP for thermal grade */ 392 return 0;
409 ret = regmap_read(map, OCOTP_MEM0, &val); 393}
410 if (ret) { 394
411 dev_err(&pdev->dev, "failed to read temp grade: %d\n", ret); 395static void imx_init_temp_grade(struct platform_device *pdev, u32 val)
412 return ret; 396{
413 } 397 struct imx_thermal_data *data = platform_get_drvdata(pdev);
414 398
415 /* The maximum die temp is specified by the Temperature Grade */ 399 /* The maximum die temp is specified by the Temperature Grade */
416 switch ((val >> 6) & 0x3) { 400 switch ((val >> 6) & 0x3) {
@@ -438,6 +422,55 @@ static int imx_get_sensor_data(struct platform_device *pdev)
438 */ 422 */
439 data->temp_critical = data->temp_max - (1000 * 5); 423 data->temp_critical = data->temp_max - (1000 * 5);
440 data->temp_passive = data->temp_max - (1000 * 10); 424 data->temp_passive = data->temp_max - (1000 * 10);
425}
426
427static int imx_init_from_tempmon_data(struct platform_device *pdev)
428{
429 struct regmap *map;
430 int ret;
431 u32 val;
432
433 map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
434 "fsl,tempmon-data");
435 if (IS_ERR(map)) {
436 ret = PTR_ERR(map);
437 dev_err(&pdev->dev, "failed to get sensor regmap: %d\n", ret);
438 return ret;
439 }
440
441 ret = regmap_read(map, OCOTP_ANA1, &val);
442 if (ret) {
443 dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
444 return ret;
445 }
446 ret = imx_init_calib(pdev, val);
447 if (ret)
448 return ret;
449
450 ret = regmap_read(map, OCOTP_MEM0, &val);
451 if (ret) {
452 dev_err(&pdev->dev, "failed to read sensor data: %d\n", ret);
453 return ret;
454 }
455 imx_init_temp_grade(pdev, val);
456
457 return 0;
458}
459
460static int imx_init_from_nvmem_cells(struct platform_device *pdev)
461{
462 int ret;
463 u32 val;
464
465 ret = nvmem_cell_read_u32(&pdev->dev, "calib", &val);
466 if (ret)
467 return ret;
468 imx_init_calib(pdev, val);
469
470 ret = nvmem_cell_read_u32(&pdev->dev, "temp_grade", &val);
471 if (ret)
472 return ret;
473 imx_init_temp_grade(pdev, val);
441 474
442 return 0; 475 return 0;
443} 476}
@@ -514,10 +547,21 @@ static int imx_thermal_probe(struct platform_device *pdev)
514 547
515 platform_set_drvdata(pdev, data); 548 platform_set_drvdata(pdev, data);
516 549
517 ret = imx_get_sensor_data(pdev); 550 if (of_find_property(pdev->dev.of_node, "nvmem-cells", NULL)) {
518 if (ret) { 551 ret = imx_init_from_nvmem_cells(pdev);
519 dev_err(&pdev->dev, "failed to get sensor data\n"); 552 if (ret == -EPROBE_DEFER)
520 return ret; 553 return ret;
554 if (ret) {
555 dev_err(&pdev->dev, "failed to init from nvmem: %d\n",
556 ret);
557 return ret;
558 }
559 } else {
560 ret = imx_init_from_tempmon_data(pdev);
561 if (ret) {
562 dev_err(&pdev->dev, "failed to init from from fsl,tempmon-data\n");
563 return ret;
564 }
521 } 565 }
522 566
523 /* Make sure sensor is in known good state for measurements */ 567 /* Make sure sensor is in known good state for measurements */