upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / staging / iio / light / bh1721.c
1 /*
2  *  Copyright (C) 2010 Samsung Electronics
3  *  Hwansoon sung <hs2704.sung@samsung.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation.
8  */
9
10 #include <linux/module.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/platform_device.h>
14 #include <linux/workqueue.h>
15 #include <linux/mutex.h>
16 #include <linux/err.h>
17 #include <linux/i2c.h>
18 #include <linux/delay.h>
19 #include <linux/gpio.h>
20 #include <linux/completion.h>
21 #include <linux/pm_runtime.h>
22 #include <linux/slab.h>
23
24 #include "../iio.h"
25 #include "../sysfs.h"
26 #include "bh1721.h"
27
28 #define BH1721_MAX_LUX_TABLE            10
29
30 const unsigned char POWERDOWN   = 0x00;
31 const unsigned char POWERON   = 0x01;
32 const unsigned char AUTO_RESOLUTION_1   = 0x10;
33 const unsigned char AUTO_RESOLUTION_2  = 0x20;
34 const unsigned char H_RESOLUTION_1      = 0x12;
35 const unsigned char H_RESOLUTION_2  = 0x22;
36 const unsigned char L_RESOLUTION_1      = 0x13;
37 const unsigned char L_RESOLUTION_2  = 0x23;
38 const unsigned char L_RESOLUTION_3      = 0x16;
39 const unsigned char L_RESOLUTION_4  = 0x26;
40
41 enum {
42         INPUT,
43         LEVEL,
44 };
45
46 static int lux_table[BH1721_MAX_LUX_TABLE] = {
47         1, 165, 288, 497, 869, 1532, 2692, 4692, 8280, 100000,
48 };
49
50 static int bh1721_write_command(struct i2c_client *client, const char *command)
51 {
52                   return i2c_master_send(client, command, NUM_OF_BYTES_WRITE);
53 }
54
55 static int bh1721_read_value(struct i2c_client *client, char *buf)
56 {
57                   return i2c_master_recv(client, buf, NUM_OF_BYTES_READ);
58 }
59
60 /* initial state is power down mode after vcc supply
61  * power on command is possible to omit
62  * there are 3mode: HIGH_RES, LOW_RES, AUTO_RES
63  * IN AUTO_RES, if current illuminance is more than 4000 Lx,
64  * data is output at LOW_RES mode and vice versa
65 */
66
67 #define BH1721_INPUT(set_mode, name)                            \
68 static ssize_t bh1721_store_##name(struct device *dev,          \
69                         struct device_attribute *attr, const char *buf, \
70                         size_t count)           \
71 {                                                                       \
72         struct iio_dev *indio_dev = dev_get_drvdata(dev);               \
73         struct bh1721_chip *bc = indio_dev->dev_data;                   \
74         if (!count)                                                     \
75                 return -EINVAL;                                         \
76         bc->mode = set_mode;    \
77         return count;   \
78 }       \
79 static DEVICE_ATTR(name, S_IWUGO, NULL, bh1721_store_##name); \
80
81 #define BH1721_OUTPUT_MODE(name)        \
82 static ssize_t bh1721_show_##name(struct device *dev,           \
83                         struct device_attribute *attr, char *buf) \
84 {                                                                       \
85         struct iio_dev *indio_dev = dev_get_drvdata(dev);               \
86         struct bh1721_chip *bc = indio_dev->dev_data;                   \
87         return sprintf(buf, "%d\n", bc->mode);          \
88 }       \
89 static DEVICE_ATTR(name, S_IRUGO, bh1721_show_##name, NULL); \
90
91 #define BH1721_OUTPUT(name, set_value_type)                             \
92 static ssize_t bh1721_show_##name(struct device *dev,           \
93                         struct device_attribute *attr, char *buf)       \
94 {                                                                       \
95         struct iio_dev *indio_dev = dev_get_drvdata(dev);               \
96         struct bh1721_chip *bc = indio_dev->dev_data;                   \
97         unsigned int result;            \
98         int gpio = bc->pdata->gpio; \
99         int level = 0, i; \
100         if (bc->power_control)  \
101                 bc->power_control(ON);  \
102         if (bc->reset)  \
103                 bc->reset(gpio, ON);    \
104         else    \
105                 printk(KERN_INFO "bh1721 reset func doesn't exist.\n"); \
106         bh1721_write_command(bc->client, &AUTO_RESOLUTION_1); \
107                                                 \
108         switch (bc->mode) {     \
109         case AUTO_RES:  \
110                 bh1721_write_command(bc->client, &AUTO_RESOLUTION_1); \
111                 msleep(MAX_AUTO_RES_MEASURE_TIME);              \
112                 break;  \
113         case HIGH_RES:  \
114                 bh1721_write_command(bc->client, &H_RESOLUTION_2); \
115                 msleep(MAX_HIGH_RES_MEASURE_TIME);              \
116                 break;  \
117         case LOW_RES:   \
118                 bh1721_write_command(bc->client, &L_RESOLUTION_2); \
119                 msleep(MAX_LOW_RES_MEASURE_TIME);               \
120                 break;  \
121         default:        \
122                 return -EINVAL; \
123         }       \
124         bh1721_read_value(bc->client, bc->illuminance_data);    \
125         bh1721_write_command(bc->client, &POWERDOWN);   \
126         if (bc->reset)  \
127                 bc->reset(gpio, OFF);   \
128         else    \
129                 printk(KERN_INFO "bh1721 reset func doesn't exist.\n"); \
130         if (bc->power_control)  \
131                 bc->power_control(OFF); \
132         if (set_value_type == INPUT) \
133                 result = bc->illuminance_data[0] << NUM_OF_BYTE |       \
134                   bc->illuminance_data[1]*10/12;        \
135         else {\
136                 result = bc->illuminance_data[0] << NUM_OF_BYTE |       \
137                   bc->illuminance_data[1]*10/12;        \
138                 for (i = 0; i < BH1721_MAX_LUX_TABLE; i++) { \
139                         if (lux_table[i] > result) {\
140                                 level = i; \
141                                 break; \
142                         } \
143                 } \
144         result = level;\
145         } \
146         return sprintf(buf, "%d\n", result);                            \
147 }                                                                       \
148 static DEVICE_ATTR(name, S_IRUGO, bh1721_show_##name, NULL); \
149
150 static ssize_t bh1721_show_name(struct device *dev,
151                         struct device_attribute *attr,
152                         char *buf)
153 {
154         struct iio_dev *indio_dev = dev_get_drvdata(dev);
155         struct bh1721_chip *chip = indio_dev->dev_data;
156         return sprintf(buf, "%s\n", chip->client->name);
157 }
158
159 static DEVICE_ATTR(name, S_IRUGO, bh1721_show_name, NULL);
160
161 BH1721_INPUT(HIGH_RES, high_res_mode);
162 BH1721_INPUT(LOW_RES, low_res_mode);
163 BH1721_INPUT(AUTO_RES, auto_res_mode);
164
165 BH1721_OUTPUT(illuminance0_input, INPUT);
166 BH1721_OUTPUT(level, LEVEL);
167 BH1721_OUTPUT_MODE(current_mode);
168
169 static struct attribute *bh1721_attributes[] = {
170         &dev_attr_high_res_mode.attr,
171         &dev_attr_low_res_mode.attr,
172         &dev_attr_auto_res_mode.attr,
173         &dev_attr_current_mode.attr,
174         &dev_attr_illuminance0_input.attr,
175         &dev_attr_level.attr,
176         &dev_attr_name.attr,
177         NULL
178 };
179
180 static const struct attribute_group bh1721_group = {
181         .attrs = bh1721_attributes,
182 };
183
184 static int bh1721_probe(struct i2c_client *client,
185                         const struct i2c_device_id *id)
186 {
187         struct bh1721_chip *bc;
188         int ret = -1;
189
190         bc = kzalloc(sizeof(struct bh1721_chip), GFP_KERNEL);
191         if (!bc)
192                 return -ENOMEM;
193
194         bc->indio_dev = iio_allocate_device();
195         if (!bc->indio_dev) {
196                 ret = -ENOMEM;
197                 goto error_allocate_iio_device;
198         }
199
200         bc->client = client;
201         i2c_set_clientdata(client, bc);
202
203         bc->indio_dev->attrs = &bh1721_group;
204         bc->indio_dev->dev.parent = &client->dev;
205         bc->indio_dev->dev_data = bc;
206         bc->indio_dev->driver_module = THIS_MODULE;
207         bc->indio_dev->modes = INDIO_DIRECT_MODE;
208
209         bc->mode = HIGH_RES; /* default mode */
210
211         ret = iio_device_register(bc->indio_dev);
212         if (ret)
213                 goto error_register_iio;
214
215         bc->pdata = client->dev.platform_data;
216
217         if (bc->pdata->reset)
218                 bc->reset = bc->pdata->reset;
219         else
220                 printk(KERN_INFO "bh1721 reset func doesn't exist.\n");
221         
222         if (bc->pdata->power_control)
223                 bc->power_control = bc->pdata->power_control;
224         else
225                 printk(KERN_INFO "bh1721 power_controlt func doesn't exist.\n");
226
227         return 0;
228
229 error_allocate_iio_device:
230         return ret;
231 error_register_iio:
232         iio_free_device(bc->indio_dev);
233         return ret;
234 }
235
236 static int __devexit bh1721_remove(struct i2c_client *client)
237 {
238         struct bh1721_chip *bc = i2c_get_clientdata(client);
239
240         iio_device_unregister(bc->indio_dev);
241         iio_free_device(bc->indio_dev);
242         kfree(bc);
243
244         return 0;
245 }
246
247 #ifdef CONFIG_PM
248 static int bh1721_suspend(struct device *dev)
249 {
250         struct i2c_client *client = to_i2c_client(dev);
251         struct bh1721_chip *bc = i2c_get_clientdata(client);
252         int gpio = bc->pdata->gpio;
253
254         if (bc->reset)
255                 bc->reset(gpio, OFF);
256
257         return 0;
258 }
259
260 static int bh1721_resume(struct device *dev)
261 {
262         struct i2c_client *client = to_i2c_client(dev);
263         struct bh1721_chip *bc = i2c_get_clientdata(client);
264         int gpio = bc->pdata->gpio;
265
266         if (bc->reset)
267                 bc->reset(gpio, ON);
268
269         return 0;
270 }
271
272 static const struct dev_pm_ops bh1721_dev_pm_ops = {
273         .suspend        = bh1721_suspend,
274         .resume  = bh1721_resume,
275 };
276
277 #define BH1721_DEV_PM_OPS       (&bh1721_dev_pm_ops)
278 #else
279 #define BH1721_DEV_PM_OPS       NULL
280 #endif
281
282 static const struct i2c_device_id bh1721_id[] = {
283         {"bh1721", 0},
284         {}
285 };
286
287 MODULE_DEVICE_TABLE(i2c, bh1721_id);
288
289 static struct i2c_driver bh1721_i2c_driver = {
290         .driver = {
291                    .name        = "bh1721",
292                    .pm  = BH1721_DEV_PM_OPS,
293         },
294         .probe = bh1721_probe,
295         .remove = __devexit_p(bh1721_remove),
296         .id_table = bh1721_id,
297 };
298
299 static int __init bh1721_init(void)
300 {
301         return i2c_add_driver(&bh1721_i2c_driver);
302 }
303
304 module_init(bh1721_init);
305
306 static void __exit bh1721_exit(void)
307 {
308         i2c_del_driver(&bh1721_i2c_driver);
309 }
310
311 module_exit(bh1721_exit);
312
313 MODULE_AUTHOR("Hwan soon sung <hs2704.sung@samsung.com>");
314 MODULE_DESCRIPTION("bh1721 light sensor driver");
315 MODULE_LICENSE("GPL");