linux/drivers/i2c/chips/tsl2550.c
<<
>>
Prefs
   1/*
   2 *  tsl2550.c - Linux kernel modules for ambient light sensor
   3 *
   4 *  Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
   5 *  Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
   6 *
   7 *  This program is free software; you can redistribute it and/or modify
   8 *  it under the terms of the GNU General Public License as published by
   9 *  the Free Software Foundation; either version 2 of the License, or
  10 *  (at your option) any later version.
  11 *
  12 *  This program is distributed in the hope that it will be useful,
  13 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 *  GNU General Public License for more details.
  16 *
  17 *  You should have received a copy of the GNU General Public License
  18 *  along with this program; if not, write to the Free Software
  19 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/init.h>
  24#include <linux/slab.h>
  25#include <linux/i2c.h>
  26#include <linux/mutex.h>
  27#include <linux/delay.h>
  28
  29#define TSL2550_DRV_NAME        "tsl2550"
  30#define DRIVER_VERSION          "1.1.1"
  31
  32/*
  33 * Defines
  34 */
  35
  36#define TSL2550_POWER_DOWN              0x00
  37#define TSL2550_POWER_UP                0x03
  38#define TSL2550_STANDARD_RANGE          0x18
  39#define TSL2550_EXTENDED_RANGE          0x1d
  40#define TSL2550_READ_ADC0               0x43
  41#define TSL2550_READ_ADC1               0x83
  42
  43/*
  44 * Structs
  45 */
  46
  47struct tsl2550_data {
  48        struct i2c_client *client;
  49        struct mutex update_lock;
  50
  51        unsigned int power_state : 1;
  52        unsigned int operating_mode : 1;
  53};
  54
  55/*
  56 * Global data
  57 */
  58
  59static const u8 TSL2550_MODE_RANGE[2] = {
  60        TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
  61};
  62
  63/*
  64 * Management functions
  65 */
  66
  67static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
  68{
  69        struct tsl2550_data *data = i2c_get_clientdata(client);
  70
  71        int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
  72
  73        data->operating_mode = mode;
  74
  75        return ret;
  76}
  77
  78static int tsl2550_set_power_state(struct i2c_client *client, int state)
  79{
  80        struct tsl2550_data *data = i2c_get_clientdata(client);
  81        int ret;
  82
  83        if (state == 0)
  84                ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
  85        else {
  86                ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
  87
  88                /* On power up we should reset operating mode also... */
  89                tsl2550_set_operating_mode(client, data->operating_mode);
  90        }
  91
  92        data->power_state = state;
  93
  94        return ret;
  95}
  96
  97static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
  98{
  99        unsigned long end;
 100        int loop = 0, ret = 0;
 101
 102        /*
 103         * Read ADC channel waiting at most 400ms (see data sheet for further
 104         * info).
 105         * To avoid long busy wait we spin for few milliseconds then
 106         * start sleeping.
 107         */
 108        end = jiffies + msecs_to_jiffies(400);
 109        while (time_before(jiffies, end)) {
 110                i2c_smbus_write_byte(client, cmd);
 111
 112                if (loop++ < 5)
 113                        mdelay(1);
 114                else
 115                        msleep(1);
 116
 117                ret = i2c_smbus_read_byte(client);
 118                if (ret < 0)
 119                        return ret;
 120                else if (ret & 0x0080)
 121                        break;
 122        }
 123        if (!(ret & 0x80))
 124                return -EIO;
 125        return ret & 0x7f;      /* remove the "valid" bit */
 126}
 127
 128/*
 129 * LUX calculation
 130 */
 131
 132#define TSL2550_MAX_LUX         1846
 133
 134static const u8 ratio_lut[] = {
 135        100, 100, 100, 100, 100, 100, 100, 100,
 136        100, 100, 100, 100, 100, 100, 99, 99,
 137        99, 99, 99, 99, 99, 99, 99, 99,
 138        99, 99, 99, 98, 98, 98, 98, 98,
 139        98, 98, 97, 97, 97, 97, 97, 96,
 140        96, 96, 96, 95, 95, 95, 94, 94,
 141        93, 93, 93, 92, 92, 91, 91, 90,
 142        89, 89, 88, 87, 87, 86, 85, 84,
 143        83, 82, 81, 80, 79, 78, 77, 75,
 144        74, 73, 71, 69, 68, 66, 64, 62,
 145        60, 58, 56, 54, 52, 49, 47, 44,
 146        42, 41, 40, 40, 39, 39, 38, 38,
 147        37, 37, 37, 36, 36, 36, 35, 35,
 148        35, 35, 34, 34, 34, 34, 33, 33,
 149        33, 33, 32, 32, 32, 32, 32, 31,
 150        31, 31, 31, 31, 30, 30, 30, 30,
 151        30,
 152};
 153
 154static const u16 count_lut[] = {
 155        0, 1, 2, 3, 4, 5, 6, 7,
 156        8, 9, 10, 11, 12, 13, 14, 15,
 157        16, 18, 20, 22, 24, 26, 28, 30,
 158        32, 34, 36, 38, 40, 42, 44, 46,
 159        49, 53, 57, 61, 65, 69, 73, 77,
 160        81, 85, 89, 93, 97, 101, 105, 109,
 161        115, 123, 131, 139, 147, 155, 163, 171,
 162        179, 187, 195, 203, 211, 219, 227, 235,
 163        247, 263, 279, 295, 311, 327, 343, 359,
 164        375, 391, 407, 423, 439, 455, 471, 487,
 165        511, 543, 575, 607, 639, 671, 703, 735,
 166        767, 799, 831, 863, 895, 927, 959, 991,
 167        1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
 168        1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
 169        2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
 170        3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
 171};
 172
 173/*
 174 * This function is described into Taos TSL2550 Designer's Notebook
 175 * pages 2, 3.
 176 */
 177static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
 178{
 179        unsigned int lux;
 180
 181        /* Look up count from channel values */
 182        u16 c0 = count_lut[ch0];
 183        u16 c1 = count_lut[ch1];
 184
 185        /*
 186         * Calculate ratio.
 187         * Note: the "128" is a scaling factor
 188         */
 189        u8 r = 128;
 190
 191        /* Avoid division by 0 and count 1 cannot be greater than count 0 */
 192        if (c0 && (c1 <= c0))
 193                r = c1 * 128 / c0;
 194        else
 195                return -1;
 196
 197        /* Calculate LUX */
 198        lux = ((c0 - c1) * ratio_lut[r]) / 256;
 199
 200        /* LUX range check */
 201        return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
 202}
 203
 204/*
 205 * SysFS support
 206 */
 207
 208static ssize_t tsl2550_show_power_state(struct device *dev,
 209                struct device_attribute *attr, char *buf)
 210{
 211        struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
 212
 213        return sprintf(buf, "%u\n", data->power_state);
 214}
 215
 216static ssize_t tsl2550_store_power_state(struct device *dev,
 217                struct device_attribute *attr, const char *buf, size_t count)
 218{
 219        struct i2c_client *client = to_i2c_client(dev);
 220        struct tsl2550_data *data = i2c_get_clientdata(client);
 221        unsigned long val = simple_strtoul(buf, NULL, 10);
 222        int ret;
 223
 224        if (val < 0 || val > 1)
 225                return -EINVAL;
 226
 227        mutex_lock(&data->update_lock);
 228        ret = tsl2550_set_power_state(client, val);
 229        mutex_unlock(&data->update_lock);
 230
 231        if (ret < 0)
 232                return ret;
 233
 234        return count;
 235}
 236
 237static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
 238                   tsl2550_show_power_state, tsl2550_store_power_state);
 239
 240static ssize_t tsl2550_show_operating_mode(struct device *dev,
 241                struct device_attribute *attr, char *buf)
 242{
 243        struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
 244
 245        return sprintf(buf, "%u\n", data->operating_mode);
 246}
 247
 248static ssize_t tsl2550_store_operating_mode(struct device *dev,
 249                struct device_attribute *attr, const char *buf, size_t count)
 250{
 251        struct i2c_client *client = to_i2c_client(dev);
 252        struct tsl2550_data *data = i2c_get_clientdata(client);
 253        unsigned long val = simple_strtoul(buf, NULL, 10);
 254        int ret;
 255
 256        if (val < 0 || val > 1)
 257                return -EINVAL;
 258
 259        if (data->power_state == 0)
 260                return -EBUSY;
 261
 262        mutex_lock(&data->update_lock);
 263        ret = tsl2550_set_operating_mode(client, val);
 264        mutex_unlock(&data->update_lock);
 265
 266        if (ret < 0)
 267                return ret;
 268
 269        return count;
 270}
 271
 272static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
 273                   tsl2550_show_operating_mode, tsl2550_store_operating_mode);
 274
 275static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
 276{
 277        u8 ch0, ch1;
 278        int ret;
 279
 280        ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
 281        if (ret < 0)
 282                return ret;
 283        ch0 = ret;
 284
 285        mdelay(1);
 286
 287        ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
 288        if (ret < 0)
 289                return ret;
 290        ch1 = ret;
 291
 292        /* Do the job */
 293        ret = tsl2550_calculate_lux(ch0, ch1);
 294        if (ret < 0)
 295                return ret;
 296
 297        return sprintf(buf, "%d\n", ret);
 298}
 299
 300static ssize_t tsl2550_show_lux1_input(struct device *dev,
 301                        struct device_attribute *attr, char *buf)
 302{
 303        struct i2c_client *client = to_i2c_client(dev);
 304        struct tsl2550_data *data = i2c_get_clientdata(client);
 305        int ret;
 306
 307        /* No LUX data if not operational */
 308        if (!data->power_state)
 309                return -EBUSY;
 310
 311        mutex_lock(&data->update_lock);
 312        ret = __tsl2550_show_lux(client, buf);
 313        mutex_unlock(&data->update_lock);
 314
 315        return ret;
 316}
 317
 318static DEVICE_ATTR(lux1_input, S_IRUGO,
 319                   tsl2550_show_lux1_input, NULL);
 320
 321static struct attribute *tsl2550_attributes[] = {
 322        &dev_attr_power_state.attr,
 323        &dev_attr_operating_mode.attr,
 324        &dev_attr_lux1_input.attr,
 325        NULL
 326};
 327
 328static const struct attribute_group tsl2550_attr_group = {
 329        .attrs = tsl2550_attributes,
 330};
 331
 332/*
 333 * Initialization function
 334 */
 335
 336static int tsl2550_init_client(struct i2c_client *client)
 337{
 338        struct tsl2550_data *data = i2c_get_clientdata(client);
 339        int err;
 340
 341        /*
 342         * Probe the chip. To do so we try to power up the device and then to
 343         * read back the 0x03 code
 344         */
 345        err = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
 346        if (err < 0)
 347                return err;
 348        mdelay(1);
 349        if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
 350                return -ENODEV;
 351        data->power_state = 1;
 352
 353        /* Set the default operating mode */
 354        err = i2c_smbus_write_byte(client,
 355                                   TSL2550_MODE_RANGE[data->operating_mode]);
 356        if (err < 0)
 357                return err;
 358
 359        return 0;
 360}
 361
 362/*
 363 * I2C init/probing/exit functions
 364 */
 365
 366static struct i2c_driver tsl2550_driver;
 367static int __devinit tsl2550_probe(struct i2c_client *client,
 368                                   const struct i2c_device_id *id)
 369{
 370        struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
 371        struct tsl2550_data *data;
 372        int *opmode, err = 0;
 373
 374        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
 375                err = -EIO;
 376                goto exit;
 377        }
 378
 379        data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
 380        if (!data) {
 381                err = -ENOMEM;
 382                goto exit;
 383        }
 384        data->client = client;
 385        i2c_set_clientdata(client, data);
 386
 387        /* Check platform data */
 388        opmode = client->dev.platform_data;
 389        if (opmode) {
 390                if (*opmode < 0 || *opmode > 1) {
 391                        dev_err(&client->dev, "invalid operating_mode (%d)\n",
 392                                        *opmode);
 393                        err = -EINVAL;
 394                        goto exit_kfree;
 395                }
 396                data->operating_mode = *opmode;
 397        } else
 398                data->operating_mode = 0;       /* default mode is standard */
 399        dev_info(&client->dev, "%s operating mode\n",
 400                        data->operating_mode ? "extended" : "standard");
 401
 402        mutex_init(&data->update_lock);
 403
 404        /* Initialize the TSL2550 chip */
 405        err = tsl2550_init_client(client);
 406        if (err)
 407                goto exit_kfree;
 408
 409        /* Register sysfs hooks */
 410        err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
 411        if (err)
 412                goto exit_kfree;
 413
 414        dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
 415
 416        return 0;
 417
 418exit_kfree:
 419        kfree(data);
 420exit:
 421        return err;
 422}
 423
 424static int __devexit tsl2550_remove(struct i2c_client *client)
 425{
 426        sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
 427
 428        /* Power down the device */
 429        tsl2550_set_power_state(client, 0);
 430
 431        kfree(i2c_get_clientdata(client));
 432
 433        return 0;
 434}
 435
 436#ifdef CONFIG_PM
 437
 438static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
 439{
 440        return tsl2550_set_power_state(client, 0);
 441}
 442
 443static int tsl2550_resume(struct i2c_client *client)
 444{
 445        return tsl2550_set_power_state(client, 1);
 446}
 447
 448#else
 449
 450#define tsl2550_suspend         NULL
 451#define tsl2550_resume          NULL
 452
 453#endif /* CONFIG_PM */
 454
 455static const struct i2c_device_id tsl2550_id[] = {
 456        { "tsl2550", 0 },
 457        { }
 458};
 459MODULE_DEVICE_TABLE(i2c, tsl2550_id);
 460
 461static struct i2c_driver tsl2550_driver = {
 462        .driver = {
 463                .name   = TSL2550_DRV_NAME,
 464                .owner  = THIS_MODULE,
 465        },
 466        .suspend = tsl2550_suspend,
 467        .resume = tsl2550_resume,
 468        .probe  = tsl2550_probe,
 469        .remove = __devexit_p(tsl2550_remove),
 470        .id_table = tsl2550_id,
 471};
 472
 473static int __init tsl2550_init(void)
 474{
 475        return i2c_add_driver(&tsl2550_driver);
 476}
 477
 478static void __exit tsl2550_exit(void)
 479{
 480        i2c_del_driver(&tsl2550_driver);
 481}
 482
 483MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
 484MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
 485MODULE_LICENSE("GPL");
 486MODULE_VERSION(DRIVER_VERSION);
 487
 488module_init(tsl2550_init);
 489module_exit(tsl2550_exit);
 490
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.