2 * tsl2561.c - Linux kernel modules for light to digital convertor
4 * Copyright (C) 2008-2009 Jonathan Cameron <jic23@cam.ac.uk>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * Some portions based upon the tsl2550 driver.
22 * This driver could probably be adapted easily to talk to the tsl2560 (smbus)
24 * Needs some work to support the events this can generate.
25 * Todo: Implement interrupt handling. Currently a hardware bug means
26 * this isn't available on my test board.
29 #include <linux/module.h>
30 #include <linux/init.h>
31 #include <linux/i2c.h>
36 #define TSL2561_CONTROL_REGISTER 0x00
37 #define TSL2561_TIMING_REGISTER 0x01
38 #define TSL2561_THRESHLOW_LOW_REGISTER 0x02
39 #define TSL2561_THRESHLOW_HIGH_REGISTER 0x03
40 #define TSL2561_THRESHHIGH_LOW_REGISTER 0x04
41 #define TSL2561_THRESHHIGH_HIGH_REGISTER 0x05
42 #define TSL2561_INT_CONTROL_REGISTER 0x06
44 #define TSL2561_INT_REG_INT_OFF 0x00
45 #define TSL2561_INT_REG_INT_LEVEL 0x08
46 #define TSL2561_INT_REG_INT_SMBUS 0x10
47 #define TSL2561_INT_REG_INT_TEST 0x18
49 #define TSL2561_ID_REGISTER 0x0A
51 #define TSL2561_DATA_0_LOW 0x0C
52 #define TSL2561_DATA_1_LOW 0x0E
54 /* Control Register Values */
55 #define TSL2561_CONT_REG_PWR_ON 0x03
56 #define TSL2561_CONT_REG_PWR_OFF 0x00
59 * struct tsl2561_state - device specific state
60 * @indio_dev: the industrialio I/O info structure
62 * @command_buf: single command buffer used for all operations
63 * @command_buf_lock: ensure unique access to command_buf
65 struct tsl2561_state
{
66 struct iio_dev
*indio_dev
;
67 struct i2c_client
*client
;
68 struct tsl2561_command
*command_buf
;
69 struct mutex command_buf_lock
;
73 * struct tsl2561_command - command byte for smbus
74 * @address: register address
75 * @block: is this a block r/w
76 * @word: is this a word r/w
77 * @clear: set to 1 to clear pending interrupt
78 * @cmd: select the command register - always 1.
80 struct tsl2561_command
{
81 unsigned int address
:4;
88 static inline void tsl2561_init_command_buf(struct tsl2561_command
*buf
)
97 static ssize_t
tsl2561_read_val(struct device
*dev
,
98 struct device_attribute
*attr
,
103 struct iio_dev_attr
*this_attr
= to_iio_dev_attr(attr
);
104 struct iio_dev
*indio_dev
= dev_get_drvdata(dev
);
105 struct tsl2561_state
*st
= indio_dev
->dev_data
;
107 mutex_lock(&st
->command_buf_lock
);
108 st
->command_buf
->cmd
= 1;
109 st
->command_buf
->word
= 1;
110 st
->command_buf
->address
= this_attr
->address
;
112 data
= i2c_smbus_read_word_data(st
->client
, *(char *)(st
->command_buf
));
117 len
= sprintf(buf
, "%u\n", data
);
120 mutex_unlock(&st
->command_buf_lock
);
122 return ret
? ret
: len
;
125 static IIO_DEV_ATTR_LIGHT_INFRARED(0, tsl2561_read_val
, TSL2561_DATA_0_LOW
);
126 static IIO_DEV_ATTR_LIGHT_BROAD(0, tsl2561_read_val
, TSL2561_DATA_1_LOW
);
128 static struct attribute
*tsl2561_attributes
[] = {
129 &iio_dev_attr_light_infrared0
.dev_attr
.attr
,
130 &iio_dev_attr_light_broadspectrum0
.dev_attr
.attr
,
134 static const struct attribute_group tsl2561_attribute_group
= {
135 .attrs
= tsl2561_attributes
,
138 static int tsl2561_initialize(struct tsl2561_state
*st
)
142 mutex_lock(&st
->command_buf_lock
);
143 st
->command_buf
->word
= 0;
144 st
->command_buf
->block
= 0;
145 st
->command_buf
->address
= TSL2561_CONTROL_REGISTER
;
146 err
= i2c_smbus_write_byte_data(st
->client
, *(char *)(st
->command_buf
),
147 TSL2561_CONT_REG_PWR_ON
);
151 st
->command_buf
->address
= TSL2561_INT_CONTROL_REGISTER
;
152 err
= i2c_smbus_write_byte_data(st
->client
, *(char *)(st
->command_buf
),
153 TSL2561_INT_REG_INT_TEST
);
156 mutex_unlock(&st
->command_buf_lock
);
161 static int tsl2561_powerdown(struct i2c_client
*client
)
164 struct tsl2561_command Command
= {
169 .address
= TSL2561_CONTROL_REGISTER
,
172 err
= i2c_smbus_write_byte_data(client
, *(char *)(&Command
),
173 TSL2561_CONT_REG_PWR_OFF
);
174 return (err
< 0) ? err
: 0;
176 static int __devinit
tsl2561_probe(struct i2c_client
*client
,
177 const struct i2c_device_id
*id
)
179 int ret
= 0, regdone
= 0;
180 struct tsl2561_state
*st
= kzalloc(sizeof(*st
), GFP_KERNEL
);
186 i2c_set_clientdata(client
, st
);
188 mutex_init(&st
->command_buf_lock
);
190 st
->command_buf
= kmalloc(sizeof(*st
->command_buf
), GFP_KERNEL
);
191 if (st
->command_buf
== NULL
) {
193 goto error_free_state
;
195 tsl2561_init_command_buf(st
->command_buf
);
197 st
->indio_dev
= iio_allocate_device();
198 if (st
->indio_dev
== NULL
) {
200 goto error_free_command_buf
;
202 st
->indio_dev
->attrs
= &tsl2561_attribute_group
;
203 st
->indio_dev
->dev
.parent
= &client
->dev
;
204 st
->indio_dev
->dev_data
= (void *)(st
);
205 st
->indio_dev
->driver_module
= THIS_MODULE
;
206 st
->indio_dev
->modes
= INDIO_DIRECT_MODE
;
207 ret
= iio_device_register(st
->indio_dev
);
209 goto error_free_iiodev
;
211 /* Intialize the chip */
212 ret
= tsl2561_initialize(st
);
214 goto error_unregister_iiodev
;
217 error_unregister_iiodev
:
220 iio_device_unregister(st
->indio_dev
);
222 iio_free_device(st
->indio_dev
);
223 error_free_command_buf
:
224 kfree(st
->command_buf
);
232 static int __devexit
tsl2561_remove(struct i2c_client
*client
)
234 struct tsl2561_state
*st
= i2c_get_clientdata(client
);
236 iio_device_unregister(st
->indio_dev
);
239 return tsl2561_powerdown(client
);
242 static const struct i2c_device_id tsl2561_id
[] = {
246 MODULE_DEVICE_TABLE(i2c
, tsl2561_id
);
249 static struct i2c_driver tsl2561_driver
= {
253 .probe
= tsl2561_probe
,
254 .remove
= __devexit_p(tsl2561_remove
),
255 .id_table
= tsl2561_id
,
258 static __init
int tsl2561_init(void)
260 return i2c_add_driver(&tsl2561_driver
);
262 module_init(tsl2561_init
);
264 static __exit
void tsl2561_exit(void)
266 i2c_del_driver(&tsl2561_driver
);
268 module_exit(tsl2561_exit
);
270 MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
271 MODULE_DESCRIPTION("TSL2561 light sensor driver");
272 MODULE_LICENSE("GPL");