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