diff options
author | Peter Meerwald <pmeerw@pmeerw.net> | 2014-10-01 17:01:00 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2014-01-12 13:15:40 -0500 |
commit | 2690be9051236898fb3f5da6d86c1202ec3f1aed (patch) | |
tree | d6fcbcab4c659433c18c67c51ade250ee2f2d8f9 /drivers/iio/light | |
parent | 1a5b7d41f8f6ec087372bef348c46f5844a472b6 (diff) |
iio: Add Lite-On ltr501 ambient light / proximity sensor driver
combined ambient light (two channels) and proximity sensor with I2C
interface; the ALS channels are visible+IR and IR
datasheet is here
http://optoelectronics.liteon.com/upload/download/DS86-2012-0006/P_100_LTR-501ALS-01_PrelimDS_ver1.1.pdf
v3:
* fix use of sizeof in _read_als()
v2: (thanks to Lars-Peter Clausen)
* cannot use devm_iio_device_register() due to cleanup order in _remove()
* mutex around data wait/read
* turn info message in _probe() into check for part number
* change copyright year to 2014
Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net>
Reviewed-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/light')
-rw-r--r-- | drivers/iio/light/Kconfig | 12 | ||||
-rw-r--r-- | drivers/iio/light/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/light/ltr501.c | 445 |
3 files changed, 458 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index d12b2a0dbfbc..3a7a5d9f03a3 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig | |||
@@ -90,6 +90,18 @@ config SENSORS_LM3533 | |||
90 | changes. The ALS-control output values can be set per zone for the | 90 | changes. The ALS-control output values can be set per zone for the |
91 | three current output channels. | 91 | three current output channels. |
92 | 92 | ||
93 | config LTR501 | ||
94 | tristate "LTR-501ALS-01 light sensor" | ||
95 | depends on I2C | ||
96 | select IIO_BUFFER | ||
97 | select IIO_TRIGGERED_BUFFER | ||
98 | help | ||
99 | If you say yes here you get support for the Lite-On LTR-501ALS-01 | ||
100 | ambient light and proximity sensor. | ||
101 | |||
102 | This driver can also be built as a module. If so, the module | ||
103 | will be called ltr501. | ||
104 | |||
93 | config TCS3472 | 105 | config TCS3472 |
94 | tristate "TAOS TCS3472 color light-to-digital converter" | 106 | tristate "TAOS TCS3472 color light-to-digital converter" |
95 | depends on I2C | 107 | depends on I2C |
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 60e35ac07ff0..924530597f83 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile | |||
@@ -10,6 +10,7 @@ obj-$(CONFIG_CM36651) += cm36651.o | |||
10 | obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o | 10 | obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o |
11 | obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o | 11 | obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o |
12 | obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o | 12 | obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o |
13 | obj-$(CONFIG_LTR501) += ltr501.o | ||
13 | obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o | 14 | obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o |
14 | obj-$(CONFIG_TCS3472) += tcs3472.o | 15 | obj-$(CONFIG_TCS3472) += tcs3472.o |
15 | obj-$(CONFIG_TSL4531) += tsl4531.o | 16 | obj-$(CONFIG_TSL4531) += tsl4531.o |
diff --git a/drivers/iio/light/ltr501.c b/drivers/iio/light/ltr501.c new file mode 100644 index 000000000000..62b7072af4de --- /dev/null +++ b/drivers/iio/light/ltr501.c | |||
@@ -0,0 +1,445 @@ | |||
1 | /* | ||
2 | * ltr501.c - Support for Lite-On LTR501 ambient light and proximity sensor | ||
3 | * | ||
4 | * Copyright 2014 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 | * 7-bit I2C slave address 0x23 | ||
11 | * | ||
12 | * TODO: interrupt, threshold, measurement rate, IR LED characteristics | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/i2c.h> | ||
17 | #include <linux/err.h> | ||
18 | #include <linux/delay.h> | ||
19 | |||
20 | #include <linux/iio/iio.h> | ||
21 | #include <linux/iio/sysfs.h> | ||
22 | #include <linux/iio/trigger_consumer.h> | ||
23 | #include <linux/iio/buffer.h> | ||
24 | #include <linux/iio/triggered_buffer.h> | ||
25 | |||
26 | #define LTR501_DRV_NAME "ltr501" | ||
27 | |||
28 | #define LTR501_ALS_CONTR 0x80 /* ALS operation mode, SW reset */ | ||
29 | #define LTR501_PS_CONTR 0x81 /* PS operation mode */ | ||
30 | #define LTR501_PART_ID 0x86 | ||
31 | #define LTR501_MANUFAC_ID 0x87 | ||
32 | #define LTR501_ALS_DATA1 0x88 /* 16-bit, little endian */ | ||
33 | #define LTR501_ALS_DATA0 0x8a /* 16-bit, little endian */ | ||
34 | #define LTR501_ALS_PS_STATUS 0x8c | ||
35 | #define LTR501_PS_DATA 0x8d /* 16-bit, little endian */ | ||
36 | |||
37 | #define LTR501_ALS_CONTR_SW_RESET BIT(2) | ||
38 | #define LTR501_CONTR_PS_GAIN_MASK (BIT(3) | BIT(2)) | ||
39 | #define LTR501_CONTR_PS_GAIN_SHIFT 2 | ||
40 | #define LTR501_CONTR_ALS_GAIN_MASK BIT(3) | ||
41 | #define LTR501_CONTR_ACTIVE BIT(1) | ||
42 | |||
43 | #define LTR501_STATUS_ALS_RDY BIT(2) | ||
44 | #define LTR501_STATUS_PS_RDY BIT(0) | ||
45 | |||
46 | #define LTR501_PS_DATA_MASK 0x7ff | ||
47 | |||
48 | struct ltr501_data { | ||
49 | struct i2c_client *client; | ||
50 | struct mutex lock_als, lock_ps; | ||
51 | u8 als_contr, ps_contr; | ||
52 | }; | ||
53 | |||
54 | static int ltr501_drdy(struct ltr501_data *data, u8 drdy_mask) | ||
55 | { | ||
56 | int tries = 100; | ||
57 | int ret; | ||
58 | |||
59 | while (tries--) { | ||
60 | ret = i2c_smbus_read_byte_data(data->client, | ||
61 | LTR501_ALS_PS_STATUS); | ||
62 | if (ret < 0) | ||
63 | return ret; | ||
64 | if ((ret & drdy_mask) == drdy_mask) | ||
65 | return 0; | ||
66 | msleep(25); | ||
67 | } | ||
68 | |||
69 | dev_err(&data->client->dev, "ltr501_drdy() failed, data not ready\n"); | ||
70 | return -EIO; | ||
71 | } | ||
72 | |||
73 | static int ltr501_read_als(struct ltr501_data *data, __le16 buf[2]) | ||
74 | { | ||
75 | int ret = ltr501_drdy(data, LTR501_STATUS_ALS_RDY); | ||
76 | if (ret < 0) | ||
77 | return ret; | ||
78 | /* always read both ALS channels in given order */ | ||
79 | return i2c_smbus_read_i2c_block_data(data->client, | ||
80 | LTR501_ALS_DATA1, 2 * sizeof(__le16), (u8 *) buf); | ||
81 | } | ||
82 | |||
83 | static int ltr501_read_ps(struct ltr501_data *data) | ||
84 | { | ||
85 | int ret = ltr501_drdy(data, LTR501_STATUS_PS_RDY); | ||
86 | if (ret < 0) | ||
87 | return ret; | ||
88 | return i2c_smbus_read_word_data(data->client, LTR501_PS_DATA); | ||
89 | } | ||
90 | |||
91 | #define LTR501_INTENSITY_CHANNEL(_idx, _addr, _mod, _shared) { \ | ||
92 | .type = IIO_INTENSITY, \ | ||
93 | .modified = 1, \ | ||
94 | .address = (_addr), \ | ||
95 | .channel2 = (_mod), \ | ||
96 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
97 | .info_mask_shared_by_type = (_shared), \ | ||
98 | .scan_index = (_idx), \ | ||
99 | .scan_type = { \ | ||
100 | .sign = 'u', \ | ||
101 | .realbits = 16, \ | ||
102 | .storagebits = 16, \ | ||
103 | .endianness = IIO_CPU, \ | ||
104 | } \ | ||
105 | } | ||
106 | |||
107 | static const struct iio_chan_spec ltr501_channels[] = { | ||
108 | LTR501_INTENSITY_CHANNEL(0, LTR501_ALS_DATA0, IIO_MOD_LIGHT_BOTH, 0), | ||
109 | LTR501_INTENSITY_CHANNEL(1, LTR501_ALS_DATA1, IIO_MOD_LIGHT_IR, | ||
110 | BIT(IIO_CHAN_INFO_SCALE)), | ||
111 | { | ||
112 | .type = IIO_PROXIMITY, | ||
113 | .address = LTR501_PS_DATA, | ||
114 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | ||
115 | BIT(IIO_CHAN_INFO_SCALE), | ||
116 | .scan_index = 2, | ||
117 | .scan_type = { | ||
118 | .sign = 'u', | ||
119 | .realbits = 11, | ||
120 | .storagebits = 16, | ||
121 | .endianness = IIO_CPU, | ||
122 | }, | ||
123 | }, | ||
124 | IIO_CHAN_SOFT_TIMESTAMP(3), | ||
125 | }; | ||
126 | |||
127 | static const int ltr501_ps_gain[4][2] = { | ||
128 | {1, 0}, {0, 250000}, {0, 125000}, {0, 62500} | ||
129 | }; | ||
130 | |||
131 | static int ltr501_read_raw(struct iio_dev *indio_dev, | ||
132 | struct iio_chan_spec const *chan, | ||
133 | int *val, int *val2, long mask) | ||
134 | { | ||
135 | struct ltr501_data *data = iio_priv(indio_dev); | ||
136 | __le16 buf[2]; | ||
137 | int ret, i; | ||
138 | |||
139 | switch (mask) { | ||
140 | case IIO_CHAN_INFO_RAW: | ||
141 | if (iio_buffer_enabled(indio_dev)) | ||
142 | return -EBUSY; | ||
143 | |||
144 | switch (chan->type) { | ||
145 | case IIO_INTENSITY: | ||
146 | mutex_lock(&data->lock_als); | ||
147 | ret = ltr501_read_als(data, buf); | ||
148 | mutex_unlock(&data->lock_als); | ||
149 | if (ret < 0) | ||
150 | return ret; | ||
151 | *val = le16_to_cpu(chan->address == LTR501_ALS_DATA1 ? | ||
152 | buf[0] : buf[1]); | ||
153 | return IIO_VAL_INT; | ||
154 | case IIO_PROXIMITY: | ||
155 | mutex_lock(&data->lock_ps); | ||
156 | ret = ltr501_read_ps(data); | ||
157 | mutex_unlock(&data->lock_ps); | ||
158 | if (ret < 0) | ||
159 | return ret; | ||
160 | *val = ret & LTR501_PS_DATA_MASK; | ||
161 | return IIO_VAL_INT; | ||
162 | default: | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | case IIO_CHAN_INFO_SCALE: | ||
166 | switch (chan->type) { | ||
167 | case IIO_INTENSITY: | ||
168 | if (data->als_contr & LTR501_CONTR_ALS_GAIN_MASK) { | ||
169 | *val = 0; | ||
170 | *val2 = 5000; | ||
171 | return IIO_VAL_INT_PLUS_MICRO; | ||
172 | } else { | ||
173 | *val = 1; | ||
174 | *val2 = 0; | ||
175 | return IIO_VAL_INT; | ||
176 | } | ||
177 | case IIO_PROXIMITY: | ||
178 | i = (data->ps_contr & LTR501_CONTR_PS_GAIN_MASK) >> | ||
179 | LTR501_CONTR_PS_GAIN_SHIFT; | ||
180 | *val = ltr501_ps_gain[i][0]; | ||
181 | *val2 = ltr501_ps_gain[i][1]; | ||
182 | return IIO_VAL_INT_PLUS_MICRO; | ||
183 | default: | ||
184 | return -EINVAL; | ||
185 | } | ||
186 | } | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | |||
190 | static int ltr501_get_ps_gain_index(int val, int val2) | ||
191 | { | ||
192 | int i; | ||
193 | |||
194 | for (i = 0; i < ARRAY_SIZE(ltr501_ps_gain); i++) | ||
195 | if (val == ltr501_ps_gain[i][0] && val2 == ltr501_ps_gain[i][1]) | ||
196 | return i; | ||
197 | |||
198 | return -1; | ||
199 | } | ||
200 | |||
201 | static int ltr501_write_raw(struct iio_dev *indio_dev, | ||
202 | struct iio_chan_spec const *chan, | ||
203 | int val, int val2, long mask) | ||
204 | { | ||
205 | struct ltr501_data *data = iio_priv(indio_dev); | ||
206 | int i; | ||
207 | |||
208 | if (iio_buffer_enabled(indio_dev)) | ||
209 | return -EBUSY; | ||
210 | |||
211 | switch (mask) { | ||
212 | case IIO_CHAN_INFO_SCALE: | ||
213 | switch (chan->type) { | ||
214 | case IIO_INTENSITY: | ||
215 | if (val == 0 && val2 == 5000) | ||
216 | data->als_contr |= LTR501_CONTR_ALS_GAIN_MASK; | ||
217 | else if (val == 1 && val2 == 0) | ||
218 | data->als_contr &= ~LTR501_CONTR_ALS_GAIN_MASK; | ||
219 | else | ||
220 | return -EINVAL; | ||
221 | return i2c_smbus_write_byte_data(data->client, | ||
222 | LTR501_ALS_CONTR, data->als_contr); | ||
223 | case IIO_PROXIMITY: | ||
224 | i = ltr501_get_ps_gain_index(val, val2); | ||
225 | if (i < 0) | ||
226 | return -EINVAL; | ||
227 | data->ps_contr &= ~LTR501_CONTR_PS_GAIN_MASK; | ||
228 | data->ps_contr |= i << LTR501_CONTR_PS_GAIN_SHIFT; | ||
229 | return i2c_smbus_write_byte_data(data->client, | ||
230 | LTR501_PS_CONTR, data->ps_contr); | ||
231 | default: | ||
232 | return -EINVAL; | ||
233 | } | ||
234 | } | ||
235 | return -EINVAL; | ||
236 | } | ||
237 | |||
238 | static IIO_CONST_ATTR(in_proximity_scale_available, "1 0.25 0.125 0.0625"); | ||
239 | static IIO_CONST_ATTR(in_intensity_scale_available, "1 0.005"); | ||
240 | |||
241 | static struct attribute *ltr501_attributes[] = { | ||
242 | &iio_const_attr_in_proximity_scale_available.dev_attr.attr, | ||
243 | &iio_const_attr_in_intensity_scale_available.dev_attr.attr, | ||
244 | NULL | ||
245 | }; | ||
246 | |||
247 | static const struct attribute_group ltr501_attribute_group = { | ||
248 | .attrs = ltr501_attributes, | ||
249 | }; | ||
250 | |||
251 | static const struct iio_info ltr501_info = { | ||
252 | .read_raw = ltr501_read_raw, | ||
253 | .write_raw = ltr501_write_raw, | ||
254 | .attrs = <r501_attribute_group, | ||
255 | .driver_module = THIS_MODULE, | ||
256 | }; | ||
257 | |||
258 | static int ltr501_write_contr(struct i2c_client *client, u8 als_val, u8 ps_val) | ||
259 | { | ||
260 | int ret = i2c_smbus_write_byte_data(client, LTR501_ALS_CONTR, als_val); | ||
261 | if (ret < 0) | ||
262 | return ret; | ||
263 | |||
264 | return i2c_smbus_write_byte_data(client, LTR501_PS_CONTR, ps_val); | ||
265 | } | ||
266 | |||
267 | static irqreturn_t ltr501_trigger_handler(int irq, void *p) | ||
268 | { | ||
269 | struct iio_poll_func *pf = p; | ||
270 | struct iio_dev *indio_dev = pf->indio_dev; | ||
271 | struct ltr501_data *data = iio_priv(indio_dev); | ||
272 | u16 buf[8]; | ||
273 | __le16 als_buf[2]; | ||
274 | u8 mask = 0; | ||
275 | int j = 0; | ||
276 | int ret; | ||
277 | |||
278 | memset(buf, 0, sizeof(buf)); | ||
279 | |||
280 | /* figure out which data needs to be ready */ | ||
281 | if (test_bit(0, indio_dev->active_scan_mask) || | ||
282 | test_bit(1, indio_dev->active_scan_mask)) | ||
283 | mask |= LTR501_STATUS_ALS_RDY; | ||
284 | if (test_bit(2, indio_dev->active_scan_mask)) | ||
285 | mask |= LTR501_STATUS_PS_RDY; | ||
286 | |||
287 | ret = ltr501_drdy(data, mask); | ||
288 | if (ret < 0) | ||
289 | goto done; | ||
290 | |||
291 | if (mask & LTR501_STATUS_ALS_RDY) { | ||
292 | ret = i2c_smbus_read_i2c_block_data(data->client, | ||
293 | LTR501_ALS_DATA1, sizeof(als_buf), (u8 *) als_buf); | ||
294 | if (ret < 0) | ||
295 | return ret; | ||
296 | if (test_bit(0, indio_dev->active_scan_mask)) | ||
297 | buf[j++] = le16_to_cpu(als_buf[1]); | ||
298 | if (test_bit(1, indio_dev->active_scan_mask)) | ||
299 | buf[j++] = le16_to_cpu(als_buf[0]); | ||
300 | } | ||
301 | |||
302 | if (mask & LTR501_STATUS_PS_RDY) { | ||
303 | ret = i2c_smbus_read_word_data(data->client, LTR501_PS_DATA); | ||
304 | if (ret < 0) | ||
305 | goto done; | ||
306 | buf[j++] = ret & LTR501_PS_DATA_MASK; | ||
307 | } | ||
308 | |||
309 | iio_push_to_buffers_with_timestamp(indio_dev, buf, | ||
310 | iio_get_time_ns()); | ||
311 | |||
312 | done: | ||
313 | iio_trigger_notify_done(indio_dev->trig); | ||
314 | |||
315 | return IRQ_HANDLED; | ||
316 | } | ||
317 | |||
318 | static int ltr501_init(struct ltr501_data *data) | ||
319 | { | ||
320 | int ret; | ||
321 | |||
322 | ret = i2c_smbus_read_byte_data(data->client, LTR501_ALS_CONTR); | ||
323 | if (ret < 0) | ||
324 | return ret; | ||
325 | data->als_contr = ret | LTR501_CONTR_ACTIVE; | ||
326 | |||
327 | ret = i2c_smbus_read_byte_data(data->client, LTR501_PS_CONTR); | ||
328 | if (ret < 0) | ||
329 | return ret; | ||
330 | data->ps_contr = ret | LTR501_CONTR_ACTIVE; | ||
331 | |||
332 | return ltr501_write_contr(data->client, data->als_contr, | ||
333 | data->ps_contr); | ||
334 | } | ||
335 | |||
336 | static int ltr501_probe(struct i2c_client *client, | ||
337 | const struct i2c_device_id *id) | ||
338 | { | ||
339 | struct ltr501_data *data; | ||
340 | struct iio_dev *indio_dev; | ||
341 | int ret; | ||
342 | |||
343 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | ||
344 | if (!indio_dev) | ||
345 | return -ENOMEM; | ||
346 | |||
347 | data = iio_priv(indio_dev); | ||
348 | i2c_set_clientdata(client, indio_dev); | ||
349 | data->client = client; | ||
350 | mutex_init(&data->lock_als); | ||
351 | mutex_init(&data->lock_ps); | ||
352 | |||
353 | ret = i2c_smbus_read_byte_data(data->client, LTR501_PART_ID); | ||
354 | if (ret < 0) | ||
355 | return ret; | ||
356 | if ((ret >> 4) != 0x8) | ||
357 | return -ENODEV; | ||
358 | |||
359 | indio_dev->dev.parent = &client->dev; | ||
360 | indio_dev->info = <r501_info; | ||
361 | indio_dev->channels = ltr501_channels; | ||
362 | indio_dev->num_channels = ARRAY_SIZE(ltr501_channels); | ||
363 | indio_dev->name = LTR501_DRV_NAME; | ||
364 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
365 | |||
366 | ret = ltr501_init(data); | ||
367 | if (ret < 0) | ||
368 | return ret; | ||
369 | |||
370 | ret = iio_triggered_buffer_setup(indio_dev, NULL, | ||
371 | ltr501_trigger_handler, NULL); | ||
372 | if (ret) | ||
373 | return ret; | ||
374 | |||
375 | ret = iio_device_register(indio_dev); | ||
376 | if (ret) | ||
377 | goto error_unreg_buffer; | ||
378 | |||
379 | return 0; | ||
380 | |||
381 | error_unreg_buffer: | ||
382 | iio_triggered_buffer_cleanup(indio_dev); | ||
383 | return ret; | ||
384 | } | ||
385 | |||
386 | static int ltr501_powerdown(struct ltr501_data *data) | ||
387 | { | ||
388 | return ltr501_write_contr(data->client, | ||
389 | data->als_contr & ~LTR501_CONTR_ACTIVE, | ||
390 | data->ps_contr & ~LTR501_CONTR_ACTIVE); | ||
391 | } | ||
392 | |||
393 | static int ltr501_remove(struct i2c_client *client) | ||
394 | { | ||
395 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
396 | |||
397 | iio_device_unregister(indio_dev); | ||
398 | iio_triggered_buffer_cleanup(indio_dev); | ||
399 | ltr501_powerdown(iio_priv(indio_dev)); | ||
400 | |||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | #ifdef CONFIG_PM_SLEEP | ||
405 | static int ltr501_suspend(struct device *dev) | ||
406 | { | ||
407 | struct ltr501_data *data = iio_priv(i2c_get_clientdata( | ||
408 | to_i2c_client(dev))); | ||
409 | return ltr501_powerdown(data); | ||
410 | } | ||
411 | |||
412 | static int ltr501_resume(struct device *dev) | ||
413 | { | ||
414 | struct ltr501_data *data = iio_priv(i2c_get_clientdata( | ||
415 | to_i2c_client(dev))); | ||
416 | |||
417 | return ltr501_write_contr(data->client, data->als_contr, | ||
418 | data->ps_contr); | ||
419 | } | ||
420 | #endif | ||
421 | |||
422 | static SIMPLE_DEV_PM_OPS(ltr501_pm_ops, ltr501_suspend, ltr501_resume); | ||
423 | |||
424 | static const struct i2c_device_id ltr501_id[] = { | ||
425 | { "ltr501", 0 }, | ||
426 | { } | ||
427 | }; | ||
428 | MODULE_DEVICE_TABLE(i2c, ltr501_id); | ||
429 | |||
430 | static struct i2c_driver ltr501_driver = { | ||
431 | .driver = { | ||
432 | .name = LTR501_DRV_NAME, | ||
433 | .pm = <r501_pm_ops, | ||
434 | .owner = THIS_MODULE, | ||
435 | }, | ||
436 | .probe = ltr501_probe, | ||
437 | .remove = ltr501_remove, | ||
438 | .id_table = ltr501_id, | ||
439 | }; | ||
440 | |||
441 | module_i2c_driver(ltr501_driver); | ||
442 | |||
443 | MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); | ||
444 | MODULE_DESCRIPTION("Lite-On LTR501 ambient light and proximity sensor driver"); | ||
445 | MODULE_LICENSE("GPL"); | ||