aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdriana Reus <adriana.reus@intel.com>2015-12-14 07:24:46 -0500
committerJonathan Cameron <jic23@kernel.org>2015-12-22 13:07:05 -0500
commitb6695254f800698faee4f30a8f0b199459ebeafe (patch)
treee91bfc8c5cc24a734f1899c53a2a7576a9f8f5d6
parent58e9042f5f130bf3f9043cf75aa2632fc12140e6 (diff)
iio: light: us5182d: Add interrupt support and events
Add interrupt support for proximity. Add two threshold events to signal rising and falling directions. Signed-off-by: Adriana Reus <adriana.reus@intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/light/us5182d.c271
1 files changed, 270 insertions, 1 deletions
diff --git a/drivers/iio/light/us5182d.c b/drivers/iio/light/us5182d.c
index f24b687bd152..213f7785095f 100644
--- a/drivers/iio/light/us5182d.c
+++ b/drivers/iio/light/us5182d.c
@@ -20,7 +20,10 @@
20#include <linux/acpi.h> 20#include <linux/acpi.h>
21#include <linux/delay.h> 21#include <linux/delay.h>
22#include <linux/i2c.h> 22#include <linux/i2c.h>
23#include <linux/iio/events.h>
23#include <linux/iio/iio.h> 24#include <linux/iio/iio.h>
25#include <linux/interrupt.h>
26#include <linux/irq.h>
24#include <linux/iio/sysfs.h> 27#include <linux/iio/sysfs.h>
25#include <linux/mutex.h> 28#include <linux/mutex.h>
26#include <linux/pm.h> 29#include <linux/pm.h>
@@ -30,6 +33,8 @@
30#define US5182D_CFG0_ONESHOT_EN BIT(6) 33#define US5182D_CFG0_ONESHOT_EN BIT(6)
31#define US5182D_CFG0_SHUTDOWN_EN BIT(7) 34#define US5182D_CFG0_SHUTDOWN_EN BIT(7)
32#define US5182D_CFG0_WORD_ENABLE BIT(0) 35#define US5182D_CFG0_WORD_ENABLE BIT(0)
36#define US5182D_CFG0_PROX BIT(3)
37#define US5182D_CFG0_PX_IRQ BIT(2)
33 38
34#define US5182D_REG_CFG1 0x01 39#define US5182D_REG_CFG1 0x01
35#define US5182D_CFG1_ALS_RES16 BIT(4) 40#define US5182D_CFG1_ALS_RES16 BIT(4)
@@ -41,6 +46,7 @@
41 46
42#define US5182D_REG_CFG3 0x03 47#define US5182D_REG_CFG3 0x03
43#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5)) 48#define US5182D_CFG3_LED_CURRENT100 (BIT(4) | BIT(5))
49#define US5182D_CFG3_INT_SOURCE_PX BIT(3)
44 50
45#define US5182D_REG_CFG4 0x10 51#define US5182D_REG_CFG4 0x10
46 52
@@ -55,6 +61,13 @@
55#define US5182D_REG_AUTO_LDARK_GAIN 0x29 61#define US5182D_REG_AUTO_LDARK_GAIN 0x29
56#define US5182D_REG_AUTO_HDARK_GAIN 0x2a 62#define US5182D_REG_AUTO_HDARK_GAIN 0x2a
57 63
64/* Thresholds for events: px low (0x08-l, 0x09-h), px high (0x0a-l 0x0b-h) */
65#define US5182D_REG_PXL_TH 0x08
66#define US5182D_REG_PXH_TH 0x0a
67
68#define US5182D_REG_PXL_TH_DEFAULT 1000
69#define US5182D_REG_PXH_TH_DEFAULT 30000
70
58#define US5182D_OPMODE_ALS 0x01 71#define US5182D_OPMODE_ALS 0x01
59#define US5182D_OPMODE_PX 0x02 72#define US5182D_OPMODE_PX 0x02
60#define US5182D_OPMODE_SHIFT 4 73#define US5182D_OPMODE_SHIFT 4
@@ -84,6 +97,8 @@
84#define US5182D_READ_WORD 2 97#define US5182D_READ_WORD 2
85#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */ 98#define US5182D_OPSTORE_SLEEP_TIME 20 /* ms */
86#define US5182D_SLEEP_MS 3000 /* ms */ 99#define US5182D_SLEEP_MS 3000 /* ms */
100#define US5182D_PXH_TH_DISABLE 0xffff
101#define US5182D_PXL_TH_DISABLE 0x0000
87 102
88/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */ 103/* Available ranges: [12354, 7065, 3998, 2202, 1285, 498, 256, 138] lux */
89static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600, 104static const int us5182d_scales[] = {188500, 107800, 61000, 33600, 19600, 7600,
@@ -119,6 +134,12 @@ struct us5182d_data {
119 u8 upper_dark_gain; 134 u8 upper_dark_gain;
120 u16 *us5182d_dark_ths; 135 u16 *us5182d_dark_ths;
121 136
137 u16 px_low_th;
138 u16 px_high_th;
139
140 int rising_en;
141 int falling_en;
142
122 u8 opmode; 143 u8 opmode;
123 u8 power_mode; 144 u8 power_mode;
124 145
@@ -148,10 +169,26 @@ static const struct {
148 {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16}, 169 {US5182D_REG_CFG1, US5182D_CFG1_ALS_RES16},
149 {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 | 170 {US5182D_REG_CFG2, (US5182D_CFG2_PX_RES16 |
150 US5182D_CFG2_PXGAIN_DEFAULT)}, 171 US5182D_CFG2_PXGAIN_DEFAULT)},
151 {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100}, 172 {US5182D_REG_CFG3, US5182D_CFG3_LED_CURRENT100 |
173 US5182D_CFG3_INT_SOURCE_PX},
152 {US5182D_REG_CFG4, 0x00}, 174 {US5182D_REG_CFG4, 0x00},
153}; 175};
154 176
177static const struct iio_event_spec us5182d_events[] = {
178 {
179 .type = IIO_EV_TYPE_THRESH,
180 .dir = IIO_EV_DIR_RISING,
181 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
182 BIT(IIO_EV_INFO_ENABLE),
183 },
184 {
185 .type = IIO_EV_TYPE_THRESH,
186 .dir = IIO_EV_DIR_FALLING,
187 .mask_separate = BIT(IIO_EV_INFO_VALUE) |
188 BIT(IIO_EV_INFO_ENABLE),
189 },
190};
191
155static const struct iio_chan_spec us5182d_channels[] = { 192static const struct iio_chan_spec us5182d_channels[] = {
156 { 193 {
157 .type = IIO_LIGHT, 194 .type = IIO_LIGHT,
@@ -161,6 +198,8 @@ static const struct iio_chan_spec us5182d_channels[] = {
161 { 198 {
162 .type = IIO_PROXIMITY, 199 .type = IIO_PROXIMITY,
163 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), 200 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
201 .event_spec = us5182d_events,
202 .num_event_specs = ARRAY_SIZE(us5182d_events),
164 } 203 }
165}; 204};
166 205
@@ -487,11 +526,201 @@ static int us5182d_write_raw(struct iio_dev *indio_dev,
487 return -EINVAL; 526 return -EINVAL;
488} 527}
489 528
529static int us5182d_setup_prox(struct iio_dev *indio_dev,
530 enum iio_event_direction dir, u16 val)
531{
532 struct us5182d_data *data = iio_priv(indio_dev);
533
534 if (dir == IIO_EV_DIR_FALLING)
535 return i2c_smbus_write_word_data(data->client,
536 US5182D_REG_PXL_TH, val);
537 else if (dir == IIO_EV_DIR_RISING)
538 return i2c_smbus_write_word_data(data->client,
539 US5182D_REG_PXH_TH, val);
540
541 return 0;
542}
543
544static int us5182d_read_thresh(struct iio_dev *indio_dev,
545 const struct iio_chan_spec *chan, enum iio_event_type type,
546 enum iio_event_direction dir, enum iio_event_info info, int *val,
547 int *val2)
548{
549 struct us5182d_data *data = iio_priv(indio_dev);
550
551 switch (dir) {
552 case IIO_EV_DIR_RISING:
553 mutex_lock(&data->lock);
554 *val = data->px_high_th;
555 mutex_unlock(&data->lock);
556 break;
557 case IIO_EV_DIR_FALLING:
558 mutex_lock(&data->lock);
559 *val = data->px_low_th;
560 mutex_unlock(&data->lock);
561 break;
562 default:
563 return -EINVAL;
564 }
565
566 return IIO_VAL_INT;
567}
568
569static int us5182d_write_thresh(struct iio_dev *indio_dev,
570 const struct iio_chan_spec *chan, enum iio_event_type type,
571 enum iio_event_direction dir, enum iio_event_info info, int val,
572 int val2)
573{
574 struct us5182d_data *data = iio_priv(indio_dev);
575 int ret;
576
577 if (val < 0 || val > USHRT_MAX || val2 != 0)
578 return -EINVAL;
579
580 switch (dir) {
581 case IIO_EV_DIR_RISING:
582 mutex_lock(&data->lock);
583 if (data->rising_en) {
584 ret = us5182d_setup_prox(indio_dev, dir, val);
585 if (ret < 0)
586 goto err;
587 }
588 data->px_high_th = val;
589 mutex_unlock(&data->lock);
590 break;
591 case IIO_EV_DIR_FALLING:
592 mutex_lock(&data->lock);
593 if (data->falling_en) {
594 ret = us5182d_setup_prox(indio_dev, dir, val);
595 if (ret < 0)
596 goto err;
597 }
598 data->px_low_th = val;
599 mutex_unlock(&data->lock);
600 break;
601 default:
602 return -EINVAL;
603 }
604
605 return 0;
606err:
607 mutex_unlock(&data->lock);
608 return ret;
609}
610
611static int us5182d_read_event_config(struct iio_dev *indio_dev,
612 const struct iio_chan_spec *chan, enum iio_event_type type,
613 enum iio_event_direction dir)
614{
615 struct us5182d_data *data = iio_priv(indio_dev);
616 int ret;
617
618 switch (dir) {
619 case IIO_EV_DIR_RISING:
620 mutex_lock(&data->lock);
621 ret = data->rising_en;
622 mutex_unlock(&data->lock);
623 break;
624 case IIO_EV_DIR_FALLING:
625 mutex_lock(&data->lock);
626 ret = data->falling_en;
627 mutex_unlock(&data->lock);
628 break;
629 default:
630 ret = -EINVAL;
631 break;
632 }
633
634 return ret;
635}
636
637static int us5182d_write_event_config(struct iio_dev *indio_dev,
638 const struct iio_chan_spec *chan, enum iio_event_type type,
639 enum iio_event_direction dir, int state)
640{
641 struct us5182d_data *data = iio_priv(indio_dev);
642 int ret;
643 u16 new_th;
644
645 mutex_lock(&data->lock);
646
647 switch (dir) {
648 case IIO_EV_DIR_RISING:
649 if (data->rising_en == state) {
650 mutex_unlock(&data->lock);
651 return 0;
652 }
653 new_th = US5182D_PXH_TH_DISABLE;
654 if (state) {
655 data->power_mode = US5182D_CONTINUOUS;
656 ret = us5182d_set_power_state(data, true);
657 if (ret < 0)
658 goto err;
659 ret = us5182d_px_enable(data);
660 if (ret < 0)
661 goto err_poweroff;
662 new_th = data->px_high_th;
663 }
664 ret = us5182d_setup_prox(indio_dev, dir, new_th);
665 if (ret < 0)
666 goto err_poweroff;
667 data->rising_en = state;
668 break;
669 case IIO_EV_DIR_FALLING:
670 if (data->falling_en == state) {
671 mutex_unlock(&data->lock);
672 return 0;
673 }
674 new_th = US5182D_PXL_TH_DISABLE;
675 if (state) {
676 data->power_mode = US5182D_CONTINUOUS;
677 ret = us5182d_set_power_state(data, true);
678 if (ret < 0)
679 goto err;
680 ret = us5182d_px_enable(data);
681 if (ret < 0)
682 goto err_poweroff;
683 new_th = data->px_low_th;
684 }
685 ret = us5182d_setup_prox(indio_dev, dir, new_th);
686 if (ret < 0)
687 goto err_poweroff;
688 data->falling_en = state;
689 break;
690 default:
691 ret = -EINVAL;
692 goto err;
693 }
694
695 if (!state) {
696 ret = us5182d_set_power_state(data, false);
697 if (ret < 0)
698 goto err;
699 }
700
701 if (!data->falling_en && !data->rising_en && !data->default_continuous)
702 data->power_mode = US5182D_ONESHOT;
703
704 mutex_unlock(&data->lock);
705 return 0;
706
707err_poweroff:
708 if (state)
709 us5182d_set_power_state(data, false);
710err:
711 mutex_unlock(&data->lock);
712 return ret;
713}
714
490static const struct iio_info us5182d_info = { 715static const struct iio_info us5182d_info = {
491 .driver_module = THIS_MODULE, 716 .driver_module = THIS_MODULE,
492 .read_raw = us5182d_read_raw, 717 .read_raw = us5182d_read_raw,
493 .write_raw = us5182d_write_raw, 718 .write_raw = us5182d_write_raw,
494 .attrs = &us5182d_attr_group, 719 .attrs = &us5182d_attr_group,
720 .read_event_value = &us5182d_read_thresh,
721 .write_event_value = &us5182d_write_thresh,
722 .read_event_config = &us5182d_read_event_config,
723 .write_event_config = &us5182d_write_event_config,
495}; 724};
496 725
497static int us5182d_reset(struct iio_dev *indio_dev) 726static int us5182d_reset(struct iio_dev *indio_dev)
@@ -513,6 +742,9 @@ static int us5182d_init(struct iio_dev *indio_dev)
513 742
514 data->opmode = 0; 743 data->opmode = 0;
515 data->power_mode = US5182D_CONTINUOUS; 744 data->power_mode = US5182D_CONTINUOUS;
745 data->px_low_th = US5182D_REG_PXL_TH_DEFAULT;
746 data->px_high_th = US5182D_REG_PXH_TH_DEFAULT;
747
516 for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) { 748 for (i = 0; i < ARRAY_SIZE(us5182d_regvals); i++) {
517 ret = i2c_smbus_write_byte_data(data->client, 749 ret = i2c_smbus_write_byte_data(data->client,
518 us5182d_regvals[i].reg, 750 us5182d_regvals[i].reg,
@@ -583,6 +815,33 @@ static int us5182d_dark_gain_config(struct iio_dev *indio_dev)
583 US5182D_REG_DARK_AUTO_EN_DEFAULT); 815 US5182D_REG_DARK_AUTO_EN_DEFAULT);
584} 816}
585 817
818static irqreturn_t us5182d_irq_thread_handler(int irq, void *private)
819{
820 struct iio_dev *indio_dev = private;
821 struct us5182d_data *data = iio_priv(indio_dev);
822 enum iio_event_direction dir;
823 int ret;
824 u64 ev;
825
826 ret = i2c_smbus_read_byte_data(data->client, US5182D_REG_CFG0);
827 if (ret < 0) {
828 dev_err(&data->client->dev, "i2c transfer error in irq\n");
829 return IRQ_HANDLED;
830 }
831
832 dir = ret & US5182D_CFG0_PROX ? IIO_EV_DIR_RISING : IIO_EV_DIR_FALLING;
833 ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, IIO_EV_TYPE_THRESH, dir);
834
835 iio_push_event(indio_dev, ev, iio_get_time_ns());
836
837 ret = i2c_smbus_write_byte_data(data->client, US5182D_REG_CFG0,
838 ret & ~US5182D_CFG0_PX_IRQ);
839 if (ret < 0)
840 dev_err(&data->client->dev, "i2c transfer error in irq\n");
841
842 return IRQ_HANDLED;
843}
844
586static int us5182d_probe(struct i2c_client *client, 845static int us5182d_probe(struct i2c_client *client,
587 const struct i2c_device_id *id) 846 const struct i2c_device_id *id)
588{ 847{
@@ -614,6 +873,16 @@ static int us5182d_probe(struct i2c_client *client,
614 return (ret < 0) ? ret : -ENODEV; 873 return (ret < 0) ? ret : -ENODEV;
615 } 874 }
616 875
876 if (client->irq > 0) {
877 ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
878 us5182d_irq_thread_handler,
879 IRQF_TRIGGER_LOW | IRQF_ONESHOT,
880 "us5182d-irq", indio_dev);
881 if (ret < 0)
882 return ret;
883 } else
884 dev_warn(&client->dev, "no valid irq found\n");
885
617 us5182d_get_platform_data(indio_dev); 886 us5182d_get_platform_data(indio_dev);
618 ret = us5182d_init(indio_dev); 887 ret = us5182d_init(indio_dev);
619 if (ret < 0) 888 if (ret < 0)