1403e5586SChristian Eggers // SPDX-License-Identifier: GPL-2.0-only
2403e5586SChristian Eggers /*
3403e5586SChristian Eggers * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor
4403e5586SChristian Eggers *
5403e5586SChristian Eggers * Author: Christian Eggers <ceggers@arri.de>
6403e5586SChristian Eggers *
7403e5586SChristian Eggers * Copyright (c) 2020 ARRI Lighting
8403e5586SChristian Eggers *
9403e5586SChristian Eggers * Color light sensor with 16-bit channels for x, y, z and temperature);
10403e5586SChristian Eggers * 7-bit I2C slave address 0x74 .. 0x77.
11403e5586SChristian Eggers *
12403e5586SChristian Eggers * Datasheet: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf
13403e5586SChristian Eggers */
14403e5586SChristian Eggers
15403e5586SChristian Eggers #include <linux/bitfield.h>
16403e5586SChristian Eggers #include <linux/completion.h>
17403e5586SChristian Eggers #include <linux/delay.h>
18403e5586SChristian Eggers #include <linux/i2c.h>
19403e5586SChristian Eggers #include <linux/iio/buffer.h>
20403e5586SChristian Eggers #include <linux/iio/iio.h>
21403e5586SChristian Eggers #include <linux/iio/sysfs.h>
22403e5586SChristian Eggers #include <linux/iio/trigger_consumer.h>
23403e5586SChristian Eggers #include <linux/iio/triggered_buffer.h>
24403e5586SChristian Eggers #include <linux/module.h>
25403e5586SChristian Eggers #include <linux/mutex.h>
26403e5586SChristian Eggers #include <linux/pm.h>
2755c653e0SDaniel Lezcano #include <linux/units.h>
28403e5586SChristian Eggers
29403e5586SChristian Eggers #define AS73211_DRV_NAME "as73211"
30403e5586SChristian Eggers
31403e5586SChristian Eggers /* AS73211 configuration registers */
32403e5586SChristian Eggers #define AS73211_REG_OSR 0x0
33403e5586SChristian Eggers #define AS73211_REG_AGEN 0x2
34403e5586SChristian Eggers #define AS73211_REG_CREG1 0x6
35403e5586SChristian Eggers #define AS73211_REG_CREG2 0x7
36403e5586SChristian Eggers #define AS73211_REG_CREG3 0x8
37403e5586SChristian Eggers
38403e5586SChristian Eggers /* AS73211 output register bank */
39403e5586SChristian Eggers #define AS73211_OUT_OSR_STATUS 0
40403e5586SChristian Eggers #define AS73211_OUT_TEMP 1
41403e5586SChristian Eggers #define AS73211_OUT_MRES1 2
42403e5586SChristian Eggers #define AS73211_OUT_MRES2 3
43403e5586SChristian Eggers #define AS73211_OUT_MRES3 4
44403e5586SChristian Eggers
45403e5586SChristian Eggers #define AS73211_OSR_SS BIT(7)
46403e5586SChristian Eggers #define AS73211_OSR_PD BIT(6)
47403e5586SChristian Eggers #define AS73211_OSR_SW_RES BIT(3)
48403e5586SChristian Eggers #define AS73211_OSR_DOS_MASK GENMASK(2, 0)
49403e5586SChristian Eggers #define AS73211_OSR_DOS_CONFIG FIELD_PREP(AS73211_OSR_DOS_MASK, 0x2)
50403e5586SChristian Eggers #define AS73211_OSR_DOS_MEASURE FIELD_PREP(AS73211_OSR_DOS_MASK, 0x3)
51403e5586SChristian Eggers
52403e5586SChristian Eggers #define AS73211_AGEN_DEVID_MASK GENMASK(7, 4)
53403e5586SChristian Eggers #define AS73211_AGEN_DEVID(x) FIELD_PREP(AS73211_AGEN_DEVID_MASK, (x))
54403e5586SChristian Eggers #define AS73211_AGEN_MUT_MASK GENMASK(3, 0)
55403e5586SChristian Eggers #define AS73211_AGEN_MUT(x) FIELD_PREP(AS73211_AGEN_MUT_MASK, (x))
56403e5586SChristian Eggers
57403e5586SChristian Eggers #define AS73211_CREG1_GAIN_MASK GENMASK(7, 4)
58403e5586SChristian Eggers #define AS73211_CREG1_GAIN_1 11
59403e5586SChristian Eggers #define AS73211_CREG1_TIME_MASK GENMASK(3, 0)
60403e5586SChristian Eggers
61403e5586SChristian Eggers #define AS73211_CREG3_CCLK_MASK GENMASK(1, 0)
62403e5586SChristian Eggers
63403e5586SChristian Eggers #define AS73211_OSR_STATUS_OUTCONVOF BIT(15)
64403e5586SChristian Eggers #define AS73211_OSR_STATUS_MRESOF BIT(14)
65403e5586SChristian Eggers #define AS73211_OSR_STATUS_ADCOF BIT(13)
66403e5586SChristian Eggers #define AS73211_OSR_STATUS_LDATA BIT(12)
67403e5586SChristian Eggers #define AS73211_OSR_STATUS_NDATA BIT(11)
68403e5586SChristian Eggers #define AS73211_OSR_STATUS_NOTREADY BIT(10)
69403e5586SChristian Eggers
70403e5586SChristian Eggers #define AS73211_SAMPLE_FREQ_BASE 1024000
71403e5586SChristian Eggers
72403e5586SChristian Eggers #define AS73211_SAMPLE_TIME_NUM 15
73403e5586SChristian Eggers #define AS73211_SAMPLE_TIME_MAX_MS BIT(AS73211_SAMPLE_TIME_NUM - 1)
74403e5586SChristian Eggers
75403e5586SChristian Eggers /* Available sample frequencies are 1.024MHz multiplied by powers of two. */
76403e5586SChristian Eggers static const int as73211_samp_freq_avail[] = {
77403e5586SChristian Eggers AS73211_SAMPLE_FREQ_BASE * 1,
78403e5586SChristian Eggers AS73211_SAMPLE_FREQ_BASE * 2,
79403e5586SChristian Eggers AS73211_SAMPLE_FREQ_BASE * 4,
80403e5586SChristian Eggers AS73211_SAMPLE_FREQ_BASE * 8,
81403e5586SChristian Eggers };
82403e5586SChristian Eggers
83403e5586SChristian Eggers static const int as73211_hardwaregain_avail[] = {
84403e5586SChristian Eggers 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
85403e5586SChristian Eggers };
86403e5586SChristian Eggers
87403e5586SChristian Eggers /**
88403e5586SChristian Eggers * struct as73211_data - Instance data for one AS73211
89403e5586SChristian Eggers * @client: I2C client.
90403e5586SChristian Eggers * @osr: Cached Operational State Register.
91403e5586SChristian Eggers * @creg1: Cached Configuration Register 1.
92403e5586SChristian Eggers * @creg2: Cached Configuration Register 2.
93403e5586SChristian Eggers * @creg3: Cached Configuration Register 3.
94403e5586SChristian Eggers * @mutex: Keeps cached registers in sync with the device.
95403e5586SChristian Eggers * @completion: Completion to wait for interrupt.
96403e5586SChristian Eggers * @int_time_avail: Available integration times (depend on sampling frequency).
97403e5586SChristian Eggers */
98403e5586SChristian Eggers struct as73211_data {
99403e5586SChristian Eggers struct i2c_client *client;
100403e5586SChristian Eggers u8 osr;
101403e5586SChristian Eggers u8 creg1;
102403e5586SChristian Eggers u8 creg2;
103403e5586SChristian Eggers u8 creg3;
104403e5586SChristian Eggers struct mutex mutex;
105403e5586SChristian Eggers struct completion completion;
106403e5586SChristian Eggers int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2];
107403e5586SChristian Eggers };
108403e5586SChristian Eggers
109403e5586SChristian Eggers #define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \
110403e5586SChristian Eggers .type = IIO_INTENSITY, \
111403e5586SChristian Eggers .modified = 1, \
112403e5586SChristian Eggers .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
113403e5586SChristian Eggers .info_mask_shared_by_type = \
114403e5586SChristian Eggers BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
115403e5586SChristian Eggers BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
116403e5586SChristian Eggers BIT(IIO_CHAN_INFO_INT_TIME), \
117403e5586SChristian Eggers .info_mask_shared_by_type_available = \
118403e5586SChristian Eggers BIT(IIO_CHAN_INFO_SAMP_FREQ) | \
119403e5586SChristian Eggers BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \
120403e5586SChristian Eggers BIT(IIO_CHAN_INFO_INT_TIME), \
121403e5586SChristian Eggers .channel2 = IIO_MOD_##_color, \
122403e5586SChristian Eggers .address = _addr, \
123403e5586SChristian Eggers .scan_index = _si, \
124403e5586SChristian Eggers .scan_type = { \
125403e5586SChristian Eggers .sign = 'u', \
126403e5586SChristian Eggers .realbits = 16, \
127403e5586SChristian Eggers .storagebits = 16, \
128403e5586SChristian Eggers .endianness = IIO_LE, \
129403e5586SChristian Eggers }, \
130403e5586SChristian Eggers }
131403e5586SChristian Eggers
132403e5586SChristian Eggers #define AS73211_OFFSET_TEMP_INT (-66)
133403e5586SChristian Eggers #define AS73211_OFFSET_TEMP_MICRO 900000
134403e5586SChristian Eggers #define AS73211_SCALE_TEMP_INT 0
135403e5586SChristian Eggers #define AS73211_SCALE_TEMP_MICRO 50000
136403e5586SChristian Eggers
137403e5586SChristian Eggers #define AS73211_SCALE_X 277071108 /* nW/m^2 */
138403e5586SChristian Eggers #define AS73211_SCALE_Y 298384270 /* nW/m^2 */
139403e5586SChristian Eggers #define AS73211_SCALE_Z 160241927 /* nW/m^2 */
140403e5586SChristian Eggers
141403e5586SChristian Eggers /* Channel order MUST match devices result register order */
142403e5586SChristian Eggers #define AS73211_SCAN_INDEX_TEMP 0
143403e5586SChristian Eggers #define AS73211_SCAN_INDEX_X 1
144403e5586SChristian Eggers #define AS73211_SCAN_INDEX_Y 2
145403e5586SChristian Eggers #define AS73211_SCAN_INDEX_Z 3
146403e5586SChristian Eggers #define AS73211_SCAN_INDEX_TS 4
147403e5586SChristian Eggers
148403e5586SChristian Eggers #define AS73211_SCAN_MASK_COLOR ( \
149403e5586SChristian Eggers BIT(AS73211_SCAN_INDEX_X) | \
150403e5586SChristian Eggers BIT(AS73211_SCAN_INDEX_Y) | \
151403e5586SChristian Eggers BIT(AS73211_SCAN_INDEX_Z))
152403e5586SChristian Eggers
153403e5586SChristian Eggers #define AS73211_SCAN_MASK_ALL ( \
154403e5586SChristian Eggers BIT(AS73211_SCAN_INDEX_TEMP) | \
155403e5586SChristian Eggers AS73211_SCAN_MASK_COLOR)
156403e5586SChristian Eggers
157403e5586SChristian Eggers static const struct iio_chan_spec as73211_channels[] = {
158403e5586SChristian Eggers {
159403e5586SChristian Eggers .type = IIO_TEMP,
160403e5586SChristian Eggers .info_mask_separate =
161403e5586SChristian Eggers BIT(IIO_CHAN_INFO_RAW) |
162403e5586SChristian Eggers BIT(IIO_CHAN_INFO_OFFSET) |
163403e5586SChristian Eggers BIT(IIO_CHAN_INFO_SCALE),
164403e5586SChristian Eggers .address = AS73211_OUT_TEMP,
165403e5586SChristian Eggers .scan_index = AS73211_SCAN_INDEX_TEMP,
166403e5586SChristian Eggers .scan_type = {
167403e5586SChristian Eggers .sign = 'u',
168403e5586SChristian Eggers .realbits = 16,
169403e5586SChristian Eggers .storagebits = 16,
170403e5586SChristian Eggers .endianness = IIO_LE,
171403e5586SChristian Eggers }
172403e5586SChristian Eggers },
173403e5586SChristian Eggers AS73211_COLOR_CHANNEL(X, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1),
174403e5586SChristian Eggers AS73211_COLOR_CHANNEL(Y, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2),
175403e5586SChristian Eggers AS73211_COLOR_CHANNEL(Z, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3),
176403e5586SChristian Eggers IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS),
177403e5586SChristian Eggers };
178403e5586SChristian Eggers
as73211_integration_time_1024cyc(struct as73211_data * data)179403e5586SChristian Eggers static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data)
180403e5586SChristian Eggers {
181403e5586SChristian Eggers /*
182403e5586SChristian Eggers * Return integration time in units of 1024 clock cycles. Integration time
183403e5586SChristian Eggers * in CREG1 is in powers of 2 (x 1024 cycles).
184403e5586SChristian Eggers */
185403e5586SChristian Eggers return BIT(FIELD_GET(AS73211_CREG1_TIME_MASK, data->creg1));
186403e5586SChristian Eggers }
187403e5586SChristian Eggers
as73211_integration_time_us(struct as73211_data * data,unsigned int integration_time_1024cyc)188403e5586SChristian Eggers static unsigned int as73211_integration_time_us(struct as73211_data *data,
189403e5586SChristian Eggers unsigned int integration_time_1024cyc)
190403e5586SChristian Eggers {
191403e5586SChristian Eggers /*
192403e5586SChristian Eggers * f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz)
193403e5586SChristian Eggers * t_cycl is configured in CREG1 in powers of 2 (x 1024 cycles)
194403e5586SChristian Eggers * t_int_us = 1 / (f_samp) * t_cycl * US_PER_SEC
195403e5586SChristian Eggers * = 1 / (2^CREG3_CCLK * 1,024,000) * 2^CREG1_CYCLES * 1,024 * US_PER_SEC
196403e5586SChristian Eggers * = 2^(-CREG3_CCLK) * 2^CREG1_CYCLES * 1,000
197403e5586SChristian Eggers * In order to get rid of negative exponents, we extend the "fraction"
198403e5586SChristian Eggers * by 2^3 (CREG3_CCLK,max = 3)
199403e5586SChristian Eggers * t_int_us = 2^(3-CREG3_CCLK) * 2^CREG1_CYCLES * 125
200403e5586SChristian Eggers */
201403e5586SChristian Eggers return BIT(3 - FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) *
202403e5586SChristian Eggers integration_time_1024cyc * 125;
203403e5586SChristian Eggers }
204403e5586SChristian Eggers
as73211_integration_time_calc_avail(struct as73211_data * data)205403e5586SChristian Eggers static void as73211_integration_time_calc_avail(struct as73211_data *data)
206403e5586SChristian Eggers {
207403e5586SChristian Eggers int i;
208403e5586SChristian Eggers
209403e5586SChristian Eggers for (i = 0; i < ARRAY_SIZE(data->int_time_avail) / 2; i++) {
210403e5586SChristian Eggers unsigned int time_us = as73211_integration_time_us(data, BIT(i));
211403e5586SChristian Eggers
212403e5586SChristian Eggers data->int_time_avail[i * 2 + 0] = time_us / USEC_PER_SEC;
213403e5586SChristian Eggers data->int_time_avail[i * 2 + 1] = time_us % USEC_PER_SEC;
214403e5586SChristian Eggers }
215403e5586SChristian Eggers }
216403e5586SChristian Eggers
as73211_gain(struct as73211_data * data)217403e5586SChristian Eggers static unsigned int as73211_gain(struct as73211_data *data)
218403e5586SChristian Eggers {
219403e5586SChristian Eggers /* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */
220403e5586SChristian Eggers return BIT(AS73211_CREG1_GAIN_1 - FIELD_GET(AS73211_CREG1_GAIN_MASK, data->creg1));
221403e5586SChristian Eggers }
222403e5586SChristian Eggers
223403e5586SChristian Eggers /* must be called with as73211_data::mutex held. */
as73211_req_data(struct as73211_data * data)224403e5586SChristian Eggers static int as73211_req_data(struct as73211_data *data)
225403e5586SChristian Eggers {
226403e5586SChristian Eggers unsigned int time_us = as73211_integration_time_us(data,
227403e5586SChristian Eggers as73211_integration_time_1024cyc(data));
228403e5586SChristian Eggers struct device *dev = &data->client->dev;
229403e5586SChristian Eggers union i2c_smbus_data smbus_data;
230403e5586SChristian Eggers u16 osr_status;
231403e5586SChristian Eggers int ret;
232403e5586SChristian Eggers
233403e5586SChristian Eggers if (data->client->irq)
234403e5586SChristian Eggers reinit_completion(&data->completion);
235403e5586SChristian Eggers
236403e5586SChristian Eggers /*
237403e5586SChristian Eggers * During measurement, there should be no traffic on the i2c bus as the
238403e5586SChristian Eggers * electrical noise would disturb the measurement process.
239403e5586SChristian Eggers */
240403e5586SChristian Eggers i2c_lock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
241403e5586SChristian Eggers
242403e5586SChristian Eggers data->osr &= ~AS73211_OSR_DOS_MASK;
243403e5586SChristian Eggers data->osr |= AS73211_OSR_DOS_MEASURE | AS73211_OSR_SS;
244403e5586SChristian Eggers
245403e5586SChristian Eggers smbus_data.byte = data->osr;
246403e5586SChristian Eggers ret = __i2c_smbus_xfer(data->client->adapter, data->client->addr,
247403e5586SChristian Eggers data->client->flags, I2C_SMBUS_WRITE,
248403e5586SChristian Eggers AS73211_REG_OSR, I2C_SMBUS_BYTE_DATA, &smbus_data);
249403e5586SChristian Eggers if (ret < 0) {
250403e5586SChristian Eggers i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
251403e5586SChristian Eggers return ret;
252403e5586SChristian Eggers }
253403e5586SChristian Eggers
254403e5586SChristian Eggers /*
255403e5586SChristian Eggers * Reset AS73211_OSR_SS (is self clearing) in order to avoid unintentional
256403e5586SChristian Eggers * triggering of further measurements later.
257403e5586SChristian Eggers */
258403e5586SChristian Eggers data->osr &= ~AS73211_OSR_SS;
259403e5586SChristian Eggers
260403e5586SChristian Eggers /*
26123e0618cSChristian Eggers * Add 33% extra margin for the timeout. fclk,min = fclk,typ - 27%.
262403e5586SChristian Eggers */
26323e0618cSChristian Eggers time_us += time_us / 3;
264403e5586SChristian Eggers if (data->client->irq) {
265403e5586SChristian Eggers ret = wait_for_completion_timeout(&data->completion, usecs_to_jiffies(time_us));
266403e5586SChristian Eggers if (!ret) {
267403e5586SChristian Eggers dev_err(dev, "timeout waiting for READY IRQ\n");
268403e5586SChristian Eggers i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
269403e5586SChristian Eggers return -ETIMEDOUT;
270403e5586SChristian Eggers }
271403e5586SChristian Eggers } else {
272403e5586SChristian Eggers /* Wait integration time */
273403e5586SChristian Eggers usleep_range(time_us, 2 * time_us);
274403e5586SChristian Eggers }
275403e5586SChristian Eggers
276403e5586SChristian Eggers i2c_unlock_bus(data->client->adapter, I2C_LOCK_SEGMENT);
277403e5586SChristian Eggers
278403e5586SChristian Eggers ret = i2c_smbus_read_word_data(data->client, AS73211_OUT_OSR_STATUS);
279403e5586SChristian Eggers if (ret < 0)
280403e5586SChristian Eggers return ret;
281403e5586SChristian Eggers
282403e5586SChristian Eggers osr_status = ret;
283403e5586SChristian Eggers if (osr_status != (AS73211_OSR_DOS_MEASURE | AS73211_OSR_STATUS_NDATA)) {
284403e5586SChristian Eggers if (osr_status & AS73211_OSR_SS) {
285403e5586SChristian Eggers dev_err(dev, "%s() Measurement has not stopped\n", __func__);
286403e5586SChristian Eggers return -ETIME;
287403e5586SChristian Eggers }
288403e5586SChristian Eggers if (osr_status & AS73211_OSR_STATUS_NOTREADY) {
289403e5586SChristian Eggers dev_err(dev, "%s() Data is not ready\n", __func__);
290403e5586SChristian Eggers return -ENODATA;
291403e5586SChristian Eggers }
292403e5586SChristian Eggers if (!(osr_status & AS73211_OSR_STATUS_NDATA)) {
293403e5586SChristian Eggers dev_err(dev, "%s() No new data available\n", __func__);
294403e5586SChristian Eggers return -ENODATA;
295403e5586SChristian Eggers }
296403e5586SChristian Eggers if (osr_status & AS73211_OSR_STATUS_LDATA) {
297403e5586SChristian Eggers dev_err(dev, "%s() Result buffer overrun\n", __func__);
298403e5586SChristian Eggers return -ENOBUFS;
299403e5586SChristian Eggers }
300403e5586SChristian Eggers if (osr_status & AS73211_OSR_STATUS_ADCOF) {
301403e5586SChristian Eggers dev_err(dev, "%s() ADC overflow\n", __func__);
302403e5586SChristian Eggers return -EOVERFLOW;
303403e5586SChristian Eggers }
304403e5586SChristian Eggers if (osr_status & AS73211_OSR_STATUS_MRESOF) {
305403e5586SChristian Eggers dev_err(dev, "%s() Measurement result overflow\n", __func__);
306403e5586SChristian Eggers return -EOVERFLOW;
307403e5586SChristian Eggers }
308403e5586SChristian Eggers if (osr_status & AS73211_OSR_STATUS_OUTCONVOF) {
309403e5586SChristian Eggers dev_err(dev, "%s() Timer overflow\n", __func__);
310403e5586SChristian Eggers return -EOVERFLOW;
311403e5586SChristian Eggers }
312403e5586SChristian Eggers dev_err(dev, "%s() Unexpected status value\n", __func__);
313403e5586SChristian Eggers return -EIO;
314403e5586SChristian Eggers }
315403e5586SChristian Eggers
316403e5586SChristian Eggers return 0;
317403e5586SChristian Eggers }
318403e5586SChristian Eggers
as73211_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)319403e5586SChristian Eggers static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
320403e5586SChristian Eggers int *val, int *val2, long mask)
321403e5586SChristian Eggers {
322403e5586SChristian Eggers struct as73211_data *data = iio_priv(indio_dev);
323403e5586SChristian Eggers
324403e5586SChristian Eggers switch (mask) {
325403e5586SChristian Eggers case IIO_CHAN_INFO_RAW: {
326403e5586SChristian Eggers int ret;
327403e5586SChristian Eggers
328403e5586SChristian Eggers ret = iio_device_claim_direct_mode(indio_dev);
329403e5586SChristian Eggers if (ret < 0)
330403e5586SChristian Eggers return ret;
331403e5586SChristian Eggers
332403e5586SChristian Eggers ret = as73211_req_data(data);
333403e5586SChristian Eggers if (ret < 0) {
334403e5586SChristian Eggers iio_device_release_direct_mode(indio_dev);
335403e5586SChristian Eggers return ret;
336403e5586SChristian Eggers }
337403e5586SChristian Eggers
338403e5586SChristian Eggers ret = i2c_smbus_read_word_data(data->client, chan->address);
339403e5586SChristian Eggers iio_device_release_direct_mode(indio_dev);
340403e5586SChristian Eggers if (ret < 0)
341403e5586SChristian Eggers return ret;
342403e5586SChristian Eggers
343403e5586SChristian Eggers *val = ret;
344403e5586SChristian Eggers return IIO_VAL_INT;
345403e5586SChristian Eggers }
346403e5586SChristian Eggers case IIO_CHAN_INFO_OFFSET:
347403e5586SChristian Eggers *val = AS73211_OFFSET_TEMP_INT;
348403e5586SChristian Eggers *val2 = AS73211_OFFSET_TEMP_MICRO;
349403e5586SChristian Eggers return IIO_VAL_INT_PLUS_MICRO;
350403e5586SChristian Eggers
351403e5586SChristian Eggers case IIO_CHAN_INFO_SCALE:
352403e5586SChristian Eggers switch (chan->type) {
353403e5586SChristian Eggers case IIO_TEMP:
354403e5586SChristian Eggers *val = AS73211_SCALE_TEMP_INT;
355403e5586SChristian Eggers *val2 = AS73211_SCALE_TEMP_MICRO;
356403e5586SChristian Eggers return IIO_VAL_INT_PLUS_MICRO;
357403e5586SChristian Eggers
358403e5586SChristian Eggers case IIO_INTENSITY: {
359403e5586SChristian Eggers unsigned int scale;
360403e5586SChristian Eggers
361403e5586SChristian Eggers switch (chan->channel2) {
362403e5586SChristian Eggers case IIO_MOD_X:
363403e5586SChristian Eggers scale = AS73211_SCALE_X;
364403e5586SChristian Eggers break;
365403e5586SChristian Eggers case IIO_MOD_Y:
366403e5586SChristian Eggers scale = AS73211_SCALE_Y;
367403e5586SChristian Eggers break;
368403e5586SChristian Eggers case IIO_MOD_Z:
369403e5586SChristian Eggers scale = AS73211_SCALE_Z;
370403e5586SChristian Eggers break;
371403e5586SChristian Eggers default:
372403e5586SChristian Eggers return -EINVAL;
373403e5586SChristian Eggers }
374403e5586SChristian Eggers scale /= as73211_gain(data);
375403e5586SChristian Eggers scale /= as73211_integration_time_1024cyc(data);
376403e5586SChristian Eggers *val = scale;
377403e5586SChristian Eggers return IIO_VAL_INT;
378403e5586SChristian Eggers
379403e5586SChristian Eggers default:
380403e5586SChristian Eggers return -EINVAL;
381403e5586SChristian Eggers }}
382403e5586SChristian Eggers
383403e5586SChristian Eggers case IIO_CHAN_INFO_SAMP_FREQ:
384403e5586SChristian Eggers /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
385403e5586SChristian Eggers *val = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) *
386403e5586SChristian Eggers AS73211_SAMPLE_FREQ_BASE;
387403e5586SChristian Eggers return IIO_VAL_INT;
388403e5586SChristian Eggers
389403e5586SChristian Eggers case IIO_CHAN_INFO_HARDWAREGAIN:
390403e5586SChristian Eggers *val = as73211_gain(data);
391403e5586SChristian Eggers return IIO_VAL_INT;
392403e5586SChristian Eggers
393403e5586SChristian Eggers case IIO_CHAN_INFO_INT_TIME: {
394403e5586SChristian Eggers unsigned int time_us;
395403e5586SChristian Eggers
396403e5586SChristian Eggers mutex_lock(&data->mutex);
397403e5586SChristian Eggers time_us = as73211_integration_time_us(data, as73211_integration_time_1024cyc(data));
398403e5586SChristian Eggers mutex_unlock(&data->mutex);
399403e5586SChristian Eggers *val = time_us / USEC_PER_SEC;
400403e5586SChristian Eggers *val2 = time_us % USEC_PER_SEC;
401403e5586SChristian Eggers return IIO_VAL_INT_PLUS_MICRO;
402403e5586SChristian Eggers
403403e5586SChristian Eggers default:
404403e5586SChristian Eggers return -EINVAL;
405403e5586SChristian Eggers }}
406403e5586SChristian Eggers }
407403e5586SChristian Eggers
as73211_read_avail(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,const int ** vals,int * type,int * length,long mask)408403e5586SChristian Eggers static int as73211_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
409403e5586SChristian Eggers const int **vals, int *type, int *length, long mask)
410403e5586SChristian Eggers {
411403e5586SChristian Eggers struct as73211_data *data = iio_priv(indio_dev);
412403e5586SChristian Eggers
413403e5586SChristian Eggers switch (mask) {
414403e5586SChristian Eggers case IIO_CHAN_INFO_SAMP_FREQ:
415403e5586SChristian Eggers *length = ARRAY_SIZE(as73211_samp_freq_avail);
416403e5586SChristian Eggers *vals = as73211_samp_freq_avail;
417403e5586SChristian Eggers *type = IIO_VAL_INT;
418403e5586SChristian Eggers return IIO_AVAIL_LIST;
419403e5586SChristian Eggers
420403e5586SChristian Eggers case IIO_CHAN_INFO_HARDWAREGAIN:
421403e5586SChristian Eggers *length = ARRAY_SIZE(as73211_hardwaregain_avail);
422403e5586SChristian Eggers *vals = as73211_hardwaregain_avail;
423403e5586SChristian Eggers *type = IIO_VAL_INT;
424403e5586SChristian Eggers return IIO_AVAIL_LIST;
425403e5586SChristian Eggers
426403e5586SChristian Eggers case IIO_CHAN_INFO_INT_TIME:
427403e5586SChristian Eggers *length = ARRAY_SIZE(data->int_time_avail);
428403e5586SChristian Eggers *vals = data->int_time_avail;
429403e5586SChristian Eggers *type = IIO_VAL_INT_PLUS_MICRO;
430403e5586SChristian Eggers return IIO_AVAIL_LIST;
431403e5586SChristian Eggers
432403e5586SChristian Eggers default:
433403e5586SChristian Eggers return -EINVAL;
434403e5586SChristian Eggers }
435403e5586SChristian Eggers }
436403e5586SChristian Eggers
_as73211_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan __always_unused,int val,int val2,long mask)437403e5586SChristian Eggers static int _as73211_write_raw(struct iio_dev *indio_dev,
438403e5586SChristian Eggers struct iio_chan_spec const *chan __always_unused,
439403e5586SChristian Eggers int val, int val2, long mask)
440403e5586SChristian Eggers {
441403e5586SChristian Eggers struct as73211_data *data = iio_priv(indio_dev);
442403e5586SChristian Eggers int ret;
443403e5586SChristian Eggers
444403e5586SChristian Eggers switch (mask) {
445403e5586SChristian Eggers case IIO_CHAN_INFO_SAMP_FREQ: {
446403e5586SChristian Eggers int reg_bits, freq_kHz = val / HZ_PER_KHZ; /* 1024, 2048, ... */
447403e5586SChristian Eggers
448403e5586SChristian Eggers /* val must be 1024 * 2^x */
449403e5586SChristian Eggers if (val < 0 || (freq_kHz * HZ_PER_KHZ) != val ||
450403e5586SChristian Eggers !is_power_of_2(freq_kHz) || val2)
451403e5586SChristian Eggers return -EINVAL;
452403e5586SChristian Eggers
453403e5586SChristian Eggers /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz (=2^10)) */
454403e5586SChristian Eggers reg_bits = ilog2(freq_kHz) - 10;
455403e5586SChristian Eggers if (!FIELD_FIT(AS73211_CREG3_CCLK_MASK, reg_bits))
456403e5586SChristian Eggers return -EINVAL;
457403e5586SChristian Eggers
458403e5586SChristian Eggers data->creg3 &= ~AS73211_CREG3_CCLK_MASK;
459403e5586SChristian Eggers data->creg3 |= FIELD_PREP(AS73211_CREG3_CCLK_MASK, reg_bits);
460403e5586SChristian Eggers as73211_integration_time_calc_avail(data);
461403e5586SChristian Eggers
462403e5586SChristian Eggers ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG3, data->creg3);
463403e5586SChristian Eggers if (ret < 0)
464403e5586SChristian Eggers return ret;
465403e5586SChristian Eggers
466403e5586SChristian Eggers return 0;
467403e5586SChristian Eggers }
468403e5586SChristian Eggers case IIO_CHAN_INFO_HARDWAREGAIN: {
469403e5586SChristian Eggers unsigned int reg_bits;
470403e5586SChristian Eggers
471403e5586SChristian Eggers if (val < 0 || !is_power_of_2(val) || val2)
472403e5586SChristian Eggers return -EINVAL;
473403e5586SChristian Eggers
474403e5586SChristian Eggers /* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */
475403e5586SChristian Eggers reg_bits = AS73211_CREG1_GAIN_1 - ilog2(val);
476403e5586SChristian Eggers if (!FIELD_FIT(AS73211_CREG1_GAIN_MASK, reg_bits))
477403e5586SChristian Eggers return -EINVAL;
478403e5586SChristian Eggers
479403e5586SChristian Eggers data->creg1 &= ~AS73211_CREG1_GAIN_MASK;
480403e5586SChristian Eggers data->creg1 |= FIELD_PREP(AS73211_CREG1_GAIN_MASK, reg_bits);
481403e5586SChristian Eggers
482403e5586SChristian Eggers ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG1, data->creg1);
483403e5586SChristian Eggers if (ret < 0)
484403e5586SChristian Eggers return ret;
485403e5586SChristian Eggers
486403e5586SChristian Eggers return 0;
487403e5586SChristian Eggers }
488403e5586SChristian Eggers case IIO_CHAN_INFO_INT_TIME: {
489403e5586SChristian Eggers int val_us = val * USEC_PER_SEC + val2;
490403e5586SChristian Eggers int time_ms;
491403e5586SChristian Eggers int reg_bits;
492403e5586SChristian Eggers
493403e5586SChristian Eggers /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */
494403e5586SChristian Eggers int f_samp_1_024mhz = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3));
495403e5586SChristian Eggers
496403e5586SChristian Eggers /*
497403e5586SChristian Eggers * time_ms = time_us * US_PER_MS * f_samp_1_024mhz / MHZ_PER_HZ
498403e5586SChristian Eggers * = time_us * f_samp_1_024mhz / 1000
499403e5586SChristian Eggers */
500403e5586SChristian Eggers time_ms = (val_us * f_samp_1_024mhz) / 1000; /* 1 ms, 2 ms, ... (power of two) */
501403e5586SChristian Eggers if (time_ms < 0 || !is_power_of_2(time_ms) || time_ms > AS73211_SAMPLE_TIME_MAX_MS)
502403e5586SChristian Eggers return -EINVAL;
503403e5586SChristian Eggers
504403e5586SChristian Eggers reg_bits = ilog2(time_ms);
505403e5586SChristian Eggers if (!FIELD_FIT(AS73211_CREG1_TIME_MASK, reg_bits))
506403e5586SChristian Eggers return -EINVAL; /* not possible due to previous tests */
507403e5586SChristian Eggers
508403e5586SChristian Eggers data->creg1 &= ~AS73211_CREG1_TIME_MASK;
509403e5586SChristian Eggers data->creg1 |= FIELD_PREP(AS73211_CREG1_TIME_MASK, reg_bits);
510403e5586SChristian Eggers
511403e5586SChristian Eggers ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_CREG1, data->creg1);
512403e5586SChristian Eggers if (ret < 0)
513403e5586SChristian Eggers return ret;
514403e5586SChristian Eggers
515403e5586SChristian Eggers return 0;
516403e5586SChristian Eggers
517403e5586SChristian Eggers default:
518403e5586SChristian Eggers return -EINVAL;
519403e5586SChristian Eggers }}
520403e5586SChristian Eggers }
521403e5586SChristian Eggers
as73211_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)522403e5586SChristian Eggers static int as73211_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan,
523403e5586SChristian Eggers int val, int val2, long mask)
524403e5586SChristian Eggers {
525403e5586SChristian Eggers struct as73211_data *data = iio_priv(indio_dev);
526403e5586SChristian Eggers int ret;
527403e5586SChristian Eggers
528403e5586SChristian Eggers mutex_lock(&data->mutex);
529403e5586SChristian Eggers
530403e5586SChristian Eggers ret = iio_device_claim_direct_mode(indio_dev);
531403e5586SChristian Eggers if (ret < 0)
532403e5586SChristian Eggers goto error_unlock;
533403e5586SChristian Eggers
534403e5586SChristian Eggers /* Need to switch to config mode ... */
535403e5586SChristian Eggers if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) {
536403e5586SChristian Eggers data->osr &= ~AS73211_OSR_DOS_MASK;
537403e5586SChristian Eggers data->osr |= AS73211_OSR_DOS_CONFIG;
538403e5586SChristian Eggers
539403e5586SChristian Eggers ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
540403e5586SChristian Eggers if (ret < 0)
541403e5586SChristian Eggers goto error_release;
542403e5586SChristian Eggers }
543403e5586SChristian Eggers
544403e5586SChristian Eggers ret = _as73211_write_raw(indio_dev, chan, val, val2, mask);
545403e5586SChristian Eggers
546403e5586SChristian Eggers error_release:
547403e5586SChristian Eggers iio_device_release_direct_mode(indio_dev);
548403e5586SChristian Eggers error_unlock:
549403e5586SChristian Eggers mutex_unlock(&data->mutex);
550403e5586SChristian Eggers return ret;
551403e5586SChristian Eggers }
552403e5586SChristian Eggers
as73211_ready_handler(int irq __always_unused,void * priv)553403e5586SChristian Eggers static irqreturn_t as73211_ready_handler(int irq __always_unused, void *priv)
554403e5586SChristian Eggers {
555403e5586SChristian Eggers struct as73211_data *data = iio_priv(priv);
556403e5586SChristian Eggers
557403e5586SChristian Eggers complete(&data->completion);
558403e5586SChristian Eggers
559403e5586SChristian Eggers return IRQ_HANDLED;
560403e5586SChristian Eggers }
561403e5586SChristian Eggers
as73211_trigger_handler(int irq __always_unused,void * p)562403e5586SChristian Eggers static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p)
563403e5586SChristian Eggers {
564403e5586SChristian Eggers struct iio_poll_func *pf = p;
565403e5586SChristian Eggers struct iio_dev *indio_dev = pf->indio_dev;
566403e5586SChristian Eggers struct as73211_data *data = iio_priv(indio_dev);
567403e5586SChristian Eggers struct {
568403e5586SChristian Eggers __le16 chan[4];
569403e5586SChristian Eggers s64 ts __aligned(8);
570403e5586SChristian Eggers } scan;
571403e5586SChristian Eggers int data_result, ret;
572403e5586SChristian Eggers
573403e5586SChristian Eggers mutex_lock(&data->mutex);
574403e5586SChristian Eggers
575403e5586SChristian Eggers data_result = as73211_req_data(data);
576403e5586SChristian Eggers if (data_result < 0 && data_result != -EOVERFLOW)
577403e5586SChristian Eggers goto done; /* don't push any data for errors other than EOVERFLOW */
578403e5586SChristian Eggers
579403e5586SChristian Eggers if (*indio_dev->active_scan_mask == AS73211_SCAN_MASK_ALL) {
580403e5586SChristian Eggers /* Optimization for reading all (color + temperature) channels */
581403e5586SChristian Eggers u8 addr = as73211_channels[0].address;
582403e5586SChristian Eggers struct i2c_msg msgs[] = {
583403e5586SChristian Eggers {
584403e5586SChristian Eggers .addr = data->client->addr,
585403e5586SChristian Eggers .flags = 0,
586403e5586SChristian Eggers .len = 1,
587403e5586SChristian Eggers .buf = &addr,
588403e5586SChristian Eggers },
589403e5586SChristian Eggers {
590403e5586SChristian Eggers .addr = data->client->addr,
591403e5586SChristian Eggers .flags = I2C_M_RD,
592403e5586SChristian Eggers .len = sizeof(scan.chan),
593403e5586SChristian Eggers .buf = (u8 *)&scan.chan,
594403e5586SChristian Eggers },
595403e5586SChristian Eggers };
596403e5586SChristian Eggers
597403e5586SChristian Eggers ret = i2c_transfer(data->client->adapter, msgs, ARRAY_SIZE(msgs));
598403e5586SChristian Eggers if (ret < 0)
599403e5586SChristian Eggers goto done;
600403e5586SChristian Eggers } else {
601403e5586SChristian Eggers /* Optimization for reading only color channels */
602403e5586SChristian Eggers
603403e5586SChristian Eggers /* AS73211 starts reading at address 2 */
604403e5586SChristian Eggers ret = i2c_master_recv(data->client,
605403e5586SChristian Eggers (char *)&scan.chan[1], 3 * sizeof(scan.chan[1]));
606403e5586SChristian Eggers if (ret < 0)
607403e5586SChristian Eggers goto done;
608403e5586SChristian Eggers }
609403e5586SChristian Eggers
610403e5586SChristian Eggers if (data_result) {
611403e5586SChristian Eggers /*
612403e5586SChristian Eggers * Saturate all channels (in case of overflows). Temperature channel
613403e5586SChristian Eggers * is not affected by overflows.
614403e5586SChristian Eggers */
615403e5586SChristian Eggers scan.chan[1] = cpu_to_le16(U16_MAX);
616403e5586SChristian Eggers scan.chan[2] = cpu_to_le16(U16_MAX);
617403e5586SChristian Eggers scan.chan[3] = cpu_to_le16(U16_MAX);
618403e5586SChristian Eggers }
619403e5586SChristian Eggers
620403e5586SChristian Eggers iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev));
621403e5586SChristian Eggers
622403e5586SChristian Eggers done:
623403e5586SChristian Eggers mutex_unlock(&data->mutex);
624403e5586SChristian Eggers iio_trigger_notify_done(indio_dev->trig);
625403e5586SChristian Eggers
626403e5586SChristian Eggers return IRQ_HANDLED;
627403e5586SChristian Eggers }
628403e5586SChristian Eggers
629403e5586SChristian Eggers static const struct iio_info as73211_info = {
630403e5586SChristian Eggers .read_raw = as73211_read_raw,
631403e5586SChristian Eggers .read_avail = as73211_read_avail,
632403e5586SChristian Eggers .write_raw = as73211_write_raw,
633403e5586SChristian Eggers };
634403e5586SChristian Eggers
as73211_power(struct iio_dev * indio_dev,bool state)635403e5586SChristian Eggers static int as73211_power(struct iio_dev *indio_dev, bool state)
636403e5586SChristian Eggers {
637403e5586SChristian Eggers struct as73211_data *data = iio_priv(indio_dev);
638403e5586SChristian Eggers int ret;
639403e5586SChristian Eggers
640403e5586SChristian Eggers mutex_lock(&data->mutex);
641403e5586SChristian Eggers
642403e5586SChristian Eggers if (state)
643403e5586SChristian Eggers data->osr &= ~AS73211_OSR_PD;
644403e5586SChristian Eggers else
645403e5586SChristian Eggers data->osr |= AS73211_OSR_PD;
646403e5586SChristian Eggers
647403e5586SChristian Eggers ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
648403e5586SChristian Eggers
649403e5586SChristian Eggers mutex_unlock(&data->mutex);
650403e5586SChristian Eggers
651403e5586SChristian Eggers if (ret < 0)
652403e5586SChristian Eggers return ret;
653403e5586SChristian Eggers
654403e5586SChristian Eggers return 0;
655403e5586SChristian Eggers }
656403e5586SChristian Eggers
as73211_power_disable(void * data)657403e5586SChristian Eggers static void as73211_power_disable(void *data)
658403e5586SChristian Eggers {
659403e5586SChristian Eggers struct iio_dev *indio_dev = data;
660403e5586SChristian Eggers
661403e5586SChristian Eggers as73211_power(indio_dev, false);
662403e5586SChristian Eggers }
663403e5586SChristian Eggers
as73211_probe(struct i2c_client * client)664403e5586SChristian Eggers static int as73211_probe(struct i2c_client *client)
665403e5586SChristian Eggers {
666403e5586SChristian Eggers struct device *dev = &client->dev;
667403e5586SChristian Eggers struct as73211_data *data;
668403e5586SChristian Eggers struct iio_dev *indio_dev;
669403e5586SChristian Eggers int ret;
670403e5586SChristian Eggers
671403e5586SChristian Eggers indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
672403e5586SChristian Eggers if (!indio_dev)
673403e5586SChristian Eggers return -ENOMEM;
674403e5586SChristian Eggers
675403e5586SChristian Eggers data = iio_priv(indio_dev);
676403e5586SChristian Eggers i2c_set_clientdata(client, indio_dev);
677403e5586SChristian Eggers data->client = client;
678403e5586SChristian Eggers
679403e5586SChristian Eggers mutex_init(&data->mutex);
680403e5586SChristian Eggers init_completion(&data->completion);
681403e5586SChristian Eggers
682403e5586SChristian Eggers indio_dev->info = &as73211_info;
683403e5586SChristian Eggers indio_dev->name = AS73211_DRV_NAME;
684403e5586SChristian Eggers indio_dev->channels = as73211_channels;
685403e5586SChristian Eggers indio_dev->num_channels = ARRAY_SIZE(as73211_channels);
686403e5586SChristian Eggers indio_dev->modes = INDIO_DIRECT_MODE;
687403e5586SChristian Eggers
688403e5586SChristian Eggers ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
689403e5586SChristian Eggers if (ret < 0)
690403e5586SChristian Eggers return ret;
691403e5586SChristian Eggers data->osr = ret;
692403e5586SChristian Eggers
693403e5586SChristian Eggers /* reset device */
694403e5586SChristian Eggers data->osr |= AS73211_OSR_SW_RES;
695403e5586SChristian Eggers ret = i2c_smbus_write_byte_data(data->client, AS73211_REG_OSR, data->osr);
696403e5586SChristian Eggers if (ret < 0)
697403e5586SChristian Eggers return ret;
698403e5586SChristian Eggers
699403e5586SChristian Eggers ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_OSR);
700403e5586SChristian Eggers if (ret < 0)
701403e5586SChristian Eggers return ret;
702403e5586SChristian Eggers data->osr = ret;
703403e5586SChristian Eggers
704403e5586SChristian Eggers /*
705403e5586SChristian Eggers * Reading AGEN is only possible after reset (AGEN is not available if
706403e5586SChristian Eggers * device is in measurement mode).
707403e5586SChristian Eggers */
708403e5586SChristian Eggers ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_AGEN);
709403e5586SChristian Eggers if (ret < 0)
710403e5586SChristian Eggers return ret;
711403e5586SChristian Eggers
712403e5586SChristian Eggers /* At the time of writing this driver, only DEVID 2 and MUT 1 are known. */
713403e5586SChristian Eggers if ((ret & AS73211_AGEN_DEVID_MASK) != AS73211_AGEN_DEVID(2) ||
714403e5586SChristian Eggers (ret & AS73211_AGEN_MUT_MASK) != AS73211_AGEN_MUT(1))
715403e5586SChristian Eggers return -ENODEV;
716403e5586SChristian Eggers
717403e5586SChristian Eggers ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG1);
718403e5586SChristian Eggers if (ret < 0)
719403e5586SChristian Eggers return ret;
720403e5586SChristian Eggers data->creg1 = ret;
721403e5586SChristian Eggers
722403e5586SChristian Eggers ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG2);
723403e5586SChristian Eggers if (ret < 0)
724403e5586SChristian Eggers return ret;
725403e5586SChristian Eggers data->creg2 = ret;
726403e5586SChristian Eggers
727403e5586SChristian Eggers ret = i2c_smbus_read_byte_data(data->client, AS73211_REG_CREG3);
728403e5586SChristian Eggers if (ret < 0)
729403e5586SChristian Eggers return ret;
730403e5586SChristian Eggers data->creg3 = ret;
731403e5586SChristian Eggers as73211_integration_time_calc_avail(data);
732403e5586SChristian Eggers
733403e5586SChristian Eggers ret = as73211_power(indio_dev, true);
734403e5586SChristian Eggers if (ret < 0)
735403e5586SChristian Eggers return ret;
736403e5586SChristian Eggers
737403e5586SChristian Eggers ret = devm_add_action_or_reset(dev, as73211_power_disable, indio_dev);
738403e5586SChristian Eggers if (ret)
739403e5586SChristian Eggers return ret;
740403e5586SChristian Eggers
741403e5586SChristian Eggers ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, as73211_trigger_handler, NULL);
742403e5586SChristian Eggers if (ret)
743403e5586SChristian Eggers return ret;
744403e5586SChristian Eggers
745403e5586SChristian Eggers if (client->irq) {
746403e5586SChristian Eggers ret = devm_request_threaded_irq(&client->dev, client->irq,
747403e5586SChristian Eggers NULL,
748403e5586SChristian Eggers as73211_ready_handler,
749403e5586SChristian Eggers IRQF_ONESHOT,
750403e5586SChristian Eggers client->name, indio_dev);
751403e5586SChristian Eggers if (ret)
752403e5586SChristian Eggers return ret;
753403e5586SChristian Eggers }
754403e5586SChristian Eggers
755403e5586SChristian Eggers return devm_iio_device_register(dev, indio_dev);
756403e5586SChristian Eggers }
757403e5586SChristian Eggers
as73211_suspend(struct device * dev)758c422aa41SJonathan Cameron static int as73211_suspend(struct device *dev)
759403e5586SChristian Eggers {
760403e5586SChristian Eggers struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
761403e5586SChristian Eggers
762403e5586SChristian Eggers return as73211_power(indio_dev, false);
763403e5586SChristian Eggers }
764403e5586SChristian Eggers
as73211_resume(struct device * dev)765c422aa41SJonathan Cameron static int as73211_resume(struct device *dev)
766403e5586SChristian Eggers {
767403e5586SChristian Eggers struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
768403e5586SChristian Eggers
769403e5586SChristian Eggers return as73211_power(indio_dev, true);
770403e5586SChristian Eggers }
771403e5586SChristian Eggers
772c422aa41SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend,
773c422aa41SJonathan Cameron as73211_resume);
774403e5586SChristian Eggers
775403e5586SChristian Eggers static const struct of_device_id as73211_of_match[] = {
776403e5586SChristian Eggers { .compatible = "ams,as73211" },
777403e5586SChristian Eggers { }
778403e5586SChristian Eggers };
779403e5586SChristian Eggers MODULE_DEVICE_TABLE(of, as73211_of_match);
780403e5586SChristian Eggers
781403e5586SChristian Eggers static const struct i2c_device_id as73211_id[] = {
782403e5586SChristian Eggers { "as73211", 0 },
783403e5586SChristian Eggers { }
784403e5586SChristian Eggers };
785403e5586SChristian Eggers MODULE_DEVICE_TABLE(i2c, as73211_id);
786403e5586SChristian Eggers
787403e5586SChristian Eggers static struct i2c_driver as73211_driver = {
788403e5586SChristian Eggers .driver = {
789403e5586SChristian Eggers .name = AS73211_DRV_NAME,
790403e5586SChristian Eggers .of_match_table = as73211_of_match,
791c422aa41SJonathan Cameron .pm = pm_sleep_ptr(&as73211_pm_ops),
792403e5586SChristian Eggers },
793*7cf15f42SUwe Kleine-König .probe = as73211_probe,
794403e5586SChristian Eggers .id_table = as73211_id,
795403e5586SChristian Eggers };
796403e5586SChristian Eggers module_i2c_driver(as73211_driver);
797403e5586SChristian Eggers
798403e5586SChristian Eggers MODULE_AUTHOR("Christian Eggers <ceggers@arri.de>");
799403e5586SChristian Eggers MODULE_DESCRIPTION("AS73211 XYZ True Color Sensor driver");
800403e5586SChristian Eggers MODULE_LICENSE("GPL");
801