diff options
author | Rhyland Klein <rklein@nvidia.com> | 2010-10-07 18:48:09 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-10-07 23:12:38 -0400 |
commit | 940428742ed208836feb715fffd7cbc006fec3cb (patch) | |
tree | 558814677af864d1d48dda34916561fb7727c0d5 /drivers/staging/iio/light/isl29018.c | |
parent | 1e3950b8483a1805bd6e6e5ce8749cdafe04ae35 (diff) |
staging: iio: light: Adding driver for ISL29018 ALS
adding support for the ISL 29018 ambient light and proximity sensor.
Addressed comments from reviews by Jonathan Cameron and Joe Perches
* Removed some excess dbg prints that only printed function name
* Renamed some properties to make them more descriptive
* Added a property to list available adc resolutions
* Defined arrays for resolutions/ranges as static const
* Change loops initialization to memset for extensibility.
* used sizeof() instead of ARRAY_SIZE() to be safer
* Added a property to list available adc ranges
* Fixed warnings and property names.
Signed-off-by: Rhyland Klein <rklein@nvidia.com>
Acked-by: Jonathan Cameron <jic23@cam.ac.uk>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/iio/light/isl29018.c')
-rw-r--r-- | drivers/staging/iio/light/isl29018.c | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c new file mode 100644 index 00000000000..f919cc1d35e --- /dev/null +++ b/drivers/staging/iio/light/isl29018.c | |||
@@ -0,0 +1,563 @@ | |||
1 | /* | ||
2 | * A iio driver for the light sensor ISL 29018. | ||
3 | * | ||
4 | * IIO driver for monitoring ambient light intensity in luxi, proximity | ||
5 | * sensing and infrared sensing. | ||
6 | * | ||
7 | * Copyright (c) 2010, NVIDIA Corporation. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
17 | * more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License along | ||
20 | * with this program; if not, write to the Free Software Foundation, Inc., | ||
21 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
22 | */ | ||
23 | |||
24 | #include <linux/module.h> | ||
25 | #include <linux/i2c.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/slab.h> | ||
30 | #include "../iio.h" | ||
31 | |||
32 | #define CONVERSION_TIME_MS 100 | ||
33 | |||
34 | #define ISL29018_REG_ADD_COMMAND1 0x00 | ||
35 | #define COMMMAND1_OPMODE_SHIFT 5 | ||
36 | #define COMMMAND1_OPMODE_MASK (7 << COMMMAND1_OPMODE_SHIFT) | ||
37 | #define COMMMAND1_OPMODE_POWER_DOWN 0 | ||
38 | #define COMMMAND1_OPMODE_ALS_ONCE 1 | ||
39 | #define COMMMAND1_OPMODE_IR_ONCE 2 | ||
40 | #define COMMMAND1_OPMODE_PROX_ONCE 3 | ||
41 | |||
42 | #define ISL29018_REG_ADD_COMMANDII 0x01 | ||
43 | #define COMMANDII_RESOLUTION_SHIFT 2 | ||
44 | #define COMMANDII_RESOLUTION_MASK (0x3 << COMMANDII_RESOLUTION_SHIFT) | ||
45 | |||
46 | #define COMMANDII_RANGE_SHIFT 0 | ||
47 | #define COMMANDII_RANGE_MASK (0x3 << COMMANDII_RANGE_SHIFT) | ||
48 | |||
49 | #define COMMANDII_SCHEME_SHIFT 7 | ||
50 | #define COMMANDII_SCHEME_MASK (0x1 << COMMANDII_SCHEME_SHIFT) | ||
51 | |||
52 | #define ISL29018_REG_ADD_DATA_LSB 0x02 | ||
53 | #define ISL29018_REG_ADD_DATA_MSB 0x03 | ||
54 | #define ISL29018_MAX_REGS ISL29018_REG_ADD_DATA_MSB | ||
55 | |||
56 | struct isl29018_chip { | ||
57 | struct iio_dev *indio_dev; | ||
58 | struct i2c_client *client; | ||
59 | struct mutex lock; | ||
60 | unsigned int range; | ||
61 | unsigned int adc_bit; | ||
62 | int prox_scheme; | ||
63 | u8 reg_cache[ISL29018_MAX_REGS]; | ||
64 | }; | ||
65 | |||
66 | static int isl29018_write_data(struct i2c_client *client, u8 reg, | ||
67 | u8 val, u8 mask, u8 shift) | ||
68 | { | ||
69 | u8 regval; | ||
70 | int ret = 0; | ||
71 | struct isl29018_chip *chip = i2c_get_clientdata(client); | ||
72 | |||
73 | regval = chip->reg_cache[reg]; | ||
74 | regval &= ~mask; | ||
75 | regval |= val << shift; | ||
76 | |||
77 | ret = i2c_smbus_write_byte_data(client, reg, regval); | ||
78 | if (ret) { | ||
79 | dev_err(&client->dev, "Write to device fails status %x\n", ret); | ||
80 | return ret; | ||
81 | } | ||
82 | chip->reg_cache[reg] = regval; | ||
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int isl29018_set_range(struct i2c_client *client, unsigned long range, | ||
88 | unsigned int *new_range) | ||
89 | { | ||
90 | static const unsigned long supp_ranges[] = {1000, 4000, 16000, 64000}; | ||
91 | int i; | ||
92 | |||
93 | for (i = 0; i < ARRAY_SIZE(supp_ranges); ++i) { | ||
94 | if (range <= supp_ranges[i]) { | ||
95 | *new_range = (unsigned int)supp_ranges[i]; | ||
96 | break; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | if (i >= ARRAY_SIZE(supp_ranges)) | ||
101 | return -EINVAL; | ||
102 | |||
103 | return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, | ||
104 | i, COMMANDII_RANGE_MASK, COMMANDII_RANGE_SHIFT); | ||
105 | } | ||
106 | |||
107 | static int isl29018_set_resolution(struct i2c_client *client, | ||
108 | unsigned long adcbit, unsigned int *conf_adc_bit) | ||
109 | { | ||
110 | static const unsigned long supp_adcbit[] = {16, 12, 8, 4}; | ||
111 | int i; | ||
112 | |||
113 | for (i = 0; i < ARRAY_SIZE(supp_adcbit); ++i) { | ||
114 | if (adcbit >= supp_adcbit[i]) { | ||
115 | *conf_adc_bit = (unsigned int)supp_adcbit[i]; | ||
116 | break; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | if (i >= ARRAY_SIZE(supp_adcbit)) | ||
121 | return -EINVAL; | ||
122 | |||
123 | return isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, | ||
124 | i, COMMANDII_RESOLUTION_MASK, | ||
125 | COMMANDII_RESOLUTION_SHIFT); | ||
126 | } | ||
127 | |||
128 | static int isl29018_read_sensor_input(struct i2c_client *client, int mode) | ||
129 | { | ||
130 | int status; | ||
131 | int lsb; | ||
132 | int msb; | ||
133 | |||
134 | /* Set mode */ | ||
135 | status = isl29018_write_data(client, ISL29018_REG_ADD_COMMAND1, | ||
136 | mode, COMMMAND1_OPMODE_MASK, COMMMAND1_OPMODE_SHIFT); | ||
137 | if (status) { | ||
138 | dev_err(&client->dev, "Error in setting operating mode\n"); | ||
139 | return status; | ||
140 | } | ||
141 | msleep(CONVERSION_TIME_MS); | ||
142 | lsb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_LSB); | ||
143 | if (lsb < 0) { | ||
144 | dev_err(&client->dev, "Error in reading LSB DATA\n"); | ||
145 | return lsb; | ||
146 | } | ||
147 | |||
148 | msb = i2c_smbus_read_byte_data(client, ISL29018_REG_ADD_DATA_MSB); | ||
149 | if (msb < 0) { | ||
150 | dev_err(&client->dev, "Error in reading MSB DATA\n"); | ||
151 | return msb; | ||
152 | } | ||
153 | dev_vdbg(&client->dev, "MSB 0x%x and LSB 0x%x\n", msb, lsb); | ||
154 | |||
155 | return (msb << 8) | lsb; | ||
156 | } | ||
157 | |||
158 | static int isl29018_read_lux(struct i2c_client *client, int *lux) | ||
159 | { | ||
160 | int lux_data; | ||
161 | struct isl29018_chip *chip = i2c_get_clientdata(client); | ||
162 | |||
163 | lux_data = isl29018_read_sensor_input(client, | ||
164 | COMMMAND1_OPMODE_ALS_ONCE); | ||
165 | |||
166 | if (lux_data < 0) | ||
167 | return lux_data; | ||
168 | |||
169 | *lux = (lux_data * chip->range) >> chip->adc_bit; | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int isl29018_read_ir(struct i2c_client *client, int *ir) | ||
175 | { | ||
176 | int ir_data; | ||
177 | |||
178 | ir_data = isl29018_read_sensor_input(client, COMMMAND1_OPMODE_IR_ONCE); | ||
179 | |||
180 | if (ir_data < 0) | ||
181 | return ir_data; | ||
182 | |||
183 | *ir = ir_data; | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static int isl29018_read_proximity_ir(struct i2c_client *client, int scheme, | ||
189 | int *near_ir) | ||
190 | { | ||
191 | int status; | ||
192 | int prox_data = -1; | ||
193 | int ir_data = -1; | ||
194 | |||
195 | /* Do proximity sensing with required scheme */ | ||
196 | status = isl29018_write_data(client, ISL29018_REG_ADD_COMMANDII, | ||
197 | scheme, COMMANDII_SCHEME_MASK, COMMANDII_SCHEME_SHIFT); | ||
198 | if (status) { | ||
199 | dev_err(&client->dev, "Error in setting operating mode\n"); | ||
200 | return status; | ||
201 | } | ||
202 | |||
203 | prox_data = isl29018_read_sensor_input(client, | ||
204 | COMMMAND1_OPMODE_PROX_ONCE); | ||
205 | if (prox_data < 0) | ||
206 | return prox_data; | ||
207 | |||
208 | if (scheme == 1) { | ||
209 | *near_ir = prox_data; | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | ir_data = isl29018_read_sensor_input(client, | ||
214 | COMMMAND1_OPMODE_IR_ONCE); | ||
215 | |||
216 | if (ir_data < 0) | ||
217 | return ir_data; | ||
218 | |||
219 | if (prox_data >= ir_data) | ||
220 | *near_ir = prox_data - ir_data; | ||
221 | else | ||
222 | *near_ir = 0; | ||
223 | |||
224 | return 0; | ||
225 | } | ||
226 | |||
227 | static ssize_t get_sensor_data(struct device *dev, char *buf, int mode) | ||
228 | { | ||
229 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
230 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
231 | struct i2c_client *client = chip->client; | ||
232 | int value = 0; | ||
233 | int status; | ||
234 | |||
235 | mutex_lock(&chip->lock); | ||
236 | switch (mode) { | ||
237 | case COMMMAND1_OPMODE_PROX_ONCE: | ||
238 | status = isl29018_read_proximity_ir(client, | ||
239 | chip->prox_scheme, &value); | ||
240 | break; | ||
241 | |||
242 | case COMMMAND1_OPMODE_ALS_ONCE: | ||
243 | status = isl29018_read_lux(client, &value); | ||
244 | break; | ||
245 | |||
246 | case COMMMAND1_OPMODE_IR_ONCE: | ||
247 | status = isl29018_read_ir(client, &value); | ||
248 | break; | ||
249 | |||
250 | default: | ||
251 | dev_err(&client->dev, "Mode %d is not supported\n", mode); | ||
252 | mutex_unlock(&chip->lock); | ||
253 | return -EBUSY; | ||
254 | } | ||
255 | if (status < 0) { | ||
256 | dev_err(&client->dev, "Error in Reading data"); | ||
257 | mutex_unlock(&chip->lock); | ||
258 | return status; | ||
259 | } | ||
260 | |||
261 | mutex_unlock(&chip->lock); | ||
262 | |||
263 | return sprintf(buf, "%d\n", value); | ||
264 | } | ||
265 | |||
266 | /* Sysfs interface */ | ||
267 | /* range */ | ||
268 | static ssize_t show_range(struct device *dev, | ||
269 | struct device_attribute *attr, char *buf) | ||
270 | { | ||
271 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
272 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
273 | |||
274 | return sprintf(buf, "%u\n", chip->range); | ||
275 | } | ||
276 | |||
277 | static ssize_t store_range(struct device *dev, | ||
278 | struct device_attribute *attr, const char *buf, size_t count) | ||
279 | { | ||
280 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
281 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
282 | struct i2c_client *client = chip->client; | ||
283 | int status; | ||
284 | unsigned long lval; | ||
285 | unsigned int new_range; | ||
286 | |||
287 | if (strict_strtoul(buf, 10, &lval)) | ||
288 | return -EINVAL; | ||
289 | |||
290 | if (!(lval == 1000UL || lval == 4000UL || | ||
291 | lval == 16000UL || lval == 64000UL)) { | ||
292 | dev_err(dev, "The range is not supported\n"); | ||
293 | return -EINVAL; | ||
294 | } | ||
295 | |||
296 | mutex_lock(&chip->lock); | ||
297 | status = isl29018_set_range(client, lval, &new_range); | ||
298 | if (status < 0) { | ||
299 | mutex_unlock(&chip->lock); | ||
300 | dev_err(dev, "Error in setting max range\n"); | ||
301 | return status; | ||
302 | } | ||
303 | chip->range = new_range; | ||
304 | mutex_unlock(&chip->lock); | ||
305 | |||
306 | return count; | ||
307 | } | ||
308 | |||
309 | /* resolution */ | ||
310 | static ssize_t show_resolution(struct device *dev, | ||
311 | struct device_attribute *attr, char *buf) | ||
312 | { | ||
313 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
314 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
315 | |||
316 | return sprintf(buf, "%u\n", chip->adc_bit); | ||
317 | } | ||
318 | |||
319 | static ssize_t store_resolution(struct device *dev, | ||
320 | struct device_attribute *attr, const char *buf, size_t count) | ||
321 | { | ||
322 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
323 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
324 | struct i2c_client *client = chip->client; | ||
325 | int status; | ||
326 | unsigned long lval; | ||
327 | unsigned int new_adc_bit; | ||
328 | |||
329 | if (strict_strtoul(buf, 10, &lval)) | ||
330 | return -EINVAL; | ||
331 | if (!(lval == 4 || lval == 8 || lval == 12 || lval == 16)) { | ||
332 | dev_err(dev, "The resolution is not supported\n"); | ||
333 | return -EINVAL; | ||
334 | } | ||
335 | |||
336 | mutex_lock(&chip->lock); | ||
337 | status = isl29018_set_resolution(client, lval, &new_adc_bit); | ||
338 | if (status < 0) { | ||
339 | mutex_unlock(&chip->lock); | ||
340 | dev_err(dev, "Error in setting resolution\n"); | ||
341 | return status; | ||
342 | } | ||
343 | chip->adc_bit = new_adc_bit; | ||
344 | mutex_unlock(&chip->lock); | ||
345 | |||
346 | return count; | ||
347 | } | ||
348 | |||
349 | /* proximity scheme */ | ||
350 | static ssize_t show_prox_infrared_supression(struct device *dev, | ||
351 | struct device_attribute *attr, char *buf) | ||
352 | { | ||
353 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
354 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
355 | |||
356 | /* return the "proximity scheme" i.e. if the chip does on chip | ||
357 | infrared supression (1 means perform on chip supression) */ | ||
358 | return sprintf(buf, "%d\n", chip->prox_scheme); | ||
359 | } | ||
360 | |||
361 | static ssize_t store_prox_infrared_supression(struct device *dev, | ||
362 | struct device_attribute *attr, const char *buf, size_t count) | ||
363 | { | ||
364 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
365 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
366 | unsigned long lval; | ||
367 | |||
368 | if (strict_strtoul(buf, 10, &lval)) | ||
369 | return -EINVAL; | ||
370 | if (!(lval == 0UL || lval == 1UL)) { | ||
371 | dev_err(dev, "The mode is not supported\n"); | ||
372 | return -EINVAL; | ||
373 | } | ||
374 | |||
375 | /* get the "proximity scheme" i.e. if the chip does on chip | ||
376 | infrared supression (1 means perform on chip supression) */ | ||
377 | mutex_lock(&chip->lock); | ||
378 | chip->prox_scheme = (int)lval; | ||
379 | mutex_unlock(&chip->lock); | ||
380 | |||
381 | return count; | ||
382 | } | ||
383 | |||
384 | /* Read lux */ | ||
385 | static ssize_t show_lux(struct device *dev, | ||
386 | struct device_attribute *devattr, char *buf) | ||
387 | { | ||
388 | return get_sensor_data(dev, buf, COMMMAND1_OPMODE_ALS_ONCE); | ||
389 | } | ||
390 | |||
391 | /* Read ir */ | ||
392 | static ssize_t show_ir(struct device *dev, | ||
393 | struct device_attribute *devattr, char *buf) | ||
394 | { | ||
395 | return get_sensor_data(dev, buf, COMMMAND1_OPMODE_IR_ONCE); | ||
396 | } | ||
397 | |||
398 | /* Read nearest ir */ | ||
399 | static ssize_t show_proxim_ir(struct device *dev, | ||
400 | struct device_attribute *devattr, char *buf) | ||
401 | { | ||
402 | return get_sensor_data(dev, buf, COMMMAND1_OPMODE_PROX_ONCE); | ||
403 | } | ||
404 | |||
405 | /* Read name */ | ||
406 | static ssize_t show_name(struct device *dev, | ||
407 | struct device_attribute *attr, char *buf) | ||
408 | { | ||
409 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
410 | struct isl29018_chip *chip = indio_dev->dev_data; | ||
411 | |||
412 | return sprintf(buf, "%s\n", chip->client->name); | ||
413 | } | ||
414 | |||
415 | static IIO_DEVICE_ATTR(range, S_IRUGO | S_IWUSR, show_range, store_range, 0); | ||
416 | static IIO_CONST_ATTR(range_available, "1000 4000 16000 64000"); | ||
417 | static IIO_CONST_ATTR(adc_resolution_available, "4 8 12 16"); | ||
418 | static IIO_DEVICE_ATTR(adc_resolution, S_IRUGO | S_IWUSR, | ||
419 | show_resolution, store_resolution, 0); | ||
420 | static IIO_DEVICE_ATTR(proximity_on_chip_ambient_infrared_supression, | ||
421 | S_IRUGO | S_IWUSR, | ||
422 | show_prox_infrared_supression, | ||
423 | store_prox_infrared_supression, 0); | ||
424 | static IIO_DEVICE_ATTR(illuminance0_input, S_IRUGO, show_lux, NULL, 0); | ||
425 | static IIO_DEVICE_ATTR(intensity_infrared_raw, S_IRUGO, show_ir, NULL, 0); | ||
426 | static IIO_DEVICE_ATTR(proximity_raw, S_IRUGO, show_proxim_ir, NULL, 0); | ||
427 | static IIO_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | ||
428 | |||
429 | #define ISL29018_DEV_ATTR(name) (&iio_dev_attr_##name.dev_attr.attr) | ||
430 | #define ISL29018_CONST_ATTR(name) (&iio_const_attr_##name.dev_attr.attr) | ||
431 | static struct attribute *isl29018_attributes[] = { | ||
432 | ISL29018_DEV_ATTR(name), | ||
433 | ISL29018_DEV_ATTR(range), | ||
434 | ISL29018_CONST_ATTR(range_available), | ||
435 | ISL29018_DEV_ATTR(adc_resolution), | ||
436 | ISL29018_CONST_ATTR(adc_resolution_available), | ||
437 | ISL29018_DEV_ATTR(proximity_on_chip_ambient_infrared_supression), | ||
438 | ISL29018_DEV_ATTR(illuminance0_input), | ||
439 | ISL29018_DEV_ATTR(intensity_infrared_raw), | ||
440 | ISL29018_DEV_ATTR(proximity_raw), | ||
441 | NULL | ||
442 | }; | ||
443 | |||
444 | static const struct attribute_group isl29108_group = { | ||
445 | .attrs = isl29018_attributes, | ||
446 | }; | ||
447 | |||
448 | static int isl29018_chip_init(struct i2c_client *client) | ||
449 | { | ||
450 | struct isl29018_chip *chip = i2c_get_clientdata(client); | ||
451 | int status; | ||
452 | int new_adc_bit; | ||
453 | unsigned int new_range; | ||
454 | |||
455 | memset(chip->reg_cache, 0, sizeof(chip->reg_cache)); | ||
456 | |||
457 | /* set defaults */ | ||
458 | status = isl29018_set_range(client, chip->range, &new_range); | ||
459 | if (status < 0) { | ||
460 | dev_err(&client->dev, "Init of isl29018 fails\n"); | ||
461 | return status; | ||
462 | } | ||
463 | |||
464 | status = isl29018_set_resolution(client, chip->adc_bit, | ||
465 | &new_adc_bit); | ||
466 | |||
467 | return 0; | ||
468 | } | ||
469 | |||
470 | static int __devinit isl29018_probe(struct i2c_client *client, | ||
471 | const struct i2c_device_id *id) | ||
472 | { | ||
473 | struct isl29018_chip *chip; | ||
474 | int err; | ||
475 | |||
476 | chip = kzalloc(sizeof(struct isl29018_chip), GFP_KERNEL); | ||
477 | if (!chip) { | ||
478 | dev_err(&client->dev, "Memory allocation fails\n"); | ||
479 | err = -ENOMEM; | ||
480 | goto exit; | ||
481 | } | ||
482 | |||
483 | i2c_set_clientdata(client, chip); | ||
484 | chip->client = client; | ||
485 | |||
486 | mutex_init(&chip->lock); | ||
487 | |||
488 | chip->range = 1000; | ||
489 | chip->adc_bit = 16; | ||
490 | |||
491 | err = isl29018_chip_init(client); | ||
492 | if (err) | ||
493 | goto exit_free; | ||
494 | |||
495 | chip->indio_dev = iio_allocate_device(); | ||
496 | if (!chip->indio_dev) { | ||
497 | dev_err(&client->dev, "iio allocation fails\n"); | ||
498 | goto exit_free; | ||
499 | } | ||
500 | chip->indio_dev->attrs = &isl29108_group; | ||
501 | chip->indio_dev->dev.parent = &client->dev; | ||
502 | chip->indio_dev->dev_data = (void *)(chip); | ||
503 | chip->indio_dev->driver_module = THIS_MODULE; | ||
504 | chip->indio_dev->modes = INDIO_DIRECT_MODE; | ||
505 | err = iio_device_register(chip->indio_dev); | ||
506 | if (err) { | ||
507 | dev_err(&client->dev, "iio registration fails\n"); | ||
508 | goto exit_iio_free; | ||
509 | } | ||
510 | |||
511 | return 0; | ||
512 | exit_iio_free: | ||
513 | iio_free_device(chip->indio_dev); | ||
514 | exit_free: | ||
515 | kfree(chip); | ||
516 | exit: | ||
517 | return err; | ||
518 | } | ||
519 | |||
520 | static int __devexit isl29018_remove(struct i2c_client *client) | ||
521 | { | ||
522 | struct isl29018_chip *chip = i2c_get_clientdata(client); | ||
523 | |||
524 | dev_dbg(&client->dev, "%s()\n", __func__); | ||
525 | iio_device_unregister(chip->indio_dev); | ||
526 | kfree(chip); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static const struct i2c_device_id isl29018_id[] = { | ||
532 | {"isl29018", 0}, | ||
533 | {} | ||
534 | }; | ||
535 | |||
536 | MODULE_DEVICE_TABLE(i2c, isl29018_id); | ||
537 | |||
538 | static struct i2c_driver isl29018_driver = { | ||
539 | .class = I2C_CLASS_HWMON, | ||
540 | .driver = { | ||
541 | .name = "isl29018", | ||
542 | .owner = THIS_MODULE, | ||
543 | }, | ||
544 | .probe = isl29018_probe, | ||
545 | .remove = __devexit_p(isl29018_remove), | ||
546 | .id_table = isl29018_id, | ||
547 | }; | ||
548 | |||
549 | static int __init isl29018_init(void) | ||
550 | { | ||
551 | return i2c_add_driver(&isl29018_driver); | ||
552 | } | ||
553 | |||
554 | static void __exit isl29018_exit(void) | ||
555 | { | ||
556 | i2c_del_driver(&isl29018_driver); | ||
557 | } | ||
558 | |||
559 | module_init(isl29018_init); | ||
560 | module_exit(isl29018_exit); | ||
561 | |||
562 | MODULE_DESCRIPTION("ISL29018 Ambient Light Sensor driver"); | ||
563 | MODULE_LICENSE("GPL"); | ||