root/drivers/video/backlight/adp8860_bl.c

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

DEFINITIONS

This source file includes following definitions.
  1. adp8860_read
  2. adp8860_write
  3. adp8860_set_bits
  4. adp8860_clr_bits
  5. adp8860_led_work
  6. adp8860_led_set
  7. adp8860_led_setup
  8. adp8860_led_probe
  9. adp8860_led_remove
  10. adp8860_led_probe
  11. adp8860_led_remove
  12. adp8860_bl_set
  13. adp8860_bl_update_status
  14. adp8860_bl_get_brightness
  15. adp8860_bl_setup
  16. adp8860_show
  17. adp8860_store
  18. adp8860_bl_l3_dark_max_show
  19. adp8860_bl_l3_dark_max_store
  20. adp8860_bl_l2_office_max_show
  21. adp8860_bl_l2_office_max_store
  22. adp8860_bl_l1_daylight_max_show
  23. adp8860_bl_l1_daylight_max_store
  24. adp8860_bl_l3_dark_dim_show
  25. adp8860_bl_l3_dark_dim_store
  26. adp8860_bl_l2_office_dim_show
  27. adp8860_bl_l2_office_dim_store
  28. adp8860_bl_l1_daylight_dim_show
  29. adp8860_bl_l1_daylight_dim_store
  30. adp8860_bl_ambient_light_level_show
  31. adp8860_bl_ambient_light_zone_show
  32. adp8860_bl_ambient_light_zone_store
  33. adp8860_probe
  34. adp8860_remove
  35. adp8860_i2c_suspend
  36. adp8860_i2c_resume

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Backlight driver for Analog Devices ADP8860 Backlight Devices
   4  *
   5  * Copyright 2009-2010 Analog Devices Inc.
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/init.h>
  10 #include <linux/errno.h>
  11 #include <linux/pm.h>
  12 #include <linux/platform_device.h>
  13 #include <linux/i2c.h>
  14 #include <linux/fb.h>
  15 #include <linux/backlight.h>
  16 #include <linux/leds.h>
  17 #include <linux/slab.h>
  18 #include <linux/workqueue.h>
  19 
  20 #include <linux/platform_data/adp8860.h>
  21 #define ADP8860_EXT_FEATURES
  22 #define ADP8860_USE_LEDS
  23 
  24 #define ADP8860_MFDVID 0x00 /* Manufacturer and device ID */
  25 #define ADP8860_MDCR 0x01 /* Device mode and status */
  26 #define ADP8860_MDCR2 0x02 /* Device mode and Status Register 2 */
  27 #define ADP8860_INTR_EN 0x03 /* Interrupts enable */
  28 #define ADP8860_CFGR 0x04 /* Configuration register */
  29 #define ADP8860_BLSEN 0x05 /* Sink enable backlight or independent */
  30 #define ADP8860_BLOFF 0x06 /* Backlight off timeout */
  31 #define ADP8860_BLDIM 0x07 /* Backlight dim timeout */
  32 #define ADP8860_BLFR 0x08 /* Backlight fade in and out rates */
  33 #define ADP8860_BLMX1 0x09 /* Backlight (Brightness Level 1-daylight) maximum current */
  34 #define ADP8860_BLDM1 0x0A /* Backlight (Brightness Level 1-daylight) dim current */
  35 #define ADP8860_BLMX2 0x0B /* Backlight (Brightness Level 2-office) maximum current */
  36 #define ADP8860_BLDM2 0x0C /* Backlight (Brightness Level 2-office) dim current */
  37 #define ADP8860_BLMX3 0x0D /* Backlight (Brightness Level 3-dark) maximum current */
  38 #define ADP8860_BLDM3 0x0E /* Backlight (Brightness Level 3-dark) dim current */
  39 #define ADP8860_ISCFR 0x0F /* Independent sink current fade control register */
  40 #define ADP8860_ISCC 0x10 /* Independent sink current control register */
  41 #define ADP8860_ISCT1 0x11 /* Independent Sink Current Timer Register LED[7:5] */
  42 #define ADP8860_ISCT2 0x12 /* Independent Sink Current Timer Register LED[4:1] */
  43 #define ADP8860_ISCF 0x13 /* Independent sink current fade register */
  44 #define ADP8860_ISC7 0x14 /* Independent Sink Current LED7 */
  45 #define ADP8860_ISC6 0x15 /* Independent Sink Current LED6 */
  46 #define ADP8860_ISC5 0x16 /* Independent Sink Current LED5 */
  47 #define ADP8860_ISC4 0x17 /* Independent Sink Current LED4 */
  48 #define ADP8860_ISC3 0x18 /* Independent Sink Current LED3 */
  49 #define ADP8860_ISC2 0x19 /* Independent Sink Current LED2 */
  50 #define ADP8860_ISC1 0x1A /* Independent Sink Current LED1 */
  51 #define ADP8860_CCFG 0x1B /* Comparator configuration */
  52 #define ADP8860_CCFG2 0x1C /* Second comparator configuration */
  53 #define ADP8860_L2_TRP 0x1D /* L2 comparator reference */
  54 #define ADP8860_L2_HYS 0x1E /* L2 hysteresis */
  55 #define ADP8860_L3_TRP 0x1F /* L3 comparator reference */
  56 #define ADP8860_L3_HYS 0x20 /* L3 hysteresis */
  57 #define ADP8860_PH1LEVL 0x21 /* First phototransistor ambient light level-low byte register */
  58 #define ADP8860_PH1LEVH 0x22 /* First phototransistor ambient light level-high byte register */
  59 #define ADP8860_PH2LEVL 0x23 /* Second phototransistor ambient light level-low byte register */
  60 #define ADP8860_PH2LEVH 0x24 /* Second phototransistor ambient light level-high byte register */
  61 
  62 #define ADP8860_MANUFID         0x0  /* Analog Devices ADP8860 Manufacturer ID */
  63 #define ADP8861_MANUFID         0x4  /* Analog Devices ADP8861 Manufacturer ID */
  64 #define ADP8863_MANUFID         0x2  /* Analog Devices ADP8863 Manufacturer ID */
  65 
  66 #define ADP8860_DEVID(x)        ((x) & 0xF)
  67 #define ADP8860_MANID(x)        ((x) >> 4)
  68 
  69 /* MDCR Device mode and status */
  70 #define INT_CFG                 (1 << 6)
  71 #define NSTBY                   (1 << 5)
  72 #define DIM_EN                  (1 << 4)
  73 #define GDWN_DIS                (1 << 3)
  74 #define SIS_EN                  (1 << 2)
  75 #define CMP_AUTOEN              (1 << 1)
  76 #define BLEN                    (1 << 0)
  77 
  78 /* ADP8860_CCFG Main ALS comparator level enable */
  79 #define L3_EN                   (1 << 1)
  80 #define L2_EN                   (1 << 0)
  81 
  82 #define CFGR_BLV_SHIFT          3
  83 #define CFGR_BLV_MASK           0x3
  84 #define ADP8860_FLAG_LED_MASK   0xFF
  85 
  86 #define FADE_VAL(in, out)       ((0xF & (in)) | ((0xF & (out)) << 4))
  87 #define BL_CFGR_VAL(law, blv)   ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1))
  88 #define ALS_CCFG_VAL(filt)      ((0x7 & filt) << 5)
  89 
  90 enum {
  91         adp8860,
  92         adp8861,
  93         adp8863
  94 };
  95 
  96 struct adp8860_led {
  97         struct led_classdev     cdev;
  98         struct work_struct      work;
  99         struct i2c_client       *client;
 100         enum led_brightness     new_brightness;
 101         int                     id;
 102         int                     flags;
 103 };
 104 
 105 struct adp8860_bl {
 106         struct i2c_client *client;
 107         struct backlight_device *bl;
 108         struct adp8860_led *led;
 109         struct adp8860_backlight_platform_data *pdata;
 110         struct mutex lock;
 111         unsigned long cached_daylight_max;
 112         int id;
 113         int revid;
 114         int current_brightness;
 115         unsigned en_ambl_sens:1;
 116         unsigned gdwn_dis:1;
 117 };
 118 
 119 static int adp8860_read(struct i2c_client *client, int reg, uint8_t *val)
 120 {
 121         int ret;
 122 
 123         ret = i2c_smbus_read_byte_data(client, reg);
 124         if (ret < 0) {
 125                 dev_err(&client->dev, "failed reading at 0x%02x\n", reg);
 126                 return ret;
 127         }
 128 
 129         *val = (uint8_t)ret;
 130         return 0;
 131 }
 132 
 133 static int adp8860_write(struct i2c_client *client, u8 reg, u8 val)
 134 {
 135         return i2c_smbus_write_byte_data(client, reg, val);
 136 }
 137 
 138 static int adp8860_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
 139 {
 140         struct adp8860_bl *data = i2c_get_clientdata(client);
 141         uint8_t reg_val;
 142         int ret;
 143 
 144         mutex_lock(&data->lock);
 145 
 146         ret = adp8860_read(client, reg, &reg_val);
 147 
 148         if (!ret && ((reg_val & bit_mask) != bit_mask)) {
 149                 reg_val |= bit_mask;
 150                 ret = adp8860_write(client, reg, reg_val);
 151         }
 152 
 153         mutex_unlock(&data->lock);
 154         return ret;
 155 }
 156 
 157 static int adp8860_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask)
 158 {
 159         struct adp8860_bl *data = i2c_get_clientdata(client);
 160         uint8_t reg_val;
 161         int ret;
 162 
 163         mutex_lock(&data->lock);
 164 
 165         ret = adp8860_read(client, reg, &reg_val);
 166 
 167         if (!ret && (reg_val & bit_mask)) {
 168                 reg_val &= ~bit_mask;
 169                 ret = adp8860_write(client, reg, reg_val);
 170         }
 171 
 172         mutex_unlock(&data->lock);
 173         return ret;
 174 }
 175 
 176 /*
 177  * Independent sink / LED
 178  */
 179 #if defined(ADP8860_USE_LEDS)
 180 static void adp8860_led_work(struct work_struct *work)
 181 {
 182         struct adp8860_led *led = container_of(work, struct adp8860_led, work);
 183 
 184         adp8860_write(led->client, ADP8860_ISC1 - led->id + 1,
 185                          led->new_brightness >> 1);
 186 }
 187 
 188 static void adp8860_led_set(struct led_classdev *led_cdev,
 189                            enum led_brightness value)
 190 {
 191         struct adp8860_led *led;
 192 
 193         led = container_of(led_cdev, struct adp8860_led, cdev);
 194         led->new_brightness = value;
 195         schedule_work(&led->work);
 196 }
 197 
 198 static int adp8860_led_setup(struct adp8860_led *led)
 199 {
 200         struct i2c_client *client = led->client;
 201         int ret = 0;
 202 
 203         ret = adp8860_write(client, ADP8860_ISC1 - led->id + 1, 0);
 204         ret |= adp8860_set_bits(client, ADP8860_ISCC, 1 << (led->id - 1));
 205 
 206         if (led->id > 4)
 207                 ret |= adp8860_set_bits(client, ADP8860_ISCT1,
 208                                 (led->flags & 0x3) << ((led->id - 5) * 2));
 209         else
 210                 ret |= adp8860_set_bits(client, ADP8860_ISCT2,
 211                                 (led->flags & 0x3) << ((led->id - 1) * 2));
 212 
 213         return ret;
 214 }
 215 
 216 static int adp8860_led_probe(struct i2c_client *client)
 217 {
 218         struct adp8860_backlight_platform_data *pdata =
 219                 dev_get_platdata(&client->dev);
 220         struct adp8860_bl *data = i2c_get_clientdata(client);
 221         struct adp8860_led *led, *led_dat;
 222         struct led_info *cur_led;
 223         int ret, i;
 224 
 225         led = devm_kcalloc(&client->dev, pdata->num_leds, sizeof(*led),
 226                                 GFP_KERNEL);
 227         if (led == NULL)
 228                 return -ENOMEM;
 229 
 230         ret = adp8860_write(client, ADP8860_ISCFR, pdata->led_fade_law);
 231         ret = adp8860_write(client, ADP8860_ISCT1,
 232                         (pdata->led_on_time & 0x3) << 6);
 233         ret |= adp8860_write(client, ADP8860_ISCF,
 234                         FADE_VAL(pdata->led_fade_in, pdata->led_fade_out));
 235 
 236         if (ret) {
 237                 dev_err(&client->dev, "failed to write\n");
 238                 return ret;
 239         }
 240 
 241         for (i = 0; i < pdata->num_leds; ++i) {
 242                 cur_led = &pdata->leds[i];
 243                 led_dat = &led[i];
 244 
 245                 led_dat->id = cur_led->flags & ADP8860_FLAG_LED_MASK;
 246 
 247                 if (led_dat->id > 7 || led_dat->id < 1) {
 248                         dev_err(&client->dev, "Invalid LED ID %d\n",
 249                                 led_dat->id);
 250                         ret = -EINVAL;
 251                         goto err;
 252                 }
 253 
 254                 if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) {
 255                         dev_err(&client->dev, "LED %d used by Backlight\n",
 256                                 led_dat->id);
 257                         ret = -EBUSY;
 258                         goto err;
 259                 }
 260 
 261                 led_dat->cdev.name = cur_led->name;
 262                 led_dat->cdev.default_trigger = cur_led->default_trigger;
 263                 led_dat->cdev.brightness_set = adp8860_led_set;
 264                 led_dat->cdev.brightness = LED_OFF;
 265                 led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT;
 266                 led_dat->client = client;
 267                 led_dat->new_brightness = LED_OFF;
 268                 INIT_WORK(&led_dat->work, adp8860_led_work);
 269 
 270                 ret = led_classdev_register(&client->dev, &led_dat->cdev);
 271                 if (ret) {
 272                         dev_err(&client->dev, "failed to register LED %d\n",
 273                                 led_dat->id);
 274                         goto err;
 275                 }
 276 
 277                 ret = adp8860_led_setup(led_dat);
 278                 if (ret) {
 279                         dev_err(&client->dev, "failed to write\n");
 280                         i++;
 281                         goto err;
 282                 }
 283         }
 284 
 285         data->led = led;
 286 
 287         return 0;
 288 
 289  err:
 290         for (i = i - 1; i >= 0; --i) {
 291                 led_classdev_unregister(&led[i].cdev);
 292                 cancel_work_sync(&led[i].work);
 293         }
 294 
 295         return ret;
 296 }
 297 
 298 static int adp8860_led_remove(struct i2c_client *client)
 299 {
 300         struct adp8860_backlight_platform_data *pdata =
 301                 dev_get_platdata(&client->dev);
 302         struct adp8860_bl *data = i2c_get_clientdata(client);
 303         int i;
 304 
 305         for (i = 0; i < pdata->num_leds; i++) {
 306                 led_classdev_unregister(&data->led[i].cdev);
 307                 cancel_work_sync(&data->led[i].work);
 308         }
 309 
 310         return 0;
 311 }
 312 #else
 313 static int adp8860_led_probe(struct i2c_client *client)
 314 {
 315         return 0;
 316 }
 317 
 318 static int adp8860_led_remove(struct i2c_client *client)
 319 {
 320         return 0;
 321 }
 322 #endif
 323 
 324 static int adp8860_bl_set(struct backlight_device *bl, int brightness)
 325 {
 326         struct adp8860_bl *data = bl_get_data(bl);
 327         struct i2c_client *client = data->client;
 328         int ret = 0;
 329 
 330         if (data->en_ambl_sens) {
 331                 if ((brightness > 0) && (brightness < ADP8860_MAX_BRIGHTNESS)) {
 332                         /* Disable Ambient Light auto adjust */
 333                         ret |= adp8860_clr_bits(client, ADP8860_MDCR,
 334                                         CMP_AUTOEN);
 335                         ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
 336                 } else {
 337                         /*
 338                          * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust
 339                          * restore daylight l1 sysfs brightness
 340                          */
 341                         ret |= adp8860_write(client, ADP8860_BLMX1,
 342                                          data->cached_daylight_max);
 343                         ret |= adp8860_set_bits(client, ADP8860_MDCR,
 344                                          CMP_AUTOEN);
 345                 }
 346         } else
 347                 ret |= adp8860_write(client, ADP8860_BLMX1, brightness);
 348 
 349         if (data->current_brightness && brightness == 0)
 350                 ret |= adp8860_set_bits(client,
 351                                 ADP8860_MDCR, DIM_EN);
 352         else if (data->current_brightness == 0 && brightness)
 353                 ret |= adp8860_clr_bits(client,
 354                                 ADP8860_MDCR, DIM_EN);
 355 
 356         if (!ret)
 357                 data->current_brightness = brightness;
 358 
 359         return ret;
 360 }
 361 
 362 static int adp8860_bl_update_status(struct backlight_device *bl)
 363 {
 364         int brightness = bl->props.brightness;
 365 
 366         if (bl->props.power != FB_BLANK_UNBLANK)
 367                 brightness = 0;
 368 
 369         if (bl->props.fb_blank != FB_BLANK_UNBLANK)
 370                 brightness = 0;
 371 
 372         return adp8860_bl_set(bl, brightness);
 373 }
 374 
 375 static int adp8860_bl_get_brightness(struct backlight_device *bl)
 376 {
 377         struct adp8860_bl *data = bl_get_data(bl);
 378 
 379         return data->current_brightness;
 380 }
 381 
 382 static const struct backlight_ops adp8860_bl_ops = {
 383         .update_status  = adp8860_bl_update_status,
 384         .get_brightness = adp8860_bl_get_brightness,
 385 };
 386 
 387 static int adp8860_bl_setup(struct backlight_device *bl)
 388 {
 389         struct adp8860_bl *data = bl_get_data(bl);
 390         struct i2c_client *client = data->client;
 391         struct adp8860_backlight_platform_data *pdata = data->pdata;
 392         int ret = 0;
 393 
 394         ret |= adp8860_write(client, ADP8860_BLSEN, ~pdata->bl_led_assign);
 395         ret |= adp8860_write(client, ADP8860_BLMX1, pdata->l1_daylight_max);
 396         ret |= adp8860_write(client, ADP8860_BLDM1, pdata->l1_daylight_dim);
 397 
 398         if (data->en_ambl_sens) {
 399                 data->cached_daylight_max = pdata->l1_daylight_max;
 400                 ret |= adp8860_write(client, ADP8860_BLMX2,
 401                                                 pdata->l2_office_max);
 402                 ret |= adp8860_write(client, ADP8860_BLDM2,
 403                                                 pdata->l2_office_dim);
 404                 ret |= adp8860_write(client, ADP8860_BLMX3,
 405                                                 pdata->l3_dark_max);
 406                 ret |= adp8860_write(client, ADP8860_BLDM3,
 407                                                 pdata->l3_dark_dim);
 408 
 409                 ret |= adp8860_write(client, ADP8860_L2_TRP, pdata->l2_trip);
 410                 ret |= adp8860_write(client, ADP8860_L2_HYS, pdata->l2_hyst);
 411                 ret |= adp8860_write(client, ADP8860_L3_TRP, pdata->l3_trip);
 412                 ret |= adp8860_write(client, ADP8860_L3_HYS, pdata->l3_hyst);
 413                 ret |= adp8860_write(client, ADP8860_CCFG, L2_EN | L3_EN |
 414                                                 ALS_CCFG_VAL(pdata->abml_filt));
 415         }
 416 
 417         ret |= adp8860_write(client, ADP8860_CFGR,
 418                         BL_CFGR_VAL(pdata->bl_fade_law, 0));
 419 
 420         ret |= adp8860_write(client, ADP8860_BLFR, FADE_VAL(pdata->bl_fade_in,
 421                         pdata->bl_fade_out));
 422 
 423         ret |= adp8860_set_bits(client, ADP8860_MDCR, BLEN | DIM_EN | NSTBY |
 424                         (data->gdwn_dis ? GDWN_DIS : 0));
 425 
 426         return ret;
 427 }
 428 
 429 static ssize_t adp8860_show(struct device *dev, char *buf, int reg)
 430 {
 431         struct adp8860_bl *data = dev_get_drvdata(dev);
 432         int error;
 433         uint8_t reg_val;
 434 
 435         mutex_lock(&data->lock);
 436         error = adp8860_read(data->client, reg, &reg_val);
 437         mutex_unlock(&data->lock);
 438 
 439         if (error < 0)
 440                 return error;
 441 
 442         return sprintf(buf, "%u\n", reg_val);
 443 }
 444 
 445 static ssize_t adp8860_store(struct device *dev, const char *buf,
 446                          size_t count, int reg)
 447 {
 448         struct adp8860_bl *data = dev_get_drvdata(dev);
 449         unsigned long val;
 450         int ret;
 451 
 452         ret = kstrtoul(buf, 10, &val);
 453         if (ret)
 454                 return ret;
 455 
 456         mutex_lock(&data->lock);
 457         adp8860_write(data->client, reg, val);
 458         mutex_unlock(&data->lock);
 459 
 460         return count;
 461 }
 462 
 463 static ssize_t adp8860_bl_l3_dark_max_show(struct device *dev,
 464                                      struct device_attribute *attr, char *buf)
 465 {
 466         return adp8860_show(dev, buf, ADP8860_BLMX3);
 467 }
 468 
 469 static ssize_t adp8860_bl_l3_dark_max_store(struct device *dev,
 470                 struct device_attribute *attr, const char *buf, size_t count)
 471 {
 472         return adp8860_store(dev, buf, count, ADP8860_BLMX3);
 473 }
 474 
 475 static DEVICE_ATTR(l3_dark_max, 0664, adp8860_bl_l3_dark_max_show,
 476                         adp8860_bl_l3_dark_max_store);
 477 
 478 static ssize_t adp8860_bl_l2_office_max_show(struct device *dev,
 479                 struct device_attribute *attr, char *buf)
 480 {
 481         return adp8860_show(dev, buf, ADP8860_BLMX2);
 482 }
 483 
 484 static ssize_t adp8860_bl_l2_office_max_store(struct device *dev,
 485                 struct device_attribute *attr, const char *buf, size_t count)
 486 {
 487         return adp8860_store(dev, buf, count, ADP8860_BLMX2);
 488 }
 489 static DEVICE_ATTR(l2_office_max, 0664, adp8860_bl_l2_office_max_show,
 490                         adp8860_bl_l2_office_max_store);
 491 
 492 static ssize_t adp8860_bl_l1_daylight_max_show(struct device *dev,
 493                         struct device_attribute *attr, char *buf)
 494 {
 495         return adp8860_show(dev, buf, ADP8860_BLMX1);
 496 }
 497 
 498 static ssize_t adp8860_bl_l1_daylight_max_store(struct device *dev,
 499                 struct device_attribute *attr, const char *buf, size_t count)
 500 {
 501         struct adp8860_bl *data = dev_get_drvdata(dev);
 502         int ret = kstrtoul(buf, 10, &data->cached_daylight_max);
 503 
 504         if (ret)
 505                 return ret;
 506 
 507         return adp8860_store(dev, buf, count, ADP8860_BLMX1);
 508 }
 509 static DEVICE_ATTR(l1_daylight_max, 0664, adp8860_bl_l1_daylight_max_show,
 510                         adp8860_bl_l1_daylight_max_store);
 511 
 512 static ssize_t adp8860_bl_l3_dark_dim_show(struct device *dev,
 513                         struct device_attribute *attr, char *buf)
 514 {
 515         return adp8860_show(dev, buf, ADP8860_BLDM3);
 516 }
 517 
 518 static ssize_t adp8860_bl_l3_dark_dim_store(struct device *dev,
 519                                      struct device_attribute *attr,
 520                                      const char *buf, size_t count)
 521 {
 522         return adp8860_store(dev, buf, count, ADP8860_BLDM3);
 523 }
 524 static DEVICE_ATTR(l3_dark_dim, 0664, adp8860_bl_l3_dark_dim_show,
 525                         adp8860_bl_l3_dark_dim_store);
 526 
 527 static ssize_t adp8860_bl_l2_office_dim_show(struct device *dev,
 528                         struct device_attribute *attr, char *buf)
 529 {
 530         return adp8860_show(dev, buf, ADP8860_BLDM2);
 531 }
 532 
 533 static ssize_t adp8860_bl_l2_office_dim_store(struct device *dev,
 534                                      struct device_attribute *attr,
 535                                      const char *buf, size_t count)
 536 {
 537         return adp8860_store(dev, buf, count, ADP8860_BLDM2);
 538 }
 539 static DEVICE_ATTR(l2_office_dim, 0664, adp8860_bl_l2_office_dim_show,
 540                         adp8860_bl_l2_office_dim_store);
 541 
 542 static ssize_t adp8860_bl_l1_daylight_dim_show(struct device *dev,
 543                                      struct device_attribute *attr, char *buf)
 544 {
 545         return adp8860_show(dev, buf, ADP8860_BLDM1);
 546 }
 547 
 548 static ssize_t adp8860_bl_l1_daylight_dim_store(struct device *dev,
 549                                      struct device_attribute *attr,
 550                                      const char *buf, size_t count)
 551 {
 552         return adp8860_store(dev, buf, count, ADP8860_BLDM1);
 553 }
 554 static DEVICE_ATTR(l1_daylight_dim, 0664, adp8860_bl_l1_daylight_dim_show,
 555                         adp8860_bl_l1_daylight_dim_store);
 556 
 557 #ifdef ADP8860_EXT_FEATURES
 558 static ssize_t adp8860_bl_ambient_light_level_show(struct device *dev,
 559                                      struct device_attribute *attr, char *buf)
 560 {
 561         struct adp8860_bl *data = dev_get_drvdata(dev);
 562         int error;
 563         uint8_t reg_val;
 564         uint16_t ret_val;
 565 
 566         mutex_lock(&data->lock);
 567         error = adp8860_read(data->client, ADP8860_PH1LEVL, &reg_val);
 568         if (!error) {
 569                 ret_val = reg_val;
 570                 error = adp8860_read(data->client, ADP8860_PH1LEVH, &reg_val);
 571         }
 572         mutex_unlock(&data->lock);
 573 
 574         if (error)
 575                 return error;
 576 
 577         /* Return 13-bit conversion value for the first light sensor */
 578         ret_val += (reg_val & 0x1F) << 8;
 579 
 580         return sprintf(buf, "%u\n", ret_val);
 581 }
 582 static DEVICE_ATTR(ambient_light_level, 0444,
 583                 adp8860_bl_ambient_light_level_show, NULL);
 584 
 585 static ssize_t adp8860_bl_ambient_light_zone_show(struct device *dev,
 586                                      struct device_attribute *attr, char *buf)
 587 {
 588         struct adp8860_bl *data = dev_get_drvdata(dev);
 589         int error;
 590         uint8_t reg_val;
 591 
 592         mutex_lock(&data->lock);
 593         error = adp8860_read(data->client, ADP8860_CFGR, &reg_val);
 594         mutex_unlock(&data->lock);
 595 
 596         if (error < 0)
 597                 return error;
 598 
 599         return sprintf(buf, "%u\n",
 600                 ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1);
 601 }
 602 
 603 static ssize_t adp8860_bl_ambient_light_zone_store(struct device *dev,
 604                                      struct device_attribute *attr,
 605                                      const char *buf, size_t count)
 606 {
 607         struct adp8860_bl *data = dev_get_drvdata(dev);
 608         unsigned long val;
 609         uint8_t reg_val;
 610         int ret;
 611 
 612         ret = kstrtoul(buf, 10, &val);
 613         if (ret)
 614                 return ret;
 615 
 616         if (val == 0) {
 617                 /* Enable automatic ambient light sensing */
 618                 adp8860_set_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
 619         } else if ((val > 0) && (val <= 3)) {
 620                 /* Disable automatic ambient light sensing */
 621                 adp8860_clr_bits(data->client, ADP8860_MDCR, CMP_AUTOEN);
 622 
 623                 /* Set user supplied ambient light zone */
 624                 mutex_lock(&data->lock);
 625                 ret = adp8860_read(data->client, ADP8860_CFGR, &reg_val);
 626                 if (!ret) {
 627                         reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT);
 628                         reg_val |= (val - 1) << CFGR_BLV_SHIFT;
 629                         adp8860_write(data->client, ADP8860_CFGR, reg_val);
 630                 }
 631                 mutex_unlock(&data->lock);
 632         }
 633 
 634         return count;
 635 }
 636 static DEVICE_ATTR(ambient_light_zone, 0664,
 637                 adp8860_bl_ambient_light_zone_show,
 638                 adp8860_bl_ambient_light_zone_store);
 639 #endif
 640 
 641 static struct attribute *adp8860_bl_attributes[] = {
 642         &dev_attr_l3_dark_max.attr,
 643         &dev_attr_l3_dark_dim.attr,
 644         &dev_attr_l2_office_max.attr,
 645         &dev_attr_l2_office_dim.attr,
 646         &dev_attr_l1_daylight_max.attr,
 647         &dev_attr_l1_daylight_dim.attr,
 648 #ifdef ADP8860_EXT_FEATURES
 649         &dev_attr_ambient_light_level.attr,
 650         &dev_attr_ambient_light_zone.attr,
 651 #endif
 652         NULL
 653 };
 654 
 655 static const struct attribute_group adp8860_bl_attr_group = {
 656         .attrs = adp8860_bl_attributes,
 657 };
 658 
 659 static int adp8860_probe(struct i2c_client *client,
 660                                         const struct i2c_device_id *id)
 661 {
 662         struct backlight_device *bl;
 663         struct adp8860_bl *data;
 664         struct adp8860_backlight_platform_data *pdata =
 665                 dev_get_platdata(&client->dev);
 666         struct backlight_properties props;
 667         uint8_t reg_val;
 668         int ret;
 669 
 670         if (!i2c_check_functionality(client->adapter,
 671                                         I2C_FUNC_SMBUS_BYTE_DATA)) {
 672                 dev_err(&client->dev, "SMBUS Byte Data not Supported\n");
 673                 return -EIO;
 674         }
 675 
 676         if (!pdata) {
 677                 dev_err(&client->dev, "no platform data?\n");
 678                 return -EINVAL;
 679         }
 680 
 681         data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
 682         if (data == NULL)
 683                 return -ENOMEM;
 684 
 685         ret = adp8860_read(client, ADP8860_MFDVID, &reg_val);
 686         if (ret < 0)
 687                 return ret;
 688 
 689         switch (ADP8860_MANID(reg_val)) {
 690         case ADP8863_MANUFID:
 691                 data->gdwn_dis = !!pdata->gdwn_dis;
 692                 /* fall through */
 693         case ADP8860_MANUFID:
 694                 data->en_ambl_sens = !!pdata->en_ambl_sens;
 695                 break;
 696         case ADP8861_MANUFID:
 697                 data->gdwn_dis = !!pdata->gdwn_dis;
 698                 break;
 699         default:
 700                 dev_err(&client->dev, "failed to probe\n");
 701                 return -ENODEV;
 702         }
 703 
 704         /* It's confirmed that the DEVID field is actually a REVID */
 705 
 706         data->revid = ADP8860_DEVID(reg_val);
 707         data->client = client;
 708         data->pdata = pdata;
 709         data->id = id->driver_data;
 710         data->current_brightness = 0;
 711         i2c_set_clientdata(client, data);
 712 
 713         memset(&props, 0, sizeof(props));
 714         props.type = BACKLIGHT_RAW;
 715         props.max_brightness = ADP8860_MAX_BRIGHTNESS;
 716 
 717         mutex_init(&data->lock);
 718 
 719         bl = devm_backlight_device_register(&client->dev,
 720                                 dev_driver_string(&client->dev),
 721                                 &client->dev, data, &adp8860_bl_ops, &props);
 722         if (IS_ERR(bl)) {
 723                 dev_err(&client->dev, "failed to register backlight\n");
 724                 return PTR_ERR(bl);
 725         }
 726 
 727         bl->props.brightness = ADP8860_MAX_BRIGHTNESS;
 728 
 729         data->bl = bl;
 730 
 731         if (data->en_ambl_sens)
 732                 ret = sysfs_create_group(&bl->dev.kobj,
 733                         &adp8860_bl_attr_group);
 734 
 735         if (ret) {
 736                 dev_err(&client->dev, "failed to register sysfs\n");
 737                 return ret;
 738         }
 739 
 740         ret = adp8860_bl_setup(bl);
 741         if (ret) {
 742                 ret = -EIO;
 743                 goto out;
 744         }
 745 
 746         backlight_update_status(bl);
 747 
 748         dev_info(&client->dev, "%s Rev.%d Backlight\n",
 749                 client->name, data->revid);
 750 
 751         if (pdata->num_leds)
 752                 adp8860_led_probe(client);
 753 
 754         return 0;
 755 
 756 out:
 757         if (data->en_ambl_sens)
 758                 sysfs_remove_group(&data->bl->dev.kobj,
 759                         &adp8860_bl_attr_group);
 760 
 761         return ret;
 762 }
 763 
 764 static int adp8860_remove(struct i2c_client *client)
 765 {
 766         struct adp8860_bl *data = i2c_get_clientdata(client);
 767 
 768         adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
 769 
 770         if (data->led)
 771                 adp8860_led_remove(client);
 772 
 773         if (data->en_ambl_sens)
 774                 sysfs_remove_group(&data->bl->dev.kobj,
 775                         &adp8860_bl_attr_group);
 776 
 777         return 0;
 778 }
 779 
 780 #ifdef CONFIG_PM_SLEEP
 781 static int adp8860_i2c_suspend(struct device *dev)
 782 {
 783         struct i2c_client *client = to_i2c_client(dev);
 784 
 785         adp8860_clr_bits(client, ADP8860_MDCR, NSTBY);
 786 
 787         return 0;
 788 }
 789 
 790 static int adp8860_i2c_resume(struct device *dev)
 791 {
 792         struct i2c_client *client = to_i2c_client(dev);
 793 
 794         adp8860_set_bits(client, ADP8860_MDCR, NSTBY | BLEN);
 795 
 796         return 0;
 797 }
 798 #endif
 799 
 800 static SIMPLE_DEV_PM_OPS(adp8860_i2c_pm_ops, adp8860_i2c_suspend,
 801                         adp8860_i2c_resume);
 802 
 803 static const struct i2c_device_id adp8860_id[] = {
 804         { "adp8860", adp8860 },
 805         { "adp8861", adp8861 },
 806         { "adp8863", adp8863 },
 807         { }
 808 };
 809 MODULE_DEVICE_TABLE(i2c, adp8860_id);
 810 
 811 static struct i2c_driver adp8860_driver = {
 812         .driver = {
 813                 .name   = KBUILD_MODNAME,
 814                 .pm     = &adp8860_i2c_pm_ops,
 815         },
 816         .probe    = adp8860_probe,
 817         .remove   = adp8860_remove,
 818         .id_table = adp8860_id,
 819 };
 820 
 821 module_i2c_driver(adp8860_driver);
 822 
 823 MODULE_LICENSE("GPL v2");
 824 MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
 825 MODULE_DESCRIPTION("ADP8860 Backlight driver");

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