xref: /OK3568_Linux_fs/kernel/drivers/iio/light/si1145.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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