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