aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Meerwald <pmeerw@pmeerw.net>2013-09-08 11:20:00 -0400
committerJonathan Cameron <jic23@kernel.org>2013-09-14 16:17:15 -0400
commitaab9ba7eb2633927d0010f00c3bc7960efcd3c23 (patch)
tree5024db22f7b847cbf5f7454b29bf112c76fee07a
parentcaeac374224a8fc180795499fbef04ee7e1ba597 (diff)
iio: Add tsl4531 ambient light sensor driver
driver for the TSL4531 family of 16-bit I2C ambient light sensors; information is here: http://www.ams.com/eng/Products/Light-Sensors/Ambient-Light-Sensor-ALS/TSL45315 the chip offers simple lux output v3 (thanks Lars-Peter Clausen): * add mutex to when updating integration time * fix chip ID checking * code cleanups v2: * rename to tsl4351 * use INT_TIME Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/light/Kconfig10
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/tsl4531.c258
3 files changed, 269 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index bf9fa0d7aff9..488fff7cd80d 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -65,6 +65,16 @@ config SENSORS_TSL2563
65 This driver can also be built as a module. If so, the module 65 This driver can also be built as a module. If so, the module
66 will be called tsl2563. 66 will be called tsl2563.
67 67
68config TSL4531
69 tristate "TAOS TSL4531 ambient light sensors"
70 depends on I2C
71 help
72 Say Y here if you want to build a driver for the TAOS TSL4531 family
73 of ambient light sensors with direct lux output.
74
75 To compile this driver as a module, choose M here: the
76 module will be called tsl4531.
77
68config VCNL4000 78config VCNL4000
69 tristate "VCNL4000 combined ALS and proximity sensor" 79 tristate "VCNL4000 combined ALS and proximity sensor"
70 depends on I2C 80 depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 354ee9ab2379..cd6f3cfe6259 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -8,4 +8,5 @@ obj-$(CONFIG_APDS9300) += apds9300.o
8obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o 8obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
9obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o 9obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
10obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o 10obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
11obj-$(CONFIG_TSL4531) += tsl4531.o
11obj-$(CONFIG_VCNL4000) += vcnl4000.o 12obj-$(CONFIG_VCNL4000) += vcnl4000.o
diff --git a/drivers/iio/light/tsl4531.c b/drivers/iio/light/tsl4531.c
new file mode 100644
index 000000000000..a15006efa137
--- /dev/null
+++ b/drivers/iio/light/tsl4531.c
@@ -0,0 +1,258 @@
1/*
2 * tsl4531.c - Support for TAOS TSL4531 ambient light sensor
3 *
4 * Copyright 2013 Peter Meerwald <pmeerw@pmeerw.net>
5 *
6 * This file is subject to the terms and conditions of version 2 of
7 * the GNU General Public License. See the file COPYING in the main
8 * directory of this archive for more details.
9 *
10 * IIO driver for the TSL4531x family
11 * TSL45311/TSL45313: 7-bit I2C slave address 0x39
12 * TSL45315/TSL45317: 7-bit I2C slave address 0x29
13 *
14 * TODO: single cycle measurement
15 */
16
17#include <linux/module.h>
18#include <linux/i2c.h>
19#include <linux/err.h>
20#include <linux/delay.h>
21
22#include <linux/iio/iio.h>
23#include <linux/iio/sysfs.h>
24
25#define TSL4531_DRV_NAME "tsl4531"
26
27#define TCS3472_COMMAND BIT(7)
28
29#define TSL4531_CONTROL (TCS3472_COMMAND | 0x00)
30#define TSL4531_CONFIG (TCS3472_COMMAND | 0x01)
31#define TSL4531_DATA (TCS3472_COMMAND | 0x04)
32#define TSL4531_ID (TCS3472_COMMAND | 0x0a)
33
34/* operating modes in control register */
35#define TSL4531_MODE_POWERDOWN 0x00
36#define TSL4531_MODE_SINGLE_ADC 0x02
37#define TSL4531_MODE_NORMAL 0x03
38
39/* integration time control in config register */
40#define TSL4531_TCNTRL_400MS 0x00
41#define TSL4531_TCNTRL_200MS 0x01
42#define TSL4531_TCNTRL_100MS 0x02
43
44/* part number in id register */
45#define TSL45311_ID 0x8
46#define TSL45313_ID 0x9
47#define TSL45315_ID 0xa
48#define TSL45317_ID 0xb
49#define TSL4531_ID_SHIFT 4
50
51struct tsl4531_data {
52 struct i2c_client *client;
53 struct mutex lock;
54 int int_time;
55};
56
57static IIO_CONST_ATTR_INT_TIME_AVAIL("0.1 0.2 0.4");
58
59static struct attribute *tsl4531_attributes[] = {
60 &iio_const_attr_integration_time_available.dev_attr.attr,
61 NULL
62};
63
64static const struct attribute_group tsl4531_attribute_group = {
65 .attrs = tsl4531_attributes,
66};
67
68static const struct iio_chan_spec tsl4531_channels[] = {
69 {
70 .type = IIO_LIGHT,
71 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
72 BIT(IIO_CHAN_INFO_SCALE) |
73 BIT(IIO_CHAN_INFO_INT_TIME)
74 }
75};
76
77static int tsl4531_read_raw(struct iio_dev *indio_dev,
78 struct iio_chan_spec const *chan,
79 int *val, int *val2, long mask)
80{
81 struct tsl4531_data *data = iio_priv(indio_dev);
82 int ret;
83
84 switch (mask) {
85 case IIO_CHAN_INFO_RAW:
86 ret = i2c_smbus_read_word_data(data->client,
87 TSL4531_DATA);
88 if (ret < 0)
89 return ret;
90 *val = ret;
91 return IIO_VAL_INT;
92 case IIO_CHAN_INFO_SCALE:
93 /* 0.. 1x, 1 .. 2x, 2 .. 4x */
94 *val = 1 << data->int_time;
95 return IIO_VAL_INT;
96 case IIO_CHAN_INFO_INT_TIME:
97 if (data->int_time == 0)
98 *val2 = 400000;
99 else if (data->int_time == 1)
100 *val2 = 200000;
101 else if (data->int_time == 2)
102 *val2 = 100000;
103 else
104 return -EINVAL;
105 *val = 0;
106 return IIO_VAL_INT_PLUS_MICRO;
107 default:
108 return -EINVAL;
109 }
110}
111
112static int tsl4531_write_raw(struct iio_dev *indio_dev,
113 struct iio_chan_spec const *chan,
114 int val, int val2, long mask)
115{
116 struct tsl4531_data *data = iio_priv(indio_dev);
117 int int_time, ret;
118
119 switch (mask) {
120 case IIO_CHAN_INFO_INT_TIME:
121 if (val != 0)
122 return -EINVAL;
123 if (val2 == 400000)
124 int_time = 0;
125 else if (val2 == 200000)
126 int_time = 1;
127 else if (val2 == 100000)
128 int_time = 2;
129 else
130 return -EINVAL;
131 mutex_lock(&data->lock);
132 ret = i2c_smbus_write_byte_data(data->client,
133 TSL4531_CONFIG, int_time);
134 if (ret >= 0)
135 data->int_time = int_time;
136 mutex_unlock(&data->lock);
137 return ret;
138 default:
139 return -EINVAL;
140 }
141}
142
143static const struct iio_info tsl4531_info = {
144 .read_raw = tsl4531_read_raw,
145 .write_raw = tsl4531_write_raw,
146 .attrs = &tsl4531_attribute_group,
147 .driver_module = THIS_MODULE,
148};
149
150static int tsl4531_check_id(struct i2c_client *client)
151{
152 int ret = i2c_smbus_read_byte_data(client, TSL4531_ID);
153 if (ret < 0)
154 return ret;
155
156 switch (ret >> TSL4531_ID_SHIFT) {
157 case TSL45311_ID:
158 case TSL45313_ID:
159 case TSL45315_ID:
160 case TSL45317_ID:
161 return 1;
162 default:
163 return 0;
164 }
165}
166
167static int tsl4531_probe(struct i2c_client *client,
168 const struct i2c_device_id *id)
169{
170 struct tsl4531_data *data;
171 struct iio_dev *indio_dev;
172 int ret;
173
174 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
175 if (!indio_dev)
176 return -ENOMEM;
177
178 data = iio_priv(indio_dev);
179 i2c_set_clientdata(client, indio_dev);
180 data->client = client;
181 mutex_init(&data->lock);
182
183 if (!tsl4531_check_id(client)) {
184 dev_err(&client->dev, "no TSL4531 sensor\n");
185 return -ENODEV;
186 }
187
188 ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONTROL,
189 TSL4531_MODE_NORMAL);
190 if (ret < 0)
191 return ret;
192
193 ret = i2c_smbus_write_byte_data(data->client, TSL4531_CONFIG,
194 TSL4531_TCNTRL_400MS);
195 if (ret < 0)
196 return ret;
197
198 indio_dev->dev.parent = &client->dev;
199 indio_dev->info = &tsl4531_info;
200 indio_dev->channels = tsl4531_channels;
201 indio_dev->num_channels = ARRAY_SIZE(tsl4531_channels);
202 indio_dev->name = TSL4531_DRV_NAME;
203 indio_dev->modes = INDIO_DIRECT_MODE;
204
205 return iio_device_register(indio_dev);
206}
207
208static int tsl4531_powerdown(struct i2c_client *client)
209{
210 return i2c_smbus_write_byte_data(client, TSL4531_CONTROL,
211 TSL4531_MODE_POWERDOWN);
212}
213
214static int tsl4531_remove(struct i2c_client *client)
215{
216 iio_device_unregister(i2c_get_clientdata(client));
217 tsl4531_powerdown(client);
218
219 return 0;
220}
221
222#ifdef CONFIG_PM_SLEEP
223static int tsl4531_suspend(struct device *dev)
224{
225 return tsl4531_powerdown(to_i2c_client(dev));
226}
227
228static int tsl4531_resume(struct device *dev)
229{
230 return i2c_smbus_write_byte_data(to_i2c_client(dev), TSL4531_CONTROL,
231 TSL4531_MODE_NORMAL);
232}
233#endif
234
235static SIMPLE_DEV_PM_OPS(tsl4531_pm_ops, tsl4531_suspend, tsl4531_resume);
236
237static const struct i2c_device_id tsl4531_id[] = {
238 { "tsl4531", 0 },
239 { }
240};
241MODULE_DEVICE_TABLE(i2c, tsl4531_id);
242
243static struct i2c_driver tsl4531_driver = {
244 .driver = {
245 .name = TSL4531_DRV_NAME,
246 .pm = &tsl4531_pm_ops,
247 .owner = THIS_MODULE,
248 },
249 .probe = tsl4531_probe,
250 .remove = tsl4531_remove,
251 .id_table = tsl4531_id,
252};
253
254module_i2c_driver(tsl4531_driver);
255
256MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
257MODULE_DESCRIPTION("TAOS TSL4531 ambient light sensors driver");
258MODULE_LICENSE("GPL");