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