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.11 239 lines 5.7 kB view raw
1/* 2 * isl29020.c - Intersil ALS Driver 3 * 4 * Copyright (C) 2008 Intel Corp 5 * 6 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; version 2 of the License. 11 * 12 * This program is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 21 * 22 * Data sheet at: http://www.intersil.com/data/fn/fn6505.pdf 23 */ 24 25#include <linux/module.h> 26#include <linux/init.h> 27#include <linux/slab.h> 28#include <linux/i2c.h> 29#include <linux/err.h> 30#include <linux/delay.h> 31#include <linux/sysfs.h> 32#include <linux/pm_runtime.h> 33 34static DEFINE_MUTEX(mutex); 35 36static ssize_t als_sensing_range_show(struct device *dev, 37 struct device_attribute *attr, char *buf) 38{ 39 struct i2c_client *client = to_i2c_client(dev); 40 int val; 41 42 val = i2c_smbus_read_byte_data(client, 0x00); 43 44 if (val < 0) 45 return val; 46 return sprintf(buf, "%d000\n", 1 << (2 * (val & 3))); 47 48} 49 50static ssize_t als_lux_input_data_show(struct device *dev, 51 struct device_attribute *attr, char *buf) 52{ 53 struct i2c_client *client = to_i2c_client(dev); 54 int ret_val, val; 55 unsigned long int lux; 56 int temp; 57 58 pm_runtime_get_sync(dev); 59 msleep(100); 60 61 mutex_lock(&mutex); 62 temp = i2c_smbus_read_byte_data(client, 0x02); /* MSB data */ 63 if (temp < 0) { 64 pm_runtime_put_sync(dev); 65 mutex_unlock(&mutex); 66 return temp; 67 } 68 69 ret_val = i2c_smbus_read_byte_data(client, 0x01); /* LSB data */ 70 mutex_unlock(&mutex); 71 72 if (ret_val < 0) { 73 pm_runtime_put_sync(dev); 74 return ret_val; 75 } 76 77 ret_val |= temp << 8; 78 val = i2c_smbus_read_byte_data(client, 0x00); 79 pm_runtime_put_sync(dev); 80 if (val < 0) 81 return val; 82 lux = ((((1 << (2 * (val & 3))))*1000) * ret_val) / 65536; 83 return sprintf(buf, "%ld\n", lux); 84} 85 86static ssize_t als_sensing_range_store(struct device *dev, 87 struct device_attribute *attr, const char *buf, size_t count) 88{ 89 struct i2c_client *client = to_i2c_client(dev); 90 int ret_val; 91 unsigned long val; 92 93 ret_val = kstrtoul(buf, 10, &val); 94 if (ret_val) 95 return ret_val; 96 97 if (val < 1 || val > 64000) 98 return -EINVAL; 99 100 /* Pick the smallest sensor range that will meet our requirements */ 101 if (val <= 1000) 102 val = 1; 103 else if (val <= 4000) 104 val = 2; 105 else if (val <= 16000) 106 val = 3; 107 else 108 val = 4; 109 110 ret_val = i2c_smbus_read_byte_data(client, 0x00); 111 if (ret_val < 0) 112 return ret_val; 113 114 ret_val &= 0xFC; /*reset the bit before setting them */ 115 ret_val |= val - 1; 116 ret_val = i2c_smbus_write_byte_data(client, 0x00, ret_val); 117 118 if (ret_val < 0) 119 return ret_val; 120 return count; 121} 122 123static void als_set_power_state(struct i2c_client *client, int enable) 124{ 125 int ret_val; 126 127 ret_val = i2c_smbus_read_byte_data(client, 0x00); 128 if (ret_val < 0) 129 return; 130 131 if (enable) 132 ret_val |= 0x80; 133 else 134 ret_val &= 0x7F; 135 136 i2c_smbus_write_byte_data(client, 0x00, ret_val); 137} 138 139static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR, 140 als_sensing_range_show, als_sensing_range_store); 141static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux_input_data_show, NULL); 142 143static struct attribute *mid_att_als[] = { 144 &dev_attr_lux0_sensor_range.attr, 145 &dev_attr_lux0_input.attr, 146 NULL 147}; 148 149static struct attribute_group m_als_gr = { 150 .name = "isl29020", 151 .attrs = mid_att_als 152}; 153 154static int als_set_default_config(struct i2c_client *client) 155{ 156 int retval; 157 158 retval = i2c_smbus_write_byte_data(client, 0x00, 0xc0); 159 if (retval < 0) { 160 dev_err(&client->dev, "default write failed."); 161 return retval; 162 } 163 return 0; 164} 165 166static int isl29020_probe(struct i2c_client *client, 167 const struct i2c_device_id *id) 168{ 169 int res; 170 171 res = als_set_default_config(client); 172 if (res < 0) 173 return res; 174 175 res = sysfs_create_group(&client->dev.kobj, &m_als_gr); 176 if (res) { 177 dev_err(&client->dev, "isl29020: device create file failed\n"); 178 return res; 179 } 180 dev_info(&client->dev, "%s isl29020: ALS chip found\n", client->name); 181 als_set_power_state(client, 0); 182 pm_runtime_enable(&client->dev); 183 return res; 184} 185 186static int isl29020_remove(struct i2c_client *client) 187{ 188 sysfs_remove_group(&client->dev.kobj, &m_als_gr); 189 return 0; 190} 191 192static struct i2c_device_id isl29020_id[] = { 193 { "isl29020", 0 }, 194 { } 195}; 196 197MODULE_DEVICE_TABLE(i2c, isl29020_id); 198 199#ifdef CONFIG_PM 200 201static int isl29020_runtime_suspend(struct device *dev) 202{ 203 struct i2c_client *client = to_i2c_client(dev); 204 als_set_power_state(client, 0); 205 return 0; 206} 207 208static int isl29020_runtime_resume(struct device *dev) 209{ 210 struct i2c_client *client = to_i2c_client(dev); 211 als_set_power_state(client, 1); 212 return 0; 213} 214 215static const struct dev_pm_ops isl29020_pm_ops = { 216 .runtime_suspend = isl29020_runtime_suspend, 217 .runtime_resume = isl29020_runtime_resume, 218}; 219 220#define ISL29020_PM_OPS (&isl29020_pm_ops) 221#else /* CONFIG_PM */ 222#define ISL29020_PM_OPS NULL 223#endif /* CONFIG_PM */ 224 225static struct i2c_driver isl29020_driver = { 226 .driver = { 227 .name = "isl29020", 228 .pm = ISL29020_PM_OPS, 229 }, 230 .probe = isl29020_probe, 231 .remove = isl29020_remove, 232 .id_table = isl29020_id, 233}; 234 235module_i2c_driver(isl29020_driver); 236 237MODULE_AUTHOR("Kalhan Trisal <kalhan.trisal@intel.com>"); 238MODULE_DESCRIPTION("Intersil isl29020 ALS Driver"); 239MODULE_LICENSE("GPL v2");