aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xdrivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl25836
-rwxr-xr-xdrivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x13
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio10
-rw-r--r--drivers/staging/iio/Documentation/sysfs-bus-iio-light15
-rw-r--r--drivers/staging/iio/light/Kconfig8
-rw-r--r--drivers/staging/iio/light/Makefile1
-rwxr-xr-xdrivers/staging/iio/light/tsl2x7x.h100
-rwxr-xr-xdrivers/staging/iio/light/tsl2x7x_core.c2072
8 files changed, 2217 insertions, 8 deletions
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583 b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
new file mode 100755
index 00000000000..470f7ad9c07
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2583
@@ -0,0 +1,6 @@
1What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
2KernelVersion: 2.6.37
3Contact: linux-iio@vger.kernel.org
4Description:
5 This property causes an internal calibration of the als gain trim
6 value which is later used in calculating illuminance in lux.
diff --git a/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
new file mode 100755
index 00000000000..b2798b258bf
--- /dev/null
+++ b/drivers/staging/iio/Documentation/light/sysfs-bus-iio-light-tsl2x7x
@@ -0,0 +1,13 @@
1What: /sys/bus/iio/devices/device[n]/in_illuminance0_calibrate
2KernelVersion: 3.3-rc1
3Contact: linux-iio@vger.kernel.org
4Description:
5 Causes an internal calibration of the als gain trim
6 value which is later used in calculating illuminance in lux.
7
8What: /sys/bus/iio/devices/device[n]/in_proximity0_calibrate
9KernelVersion: 3.3-rc1
10Contact: linux-iio@vger.kernel.org
11Description:
12 Causes a recalculation and adjustment to the
13 proximity_thresh_rising_value.
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio b/drivers/staging/iio/Documentation/sysfs-bus-iio
index ca12784aa17..eec9acbd964 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio
@@ -243,6 +243,8 @@ What: /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibbias
243What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias 243What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibbias
244What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias 244What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibbias
245What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias 245What: /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibbias
246What: /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibbias
247What: /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibbias
246KernelVersion: 2.6.35 248KernelVersion: 2.6.35
247Contact: linux-iio@vger.kernel.org 249Contact: linux-iio@vger.kernel.org
248Description: 250Description:
@@ -258,6 +260,8 @@ What /sys/bus/iio/devices/iio:deviceX/in_accel_z_calibscale
258What /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale 260What /sys/bus/iio/devices/iio:deviceX/in_anglvel_x_calibscale
259What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale 261What /sys/bus/iio/devices/iio:deviceX/in_anglvel_y_calibscale
260What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale 262What /sys/bus/iio/devices/iio:deviceX/in_anglvel_z_calibscale
263what /sys/bus/iio/devices/iio:deviceX/in_illuminance0_calibscale
264what /sys/bus/iio/devices/iio:deviceX/in_proximity0_calibscale
261KernelVersion: 2.6.35 265KernelVersion: 2.6.35
262Contact: linux-iio@vger.kernel.org 266Contact: linux-iio@vger.kernel.org
263Description: 267Description:
@@ -457,6 +461,10 @@ What: /sys/.../events/in_voltageY_raw_thresh_rising_value
457What: /sys/.../events/in_voltageY_raw_thresh_falling_value 461What: /sys/.../events/in_voltageY_raw_thresh_falling_value
458What: /sys/.../events/in_tempY_raw_thresh_rising_value 462What: /sys/.../events/in_tempY_raw_thresh_rising_value
459What: /sys/.../events/in_tempY_raw_thresh_falling_value 463What: /sys/.../events/in_tempY_raw_thresh_falling_value
464What: /sys/.../events/in_illuminance0_thresh_falling_value
465what: /sys/.../events/in_illuminance0_thresh_rising_value
466what: /sys/.../events/in_proximity0_thresh_falling_value
467what: /sys/.../events/in_proximity0_thresh_rising_value
460KernelVersion: 2.6.37 468KernelVersion: 2.6.37
461Contact: linux-iio@vger.kernel.org 469Contact: linux-iio@vger.kernel.org
462Description: 470Description:
@@ -556,6 +564,8 @@ What: /sys/.../events/in_tempY_thresh_falling_period
556What: /sys/.../events/in_tempY_roc_rising_period 564What: /sys/.../events/in_tempY_roc_rising_period
557What: /sys/.../events/in_tempY_roc_falling_period 565What: /sys/.../events/in_tempY_roc_falling_period
558What: /sys/.../events/in_accel_x&y&z_mag_falling_period 566What: /sys/.../events/in_accel_x&y&z_mag_falling_period
567What: /sys/.../events/in_intensity0_thresh_period
568What: /sys/.../events/in_proximity0_thresh_period
559KernelVersion: 2.6.37 569KernelVersion: 2.6.37
560Contact: linux-iio@vger.kernel.org 570Contact: linux-iio@vger.kernel.org
561Description: 571Description:
diff --git a/drivers/staging/iio/Documentation/sysfs-bus-iio-light b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
index edbf470e4e3..715c74dcb53 100644
--- a/drivers/staging/iio/Documentation/sysfs-bus-iio-light
+++ b/drivers/staging/iio/Documentation/sysfs-bus-iio-light
@@ -26,7 +26,7 @@ Description:
26 Hardware dependent list of possible values supported for the 26 Hardware dependent list of possible values supported for the
27 adc_resolution of the given sensor. 27 adc_resolution of the given sensor.
28 28
29What: /sys/bus/iio/devices/device[n]/illuminance0[_input|_raw] 29What: /sys/bus/iio/devices/device[n]/in_illuminance0[_input|_raw]
30KernelVersion: 2.6.35 30KernelVersion: 2.6.35
31Contact: linux-iio@vger.kernel.org 31Contact: linux-iio@vger.kernel.org
32Description: 32Description:
@@ -45,7 +45,7 @@ Description:
45 do this calculation manually by reading the infrared sensor 45 do this calculation manually by reading the infrared sensor
46 value and doing the negation in sw. 46 value and doing the negation in sw.
47 47
48What: /sys/bus/iio/devices/device[n]/proximity[_input|_raw] 48What: /sys/bus/iio/devices/device[n]/in_proximity[_input|_raw]
49KernelVersion: 2.6.37 49KernelVersion: 2.6.37
50Contact: linux-iio@vger.kernel.org 50Contact: linux-iio@vger.kernel.org
51Description: 51Description:
@@ -63,23 +63,22 @@ Description:
63 and if expressed in SI units, should include _input. If this 63 and if expressed in SI units, should include _input. If this
64 value is not in SI units, then it should include _raw. 64 value is not in SI units, then it should include _raw.
65 65
66What: /sys/bus/iio/devices/device[n]/illuminance0_target 66What: /sys/bus/iio/devices/device[n]/in_illuminance0_target
67KernelVersion: 2.6.37 67KernelVersion: 2.6.37
68Contact: linux-iio@vger.kernel.org 68Contact: linux-iio@vger.kernel.org
69Description: 69Description:
70 This property gets/sets the last known external 70 This property gets/sets the last known external
71 lux measurement used in/for calibration. 71 lux measurement used in/for calibration.
72 72
73What: /sys/bus/iio/devices/device[n]/illuminance0_integration_time 73What: /sys/bus/iio/devices/device[n]/in_illuminance0_integration_time
74KernelVersion: 2.6.37 74KernelVersion: 2.6.37
75Contact: linux-iio@vger.kernel.org 75Contact: linux-iio@vger.kernel.org
76Description: 76Description:
77 This property gets/sets the sensors ADC analog integration time. 77 This property gets/sets the sensors ADC analog integration time.
78 78
79What: /sys/bus/iio/devices/device[n]/illuminance0_calibscale 79What: /sys/bus/iio/devices/device[n]/in_illuminance0_lux_table
80KernelVersion: 2.6.37 80KernelVersion: 2.6.37
81Contact: linux-iio@vger.kernel.org 81Contact: linux-iio@vger.kernel.org
82Description: 82Description:
83 Hardware or software applied calibration scale factor assumed 83 This property gets/sets the table of coefficients
84 to account for attenuation due to industrial design (glass 84 used in calculating illuminance in lux.
85 filters or aperture holes).
diff --git a/drivers/staging/iio/light/Kconfig b/drivers/staging/iio/light/Kconfig
index fd39f72a328..4bed30eac3e 100644
--- a/drivers/staging/iio/light/Kconfig
+++ b/drivers/staging/iio/light/Kconfig
@@ -42,4 +42,12 @@ config TSL2583
42 Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. 42 Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices.
43 Access ALS data via iio, sysfs. 43 Access ALS data via iio, sysfs.
44 44
45config TSL2x7x
46 tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors"
47 depends on I2C
48 help
49 Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672,
50 tmd2672, tsl2772, tmd2772 devices.
51 Provides iio_events and direct access via sysfs.
52
45endmenu 53endmenu
diff --git a/drivers/staging/iio/light/Makefile b/drivers/staging/iio/light/Makefile
index 535d3139ccb..141af1eb164 100644
--- a/drivers/staging/iio/light/Makefile
+++ b/drivers/staging/iio/light/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
6obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o 6obj-$(CONFIG_SENSORS_ISL29018) += isl29018.o
7obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o 7obj-$(CONFIG_SENSORS_ISL29028) += isl29028.o
8obj-$(CONFIG_TSL2583) += tsl2583.o 8obj-$(CONFIG_TSL2583) += tsl2583.o
9obj-$(CONFIG_TSL2x7x) += tsl2x7x_core.o
diff --git a/drivers/staging/iio/light/tsl2x7x.h b/drivers/staging/iio/light/tsl2x7x.h
new file mode 100755
index 00000000000..c4acf5ff179
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x.h
@@ -0,0 +1,100 @@
1/*
2 * Device driver for monitoring ambient light intensity (lux)
3 * and proximity (prox) within the TAOS TSL2X7X family of devices.
4 *
5 * Copyright (c) 2012, TAOS Corporation.
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 as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#ifndef __TSL2X7X_H
23#define __TSL2X7X_H
24#include <linux/pm.h>
25
26/* Max number of segments allowable in LUX table */
27#define TSL2X7X_MAX_LUX_TABLE_SIZE 9
28#define MAX_DEFAULT_TABLE_BYTES (sizeof(int) * TSL2X7X_MAX_LUX_TABLE_SIZE)
29
30struct iio_dev;
31
32struct tsl2x7x_lux {
33 unsigned int ratio;
34 unsigned int ch0;
35 unsigned int ch1;
36};
37
38/**
39 * struct tsl2x7x_default_settings - power on defaults unless
40 * overridden by platform data.
41 * @als_time: ALS Integration time - multiple of 50mS
42 * @als_gain: Index into the ALS gain table.
43 * @als_gain_trim: default gain trim to account for
44 * aperture effects.
45 * @wait_time: Time between PRX and ALS cycles
46 * in 2.7 periods
47 * @prx_time: 5.2ms prox integration time -
48 * decrease in 2.7ms periods
49 * @prx_gain: Proximity gain index
50 * @prox_config: Prox configuration filters.
51 * @als_cal_target: Known external ALS reading for
52 * calibration.
53 * @interrupts_en: Enable/Disable - 0x00 = none, 0x10 = als,
54 * 0x20 = prx, 0x30 = bth
55 * @persistence: H/W Filters, Number of 'out of limits'
56 * ADC readings PRX/ALS.
57 * @als_thresh_low: CH0 'low' count to trigger interrupt.
58 * @als_thresh_high: CH0 'high' count to trigger interrupt.
59 * @prox_thres_low: Low threshold proximity detection.
60 * @prox_thres_high: High threshold proximity detection
61 * @prox_pulse_count: Number if proximity emitter pulses
62 * @prox_max_samples_cal: Used for prox cal.
63 */
64struct tsl2x7x_settings {
65 int als_time;
66 int als_gain;
67 int als_gain_trim;
68 int wait_time;
69 int prx_time;
70 int prox_gain;
71 int prox_config;
72 int als_cal_target;
73 u8 interrupts_en;
74 u8 persistence;
75 int als_thresh_low;
76 int als_thresh_high;
77 int prox_thres_low;
78 int prox_thres_high;
79 int prox_pulse_count;
80 int prox_max_samples_cal;
81};
82
83/**
84 * struct tsl2X7X_platform_data - Platform callback, glass and defaults
85 * @platform_power: Suspend/resume platform callback
86 * @power_on: Power on callback
87 * @power_off: Power off callback
88 * @platform_lux_table: Device specific glass coefficents
89 * @platform_default_settings: Device specific power on defaults
90 *
91 */
92struct tsl2X7X_platform_data {
93 int (*platform_power)(struct device *dev, pm_message_t);
94 int (*power_on) (struct iio_dev *indio_dev);
95 int (*power_off) (struct i2c_client *dev);
96 struct tsl2x7x_lux platform_lux_table[TSL2X7X_MAX_LUX_TABLE_SIZE];
97 struct tsl2x7x_settings *platform_default_settings;
98};
99
100#endif /* __TSL2X7X_H */
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
new file mode 100755
index 00000000000..ff449894a94
--- /dev/null
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -0,0 +1,2072 @@
1/*
2 * Device driver for monitoring ambient light intensity in (lux)
3 * and proximity detection (prox) within the TAOS TSL2X7X family of devices.
4 *
5 * Copyright (c) 2012, TAOS Corporation.
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 as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22#include <linux/kernel.h>
23#include <linux/i2c.h>
24#include <linux/errno.h>
25#include <linux/delay.h>
26#include <linux/mutex.h>
27#include <linux/interrupt.h>
28#include <linux/slab.h>
29#include <linux/module.h>
30#include <linux/version.h>
31#include "tsl2x7x.h"
32#include "../events.h"
33#include "../iio.h"
34#include "../sysfs.h"
35
36/* Cal defs*/
37#define PROX_STAT_CAL 0
38#define PROX_STAT_SAMP 1
39#define MAX_SAMPLES_CAL 200
40
41/* TSL2X7X Device ID */
42#define TRITON_ID 0x00
43#define SWORDFISH_ID 0x30
44#define HALIBUT_ID 0x20
45
46/* Lux calculation constants */
47#define TSL2X7X_LUX_CALC_OVER_FLOW 65535
48
49/* TAOS Register definitions - note:
50 * depending on device, some of these register are not used and the
51 * register address is benign.
52 */
53/* 2X7X register offsets */
54#define TSL2X7X_MAX_CONFIG_REG 16
55
56/* Device Registers and Masks */
57#define TSL2X7X_CNTRL 0x00
58#define TSL2X7X_ALS_TIME 0X01
59#define TSL2X7X_PRX_TIME 0x02
60#define TSL2X7X_WAIT_TIME 0x03
61#define TSL2X7X_ALS_MINTHRESHLO 0X04
62#define TSL2X7X_ALS_MINTHRESHHI 0X05
63#define TSL2X7X_ALS_MAXTHRESHLO 0X06
64#define TSL2X7X_ALS_MAXTHRESHHI 0X07
65#define TSL2X7X_PRX_MINTHRESHLO 0X08
66#define TSL2X7X_PRX_MINTHRESHHI 0X09
67#define TSL2X7X_PRX_MAXTHRESHLO 0X0A
68#define TSL2X7X_PRX_MAXTHRESHHI 0X0B
69#define TSL2X7X_PERSISTENCE 0x0C
70#define TSL2X7X_PRX_CONFIG 0x0D
71#define TSL2X7X_PRX_COUNT 0x0E
72#define TSL2X7X_GAIN 0x0F
73#define TSL2X7X_NOTUSED 0x10
74#define TSL2X7X_REVID 0x11
75#define TSL2X7X_CHIPID 0x12
76#define TSL2X7X_STATUS 0x13
77#define TSL2X7X_ALS_CHAN0LO 0x14
78#define TSL2X7X_ALS_CHAN0HI 0x15
79#define TSL2X7X_ALS_CHAN1LO 0x16
80#define TSL2X7X_ALS_CHAN1HI 0x17
81#define TSL2X7X_PRX_LO 0x18
82#define TSL2X7X_PRX_HI 0x19
83
84/* tsl2X7X cmd reg masks */
85#define TSL2X7X_CMD_REG 0x80
86#define TSL2X7X_CMD_SPL_FN 0x60
87
88#define TSL2X7X_CMD_PROX_INT_CLR 0X05
89#define TSL2X7X_CMD_ALS_INT_CLR 0x06
90#define TSL2X7X_CMD_PROXALS_INT_CLR 0X07
91
92/* tsl2X7X cntrl reg masks */
93#define TSL2X7X_CNTL_ADC_ENBL 0x02
94#define TSL2X7X_CNTL_PWR_ON 0x01
95
96/* tsl2X7X status reg masks */
97#define TSL2X7X_STA_ADC_VALID 0x01
98#define TSL2X7X_STA_PRX_VALID 0x02
99#define TSL2X7X_STA_ADC_PRX_VALID (TSL2X7X_STA_ADC_VALID |\
100 TSL2X7X_STA_PRX_VALID)
101#define TSL2X7X_STA_ALS_INTR 0x10
102#define TSL2X7X_STA_PRX_INTR 0x20
103
104/* tsl2X7X cntrl reg masks */
105#define TSL2X7X_CNTL_REG_CLEAR 0x00
106#define TSL2X7X_CNTL_PROX_INT_ENBL 0X20
107#define TSL2X7X_CNTL_ALS_INT_ENBL 0X10
108#define TSL2X7X_CNTL_WAIT_TMR_ENBL 0X08
109#define TSL2X7X_CNTL_PROX_DET_ENBL 0X04
110#define TSL2X7X_CNTL_PWRON 0x01
111#define TSL2X7X_CNTL_ALSPON_ENBL 0x03
112#define TSL2X7X_CNTL_INTALSPON_ENBL 0x13
113#define TSL2X7X_CNTL_PROXPON_ENBL 0x0F
114#define TSL2X7X_CNTL_INTPROXPON_ENBL 0x2F
115
116/*Prox diode to use */
117#define TSL2X7X_DIODE0 0x10
118#define TSL2X7X_DIODE1 0x20
119#define TSL2X7X_DIODE_BOTH 0x30
120
121/* LED Power */
122#define TSL2X7X_mA100 0x00
123#define TSL2X7X_mA50 0x40
124#define TSL2X7X_mA25 0x80
125#define TSL2X7X_mA13 0xD0
126#define TSL2X7X_MAX_TIMER_CNT (0xFF)
127
128/*Common device IIO EventMask */
129#define TSL2X7X_EVENT_MASK \
130 (IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING) | \
131 IIO_EV_BIT(IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING)),
132
133/* TAOS txx2x7x Device family members */
134enum {
135 tsl2571,
136 tsl2671,
137 tmd2671,
138 tsl2771,
139 tmd2771,
140 tsl2572,
141 tsl2672,
142 tmd2672,
143 tsl2772,
144 tmd2772
145};
146
147enum {
148 TSL2X7X_CHIP_UNKNOWN = 0,
149 TSL2X7X_CHIP_WORKING = 1,
150 TSL2X7X_CHIP_SUSPENDED = 2
151};
152
153struct tsl2x7x_parse_result {
154 int integer;
155 int fract;
156};
157
158/* Per-device data */
159struct tsl2x7x_als_info {
160 u16 als_ch0;
161 u16 als_ch1;
162 u16 lux;
163};
164
165struct tsl2x7x_prox_stat {
166 int min;
167 int max;
168 int mean;
169 unsigned long stddev;
170};
171
172struct tsl2x7x_chip_info {
173 int chan_table_elements;
174 struct iio_chan_spec channel[4];
175 const struct iio_info *info;
176};
177
178struct tsl2X7X_chip {
179 kernel_ulong_t id;
180 struct mutex prox_mutex;
181 struct mutex als_mutex;
182 struct i2c_client *client;
183 u16 prox_data;
184 struct tsl2x7x_als_info als_cur_info;
185 struct tsl2x7x_settings tsl2x7x_settings;
186 struct tsl2X7X_platform_data *pdata;
187 int als_time_scale;
188 int als_saturation;
189 int tsl2x7x_chip_status;
190 u8 tsl2x7x_config[TSL2X7X_MAX_CONFIG_REG];
191 const struct tsl2x7x_chip_info *chip_info;
192 const struct iio_info *info;
193 s64 event_timestamp;
194 /* This structure is intentionally large to accommodate
195 * updates via sysfs. */
196 /* Sized to 9 = max 8 segments + 1 termination segment */
197 struct tsl2x7x_lux tsl2x7x_device_lux[TSL2X7X_MAX_LUX_TABLE_SIZE];
198};
199
200/* Different devices require different coefficents */
201static const struct tsl2x7x_lux tsl2x71_lux_table[] = {
202 { 14461, 611, 1211 },
203 { 18540, 352, 623 },
204 { 0, 0, 0 },
205};
206
207static const struct tsl2x7x_lux tmd2x71_lux_table[] = {
208 { 11635, 115, 256 },
209 { 15536, 87, 179 },
210 { 0, 0, 0 },
211};
212
213static const struct tsl2x7x_lux tsl2x72_lux_table[] = {
214 { 14013, 466, 917 },
215 { 18222, 310, 552 },
216 { 0, 0, 0 },
217};
218
219static const struct tsl2x7x_lux tmd2x72_lux_table[] = {
220 { 13218, 130, 262 },
221 { 17592, 92, 169 },
222 { 0, 0, 0 },
223};
224
225static const struct tsl2x7x_lux *tsl2x7x_default_lux_table_group[] = {
226 [tsl2571] = tsl2x71_lux_table,
227 [tsl2671] = tsl2x71_lux_table,
228 [tmd2671] = tmd2x71_lux_table,
229 [tsl2771] = tsl2x71_lux_table,
230 [tmd2771] = tmd2x71_lux_table,
231 [tsl2572] = tsl2x72_lux_table,
232 [tsl2672] = tsl2x72_lux_table,
233 [tmd2672] = tmd2x72_lux_table,
234 [tsl2772] = tsl2x72_lux_table,
235 [tmd2772] = tmd2x72_lux_table,
236};
237
238static const struct tsl2x7x_settings tsl2x7x_default_settings = {
239 .als_time = 219, /* 101 ms */
240 .als_gain = 0,
241 .prx_time = 254, /* 5.4 ms */
242 .prox_gain = 1,
243 .wait_time = 245,
244 .prox_config = 0,
245 .als_gain_trim = 1000,
246 .als_cal_target = 150,
247 .als_thresh_low = 200,
248 .als_thresh_high = 256,
249 .persistence = 255,
250 .interrupts_en = 0,
251 .prox_thres_low = 0,
252 .prox_thres_high = 512,
253 .prox_max_samples_cal = 30,
254 .prox_pulse_count = 8
255};
256
257static const s16 tsl2X7X_als_gainadj[] = {
258 1,
259 8,
260 16,
261 120
262};
263
264static const s16 tsl2X7X_prx_gainadj[] = {
265 1,
266 2,
267 4,
268 8
269};
270
271/* Channel variations */
272enum {
273 ALS,
274 PRX,
275 ALSPRX,
276 PRX2,
277 ALSPRX2,
278};
279
280const u8 device_channel_config[] = {
281 ALS,
282 PRX,
283 PRX,
284 ALSPRX,
285 ALSPRX,
286 ALS,
287 PRX2,
288 PRX2,
289 ALSPRX2,
290 ALSPRX2
291};
292
293/**
294 * tsl2x7x_parse_buffer() - parse a decimal result from a buffer.
295 * @*buf: pointer to char buffer to parse
296 * @*result: pointer to buffer to contain
297 * resulting interger / decimal as ints.
298 *
299 */
300static int
301tsl2x7x_parse_buffer(const char *buf, struct tsl2x7x_parse_result *result)
302{
303 int integer = 0, fract = 0, fract_mult = 100000;
304 bool integer_part = true, negative = false;
305
306 if (buf[0] == '-') {
307 negative = true;
308 buf++;
309 }
310
311 while (*buf) {
312 if ('0' <= *buf && *buf <= '9') {
313 if (integer_part)
314 integer = integer*10 + *buf - '0';
315 else {
316 fract += fract_mult*(*buf - '0');
317 if (fract_mult == 1)
318 break;
319 fract_mult /= 10;
320 }
321 } else if (*buf == '\n') {
322 if (*(buf + 1) == '\0')
323 break;
324 else
325 return -EINVAL;
326 } else if (*buf == '.') {
327 integer_part = false;
328 } else {
329 return -EINVAL;
330 }
331 buf++;
332 }
333 if (negative) {
334 if (integer)
335 integer = -integer;
336 else
337 fract = -fract;
338 }
339
340 result->integer = integer;
341 result->fract = fract;
342
343 return 0;
344}
345
346/**
347 * tsl2x7x_i2c_read() - Read a byte from a register.
348 * @client: i2c client
349 * @reg: device register to read from
350 * @*val: pointer to location to store register contents.
351 *
352 */
353static int
354tsl2x7x_i2c_read(struct i2c_client *client, u8 reg, u8 *val)
355{
356 int ret = 0;
357
358 /* select register to write */
359 ret = i2c_smbus_write_byte(client, (TSL2X7X_CMD_REG | reg));
360 if (ret < 0) {
361 dev_err(&client->dev, "%s: failed to write register %x\n"
362 , __func__, reg);
363 return ret;
364 }
365
366 /* read the data */
367 ret = i2c_smbus_read_byte(client);
368 if (ret >= 0)
369 *val = (u8)ret;
370 else
371 dev_err(&client->dev, "%s: failed to read register %x\n"
372 , __func__, reg);
373
374 return ret;
375}
376
377/**
378 * tsl2x7x_get_lux() - Reads and calculates current lux value.
379 * @indio_dev: pointer to IIO device
380 *
381 * The raw ch0 and ch1 values of the ambient light sensed in the last
382 * integration cycle are read from the device.
383 * Time scale factor array values are adjusted based on the integration time.
384 * The raw values are multiplied by a scale factor, and device gain is obtained
385 * using gain index. Limit checks are done next, then the ratio of a multiple
386 * of ch1 value, to the ch0 value, is calculated. Array tsl2x7x_device_lux[]
387 * is then scanned to find the first ratio value that is just above the ratio
388 * we just calculated. The ch0 and ch1 multiplier constants in the array are
389 * then used along with the time scale factor array values, to calculate the
390 * lux.
391 */
392static int tsl2x7x_get_lux(struct iio_dev *indio_dev)
393{
394 u16 ch0, ch1; /* separated ch0/ch1 data from device */
395 u32 lux; /* raw lux calculated from device data */
396 u64 lux64;
397 u32 ratio;
398 u8 buf[4];
399 struct tsl2x7x_lux *p;
400 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
401 int i, ret;
402 u32 ch0lux = 0;
403 u32 ch1lux = 0;
404
405 if (mutex_trylock(&chip->als_mutex) == 0)
406 return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
407
408 if (chip->tsl2x7x_chip_status != TSL2X7X_CHIP_WORKING) {
409 /* device is not enabled */
410 dev_err(&chip->client->dev, "%s: device is not enabled\n",
411 __func__);
412 ret = -EBUSY ;
413 goto out_unlock;
414 }
415
416 ret = tsl2x7x_i2c_read(chip->client,
417 (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &buf[0]);
418 if (ret < 0) {
419 dev_err(&chip->client->dev,
420 "%s: Failed to read STATUS Reg\n", __func__);
421 goto out_unlock;
422 }
423 /* is data new & valid */
424 if (!(buf[0] & TSL2X7X_STA_ADC_VALID)) {
425 dev_err(&chip->client->dev,
426 "%s: data not valid yet\n", __func__);
427 ret = chip->als_cur_info.lux; /* return LAST VALUE */
428 goto out_unlock;
429 }
430
431 for (i = 0; i < 4; i++) {
432 ret = tsl2x7x_i2c_read(chip->client,
433 (TSL2X7X_CMD_REG | (TSL2X7X_ALS_CHAN0LO + i)),
434 &buf[i]);
435 if (ret < 0) {
436 dev_err(&chip->client->dev,
437 "%s: failed to read. err=%x\n", __func__, ret);
438 goto out_unlock;
439 }
440 }
441
442 /* clear any existing interrupt status */
443 ret = i2c_smbus_write_byte(chip->client,
444 (TSL2X7X_CMD_REG |
445 TSL2X7X_CMD_SPL_FN |
446 TSL2X7X_CMD_ALS_INT_CLR));
447 if (ret < 0) {
448 dev_err(&chip->client->dev,
449 "%s: i2c_write_command failed - err = %d\n",
450 __func__, ret);
451 goto out_unlock; /* have no data, so return failure */
452 }
453
454 /* extract ALS/lux data */
455 ch0 = le16_to_cpup((const __le16 *)&buf[0]);
456 ch1 = le16_to_cpup((const __le16 *)&buf[2]);
457
458 chip->als_cur_info.als_ch0 = ch0;
459 chip->als_cur_info.als_ch1 = ch1;
460
461 if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation)) {
462 lux = TSL2X7X_LUX_CALC_OVER_FLOW;
463 goto return_max;
464 }
465
466 if (ch0 == 0) {
467 /* have no data, so return LAST VALUE */
468 ret = chip->als_cur_info.lux;
469 goto out_unlock;
470 }
471 /* calculate ratio */
472 ratio = (ch1 << 15) / ch0;
473 /* convert to unscaled lux using the pointer to the table */
474 p = (struct tsl2x7x_lux *) chip->tsl2x7x_device_lux;
475 while (p->ratio != 0 && p->ratio < ratio)
476 p++;
477
478 if (p->ratio == 0) {
479 lux = 0;
480 } else {
481 ch0lux = DIV_ROUND_UP((ch0 * p->ch0),
482 tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
483 ch1lux = DIV_ROUND_UP((ch1 * p->ch1),
484 tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain]);
485 lux = ch0lux - ch1lux;
486 }
487
488 /* note: lux is 31 bit max at this point */
489 if (ch1lux > ch0lux) {
490 dev_dbg(&chip->client->dev, "ch1lux > ch0lux-return last value\n");
491 ret = chip->als_cur_info.lux;
492 goto out_unlock;
493 }
494
495 /* adjust for active time scale */
496 if (chip->als_time_scale == 0)
497 lux = 0;
498 else
499 lux = (lux + (chip->als_time_scale >> 1)) /
500 chip->als_time_scale;
501
502 /* adjust for active gain scale
503 * The tsl2x7x_device_lux tables have a factor of 256 built-in.
504 * User-specified gain provides a multiplier.
505 * Apply user-specified gain before shifting right to retain precision.
506 * Use 64 bits to avoid overflow on multiplication.
507 * Then go back to 32 bits before division to avoid using div_u64().
508 */
509
510 lux64 = lux;
511 lux64 = lux64 * chip->tsl2x7x_settings.als_gain_trim;
512 lux64 >>= 8;
513 lux = lux64;
514 lux = (lux + 500) / 1000;
515
516 if (lux > TSL2X7X_LUX_CALC_OVER_FLOW) /* check for overflow */
517 lux = TSL2X7X_LUX_CALC_OVER_FLOW;
518
519 /* Update the structure with the latest lux. */
520return_max:
521 chip->als_cur_info.lux = lux;
522 ret = lux;
523
524out_unlock:
525 mutex_unlock(&chip->als_mutex);
526
527 return ret;
528}
529
530/**
531 * tsl2x7x_get_prox() - Reads proximity data registers and updates
532 * chip->prox_data.
533 *
534 * @indio_dev: pointer to IIO device
535 */
536static int tsl2x7x_get_prox(struct iio_dev *indio_dev)
537{
538 int i;
539 int ret;
540 u8 status;
541 u8 chdata[2];
542 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
543
544 if (mutex_trylock(&chip->prox_mutex) == 0) {
545 dev_err(&chip->client->dev,
546 "%s: Can't get prox mutex\n", __func__);
547 return -EBUSY;
548 }
549
550 ret = tsl2x7x_i2c_read(chip->client,
551 (TSL2X7X_CMD_REG | TSL2X7X_STATUS), &status);
552 if (ret < 0) {
553 dev_err(&chip->client->dev,
554 "%s: i2c err=%d\n", __func__, ret);
555 goto prox_poll_err;
556 }
557
558 switch (chip->id) {
559 case tsl2571:
560 case tsl2671:
561 case tmd2671:
562 case tsl2771:
563 case tmd2771:
564 if (!(status & TSL2X7X_STA_ADC_VALID))
565 goto prox_poll_err;
566 break;
567 case tsl2572:
568 case tsl2672:
569 case tmd2672:
570 case tsl2772:
571 case tmd2772:
572 if (!(status & TSL2X7X_STA_PRX_VALID))
573 goto prox_poll_err;
574 break;
575 }
576
577 for (i = 0; i < 2; i++) {
578 ret = tsl2x7x_i2c_read(chip->client,
579 (TSL2X7X_CMD_REG |
580 (TSL2X7X_PRX_LO + i)), &chdata[i]);
581 if (ret < 0)
582 goto prox_poll_err;
583 }
584
585 chip->prox_data =
586 le16_to_cpup((const __le16 *)&chdata[0]);
587
588prox_poll_err:
589
590 mutex_unlock(&chip->prox_mutex);
591
592 return chip->prox_data;
593}
594
595/**
596 * tsl2x7x_defaults() - Populates the device nominal operating parameters
597 * with those provided by a 'platform' data struct or
598 * with prefined defaults.
599 *
600 * @chip: pointer to device structure.
601 */
602static void tsl2x7x_defaults(struct tsl2X7X_chip *chip)
603{
604 /* If Operational settings defined elsewhere.. */
605 if (chip->pdata && chip->pdata->platform_default_settings != 0)
606 memcpy(&(chip->tsl2x7x_settings),
607 chip->pdata->platform_default_settings,
608 sizeof(tsl2x7x_default_settings));
609 else
610 memcpy(&(chip->tsl2x7x_settings),
611 &tsl2x7x_default_settings,
612 sizeof(tsl2x7x_default_settings));
613
614 /* Load up the proper lux table. */
615 if (chip->pdata && chip->pdata->platform_lux_table[0].ratio != 0)
616 memcpy(chip->tsl2x7x_device_lux,
617 chip->pdata->platform_lux_table,
618 sizeof(chip->pdata->platform_lux_table));
619 else
620 memcpy(chip->tsl2x7x_device_lux,
621 (struct tsl2x7x_lux *)tsl2x7x_default_lux_table_group[chip->id],
622 MAX_DEFAULT_TABLE_BYTES);
623}
624
625/**
626 * tsl2x7x_als_calibrate() - Obtain single reading and calculate
627 * the als_gain_trim.
628 *
629 * @indio_dev: pointer to IIO device
630 */
631static int tsl2x7x_als_calibrate(struct iio_dev *indio_dev)
632{
633 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
634 u8 reg_val;
635 int gain_trim_val;
636 int ret;
637 int lux_val;
638
639 ret = i2c_smbus_write_byte(chip->client,
640 (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
641 if (ret < 0) {
642 dev_err(&chip->client->dev,
643 "%s: failed to write CNTRL register, ret=%d\n",
644 __func__, ret);
645 return ret;
646 }
647
648 reg_val = i2c_smbus_read_byte(chip->client);
649 if ((reg_val & (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON))
650 != (TSL2X7X_CNTL_ADC_ENBL | TSL2X7X_CNTL_PWR_ON)) {
651 dev_err(&chip->client->dev,
652 "%s: failed: ADC not enabled\n", __func__);
653 return -1;
654 }
655
656 ret = i2c_smbus_write_byte(chip->client,
657 (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
658 if (ret < 0) {
659 dev_err(&chip->client->dev,
660 "%s: failed to write ctrl reg: ret=%d\n",
661 __func__, ret);
662 return ret;
663 }
664
665 reg_val = i2c_smbus_read_byte(chip->client);
666 if ((reg_val & TSL2X7X_STA_ADC_VALID) != TSL2X7X_STA_ADC_VALID) {
667 dev_err(&chip->client->dev,
668 "%s: failed: STATUS - ADC not valid.\n", __func__);
669 return -ENODATA;
670 }
671
672 lux_val = tsl2x7x_get_lux(indio_dev);
673 if (lux_val < 0) {
674 dev_err(&chip->client->dev,
675 "%s: failed to get lux\n", __func__);
676 return lux_val;
677 }
678
679 gain_trim_val = (((chip->tsl2x7x_settings.als_cal_target)
680 * chip->tsl2x7x_settings.als_gain_trim) / lux_val);
681 if ((gain_trim_val < 250) || (gain_trim_val > 4000))
682 return -ERANGE;
683
684 chip->tsl2x7x_settings.als_gain_trim = gain_trim_val;
685 dev_info(&chip->client->dev,
686 "%s als_calibrate completed\n", chip->client->name);
687
688 return (int) gain_trim_val;
689}
690
691static int tsl2x7x_chip_on(struct iio_dev *indio_dev)
692{
693 int i;
694 int ret = 0;
695 u8 *dev_reg;
696 u8 utmp;
697 int als_count;
698 int als_time;
699 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
700 u8 reg_val = 0;
701
702 if (chip->pdata && chip->pdata->power_on)
703 chip->pdata->power_on(indio_dev);
704
705 /* Non calculated parameters */
706 chip->tsl2x7x_config[TSL2X7X_PRX_TIME] =
707 chip->tsl2x7x_settings.prx_time;
708 chip->tsl2x7x_config[TSL2X7X_WAIT_TIME] =
709 chip->tsl2x7x_settings.wait_time;
710 chip->tsl2x7x_config[TSL2X7X_PRX_CONFIG] =
711 chip->tsl2x7x_settings.prox_config;
712
713 chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHLO] =
714 (chip->tsl2x7x_settings.als_thresh_low) & 0xFF;
715 chip->tsl2x7x_config[TSL2X7X_ALS_MINTHRESHHI] =
716 (chip->tsl2x7x_settings.als_thresh_low >> 8) & 0xFF;
717 chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHLO] =
718 (chip->tsl2x7x_settings.als_thresh_high) & 0xFF;
719 chip->tsl2x7x_config[TSL2X7X_ALS_MAXTHRESHHI] =
720 (chip->tsl2x7x_settings.als_thresh_high >> 8) & 0xFF;
721 chip->tsl2x7x_config[TSL2X7X_PERSISTENCE] =
722 chip->tsl2x7x_settings.persistence;
723
724 chip->tsl2x7x_config[TSL2X7X_PRX_COUNT] =
725 chip->tsl2x7x_settings.prox_pulse_count;
726 chip->tsl2x7x_config[TSL2X7X_PRX_MINTHRESHLO] =
727 chip->tsl2x7x_settings.prox_thres_low;
728 chip->tsl2x7x_config[TSL2X7X_PRX_MAXTHRESHLO] =
729 chip->tsl2x7x_settings.prox_thres_high;
730
731 /* and make sure we're not already on */
732 if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
733 /* if forcing a register update - turn off, then on */
734 dev_info(&chip->client->dev, "device is already enabled\n");
735 return -EINVAL;
736 }
737
738 /* determine als integration regster */
739 als_count = (chip->tsl2x7x_settings.als_time * 100 + 135) / 270;
740 if (als_count == 0)
741 als_count = 1; /* ensure at least one cycle */
742
743 /* convert back to time (encompasses overrides) */
744 als_time = (als_count * 27 + 5) / 10;
745 chip->tsl2x7x_config[TSL2X7X_ALS_TIME] = 256 - als_count;
746
747 /* Set the gain based on tsl2x7x_settings struct */
748 chip->tsl2x7x_config[TSL2X7X_GAIN] =
749 (chip->tsl2x7x_settings.als_gain |
750 (TSL2X7X_mA100 | TSL2X7X_DIODE1)
751 | ((chip->tsl2x7x_settings.prox_gain) << 2));
752
753 /* set chip struct re scaling and saturation */
754 chip->als_saturation = als_count * 922; /* 90% of full scale */
755 chip->als_time_scale = (als_time + 25) / 50;
756
757 /* TSL2X7X Specific power-on / adc enable sequence
758 * Power on the device 1st. */
759 utmp = TSL2X7X_CNTL_PWR_ON;
760 ret = i2c_smbus_write_byte_data(chip->client,
761 TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
762 if (ret < 0) {
763 dev_err(&chip->client->dev,
764 "%s: failed on CNTRL reg.\n", __func__);
765 return ret;
766 }
767
768 /* Use the following shadow copy for our delay before enabling ADC.
769 * Write all the registers. */
770 for (i = 0, dev_reg = chip->tsl2x7x_config;
771 i < TSL2X7X_MAX_CONFIG_REG; i++) {
772 ret = i2c_smbus_write_byte_data(chip->client,
773 TSL2X7X_CMD_REG + i, *dev_reg++);
774 if (ret < 0) {
775 dev_err(&chip->client->dev,
776 "%s: failed on write to reg %d.\n", __func__, i);
777 return ret;
778 }
779 }
780
781 udelay(3000); /* Power-on settling time */
782
783 /* NOW enable the ADC
784 * initialize the desired mode of operation */
785 utmp = TSL2X7X_CNTL_PWR_ON |
786 TSL2X7X_CNTL_ADC_ENBL |
787 TSL2X7X_CNTL_PROX_DET_ENBL;
788 ret = i2c_smbus_write_byte_data(chip->client,
789 TSL2X7X_CMD_REG | TSL2X7X_CNTRL, utmp);
790 if (ret < 0) {
791 dev_err(&chip->client->dev,
792 "%s: failed on 2nd CTRL reg.\n", __func__);
793 return ret;
794 }
795
796 chip->tsl2x7x_chip_status = TSL2X7X_CHIP_WORKING;
797
798 if (chip->tsl2x7x_settings.interrupts_en != 0) {
799 dev_info(&chip->client->dev, "Setting Up Interrupt(s)\n");
800
801 reg_val = TSL2X7X_CNTL_PWR_ON | TSL2X7X_CNTL_ADC_ENBL;
802 if ((chip->tsl2x7x_settings.interrupts_en == 0x20) ||
803 (chip->tsl2x7x_settings.interrupts_en == 0x30))
804 reg_val |= TSL2X7X_CNTL_PROX_DET_ENBL;
805
806 reg_val |= chip->tsl2x7x_settings.interrupts_en;
807 ret = i2c_smbus_write_byte_data(chip->client,
808 (TSL2X7X_CMD_REG | TSL2X7X_CNTRL), reg_val);
809 if (ret < 0)
810 dev_err(&chip->client->dev,
811 "%s: failed in tsl2x7x_IOCTL_INT_SET.\n",
812 __func__);
813
814 /* Clear out any initial interrupts */
815 ret = i2c_smbus_write_byte(chip->client,
816 TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
817 TSL2X7X_CMD_PROXALS_INT_CLR);
818 if (ret < 0) {
819 dev_err(&chip->client->dev,
820 "%s: Failed to clear Int status\n",
821 __func__);
822 return ret;
823 }
824 }
825
826 return ret;
827}
828
829static int tsl2x7x_chip_off(struct iio_dev *indio_dev)
830{
831 int ret;
832 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
833
834 /* turn device off */
835 chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
836
837 ret = i2c_smbus_write_byte_data(chip->client,
838 TSL2X7X_CMD_REG | TSL2X7X_CNTRL, 0x00);
839
840 if (chip->pdata && chip->pdata->power_off)
841 chip->pdata->power_off(chip->client);
842
843 return ret;
844}
845
846/**
847 * tsl2x7x_invoke_change
848 * @indio_dev: pointer to IIO device
849 *
850 * Obtain and lock both ALS and PROX resources,
851 * determine and save device state (On/Off),
852 * cycle device to implement updated parameter,
853 * put device back into proper state, and unlock
854 * resource.
855 */
856int tsl2x7x_invoke_change(struct iio_dev *indio_dev)
857{
858 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
859 int device_status = chip->tsl2x7x_chip_status;
860
861 mutex_lock(&chip->als_mutex);
862 mutex_lock(&chip->prox_mutex);
863
864 if (device_status == TSL2X7X_CHIP_WORKING)
865 tsl2x7x_chip_off(indio_dev);
866
867 tsl2x7x_chip_on(indio_dev);
868
869 if (device_status != TSL2X7X_CHIP_WORKING)
870 tsl2x7x_chip_off(indio_dev);
871
872 mutex_unlock(&chip->prox_mutex);
873 mutex_unlock(&chip->als_mutex);
874
875 return 0;
876}
877
878static
879void tsl2x7x_prox_calculate(int *data, int length,
880 struct tsl2x7x_prox_stat *statP)
881{
882 int i;
883 int sample_sum;
884 int tmp;
885
886 if (length == 0)
887 length = 1;
888
889 sample_sum = 0;
890 statP->min = INT_MAX;
891 statP->max = INT_MIN;
892 for (i = 0; i < length; i++) {
893 sample_sum += data[i];
894 statP->min = min(statP->min, data[i]);
895 statP->max = max(statP->max, data[i]);
896 }
897
898 statP->mean = sample_sum / length;
899 sample_sum = 0;
900 for (i = 0; i < length; i++) {
901 tmp = data[i] - statP->mean;
902 sample_sum += tmp * tmp;
903 }
904 statP->stddev = int_sqrt((long)sample_sum)/length;
905}
906
907/**
908 * tsl2x7x_prox_cal() - Calculates std. and sets thresholds.
909 * @indio_dev: pointer to IIO device
910 *
911 * Calculates a standard deviation based on the samples,
912 * and sets the threshold accordingly.
913 */
914static void tsl2x7x_prox_cal(struct iio_dev *indio_dev)
915{
916 int prox_history[MAX_SAMPLES_CAL + 1];
917 int i;
918 struct tsl2x7x_prox_stat prox_stat_data[2];
919 struct tsl2x7x_prox_stat *calP;
920 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
921 u8 tmp_irq_settings;
922 u8 current_state = chip->tsl2x7x_chip_status;
923
924 if (chip->tsl2x7x_settings.prox_max_samples_cal > MAX_SAMPLES_CAL) {
925 dev_err(&chip->client->dev,
926 "%s: max prox samples cal is too big: %d\n",
927 __func__, chip->tsl2x7x_settings.prox_max_samples_cal);
928 chip->tsl2x7x_settings.prox_max_samples_cal = MAX_SAMPLES_CAL;
929 }
930
931 /* have to stop to change settings */
932 tsl2x7x_chip_off(indio_dev);
933
934 /* Enable proximity detection save just in case prox not wanted yet*/
935 tmp_irq_settings = chip->tsl2x7x_settings.interrupts_en;
936 chip->tsl2x7x_settings.interrupts_en |= TSL2X7X_CNTL_PROX_INT_ENBL;
937
938 /*turn on device if not already on*/
939 tsl2x7x_chip_on(indio_dev);
940
941 /*gather the samples*/
942 for (i = 0; i < chip->tsl2x7x_settings.prox_max_samples_cal; i++) {
943 mdelay(15);
944 tsl2x7x_get_prox(indio_dev);
945 prox_history[i] = chip->prox_data;
946 dev_info(&chip->client->dev, "2 i=%d prox data= %d\n",
947 i, chip->prox_data);
948 }
949
950 tsl2x7x_chip_off(indio_dev);
951 calP = &prox_stat_data[PROX_STAT_CAL];
952 tsl2x7x_prox_calculate(prox_history,
953 chip->tsl2x7x_settings.prox_max_samples_cal, calP);
954 chip->tsl2x7x_settings.prox_thres_high = (calP->max << 1) - calP->mean;
955
956 dev_info(&chip->client->dev, " cal min=%d mean=%d max=%d\n",
957 calP->min, calP->mean, calP->max);
958 dev_info(&chip->client->dev,
959 "%s proximity threshold set to %d\n",
960 chip->client->name, chip->tsl2x7x_settings.prox_thres_high);
961
962 /* back to the way they were */
963 chip->tsl2x7x_settings.interrupts_en = tmp_irq_settings;
964 if (current_state == TSL2X7X_CHIP_WORKING)
965 tsl2x7x_chip_on(indio_dev);
966}
967
968static ssize_t tsl2x7x_power_state_show(struct device *dev,
969 struct device_attribute *attr, char *buf)
970{
971 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
972
973 return snprintf(buf, PAGE_SIZE, "%d\n", chip->tsl2x7x_chip_status);
974}
975
976static ssize_t tsl2x7x_power_state_store(struct device *dev,
977 struct device_attribute *attr, const char *buf, size_t len)
978{
979 struct iio_dev *indio_dev = dev_get_drvdata(dev);
980 bool value;
981
982 if (strtobool(buf, &value))
983 return -EINVAL;
984
985 if (value)
986 tsl2x7x_chip_on(indio_dev);
987 else
988 tsl2x7x_chip_off(indio_dev);
989
990 return len;
991}
992
993static ssize_t tsl2x7x_gain_available_show(struct device *dev,
994 struct device_attribute *attr, char *buf)
995{
996 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
997
998 switch (chip->id) {
999 case tsl2571:
1000 case tsl2671:
1001 case tmd2671:
1002 case tsl2771:
1003 case tmd2771:
1004 return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 128");
1005 break;
1006 }
1007
1008 return snprintf(buf, PAGE_SIZE, "%s\n", "1 8 16 120");
1009}
1010
1011static ssize_t tsl2x7x_prox_gain_available_show(struct device *dev,
1012 struct device_attribute *attr, char *buf)
1013{
1014 return snprintf(buf, PAGE_SIZE, "%s\n", "1 2 4 8");
1015}
1016
1017static ssize_t tsl2x7x_als_time_show(struct device *dev,
1018 struct device_attribute *attr, char *buf)
1019{
1020 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1021 int y, z;
1022
1023 y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
1024 z = y * 2.72;
1025 y /= 1000;
1026 z %= 1000;
1027
1028 return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
1029}
1030
1031static ssize_t tsl2x7x_als_time_store(struct device *dev,
1032 struct device_attribute *attr, const char *buf, size_t len)
1033{
1034 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1035 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1036 struct tsl2x7x_parse_result result;
1037
1038 result.integer = 0;
1039 result.fract = 0;
1040
1041 tsl2x7x_parse_buffer(buf, &result);
1042
1043 result.fract /= 1000;
1044 result.fract /= 3;
1045 chip->tsl2x7x_settings.als_time =
1046 (TSL2X7X_MAX_TIMER_CNT - (u8)result.fract);
1047
1048 dev_info(&chip->client->dev, "%s: als time = %d",
1049 __func__, chip->tsl2x7x_settings.als_time);
1050
1051 tsl2x7x_invoke_change(indio_dev);
1052
1053 return IIO_VAL_INT_PLUS_MICRO;
1054}
1055
1056static IIO_CONST_ATTR(in_illuminance0_integration_time_available,
1057 ".00272 - .696");
1058
1059static ssize_t tsl2x7x_als_cal_target_show(struct device *dev,
1060 struct device_attribute *attr, char *buf)
1061{
1062 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1063
1064 return snprintf(buf, PAGE_SIZE, "%d\n",
1065 chip->tsl2x7x_settings.als_cal_target);
1066}
1067
1068static ssize_t tsl2x7x_als_cal_target_store(struct device *dev,
1069 struct device_attribute *attr, const char *buf, size_t len)
1070{
1071 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1072 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1073 unsigned long value;
1074
1075 if (kstrtoul(buf, 0, &value))
1076 return -EINVAL;
1077
1078 if (value)
1079 chip->tsl2x7x_settings.als_cal_target = value;
1080
1081 tsl2x7x_invoke_change(indio_dev);
1082
1083 return len;
1084}
1085
1086/* persistence settings */
1087static ssize_t tsl2x7x_als_persistence_show(struct device *dev,
1088 struct device_attribute *attr, char *buf)
1089{
1090 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1091 int y, z, filter_delay;
1092
1093 /* Determine integration time */
1094 y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
1095 z = y * 2.72;
1096 filter_delay = z * (chip->tsl2x7x_settings.persistence & 0x0F);
1097 y = (filter_delay / 1000);
1098 z = (filter_delay % 1000);
1099
1100 return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
1101}
1102
1103static ssize_t tsl2x7x_als_persistence_store(struct device *dev,
1104 struct device_attribute *attr, const char *buf, size_t len)
1105{
1106 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1107 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1108 struct tsl2x7x_parse_result result;
1109 int y, z, filter_delay;
1110
1111 result.integer = 0;
1112 result.fract = 0;
1113 tsl2x7x_parse_buffer(buf, &result);
1114
1115 result.fract /= 1000;
1116 y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.als_time) + 1;
1117 z = y * 2.72;
1118
1119 filter_delay =
1120 DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
1121
1122 chip->tsl2x7x_settings.persistence &= 0xF0;
1123 chip->tsl2x7x_settings.persistence |= (filter_delay & 0x0F);
1124
1125 dev_info(&chip->client->dev, "%s: als persistence = %d",
1126 __func__, filter_delay);
1127
1128 tsl2x7x_invoke_change(indio_dev);
1129
1130 return IIO_VAL_INT_PLUS_MICRO;
1131}
1132
1133static ssize_t tsl2x7x_prox_persistence_show(struct device *dev,
1134 struct device_attribute *attr, char *buf)
1135{
1136 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1137 int y, z, filter_delay;
1138
1139 /* Determine integration time */
1140 y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
1141 z = y * 2.72;
1142 filter_delay = z * ((chip->tsl2x7x_settings.persistence & 0xF0) >> 4);
1143 y = (filter_delay / 1000);
1144 z = (filter_delay % 1000);
1145
1146 return snprintf(buf, PAGE_SIZE, "%d.%03d\n", y, z);
1147}
1148
1149static ssize_t tsl2x7x_prox_persistence_store(struct device *dev,
1150 struct device_attribute *attr, const char *buf, size_t len)
1151{
1152 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1153 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1154 struct tsl2x7x_parse_result result;
1155 int y, z, filter_delay;
1156
1157 result.integer = 0;
1158 result.fract = 0;
1159 tsl2x7x_parse_buffer(buf, &result);
1160
1161 result.fract /= 1000;
1162 y = (TSL2X7X_MAX_TIMER_CNT - (u8)chip->tsl2x7x_settings.prx_time) + 1;
1163 z = y * 2.72;
1164
1165 filter_delay =
1166 DIV_ROUND_UP(((result.integer * 1000) + result.fract), z);
1167
1168 chip->tsl2x7x_settings.persistence &= 0x0F;
1169 chip->tsl2x7x_settings.persistence |= ((filter_delay << 4) & 0xF0);
1170
1171 dev_info(&chip->client->dev, "%s: prox persistence = %d",
1172 __func__, filter_delay);
1173
1174 tsl2x7x_invoke_change(indio_dev);
1175
1176 return IIO_VAL_INT_PLUS_MICRO;
1177}
1178
1179static ssize_t tsl2x7x_do_calibrate(struct device *dev,
1180 struct device_attribute *attr, const char *buf, size_t len)
1181{
1182 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1183 bool value;
1184
1185 if (strtobool(buf, &value))
1186 return -EINVAL;
1187
1188 if (value)
1189 tsl2x7x_als_calibrate(indio_dev);
1190
1191 tsl2x7x_invoke_change(indio_dev);
1192
1193 return len;
1194}
1195
1196static ssize_t tsl2x7x_luxtable_show(struct device *dev,
1197 struct device_attribute *attr, char *buf)
1198{
1199 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1200 int i = 0;
1201 int offset = 0;
1202
1203 while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
1204 offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,",
1205 chip->tsl2x7x_device_lux[i].ratio,
1206 chip->tsl2x7x_device_lux[i].ch0,
1207 chip->tsl2x7x_device_lux[i].ch1);
1208 if (chip->tsl2x7x_device_lux[i].ratio == 0) {
1209 /* We just printed the first "0" entry.
1210 * Now get rid of the extra "," and break. */
1211 offset--;
1212 break;
1213 }
1214 i++;
1215 }
1216
1217 offset += snprintf(buf + offset, PAGE_SIZE, "\n");
1218 return offset;
1219}
1220
1221static ssize_t tsl2x7x_luxtable_store(struct device *dev,
1222 struct device_attribute *attr, const char *buf, size_t len)
1223{
1224 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1225 struct tsl2X7X_chip *chip = iio_priv(dev_get_drvdata(dev));
1226 int value[ARRAY_SIZE(chip->tsl2x7x_device_lux)*3 + 1];
1227 int n;
1228
1229 get_options(buf, ARRAY_SIZE(value), value);
1230
1231 /* We now have an array of ints starting at value[1], and
1232 * enumerated by value[0].
1233 * We expect each group of three ints is one table entry,
1234 * and the last table entry is all 0.
1235 */
1236 n = value[0];
1237 if ((n % 3) || n < 6 ||
1238 n > ((ARRAY_SIZE(chip->tsl2x7x_device_lux) - 1) * 3)) {
1239 dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
1240 return -EINVAL;
1241 }
1242
1243 if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
1244 dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
1245 return -EINVAL;
1246 }
1247
1248 if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING)
1249 tsl2x7x_chip_off(indio_dev);
1250
1251 /* Zero out the table */
1252 memset(chip->tsl2x7x_device_lux, 0, sizeof(chip->tsl2x7x_device_lux));
1253 memcpy(chip->tsl2x7x_device_lux, &value[1], (value[0] * 4));
1254
1255 tsl2x7x_invoke_change(indio_dev);
1256
1257 return len;
1258}
1259
1260static ssize_t tsl2x7x_do_prox_calibrate(struct device *dev,
1261 struct device_attribute *attr, const char *buf, size_t len)
1262{
1263 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1264 bool value;
1265
1266 if (strtobool(buf, &value))
1267 return -EINVAL;
1268
1269 if (value)
1270 tsl2x7x_prox_cal(indio_dev);
1271
1272 tsl2x7x_invoke_change(indio_dev);
1273
1274 return len;
1275}
1276
1277static int tsl2x7x_read_interrupt_config(struct iio_dev *indio_dev,
1278 u64 event_code)
1279{
1280 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1281 int ret;
1282
1283 if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY)
1284 ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x10);
1285 else
1286 ret = !!(chip->tsl2x7x_settings.interrupts_en & 0x20);
1287
1288 return ret;
1289}
1290
1291static int tsl2x7x_write_interrupt_config(struct iio_dev *indio_dev,
1292 u64 event_code,
1293 int val)
1294{
1295 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1296
1297 if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
1298 if (val)
1299 chip->tsl2x7x_settings.interrupts_en |= 0x10;
1300 else
1301 chip->tsl2x7x_settings.interrupts_en &= 0x20;
1302 } else {
1303 if (val)
1304 chip->tsl2x7x_settings.interrupts_en |= 0x20;
1305 else
1306 chip->tsl2x7x_settings.interrupts_en &= 0x10;
1307 }
1308
1309 tsl2x7x_invoke_change(indio_dev);
1310
1311 return 0;
1312}
1313
1314static int tsl2x7x_write_thresh(struct iio_dev *indio_dev,
1315 u64 event_code,
1316 int val)
1317{
1318 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1319
1320 if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
1321 switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
1322 case IIO_EV_DIR_RISING:
1323 chip->tsl2x7x_settings.als_thresh_high = val;
1324 break;
1325 case IIO_EV_DIR_FALLING:
1326 chip->tsl2x7x_settings.als_thresh_low = val;
1327 break;
1328 default:
1329 return -EINVAL;
1330 }
1331 } else {
1332 switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
1333 case IIO_EV_DIR_RISING:
1334 chip->tsl2x7x_settings.prox_thres_high = val;
1335 break;
1336 case IIO_EV_DIR_FALLING:
1337 chip->tsl2x7x_settings.prox_thres_low = val;
1338 break;
1339 default:
1340 return -EINVAL;
1341 }
1342 }
1343
1344 tsl2x7x_invoke_change(indio_dev);
1345
1346 return 0;
1347}
1348
1349static int tsl2x7x_read_thresh(struct iio_dev *indio_dev,
1350 u64 event_code,
1351 int *val)
1352{
1353 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1354
1355 if (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code) == IIO_INTENSITY) {
1356 switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
1357 case IIO_EV_DIR_RISING:
1358 *val = chip->tsl2x7x_settings.als_thresh_high;
1359 break;
1360 case IIO_EV_DIR_FALLING:
1361 *val = chip->tsl2x7x_settings.als_thresh_low;
1362 break;
1363 default:
1364 return -EINVAL;
1365 }
1366 } else {
1367 switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
1368 case IIO_EV_DIR_RISING:
1369 *val = chip->tsl2x7x_settings.prox_thres_high;
1370 break;
1371 case IIO_EV_DIR_FALLING:
1372 *val = chip->tsl2x7x_settings.prox_thres_low;
1373 break;
1374 default:
1375 return -EINVAL;
1376 }
1377 }
1378
1379 return 0;
1380}
1381
1382static int tsl2x7x_read_raw(struct iio_dev *indio_dev,
1383 struct iio_chan_spec const *chan,
1384 int *val,
1385 int *val2,
1386 long mask)
1387{
1388 int ret = -EINVAL;
1389 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1390
1391 switch (mask) {
1392 case IIO_CHAN_INFO_RAW:
1393 switch (chan->type) {
1394 case IIO_LIGHT:
1395 tsl2x7x_get_lux(indio_dev);
1396 *val = chip->als_cur_info.lux;
1397 ret = IIO_VAL_INT;
1398 break;
1399 case IIO_INTENSITY:
1400 tsl2x7x_get_lux(indio_dev);
1401 if (chan->channel == 0)
1402 *val = chip->als_cur_info.als_ch0;
1403 else
1404 *val = chip->als_cur_info.als_ch1;
1405 ret = IIO_VAL_INT;
1406 break;
1407 case IIO_PROXIMITY:
1408 tsl2x7x_get_prox(indio_dev);
1409 *val = chip->prox_data;
1410 ret = IIO_VAL_INT;
1411 break;
1412 default:
1413 return -EINVAL;
1414 break;
1415 }
1416 break;
1417 case IIO_CHAN_INFO_CALIBSCALE:
1418 if (chan->type == IIO_LIGHT)
1419 *val =
1420 tsl2X7X_als_gainadj[chip->tsl2x7x_settings.als_gain];
1421 else
1422 *val =
1423 tsl2X7X_prx_gainadj[chip->tsl2x7x_settings.prox_gain];
1424 ret = IIO_VAL_INT;
1425 break;
1426 case IIO_CHAN_INFO_CALIBBIAS:
1427 *val = chip->tsl2x7x_settings.als_gain_trim;
1428 ret = IIO_VAL_INT;
1429 break;
1430
1431 default:
1432 ret = -EINVAL;
1433 }
1434
1435 return ret;
1436}
1437
1438static int tsl2x7x_write_raw(struct iio_dev *indio_dev,
1439 struct iio_chan_spec const *chan,
1440 int val,
1441 int val2,
1442 long mask)
1443{
1444 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1445
1446 switch (mask) {
1447 case IIO_CHAN_INFO_CALIBSCALE:
1448 if (chan->type == IIO_INTENSITY) {
1449 switch (val) {
1450 case 1:
1451 chip->tsl2x7x_settings.als_gain = 0;
1452 break;
1453 case 8:
1454 chip->tsl2x7x_settings.als_gain = 1;
1455 break;
1456 case 16:
1457 chip->tsl2x7x_settings.als_gain = 2;
1458 break;
1459 case 120:
1460 switch (chip->id) {
1461 case tsl2572:
1462 case tsl2672:
1463 case tmd2672:
1464 case tsl2772:
1465 case tmd2772:
1466 return -EINVAL;
1467 break;
1468 }
1469 chip->tsl2x7x_settings.als_gain = 3;
1470 break;
1471 case 128:
1472 switch (chip->id) {
1473 case tsl2571:
1474 case tsl2671:
1475 case tmd2671:
1476 case tsl2771:
1477 case tmd2771:
1478 return -EINVAL;
1479 break;
1480 }
1481 chip->tsl2x7x_settings.als_gain = 3;
1482 break;
1483 default:
1484 return -EINVAL;
1485 }
1486 } else {
1487 switch (val) {
1488 case 1:
1489 chip->tsl2x7x_settings.prox_gain = 0;
1490 break;
1491 case 2:
1492 chip->tsl2x7x_settings.prox_gain = 1;
1493 break;
1494 case 4:
1495 chip->tsl2x7x_settings.prox_gain = 2;
1496 break;
1497 case 8:
1498 chip->tsl2x7x_settings.prox_gain = 3;
1499 break;
1500 default:
1501 return -EINVAL;
1502 }
1503 }
1504 break;
1505 case IIO_CHAN_INFO_CALIBBIAS:
1506 chip->tsl2x7x_settings.als_gain_trim = val;
1507 break;
1508
1509 default:
1510 return -EINVAL;
1511 }
1512
1513 tsl2x7x_invoke_change(indio_dev);
1514
1515 return 0;
1516}
1517
1518static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
1519 tsl2x7x_power_state_show, tsl2x7x_power_state_store);
1520
1521static DEVICE_ATTR(in_proximity0_calibscale_available, S_IRUGO,
1522 tsl2x7x_prox_gain_available_show, NULL);
1523
1524static DEVICE_ATTR(in_illuminance0_calibscale_available, S_IRUGO,
1525 tsl2x7x_gain_available_show, NULL);
1526
1527static DEVICE_ATTR(in_illuminance0_integration_time, S_IRUGO | S_IWUSR,
1528 tsl2x7x_als_time_show, tsl2x7x_als_time_store);
1529
1530static DEVICE_ATTR(in_illuminance0_target_input, S_IRUGO | S_IWUSR,
1531 tsl2x7x_als_cal_target_show, tsl2x7x_als_cal_target_store);
1532
1533static DEVICE_ATTR(in_illuminance0_calibrate, S_IWUSR, NULL,
1534 tsl2x7x_do_calibrate);
1535
1536static DEVICE_ATTR(in_proximity0_calibrate, S_IWUSR, NULL,
1537 tsl2x7x_do_prox_calibrate);
1538
1539static DEVICE_ATTR(in_illuminance0_lux_table, S_IRUGO | S_IWUSR,
1540 tsl2x7x_luxtable_show, tsl2x7x_luxtable_store);
1541
1542static DEVICE_ATTR(in_intensity0_thresh_period, S_IRUGO | S_IWUSR,
1543 tsl2x7x_als_persistence_show, tsl2x7x_als_persistence_store);
1544
1545static DEVICE_ATTR(in_proximity0_thresh_period, S_IRUGO | S_IWUSR,
1546 tsl2x7x_prox_persistence_show, tsl2x7x_prox_persistence_store);
1547
1548/* Use the default register values to identify the Taos device */
1549static int tsl2x7x_device_id(unsigned char *id, int target)
1550{
1551 switch (target) {
1552 case tsl2571:
1553 case tsl2671:
1554 case tsl2771:
1555 return ((*id & 0xf0) == TRITON_ID);
1556 break;
1557 case tmd2671:
1558 case tmd2771:
1559 return ((*id & 0xf0) == HALIBUT_ID);
1560 break;
1561 case tsl2572:
1562 case tsl2672:
1563 case tmd2672:
1564 case tsl2772:
1565 case tmd2772:
1566 return ((*id & 0xf0) == SWORDFISH_ID);
1567 break;
1568 }
1569
1570 return -EINVAL;
1571}
1572
1573static irqreturn_t tsl2x7x_event_handler(int irq, void *private)
1574{
1575 struct iio_dev *indio_dev = private;
1576 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1577 s64 timestamp = iio_get_time_ns();
1578 int ret;
1579 u8 value;
1580
1581 value = i2c_smbus_read_byte_data(chip->client,
1582 TSL2X7X_CMD_REG | TSL2X7X_STATUS);
1583
1584 /* What type of interrupt do we need to process */
1585 if (value & TSL2X7X_STA_PRX_INTR) {
1586 tsl2x7x_get_prox(indio_dev); /* freshen data for ABI */
1587 iio_push_event(indio_dev,
1588 IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
1589 0,
1590 IIO_EV_TYPE_THRESH,
1591 IIO_EV_DIR_EITHER),
1592 timestamp);
1593 }
1594
1595 if (value & TSL2X7X_STA_ALS_INTR) {
1596 tsl2x7x_get_lux(indio_dev); /* freshen data for ABI */
1597 iio_push_event(indio_dev,
1598 IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
1599 0,
1600 IIO_EV_TYPE_THRESH,
1601 IIO_EV_DIR_EITHER),
1602 timestamp);
1603 }
1604 /* Clear interrupt now that we have handled it. */
1605 ret = i2c_smbus_write_byte(chip->client,
1606 TSL2X7X_CMD_REG | TSL2X7X_CMD_SPL_FN |
1607 TSL2X7X_CMD_PROXALS_INT_CLR);
1608 if (ret < 0)
1609 dev_err(&chip->client->dev,
1610 "%s: Failed to clear irq from event handler. err = %d\n",
1611 __func__, ret);
1612
1613 return IRQ_HANDLED;
1614}
1615
1616static struct attribute *tsl2x7x_ALS_device_attrs[] = {
1617 &dev_attr_power_state.attr,
1618 &dev_attr_in_illuminance0_calibscale_available.attr,
1619 &dev_attr_in_illuminance0_integration_time.attr,
1620 &iio_const_attr_in_illuminance0_integration_time_available\
1621 .dev_attr.attr,
1622 &dev_attr_in_illuminance0_target_input.attr,
1623 &dev_attr_in_illuminance0_calibrate.attr,
1624 &dev_attr_in_illuminance0_lux_table.attr,
1625 NULL
1626};
1627
1628static struct attribute *tsl2x7x_PRX_device_attrs[] = {
1629 &dev_attr_power_state.attr,
1630 &dev_attr_in_proximity0_calibrate.attr,
1631 NULL
1632};
1633
1634static struct attribute *tsl2x7x_ALSPRX_device_attrs[] = {
1635 &dev_attr_power_state.attr,
1636 &dev_attr_in_illuminance0_calibscale_available.attr,
1637 &dev_attr_in_illuminance0_integration_time.attr,
1638 &iio_const_attr_in_illuminance0_integration_time_available\
1639 .dev_attr.attr,
1640 &dev_attr_in_illuminance0_target_input.attr,
1641 &dev_attr_in_illuminance0_calibrate.attr,
1642 &dev_attr_in_illuminance0_lux_table.attr,
1643 &dev_attr_in_proximity0_calibrate.attr,
1644 NULL
1645};
1646
1647static struct attribute *tsl2x7x_PRX2_device_attrs[] = {
1648 &dev_attr_power_state.attr,
1649 &dev_attr_in_proximity0_calibrate.attr,
1650 &dev_attr_in_proximity0_calibscale_available.attr,
1651 NULL
1652};
1653
1654static struct attribute *tsl2x7x_ALSPRX2_device_attrs[] = {
1655 &dev_attr_power_state.attr,
1656 &dev_attr_in_illuminance0_calibscale_available.attr,
1657 &dev_attr_in_illuminance0_integration_time.attr,
1658 &iio_const_attr_in_illuminance0_integration_time_available\
1659 .dev_attr.attr,
1660 &dev_attr_in_illuminance0_target_input.attr,
1661 &dev_attr_in_illuminance0_calibrate.attr,
1662 &dev_attr_in_illuminance0_lux_table.attr,
1663 &dev_attr_in_proximity0_calibrate.attr,
1664 &dev_attr_in_proximity0_calibscale_available.attr,
1665 NULL
1666};
1667
1668static struct attribute *tsl2X7X_ALS_event_attrs[] = {
1669 &dev_attr_in_intensity0_thresh_period.attr,
1670 NULL,
1671};
1672static struct attribute *tsl2X7X_PRX_event_attrs[] = {
1673 &dev_attr_in_proximity0_thresh_period.attr,
1674 NULL,
1675};
1676
1677static struct attribute *tsl2X7X_ALSPRX_event_attrs[] = {
1678 &dev_attr_in_intensity0_thresh_period.attr,
1679 &dev_attr_in_proximity0_thresh_period.attr,
1680 NULL,
1681};
1682
1683static const struct attribute_group tsl2X7X_device_attr_group_tbl[] = {
1684 [ALS] = {
1685 .attrs = tsl2x7x_ALS_device_attrs,
1686 },
1687 [PRX] = {
1688 .attrs = tsl2x7x_PRX_device_attrs,
1689 },
1690 [ALSPRX] = {
1691 .attrs = tsl2x7x_ALSPRX_device_attrs,
1692 },
1693 [PRX2] = {
1694 .attrs = tsl2x7x_PRX2_device_attrs,
1695 },
1696 [ALSPRX2] = {
1697 .attrs = tsl2x7x_ALSPRX2_device_attrs,
1698 },
1699};
1700
1701static struct attribute_group tsl2X7X_event_attr_group_tbl[] = {
1702 [ALS] = {
1703 .attrs = tsl2X7X_ALS_event_attrs,
1704 .name = "events",
1705 },
1706 [PRX] = {
1707 .attrs = tsl2X7X_PRX_event_attrs,
1708 .name = "events",
1709 },
1710 [ALSPRX] = {
1711 .attrs = tsl2X7X_ALSPRX_event_attrs,
1712 .name = "events",
1713 },
1714};
1715
1716static const struct iio_info tsl2X7X_device_info[] = {
1717 [ALS] = {
1718 .attrs = &tsl2X7X_device_attr_group_tbl[ALS],
1719 .event_attrs = &tsl2X7X_event_attr_group_tbl[ALS],
1720 .driver_module = THIS_MODULE,
1721 .read_raw = &tsl2x7x_read_raw,
1722 .write_raw = &tsl2x7x_write_raw,
1723 .read_event_value = &tsl2x7x_read_thresh,
1724 .write_event_value = &tsl2x7x_write_thresh,
1725 .read_event_config = &tsl2x7x_read_interrupt_config,
1726 .write_event_config = &tsl2x7x_write_interrupt_config,
1727 },
1728 [PRX] = {
1729 .attrs = &tsl2X7X_device_attr_group_tbl[PRX],
1730 .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
1731 .driver_module = THIS_MODULE,
1732 .read_raw = &tsl2x7x_read_raw,
1733 .write_raw = &tsl2x7x_write_raw,
1734 .read_event_value = &tsl2x7x_read_thresh,
1735 .write_event_value = &tsl2x7x_write_thresh,
1736 .read_event_config = &tsl2x7x_read_interrupt_config,
1737 .write_event_config = &tsl2x7x_write_interrupt_config,
1738 },
1739 [ALSPRX] = {
1740 .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX],
1741 .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
1742 .driver_module = THIS_MODULE,
1743 .read_raw = &tsl2x7x_read_raw,
1744 .write_raw = &tsl2x7x_write_raw,
1745 .read_event_value = &tsl2x7x_read_thresh,
1746 .write_event_value = &tsl2x7x_write_thresh,
1747 .read_event_config = &tsl2x7x_read_interrupt_config,
1748 .write_event_config = &tsl2x7x_write_interrupt_config,
1749 },
1750 [PRX2] = {
1751 .attrs = &tsl2X7X_device_attr_group_tbl[PRX2],
1752 .event_attrs = &tsl2X7X_event_attr_group_tbl[PRX],
1753 .driver_module = THIS_MODULE,
1754 .read_raw = &tsl2x7x_read_raw,
1755 .write_raw = &tsl2x7x_write_raw,
1756 .read_event_value = &tsl2x7x_read_thresh,
1757 .write_event_value = &tsl2x7x_write_thresh,
1758 .read_event_config = &tsl2x7x_read_interrupt_config,
1759 .write_event_config = &tsl2x7x_write_interrupt_config,
1760 },
1761 [ALSPRX2] = {
1762 .attrs = &tsl2X7X_device_attr_group_tbl[ALSPRX2],
1763 .event_attrs = &tsl2X7X_event_attr_group_tbl[ALSPRX],
1764 .driver_module = THIS_MODULE,
1765 .read_raw = &tsl2x7x_read_raw,
1766 .write_raw = &tsl2x7x_write_raw,
1767 .read_event_value = &tsl2x7x_read_thresh,
1768 .write_event_value = &tsl2x7x_write_thresh,
1769 .read_event_config = &tsl2x7x_read_interrupt_config,
1770 .write_event_config = &tsl2x7x_write_interrupt_config,
1771 },
1772};
1773
1774static const struct tsl2x7x_chip_info tsl2x7x_chip_info_tbl[] = {
1775 [ALS] = {
1776 .channel = {
1777 {
1778 .type = IIO_LIGHT,
1779 .indexed = 1,
1780 .channel = 0,
1781 .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
1782 }, {
1783 .type = IIO_INTENSITY,
1784 .indexed = 1,
1785 .channel = 0,
1786 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
1787 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
1788 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
1789 .event_mask = TSL2X7X_EVENT_MASK
1790 }, {
1791 .type = IIO_INTENSITY,
1792 .indexed = 1,
1793 .channel = 1,
1794 },
1795 },
1796 .chan_table_elements = 3,
1797 .info = &tsl2X7X_device_info[ALS],
1798 },
1799 [PRX] = {
1800 .channel = {
1801 {
1802 .type = IIO_PROXIMITY,
1803 .indexed = 1,
1804 .channel = 0,
1805 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
1806 .event_mask = TSL2X7X_EVENT_MASK
1807 },
1808 },
1809 .chan_table_elements = 1,
1810 .info = &tsl2X7X_device_info[PRX],
1811 },
1812 [ALSPRX] = {
1813 .channel = {
1814 {
1815 .type = IIO_LIGHT,
1816 .indexed = 1,
1817 .channel = 0,
1818 .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT
1819 }, {
1820 .type = IIO_INTENSITY,
1821 .indexed = 1,
1822 .channel = 0,
1823 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
1824 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
1825 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
1826 .event_mask = TSL2X7X_EVENT_MASK
1827 }, {
1828 .type = IIO_INTENSITY,
1829 .indexed = 1,
1830 .channel = 1,
1831 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
1832 }, {
1833 .type = IIO_PROXIMITY,
1834 .indexed = 1,
1835 .channel = 0,
1836 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
1837 .event_mask = TSL2X7X_EVENT_MASK
1838 },
1839 },
1840 .chan_table_elements = 4,
1841 .info = &tsl2X7X_device_info[ALSPRX],
1842 },
1843 [PRX2] = {
1844 .channel = {
1845 {
1846 .type = IIO_PROXIMITY,
1847 .indexed = 1,
1848 .channel = 0,
1849 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
1850 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
1851 .event_mask = TSL2X7X_EVENT_MASK
1852 },
1853 },
1854 .chan_table_elements = 1,
1855 .info = &tsl2X7X_device_info[PRX2],
1856 },
1857 [ALSPRX2] = {
1858 .channel = {
1859 {
1860 .type = IIO_LIGHT,
1861 .indexed = 1,
1862 .channel = 0,
1863 .info_mask = IIO_CHAN_INFO_PROCESSED_SEPARATE_BIT,
1864 }, {
1865 .type = IIO_INTENSITY,
1866 .indexed = 1,
1867 .channel = 0,
1868 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
1869 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT |
1870 IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT,
1871 .event_mask = TSL2X7X_EVENT_MASK
1872 }, {
1873 .type = IIO_INTENSITY,
1874 .indexed = 1,
1875 .channel = 1,
1876 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT,
1877 }, {
1878 .type = IIO_PROXIMITY,
1879 .indexed = 1,
1880 .channel = 0,
1881 .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT |
1882 IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT,
1883 .event_mask = TSL2X7X_EVENT_MASK
1884 },
1885 },
1886 .chan_table_elements = 4,
1887 .info = &tsl2X7X_device_info[ALSPRX2],
1888 },
1889};
1890
1891static int __devinit tsl2x7x_probe(struct i2c_client *clientp,
1892 const struct i2c_device_id *id)
1893{
1894 int ret;
1895 unsigned char device_id;
1896 struct iio_dev *indio_dev;
1897 struct tsl2X7X_chip *chip;
1898
1899 indio_dev = iio_allocate_device(sizeof(*chip));
1900 if (!indio_dev)
1901 return -ENOMEM;
1902
1903 chip = iio_priv(indio_dev);
1904 chip->client = clientp;
1905 i2c_set_clientdata(clientp, indio_dev);
1906
1907 ret = tsl2x7x_i2c_read(chip->client,
1908 TSL2X7X_CHIPID, &device_id);
1909 if (ret < 0)
1910 goto fail1;
1911
1912 if ((!tsl2x7x_device_id(&device_id, id->driver_data)) ||
1913 (tsl2x7x_device_id(&device_id, id->driver_data) == -EINVAL)) {
1914 dev_info(&chip->client->dev,
1915 "%s: i2c device found does not match expected id\n",
1916 __func__);
1917 goto fail1;
1918 }
1919
1920 ret = i2c_smbus_write_byte(clientp, (TSL2X7X_CMD_REG | TSL2X7X_CNTRL));
1921 if (ret < 0) {
1922 dev_err(&clientp->dev, "%s: write to cmd reg failed. err = %d\n",
1923 __func__, ret);
1924 goto fail1;
1925 }
1926
1927 /* ALS and PROX functions can be invoked via user space poll
1928 * or H/W interrupt. If busy return last sample. */
1929 mutex_init(&chip->als_mutex);
1930 mutex_init(&chip->prox_mutex);
1931
1932 chip->tsl2x7x_chip_status = TSL2X7X_CHIP_UNKNOWN;
1933 chip->pdata = clientp->dev.platform_data;
1934 chip->id = id->driver_data;
1935 chip->chip_info =
1936 &tsl2x7x_chip_info_tbl[device_channel_config[id->driver_data]];
1937
1938 indio_dev->info = chip->chip_info->info;
1939 indio_dev->dev.parent = &clientp->dev;
1940 indio_dev->modes = INDIO_DIRECT_MODE;
1941 indio_dev->name = chip->client->name;
1942 indio_dev->channels = chip->chip_info->channel;
1943 indio_dev->num_channels = chip->chip_info->chan_table_elements;
1944
1945 if (clientp->irq) {
1946 ret = request_threaded_irq(clientp->irq,
1947 NULL,
1948 &tsl2x7x_event_handler,
1949 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
1950 "TSL2X7X_event",
1951 indio_dev);
1952 if (ret) {
1953 dev_err(&clientp->dev,
1954 "%s: irq request failed", __func__);
1955 goto fail2;
1956 }
1957 }
1958
1959 /* Load up the defaults */
1960 tsl2x7x_defaults(chip);
1961 /* Make sure the chip is on */
1962 tsl2x7x_chip_on(indio_dev);
1963
1964 ret = iio_device_register(indio_dev);
1965 if (ret) {
1966 dev_err(&clientp->dev,
1967 "%s: iio registration failed\n", __func__);
1968 goto fail1;
1969 }
1970
1971 dev_info(&clientp->dev, "%s Light sensor found.\n", id->name);
1972
1973 return 0;
1974
1975fail1:
1976 if (clientp->irq)
1977 free_irq(clientp->irq, indio_dev);
1978fail2:
1979 iio_free_device(indio_dev);
1980
1981 return ret;
1982}
1983
1984static int tsl2x7x_suspend(struct device *dev)
1985{
1986 struct iio_dev *indio_dev = dev_get_drvdata(dev);
1987 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
1988 int ret = 0;
1989
1990 if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_WORKING) {
1991 ret = tsl2x7x_chip_off(indio_dev);
1992 chip->tsl2x7x_chip_status = TSL2X7X_CHIP_SUSPENDED;
1993 }
1994
1995 if (chip->pdata && chip->pdata->platform_power) {
1996 pm_message_t pmm = {PM_EVENT_SUSPEND};
1997 chip->pdata->platform_power(dev, pmm);
1998 }
1999
2000 return ret;
2001}
2002
2003static int tsl2x7x_resume(struct device *dev)
2004{
2005 struct iio_dev *indio_dev = dev_get_drvdata(dev);
2006 struct tsl2X7X_chip *chip = iio_priv(indio_dev);
2007 int ret = 0;
2008
2009 if (chip->pdata && chip->pdata->platform_power) {
2010 pm_message_t pmm = {PM_EVENT_RESUME};
2011 chip->pdata->platform_power(dev, pmm);
2012 }
2013
2014 if (chip->tsl2x7x_chip_status == TSL2X7X_CHIP_SUSPENDED)
2015 ret = tsl2x7x_chip_on(indio_dev);
2016
2017 return ret;
2018}
2019
2020static int __devexit tsl2x7x_remove(struct i2c_client *client)
2021{
2022 struct tsl2X7X_chip *chip = i2c_get_clientdata(client);
2023 struct iio_dev *indio_dev = iio_priv_to_dev(chip);
2024
2025 tsl2x7x_chip_off(indio_dev);
2026
2027 iio_device_unregister(indio_dev);
2028 if (client->irq)
2029 free_irq(client->irq, chip->client->name);
2030
2031 iio_free_device(indio_dev);
2032
2033 return 0;
2034}
2035
2036static struct i2c_device_id tsl2x7x_idtable[] = {
2037 { "tsl2571", tsl2571 },
2038 { "tsl2671", tsl2671 },
2039 { "tmd2671", tmd2671 },
2040 { "tsl2771", tsl2771 },
2041 { "tmd2771", tmd2771 },
2042 { "tsl2572", tsl2572 },
2043 { "tsl2672", tsl2672 },
2044 { "tmd2672", tmd2672 },
2045 { "tsl2772", tsl2772 },
2046 { "tmd2772", tmd2772 },
2047 {}
2048};
2049
2050MODULE_DEVICE_TABLE(i2c, tsl2x7x_idtable);
2051
2052static const struct dev_pm_ops tsl2x7x_pm_ops = {
2053 .suspend = tsl2x7x_suspend,
2054 .resume = tsl2x7x_resume,
2055};
2056
2057/* Driver definition */
2058static struct i2c_driver tsl2x7x_driver = {
2059 .driver = {
2060 .name = "tsl2x7x",
2061 .pm = &tsl2x7x_pm_ops,
2062 },
2063 .id_table = tsl2x7x_idtable,
2064 .probe = tsl2x7x_probe,
2065 .remove = __devexit_p(tsl2x7x_remove),
2066};
2067
2068module_i2c_driver(tsl2x7x_driver);
2069
2070MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
2071MODULE_DESCRIPTION("TAOS tsl2x7x ambient and proximity light sensor driver");
2072MODULE_LICENSE("GPL");