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 
bh1780_write(struct bh1780_data * ddata,u8 reg,u8 val,char * msg)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 
bh1780_read(struct bh1780_data * ddata,u8 reg,char * msg)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 
bh1780_show_lux(struct device * dev,struct device_attribute * attr,char * buf)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 
bh1780_show_power_state(struct device * dev,struct device_attribute * attr,char * buf)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 
bh1780_store_power_state(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)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 
bh1780_probe(struct i2c_client * client,const struct i2c_device_id * id)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 
bh1780_remove(struct i2c_client * client)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
bh1780_suspend(struct device * dev)199 static int bh1780_suspend(struct device *dev)
200 {
201 	struct bh1780_data *ddata;
202 	int state, ret;
203 	struct i2c_client *client = to_i2c_client(dev);
204 
205 	ddata = i2c_get_clientdata(client);
206 	state = bh1780_read(ddata, BH1780_REG_CONTROL, "CONTROL");
207 	if (state < 0)
208 		return state;
209 
210 	ddata->power_state = state & BH1780_POWMASK;
211 
212 	ret = bh1780_write(ddata, BH1780_REG_CONTROL, BH1780_POFF,
213 				"CONTROL");
214 
215 	if (ret < 0)
216 		return ret;
217 
218 	return 0;
219 }
220 
bh1780_resume(struct device * dev)221 static int bh1780_resume(struct device *dev)
222 {
223 	struct bh1780_data *ddata;
224 	int state, ret;
225 	struct i2c_client *client = to_i2c_client(dev);
226 
227 	ddata = i2c_get_clientdata(client);
228 	state = ddata->power_state;
229 	ret = bh1780_write(ddata, BH1780_REG_CONTROL, state,
230 				"CONTROL");
231 
232 	if (ret < 0)
233 		return ret;
234 
235 	return 0;
236 }
237 static SIMPLE_DEV_PM_OPS(bh1780_pm, bh1780_suspend, bh1780_resume);
238 #define BH1780_PMOPS (&bh1780_pm)
239 #else
240 #define BH1780_PMOPS NULL
241 #endif /* CONFIG_PM */
242 
243 static const struct i2c_device_id bh1780_id[] = {
244 	{ "bh1780", 0 },
245 	{ },
246 };
247 
248 static struct i2c_driver bh1780_driver = {
249 	.probe		= bh1780_probe,
250 	.remove		= bh1780_remove,
251 	.id_table	= bh1780_id,
252 	.driver = {
253 		.name = "bh1780",
254 		.pm	= BH1780_PMOPS,
255 },
256 };
257 
bh1780_init(void)258 static int __init bh1780_init(void)
259 {
260 	return i2c_add_driver(&bh1780_driver);
261 }
262 
bh1780_exit(void)263 static void __exit bh1780_exit(void)
264 {
265 	i2c_del_driver(&bh1780_driver);
266 }
267 
268 module_init(bh1780_init)
269 module_exit(bh1780_exit)
270 
271 MODULE_DESCRIPTION("BH1780GLI Ambient Light Sensor Driver");
272 MODULE_LICENSE("GPL");
273 MODULE_AUTHOR("Hemanth V <hemanthv@ti.com>");
274