linux/drivers/misc/apds9802als.c
<<
>>
Prefs
   1/*
   2 * apds9802als.c - apds9802  ALS Driver
   3 *
   4 * Copyright (C) 2009 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 */
  23
  24#include <linux/module.h>
  25#include <linux/init.h>
  26#include <linux/slab.h>
  27#include <linux/i2c.h>
  28#include <linux/err.h>
  29#include <linux/delay.h>
  30#include <linux/mutex.h>
  31#include <linux/sysfs.h>
  32#include <linux/pm_runtime.h>
  33
  34#define ALS_MIN_RANGE_VAL 1
  35#define ALS_MAX_RANGE_VAL 2
  36#define POWER_STA_ENABLE 1
  37#define POWER_STA_DISABLE 0
  38
  39#define DRIVER_NAME "apds9802als"
  40
  41struct als_data {
  42        struct mutex mutex;
  43};
  44
  45static ssize_t als_sensing_range_show(struct device *dev,
  46                        struct device_attribute *attr,  char *buf)
  47{
  48        struct i2c_client *client = to_i2c_client(dev);
  49        int  val;
  50
  51        val = i2c_smbus_read_byte_data(client, 0x81);
  52        if (val < 0)
  53                return val;
  54        if (val & 1)
  55                return sprintf(buf, "4095\n");
  56        else
  57                return sprintf(buf, "65535\n");
  58}
  59
  60static int als_wait_for_data_ready(struct device *dev)
  61{
  62        struct i2c_client *client = to_i2c_client(dev);
  63        int ret;
  64        int retry = 10;
  65
  66        do {
  67                msleep(30);
  68                ret = i2c_smbus_read_byte_data(client, 0x86);
  69        } while (!(ret & 0x80) && retry--);
  70
  71        if (!retry) {
  72                dev_warn(dev, "timeout waiting for data ready\n");
  73                return -ETIMEDOUT;
  74        }
  75
  76        return 0;
  77}
  78
  79static ssize_t als_lux0_input_data_show(struct device *dev,
  80                        struct device_attribute *attr, char *buf)
  81{
  82        struct i2c_client *client = to_i2c_client(dev);
  83        struct als_data *data = i2c_get_clientdata(client);
  84        int ret_val;
  85        int temp;
  86
  87        /* Protect against parallel reads */
  88        pm_runtime_get_sync(dev);
  89        mutex_lock(&data->mutex);
  90
  91        /* clear EOC interrupt status */
  92        i2c_smbus_write_byte(client, 0x40);
  93        /* start measurement */
  94        temp = i2c_smbus_read_byte_data(client, 0x81);
  95        i2c_smbus_write_byte_data(client, 0x81, temp | 0x08);
  96
  97        ret_val = als_wait_for_data_ready(dev);
  98        if (ret_val < 0)
  99                goto failed;
 100
 101        temp = i2c_smbus_read_byte_data(client, 0x8C); /* LSB data */
 102        if (temp < 0) {
 103                ret_val = temp;
 104                goto failed;
 105        }
 106        ret_val = i2c_smbus_read_byte_data(client, 0x8D); /* MSB data */
 107        if (ret_val < 0)
 108                goto failed;
 109
 110        mutex_unlock(&data->mutex);
 111        pm_runtime_put_sync(dev);
 112
 113        temp = (ret_val << 8) | temp;
 114        return sprintf(buf, "%d\n", temp);
 115failed:
 116        mutex_unlock(&data->mutex);
 117        pm_runtime_put_sync(dev);
 118        return ret_val;
 119}
 120
 121static ssize_t als_sensing_range_store(struct device *dev,
 122                struct device_attribute *attr, const  char *buf, size_t count)
 123{
 124        struct i2c_client *client = to_i2c_client(dev);
 125        struct als_data *data = i2c_get_clientdata(client);
 126        int ret_val;
 127        unsigned long val;
 128
 129        if (strict_strtoul(buf, 10, &val))
 130                return -EINVAL;
 131
 132        if (val < 4096)
 133                val = 1;
 134        else if (val < 65536)
 135                val = 2;
 136        else
 137                return -ERANGE;
 138
 139        pm_runtime_get_sync(dev);
 140
 141        /* Make sure nobody else reads/modifies/writes 0x81 while we
 142           are active */
 143        mutex_lock(&data->mutex);
 144
 145        ret_val = i2c_smbus_read_byte_data(client, 0x81);
 146        if (ret_val < 0)
 147                goto fail;
 148
 149        /* Reset the bits before setting them */
 150        ret_val = ret_val & 0xFA;
 151
 152        if (val == 1) /* Setting detection range up to 4k LUX */
 153                ret_val = (ret_val | 0x01);
 154        else /* Setting detection range up to 64k LUX*/
 155                ret_val = (ret_val | 0x00);
 156
 157        ret_val = i2c_smbus_write_byte_data(client, 0x81, ret_val);
 158
 159        if (ret_val >= 0) {
 160                /* All OK */
 161                mutex_unlock(&data->mutex);
 162                pm_runtime_put_sync(dev);
 163                return count;
 164        }
 165fail:
 166        mutex_unlock(&data->mutex);
 167        pm_runtime_put_sync(dev);
 168        return ret_val;
 169}
 170
 171static int als_set_power_state(struct i2c_client *client, bool on_off)
 172{
 173        int ret_val;
 174        struct als_data *data = i2c_get_clientdata(client);
 175
 176        mutex_lock(&data->mutex);
 177        ret_val = i2c_smbus_read_byte_data(client, 0x80);
 178        if (ret_val < 0)
 179                goto fail;
 180        if (on_off)
 181                ret_val = ret_val | 0x01;
 182        else
 183                ret_val = ret_val & 0xFE;
 184        ret_val = i2c_smbus_write_byte_data(client, 0x80, ret_val);
 185fail:
 186        mutex_unlock(&data->mutex);
 187        return ret_val;
 188}
 189
 190static DEVICE_ATTR(lux0_sensor_range, S_IRUGO | S_IWUSR,
 191        als_sensing_range_show, als_sensing_range_store);
 192static DEVICE_ATTR(lux0_input, S_IRUGO, als_lux0_input_data_show, NULL);
 193
 194static struct attribute *mid_att_als[] = {
 195        &dev_attr_lux0_sensor_range.attr,
 196        &dev_attr_lux0_input.attr,
 197        NULL
 198};
 199
 200static struct attribute_group m_als_gr = {
 201        .name = "apds9802als",
 202        .attrs = mid_att_als
 203};
 204
 205static int als_set_default_config(struct i2c_client *client)
 206{
 207        int ret_val;
 208        /* Write the command and then switch on */
 209        ret_val = i2c_smbus_write_byte_data(client, 0x80, 0x01);
 210        if (ret_val < 0) {
 211                dev_err(&client->dev, "failed default switch on write\n");
 212                return ret_val;
 213        }
 214        /* detection range: 1~64K Lux, maunal measurement */
 215        ret_val = i2c_smbus_write_byte_data(client, 0x81, 0x08);
 216        if (ret_val < 0)
 217                dev_err(&client->dev, "failed default LUX on write\n");
 218
 219        /*  We always get 0 for the 1st measurement after system power on,
 220         *  so make sure it is finished before user asks for data.
 221         */
 222        als_wait_for_data_ready(&client->dev);
 223
 224        return ret_val;
 225}
 226
 227static int apds9802als_probe(struct i2c_client *client,
 228                             const struct i2c_device_id *id)
 229{
 230        int res;
 231        struct als_data *data;
 232
 233        data = kzalloc(sizeof(struct als_data), GFP_KERNEL);
 234        if (data == NULL) {
 235                dev_err(&client->dev, "Memory allocation failed\n");
 236                return -ENOMEM;
 237        }
 238        i2c_set_clientdata(client, data);
 239        res = sysfs_create_group(&client->dev.kobj, &m_als_gr);
 240        if (res) {
 241                dev_err(&client->dev, "device create file failed\n");
 242                goto als_error1;
 243        }
 244        dev_info(&client->dev, "ALS chip found\n");
 245        als_set_default_config(client);
 246        mutex_init(&data->mutex);
 247
 248        pm_runtime_enable(&client->dev);
 249        pm_runtime_get(&client->dev);
 250        pm_runtime_put(&client->dev);
 251
 252        return res;
 253als_error1:
 254        kfree(data);
 255        return res;
 256}
 257
 258static int apds9802als_remove(struct i2c_client *client)
 259{
 260        struct als_data *data = i2c_get_clientdata(client);
 261
 262        als_set_power_state(client, false);
 263        sysfs_remove_group(&client->dev.kobj, &m_als_gr);
 264        kfree(data);
 265        return 0;
 266}
 267
 268#ifdef CONFIG_PM
 269static int apds9802als_suspend(struct i2c_client *client, pm_message_t mesg)
 270{
 271        als_set_power_state(client, false);
 272        return 0;
 273}
 274
 275static int apds9802als_resume(struct i2c_client *client)
 276{
 277        als_set_default_config(client);
 278
 279        pm_runtime_get(&client->dev);
 280        pm_runtime_put(&client->dev);
 281        return 0;
 282}
 283
 284static int apds9802als_runtime_suspend(struct device *dev)
 285{
 286        struct i2c_client *client = to_i2c_client(dev);
 287
 288        als_set_power_state(client, false);
 289        return 0;
 290}
 291
 292static int apds9802als_runtime_resume(struct device *dev)
 293{
 294        struct i2c_client *client = to_i2c_client(dev);
 295
 296        als_set_power_state(client, true);
 297        return 0;
 298}
 299
 300static const struct dev_pm_ops apds9802als_pm_ops = {
 301        .runtime_suspend = apds9802als_runtime_suspend,
 302        .runtime_resume = apds9802als_runtime_resume,
 303};
 304
 305#define APDS9802ALS_PM_OPS (&apds9802als_pm_ops)
 306
 307#else   /* CONFIG_PM */
 308#define apds9802als_suspend NULL
 309#define apds9802als_resume NULL
 310#define APDS9802ALS_PM_OPS NULL
 311#endif  /* CONFIG_PM */
 312
 313static struct i2c_device_id apds9802als_id[] = {
 314        { DRIVER_NAME, 0 },
 315        { }
 316};
 317
 318MODULE_DEVICE_TABLE(i2c, apds9802als_id);
 319
 320static struct i2c_driver apds9802als_driver = {
 321        .driver = {
 322                .name = DRIVER_NAME,
 323                .pm = APDS9802ALS_PM_OPS,
 324        },
 325        .probe = apds9802als_probe,
 326        .remove = apds9802als_remove,
 327        .suspend = apds9802als_suspend,
 328        .resume = apds9802als_resume,
 329        .id_table = apds9802als_id,
 330};
 331
 332static int __init sensor_apds9802als_init(void)
 333{
 334        return i2c_add_driver(&apds9802als_driver);
 335}
 336
 337static void  __exit sensor_apds9802als_exit(void)
 338{
 339        i2c_del_driver(&apds9802als_driver);
 340}
 341module_init(sensor_apds9802als_init);
 342module_exit(sensor_apds9802als_exit);
 343
 344MODULE_AUTHOR("Anantha Narayanan <Anantha.Narayanan@intel.com");
 345MODULE_DESCRIPTION("Avago apds9802als ALS Driver");
 346MODULE_LICENSE("GPL v2");
 347