]>
Commit | Line | Data |
---|---|---|
eec96d1e AD |
1 | /* |
2 | * AFE4403 Heart Rate Monitors and Low-Cost Pulse Oximeters | |
3 | * | |
f59e6b5a | 4 | * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ |
eec96d1e AD |
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/kernel.h> | |
21 | #include <linux/module.h> | |
22 | #include <linux/regmap.h> | |
23 | #include <linux/spi/spi.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 AFE4403_DRIVER_NAME "afe4403" | |
37 | ||
38 | /* AFE4403 Registers */ | |
39 | #define AFE4403_TIAGAIN 0x20 | |
40 | #define AFE4403_TIA_AMB_GAIN 0x21 | |
41 | ||
b36e8257 AD |
42 | enum afe4403_fields { |
43 | /* Gains */ | |
44 | F_RF_LED1, F_CF_LED1, | |
45 | F_RF_LED, F_CF_LED, | |
46 | ||
47 | /* LED Current */ | |
48 | F_ILED1, F_ILED2, | |
49 | ||
50 | /* sentinel */ | |
51 | F_MAX_FIELDS | |
52 | }; | |
53 | ||
54 | static const struct reg_field afe4403_reg_fields[] = { | |
55 | /* Gains */ | |
56 | [F_RF_LED1] = REG_FIELD(AFE4403_TIAGAIN, 0, 2), | |
57 | [F_CF_LED1] = REG_FIELD(AFE4403_TIAGAIN, 3, 7), | |
58 | [F_RF_LED] = REG_FIELD(AFE4403_TIA_AMB_GAIN, 0, 2), | |
59 | [F_CF_LED] = REG_FIELD(AFE4403_TIA_AMB_GAIN, 3, 7), | |
60 | /* LED Current */ | |
61 | [F_ILED1] = REG_FIELD(AFE440X_LEDCNTRL, 0, 7), | |
62 | [F_ILED2] = REG_FIELD(AFE440X_LEDCNTRL, 8, 15), | |
63 | }; | |
64 | ||
eec96d1e | 65 | /** |
f59e6b5a AD |
66 | * struct afe4403_data - AFE4403 device instance data |
67 | * @dev: Device structure | |
68 | * @spi: SPI device handle | |
69 | * @regmap: Register map of the device | |
b36e8257 | 70 | * @fields: Register fields of the device |
f59e6b5a AD |
71 | * @regulator: Pointer to the regulator for the IC |
72 | * @trig: IIO trigger for this device | |
73 | * @irq: ADC_RDY line interrupt number | |
eec96d1e AD |
74 | */ |
75 | struct afe4403_data { | |
76 | struct device *dev; | |
77 | struct spi_device *spi; | |
78 | struct regmap *regmap; | |
b36e8257 | 79 | struct regmap_field *fields[F_MAX_FIELDS]; |
eec96d1e AD |
80 | struct regulator *regulator; |
81 | struct iio_trigger *trig; | |
82 | int irq; | |
83 | }; | |
84 | ||
85 | enum afe4403_chan_id { | |
24b9dea7 AD |
86 | LED2 = 1, |
87 | ALED2, | |
eec96d1e AD |
88 | LED1, |
89 | ALED1, | |
eec96d1e | 90 | LED2_ALED2, |
24b9dea7 | 91 | LED1_ALED1, |
eec96d1e AD |
92 | }; |
93 | ||
b36e8257 AD |
94 | static const unsigned int afe4403_channel_values[] = { |
95 | [LED2] = AFE440X_LED2VAL, | |
96 | [ALED2] = AFE440X_ALED2VAL, | |
97 | [LED1] = AFE440X_LED1VAL, | |
98 | [ALED1] = AFE440X_ALED1VAL, | |
99 | [LED2_ALED2] = AFE440X_LED2_ALED2VAL, | |
100 | [LED1_ALED1] = AFE440X_LED1_ALED1VAL, | |
101 | }; | |
102 | ||
103 | static const unsigned int afe4403_channel_leds[] = { | |
3ff34ee2 AD |
104 | [LED2] = F_ILED2, |
105 | [LED1] = F_ILED1, | |
eec96d1e AD |
106 | }; |
107 | ||
108 | static const struct iio_chan_spec afe4403_channels[] = { | |
109 | /* ADC values */ | |
24b9dea7 AD |
110 | AFE440X_INTENSITY_CHAN(LED2, 0), |
111 | AFE440X_INTENSITY_CHAN(ALED2, 0), | |
112 | AFE440X_INTENSITY_CHAN(LED1, 0), | |
113 | AFE440X_INTENSITY_CHAN(ALED1, 0), | |
114 | AFE440X_INTENSITY_CHAN(LED2_ALED2, 0), | |
115 | AFE440X_INTENSITY_CHAN(LED1_ALED1, 0), | |
eec96d1e | 116 | /* LED current */ |
3ff34ee2 AD |
117 | AFE440X_CURRENT_CHAN(LED2), |
118 | AFE440X_CURRENT_CHAN(LED1), | |
eec96d1e AD |
119 | }; |
120 | ||
121 | static const struct afe440x_val_table afe4403_res_table[] = { | |
122 | { 500000 }, { 250000 }, { 100000 }, { 50000 }, | |
123 | { 25000 }, { 10000 }, { 1000000 }, { 0 }, | |
124 | }; | |
1276187c | 125 | AFE440X_TABLE_ATTR(in_intensity_resistance_available, afe4403_res_table); |
eec96d1e AD |
126 | |
127 | static const struct afe440x_val_table afe4403_cap_table[] = { | |
128 | { 0, 5000 }, { 0, 10000 }, { 0, 20000 }, { 0, 25000 }, | |
129 | { 0, 30000 }, { 0, 35000 }, { 0, 45000 }, { 0, 50000 }, | |
130 | { 0, 55000 }, { 0, 60000 }, { 0, 70000 }, { 0, 75000 }, | |
131 | { 0, 80000 }, { 0, 85000 }, { 0, 95000 }, { 0, 100000 }, | |
132 | { 0, 155000 }, { 0, 160000 }, { 0, 170000 }, { 0, 175000 }, | |
133 | { 0, 180000 }, { 0, 185000 }, { 0, 195000 }, { 0, 200000 }, | |
134 | { 0, 205000 }, { 0, 210000 }, { 0, 220000 }, { 0, 225000 }, | |
135 | { 0, 230000 }, { 0, 235000 }, { 0, 245000 }, { 0, 250000 }, | |
136 | }; | |
1276187c | 137 | AFE440X_TABLE_ATTR(in_intensity_capacitance_available, afe4403_cap_table); |
eec96d1e AD |
138 | |
139 | static ssize_t afe440x_show_register(struct device *dev, | |
140 | struct device_attribute *attr, | |
141 | char *buf) | |
142 | { | |
143 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
144 | struct afe4403_data *afe = iio_priv(indio_dev); | |
145 | struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr); | |
81f51727 | 146 | unsigned int reg_val; |
eec96d1e | 147 | int vals[2]; |
81f51727 | 148 | int ret; |
eec96d1e | 149 | |
b36e8257 | 150 | ret = regmap_field_read(afe->fields[afe440x_attr->field], ®_val); |
eec96d1e AD |
151 | if (ret) |
152 | return ret; | |
153 | ||
81f51727 | 154 | if (reg_val >= afe440x_attr->table_size) |
eec96d1e | 155 | return -EINVAL; |
eec96d1e | 156 | |
81f51727 AD |
157 | vals[0] = afe440x_attr->val_table[reg_val].integer; |
158 | vals[1] = afe440x_attr->val_table[reg_val].fract; | |
159 | ||
160 | return iio_format_value(buf, IIO_VAL_INT_PLUS_MICRO, 2, vals); | |
eec96d1e AD |
161 | } |
162 | ||
163 | static ssize_t afe440x_store_register(struct device *dev, | |
164 | struct device_attribute *attr, | |
165 | const char *buf, size_t count) | |
166 | { | |
167 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); | |
168 | struct afe4403_data *afe = iio_priv(indio_dev); | |
169 | struct afe440x_attr *afe440x_attr = to_afe440x_attr(attr); | |
170 | int val, integer, fract, ret; | |
171 | ||
172 | ret = iio_str_to_fixpoint(buf, 100000, &integer, &fract); | |
173 | if (ret) | |
174 | return ret; | |
175 | ||
81f51727 AD |
176 | for (val = 0; val < afe440x_attr->table_size; val++) |
177 | if (afe440x_attr->val_table[val].integer == integer && | |
178 | afe440x_attr->val_table[val].fract == fract) | |
179 | break; | |
180 | if (val == afe440x_attr->table_size) | |
eec96d1e | 181 | return -EINVAL; |
eec96d1e | 182 | |
b36e8257 | 183 | ret = regmap_field_write(afe->fields[afe440x_attr->field], val); |
eec96d1e AD |
184 | if (ret) |
185 | return ret; | |
186 | ||
187 | return count; | |
188 | } | |
189 | ||
1276187c AD |
190 | static AFE440X_ATTR(in_intensity1_resistance, F_RF_LED, afe4403_res_table); |
191 | static AFE440X_ATTR(in_intensity1_capacitance, F_CF_LED, afe4403_cap_table); | |
eec96d1e | 192 | |
1276187c AD |
193 | static AFE440X_ATTR(in_intensity2_resistance, F_RF_LED, afe4403_res_table); |
194 | static AFE440X_ATTR(in_intensity2_capacitance, F_CF_LED, afe4403_cap_table); | |
195 | ||
196 | static AFE440X_ATTR(in_intensity3_resistance, F_RF_LED1, afe4403_res_table); | |
197 | static AFE440X_ATTR(in_intensity3_capacitance, F_CF_LED1, afe4403_cap_table); | |
198 | ||
199 | static AFE440X_ATTR(in_intensity4_resistance, F_RF_LED1, afe4403_res_table); | |
200 | static AFE440X_ATTR(in_intensity4_capacitance, F_CF_LED1, afe4403_cap_table); | |
eec96d1e AD |
201 | |
202 | static struct attribute *afe440x_attributes[] = { | |
1276187c AD |
203 | &dev_attr_in_intensity_resistance_available.attr, |
204 | &dev_attr_in_intensity_capacitance_available.attr, | |
205 | &afe440x_attr_in_intensity1_resistance.dev_attr.attr, | |
206 | &afe440x_attr_in_intensity1_capacitance.dev_attr.attr, | |
207 | &afe440x_attr_in_intensity2_resistance.dev_attr.attr, | |
208 | &afe440x_attr_in_intensity2_capacitance.dev_attr.attr, | |
209 | &afe440x_attr_in_intensity3_resistance.dev_attr.attr, | |
210 | &afe440x_attr_in_intensity3_capacitance.dev_attr.attr, | |
211 | &afe440x_attr_in_intensity4_resistance.dev_attr.attr, | |
212 | &afe440x_attr_in_intensity4_capacitance.dev_attr.attr, | |
eec96d1e AD |
213 | NULL |
214 | }; | |
215 | ||
216 | static const struct attribute_group afe440x_attribute_group = { | |
217 | .attrs = afe440x_attributes | |
218 | }; | |
219 | ||
220 | static int afe4403_read(struct afe4403_data *afe, unsigned int reg, u32 *val) | |
221 | { | |
222 | u8 tx[4] = {AFE440X_CONTROL0, 0x0, 0x0, AFE440X_CONTROL0_READ}; | |
223 | u8 rx[3]; | |
224 | int ret; | |
225 | ||
226 | /* Enable reading from the device */ | |
227 | ret = spi_write_then_read(afe->spi, tx, 4, NULL, 0); | |
228 | if (ret) | |
229 | return ret; | |
230 | ||
231 | ret = spi_write_then_read(afe->spi, ®, 1, rx, 3); | |
232 | if (ret) | |
233 | return ret; | |
234 | ||
235 | *val = (rx[0] << 16) | | |
236 | (rx[1] << 8) | | |
237 | (rx[2]); | |
238 | ||
239 | /* Disable reading from the device */ | |
240 | tx[3] = AFE440X_CONTROL0_WRITE; | |
241 | ret = spi_write_then_read(afe->spi, tx, 4, NULL, 0); | |
242 | if (ret) | |
243 | return ret; | |
244 | ||
245 | return 0; | |
246 | } | |
247 | ||
248 | static int afe4403_read_raw(struct iio_dev *indio_dev, | |
249 | struct iio_chan_spec const *chan, | |
250 | int *val, int *val2, long mask) | |
251 | { | |
252 | struct afe4403_data *afe = iio_priv(indio_dev); | |
b36e8257 AD |
253 | unsigned int reg = afe4403_channel_values[chan->address]; |
254 | unsigned int field = afe4403_channel_leds[chan->address]; | |
eec96d1e AD |
255 | int ret; |
256 | ||
257 | switch (chan->type) { | |
258 | case IIO_INTENSITY: | |
259 | switch (mask) { | |
260 | case IIO_CHAN_INFO_RAW: | |
b36e8257 | 261 | ret = afe4403_read(afe, reg, val); |
eec96d1e AD |
262 | if (ret) |
263 | return ret; | |
264 | return IIO_VAL_INT; | |
eec96d1e AD |
265 | } |
266 | break; | |
267 | case IIO_CURRENT: | |
268 | switch (mask) { | |
269 | case IIO_CHAN_INFO_RAW: | |
b36e8257 | 270 | ret = regmap_field_read(afe->fields[field], val); |
eec96d1e AD |
271 | if (ret) |
272 | return ret; | |
eec96d1e AD |
273 | return IIO_VAL_INT; |
274 | case IIO_CHAN_INFO_SCALE: | |
275 | *val = 0; | |
276 | *val2 = 800000; | |
277 | return IIO_VAL_INT_PLUS_MICRO; | |
278 | } | |
279 | break; | |
280 | default: | |
281 | break; | |
282 | } | |
283 | ||
284 | return -EINVAL; | |
285 | } | |
286 | ||
287 | static int afe4403_write_raw(struct iio_dev *indio_dev, | |
288 | struct iio_chan_spec const *chan, | |
289 | int val, int val2, long mask) | |
290 | { | |
291 | struct afe4403_data *afe = iio_priv(indio_dev); | |
b36e8257 | 292 | unsigned int field = afe4403_channel_leds[chan->address]; |
eec96d1e AD |
293 | |
294 | switch (chan->type) { | |
eec96d1e AD |
295 | case IIO_CURRENT: |
296 | switch (mask) { | |
297 | case IIO_CHAN_INFO_RAW: | |
b36e8257 | 298 | return regmap_field_write(afe->fields[field], val); |
eec96d1e AD |
299 | } |
300 | break; | |
301 | default: | |
302 | break; | |
303 | } | |
304 | ||
305 | return -EINVAL; | |
306 | } | |
307 | ||
308 | static const struct iio_info afe4403_iio_info = { | |
309 | .attrs = &afe440x_attribute_group, | |
310 | .read_raw = afe4403_read_raw, | |
311 | .write_raw = afe4403_write_raw, | |
eec96d1e AD |
312 | }; |
313 | ||
314 | static irqreturn_t afe4403_trigger_handler(int irq, void *private) | |
315 | { | |
316 | struct iio_poll_func *pf = private; | |
317 | struct iio_dev *indio_dev = pf->indio_dev; | |
318 | struct afe4403_data *afe = iio_priv(indio_dev); | |
319 | int ret, bit, i = 0; | |
320 | s32 buffer[8]; | |
321 | u8 tx[4] = {AFE440X_CONTROL0, 0x0, 0x0, AFE440X_CONTROL0_READ}; | |
322 | u8 rx[3]; | |
323 | ||
324 | /* Enable reading from the device */ | |
325 | ret = spi_write_then_read(afe->spi, tx, 4, NULL, 0); | |
326 | if (ret) | |
327 | goto err; | |
328 | ||
329 | for_each_set_bit(bit, indio_dev->active_scan_mask, | |
330 | indio_dev->masklength) { | |
331 | ret = spi_write_then_read(afe->spi, | |
b36e8257 | 332 | &afe4403_channel_values[bit], 1, |
eec96d1e AD |
333 | rx, 3); |
334 | if (ret) | |
335 | goto err; | |
336 | ||
337 | buffer[i++] = (rx[0] << 16) | | |
338 | (rx[1] << 8) | | |
339 | (rx[2]); | |
340 | } | |
341 | ||
342 | /* Disable reading from the device */ | |
343 | tx[3] = AFE440X_CONTROL0_WRITE; | |
344 | ret = spi_write_then_read(afe->spi, tx, 4, NULL, 0); | |
345 | if (ret) | |
346 | goto err; | |
347 | ||
348 | iio_push_to_buffers_with_timestamp(indio_dev, buffer, pf->timestamp); | |
349 | err: | |
350 | iio_trigger_notify_done(indio_dev->trig); | |
351 | ||
352 | return IRQ_HANDLED; | |
353 | } | |
354 | ||
355 | static const struct iio_trigger_ops afe4403_trigger_ops = { | |
eec96d1e AD |
356 | }; |
357 | ||
358 | #define AFE4403_TIMING_PAIRS \ | |
359 | { AFE440X_LED2STC, 0x000050 }, \ | |
360 | { AFE440X_LED2ENDC, 0x0003e7 }, \ | |
361 | { AFE440X_LED1LEDSTC, 0x0007d0 }, \ | |
362 | { AFE440X_LED1LEDENDC, 0x000bb7 }, \ | |
363 | { AFE440X_ALED2STC, 0x000438 }, \ | |
364 | { AFE440X_ALED2ENDC, 0x0007cf }, \ | |
365 | { AFE440X_LED1STC, 0x000820 }, \ | |
366 | { AFE440X_LED1ENDC, 0x000bb7 }, \ | |
367 | { AFE440X_LED2LEDSTC, 0x000000 }, \ | |
368 | { AFE440X_LED2LEDENDC, 0x0003e7 }, \ | |
369 | { AFE440X_ALED1STC, 0x000c08 }, \ | |
370 | { AFE440X_ALED1ENDC, 0x000f9f }, \ | |
371 | { AFE440X_LED2CONVST, 0x0003ef }, \ | |
372 | { AFE440X_LED2CONVEND, 0x0007cf }, \ | |
373 | { AFE440X_ALED2CONVST, 0x0007d7 }, \ | |
374 | { AFE440X_ALED2CONVEND, 0x000bb7 }, \ | |
375 | { AFE440X_LED1CONVST, 0x000bbf }, \ | |
376 | { AFE440X_LED1CONVEND, 0x009c3f }, \ | |
377 | { AFE440X_ALED1CONVST, 0x000fa7 }, \ | |
378 | { AFE440X_ALED1CONVEND, 0x001387 }, \ | |
379 | { AFE440X_ADCRSTSTCT0, 0x0003e8 }, \ | |
380 | { AFE440X_ADCRSTENDCT0, 0x0003eb }, \ | |
381 | { AFE440X_ADCRSTSTCT1, 0x0007d0 }, \ | |
382 | { AFE440X_ADCRSTENDCT1, 0x0007d3 }, \ | |
383 | { AFE440X_ADCRSTSTCT2, 0x000bb8 }, \ | |
384 | { AFE440X_ADCRSTENDCT2, 0x000bbb }, \ | |
385 | { AFE440X_ADCRSTSTCT3, 0x000fa0 }, \ | |
386 | { AFE440X_ADCRSTENDCT3, 0x000fa3 }, \ | |
387 | { AFE440X_PRPCOUNT, 0x009c3f }, \ | |
388 | { AFE440X_PDNCYCLESTC, 0x001518 }, \ | |
389 | { AFE440X_PDNCYCLEENDC, 0x00991f } | |
390 | ||
391 | static const struct reg_sequence afe4403_reg_sequences[] = { | |
392 | AFE4403_TIMING_PAIRS, | |
e85fa033 | 393 | { AFE440X_CONTROL1, AFE440X_CONTROL1_TIMEREN }, |
81f51727 | 394 | { AFE4403_TIAGAIN, AFE440X_TIAGAIN_ENSEPGAIN }, |
eec96d1e AD |
395 | }; |
396 | ||
397 | static const struct regmap_range afe4403_yes_ranges[] = { | |
398 | regmap_reg_range(AFE440X_LED2VAL, AFE440X_LED1_ALED1VAL), | |
399 | }; | |
400 | ||
401 | static const struct regmap_access_table afe4403_volatile_table = { | |
402 | .yes_ranges = afe4403_yes_ranges, | |
403 | .n_yes_ranges = ARRAY_SIZE(afe4403_yes_ranges), | |
404 | }; | |
405 | ||
406 | static const struct regmap_config afe4403_regmap_config = { | |
407 | .reg_bits = 8, | |
408 | .val_bits = 24, | |
409 | ||
410 | .max_register = AFE440X_PDNCYCLEENDC, | |
411 | .cache_type = REGCACHE_RBTREE, | |
412 | .volatile_table = &afe4403_volatile_table, | |
413 | }; | |
414 | ||
eec96d1e AD |
415 | static const struct of_device_id afe4403_of_match[] = { |
416 | { .compatible = "ti,afe4403", }, | |
417 | { /* sentinel */ } | |
418 | }; | |
419 | MODULE_DEVICE_TABLE(of, afe4403_of_match); | |
eec96d1e | 420 | |
9e8be75e | 421 | static int __maybe_unused afe4403_suspend(struct device *dev) |
eec96d1e | 422 | { |
a5badd1e | 423 | struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev)); |
eec96d1e AD |
424 | struct afe4403_data *afe = iio_priv(indio_dev); |
425 | int ret; | |
426 | ||
427 | ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, | |
428 | AFE440X_CONTROL2_PDN_AFE, | |
429 | AFE440X_CONTROL2_PDN_AFE); | |
430 | if (ret) | |
431 | return ret; | |
432 | ||
433 | ret = regulator_disable(afe->regulator); | |
434 | if (ret) { | |
435 | dev_err(dev, "Unable to disable regulator\n"); | |
436 | return ret; | |
437 | } | |
438 | ||
439 | return 0; | |
440 | } | |
441 | ||
9e8be75e | 442 | static int __maybe_unused afe4403_resume(struct device *dev) |
eec96d1e | 443 | { |
a5badd1e | 444 | struct iio_dev *indio_dev = spi_get_drvdata(to_spi_device(dev)); |
eec96d1e AD |
445 | struct afe4403_data *afe = iio_priv(indio_dev); |
446 | int ret; | |
447 | ||
448 | ret = regulator_enable(afe->regulator); | |
449 | if (ret) { | |
450 | dev_err(dev, "Unable to enable regulator\n"); | |
451 | return ret; | |
452 | } | |
453 | ||
454 | ret = regmap_update_bits(afe->regmap, AFE440X_CONTROL2, | |
455 | AFE440X_CONTROL2_PDN_AFE, 0); | |
456 | if (ret) | |
457 | return ret; | |
458 | ||
459 | return 0; | |
460 | } | |
461 | ||
462 | static SIMPLE_DEV_PM_OPS(afe4403_pm_ops, afe4403_suspend, afe4403_resume); | |
463 | ||
464 | static int afe4403_probe(struct spi_device *spi) | |
465 | { | |
466 | struct iio_dev *indio_dev; | |
467 | struct afe4403_data *afe; | |
b36e8257 | 468 | int i, ret; |
eec96d1e AD |
469 | |
470 | indio_dev = devm_iio_device_alloc(&spi->dev, sizeof(*afe)); | |
471 | if (!indio_dev) | |
472 | return -ENOMEM; | |
473 | ||
474 | afe = iio_priv(indio_dev); | |
475 | spi_set_drvdata(spi, indio_dev); | |
476 | ||
477 | afe->dev = &spi->dev; | |
478 | afe->spi = spi; | |
479 | afe->irq = spi->irq; | |
480 | ||
481 | afe->regmap = devm_regmap_init_spi(spi, &afe4403_regmap_config); | |
482 | if (IS_ERR(afe->regmap)) { | |
483 | dev_err(afe->dev, "Unable to allocate register map\n"); | |
484 | return PTR_ERR(afe->regmap); | |
485 | } | |
486 | ||
b36e8257 AD |
487 | for (i = 0; i < F_MAX_FIELDS; i++) { |
488 | afe->fields[i] = devm_regmap_field_alloc(afe->dev, afe->regmap, | |
489 | afe4403_reg_fields[i]); | |
490 | if (IS_ERR(afe->fields[i])) { | |
491 | dev_err(afe->dev, "Unable to allocate regmap fields\n"); | |
492 | return PTR_ERR(afe->fields[i]); | |
493 | } | |
494 | } | |
495 | ||
eec96d1e AD |
496 | afe->regulator = devm_regulator_get(afe->dev, "tx_sup"); |
497 | if (IS_ERR(afe->regulator)) { | |
498 | dev_err(afe->dev, "Unable to get regulator\n"); | |
499 | return PTR_ERR(afe->regulator); | |
500 | } | |
501 | ret = regulator_enable(afe->regulator); | |
502 | if (ret) { | |
503 | dev_err(afe->dev, "Unable to enable regulator\n"); | |
504 | return ret; | |
505 | } | |
506 | ||
507 | ret = regmap_write(afe->regmap, AFE440X_CONTROL0, | |
508 | AFE440X_CONTROL0_SW_RESET); | |
509 | if (ret) { | |
510 | dev_err(afe->dev, "Unable to reset device\n"); | |
511 | goto err_disable_reg; | |
512 | } | |
513 | ||
514 | ret = regmap_multi_reg_write(afe->regmap, afe4403_reg_sequences, | |
515 | ARRAY_SIZE(afe4403_reg_sequences)); | |
516 | if (ret) { | |
517 | dev_err(afe->dev, "Unable to set register defaults\n"); | |
518 | goto err_disable_reg; | |
519 | } | |
520 | ||
521 | indio_dev->modes = INDIO_DIRECT_MODE; | |
522 | indio_dev->dev.parent = afe->dev; | |
523 | indio_dev->channels = afe4403_channels; | |
524 | indio_dev->num_channels = ARRAY_SIZE(afe4403_channels); | |
525 | indio_dev->name = AFE4403_DRIVER_NAME; | |
526 | indio_dev->info = &afe4403_iio_info; | |
527 | ||
528 | if (afe->irq > 0) { | |
529 | afe->trig = devm_iio_trigger_alloc(afe->dev, | |
530 | "%s-dev%d", | |
531 | indio_dev->name, | |
532 | indio_dev->id); | |
533 | if (!afe->trig) { | |
534 | dev_err(afe->dev, "Unable to allocate IIO trigger\n"); | |
535 | ret = -ENOMEM; | |
536 | goto err_disable_reg; | |
537 | } | |
538 | ||
539 | iio_trigger_set_drvdata(afe->trig, indio_dev); | |
540 | ||
541 | afe->trig->ops = &afe4403_trigger_ops; | |
542 | afe->trig->dev.parent = afe->dev; | |
543 | ||
544 | ret = iio_trigger_register(afe->trig); | |
545 | if (ret) { | |
546 | dev_err(afe->dev, "Unable to register IIO trigger\n"); | |
547 | goto err_disable_reg; | |
548 | } | |
549 | ||
550 | ret = devm_request_threaded_irq(afe->dev, afe->irq, | |
551 | iio_trigger_generic_data_rdy_poll, | |
552 | NULL, IRQF_ONESHOT, | |
553 | AFE4403_DRIVER_NAME, | |
554 | afe->trig); | |
555 | if (ret) { | |
556 | dev_err(afe->dev, "Unable to request IRQ\n"); | |
557 | goto err_trig; | |
558 | } | |
559 | } | |
560 | ||
561 | ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, | |
562 | afe4403_trigger_handler, NULL); | |
563 | if (ret) { | |
564 | dev_err(afe->dev, "Unable to setup buffer\n"); | |
565 | goto err_trig; | |
566 | } | |
567 | ||
568 | ret = iio_device_register(indio_dev); | |
569 | if (ret) { | |
570 | dev_err(afe->dev, "Unable to register IIO device\n"); | |
571 | goto err_buff; | |
572 | } | |
573 | ||
574 | return 0; | |
575 | ||
576 | err_buff: | |
577 | iio_triggered_buffer_cleanup(indio_dev); | |
578 | err_trig: | |
579 | if (afe->irq > 0) | |
580 | iio_trigger_unregister(afe->trig); | |
581 | err_disable_reg: | |
582 | regulator_disable(afe->regulator); | |
583 | ||
584 | return ret; | |
585 | } | |
586 | ||
587 | static int afe4403_remove(struct spi_device *spi) | |
588 | { | |
589 | struct iio_dev *indio_dev = spi_get_drvdata(spi); | |
590 | struct afe4403_data *afe = iio_priv(indio_dev); | |
591 | int ret; | |
592 | ||
593 | iio_device_unregister(indio_dev); | |
594 | ||
595 | iio_triggered_buffer_cleanup(indio_dev); | |
596 | ||
597 | if (afe->irq > 0) | |
598 | iio_trigger_unregister(afe->trig); | |
599 | ||
600 | ret = regulator_disable(afe->regulator); | |
601 | if (ret) { | |
602 | dev_err(afe->dev, "Unable to disable regulator\n"); | |
603 | return ret; | |
604 | } | |
605 | ||
606 | return 0; | |
607 | } | |
608 | ||
609 | static const struct spi_device_id afe4403_ids[] = { | |
610 | { "afe4403", 0 }, | |
611 | { /* sentinel */ } | |
612 | }; | |
613 | MODULE_DEVICE_TABLE(spi, afe4403_ids); | |
614 | ||
615 | static struct spi_driver afe4403_spi_driver = { | |
616 | .driver = { | |
617 | .name = AFE4403_DRIVER_NAME, | |
daffd7a7 | 618 | .of_match_table = afe4403_of_match, |
eec96d1e AD |
619 | .pm = &afe4403_pm_ops, |
620 | }, | |
621 | .probe = afe4403_probe, | |
622 | .remove = afe4403_remove, | |
623 | .id_table = afe4403_ids, | |
624 | }; | |
625 | module_spi_driver(afe4403_spi_driver); | |
626 | ||
627 | MODULE_AUTHOR("Andrew F. Davis <[email protected]>"); | |
f59e6b5a | 628 | MODULE_DESCRIPTION("TI AFE4403 Heart Rate Monitor and Pulse Oximeter AFE"); |
eec96d1e | 629 | MODULE_LICENSE("GPL v2"); |