root/drivers/iio/light/lm3533-als.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lm3533_als_get_adc
  2. _lm3533_als_get_zone
  3. lm3533_als_get_zone
  4. lm3533_als_get_target_reg
  5. lm3533_als_get_target
  6. lm3533_als_set_target
  7. lm3533_als_get_current
  8. lm3533_als_read_raw
  9. lm3533_als_isr
  10. lm3533_als_set_int_mode
  11. lm3533_als_get_int_mode
  12. lm3533_als_get_threshold_reg
  13. lm3533_als_get_threshold
  14. lm3533_als_set_threshold
  15. lm3533_als_get_hysteresis
  16. show_thresh_either_en
  17. store_thresh_either_en
  18. show_zone
  19. to_lm3533_als_attr
  20. show_als_attr
  21. store_als_attr
  22. lm3533_als_set_input_mode
  23. lm3533_als_set_resistor
  24. lm3533_als_setup
  25. lm3533_als_setup_irq
  26. lm3533_als_enable
  27. lm3533_als_disable
  28. lm3533_als_probe
  29. lm3533_als_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * lm3533-als.c -- LM3533 Ambient Light Sensor driver
   4  *
   5  * Copyright (C) 2011-2012 Texas Instruments
   6  *
   7  * Author: Johan Hovold <jhovold@gmail.com>
   8  */
   9 
  10 #include <linux/atomic.h>
  11 #include <linux/fs.h>
  12 #include <linux/interrupt.h>
  13 #include <linux/io.h>
  14 #include <linux/iio/events.h>
  15 #include <linux/iio/iio.h>
  16 #include <linux/module.h>
  17 #include <linux/mutex.h>
  18 #include <linux/mfd/core.h>
  19 #include <linux/platform_device.h>
  20 #include <linux/slab.h>
  21 #include <linux/uaccess.h>
  22 
  23 #include <linux/mfd/lm3533.h>
  24 
  25 
  26 #define LM3533_ALS_RESISTOR_MIN                 1
  27 #define LM3533_ALS_RESISTOR_MAX                 127
  28 #define LM3533_ALS_CHANNEL_CURRENT_MAX          2
  29 #define LM3533_ALS_THRESH_MAX                   3
  30 #define LM3533_ALS_ZONE_MAX                     4
  31 
  32 #define LM3533_REG_ALS_RESISTOR_SELECT          0x30
  33 #define LM3533_REG_ALS_CONF                     0x31
  34 #define LM3533_REG_ALS_ZONE_INFO                0x34
  35 #define LM3533_REG_ALS_READ_ADC_RAW             0x37
  36 #define LM3533_REG_ALS_READ_ADC_AVERAGE         0x38
  37 #define LM3533_REG_ALS_BOUNDARY_BASE            0x50
  38 #define LM3533_REG_ALS_TARGET_BASE              0x60
  39 
  40 #define LM3533_ALS_ENABLE_MASK                  0x01
  41 #define LM3533_ALS_INPUT_MODE_MASK              0x02
  42 #define LM3533_ALS_INT_ENABLE_MASK              0x01
  43 
  44 #define LM3533_ALS_ZONE_SHIFT                   2
  45 #define LM3533_ALS_ZONE_MASK                    0x1c
  46 
  47 #define LM3533_ALS_FLAG_INT_ENABLED             1
  48 
  49 
  50 struct lm3533_als {
  51         struct lm3533 *lm3533;
  52         struct platform_device *pdev;
  53 
  54         unsigned long flags;
  55         int irq;
  56 
  57         atomic_t zone;
  58         struct mutex thresh_mutex;
  59 };
  60 
  61 
  62 static int lm3533_als_get_adc(struct iio_dev *indio_dev, bool average,
  63                                                                 int *adc)
  64 {
  65         struct lm3533_als *als = iio_priv(indio_dev);
  66         u8 reg;
  67         u8 val;
  68         int ret;
  69 
  70         if (average)
  71                 reg = LM3533_REG_ALS_READ_ADC_AVERAGE;
  72         else
  73                 reg = LM3533_REG_ALS_READ_ADC_RAW;
  74 
  75         ret = lm3533_read(als->lm3533, reg, &val);
  76         if (ret) {
  77                 dev_err(&indio_dev->dev, "failed to read adc\n");
  78                 return ret;
  79         }
  80 
  81         *adc = val;
  82 
  83         return 0;
  84 }
  85 
  86 static int _lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
  87 {
  88         struct lm3533_als *als = iio_priv(indio_dev);
  89         u8 val;
  90         int ret;
  91 
  92         ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
  93         if (ret) {
  94                 dev_err(&indio_dev->dev, "failed to read zone\n");
  95                 return ret;
  96         }
  97 
  98         val = (val & LM3533_ALS_ZONE_MASK) >> LM3533_ALS_ZONE_SHIFT;
  99         *zone = min_t(u8, val, LM3533_ALS_ZONE_MAX);
 100 
 101         return 0;
 102 }
 103 
 104 static int lm3533_als_get_zone(struct iio_dev *indio_dev, u8 *zone)
 105 {
 106         struct lm3533_als *als = iio_priv(indio_dev);
 107         int ret;
 108 
 109         if (test_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags)) {
 110                 *zone = atomic_read(&als->zone);
 111         } else {
 112                 ret = _lm3533_als_get_zone(indio_dev, zone);
 113                 if (ret)
 114                         return ret;
 115         }
 116 
 117         return 0;
 118 }
 119 
 120 /*
 121  * channel      output channel 0..2
 122  * zone         zone 0..4
 123  */
 124 static inline u8 lm3533_als_get_target_reg(unsigned channel, unsigned zone)
 125 {
 126         return LM3533_REG_ALS_TARGET_BASE + 5 * channel + zone;
 127 }
 128 
 129 static int lm3533_als_get_target(struct iio_dev *indio_dev, unsigned channel,
 130                                                         unsigned zone, u8 *val)
 131 {
 132         struct lm3533_als *als = iio_priv(indio_dev);
 133         u8 reg;
 134         int ret;
 135 
 136         if (channel > LM3533_ALS_CHANNEL_CURRENT_MAX)
 137                 return -EINVAL;
 138 
 139         if (zone > LM3533_ALS_ZONE_MAX)
 140                 return -EINVAL;
 141 
 142         reg = lm3533_als_get_target_reg(channel, zone);
 143         ret = lm3533_read(als->lm3533, reg, val);
 144         if (ret)
 145                 dev_err(&indio_dev->dev, "failed to get target current\n");
 146 
 147         return ret;
 148 }
 149 
 150 static int lm3533_als_set_target(struct iio_dev *indio_dev, unsigned channel,
 151                                                         unsigned zone, u8 val)
 152 {
 153         struct lm3533_als *als = iio_priv(indio_dev);
 154         u8 reg;
 155         int ret;
 156 
 157         if (channel > LM3533_ALS_CHANNEL_CURRENT_MAX)
 158                 return -EINVAL;
 159 
 160         if (zone > LM3533_ALS_ZONE_MAX)
 161                 return -EINVAL;
 162 
 163         reg = lm3533_als_get_target_reg(channel, zone);
 164         ret = lm3533_write(als->lm3533, reg, val);
 165         if (ret)
 166                 dev_err(&indio_dev->dev, "failed to set target current\n");
 167 
 168         return ret;
 169 }
 170 
 171 static int lm3533_als_get_current(struct iio_dev *indio_dev, unsigned channel,
 172                                                                 int *val)
 173 {
 174         u8 zone;
 175         u8 target;
 176         int ret;
 177 
 178         ret = lm3533_als_get_zone(indio_dev, &zone);
 179         if (ret)
 180                 return ret;
 181 
 182         ret = lm3533_als_get_target(indio_dev, channel, zone, &target);
 183         if (ret)
 184                 return ret;
 185 
 186         *val = target;
 187 
 188         return 0;
 189 }
 190 
 191 static int lm3533_als_read_raw(struct iio_dev *indio_dev,
 192                                 struct iio_chan_spec const *chan,
 193                                 int *val, int *val2, long mask)
 194 {
 195         int ret;
 196 
 197         switch (mask) {
 198         case IIO_CHAN_INFO_RAW:
 199                 switch (chan->type) {
 200                 case IIO_LIGHT:
 201                         ret = lm3533_als_get_adc(indio_dev, false, val);
 202                         break;
 203                 case IIO_CURRENT:
 204                         ret = lm3533_als_get_current(indio_dev, chan->channel,
 205                                                                         val);
 206                         break;
 207                 default:
 208                         return -EINVAL;
 209                 }
 210                 break;
 211         case IIO_CHAN_INFO_AVERAGE_RAW:
 212                 ret = lm3533_als_get_adc(indio_dev, true, val);
 213                 break;
 214         default:
 215                 return -EINVAL;
 216         }
 217 
 218         if (ret)
 219                 return ret;
 220 
 221         return IIO_VAL_INT;
 222 }
 223 
 224 #define CHANNEL_CURRENT(_channel)                                       \
 225         {                                                               \
 226                 .type           = IIO_CURRENT,                          \
 227                 .channel        = _channel,                             \
 228                 .indexed        = true,                                 \
 229                 .output         = true,                                 \
 230                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),           \
 231         }
 232 
 233 static const struct iio_chan_spec lm3533_als_channels[] = {
 234         {
 235                 .type           = IIO_LIGHT,
 236                 .channel        = 0,
 237                 .indexed        = true,
 238                 .info_mask_separate = BIT(IIO_CHAN_INFO_AVERAGE_RAW) |
 239                                    BIT(IIO_CHAN_INFO_RAW),
 240         },
 241         CHANNEL_CURRENT(0),
 242         CHANNEL_CURRENT(1),
 243         CHANNEL_CURRENT(2),
 244 };
 245 
 246 static irqreturn_t lm3533_als_isr(int irq, void *dev_id)
 247 {
 248 
 249         struct iio_dev *indio_dev = dev_id;
 250         struct lm3533_als *als = iio_priv(indio_dev);
 251         u8 zone;
 252         int ret;
 253 
 254         /* Clear interrupt by reading the ALS zone register. */
 255         ret = _lm3533_als_get_zone(indio_dev, &zone);
 256         if (ret)
 257                 goto out;
 258 
 259         atomic_set(&als->zone, zone);
 260 
 261         iio_push_event(indio_dev,
 262                        IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
 263                                             0,
 264                                             IIO_EV_TYPE_THRESH,
 265                                             IIO_EV_DIR_EITHER),
 266                        iio_get_time_ns(indio_dev));
 267 out:
 268         return IRQ_HANDLED;
 269 }
 270 
 271 static int lm3533_als_set_int_mode(struct iio_dev *indio_dev, int enable)
 272 {
 273         struct lm3533_als *als = iio_priv(indio_dev);
 274         u8 mask = LM3533_ALS_INT_ENABLE_MASK;
 275         u8 val;
 276         int ret;
 277 
 278         if (enable)
 279                 val = mask;
 280         else
 281                 val = 0;
 282 
 283         ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, val, mask);
 284         if (ret) {
 285                 dev_err(&indio_dev->dev, "failed to set int mode %d\n",
 286                                                                 enable);
 287                 return ret;
 288         }
 289 
 290         return 0;
 291 }
 292 
 293 static int lm3533_als_get_int_mode(struct iio_dev *indio_dev, int *enable)
 294 {
 295         struct lm3533_als *als = iio_priv(indio_dev);
 296         u8 mask = LM3533_ALS_INT_ENABLE_MASK;
 297         u8 val;
 298         int ret;
 299 
 300         ret = lm3533_read(als->lm3533, LM3533_REG_ALS_ZONE_INFO, &val);
 301         if (ret) {
 302                 dev_err(&indio_dev->dev, "failed to get int mode\n");
 303                 return ret;
 304         }
 305 
 306         *enable = !!(val & mask);
 307 
 308         return 0;
 309 }
 310 
 311 static inline u8 lm3533_als_get_threshold_reg(unsigned nr, bool raising)
 312 {
 313         u8 offset = !raising;
 314 
 315         return LM3533_REG_ALS_BOUNDARY_BASE + 2 * nr + offset;
 316 }
 317 
 318 static int lm3533_als_get_threshold(struct iio_dev *indio_dev, unsigned nr,
 319                                                         bool raising, u8 *val)
 320 {
 321         struct lm3533_als *als = iio_priv(indio_dev);
 322         u8 reg;
 323         int ret;
 324 
 325         if (nr > LM3533_ALS_THRESH_MAX)
 326                 return -EINVAL;
 327 
 328         reg = lm3533_als_get_threshold_reg(nr, raising);
 329         ret = lm3533_read(als->lm3533, reg, val);
 330         if (ret)
 331                 dev_err(&indio_dev->dev, "failed to get threshold\n");
 332 
 333         return ret;
 334 }
 335 
 336 static int lm3533_als_set_threshold(struct iio_dev *indio_dev, unsigned nr,
 337                                                         bool raising, u8 val)
 338 {
 339         struct lm3533_als *als = iio_priv(indio_dev);
 340         u8 val2;
 341         u8 reg, reg2;
 342         int ret;
 343 
 344         if (nr > LM3533_ALS_THRESH_MAX)
 345                 return -EINVAL;
 346 
 347         reg = lm3533_als_get_threshold_reg(nr, raising);
 348         reg2 = lm3533_als_get_threshold_reg(nr, !raising);
 349 
 350         mutex_lock(&als->thresh_mutex);
 351         ret = lm3533_read(als->lm3533, reg2, &val2);
 352         if (ret) {
 353                 dev_err(&indio_dev->dev, "failed to get threshold\n");
 354                 goto out;
 355         }
 356         /*
 357          * This device does not allow negative hysteresis (in fact, it uses
 358          * whichever value is smaller as the lower bound) so we need to make
 359          * sure that thresh_falling <= thresh_raising.
 360          */
 361         if ((raising && (val < val2)) || (!raising && (val > val2))) {
 362                 ret = -EINVAL;
 363                 goto out;
 364         }
 365 
 366         ret = lm3533_write(als->lm3533, reg, val);
 367         if (ret) {
 368                 dev_err(&indio_dev->dev, "failed to set threshold\n");
 369                 goto out;
 370         }
 371 out:
 372         mutex_unlock(&als->thresh_mutex);
 373 
 374         return ret;
 375 }
 376 
 377 static int lm3533_als_get_hysteresis(struct iio_dev *indio_dev, unsigned nr,
 378                                                                 u8 *val)
 379 {
 380         struct lm3533_als *als = iio_priv(indio_dev);
 381         u8 falling;
 382         u8 raising;
 383         int ret;
 384 
 385         if (nr > LM3533_ALS_THRESH_MAX)
 386                 return -EINVAL;
 387 
 388         mutex_lock(&als->thresh_mutex);
 389         ret = lm3533_als_get_threshold(indio_dev, nr, false, &falling);
 390         if (ret)
 391                 goto out;
 392         ret = lm3533_als_get_threshold(indio_dev, nr, true, &raising);
 393         if (ret)
 394                 goto out;
 395 
 396         *val = raising - falling;
 397 out:
 398         mutex_unlock(&als->thresh_mutex);
 399 
 400         return ret;
 401 }
 402 
 403 static ssize_t show_thresh_either_en(struct device *dev,
 404                                         struct device_attribute *attr,
 405                                         char *buf)
 406 {
 407         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 408         struct lm3533_als *als = iio_priv(indio_dev);
 409         int enable;
 410         int ret;
 411 
 412         if (als->irq) {
 413                 ret = lm3533_als_get_int_mode(indio_dev, &enable);
 414                 if (ret)
 415                         return ret;
 416         } else {
 417                 enable = 0;
 418         }
 419 
 420         return scnprintf(buf, PAGE_SIZE, "%u\n", enable);
 421 }
 422 
 423 static ssize_t store_thresh_either_en(struct device *dev,
 424                                         struct device_attribute *attr,
 425                                         const char *buf, size_t len)
 426 {
 427         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 428         struct lm3533_als *als = iio_priv(indio_dev);
 429         unsigned long enable;
 430         bool int_enabled;
 431         u8 zone;
 432         int ret;
 433 
 434         if (!als->irq)
 435                 return -EBUSY;
 436 
 437         if (kstrtoul(buf, 0, &enable))
 438                 return -EINVAL;
 439 
 440         int_enabled = test_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
 441 
 442         if (enable && !int_enabled) {
 443                 ret = lm3533_als_get_zone(indio_dev, &zone);
 444                 if (ret)
 445                         return ret;
 446 
 447                 atomic_set(&als->zone, zone);
 448 
 449                 set_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
 450         }
 451 
 452         ret = lm3533_als_set_int_mode(indio_dev, enable);
 453         if (ret) {
 454                 if (!int_enabled)
 455                         clear_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
 456 
 457                 return ret;
 458         }
 459 
 460         if (!enable)
 461                 clear_bit(LM3533_ALS_FLAG_INT_ENABLED, &als->flags);
 462 
 463         return len;
 464 }
 465 
 466 static ssize_t show_zone(struct device *dev,
 467                                 struct device_attribute *attr, char *buf)
 468 {
 469         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 470         u8 zone;
 471         int ret;
 472 
 473         ret = lm3533_als_get_zone(indio_dev, &zone);
 474         if (ret)
 475                 return ret;
 476 
 477         return scnprintf(buf, PAGE_SIZE, "%u\n", zone);
 478 }
 479 
 480 enum lm3533_als_attribute_type {
 481         LM3533_ATTR_TYPE_HYSTERESIS,
 482         LM3533_ATTR_TYPE_TARGET,
 483         LM3533_ATTR_TYPE_THRESH_FALLING,
 484         LM3533_ATTR_TYPE_THRESH_RAISING,
 485 };
 486 
 487 struct lm3533_als_attribute {
 488         struct device_attribute dev_attr;
 489         enum lm3533_als_attribute_type type;
 490         u8 val1;
 491         u8 val2;
 492 };
 493 
 494 static inline struct lm3533_als_attribute *
 495 to_lm3533_als_attr(struct device_attribute *attr)
 496 {
 497         return container_of(attr, struct lm3533_als_attribute, dev_attr);
 498 }
 499 
 500 static ssize_t show_als_attr(struct device *dev,
 501                                         struct device_attribute *attr,
 502                                         char *buf)
 503 {
 504         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 505         struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
 506         u8 val;
 507         int ret;
 508 
 509         switch (als_attr->type) {
 510         case LM3533_ATTR_TYPE_HYSTERESIS:
 511                 ret = lm3533_als_get_hysteresis(indio_dev, als_attr->val1,
 512                                                                         &val);
 513                 break;
 514         case LM3533_ATTR_TYPE_TARGET:
 515                 ret = lm3533_als_get_target(indio_dev, als_attr->val1,
 516                                                         als_attr->val2, &val);
 517                 break;
 518         case LM3533_ATTR_TYPE_THRESH_FALLING:
 519                 ret = lm3533_als_get_threshold(indio_dev, als_attr->val1,
 520                                                                 false, &val);
 521                 break;
 522         case LM3533_ATTR_TYPE_THRESH_RAISING:
 523                 ret = lm3533_als_get_threshold(indio_dev, als_attr->val1,
 524                                                                 true, &val);
 525                 break;
 526         default:
 527                 ret = -ENXIO;
 528         }
 529 
 530         if (ret)
 531                 return ret;
 532 
 533         return scnprintf(buf, PAGE_SIZE, "%u\n", val);
 534 }
 535 
 536 static ssize_t store_als_attr(struct device *dev,
 537                                         struct device_attribute *attr,
 538                                         const char *buf, size_t len)
 539 {
 540         struct iio_dev *indio_dev = dev_to_iio_dev(dev);
 541         struct lm3533_als_attribute *als_attr = to_lm3533_als_attr(attr);
 542         u8 val;
 543         int ret;
 544 
 545         if (kstrtou8(buf, 0, &val))
 546                 return -EINVAL;
 547 
 548         switch (als_attr->type) {
 549         case LM3533_ATTR_TYPE_TARGET:
 550                 ret = lm3533_als_set_target(indio_dev, als_attr->val1,
 551                                                         als_attr->val2, val);
 552                 break;
 553         case LM3533_ATTR_TYPE_THRESH_FALLING:
 554                 ret = lm3533_als_set_threshold(indio_dev, als_attr->val1,
 555                                                                 false, val);
 556                 break;
 557         case LM3533_ATTR_TYPE_THRESH_RAISING:
 558                 ret = lm3533_als_set_threshold(indio_dev, als_attr->val1,
 559                                                                 true, val);
 560                 break;
 561         default:
 562                 ret = -ENXIO;
 563         }
 564 
 565         if (ret)
 566                 return ret;
 567 
 568         return len;
 569 }
 570 
 571 #define ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2)      \
 572         { .dev_attr     = __ATTR(_name, _mode, _show, _store),          \
 573           .type         = _type,                                        \
 574           .val1         = _val1,                                        \
 575           .val2         = _val2 }
 576 
 577 #define LM3533_ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2) \
 578         struct lm3533_als_attribute lm3533_als_attr_##_name =             \
 579                 ALS_ATTR(_name, _mode, _show, _store, _type, _val1, _val2)
 580 
 581 #define ALS_TARGET_ATTR_RW(_channel, _zone)                             \
 582         LM3533_ALS_ATTR(out_current##_channel##_current##_zone##_raw,   \
 583                                 S_IRUGO | S_IWUSR,                      \
 584                                 show_als_attr, store_als_attr,          \
 585                                 LM3533_ATTR_TYPE_TARGET, _channel, _zone)
 586 /*
 587  * ALS output current values (ALS mapper targets)
 588  *
 589  * out_current[0-2]_current[0-4]_raw            0-255
 590  */
 591 static ALS_TARGET_ATTR_RW(0, 0);
 592 static ALS_TARGET_ATTR_RW(0, 1);
 593 static ALS_TARGET_ATTR_RW(0, 2);
 594 static ALS_TARGET_ATTR_RW(0, 3);
 595 static ALS_TARGET_ATTR_RW(0, 4);
 596 
 597 static ALS_TARGET_ATTR_RW(1, 0);
 598 static ALS_TARGET_ATTR_RW(1, 1);
 599 static ALS_TARGET_ATTR_RW(1, 2);
 600 static ALS_TARGET_ATTR_RW(1, 3);
 601 static ALS_TARGET_ATTR_RW(1, 4);
 602 
 603 static ALS_TARGET_ATTR_RW(2, 0);
 604 static ALS_TARGET_ATTR_RW(2, 1);
 605 static ALS_TARGET_ATTR_RW(2, 2);
 606 static ALS_TARGET_ATTR_RW(2, 3);
 607 static ALS_TARGET_ATTR_RW(2, 4);
 608 
 609 #define ALS_THRESH_FALLING_ATTR_RW(_nr)                                 \
 610         LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_falling_value,    \
 611                         S_IRUGO | S_IWUSR,                              \
 612                         show_als_attr, store_als_attr,          \
 613                         LM3533_ATTR_TYPE_THRESH_FALLING, _nr, 0)
 614 
 615 #define ALS_THRESH_RAISING_ATTR_RW(_nr)                                 \
 616         LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_raising_value,    \
 617                         S_IRUGO | S_IWUSR,                              \
 618                         show_als_attr, store_als_attr,                  \
 619                         LM3533_ATTR_TYPE_THRESH_RAISING, _nr, 0)
 620 /*
 621  * ALS Zone thresholds (boundaries)
 622  *
 623  * in_illuminance0_thresh[0-3]_falling_value    0-255
 624  * in_illuminance0_thresh[0-3]_raising_value    0-255
 625  */
 626 static ALS_THRESH_FALLING_ATTR_RW(0);
 627 static ALS_THRESH_FALLING_ATTR_RW(1);
 628 static ALS_THRESH_FALLING_ATTR_RW(2);
 629 static ALS_THRESH_FALLING_ATTR_RW(3);
 630 
 631 static ALS_THRESH_RAISING_ATTR_RW(0);
 632 static ALS_THRESH_RAISING_ATTR_RW(1);
 633 static ALS_THRESH_RAISING_ATTR_RW(2);
 634 static ALS_THRESH_RAISING_ATTR_RW(3);
 635 
 636 #define ALS_HYSTERESIS_ATTR_RO(_nr)                                     \
 637         LM3533_ALS_ATTR(in_illuminance0_thresh##_nr##_hysteresis,       \
 638                         S_IRUGO, show_als_attr, NULL,                   \
 639                         LM3533_ATTR_TYPE_HYSTERESIS, _nr, 0)
 640 /*
 641  * ALS Zone threshold hysteresis
 642  *
 643  * threshY_hysteresis = threshY_raising - threshY_falling
 644  *
 645  * in_illuminance0_thresh[0-3]_hysteresis       0-255
 646  * in_illuminance0_thresh[0-3]_hysteresis       0-255
 647  */
 648 static ALS_HYSTERESIS_ATTR_RO(0);
 649 static ALS_HYSTERESIS_ATTR_RO(1);
 650 static ALS_HYSTERESIS_ATTR_RO(2);
 651 static ALS_HYSTERESIS_ATTR_RO(3);
 652 
 653 #define ILLUMINANCE_ATTR_RO(_name) \
 654         DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO, show_##_name, NULL)
 655 #define ILLUMINANCE_ATTR_RW(_name) \
 656         DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR, \
 657                                                 show_##_name, store_##_name)
 658 /*
 659  * ALS Zone threshold-event enable
 660  *
 661  * in_illuminance0_thresh_either_en             0,1
 662  */
 663 static ILLUMINANCE_ATTR_RW(thresh_either_en);
 664 
 665 /*
 666  * ALS Current Zone
 667  *
 668  * in_illuminance0_zone         0-4
 669  */
 670 static ILLUMINANCE_ATTR_RO(zone);
 671 
 672 static struct attribute *lm3533_als_event_attributes[] = {
 673         &dev_attr_in_illuminance0_thresh_either_en.attr,
 674         &lm3533_als_attr_in_illuminance0_thresh0_falling_value.dev_attr.attr,
 675         &lm3533_als_attr_in_illuminance0_thresh0_hysteresis.dev_attr.attr,
 676         &lm3533_als_attr_in_illuminance0_thresh0_raising_value.dev_attr.attr,
 677         &lm3533_als_attr_in_illuminance0_thresh1_falling_value.dev_attr.attr,
 678         &lm3533_als_attr_in_illuminance0_thresh1_hysteresis.dev_attr.attr,
 679         &lm3533_als_attr_in_illuminance0_thresh1_raising_value.dev_attr.attr,
 680         &lm3533_als_attr_in_illuminance0_thresh2_falling_value.dev_attr.attr,
 681         &lm3533_als_attr_in_illuminance0_thresh2_hysteresis.dev_attr.attr,
 682         &lm3533_als_attr_in_illuminance0_thresh2_raising_value.dev_attr.attr,
 683         &lm3533_als_attr_in_illuminance0_thresh3_falling_value.dev_attr.attr,
 684         &lm3533_als_attr_in_illuminance0_thresh3_hysteresis.dev_attr.attr,
 685         &lm3533_als_attr_in_illuminance0_thresh3_raising_value.dev_attr.attr,
 686         NULL
 687 };
 688 
 689 static const struct attribute_group lm3533_als_event_attribute_group = {
 690         .attrs = lm3533_als_event_attributes
 691 };
 692 
 693 static struct attribute *lm3533_als_attributes[] = {
 694         &dev_attr_in_illuminance0_zone.attr,
 695         &lm3533_als_attr_out_current0_current0_raw.dev_attr.attr,
 696         &lm3533_als_attr_out_current0_current1_raw.dev_attr.attr,
 697         &lm3533_als_attr_out_current0_current2_raw.dev_attr.attr,
 698         &lm3533_als_attr_out_current0_current3_raw.dev_attr.attr,
 699         &lm3533_als_attr_out_current0_current4_raw.dev_attr.attr,
 700         &lm3533_als_attr_out_current1_current0_raw.dev_attr.attr,
 701         &lm3533_als_attr_out_current1_current1_raw.dev_attr.attr,
 702         &lm3533_als_attr_out_current1_current2_raw.dev_attr.attr,
 703         &lm3533_als_attr_out_current1_current3_raw.dev_attr.attr,
 704         &lm3533_als_attr_out_current1_current4_raw.dev_attr.attr,
 705         &lm3533_als_attr_out_current2_current0_raw.dev_attr.attr,
 706         &lm3533_als_attr_out_current2_current1_raw.dev_attr.attr,
 707         &lm3533_als_attr_out_current2_current2_raw.dev_attr.attr,
 708         &lm3533_als_attr_out_current2_current3_raw.dev_attr.attr,
 709         &lm3533_als_attr_out_current2_current4_raw.dev_attr.attr,
 710         NULL
 711 };
 712 
 713 static const struct attribute_group lm3533_als_attribute_group = {
 714         .attrs = lm3533_als_attributes
 715 };
 716 
 717 static int lm3533_als_set_input_mode(struct lm3533_als *als, bool pwm_mode)
 718 {
 719         u8 mask = LM3533_ALS_INPUT_MODE_MASK;
 720         u8 val;
 721         int ret;
 722 
 723         if (pwm_mode)
 724                 val = mask;     /* pwm input */
 725         else
 726                 val = 0;        /* analog input */
 727 
 728         ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, val, mask);
 729         if (ret) {
 730                 dev_err(&als->pdev->dev, "failed to set input mode %d\n",
 731                                                                 pwm_mode);
 732                 return ret;
 733         }
 734 
 735         return 0;
 736 }
 737 
 738 static int lm3533_als_set_resistor(struct lm3533_als *als, u8 val)
 739 {
 740         int ret;
 741 
 742         if (val < LM3533_ALS_RESISTOR_MIN || val > LM3533_ALS_RESISTOR_MAX) {
 743                 dev_err(&als->pdev->dev, "invalid resistor value\n");
 744                 return -EINVAL;
 745         };
 746 
 747         ret = lm3533_write(als->lm3533, LM3533_REG_ALS_RESISTOR_SELECT, val);
 748         if (ret) {
 749                 dev_err(&als->pdev->dev, "failed to set resistor\n");
 750                 return ret;
 751         }
 752 
 753         return 0;
 754 }
 755 
 756 static int lm3533_als_setup(struct lm3533_als *als,
 757                             struct lm3533_als_platform_data *pdata)
 758 {
 759         int ret;
 760 
 761         ret = lm3533_als_set_input_mode(als, pdata->pwm_mode);
 762         if (ret)
 763                 return ret;
 764 
 765         /* ALS input is always high impedance in PWM-mode. */
 766         if (!pdata->pwm_mode) {
 767                 ret = lm3533_als_set_resistor(als, pdata->r_select);
 768                 if (ret)
 769                         return ret;
 770         }
 771 
 772         return 0;
 773 }
 774 
 775 static int lm3533_als_setup_irq(struct lm3533_als *als, void *dev)
 776 {
 777         u8 mask = LM3533_ALS_INT_ENABLE_MASK;
 778         int ret;
 779 
 780         /* Make sure interrupts are disabled. */
 781         ret = lm3533_update(als->lm3533, LM3533_REG_ALS_ZONE_INFO, 0, mask);
 782         if (ret) {
 783                 dev_err(&als->pdev->dev, "failed to disable interrupts\n");
 784                 return ret;
 785         }
 786 
 787         ret = request_threaded_irq(als->irq, NULL, lm3533_als_isr,
 788                                         IRQF_TRIGGER_LOW | IRQF_ONESHOT,
 789                                         dev_name(&als->pdev->dev), dev);
 790         if (ret) {
 791                 dev_err(&als->pdev->dev, "failed to request irq %d\n",
 792                                                                 als->irq);
 793                 return ret;
 794         }
 795 
 796         return 0;
 797 }
 798 
 799 static int lm3533_als_enable(struct lm3533_als *als)
 800 {
 801         u8 mask = LM3533_ALS_ENABLE_MASK;
 802         int ret;
 803 
 804         ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, mask, mask);
 805         if (ret)
 806                 dev_err(&als->pdev->dev, "failed to enable ALS\n");
 807 
 808         return ret;
 809 }
 810 
 811 static int lm3533_als_disable(struct lm3533_als *als)
 812 {
 813         u8 mask = LM3533_ALS_ENABLE_MASK;
 814         int ret;
 815 
 816         ret = lm3533_update(als->lm3533, LM3533_REG_ALS_CONF, 0, mask);
 817         if (ret)
 818                 dev_err(&als->pdev->dev, "failed to disable ALS\n");
 819 
 820         return ret;
 821 }
 822 
 823 static const struct iio_info lm3533_als_info = {
 824         .attrs          = &lm3533_als_attribute_group,
 825         .event_attrs    = &lm3533_als_event_attribute_group,
 826         .read_raw       = &lm3533_als_read_raw,
 827 };
 828 
 829 static int lm3533_als_probe(struct platform_device *pdev)
 830 {
 831         struct lm3533 *lm3533;
 832         struct lm3533_als_platform_data *pdata;
 833         struct lm3533_als *als;
 834         struct iio_dev *indio_dev;
 835         int ret;
 836 
 837         lm3533 = dev_get_drvdata(pdev->dev.parent);
 838         if (!lm3533)
 839                 return -EINVAL;
 840 
 841         pdata = pdev->dev.platform_data;
 842         if (!pdata) {
 843                 dev_err(&pdev->dev, "no platform data\n");
 844                 return -EINVAL;
 845         }
 846 
 847         indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*als));
 848         if (!indio_dev)
 849                 return -ENOMEM;
 850 
 851         indio_dev->info = &lm3533_als_info;
 852         indio_dev->channels = lm3533_als_channels;
 853         indio_dev->num_channels = ARRAY_SIZE(lm3533_als_channels);
 854         indio_dev->name = dev_name(&pdev->dev);
 855         indio_dev->dev.parent = pdev->dev.parent;
 856         indio_dev->modes = INDIO_DIRECT_MODE;
 857 
 858         als = iio_priv(indio_dev);
 859         als->lm3533 = lm3533;
 860         als->pdev = pdev;
 861         als->irq = lm3533->irq;
 862         atomic_set(&als->zone, 0);
 863         mutex_init(&als->thresh_mutex);
 864 
 865         platform_set_drvdata(pdev, indio_dev);
 866 
 867         if (als->irq) {
 868                 ret = lm3533_als_setup_irq(als, indio_dev);
 869                 if (ret)
 870                         return ret;
 871         }
 872 
 873         ret = lm3533_als_setup(als, pdata);
 874         if (ret)
 875                 goto err_free_irq;
 876 
 877         ret = lm3533_als_enable(als);
 878         if (ret)
 879                 goto err_free_irq;
 880 
 881         ret = iio_device_register(indio_dev);
 882         if (ret) {
 883                 dev_err(&pdev->dev, "failed to register ALS\n");
 884                 goto err_disable;
 885         }
 886 
 887         return 0;
 888 
 889 err_disable:
 890         lm3533_als_disable(als);
 891 err_free_irq:
 892         if (als->irq)
 893                 free_irq(als->irq, indio_dev);
 894 
 895         return ret;
 896 }
 897 
 898 static int lm3533_als_remove(struct platform_device *pdev)
 899 {
 900         struct iio_dev *indio_dev = platform_get_drvdata(pdev);
 901         struct lm3533_als *als = iio_priv(indio_dev);
 902 
 903         lm3533_als_set_int_mode(indio_dev, false);
 904         iio_device_unregister(indio_dev);
 905         lm3533_als_disable(als);
 906         if (als->irq)
 907                 free_irq(als->irq, indio_dev);
 908 
 909         return 0;
 910 }
 911 
 912 static struct platform_driver lm3533_als_driver = {
 913         .driver = {
 914                 .name   = "lm3533-als",
 915         },
 916         .probe          = lm3533_als_probe,
 917         .remove         = lm3533_als_remove,
 918 };
 919 module_platform_driver(lm3533_als_driver);
 920 
 921 MODULE_AUTHOR("Johan Hovold <jhovold@gmail.com>");
 922 MODULE_DESCRIPTION("LM3533 Ambient Light Sensor driver");
 923 MODULE_LICENSE("GPL");
 924 MODULE_ALIAS("platform:lm3533-als");

/* [<][>][^][v][top][bottom][index][help] */