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