1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * si1145.c - Support for Silabs SI1132 and SI1141/2/3/5/6/7 combined ambient
4*4882a593Smuzhiyun * light, UV index and proximity sensors
5*4882a593Smuzhiyun *
6*4882a593Smuzhiyun * Copyright 2014-16 Peter Meerwald-Stadler <pmeerw@pmeerw.net>
7*4882a593Smuzhiyun * Copyright 2016 Crestez Dan Leonard <leonard.crestez@intel.com>
8*4882a593Smuzhiyun *
9*4882a593Smuzhiyun * SI1132 (7-bit I2C slave address 0x60)
10*4882a593Smuzhiyun * SI1141/2/3 (7-bit I2C slave address 0x5a)
11*4882a593Smuzhiyun * SI1145/6/6 (7-bit I2C slave address 0x60)
12*4882a593Smuzhiyun */
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/i2c.h>
16*4882a593Smuzhiyun #include <linux/err.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun #include <linux/irq.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun #include <linux/iio/iio.h>
22*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
23*4882a593Smuzhiyun #include <linux/iio/trigger.h>
24*4882a593Smuzhiyun #include <linux/iio/trigger_consumer.h>
25*4882a593Smuzhiyun #include <linux/iio/triggered_buffer.h>
26*4882a593Smuzhiyun #include <linux/iio/buffer.h>
27*4882a593Smuzhiyun #include <linux/util_macros.h>
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun #define SI1145_REG_PART_ID 0x00
30*4882a593Smuzhiyun #define SI1145_REG_REV_ID 0x01
31*4882a593Smuzhiyun #define SI1145_REG_SEQ_ID 0x02
32*4882a593Smuzhiyun #define SI1145_REG_INT_CFG 0x03
33*4882a593Smuzhiyun #define SI1145_REG_IRQ_ENABLE 0x04
34*4882a593Smuzhiyun #define SI1145_REG_IRQ_MODE 0x05
35*4882a593Smuzhiyun #define SI1145_REG_HW_KEY 0x07
36*4882a593Smuzhiyun #define SI1145_REG_MEAS_RATE 0x08
37*4882a593Smuzhiyun #define SI1145_REG_PS_LED21 0x0f
38*4882a593Smuzhiyun #define SI1145_REG_PS_LED3 0x10
39*4882a593Smuzhiyun #define SI1145_REG_UCOEF1 0x13
40*4882a593Smuzhiyun #define SI1145_REG_UCOEF2 0x14
41*4882a593Smuzhiyun #define SI1145_REG_UCOEF3 0x15
42*4882a593Smuzhiyun #define SI1145_REG_UCOEF4 0x16
43*4882a593Smuzhiyun #define SI1145_REG_PARAM_WR 0x17
44*4882a593Smuzhiyun #define SI1145_REG_COMMAND 0x18
45*4882a593Smuzhiyun #define SI1145_REG_RESPONSE 0x20
46*4882a593Smuzhiyun #define SI1145_REG_IRQ_STATUS 0x21
47*4882a593Smuzhiyun #define SI1145_REG_ALSVIS_DATA 0x22
48*4882a593Smuzhiyun #define SI1145_REG_ALSIR_DATA 0x24
49*4882a593Smuzhiyun #define SI1145_REG_PS1_DATA 0x26
50*4882a593Smuzhiyun #define SI1145_REG_PS2_DATA 0x28
51*4882a593Smuzhiyun #define SI1145_REG_PS3_DATA 0x2a
52*4882a593Smuzhiyun #define SI1145_REG_AUX_DATA 0x2c
53*4882a593Smuzhiyun #define SI1145_REG_PARAM_RD 0x2e
54*4882a593Smuzhiyun #define SI1145_REG_CHIP_STAT 0x30
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun #define SI1145_UCOEF1_DEFAULT 0x7b
57*4882a593Smuzhiyun #define SI1145_UCOEF2_DEFAULT 0x6b
58*4882a593Smuzhiyun #define SI1145_UCOEF3_DEFAULT 0x01
59*4882a593Smuzhiyun #define SI1145_UCOEF4_DEFAULT 0x00
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun /* Helper to figure out PS_LED register / shift per channel */
62*4882a593Smuzhiyun #define SI1145_PS_LED_REG(ch) \
63*4882a593Smuzhiyun (((ch) == 2) ? SI1145_REG_PS_LED3 : SI1145_REG_PS_LED21)
64*4882a593Smuzhiyun #define SI1145_PS_LED_SHIFT(ch) \
65*4882a593Smuzhiyun (((ch) == 1) ? 4 : 0)
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* Parameter offsets */
68*4882a593Smuzhiyun #define SI1145_PARAM_CHLIST 0x01
69*4882a593Smuzhiyun #define SI1145_PARAM_PSLED12_SELECT 0x02
70*4882a593Smuzhiyun #define SI1145_PARAM_PSLED3_SELECT 0x03
71*4882a593Smuzhiyun #define SI1145_PARAM_PS_ENCODING 0x05
72*4882a593Smuzhiyun #define SI1145_PARAM_ALS_ENCODING 0x06
73*4882a593Smuzhiyun #define SI1145_PARAM_PS1_ADC_MUX 0x07
74*4882a593Smuzhiyun #define SI1145_PARAM_PS2_ADC_MUX 0x08
75*4882a593Smuzhiyun #define SI1145_PARAM_PS3_ADC_MUX 0x09
76*4882a593Smuzhiyun #define SI1145_PARAM_PS_ADC_COUNTER 0x0a
77*4882a593Smuzhiyun #define SI1145_PARAM_PS_ADC_GAIN 0x0b
78*4882a593Smuzhiyun #define SI1145_PARAM_PS_ADC_MISC 0x0c
79*4882a593Smuzhiyun #define SI1145_PARAM_ALS_ADC_MUX 0x0d
80*4882a593Smuzhiyun #define SI1145_PARAM_ALSIR_ADC_MUX 0x0e
81*4882a593Smuzhiyun #define SI1145_PARAM_AUX_ADC_MUX 0x0f
82*4882a593Smuzhiyun #define SI1145_PARAM_ALSVIS_ADC_COUNTER 0x10
83*4882a593Smuzhiyun #define SI1145_PARAM_ALSVIS_ADC_GAIN 0x11
84*4882a593Smuzhiyun #define SI1145_PARAM_ALSVIS_ADC_MISC 0x12
85*4882a593Smuzhiyun #define SI1145_PARAM_LED_RECOVERY 0x1c
86*4882a593Smuzhiyun #define SI1145_PARAM_ALSIR_ADC_COUNTER 0x1d
87*4882a593Smuzhiyun #define SI1145_PARAM_ALSIR_ADC_GAIN 0x1e
88*4882a593Smuzhiyun #define SI1145_PARAM_ALSIR_ADC_MISC 0x1f
89*4882a593Smuzhiyun #define SI1145_PARAM_ADC_OFFSET 0x1a
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun /* Channel enable masks for CHLIST parameter */
92*4882a593Smuzhiyun #define SI1145_CHLIST_EN_PS1 BIT(0)
93*4882a593Smuzhiyun #define SI1145_CHLIST_EN_PS2 BIT(1)
94*4882a593Smuzhiyun #define SI1145_CHLIST_EN_PS3 BIT(2)
95*4882a593Smuzhiyun #define SI1145_CHLIST_EN_ALSVIS BIT(4)
96*4882a593Smuzhiyun #define SI1145_CHLIST_EN_ALSIR BIT(5)
97*4882a593Smuzhiyun #define SI1145_CHLIST_EN_AUX BIT(6)
98*4882a593Smuzhiyun #define SI1145_CHLIST_EN_UV BIT(7)
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun /* Proximity measurement mode for ADC_MISC parameter */
101*4882a593Smuzhiyun #define SI1145_PS_ADC_MODE_NORMAL BIT(2)
102*4882a593Smuzhiyun /* Signal range mask for ADC_MISC parameter */
103*4882a593Smuzhiyun #define SI1145_ADC_MISC_RANGE BIT(5)
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun /* Commands for REG_COMMAND */
106*4882a593Smuzhiyun #define SI1145_CMD_NOP 0x00
107*4882a593Smuzhiyun #define SI1145_CMD_RESET 0x01
108*4882a593Smuzhiyun #define SI1145_CMD_PS_FORCE 0x05
109*4882a593Smuzhiyun #define SI1145_CMD_ALS_FORCE 0x06
110*4882a593Smuzhiyun #define SI1145_CMD_PSALS_FORCE 0x07
111*4882a593Smuzhiyun #define SI1145_CMD_PS_PAUSE 0x09
112*4882a593Smuzhiyun #define SI1145_CMD_ALS_PAUSE 0x0a
113*4882a593Smuzhiyun #define SI1145_CMD_PSALS_PAUSE 0x0b
114*4882a593Smuzhiyun #define SI1145_CMD_PS_AUTO 0x0d
115*4882a593Smuzhiyun #define SI1145_CMD_ALS_AUTO 0x0e
116*4882a593Smuzhiyun #define SI1145_CMD_PSALS_AUTO 0x0f
117*4882a593Smuzhiyun #define SI1145_CMD_PARAM_QUERY 0x80
118*4882a593Smuzhiyun #define SI1145_CMD_PARAM_SET 0xa0
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun #define SI1145_RSP_INVALID_SETTING 0x80
121*4882a593Smuzhiyun #define SI1145_RSP_COUNTER_MASK 0x0F
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun /* Minimum sleep after each command to ensure it's received */
124*4882a593Smuzhiyun #define SI1145_COMMAND_MINSLEEP_MS 5
125*4882a593Smuzhiyun /* Return -ETIMEDOUT after this long */
126*4882a593Smuzhiyun #define SI1145_COMMAND_TIMEOUT_MS 25
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun /* Interrupt configuration masks for INT_CFG register */
129*4882a593Smuzhiyun #define SI1145_INT_CFG_OE BIT(0) /* enable interrupt */
130*4882a593Smuzhiyun #define SI1145_INT_CFG_MODE BIT(1) /* auto reset interrupt pin */
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /* Interrupt enable masks for IRQ_ENABLE register */
133*4882a593Smuzhiyun #define SI1145_MASK_ALL_IE (BIT(4) | BIT(3) | BIT(2) | BIT(0))
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun #define SI1145_MUX_TEMP 0x65
136*4882a593Smuzhiyun #define SI1145_MUX_VDD 0x75
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun /* Proximity LED current; see Table 2 in datasheet */
139*4882a593Smuzhiyun #define SI1145_LED_CURRENT_45mA 0x04
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun enum {
142*4882a593Smuzhiyun SI1132,
143*4882a593Smuzhiyun SI1141,
144*4882a593Smuzhiyun SI1142,
145*4882a593Smuzhiyun SI1143,
146*4882a593Smuzhiyun SI1145,
147*4882a593Smuzhiyun SI1146,
148*4882a593Smuzhiyun SI1147,
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun struct si1145_part_info {
152*4882a593Smuzhiyun u8 part;
153*4882a593Smuzhiyun const struct iio_info *iio_info;
154*4882a593Smuzhiyun const struct iio_chan_spec *channels;
155*4882a593Smuzhiyun unsigned int num_channels;
156*4882a593Smuzhiyun unsigned int num_leds;
157*4882a593Smuzhiyun bool uncompressed_meas_rate;
158*4882a593Smuzhiyun };
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /**
161*4882a593Smuzhiyun * struct si1145_data - si1145 chip state data
162*4882a593Smuzhiyun * @client: I2C client
163*4882a593Smuzhiyun * @lock: mutex to protect shared state.
164*4882a593Smuzhiyun * @cmdlock: Low-level mutex to protect command execution only
165*4882a593Smuzhiyun * @rsp_seq: Next expected response number or -1 if counter reset required
166*4882a593Smuzhiyun * @scan_mask: Saved scan mask to avoid duplicate set_chlist
167*4882a593Smuzhiyun * @autonomous: If automatic measurements are active (for buffer support)
168*4882a593Smuzhiyun * @part_info: Part information
169*4882a593Smuzhiyun * @trig: Pointer to iio trigger
170*4882a593Smuzhiyun * @meas_rate: Value of MEAS_RATE register. Only set in HW in auto mode
171*4882a593Smuzhiyun * @buffer: Used to pack data read from sensor.
172*4882a593Smuzhiyun */
173*4882a593Smuzhiyun struct si1145_data {
174*4882a593Smuzhiyun struct i2c_client *client;
175*4882a593Smuzhiyun struct mutex lock;
176*4882a593Smuzhiyun struct mutex cmdlock;
177*4882a593Smuzhiyun int rsp_seq;
178*4882a593Smuzhiyun const struct si1145_part_info *part_info;
179*4882a593Smuzhiyun unsigned long scan_mask;
180*4882a593Smuzhiyun bool autonomous;
181*4882a593Smuzhiyun struct iio_trigger *trig;
182*4882a593Smuzhiyun int meas_rate;
183*4882a593Smuzhiyun /*
184*4882a593Smuzhiyun * Ensure timestamp will be naturally aligned if present.
185*4882a593Smuzhiyun * Maximum buffer size (may be only partly used if not all
186*4882a593Smuzhiyun * channels are enabled):
187*4882a593Smuzhiyun * 6*2 bytes channels data + 4 bytes alignment +
188*4882a593Smuzhiyun * 8 bytes timestamp
189*4882a593Smuzhiyun */
190*4882a593Smuzhiyun u8 buffer[24] __aligned(8);
191*4882a593Smuzhiyun };
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun /*
194*4882a593Smuzhiyun * __si1145_command_reset() - Send CMD_NOP and wait for response 0
195*4882a593Smuzhiyun *
196*4882a593Smuzhiyun * Does not modify data->rsp_seq
197*4882a593Smuzhiyun *
198*4882a593Smuzhiyun * Return: 0 on success and -errno on error.
199*4882a593Smuzhiyun */
__si1145_command_reset(struct si1145_data * data)200*4882a593Smuzhiyun static int __si1145_command_reset(struct si1145_data *data)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun struct device *dev = &data->client->dev;
203*4882a593Smuzhiyun unsigned long stop_jiffies;
204*4882a593Smuzhiyun int ret;
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client, SI1145_REG_COMMAND,
207*4882a593Smuzhiyun SI1145_CMD_NOP);
208*4882a593Smuzhiyun if (ret < 0)
209*4882a593Smuzhiyun return ret;
210*4882a593Smuzhiyun msleep(SI1145_COMMAND_MINSLEEP_MS);
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun stop_jiffies = jiffies + SI1145_COMMAND_TIMEOUT_MS * HZ / 1000;
213*4882a593Smuzhiyun while (true) {
214*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(data->client,
215*4882a593Smuzhiyun SI1145_REG_RESPONSE);
216*4882a593Smuzhiyun if (ret <= 0)
217*4882a593Smuzhiyun return ret;
218*4882a593Smuzhiyun if (time_after(jiffies, stop_jiffies)) {
219*4882a593Smuzhiyun dev_warn(dev, "timeout on reset\n");
220*4882a593Smuzhiyun return -ETIMEDOUT;
221*4882a593Smuzhiyun }
222*4882a593Smuzhiyun msleep(SI1145_COMMAND_MINSLEEP_MS);
223*4882a593Smuzhiyun continue;
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun /*
228*4882a593Smuzhiyun * si1145_command() - Execute a command and poll the response register
229*4882a593Smuzhiyun *
230*4882a593Smuzhiyun * All conversion overflows are reported as -EOVERFLOW
231*4882a593Smuzhiyun * INVALID_SETTING is reported as -EINVAL
232*4882a593Smuzhiyun * Timeouts are reported as -ETIMEDOUT
233*4882a593Smuzhiyun *
234*4882a593Smuzhiyun * Return: 0 on success or -errno on failure
235*4882a593Smuzhiyun */
si1145_command(struct si1145_data * data,u8 cmd)236*4882a593Smuzhiyun static int si1145_command(struct si1145_data *data, u8 cmd)
237*4882a593Smuzhiyun {
238*4882a593Smuzhiyun struct device *dev = &data->client->dev;
239*4882a593Smuzhiyun unsigned long stop_jiffies;
240*4882a593Smuzhiyun int ret;
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun mutex_lock(&data->cmdlock);
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (data->rsp_seq < 0) {
245*4882a593Smuzhiyun ret = __si1145_command_reset(data);
246*4882a593Smuzhiyun if (ret < 0) {
247*4882a593Smuzhiyun dev_err(dev, "failed to reset command counter, ret=%d\n",
248*4882a593Smuzhiyun ret);
249*4882a593Smuzhiyun goto out;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun data->rsp_seq = 0;
252*4882a593Smuzhiyun }
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client, SI1145_REG_COMMAND, cmd);
255*4882a593Smuzhiyun if (ret) {
256*4882a593Smuzhiyun dev_warn(dev, "failed to write command, ret=%d\n", ret);
257*4882a593Smuzhiyun goto out;
258*4882a593Smuzhiyun }
259*4882a593Smuzhiyun /* Sleep a little to ensure the command is received */
260*4882a593Smuzhiyun msleep(SI1145_COMMAND_MINSLEEP_MS);
261*4882a593Smuzhiyun
262*4882a593Smuzhiyun stop_jiffies = jiffies + SI1145_COMMAND_TIMEOUT_MS * HZ / 1000;
263*4882a593Smuzhiyun while (true) {
264*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(data->client,
265*4882a593Smuzhiyun SI1145_REG_RESPONSE);
266*4882a593Smuzhiyun if (ret < 0) {
267*4882a593Smuzhiyun dev_warn(dev, "failed to read response, ret=%d\n", ret);
268*4882a593Smuzhiyun break;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun if ((ret & ~SI1145_RSP_COUNTER_MASK) == 0) {
272*4882a593Smuzhiyun if (ret == data->rsp_seq) {
273*4882a593Smuzhiyun if (time_after(jiffies, stop_jiffies)) {
274*4882a593Smuzhiyun dev_warn(dev, "timeout on command %#02hhx\n",
275*4882a593Smuzhiyun cmd);
276*4882a593Smuzhiyun ret = -ETIMEDOUT;
277*4882a593Smuzhiyun break;
278*4882a593Smuzhiyun }
279*4882a593Smuzhiyun msleep(SI1145_COMMAND_MINSLEEP_MS);
280*4882a593Smuzhiyun continue;
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun if (ret == ((data->rsp_seq + 1) &
283*4882a593Smuzhiyun SI1145_RSP_COUNTER_MASK)) {
284*4882a593Smuzhiyun data->rsp_seq = ret;
285*4882a593Smuzhiyun ret = 0;
286*4882a593Smuzhiyun break;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun dev_warn(dev, "unexpected response counter %d instead of %d\n",
289*4882a593Smuzhiyun ret, (data->rsp_seq + 1) &
290*4882a593Smuzhiyun SI1145_RSP_COUNTER_MASK);
291*4882a593Smuzhiyun ret = -EIO;
292*4882a593Smuzhiyun } else {
293*4882a593Smuzhiyun if (ret == SI1145_RSP_INVALID_SETTING) {
294*4882a593Smuzhiyun dev_warn(dev, "INVALID_SETTING error on command %#02hhx\n",
295*4882a593Smuzhiyun cmd);
296*4882a593Smuzhiyun ret = -EINVAL;
297*4882a593Smuzhiyun } else {
298*4882a593Smuzhiyun /* All overflows are treated identically */
299*4882a593Smuzhiyun dev_dbg(dev, "overflow, ret=%d, cmd=%#02hhx\n",
300*4882a593Smuzhiyun ret, cmd);
301*4882a593Smuzhiyun ret = -EOVERFLOW;
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun /* Force a counter reset next time */
306*4882a593Smuzhiyun data->rsp_seq = -1;
307*4882a593Smuzhiyun break;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun out:
311*4882a593Smuzhiyun mutex_unlock(&data->cmdlock);
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun return ret;
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
si1145_param_update(struct si1145_data * data,u8 op,u8 param,u8 value)316*4882a593Smuzhiyun static int si1145_param_update(struct si1145_data *data, u8 op, u8 param,
317*4882a593Smuzhiyun u8 value)
318*4882a593Smuzhiyun {
319*4882a593Smuzhiyun int ret;
320*4882a593Smuzhiyun
321*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
322*4882a593Smuzhiyun SI1145_REG_PARAM_WR, value);
323*4882a593Smuzhiyun if (ret < 0)
324*4882a593Smuzhiyun return ret;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return si1145_command(data, op | (param & 0x1F));
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
si1145_param_set(struct si1145_data * data,u8 param,u8 value)329*4882a593Smuzhiyun static int si1145_param_set(struct si1145_data *data, u8 param, u8 value)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun return si1145_param_update(data, SI1145_CMD_PARAM_SET, param, value);
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun /* Set param. Returns negative errno or current value */
si1145_param_query(struct si1145_data * data,u8 param)335*4882a593Smuzhiyun static int si1145_param_query(struct si1145_data *data, u8 param)
336*4882a593Smuzhiyun {
337*4882a593Smuzhiyun int ret;
338*4882a593Smuzhiyun
339*4882a593Smuzhiyun ret = si1145_command(data, SI1145_CMD_PARAM_QUERY | (param & 0x1F));
340*4882a593Smuzhiyun if (ret < 0)
341*4882a593Smuzhiyun return ret;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun return i2c_smbus_read_byte_data(data->client, SI1145_REG_PARAM_RD);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun /* Expand 8 bit compressed value to 16 bit, see Silabs AN498 */
si1145_uncompress(u8 x)347*4882a593Smuzhiyun static u16 si1145_uncompress(u8 x)
348*4882a593Smuzhiyun {
349*4882a593Smuzhiyun u16 result = 0;
350*4882a593Smuzhiyun u8 exponent = 0;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun if (x < 8)
353*4882a593Smuzhiyun return 0;
354*4882a593Smuzhiyun
355*4882a593Smuzhiyun exponent = (x & 0xf0) >> 4;
356*4882a593Smuzhiyun result = 0x10 | (x & 0x0f);
357*4882a593Smuzhiyun
358*4882a593Smuzhiyun if (exponent >= 4)
359*4882a593Smuzhiyun return result << (exponent - 4);
360*4882a593Smuzhiyun return result >> (4 - exponent);
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun /* Compress 16 bit value to 8 bit, see Silabs AN498 */
si1145_compress(u16 x)364*4882a593Smuzhiyun static u8 si1145_compress(u16 x)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun u32 exponent = 0;
367*4882a593Smuzhiyun u32 significand = 0;
368*4882a593Smuzhiyun u32 tmp = x;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun if (x == 0x0000)
371*4882a593Smuzhiyun return 0x00;
372*4882a593Smuzhiyun if (x == 0x0001)
373*4882a593Smuzhiyun return 0x08;
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun while (1) {
376*4882a593Smuzhiyun tmp >>= 1;
377*4882a593Smuzhiyun exponent += 1;
378*4882a593Smuzhiyun if (tmp == 1)
379*4882a593Smuzhiyun break;
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun if (exponent < 5) {
383*4882a593Smuzhiyun significand = x << (4 - exponent);
384*4882a593Smuzhiyun return (exponent << 4) | (significand & 0xF);
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
387*4882a593Smuzhiyun significand = x >> (exponent - 5);
388*4882a593Smuzhiyun if (significand & 1) {
389*4882a593Smuzhiyun significand += 2;
390*4882a593Smuzhiyun if (significand & 0x0040) {
391*4882a593Smuzhiyun exponent += 1;
392*4882a593Smuzhiyun significand >>= 1;
393*4882a593Smuzhiyun }
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun return (exponent << 4) | ((significand >> 1) & 0xF);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun
399*4882a593Smuzhiyun /* Write meas_rate in hardware */
si1145_set_meas_rate(struct si1145_data * data,int interval)400*4882a593Smuzhiyun static int si1145_set_meas_rate(struct si1145_data *data, int interval)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun if (data->part_info->uncompressed_meas_rate)
403*4882a593Smuzhiyun return i2c_smbus_write_word_data(data->client,
404*4882a593Smuzhiyun SI1145_REG_MEAS_RATE, interval);
405*4882a593Smuzhiyun else
406*4882a593Smuzhiyun return i2c_smbus_write_byte_data(data->client,
407*4882a593Smuzhiyun SI1145_REG_MEAS_RATE, interval);
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
si1145_read_samp_freq(struct si1145_data * data,int * val,int * val2)410*4882a593Smuzhiyun static int si1145_read_samp_freq(struct si1145_data *data, int *val, int *val2)
411*4882a593Smuzhiyun {
412*4882a593Smuzhiyun *val = 32000;
413*4882a593Smuzhiyun if (data->part_info->uncompressed_meas_rate)
414*4882a593Smuzhiyun *val2 = data->meas_rate;
415*4882a593Smuzhiyun else
416*4882a593Smuzhiyun *val2 = si1145_uncompress(data->meas_rate);
417*4882a593Smuzhiyun return IIO_VAL_FRACTIONAL;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun /* Set the samp freq in driver private data */
si1145_store_samp_freq(struct si1145_data * data,int val)421*4882a593Smuzhiyun static int si1145_store_samp_freq(struct si1145_data *data, int val)
422*4882a593Smuzhiyun {
423*4882a593Smuzhiyun int ret = 0;
424*4882a593Smuzhiyun int meas_rate;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun if (val <= 0 || val > 32000)
427*4882a593Smuzhiyun return -ERANGE;
428*4882a593Smuzhiyun meas_rate = 32000 / val;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun mutex_lock(&data->lock);
431*4882a593Smuzhiyun if (data->autonomous) {
432*4882a593Smuzhiyun ret = si1145_set_meas_rate(data, meas_rate);
433*4882a593Smuzhiyun if (ret)
434*4882a593Smuzhiyun goto out;
435*4882a593Smuzhiyun }
436*4882a593Smuzhiyun if (data->part_info->uncompressed_meas_rate)
437*4882a593Smuzhiyun data->meas_rate = meas_rate;
438*4882a593Smuzhiyun else
439*4882a593Smuzhiyun data->meas_rate = si1145_compress(meas_rate);
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun out:
442*4882a593Smuzhiyun mutex_unlock(&data->lock);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun return ret;
445*4882a593Smuzhiyun }
446*4882a593Smuzhiyun
si1145_trigger_handler(int irq,void * private)447*4882a593Smuzhiyun static irqreturn_t si1145_trigger_handler(int irq, void *private)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun struct iio_poll_func *pf = private;
450*4882a593Smuzhiyun struct iio_dev *indio_dev = pf->indio_dev;
451*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
452*4882a593Smuzhiyun int i, j = 0;
453*4882a593Smuzhiyun int ret;
454*4882a593Smuzhiyun u8 irq_status = 0;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun if (!data->autonomous) {
457*4882a593Smuzhiyun ret = si1145_command(data, SI1145_CMD_PSALS_FORCE);
458*4882a593Smuzhiyun if (ret < 0 && ret != -EOVERFLOW)
459*4882a593Smuzhiyun goto done;
460*4882a593Smuzhiyun } else {
461*4882a593Smuzhiyun irq_status = ret = i2c_smbus_read_byte_data(data->client,
462*4882a593Smuzhiyun SI1145_REG_IRQ_STATUS);
463*4882a593Smuzhiyun if (ret < 0)
464*4882a593Smuzhiyun goto done;
465*4882a593Smuzhiyun if (!(irq_status & SI1145_MASK_ALL_IE))
466*4882a593Smuzhiyun goto done;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun for_each_set_bit(i, indio_dev->active_scan_mask,
470*4882a593Smuzhiyun indio_dev->masklength) {
471*4882a593Smuzhiyun int run = 1;
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun while (i + run < indio_dev->masklength) {
474*4882a593Smuzhiyun if (!test_bit(i + run, indio_dev->active_scan_mask))
475*4882a593Smuzhiyun break;
476*4882a593Smuzhiyun if (indio_dev->channels[i + run].address !=
477*4882a593Smuzhiyun indio_dev->channels[i].address + 2 * run)
478*4882a593Smuzhiyun break;
479*4882a593Smuzhiyun run++;
480*4882a593Smuzhiyun }
481*4882a593Smuzhiyun
482*4882a593Smuzhiyun ret = i2c_smbus_read_i2c_block_data_or_emulated(
483*4882a593Smuzhiyun data->client, indio_dev->channels[i].address,
484*4882a593Smuzhiyun sizeof(u16) * run, &data->buffer[j]);
485*4882a593Smuzhiyun if (ret < 0)
486*4882a593Smuzhiyun goto done;
487*4882a593Smuzhiyun j += run * sizeof(u16);
488*4882a593Smuzhiyun i += run - 1;
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun
491*4882a593Smuzhiyun if (data->autonomous) {
492*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
493*4882a593Smuzhiyun SI1145_REG_IRQ_STATUS,
494*4882a593Smuzhiyun irq_status & SI1145_MASK_ALL_IE);
495*4882a593Smuzhiyun if (ret < 0)
496*4882a593Smuzhiyun goto done;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
500*4882a593Smuzhiyun iio_get_time_ns(indio_dev));
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun done:
503*4882a593Smuzhiyun iio_trigger_notify_done(indio_dev->trig);
504*4882a593Smuzhiyun return IRQ_HANDLED;
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
si1145_set_chlist(struct iio_dev * indio_dev,unsigned long scan_mask)507*4882a593Smuzhiyun static int si1145_set_chlist(struct iio_dev *indio_dev, unsigned long scan_mask)
508*4882a593Smuzhiyun {
509*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
510*4882a593Smuzhiyun u8 reg = 0, mux;
511*4882a593Smuzhiyun int ret;
512*4882a593Smuzhiyun int i;
513*4882a593Smuzhiyun
514*4882a593Smuzhiyun /* channel list already set, no need to reprogram */
515*4882a593Smuzhiyun if (data->scan_mask == scan_mask)
516*4882a593Smuzhiyun return 0;
517*4882a593Smuzhiyun
518*4882a593Smuzhiyun for_each_set_bit(i, &scan_mask, indio_dev->masklength) {
519*4882a593Smuzhiyun switch (indio_dev->channels[i].address) {
520*4882a593Smuzhiyun case SI1145_REG_ALSVIS_DATA:
521*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_ALSVIS;
522*4882a593Smuzhiyun break;
523*4882a593Smuzhiyun case SI1145_REG_ALSIR_DATA:
524*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_ALSIR;
525*4882a593Smuzhiyun break;
526*4882a593Smuzhiyun case SI1145_REG_PS1_DATA:
527*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_PS1;
528*4882a593Smuzhiyun break;
529*4882a593Smuzhiyun case SI1145_REG_PS2_DATA:
530*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_PS2;
531*4882a593Smuzhiyun break;
532*4882a593Smuzhiyun case SI1145_REG_PS3_DATA:
533*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_PS3;
534*4882a593Smuzhiyun break;
535*4882a593Smuzhiyun case SI1145_REG_AUX_DATA:
536*4882a593Smuzhiyun switch (indio_dev->channels[i].type) {
537*4882a593Smuzhiyun case IIO_UVINDEX:
538*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_UV;
539*4882a593Smuzhiyun break;
540*4882a593Smuzhiyun default:
541*4882a593Smuzhiyun reg |= SI1145_CHLIST_EN_AUX;
542*4882a593Smuzhiyun if (indio_dev->channels[i].type == IIO_TEMP)
543*4882a593Smuzhiyun mux = SI1145_MUX_TEMP;
544*4882a593Smuzhiyun else
545*4882a593Smuzhiyun mux = SI1145_MUX_VDD;
546*4882a593Smuzhiyun ret = si1145_param_set(data,
547*4882a593Smuzhiyun SI1145_PARAM_AUX_ADC_MUX, mux);
548*4882a593Smuzhiyun if (ret < 0)
549*4882a593Smuzhiyun return ret;
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun break;
552*4882a593Smuzhiyun }
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun }
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun data->scan_mask = scan_mask;
557*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_CHLIST, reg);
558*4882a593Smuzhiyun
559*4882a593Smuzhiyun return ret < 0 ? ret : 0;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun
si1145_measure(struct iio_dev * indio_dev,struct iio_chan_spec const * chan)562*4882a593Smuzhiyun static int si1145_measure(struct iio_dev *indio_dev,
563*4882a593Smuzhiyun struct iio_chan_spec const *chan)
564*4882a593Smuzhiyun {
565*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
566*4882a593Smuzhiyun u8 cmd;
567*4882a593Smuzhiyun int ret;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun ret = si1145_set_chlist(indio_dev, BIT(chan->scan_index));
570*4882a593Smuzhiyun if (ret < 0)
571*4882a593Smuzhiyun return ret;
572*4882a593Smuzhiyun
573*4882a593Smuzhiyun cmd = (chan->type == IIO_PROXIMITY) ? SI1145_CMD_PS_FORCE :
574*4882a593Smuzhiyun SI1145_CMD_ALS_FORCE;
575*4882a593Smuzhiyun ret = si1145_command(data, cmd);
576*4882a593Smuzhiyun if (ret < 0 && ret != -EOVERFLOW)
577*4882a593Smuzhiyun return ret;
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun return i2c_smbus_read_word_data(data->client, chan->address);
580*4882a593Smuzhiyun }
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun /*
583*4882a593Smuzhiyun * Conversion between iio scale and ADC_GAIN values
584*4882a593Smuzhiyun * These could be further adjusted but proximity/intensity are dimensionless
585*4882a593Smuzhiyun */
586*4882a593Smuzhiyun static const int si1145_proximity_scale_available[] = {
587*4882a593Smuzhiyun 128, 64, 32, 16, 8, 4};
588*4882a593Smuzhiyun static const int si1145_intensity_scale_available[] = {
589*4882a593Smuzhiyun 128, 64, 32, 16, 8, 4, 2, 1};
590*4882a593Smuzhiyun static IIO_CONST_ATTR(in_proximity_scale_available,
591*4882a593Smuzhiyun "128 64 32 16 8 4");
592*4882a593Smuzhiyun static IIO_CONST_ATTR(in_intensity_scale_available,
593*4882a593Smuzhiyun "128 64 32 16 8 4 2 1");
594*4882a593Smuzhiyun static IIO_CONST_ATTR(in_intensity_ir_scale_available,
595*4882a593Smuzhiyun "128 64 32 16 8 4 2 1");
596*4882a593Smuzhiyun
si1145_scale_from_adcgain(int regval)597*4882a593Smuzhiyun static int si1145_scale_from_adcgain(int regval)
598*4882a593Smuzhiyun {
599*4882a593Smuzhiyun return 128 >> regval;
600*4882a593Smuzhiyun }
601*4882a593Smuzhiyun
si1145_proximity_adcgain_from_scale(int val,int val2)602*4882a593Smuzhiyun static int si1145_proximity_adcgain_from_scale(int val, int val2)
603*4882a593Smuzhiyun {
604*4882a593Smuzhiyun val = find_closest_descending(val, si1145_proximity_scale_available,
605*4882a593Smuzhiyun ARRAY_SIZE(si1145_proximity_scale_available));
606*4882a593Smuzhiyun if (val < 0 || val > 5 || val2 != 0)
607*4882a593Smuzhiyun return -EINVAL;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun return val;
610*4882a593Smuzhiyun }
611*4882a593Smuzhiyun
si1145_intensity_adcgain_from_scale(int val,int val2)612*4882a593Smuzhiyun static int si1145_intensity_adcgain_from_scale(int val, int val2)
613*4882a593Smuzhiyun {
614*4882a593Smuzhiyun val = find_closest_descending(val, si1145_intensity_scale_available,
615*4882a593Smuzhiyun ARRAY_SIZE(si1145_intensity_scale_available));
616*4882a593Smuzhiyun if (val < 0 || val > 7 || val2 != 0)
617*4882a593Smuzhiyun return -EINVAL;
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun return val;
620*4882a593Smuzhiyun }
621*4882a593Smuzhiyun
si1145_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)622*4882a593Smuzhiyun static int si1145_read_raw(struct iio_dev *indio_dev,
623*4882a593Smuzhiyun struct iio_chan_spec const *chan,
624*4882a593Smuzhiyun int *val, int *val2, long mask)
625*4882a593Smuzhiyun {
626*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
627*4882a593Smuzhiyun int ret;
628*4882a593Smuzhiyun u8 reg;
629*4882a593Smuzhiyun
630*4882a593Smuzhiyun switch (mask) {
631*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
632*4882a593Smuzhiyun switch (chan->type) {
633*4882a593Smuzhiyun case IIO_INTENSITY:
634*4882a593Smuzhiyun case IIO_PROXIMITY:
635*4882a593Smuzhiyun case IIO_VOLTAGE:
636*4882a593Smuzhiyun case IIO_TEMP:
637*4882a593Smuzhiyun case IIO_UVINDEX:
638*4882a593Smuzhiyun ret = iio_device_claim_direct_mode(indio_dev);
639*4882a593Smuzhiyun if (ret)
640*4882a593Smuzhiyun return ret;
641*4882a593Smuzhiyun ret = si1145_measure(indio_dev, chan);
642*4882a593Smuzhiyun iio_device_release_direct_mode(indio_dev);
643*4882a593Smuzhiyun
644*4882a593Smuzhiyun if (ret < 0)
645*4882a593Smuzhiyun return ret;
646*4882a593Smuzhiyun
647*4882a593Smuzhiyun *val = ret;
648*4882a593Smuzhiyun
649*4882a593Smuzhiyun return IIO_VAL_INT;
650*4882a593Smuzhiyun case IIO_CURRENT:
651*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(data->client,
652*4882a593Smuzhiyun SI1145_PS_LED_REG(chan->channel));
653*4882a593Smuzhiyun if (ret < 0)
654*4882a593Smuzhiyun return ret;
655*4882a593Smuzhiyun
656*4882a593Smuzhiyun *val = (ret >> SI1145_PS_LED_SHIFT(chan->channel))
657*4882a593Smuzhiyun & 0x0f;
658*4882a593Smuzhiyun
659*4882a593Smuzhiyun return IIO_VAL_INT;
660*4882a593Smuzhiyun default:
661*4882a593Smuzhiyun return -EINVAL;
662*4882a593Smuzhiyun }
663*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
664*4882a593Smuzhiyun switch (chan->type) {
665*4882a593Smuzhiyun case IIO_PROXIMITY:
666*4882a593Smuzhiyun reg = SI1145_PARAM_PS_ADC_GAIN;
667*4882a593Smuzhiyun break;
668*4882a593Smuzhiyun case IIO_INTENSITY:
669*4882a593Smuzhiyun if (chan->channel2 == IIO_MOD_LIGHT_IR)
670*4882a593Smuzhiyun reg = SI1145_PARAM_ALSIR_ADC_GAIN;
671*4882a593Smuzhiyun else
672*4882a593Smuzhiyun reg = SI1145_PARAM_ALSVIS_ADC_GAIN;
673*4882a593Smuzhiyun break;
674*4882a593Smuzhiyun case IIO_TEMP:
675*4882a593Smuzhiyun *val = 28;
676*4882a593Smuzhiyun *val2 = 571429;
677*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
678*4882a593Smuzhiyun case IIO_UVINDEX:
679*4882a593Smuzhiyun *val = 0;
680*4882a593Smuzhiyun *val2 = 10000;
681*4882a593Smuzhiyun return IIO_VAL_INT_PLUS_MICRO;
682*4882a593Smuzhiyun default:
683*4882a593Smuzhiyun return -EINVAL;
684*4882a593Smuzhiyun }
685*4882a593Smuzhiyun
686*4882a593Smuzhiyun ret = si1145_param_query(data, reg);
687*4882a593Smuzhiyun if (ret < 0)
688*4882a593Smuzhiyun return ret;
689*4882a593Smuzhiyun
690*4882a593Smuzhiyun *val = si1145_scale_from_adcgain(ret & 0x07);
691*4882a593Smuzhiyun
692*4882a593Smuzhiyun return IIO_VAL_INT;
693*4882a593Smuzhiyun case IIO_CHAN_INFO_OFFSET:
694*4882a593Smuzhiyun switch (chan->type) {
695*4882a593Smuzhiyun case IIO_TEMP:
696*4882a593Smuzhiyun /*
697*4882a593Smuzhiyun * -ADC offset - ADC counts @ 25°C -
698*4882a593Smuzhiyun * 35 * ADC counts / °C
699*4882a593Smuzhiyun */
700*4882a593Smuzhiyun *val = -256 - 11136 + 25 * 35;
701*4882a593Smuzhiyun return IIO_VAL_INT;
702*4882a593Smuzhiyun default:
703*4882a593Smuzhiyun /*
704*4882a593Smuzhiyun * All ADC measurements have are by default offset
705*4882a593Smuzhiyun * by -256
706*4882a593Smuzhiyun * See AN498 5.6.3
707*4882a593Smuzhiyun */
708*4882a593Smuzhiyun ret = si1145_param_query(data, SI1145_PARAM_ADC_OFFSET);
709*4882a593Smuzhiyun if (ret < 0)
710*4882a593Smuzhiyun return ret;
711*4882a593Smuzhiyun *val = -si1145_uncompress(ret);
712*4882a593Smuzhiyun return IIO_VAL_INT;
713*4882a593Smuzhiyun }
714*4882a593Smuzhiyun case IIO_CHAN_INFO_SAMP_FREQ:
715*4882a593Smuzhiyun return si1145_read_samp_freq(data, val, val2);
716*4882a593Smuzhiyun default:
717*4882a593Smuzhiyun return -EINVAL;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun }
720*4882a593Smuzhiyun
si1145_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)721*4882a593Smuzhiyun static int si1145_write_raw(struct iio_dev *indio_dev,
722*4882a593Smuzhiyun struct iio_chan_spec const *chan,
723*4882a593Smuzhiyun int val, int val2, long mask)
724*4882a593Smuzhiyun {
725*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
726*4882a593Smuzhiyun u8 reg1, reg2, shift;
727*4882a593Smuzhiyun int ret;
728*4882a593Smuzhiyun
729*4882a593Smuzhiyun switch (mask) {
730*4882a593Smuzhiyun case IIO_CHAN_INFO_SCALE:
731*4882a593Smuzhiyun switch (chan->type) {
732*4882a593Smuzhiyun case IIO_PROXIMITY:
733*4882a593Smuzhiyun val = si1145_proximity_adcgain_from_scale(val, val2);
734*4882a593Smuzhiyun if (val < 0)
735*4882a593Smuzhiyun return val;
736*4882a593Smuzhiyun reg1 = SI1145_PARAM_PS_ADC_GAIN;
737*4882a593Smuzhiyun reg2 = SI1145_PARAM_PS_ADC_COUNTER;
738*4882a593Smuzhiyun break;
739*4882a593Smuzhiyun case IIO_INTENSITY:
740*4882a593Smuzhiyun val = si1145_intensity_adcgain_from_scale(val, val2);
741*4882a593Smuzhiyun if (val < 0)
742*4882a593Smuzhiyun return val;
743*4882a593Smuzhiyun if (chan->channel2 == IIO_MOD_LIGHT_IR) {
744*4882a593Smuzhiyun reg1 = SI1145_PARAM_ALSIR_ADC_GAIN;
745*4882a593Smuzhiyun reg2 = SI1145_PARAM_ALSIR_ADC_COUNTER;
746*4882a593Smuzhiyun } else {
747*4882a593Smuzhiyun reg1 = SI1145_PARAM_ALSVIS_ADC_GAIN;
748*4882a593Smuzhiyun reg2 = SI1145_PARAM_ALSVIS_ADC_COUNTER;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun break;
751*4882a593Smuzhiyun default:
752*4882a593Smuzhiyun return -EINVAL;
753*4882a593Smuzhiyun }
754*4882a593Smuzhiyun
755*4882a593Smuzhiyun ret = iio_device_claim_direct_mode(indio_dev);
756*4882a593Smuzhiyun if (ret)
757*4882a593Smuzhiyun return ret;
758*4882a593Smuzhiyun
759*4882a593Smuzhiyun ret = si1145_param_set(data, reg1, val);
760*4882a593Smuzhiyun if (ret < 0) {
761*4882a593Smuzhiyun iio_device_release_direct_mode(indio_dev);
762*4882a593Smuzhiyun return ret;
763*4882a593Smuzhiyun }
764*4882a593Smuzhiyun /* Set recovery period to one's complement of gain */
765*4882a593Smuzhiyun ret = si1145_param_set(data, reg2, (~val & 0x07) << 4);
766*4882a593Smuzhiyun iio_device_release_direct_mode(indio_dev);
767*4882a593Smuzhiyun return ret;
768*4882a593Smuzhiyun case IIO_CHAN_INFO_RAW:
769*4882a593Smuzhiyun if (chan->type != IIO_CURRENT)
770*4882a593Smuzhiyun return -EINVAL;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun if (val < 0 || val > 15 || val2 != 0)
773*4882a593Smuzhiyun return -EINVAL;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun reg1 = SI1145_PS_LED_REG(chan->channel);
776*4882a593Smuzhiyun shift = SI1145_PS_LED_SHIFT(chan->channel);
777*4882a593Smuzhiyun
778*4882a593Smuzhiyun ret = iio_device_claim_direct_mode(indio_dev);
779*4882a593Smuzhiyun if (ret)
780*4882a593Smuzhiyun return ret;
781*4882a593Smuzhiyun
782*4882a593Smuzhiyun ret = i2c_smbus_read_byte_data(data->client, reg1);
783*4882a593Smuzhiyun if (ret < 0) {
784*4882a593Smuzhiyun iio_device_release_direct_mode(indio_dev);
785*4882a593Smuzhiyun return ret;
786*4882a593Smuzhiyun }
787*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client, reg1,
788*4882a593Smuzhiyun (ret & ~(0x0f << shift)) |
789*4882a593Smuzhiyun ((val & 0x0f) << shift));
790*4882a593Smuzhiyun iio_device_release_direct_mode(indio_dev);
791*4882a593Smuzhiyun return ret;
792*4882a593Smuzhiyun case IIO_CHAN_INFO_SAMP_FREQ:
793*4882a593Smuzhiyun return si1145_store_samp_freq(data, val);
794*4882a593Smuzhiyun default:
795*4882a593Smuzhiyun return -EINVAL;
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun
799*4882a593Smuzhiyun #define SI1145_ST { \
800*4882a593Smuzhiyun .sign = 'u', \
801*4882a593Smuzhiyun .realbits = 16, \
802*4882a593Smuzhiyun .storagebits = 16, \
803*4882a593Smuzhiyun .endianness = IIO_LE, \
804*4882a593Smuzhiyun }
805*4882a593Smuzhiyun
806*4882a593Smuzhiyun #define SI1145_INTENSITY_CHANNEL(_si) { \
807*4882a593Smuzhiyun .type = IIO_INTENSITY, \
808*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
809*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET) | \
810*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE), \
811*4882a593Smuzhiyun .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
812*4882a593Smuzhiyun .scan_type = SI1145_ST, \
813*4882a593Smuzhiyun .scan_index = _si, \
814*4882a593Smuzhiyun .address = SI1145_REG_ALSVIS_DATA, \
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun
817*4882a593Smuzhiyun #define SI1145_INTENSITY_IR_CHANNEL(_si) { \
818*4882a593Smuzhiyun .type = IIO_INTENSITY, \
819*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
820*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET) | \
821*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE), \
822*4882a593Smuzhiyun .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
823*4882a593Smuzhiyun .modified = 1, \
824*4882a593Smuzhiyun .channel2 = IIO_MOD_LIGHT_IR, \
825*4882a593Smuzhiyun .scan_type = SI1145_ST, \
826*4882a593Smuzhiyun .scan_index = _si, \
827*4882a593Smuzhiyun .address = SI1145_REG_ALSIR_DATA, \
828*4882a593Smuzhiyun }
829*4882a593Smuzhiyun
830*4882a593Smuzhiyun #define SI1145_TEMP_CHANNEL(_si) { \
831*4882a593Smuzhiyun .type = IIO_TEMP, \
832*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
833*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET) | \
834*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE), \
835*4882a593Smuzhiyun .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
836*4882a593Smuzhiyun .scan_type = SI1145_ST, \
837*4882a593Smuzhiyun .scan_index = _si, \
838*4882a593Smuzhiyun .address = SI1145_REG_AUX_DATA, \
839*4882a593Smuzhiyun }
840*4882a593Smuzhiyun
841*4882a593Smuzhiyun #define SI1145_UV_CHANNEL(_si) { \
842*4882a593Smuzhiyun .type = IIO_UVINDEX, \
843*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
844*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_SCALE), \
845*4882a593Smuzhiyun .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
846*4882a593Smuzhiyun .scan_type = SI1145_ST, \
847*4882a593Smuzhiyun .scan_index = _si, \
848*4882a593Smuzhiyun .address = SI1145_REG_AUX_DATA, \
849*4882a593Smuzhiyun }
850*4882a593Smuzhiyun
851*4882a593Smuzhiyun #define SI1145_PROXIMITY_CHANNEL(_si, _ch) { \
852*4882a593Smuzhiyun .type = IIO_PROXIMITY, \
853*4882a593Smuzhiyun .indexed = 1, \
854*4882a593Smuzhiyun .channel = _ch, \
855*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
856*4882a593Smuzhiyun .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
857*4882a593Smuzhiyun BIT(IIO_CHAN_INFO_OFFSET), \
858*4882a593Smuzhiyun .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
859*4882a593Smuzhiyun .scan_type = SI1145_ST, \
860*4882a593Smuzhiyun .scan_index = _si, \
861*4882a593Smuzhiyun .address = SI1145_REG_PS1_DATA + _ch * 2, \
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun #define SI1145_VOLTAGE_CHANNEL(_si) { \
865*4882a593Smuzhiyun .type = IIO_VOLTAGE, \
866*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
867*4882a593Smuzhiyun .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
868*4882a593Smuzhiyun .scan_type = SI1145_ST, \
869*4882a593Smuzhiyun .scan_index = _si, \
870*4882a593Smuzhiyun .address = SI1145_REG_AUX_DATA, \
871*4882a593Smuzhiyun }
872*4882a593Smuzhiyun
873*4882a593Smuzhiyun #define SI1145_CURRENT_CHANNEL(_ch) { \
874*4882a593Smuzhiyun .type = IIO_CURRENT, \
875*4882a593Smuzhiyun .indexed = 1, \
876*4882a593Smuzhiyun .channel = _ch, \
877*4882a593Smuzhiyun .output = 1, \
878*4882a593Smuzhiyun .scan_index = -1, \
879*4882a593Smuzhiyun .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
880*4882a593Smuzhiyun }
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun static const struct iio_chan_spec si1132_channels[] = {
883*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
884*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
885*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(2),
886*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(3),
887*4882a593Smuzhiyun SI1145_UV_CHANNEL(4),
888*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(6),
889*4882a593Smuzhiyun };
890*4882a593Smuzhiyun
891*4882a593Smuzhiyun static const struct iio_chan_spec si1141_channels[] = {
892*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
893*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
894*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(2, 0),
895*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(3),
896*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(4),
897*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(5),
898*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(0),
899*4882a593Smuzhiyun };
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun static const struct iio_chan_spec si1142_channels[] = {
902*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
903*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
904*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(2, 0),
905*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(3, 1),
906*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(4),
907*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(5),
908*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(6),
909*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(0),
910*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(1),
911*4882a593Smuzhiyun };
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun static const struct iio_chan_spec si1143_channels[] = {
914*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
915*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
916*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(2, 0),
917*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(3, 1),
918*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(4, 2),
919*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(5),
920*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(6),
921*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(7),
922*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(0),
923*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(1),
924*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(2),
925*4882a593Smuzhiyun };
926*4882a593Smuzhiyun
927*4882a593Smuzhiyun static const struct iio_chan_spec si1145_channels[] = {
928*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
929*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
930*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(2, 0),
931*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(3),
932*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(4),
933*4882a593Smuzhiyun SI1145_UV_CHANNEL(5),
934*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(6),
935*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(0),
936*4882a593Smuzhiyun };
937*4882a593Smuzhiyun
938*4882a593Smuzhiyun static const struct iio_chan_spec si1146_channels[] = {
939*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
940*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
941*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(2),
942*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(3),
943*4882a593Smuzhiyun SI1145_UV_CHANNEL(4),
944*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(5, 0),
945*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(6, 1),
946*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(7),
947*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(0),
948*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(1),
949*4882a593Smuzhiyun };
950*4882a593Smuzhiyun
951*4882a593Smuzhiyun static const struct iio_chan_spec si1147_channels[] = {
952*4882a593Smuzhiyun SI1145_INTENSITY_CHANNEL(0),
953*4882a593Smuzhiyun SI1145_INTENSITY_IR_CHANNEL(1),
954*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(2, 0),
955*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(3, 1),
956*4882a593Smuzhiyun SI1145_PROXIMITY_CHANNEL(4, 2),
957*4882a593Smuzhiyun SI1145_TEMP_CHANNEL(5),
958*4882a593Smuzhiyun SI1145_VOLTAGE_CHANNEL(6),
959*4882a593Smuzhiyun SI1145_UV_CHANNEL(7),
960*4882a593Smuzhiyun IIO_CHAN_SOFT_TIMESTAMP(8),
961*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(0),
962*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(1),
963*4882a593Smuzhiyun SI1145_CURRENT_CHANNEL(2),
964*4882a593Smuzhiyun };
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun static struct attribute *si1132_attributes[] = {
967*4882a593Smuzhiyun &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
968*4882a593Smuzhiyun &iio_const_attr_in_intensity_ir_scale_available.dev_attr.attr,
969*4882a593Smuzhiyun NULL,
970*4882a593Smuzhiyun };
971*4882a593Smuzhiyun
972*4882a593Smuzhiyun static struct attribute *si114x_attributes[] = {
973*4882a593Smuzhiyun &iio_const_attr_in_intensity_scale_available.dev_attr.attr,
974*4882a593Smuzhiyun &iio_const_attr_in_intensity_ir_scale_available.dev_attr.attr,
975*4882a593Smuzhiyun &iio_const_attr_in_proximity_scale_available.dev_attr.attr,
976*4882a593Smuzhiyun NULL,
977*4882a593Smuzhiyun };
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun static const struct attribute_group si1132_attribute_group = {
980*4882a593Smuzhiyun .attrs = si1132_attributes,
981*4882a593Smuzhiyun };
982*4882a593Smuzhiyun
983*4882a593Smuzhiyun static const struct attribute_group si114x_attribute_group = {
984*4882a593Smuzhiyun .attrs = si114x_attributes,
985*4882a593Smuzhiyun };
986*4882a593Smuzhiyun
987*4882a593Smuzhiyun
988*4882a593Smuzhiyun static const struct iio_info si1132_info = {
989*4882a593Smuzhiyun .read_raw = si1145_read_raw,
990*4882a593Smuzhiyun .write_raw = si1145_write_raw,
991*4882a593Smuzhiyun .attrs = &si1132_attribute_group,
992*4882a593Smuzhiyun };
993*4882a593Smuzhiyun
994*4882a593Smuzhiyun static const struct iio_info si114x_info = {
995*4882a593Smuzhiyun .read_raw = si1145_read_raw,
996*4882a593Smuzhiyun .write_raw = si1145_write_raw,
997*4882a593Smuzhiyun .attrs = &si114x_attribute_group,
998*4882a593Smuzhiyun };
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun #define SI1145_PART(id, iio_info, chans, leds, uncompressed_meas_rate) \
1001*4882a593Smuzhiyun {id, iio_info, chans, ARRAY_SIZE(chans), leds, uncompressed_meas_rate}
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun static const struct si1145_part_info si1145_part_info[] = {
1004*4882a593Smuzhiyun [SI1132] = SI1145_PART(0x32, &si1132_info, si1132_channels, 0, true),
1005*4882a593Smuzhiyun [SI1141] = SI1145_PART(0x41, &si114x_info, si1141_channels, 1, false),
1006*4882a593Smuzhiyun [SI1142] = SI1145_PART(0x42, &si114x_info, si1142_channels, 2, false),
1007*4882a593Smuzhiyun [SI1143] = SI1145_PART(0x43, &si114x_info, si1143_channels, 3, false),
1008*4882a593Smuzhiyun [SI1145] = SI1145_PART(0x45, &si114x_info, si1145_channels, 1, true),
1009*4882a593Smuzhiyun [SI1146] = SI1145_PART(0x46, &si114x_info, si1146_channels, 2, true),
1010*4882a593Smuzhiyun [SI1147] = SI1145_PART(0x47, &si114x_info, si1147_channels, 3, true),
1011*4882a593Smuzhiyun };
1012*4882a593Smuzhiyun
si1145_initialize(struct si1145_data * data)1013*4882a593Smuzhiyun static int si1145_initialize(struct si1145_data *data)
1014*4882a593Smuzhiyun {
1015*4882a593Smuzhiyun struct i2c_client *client = data->client;
1016*4882a593Smuzhiyun int ret;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(client, SI1145_REG_COMMAND,
1019*4882a593Smuzhiyun SI1145_CMD_RESET);
1020*4882a593Smuzhiyun if (ret < 0)
1021*4882a593Smuzhiyun return ret;
1022*4882a593Smuzhiyun msleep(SI1145_COMMAND_TIMEOUT_MS);
1023*4882a593Smuzhiyun
1024*4882a593Smuzhiyun /* Hardware key, magic value */
1025*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(client, SI1145_REG_HW_KEY, 0x17);
1026*4882a593Smuzhiyun if (ret < 0)
1027*4882a593Smuzhiyun return ret;
1028*4882a593Smuzhiyun msleep(SI1145_COMMAND_TIMEOUT_MS);
1029*4882a593Smuzhiyun
1030*4882a593Smuzhiyun /* Turn off autonomous mode */
1031*4882a593Smuzhiyun ret = si1145_set_meas_rate(data, 0);
1032*4882a593Smuzhiyun if (ret < 0)
1033*4882a593Smuzhiyun return ret;
1034*4882a593Smuzhiyun
1035*4882a593Smuzhiyun /* Initialize sampling freq to 10 Hz */
1036*4882a593Smuzhiyun ret = si1145_store_samp_freq(data, 10);
1037*4882a593Smuzhiyun if (ret < 0)
1038*4882a593Smuzhiyun return ret;
1039*4882a593Smuzhiyun
1040*4882a593Smuzhiyun /* Set LED currents to 45 mA; have 4 bits, see Table 2 in datasheet */
1041*4882a593Smuzhiyun switch (data->part_info->num_leds) {
1042*4882a593Smuzhiyun case 3:
1043*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(client,
1044*4882a593Smuzhiyun SI1145_REG_PS_LED3,
1045*4882a593Smuzhiyun SI1145_LED_CURRENT_45mA);
1046*4882a593Smuzhiyun if (ret < 0)
1047*4882a593Smuzhiyun return ret;
1048*4882a593Smuzhiyun fallthrough;
1049*4882a593Smuzhiyun case 2:
1050*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(client,
1051*4882a593Smuzhiyun SI1145_REG_PS_LED21,
1052*4882a593Smuzhiyun (SI1145_LED_CURRENT_45mA << 4) |
1053*4882a593Smuzhiyun SI1145_LED_CURRENT_45mA);
1054*4882a593Smuzhiyun break;
1055*4882a593Smuzhiyun case 1:
1056*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(client,
1057*4882a593Smuzhiyun SI1145_REG_PS_LED21,
1058*4882a593Smuzhiyun SI1145_LED_CURRENT_45mA);
1059*4882a593Smuzhiyun break;
1060*4882a593Smuzhiyun default:
1061*4882a593Smuzhiyun ret = 0;
1062*4882a593Smuzhiyun break;
1063*4882a593Smuzhiyun }
1064*4882a593Smuzhiyun if (ret < 0)
1065*4882a593Smuzhiyun return ret;
1066*4882a593Smuzhiyun
1067*4882a593Smuzhiyun /* Set normal proximity measurement mode */
1068*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_PS_ADC_MISC,
1069*4882a593Smuzhiyun SI1145_PS_ADC_MODE_NORMAL);
1070*4882a593Smuzhiyun if (ret < 0)
1071*4882a593Smuzhiyun return ret;
1072*4882a593Smuzhiyun
1073*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_PS_ADC_GAIN, 0x01);
1074*4882a593Smuzhiyun if (ret < 0)
1075*4882a593Smuzhiyun return ret;
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun /* ADC_COUNTER should be one complement of ADC_GAIN */
1078*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_PS_ADC_COUNTER, 0x06 << 4);
1079*4882a593Smuzhiyun if (ret < 0)
1080*4882a593Smuzhiyun return ret;
1081*4882a593Smuzhiyun
1082*4882a593Smuzhiyun /* Set ALS visible measurement mode */
1083*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_ALSVIS_ADC_MISC,
1084*4882a593Smuzhiyun SI1145_ADC_MISC_RANGE);
1085*4882a593Smuzhiyun if (ret < 0)
1086*4882a593Smuzhiyun return ret;
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_ALSVIS_ADC_GAIN, 0x03);
1089*4882a593Smuzhiyun if (ret < 0)
1090*4882a593Smuzhiyun return ret;
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_ALSVIS_ADC_COUNTER,
1093*4882a593Smuzhiyun 0x04 << 4);
1094*4882a593Smuzhiyun if (ret < 0)
1095*4882a593Smuzhiyun return ret;
1096*4882a593Smuzhiyun
1097*4882a593Smuzhiyun /* Set ALS IR measurement mode */
1098*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_ALSIR_ADC_MISC,
1099*4882a593Smuzhiyun SI1145_ADC_MISC_RANGE);
1100*4882a593Smuzhiyun if (ret < 0)
1101*4882a593Smuzhiyun return ret;
1102*4882a593Smuzhiyun
1103*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_ALSIR_ADC_GAIN, 0x01);
1104*4882a593Smuzhiyun if (ret < 0)
1105*4882a593Smuzhiyun return ret;
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun ret = si1145_param_set(data, SI1145_PARAM_ALSIR_ADC_COUNTER,
1108*4882a593Smuzhiyun 0x06 << 4);
1109*4882a593Smuzhiyun if (ret < 0)
1110*4882a593Smuzhiyun return ret;
1111*4882a593Smuzhiyun
1112*4882a593Smuzhiyun /*
1113*4882a593Smuzhiyun * Initialize UCOEF to default values in datasheet
1114*4882a593Smuzhiyun * These registers are normally zero on reset
1115*4882a593Smuzhiyun */
1116*4882a593Smuzhiyun if (data->part_info == &si1145_part_info[SI1132] ||
1117*4882a593Smuzhiyun data->part_info == &si1145_part_info[SI1145] ||
1118*4882a593Smuzhiyun data->part_info == &si1145_part_info[SI1146] ||
1119*4882a593Smuzhiyun data->part_info == &si1145_part_info[SI1147]) {
1120*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
1121*4882a593Smuzhiyun SI1145_REG_UCOEF1,
1122*4882a593Smuzhiyun SI1145_UCOEF1_DEFAULT);
1123*4882a593Smuzhiyun if (ret < 0)
1124*4882a593Smuzhiyun return ret;
1125*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
1126*4882a593Smuzhiyun SI1145_REG_UCOEF2, SI1145_UCOEF2_DEFAULT);
1127*4882a593Smuzhiyun if (ret < 0)
1128*4882a593Smuzhiyun return ret;
1129*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
1130*4882a593Smuzhiyun SI1145_REG_UCOEF3, SI1145_UCOEF3_DEFAULT);
1131*4882a593Smuzhiyun if (ret < 0)
1132*4882a593Smuzhiyun return ret;
1133*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
1134*4882a593Smuzhiyun SI1145_REG_UCOEF4, SI1145_UCOEF4_DEFAULT);
1135*4882a593Smuzhiyun if (ret < 0)
1136*4882a593Smuzhiyun return ret;
1137*4882a593Smuzhiyun }
1138*4882a593Smuzhiyun
1139*4882a593Smuzhiyun return 0;
1140*4882a593Smuzhiyun }
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun /*
1143*4882a593Smuzhiyun * Program the channels we want to measure with CMD_PSALS_AUTO. No need for
1144*4882a593Smuzhiyun * _postdisable as we stop with CMD_PSALS_PAUSE; single measurement (direct)
1145*4882a593Smuzhiyun * mode reprograms the channels list anyway...
1146*4882a593Smuzhiyun */
si1145_buffer_preenable(struct iio_dev * indio_dev)1147*4882a593Smuzhiyun static int si1145_buffer_preenable(struct iio_dev *indio_dev)
1148*4882a593Smuzhiyun {
1149*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
1150*4882a593Smuzhiyun int ret;
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun mutex_lock(&data->lock);
1153*4882a593Smuzhiyun ret = si1145_set_chlist(indio_dev, *indio_dev->active_scan_mask);
1154*4882a593Smuzhiyun mutex_unlock(&data->lock);
1155*4882a593Smuzhiyun
1156*4882a593Smuzhiyun return ret;
1157*4882a593Smuzhiyun }
1158*4882a593Smuzhiyun
si1145_validate_scan_mask(struct iio_dev * indio_dev,const unsigned long * scan_mask)1159*4882a593Smuzhiyun static bool si1145_validate_scan_mask(struct iio_dev *indio_dev,
1160*4882a593Smuzhiyun const unsigned long *scan_mask)
1161*4882a593Smuzhiyun {
1162*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
1163*4882a593Smuzhiyun unsigned int count = 0;
1164*4882a593Smuzhiyun int i;
1165*4882a593Smuzhiyun
1166*4882a593Smuzhiyun /* Check that at most one AUX channel is enabled */
1167*4882a593Smuzhiyun for_each_set_bit(i, scan_mask, data->part_info->num_channels) {
1168*4882a593Smuzhiyun if (indio_dev->channels[i].address == SI1145_REG_AUX_DATA)
1169*4882a593Smuzhiyun count++;
1170*4882a593Smuzhiyun }
1171*4882a593Smuzhiyun
1172*4882a593Smuzhiyun return count <= 1;
1173*4882a593Smuzhiyun }
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun static const struct iio_buffer_setup_ops si1145_buffer_setup_ops = {
1176*4882a593Smuzhiyun .preenable = si1145_buffer_preenable,
1177*4882a593Smuzhiyun .validate_scan_mask = si1145_validate_scan_mask,
1178*4882a593Smuzhiyun };
1179*4882a593Smuzhiyun
1180*4882a593Smuzhiyun /*
1181*4882a593Smuzhiyun * si1145_trigger_set_state() - Set trigger state
1182*4882a593Smuzhiyun *
1183*4882a593Smuzhiyun * When not using triggers interrupts are disabled and measurement rate is
1184*4882a593Smuzhiyun * set to zero in order to minimize power consumption.
1185*4882a593Smuzhiyun */
si1145_trigger_set_state(struct iio_trigger * trig,bool state)1186*4882a593Smuzhiyun static int si1145_trigger_set_state(struct iio_trigger *trig, bool state)
1187*4882a593Smuzhiyun {
1188*4882a593Smuzhiyun struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
1189*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
1190*4882a593Smuzhiyun int err = 0, ret;
1191*4882a593Smuzhiyun
1192*4882a593Smuzhiyun mutex_lock(&data->lock);
1193*4882a593Smuzhiyun
1194*4882a593Smuzhiyun if (state) {
1195*4882a593Smuzhiyun data->autonomous = true;
1196*4882a593Smuzhiyun err = i2c_smbus_write_byte_data(data->client,
1197*4882a593Smuzhiyun SI1145_REG_INT_CFG, SI1145_INT_CFG_OE);
1198*4882a593Smuzhiyun if (err < 0)
1199*4882a593Smuzhiyun goto disable;
1200*4882a593Smuzhiyun err = i2c_smbus_write_byte_data(data->client,
1201*4882a593Smuzhiyun SI1145_REG_IRQ_ENABLE, SI1145_MASK_ALL_IE);
1202*4882a593Smuzhiyun if (err < 0)
1203*4882a593Smuzhiyun goto disable;
1204*4882a593Smuzhiyun err = si1145_set_meas_rate(data, data->meas_rate);
1205*4882a593Smuzhiyun if (err < 0)
1206*4882a593Smuzhiyun goto disable;
1207*4882a593Smuzhiyun err = si1145_command(data, SI1145_CMD_PSALS_AUTO);
1208*4882a593Smuzhiyun if (err < 0)
1209*4882a593Smuzhiyun goto disable;
1210*4882a593Smuzhiyun } else {
1211*4882a593Smuzhiyun disable:
1212*4882a593Smuzhiyun /* Disable as much as possible skipping errors */
1213*4882a593Smuzhiyun ret = si1145_command(data, SI1145_CMD_PSALS_PAUSE);
1214*4882a593Smuzhiyun if (ret < 0 && !err)
1215*4882a593Smuzhiyun err = ret;
1216*4882a593Smuzhiyun ret = si1145_set_meas_rate(data, 0);
1217*4882a593Smuzhiyun if (ret < 0 && !err)
1218*4882a593Smuzhiyun err = ret;
1219*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
1220*4882a593Smuzhiyun SI1145_REG_IRQ_ENABLE, 0);
1221*4882a593Smuzhiyun if (ret < 0 && !err)
1222*4882a593Smuzhiyun err = ret;
1223*4882a593Smuzhiyun ret = i2c_smbus_write_byte_data(data->client,
1224*4882a593Smuzhiyun SI1145_REG_INT_CFG, 0);
1225*4882a593Smuzhiyun if (ret < 0 && !err)
1226*4882a593Smuzhiyun err = ret;
1227*4882a593Smuzhiyun data->autonomous = false;
1228*4882a593Smuzhiyun }
1229*4882a593Smuzhiyun
1230*4882a593Smuzhiyun mutex_unlock(&data->lock);
1231*4882a593Smuzhiyun return err;
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun
1234*4882a593Smuzhiyun static const struct iio_trigger_ops si1145_trigger_ops = {
1235*4882a593Smuzhiyun .set_trigger_state = si1145_trigger_set_state,
1236*4882a593Smuzhiyun };
1237*4882a593Smuzhiyun
si1145_probe_trigger(struct iio_dev * indio_dev)1238*4882a593Smuzhiyun static int si1145_probe_trigger(struct iio_dev *indio_dev)
1239*4882a593Smuzhiyun {
1240*4882a593Smuzhiyun struct si1145_data *data = iio_priv(indio_dev);
1241*4882a593Smuzhiyun struct i2c_client *client = data->client;
1242*4882a593Smuzhiyun struct iio_trigger *trig;
1243*4882a593Smuzhiyun int ret;
1244*4882a593Smuzhiyun
1245*4882a593Smuzhiyun trig = devm_iio_trigger_alloc(&client->dev,
1246*4882a593Smuzhiyun "%s-dev%d", indio_dev->name, indio_dev->id);
1247*4882a593Smuzhiyun if (!trig)
1248*4882a593Smuzhiyun return -ENOMEM;
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun trig->dev.parent = &client->dev;
1251*4882a593Smuzhiyun trig->ops = &si1145_trigger_ops;
1252*4882a593Smuzhiyun iio_trigger_set_drvdata(trig, indio_dev);
1253*4882a593Smuzhiyun
1254*4882a593Smuzhiyun ret = devm_request_irq(&client->dev, client->irq,
1255*4882a593Smuzhiyun iio_trigger_generic_data_rdy_poll,
1256*4882a593Smuzhiyun IRQF_TRIGGER_FALLING,
1257*4882a593Smuzhiyun "si1145_irq",
1258*4882a593Smuzhiyun trig);
1259*4882a593Smuzhiyun if (ret < 0) {
1260*4882a593Smuzhiyun dev_err(&client->dev, "irq request failed\n");
1261*4882a593Smuzhiyun return ret;
1262*4882a593Smuzhiyun }
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun ret = devm_iio_trigger_register(&client->dev, trig);
1265*4882a593Smuzhiyun if (ret)
1266*4882a593Smuzhiyun return ret;
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun data->trig = trig;
1269*4882a593Smuzhiyun indio_dev->trig = iio_trigger_get(data->trig);
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun return 0;
1272*4882a593Smuzhiyun }
1273*4882a593Smuzhiyun
si1145_probe(struct i2c_client * client,const struct i2c_device_id * id)1274*4882a593Smuzhiyun static int si1145_probe(struct i2c_client *client,
1275*4882a593Smuzhiyun const struct i2c_device_id *id)
1276*4882a593Smuzhiyun {
1277*4882a593Smuzhiyun struct si1145_data *data;
1278*4882a593Smuzhiyun struct iio_dev *indio_dev;
1279*4882a593Smuzhiyun u8 part_id, rev_id, seq_id;
1280*4882a593Smuzhiyun int ret;
1281*4882a593Smuzhiyun
1282*4882a593Smuzhiyun indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
1283*4882a593Smuzhiyun if (!indio_dev)
1284*4882a593Smuzhiyun return -ENOMEM;
1285*4882a593Smuzhiyun
1286*4882a593Smuzhiyun data = iio_priv(indio_dev);
1287*4882a593Smuzhiyun i2c_set_clientdata(client, indio_dev);
1288*4882a593Smuzhiyun data->client = client;
1289*4882a593Smuzhiyun data->part_info = &si1145_part_info[id->driver_data];
1290*4882a593Smuzhiyun
1291*4882a593Smuzhiyun part_id = ret = i2c_smbus_read_byte_data(data->client,
1292*4882a593Smuzhiyun SI1145_REG_PART_ID);
1293*4882a593Smuzhiyun if (ret < 0)
1294*4882a593Smuzhiyun return ret;
1295*4882a593Smuzhiyun rev_id = ret = i2c_smbus_read_byte_data(data->client,
1296*4882a593Smuzhiyun SI1145_REG_REV_ID);
1297*4882a593Smuzhiyun if (ret < 0)
1298*4882a593Smuzhiyun return ret;
1299*4882a593Smuzhiyun seq_id = ret = i2c_smbus_read_byte_data(data->client,
1300*4882a593Smuzhiyun SI1145_REG_SEQ_ID);
1301*4882a593Smuzhiyun if (ret < 0)
1302*4882a593Smuzhiyun return ret;
1303*4882a593Smuzhiyun dev_info(&client->dev, "device ID part %#02hhx rev %#02hhx seq %#02hhx\n",
1304*4882a593Smuzhiyun part_id, rev_id, seq_id);
1305*4882a593Smuzhiyun if (part_id != data->part_info->part) {
1306*4882a593Smuzhiyun dev_err(&client->dev, "part ID mismatch got %#02hhx, expected %#02x\n",
1307*4882a593Smuzhiyun part_id, data->part_info->part);
1308*4882a593Smuzhiyun return -ENODEV;
1309*4882a593Smuzhiyun }
1310*4882a593Smuzhiyun
1311*4882a593Smuzhiyun indio_dev->name = id->name;
1312*4882a593Smuzhiyun indio_dev->channels = data->part_info->channels;
1313*4882a593Smuzhiyun indio_dev->num_channels = data->part_info->num_channels;
1314*4882a593Smuzhiyun indio_dev->info = data->part_info->iio_info;
1315*4882a593Smuzhiyun indio_dev->modes = INDIO_DIRECT_MODE;
1316*4882a593Smuzhiyun
1317*4882a593Smuzhiyun mutex_init(&data->lock);
1318*4882a593Smuzhiyun mutex_init(&data->cmdlock);
1319*4882a593Smuzhiyun
1320*4882a593Smuzhiyun ret = si1145_initialize(data);
1321*4882a593Smuzhiyun if (ret < 0)
1322*4882a593Smuzhiyun return ret;
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun ret = devm_iio_triggered_buffer_setup(&client->dev,
1325*4882a593Smuzhiyun indio_dev, NULL,
1326*4882a593Smuzhiyun si1145_trigger_handler, &si1145_buffer_setup_ops);
1327*4882a593Smuzhiyun if (ret < 0)
1328*4882a593Smuzhiyun return ret;
1329*4882a593Smuzhiyun
1330*4882a593Smuzhiyun if (client->irq) {
1331*4882a593Smuzhiyun ret = si1145_probe_trigger(indio_dev);
1332*4882a593Smuzhiyun if (ret < 0)
1333*4882a593Smuzhiyun return ret;
1334*4882a593Smuzhiyun } else {
1335*4882a593Smuzhiyun dev_info(&client->dev, "no irq, using polling\n");
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun
1338*4882a593Smuzhiyun return devm_iio_device_register(&client->dev, indio_dev);
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun static const struct i2c_device_id si1145_ids[] = {
1342*4882a593Smuzhiyun { "si1132", SI1132 },
1343*4882a593Smuzhiyun { "si1141", SI1141 },
1344*4882a593Smuzhiyun { "si1142", SI1142 },
1345*4882a593Smuzhiyun { "si1143", SI1143 },
1346*4882a593Smuzhiyun { "si1145", SI1145 },
1347*4882a593Smuzhiyun { "si1146", SI1146 },
1348*4882a593Smuzhiyun { "si1147", SI1147 },
1349*4882a593Smuzhiyun { }
1350*4882a593Smuzhiyun };
1351*4882a593Smuzhiyun MODULE_DEVICE_TABLE(i2c, si1145_ids);
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun static struct i2c_driver si1145_driver = {
1354*4882a593Smuzhiyun .driver = {
1355*4882a593Smuzhiyun .name = "si1145",
1356*4882a593Smuzhiyun },
1357*4882a593Smuzhiyun .probe = si1145_probe,
1358*4882a593Smuzhiyun .id_table = si1145_ids,
1359*4882a593Smuzhiyun };
1360*4882a593Smuzhiyun
1361*4882a593Smuzhiyun module_i2c_driver(si1145_driver);
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun MODULE_AUTHOR("Peter Meerwald-Stadler <pmeerw@pmeerw.net>");
1364*4882a593Smuzhiyun MODULE_DESCRIPTION("Silabs SI1132 and SI1141/2/3/5/6/7 proximity, ambient light and UV index sensor driver");
1365*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1366