linux/drivers/misc/isl29003.c
<<
>>
Prefs
   1/*
   2 *  isl29003.c - Linux kernel module for
   3 *      Intersil ISL29003 ambient light sensor
   4 *
   5 *  See file:Documentation/misc-devices/isl29003
   6 *
   7 *  Copyright (c) 2009 Daniel Mack <daniel@caiaq.de>
   8 *
   9 *  Based on code written by
  10 *      Rodolfo Giometti <giometti@linux.it>
  11 *      Eurotech S.p.A. <info@eurotech.it>
  12 *
  13 *  This program is free software; you can redistribute it and/or modify
  14 *  it under the terms of the GNU General Public License as published by
  15 *  the Free Software Foundation; either version 2 of the License, or
  16 *  (at your option) any later version.
  17 *
  18 *  This program is distributed in the hope that it will be useful,
  19 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  20 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21 *  GNU General Public License for more details.
  22 *
  23 *  You should have received a copy of the GNU General Public License
  24 *  along with this program; if not, write to the Free Software
  25 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  26 */
  27
  28#include <linux/module.h>
  29#include <linux/slab.h>
  30#include <linux/i2c.h>
  31#include <linux/mutex.h>
  32#include <linux/delay.h>
  33
  34#define ISL29003_DRV_NAME       "isl29003"
  35#define DRIVER_VERSION          "1.0"
  36
  37#define ISL29003_REG_COMMAND            0x00
  38#define ISL29003_ADC_ENABLED            (1 << 7)
  39#define ISL29003_ADC_PD                 (1 << 6)
  40#define ISL29003_TIMING_INT             (1 << 5)
  41#define ISL29003_MODE_SHIFT             (2)
  42#define ISL29003_MODE_MASK              (0x3 << ISL29003_MODE_SHIFT)
  43#define ISL29003_RES_SHIFT              (0)
  44#define ISL29003_RES_MASK               (0x3 << ISL29003_RES_SHIFT)
  45
  46#define ISL29003_REG_CONTROL            0x01
  47#define ISL29003_INT_FLG                (1 << 5)
  48#define ISL29003_RANGE_SHIFT            (2)
  49#define ISL29003_RANGE_MASK             (0x3 << ISL29003_RANGE_SHIFT)
  50#define ISL29003_INT_PERSISTS_SHIFT     (0)
  51#define ISL29003_INT_PERSISTS_MASK      (0xf << ISL29003_INT_PERSISTS_SHIFT)
  52
  53#define ISL29003_REG_IRQ_THRESH_HI      0x02
  54#define ISL29003_REG_IRQ_THRESH_LO      0x03
  55#define ISL29003_REG_LSB_SENSOR         0x04
  56#define ISL29003_REG_MSB_SENSOR         0x05
  57#define ISL29003_REG_LSB_TIMER          0x06
  58#define ISL29003_REG_MSB_TIMER          0x07
  59
  60#define ISL29003_NUM_CACHABLE_REGS      4
  61
  62struct isl29003_data {
  63        struct i2c_client *client;
  64        struct mutex lock;
  65        u8 reg_cache[ISL29003_NUM_CACHABLE_REGS];
  66        u8 power_state_before_suspend;
  67};
  68
  69static int gain_range[] = {
  70        1000, 4000, 16000, 64000
  71};
  72
  73/*
  74 * register access helpers
  75 */
  76
  77static int __isl29003_read_reg(struct i2c_client *client,
  78                               u32 reg, u8 mask, u8 shift)
  79{
  80        struct isl29003_data *data = i2c_get_clientdata(client);
  81
  82        return (data->reg_cache[reg] & mask) >> shift;
  83}
  84
  85static int __isl29003_write_reg(struct i2c_client *client,
  86                                u32 reg, u8 mask, u8 shift, u8 val)
  87{
  88        struct isl29003_data *data = i2c_get_clientdata(client);
  89        int ret = 0;
  90        u8 tmp;
  91
  92        if (reg >= ISL29003_NUM_CACHABLE_REGS)
  93                return -EINVAL;
  94
  95        mutex_lock(&data->lock);
  96
  97        tmp = data->reg_cache[reg];
  98        tmp &= ~mask;
  99        tmp |= val << shift;
 100
 101        ret = i2c_smbus_write_byte_data(client, reg, tmp);
 102        if (!ret)
 103                data->reg_cache[reg] = tmp;
 104
 105        mutex_unlock(&data->lock);
 106        return ret;
 107}
 108
 109/*
 110 * internally used functions
 111 */
 112
 113/* range */
 114static int isl29003_get_range(struct i2c_client *client)
 115{
 116        return __isl29003_read_reg(client, ISL29003_REG_CONTROL,
 117                ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT);
 118}
 119
 120static int isl29003_set_range(struct i2c_client *client, int range)
 121{
 122        return __isl29003_write_reg(client, ISL29003_REG_CONTROL,
 123                ISL29003_RANGE_MASK, ISL29003_RANGE_SHIFT, range);
 124}
 125
 126/* resolution */
 127static int isl29003_get_resolution(struct i2c_client *client)
 128{
 129        return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
 130                ISL29003_RES_MASK, ISL29003_RES_SHIFT);
 131}
 132
 133static int isl29003_set_resolution(struct i2c_client *client, int res)
 134{
 135        return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
 136                ISL29003_RES_MASK, ISL29003_RES_SHIFT, res);
 137}
 138
 139/* mode */
 140static int isl29003_get_mode(struct i2c_client *client)
 141{
 142        return __isl29003_read_reg(client, ISL29003_REG_COMMAND,
 143                ISL29003_RES_MASK, ISL29003_RES_SHIFT);
 144}
 145
 146static int isl29003_set_mode(struct i2c_client *client, int mode)
 147{
 148        return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
 149                ISL29003_RES_MASK, ISL29003_RES_SHIFT, mode);
 150}
 151
 152/* power_state */
 153static int isl29003_set_power_state(struct i2c_client *client, int state)
 154{
 155        return __isl29003_write_reg(client, ISL29003_REG_COMMAND,
 156                                ISL29003_ADC_ENABLED | ISL29003_ADC_PD, 0,
 157                                state ? ISL29003_ADC_ENABLED : ISL29003_ADC_PD);
 158}
 159
 160static int isl29003_get_power_state(struct i2c_client *client)
 161{
 162        struct isl29003_data *data = i2c_get_clientdata(client);
 163        u8 cmdreg = data->reg_cache[ISL29003_REG_COMMAND];
 164
 165        return ~cmdreg & ISL29003_ADC_PD;
 166}
 167
 168static int isl29003_get_adc_value(struct i2c_client *client)
 169{
 170        struct isl29003_data *data = i2c_get_clientdata(client);
 171        int lsb, msb, range, bitdepth;
 172
 173        mutex_lock(&data->lock);
 174        lsb = i2c_smbus_read_byte_data(client, ISL29003_REG_LSB_SENSOR);
 175
 176        if (lsb < 0) {
 177                mutex_unlock(&data->lock);
 178                return lsb;
 179        }
 180
 181        msb = i2c_smbus_read_byte_data(client, ISL29003_REG_MSB_SENSOR);
 182        mutex_unlock(&data->lock);
 183
 184        if (msb < 0)
 185                return msb;
 186
 187        range = isl29003_get_range(client);
 188        bitdepth = (4 - isl29003_get_resolution(client)) * 4;
 189        return (((msb << 8) | lsb) * gain_range[range]) >> bitdepth;
 190}
 191
 192/*
 193 * sysfs layer
 194 */
 195
 196/* range */
 197static ssize_t isl29003_show_range(struct device *dev,
 198                                   struct device_attribute *attr, char *buf)
 199{
 200        struct i2c_client *client = to_i2c_client(dev);
 201
 202        return sprintf(buf, "%i\n", isl29003_get_range(client));
 203}
 204
 205static ssize_t isl29003_store_range(struct device *dev,
 206                                    struct device_attribute *attr,
 207                                    const char *buf, size_t count)
 208{
 209        struct i2c_client *client = to_i2c_client(dev);
 210        unsigned long val;
 211        int ret;
 212
 213        ret = kstrtoul(buf, 10, &val);
 214        if (ret)
 215                return ret;
 216
 217        if (val > 3)
 218                return -EINVAL;
 219
 220        ret = isl29003_set_range(client, val);
 221        if (ret < 0)
 222                return ret;
 223
 224        return count;
 225}
 226
 227static DEVICE_ATTR(range, S_IWUSR | S_IRUGO,
 228                   isl29003_show_range, isl29003_store_range);
 229
 230
 231/* resolution */
 232static ssize_t isl29003_show_resolution(struct device *dev,
 233                                        struct device_attribute *attr,
 234                                        char *buf)
 235{
 236        struct i2c_client *client = to_i2c_client(dev);
 237
 238        return sprintf(buf, "%d\n", isl29003_get_resolution(client));
 239}
 240
 241static ssize_t isl29003_store_resolution(struct device *dev,
 242                                         struct device_attribute *attr,
 243                                         const char *buf, size_t count)
 244{
 245        struct i2c_client *client = to_i2c_client(dev);
 246        unsigned long val;
 247        int ret;
 248
 249        ret = kstrtoul(buf, 10, &val);
 250        if (ret)
 251                return ret;
 252
 253        if (val > 3)
 254                return -EINVAL;
 255
 256        ret = isl29003_set_resolution(client, val);
 257        if (ret < 0)
 258                return ret;
 259
 260        return count;
 261}
 262
 263static DEVICE_ATTR(resolution, S_IWUSR | S_IRUGO,
 264                   isl29003_show_resolution, isl29003_store_resolution);
 265
 266/* mode */
 267static ssize_t isl29003_show_mode(struct device *dev,
 268                                  struct device_attribute *attr, char *buf)
 269{
 270        struct i2c_client *client = to_i2c_client(dev);
 271
 272        return sprintf(buf, "%d\n", isl29003_get_mode(client));
 273}
 274
 275static ssize_t isl29003_store_mode(struct device *dev,
 276                struct device_attribute *attr, const char *buf, size_t count)
 277{
 278        struct i2c_client *client = to_i2c_client(dev);
 279        unsigned long val;
 280        int ret;
 281
 282        ret = kstrtoul(buf, 10, &val);
 283        if (ret)
 284                return ret;
 285
 286        if (val > 2)
 287                return -EINVAL;
 288
 289        ret = isl29003_set_mode(client, val);
 290        if (ret < 0)
 291                return ret;
 292
 293        return count;
 294}
 295
 296static DEVICE_ATTR(mode, S_IWUSR | S_IRUGO,
 297                   isl29003_show_mode, isl29003_store_mode);
 298
 299
 300/* power state */
 301static ssize_t isl29003_show_power_state(struct device *dev,
 302                                         struct device_attribute *attr,
 303                                         char *buf)
 304{
 305        struct i2c_client *client = to_i2c_client(dev);
 306
 307        return sprintf(buf, "%d\n", isl29003_get_power_state(client));
 308}
 309
 310static ssize_t isl29003_store_power_state(struct device *dev,
 311                                          struct device_attribute *attr,
 312                                          const char *buf, size_t count)
 313{
 314        struct i2c_client *client = to_i2c_client(dev);
 315        unsigned long val;
 316        int ret;
 317
 318        ret = kstrtoul(buf, 10, &val);
 319        if (ret)
 320                return ret;
 321
 322        if (val > 1)
 323                return -EINVAL;
 324
 325        ret = isl29003_set_power_state(client, val);
 326        return ret ? ret : count;
 327}
 328
 329static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
 330                   isl29003_show_power_state, isl29003_store_power_state);
 331
 332
 333/* lux */
 334static ssize_t isl29003_show_lux(struct device *dev,
 335                                 struct device_attribute *attr, char *buf)
 336{
 337        struct i2c_client *client = to_i2c_client(dev);
 338
 339        /* No LUX data if not operational */
 340        if (!isl29003_get_power_state(client))
 341                return -EBUSY;
 342
 343        return sprintf(buf, "%d\n", isl29003_get_adc_value(client));
 344}
 345
 346static DEVICE_ATTR(lux, S_IRUGO, isl29003_show_lux, NULL);
 347
 348static struct attribute *isl29003_attributes[] = {
 349        &dev_attr_range.attr,
 350        &dev_attr_resolution.attr,
 351        &dev_attr_mode.attr,
 352        &dev_attr_power_state.attr,
 353        &dev_attr_lux.attr,
 354        NULL
 355};
 356
 357static const struct attribute_group isl29003_attr_group = {
 358        .attrs = isl29003_attributes,
 359};
 360
 361static int isl29003_init_client(struct i2c_client *client)
 362{
 363        struct isl29003_data *data = i2c_get_clientdata(client);
 364        int i;
 365
 366        /* read all the registers once to fill the cache.
 367         * if one of the reads fails, we consider the init failed */
 368        for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++) {
 369                int v = i2c_smbus_read_byte_data(client, i);
 370
 371                if (v < 0)
 372                        return -ENODEV;
 373
 374                data->reg_cache[i] = v;
 375        }
 376
 377        /* set defaults */
 378        isl29003_set_range(client, 0);
 379        isl29003_set_resolution(client, 0);
 380        isl29003_set_mode(client, 0);
 381        isl29003_set_power_state(client, 0);
 382
 383        return 0;
 384}
 385
 386/*
 387 * I2C layer
 388 */
 389
 390static int isl29003_probe(struct i2c_client *client,
 391                                    const struct i2c_device_id *id)
 392{
 393        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 394        struct isl29003_data *data;
 395        int err = 0;
 396
 397        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
 398                return -EIO;
 399
 400        data = kzalloc(sizeof(struct isl29003_data), GFP_KERNEL);
 401        if (!data)
 402                return -ENOMEM;
 403
 404        data->client = client;
 405        i2c_set_clientdata(client, data);
 406        mutex_init(&data->lock);
 407
 408        /* initialize the ISL29003 chip */
 409        err = isl29003_init_client(client);
 410        if (err)
 411                goto exit_kfree;
 412
 413        /* register sysfs hooks */
 414        err = sysfs_create_group(&client->dev.kobj, &isl29003_attr_group);
 415        if (err)
 416                goto exit_kfree;
 417
 418        dev_info(&client->dev, "driver version %s enabled\n", DRIVER_VERSION);
 419        return 0;
 420
 421exit_kfree:
 422        kfree(data);
 423        return err;
 424}
 425
 426static int isl29003_remove(struct i2c_client *client)
 427{
 428        sysfs_remove_group(&client->dev.kobj, &isl29003_attr_group);
 429        isl29003_set_power_state(client, 0);
 430        kfree(i2c_get_clientdata(client));
 431        return 0;
 432}
 433
 434#ifdef CONFIG_PM_SLEEP
 435static int isl29003_suspend(struct device *dev)
 436{
 437        struct i2c_client *client = to_i2c_client(dev);
 438        struct isl29003_data *data = i2c_get_clientdata(client);
 439
 440        data->power_state_before_suspend = isl29003_get_power_state(client);
 441        return isl29003_set_power_state(client, 0);
 442}
 443
 444static int isl29003_resume(struct device *dev)
 445{
 446        int i;
 447        struct i2c_client *client = to_i2c_client(dev);
 448        struct isl29003_data *data = i2c_get_clientdata(client);
 449
 450        /* restore registers from cache */
 451        for (i = 0; i < ARRAY_SIZE(data->reg_cache); i++)
 452                if (i2c_smbus_write_byte_data(client, i, data->reg_cache[i]))
 453                        return -EIO;
 454
 455        return isl29003_set_power_state(client,
 456                data->power_state_before_suspend);
 457}
 458
 459static SIMPLE_DEV_PM_OPS(isl29003_pm_ops, isl29003_suspend, isl29003_resume);
 460#define ISL29003_PM_OPS (&isl29003_pm_ops)
 461
 462#else
 463#define ISL29003_PM_OPS NULL
 464#endif /* CONFIG_PM_SLEEP */
 465
 466static const struct i2c_device_id isl29003_id[] = {
 467        { "isl29003", 0 },
 468        {}
 469};
 470MODULE_DEVICE_TABLE(i2c, isl29003_id);
 471
 472static struct i2c_driver isl29003_driver = {
 473        .driver = {
 474                .name   = ISL29003_DRV_NAME,
 475                .pm     = ISL29003_PM_OPS,
 476        },
 477        .probe  = isl29003_probe,
 478        .remove = isl29003_remove,
 479        .id_table = isl29003_id,
 480};
 481
 482module_i2c_driver(isl29003_driver);
 483
 484MODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>");
 485MODULE_DESCRIPTION("ISL29003 ambient light sensor driver");
 486MODULE_LICENSE("GPL v2");
 487MODULE_VERSION(DRIVER_VERSION);
 488