]>
Commit | Line | Data |
---|---|---|
87aec56e AD |
1 | /* |
2 | * AFE4404 Heart Rate Monitors and Low-Cost Pulse Oximeters | |
3 | * | |
4 | * Copyright (C) 2015 Texas Instruments Incorporated - http://www.ti.com/ | |
5 | * Andrew F. Davis <[email protected]> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but | |
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * General Public License for more details. | |
15 | */ | |
16 | ||
17 | #include <linux/device.h> | |
18 | #include <linux/err.h> | |
19 | #include <linux/interrupt.h> | |
20 | #include <linux/i2c.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/module.h> | |
23 | #include <linux/regmap.h> | |
24 | #include <linux/sysfs.h> | |
25 | #include <linux/regulator/consumer.h> | |
26 | ||
27 | #include <linux/iio/iio.h> | |
28 | #include <linux/iio/sysfs.h> | |
29 | #include <linux/iio/buffer.h> | |
30 | #include <linux/iio/trigger.h> | |
31 | #include <linux/iio/triggered_buffer.h> | |
32 | #include <linux/iio/trigger_consumer.h> | |
33 | ||
34 | #include "afe440x.h" | |
35 | ||
36 | #define AFE4404_DRIVER_NAME "afe4404" | |
37 | ||
38 | /* AFE4404 registers */ | |
39 | #define AFE4404_TIA_GAIN_SEP 0x20 | |
40 | #define AFE4404_TIA_GAIN 0x21 | |
41 | #define AFE4404_PROG_TG_STC 0x34 | |
42 | #define AFE4404_PROG_TG_ENDC 0x35 | |
43 | #define AFE4404_LED3LEDSTC 0x36 | |
44 | #define AFE4404_LED3LEDENDC 0x37 | |
45 | #define AFE4404_CLKDIV_PRF 0x39 | |
46 | #define AFE4404_OFFDAC 0x3a | |
47 | #define AFE4404_DEC 0x3d | |
48 | #define AFE4404_AVG_LED2_ALED2VAL 0x3f | |
49 | #define AFE4404_AVG_LED1_ALED1VAL 0x40 | |
50 | ||
51 | /* AFE4404 GAIN register fields */ | |
52 | #define AFE4404_TIA_GAIN_RES_MASK GENMASK(2, 0) | |
53 | #define AFE4404_TIA_GAIN_RES_SHIFT 0 | |
54 | #define AFE4404_TIA_GAIN_CAP_MASK GENMASK(5, 3) | |
55 | #define AFE4404_TIA_GAIN_CAP_SHIFT 3 | |
56 | ||
57 | /* AFE4404 LEDCNTRL register fields */ | |
58 | #define AFE4404_LEDCNTRL_ILED1_MASK GENMASK(5, 0) | |
59 | #define AFE4404_LEDCNTRL_ILED1_SHIFT 0 | |
60 | #define AFE4404_LEDCNTRL_ILED2_MASK GENMASK(11, 6) | |
61 | #define AFE4404_LEDCNTRL_ILED2_SHIFT 6 | |
62 | #define AFE4404_LEDCNTRL_ILED3_MASK GENMASK(17, 12) | |
63 | #define AFE4404_LEDCNTRL_ILED3_SHIFT 12 | |
64 | ||
65 | /* AFE4404 CONTROL2 register fields */ | |
66 | #define AFE440X_CONTROL2_ILED_2X_MASK BIT(17) | |
67 | #define AFE440X_CONTROL2_ILED_2X_SHIFT 17 | |
68 | ||
69 | /* AFE4404 CONTROL3 register fields */ | |
70 | #define AFE440X_CONTROL3_OSC_ENABLE BIT(9) | |
71 | ||
72 | /* AFE4404 OFFDAC register current fields */ | |
73 | #define AFE4404_OFFDAC_CURR_LED1_MASK GENMASK(9, 5) | |
74 | #define AFE4404_OFFDAC_CURR_LED1_SHIFT 5 | |
75 | #define AFE4404_OFFDAC_CURR_LED2_MASK GENMASK(19, 15) | |
76 | #define AFE4404_OFFDAC_CURR_LED2_SHIFT 15 | |
77 | #define AFE4404_OFFDAC_CURR_LED3_MASK GENMASK(4, 0) | |
78 | #define AFE4404_OFFDAC_CURR_LED3_SHIFT 0 | |
79 | #define AFE4404_OFFDAC_CURR_ALED1_MASK GENMASK(14, 10) | |
80 | #define AFE4404_OFFDAC_CURR_ALED1_SHIFT 10 | |
81 | #define AFE4404_OFFDAC_CURR_ALED2_MASK GENMASK(4, 0) | |
82 | #define AFE4404_OFFDAC_CURR_ALED2_SHIFT 0 | |
83 | ||
84 | /* AFE4404 NULL fields */ | |
85 | #define NULL_MASK 0 | |
86 | #define NULL_SHIFT 0 | |
87 | ||
88 | /* AFE4404 TIA_GAIN_CAP values */ | |
89 | #define AFE4404_TIA_GAIN_CAP_5_P 0x0 | |
90 | #define AFE4404_TIA_GAIN_CAP_2_5_P 0x1 | |
91 | #define AFE4404_TIA_GAIN_CAP_10_P 0x2 | |
92 | #define AFE4404_TIA_GAIN_CAP_7_5_P 0x3 | |
93 | #define AFE4404_TIA_GAIN_CAP_20_P 0x4 | |
94 | #define AFE4404_TIA_GAIN_CAP_17_5_P 0x5 | |
95 | #define AFE4404_TIA_GAIN_CAP_25_P 0x6 | |
96 | #define AFE4404_TIA_GAIN_CAP_22_5_P 0x7 | |
97 | ||
98 | /* AFE4404 TIA_GAIN_RES values */ | |
99 | #define AFE4404_TIA_GAIN_RES_500_K 0x0 | |
100 | #define AFE4404_TIA_GAIN_RES_250_K 0x1 | |
101 | #define AFE4404_TIA_GAIN_RES_100_K 0x2 | |
102 | #define AFE4404_TIA_GAIN_RES_50_K 0x3 | |
103 | #define AFE4404_TIA_GAIN_RES_25_K 0x4 | |
104 | #define AFE4404_TIA_GAIN_RES_10_K 0x5 | |
105 | #define AFE4404_TIA_GAIN_RES_1_M 0x6 | |
106 | #define AFE4404_TIA_GAIN_RES_2_M 0x7 | |
107 | ||
108 | /** | |
109 | * struct afe4404_data | |
110 | * @dev - Device structure | |
111 | * @regmap - Register map of the device | |
112 | * @regulator - Pointer to the regulator for the IC | |
113 | * @trig - IIO trigger for this device | |
114 | * @irq - ADC_RDY line interrupt number | |
115 | */ | |
116 | struct afe4404_data { | |
117 | struct device *dev; | |
118 | struct regmap *regmap; | |
119 | struct regulator *regulator; | |
120 | struct iio_trigger *trig; | |
121 | int irq; | |
122 | }; | |
123 | ||
124 | enum afe4404_chan_id { | |
125 | LED1, | |
126 | ALED1, | |
127 | LED2, | |
128 | ALED2, | |
129 | LED3, | |
130 | LED1_ALED1, | |
131 | LED2_ALED2, | |
132 | ILED1, | |
133 | ILED2, | |
134 | ILED3, | |
135 | }; | |
136 | ||
137 | static const struct afe440x_reg_info afe4404_reg_info[] = { | |
138 | [LED1] = AFE440X_REG_INFO(AFE440X_LED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED1), | |
139 | [ALED1] = AFE440X_REG_INFO(AFE440X_ALED1VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED1), | |
140 | [LED2] = AFE440X_REG_INFO(AFE440X_LED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_LED2), | |
141 | [ALED2] = AFE440X_REG_INFO(AFE440X_ALED2VAL, AFE4404_OFFDAC, AFE4404_OFFDAC_CURR_ALED2), | |
142 | [LED3] = AFE440X_REG_INFO(AFE440X_ALED2VAL, 0, NULL), | |
143 | [LED1_ALED1] = AFE440X_REG_INFO(AFE440X_LED1_ALED1VAL, 0, NULL), | |
144 | [LED2_ALED2] = AFE440X_REG_INFO(AFE440X_LED2_ALED2VAL, 0, NULL), | |
145 | [ILED1] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED1), | |
146 | [ILED2] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED2), | |
147 | [ILED3] = AFE440X_REG_INFO(AFE440X_LEDCNTRL, 0, AFE4404_LEDCNTRL_ILED3), | |
148 | }; | |
149 | ||
150 | static const struct iio_chan_spec afe4404_channels[] = { | |
151 | /* ADC values */ | |
152 | AFE440X_INTENSITY_CHAN(LED1, "led1", BIT(IIO_CHAN_INFO_OFFSET)), | |
153 | AFE440X_INTENSITY_CHAN(ALED1, "led1_ambient", BIT(IIO_CHAN_INFO_OFFSET)), | |
154 | AFE440X_INTENSITY_CHAN(LED2, "led2", BIT(IIO_CHAN_INFO_OFFSET)), | |
155 | AFE440X_INTENSITY_CHAN(ALED2, "led2_ambient", BIT(IIO_CHAN_INFO_OFFSET)), | |
156 | AFE440X_INTENSITY_CHAN(LED3, "led3", BIT(IIO_CHAN_INFO_OFFSET)), | |
157 | AFE440X_INTENSITY_CHAN(LED1_ALED1, "led1-led1_ambient", 0), | |
158 | AFE440X_INTENSITY_CHAN(LED2_ALED2, "led2-led2_ambient", 0), | |
159 | /* LED current */ | |
160 | AFE440X_CURRENT_CHAN(ILED1, "led1"), | |
161 | AFE440X_CURRENT_CHAN(ILED2, "led2"), | |
162 | AFE440X_CURRENT_CHAN(ILED3, "led3"), | |
163 | }; | |
164 | ||
165 | static const struct afe440x_val_table afe4404_res_table[] = { | |
166 | { .integer = 500000, .fract = 0 }, | |
167 | { .integer = 250000, .fract = 0 }, | |
168 | { .integer = 100000, .fract = 0 }, | |
169 | { .integer = 50000, .fract = 0 }, | |
170 | { .integer = 25000, .fract = 0 }, | |
171 | { .integer = 10000, .fract = 0 }, | |
172 | { .integer = 1000000, .fract = 0 }, | |
173 | { .integer = 2000000, .fract = 0 }, | |
174 | }; | |
175 | AFE440X_TABLE_ATTR(tia_resistance_available, afe4404_res_table); | |
176 | ||
177 | static const struct afe440x_val_table afe4404_cap_table[] = { | |
178 | { .integer = 0, .fract = 5000 }, | |
179 | { .integer = 0, .fract = 2500 }, | |
180 | { .integer = 0, .fract = 10000 }, | |
181 | { .integer = 0, .fract = 7500 }, | |
182 | { .integer = 0, .fract = 20000 }, | |
183 | { .integer = 0, .fract = 17500 }, | |
184 | { .integer = 0, .fract = 25000 }, | |
185 | { .integer = 0, .fract = 22500 }, | |
186 | }; | |
187 | AFE440X_TABLE_ATTR(tia_capacitance_available, afe4404_cap_table); | |
188 | ||
189 | static ssize_t afe440x_show_register(struct device *dev, | |
190 | struct device_attribute *attr, | |
191 | char *buf) | |
192 | { | |
193 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
194 | struct afe4404_data *afe = iio_priv(indio_dev); | |
195 | struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr); | |
196 | unsigned int reg_val, type; | |
197 | int vals[2]; | |
198 | int ret, val_len; | |
199 | ||
200 | ret = regmap_read(afe->regmap, afe440x_attr->reg, ®_val); | |
201 | if (ret) | |
202 | return ret; | |
203 | ||
204 | reg_val &= afe440x_attr->mask; | |
205 | reg_val >>= afe440x_attr->shift; | |
206 | ||
207 | switch (afe440x_attr->type) { | |
208 | case SIMPLE: | |
209 | type = IIO_VAL_INT; | |
210 | val_len = 1; | |
211 | vals[0] = reg_val; | |
212 | break; | |
213 | case RESISTANCE: | |
214 | case CAPACITANCE: | |
215 | type = IIO_VAL_INT_PLUS_MICRO; | |
216 | val_len = 2; | |
217 | if (reg_val < afe440x_attr->table_size) { | |
218 | vals[0] = afe440x_attr->val_table[reg_val].integer; | |
219 | vals[1] = afe440x_attr->val_table[reg_val].fract; | |
220 | break; | |
221 | } | |
222 | return -EINVAL; | |
223 | default: | |
224 | return -EINVAL; | |
225 | } | |
226 | ||
227 | return iio_format_value(buf, type, val_len, vals); | |
228 | } | |
229 | ||
230 | static ssize_t afe440x_store_register(struct device *dev, | |
231 | struct device_attribute *attr, | |
232 | const char *buf, size_t count) | |
233 | { | |
234 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
235 | struct afe4404_data *afe = iio_priv(indio_dev); | |
236 | struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr); | |
237 | int val, integer, fract, ret; | |
238 | ||
239 | ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract); | |
240 | if (ret) | |
241 | return ret; | |
242 | ||
243 | switch (afe440x_attr->type) { | |
244 | case SIMPLE: | |
245 | val = integer; | |
246 | break; | |
247 | case RESISTANCE: | |
248 | case CAPACITANCE: | |
249 | for (val = 0; val < afe440x_attr->table_size; val++) | |
250 | if (afe440x_attr->val_table[val].integer == integer && | |
251 | afe440x_attr->val_table[val].fract == fract) | |
252 | break; | |
253 | if (val == afe440x_attr->table_size) | |
254 | return -EINVAL; | |
255 | break; | |
256 | default: | |
257 | return -EINVAL; | |
258 | } | |
259 | ||
260 | ret = regmap_update_bits(afe->regmap, afe440x_attr->reg, | |
261 | afe440x_attr->mask, | |
262 | (val << afe440x_attr->shift)); | |
263 | if (ret) | |
264 | return ret; | |
265 | ||
266 | return count; | |
267 | } | |
268 | ||
269 | static AFE440X_ATTR(tia_separate_en, AFE4404_TIA_GAIN_SEP, AFE440X_TIAGAIN_ENSEPGAIN, SIMPLE, NULL, 0); | |
270 | ||
271 | static AFE440X_ATTR(tia_resistance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table)); | |
272 | static AFE440X_ATTR(tia_capacitance1, AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table)); | |
273 | ||
274 | static AFE440X_ATTR(tia_resistance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_RES, RESISTANCE, afe4404_res_table, ARRAY_SIZE(afe4404_res_table)); | |
275 | static AFE440X_ATTR(tia_capacitance2, AFE4404_TIA_GAIN_SEP, AFE4404_TIA_GAIN_CAP, CAPACITANCE, afe4404_cap_table, ARRAY_SIZE(afe4404_cap_table)); | |
276 | ||
277 | static struct attribute *afe440x_attributes[] = { | |
278 | &afe440x_attr_tia_separate_en.dev_attr.attr, | |
279 | &afe440x_attr_tia_resistance1.dev_attr.attr, | |
280 | &afe440x_attr_tia_capacitance1.dev_attr.attr, | |
281 | &afe440x_attr_tia_resistance2.dev_attr.attr, | |
282 | &afe440x_attr_tia_capacitance2.dev_attr.attr, | |
283 | &dev_attr_tia_resistance_available.attr, | |
284 | &dev_attr_tia_capacitance_available.attr, | |
285 | NULL | |
286 | }; | |
287 | ||
288 | static const struct attribute_group afe440x_attribute_group = { | |
289 | .attrs = afe440x_attributes | |
290 | }; | |
291 | ||
292 | static int afe4404_read_raw(struct iio_dev *indio_dev, | |
293 | struct iio_chan_spec const *chan, | |
294 | int *val, int *val2, long mask) | |
295 | { | |
296 | struct afe4404_data *afe = iio_priv(indio_dev); | |
297 | const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address]; | |
298 | int ret; | |
299 | ||
300 | switch (chan->type) { | |
301 | case IIO_INTENSITY: | |
302 | switch (mask) { | |
303 | case IIO_CHAN_INFO_RAW: | |
304 | ret = regmap_read(afe->regmap, reg_info.reg, val); | |
305 | if (ret) | |
306 | return ret; | |
307 | return IIO_VAL_INT; | |
308 | case IIO_CHAN_INFO_OFFSET: | |
309 | ret = regmap_read(afe->regmap, reg_info.offreg, | |
310 | val); | |
311 | if (ret) | |
312 | return ret; | |
313 | *val &= reg_info.mask; | |
314 | *val >>= reg_info.shift; | |
315 | return IIO_VAL_INT; | |
316 | } | |
317 | break; | |
318 | case IIO_CURRENT: | |
319 | switch (mask) { | |
320 | case IIO_CHAN_INFO_RAW: | |
321 | ret = regmap_read(afe->regmap, reg_info.reg, val); | |
322 | if (ret) | |
323 | return ret; | |
324 | *val &= reg_info.mask; | |
325 | *val >>= reg_info.shift; | |
326 | return IIO_VAL_INT; | |
327 | case IIO_CHAN_INFO_SCALE: | |
328 | *val = 0; | |
329 | *val2 = 800000; | |
330 | return IIO_VAL_INT_PLUS_MICRO; | |
331 | } | |
332 | break; | |
333 | default: | |
334 | break; | |
335 | } | |
336 | ||
337 | return -EINVAL; | |
338 | } | |
339 | ||
340 | static int afe4404_write_raw(struct iio_dev *indio_dev, | |
341 | struct iio_chan_spec const *chan, | |
342 | int val, int val2, long mask) | |
343 | { | |
344 | struct afe4404_data *afe = iio_priv(indio_dev); | |
345 | const struct afe440x_reg_info reg_info = afe4404_reg_info[chan->address]; | |
346 | ||
347 | switch (chan->type) { | |
348 | case IIO_INTENSITY: | |
349 | switch (mask) { | |
350 | case IIO_CHAN_INFO_OFFSET: | |
351 | return regmap_update_bits(afe->regmap, | |
352 | reg_info.offreg, | |
353 | reg_info.mask, | |
354 | (val << reg_info.shift)); | |
355 | } | |
356 | break; | |
357 | case IIO_CURRENT: | |
358 | switch (mask) { | |
359 | case IIO_CHAN_INFO_RAW: | |
360 | return regmap_update_bits(afe->regmap, | |
361 | reg_info.reg, | |
362 | reg_info.mask, | |
363 | (val << reg_info.shift)); | |
364 | } | |
365 | break; | |
366 | default: | |
367 | break; | |
368 | } | |
369 | ||
370 | return -EINVAL; | |
371 | } | |
372 | ||
373 | static const struct iio_info afe4404_iio_info = { | |
374 | .attrs = &afe440x_attribute_group, | |
375 | .read_raw = afe4404_read_raw, | |
376 | .write_raw = afe4404_write_raw, | |
377 | .driver_module = THIS_MODULE, | |
378 | }; | |
379 | ||
380 | static irqreturn_t afe4404_trigger_handler(int irq, void *private) | |
381 | { | |
382 | struct iio_poll_func *pf = private; | |
383 | struct iio_dev *indio_dev = pf->indio_dev; | |
384 | struct afe4404_data *afe = iio_priv(indio_dev); | |
385 | int ret, bit, i = 0; | |
386 | s32 buffer[10]; | |
387 | ||
388 | for_each_set_bit(bit, indio_dev->active_scan_mask, | |
389 | indio_dev->masklength) { | |
390 | ret = regmap_read(afe->regmap, afe4404_reg_info[bit].reg, | |
391 | &buffer[i++]); | |
392 | if (ret) | |
393 | goto err; | |
394 | } | |
395 | ||
396 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); | |
397 | err: | |
398 | iio_trigger_notify_done(indio_dev->trig); | |
399 | ||
400 | return IRQ_HANDLED; | |
401 | } | |
402 | ||
403 | static const struct iio_trigger_ops afe4404_trigger_ops = { | |
404 | .owner = THIS_MODULE, | |
405 | }; | |
406 | ||
407 | /* Default timings from data-sheet */ | |
408 | #define AFE4404_TIMING_PAIRS \ | |
409 | { AFE440X_PRPCOUNT, 39999 }, \ | |
410 | { AFE440X_LED2LEDSTC, 0 }, \ | |
411 | { AFE440X_LED2LEDENDC, 398 }, \ | |
412 | { AFE440X_LED2STC, 80 }, \ | |
413 | { AFE440X_LED2ENDC, 398 }, \ | |
414 | { AFE440X_ADCRSTSTCT0, 5600 }, \ | |
415 | { AFE440X_ADCRSTENDCT0, 5606 }, \ | |
416 | { AFE440X_LED2CONVST, 5607 }, \ | |
417 | { AFE440X_LED2CONVEND, 6066 }, \ | |
418 | { AFE4404_LED3LEDSTC, 400 }, \ | |
419 | { AFE4404_LED3LEDENDC, 798 }, \ | |
420 | { AFE440X_ALED2STC, 480 }, \ | |
421 | { AFE440X_ALED2ENDC, 798 }, \ | |
422 | { AFE440X_ADCRSTSTCT1, 6068 }, \ | |
423 | { AFE440X_ADCRSTENDCT1, 6074 }, \ | |
424 | { AFE440X_ALED2CONVST, 6075 }, \ | |
425 | { AFE440X_ALED2CONVEND, 6534 }, \ | |
426 | { AFE440X_LED1LEDSTC, 800 }, \ | |
427 | { AFE440X_LED1LEDENDC, 1198 }, \ | |
428 | { AFE440X_LED1STC, 880 }, \ | |
429 | { AFE440X_LED1ENDC, 1198 }, \ | |
430 | { AFE440X_ADCRSTSTCT2, 6536 }, \ | |
431 | { AFE440X_ADCRSTENDCT2, 6542 }, \ | |
432 | { AFE440X_LED1CONVST, 6543 }, \ | |
433 | { AFE440X_LED1CONVEND, 7003 }, \ | |
434 | { AFE440X_ALED1STC, 1280 }, \ | |
435 | { AFE440X_ALED1ENDC, 1598 }, \ | |
436 | { AFE440X_ADCRSTSTCT3, 7005 }, \ | |
437 | { AFE440X_ADCRSTENDCT3, 7011 }, \ | |
438 | { AFE440X_ALED1CONVST, 7012 }, \ | |
439 | { AFE440X_ALED1CONVEND, 7471 }, \ | |
440 | { AFE440X_PDNCYCLESTC, 7671 }, \ | |
441 | { AFE440X_PDNCYCLEENDC, 39199 } | |
442 | ||
443 | static const struct reg_sequence afe4404_reg_sequences[] = { | |
444 | AFE4404_TIMING_PAIRS, | |
445 | { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, | |
446 | { AFE4404_TIA_GAIN, AFE4404_TIA_GAIN_RES_50_K }, | |
447 | { AFE440X_LEDCNTRL, (0xf << AFE4404_LEDCNTRL_ILED1_SHIFT) | | |
448 | (0x3 << AFE4404_LEDCNTRL_ILED2_SHIFT) | | |
449 | (0x3 << AFE4404_LEDCNTRL_ILED3_SHIFT) }, | |
450 | { AFE440X_CONTROL2, AFE440X_CONTROL3_OSC_ENABLE }, | |
451 | }; | |
452 | ||
453 | static const struct regmap_range afe4404_yes_ranges[] = { | |
454 | regmap_reg_range(AFE440X_LED2VAL, AFE440X_LED1_ALED1VAL), | |
455 | regmap_reg_range(AFE4404_AVG_LED2_ALED2VAL, AFE4404_AVG_LED1_ALED1VAL), | |
456 | }; | |
457 | ||
458 | static const struct regmap_access_table afe4404_volatile_table = { | |
459 | .yes_ranges = afe4404_yes_ranges, | |
460 | .n_yes_ranges = ARRAY_SIZE(afe4404_yes_ranges), | |
461 | }; | |
462 | ||
463 | static const struct regmap_config afe4404_regmap_config = { | |
464 | .reg_bits = 8, | |
465 | .val_bits = 24, | |
466 | ||
467 | .max_register = AFE4404_AVG_LED1_ALED1VAL, | |
468 | .cache_type = REGCACHE_RBTREE, | |
469 | .volatile_table = &afe4404_volatile_table, | |
470 | }; | |
471 | ||
472 | #ifdef CONFIG_OF | |
473 | static const struct of_device_id afe4404_of_match[] = { | |
474 | { .compatible = "ti,afe4404", }, | |
475 | { /* sentinel */ } | |
476 | }; | |
477 | MODULE_DEVICE_TABLE(of, afe4404_of_match); | |
478 | #endif | |
479 | ||
0e6071ab | 480 | static int __maybe_unused afe4404_suspend(struct device *dev) |
87aec56e AD |
481 | { |
482 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
483 | struct afe4404_data *afe = iio_priv(indio_dev); | |
484 | int ret; | |
485 | ||
486 | ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, | |
487 | AFE440X_CONTROL2_PDN_AFE, | |
488 | AFE440X_CONTROL2_PDN_AFE); | |
489 | if (ret) | |
490 | return ret; | |
491 | ||
492 | ret = regulator_disable(afe->regulator); | |
493 | if (ret) { | |
494 | dev_err(dev, "Unable to disable regulator\n"); | |
495 | return ret; | |
496 | } | |
497 | ||
498 | return 0; | |
499 | } | |
500 | ||
0e6071ab | 501 | static int __maybe_unused afe4404_resume(struct device *dev) |
87aec56e AD |
502 | { |
503 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
504 | struct afe4404_data *afe = iio_priv(indio_dev); | |
505 | int ret; | |
506 | ||
507 | ret = regulator_enable(afe->regulator); | |
508 | if (ret) { | |
509 | dev_err(dev, "Unable to enable regulator\n"); | |
510 | return ret; | |
511 | } | |
512 | ||
513 | ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, | |
514 | AFE440X_CONTROL2_PDN_AFE, 0); | |
515 | if (ret) | |
516 | return ret; | |
517 | ||
518 | return 0; | |
519 | } | |
520 | ||
521 | static SIMPLE_DEV_PM_OPS(afe4404_pm_ops, afe4404_suspend, afe4404_resume); | |
522 | ||
523 | static int afe4404_probe(struct i2c_client *client, | |
524 | const struct i2c_device_id *id) | |
525 | { | |
526 | struct iio_dev *indio_dev; | |
527 | struct afe4404_data *afe; | |
528 | int ret; | |
529 | ||
530 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*afe)); | |
531 | if (!indio_dev) | |
532 | return -ENOMEM; | |
533 | ||
534 | afe = iio_priv(indio_dev); | |
535 | i2c_set_clientdata(client, indio_dev); | |
536 | ||
537 | afe->dev = &client->dev; | |
538 | afe->irq = client->irq; | |
539 | ||
540 | afe->regmap = devm_regmap_init_i2c(client, &afe4404_regmap_config); | |
541 | if (IS_ERR(afe->regmap)) { | |
542 | dev_err(afe->dev, "Unable to allocate register map\n"); | |
543 | return PTR_ERR(afe->regmap); | |
544 | } | |
545 | ||
546 | afe->regulator = devm_regulator_get(afe->dev, "tx_sup"); | |
547 | if (IS_ERR(afe->regulator)) { | |
548 | dev_err(afe->dev, "Unable to get regulator\n"); | |
549 | return PTR_ERR(afe->regulator); | |
550 | } | |
551 | ret = regulator_enable(afe->regulator); | |
552 | if (ret) { | |
553 | dev_err(afe->dev, "Unable to enable regulator\n"); | |
554 | return ret; | |
555 | } | |
556 | ||
557 | ret = regmap_write(afe->regmap, AFE440X_CONTROL0, | |
558 | AFE440X_CONTROL0_SW_RESET); | |
559 | if (ret) { | |
560 | dev_err(afe->dev, "Unable to reset device\n"); | |
561 | goto disable_reg; | |
562 | } | |
563 | ||
564 | ret = regmap_multi_reg_write(afe->regmap, afe4404_reg_sequences, | |
565 | ARRAY_SIZE(afe4404_reg_sequences)); | |
566 | if (ret) { | |
567 | dev_err(afe->dev, "Unable to set register defaults\n"); | |
568 | goto disable_reg; | |
569 | } | |
570 | ||
571 | indio_dev->modes = INDIO_DIRECT_MODE; | |
572 | indio_dev->dev.parent = afe->dev; | |
573 | indio_dev->channels = afe4404_channels; | |
574 | indio_dev->num_channels = ARRAY_SIZE(afe4404_channels); | |
575 | indio_dev->name = AFE4404_DRIVER_NAME; | |
576 | indio_dev->info = &afe4404_iio_info; | |
577 | ||
578 | if (afe->irq > 0) { | |
579 | afe->trig = devm_iio_trigger_alloc(afe->dev, | |
580 | "%s-dev%d", | |
581 | indio_dev->name, | |
582 | indio_dev->id); | |
583 | if (!afe->trig) { | |
584 | dev_err(afe->dev, "Unable to allocate IIO trigger\n"); | |
585 | ret = -ENOMEM; | |
586 | goto disable_reg; | |
587 | } | |
588 | ||
589 | iio_trigger_set_drvdata(afe->trig, indio_dev); | |
590 | ||
591 | afe->trig->ops = &afe4404_trigger_ops; | |
592 | afe->trig->dev.parent = afe->dev; | |
593 | ||
594 | ret = iio_trigger_register(afe->trig); | |
595 | if (ret) { | |
596 | dev_err(afe->dev, "Unable to register IIO trigger\n"); | |
597 | goto disable_reg; | |
598 | } | |
599 | ||
600 | ret = devm_request_threaded_irq(afe->dev, afe->irq, | |
601 | iio_trigger_generic_data_rdy_poll, | |
602 | NULL, IRQF_ONESHOT, | |
603 | AFE4404_DRIVER_NAME, | |
604 | afe->trig); | |
605 | if (ret) { | |
606 | dev_err(afe->dev, "Unable to request IRQ\n"); | |
607 | goto disable_reg; | |
608 | } | |
609 | } | |
610 | ||
611 | ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | |
612 | afe4404_trigger_handler, NULL); | |
613 | if (ret) { | |
614 | dev_err(afe->dev, "Unable to setup buffer\n"); | |
615 | goto unregister_trigger; | |
616 | } | |
617 | ||
618 | ret = iio_device_register(indio_dev); | |
619 | if (ret) { | |
620 | dev_err(afe->dev, "Unable to register IIO device\n"); | |
621 | goto unregister_triggered_buffer; | |
622 | } | |
623 | ||
624 | return 0; | |
625 | ||
626 | unregister_triggered_buffer: | |
627 | iio_triggered_buffer_cleanup(indio_dev); | |
628 | unregister_trigger: | |
629 | if (afe->irq > 0) | |
630 | iio_trigger_unregister(afe->trig); | |
631 | disable_reg: | |
632 | regulator_disable(afe->regulator); | |
633 | ||
634 | return ret; | |
635 | } | |
636 | ||
637 | static int afe4404_remove(struct i2c_client *client) | |
638 | { | |
639 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
640 | struct afe4404_data *afe = iio_priv(indio_dev); | |
641 | int ret; | |
642 | ||
643 | iio_device_unregister(indio_dev); | |
644 | ||
645 | iio_triggered_buffer_cleanup(indio_dev); | |
646 | ||
647 | if (afe->irq > 0) | |
648 | iio_trigger_unregister(afe->trig); | |
649 | ||
650 | ret = regulator_disable(afe->regulator); | |
651 | if (ret) { | |
652 | dev_err(afe->dev, "Unable to disable regulator\n"); | |
653 | return ret; | |
654 | } | |
655 | ||
656 | return 0; | |
657 | } | |
658 | ||
659 | static const struct i2c_device_id afe4404_ids[] = { | |
660 | { "afe4404", 0 }, | |
661 | { /* sentinel */ } | |
662 | }; | |
663 | MODULE_DEVICE_TABLE(i2c, afe4404_ids); | |
664 | ||
665 | static struct i2c_driver afe4404_i2c_driver = { | |
666 | .driver = { | |
667 | .name = AFE4404_DRIVER_NAME, | |
668 | .of_match_table = of_match_ptr(afe4404_of_match), | |
669 | .pm = &afe4404_pm_ops, | |
670 | }, | |
671 | .probe = afe4404_probe, | |
672 | .remove = afe4404_remove, | |
673 | .id_table = afe4404_ids, | |
674 | }; | |
675 | module_i2c_driver(afe4404_i2c_driver); | |
676 | ||
677 | MODULE_AUTHOR("Andrew F. Davis <[email protected]>"); | |
678 | MODULE_DESCRIPTION("TI AFE4404 Heart Rate and Pulse Oximeter"); | |
679 | MODULE_LICENSE("GPL v2"); |