xref: /OK3568_Linux_fs/kernel/drivers/thermal/sun8i_thermal.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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