1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
|
// SPDX-License-Identifier: GPL-2.0-only
/*
* Driver for Nicera D3-323-AA PIR sensor.
*
* Copyright (C) 2025 Axis Communications AB
*/
#include <linux/bitmap.h>
#include <linux/cleanup.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/types.h>
#include <linux/iio/events.h>
#include <linux/iio/iio.h>
/*
* Register bitmap.
* For some reason the first bit is denoted as F37 in the datasheet, the second
* as F38 and so on. Note the gap between F60 and F64.
*/
#define D3323AA_REG_BIT_SLAVEA1 0 /* F37. */
#define D3323AA_REG_BIT_SLAVEA2 1 /* F38. */
#define D3323AA_REG_BIT_SLAVEA3 2 /* F39. */
#define D3323AA_REG_BIT_SLAVEA4 3 /* F40. */
#define D3323AA_REG_BIT_SLAVEA5 4 /* F41. */
#define D3323AA_REG_BIT_SLAVEA6 5 /* F42. */
#define D3323AA_REG_BIT_SLAVEA7 6 /* F43. */
#define D3323AA_REG_BIT_SLAVEA8 7 /* F44. */
#define D3323AA_REG_BIT_SLAVEA9 8 /* F45. */
#define D3323AA_REG_BIT_SLAVEA10 9 /* F46. */
#define D3323AA_REG_BIT_DETLVLABS0 10 /* F47. */
#define D3323AA_REG_BIT_DETLVLABS1 11 /* F48. */
#define D3323AA_REG_BIT_DETLVLABS2 12 /* F49. */
#define D3323AA_REG_BIT_DETLVLABS3 13 /* F50. */
#define D3323AA_REG_BIT_DETLVLABS4 14 /* F51. */
#define D3323AA_REG_BIT_DETLVLABS5 15 /* F52. */
#define D3323AA_REG_BIT_DETLVLABS6 16 /* F53. */
#define D3323AA_REG_BIT_DETLVLABS7 17 /* F54. */
#define D3323AA_REG_BIT_DSLP 18 /* F55. */
#define D3323AA_REG_BIT_FSTEP0 19 /* F56. */
#define D3323AA_REG_BIT_FSTEP1 20 /* F57. */
#define D3323AA_REG_BIT_FILSEL0 21 /* F58. */
#define D3323AA_REG_BIT_FILSEL1 22 /* F59. */
#define D3323AA_REG_BIT_FILSEL2 23 /* F60. */
#define D3323AA_REG_BIT_FDSET 24 /* F64. */
#define D3323AA_REG_BIT_F65 25
#define D3323AA_REG_BIT_F87 (D3323AA_REG_BIT_F65 + (87 - 65))
#define D3323AA_REG_NR_BITS (D3323AA_REG_BIT_F87 - D3323AA_REG_BIT_SLAVEA1 + 1)
#define D3323AA_THRESH_REG_NR_BITS \
(D3323AA_REG_BIT_DETLVLABS7 - D3323AA_REG_BIT_DETLVLABS0 + 1)
#define D3323AA_FILTER_TYPE_NR_BITS \
(D3323AA_REG_BIT_FILSEL2 - D3323AA_REG_BIT_FILSEL0 + 1)
#define D3323AA_FILTER_GAIN_REG_NR_BITS \
(D3323AA_REG_BIT_FSTEP1 - D3323AA_REG_BIT_FSTEP0 + 1)
#define D3323AA_THRESH_DEFAULT_VAL 56
#define D3323AA_FILTER_GAIN_DEFAULT_IDX 1
#define D3323AA_LP_FILTER_FREQ_DEFAULT_IDX 1
/*
* The pattern is 0b01101, but store it reversed (0b10110) due to writing from
* LSB on the wire (c.f. d3323aa_write_settings()).
*/
#define D3323AA_SETTING_END_PATTERN 0x16
#define D3323AA_SETTING_END_PATTERN_NR_BITS 5
/*
* Device should be ready for configuration after this many milliseconds.
* Datasheet mentions "approx. 1.2 s". Measurements show around 1.23 s,
* therefore add 100 ms of slack.
*/
#define D3323AA_RESET_TIMEOUT (1200 + 100)
/*
* The configuration of the device (write and read) should be done within this
* many milliseconds.
*/
#define D3323AA_CONFIG_TIMEOUT 1400
/* Number of IRQs needed for configuration stage after reset. */
#define D3323AA_IRQ_RESET_COUNT 2
/*
* High-pass filter cutoff frequency for the band-pass filter. There is a
* corresponding low-pass cutoff frequency for each of the filter types
* (denoted A, B, C and D in the datasheet). The index in this array matches
* that corresponding value in d3323aa_lp_filter_freq.
* Note that this represents a fractional value (e.g. the first value
* corresponds to 40 / 100 = 0.4 Hz).
*/
static const int d3323aa_hp_filter_freq[][2] = {
{ 40, 100 },
{ 30, 100 },
{ 30, 100 },
{ 1, 100 },
};
/*
* Low-pass filter cutoff frequency for the band-pass filter. There is a
* corresponding high-pass cutoff frequency for each of the filter types
* (denoted A, B, C and D in the datasheet). The index in this array matches
* that corresponding value in d3323aa_hp_filter_freq.
* Note that this represents a fractional value (e.g. the first value
* corresponds to 27 / 10 = 2.7 Hz).
*/
static const int d3323aa_lp_filter_freq[][2] = {
{ 27, 10 },
{ 15, 10 },
{ 5, 1 },
{ 100, 1 },
};
/*
* Register bitmap values for filter types (denoted A, B, C and D in the
* datasheet). The index in this array matches the corresponding value in
* d3323aa_lp_filter_freq (which in turn matches d3323aa_hp_filter_freq). For
* example, the first value 7 corresponds to 2.7 Hz low-pass and 0.4 Hz
* high-pass cutoff frequency.
*/
static const int d3323aa_lp_filter_regval[] = {
7,
0,
1,
2,
};
/*
* This is denoted as "step" in datasheet and corresponds to the gain at peak
* for the band-pass filter. The index in this array is the corresponding index
* in d3323aa_filter_gain_regval for the register bitmap value.
*/
static const int d3323aa_filter_gain[] = { 1, 2, 3 };
/*
* Register bitmap values for the filter gain. The index in this array is the
* corresponding index in d3323aa_filter_gain for the gain value.
*/
static const u8 d3323aa_filter_gain_regval[] = { 1, 3, 0 };
struct d3323aa_data {
struct completion reset_completion;
/*
* Since the setup process always requires a complete write of _all_
* the state variables, we need to synchronize them with a lock.
*/
struct mutex statevar_lock;
struct device *dev;
/* Supply voltage. */
struct regulator *regulator_vdd;
/* Input clock or output detection signal (Vout). */
struct gpio_desc *gpiod_clkin_detectout;
/* Input (setting) or output data. */
struct gpio_desc *gpiod_data;
/*
* We only need the low-pass cutoff frequency to unambiguously choose
* the type of band-pass filter. For example, both filter type B and C
* have 0.3 Hz as high-pass cutoff frequency (see
* d3323aa_hp_filter_freq).
*/
size_t lp_filter_freq_idx;
size_t filter_gain_idx;
u8 detect_thresh;
u8 irq_reset_count;
/* Indicator for operational mode (configuring or detecting). */
bool detecting;
};
static int d3323aa_read_settings(struct iio_dev *indio_dev,
unsigned long *regbitmap)
{
struct d3323aa_data *data = iio_priv(indio_dev);
size_t i;
int ret;
/* Bit bang the clock and data pins. */
ret = gpiod_direction_output(data->gpiod_clkin_detectout, 0);
if (ret)
return ret;
ret = gpiod_direction_input(data->gpiod_data);
if (ret)
return ret;
dev_dbg(data->dev, "Reading settings...\n");
for (i = 0; i < D3323AA_REG_NR_BITS; ++i) {
/* Clock frequency needs to be 1 kHz. */
gpiod_set_value(data->gpiod_clkin_detectout, 1);
udelay(500);
/* The data seems to change when clock signal is high. */
if (gpiod_get_value(data->gpiod_data))
set_bit(i, regbitmap);
gpiod_set_value(data->gpiod_clkin_detectout, 0);
udelay(500);
}
/* The first bit (F37) is just dummy data. Discard it. */
clear_bit(0, regbitmap);
/* Datasheet says to wait 30 ms after reading the settings. */
msleep(30);
return 0;
}
static int d3323aa_write_settings(struct iio_dev *indio_dev,
unsigned long *written_regbitmap)
{
#define REGBITMAP_LEN \
(D3323AA_REG_NR_BITS + D3323AA_SETTING_END_PATTERN_NR_BITS)
DECLARE_BITMAP(regbitmap, REGBITMAP_LEN);
struct d3323aa_data *data = iio_priv(indio_dev);
size_t i;
int ret;
/* Build the register bitmap. */
bitmap_zero(regbitmap, REGBITMAP_LEN);
bitmap_write(regbitmap, data->detect_thresh, D3323AA_REG_BIT_DETLVLABS0,
D3323AA_REG_BIT_DETLVLABS7 - D3323AA_REG_BIT_DETLVLABS0 +
1);
bitmap_write(regbitmap,
d3323aa_filter_gain_regval[data->filter_gain_idx],
D3323AA_REG_BIT_FSTEP0,
D3323AA_REG_BIT_FSTEP1 - D3323AA_REG_BIT_FSTEP0 + 1);
bitmap_write(regbitmap,
d3323aa_lp_filter_regval[data->lp_filter_freq_idx],
D3323AA_REG_BIT_FILSEL0,
D3323AA_REG_BIT_FILSEL2 - D3323AA_REG_BIT_FILSEL0 + 1);
/* Compulsory end pattern. */
bitmap_write(regbitmap, D3323AA_SETTING_END_PATTERN,
D3323AA_REG_NR_BITS, D3323AA_SETTING_END_PATTERN_NR_BITS);
/* Bit bang the clock and data pins. */
ret = gpiod_direction_output(data->gpiod_clkin_detectout, 0);
if (ret)
return ret;
ret = gpiod_direction_output(data->gpiod_data, 0);
if (ret)
return ret;
dev_dbg(data->dev, "Writing settings...\n");
/* First bit (F37) is not used when writing the register bitmap. */
for (i = 1; i < REGBITMAP_LEN; ++i) {
gpiod_set_value(data->gpiod_data, test_bit(i, regbitmap));
/* Clock frequency needs to be 1 kHz. */
gpiod_set_value(data->gpiod_clkin_detectout, 1);
udelay(500);
gpiod_set_value(data->gpiod_clkin_detectout, 0);
udelay(500);
}
/* Datasheet says to wait 30 ms after writing the settings. */
msleep(30);
bitmap_copy(written_regbitmap, regbitmap, D3323AA_REG_NR_BITS);
return 0;
}
static irqreturn_t d3323aa_irq_handler(int irq, void *dev_id)
{
struct iio_dev *indio_dev = dev_id;
struct d3323aa_data *data = iio_priv(indio_dev);
enum iio_event_direction dir;
int val;
val = gpiod_get_value(data->gpiod_clkin_detectout);
if (val < 0) {
dev_err_ratelimited(data->dev,
"Could not read from GPIO vout-clk (%d)\n",
val);
return IRQ_HANDLED;
}
if (!data->detecting) {
/* Reset interrupt counting falling edges. */
if (!val && ++data->irq_reset_count == D3323AA_IRQ_RESET_COUNT)
complete(&data->reset_completion);
return IRQ_HANDLED;
}
/* Detection interrupt. */
dir = val ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
iio_push_event(indio_dev,
IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 0,
IIO_EV_TYPE_THRESH, dir),
iio_get_time_ns(indio_dev));
return IRQ_HANDLED;
}
static int d3323aa_reset(struct iio_dev *indio_dev)
{
struct d3323aa_data *data = iio_priv(indio_dev);
long time;
int ret;
/* During probe() the regulator may already be disabled. */
if (regulator_is_enabled(data->regulator_vdd)) {
ret = regulator_disable(data->regulator_vdd);
if (ret)
return ret;
}
/*
* Datasheet says VDD needs to be low at least for 30 ms. Let's add a
* couple more to allow VDD to completely discharge as well.
*/
fsleep((30 + 5) * USEC_PER_MSEC);
/*
* When later enabling VDD, the device will signal with
* D3323AA_IRQ_RESET_COUNT falling edges on Vout/CLK that it is now
* ready for configuration. Datasheet says that this should happen
* within D3323AA_RESET_TIMEOUT ms. Count these two edges within that
* timeout.
*/
data->irq_reset_count = 0;
reinit_completion(&data->reset_completion);
data->detecting = false;
ret = gpiod_direction_input(data->gpiod_clkin_detectout);
if (ret)
return ret;
dev_dbg(data->dev, "Resetting...\n");
ret = regulator_enable(data->regulator_vdd);
if (ret)
return ret;
/*
* Wait for VDD to completely charge up. Measurements have shown that
* Vout/CLK signal slowly ramps up during this period. Thus, the digital
* signal will have bogus values. It is therefore necessary to wait
* before we can count the "real" falling edges.
*/
fsleep(2000);
time = wait_for_completion_killable_timeout(
&data->reset_completion,
msecs_to_jiffies(D3323AA_RESET_TIMEOUT));
if (time == 0) {
return -ETIMEDOUT;
} else if (time < 0) {
/* Got interrupted. */
return time;
}
dev_dbg(data->dev, "Reset completed\n");
return 0;
}
static int d3323aa_setup(struct iio_dev *indio_dev, size_t lp_filter_freq_idx,
size_t filter_gain_idx, u8 detect_thresh)
{
DECLARE_BITMAP(write_regbitmap, D3323AA_REG_NR_BITS);
DECLARE_BITMAP(read_regbitmap, D3323AA_REG_NR_BITS);
struct d3323aa_data *data = iio_priv(indio_dev);
unsigned long start_time;
int ret;
ret = d3323aa_reset(indio_dev);
if (ret) {
if (ret != -ERESTARTSYS)
dev_err(data->dev, "Could not reset device (%d)\n",
ret);
return ret;
}
/*
* Datasheet says to wait 10 us before setting the configuration.
* Moreover, the total configuration should be done within
* D3323AA_CONFIG_TIMEOUT ms. Clock it.
*/
fsleep(10);
start_time = jiffies;
ret = d3323aa_write_settings(indio_dev, write_regbitmap);
if (ret) {
dev_err(data->dev, "Could not write settings (%d)\n", ret);
return ret;
}
ret = d3323aa_read_settings(indio_dev, read_regbitmap);
if (ret) {
dev_err(data->dev, "Could not read settings (%d)\n", ret);
return ret;
}
if (time_is_before_jiffies(start_time +
msecs_to_jiffies(D3323AA_CONFIG_TIMEOUT))) {
dev_err(data->dev, "Could not set up configuration in time\n");
return -EAGAIN;
}
/* Check if settings were set successfully. */
if (!bitmap_equal(write_regbitmap, read_regbitmap,
D3323AA_REG_NR_BITS)) {
dev_err(data->dev, "Settings data mismatch\n");
return -EIO;
}
/* Now in operational mode. */
ret = gpiod_direction_input(data->gpiod_clkin_detectout);
if (ret) {
dev_err(data->dev,
"Could not set GPIO vout-clk as input (%d)\n", ret);
return ret;
}
ret = gpiod_direction_input(data->gpiod_data);
if (ret) {
dev_err(data->dev, "Could not set GPIO data as input (%d)\n",
ret);
return ret;
}
data->lp_filter_freq_idx = lp_filter_freq_idx;
data->filter_gain_idx = filter_gain_idx;
data->detect_thresh = detect_thresh;
data->detecting = true;
dev_dbg(data->dev, "Setup done\n");
return 0;
}
static int d3323aa_set_lp_filter_freq(struct iio_dev *indio_dev, const int val,
int val2)
{
struct d3323aa_data *data = iio_priv(indio_dev);
size_t idx;
/* Truncate fractional part to one digit. */
val2 /= 100000;
for (idx = 0; idx < ARRAY_SIZE(d3323aa_lp_filter_freq); ++idx) {
int integer = d3323aa_lp_filter_freq[idx][0] /
d3323aa_lp_filter_freq[idx][1];
int fract = d3323aa_lp_filter_freq[idx][0] %
d3323aa_lp_filter_freq[idx][1];
if (val == integer && val2 == fract)
break;
}
if (idx == ARRAY_SIZE(d3323aa_lp_filter_freq))
return -EINVAL;
return d3323aa_setup(indio_dev, idx, data->filter_gain_idx,
data->detect_thresh);
}
static int d3323aa_set_hp_filter_freq(struct iio_dev *indio_dev, const int val,
int val2)
{
struct d3323aa_data *data = iio_priv(indio_dev);
size_t idx;
/* Truncate fractional part to two digits. */
val2 /= 10000;
for (idx = 0; idx < ARRAY_SIZE(d3323aa_hp_filter_freq); ++idx) {
int integer = d3323aa_hp_filter_freq[idx][0] /
d3323aa_hp_filter_freq[idx][1];
int fract = d3323aa_hp_filter_freq[idx][0] %
d3323aa_hp_filter_freq[idx][1];
if (val == integer && val2 == fract)
break;
}
if (idx == ARRAY_SIZE(d3323aa_hp_filter_freq))
return -EINVAL;
if (idx == data->lp_filter_freq_idx) {
/* Corresponding filter frequency already set. */
return 0;
}
if (idx == 1 && data->lp_filter_freq_idx == 2) {
/*
* The low-pass cutoff frequency is the only way to
* unambiguously choose the type of band-pass filter. For
* example, both filter type B (index 1) and C (index 2) have
* 0.3 Hz as high-pass cutoff frequency (see
* d3323aa_hp_filter_freq). Therefore, if one of these are
* requested _and_ the corresponding low-pass filter frequency
* is already set, we can't know which filter type is the wanted
* one. The low-pass filter frequency is the decider (i.e. in
* this case index 2).
*/
return 0;
}
return d3323aa_setup(indio_dev, idx, data->filter_gain_idx,
data->detect_thresh);
}
static int d3323aa_set_filter_gain(struct iio_dev *indio_dev, const int val)
{
struct d3323aa_data *data = iio_priv(indio_dev);
size_t idx;
for (idx = 0; idx < ARRAY_SIZE(d3323aa_filter_gain); ++idx) {
if (d3323aa_filter_gain[idx] == val)
break;
}
if (idx == ARRAY_SIZE(d3323aa_filter_gain))
return -EINVAL;
return d3323aa_setup(indio_dev, data->lp_filter_freq_idx, idx,
data->detect_thresh);
}
static int d3323aa_set_threshold(struct iio_dev *indio_dev, const int val)
{
struct d3323aa_data *data = iio_priv(indio_dev);
if (val > ((1 << D3323AA_THRESH_REG_NR_BITS) - 1))
return -EINVAL;
return d3323aa_setup(indio_dev, data->lp_filter_freq_idx,
data->filter_gain_idx, val);
}
static int d3323aa_read_avail(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
const int **vals, int *type, int *length,
long mask)
{
switch (mask) {
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
*vals = (int *)d3323aa_hp_filter_freq;
*type = IIO_VAL_FRACTIONAL;
*length = 2 * ARRAY_SIZE(d3323aa_hp_filter_freq);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*vals = (int *)d3323aa_lp_filter_freq;
*type = IIO_VAL_FRACTIONAL;
*length = 2 * ARRAY_SIZE(d3323aa_lp_filter_freq);
return IIO_AVAIL_LIST;
case IIO_CHAN_INFO_HARDWAREGAIN:
*vals = (int *)d3323aa_filter_gain;
*type = IIO_VAL_INT;
*length = ARRAY_SIZE(d3323aa_filter_gain);
return IIO_AVAIL_LIST;
default:
return -EINVAL;
}
}
static int d3323aa_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int *val,
int *val2, long mask)
{
struct d3323aa_data *data = iio_priv(indio_dev);
guard(mutex)(&data->statevar_lock);
switch (mask) {
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
*val = d3323aa_hp_filter_freq[data->lp_filter_freq_idx][0];
*val2 = d3323aa_hp_filter_freq[data->lp_filter_freq_idx][1];
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
*val = d3323aa_lp_filter_freq[data->lp_filter_freq_idx][0];
*val2 = d3323aa_lp_filter_freq[data->lp_filter_freq_idx][1];
return IIO_VAL_FRACTIONAL;
case IIO_CHAN_INFO_HARDWAREGAIN:
*val = d3323aa_filter_gain[data->filter_gain_idx];
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int d3323aa_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan, int val,
int val2, long mask)
{
struct d3323aa_data *data = iio_priv(indio_dev);
guard(mutex)(&data->statevar_lock);
switch (mask) {
case IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY:
return d3323aa_set_hp_filter_freq(indio_dev, val, val2);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return d3323aa_set_lp_filter_freq(indio_dev, val, val2);
case IIO_CHAN_INFO_HARDWAREGAIN:
return d3323aa_set_filter_gain(indio_dev, val);
default:
return -EINVAL;
}
}
static int d3323aa_read_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info, int *val, int *val2)
{
struct d3323aa_data *data = iio_priv(indio_dev);
guard(mutex)(&data->statevar_lock);
switch (info) {
case IIO_EV_INFO_VALUE:
*val = data->detect_thresh;
return IIO_VAL_INT;
default:
return -EINVAL;
}
}
static int d3323aa_write_event(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan,
enum iio_event_type type,
enum iio_event_direction dir,
enum iio_event_info info, int val, int val2)
{
struct d3323aa_data *data = iio_priv(indio_dev);
guard(mutex)(&data->statevar_lock);
switch (info) {
case IIO_EV_INFO_VALUE:
return d3323aa_set_threshold(indio_dev, val);
default:
return -EINVAL;
}
}
static const struct iio_info d3323aa_info = {
.read_avail = d3323aa_read_avail,
.read_raw = d3323aa_read_raw,
.write_raw = d3323aa_write_raw,
.read_event_value = d3323aa_read_event,
.write_event_value = d3323aa_write_event,
};
static const struct iio_event_spec d3323aa_event_spec[] = {
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_RISING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
},
{
.type = IIO_EV_TYPE_THRESH,
.dir = IIO_EV_DIR_FALLING,
.mask_separate = BIT(IIO_EV_INFO_VALUE),
},
};
static const struct iio_chan_spec d3323aa_channels[] = {
{
.type = IIO_PROXIMITY,
.info_mask_separate =
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
BIT(IIO_CHAN_INFO_HARDWAREGAIN),
.info_mask_separate_available =
BIT(IIO_CHAN_INFO_HIGH_PASS_FILTER_3DB_FREQUENCY) |
BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY) |
BIT(IIO_CHAN_INFO_HARDWAREGAIN),
.event_spec = d3323aa_event_spec,
.num_event_specs = ARRAY_SIZE(d3323aa_event_spec),
},
};
static void d3323aa_disable_regulator(void *indata)
{
struct d3323aa_data *data = indata;
int ret;
/*
* During probe() the regulator may be disabled. It is enabled during
* device setup (in d3323aa_reset(), where it is also briefly disabled).
* The check is therefore needed in order to have balanced
* regulator_enable/disable() calls.
*/
if (!regulator_is_enabled(data->regulator_vdd))
return;
ret = regulator_disable(data->regulator_vdd);
if (ret)
dev_err(data->dev, "Could not disable regulator (%d)\n", ret);
}
static int d3323aa_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct d3323aa_data *data;
struct iio_dev *indio_dev;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return dev_err_probe(dev, -ENOMEM,
"Could not allocate iio device\n");
data = iio_priv(indio_dev);
data->dev = dev;
init_completion(&data->reset_completion);
ret = devm_mutex_init(dev, &data->statevar_lock);
if (ret)
return dev_err_probe(dev, ret, "Could not initialize mutex\n");
data->regulator_vdd = devm_regulator_get_exclusive(dev, "vdd");
if (IS_ERR(data->regulator_vdd))
return dev_err_probe(dev, PTR_ERR(data->regulator_vdd),
"Could not get regulator\n");
/*
* The regulator will be enabled for the first time during the
* device setup below (in d3323aa_reset()). However parameter changes
* from userspace can require a temporary disable of the regulator.
* To avoid complex handling of state, use a callback that will disable
* the regulator if it happens to be enabled at time of devm unwind.
*/
ret = devm_add_action_or_reset(dev, d3323aa_disable_regulator, data);
if (ret)
return ret;
data->gpiod_clkin_detectout =
devm_gpiod_get(dev, "vout-clk", GPIOD_OUT_LOW);
if (IS_ERR(data->gpiod_clkin_detectout))
return dev_err_probe(dev, PTR_ERR(data->gpiod_clkin_detectout),
"Could not get GPIO vout-clk\n");
data->gpiod_data = devm_gpiod_get(dev, "data", GPIOD_OUT_LOW);
if (IS_ERR(data->gpiod_data))
return dev_err_probe(dev, PTR_ERR(data->gpiod_data),
"Could not get GPIO data\n");
ret = gpiod_to_irq(data->gpiod_clkin_detectout);
if (ret < 0)
return dev_err_probe(dev, ret, "Could not get IRQ\n");
/*
* Device signals with a rising or falling detection signal when the
* proximity data is above or below the threshold, respectively.
*/
ret = devm_request_irq(dev, ret, d3323aa_irq_handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
dev_name(dev), indio_dev);
if (ret)
return dev_err_probe(dev, ret, "Could not request IRQ\n");
ret = d3323aa_setup(indio_dev, D3323AA_LP_FILTER_FREQ_DEFAULT_IDX,
D3323AA_FILTER_GAIN_DEFAULT_IDX,
D3323AA_THRESH_DEFAULT_VAL);
if (ret)
return ret;
indio_dev->info = &d3323aa_info;
indio_dev->name = "d3323aa";
indio_dev->channels = d3323aa_channels;
indio_dev->num_channels = ARRAY_SIZE(d3323aa_channels);
ret = devm_iio_device_register(dev, indio_dev);
if (ret)
return dev_err_probe(dev, ret,
"Could not register iio device\n");
return 0;
}
static const struct of_device_id d3323aa_of_match[] = {
{
.compatible = "nicera,d3323aa",
},
{ }
};
MODULE_DEVICE_TABLE(of, d3323aa_of_match);
static struct platform_driver d3323aa_driver = {
.probe = d3323aa_probe,
.driver = {
.name = "d3323aa",
.of_match_table = d3323aa_of_match,
},
};
module_platform_driver(d3323aa_driver);
MODULE_AUTHOR("Waqar Hameed <waqar.hameed@axis.com>");
MODULE_DESCRIPTION("Nicera D3-323-AA PIR sensor driver");
MODULE_LICENSE("GPL");
|