1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Thermal sensor driver for Allwinner SOC
4*4882a593Smuzhiyun * Copyright (C) 2019 Yangtao Li
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Based on the work of Icenowy Zheng <icenowy@aosc.io>
7*4882a593Smuzhiyun * Based on the work of Ondrej Jirman <megous@megous.com>
8*4882a593Smuzhiyun * Based on the work of Josef Gajdusek <atx@atx.name>
9*4882a593Smuzhiyun */
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun #include <linux/clk.h>
12*4882a593Smuzhiyun #include <linux/device.h>
13*4882a593Smuzhiyun #include <linux/interrupt.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/nvmem-consumer.h>
16*4882a593Smuzhiyun #include <linux/of_device.h>
17*4882a593Smuzhiyun #include <linux/platform_device.h>
18*4882a593Smuzhiyun #include <linux/regmap.h>
19*4882a593Smuzhiyun #include <linux/reset.h>
20*4882a593Smuzhiyun #include <linux/slab.h>
21*4882a593Smuzhiyun #include <linux/thermal.h>
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun #include "thermal_hwmon.h"
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun #define MAX_SENSOR_NUM 4
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun #define FT_TEMP_MASK GENMASK(11, 0)
28*4882a593Smuzhiyun #define TEMP_CALIB_MASK GENMASK(11, 0)
29*4882a593Smuzhiyun #define CALIBRATE_DEFAULT 0x800
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define SUN8I_THS_CTRL0 0x00
32*4882a593Smuzhiyun #define SUN8I_THS_CTRL2 0x40
33*4882a593Smuzhiyun #define SUN8I_THS_IC 0x44
34*4882a593Smuzhiyun #define SUN8I_THS_IS 0x48
35*4882a593Smuzhiyun #define SUN8I_THS_MFC 0x70
36*4882a593Smuzhiyun #define SUN8I_THS_TEMP_CALIB 0x74
37*4882a593Smuzhiyun #define SUN8I_THS_TEMP_DATA 0x80
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #define SUN50I_THS_CTRL0 0x00
40*4882a593Smuzhiyun #define SUN50I_H6_THS_ENABLE 0x04
41*4882a593Smuzhiyun #define SUN50I_H6_THS_PC 0x08
42*4882a593Smuzhiyun #define SUN50I_H6_THS_DIC 0x10
43*4882a593Smuzhiyun #define SUN50I_H6_THS_DIS 0x20
44*4882a593Smuzhiyun #define SUN50I_H6_THS_MFC 0x30
45*4882a593Smuzhiyun #define SUN50I_H6_THS_TEMP_CALIB 0xa0
46*4882a593Smuzhiyun #define SUN50I_H6_THS_TEMP_DATA 0xc0
47*4882a593Smuzhiyun
48*4882a593Smuzhiyun #define SUN8I_THS_CTRL0_T_ACQ0(x) (GENMASK(15, 0) & (x))
49*4882a593Smuzhiyun #define SUN8I_THS_CTRL2_T_ACQ1(x) ((GENMASK(15, 0) & (x)) << 16)
50*4882a593Smuzhiyun #define SUN8I_THS_DATA_IRQ_STS(x) BIT(x + 8)
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun #define SUN50I_THS_CTRL0_T_ACQ(x) ((GENMASK(15, 0) & (x)) << 16)
53*4882a593Smuzhiyun #define SUN50I_THS_FILTER_EN BIT(2)
54*4882a593Smuzhiyun #define SUN50I_THS_FILTER_TYPE(x) (GENMASK(1, 0) & (x))
55*4882a593Smuzhiyun #define SUN50I_H6_THS_PC_TEMP_PERIOD(x) ((GENMASK(19, 0) & (x)) << 12)
56*4882a593Smuzhiyun #define SUN50I_H6_THS_DATA_IRQ_STS(x) BIT(x)
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun /* millidegree celsius */
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun struct tsensor {
61*4882a593Smuzhiyun struct ths_device *tmdev;
62*4882a593Smuzhiyun struct thermal_zone_device *tzd;
63*4882a593Smuzhiyun int id;
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun struct ths_thermal_chip {
67*4882a593Smuzhiyun bool has_mod_clk;
68*4882a593Smuzhiyun bool has_bus_clk_reset;
69*4882a593Smuzhiyun int sensor_num;
70*4882a593Smuzhiyun int offset;
71*4882a593Smuzhiyun int scale;
72*4882a593Smuzhiyun int ft_deviation;
73*4882a593Smuzhiyun int temp_data_base;
74*4882a593Smuzhiyun int (*calibrate)(struct ths_device *tmdev,
75*4882a593Smuzhiyun u16 *caldata, int callen);
76*4882a593Smuzhiyun int (*init)(struct ths_device *tmdev);
77*4882a593Smuzhiyun int (*irq_ack)(struct ths_device *tmdev);
78*4882a593Smuzhiyun int (*calc_temp)(struct ths_device *tmdev,
79*4882a593Smuzhiyun int id, int reg);
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun struct ths_device {
83*4882a593Smuzhiyun const struct ths_thermal_chip *chip;
84*4882a593Smuzhiyun struct device *dev;
85*4882a593Smuzhiyun struct regmap *regmap;
86*4882a593Smuzhiyun struct reset_control *reset;
87*4882a593Smuzhiyun struct clk *bus_clk;
88*4882a593Smuzhiyun struct clk *mod_clk;
89*4882a593Smuzhiyun struct tsensor sensor[MAX_SENSOR_NUM];
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /* Temp Unit: millidegree Celsius */
sun8i_ths_calc_temp(struct ths_device * tmdev,int id,int reg)93*4882a593Smuzhiyun static int sun8i_ths_calc_temp(struct ths_device *tmdev,
94*4882a593Smuzhiyun int id, int reg)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun return tmdev->chip->offset - (reg * tmdev->chip->scale / 10);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun
sun50i_h5_calc_temp(struct ths_device * tmdev,int id,int reg)99*4882a593Smuzhiyun static int sun50i_h5_calc_temp(struct ths_device *tmdev,
100*4882a593Smuzhiyun int id, int reg)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun if (reg >= 0x500)
103*4882a593Smuzhiyun return -1191 * reg / 10 + 223000;
104*4882a593Smuzhiyun else if (!id)
105*4882a593Smuzhiyun return -1452 * reg / 10 + 259000;
106*4882a593Smuzhiyun else
107*4882a593Smuzhiyun return -1590 * reg / 10 + 276000;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun
sun8i_ths_get_temp(void * data,int * temp)110*4882a593Smuzhiyun static int sun8i_ths_get_temp(void *data, int *temp)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun struct tsensor *s = data;
113*4882a593Smuzhiyun struct ths_device *tmdev = s->tmdev;
114*4882a593Smuzhiyun int val = 0;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun regmap_read(tmdev->regmap, tmdev->chip->temp_data_base +
117*4882a593Smuzhiyun 0x4 * s->id, &val);
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /* ths have no data yet */
120*4882a593Smuzhiyun if (!val)
121*4882a593Smuzhiyun return -EAGAIN;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun *temp = tmdev->chip->calc_temp(tmdev, s->id, val);
124*4882a593Smuzhiyun /*
125*4882a593Smuzhiyun * According to the original sdk, there are some platforms(rarely)
126*4882a593Smuzhiyun * that add a fixed offset value after calculating the temperature
127*4882a593Smuzhiyun * value. We can't simply put it on the formula for calculating the
128*4882a593Smuzhiyun * temperature above, because the formula for calculating the
129*4882a593Smuzhiyun * temperature above is also used when the sensor is calibrated. If
130*4882a593Smuzhiyun * do this, the correct calibration formula is hard to know.
131*4882a593Smuzhiyun */
132*4882a593Smuzhiyun *temp += tmdev->chip->ft_deviation;
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun return 0;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun static const struct thermal_zone_of_device_ops ths_ops = {
138*4882a593Smuzhiyun .get_temp = sun8i_ths_get_temp,
139*4882a593Smuzhiyun };
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun static const struct regmap_config config = {
142*4882a593Smuzhiyun .reg_bits = 32,
143*4882a593Smuzhiyun .val_bits = 32,
144*4882a593Smuzhiyun .reg_stride = 4,
145*4882a593Smuzhiyun .fast_io = true,
146*4882a593Smuzhiyun .max_register = 0xfc,
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun
sun8i_h3_irq_ack(struct ths_device * tmdev)149*4882a593Smuzhiyun static int sun8i_h3_irq_ack(struct ths_device *tmdev)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun int i, state, ret = 0;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun regmap_read(tmdev->regmap, SUN8I_THS_IS, &state);
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun for (i = 0; i < tmdev->chip->sensor_num; i++) {
156*4882a593Smuzhiyun if (state & SUN8I_THS_DATA_IRQ_STS(i)) {
157*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN8I_THS_IS,
158*4882a593Smuzhiyun SUN8I_THS_DATA_IRQ_STS(i));
159*4882a593Smuzhiyun ret |= BIT(i);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun return ret;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun
sun50i_h6_irq_ack(struct ths_device * tmdev)166*4882a593Smuzhiyun static int sun50i_h6_irq_ack(struct ths_device *tmdev)
167*4882a593Smuzhiyun {
168*4882a593Smuzhiyun int i, state, ret = 0;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun regmap_read(tmdev->regmap, SUN50I_H6_THS_DIS, &state);
171*4882a593Smuzhiyun
172*4882a593Smuzhiyun for (i = 0; i < tmdev->chip->sensor_num; i++) {
173*4882a593Smuzhiyun if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) {
174*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN50I_H6_THS_DIS,
175*4882a593Smuzhiyun SUN50I_H6_THS_DATA_IRQ_STS(i));
176*4882a593Smuzhiyun ret |= BIT(i);
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun
180*4882a593Smuzhiyun return ret;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun
sun8i_irq_thread(int irq,void * data)183*4882a593Smuzhiyun static irqreturn_t sun8i_irq_thread(int irq, void *data)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun struct ths_device *tmdev = data;
186*4882a593Smuzhiyun int i, state;
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun state = tmdev->chip->irq_ack(tmdev);
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun for (i = 0; i < tmdev->chip->sensor_num; i++) {
191*4882a593Smuzhiyun if (state & BIT(i))
192*4882a593Smuzhiyun thermal_zone_device_update(tmdev->sensor[i].tzd,
193*4882a593Smuzhiyun THERMAL_EVENT_UNSPECIFIED);
194*4882a593Smuzhiyun }
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun return IRQ_HANDLED;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
sun8i_h3_ths_calibrate(struct ths_device * tmdev,u16 * caldata,int callen)199*4882a593Smuzhiyun static int sun8i_h3_ths_calibrate(struct ths_device *tmdev,
200*4882a593Smuzhiyun u16 *caldata, int callen)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun int i;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun if (!caldata[0] || callen < 2 * tmdev->chip->sensor_num)
205*4882a593Smuzhiyun return -EINVAL;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun for (i = 0; i < tmdev->chip->sensor_num; i++) {
208*4882a593Smuzhiyun int offset = (i % 2) << 4;
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun regmap_update_bits(tmdev->regmap,
211*4882a593Smuzhiyun SUN8I_THS_TEMP_CALIB + (4 * (i >> 1)),
212*4882a593Smuzhiyun 0xfff << offset,
213*4882a593Smuzhiyun caldata[i] << offset);
214*4882a593Smuzhiyun }
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
sun50i_h6_ths_calibrate(struct ths_device * tmdev,u16 * caldata,int callen)219*4882a593Smuzhiyun static int sun50i_h6_ths_calibrate(struct ths_device *tmdev,
220*4882a593Smuzhiyun u16 *caldata, int callen)
221*4882a593Smuzhiyun {
222*4882a593Smuzhiyun struct device *dev = tmdev->dev;
223*4882a593Smuzhiyun int i, ft_temp;
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun if (!caldata[0] || callen < 2 + 2 * tmdev->chip->sensor_num)
226*4882a593Smuzhiyun return -EINVAL;
227*4882a593Smuzhiyun
228*4882a593Smuzhiyun /*
229*4882a593Smuzhiyun * efuse layout:
230*4882a593Smuzhiyun *
231*4882a593Smuzhiyun * 0 11 16 32
232*4882a593Smuzhiyun * +-------+-------+-------+
233*4882a593Smuzhiyun * |temp| |sensor0|sensor1|
234*4882a593Smuzhiyun * +-------+-------+-------+
235*4882a593Smuzhiyun *
236*4882a593Smuzhiyun * The calibration data on the H6 is the ambient temperature and
237*4882a593Smuzhiyun * sensor values that are filled during the factory test stage.
238*4882a593Smuzhiyun *
239*4882a593Smuzhiyun * The unit of stored FT temperature is 0.1 degreee celusis.
240*4882a593Smuzhiyun *
241*4882a593Smuzhiyun * We need to calculate a delta between measured and caluclated
242*4882a593Smuzhiyun * register values and this will become a calibration offset.
243*4882a593Smuzhiyun */
244*4882a593Smuzhiyun ft_temp = (caldata[0] & FT_TEMP_MASK) * 100;
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun for (i = 0; i < tmdev->chip->sensor_num; i++) {
247*4882a593Smuzhiyun int sensor_reg = caldata[i + 1] & TEMP_CALIB_MASK;
248*4882a593Smuzhiyun int cdata, offset;
249*4882a593Smuzhiyun int sensor_temp = tmdev->chip->calc_temp(tmdev, i, sensor_reg);
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun /*
252*4882a593Smuzhiyun * Calibration data is CALIBRATE_DEFAULT - (calculated
253*4882a593Smuzhiyun * temperature from sensor reading at factory temperature
254*4882a593Smuzhiyun * minus actual factory temperature) * 14.88 (scale from
255*4882a593Smuzhiyun * temperature to register values)
256*4882a593Smuzhiyun */
257*4882a593Smuzhiyun cdata = CALIBRATE_DEFAULT -
258*4882a593Smuzhiyun ((sensor_temp - ft_temp) * 10 / tmdev->chip->scale);
259*4882a593Smuzhiyun if (cdata & ~TEMP_CALIB_MASK) {
260*4882a593Smuzhiyun /*
261*4882a593Smuzhiyun * Calibration value more than 12-bit, but calibration
262*4882a593Smuzhiyun * register is 12-bit. In this case, ths hardware can
263*4882a593Smuzhiyun * still work without calibration, although the data
264*4882a593Smuzhiyun * won't be so accurate.
265*4882a593Smuzhiyun */
266*4882a593Smuzhiyun dev_warn(dev, "sensor%d is not calibrated.\n", i);
267*4882a593Smuzhiyun continue;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun offset = (i % 2) * 16;
271*4882a593Smuzhiyun regmap_update_bits(tmdev->regmap,
272*4882a593Smuzhiyun SUN50I_H6_THS_TEMP_CALIB + (i / 2 * 4),
273*4882a593Smuzhiyun 0xfff << offset,
274*4882a593Smuzhiyun cdata << offset);
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun return 0;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun
sun8i_ths_calibrate(struct ths_device * tmdev)280*4882a593Smuzhiyun static int sun8i_ths_calibrate(struct ths_device *tmdev)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun struct nvmem_cell *calcell;
283*4882a593Smuzhiyun struct device *dev = tmdev->dev;
284*4882a593Smuzhiyun u16 *caldata;
285*4882a593Smuzhiyun size_t callen;
286*4882a593Smuzhiyun int ret = 0;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun calcell = devm_nvmem_cell_get(dev, "calibration");
289*4882a593Smuzhiyun if (IS_ERR(calcell)) {
290*4882a593Smuzhiyun if (PTR_ERR(calcell) == -EPROBE_DEFER)
291*4882a593Smuzhiyun return -EPROBE_DEFER;
292*4882a593Smuzhiyun /*
293*4882a593Smuzhiyun * Even if the external calibration data stored in sid is
294*4882a593Smuzhiyun * not accessible, the THS hardware can still work, although
295*4882a593Smuzhiyun * the data won't be so accurate.
296*4882a593Smuzhiyun *
297*4882a593Smuzhiyun * The default value of calibration register is 0x800 for
298*4882a593Smuzhiyun * every sensor, and the calibration value is usually 0x7xx
299*4882a593Smuzhiyun * or 0x8xx, so they won't be away from the default value
300*4882a593Smuzhiyun * for a lot.
301*4882a593Smuzhiyun *
302*4882a593Smuzhiyun * So here we do not return error if the calibartion data is
303*4882a593Smuzhiyun * not available, except the probe needs deferring.
304*4882a593Smuzhiyun */
305*4882a593Smuzhiyun goto out;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun caldata = nvmem_cell_read(calcell, &callen);
309*4882a593Smuzhiyun if (IS_ERR(caldata)) {
310*4882a593Smuzhiyun ret = PTR_ERR(caldata);
311*4882a593Smuzhiyun goto out;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun tmdev->chip->calibrate(tmdev, caldata, callen);
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun kfree(caldata);
317*4882a593Smuzhiyun out:
318*4882a593Smuzhiyun return ret;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
sun8i_ths_resource_init(struct ths_device * tmdev)321*4882a593Smuzhiyun static int sun8i_ths_resource_init(struct ths_device *tmdev)
322*4882a593Smuzhiyun {
323*4882a593Smuzhiyun struct device *dev = tmdev->dev;
324*4882a593Smuzhiyun struct platform_device *pdev = to_platform_device(dev);
325*4882a593Smuzhiyun void __iomem *base;
326*4882a593Smuzhiyun int ret;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun base = devm_platform_ioremap_resource(pdev, 0);
329*4882a593Smuzhiyun if (IS_ERR(base))
330*4882a593Smuzhiyun return PTR_ERR(base);
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun tmdev->regmap = devm_regmap_init_mmio(dev, base, &config);
333*4882a593Smuzhiyun if (IS_ERR(tmdev->regmap))
334*4882a593Smuzhiyun return PTR_ERR(tmdev->regmap);
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun if (tmdev->chip->has_bus_clk_reset) {
337*4882a593Smuzhiyun tmdev->reset = devm_reset_control_get(dev, NULL);
338*4882a593Smuzhiyun if (IS_ERR(tmdev->reset))
339*4882a593Smuzhiyun return PTR_ERR(tmdev->reset);
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun tmdev->bus_clk = devm_clk_get(&pdev->dev, "bus");
342*4882a593Smuzhiyun if (IS_ERR(tmdev->bus_clk))
343*4882a593Smuzhiyun return PTR_ERR(tmdev->bus_clk);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (tmdev->chip->has_mod_clk) {
347*4882a593Smuzhiyun tmdev->mod_clk = devm_clk_get(&pdev->dev, "mod");
348*4882a593Smuzhiyun if (IS_ERR(tmdev->mod_clk))
349*4882a593Smuzhiyun return PTR_ERR(tmdev->mod_clk);
350*4882a593Smuzhiyun }
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun ret = reset_control_deassert(tmdev->reset);
353*4882a593Smuzhiyun if (ret)
354*4882a593Smuzhiyun return ret;
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun ret = clk_prepare_enable(tmdev->bus_clk);
357*4882a593Smuzhiyun if (ret)
358*4882a593Smuzhiyun goto assert_reset;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun ret = clk_set_rate(tmdev->mod_clk, 24000000);
361*4882a593Smuzhiyun if (ret)
362*4882a593Smuzhiyun goto bus_disable;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun ret = clk_prepare_enable(tmdev->mod_clk);
365*4882a593Smuzhiyun if (ret)
366*4882a593Smuzhiyun goto bus_disable;
367*4882a593Smuzhiyun
368*4882a593Smuzhiyun ret = sun8i_ths_calibrate(tmdev);
369*4882a593Smuzhiyun if (ret)
370*4882a593Smuzhiyun goto mod_disable;
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun return 0;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun mod_disable:
375*4882a593Smuzhiyun clk_disable_unprepare(tmdev->mod_clk);
376*4882a593Smuzhiyun bus_disable:
377*4882a593Smuzhiyun clk_disable_unprepare(tmdev->bus_clk);
378*4882a593Smuzhiyun assert_reset:
379*4882a593Smuzhiyun reset_control_assert(tmdev->reset);
380*4882a593Smuzhiyun
381*4882a593Smuzhiyun return ret;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun
sun8i_h3_thermal_init(struct ths_device * tmdev)384*4882a593Smuzhiyun static int sun8i_h3_thermal_init(struct ths_device *tmdev)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun int val;
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun /* average over 4 samples */
389*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN8I_THS_MFC,
390*4882a593Smuzhiyun SUN50I_THS_FILTER_EN |
391*4882a593Smuzhiyun SUN50I_THS_FILTER_TYPE(1));
392*4882a593Smuzhiyun /*
393*4882a593Smuzhiyun * clkin = 24MHz
394*4882a593Smuzhiyun * filter_samples = 4
395*4882a593Smuzhiyun * period = 0.25s
396*4882a593Smuzhiyun *
397*4882a593Smuzhiyun * x = period * clkin / 4096 / filter_samples - 1
398*4882a593Smuzhiyun * = 365
399*4882a593Smuzhiyun */
400*4882a593Smuzhiyun val = GENMASK(7 + tmdev->chip->sensor_num, 8);
401*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN8I_THS_IC,
402*4882a593Smuzhiyun SUN50I_H6_THS_PC_TEMP_PERIOD(365) | val);
403*4882a593Smuzhiyun /*
404*4882a593Smuzhiyun * T_acq = 20us
405*4882a593Smuzhiyun * clkin = 24MHz
406*4882a593Smuzhiyun *
407*4882a593Smuzhiyun * x = T_acq * clkin - 1
408*4882a593Smuzhiyun * = 479
409*4882a593Smuzhiyun */
410*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN8I_THS_CTRL0,
411*4882a593Smuzhiyun SUN8I_THS_CTRL0_T_ACQ0(479));
412*4882a593Smuzhiyun val = GENMASK(tmdev->chip->sensor_num - 1, 0);
413*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN8I_THS_CTRL2,
414*4882a593Smuzhiyun SUN8I_THS_CTRL2_T_ACQ1(479) | val);
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun return 0;
417*4882a593Smuzhiyun }
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /*
420*4882a593Smuzhiyun * Without this undocummented value, the returned temperatures would
421*4882a593Smuzhiyun * be higher than real ones by about 20C.
422*4882a593Smuzhiyun */
423*4882a593Smuzhiyun #define SUN50I_H6_CTRL0_UNK 0x0000002f
424*4882a593Smuzhiyun
sun50i_h6_thermal_init(struct ths_device * tmdev)425*4882a593Smuzhiyun static int sun50i_h6_thermal_init(struct ths_device *tmdev)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun int val;
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun /*
430*4882a593Smuzhiyun * T_acq = 20us
431*4882a593Smuzhiyun * clkin = 24MHz
432*4882a593Smuzhiyun *
433*4882a593Smuzhiyun * x = T_acq * clkin - 1
434*4882a593Smuzhiyun * = 479
435*4882a593Smuzhiyun */
436*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN50I_THS_CTRL0,
437*4882a593Smuzhiyun SUN50I_H6_CTRL0_UNK | SUN50I_THS_CTRL0_T_ACQ(479));
438*4882a593Smuzhiyun /* average over 4 samples */
439*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN50I_H6_THS_MFC,
440*4882a593Smuzhiyun SUN50I_THS_FILTER_EN |
441*4882a593Smuzhiyun SUN50I_THS_FILTER_TYPE(1));
442*4882a593Smuzhiyun /*
443*4882a593Smuzhiyun * clkin = 24MHz
444*4882a593Smuzhiyun * filter_samples = 4
445*4882a593Smuzhiyun * period = 0.25s
446*4882a593Smuzhiyun *
447*4882a593Smuzhiyun * x = period * clkin / 4096 / filter_samples - 1
448*4882a593Smuzhiyun * = 365
449*4882a593Smuzhiyun */
450*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN50I_H6_THS_PC,
451*4882a593Smuzhiyun SUN50I_H6_THS_PC_TEMP_PERIOD(365));
452*4882a593Smuzhiyun /* enable sensor */
453*4882a593Smuzhiyun val = GENMASK(tmdev->chip->sensor_num - 1, 0);
454*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN50I_H6_THS_ENABLE, val);
455*4882a593Smuzhiyun /* thermal data interrupt enable */
456*4882a593Smuzhiyun val = GENMASK(tmdev->chip->sensor_num - 1, 0);
457*4882a593Smuzhiyun regmap_write(tmdev->regmap, SUN50I_H6_THS_DIC, val);
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun return 0;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
sun8i_ths_register(struct ths_device * tmdev)462*4882a593Smuzhiyun static int sun8i_ths_register(struct ths_device *tmdev)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun int i;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun for (i = 0; i < tmdev->chip->sensor_num; i++) {
467*4882a593Smuzhiyun tmdev->sensor[i].tmdev = tmdev;
468*4882a593Smuzhiyun tmdev->sensor[i].id = i;
469*4882a593Smuzhiyun tmdev->sensor[i].tzd =
470*4882a593Smuzhiyun devm_thermal_zone_of_sensor_register(tmdev->dev,
471*4882a593Smuzhiyun i,
472*4882a593Smuzhiyun &tmdev->sensor[i],
473*4882a593Smuzhiyun &ths_ops);
474*4882a593Smuzhiyun if (IS_ERR(tmdev->sensor[i].tzd))
475*4882a593Smuzhiyun return PTR_ERR(tmdev->sensor[i].tzd);
476*4882a593Smuzhiyun
477*4882a593Smuzhiyun if (devm_thermal_add_hwmon_sysfs(tmdev->sensor[i].tzd))
478*4882a593Smuzhiyun dev_warn(tmdev->dev,
479*4882a593Smuzhiyun "Failed to add hwmon sysfs attributes\n");
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun return 0;
483*4882a593Smuzhiyun }
484*4882a593Smuzhiyun
sun8i_ths_probe(struct platform_device * pdev)485*4882a593Smuzhiyun static int sun8i_ths_probe(struct platform_device *pdev)
486*4882a593Smuzhiyun {
487*4882a593Smuzhiyun struct ths_device *tmdev;
488*4882a593Smuzhiyun struct device *dev = &pdev->dev;
489*4882a593Smuzhiyun int ret, irq;
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun tmdev = devm_kzalloc(dev, sizeof(*tmdev), GFP_KERNEL);
492*4882a593Smuzhiyun if (!tmdev)
493*4882a593Smuzhiyun return -ENOMEM;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun tmdev->dev = dev;
496*4882a593Smuzhiyun tmdev->chip = of_device_get_match_data(&pdev->dev);
497*4882a593Smuzhiyun if (!tmdev->chip)
498*4882a593Smuzhiyun return -EINVAL;
499*4882a593Smuzhiyun
500*4882a593Smuzhiyun platform_set_drvdata(pdev, tmdev);
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun ret = sun8i_ths_resource_init(tmdev);
503*4882a593Smuzhiyun if (ret)
504*4882a593Smuzhiyun return ret;
505*4882a593Smuzhiyun
506*4882a593Smuzhiyun irq = platform_get_irq(pdev, 0);
507*4882a593Smuzhiyun if (irq < 0)
508*4882a593Smuzhiyun return irq;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun ret = tmdev->chip->init(tmdev);
511*4882a593Smuzhiyun if (ret)
512*4882a593Smuzhiyun return ret;
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun ret = sun8i_ths_register(tmdev);
515*4882a593Smuzhiyun if (ret)
516*4882a593Smuzhiyun return ret;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun /*
519*4882a593Smuzhiyun * Avoid entering the interrupt handler, the thermal device is not
520*4882a593Smuzhiyun * registered yet, we deffer the registration of the interrupt to
521*4882a593Smuzhiyun * the end.
522*4882a593Smuzhiyun */
523*4882a593Smuzhiyun ret = devm_request_threaded_irq(dev, irq, NULL,
524*4882a593Smuzhiyun sun8i_irq_thread,
525*4882a593Smuzhiyun IRQF_ONESHOT, "ths", tmdev);
526*4882a593Smuzhiyun if (ret)
527*4882a593Smuzhiyun return ret;
528*4882a593Smuzhiyun
529*4882a593Smuzhiyun return 0;
530*4882a593Smuzhiyun }
531*4882a593Smuzhiyun
sun8i_ths_remove(struct platform_device * pdev)532*4882a593Smuzhiyun static int sun8i_ths_remove(struct platform_device *pdev)
533*4882a593Smuzhiyun {
534*4882a593Smuzhiyun struct ths_device *tmdev = platform_get_drvdata(pdev);
535*4882a593Smuzhiyun
536*4882a593Smuzhiyun clk_disable_unprepare(tmdev->mod_clk);
537*4882a593Smuzhiyun clk_disable_unprepare(tmdev->bus_clk);
538*4882a593Smuzhiyun reset_control_assert(tmdev->reset);
539*4882a593Smuzhiyun
540*4882a593Smuzhiyun return 0;
541*4882a593Smuzhiyun }
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun static const struct ths_thermal_chip sun8i_a83t_ths = {
544*4882a593Smuzhiyun .sensor_num = 3,
545*4882a593Smuzhiyun .scale = 705,
546*4882a593Smuzhiyun .offset = 191668,
547*4882a593Smuzhiyun .temp_data_base = SUN8I_THS_TEMP_DATA,
548*4882a593Smuzhiyun .calibrate = sun8i_h3_ths_calibrate,
549*4882a593Smuzhiyun .init = sun8i_h3_thermal_init,
550*4882a593Smuzhiyun .irq_ack = sun8i_h3_irq_ack,
551*4882a593Smuzhiyun .calc_temp = sun8i_ths_calc_temp,
552*4882a593Smuzhiyun };
553*4882a593Smuzhiyun
554*4882a593Smuzhiyun static const struct ths_thermal_chip sun8i_h3_ths = {
555*4882a593Smuzhiyun .sensor_num = 1,
556*4882a593Smuzhiyun .scale = 1211,
557*4882a593Smuzhiyun .offset = 217000,
558*4882a593Smuzhiyun .has_mod_clk = true,
559*4882a593Smuzhiyun .has_bus_clk_reset = true,
560*4882a593Smuzhiyun .temp_data_base = SUN8I_THS_TEMP_DATA,
561*4882a593Smuzhiyun .calibrate = sun8i_h3_ths_calibrate,
562*4882a593Smuzhiyun .init = sun8i_h3_thermal_init,
563*4882a593Smuzhiyun .irq_ack = sun8i_h3_irq_ack,
564*4882a593Smuzhiyun .calc_temp = sun8i_ths_calc_temp,
565*4882a593Smuzhiyun };
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun static const struct ths_thermal_chip sun8i_r40_ths = {
568*4882a593Smuzhiyun .sensor_num = 2,
569*4882a593Smuzhiyun .offset = 251086,
570*4882a593Smuzhiyun .scale = 1130,
571*4882a593Smuzhiyun .has_mod_clk = true,
572*4882a593Smuzhiyun .has_bus_clk_reset = true,
573*4882a593Smuzhiyun .temp_data_base = SUN8I_THS_TEMP_DATA,
574*4882a593Smuzhiyun .calibrate = sun8i_h3_ths_calibrate,
575*4882a593Smuzhiyun .init = sun8i_h3_thermal_init,
576*4882a593Smuzhiyun .irq_ack = sun8i_h3_irq_ack,
577*4882a593Smuzhiyun .calc_temp = sun8i_ths_calc_temp,
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun
580*4882a593Smuzhiyun static const struct ths_thermal_chip sun50i_a64_ths = {
581*4882a593Smuzhiyun .sensor_num = 3,
582*4882a593Smuzhiyun .offset = 260890,
583*4882a593Smuzhiyun .scale = 1170,
584*4882a593Smuzhiyun .has_mod_clk = true,
585*4882a593Smuzhiyun .has_bus_clk_reset = true,
586*4882a593Smuzhiyun .temp_data_base = SUN8I_THS_TEMP_DATA,
587*4882a593Smuzhiyun .calibrate = sun8i_h3_ths_calibrate,
588*4882a593Smuzhiyun .init = sun8i_h3_thermal_init,
589*4882a593Smuzhiyun .irq_ack = sun8i_h3_irq_ack,
590*4882a593Smuzhiyun .calc_temp = sun8i_ths_calc_temp,
591*4882a593Smuzhiyun };
592*4882a593Smuzhiyun
593*4882a593Smuzhiyun static const struct ths_thermal_chip sun50i_a100_ths = {
594*4882a593Smuzhiyun .sensor_num = 3,
595*4882a593Smuzhiyun .has_bus_clk_reset = true,
596*4882a593Smuzhiyun .ft_deviation = 8000,
597*4882a593Smuzhiyun .offset = 187744,
598*4882a593Smuzhiyun .scale = 672,
599*4882a593Smuzhiyun .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
600*4882a593Smuzhiyun .calibrate = sun50i_h6_ths_calibrate,
601*4882a593Smuzhiyun .init = sun50i_h6_thermal_init,
602*4882a593Smuzhiyun .irq_ack = sun50i_h6_irq_ack,
603*4882a593Smuzhiyun .calc_temp = sun8i_ths_calc_temp,
604*4882a593Smuzhiyun };
605*4882a593Smuzhiyun
606*4882a593Smuzhiyun static const struct ths_thermal_chip sun50i_h5_ths = {
607*4882a593Smuzhiyun .sensor_num = 2,
608*4882a593Smuzhiyun .has_mod_clk = true,
609*4882a593Smuzhiyun .has_bus_clk_reset = true,
610*4882a593Smuzhiyun .temp_data_base = SUN8I_THS_TEMP_DATA,
611*4882a593Smuzhiyun .calibrate = sun8i_h3_ths_calibrate,
612*4882a593Smuzhiyun .init = sun8i_h3_thermal_init,
613*4882a593Smuzhiyun .irq_ack = sun8i_h3_irq_ack,
614*4882a593Smuzhiyun .calc_temp = sun50i_h5_calc_temp,
615*4882a593Smuzhiyun };
616*4882a593Smuzhiyun
617*4882a593Smuzhiyun static const struct ths_thermal_chip sun50i_h6_ths = {
618*4882a593Smuzhiyun .sensor_num = 2,
619*4882a593Smuzhiyun .has_bus_clk_reset = true,
620*4882a593Smuzhiyun .ft_deviation = 7000,
621*4882a593Smuzhiyun .offset = 187744,
622*4882a593Smuzhiyun .scale = 672,
623*4882a593Smuzhiyun .temp_data_base = SUN50I_H6_THS_TEMP_DATA,
624*4882a593Smuzhiyun .calibrate = sun50i_h6_ths_calibrate,
625*4882a593Smuzhiyun .init = sun50i_h6_thermal_init,
626*4882a593Smuzhiyun .irq_ack = sun50i_h6_irq_ack,
627*4882a593Smuzhiyun .calc_temp = sun8i_ths_calc_temp,
628*4882a593Smuzhiyun };
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun static const struct of_device_id of_ths_match[] = {
631*4882a593Smuzhiyun { .compatible = "allwinner,sun8i-a83t-ths", .data = &sun8i_a83t_ths },
632*4882a593Smuzhiyun { .compatible = "allwinner,sun8i-h3-ths", .data = &sun8i_h3_ths },
633*4882a593Smuzhiyun { .compatible = "allwinner,sun8i-r40-ths", .data = &sun8i_r40_ths },
634*4882a593Smuzhiyun { .compatible = "allwinner,sun50i-a64-ths", .data = &sun50i_a64_ths },
635*4882a593Smuzhiyun { .compatible = "allwinner,sun50i-a100-ths", .data = &sun50i_a100_ths },
636*4882a593Smuzhiyun { .compatible = "allwinner,sun50i-h5-ths", .data = &sun50i_h5_ths },
637*4882a593Smuzhiyun { .compatible = "allwinner,sun50i-h6-ths", .data = &sun50i_h6_ths },
638*4882a593Smuzhiyun { /* sentinel */ },
639*4882a593Smuzhiyun };
640*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_ths_match);
641*4882a593Smuzhiyun
642*4882a593Smuzhiyun static struct platform_driver ths_driver = {
643*4882a593Smuzhiyun .probe = sun8i_ths_probe,
644*4882a593Smuzhiyun .remove = sun8i_ths_remove,
645*4882a593Smuzhiyun .driver = {
646*4882a593Smuzhiyun .name = "sun8i-thermal",
647*4882a593Smuzhiyun .of_match_table = of_ths_match,
648*4882a593Smuzhiyun },
649*4882a593Smuzhiyun };
650*4882a593Smuzhiyun module_platform_driver(ths_driver);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun MODULE_DESCRIPTION("Thermal sensor driver for Allwinner SOC");
653*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
654