linux/drivers/staging/iio/light/tsl2583.c
<<
>>
Prefs
   1/*
   2 * Device driver for monitoring ambient light intensity (lux)
   3 * within the TAOS tsl258x family of devices (tsl2580, tsl2581).
   4 *
   5 * Copyright (c) 2011, TAOS Corporation.
   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, but WITHOUT
  13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  15 * 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 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  20 */
  21
  22#include <linux/kernel.h>
  23#include <linux/i2c.h>
  24#include <linux/errno.h>
  25#include <linux/delay.h>
  26#include <linux/string.h>
  27#include <linux/mutex.h>
  28#include <linux/unistd.h>
  29#include <linux/slab.h>
  30#include <linux/module.h>
  31#include <linux/iio/iio.h>
  32
  33#define TSL258X_MAX_DEVICE_REGS         32
  34
  35/* Triton register offsets */
  36#define TSL258X_REG_MAX         8
  37
  38/* Device Registers and Masks */
  39#define TSL258X_CNTRL                   0x00
  40#define TSL258X_ALS_TIME                0X01
  41#define TSL258X_INTERRUPT               0x02
  42#define TSL258X_GAIN                    0x07
  43#define TSL258X_REVID                   0x11
  44#define TSL258X_CHIPID                  0x12
  45#define TSL258X_ALS_CHAN0LO             0x14
  46#define TSL258X_ALS_CHAN0HI             0x15
  47#define TSL258X_ALS_CHAN1LO             0x16
  48#define TSL258X_ALS_CHAN1HI             0x17
  49#define TSL258X_TMR_LO                  0x18
  50#define TSL258X_TMR_HI                  0x19
  51
  52/* tsl2583 cmd reg masks */
  53#define TSL258X_CMD_REG                 0x80
  54#define TSL258X_CMD_SPL_FN              0x60
  55#define TSL258X_CMD_ALS_INT_CLR 0X01
  56
  57/* tsl2583 cntrl reg masks */
  58#define TSL258X_CNTL_ADC_ENBL   0x02
  59#define TSL258X_CNTL_PWR_ON             0x01
  60
  61/* tsl2583 status reg masks */
  62#define TSL258X_STA_ADC_VALID   0x01
  63#define TSL258X_STA_ADC_INTR    0x10
  64
  65/* Lux calculation constants */
  66#define TSL258X_LUX_CALC_OVER_FLOW              65535
  67
  68enum {
  69        TSL258X_CHIP_UNKNOWN = 0,
  70        TSL258X_CHIP_WORKING = 1,
  71        TSL258X_CHIP_SUSPENDED = 2
  72};
  73
  74/* Per-device data */
  75struct taos_als_info {
  76        u16 als_ch0;
  77        u16 als_ch1;
  78        u16 lux;
  79};
  80
  81struct taos_settings {
  82        int als_time;
  83        int als_gain;
  84        int als_gain_trim;
  85        int als_cal_target;
  86};
  87
  88struct tsl2583_chip {
  89        struct mutex als_mutex;
  90        struct i2c_client *client;
  91        struct taos_als_info als_cur_info;
  92        struct taos_settings taos_settings;
  93        int als_time_scale;
  94        int als_saturation;
  95        int taos_chip_status;
  96        u8 taos_config[8];
  97};
  98
  99/*
 100 * Initial values for device - this values can/will be changed by driver.
 101 * and applications as needed.
 102 * These values are dynamic.
 103 */
 104static const u8 taos_config[8] = {
 105                0x00, 0xee, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00
 106}; /*   cntrl atime intC  Athl0 Athl1 Athh0 Athh1 gain */
 107
 108struct taos_lux {
 109        unsigned int ratio;
 110        unsigned int ch0;
 111        unsigned int ch1;
 112};
 113
 114/* This structure is intentionally large to accommodate updates via sysfs. */
 115/* Sized to 11 = max 10 segments + 1 termination segment */
 116/* Assumption is one and only one type of glass used  */
 117static struct taos_lux taos_device_lux[11] = {
 118        {  9830,  8520, 15729 },
 119        { 12452, 10807, 23344 },
 120        { 14746,  6383, 11705 },
 121        { 17695,  4063,  6554 },
 122};
 123
 124struct gainadj {
 125        s16 ch0;
 126        s16 ch1;
 127};
 128
 129/* Index = (0 - 3) Used to validate the gain selection index */
 130static const struct gainadj gainadj[] = {
 131        { 1, 1 },
 132        { 8, 8 },
 133        { 16, 16 },
 134        { 107, 115 }
 135};
 136
 137/*
 138 * Provides initial operational parameter defaults.
 139 * These defaults may be changed through the device's sysfs files.
 140 */
 141static void taos_defaults(struct tsl2583_chip *chip)
 142{
 143        /* Operational parameters */
 144        chip->taos_settings.als_time = 100;
 145        /* must be a multiple of 50mS */
 146        chip->taos_settings.als_gain = 0;
 147        /* this is actually an index into the gain table */
 148        /* assume clear glass as default */
 149        chip->taos_settings.als_gain_trim = 1000;
 150        /* default gain trim to account for aperture effects */
 151        chip->taos_settings.als_cal_target = 130;
 152        /* Known external ALS reading used for calibration */
 153}
 154
 155/*
 156 * Read a number of bytes starting at register (reg) location.
 157 * Return 0, or i2c_smbus_write_byte ERROR code.
 158 */
 159static int
 160taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len)
 161{
 162        int i, ret;
 163
 164        for (i = 0; i < len; i++) {
 165                /* select register to write */
 166                ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg));
 167                if (ret < 0) {
 168                        dev_err(&client->dev, "taos_i2c_read failed to write"
 169                                " register %x\n", reg);
 170                        return ret;
 171                }
 172                /* read the data */
 173                *val = i2c_smbus_read_byte(client);
 174                val++;
 175                reg++;
 176        }
 177        return 0;
 178}
 179
 180/*
 181 * Reads and calculates current lux value.
 182 * The raw ch0 and ch1 values of the ambient light sensed in the last
 183 * integration cycle are read from the device.
 184 * Time scale factor array values are adjusted based on the integration time.
 185 * The raw values are multiplied by a scale factor, and device gain is obtained
 186 * using gain index. Limit checks are done next, then the ratio of a multiple
 187 * of ch1 value, to the ch0 value, is calculated. The array taos_device_lux[]
 188 * declared above is then scanned to find the first ratio value that is just
 189 * above the ratio we just calculated. The ch0 and ch1 multiplier constants in
 190 * the array are then used along with the time scale factor array values, to
 191 * calculate the lux.
 192 */
 193static int taos_get_lux(struct iio_dev *indio_dev)
 194{
 195        u16 ch0, ch1; /* separated ch0/ch1 data from device */
 196        u32 lux; /* raw lux calculated from device data */
 197        u64 lux64;
 198        u32 ratio;
 199        u8 buf[5];
 200        struct taos_lux *p;
 201        struct tsl2583_chip *chip = iio_priv(indio_dev);
 202        int i, ret;
 203        u32 ch0lux = 0;
 204        u32 ch1lux = 0;
 205
 206        if (mutex_trylock(&chip->als_mutex) == 0) {
 207                dev_info(&chip->client->dev, "taos_get_lux device is busy\n");
 208                return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
 209        }
 210
 211        if (chip->taos_chip_status != TSL258X_CHIP_WORKING) {
 212                /* device is not enabled */
 213                dev_err(&chip->client->dev, "taos_get_lux device is not enabled\n");
 214                ret = -EBUSY ;
 215                goto out_unlock;
 216        }
 217
 218        ret = taos_i2c_read(chip->client, (TSL258X_CMD_REG), &buf[0], 1);
 219        if (ret < 0) {
 220                dev_err(&chip->client->dev, "taos_get_lux failed to read CMD_REG\n");
 221                goto out_unlock;
 222        }
 223        /* is data new & valid */
 224        if (!(buf[0] & TSL258X_STA_ADC_INTR)) {
 225                dev_err(&chip->client->dev, "taos_get_lux data not valid\n");
 226                ret = chip->als_cur_info.lux; /* return LAST VALUE */
 227                goto out_unlock;
 228        }
 229
 230        for (i = 0; i < 4; i++) {
 231                int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i);
 232                ret = taos_i2c_read(chip->client, reg, &buf[i], 1);
 233                if (ret < 0) {
 234                        dev_err(&chip->client->dev, "taos_get_lux failed to read"
 235                                " register %x\n", reg);
 236                        goto out_unlock;
 237                }
 238        }
 239
 240        /* clear status, really interrupt status (interrupts are off), but
 241         * we use the bit anyway - don't forget 0x80 - this is a command*/
 242        ret = i2c_smbus_write_byte(chip->client,
 243                                   (TSL258X_CMD_REG | TSL258X_CMD_SPL_FN |
 244                                    TSL258X_CMD_ALS_INT_CLR));
 245
 246        if (ret < 0) {
 247                dev_err(&chip->client->dev,
 248                        "taos_i2c_write_command failed in taos_get_lux, err = %d\n",
 249                        ret);
 250                goto out_unlock; /* have no data, so return failure */
 251        }
 252
 253        /* extract ALS/lux data */
 254        ch0 = le16_to_cpup((const __le16 *)&buf[0]);
 255        ch1 = le16_to_cpup((const __le16 *)&buf[2]);
 256
 257        chip->als_cur_info.als_ch0 = ch0;
 258        chip->als_cur_info.als_ch1 = ch1;
 259
 260        if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation))
 261                goto return_max;
 262
 263        if (ch0 == 0) {
 264                /* have no data, so return LAST VALUE */
 265                ret = chip->als_cur_info.lux = 0;
 266                goto out_unlock;
 267        }
 268        /* calculate ratio */
 269        ratio = (ch1 << 15) / ch0;
 270        /* convert to unscaled lux using the pointer to the table */
 271        for (p = (struct taos_lux *) taos_device_lux;
 272             p->ratio != 0 && p->ratio < ratio; p++)
 273                ;
 274
 275        if (p->ratio == 0) {
 276                lux = 0;
 277        } else {
 278                ch0lux = ((ch0 * p->ch0) +
 279                          (gainadj[chip->taos_settings.als_gain].ch0 >> 1))
 280                         / gainadj[chip->taos_settings.als_gain].ch0;
 281                ch1lux = ((ch1 * p->ch1) +
 282                          (gainadj[chip->taos_settings.als_gain].ch1 >> 1))
 283                         / gainadj[chip->taos_settings.als_gain].ch1;
 284                lux = ch0lux - ch1lux;
 285        }
 286
 287        /* note: lux is 31 bit max at this point */
 288        if (ch1lux > ch0lux) {
 289                dev_dbg(&chip->client->dev, "No Data - Return last value\n");
 290                ret = chip->als_cur_info.lux = 0;
 291                goto out_unlock;
 292        }
 293
 294        /* adjust for active time scale */
 295        if (chip->als_time_scale == 0)
 296                lux = 0;
 297        else
 298                lux = (lux + (chip->als_time_scale >> 1)) /
 299                        chip->als_time_scale;
 300
 301        /* Adjust for active gain scale.
 302         * The taos_device_lux tables above have a factor of 8192 built in,
 303         * so we need to shift right.
 304         * User-specified gain provides a multiplier.
 305         * Apply user-specified gain before shifting right to retain precision.
 306         * Use 64 bits to avoid overflow on multiplication.
 307         * Then go back to 32 bits before division to avoid using div_u64().
 308         */
 309        lux64 = lux;
 310        lux64 = lux64 * chip->taos_settings.als_gain_trim;
 311        lux64 >>= 13;
 312        lux = lux64;
 313        lux = (lux + 500) / 1000;
 314        if (lux > TSL258X_LUX_CALC_OVER_FLOW) { /* check for overflow */
 315return_max:
 316                lux = TSL258X_LUX_CALC_OVER_FLOW;
 317        }
 318
 319        /* Update the structure with the latest VALID lux. */
 320        chip->als_cur_info.lux = lux;
 321        ret = lux;
 322
 323out_unlock:
 324        mutex_unlock(&chip->als_mutex);
 325        return ret;
 326}
 327
 328/*
 329 * Obtain single reading and calculate the als_gain_trim (later used
 330 * to derive actual lux).
 331 * Return updated gain_trim value.
 332 */
 333static int taos_als_calibrate(struct iio_dev *indio_dev)
 334{
 335        struct tsl2583_chip *chip = iio_priv(indio_dev);
 336        u8 reg_val;
 337        unsigned int gain_trim_val;
 338        int ret;
 339        int lux_val;
 340
 341        ret = i2c_smbus_write_byte(chip->client,
 342                                   (TSL258X_CMD_REG | TSL258X_CNTRL));
 343        if (ret < 0) {
 344                dev_err(&chip->client->dev,
 345                        "taos_als_calibrate failed to reach the CNTRL register, ret=%d\n",
 346                        ret);
 347                return ret;
 348        }
 349
 350        reg_val = i2c_smbus_read_byte(chip->client);
 351        if ((reg_val & (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON))
 352                        != (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) {
 353                dev_err(&chip->client->dev,
 354                        "taos_als_calibrate failed: device not powered on with ADC enabled\n");
 355                return -1;
 356        }
 357
 358        ret = i2c_smbus_write_byte(chip->client,
 359                                   (TSL258X_CMD_REG | TSL258X_CNTRL));
 360        if (ret < 0) {
 361                dev_err(&chip->client->dev,
 362                        "taos_als_calibrate failed to reach the STATUS register, ret=%d\n",
 363                        ret);
 364                return ret;
 365        }
 366        reg_val = i2c_smbus_read_byte(chip->client);
 367
 368        if ((reg_val & TSL258X_STA_ADC_VALID) != TSL258X_STA_ADC_VALID) {
 369                dev_err(&chip->client->dev,
 370                        "taos_als_calibrate failed: STATUS - ADC not valid.\n");
 371                return -ENODATA;
 372        }
 373        lux_val = taos_get_lux(indio_dev);
 374        if (lux_val < 0) {
 375                dev_err(&chip->client->dev, "taos_als_calibrate failed to get lux\n");
 376                return lux_val;
 377        }
 378        gain_trim_val = (unsigned int) (((chip->taos_settings.als_cal_target)
 379                        * chip->taos_settings.als_gain_trim) / lux_val);
 380
 381        if ((gain_trim_val < 250) || (gain_trim_val > 4000)) {
 382                dev_err(&chip->client->dev,
 383                        "taos_als_calibrate failed: trim_val of %d is out of range\n",
 384                        gain_trim_val);
 385                return -ENODATA;
 386        }
 387        chip->taos_settings.als_gain_trim = (int) gain_trim_val;
 388
 389        return (int) gain_trim_val;
 390}
 391
 392/*
 393 * Turn the device on.
 394 * Configuration must be set before calling this function.
 395 */
 396static int taos_chip_on(struct iio_dev *indio_dev)
 397{
 398        int i;
 399        int ret;
 400        u8 *uP;
 401        u8 utmp;
 402        int als_count;
 403        int als_time;
 404        struct tsl2583_chip *chip = iio_priv(indio_dev);
 405
 406        /* and make sure we're not already on */
 407        if (chip->taos_chip_status == TSL258X_CHIP_WORKING) {
 408                /* if forcing a register update - turn off, then on */
 409                dev_info(&chip->client->dev, "device is already enabled\n");
 410                return -EINVAL;
 411        }
 412
 413        /* determine als integration register */
 414        als_count = (chip->taos_settings.als_time * 100 + 135) / 270;
 415        if (als_count == 0)
 416                als_count = 1; /* ensure at least one cycle */
 417
 418        /* convert back to time (encompasses overrides) */
 419        als_time = (als_count * 27 + 5) / 10;
 420        chip->taos_config[TSL258X_ALS_TIME] = 256 - als_count;
 421
 422        /* Set the gain based on taos_settings struct */
 423        chip->taos_config[TSL258X_GAIN] = chip->taos_settings.als_gain;
 424
 425        /* set chip struct re scaling and saturation */
 426        chip->als_saturation = als_count * 922; /* 90% of full scale */
 427        chip->als_time_scale = (als_time + 25) / 50;
 428
 429        /* TSL258x Specific power-on / adc enable sequence
 430         * Power on the device 1st. */
 431        utmp = TSL258X_CNTL_PWR_ON;
 432        ret = i2c_smbus_write_byte_data(chip->client,
 433                                        TSL258X_CMD_REG | TSL258X_CNTRL, utmp);
 434        if (ret < 0) {
 435                dev_err(&chip->client->dev, "taos_chip_on failed on CNTRL reg.\n");
 436                return -1;
 437        }
 438
 439        /* Use the following shadow copy for our delay before enabling ADC.
 440         * Write all the registers. */
 441        for (i = 0, uP = chip->taos_config; i < TSL258X_REG_MAX; i++) {
 442                ret = i2c_smbus_write_byte_data(chip->client,
 443                                                TSL258X_CMD_REG + i,
 444                                                *uP++);
 445                if (ret < 0) {
 446                        dev_err(&chip->client->dev,
 447                                "taos_chip_on failed on reg %d.\n", i);
 448                        return -1;
 449                }
 450        }
 451
 452        msleep(3);
 453        /* NOW enable the ADC
 454         * initialize the desired mode of operation */
 455        utmp = TSL258X_CNTL_PWR_ON | TSL258X_CNTL_ADC_ENBL;
 456        ret = i2c_smbus_write_byte_data(chip->client,
 457                                        TSL258X_CMD_REG | TSL258X_CNTRL,
 458                                        utmp);
 459        if (ret < 0) {
 460                dev_err(&chip->client->dev, "taos_chip_on failed on 2nd CTRL reg.\n");
 461                return -1;
 462        }
 463        chip->taos_chip_status = TSL258X_CHIP_WORKING;
 464
 465        return ret;
 466}
 467
 468static int taos_chip_off(struct iio_dev *indio_dev)
 469{
 470        struct tsl2583_chip *chip = iio_priv(indio_dev);
 471        int ret;
 472
 473        /* turn device off */
 474        chip->taos_chip_status = TSL258X_CHIP_SUSPENDED;
 475        ret = i2c_smbus_write_byte_data(chip->client,
 476                                        TSL258X_CMD_REG | TSL258X_CNTRL,
 477                                        0x00);
 478        return ret;
 479}
 480
 481/* Sysfs Interface Functions */
 482
 483static ssize_t taos_power_state_show(struct device *dev,
 484        struct device_attribute *attr, char *buf)
 485{
 486        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 487        struct tsl2583_chip *chip = iio_priv(indio_dev);
 488
 489        return sprintf(buf, "%d\n", chip->taos_chip_status);
 490}
 491
 492static ssize_t taos_power_state_store(struct device *dev,
 493        struct device_attribute *attr, const char *buf, size_t len)
 494{
 495        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 496        unsigned long value;
 497
 498        if (strict_strtoul(buf, 0, &value))
 499                return -EINVAL;
 500
 501        if (value == 0)
 502                taos_chip_off(indio_dev);
 503        else
 504                taos_chip_on(indio_dev);
 505
 506        return len;
 507}
 508
 509static ssize_t taos_gain_show(struct device *dev,
 510        struct device_attribute *attr, char *buf)
 511{
 512        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 513        struct tsl2583_chip *chip = iio_priv(indio_dev);
 514        char gain[4] = {0};
 515
 516        switch (chip->taos_settings.als_gain) {
 517        case 0:
 518                strcpy(gain, "001");
 519                break;
 520        case 1:
 521                strcpy(gain, "008");
 522                break;
 523        case 2:
 524                strcpy(gain, "016");
 525                break;
 526        case 3:
 527                strcpy(gain, "111");
 528                break;
 529        }
 530
 531        return sprintf(buf, "%s\n", gain);
 532}
 533
 534static ssize_t taos_gain_store(struct device *dev,
 535        struct device_attribute *attr, const char *buf, size_t len)
 536{
 537        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 538        struct tsl2583_chip *chip = iio_priv(indio_dev);
 539        unsigned long value;
 540
 541        if (strict_strtoul(buf, 0, &value))
 542                return -EINVAL;
 543
 544        switch (value) {
 545        case 1:
 546                chip->taos_settings.als_gain = 0;
 547                break;
 548        case 8:
 549                chip->taos_settings.als_gain = 1;
 550                break;
 551        case 16:
 552                chip->taos_settings.als_gain = 2;
 553                break;
 554        case 111:
 555                chip->taos_settings.als_gain = 3;
 556                break;
 557        default:
 558                dev_err(dev, "Invalid Gain Index (must be 1,8,16,111)\n");
 559                return -1;
 560        }
 561
 562        return len;
 563}
 564
 565static ssize_t taos_gain_available_show(struct device *dev,
 566        struct device_attribute *attr, char *buf)
 567{
 568        return sprintf(buf, "%s\n", "1 8 16 111");
 569}
 570
 571static ssize_t taos_als_time_show(struct device *dev,
 572        struct device_attribute *attr, char *buf)
 573{
 574        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 575        struct tsl2583_chip *chip = iio_priv(indio_dev);
 576
 577        return sprintf(buf, "%d\n", chip->taos_settings.als_time);
 578}
 579
 580static ssize_t taos_als_time_store(struct device *dev,
 581        struct device_attribute *attr, const char *buf, size_t len)
 582{
 583        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 584        struct tsl2583_chip *chip = iio_priv(indio_dev);
 585        unsigned long value;
 586
 587        if (strict_strtoul(buf, 0, &value))
 588                return -EINVAL;
 589
 590        if ((value < 50) || (value > 650))
 591                return -EINVAL;
 592
 593        if (value % 50)
 594                return -EINVAL;
 595
 596        chip->taos_settings.als_time = value;
 597
 598        return len;
 599}
 600
 601static ssize_t taos_als_time_available_show(struct device *dev,
 602        struct device_attribute *attr, char *buf)
 603{
 604        return sprintf(buf, "%s\n",
 605                "50 100 150 200 250 300 350 400 450 500 550 600 650");
 606}
 607
 608static ssize_t taos_als_trim_show(struct device *dev,
 609        struct device_attribute *attr, char *buf)
 610{
 611        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 612        struct tsl2583_chip *chip = iio_priv(indio_dev);
 613
 614        return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim);
 615}
 616
 617static ssize_t taos_als_trim_store(struct device *dev,
 618        struct device_attribute *attr, const char *buf, size_t len)
 619{
 620        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 621        struct tsl2583_chip *chip = iio_priv(indio_dev);
 622        unsigned long value;
 623
 624        if (strict_strtoul(buf, 0, &value))
 625                return -EINVAL;
 626
 627        if (value)
 628                chip->taos_settings.als_gain_trim = value;
 629
 630        return len;
 631}
 632
 633static ssize_t taos_als_cal_target_show(struct device *dev,
 634        struct device_attribute *attr, char *buf)
 635{
 636        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 637        struct tsl2583_chip *chip = iio_priv(indio_dev);
 638
 639        return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target);
 640}
 641
 642static ssize_t taos_als_cal_target_store(struct device *dev,
 643        struct device_attribute *attr, const char *buf, size_t len)
 644{
 645        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 646        struct tsl2583_chip *chip = iio_priv(indio_dev);
 647        unsigned long value;
 648
 649        if (strict_strtoul(buf, 0, &value))
 650                return -EINVAL;
 651
 652        if (value)
 653                chip->taos_settings.als_cal_target = value;
 654
 655        return len;
 656}
 657
 658static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
 659        char *buf)
 660{
 661        int ret;
 662
 663        ret = taos_get_lux(dev_to_iio_dev(dev));
 664        if (ret < 0)
 665                return ret;
 666
 667        return sprintf(buf, "%d\n", ret);
 668}
 669
 670static ssize_t taos_do_calibrate(struct device *dev,
 671        struct device_attribute *attr, const char *buf, size_t len)
 672{
 673        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 674        unsigned long value;
 675
 676        if (strict_strtoul(buf, 0, &value))
 677                return -EINVAL;
 678
 679        if (value == 1)
 680                taos_als_calibrate(indio_dev);
 681
 682        return len;
 683}
 684
 685static ssize_t taos_luxtable_show(struct device *dev,
 686        struct device_attribute *attr, char *buf)
 687{
 688        int i;
 689        int offset = 0;
 690
 691        for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) {
 692                offset += sprintf(buf + offset, "%d,%d,%d,",
 693                                  taos_device_lux[i].ratio,
 694                                  taos_device_lux[i].ch0,
 695                                  taos_device_lux[i].ch1);
 696                if (taos_device_lux[i].ratio == 0) {
 697                        /* We just printed the first "0" entry.
 698                         * Now get rid of the extra "," and break. */
 699                        offset--;
 700                        break;
 701                }
 702        }
 703
 704        offset += sprintf(buf + offset, "\n");
 705        return offset;
 706}
 707
 708static ssize_t taos_luxtable_store(struct device *dev,
 709        struct device_attribute *attr, const char *buf, size_t len)
 710{
 711        struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 712        struct tsl2583_chip *chip = iio_priv(indio_dev);
 713        int value[ARRAY_SIZE(taos_device_lux)*3 + 1];
 714        int n;
 715
 716        get_options(buf, ARRAY_SIZE(value), value);
 717
 718        /* We now have an array of ints starting at value[1], and
 719         * enumerated by value[0].
 720         * We expect each group of three ints is one table entry,
 721         * and the last table entry is all 0.
 722         */
 723        n = value[0];
 724        if ((n % 3) || n < 6 || n > ((ARRAY_SIZE(taos_device_lux) - 1) * 3)) {
 725                dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
 726                return -EINVAL;
 727        }
 728        if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
 729                dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
 730                return -EINVAL;
 731        }
 732
 733        if (chip->taos_chip_status == TSL258X_CHIP_WORKING)
 734                taos_chip_off(indio_dev);
 735
 736        /* Zero out the table */
 737        memset(taos_device_lux, 0, sizeof(taos_device_lux));
 738        memcpy(taos_device_lux, &value[1], (value[0] * 4));
 739
 740        taos_chip_on(indio_dev);
 741
 742        return len;
 743}
 744
 745static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
 746                taos_power_state_show, taos_power_state_store);
 747
 748static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR,
 749                taos_gain_show, taos_gain_store);
 750static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO,
 751                taos_gain_available_show, NULL);
 752
 753static DEVICE_ATTR(illuminance0_integration_time, S_IRUGO | S_IWUSR,
 754                taos_als_time_show, taos_als_time_store);
 755static DEVICE_ATTR(illuminance0_integration_time_available, S_IRUGO,
 756                taos_als_time_available_show, NULL);
 757
 758static DEVICE_ATTR(illuminance0_calibbias, S_IRUGO | S_IWUSR,
 759                taos_als_trim_show, taos_als_trim_store);
 760
 761static DEVICE_ATTR(illuminance0_input_target, S_IRUGO | S_IWUSR,
 762                taos_als_cal_target_show, taos_als_cal_target_store);
 763
 764static DEVICE_ATTR(illuminance0_input, S_IRUGO, taos_lux_show, NULL);
 765static DEVICE_ATTR(illuminance0_calibrate, S_IWUSR, NULL, taos_do_calibrate);
 766static DEVICE_ATTR(illuminance0_lux_table, S_IRUGO | S_IWUSR,
 767                taos_luxtable_show, taos_luxtable_store);
 768
 769static struct attribute *sysfs_attrs_ctrl[] = {
 770        &dev_attr_power_state.attr,
 771        &dev_attr_illuminance0_calibscale.attr,                 /* Gain  */
 772        &dev_attr_illuminance0_calibscale_available.attr,
 773        &dev_attr_illuminance0_integration_time.attr,   /* I time*/
 774        &dev_attr_illuminance0_integration_time_available.attr,
 775        &dev_attr_illuminance0_calibbias.attr,                  /* trim  */
 776        &dev_attr_illuminance0_input_target.attr,
 777        &dev_attr_illuminance0_input.attr,
 778        &dev_attr_illuminance0_calibrate.attr,
 779        &dev_attr_illuminance0_lux_table.attr,
 780        NULL
 781};
 782
 783static struct attribute_group tsl2583_attribute_group = {
 784        .attrs = sysfs_attrs_ctrl,
 785};
 786
 787/* Use the default register values to identify the Taos device */
 788static int taos_tsl258x_device(unsigned char *bufp)
 789{
 790        return ((bufp[TSL258X_CHIPID] & 0xf0) == 0x90);
 791}
 792
 793static const struct iio_info tsl2583_info = {
 794        .attrs = &tsl2583_attribute_group,
 795        .driver_module = THIS_MODULE,
 796};
 797
 798/*
 799 * Client probe function - When a valid device is found, the driver's device
 800 * data structure is updated, and initialization completes successfully.
 801 */
 802static int taos_probe(struct i2c_client *clientp,
 803                      const struct i2c_device_id *idp)
 804{
 805        int i, ret;
 806        unsigned char buf[TSL258X_MAX_DEVICE_REGS];
 807        struct tsl2583_chip *chip;
 808        struct iio_dev *indio_dev;
 809
 810        if (!i2c_check_functionality(clientp->adapter,
 811                I2C_FUNC_SMBUS_BYTE_DATA)) {
 812                dev_err(&clientp->dev,
 813                        "taos_probe() - i2c smbus byte data "
 814                        "functions unsupported\n");
 815                return -EOPNOTSUPP;
 816        }
 817
 818        indio_dev = iio_device_alloc(sizeof(*chip));
 819        if (indio_dev == NULL) {
 820                ret = -ENOMEM;
 821                dev_err(&clientp->dev, "iio allocation failed\n");
 822                goto fail1;
 823        }
 824        chip = iio_priv(indio_dev);
 825        chip->client = clientp;
 826        i2c_set_clientdata(clientp, indio_dev);
 827
 828        mutex_init(&chip->als_mutex);
 829        chip->taos_chip_status = TSL258X_CHIP_UNKNOWN;
 830        memcpy(chip->taos_config, taos_config, sizeof(chip->taos_config));
 831
 832        for (i = 0; i < TSL258X_MAX_DEVICE_REGS; i++) {
 833                ret = i2c_smbus_write_byte(clientp,
 834                                (TSL258X_CMD_REG | (TSL258X_CNTRL + i)));
 835                if (ret < 0) {
 836                        dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd "
 837                                "reg failed in taos_probe(), err = %d\n", ret);
 838                        goto fail2;
 839                }
 840                ret = i2c_smbus_read_byte(clientp);
 841                if (ret < 0) {
 842                        dev_err(&clientp->dev, "i2c_smbus_read_byte from "
 843                                "reg failed in taos_probe(), err = %d\n", ret);
 844
 845                        goto fail2;
 846                }
 847                buf[i] = ret;
 848        }
 849
 850        if (!taos_tsl258x_device(buf)) {
 851                dev_info(&clientp->dev, "i2c device found but does not match "
 852                        "expected id in taos_probe()\n");
 853                goto fail2;
 854        }
 855
 856        ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL));
 857        if (ret < 0) {
 858                dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg "
 859                        "failed in taos_probe(), err = %d\n", ret);
 860                goto fail2;
 861        }
 862
 863        indio_dev->info = &tsl2583_info;
 864        indio_dev->dev.parent = &clientp->dev;
 865        indio_dev->modes = INDIO_DIRECT_MODE;
 866        indio_dev->name = chip->client->name;
 867        ret = iio_device_register(indio_dev);
 868        if (ret) {
 869                dev_err(&clientp->dev, "iio registration failed\n");
 870                goto fail2;
 871        }
 872
 873        /* Load up the V2 defaults (these are hard coded defaults for now) */
 874        taos_defaults(chip);
 875
 876        /* Make sure the chip is on */
 877        taos_chip_on(indio_dev);
 878
 879        dev_info(&clientp->dev, "Light sensor found.\n");
 880        return 0;
 881fail1:
 882        iio_device_free(indio_dev);
 883fail2:
 884        return ret;
 885}
 886
 887#ifdef CONFIG_PM_SLEEP
 888static int taos_suspend(struct device *dev)
 889{
 890        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 891        struct tsl2583_chip *chip = iio_priv(indio_dev);
 892        int ret = 0;
 893
 894        mutex_lock(&chip->als_mutex);
 895
 896        if (chip->taos_chip_status == TSL258X_CHIP_WORKING) {
 897                ret = taos_chip_off(indio_dev);
 898                chip->taos_chip_status = TSL258X_CHIP_SUSPENDED;
 899        }
 900
 901        mutex_unlock(&chip->als_mutex);
 902        return ret;
 903}
 904
 905static int taos_resume(struct device *dev)
 906{
 907        struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
 908        struct tsl2583_chip *chip = iio_priv(indio_dev);
 909        int ret = 0;
 910
 911        mutex_lock(&chip->als_mutex);
 912
 913        if (chip->taos_chip_status == TSL258X_CHIP_SUSPENDED)
 914                ret = taos_chip_on(indio_dev);
 915
 916        mutex_unlock(&chip->als_mutex);
 917        return ret;
 918}
 919
 920static SIMPLE_DEV_PM_OPS(taos_pm_ops, taos_suspend, taos_resume);
 921#define TAOS_PM_OPS (&taos_pm_ops)
 922#else
 923#define TAOS_PM_OPS NULL
 924#endif
 925
 926static int taos_remove(struct i2c_client *client)
 927{
 928        iio_device_unregister(i2c_get_clientdata(client));
 929        iio_device_free(i2c_get_clientdata(client));
 930
 931        return 0;
 932}
 933
 934static struct i2c_device_id taos_idtable[] = {
 935        { "tsl2580", 0 },
 936        { "tsl2581", 1 },
 937        { "tsl2583", 2 },
 938        {}
 939};
 940MODULE_DEVICE_TABLE(i2c, taos_idtable);
 941
 942/* Driver definition */
 943static struct i2c_driver taos_driver = {
 944        .driver = {
 945                .name = "tsl2583",
 946                .pm = TAOS_PM_OPS,
 947        },
 948        .id_table = taos_idtable,
 949        .probe = taos_probe,
 950        .remove = taos_remove,
 951};
 952module_i2c_driver(taos_driver);
 953
 954MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
 955MODULE_DESCRIPTION("TAOS tsl2583 ambient light sensor driver");
 956MODULE_LICENSE("GPL");
 957