2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
15 #include <linux/err.h>
17 #include <linux/nvmem-consumer.h>
18 #include <linux/of_address.h>
19 #include <linux/of_platform.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
24 #define S0_ST_ADDR 0x1030
25 #define SN_ADDR_OFFSET 0x4
26 #define SN_ST_TEMP_MASK 0x3ff
27 #define CAL_DEGC_PT1 30
28 #define CAL_DEGC_PT2 120
29 #define SLOPE_FACTOR 1000
30 #define SLOPE_DEFAULT 3200
32 char *qfprom_read(struct device
*dev
, const char *cname
)
34 struct nvmem_cell
*cell
;
38 cell
= nvmem_cell_get(dev
, cname
);
40 return ERR_CAST(cell
);
42 ret
= nvmem_cell_read(cell
, &data
);
49 * Use this function on devices where slope and offset calculations
50 * depend on calibration data read from qfprom. On others the slope
51 * and offset values are derived from tz->tzp->slope and tz->tzp->offset
54 void compute_intercept_slope(struct tsens_device
*tmdev
, u32
*p1
,
60 for (i
= 0; i
< tmdev
->num_sensors
; i
++) {
62 "sensor%d - data_point1:%#x data_point2:%#x\n",
65 tmdev
->sensor
[i
].slope
= SLOPE_DEFAULT
;
66 if (mode
== TWO_PT_CALIB
) {
68 * slope (m) = adc_code2 - adc_code1 (y2 - y1)/
69 * temp_120_degc - temp_30_degc (x2 - x1)
73 den
= CAL_DEGC_PT2
- CAL_DEGC_PT1
;
74 tmdev
->sensor
[i
].slope
= num
/ den
;
77 tmdev
->sensor
[i
].offset
= (p1
[i
] * SLOPE_FACTOR
) -
79 tmdev
->sensor
[i
].slope
);
80 dev_dbg(tmdev
->dev
, "offset:%d\n", tmdev
->sensor
[i
].offset
);
84 static inline int code_to_degc(u32 adc_code
, const struct tsens_sensor
*s
)
88 num
= (adc_code
* SLOPE_FACTOR
) - s
->offset
;
92 degc
= num
+ (den
/ 2);
94 degc
= num
- (den
/ 2);
103 int get_temp_common(struct tsens_device
*tmdev
, int id
, int *temp
)
105 struct tsens_sensor
*s
= &tmdev
->sensor
[id
];
107 unsigned int status_reg
;
108 int last_temp
= 0, ret
;
110 status_reg
= S0_ST_ADDR
+ s
->hw_id
* SN_ADDR_OFFSET
;
111 ret
= regmap_read(tmdev
->map
, status_reg
, &code
);
114 last_temp
= code
& SN_ST_TEMP_MASK
;
116 *temp
= code_to_degc(last_temp
, s
) * 1000;
121 static const struct regmap_config tsens_config
= {
127 int __init
init_common(struct tsens_device
*tmdev
)
130 struct resource
*res
;
131 struct platform_device
*op
= of_find_device_by_node(tmdev
->dev
->of_node
);
136 /* The driver only uses the TM register address space for now */
137 if (op
->num_resources
> 1) {
138 tmdev
->tm_offset
= 0;
140 /* old DTs where SROT and TM were in a contiguous 2K block */
141 tmdev
->tm_offset
= 0x1000;
144 res
= platform_get_resource(op
, IORESOURCE_MEM
, 0);
145 base
= devm_ioremap_resource(&op
->dev
, res
);
147 return PTR_ERR(base
);
149 tmdev
->map
= devm_regmap_init_mmio(tmdev
->dev
, base
, &tsens_config
);
150 if (IS_ERR(tmdev
->map
))
151 return PTR_ERR(tmdev
->map
);