xref: /linux/drivers/misc/isl29003.c (revision b8bb76713ec50df2f11efee386e16f93d51e1076)
1 /*
2  *  isl29003.c - Linux kernel module for
3  * 	Intersil ISL29003 ambient light sensor
4  *
5  *  See file:Documentation/misc-devices/isl29003
6  *
7  *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
8  *
9  *  Based on code written by
10  *  	Rodolfo Giometti <giometti@linux.it>
11  *  	Eurotech S.p.A. <info@eurotech.it>
12  *
13  *  This program is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU General Public License as published by
15  *  the Free Software Foundation; either version 2 of the License, or
16  *  (at your option) any later version.
17  *
18  *  This program is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU General Public License for more details.
22  *
23  *  You should have received a copy of the GNU General Public License
24  *  along with this program; if not, write to the Free Software
25  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  */
27 
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/slab.h>
31 #include <linux/i2c.h>
32 #include <linux/mutex.h>
33 #include <linux/delay.h>
34 
35 #define ISL29003_DRV_NAME	"isl29003"
36 #define DRIVER_VERSION		"1.0"
37 
38 #define ISL29003_REG_COMMAND		0x00
39 #define ISL29003_ADC_ENABLED		(1 << 7)
40 #define ISL29003_ADC_PD			(1 << 6)
41 #define ISL29003_TIMING_INT		(1 << 5)
42 #define ISL29003_MODE_SHIFT		(2)
43 #define ISL29003_MODE_MASK		(0x3 << ISL29003_MODE_SHIFT)
44 #define ISL29003_RES_SHIFT		(0)
45 #define ISL29003_RES_MASK		(0x3 << ISL29003_RES_SHIFT)
46 
47 #define ISL29003_REG_CONTROL		0x01
48 #define ISL29003_INT_FLG		(1 << 5)
49 #define ISL29003_RANGE_SHIFT		(2)
50 #define ISL29003_RANGE_MASK		(0x3 << ISL29003_RANGE_SHIFT)
51 #define ISL29003_INT_PERSISTS_SHIFT	(0)
52 #define ISL29003_INT_PERSISTS_MASK	(0xf << ISL29003_INT_PERSISTS_SHIFT)
53 
54 #define ISL29003_REG_IRQ_THRESH_HI	0x02
55 #define ISL29003_REG_IRQ_THRESH_LO	0x03
56 #define ISL29003_REG_LSB_SENSOR		0x04
57 #define ISL29003_REG_MSB_SENSOR		0x05
58 #define ISL29003_REG_LSB_TIMER		0x06
59 #define ISL29003_REG_MSB_TIMER		0x07
60 
61 #define ISL29003_NUM_CACHABLE_REGS	4
62 
63 struct isl29003_data {
64 	struct i2c_client *client;
65 	struct mutex lock;
66 	u8 reg_cache[ISL29003_NUM_CACHABLE_REGS];
67 };
68 
69 static int gain_range[] = {
70 	1000, 4000, 16000, 64000
71 };
72 
73 /*
74  * register access helpers
75  */
76 
77 static int __isl29003_read_reg(struct i2c_client *client,
78 			       u32 reg, u8 mask, u8 shift)
79 {
80 	struct isl29003_data *data = i2c_get_clientdata(client);
81 	return (data->reg_cache[reg] & mask) >> shift;
82 }
83 
84 static int __isl29003_write_reg(struct i2c_client *client,
85 				u32 reg, u8 mask, u8 shift, u8 val)
86 {
87 	struct isl29003_data *data = i2c_get_clientdata(client);
88 	int ret = 0;
89 	u8 tmp;
90 
91 	if (reg >= ISL29003_NUM_CACHABLE_REGS)
92 		return -EINVAL;
93 
94 	mutex_lock(&data->lock);
95 
96 	tmp = data->reg_cache[reg];
97 	tmp &= ~mask;
98 	tmp |= val << shift;
99 
100 	ret = i2c_smbus_write_byte_data(client, reg, tmp);
101 	if (!ret)
102 		data->reg_cache[reg] = tmp;
103 
104 	mutex_unlock(&data->lock);
105 	return ret;
106 }
107 
108 /*
109  * internally used functions
110  */
111 
112 /* range */
113 static int isl29003_get_range(struct i2c_client *client)
114 {
115 	return __isl29003_read_reg(client, ISL29003_REG_CONTROL,
116 		ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT);
117 }
118 
119 static int isl29003_set_range(struct i2c_client *client, int range)
120 {
121 	return __isl29003_write_reg(client, ISL29003_REG_CONTROL,
122 		ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range);
123 }
124 
125 /* resolution */
126 static int isl29003_get_resolution(struct i2c_client *client)
127 {
128 	return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
129 		ISL29003_RES_MASK, ISL29003_RES_SHIFT);
130 }
131 
132 static int isl29003_set_resolution(struct i2c_client *client, int res)
133 {
134 	return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
135 		ISL29003_RES_MASK, ISL29003_RES_SHIFT, res);
136 }
137 
138 /* mode */
139 static int isl29003_get_mode(struct i2c_client *client)
140 {
141 	return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
142 		ISL29003_RES_MASK, ISL29003_RES_SHIFT);
143 }
144 
145 static int isl29003_set_mode(struct i2c_client *client, int mode)
146 {
147 	return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
148 		ISL29003_RES_MASK, ISL29003_RES_SHIFT, mode);
149 }
150 
151 /* power_state */
152 static int isl29003_set_power_state(struct i2c_client *client, int state)
153 {
154 	return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
155 				ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0,
156 				state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD);
157 }
158 
159 static int isl29003_get_power_state(struct i2c_client *client)
160 {
161 	struct isl29003_data *data = i2c_get_clientdata(client);
162 	u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND];
163 	return ~cmdreg & ISL29003_ADC_PD;
164 }
165 
166 static int isl29003_get_adc_value(struct i2c_client *client)
167 {
168 	struct isl29003_data *data = i2c_get_clientdata(client);
169 	int lsb, msb, range, bitdepth;
170 
171 	mutex_lock(&data->lock);
172 	lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR);
173 
174 	if (lsb < 0) {
175 		mutex_unlock(&data->lock);
176 		return lsb;
177 	}
178 
179 	msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR);
180 	mutex_unlock(&data->lock);
181 
182 	if (msb < 0)
183 		return msb;
184 
185 	range = isl29003_get_range(client);
186 	bitdepth = (4 - isl29003_get_resolution(client)) * 4;
187 	return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth;
188 }
189 
190 /*
191  * sysfs layer
192  */
193 
194 /* range */
195 static ssize_t isl29003_show_range(struct device *dev,
196 				   struct device_attribute *attr, char *buf)
197 {
198 	struct i2c_client *client = to_i2c_client(dev);
199 	return sprintf(buf, "%i\n", isl29003_get_range(client));
200 }
201 
202 static ssize_t isl29003_store_range(struct device *dev,
203 				    struct device_attribute *attr,
204 				    const char *buf, size_t count)
205 {
206 	struct i2c_client *client = to_i2c_client(dev);
207 	unsigned long val;
208 	int ret;
209 
210 	if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3))
211 		return -EINVAL;
212 
213 	ret = isl29003_set_range(client, val);
214 	if (ret < 0)
215 		return ret;
216 
217 	return count;
218 }
219 
220 static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
221 		   isl29003_show_range, isl29003_store_range);
222 
223 
224 /* resolution */
225 static ssize_t isl29003_show_resolution(struct device *dev,
226 					struct device_attribute *attr,
227 					char *buf)
228 {
229 	struct i2c_client *client = to_i2c_client(dev);
230 	return sprintf(buf, "%d\n", isl29003_get_resolution(client));
231 }
232 
233 static ssize_t isl29003_store_resolution(struct device *dev,
234 					 struct device_attribute *attr,
235 					 const char *buf, size_t count)
236 {
237 	struct i2c_client *client = to_i2c_client(dev);
238 	unsigned long val;
239 	int ret;
240 
241 	if ((strict_strtoul(buf, 10, &val) < 0) || (val > 3))
242 		return -EINVAL;
243 
244 	ret = isl29003_set_resolution(client, val);
245 	if (ret < 0)
246 		return ret;
247 
248 	return count;
249 }
250 
251 static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
252 		   isl29003_show_resolution, isl29003_store_resolution);
253 
254 /* mode */
255 static ssize_t isl29003_show_mode(struct device *dev,
256 				  struct device_attribute *attr, char *buf)
257 {
258 	struct i2c_client *client = to_i2c_client(dev);
259 	return sprintf(buf, "%d\n", isl29003_get_mode(client));
260 }
261 
262 static ssize_t isl29003_store_mode(struct device *dev,
263 		struct device_attribute *attr, const char *buf, size_t count)
264 {
265 	struct i2c_client *client = to_i2c_client(dev);
266 	unsigned long val;
267 	int ret;
268 
269 	if ((strict_strtoul(buf, 10, &val) < 0) || (val > 2))
270 		return -EINVAL;
271 
272 	ret = isl29003_set_mode(client, val);
273 	if (ret < 0)
274 		return ret;
275 
276 	return count;
277 }
278 
279 static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
280 		   isl29003_show_mode, isl29003_store_mode);
281 
282 
283 /* power state */
284 static ssize_t isl29003_show_power_state(struct device *dev,
285 					 struct device_attribute *attr,
286 					 char *buf)
287 {
288 	struct i2c_client *client = to_i2c_client(dev);
289 	return sprintf(buf, "%d\n", isl29003_get_power_state(client));
290 }
291 
292 static ssize_t isl29003_store_power_state(struct device *dev,
293 					  struct device_attribute *attr,
294 					  const char *buf, size_t count)
295 {
296 	struct i2c_client *client = to_i2c_client(dev);
297 	unsigned long val;
298 	int ret;
299 
300 	if ((strict_strtoul(buf, 10, &val) < 0) || (val > 1))
301 		return -EINVAL;
302 
303 	ret = isl29003_set_power_state(client, val);
304 	return ret ? ret : count;
305 }
306 
307 static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
308 		   isl29003_show_power_state, isl29003_store_power_state);
309 
310 
311 /* lux */
312 static ssize_t isl29003_show_lux(struct device *dev,
313 				 struct device_attribute *attr, char *buf)
314 {
315 	struct i2c_client *client = to_i2c_client(dev);
316 
317 	/* No LUX data if not operational */
318 	if (!isl29003_get_power_state(client))
319 		return -EBUSY;
320 
321 	return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
322 }
323 
324 static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
325 
326 static struct attribute *isl29003_attributes[] = {
327 	&dev_attr_range.attr,
328 	&dev_attr_resolution.attr,
329 	&dev_attr_mode.attr,
330 	&dev_attr_power_state.attr,
331 	&dev_attr_lux.attr,
332 	NULL
333 };
334 
335 static const struct attribute_group isl29003_attr_group = {
336 	.attrs = isl29003_attributes,
337 };
338 
339 static int isl29003_init_client(struct i2c_client *client)
340 {
341 	struct isl29003_data *data = i2c_get_clientdata(client);
342 	int i;
343 
344 	/* read all the registers once to fill the cache.
345 	 * if one of the reads fails, we consider the init failed */
346 	for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
347 		int v = i2c_smbus_read_byte_data(client, i);
348 		if (v < 0)
349 			return -ENODEV;
350 
351 		data->reg_cache[i] = v;
352 	}
353 
354 	/* set defaults */
355 	isl29003_set_range(client, 0);
356 	isl29003_set_resolution(client, 0);
357 	isl29003_set_mode(client, 0);
358 	isl29003_set_power_state(client, 0);
359 
360 	return 0;
361 }
362 
363 /*
364  * I2C layer
365  */
366 
367 static int __devinit isl29003_probe(struct i2c_client *client,
368 				    const struct i2c_device_id *id)
369 {
370 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
371 	struct isl29003_data *data;
372 	int err = 0;
373 
374 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
375 		return -EIO;
376 
377 	data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
378 	if (!data)
379 		return -ENOMEM;
380 
381 	data->client = client;
382 	i2c_set_clientdata(client, data);
383 	mutex_init(&data->lock);
384 
385 	/* initialize the ISL29003 chip */
386 	err = isl29003_init_client(client);
387 	if (err)
388 		goto exit_kfree;
389 
390 	/* register sysfs hooks */
391 	err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group);
392 	if (err)
393 		goto exit_kfree;
394 
395 	dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
396 	return 0;
397 
398 exit_kfree:
399 	kfree(data);
400 	return err;
401 }
402 
403 static int __devexit isl29003_remove(struct i2c_client *client)
404 {
405 	sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group);
406 	isl29003_set_power_state(client, 0);
407 	kfree(i2c_get_clientdata(client));
408 	return 0;
409 }
410 
411 #ifdef CONFIG_PM
412 static int isl29003_suspend(struct i2c_client *client, pm_message_t mesg)
413 {
414 	return isl29003_set_power_state(client, 0);
415 }
416 
417 static int isl29003_resume(struct i2c_client *client)
418 {
419 	int i;
420 	struct isl29003_data *data = i2c_get_clientdata(client);
421 
422 	/* restore registers from cache */
423 	for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
424 		if (!i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
425 			return -EIO;
426 
427 	return 0;
428 }
429 
430 #else
431 #define isl29003_suspend	NULL
432 #define isl29003_resume		NULL
433 #endif /* CONFIG_PM */
434 
435 static const struct i2c_device_id isl29003_id[] = {
436 	{ "isl29003", 0 },
437 	{}
438 };
439 MODULE_DEVICE_TABLE(i2c, isl29003_id);
440 
441 static struct i2c_driver isl29003_driver = {
442 	.driver = {
443 		.name	= ISL29003_DRV_NAME,
444 		.owner	= THIS_MODULE,
445 	},
446 	.suspend = isl29003_suspend,
447 	.resume	= isl29003_resume,
448 	.probe	= isl29003_probe,
449 	.remove	= __devexit_p(isl29003_remove),
450 	.id_table = isl29003_id,
451 };
452 
453 static int __init isl29003_init(void)
454 {
455 	return i2c_add_driver(&isl29003_driver);
456 }
457 
458 static void __exit isl29003_exit(void)
459 {
460 	i2c_del_driver(&isl29003_driver);
461 }
462 
463 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
464 MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
465 MODULE_LICENSE("GPL v2");
466 MODULE_VERSION(DRIVER_VERSION);
467 
468 module_init(isl29003_init);
469 module_exit(isl29003_exit);
470 
471