1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Support for AMS AS73211 JENCOLOR(R) Digital XYZ Sensor and AMS AS7331 |
4 | * UVA, UVB and UVC (DUV) Ultraviolet Sensor |
5 | * |
6 | * Author: Christian Eggers <ceggers@arri.de> |
7 | * |
8 | * Copyright (c) 2020 ARRI Lighting |
9 | * |
10 | * Color light sensor with 16-bit channels for x, y, z and temperature); |
11 | * 7-bit I2C slave address 0x74 .. 0x77. |
12 | * |
13 | * Datasheets: |
14 | * AS73211: https://ams.com/documents/20143/36005/AS73211_DS000556_3-01.pdf |
15 | * AS7331: https://ams.com/documents/20143/9106314/AS7331_DS001047_4-00.pdf |
16 | */ |
17 | |
18 | #include <linux/bitfield.h> |
19 | #include <linux/completion.h> |
20 | #include <linux/delay.h> |
21 | #include <linux/i2c.h> |
22 | #include <linux/iio/buffer.h> |
23 | #include <linux/iio/iio.h> |
24 | #include <linux/iio/sysfs.h> |
25 | #include <linux/iio/trigger_consumer.h> |
26 | #include <linux/iio/triggered_buffer.h> |
27 | #include <linux/module.h> |
28 | #include <linux/mutex.h> |
29 | #include <linux/pm.h> |
30 | #include <linux/units.h> |
31 | |
32 | #define AS73211_DRV_NAME "as73211" |
33 | |
34 | /* AS73211 configuration registers */ |
35 | #define AS73211_REG_OSR 0x0 |
36 | #define AS73211_REG_AGEN 0x2 |
37 | #define AS73211_REG_CREG1 0x6 |
38 | #define AS73211_REG_CREG2 0x7 |
39 | #define AS73211_REG_CREG3 0x8 |
40 | |
41 | /* AS73211 output register bank */ |
42 | #define AS73211_OUT_OSR_STATUS 0 |
43 | #define AS73211_OUT_TEMP 1 |
44 | #define AS73211_OUT_MRES1 2 |
45 | #define AS73211_OUT_MRES2 3 |
46 | #define AS73211_OUT_MRES3 4 |
47 | |
48 | #define AS73211_OSR_SS BIT(7) |
49 | #define AS73211_OSR_PD BIT(6) |
50 | #define AS73211_OSR_SW_RES BIT(3) |
51 | #define AS73211_OSR_DOS_MASK GENMASK(2, 0) |
52 | #define AS73211_OSR_DOS_CONFIG FIELD_PREP(AS73211_OSR_DOS_MASK, 0x2) |
53 | #define AS73211_OSR_DOS_MEASURE FIELD_PREP(AS73211_OSR_DOS_MASK, 0x3) |
54 | |
55 | #define AS73211_AGEN_DEVID_MASK GENMASK(7, 4) |
56 | #define AS73211_AGEN_DEVID(x) FIELD_PREP(AS73211_AGEN_DEVID_MASK, (x)) |
57 | #define AS73211_AGEN_MUT_MASK GENMASK(3, 0) |
58 | #define AS73211_AGEN_MUT(x) FIELD_PREP(AS73211_AGEN_MUT_MASK, (x)) |
59 | |
60 | #define AS73211_CREG1_GAIN_MASK GENMASK(7, 4) |
61 | #define AS73211_CREG1_GAIN_1 11 |
62 | #define AS73211_CREG1_TIME_MASK GENMASK(3, 0) |
63 | |
64 | #define AS73211_CREG3_CCLK_MASK GENMASK(1, 0) |
65 | |
66 | #define AS73211_OSR_STATUS_OUTCONVOF BIT(15) |
67 | #define AS73211_OSR_STATUS_MRESOF BIT(14) |
68 | #define AS73211_OSR_STATUS_ADCOF BIT(13) |
69 | #define AS73211_OSR_STATUS_LDATA BIT(12) |
70 | #define AS73211_OSR_STATUS_NDATA BIT(11) |
71 | #define AS73211_OSR_STATUS_NOTREADY BIT(10) |
72 | |
73 | #define AS73211_SAMPLE_FREQ_BASE 1024000 |
74 | |
75 | #define AS73211_SAMPLE_TIME_NUM 15 |
76 | #define AS73211_SAMPLE_TIME_MAX_MS BIT(AS73211_SAMPLE_TIME_NUM - 1) |
77 | |
78 | /* Available sample frequencies are 1.024MHz multiplied by powers of two. */ |
79 | static const int as73211_samp_freq_avail[] = { |
80 | AS73211_SAMPLE_FREQ_BASE * 1, |
81 | AS73211_SAMPLE_FREQ_BASE * 2, |
82 | AS73211_SAMPLE_FREQ_BASE * 4, |
83 | AS73211_SAMPLE_FREQ_BASE * 8, |
84 | }; |
85 | |
86 | static const int as73211_hardwaregain_avail[] = { |
87 | 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, |
88 | }; |
89 | |
90 | struct as73211_data; |
91 | |
92 | /** |
93 | * struct as73211_spec_dev_data - device-specific data |
94 | * @intensity_scale: Function to retrieve intensity scale values. |
95 | * @channels: Device channels. |
96 | * @num_channels: Number of channels of the device. |
97 | */ |
98 | struct as73211_spec_dev_data { |
99 | int (*intensity_scale)(struct as73211_data *data, int chan, int *val, int *val2); |
100 | struct iio_chan_spec const *channels; |
101 | int num_channels; |
102 | }; |
103 | |
104 | /** |
105 | * struct as73211_data - Instance data for one AS73211 |
106 | * @client: I2C client. |
107 | * @osr: Cached Operational State Register. |
108 | * @creg1: Cached Configuration Register 1. |
109 | * @creg2: Cached Configuration Register 2. |
110 | * @creg3: Cached Configuration Register 3. |
111 | * @mutex: Keeps cached registers in sync with the device. |
112 | * @completion: Completion to wait for interrupt. |
113 | * @int_time_avail: Available integration times (depend on sampling frequency). |
114 | * @spec_dev: device-specific configuration. |
115 | */ |
116 | struct as73211_data { |
117 | struct i2c_client *client; |
118 | u8 osr; |
119 | u8 creg1; |
120 | u8 creg2; |
121 | u8 creg3; |
122 | struct mutex mutex; |
123 | struct completion completion; |
124 | int int_time_avail[AS73211_SAMPLE_TIME_NUM * 2]; |
125 | const struct as73211_spec_dev_data *spec_dev; |
126 | }; |
127 | |
128 | #define AS73211_COLOR_CHANNEL(_color, _si, _addr) { \ |
129 | .type = IIO_INTENSITY, \ |
130 | .modified = 1, \ |
131 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \ |
132 | .info_mask_shared_by_type = \ |
133 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ |
134 | BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ |
135 | BIT(IIO_CHAN_INFO_INT_TIME), \ |
136 | .info_mask_shared_by_type_available = \ |
137 | BIT(IIO_CHAN_INFO_SAMP_FREQ) | \ |
138 | BIT(IIO_CHAN_INFO_HARDWAREGAIN) | \ |
139 | BIT(IIO_CHAN_INFO_INT_TIME), \ |
140 | .channel2 = IIO_MOD_##_color, \ |
141 | .address = _addr, \ |
142 | .scan_index = _si, \ |
143 | .scan_type = { \ |
144 | .sign = 'u', \ |
145 | .realbits = 16, \ |
146 | .storagebits = 16, \ |
147 | .endianness = IIO_LE, \ |
148 | }, \ |
149 | } |
150 | |
151 | #define AS73211_OFFSET_TEMP_INT (-66) |
152 | #define AS73211_OFFSET_TEMP_MICRO 900000 |
153 | #define AS73211_SCALE_TEMP_INT 0 |
154 | #define AS73211_SCALE_TEMP_MICRO 50000 |
155 | |
156 | #define AS73211_SCALE_X 277071108 /* nW/m^2 */ |
157 | #define AS73211_SCALE_Y 298384270 /* nW/m^2 */ |
158 | #define AS73211_SCALE_Z 160241927 /* nW/m^2 */ |
159 | |
160 | #define AS7331_SCALE_UVA 340000 /* nW/cm^2 */ |
161 | #define AS7331_SCALE_UVB 378000 /* nW/cm^2 */ |
162 | #define AS7331_SCALE_UVC 166000 /* nW/cm^2 */ |
163 | |
164 | /* Channel order MUST match devices result register order */ |
165 | #define AS73211_SCAN_INDEX_TEMP 0 |
166 | #define AS73211_SCAN_INDEX_X 1 |
167 | #define AS73211_SCAN_INDEX_Y 2 |
168 | #define AS73211_SCAN_INDEX_Z 3 |
169 | #define AS73211_SCAN_INDEX_TS 4 |
170 | |
171 | #define AS73211_SCAN_MASK_COLOR ( \ |
172 | BIT(AS73211_SCAN_INDEX_X) | \ |
173 | BIT(AS73211_SCAN_INDEX_Y) | \ |
174 | BIT(AS73211_SCAN_INDEX_Z)) |
175 | |
176 | #define AS73211_SCAN_MASK_ALL ( \ |
177 | BIT(AS73211_SCAN_INDEX_TEMP) | \ |
178 | AS73211_SCAN_MASK_COLOR) |
179 | |
180 | static const struct iio_chan_spec as73211_channels[] = { |
181 | { |
182 | .type = IIO_TEMP, |
183 | .info_mask_separate = |
184 | BIT(IIO_CHAN_INFO_RAW) | |
185 | BIT(IIO_CHAN_INFO_OFFSET) | |
186 | BIT(IIO_CHAN_INFO_SCALE), |
187 | .address = AS73211_OUT_TEMP, |
188 | .scan_index = AS73211_SCAN_INDEX_TEMP, |
189 | .scan_type = { |
190 | .sign = 'u', |
191 | .realbits = 16, |
192 | .storagebits = 16, |
193 | .endianness = IIO_LE, |
194 | } |
195 | }, |
196 | AS73211_COLOR_CHANNEL(X, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1), |
197 | AS73211_COLOR_CHANNEL(Y, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2), |
198 | AS73211_COLOR_CHANNEL(Z, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3), |
199 | IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), |
200 | }; |
201 | |
202 | static const struct iio_chan_spec as7331_channels[] = { |
203 | { |
204 | .type = IIO_TEMP, |
205 | .info_mask_separate = |
206 | BIT(IIO_CHAN_INFO_RAW) | |
207 | BIT(IIO_CHAN_INFO_OFFSET) | |
208 | BIT(IIO_CHAN_INFO_SCALE), |
209 | .address = AS73211_OUT_TEMP, |
210 | .scan_index = AS73211_SCAN_INDEX_TEMP, |
211 | .scan_type = { |
212 | .sign = 'u', |
213 | .realbits = 16, |
214 | .storagebits = 16, |
215 | .endianness = IIO_LE, |
216 | } |
217 | }, |
218 | AS73211_COLOR_CHANNEL(LIGHT_UVA, AS73211_SCAN_INDEX_X, AS73211_OUT_MRES1), |
219 | AS73211_COLOR_CHANNEL(LIGHT_UVB, AS73211_SCAN_INDEX_Y, AS73211_OUT_MRES2), |
220 | AS73211_COLOR_CHANNEL(LIGHT_DUV, AS73211_SCAN_INDEX_Z, AS73211_OUT_MRES3), |
221 | IIO_CHAN_SOFT_TIMESTAMP(AS73211_SCAN_INDEX_TS), |
222 | }; |
223 | |
224 | static unsigned int as73211_integration_time_1024cyc(struct as73211_data *data) |
225 | { |
226 | /* |
227 | * Return integration time in units of 1024 clock cycles. Integration time |
228 | * in CREG1 is in powers of 2 (x 1024 cycles). |
229 | */ |
230 | return BIT(FIELD_GET(AS73211_CREG1_TIME_MASK, data->creg1)); |
231 | } |
232 | |
233 | static unsigned int as73211_integration_time_us(struct as73211_data *data, |
234 | unsigned int integration_time_1024cyc) |
235 | { |
236 | /* |
237 | * f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) |
238 | * t_cycl is configured in CREG1 in powers of 2 (x 1024 cycles) |
239 | * t_int_us = 1 / (f_samp) * t_cycl * US_PER_SEC |
240 | * = 1 / (2^CREG3_CCLK * 1,024,000) * 2^CREG1_CYCLES * 1,024 * US_PER_SEC |
241 | * = 2^(-CREG3_CCLK) * 2^CREG1_CYCLES * 1,000 |
242 | * In order to get rid of negative exponents, we extend the "fraction" |
243 | * by 2^3 (CREG3_CCLK,max = 3) |
244 | * t_int_us = 2^(3-CREG3_CCLK) * 2^CREG1_CYCLES * 125 |
245 | */ |
246 | return BIT(3 - FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) * |
247 | integration_time_1024cyc * 125; |
248 | } |
249 | |
250 | static void as73211_integration_time_calc_avail(struct as73211_data *data) |
251 | { |
252 | int i; |
253 | |
254 | for (i = 0; i < ARRAY_SIZE(data->int_time_avail) / 2; i++) { |
255 | unsigned int time_us = as73211_integration_time_us(data, BIT(i)); |
256 | |
257 | data->int_time_avail[i * 2 + 0] = time_us / USEC_PER_SEC; |
258 | data->int_time_avail[i * 2 + 1] = time_us % USEC_PER_SEC; |
259 | } |
260 | } |
261 | |
262 | static unsigned int as73211_gain(struct as73211_data *data) |
263 | { |
264 | /* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */ |
265 | return BIT(AS73211_CREG1_GAIN_1 - FIELD_GET(AS73211_CREG1_GAIN_MASK, data->creg1)); |
266 | } |
267 | |
268 | /* must be called with as73211_data::mutex held. */ |
269 | static int as73211_req_data(struct as73211_data *data) |
270 | { |
271 | unsigned int time_us = as73211_integration_time_us(data, |
272 | integration_time_1024cyc: as73211_integration_time_1024cyc(data)); |
273 | struct device *dev = &data->client->dev; |
274 | union i2c_smbus_data smbus_data; |
275 | u16 osr_status; |
276 | int ret; |
277 | |
278 | if (data->client->irq) |
279 | reinit_completion(x: &data->completion); |
280 | |
281 | /* |
282 | * During measurement, there should be no traffic on the i2c bus as the |
283 | * electrical noise would disturb the measurement process. |
284 | */ |
285 | i2c_lock_bus(adapter: data->client->adapter, I2C_LOCK_SEGMENT); |
286 | |
287 | data->osr &= ~AS73211_OSR_DOS_MASK; |
288 | data->osr |= AS73211_OSR_DOS_MEASURE | AS73211_OSR_SS; |
289 | |
290 | smbus_data.byte = data->osr; |
291 | ret = __i2c_smbus_xfer(adapter: data->client->adapter, addr: data->client->addr, |
292 | flags: data->client->flags, I2C_SMBUS_WRITE, |
293 | AS73211_REG_OSR, I2C_SMBUS_BYTE_DATA, data: &smbus_data); |
294 | if (ret < 0) { |
295 | i2c_unlock_bus(adapter: data->client->adapter, I2C_LOCK_SEGMENT); |
296 | return ret; |
297 | } |
298 | |
299 | /* |
300 | * Reset AS73211_OSR_SS (is self clearing) in order to avoid unintentional |
301 | * triggering of further measurements later. |
302 | */ |
303 | data->osr &= ~AS73211_OSR_SS; |
304 | |
305 | /* |
306 | * Add 33% extra margin for the timeout. fclk,min = fclk,typ - 27%. |
307 | */ |
308 | time_us += time_us / 3; |
309 | if (data->client->irq) { |
310 | ret = wait_for_completion_timeout(x: &data->completion, timeout: usecs_to_jiffies(u: time_us)); |
311 | if (!ret) { |
312 | dev_err(dev, "timeout waiting for READY IRQ\n" ); |
313 | i2c_unlock_bus(adapter: data->client->adapter, I2C_LOCK_SEGMENT); |
314 | return -ETIMEDOUT; |
315 | } |
316 | } else { |
317 | /* Wait integration time */ |
318 | usleep_range(min: time_us, max: 2 * time_us); |
319 | } |
320 | |
321 | i2c_unlock_bus(adapter: data->client->adapter, I2C_LOCK_SEGMENT); |
322 | |
323 | ret = i2c_smbus_read_word_data(client: data->client, AS73211_OUT_OSR_STATUS); |
324 | if (ret < 0) |
325 | return ret; |
326 | |
327 | osr_status = ret; |
328 | if (osr_status != (AS73211_OSR_DOS_MEASURE | AS73211_OSR_STATUS_NDATA)) { |
329 | if (osr_status & AS73211_OSR_SS) { |
330 | dev_err(dev, "%s() Measurement has not stopped\n" , __func__); |
331 | return -ETIME; |
332 | } |
333 | if (osr_status & AS73211_OSR_STATUS_NOTREADY) { |
334 | dev_err(dev, "%s() Data is not ready\n" , __func__); |
335 | return -ENODATA; |
336 | } |
337 | if (!(osr_status & AS73211_OSR_STATUS_NDATA)) { |
338 | dev_err(dev, "%s() No new data available\n" , __func__); |
339 | return -ENODATA; |
340 | } |
341 | if (osr_status & AS73211_OSR_STATUS_LDATA) { |
342 | dev_err(dev, "%s() Result buffer overrun\n" , __func__); |
343 | return -ENOBUFS; |
344 | } |
345 | if (osr_status & AS73211_OSR_STATUS_ADCOF) { |
346 | dev_err(dev, "%s() ADC overflow\n" , __func__); |
347 | return -EOVERFLOW; |
348 | } |
349 | if (osr_status & AS73211_OSR_STATUS_MRESOF) { |
350 | dev_err(dev, "%s() Measurement result overflow\n" , __func__); |
351 | return -EOVERFLOW; |
352 | } |
353 | if (osr_status & AS73211_OSR_STATUS_OUTCONVOF) { |
354 | dev_err(dev, "%s() Timer overflow\n" , __func__); |
355 | return -EOVERFLOW; |
356 | } |
357 | dev_err(dev, "%s() Unexpected status value\n" , __func__); |
358 | return -EIO; |
359 | } |
360 | |
361 | return 0; |
362 | } |
363 | |
364 | static int as73211_intensity_scale(struct as73211_data *data, int chan, |
365 | int *val, int *val2) |
366 | { |
367 | switch (chan) { |
368 | case IIO_MOD_X: |
369 | *val = AS73211_SCALE_X; |
370 | break; |
371 | case IIO_MOD_Y: |
372 | *val = AS73211_SCALE_Y; |
373 | break; |
374 | case IIO_MOD_Z: |
375 | *val = AS73211_SCALE_Z; |
376 | break; |
377 | default: |
378 | return -EINVAL; |
379 | } |
380 | *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data); |
381 | |
382 | return IIO_VAL_FRACTIONAL; |
383 | } |
384 | |
385 | static int as7331_intensity_scale(struct as73211_data *data, int chan, |
386 | int *val, int *val2) |
387 | { |
388 | switch (chan) { |
389 | case IIO_MOD_LIGHT_UVA: |
390 | *val = AS7331_SCALE_UVA; |
391 | break; |
392 | case IIO_MOD_LIGHT_UVB: |
393 | *val = AS7331_SCALE_UVB; |
394 | break; |
395 | case IIO_MOD_LIGHT_DUV: |
396 | *val = AS7331_SCALE_UVC; |
397 | break; |
398 | default: |
399 | return -EINVAL; |
400 | } |
401 | *val2 = as73211_integration_time_1024cyc(data) * as73211_gain(data); |
402 | |
403 | return IIO_VAL_FRACTIONAL; |
404 | } |
405 | |
406 | static int as73211_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
407 | int *val, int *val2, long mask) |
408 | { |
409 | struct as73211_data *data = iio_priv(indio_dev); |
410 | |
411 | switch (mask) { |
412 | case IIO_CHAN_INFO_RAW: { |
413 | int ret; |
414 | |
415 | ret = iio_device_claim_direct_mode(indio_dev); |
416 | if (ret < 0) |
417 | return ret; |
418 | |
419 | ret = as73211_req_data(data); |
420 | if (ret < 0) { |
421 | iio_device_release_direct_mode(indio_dev); |
422 | return ret; |
423 | } |
424 | |
425 | ret = i2c_smbus_read_word_data(client: data->client, command: chan->address); |
426 | iio_device_release_direct_mode(indio_dev); |
427 | if (ret < 0) |
428 | return ret; |
429 | |
430 | *val = ret; |
431 | return IIO_VAL_INT; |
432 | } |
433 | case IIO_CHAN_INFO_OFFSET: |
434 | *val = AS73211_OFFSET_TEMP_INT; |
435 | *val2 = AS73211_OFFSET_TEMP_MICRO; |
436 | return IIO_VAL_INT_PLUS_MICRO; |
437 | |
438 | case IIO_CHAN_INFO_SCALE: |
439 | switch (chan->type) { |
440 | case IIO_TEMP: |
441 | *val = AS73211_SCALE_TEMP_INT; |
442 | *val2 = AS73211_SCALE_TEMP_MICRO; |
443 | return IIO_VAL_INT_PLUS_MICRO; |
444 | |
445 | case IIO_INTENSITY: |
446 | return data->spec_dev->intensity_scale(data, chan->channel2, |
447 | val, val2); |
448 | |
449 | default: |
450 | return -EINVAL; |
451 | } |
452 | |
453 | case IIO_CHAN_INFO_SAMP_FREQ: |
454 | /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */ |
455 | *val = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)) * |
456 | AS73211_SAMPLE_FREQ_BASE; |
457 | return IIO_VAL_INT; |
458 | |
459 | case IIO_CHAN_INFO_HARDWAREGAIN: |
460 | *val = as73211_gain(data); |
461 | return IIO_VAL_INT; |
462 | |
463 | case IIO_CHAN_INFO_INT_TIME: { |
464 | unsigned int time_us; |
465 | |
466 | mutex_lock(&data->mutex); |
467 | time_us = as73211_integration_time_us(data, integration_time_1024cyc: as73211_integration_time_1024cyc(data)); |
468 | mutex_unlock(lock: &data->mutex); |
469 | *val = time_us / USEC_PER_SEC; |
470 | *val2 = time_us % USEC_PER_SEC; |
471 | return IIO_VAL_INT_PLUS_MICRO; |
472 | |
473 | default: |
474 | return -EINVAL; |
475 | }} |
476 | } |
477 | |
478 | static int as73211_read_avail(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
479 | const int **vals, int *type, int *length, long mask) |
480 | { |
481 | struct as73211_data *data = iio_priv(indio_dev); |
482 | |
483 | switch (mask) { |
484 | case IIO_CHAN_INFO_SAMP_FREQ: |
485 | *length = ARRAY_SIZE(as73211_samp_freq_avail); |
486 | *vals = as73211_samp_freq_avail; |
487 | *type = IIO_VAL_INT; |
488 | return IIO_AVAIL_LIST; |
489 | |
490 | case IIO_CHAN_INFO_HARDWAREGAIN: |
491 | *length = ARRAY_SIZE(as73211_hardwaregain_avail); |
492 | *vals = as73211_hardwaregain_avail; |
493 | *type = IIO_VAL_INT; |
494 | return IIO_AVAIL_LIST; |
495 | |
496 | case IIO_CHAN_INFO_INT_TIME: |
497 | *length = ARRAY_SIZE(data->int_time_avail); |
498 | *vals = data->int_time_avail; |
499 | *type = IIO_VAL_INT_PLUS_MICRO; |
500 | return IIO_AVAIL_LIST; |
501 | |
502 | default: |
503 | return -EINVAL; |
504 | } |
505 | } |
506 | |
507 | static int _as73211_write_raw(struct iio_dev *indio_dev, |
508 | struct iio_chan_spec const *chan __always_unused, |
509 | int val, int val2, long mask) |
510 | { |
511 | struct as73211_data *data = iio_priv(indio_dev); |
512 | int ret; |
513 | |
514 | switch (mask) { |
515 | case IIO_CHAN_INFO_SAMP_FREQ: { |
516 | int reg_bits, freq_kHz = val / HZ_PER_KHZ; /* 1024, 2048, ... */ |
517 | |
518 | /* val must be 1024 * 2^x */ |
519 | if (val < 0 || (freq_kHz * HZ_PER_KHZ) != val || |
520 | !is_power_of_2(n: freq_kHz) || val2) |
521 | return -EINVAL; |
522 | |
523 | /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz (=2^10)) */ |
524 | reg_bits = ilog2(freq_kHz) - 10; |
525 | if (!FIELD_FIT(AS73211_CREG3_CCLK_MASK, reg_bits)) |
526 | return -EINVAL; |
527 | |
528 | data->creg3 &= ~AS73211_CREG3_CCLK_MASK; |
529 | data->creg3 |= FIELD_PREP(AS73211_CREG3_CCLK_MASK, reg_bits); |
530 | as73211_integration_time_calc_avail(data); |
531 | |
532 | ret = i2c_smbus_write_byte_data(client: data->client, AS73211_REG_CREG3, value: data->creg3); |
533 | if (ret < 0) |
534 | return ret; |
535 | |
536 | return 0; |
537 | } |
538 | case IIO_CHAN_INFO_HARDWAREGAIN: { |
539 | unsigned int reg_bits; |
540 | |
541 | if (val < 0 || !is_power_of_2(n: val) || val2) |
542 | return -EINVAL; |
543 | |
544 | /* gain can be calculated from CREG1 as 2^(11 - CREG1_GAIN) */ |
545 | reg_bits = AS73211_CREG1_GAIN_1 - ilog2(val); |
546 | if (!FIELD_FIT(AS73211_CREG1_GAIN_MASK, reg_bits)) |
547 | return -EINVAL; |
548 | |
549 | data->creg1 &= ~AS73211_CREG1_GAIN_MASK; |
550 | data->creg1 |= FIELD_PREP(AS73211_CREG1_GAIN_MASK, reg_bits); |
551 | |
552 | ret = i2c_smbus_write_byte_data(client: data->client, AS73211_REG_CREG1, value: data->creg1); |
553 | if (ret < 0) |
554 | return ret; |
555 | |
556 | return 0; |
557 | } |
558 | case IIO_CHAN_INFO_INT_TIME: { |
559 | int val_us = val * USEC_PER_SEC + val2; |
560 | int time_ms; |
561 | int reg_bits; |
562 | |
563 | /* f_samp is configured in CREG3 in powers of 2 (x 1.024 MHz) */ |
564 | int f_samp_1_024mhz = BIT(FIELD_GET(AS73211_CREG3_CCLK_MASK, data->creg3)); |
565 | |
566 | /* |
567 | * time_ms = time_us * US_PER_MS * f_samp_1_024mhz / MHZ_PER_HZ |
568 | * = time_us * f_samp_1_024mhz / 1000 |
569 | */ |
570 | time_ms = (val_us * f_samp_1_024mhz) / 1000; /* 1 ms, 2 ms, ... (power of two) */ |
571 | if (time_ms < 0 || !is_power_of_2(n: time_ms) || time_ms > AS73211_SAMPLE_TIME_MAX_MS) |
572 | return -EINVAL; |
573 | |
574 | reg_bits = ilog2(time_ms); |
575 | if (!FIELD_FIT(AS73211_CREG1_TIME_MASK, reg_bits)) |
576 | return -EINVAL; /* not possible due to previous tests */ |
577 | |
578 | data->creg1 &= ~AS73211_CREG1_TIME_MASK; |
579 | data->creg1 |= FIELD_PREP(AS73211_CREG1_TIME_MASK, reg_bits); |
580 | |
581 | ret = i2c_smbus_write_byte_data(client: data->client, AS73211_REG_CREG1, value: data->creg1); |
582 | if (ret < 0) |
583 | return ret; |
584 | |
585 | return 0; |
586 | |
587 | default: |
588 | return -EINVAL; |
589 | }} |
590 | } |
591 | |
592 | static int as73211_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, |
593 | int val, int val2, long mask) |
594 | { |
595 | struct as73211_data *data = iio_priv(indio_dev); |
596 | int ret; |
597 | |
598 | mutex_lock(&data->mutex); |
599 | |
600 | ret = iio_device_claim_direct_mode(indio_dev); |
601 | if (ret < 0) |
602 | goto error_unlock; |
603 | |
604 | /* Need to switch to config mode ... */ |
605 | if ((data->osr & AS73211_OSR_DOS_MASK) != AS73211_OSR_DOS_CONFIG) { |
606 | data->osr &= ~AS73211_OSR_DOS_MASK; |
607 | data->osr |= AS73211_OSR_DOS_CONFIG; |
608 | |
609 | ret = i2c_smbus_write_byte_data(client: data->client, AS73211_REG_OSR, value: data->osr); |
610 | if (ret < 0) |
611 | goto error_release; |
612 | } |
613 | |
614 | ret = _as73211_write_raw(indio_dev, chan, val, val2, mask); |
615 | |
616 | error_release: |
617 | iio_device_release_direct_mode(indio_dev); |
618 | error_unlock: |
619 | mutex_unlock(lock: &data->mutex); |
620 | return ret; |
621 | } |
622 | |
623 | static irqreturn_t as73211_ready_handler(int irq __always_unused, void *priv) |
624 | { |
625 | struct as73211_data *data = iio_priv(indio_dev: priv); |
626 | |
627 | complete(&data->completion); |
628 | |
629 | return IRQ_HANDLED; |
630 | } |
631 | |
632 | static irqreturn_t as73211_trigger_handler(int irq __always_unused, void *p) |
633 | { |
634 | struct iio_poll_func *pf = p; |
635 | struct iio_dev *indio_dev = pf->indio_dev; |
636 | struct as73211_data *data = iio_priv(indio_dev); |
637 | struct { |
638 | __le16 chan[4]; |
639 | s64 ts __aligned(8); |
640 | } scan; |
641 | int data_result, ret; |
642 | |
643 | mutex_lock(&data->mutex); |
644 | |
645 | data_result = as73211_req_data(data); |
646 | if (data_result < 0 && data_result != -EOVERFLOW) |
647 | goto done; /* don't push any data for errors other than EOVERFLOW */ |
648 | |
649 | if (*indio_dev->active_scan_mask == AS73211_SCAN_MASK_ALL) { |
650 | /* Optimization for reading all (color + temperature) channels */ |
651 | u8 addr = as73211_channels[0].address; |
652 | struct i2c_msg msgs[] = { |
653 | { |
654 | .addr = data->client->addr, |
655 | .flags = 0, |
656 | .len = 1, |
657 | .buf = &addr, |
658 | }, |
659 | { |
660 | .addr = data->client->addr, |
661 | .flags = I2C_M_RD, |
662 | .len = sizeof(scan.chan), |
663 | .buf = (u8 *)&scan.chan, |
664 | }, |
665 | }; |
666 | |
667 | ret = i2c_transfer(adap: data->client->adapter, msgs, ARRAY_SIZE(msgs)); |
668 | if (ret < 0) |
669 | goto done; |
670 | } else { |
671 | /* Optimization for reading only color channels */ |
672 | |
673 | /* AS73211 starts reading at address 2 */ |
674 | ret = i2c_master_recv(client: data->client, |
675 | buf: (char *)&scan.chan[1], count: 3 * sizeof(scan.chan[1])); |
676 | if (ret < 0) |
677 | goto done; |
678 | } |
679 | |
680 | if (data_result) { |
681 | /* |
682 | * Saturate all channels (in case of overflows). Temperature channel |
683 | * is not affected by overflows. |
684 | */ |
685 | scan.chan[1] = cpu_to_le16(U16_MAX); |
686 | scan.chan[2] = cpu_to_le16(U16_MAX); |
687 | scan.chan[3] = cpu_to_le16(U16_MAX); |
688 | } |
689 | |
690 | iio_push_to_buffers_with_timestamp(indio_dev, data: &scan, timestamp: iio_get_time_ns(indio_dev)); |
691 | |
692 | done: |
693 | mutex_unlock(lock: &data->mutex); |
694 | iio_trigger_notify_done(trig: indio_dev->trig); |
695 | |
696 | return IRQ_HANDLED; |
697 | } |
698 | |
699 | static const struct iio_info as73211_info = { |
700 | .read_raw = as73211_read_raw, |
701 | .read_avail = as73211_read_avail, |
702 | .write_raw = as73211_write_raw, |
703 | }; |
704 | |
705 | static int as73211_power(struct iio_dev *indio_dev, bool state) |
706 | { |
707 | struct as73211_data *data = iio_priv(indio_dev); |
708 | int ret; |
709 | |
710 | mutex_lock(&data->mutex); |
711 | |
712 | if (state) |
713 | data->osr &= ~AS73211_OSR_PD; |
714 | else |
715 | data->osr |= AS73211_OSR_PD; |
716 | |
717 | ret = i2c_smbus_write_byte_data(client: data->client, AS73211_REG_OSR, value: data->osr); |
718 | |
719 | mutex_unlock(lock: &data->mutex); |
720 | |
721 | if (ret < 0) |
722 | return ret; |
723 | |
724 | return 0; |
725 | } |
726 | |
727 | static void as73211_power_disable(void *data) |
728 | { |
729 | struct iio_dev *indio_dev = data; |
730 | |
731 | as73211_power(indio_dev, state: false); |
732 | } |
733 | |
734 | static int as73211_probe(struct i2c_client *client) |
735 | { |
736 | struct device *dev = &client->dev; |
737 | struct as73211_data *data; |
738 | struct iio_dev *indio_dev; |
739 | int ret; |
740 | |
741 | indio_dev = devm_iio_device_alloc(parent: dev, sizeof_priv: sizeof(*data)); |
742 | if (!indio_dev) |
743 | return -ENOMEM; |
744 | |
745 | data = iio_priv(indio_dev); |
746 | i2c_set_clientdata(client, data: indio_dev); |
747 | data->client = client; |
748 | |
749 | data->spec_dev = i2c_get_match_data(client); |
750 | if (!data->spec_dev) |
751 | return -EINVAL; |
752 | |
753 | mutex_init(&data->mutex); |
754 | init_completion(x: &data->completion); |
755 | |
756 | indio_dev->info = &as73211_info; |
757 | indio_dev->name = AS73211_DRV_NAME; |
758 | indio_dev->channels = data->spec_dev->channels; |
759 | indio_dev->num_channels = data->spec_dev->num_channels; |
760 | indio_dev->modes = INDIO_DIRECT_MODE; |
761 | |
762 | ret = i2c_smbus_read_byte_data(client: data->client, AS73211_REG_OSR); |
763 | if (ret < 0) |
764 | return ret; |
765 | data->osr = ret; |
766 | |
767 | /* reset device */ |
768 | data->osr |= AS73211_OSR_SW_RES; |
769 | ret = i2c_smbus_write_byte_data(client: data->client, AS73211_REG_OSR, value: data->osr); |
770 | if (ret < 0) |
771 | return ret; |
772 | |
773 | ret = i2c_smbus_read_byte_data(client: data->client, AS73211_REG_OSR); |
774 | if (ret < 0) |
775 | return ret; |
776 | data->osr = ret; |
777 | |
778 | /* |
779 | * Reading AGEN is only possible after reset (AGEN is not available if |
780 | * device is in measurement mode). |
781 | */ |
782 | ret = i2c_smbus_read_byte_data(client: data->client, AS73211_REG_AGEN); |
783 | if (ret < 0) |
784 | return ret; |
785 | |
786 | /* At the time of writing this driver, only DEVID 2 and MUT 1 are known. */ |
787 | if ((ret & AS73211_AGEN_DEVID_MASK) != AS73211_AGEN_DEVID(2) || |
788 | (ret & AS73211_AGEN_MUT_MASK) != AS73211_AGEN_MUT(1)) |
789 | return -ENODEV; |
790 | |
791 | ret = i2c_smbus_read_byte_data(client: data->client, AS73211_REG_CREG1); |
792 | if (ret < 0) |
793 | return ret; |
794 | data->creg1 = ret; |
795 | |
796 | ret = i2c_smbus_read_byte_data(client: data->client, AS73211_REG_CREG2); |
797 | if (ret < 0) |
798 | return ret; |
799 | data->creg2 = ret; |
800 | |
801 | ret = i2c_smbus_read_byte_data(client: data->client, AS73211_REG_CREG3); |
802 | if (ret < 0) |
803 | return ret; |
804 | data->creg3 = ret; |
805 | as73211_integration_time_calc_avail(data); |
806 | |
807 | ret = as73211_power(indio_dev, state: true); |
808 | if (ret < 0) |
809 | return ret; |
810 | |
811 | ret = devm_add_action_or_reset(dev, as73211_power_disable, indio_dev); |
812 | if (ret) |
813 | return ret; |
814 | |
815 | ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, as73211_trigger_handler, NULL); |
816 | if (ret) |
817 | return ret; |
818 | |
819 | if (client->irq) { |
820 | ret = devm_request_threaded_irq(dev: &client->dev, irq: client->irq, |
821 | NULL, |
822 | thread_fn: as73211_ready_handler, |
823 | IRQF_ONESHOT, |
824 | devname: client->name, dev_id: indio_dev); |
825 | if (ret) |
826 | return ret; |
827 | } |
828 | |
829 | return devm_iio_device_register(dev, indio_dev); |
830 | } |
831 | |
832 | static int as73211_suspend(struct device *dev) |
833 | { |
834 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
835 | |
836 | return as73211_power(indio_dev, state: false); |
837 | } |
838 | |
839 | static int as73211_resume(struct device *dev) |
840 | { |
841 | struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev)); |
842 | |
843 | return as73211_power(indio_dev, state: true); |
844 | } |
845 | |
846 | static DEFINE_SIMPLE_DEV_PM_OPS(as73211_pm_ops, as73211_suspend, |
847 | as73211_resume); |
848 | |
849 | static const struct as73211_spec_dev_data as73211_spec = { |
850 | .intensity_scale = as73211_intensity_scale, |
851 | .channels = as73211_channels, |
852 | .num_channels = ARRAY_SIZE(as73211_channels), |
853 | }; |
854 | |
855 | static const struct as73211_spec_dev_data as7331_spec = { |
856 | .intensity_scale = as7331_intensity_scale, |
857 | .channels = as7331_channels, |
858 | .num_channels = ARRAY_SIZE(as7331_channels), |
859 | }; |
860 | |
861 | static const struct of_device_id as73211_of_match[] = { |
862 | { .compatible = "ams,as73211" , &as73211_spec }, |
863 | { .compatible = "ams,as7331" , &as7331_spec }, |
864 | { } |
865 | }; |
866 | MODULE_DEVICE_TABLE(of, as73211_of_match); |
867 | |
868 | static const struct i2c_device_id as73211_id[] = { |
869 | { "as73211" , (kernel_ulong_t)&as73211_spec }, |
870 | { "as7331" , (kernel_ulong_t)&as7331_spec }, |
871 | { } |
872 | }; |
873 | MODULE_DEVICE_TABLE(i2c, as73211_id); |
874 | |
875 | static struct i2c_driver as73211_driver = { |
876 | .driver = { |
877 | .name = AS73211_DRV_NAME, |
878 | .of_match_table = as73211_of_match, |
879 | .pm = pm_sleep_ptr(&as73211_pm_ops), |
880 | }, |
881 | .probe = as73211_probe, |
882 | .id_table = as73211_id, |
883 | }; |
884 | module_i2c_driver(as73211_driver); |
885 | |
886 | MODULE_AUTHOR("Christian Eggers <ceggers@arri.de>" ); |
887 | MODULE_DESCRIPTION("AS73211 XYZ True Color Sensor driver" ); |
888 | MODULE_LICENSE("GPL" ); |
889 | |