Root/
1 | /* |
2 | * bh1780gli.c |
3 | * ROHM Ambient Light Sensor Driver |
4 | * |
5 | * Copyright (C) 2010 Texas Instruments |
6 | * Author: Hemanth V <hemanthv@ti.com> |
7 | * |
8 | * This program is free software; you can redistribute it and/or modify it |
9 | * under the terms of the GNU General Public License version 2 as published by |
10 | * the Free Software Foundation. |
11 | * |
12 | * This program is distributed in the hope that it will be useful, but WITHOUT |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | * more details. |
16 | * |
17 | * You should have received a copy of the GNU General Public License along with |
18 | * this program. If not, see <http://www.gnu.org/licenses/>. |
19 | */ |
20 | #include <linux/i2c.h> |
21 | #include <linux/slab.h> |
22 | #include <linux/mutex.h> |
23 | #include <linux/platform_device.h> |
24 | #include <linux/delay.h> |
25 | |
26 | #define BH1780_REG_CONTROL 0x80 |
27 | #define BH1780_REG_PARTID 0x8A |
28 | #define BH1780_REG_MANFID 0x8B |
29 | #define BH1780_REG_DLOW 0x8C |
30 | #define BH1780_REG_DHIGH 0x8D |
31 | |
32 | #define BH1780_REVMASK (0xf) |
33 | #define BH1780_POWMASK (0x3) |
34 | #define BH1780_POFF (0x0) |
35 | #define BH1780_PON (0x3) |
36 | |
37 | /* power on settling time in ms */ |
38 | #define BH1780_PON_DELAY 2 |
39 | |
40 | struct bh1780_data { |
41 | struct i2c_client *client; |
42 | int power_state; |
43 | /* lock for sysfs operations */ |
44 | struct mutex lock; |
45 | }; |
46 | |
47 | static int bh1780_write(struct bh1780_data *ddata, u8 reg, u8 val, char *msg) |
48 | { |
49 | int ret = i2c_smbus_write_byte_data(ddata->client, reg, val); |
50 | if (ret < 0) |
51 | dev_err(&ddata->client->dev, |
52 | "i2c_smbus_write_byte_data failed error %d\ |
53 | Register (%s)\n", ret, msg); |
54 | return ret; |
55 | } |
56 | |
57 | static int bh1780_read(struct bh1780_data *ddata, u8 reg, char *msg) |
58 | { |
59 | int ret = i2c_smbus_read_byte_data(ddata->client, reg); |
60 | if (ret < 0) |
61 | dev_err(&ddata->client->dev, |
62 | "i2c_smbus_read_byte_data failed error %d\ |
63 | Register (%s)\n", ret, msg); |
64 | return ret; |
65 | } |
66 | |
67 | static ssize_t bh1780_show_lux(struct device *dev, |
68 | struct device_attribute *attr, char *buf) |
69 | { |
70 | struct platform_device *pdev = to_platform_device(dev); |
71 | struct bh1780_data *ddata = platform_get_drvdata(pdev); |
72 | int lsb, msb; |
73 | |
74 | lsb = bh1780_read(ddata, BH1780_REG_DLOW, "DLOW"); |
75 | if (lsb < 0) |
76 | return lsb; |
77 | |
78 | msb = bh1780_read(ddata, BH1780_REG_DHIGH, "DHIGH"); |
79 | if (msb < 0) |
80 | return msb; |
81 | |
82 | return sprintf(buf, "%d\n", (msb << 8) | lsb); |
83 | } |
84 | |
85 | static ssize_t bh1780_show_power_state(struct device *dev, |
86 | struct device_attribute *attr, |
87 | char *buf) |
88 | { |
89 | struct platform_device *pdev = to_platform_device(dev); |
90 | struct bh1780_data *ddata = platform_get_drvdata(pdev); |
91 | int state; |
92 | |
93 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); |
94 | if (state < 0) |
95 | return state; |
96 | |
97 | return sprintf(buf, "%d\n", state & BH1780_POWMASK); |
98 | } |
99 | |
100 | static ssize_t bh1780_store_power_state(struct device *dev, |
101 | struct device_attribute *attr, |
102 | const char *buf, size_t count) |
103 | { |
104 | struct platform_device *pdev = to_platform_device(dev); |
105 | struct bh1780_data *ddata = platform_get_drvdata(pdev); |
106 | unsigned long val; |
107 | int error; |
108 | |
109 | error = strict_strtoul(buf, 0, &val); |
110 | if (error) |
111 | return error; |
112 | |
113 | if (val < BH1780_POFF || val > BH1780_PON) |
114 | return -EINVAL; |
115 | |
116 | mutex_lock(&ddata->lock); |
117 | |
118 | error = bh1780_write(ddata, BH1780_REG_CONTROL, val, "CONTROL"); |
119 | if (error < 0) { |
120 | mutex_unlock(&ddata->lock); |
121 | return error; |
122 | } |
123 | |
124 | msleep(BH1780_PON_DELAY); |
125 | ddata->power_state = val; |
126 | mutex_unlock(&ddata->lock); |
127 | |
128 | return count; |
129 | } |
130 | |
131 | static DEVICE_ATTR(lux, S_IRUGO, bh1780_show_lux, NULL); |
132 | |
133 | static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, |
134 | bh1780_show_power_state, bh1780_store_power_state); |
135 | |
136 | static struct attribute *bh1780_attributes[] = { |
137 | &dev_attr_power_state.attr, |
138 | &dev_attr_lux.attr, |
139 | NULL |
140 | }; |
141 | |
142 | static const struct attribute_group bh1780_attr_group = { |
143 | .attrs = bh1780_attributes, |
144 | }; |
145 | |
146 | static int __devinit bh1780_probe(struct i2c_client *client, |
147 | const struct i2c_device_id *id) |
148 | { |
149 | int ret; |
150 | struct bh1780_data *ddata = NULL; |
151 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
152 | |
153 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { |
154 | ret = -EIO; |
155 | goto err_op_failed; |
156 | } |
157 | |
158 | ddata = kzalloc(sizeof(struct bh1780_data), GFP_KERNEL); |
159 | if (ddata == NULL) { |
160 | ret = -ENOMEM; |
161 | goto err_op_failed; |
162 | } |
163 | |
164 | ddata->client = client; |
165 | i2c_set_clientdata(client, ddata); |
166 | |
167 | ret = bh1780_read(ddata, BH1780_REG_PARTID, "PART ID"); |
168 | if (ret < 0) |
169 | goto err_op_failed; |
170 | |
171 | dev_info(&client->dev, "Ambient Light Sensor, Rev : %d\n", |
172 | (ret & BH1780_REVMASK)); |
173 | |
174 | mutex_init(&ddata->lock); |
175 | |
176 | ret = sysfs_create_group(&client->dev.kobj, &bh1780_attr_group); |
177 | if (ret) |
178 | goto err_op_failed; |
179 | |
180 | return 0; |
181 | |
182 | err_op_failed: |
183 | kfree(ddata); |
184 | return ret; |
185 | } |
186 | |
187 | static int __devexit bh1780_remove(struct i2c_client *client) |
188 | { |
189 | struct bh1780_data *ddata; |
190 | |
191 | ddata = i2c_get_clientdata(client); |
192 | sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group); |
193 | kfree(ddata); |
194 | |
195 | return 0; |
196 | } |
197 | |
198 | #ifdef CONFIG_PM |
199 | static int bh1780_suspend(struct i2c_client *client, pm_message_t mesg) |
200 | { |
201 | struct bh1780_data *ddata; |
202 | int state, ret; |
203 | |
204 | ddata = i2c_get_clientdata(client); |
205 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); |
206 | if (state < 0) |
207 | return state; |
208 | |
209 | ddata->power_state = state & BH1780_POWMASK; |
210 | |
211 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, BH1780_POFF, |
212 | "CONTROL"); |
213 | |
214 | if (ret < 0) |
215 | return ret; |
216 | |
217 | return 0; |
218 | } |
219 | |
220 | static int bh1780_resume(struct i2c_client *client) |
221 | { |
222 | struct bh1780_data *ddata; |
223 | int state, ret; |
224 | |
225 | ddata = i2c_get_clientdata(client); |
226 | state = ddata->power_state; |
227 | |
228 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, state, |
229 | "CONTROL"); |
230 | |
231 | if (ret < 0) |
232 | return ret; |
233 | |
234 | return 0; |
235 | } |
236 | #else |
237 | #define bh1780_suspend NULL |
238 | #define bh1780_resume NULL |
239 | #endif /* CONFIG_PM */ |
240 | |
241 | static const struct i2c_device_id bh1780_id[] = { |
242 | { "bh1780", 0 }, |
243 | { }, |
244 | }; |
245 | |
246 | static struct i2c_driver bh1780_driver = { |
247 | .probe = bh1780_probe, |
248 | .remove = bh1780_remove, |
249 | .id_table = bh1780_id, |
250 | .suspend = bh1780_suspend, |
251 | .resume = bh1780_resume, |
252 | .driver = { |
253 | .name = "bh1780" |
254 | }, |
255 | }; |
256 | |
257 | static int __init bh1780_init(void) |
258 | { |
259 | return i2c_add_driver(&bh1780_driver); |
260 | } |
261 | |
262 | static void __exit bh1780_exit(void) |
263 | { |
264 | i2c_del_driver(&bh1780_driver); |
265 | } |
266 | |
267 | module_init(bh1780_init) |
268 | module_exit(bh1780_exit) |
269 | |
270 | MODULE_DESCRIPTION("BH1780GLI Ambient Light Sensor Driver"); |
271 | MODULE_LICENSE("GPL"); |
272 | MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); |
273 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9