xref: /OK3568_Linux_fs/kernel/drivers/iio/adc/twl6030-gpadc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * TWL6030 GPADC module driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009-2013 Texas Instruments Inc.
6*4882a593Smuzhiyun  * Nishant Kamat <nskamat@ti.com>
7*4882a593Smuzhiyun  * Balaji T K <balajitk@ti.com>
8*4882a593Smuzhiyun  * Graeme Gregory <gg@slimlogic.co.uk>
9*4882a593Smuzhiyun  * Girish S Ghongdemath <girishsg@ti.com>
10*4882a593Smuzhiyun  * Ambresh K <ambresh@ti.com>
11*4882a593Smuzhiyun  * Oleksandr Kozaruk <oleksandr.kozaruk@ti.com
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * Based on twl4030-madc.c
14*4882a593Smuzhiyun  * Copyright (C) 2008 Nokia Corporation
15*4882a593Smuzhiyun  * Mikko Ylinen <mikko.k.ylinen@nokia.com>
16*4882a593Smuzhiyun  */
17*4882a593Smuzhiyun #include <linux/interrupt.h>
18*4882a593Smuzhiyun #include <linux/kernel.h>
19*4882a593Smuzhiyun #include <linux/module.h>
20*4882a593Smuzhiyun #include <linux/platform_device.h>
21*4882a593Smuzhiyun #include <linux/of_platform.h>
22*4882a593Smuzhiyun #include <linux/mfd/twl.h>
23*4882a593Smuzhiyun #include <linux/iio/iio.h>
24*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #define DRIVER_NAME		"twl6030_gpadc"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /*
29*4882a593Smuzhiyun  * twl6030 per TRM has 17 channels, and twl6032 has 19 channels
30*4882a593Smuzhiyun  * 2 test network channels are not used,
31*4882a593Smuzhiyun  * 2 die temperature channels are not used either, as it is not
32*4882a593Smuzhiyun  * defined how to convert ADC value to temperature
33*4882a593Smuzhiyun  */
34*4882a593Smuzhiyun #define TWL6030_GPADC_USED_CHANNELS		13
35*4882a593Smuzhiyun #define TWL6030_GPADC_MAX_CHANNELS		15
36*4882a593Smuzhiyun #define TWL6032_GPADC_USED_CHANNELS		15
37*4882a593Smuzhiyun #define TWL6032_GPADC_MAX_CHANNELS		19
38*4882a593Smuzhiyun #define TWL6030_GPADC_NUM_TRIM_REGS		16
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define TWL6030_GPADC_CTRL_P1			0x05
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #define TWL6032_GPADC_GPSELECT_ISB		0x07
43*4882a593Smuzhiyun #define TWL6032_GPADC_CTRL_P1			0x08
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define TWL6032_GPADC_GPCH0_LSB			0x0d
46*4882a593Smuzhiyun #define TWL6032_GPADC_GPCH0_MSB			0x0e
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #define TWL6030_GPADC_CTRL_P1_SP1		BIT(3)
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun #define TWL6030_GPADC_GPCH0_LSB			(0x29)
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define TWL6030_GPADC_RT_SW1_EOC_MASK		BIT(5)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define TWL6030_GPADC_TRIM1			0xCD
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #define TWL6030_REG_TOGGLE1			0x90
57*4882a593Smuzhiyun #define TWL6030_GPADCS				BIT(1)
58*4882a593Smuzhiyun #define TWL6030_GPADCR				BIT(0)
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun /**
61*4882a593Smuzhiyun  * struct twl6030_chnl_calib - channel calibration
62*4882a593Smuzhiyun  * @gain:		slope coefficient for ideal curve
63*4882a593Smuzhiyun  * @gain_error:		gain error
64*4882a593Smuzhiyun  * @offset_error:	offset of the real curve
65*4882a593Smuzhiyun  */
66*4882a593Smuzhiyun struct twl6030_chnl_calib {
67*4882a593Smuzhiyun 	s32 gain;
68*4882a593Smuzhiyun 	s32 gain_error;
69*4882a593Smuzhiyun 	s32 offset_error;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /**
73*4882a593Smuzhiyun  * struct twl6030_ideal_code - GPADC calibration parameters
74*4882a593Smuzhiyun  * GPADC is calibrated in two points: close to the beginning and
75*4882a593Smuzhiyun  * to the and of the measurable input range
76*4882a593Smuzhiyun  *
77*4882a593Smuzhiyun  * @channel:	channel number
78*4882a593Smuzhiyun  * @code1:	ideal code for the input at the beginning
79*4882a593Smuzhiyun  * @code2:	ideal code for at the end of the range
80*4882a593Smuzhiyun  * @volt1:	voltage input at the beginning(low voltage)
81*4882a593Smuzhiyun  * @volt2:	voltage input at the end(high voltage)
82*4882a593Smuzhiyun  */
83*4882a593Smuzhiyun struct twl6030_ideal_code {
84*4882a593Smuzhiyun 	int channel;
85*4882a593Smuzhiyun 	u16 code1;
86*4882a593Smuzhiyun 	u16 code2;
87*4882a593Smuzhiyun 	u16 volt1;
88*4882a593Smuzhiyun 	u16 volt2;
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun struct twl6030_gpadc_data;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun /**
94*4882a593Smuzhiyun  * struct twl6030_gpadc_platform_data - platform specific data
95*4882a593Smuzhiyun  * @nchannels:		number of GPADC channels
96*4882a593Smuzhiyun  * @iio_channels:	iio channels
97*4882a593Smuzhiyun  * @ideal:		pointer to calibration parameters
98*4882a593Smuzhiyun  * @start_conversion:	pointer to ADC start conversion function
99*4882a593Smuzhiyun  * @channel_to_reg:	pointer to ADC function to convert channel to
100*4882a593Smuzhiyun  *			register address for reading conversion result
101*4882a593Smuzhiyun  * @calibrate:		pointer to calibration function
102*4882a593Smuzhiyun  */
103*4882a593Smuzhiyun struct twl6030_gpadc_platform_data {
104*4882a593Smuzhiyun 	const int nchannels;
105*4882a593Smuzhiyun 	const struct iio_chan_spec *iio_channels;
106*4882a593Smuzhiyun 	const struct twl6030_ideal_code *ideal;
107*4882a593Smuzhiyun 	int (*start_conversion)(int channel);
108*4882a593Smuzhiyun 	u8 (*channel_to_reg)(int channel);
109*4882a593Smuzhiyun 	int (*calibrate)(struct twl6030_gpadc_data *gpadc);
110*4882a593Smuzhiyun };
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /**
113*4882a593Smuzhiyun  * struct twl6030_gpadc_data - GPADC data
114*4882a593Smuzhiyun  * @dev:		device pointer
115*4882a593Smuzhiyun  * @lock:		mutual exclusion lock for the structure
116*4882a593Smuzhiyun  * @irq_complete:	completion to signal end of conversion
117*4882a593Smuzhiyun  * @twl6030_cal_tbl:	pointer to calibration data for each
118*4882a593Smuzhiyun  *			channel with gain error and offset
119*4882a593Smuzhiyun  * @pdata:		pointer to device specific data
120*4882a593Smuzhiyun  */
121*4882a593Smuzhiyun struct twl6030_gpadc_data {
122*4882a593Smuzhiyun 	struct device	*dev;
123*4882a593Smuzhiyun 	struct mutex	lock;
124*4882a593Smuzhiyun 	struct completion	irq_complete;
125*4882a593Smuzhiyun 	struct twl6030_chnl_calib	*twl6030_cal_tbl;
126*4882a593Smuzhiyun 	const struct twl6030_gpadc_platform_data *pdata;
127*4882a593Smuzhiyun };
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun /*
130*4882a593Smuzhiyun  * channels 11, 12, 13, 15 and 16 have no calibration data
131*4882a593Smuzhiyun  * calibration offset is same for channels 1, 3, 4, 5
132*4882a593Smuzhiyun  *
133*4882a593Smuzhiyun  * The data is taken from GPADC_TRIM registers description.
134*4882a593Smuzhiyun  * GPADC_TRIM registers keep difference between the code measured
135*4882a593Smuzhiyun  * at volt1 and volt2 input voltages and corresponding code1 and code2
136*4882a593Smuzhiyun  */
137*4882a593Smuzhiyun static const struct twl6030_ideal_code
138*4882a593Smuzhiyun 	twl6030_ideal[TWL6030_GPADC_USED_CHANNELS] = {
139*4882a593Smuzhiyun 	[0] = { /* ch 0, external, battery type, resistor value */
140*4882a593Smuzhiyun 		.channel = 0,
141*4882a593Smuzhiyun 		.code1 = 116,
142*4882a593Smuzhiyun 		.code2 = 745,
143*4882a593Smuzhiyun 		.volt1 = 141,
144*4882a593Smuzhiyun 		.volt2 = 910,
145*4882a593Smuzhiyun 	},
146*4882a593Smuzhiyun 	[1] = { /* ch 1, external, battery temperature, NTC resistor value */
147*4882a593Smuzhiyun 		.channel = 1,
148*4882a593Smuzhiyun 		.code1 = 82,
149*4882a593Smuzhiyun 		.code2 = 900,
150*4882a593Smuzhiyun 		.volt1 = 100,
151*4882a593Smuzhiyun 		.volt2 = 1100,
152*4882a593Smuzhiyun 	},
153*4882a593Smuzhiyun 	[2] = { /* ch 2, external, audio accessory/general purpose */
154*4882a593Smuzhiyun 		.channel = 2,
155*4882a593Smuzhiyun 		.code1 = 55,
156*4882a593Smuzhiyun 		.code2 = 818,
157*4882a593Smuzhiyun 		.volt1 = 101,
158*4882a593Smuzhiyun 		.volt2 = 1499,
159*4882a593Smuzhiyun 	},
160*4882a593Smuzhiyun 	[3] = { /* ch 3, external, general purpose */
161*4882a593Smuzhiyun 		.channel = 3,
162*4882a593Smuzhiyun 		.code1 = 82,
163*4882a593Smuzhiyun 		.code2 = 900,
164*4882a593Smuzhiyun 		.volt1 = 100,
165*4882a593Smuzhiyun 		.volt2 = 1100,
166*4882a593Smuzhiyun 	},
167*4882a593Smuzhiyun 	[4] = { /* ch 4, external, temperature measurement/general purpose */
168*4882a593Smuzhiyun 		.channel = 4,
169*4882a593Smuzhiyun 		.code1 = 82,
170*4882a593Smuzhiyun 		.code2 = 900,
171*4882a593Smuzhiyun 		.volt1 = 100,
172*4882a593Smuzhiyun 		.volt2 = 1100,
173*4882a593Smuzhiyun 	},
174*4882a593Smuzhiyun 	[5] = { /* ch 5, external, general purpose */
175*4882a593Smuzhiyun 		.channel = 5,
176*4882a593Smuzhiyun 		.code1 = 82,
177*4882a593Smuzhiyun 		.code2 = 900,
178*4882a593Smuzhiyun 		.volt1 = 100,
179*4882a593Smuzhiyun 		.volt2 = 1100,
180*4882a593Smuzhiyun 	},
181*4882a593Smuzhiyun 	[6] = { /* ch 6, external, general purpose */
182*4882a593Smuzhiyun 		.channel = 6,
183*4882a593Smuzhiyun 		.code1 = 82,
184*4882a593Smuzhiyun 		.code2 = 900,
185*4882a593Smuzhiyun 		.volt1 = 100,
186*4882a593Smuzhiyun 		.volt2 = 1100,
187*4882a593Smuzhiyun 	},
188*4882a593Smuzhiyun 	[7] = { /* ch 7, internal, main battery */
189*4882a593Smuzhiyun 		.channel = 7,
190*4882a593Smuzhiyun 		.code1 = 614,
191*4882a593Smuzhiyun 		.code2 = 941,
192*4882a593Smuzhiyun 		.volt1 = 3001,
193*4882a593Smuzhiyun 		.volt2 = 4599,
194*4882a593Smuzhiyun 	},
195*4882a593Smuzhiyun 	[8] = { /* ch 8, internal, backup battery */
196*4882a593Smuzhiyun 		.channel = 8,
197*4882a593Smuzhiyun 		.code1 = 82,
198*4882a593Smuzhiyun 		.code2 = 688,
199*4882a593Smuzhiyun 		.volt1 = 501,
200*4882a593Smuzhiyun 		.volt2 = 4203,
201*4882a593Smuzhiyun 	},
202*4882a593Smuzhiyun 	[9] = { /* ch 9, internal, external charger input */
203*4882a593Smuzhiyun 		.channel = 9,
204*4882a593Smuzhiyun 		.code1 = 182,
205*4882a593Smuzhiyun 		.code2 = 818,
206*4882a593Smuzhiyun 		.volt1 = 2001,
207*4882a593Smuzhiyun 		.volt2 = 8996,
208*4882a593Smuzhiyun 	},
209*4882a593Smuzhiyun 	[10] = { /* ch 10, internal, VBUS */
210*4882a593Smuzhiyun 		.channel = 10,
211*4882a593Smuzhiyun 		.code1 = 149,
212*4882a593Smuzhiyun 		.code2 = 818,
213*4882a593Smuzhiyun 		.volt1 = 1001,
214*4882a593Smuzhiyun 		.volt2 = 5497,
215*4882a593Smuzhiyun 	},
216*4882a593Smuzhiyun 	[11] = { /* ch 11, internal, VBUS charging current */
217*4882a593Smuzhiyun 		.channel = 11,
218*4882a593Smuzhiyun 	},
219*4882a593Smuzhiyun 		/* ch 12, internal, Die temperature */
220*4882a593Smuzhiyun 		/* ch 13, internal, Die temperature */
221*4882a593Smuzhiyun 	[12] = { /* ch 14, internal, USB ID line */
222*4882a593Smuzhiyun 		.channel = 14,
223*4882a593Smuzhiyun 		.code1 = 48,
224*4882a593Smuzhiyun 		.code2 = 714,
225*4882a593Smuzhiyun 		.volt1 = 323,
226*4882a593Smuzhiyun 		.volt2 = 4800,
227*4882a593Smuzhiyun 	},
228*4882a593Smuzhiyun };
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static const struct twl6030_ideal_code
231*4882a593Smuzhiyun 			twl6032_ideal[TWL6032_GPADC_USED_CHANNELS] = {
232*4882a593Smuzhiyun 	[0] = { /* ch 0, external, battery type, resistor value */
233*4882a593Smuzhiyun 		.channel = 0,
234*4882a593Smuzhiyun 		.code1 = 1441,
235*4882a593Smuzhiyun 		.code2 = 3276,
236*4882a593Smuzhiyun 		.volt1 = 440,
237*4882a593Smuzhiyun 		.volt2 = 1000,
238*4882a593Smuzhiyun 	},
239*4882a593Smuzhiyun 	[1] = { /* ch 1, external, battery temperature, NTC resistor value */
240*4882a593Smuzhiyun 		.channel = 1,
241*4882a593Smuzhiyun 		.code1 = 1441,
242*4882a593Smuzhiyun 		.code2 = 3276,
243*4882a593Smuzhiyun 		.volt1 = 440,
244*4882a593Smuzhiyun 		.volt2 = 1000,
245*4882a593Smuzhiyun 	},
246*4882a593Smuzhiyun 	[2] = { /* ch 2, external, audio accessory/general purpose */
247*4882a593Smuzhiyun 		.channel = 2,
248*4882a593Smuzhiyun 		.code1 = 1441,
249*4882a593Smuzhiyun 		.code2 = 3276,
250*4882a593Smuzhiyun 		.volt1 = 660,
251*4882a593Smuzhiyun 		.volt2 = 1500,
252*4882a593Smuzhiyun 	},
253*4882a593Smuzhiyun 	[3] = { /* ch 3, external, temperature with external diode/general
254*4882a593Smuzhiyun 								purpose */
255*4882a593Smuzhiyun 		.channel = 3,
256*4882a593Smuzhiyun 		.code1 = 1441,
257*4882a593Smuzhiyun 		.code2 = 3276,
258*4882a593Smuzhiyun 		.volt1 = 440,
259*4882a593Smuzhiyun 		.volt2 = 1000,
260*4882a593Smuzhiyun 	},
261*4882a593Smuzhiyun 	[4] = { /* ch 4, external, temperature measurement/general purpose */
262*4882a593Smuzhiyun 		.channel = 4,
263*4882a593Smuzhiyun 		.code1 = 1441,
264*4882a593Smuzhiyun 		.code2 = 3276,
265*4882a593Smuzhiyun 		.volt1 = 440,
266*4882a593Smuzhiyun 		.volt2 = 1000,
267*4882a593Smuzhiyun 	},
268*4882a593Smuzhiyun 	[5] = { /* ch 5, external, general purpose */
269*4882a593Smuzhiyun 		.channel = 5,
270*4882a593Smuzhiyun 		.code1 = 1441,
271*4882a593Smuzhiyun 		.code2 = 3276,
272*4882a593Smuzhiyun 		.volt1 = 440,
273*4882a593Smuzhiyun 		.volt2 = 1000,
274*4882a593Smuzhiyun 	},
275*4882a593Smuzhiyun 	[6] = { /* ch 6, external, general purpose */
276*4882a593Smuzhiyun 		.channel = 6,
277*4882a593Smuzhiyun 		.code1 = 1441,
278*4882a593Smuzhiyun 		.code2 = 3276,
279*4882a593Smuzhiyun 		.volt1 = 440,
280*4882a593Smuzhiyun 		.volt2 = 1000,
281*4882a593Smuzhiyun 	},
282*4882a593Smuzhiyun 	[7] = { /* ch7, internal, system supply */
283*4882a593Smuzhiyun 		.channel = 7,
284*4882a593Smuzhiyun 		.code1 = 1441,
285*4882a593Smuzhiyun 		.code2 = 3276,
286*4882a593Smuzhiyun 		.volt1 = 2200,
287*4882a593Smuzhiyun 		.volt2 = 5000,
288*4882a593Smuzhiyun 	},
289*4882a593Smuzhiyun 	[8] = { /* ch8, internal, backup battery */
290*4882a593Smuzhiyun 		.channel = 8,
291*4882a593Smuzhiyun 		.code1 = 1441,
292*4882a593Smuzhiyun 		.code2 = 3276,
293*4882a593Smuzhiyun 		.volt1 = 2200,
294*4882a593Smuzhiyun 		.volt2 = 5000,
295*4882a593Smuzhiyun 	},
296*4882a593Smuzhiyun 	[9] = { /* ch 9, internal, external charger input */
297*4882a593Smuzhiyun 		.channel = 9,
298*4882a593Smuzhiyun 		.code1 = 1441,
299*4882a593Smuzhiyun 		.code2 = 3276,
300*4882a593Smuzhiyun 		.volt1 = 3960,
301*4882a593Smuzhiyun 		.volt2 = 9000,
302*4882a593Smuzhiyun 	},
303*4882a593Smuzhiyun 	[10] = { /* ch10, internal, VBUS */
304*4882a593Smuzhiyun 		.channel = 10,
305*4882a593Smuzhiyun 		.code1 = 150,
306*4882a593Smuzhiyun 		.code2 = 751,
307*4882a593Smuzhiyun 		.volt1 = 1000,
308*4882a593Smuzhiyun 		.volt2 = 5000,
309*4882a593Smuzhiyun 	},
310*4882a593Smuzhiyun 	[11] = { /* ch 11, internal, VBUS DC-DC output current */
311*4882a593Smuzhiyun 		.channel = 11,
312*4882a593Smuzhiyun 		.code1 = 1441,
313*4882a593Smuzhiyun 		.code2 = 3276,
314*4882a593Smuzhiyun 		.volt1 = 660,
315*4882a593Smuzhiyun 		.volt2 = 1500,
316*4882a593Smuzhiyun 	},
317*4882a593Smuzhiyun 		/* ch 12, internal, Die temperature */
318*4882a593Smuzhiyun 		/* ch 13, internal, Die temperature */
319*4882a593Smuzhiyun 	[12] = { /* ch 14, internal, USB ID line */
320*4882a593Smuzhiyun 		.channel = 14,
321*4882a593Smuzhiyun 		.code1 = 1441,
322*4882a593Smuzhiyun 		.code2 = 3276,
323*4882a593Smuzhiyun 		.volt1 = 2420,
324*4882a593Smuzhiyun 		.volt2 = 5500,
325*4882a593Smuzhiyun 	},
326*4882a593Smuzhiyun 		/* ch 15, internal, test network */
327*4882a593Smuzhiyun 		/* ch 16, internal, test network */
328*4882a593Smuzhiyun 	[13] = { /* ch 17, internal, battery charging current */
329*4882a593Smuzhiyun 		.channel = 17,
330*4882a593Smuzhiyun 	},
331*4882a593Smuzhiyun 	[14] = { /* ch 18, internal, battery voltage */
332*4882a593Smuzhiyun 		.channel = 18,
333*4882a593Smuzhiyun 		.code1 = 1441,
334*4882a593Smuzhiyun 		.code2 = 3276,
335*4882a593Smuzhiyun 		.volt1 = 2200,
336*4882a593Smuzhiyun 		.volt2 = 5000,
337*4882a593Smuzhiyun 	},
338*4882a593Smuzhiyun };
339*4882a593Smuzhiyun 
twl6030_gpadc_write(u8 reg,u8 val)340*4882a593Smuzhiyun static inline int twl6030_gpadc_write(u8 reg, u8 val)
341*4882a593Smuzhiyun {
342*4882a593Smuzhiyun 	return twl_i2c_write_u8(TWL6030_MODULE_GPADC, val, reg);
343*4882a593Smuzhiyun }
344*4882a593Smuzhiyun 
twl6030_gpadc_read(u8 reg,u8 * val)345*4882a593Smuzhiyun static inline int twl6030_gpadc_read(u8 reg, u8 *val)
346*4882a593Smuzhiyun {
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	return twl_i2c_read(TWL6030_MODULE_GPADC, val, reg, 2);
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
twl6030_gpadc_enable_irq(u8 mask)351*4882a593Smuzhiyun static int twl6030_gpadc_enable_irq(u8 mask)
352*4882a593Smuzhiyun {
353*4882a593Smuzhiyun 	int ret;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_LINE_B);
356*4882a593Smuzhiyun 	if (ret < 0)
357*4882a593Smuzhiyun 		return ret;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_STS_B);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	return ret;
362*4882a593Smuzhiyun }
363*4882a593Smuzhiyun 
twl6030_gpadc_disable_irq(u8 mask)364*4882a593Smuzhiyun static void twl6030_gpadc_disable_irq(u8 mask)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	twl6030_interrupt_mask(mask, REG_INT_MSK_LINE_B);
367*4882a593Smuzhiyun 	twl6030_interrupt_mask(mask, REG_INT_MSK_STS_B);
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
twl6030_gpadc_irq_handler(int irq,void * indio_dev)370*4882a593Smuzhiyun static irqreturn_t twl6030_gpadc_irq_handler(int irq, void *indio_dev)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	complete(&gpadc->irq_complete);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	return IRQ_HANDLED;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun 
twl6030_start_conversion(int channel)379*4882a593Smuzhiyun static int twl6030_start_conversion(int channel)
380*4882a593Smuzhiyun {
381*4882a593Smuzhiyun 	return twl6030_gpadc_write(TWL6030_GPADC_CTRL_P1,
382*4882a593Smuzhiyun 					TWL6030_GPADC_CTRL_P1_SP1);
383*4882a593Smuzhiyun }
384*4882a593Smuzhiyun 
twl6032_start_conversion(int channel)385*4882a593Smuzhiyun static int twl6032_start_conversion(int channel)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	int ret;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	ret = twl6030_gpadc_write(TWL6032_GPADC_GPSELECT_ISB, channel);
390*4882a593Smuzhiyun 	if (ret)
391*4882a593Smuzhiyun 		return ret;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	return twl6030_gpadc_write(TWL6032_GPADC_CTRL_P1,
394*4882a593Smuzhiyun 						TWL6030_GPADC_CTRL_P1_SP1);
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
twl6030_channel_to_reg(int channel)397*4882a593Smuzhiyun static u8 twl6030_channel_to_reg(int channel)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun 	return TWL6030_GPADC_GPCH0_LSB + 2 * channel;
400*4882a593Smuzhiyun }
401*4882a593Smuzhiyun 
twl6032_channel_to_reg(int channel)402*4882a593Smuzhiyun static u8 twl6032_channel_to_reg(int channel)
403*4882a593Smuzhiyun {
404*4882a593Smuzhiyun 	/*
405*4882a593Smuzhiyun 	 * for any prior chosen channel, when the conversion is ready
406*4882a593Smuzhiyun 	 * the result is avalable in GPCH0_LSB, GPCH0_MSB.
407*4882a593Smuzhiyun 	 */
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return TWL6032_GPADC_GPCH0_LSB;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
twl6030_gpadc_lookup(const struct twl6030_ideal_code * ideal,int channel,int size)412*4882a593Smuzhiyun static int twl6030_gpadc_lookup(const struct twl6030_ideal_code *ideal,
413*4882a593Smuzhiyun 		int channel, int size)
414*4882a593Smuzhiyun {
415*4882a593Smuzhiyun 	int i;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	for (i = 0; i < size; i++)
418*4882a593Smuzhiyun 		if (ideal[i].channel == channel)
419*4882a593Smuzhiyun 			break;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	return i;
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data * pdata,int channel)424*4882a593Smuzhiyun static int twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data
425*4882a593Smuzhiyun 		*pdata, int channel)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	const struct twl6030_ideal_code *ideal = pdata->ideal;
428*4882a593Smuzhiyun 	int i;
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	i = twl6030_gpadc_lookup(ideal, channel, pdata->nchannels);
431*4882a593Smuzhiyun 	/* not calibrated channels have 0 in all structure members */
432*4882a593Smuzhiyun 	return pdata->ideal[i].code2;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
twl6030_gpadc_make_correction(struct twl6030_gpadc_data * gpadc,int channel,int raw_code)435*4882a593Smuzhiyun static int twl6030_gpadc_make_correction(struct twl6030_gpadc_data *gpadc,
436*4882a593Smuzhiyun 		int channel, int raw_code)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun 	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
439*4882a593Smuzhiyun 	int corrected_code;
440*4882a593Smuzhiyun 	int i;
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
443*4882a593Smuzhiyun 	corrected_code = ((raw_code * 1000) -
444*4882a593Smuzhiyun 		gpadc->twl6030_cal_tbl[i].offset_error) /
445*4882a593Smuzhiyun 		gpadc->twl6030_cal_tbl[i].gain_error;
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun 	return corrected_code;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun 
twl6030_gpadc_get_raw(struct twl6030_gpadc_data * gpadc,int channel,int * res)450*4882a593Smuzhiyun static int twl6030_gpadc_get_raw(struct twl6030_gpadc_data *gpadc,
451*4882a593Smuzhiyun 		int channel, int *res)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	u8 reg = gpadc->pdata->channel_to_reg(channel);
454*4882a593Smuzhiyun 	__le16 val;
455*4882a593Smuzhiyun 	int raw_code;
456*4882a593Smuzhiyun 	int ret;
457*4882a593Smuzhiyun 
458*4882a593Smuzhiyun 	ret = twl6030_gpadc_read(reg, (u8 *)&val);
459*4882a593Smuzhiyun 	if (ret) {
460*4882a593Smuzhiyun 		dev_dbg(gpadc->dev, "unable to read register 0x%X\n", reg);
461*4882a593Smuzhiyun 		return ret;
462*4882a593Smuzhiyun 	}
463*4882a593Smuzhiyun 
464*4882a593Smuzhiyun 	raw_code = le16_to_cpu(val);
465*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC raw code: %d", raw_code);
466*4882a593Smuzhiyun 
467*4882a593Smuzhiyun 	if (twl6030_channel_calibrated(gpadc->pdata, channel))
468*4882a593Smuzhiyun 		*res = twl6030_gpadc_make_correction(gpadc, channel, raw_code);
469*4882a593Smuzhiyun 	else
470*4882a593Smuzhiyun 		*res = raw_code;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	return ret;
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun 
twl6030_gpadc_get_processed(struct twl6030_gpadc_data * gpadc,int channel,int * val)475*4882a593Smuzhiyun static int twl6030_gpadc_get_processed(struct twl6030_gpadc_data *gpadc,
476*4882a593Smuzhiyun 		int channel, int *val)
477*4882a593Smuzhiyun {
478*4882a593Smuzhiyun 	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
479*4882a593Smuzhiyun 	int corrected_code;
480*4882a593Smuzhiyun 	int channel_value;
481*4882a593Smuzhiyun 	int i;
482*4882a593Smuzhiyun 	int ret;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	ret = twl6030_gpadc_get_raw(gpadc, channel, &corrected_code);
485*4882a593Smuzhiyun 	if (ret)
486*4882a593Smuzhiyun 		return ret;
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
489*4882a593Smuzhiyun 	channel_value = corrected_code *
490*4882a593Smuzhiyun 			gpadc->twl6030_cal_tbl[i].gain;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	/* Shift back into mV range */
493*4882a593Smuzhiyun 	channel_value /= 1000;
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC corrected code: %d", corrected_code);
496*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC value: %d", channel_value);
497*4882a593Smuzhiyun 
498*4882a593Smuzhiyun 	*val = channel_value;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 	return ret;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
twl6030_gpadc_read_raw(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,int * val,int * val2,long mask)503*4882a593Smuzhiyun static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
504*4882a593Smuzhiyun 			     const struct iio_chan_spec *chan,
505*4882a593Smuzhiyun 			     int *val, int *val2, long mask)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
508*4882a593Smuzhiyun 	int ret;
509*4882a593Smuzhiyun 	long timeout;
510*4882a593Smuzhiyun 
511*4882a593Smuzhiyun 	mutex_lock(&gpadc->lock);
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	ret = gpadc->pdata->start_conversion(chan->channel);
514*4882a593Smuzhiyun 	if (ret) {
515*4882a593Smuzhiyun 		dev_err(gpadc->dev, "failed to start conversion\n");
516*4882a593Smuzhiyun 		goto err;
517*4882a593Smuzhiyun 	}
518*4882a593Smuzhiyun 	/* wait for conversion to complete */
519*4882a593Smuzhiyun 	timeout = wait_for_completion_interruptible_timeout(
520*4882a593Smuzhiyun 				&gpadc->irq_complete, msecs_to_jiffies(5000));
521*4882a593Smuzhiyun 	if (timeout == 0) {
522*4882a593Smuzhiyun 		ret = -ETIMEDOUT;
523*4882a593Smuzhiyun 		goto err;
524*4882a593Smuzhiyun 	} else if (timeout < 0) {
525*4882a593Smuzhiyun 		ret = -EINTR;
526*4882a593Smuzhiyun 		goto err;
527*4882a593Smuzhiyun 	}
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	switch (mask) {
530*4882a593Smuzhiyun 	case IIO_CHAN_INFO_RAW:
531*4882a593Smuzhiyun 		ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val);
532*4882a593Smuzhiyun 		ret = ret ? -EIO : IIO_VAL_INT;
533*4882a593Smuzhiyun 		break;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	case IIO_CHAN_INFO_PROCESSED:
536*4882a593Smuzhiyun 		ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val);
537*4882a593Smuzhiyun 		ret = ret ? -EIO : IIO_VAL_INT;
538*4882a593Smuzhiyun 		break;
539*4882a593Smuzhiyun 
540*4882a593Smuzhiyun 	default:
541*4882a593Smuzhiyun 		break;
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun err:
544*4882a593Smuzhiyun 	mutex_unlock(&gpadc->lock);
545*4882a593Smuzhiyun 
546*4882a593Smuzhiyun 	return ret;
547*4882a593Smuzhiyun }
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun /*
550*4882a593Smuzhiyun  * The GPADC channels are calibrated using a two point calibration method.
551*4882a593Smuzhiyun  * The channels measured with two known values: volt1 and volt2, and
552*4882a593Smuzhiyun  * ideal corresponding output codes are known: code1, code2.
553*4882a593Smuzhiyun  * The difference(d1, d2) between ideal and measured codes stored in trim
554*4882a593Smuzhiyun  * registers.
555*4882a593Smuzhiyun  * The goal is to find offset and gain of the real curve for each calibrated
556*4882a593Smuzhiyun  * channel.
557*4882a593Smuzhiyun  * gain: k = 1 + ((d2 - d1) / (x2 - x1))
558*4882a593Smuzhiyun  * offset: b = d1 + (k - 1) * x1
559*4882a593Smuzhiyun  */
twl6030_calibrate_channel(struct twl6030_gpadc_data * gpadc,int channel,int d1,int d2)560*4882a593Smuzhiyun static void twl6030_calibrate_channel(struct twl6030_gpadc_data *gpadc,
561*4882a593Smuzhiyun 		int channel, int d1, int d2)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun 	int b, k, gain, x1, x2, i;
564*4882a593Smuzhiyun 	const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal;
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels);
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	/* Gain */
569*4882a593Smuzhiyun 	gain = ((ideal[i].volt2 - ideal[i].volt1) * 1000) /
570*4882a593Smuzhiyun 		(ideal[i].code2 - ideal[i].code1);
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	x1 = ideal[i].code1;
573*4882a593Smuzhiyun 	x2 = ideal[i].code2;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	/* k - real curve gain */
576*4882a593Smuzhiyun 	k = 1000 + (((d2 - d1) * 1000) / (x2 - x1));
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	/* b - offset of the real curve gain */
579*4882a593Smuzhiyun 	b = (d1 * 1000) - (k - 1000) * x1;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	gpadc->twl6030_cal_tbl[i].gain = gain;
582*4882a593Smuzhiyun 	gpadc->twl6030_cal_tbl[i].gain_error = k;
583*4882a593Smuzhiyun 	gpadc->twl6030_cal_tbl[i].offset_error = b;
584*4882a593Smuzhiyun 
585*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC d1   for Chn: %d = %d\n", channel, d1);
586*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC d2   for Chn: %d = %d\n", channel, d2);
587*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC x1   for Chn: %d = %d\n", channel, x1);
588*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC x2   for Chn: %d = %d\n", channel, x2);
589*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC Gain for Chn: %d = %d\n", channel, gain);
590*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC k    for Chn: %d = %d\n", channel, k);
591*4882a593Smuzhiyun 	dev_dbg(gpadc->dev, "GPADC b    for Chn: %d = %d\n", channel, b);
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
twl6030_gpadc_get_trim_offset(s8 d)594*4882a593Smuzhiyun static inline int twl6030_gpadc_get_trim_offset(s8 d)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	/*
597*4882a593Smuzhiyun 	 * XXX NOTE!
598*4882a593Smuzhiyun 	 * bit 0 - sign, bit 7 - reserved, 6..1 - trim value
599*4882a593Smuzhiyun 	 * though, the documentation states that trim value
600*4882a593Smuzhiyun 	 * is absolute value, the correct conversion results are
601*4882a593Smuzhiyun 	 * obtained if the value is interpreted as 2's complement.
602*4882a593Smuzhiyun 	 */
603*4882a593Smuzhiyun 	__u32 temp = ((d & 0x7f) >> 1) | ((d & 1) << 6);
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun 	return sign_extend32(temp, 6);
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
twl6030_calibration(struct twl6030_gpadc_data * gpadc)608*4882a593Smuzhiyun static int twl6030_calibration(struct twl6030_gpadc_data *gpadc)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun 	int ret;
611*4882a593Smuzhiyun 	int chn;
612*4882a593Smuzhiyun 	u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS];
613*4882a593Smuzhiyun 	s8 d1, d2;
614*4882a593Smuzhiyun 
615*4882a593Smuzhiyun 	/*
616*4882a593Smuzhiyun 	 * for calibration two measurements have been performed at
617*4882a593Smuzhiyun 	 * factory, for some channels, during the production test and
618*4882a593Smuzhiyun 	 * have been stored in registers. This two stored values are
619*4882a593Smuzhiyun 	 * used to correct the measurements. The values represent
620*4882a593Smuzhiyun 	 * offsets for the given input from the output on ideal curve.
621*4882a593Smuzhiyun 	 */
622*4882a593Smuzhiyun 	ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs,
623*4882a593Smuzhiyun 			TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS);
624*4882a593Smuzhiyun 	if (ret < 0) {
625*4882a593Smuzhiyun 		dev_err(gpadc->dev, "calibration failed\n");
626*4882a593Smuzhiyun 		return ret;
627*4882a593Smuzhiyun 	}
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	for (chn = 0; chn < TWL6030_GPADC_MAX_CHANNELS; chn++) {
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 		switch (chn) {
632*4882a593Smuzhiyun 		case 0:
633*4882a593Smuzhiyun 			d1 = trim_regs[0];
634*4882a593Smuzhiyun 			d2 = trim_regs[1];
635*4882a593Smuzhiyun 			break;
636*4882a593Smuzhiyun 		case 1:
637*4882a593Smuzhiyun 		case 3:
638*4882a593Smuzhiyun 		case 4:
639*4882a593Smuzhiyun 		case 5:
640*4882a593Smuzhiyun 		case 6:
641*4882a593Smuzhiyun 			d1 = trim_regs[4];
642*4882a593Smuzhiyun 			d2 = trim_regs[5];
643*4882a593Smuzhiyun 			break;
644*4882a593Smuzhiyun 		case 2:
645*4882a593Smuzhiyun 			d1 = trim_regs[12];
646*4882a593Smuzhiyun 			d2 = trim_regs[13];
647*4882a593Smuzhiyun 			break;
648*4882a593Smuzhiyun 		case 7:
649*4882a593Smuzhiyun 			d1 = trim_regs[6];
650*4882a593Smuzhiyun 			d2 = trim_regs[7];
651*4882a593Smuzhiyun 			break;
652*4882a593Smuzhiyun 		case 8:
653*4882a593Smuzhiyun 			d1 = trim_regs[2];
654*4882a593Smuzhiyun 			d2 = trim_regs[3];
655*4882a593Smuzhiyun 			break;
656*4882a593Smuzhiyun 		case 9:
657*4882a593Smuzhiyun 			d1 = trim_regs[8];
658*4882a593Smuzhiyun 			d2 = trim_regs[9];
659*4882a593Smuzhiyun 			break;
660*4882a593Smuzhiyun 		case 10:
661*4882a593Smuzhiyun 			d1 = trim_regs[10];
662*4882a593Smuzhiyun 			d2 = trim_regs[11];
663*4882a593Smuzhiyun 			break;
664*4882a593Smuzhiyun 		case 14:
665*4882a593Smuzhiyun 			d1 = trim_regs[14];
666*4882a593Smuzhiyun 			d2 = trim_regs[15];
667*4882a593Smuzhiyun 			break;
668*4882a593Smuzhiyun 		default:
669*4882a593Smuzhiyun 			continue;
670*4882a593Smuzhiyun 		}
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 		d1 = twl6030_gpadc_get_trim_offset(d1);
673*4882a593Smuzhiyun 		d2 = twl6030_gpadc_get_trim_offset(d2);
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 		twl6030_calibrate_channel(gpadc, chn, d1, d2);
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	return 0;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun 
twl6032_get_trim_value(u8 * trim_regs,unsigned int reg0,unsigned int reg1,unsigned int mask0,unsigned int mask1,unsigned int shift0)681*4882a593Smuzhiyun static int twl6032_get_trim_value(u8 *trim_regs, unsigned int reg0,
682*4882a593Smuzhiyun 		unsigned int reg1, unsigned int mask0, unsigned int mask1,
683*4882a593Smuzhiyun 		unsigned int shift0)
684*4882a593Smuzhiyun {
685*4882a593Smuzhiyun 	int val;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	val = (trim_regs[reg0] & mask0) << shift0;
688*4882a593Smuzhiyun 	val |= (trim_regs[reg1] & mask1) >> 1;
689*4882a593Smuzhiyun 	if (trim_regs[reg1] & 0x01)
690*4882a593Smuzhiyun 		val = -val;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	return val;
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
twl6032_calibration(struct twl6030_gpadc_data * gpadc)695*4882a593Smuzhiyun static int twl6032_calibration(struct twl6030_gpadc_data *gpadc)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	int chn, d1 = 0, d2 = 0, temp;
698*4882a593Smuzhiyun 	u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS];
699*4882a593Smuzhiyun 	int ret;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 	ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs,
702*4882a593Smuzhiyun 			TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS);
703*4882a593Smuzhiyun 	if (ret < 0) {
704*4882a593Smuzhiyun 		dev_err(gpadc->dev, "calibration failed\n");
705*4882a593Smuzhiyun 		return ret;
706*4882a593Smuzhiyun 	}
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	/*
709*4882a593Smuzhiyun 	 * Loop to calculate the value needed for returning voltages from
710*4882a593Smuzhiyun 	 * GPADC not values.
711*4882a593Smuzhiyun 	 *
712*4882a593Smuzhiyun 	 * gain is calculated to 3 decimal places fixed point.
713*4882a593Smuzhiyun 	 */
714*4882a593Smuzhiyun 	for (chn = 0; chn < TWL6032_GPADC_MAX_CHANNELS; chn++) {
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 		switch (chn) {
717*4882a593Smuzhiyun 		case 0:
718*4882a593Smuzhiyun 		case 1:
719*4882a593Smuzhiyun 		case 2:
720*4882a593Smuzhiyun 		case 3:
721*4882a593Smuzhiyun 		case 4:
722*4882a593Smuzhiyun 		case 5:
723*4882a593Smuzhiyun 		case 6:
724*4882a593Smuzhiyun 		case 11:
725*4882a593Smuzhiyun 		case 14:
726*4882a593Smuzhiyun 			d1 = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
727*4882a593Smuzhiyun 								0x06, 2);
728*4882a593Smuzhiyun 			d2 = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
729*4882a593Smuzhiyun 								0x06, 2);
730*4882a593Smuzhiyun 			break;
731*4882a593Smuzhiyun 		case 8:
732*4882a593Smuzhiyun 			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
733*4882a593Smuzhiyun 								0x06, 2);
734*4882a593Smuzhiyun 			d1 = temp + twl6032_get_trim_value(trim_regs, 7, 6,
735*4882a593Smuzhiyun 								0x18, 0x1E, 1);
736*4882a593Smuzhiyun 
737*4882a593Smuzhiyun 			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3F,
738*4882a593Smuzhiyun 								0x06, 2);
739*4882a593Smuzhiyun 			d2 = temp + twl6032_get_trim_value(trim_regs, 9, 7,
740*4882a593Smuzhiyun 								0x1F, 0x06, 2);
741*4882a593Smuzhiyun 			break;
742*4882a593Smuzhiyun 		case 9:
743*4882a593Smuzhiyun 			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
744*4882a593Smuzhiyun 								0x06, 2);
745*4882a593Smuzhiyun 			d1 = temp + twl6032_get_trim_value(trim_regs, 13, 11,
746*4882a593Smuzhiyun 								0x18, 0x1E, 1);
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun 			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
749*4882a593Smuzhiyun 								0x06, 2);
750*4882a593Smuzhiyun 			d2 = temp + twl6032_get_trim_value(trim_regs, 15, 13,
751*4882a593Smuzhiyun 								0x1F, 0x06, 1);
752*4882a593Smuzhiyun 			break;
753*4882a593Smuzhiyun 		case 10:
754*4882a593Smuzhiyun 			d1 = twl6032_get_trim_value(trim_regs, 10, 8, 0x0f,
755*4882a593Smuzhiyun 								0x0E, 3);
756*4882a593Smuzhiyun 			d2 = twl6032_get_trim_value(trim_regs, 14, 12, 0x0f,
757*4882a593Smuzhiyun 								0x0E, 3);
758*4882a593Smuzhiyun 			break;
759*4882a593Smuzhiyun 		case 7:
760*4882a593Smuzhiyun 		case 18:
761*4882a593Smuzhiyun 			temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f,
762*4882a593Smuzhiyun 								0x06, 2);
763*4882a593Smuzhiyun 
764*4882a593Smuzhiyun 			d1 = (trim_regs[4] & 0x7E) >> 1;
765*4882a593Smuzhiyun 			if (trim_regs[4] & 0x01)
766*4882a593Smuzhiyun 				d1 = -d1;
767*4882a593Smuzhiyun 			d1 += temp;
768*4882a593Smuzhiyun 
769*4882a593Smuzhiyun 			temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f,
770*4882a593Smuzhiyun 								0x06, 2);
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 			d2 = (trim_regs[5] & 0xFE) >> 1;
773*4882a593Smuzhiyun 			if (trim_regs[5] & 0x01)
774*4882a593Smuzhiyun 				d2 = -d2;
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 			d2 += temp;
777*4882a593Smuzhiyun 			break;
778*4882a593Smuzhiyun 		default:
779*4882a593Smuzhiyun 			/* No data for other channels */
780*4882a593Smuzhiyun 			continue;
781*4882a593Smuzhiyun 		}
782*4882a593Smuzhiyun 
783*4882a593Smuzhiyun 		twl6030_calibrate_channel(gpadc, chn, d1, d2);
784*4882a593Smuzhiyun 	}
785*4882a593Smuzhiyun 
786*4882a593Smuzhiyun 	return 0;
787*4882a593Smuzhiyun }
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun #define TWL6030_GPADC_CHAN(chn, _type, chan_info) {	\
790*4882a593Smuzhiyun 	.type = _type,					\
791*4882a593Smuzhiyun 	.channel = chn,					\
792*4882a593Smuzhiyun 	.info_mask_separate = BIT(chan_info),		\
793*4882a593Smuzhiyun 	.indexed = 1,					\
794*4882a593Smuzhiyun }
795*4882a593Smuzhiyun 
796*4882a593Smuzhiyun static const struct iio_chan_spec twl6030_gpadc_iio_channels[] = {
797*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
798*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW),
799*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
800*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
801*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW),
802*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
803*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
804*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
805*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
806*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
807*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
808*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
809*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
810*4882a593Smuzhiyun };
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun static const struct iio_chan_spec twl6032_gpadc_iio_channels[] = {
813*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
814*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW),
815*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
816*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
817*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW),
818*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
819*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
820*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
821*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
822*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
823*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
824*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
825*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
826*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(17, IIO_VOLTAGE, IIO_CHAN_INFO_RAW),
827*4882a593Smuzhiyun 	TWL6030_GPADC_CHAN(18, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED),
828*4882a593Smuzhiyun };
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun static const struct iio_info twl6030_gpadc_iio_info = {
831*4882a593Smuzhiyun 	.read_raw = &twl6030_gpadc_read_raw,
832*4882a593Smuzhiyun };
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun static const struct twl6030_gpadc_platform_data twl6030_pdata = {
835*4882a593Smuzhiyun 	.iio_channels = twl6030_gpadc_iio_channels,
836*4882a593Smuzhiyun 	.nchannels = TWL6030_GPADC_USED_CHANNELS,
837*4882a593Smuzhiyun 	.ideal = twl6030_ideal,
838*4882a593Smuzhiyun 	.start_conversion = twl6030_start_conversion,
839*4882a593Smuzhiyun 	.channel_to_reg = twl6030_channel_to_reg,
840*4882a593Smuzhiyun 	.calibrate = twl6030_calibration,
841*4882a593Smuzhiyun };
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun static const struct twl6030_gpadc_platform_data twl6032_pdata = {
844*4882a593Smuzhiyun 	.iio_channels = twl6032_gpadc_iio_channels,
845*4882a593Smuzhiyun 	.nchannels = TWL6032_GPADC_USED_CHANNELS,
846*4882a593Smuzhiyun 	.ideal = twl6032_ideal,
847*4882a593Smuzhiyun 	.start_conversion = twl6032_start_conversion,
848*4882a593Smuzhiyun 	.channel_to_reg = twl6032_channel_to_reg,
849*4882a593Smuzhiyun 	.calibrate = twl6032_calibration,
850*4882a593Smuzhiyun };
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun static const struct of_device_id of_twl6030_match_tbl[] = {
853*4882a593Smuzhiyun 	{
854*4882a593Smuzhiyun 		.compatible = "ti,twl6030-gpadc",
855*4882a593Smuzhiyun 		.data = &twl6030_pdata,
856*4882a593Smuzhiyun 	},
857*4882a593Smuzhiyun 	{
858*4882a593Smuzhiyun 		.compatible = "ti,twl6032-gpadc",
859*4882a593Smuzhiyun 		.data = &twl6032_pdata,
860*4882a593Smuzhiyun 	},
861*4882a593Smuzhiyun 	{ /* end */ }
862*4882a593Smuzhiyun };
863*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl);
864*4882a593Smuzhiyun 
twl6030_gpadc_probe(struct platform_device * pdev)865*4882a593Smuzhiyun static int twl6030_gpadc_probe(struct platform_device *pdev)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
868*4882a593Smuzhiyun 	struct twl6030_gpadc_data *gpadc;
869*4882a593Smuzhiyun 	const struct twl6030_gpadc_platform_data *pdata;
870*4882a593Smuzhiyun 	const struct of_device_id *match;
871*4882a593Smuzhiyun 	struct iio_dev *indio_dev;
872*4882a593Smuzhiyun 	int irq;
873*4882a593Smuzhiyun 	int ret;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 	match = of_match_device(of_twl6030_match_tbl, dev);
876*4882a593Smuzhiyun 	if (!match)
877*4882a593Smuzhiyun 		return -EINVAL;
878*4882a593Smuzhiyun 
879*4882a593Smuzhiyun 	pdata = match->data;
880*4882a593Smuzhiyun 
881*4882a593Smuzhiyun 	indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc));
882*4882a593Smuzhiyun 	if (!indio_dev)
883*4882a593Smuzhiyun 		return -ENOMEM;
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 	gpadc = iio_priv(indio_dev);
886*4882a593Smuzhiyun 
887*4882a593Smuzhiyun 	gpadc->twl6030_cal_tbl = devm_kcalloc(dev,
888*4882a593Smuzhiyun 					pdata->nchannels,
889*4882a593Smuzhiyun 					sizeof(*gpadc->twl6030_cal_tbl),
890*4882a593Smuzhiyun 					GFP_KERNEL);
891*4882a593Smuzhiyun 	if (!gpadc->twl6030_cal_tbl)
892*4882a593Smuzhiyun 		return -ENOMEM;
893*4882a593Smuzhiyun 
894*4882a593Smuzhiyun 	gpadc->dev = dev;
895*4882a593Smuzhiyun 	gpadc->pdata = pdata;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	platform_set_drvdata(pdev, indio_dev);
898*4882a593Smuzhiyun 	mutex_init(&gpadc->lock);
899*4882a593Smuzhiyun 	init_completion(&gpadc->irq_complete);
900*4882a593Smuzhiyun 
901*4882a593Smuzhiyun 	ret = pdata->calibrate(gpadc);
902*4882a593Smuzhiyun 	if (ret < 0) {
903*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to read calibration registers\n");
904*4882a593Smuzhiyun 		return ret;
905*4882a593Smuzhiyun 	}
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	irq = platform_get_irq(pdev, 0);
908*4882a593Smuzhiyun 	if (irq < 0)
909*4882a593Smuzhiyun 		return irq;
910*4882a593Smuzhiyun 
911*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(dev, irq, NULL,
912*4882a593Smuzhiyun 				twl6030_gpadc_irq_handler,
913*4882a593Smuzhiyun 				IRQF_ONESHOT, "twl6030_gpadc", indio_dev);
914*4882a593Smuzhiyun 	if (ret)
915*4882a593Smuzhiyun 		return ret;
916*4882a593Smuzhiyun 
917*4882a593Smuzhiyun 	ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
918*4882a593Smuzhiyun 	if (ret < 0) {
919*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
920*4882a593Smuzhiyun 		return ret;
921*4882a593Smuzhiyun 	}
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
924*4882a593Smuzhiyun 					TWL6030_REG_TOGGLE1);
925*4882a593Smuzhiyun 	if (ret < 0) {
926*4882a593Smuzhiyun 		dev_err(&pdev->dev, "failed to enable GPADC module\n");
927*4882a593Smuzhiyun 		return ret;
928*4882a593Smuzhiyun 	}
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	indio_dev->name = DRIVER_NAME;
931*4882a593Smuzhiyun 	indio_dev->info = &twl6030_gpadc_iio_info;
932*4882a593Smuzhiyun 	indio_dev->modes = INDIO_DIRECT_MODE;
933*4882a593Smuzhiyun 	indio_dev->channels = pdata->iio_channels;
934*4882a593Smuzhiyun 	indio_dev->num_channels = pdata->nchannels;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	return iio_device_register(indio_dev);
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun 
twl6030_gpadc_remove(struct platform_device * pdev)939*4882a593Smuzhiyun static int twl6030_gpadc_remove(struct platform_device *pdev)
940*4882a593Smuzhiyun {
941*4882a593Smuzhiyun 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
944*4882a593Smuzhiyun 	iio_device_unregister(indio_dev);
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	return 0;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun #ifdef CONFIG_PM_SLEEP
twl6030_gpadc_suspend(struct device * pdev)950*4882a593Smuzhiyun static int twl6030_gpadc_suspend(struct device *pdev)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	int ret;
953*4882a593Smuzhiyun 
954*4882a593Smuzhiyun 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR,
955*4882a593Smuzhiyun 				TWL6030_REG_TOGGLE1);
956*4882a593Smuzhiyun 	if (ret)
957*4882a593Smuzhiyun 		dev_err(pdev, "error resetting GPADC (%d)!\n", ret);
958*4882a593Smuzhiyun 
959*4882a593Smuzhiyun 	return 0;
960*4882a593Smuzhiyun };
961*4882a593Smuzhiyun 
twl6030_gpadc_resume(struct device * pdev)962*4882a593Smuzhiyun static int twl6030_gpadc_resume(struct device *pdev)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun 	int ret;
965*4882a593Smuzhiyun 
966*4882a593Smuzhiyun 	ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
967*4882a593Smuzhiyun 				TWL6030_REG_TOGGLE1);
968*4882a593Smuzhiyun 	if (ret)
969*4882a593Smuzhiyun 		dev_err(pdev, "error setting GPADC (%d)!\n", ret);
970*4882a593Smuzhiyun 
971*4882a593Smuzhiyun 	return 0;
972*4882a593Smuzhiyun };
973*4882a593Smuzhiyun #endif
974*4882a593Smuzhiyun 
975*4882a593Smuzhiyun static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend,
976*4882a593Smuzhiyun 					twl6030_gpadc_resume);
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun static struct platform_driver twl6030_gpadc_driver = {
979*4882a593Smuzhiyun 	.probe		= twl6030_gpadc_probe,
980*4882a593Smuzhiyun 	.remove		= twl6030_gpadc_remove,
981*4882a593Smuzhiyun 	.driver		= {
982*4882a593Smuzhiyun 		.name	= DRIVER_NAME,
983*4882a593Smuzhiyun 		.pm	= &twl6030_gpadc_pm_ops,
984*4882a593Smuzhiyun 		.of_match_table = of_twl6030_match_tbl,
985*4882a593Smuzhiyun 	},
986*4882a593Smuzhiyun };
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun module_platform_driver(twl6030_gpadc_driver);
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun MODULE_ALIAS("platform:" DRIVER_NAME);
991*4882a593Smuzhiyun MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
992*4882a593Smuzhiyun MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
993*4882a593Smuzhiyun MODULE_AUTHOR("Oleksandr Kozaruk <oleksandr.kozaruk@ti.com");
994*4882a593Smuzhiyun MODULE_DESCRIPTION("twl6030 ADC driver");
995*4882a593Smuzhiyun MODULE_LICENSE("GPL");
996