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