xref: /openbmc/linux/drivers/misc/isl29003.c (revision 1c2dd16a)
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/slab.h>
30 #include <linux/i2c.h>
31 #include <linux/mutex.h>
32 #include <linux/delay.h>
33 
34 #define ISL29003_DRV_NAME	"isl29003"
35 #define DRIVER_VERSION		"1.0"
36 
37 #define ISL29003_REG_COMMAND		0x00
38 #define ISL29003_ADC_ENABLED		(1 << 7)
39 #define ISL29003_ADC_PD			(1 << 6)
40 #define ISL29003_TIMING_INT		(1 << 5)
41 #define ISL29003_MODE_SHIFT		(2)
42 #define ISL29003_MODE_MASK		(0x3 << ISL29003_MODE_SHIFT)
43 #define ISL29003_RES_SHIFT		(0)
44 #define ISL29003_RES_MASK		(0x3 << ISL29003_RES_SHIFT)
45 
46 #define ISL29003_REG_CONTROL		0x01
47 #define ISL29003_INT_FLG		(1 << 5)
48 #define ISL29003_RANGE_SHIFT		(2)
49 #define ISL29003_RANGE_MASK		(0x3 << ISL29003_RANGE_SHIFT)
50 #define ISL29003_INT_PERSISTS_SHIFT	(0)
51 #define ISL29003_INT_PERSISTS_MASK	(0xf << ISL29003_INT_PERSISTS_SHIFT)
52 
53 #define ISL29003_REG_IRQ_THRESH_HI	0x02
54 #define ISL29003_REG_IRQ_THRESH_LO	0x03
55 #define ISL29003_REG_LSB_SENSOR		0x04
56 #define ISL29003_REG_MSB_SENSOR		0x05
57 #define ISL29003_REG_LSB_TIMER		0x06
58 #define ISL29003_REG_MSB_TIMER		0x07
59 
60 #define ISL29003_NUM_CACHABLE_REGS	4
61 
62 struct isl29003_data {
63 	struct i2c_client *client;
64 	struct mutex lock;
65 	u8 reg_cache[ISL29003_NUM_CACHABLE_REGS];
66 	u8 power_state_before_suspend;
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 	ret = kstrtoul(buf, 10, &val);
211 	if (ret)
212 		return ret;
213 
214 	if (val > 3)
215 		return -EINVAL;
216 
217 	ret = isl29003_set_range(client, val);
218 	if (ret < 0)
219 		return ret;
220 
221 	return count;
222 }
223 
224 static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
225 		   isl29003_show_range, isl29003_store_range);
226 
227 
228 /* resolution */
229 static ssize_t isl29003_show_resolution(struct device *dev,
230 					struct device_attribute *attr,
231 					char *buf)
232 {
233 	struct i2c_client *client = to_i2c_client(dev);
234 	return sprintf(buf, "%d\n", isl29003_get_resolution(client));
235 }
236 
237 static ssize_t isl29003_store_resolution(struct device *dev,
238 					 struct device_attribute *attr,
239 					 const char *buf, size_t count)
240 {
241 	struct i2c_client *client = to_i2c_client(dev);
242 	unsigned long val;
243 	int ret;
244 
245 	ret = kstrtoul(buf, 10, &val);
246 	if (ret)
247 		return ret;
248 
249 	if (val > 3)
250 		return -EINVAL;
251 
252 	ret = isl29003_set_resolution(client, val);
253 	if (ret < 0)
254 		return ret;
255 
256 	return count;
257 }
258 
259 static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
260 		   isl29003_show_resolution, isl29003_store_resolution);
261 
262 /* mode */
263 static ssize_t isl29003_show_mode(struct device *dev,
264 				  struct device_attribute *attr, char *buf)
265 {
266 	struct i2c_client *client = to_i2c_client(dev);
267 	return sprintf(buf, "%d\n", isl29003_get_mode(client));
268 }
269 
270 static ssize_t isl29003_store_mode(struct device *dev,
271 		struct device_attribute *attr, const char *buf, size_t count)
272 {
273 	struct i2c_client *client = to_i2c_client(dev);
274 	unsigned long val;
275 	int ret;
276 
277 	ret = kstrtoul(buf, 10, &val);
278 	if (ret)
279 		return ret;
280 
281 	if (val > 2)
282 		return -EINVAL;
283 
284 	ret = isl29003_set_mode(client, val);
285 	if (ret < 0)
286 		return ret;
287 
288 	return count;
289 }
290 
291 static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
292 		   isl29003_show_mode, isl29003_store_mode);
293 
294 
295 /* power state */
296 static ssize_t isl29003_show_power_state(struct device *dev,
297 					 struct device_attribute *attr,
298 					 char *buf)
299 {
300 	struct i2c_client *client = to_i2c_client(dev);
301 	return sprintf(buf, "%d\n", isl29003_get_power_state(client));
302 }
303 
304 static ssize_t isl29003_store_power_state(struct device *dev,
305 					  struct device_attribute *attr,
306 					  const char *buf, size_t count)
307 {
308 	struct i2c_client *client = to_i2c_client(dev);
309 	unsigned long val;
310 	int ret;
311 
312 	ret = kstrtoul(buf, 10, &val);
313 	if (ret)
314 		return ret;
315 
316 	if (val > 1)
317 		return -EINVAL;
318 
319 	ret = isl29003_set_power_state(client, val);
320 	return ret ? ret : count;
321 }
322 
323 static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
324 		   isl29003_show_power_state, isl29003_store_power_state);
325 
326 
327 /* lux */
328 static ssize_t isl29003_show_lux(struct device *dev,
329 				 struct device_attribute *attr, char *buf)
330 {
331 	struct i2c_client *client = to_i2c_client(dev);
332 
333 	/* No LUX data if not operational */
334 	if (!isl29003_get_power_state(client))
335 		return -EBUSY;
336 
337 	return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
338 }
339 
340 static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
341 
342 static struct attribute *isl29003_attributes[] = {
343 	&dev_attr_range.attr,
344 	&dev_attr_resolution.attr,
345 	&dev_attr_mode.attr,
346 	&dev_attr_power_state.attr,
347 	&dev_attr_lux.attr,
348 	NULL
349 };
350 
351 static const struct attribute_group isl29003_attr_group = {
352 	.attrs = isl29003_attributes,
353 };
354 
355 static int isl29003_init_client(struct i2c_client *client)
356 {
357 	struct isl29003_data *data = i2c_get_clientdata(client);
358 	int i;
359 
360 	/* read all the registers once to fill the cache.
361 	 * if one of the reads fails, we consider the init failed */
362 	for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
363 		int v = i2c_smbus_read_byte_data(client, i);
364 		if (v < 0)
365 			return -ENODEV;
366 
367 		data->reg_cache[i] = v;
368 	}
369 
370 	/* set defaults */
371 	isl29003_set_range(client, 0);
372 	isl29003_set_resolution(client, 0);
373 	isl29003_set_mode(client, 0);
374 	isl29003_set_power_state(client, 0);
375 
376 	return 0;
377 }
378 
379 /*
380  * I2C layer
381  */
382 
383 static int isl29003_probe(struct i2c_client *client,
384 				    const struct i2c_device_id *id)
385 {
386 	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
387 	struct isl29003_data *data;
388 	int err = 0;
389 
390 	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
391 		return -EIO;
392 
393 	data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
394 	if (!data)
395 		return -ENOMEM;
396 
397 	data->client = client;
398 	i2c_set_clientdata(client, data);
399 	mutex_init(&data->lock);
400 
401 	/* initialize the ISL29003 chip */
402 	err = isl29003_init_client(client);
403 	if (err)
404 		goto exit_kfree;
405 
406 	/* register sysfs hooks */
407 	err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group);
408 	if (err)
409 		goto exit_kfree;
410 
411 	dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
412 	return 0;
413 
414 exit_kfree:
415 	kfree(data);
416 	return err;
417 }
418 
419 static int isl29003_remove(struct i2c_client *client)
420 {
421 	sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group);
422 	isl29003_set_power_state(client, 0);
423 	kfree(i2c_get_clientdata(client));
424 	return 0;
425 }
426 
427 #ifdef CONFIG_PM_SLEEP
428 static int isl29003_suspend(struct device *dev)
429 {
430 	struct i2c_client *client = to_i2c_client(dev);
431 	struct isl29003_data *data = i2c_get_clientdata(client);
432 
433 	data->power_state_before_suspend = isl29003_get_power_state(client);
434 	return isl29003_set_power_state(client, 0);
435 }
436 
437 static int isl29003_resume(struct device *dev)
438 {
439 	int i;
440 	struct i2c_client *client = to_i2c_client(dev);
441 	struct isl29003_data *data = i2c_get_clientdata(client);
442 
443 	/* restore registers from cache */
444 	for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
445 		if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
446 			return -EIO;
447 
448 	return isl29003_set_power_state(client,
449 		data->power_state_before_suspend);
450 }
451 
452 static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume);
453 #define ISL29003_PM_OPS (&isl29003_pm_ops)
454 
455 #else
456 #define ISL29003_PM_OPS NULL
457 #endif /* CONFIG_PM_SLEEP */
458 
459 static const struct i2c_device_id isl29003_id[] = {
460 	{ "isl29003", 0 },
461 	{}
462 };
463 MODULE_DEVICE_TABLE(i2c, isl29003_id);
464 
465 static struct i2c_driver isl29003_driver = {
466 	.driver = {
467 		.name	= ISL29003_DRV_NAME,
468 		.pm	= ISL29003_PM_OPS,
469 	},
470 	.probe	= isl29003_probe,
471 	.remove	= isl29003_remove,
472 	.id_table = isl29003_id,
473 };
474 
475 module_i2c_driver(isl29003_driver);
476 
477 MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
478 MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
479 MODULE_LICENSE("GPL v2");
480 MODULE_VERSION(DRIVER_VERSION);
481