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 | #include <linux/module.h> |
26 | |
27 | #define BH1780_REG_CONTROL 0x80 |
28 | #define BH1780_REG_PARTID 0x8A |
29 | #define BH1780_REG_MANFID 0x8B |
30 | #define BH1780_REG_DLOW 0x8C |
31 | #define BH1780_REG_DHIGH 0x8D |
32 | |
33 | #define BH1780_REVMASK (0xf) |
34 | #define BH1780_POWMASK (0x3) |
35 | #define BH1780_POFF (0x0) |
36 | #define BH1780_PON (0x3) |
37 | |
38 | /* power on settling time in ms */ |
39 | #define BH1780_PON_DELAY 2 |
40 | |
41 | struct bh1780_data { |
42 | struct i2c_client *client; |
43 | int power_state; |
44 | /* lock for sysfs operations */ |
45 | struct mutex lock; |
46 | }; |
47 | |
48 | static int bh1780_write(struct bh1780_data *ddata, u8 reg, u8 val, char *msg) |
49 | { |
50 | int ret = i2c_smbus_write_byte_data(ddata->client, reg, val); |
51 | if (ret < 0) |
52 | dev_err(&ddata->client->dev, |
53 | "i2c_smbus_write_byte_data failed error %d Register (%s)\n", |
54 | ret, msg); |
55 | return ret; |
56 | } |
57 | |
58 | static int bh1780_read(struct bh1780_data *ddata, u8 reg, char *msg) |
59 | { |
60 | int ret = i2c_smbus_read_byte_data(ddata->client, reg); |
61 | if (ret < 0) |
62 | dev_err(&ddata->client->dev, |
63 | "i2c_smbus_read_byte_data failed error %d Register (%s)\n", |
64 | ret, msg); |
65 | return ret; |
66 | } |
67 | |
68 | static ssize_t bh1780_show_lux(struct device *dev, |
69 | struct device_attribute *attr, char *buf) |
70 | { |
71 | struct platform_device *pdev = to_platform_device(dev); |
72 | struct bh1780_data *ddata = platform_get_drvdata(pdev); |
73 | int lsb, msb; |
74 | |
75 | lsb = bh1780_read(ddata, BH1780_REG_DLOW, "DLOW"); |
76 | if (lsb < 0) |
77 | return lsb; |
78 | |
79 | msb = bh1780_read(ddata, BH1780_REG_DHIGH, "DHIGH"); |
80 | if (msb < 0) |
81 | return msb; |
82 | |
83 | return sprintf(buf, "%d\n", (msb << 8) | lsb); |
84 | } |
85 | |
86 | static ssize_t bh1780_show_power_state(struct device *dev, |
87 | struct device_attribute *attr, |
88 | char *buf) |
89 | { |
90 | struct platform_device *pdev = to_platform_device(dev); |
91 | struct bh1780_data *ddata = platform_get_drvdata(pdev); |
92 | int state; |
93 | |
94 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); |
95 | if (state < 0) |
96 | return state; |
97 | |
98 | return sprintf(buf, "%d\n", state & BH1780_POWMASK); |
99 | } |
100 | |
101 | static ssize_t bh1780_store_power_state(struct device *dev, |
102 | struct device_attribute *attr, |
103 | const char *buf, size_t count) |
104 | { |
105 | struct platform_device *pdev = to_platform_device(dev); |
106 | struct bh1780_data *ddata = platform_get_drvdata(pdev); |
107 | unsigned long val; |
108 | int error; |
109 | |
110 | error = strict_strtoul(buf, 0, &val); |
111 | if (error) |
112 | return error; |
113 | |
114 | if (val < BH1780_POFF || val > BH1780_PON) |
115 | return -EINVAL; |
116 | |
117 | mutex_lock(&ddata->lock); |
118 | |
119 | error = bh1780_write(ddata, BH1780_REG_CONTROL, val, "CONTROL"); |
120 | if (error < 0) { |
121 | mutex_unlock(&ddata->lock); |
122 | return error; |
123 | } |
124 | |
125 | msleep(BH1780_PON_DELAY); |
126 | ddata->power_state = val; |
127 | mutex_unlock(&ddata->lock); |
128 | |
129 | return count; |
130 | } |
131 | |
132 | static DEVICE_ATTR(lux, S_IRUGO, bh1780_show_lux, NULL); |
133 | |
134 | static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO, |
135 | bh1780_show_power_state, bh1780_store_power_state); |
136 | |
137 | static struct attribute *bh1780_attributes[] = { |
138 | &dev_attr_power_state.attr, |
139 | &dev_attr_lux.attr, |
140 | NULL |
141 | }; |
142 | |
143 | static const struct attribute_group bh1780_attr_group = { |
144 | .attrs = bh1780_attributes, |
145 | }; |
146 | |
147 | static int __devinit bh1780_probe(struct i2c_client *client, |
148 | const struct i2c_device_id *id) |
149 | { |
150 | int ret; |
151 | struct bh1780_data *ddata = NULL; |
152 | struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); |
153 | |
154 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { |
155 | ret = -EIO; |
156 | goto err_op_failed; |
157 | } |
158 | |
159 | ddata = kzalloc(sizeof(struct bh1780_data), GFP_KERNEL); |
160 | if (ddata == NULL) { |
161 | ret = -ENOMEM; |
162 | goto err_op_failed; |
163 | } |
164 | |
165 | ddata->client = client; |
166 | i2c_set_clientdata(client, ddata); |
167 | |
168 | ret = bh1780_read(ddata, BH1780_REG_PARTID, "PART ID"); |
169 | if (ret < 0) |
170 | goto err_op_failed; |
171 | |
172 | dev_info(&client->dev, "Ambient Light Sensor, Rev : %d\n", |
173 | (ret & BH1780_REVMASK)); |
174 | |
175 | mutex_init(&ddata->lock); |
176 | |
177 | ret = sysfs_create_group(&client->dev.kobj, &bh1780_attr_group); |
178 | if (ret) |
179 | goto err_op_failed; |
180 | |
181 | return 0; |
182 | |
183 | err_op_failed: |
184 | kfree(ddata); |
185 | return ret; |
186 | } |
187 | |
188 | static int __devexit bh1780_remove(struct i2c_client *client) |
189 | { |
190 | struct bh1780_data *ddata; |
191 | |
192 | ddata = i2c_get_clientdata(client); |
193 | sysfs_remove_group(&client->dev.kobj, &bh1780_attr_group); |
194 | kfree(ddata); |
195 | |
196 | return 0; |
197 | } |
198 | |
199 | #ifdef CONFIG_PM |
200 | static int bh1780_suspend(struct device *dev) |
201 | { |
202 | struct bh1780_data *ddata; |
203 | int state, ret; |
204 | struct i2c_client *client = to_i2c_client(dev); |
205 | |
206 | ddata = i2c_get_clientdata(client); |
207 | state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL"); |
208 | if (state < 0) |
209 | return state; |
210 | |
211 | ddata->power_state = state & BH1780_POWMASK; |
212 | |
213 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, BH1780_POFF, |
214 | "CONTROL"); |
215 | |
216 | if (ret < 0) |
217 | return ret; |
218 | |
219 | return 0; |
220 | } |
221 | |
222 | static int bh1780_resume(struct device *dev) |
223 | { |
224 | struct bh1780_data *ddata; |
225 | int state, ret; |
226 | struct i2c_client *client = to_i2c_client(dev); |
227 | |
228 | ddata = i2c_get_clientdata(client); |
229 | state = ddata->power_state; |
230 | ret = bh1780_write(ddata, BH1780_REG_CONTROL, state, |
231 | "CONTROL"); |
232 | |
233 | if (ret < 0) |
234 | return ret; |
235 | |
236 | return 0; |
237 | } |
238 | static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume); |
239 | #define BH1780_PMOPS (&bh1780_pm) |
240 | #else |
241 | #define BH1780_PMOPS NULL |
242 | #endif /* CONFIG_PM */ |
243 | |
244 | static const struct i2c_device_id bh1780_id[] = { |
245 | { "bh1780", 0 }, |
246 | { }, |
247 | }; |
248 | |
249 | static struct i2c_driver bh1780_driver = { |
250 | .probe = bh1780_probe, |
251 | .remove = __devexit_p(bh1780_remove), |
252 | .id_table = bh1780_id, |
253 | .driver = { |
254 | .name = "bh1780", |
255 | .pm = BH1780_PMOPS, |
256 | }, |
257 | }; |
258 | |
259 | module_i2c_driver(bh1780_driver); |
260 | |
261 | MODULE_DESCRIPTION("BH1780GLI Ambient Light Sensor Driver"); |
262 | MODULE_LICENSE("GPL"); |
263 | MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>"); |
264 |
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