xref: /OK3568_Linux_fs/kernel/drivers/iio/light/si1133.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * si1133.c - Support for Silabs SI1133 combined ambient
4*4882a593Smuzhiyun  * light and UV index sensors
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  * Copyright 2018 Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>
7*4882a593Smuzhiyun  */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun #include <linux/delay.h>
10*4882a593Smuzhiyun #include <linux/i2c.h>
11*4882a593Smuzhiyun #include <linux/interrupt.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/regmap.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/iio/iio.h>
16*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun #include <linux/util_macros.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <asm/unaligned.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define SI1133_REG_PART_ID		0x00
23*4882a593Smuzhiyun #define SI1133_REG_REV_ID		0x01
24*4882a593Smuzhiyun #define SI1133_REG_MFR_ID		0x02
25*4882a593Smuzhiyun #define SI1133_REG_INFO0		0x03
26*4882a593Smuzhiyun #define SI1133_REG_INFO1		0x04
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define SI1133_PART_ID			0x33
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #define SI1133_REG_HOSTIN0		0x0A
31*4882a593Smuzhiyun #define SI1133_REG_COMMAND		0x0B
32*4882a593Smuzhiyun #define SI1133_REG_IRQ_ENABLE		0x0F
33*4882a593Smuzhiyun #define SI1133_REG_RESPONSE1		0x10
34*4882a593Smuzhiyun #define SI1133_REG_RESPONSE0		0x11
35*4882a593Smuzhiyun #define SI1133_REG_IRQ_STATUS		0x12
36*4882a593Smuzhiyun #define SI1133_REG_MEAS_RATE		0x1A
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #define SI1133_IRQ_CHANNEL_ENABLE	0xF
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun #define SI1133_CMD_RESET_CTR		0x00
41*4882a593Smuzhiyun #define SI1133_CMD_RESET_SW		0x01
42*4882a593Smuzhiyun #define SI1133_CMD_FORCE		0x11
43*4882a593Smuzhiyun #define SI1133_CMD_START_AUTONOMOUS	0x13
44*4882a593Smuzhiyun #define SI1133_CMD_PARAM_SET		0x80
45*4882a593Smuzhiyun #define SI1133_CMD_PARAM_QUERY		0x40
46*4882a593Smuzhiyun #define SI1133_CMD_PARAM_MASK		0x3F
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun #define SI1133_CMD_ERR_MASK		BIT(4)
49*4882a593Smuzhiyun #define SI1133_CMD_SEQ_MASK		0xF
50*4882a593Smuzhiyun #define SI1133_MAX_CMD_CTR		0xF
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define SI1133_PARAM_REG_CHAN_LIST	0x01
53*4882a593Smuzhiyun #define SI1133_PARAM_REG_ADCCONFIG(x)	((x) * 4) + 2
54*4882a593Smuzhiyun #define SI1133_PARAM_REG_ADCSENS(x)	((x) * 4) + 3
55*4882a593Smuzhiyun #define SI1133_PARAM_REG_ADCPOST(x)	((x) * 4) + 4
56*4882a593Smuzhiyun 
57*4882a593Smuzhiyun #define SI1133_ADCMUX_MASK 0x1F
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define SI1133_ADCCONFIG_DECIM_RATE(x)	(x) << 5
60*4882a593Smuzhiyun 
61*4882a593Smuzhiyun #define SI1133_ADCSENS_SCALE_MASK 0x70
62*4882a593Smuzhiyun #define SI1133_ADCSENS_SCALE_SHIFT 4
63*4882a593Smuzhiyun #define SI1133_ADCSENS_HSIG_MASK BIT(7)
64*4882a593Smuzhiyun #define SI1133_ADCSENS_HSIG_SHIFT 7
65*4882a593Smuzhiyun #define SI1133_ADCSENS_HW_GAIN_MASK 0xF
66*4882a593Smuzhiyun #define SI1133_ADCSENS_NB_MEAS(x)	fls(x) << SI1133_ADCSENS_SCALE_SHIFT
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define SI1133_ADCPOST_24BIT_EN BIT(6)
69*4882a593Smuzhiyun #define SI1133_ADCPOST_POSTSHIFT_BITQTY(x) (x & GENMASK(2, 0)) << 3
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_SMALL_IR	0x0
72*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_MED_IR	0x1
73*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_LARGE_IR	0x2
74*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_WHITE	0xB
75*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_LARGE_WHITE	0xD
76*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_UV		0x18
77*4882a593Smuzhiyun #define SI1133_PARAM_ADCMUX_UV_DEEP	0x19
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun #define SI1133_ERR_INVALID_CMD		0x0
80*4882a593Smuzhiyun #define SI1133_ERR_INVALID_LOCATION_CMD 0x1
81*4882a593Smuzhiyun #define SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION 0x2
82*4882a593Smuzhiyun #define SI1133_ERR_OUTPUT_BUFFER_OVERFLOW 0x3
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun #define SI1133_COMPLETION_TIMEOUT_MS	500
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun #define SI1133_CMD_MINSLEEP_US_LOW	5000
87*4882a593Smuzhiyun #define SI1133_CMD_MINSLEEP_US_HIGH	7500
88*4882a593Smuzhiyun #define SI1133_CMD_TIMEOUT_MS		25
89*4882a593Smuzhiyun #define SI1133_CMD_LUX_TIMEOUT_MS	5000
90*4882a593Smuzhiyun #define SI1133_CMD_TIMEOUT_US		SI1133_CMD_TIMEOUT_MS * 1000
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun #define SI1133_REG_HOSTOUT(x)		(x) + 0x13
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun #define SI1133_MEASUREMENT_FREQUENCY 1250
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun #define SI1133_X_ORDER_MASK            0x0070
97*4882a593Smuzhiyun #define SI1133_Y_ORDER_MASK            0x0007
98*4882a593Smuzhiyun #define si1133_get_x_order(m)          ((m) & SI1133_X_ORDER_MASK) >> 4
99*4882a593Smuzhiyun #define si1133_get_y_order(m)          ((m) & SI1133_Y_ORDER_MASK)
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #define SI1133_LUX_ADC_MASK		0xE
102*4882a593Smuzhiyun #define SI1133_ADC_THRESHOLD		16000
103*4882a593Smuzhiyun #define SI1133_INPUT_FRACTION_HIGH	7
104*4882a593Smuzhiyun #define SI1133_INPUT_FRACTION_LOW	15
105*4882a593Smuzhiyun #define SI1133_LUX_OUTPUT_FRACTION	12
106*4882a593Smuzhiyun #define SI1133_LUX_BUFFER_SIZE		9
107*4882a593Smuzhiyun #define SI1133_MEASURE_BUFFER_SIZE	3
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun static const int si1133_scale_available[] = {
110*4882a593Smuzhiyun 	1, 2, 4, 8, 16, 32, 64, 128};
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun static IIO_CONST_ATTR(scale_available, "1 2 4 8 16 32 64 128");
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun static IIO_CONST_ATTR_INT_TIME_AVAIL("0.0244 0.0488 0.0975 0.195 0.390 0.780 "
115*4882a593Smuzhiyun 				     "1.560 3.120 6.24 12.48 25.0 50.0");
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun /* A.K.A. HW_GAIN in datasheet */
118*4882a593Smuzhiyun enum si1133_int_time {
119*4882a593Smuzhiyun 	    _24_4_us = 0,
120*4882a593Smuzhiyun 	    _48_8_us = 1,
121*4882a593Smuzhiyun 	    _97_5_us = 2,
122*4882a593Smuzhiyun 	   _195_0_us = 3,
123*4882a593Smuzhiyun 	   _390_0_us = 4,
124*4882a593Smuzhiyun 	   _780_0_us = 5,
125*4882a593Smuzhiyun 	 _1_560_0_us = 6,
126*4882a593Smuzhiyun 	 _3_120_0_us = 7,
127*4882a593Smuzhiyun 	 _6_240_0_us = 8,
128*4882a593Smuzhiyun 	_12_480_0_us = 9,
129*4882a593Smuzhiyun 	_25_ms = 10,
130*4882a593Smuzhiyun 	_50_ms = 11,
131*4882a593Smuzhiyun };
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun /* Integration time in milliseconds, nanoseconds */
134*4882a593Smuzhiyun static const int si1133_int_time_table[][2] = {
135*4882a593Smuzhiyun 	[_24_4_us] = {0, 24400},
136*4882a593Smuzhiyun 	[_48_8_us] = {0, 48800},
137*4882a593Smuzhiyun 	[_97_5_us] = {0, 97500},
138*4882a593Smuzhiyun 	[_195_0_us] = {0, 195000},
139*4882a593Smuzhiyun 	[_390_0_us] = {0, 390000},
140*4882a593Smuzhiyun 	[_780_0_us] = {0, 780000},
141*4882a593Smuzhiyun 	[_1_560_0_us] = {1, 560000},
142*4882a593Smuzhiyun 	[_3_120_0_us] = {3, 120000},
143*4882a593Smuzhiyun 	[_6_240_0_us] = {6, 240000},
144*4882a593Smuzhiyun 	[_12_480_0_us] = {12, 480000},
145*4882a593Smuzhiyun 	[_25_ms] = {25, 000000},
146*4882a593Smuzhiyun 	[_50_ms] = {50, 000000},
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun static const struct regmap_range si1133_reg_ranges[] = {
150*4882a593Smuzhiyun 	regmap_reg_range(0x00, 0x02),
151*4882a593Smuzhiyun 	regmap_reg_range(0x0A, 0x0B),
152*4882a593Smuzhiyun 	regmap_reg_range(0x0F, 0x0F),
153*4882a593Smuzhiyun 	regmap_reg_range(0x10, 0x12),
154*4882a593Smuzhiyun 	regmap_reg_range(0x13, 0x2C),
155*4882a593Smuzhiyun };
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun static const struct regmap_range si1133_reg_ro_ranges[] = {
158*4882a593Smuzhiyun 	regmap_reg_range(0x00, 0x02),
159*4882a593Smuzhiyun 	regmap_reg_range(0x10, 0x2C),
160*4882a593Smuzhiyun };
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun static const struct regmap_range si1133_precious_ranges[] = {
163*4882a593Smuzhiyun 	regmap_reg_range(0x12, 0x12),
164*4882a593Smuzhiyun };
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun static const struct regmap_access_table si1133_write_ranges_table = {
167*4882a593Smuzhiyun 	.yes_ranges	= si1133_reg_ranges,
168*4882a593Smuzhiyun 	.n_yes_ranges	= ARRAY_SIZE(si1133_reg_ranges),
169*4882a593Smuzhiyun 	.no_ranges	= si1133_reg_ro_ranges,
170*4882a593Smuzhiyun 	.n_no_ranges	= ARRAY_SIZE(si1133_reg_ro_ranges),
171*4882a593Smuzhiyun };
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun static const struct regmap_access_table si1133_read_ranges_table = {
174*4882a593Smuzhiyun 	.yes_ranges	= si1133_reg_ranges,
175*4882a593Smuzhiyun 	.n_yes_ranges	= ARRAY_SIZE(si1133_reg_ranges),
176*4882a593Smuzhiyun };
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun static const struct regmap_access_table si1133_precious_table = {
179*4882a593Smuzhiyun 	.yes_ranges	= si1133_precious_ranges,
180*4882a593Smuzhiyun 	.n_yes_ranges	= ARRAY_SIZE(si1133_precious_ranges),
181*4882a593Smuzhiyun };
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun static const struct regmap_config si1133_regmap_config = {
184*4882a593Smuzhiyun 	.reg_bits = 8,
185*4882a593Smuzhiyun 	.val_bits = 8,
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	.max_register = 0x2C,
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	.wr_table = &si1133_write_ranges_table,
190*4882a593Smuzhiyun 	.rd_table = &si1133_read_ranges_table,
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	.precious_table = &si1133_precious_table,
193*4882a593Smuzhiyun };
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun struct si1133_data {
196*4882a593Smuzhiyun 	struct regmap *regmap;
197*4882a593Smuzhiyun 	struct i2c_client *client;
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* Lock protecting one command at a time can be processed */
200*4882a593Smuzhiyun 	struct mutex mutex;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	int rsp_seq;
203*4882a593Smuzhiyun 	u8 scan_mask;
204*4882a593Smuzhiyun 	u8 adc_sens[6];
205*4882a593Smuzhiyun 	u8 adc_config[6];
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	struct completion completion;
208*4882a593Smuzhiyun };
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun struct si1133_coeff {
211*4882a593Smuzhiyun 	s16 info;
212*4882a593Smuzhiyun 	u16 mag;
213*4882a593Smuzhiyun };
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun struct si1133_lux_coeff {
216*4882a593Smuzhiyun 	struct si1133_coeff coeff_high[4];
217*4882a593Smuzhiyun 	struct si1133_coeff coeff_low[9];
218*4882a593Smuzhiyun };
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun static const struct si1133_lux_coeff lux_coeff = {
221*4882a593Smuzhiyun 	{
222*4882a593Smuzhiyun 		{  0,   209},
223*4882a593Smuzhiyun 		{ 1665,  93},
224*4882a593Smuzhiyun 		{ 2064,  65},
225*4882a593Smuzhiyun 		{-2671, 234}
226*4882a593Smuzhiyun 	},
227*4882a593Smuzhiyun 	{
228*4882a593Smuzhiyun 		{    0,     0},
229*4882a593Smuzhiyun 		{ 1921, 29053},
230*4882a593Smuzhiyun 		{-1022, 36363},
231*4882a593Smuzhiyun 		{ 2320, 20789},
232*4882a593Smuzhiyun 		{ -367, 57909},
233*4882a593Smuzhiyun 		{-1774, 38240},
234*4882a593Smuzhiyun 		{ -608, 46775},
235*4882a593Smuzhiyun 		{-1503, 51831},
236*4882a593Smuzhiyun 		{-1886, 58928}
237*4882a593Smuzhiyun 	}
238*4882a593Smuzhiyun };
239*4882a593Smuzhiyun 
si1133_calculate_polynomial_inner(s32 input,u8 fraction,u16 mag,s8 shift)240*4882a593Smuzhiyun static int si1133_calculate_polynomial_inner(s32 input, u8 fraction, u16 mag,
241*4882a593Smuzhiyun 					     s8 shift)
242*4882a593Smuzhiyun {
243*4882a593Smuzhiyun 	return ((input << fraction) / mag) << shift;
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
si1133_calculate_output(s32 x,s32 y,u8 x_order,u8 y_order,u8 input_fraction,s8 sign,const struct si1133_coeff * coeffs)246*4882a593Smuzhiyun static int si1133_calculate_output(s32 x, s32 y, u8 x_order, u8 y_order,
247*4882a593Smuzhiyun 				   u8 input_fraction, s8 sign,
248*4882a593Smuzhiyun 				   const struct si1133_coeff *coeffs)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun 	s8 shift;
251*4882a593Smuzhiyun 	int x1 = 1;
252*4882a593Smuzhiyun 	int x2 = 1;
253*4882a593Smuzhiyun 	int y1 = 1;
254*4882a593Smuzhiyun 	int y2 = 1;
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	shift = ((u16)coeffs->info & 0xFF00) >> 8;
257*4882a593Smuzhiyun 	shift ^= 0xFF;
258*4882a593Smuzhiyun 	shift += 1;
259*4882a593Smuzhiyun 	shift = -shift;
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (x_order > 0) {
262*4882a593Smuzhiyun 		x1 = si1133_calculate_polynomial_inner(x, input_fraction,
263*4882a593Smuzhiyun 						       coeffs->mag, shift);
264*4882a593Smuzhiyun 		if (x_order > 1)
265*4882a593Smuzhiyun 			x2 = x1;
266*4882a593Smuzhiyun 	}
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	if (y_order > 0) {
269*4882a593Smuzhiyun 		y1 = si1133_calculate_polynomial_inner(y, input_fraction,
270*4882a593Smuzhiyun 						       coeffs->mag, shift);
271*4882a593Smuzhiyun 		if (y_order > 1)
272*4882a593Smuzhiyun 			y2 = y1;
273*4882a593Smuzhiyun 	}
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return sign * x1 * x2 * y1 * y2;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun /*
279*4882a593Smuzhiyun  * The algorithm is from:
280*4882a593Smuzhiyun  * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00716
281*4882a593Smuzhiyun  */
si1133_calc_polynomial(s32 x,s32 y,u8 input_fraction,u8 num_coeff,const struct si1133_coeff * coeffs)282*4882a593Smuzhiyun static int si1133_calc_polynomial(s32 x, s32 y, u8 input_fraction, u8 num_coeff,
283*4882a593Smuzhiyun 				  const struct si1133_coeff *coeffs)
284*4882a593Smuzhiyun {
285*4882a593Smuzhiyun 	u8 x_order, y_order;
286*4882a593Smuzhiyun 	u8 counter;
287*4882a593Smuzhiyun 	s8 sign;
288*4882a593Smuzhiyun 	int output = 0;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	for (counter = 0; counter < num_coeff; counter++) {
291*4882a593Smuzhiyun 		if (coeffs->info < 0)
292*4882a593Smuzhiyun 			sign = -1;
293*4882a593Smuzhiyun 		else
294*4882a593Smuzhiyun 			sign = 1;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 		x_order = si1133_get_x_order(coeffs->info);
297*4882a593Smuzhiyun 		y_order = si1133_get_y_order(coeffs->info);
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 		if ((x_order == 0) && (y_order == 0))
300*4882a593Smuzhiyun 			output +=
301*4882a593Smuzhiyun 			       sign * coeffs->mag << SI1133_LUX_OUTPUT_FRACTION;
302*4882a593Smuzhiyun 		else
303*4882a593Smuzhiyun 			output += si1133_calculate_output(x, y, x_order,
304*4882a593Smuzhiyun 							  y_order,
305*4882a593Smuzhiyun 							  input_fraction, sign,
306*4882a593Smuzhiyun 							  coeffs);
307*4882a593Smuzhiyun 		coeffs++;
308*4882a593Smuzhiyun 	}
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun 	return abs(output);
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun 
si1133_cmd_reset_sw(struct si1133_data * data)313*4882a593Smuzhiyun static int si1133_cmd_reset_sw(struct si1133_data *data)
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	struct device *dev = &data->client->dev;
316*4882a593Smuzhiyun 	unsigned int resp;
317*4882a593Smuzhiyun 	unsigned long timeout;
318*4882a593Smuzhiyun 	int err;
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	err = regmap_write(data->regmap, SI1133_REG_COMMAND,
321*4882a593Smuzhiyun 			   SI1133_CMD_RESET_SW);
322*4882a593Smuzhiyun 	if (err)
323*4882a593Smuzhiyun 		return err;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	timeout = jiffies + msecs_to_jiffies(SI1133_CMD_TIMEOUT_MS);
326*4882a593Smuzhiyun 	while (true) {
327*4882a593Smuzhiyun 		err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);
328*4882a593Smuzhiyun 		if (err == -ENXIO) {
329*4882a593Smuzhiyun 			usleep_range(SI1133_CMD_MINSLEEP_US_LOW,
330*4882a593Smuzhiyun 				     SI1133_CMD_MINSLEEP_US_HIGH);
331*4882a593Smuzhiyun 			continue;
332*4882a593Smuzhiyun 		}
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun 		if ((resp & SI1133_MAX_CMD_CTR) == SI1133_MAX_CMD_CTR)
335*4882a593Smuzhiyun 			break;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 		if (time_after(jiffies, timeout)) {
338*4882a593Smuzhiyun 			dev_warn(dev, "Timeout on reset ctr resp: %d\n", resp);
339*4882a593Smuzhiyun 			return -ETIMEDOUT;
340*4882a593Smuzhiyun 		}
341*4882a593Smuzhiyun 	}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (!err)
344*4882a593Smuzhiyun 		data->rsp_seq = SI1133_MAX_CMD_CTR;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	return err;
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun 
si1133_parse_response_err(struct device * dev,u32 resp,u8 cmd)349*4882a593Smuzhiyun static int si1133_parse_response_err(struct device *dev, u32 resp, u8 cmd)
350*4882a593Smuzhiyun {
351*4882a593Smuzhiyun 	resp &= 0xF;
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	switch (resp) {
354*4882a593Smuzhiyun 	case SI1133_ERR_OUTPUT_BUFFER_OVERFLOW:
355*4882a593Smuzhiyun 		dev_warn(dev, "Output buffer overflow: %#02hhx\n", cmd);
356*4882a593Smuzhiyun 		return -EOVERFLOW;
357*4882a593Smuzhiyun 	case SI1133_ERR_SATURATION_ADC_OR_OVERFLOW_ACCUMULATION:
358*4882a593Smuzhiyun 		dev_warn(dev, "Saturation of the ADC or overflow of accumulation: %#02hhx\n",
359*4882a593Smuzhiyun 			 cmd);
360*4882a593Smuzhiyun 		return -EOVERFLOW;
361*4882a593Smuzhiyun 	case SI1133_ERR_INVALID_LOCATION_CMD:
362*4882a593Smuzhiyun 		dev_warn(dev,
363*4882a593Smuzhiyun 			 "Parameter access to an invalid location: %#02hhx\n",
364*4882a593Smuzhiyun 			 cmd);
365*4882a593Smuzhiyun 		return -EINVAL;
366*4882a593Smuzhiyun 	case SI1133_ERR_INVALID_CMD:
367*4882a593Smuzhiyun 		dev_warn(dev, "Invalid command %#02hhx\n", cmd);
368*4882a593Smuzhiyun 		return -EINVAL;
369*4882a593Smuzhiyun 	default:
370*4882a593Smuzhiyun 		dev_warn(dev, "Unknown error %#02hhx\n", cmd);
371*4882a593Smuzhiyun 		return -EINVAL;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
si1133_cmd_reset_counter(struct si1133_data * data)375*4882a593Smuzhiyun static int si1133_cmd_reset_counter(struct si1133_data *data)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	int err = regmap_write(data->regmap, SI1133_REG_COMMAND,
378*4882a593Smuzhiyun 			       SI1133_CMD_RESET_CTR);
379*4882a593Smuzhiyun 	if (err)
380*4882a593Smuzhiyun 		return err;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 	data->rsp_seq = 0;
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	return 0;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun 
si1133_command(struct si1133_data * data,u8 cmd)387*4882a593Smuzhiyun static int si1133_command(struct si1133_data *data, u8 cmd)
388*4882a593Smuzhiyun {
389*4882a593Smuzhiyun 	struct device *dev = &data->client->dev;
390*4882a593Smuzhiyun 	u32 resp;
391*4882a593Smuzhiyun 	int err;
392*4882a593Smuzhiyun 	int expected_seq;
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	mutex_lock(&data->mutex);
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	expected_seq = (data->rsp_seq + 1) & SI1133_MAX_CMD_CTR;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	if (cmd == SI1133_CMD_FORCE)
399*4882a593Smuzhiyun 		reinit_completion(&data->completion);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun 	err = regmap_write(data->regmap, SI1133_REG_COMMAND, cmd);
402*4882a593Smuzhiyun 	if (err) {
403*4882a593Smuzhiyun 		dev_warn(dev, "Failed to write command %#02hhx, ret=%d\n", cmd,
404*4882a593Smuzhiyun 			 err);
405*4882a593Smuzhiyun 		goto out;
406*4882a593Smuzhiyun 	}
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun 	if (cmd == SI1133_CMD_FORCE) {
409*4882a593Smuzhiyun 		/* wait for irq */
410*4882a593Smuzhiyun 		if (!wait_for_completion_timeout(&data->completion,
411*4882a593Smuzhiyun 			msecs_to_jiffies(SI1133_COMPLETION_TIMEOUT_MS))) {
412*4882a593Smuzhiyun 			err = -ETIMEDOUT;
413*4882a593Smuzhiyun 			goto out;
414*4882a593Smuzhiyun 		}
415*4882a593Smuzhiyun 		err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);
416*4882a593Smuzhiyun 		if (err)
417*4882a593Smuzhiyun 			goto out;
418*4882a593Smuzhiyun 	} else {
419*4882a593Smuzhiyun 		err = regmap_read_poll_timeout(data->regmap,
420*4882a593Smuzhiyun 					       SI1133_REG_RESPONSE0, resp,
421*4882a593Smuzhiyun 					       (resp & SI1133_CMD_SEQ_MASK) ==
422*4882a593Smuzhiyun 					       expected_seq ||
423*4882a593Smuzhiyun 					       (resp & SI1133_CMD_ERR_MASK),
424*4882a593Smuzhiyun 					       SI1133_CMD_MINSLEEP_US_LOW,
425*4882a593Smuzhiyun 					       SI1133_CMD_TIMEOUT_MS * 1000);
426*4882a593Smuzhiyun 		if (err) {
427*4882a593Smuzhiyun 			dev_warn(dev,
428*4882a593Smuzhiyun 				 "Failed to read command %#02hhx, ret=%d\n",
429*4882a593Smuzhiyun 				 cmd, err);
430*4882a593Smuzhiyun 			goto out;
431*4882a593Smuzhiyun 		}
432*4882a593Smuzhiyun 	}
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 	if (resp & SI1133_CMD_ERR_MASK) {
435*4882a593Smuzhiyun 		err = si1133_parse_response_err(dev, resp, cmd);
436*4882a593Smuzhiyun 		si1133_cmd_reset_counter(data);
437*4882a593Smuzhiyun 	} else {
438*4882a593Smuzhiyun 		data->rsp_seq = expected_seq;
439*4882a593Smuzhiyun 	}
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun out:
442*4882a593Smuzhiyun 	mutex_unlock(&data->mutex);
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	return err;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun 
si1133_param_set(struct si1133_data * data,u8 param,u32 value)447*4882a593Smuzhiyun static int si1133_param_set(struct si1133_data *data, u8 param, u32 value)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun 	int err = regmap_write(data->regmap, SI1133_REG_HOSTIN0, value);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	if (err)
452*4882a593Smuzhiyun 		return err;
453*4882a593Smuzhiyun 
454*4882a593Smuzhiyun 	return si1133_command(data, SI1133_CMD_PARAM_SET |
455*4882a593Smuzhiyun 			      (param & SI1133_CMD_PARAM_MASK));
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun 
si1133_param_query(struct si1133_data * data,u8 param,u32 * result)458*4882a593Smuzhiyun static int si1133_param_query(struct si1133_data *data, u8 param, u32 *result)
459*4882a593Smuzhiyun {
460*4882a593Smuzhiyun 	int err = si1133_command(data, SI1133_CMD_PARAM_QUERY |
461*4882a593Smuzhiyun 				 (param & SI1133_CMD_PARAM_MASK));
462*4882a593Smuzhiyun 	if (err)
463*4882a593Smuzhiyun 		return err;
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	return regmap_read(data->regmap, SI1133_REG_RESPONSE1, result);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun #define SI1133_CHANNEL(_ch, _type) \
469*4882a593Smuzhiyun 	.type = _type, \
470*4882a593Smuzhiyun 	.channel = _ch, \
471*4882a593Smuzhiyun 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
472*4882a593Smuzhiyun 	.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME) | \
473*4882a593Smuzhiyun 		BIT(IIO_CHAN_INFO_SCALE) | \
474*4882a593Smuzhiyun 		BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun static const struct iio_chan_spec si1133_channels[] = {
477*4882a593Smuzhiyun 	{
478*4882a593Smuzhiyun 		.type = IIO_LIGHT,
479*4882a593Smuzhiyun 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
480*4882a593Smuzhiyun 		.channel = 0,
481*4882a593Smuzhiyun 	},
482*4882a593Smuzhiyun 	{
483*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_WHITE, IIO_INTENSITY)
484*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_BOTH,
485*4882a593Smuzhiyun 	},
486*4882a593Smuzhiyun 	{
487*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_WHITE, IIO_INTENSITY)
488*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_BOTH,
489*4882a593Smuzhiyun 		.extend_name = "large",
490*4882a593Smuzhiyun 	},
491*4882a593Smuzhiyun 	{
492*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_SMALL_IR, IIO_INTENSITY)
493*4882a593Smuzhiyun 		.extend_name = "small",
494*4882a593Smuzhiyun 		.modified = 1,
495*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_IR,
496*4882a593Smuzhiyun 	},
497*4882a593Smuzhiyun 	{
498*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_MED_IR, IIO_INTENSITY)
499*4882a593Smuzhiyun 		.modified = 1,
500*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_IR,
501*4882a593Smuzhiyun 	},
502*4882a593Smuzhiyun 	{
503*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_LARGE_IR, IIO_INTENSITY)
504*4882a593Smuzhiyun 		.extend_name = "large",
505*4882a593Smuzhiyun 		.modified = 1,
506*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_IR,
507*4882a593Smuzhiyun 	},
508*4882a593Smuzhiyun 	{
509*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV, IIO_UVINDEX)
510*4882a593Smuzhiyun 	},
511*4882a593Smuzhiyun 	{
512*4882a593Smuzhiyun 		SI1133_CHANNEL(SI1133_PARAM_ADCMUX_UV_DEEP, IIO_UVINDEX)
513*4882a593Smuzhiyun 		.modified = 1,
514*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_DUV,
515*4882a593Smuzhiyun 	}
516*4882a593Smuzhiyun };
517*4882a593Smuzhiyun 
si1133_get_int_time_index(int milliseconds,int nanoseconds)518*4882a593Smuzhiyun static int si1133_get_int_time_index(int milliseconds, int nanoseconds)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun 	int i;
521*4882a593Smuzhiyun 
522*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(si1133_int_time_table); i++) {
523*4882a593Smuzhiyun 		if (milliseconds == si1133_int_time_table[i][0] &&
524*4882a593Smuzhiyun 		    nanoseconds == si1133_int_time_table[i][1])
525*4882a593Smuzhiyun 			return i;
526*4882a593Smuzhiyun 	}
527*4882a593Smuzhiyun 	return -EINVAL;
528*4882a593Smuzhiyun }
529*4882a593Smuzhiyun 
si1133_set_integration_time(struct si1133_data * data,u8 adc,int milliseconds,int nanoseconds)530*4882a593Smuzhiyun static int si1133_set_integration_time(struct si1133_data *data, u8 adc,
531*4882a593Smuzhiyun 				       int milliseconds, int nanoseconds)
532*4882a593Smuzhiyun {
533*4882a593Smuzhiyun 	int index;
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun 	index = si1133_get_int_time_index(milliseconds, nanoseconds);
536*4882a593Smuzhiyun 	if (index < 0)
537*4882a593Smuzhiyun 		return index;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	data->adc_sens[adc] &= 0xF0;
540*4882a593Smuzhiyun 	data->adc_sens[adc] |= index;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	return si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(0),
543*4882a593Smuzhiyun 				data->adc_sens[adc]);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
si1133_set_chlist(struct si1133_data * data,u8 scan_mask)546*4882a593Smuzhiyun static int si1133_set_chlist(struct si1133_data *data, u8 scan_mask)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	/* channel list already set, no need to reprogram */
549*4882a593Smuzhiyun 	if (data->scan_mask == scan_mask)
550*4882a593Smuzhiyun 		return 0;
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	data->scan_mask = scan_mask;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	return si1133_param_set(data, SI1133_PARAM_REG_CHAN_LIST, scan_mask);
555*4882a593Smuzhiyun }
556*4882a593Smuzhiyun 
si1133_chan_set_adcconfig(struct si1133_data * data,u8 adc,u8 adc_config)557*4882a593Smuzhiyun static int si1133_chan_set_adcconfig(struct si1133_data *data, u8 adc,
558*4882a593Smuzhiyun 				     u8 adc_config)
559*4882a593Smuzhiyun {
560*4882a593Smuzhiyun 	int err;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	err = si1133_param_set(data, SI1133_PARAM_REG_ADCCONFIG(adc),
563*4882a593Smuzhiyun 			       adc_config);
564*4882a593Smuzhiyun 	if (err)
565*4882a593Smuzhiyun 		return err;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	data->adc_config[adc] = adc_config;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	return 0;
570*4882a593Smuzhiyun }
571*4882a593Smuzhiyun 
si1133_update_adcconfig(struct si1133_data * data,uint8_t adc,u8 mask,u8 shift,u8 value)572*4882a593Smuzhiyun static int si1133_update_adcconfig(struct si1133_data *data, uint8_t adc,
573*4882a593Smuzhiyun 				   u8 mask, u8 shift, u8 value)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	u32 adc_config;
576*4882a593Smuzhiyun 	int err;
577*4882a593Smuzhiyun 
578*4882a593Smuzhiyun 	err = si1133_param_query(data, SI1133_PARAM_REG_ADCCONFIG(adc),
579*4882a593Smuzhiyun 				 &adc_config);
580*4882a593Smuzhiyun 	if (err)
581*4882a593Smuzhiyun 		return err;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	adc_config &= ~mask;
584*4882a593Smuzhiyun 	adc_config |= (value << shift);
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	return si1133_chan_set_adcconfig(data, adc, adc_config);
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun 
si1133_set_adcmux(struct si1133_data * data,u8 adc,u8 mux)589*4882a593Smuzhiyun static int si1133_set_adcmux(struct si1133_data *data, u8 adc, u8 mux)
590*4882a593Smuzhiyun {
591*4882a593Smuzhiyun 	if ((mux & data->adc_config[adc]) == mux)
592*4882a593Smuzhiyun 		return 0; /* mux already set to correct value */
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	return si1133_update_adcconfig(data, adc, SI1133_ADCMUX_MASK, 0, mux);
595*4882a593Smuzhiyun }
596*4882a593Smuzhiyun 
si1133_force_measurement(struct si1133_data * data)597*4882a593Smuzhiyun static int si1133_force_measurement(struct si1133_data *data)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun 	return si1133_command(data, SI1133_CMD_FORCE);
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun 
si1133_bulk_read(struct si1133_data * data,u8 start_reg,u8 length,u8 * buffer)602*4882a593Smuzhiyun static int si1133_bulk_read(struct si1133_data *data, u8 start_reg, u8 length,
603*4882a593Smuzhiyun 			    u8 *buffer)
604*4882a593Smuzhiyun {
605*4882a593Smuzhiyun 	int err;
606*4882a593Smuzhiyun 
607*4882a593Smuzhiyun 	err = si1133_force_measurement(data);
608*4882a593Smuzhiyun 	if (err)
609*4882a593Smuzhiyun 		return err;
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	return regmap_bulk_read(data->regmap, start_reg, buffer, length);
612*4882a593Smuzhiyun }
613*4882a593Smuzhiyun 
si1133_measure(struct si1133_data * data,struct iio_chan_spec const * chan,int * val)614*4882a593Smuzhiyun static int si1133_measure(struct si1133_data *data,
615*4882a593Smuzhiyun 			  struct iio_chan_spec const *chan,
616*4882a593Smuzhiyun 			  int *val)
617*4882a593Smuzhiyun {
618*4882a593Smuzhiyun 	int err;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	u8 buffer[SI1133_MEASURE_BUFFER_SIZE];
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	err = si1133_set_adcmux(data, 0, chan->channel);
623*4882a593Smuzhiyun 	if (err)
624*4882a593Smuzhiyun 		return err;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	/* Deactivate lux measurements if they were active */
627*4882a593Smuzhiyun 	err = si1133_set_chlist(data, BIT(0));
628*4882a593Smuzhiyun 	if (err)
629*4882a593Smuzhiyun 		return err;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0), sizeof(buffer),
632*4882a593Smuzhiyun 			       buffer);
633*4882a593Smuzhiyun 	if (err)
634*4882a593Smuzhiyun 		return err;
635*4882a593Smuzhiyun 
636*4882a593Smuzhiyun 	*val = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	return err;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun 
si1133_threaded_irq_handler(int irq,void * private)641*4882a593Smuzhiyun static irqreturn_t si1133_threaded_irq_handler(int irq, void *private)
642*4882a593Smuzhiyun {
643*4882a593Smuzhiyun 	struct iio_dev *iio_dev = private;
644*4882a593Smuzhiyun 	struct si1133_data *data = iio_priv(iio_dev);
645*4882a593Smuzhiyun 	u32 irq_status;
646*4882a593Smuzhiyun 	int err;
647*4882a593Smuzhiyun 
648*4882a593Smuzhiyun 	err = regmap_read(data->regmap, SI1133_REG_IRQ_STATUS, &irq_status);
649*4882a593Smuzhiyun 	if (err) {
650*4882a593Smuzhiyun 		dev_err_ratelimited(&iio_dev->dev, "Error reading IRQ\n");
651*4882a593Smuzhiyun 		goto out;
652*4882a593Smuzhiyun 	}
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	if (irq_status != data->scan_mask)
655*4882a593Smuzhiyun 		return IRQ_NONE;
656*4882a593Smuzhiyun 
657*4882a593Smuzhiyun out:
658*4882a593Smuzhiyun 	complete(&data->completion);
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	return IRQ_HANDLED;
661*4882a593Smuzhiyun }
662*4882a593Smuzhiyun 
si1133_scale_to_swgain(int scale_integer,int scale_fractional)663*4882a593Smuzhiyun static int si1133_scale_to_swgain(int scale_integer, int scale_fractional)
664*4882a593Smuzhiyun {
665*4882a593Smuzhiyun 	scale_integer = find_closest(scale_integer, si1133_scale_available,
666*4882a593Smuzhiyun 				     ARRAY_SIZE(si1133_scale_available));
667*4882a593Smuzhiyun 	if (scale_integer < 0 ||
668*4882a593Smuzhiyun 	    scale_integer > ARRAY_SIZE(si1133_scale_available) ||
669*4882a593Smuzhiyun 	    scale_fractional != 0)
670*4882a593Smuzhiyun 		return -EINVAL;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	return scale_integer;
673*4882a593Smuzhiyun }
674*4882a593Smuzhiyun 
si1133_chan_set_adcsens(struct si1133_data * data,u8 adc,u8 adc_sens)675*4882a593Smuzhiyun static int si1133_chan_set_adcsens(struct si1133_data *data, u8 adc,
676*4882a593Smuzhiyun 				   u8 adc_sens)
677*4882a593Smuzhiyun {
678*4882a593Smuzhiyun 	int err;
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	err = si1133_param_set(data, SI1133_PARAM_REG_ADCSENS(adc), adc_sens);
681*4882a593Smuzhiyun 	if (err)
682*4882a593Smuzhiyun 		return err;
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	data->adc_sens[adc] = adc_sens;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	return 0;
687*4882a593Smuzhiyun }
688*4882a593Smuzhiyun 
si1133_update_adcsens(struct si1133_data * data,u8 mask,u8 shift,u8 value)689*4882a593Smuzhiyun static int si1133_update_adcsens(struct si1133_data *data, u8 mask,
690*4882a593Smuzhiyun 				 u8 shift, u8 value)
691*4882a593Smuzhiyun {
692*4882a593Smuzhiyun 	int err;
693*4882a593Smuzhiyun 	u32 adc_sens;
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	err = si1133_param_query(data, SI1133_PARAM_REG_ADCSENS(0),
696*4882a593Smuzhiyun 				 &adc_sens);
697*4882a593Smuzhiyun 	if (err)
698*4882a593Smuzhiyun 		return err;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	adc_sens &= ~mask;
701*4882a593Smuzhiyun 	adc_sens |= (value << shift);
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	return si1133_chan_set_adcsens(data, 0, adc_sens);
704*4882a593Smuzhiyun }
705*4882a593Smuzhiyun 
si1133_get_lux(struct si1133_data * data,int * val)706*4882a593Smuzhiyun static int si1133_get_lux(struct si1133_data *data, int *val)
707*4882a593Smuzhiyun {
708*4882a593Smuzhiyun 	int err;
709*4882a593Smuzhiyun 	int lux;
710*4882a593Smuzhiyun 	s32 high_vis;
711*4882a593Smuzhiyun 	s32 low_vis;
712*4882a593Smuzhiyun 	s32 ir;
713*4882a593Smuzhiyun 	u8 buffer[SI1133_LUX_BUFFER_SIZE];
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	/* Activate lux channels */
716*4882a593Smuzhiyun 	err = si1133_set_chlist(data, SI1133_LUX_ADC_MASK);
717*4882a593Smuzhiyun 	if (err)
718*4882a593Smuzhiyun 		return err;
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun 	err = si1133_bulk_read(data, SI1133_REG_HOSTOUT(0),
721*4882a593Smuzhiyun 			       SI1133_LUX_BUFFER_SIZE, buffer);
722*4882a593Smuzhiyun 	if (err)
723*4882a593Smuzhiyun 		return err;
724*4882a593Smuzhiyun 
725*4882a593Smuzhiyun 	high_vis = sign_extend32(get_unaligned_be24(&buffer[0]), 23);
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	low_vis = sign_extend32(get_unaligned_be24(&buffer[3]), 23);
728*4882a593Smuzhiyun 
729*4882a593Smuzhiyun 	ir = sign_extend32(get_unaligned_be24(&buffer[6]), 23);
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	if (high_vis > SI1133_ADC_THRESHOLD || ir > SI1133_ADC_THRESHOLD)
732*4882a593Smuzhiyun 		lux = si1133_calc_polynomial(high_vis, ir,
733*4882a593Smuzhiyun 					     SI1133_INPUT_FRACTION_HIGH,
734*4882a593Smuzhiyun 					     ARRAY_SIZE(lux_coeff.coeff_high),
735*4882a593Smuzhiyun 					     &lux_coeff.coeff_high[0]);
736*4882a593Smuzhiyun 	else
737*4882a593Smuzhiyun 		lux = si1133_calc_polynomial(low_vis, ir,
738*4882a593Smuzhiyun 					     SI1133_INPUT_FRACTION_LOW,
739*4882a593Smuzhiyun 					     ARRAY_SIZE(lux_coeff.coeff_low),
740*4882a593Smuzhiyun 					     &lux_coeff.coeff_low[0]);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun 	*val = lux >> SI1133_LUX_OUTPUT_FRACTION;
743*4882a593Smuzhiyun 
744*4882a593Smuzhiyun 	return err;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun 
si1133_read_raw(struct iio_dev * iio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)747*4882a593Smuzhiyun static int si1133_read_raw(struct iio_dev *iio_dev,
748*4882a593Smuzhiyun 			   struct iio_chan_spec const *chan,
749*4882a593Smuzhiyun 			   int *val, int *val2, long mask)
750*4882a593Smuzhiyun {
751*4882a593Smuzhiyun 	struct si1133_data *data = iio_priv(iio_dev);
752*4882a593Smuzhiyun 	u8 adc_sens = data->adc_sens[0];
753*4882a593Smuzhiyun 	int err;
754*4882a593Smuzhiyun 
755*4882a593Smuzhiyun 	switch (mask) {
756*4882a593Smuzhiyun 	case IIO_CHAN_INFO_PROCESSED:
757*4882a593Smuzhiyun 		switch (chan->type) {
758*4882a593Smuzhiyun 		case IIO_LIGHT:
759*4882a593Smuzhiyun 			err = si1133_get_lux(data, val);
760*4882a593Smuzhiyun 			if (err)
761*4882a593Smuzhiyun 				return err;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 			return IIO_VAL_INT;
764*4882a593Smuzhiyun 		default:
765*4882a593Smuzhiyun 			return -EINVAL;
766*4882a593Smuzhiyun 		}
767*4882a593Smuzhiyun 	case IIO_CHAN_INFO_RAW:
768*4882a593Smuzhiyun 		switch (chan->type) {
769*4882a593Smuzhiyun 		case IIO_INTENSITY:
770*4882a593Smuzhiyun 		case IIO_UVINDEX:
771*4882a593Smuzhiyun 			err = si1133_measure(data, chan, val);
772*4882a593Smuzhiyun 			if (err)
773*4882a593Smuzhiyun 				return err;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 			return IIO_VAL_INT;
776*4882a593Smuzhiyun 		default:
777*4882a593Smuzhiyun 			return -EINVAL;
778*4882a593Smuzhiyun 		}
779*4882a593Smuzhiyun 	case IIO_CHAN_INFO_INT_TIME:
780*4882a593Smuzhiyun 		switch (chan->type) {
781*4882a593Smuzhiyun 		case IIO_INTENSITY:
782*4882a593Smuzhiyun 		case IIO_UVINDEX:
783*4882a593Smuzhiyun 			adc_sens &= SI1133_ADCSENS_HW_GAIN_MASK;
784*4882a593Smuzhiyun 
785*4882a593Smuzhiyun 			*val = si1133_int_time_table[adc_sens][0];
786*4882a593Smuzhiyun 			*val2 = si1133_int_time_table[adc_sens][1];
787*4882a593Smuzhiyun 			return IIO_VAL_INT_PLUS_MICRO;
788*4882a593Smuzhiyun 		default:
789*4882a593Smuzhiyun 			return -EINVAL;
790*4882a593Smuzhiyun 		}
791*4882a593Smuzhiyun 	case IIO_CHAN_INFO_SCALE:
792*4882a593Smuzhiyun 		switch (chan->type) {
793*4882a593Smuzhiyun 		case IIO_INTENSITY:
794*4882a593Smuzhiyun 		case IIO_UVINDEX:
795*4882a593Smuzhiyun 			adc_sens &= SI1133_ADCSENS_SCALE_MASK;
796*4882a593Smuzhiyun 			adc_sens >>= SI1133_ADCSENS_SCALE_SHIFT;
797*4882a593Smuzhiyun 
798*4882a593Smuzhiyun 			*val = BIT(adc_sens);
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun 			return IIO_VAL_INT;
801*4882a593Smuzhiyun 		default:
802*4882a593Smuzhiyun 			return -EINVAL;
803*4882a593Smuzhiyun 		}
804*4882a593Smuzhiyun 	case IIO_CHAN_INFO_HARDWAREGAIN:
805*4882a593Smuzhiyun 		switch (chan->type) {
806*4882a593Smuzhiyun 		case IIO_INTENSITY:
807*4882a593Smuzhiyun 		case IIO_UVINDEX:
808*4882a593Smuzhiyun 			adc_sens >>= SI1133_ADCSENS_HSIG_SHIFT;
809*4882a593Smuzhiyun 
810*4882a593Smuzhiyun 			*val = adc_sens;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 			return IIO_VAL_INT;
813*4882a593Smuzhiyun 		default:
814*4882a593Smuzhiyun 			return -EINVAL;
815*4882a593Smuzhiyun 		}
816*4882a593Smuzhiyun 	default:
817*4882a593Smuzhiyun 		return -EINVAL;
818*4882a593Smuzhiyun 	}
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun 
si1133_write_raw(struct iio_dev * iio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)821*4882a593Smuzhiyun static int si1133_write_raw(struct iio_dev *iio_dev,
822*4882a593Smuzhiyun 			    struct iio_chan_spec const *chan,
823*4882a593Smuzhiyun 			    int val, int val2, long mask)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun 	struct si1133_data *data = iio_priv(iio_dev);
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	switch (mask) {
828*4882a593Smuzhiyun 	case IIO_CHAN_INFO_SCALE:
829*4882a593Smuzhiyun 		switch (chan->type) {
830*4882a593Smuzhiyun 		case IIO_INTENSITY:
831*4882a593Smuzhiyun 		case IIO_UVINDEX:
832*4882a593Smuzhiyun 			val = si1133_scale_to_swgain(val, val2);
833*4882a593Smuzhiyun 			if (val < 0)
834*4882a593Smuzhiyun 				return val;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 			return si1133_update_adcsens(data,
837*4882a593Smuzhiyun 						     SI1133_ADCSENS_SCALE_MASK,
838*4882a593Smuzhiyun 						     SI1133_ADCSENS_SCALE_SHIFT,
839*4882a593Smuzhiyun 						     val);
840*4882a593Smuzhiyun 		default:
841*4882a593Smuzhiyun 			return -EINVAL;
842*4882a593Smuzhiyun 		}
843*4882a593Smuzhiyun 	case IIO_CHAN_INFO_INT_TIME:
844*4882a593Smuzhiyun 		return si1133_set_integration_time(data, 0, val, val2);
845*4882a593Smuzhiyun 	case IIO_CHAN_INFO_HARDWAREGAIN:
846*4882a593Smuzhiyun 		switch (chan->type) {
847*4882a593Smuzhiyun 		case IIO_INTENSITY:
848*4882a593Smuzhiyun 		case IIO_UVINDEX:
849*4882a593Smuzhiyun 			if (val != 0 && val != 1)
850*4882a593Smuzhiyun 				return -EINVAL;
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun 			return si1133_update_adcsens(data,
853*4882a593Smuzhiyun 						     SI1133_ADCSENS_HSIG_MASK,
854*4882a593Smuzhiyun 						     SI1133_ADCSENS_HSIG_SHIFT,
855*4882a593Smuzhiyun 						     val);
856*4882a593Smuzhiyun 		default:
857*4882a593Smuzhiyun 			return -EINVAL;
858*4882a593Smuzhiyun 		}
859*4882a593Smuzhiyun 	default:
860*4882a593Smuzhiyun 		return -EINVAL;
861*4882a593Smuzhiyun 	}
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun 
864*4882a593Smuzhiyun static struct attribute *si1133_attributes[] = {
865*4882a593Smuzhiyun 	&iio_const_attr_integration_time_available.dev_attr.attr,
866*4882a593Smuzhiyun 	&iio_const_attr_scale_available.dev_attr.attr,
867*4882a593Smuzhiyun 	NULL,
868*4882a593Smuzhiyun };
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun static const struct attribute_group si1133_attribute_group = {
871*4882a593Smuzhiyun 	.attrs = si1133_attributes,
872*4882a593Smuzhiyun };
873*4882a593Smuzhiyun 
874*4882a593Smuzhiyun static const struct iio_info si1133_info = {
875*4882a593Smuzhiyun 	.read_raw = si1133_read_raw,
876*4882a593Smuzhiyun 	.write_raw = si1133_write_raw,
877*4882a593Smuzhiyun 	.attrs = &si1133_attribute_group,
878*4882a593Smuzhiyun };
879*4882a593Smuzhiyun 
880*4882a593Smuzhiyun /*
881*4882a593Smuzhiyun  * si1133_init_lux_channels - Configure 3 different channels(adc) (1,2 and 3)
882*4882a593Smuzhiyun  * The channel configuration for the lux measurement was taken from :
883*4882a593Smuzhiyun  * https://siliconlabs.github.io/Gecko_SDK_Doc/efm32zg/html/si1133_8c_source.html#l00578
884*4882a593Smuzhiyun  *
885*4882a593Smuzhiyun  * Reserved the channel 0 for the other raw measurements
886*4882a593Smuzhiyun  */
si1133_init_lux_channels(struct si1133_data * data)887*4882a593Smuzhiyun static int si1133_init_lux_channels(struct si1133_data *data)
888*4882a593Smuzhiyun {
889*4882a593Smuzhiyun 	int err;
890*4882a593Smuzhiyun 
891*4882a593Smuzhiyun 	err = si1133_chan_set_adcconfig(data, 1,
892*4882a593Smuzhiyun 					SI1133_ADCCONFIG_DECIM_RATE(1) |
893*4882a593Smuzhiyun 					SI1133_PARAM_ADCMUX_LARGE_WHITE);
894*4882a593Smuzhiyun 	if (err)
895*4882a593Smuzhiyun 		return err;
896*4882a593Smuzhiyun 
897*4882a593Smuzhiyun 	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(1),
898*4882a593Smuzhiyun 			       SI1133_ADCPOST_24BIT_EN |
899*4882a593Smuzhiyun 			       SI1133_ADCPOST_POSTSHIFT_BITQTY(0));
900*4882a593Smuzhiyun 	if (err)
901*4882a593Smuzhiyun 		return err;
902*4882a593Smuzhiyun 	err = si1133_chan_set_adcsens(data, 1, SI1133_ADCSENS_HSIG_MASK |
903*4882a593Smuzhiyun 				      SI1133_ADCSENS_NB_MEAS(64) | _48_8_us);
904*4882a593Smuzhiyun 	if (err)
905*4882a593Smuzhiyun 		return err;
906*4882a593Smuzhiyun 
907*4882a593Smuzhiyun 	err = si1133_chan_set_adcconfig(data, 2,
908*4882a593Smuzhiyun 					SI1133_ADCCONFIG_DECIM_RATE(1) |
909*4882a593Smuzhiyun 					SI1133_PARAM_ADCMUX_LARGE_WHITE);
910*4882a593Smuzhiyun 	if (err)
911*4882a593Smuzhiyun 		return err;
912*4882a593Smuzhiyun 
913*4882a593Smuzhiyun 	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(2),
914*4882a593Smuzhiyun 			       SI1133_ADCPOST_24BIT_EN |
915*4882a593Smuzhiyun 			       SI1133_ADCPOST_POSTSHIFT_BITQTY(2));
916*4882a593Smuzhiyun 	if (err)
917*4882a593Smuzhiyun 		return err;
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun 	err = si1133_chan_set_adcsens(data, 2, SI1133_ADCSENS_HSIG_MASK |
920*4882a593Smuzhiyun 				      SI1133_ADCSENS_NB_MEAS(1) | _3_120_0_us);
921*4882a593Smuzhiyun 	if (err)
922*4882a593Smuzhiyun 		return err;
923*4882a593Smuzhiyun 
924*4882a593Smuzhiyun 	err = si1133_chan_set_adcconfig(data, 3,
925*4882a593Smuzhiyun 					SI1133_ADCCONFIG_DECIM_RATE(1) |
926*4882a593Smuzhiyun 					SI1133_PARAM_ADCMUX_MED_IR);
927*4882a593Smuzhiyun 	if (err)
928*4882a593Smuzhiyun 		return err;
929*4882a593Smuzhiyun 
930*4882a593Smuzhiyun 	err = si1133_param_set(data, SI1133_PARAM_REG_ADCPOST(3),
931*4882a593Smuzhiyun 			       SI1133_ADCPOST_24BIT_EN |
932*4882a593Smuzhiyun 			       SI1133_ADCPOST_POSTSHIFT_BITQTY(2));
933*4882a593Smuzhiyun 	if (err)
934*4882a593Smuzhiyun 		return err;
935*4882a593Smuzhiyun 
936*4882a593Smuzhiyun 	return  si1133_chan_set_adcsens(data, 3, SI1133_ADCSENS_HSIG_MASK |
937*4882a593Smuzhiyun 					SI1133_ADCSENS_NB_MEAS(64) | _48_8_us);
938*4882a593Smuzhiyun }
939*4882a593Smuzhiyun 
si1133_initialize(struct si1133_data * data)940*4882a593Smuzhiyun static int si1133_initialize(struct si1133_data *data)
941*4882a593Smuzhiyun {
942*4882a593Smuzhiyun 	int err;
943*4882a593Smuzhiyun 
944*4882a593Smuzhiyun 	err = si1133_cmd_reset_sw(data);
945*4882a593Smuzhiyun 	if (err)
946*4882a593Smuzhiyun 		return err;
947*4882a593Smuzhiyun 
948*4882a593Smuzhiyun 	/* Turn off autonomous mode */
949*4882a593Smuzhiyun 	err = si1133_param_set(data, SI1133_REG_MEAS_RATE, 0);
950*4882a593Smuzhiyun 	if (err)
951*4882a593Smuzhiyun 		return err;
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	err = si1133_init_lux_channels(data);
954*4882a593Smuzhiyun 	if (err)
955*4882a593Smuzhiyun 		return err;
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun 	return regmap_write(data->regmap, SI1133_REG_IRQ_ENABLE,
958*4882a593Smuzhiyun 			    SI1133_IRQ_CHANNEL_ENABLE);
959*4882a593Smuzhiyun }
960*4882a593Smuzhiyun 
si1133_validate_ids(struct iio_dev * iio_dev)961*4882a593Smuzhiyun static int si1133_validate_ids(struct iio_dev *iio_dev)
962*4882a593Smuzhiyun {
963*4882a593Smuzhiyun 	struct si1133_data *data = iio_priv(iio_dev);
964*4882a593Smuzhiyun 
965*4882a593Smuzhiyun 	unsigned int part_id, rev_id, mfr_id;
966*4882a593Smuzhiyun 	int err;
967*4882a593Smuzhiyun 
968*4882a593Smuzhiyun 	err = regmap_read(data->regmap, SI1133_REG_PART_ID, &part_id);
969*4882a593Smuzhiyun 	if (err)
970*4882a593Smuzhiyun 		return err;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	err = regmap_read(data->regmap, SI1133_REG_REV_ID, &rev_id);
973*4882a593Smuzhiyun 	if (err)
974*4882a593Smuzhiyun 		return err;
975*4882a593Smuzhiyun 
976*4882a593Smuzhiyun 	err = regmap_read(data->regmap, SI1133_REG_MFR_ID, &mfr_id);
977*4882a593Smuzhiyun 	if (err)
978*4882a593Smuzhiyun 		return err;
979*4882a593Smuzhiyun 
980*4882a593Smuzhiyun 	dev_info(&iio_dev->dev,
981*4882a593Smuzhiyun 		 "Device ID part %#02hhx rev %#02hhx mfr %#02hhx\n",
982*4882a593Smuzhiyun 		 part_id, rev_id, mfr_id);
983*4882a593Smuzhiyun 	if (part_id != SI1133_PART_ID) {
984*4882a593Smuzhiyun 		dev_err(&iio_dev->dev,
985*4882a593Smuzhiyun 			"Part ID mismatch got %#02hhx, expected %#02x\n",
986*4882a593Smuzhiyun 			part_id, SI1133_PART_ID);
987*4882a593Smuzhiyun 		return -ENODEV;
988*4882a593Smuzhiyun 	}
989*4882a593Smuzhiyun 
990*4882a593Smuzhiyun 	return 0;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun 
si1133_probe(struct i2c_client * client,const struct i2c_device_id * id)993*4882a593Smuzhiyun static int si1133_probe(struct i2c_client *client,
994*4882a593Smuzhiyun 			const struct i2c_device_id *id)
995*4882a593Smuzhiyun {
996*4882a593Smuzhiyun 	struct si1133_data *data;
997*4882a593Smuzhiyun 	struct iio_dev *iio_dev;
998*4882a593Smuzhiyun 	int err;
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun 	iio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1001*4882a593Smuzhiyun 	if (!iio_dev)
1002*4882a593Smuzhiyun 		return -ENOMEM;
1003*4882a593Smuzhiyun 
1004*4882a593Smuzhiyun 	data = iio_priv(iio_dev);
1005*4882a593Smuzhiyun 
1006*4882a593Smuzhiyun 	init_completion(&data->completion);
1007*4882a593Smuzhiyun 
1008*4882a593Smuzhiyun 	data->regmap = devm_regmap_init_i2c(client, &si1133_regmap_config);
1009*4882a593Smuzhiyun 	if (IS_ERR(data->regmap)) {
1010*4882a593Smuzhiyun 		err = PTR_ERR(data->regmap);
1011*4882a593Smuzhiyun 		dev_err(&client->dev, "Failed to initialise regmap: %d\n", err);
1012*4882a593Smuzhiyun 		return err;
1013*4882a593Smuzhiyun 	}
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	i2c_set_clientdata(client, iio_dev);
1016*4882a593Smuzhiyun 	data->client = client;
1017*4882a593Smuzhiyun 
1018*4882a593Smuzhiyun 	iio_dev->name = id->name;
1019*4882a593Smuzhiyun 	iio_dev->channels = si1133_channels;
1020*4882a593Smuzhiyun 	iio_dev->num_channels = ARRAY_SIZE(si1133_channels);
1021*4882a593Smuzhiyun 	iio_dev->info = &si1133_info;
1022*4882a593Smuzhiyun 	iio_dev->modes = INDIO_DIRECT_MODE;
1023*4882a593Smuzhiyun 
1024*4882a593Smuzhiyun 	mutex_init(&data->mutex);
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	err = si1133_validate_ids(iio_dev);
1027*4882a593Smuzhiyun 	if (err)
1028*4882a593Smuzhiyun 		return err;
1029*4882a593Smuzhiyun 
1030*4882a593Smuzhiyun 	err = si1133_initialize(data);
1031*4882a593Smuzhiyun 	if (err) {
1032*4882a593Smuzhiyun 		dev_err(&client->dev,
1033*4882a593Smuzhiyun 			"Error when initializing chip: %d\n", err);
1034*4882a593Smuzhiyun 		return err;
1035*4882a593Smuzhiyun 	}
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	if (!client->irq) {
1038*4882a593Smuzhiyun 		dev_err(&client->dev,
1039*4882a593Smuzhiyun 			"Required interrupt not provided, cannot proceed\n");
1040*4882a593Smuzhiyun 		return -EINVAL;
1041*4882a593Smuzhiyun 	}
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun 	err = devm_request_threaded_irq(&client->dev, client->irq,
1044*4882a593Smuzhiyun 					NULL,
1045*4882a593Smuzhiyun 					si1133_threaded_irq_handler,
1046*4882a593Smuzhiyun 					IRQF_ONESHOT | IRQF_SHARED,
1047*4882a593Smuzhiyun 					client->name, iio_dev);
1048*4882a593Smuzhiyun 	if (err) {
1049*4882a593Smuzhiyun 		dev_warn(&client->dev, "Request irq %d failed: %i\n",
1050*4882a593Smuzhiyun 			 client->irq, err);
1051*4882a593Smuzhiyun 		return err;
1052*4882a593Smuzhiyun 	}
1053*4882a593Smuzhiyun 
1054*4882a593Smuzhiyun 	return devm_iio_device_register(&client->dev, iio_dev);
1055*4882a593Smuzhiyun }
1056*4882a593Smuzhiyun 
1057*4882a593Smuzhiyun static const struct i2c_device_id si1133_ids[] = {
1058*4882a593Smuzhiyun 	{ "si1133", 0 },
1059*4882a593Smuzhiyun 	{ }
1060*4882a593Smuzhiyun };
1061*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, si1133_ids);
1062*4882a593Smuzhiyun 
1063*4882a593Smuzhiyun static struct i2c_driver si1133_driver = {
1064*4882a593Smuzhiyun 	.driver = {
1065*4882a593Smuzhiyun 	    .name   = "si1133",
1066*4882a593Smuzhiyun 	},
1067*4882a593Smuzhiyun 	.probe  = si1133_probe,
1068*4882a593Smuzhiyun 	.id_table = si1133_ids,
1069*4882a593Smuzhiyun };
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun module_i2c_driver(si1133_driver);
1072*4882a593Smuzhiyun 
1073*4882a593Smuzhiyun MODULE_AUTHOR("Maxime Roussin-Belanger <maxime.roussinbelanger@gmail.com>");
1074*4882a593Smuzhiyun MODULE_DESCRIPTION("Silabs SI1133, UV index sensor and ambient light sensor driver");
1075*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1076