Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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