Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.15-rc7 984 lines 27 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Backlight driver for Analog Devices ADP8870 Backlight Devices 4 * 5 * Copyright 2009-2011 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/backlight.h> 15#include <linux/leds.h> 16#include <linux/workqueue.h> 17#include <linux/slab.h> 18 19#include <linux/platform_data/adp8870.h> 20#define ADP8870_EXT_FEATURES 21#define ADP8870_USE_LEDS 22 23 24#define ADP8870_MFDVID 0x00 /* Manufacturer and device ID */ 25#define ADP8870_MDCR 0x01 /* Device mode and status */ 26#define ADP8870_INT_STAT 0x02 /* Interrupts status */ 27#define ADP8870_INT_EN 0x03 /* Interrupts enable */ 28#define ADP8870_CFGR 0x04 /* Configuration register */ 29#define ADP8870_BLSEL 0x05 /* Sink enable backlight or independent */ 30#define ADP8870_PWMLED 0x06 /* PWM Enable Selection Register */ 31#define ADP8870_BLOFF 0x07 /* Backlight off timeout */ 32#define ADP8870_BLDIM 0x08 /* Backlight dim timeout */ 33#define ADP8870_BLFR 0x09 /* Backlight fade in and out rates */ 34#define ADP8870_BLMX1 0x0A /* Backlight (Brightness Level 1-daylight) maximum current */ 35#define ADP8870_BLDM1 0x0B /* Backlight (Brightness Level 1-daylight) dim current */ 36#define ADP8870_BLMX2 0x0C /* Backlight (Brightness Level 2-bright) maximum current */ 37#define ADP8870_BLDM2 0x0D /* Backlight (Brightness Level 2-bright) dim current */ 38#define ADP8870_BLMX3 0x0E /* Backlight (Brightness Level 3-office) maximum current */ 39#define ADP8870_BLDM3 0x0F /* Backlight (Brightness Level 3-office) dim current */ 40#define ADP8870_BLMX4 0x10 /* Backlight (Brightness Level 4-indoor) maximum current */ 41#define ADP8870_BLDM4 0x11 /* Backlight (Brightness Level 4-indoor) dim current */ 42#define ADP8870_BLMX5 0x12 /* Backlight (Brightness Level 5-dark) maximum current */ 43#define ADP8870_BLDM5 0x13 /* Backlight (Brightness Level 5-dark) dim current */ 44#define ADP8870_ISCLAW 0x1A /* Independent sink current fade law register */ 45#define ADP8870_ISCC 0x1B /* Independent sink current control register */ 46#define ADP8870_ISCT1 0x1C /* Independent Sink Current Timer Register LED[7:5] */ 47#define ADP8870_ISCT2 0x1D /* Independent Sink Current Timer Register LED[4:1] */ 48#define ADP8870_ISCF 0x1E /* Independent sink current fade register */ 49#define ADP8870_ISC1 0x1F /* Independent Sink Current LED1 */ 50#define ADP8870_ISC2 0x20 /* Independent Sink Current LED2 */ 51#define ADP8870_ISC3 0x21 /* Independent Sink Current LED3 */ 52#define ADP8870_ISC4 0x22 /* Independent Sink Current LED4 */ 53#define ADP8870_ISC5 0x23 /* Independent Sink Current LED5 */ 54#define ADP8870_ISC6 0x24 /* Independent Sink Current LED6 */ 55#define ADP8870_ISC7 0x25 /* Independent Sink Current LED7 (Brightness Level 1-daylight) */ 56#define ADP8870_ISC7_L2 0x26 /* Independent Sink Current LED7 (Brightness Level 2-bright) */ 57#define ADP8870_ISC7_L3 0x27 /* Independent Sink Current LED7 (Brightness Level 3-office) */ 58#define ADP8870_ISC7_L4 0x28 /* Independent Sink Current LED7 (Brightness Level 4-indoor) */ 59#define ADP8870_ISC7_L5 0x29 /* Independent Sink Current LED7 (Brightness Level 5-dark) */ 60#define ADP8870_CMP_CTL 0x2D /* ALS Comparator Control Register */ 61#define ADP8870_ALS1_EN 0x2E /* Main ALS comparator level enable */ 62#define ADP8870_ALS2_EN 0x2F /* Second ALS comparator level enable */ 63#define ADP8870_ALS1_STAT 0x30 /* Main ALS Comparator Status Register */ 64#define ADP8870_ALS2_STAT 0x31 /* Second ALS Comparator Status Register */ 65#define ADP8870_L2TRP 0x32 /* L2 comparator reference */ 66#define ADP8870_L2HYS 0x33 /* L2 hysteresis */ 67#define ADP8870_L3TRP 0x34 /* L3 comparator reference */ 68#define ADP8870_L3HYS 0x35 /* L3 hysteresis */ 69#define ADP8870_L4TRP 0x36 /* L4 comparator reference */ 70#define ADP8870_L4HYS 0x37 /* L4 hysteresis */ 71#define ADP8870_L5TRP 0x38 /* L5 comparator reference */ 72#define ADP8870_L5HYS 0x39 /* L5 hysteresis */ 73#define ADP8870_PH1LEVL 0x40 /* First phototransistor ambient light level-low byte register */ 74#define ADP8870_PH1LEVH 0x41 /* First phototransistor ambient light level-high byte register */ 75#define ADP8870_PH2LEVL 0x42 /* Second phototransistor ambient light level-low byte register */ 76#define ADP8870_PH2LEVH 0x43 /* Second phototransistor ambient light level-high byte register */ 77 78#define ADP8870_MANUFID 0x3 /* Analog Devices AD8870 Manufacturer and device ID */ 79#define ADP8870_DEVID(x) ((x) & 0xF) 80#define ADP8870_MANID(x) ((x) >> 4) 81 82/* MDCR Device mode and status */ 83#define D7ALSEN (1 << 7) 84#define INT_CFG (1 << 6) 85#define NSTBY (1 << 5) 86#define DIM_EN (1 << 4) 87#define GDWN_DIS (1 << 3) 88#define SIS_EN (1 << 2) 89#define CMP_AUTOEN (1 << 1) 90#define BLEN (1 << 0) 91 92/* ADP8870_ALS1_EN Main ALS comparator level enable */ 93#define L5_EN (1 << 3) 94#define L4_EN (1 << 2) 95#define L3_EN (1 << 1) 96#define L2_EN (1 << 0) 97 98#define CFGR_BLV_SHIFT 3 99#define CFGR_BLV_MASK 0x7 100#define ADP8870_FLAG_LED_MASK 0xFF 101 102#define FADE_VAL(in, out) ((0xF & (in)) | ((0xF & (out)) << 4)) 103#define BL_CFGR_VAL(law, blv) ((((blv) & CFGR_BLV_MASK) << CFGR_BLV_SHIFT) | ((0x3 & (law)) << 1)) 104#define ALS_CMPR_CFG_VAL(filt) ((0x7 & (filt)) << 1) 105 106struct adp8870_bl { 107 struct i2c_client *client; 108 struct backlight_device *bl; 109 struct adp8870_led *led; 110 struct adp8870_backlight_platform_data *pdata; 111 struct mutex lock; 112 unsigned long cached_daylight_max; 113 int id; 114 int revid; 115 int current_brightness; 116}; 117 118struct adp8870_led { 119 struct led_classdev cdev; 120 struct work_struct work; 121 struct i2c_client *client; 122 enum led_brightness new_brightness; 123 int id; 124 int flags; 125}; 126 127static int adp8870_read(struct i2c_client *client, int reg, uint8_t *val) 128{ 129 int ret; 130 131 ret = i2c_smbus_read_byte_data(client, reg); 132 if (ret < 0) { 133 dev_err(&client->dev, "failed reading at 0x%02x\n", reg); 134 return ret; 135 } 136 137 *val = ret; 138 return 0; 139} 140 141 142static int adp8870_write(struct i2c_client *client, u8 reg, u8 val) 143{ 144 int ret = i2c_smbus_write_byte_data(client, reg, val); 145 146 if (ret) 147 dev_err(&client->dev, "failed to write\n"); 148 149 return ret; 150} 151 152static int adp8870_set_bits(struct i2c_client *client, int reg, uint8_t bit_mask) 153{ 154 struct adp8870_bl *data = i2c_get_clientdata(client); 155 uint8_t reg_val; 156 int ret; 157 158 mutex_lock(&data->lock); 159 160 ret = adp8870_read(client, reg, &reg_val); 161 162 if (!ret && ((reg_val & bit_mask) != bit_mask)) { 163 reg_val |= bit_mask; 164 ret = adp8870_write(client, reg, reg_val); 165 } 166 167 mutex_unlock(&data->lock); 168 return ret; 169} 170 171static int adp8870_clr_bits(struct i2c_client *client, int reg, uint8_t bit_mask) 172{ 173 struct adp8870_bl *data = i2c_get_clientdata(client); 174 uint8_t reg_val; 175 int ret; 176 177 mutex_lock(&data->lock); 178 179 ret = adp8870_read(client, reg, &reg_val); 180 181 if (!ret && (reg_val & bit_mask)) { 182 reg_val &= ~bit_mask; 183 ret = adp8870_write(client, reg, reg_val); 184 } 185 186 mutex_unlock(&data->lock); 187 return ret; 188} 189 190/* 191 * Independent sink / LED 192 */ 193#if defined(ADP8870_USE_LEDS) 194static void adp8870_led_work(struct work_struct *work) 195{ 196 struct adp8870_led *led = container_of(work, struct adp8870_led, work); 197 198 adp8870_write(led->client, ADP8870_ISC1 + led->id - 1, 199 led->new_brightness >> 1); 200} 201 202static void adp8870_led_set(struct led_classdev *led_cdev, 203 enum led_brightness value) 204{ 205 struct adp8870_led *led; 206 207 led = container_of(led_cdev, struct adp8870_led, cdev); 208 led->new_brightness = value; 209 /* 210 * Use workqueue for IO since I2C operations can sleep. 211 */ 212 schedule_work(&led->work); 213} 214 215static int adp8870_led_setup(struct adp8870_led *led) 216{ 217 struct i2c_client *client = led->client; 218 int ret = 0; 219 220 ret = adp8870_write(client, ADP8870_ISC1 + led->id - 1, 0); 221 if (ret) 222 return ret; 223 224 ret = adp8870_set_bits(client, ADP8870_ISCC, 1 << (led->id - 1)); 225 if (ret) 226 return ret; 227 228 if (led->id > 4) 229 ret = adp8870_set_bits(client, ADP8870_ISCT1, 230 (led->flags & 0x3) << ((led->id - 5) * 2)); 231 else 232 ret = adp8870_set_bits(client, ADP8870_ISCT2, 233 (led->flags & 0x3) << ((led->id - 1) * 2)); 234 235 return ret; 236} 237 238static int adp8870_led_probe(struct i2c_client *client) 239{ 240 struct adp8870_backlight_platform_data *pdata = 241 dev_get_platdata(&client->dev); 242 struct adp8870_bl *data = i2c_get_clientdata(client); 243 struct adp8870_led *led, *led_dat; 244 struct led_info *cur_led; 245 int ret, i; 246 247 led = devm_kcalloc(&client->dev, pdata->num_leds, sizeof(*led), 248 GFP_KERNEL); 249 if (led == NULL) 250 return -ENOMEM; 251 252 ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law); 253 if (ret) 254 return ret; 255 256 ret = adp8870_write(client, ADP8870_ISCT1, 257 (pdata->led_on_time & 0x3) << 6); 258 if (ret) 259 return ret; 260 261 ret = adp8870_write(client, ADP8870_ISCF, 262 FADE_VAL(pdata->led_fade_in, pdata->led_fade_out)); 263 if (ret) 264 return ret; 265 266 for (i = 0; i < pdata->num_leds; ++i) { 267 cur_led = &pdata->leds[i]; 268 led_dat = &led[i]; 269 270 led_dat->id = cur_led->flags & ADP8870_FLAG_LED_MASK; 271 272 if (led_dat->id > 7 || led_dat->id < 1) { 273 dev_err(&client->dev, "Invalid LED ID %d\n", 274 led_dat->id); 275 ret = -EINVAL; 276 goto err; 277 } 278 279 if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { 280 dev_err(&client->dev, "LED %d used by Backlight\n", 281 led_dat->id); 282 ret = -EBUSY; 283 goto err; 284 } 285 286 led_dat->cdev.name = cur_led->name; 287 led_dat->cdev.default_trigger = cur_led->default_trigger; 288 led_dat->cdev.brightness_set = adp8870_led_set; 289 led_dat->cdev.brightness = LED_OFF; 290 led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT; 291 led_dat->client = client; 292 led_dat->new_brightness = LED_OFF; 293 INIT_WORK(&led_dat->work, adp8870_led_work); 294 295 ret = led_classdev_register(&client->dev, &led_dat->cdev); 296 if (ret) { 297 dev_err(&client->dev, "failed to register LED %d\n", 298 led_dat->id); 299 goto err; 300 } 301 302 ret = adp8870_led_setup(led_dat); 303 if (ret) { 304 dev_err(&client->dev, "failed to write\n"); 305 i++; 306 goto err; 307 } 308 } 309 310 data->led = led; 311 312 return 0; 313 314 err: 315 for (i = i - 1; i >= 0; --i) { 316 led_classdev_unregister(&led[i].cdev); 317 cancel_work_sync(&led[i].work); 318 } 319 320 return ret; 321} 322 323static int adp8870_led_remove(struct i2c_client *client) 324{ 325 struct adp8870_backlight_platform_data *pdata = 326 dev_get_platdata(&client->dev); 327 struct adp8870_bl *data = i2c_get_clientdata(client); 328 int i; 329 330 for (i = 0; i < pdata->num_leds; i++) { 331 led_classdev_unregister(&data->led[i].cdev); 332 cancel_work_sync(&data->led[i].work); 333 } 334 335 return 0; 336} 337#else 338static int adp8870_led_probe(struct i2c_client *client) 339{ 340 return 0; 341} 342 343static int adp8870_led_remove(struct i2c_client *client) 344{ 345 return 0; 346} 347#endif 348 349static int adp8870_bl_set(struct backlight_device *bl, int brightness) 350{ 351 struct adp8870_bl *data = bl_get_data(bl); 352 struct i2c_client *client = data->client; 353 int ret = 0; 354 355 if (data->pdata->en_ambl_sens) { 356 if ((brightness > 0) && (brightness < ADP8870_MAX_BRIGHTNESS)) { 357 /* Disable Ambient Light auto adjust */ 358 ret = adp8870_clr_bits(client, ADP8870_MDCR, 359 CMP_AUTOEN); 360 if (ret) 361 return ret; 362 ret = adp8870_write(client, ADP8870_BLMX1, brightness); 363 if (ret) 364 return ret; 365 } else { 366 /* 367 * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust 368 * restore daylight l1 sysfs brightness 369 */ 370 ret = adp8870_write(client, ADP8870_BLMX1, 371 data->cached_daylight_max); 372 if (ret) 373 return ret; 374 375 ret = adp8870_set_bits(client, ADP8870_MDCR, 376 CMP_AUTOEN); 377 if (ret) 378 return ret; 379 } 380 } else { 381 ret = adp8870_write(client, ADP8870_BLMX1, brightness); 382 if (ret) 383 return ret; 384 } 385 386 if (data->current_brightness && brightness == 0) 387 ret = adp8870_set_bits(client, 388 ADP8870_MDCR, DIM_EN); 389 else if (data->current_brightness == 0 && brightness) 390 ret = adp8870_clr_bits(client, 391 ADP8870_MDCR, DIM_EN); 392 393 if (!ret) 394 data->current_brightness = brightness; 395 396 return ret; 397} 398 399static int adp8870_bl_update_status(struct backlight_device *bl) 400{ 401 return adp8870_bl_set(bl, backlight_get_brightness(bl)); 402} 403 404static int adp8870_bl_get_brightness(struct backlight_device *bl) 405{ 406 struct adp8870_bl *data = bl_get_data(bl); 407 408 return data->current_brightness; 409} 410 411static const struct backlight_ops adp8870_bl_ops = { 412 .update_status = adp8870_bl_update_status, 413 .get_brightness = adp8870_bl_get_brightness, 414}; 415 416static int adp8870_bl_setup(struct backlight_device *bl) 417{ 418 struct adp8870_bl *data = bl_get_data(bl); 419 struct i2c_client *client = data->client; 420 struct adp8870_backlight_platform_data *pdata = data->pdata; 421 int ret = 0; 422 423 ret = adp8870_write(client, ADP8870_BLSEL, ~pdata->bl_led_assign); 424 if (ret) 425 return ret; 426 427 ret = adp8870_write(client, ADP8870_PWMLED, pdata->pwm_assign); 428 if (ret) 429 return ret; 430 431 ret = adp8870_write(client, ADP8870_BLMX1, pdata->l1_daylight_max); 432 if (ret) 433 return ret; 434 435 ret = adp8870_write(client, ADP8870_BLDM1, pdata->l1_daylight_dim); 436 if (ret) 437 return ret; 438 439 if (pdata->en_ambl_sens) { 440 data->cached_daylight_max = pdata->l1_daylight_max; 441 ret = adp8870_write(client, ADP8870_BLMX2, 442 pdata->l2_bright_max); 443 if (ret) 444 return ret; 445 ret = adp8870_write(client, ADP8870_BLDM2, 446 pdata->l2_bright_dim); 447 if (ret) 448 return ret; 449 450 ret = adp8870_write(client, ADP8870_BLMX3, 451 pdata->l3_office_max); 452 if (ret) 453 return ret; 454 ret = adp8870_write(client, ADP8870_BLDM3, 455 pdata->l3_office_dim); 456 if (ret) 457 return ret; 458 459 ret = adp8870_write(client, ADP8870_BLMX4, 460 pdata->l4_indoor_max); 461 if (ret) 462 return ret; 463 464 ret = adp8870_write(client, ADP8870_BLDM4, 465 pdata->l4_indor_dim); 466 if (ret) 467 return ret; 468 469 ret = adp8870_write(client, ADP8870_BLMX5, 470 pdata->l5_dark_max); 471 if (ret) 472 return ret; 473 474 ret = adp8870_write(client, ADP8870_BLDM5, 475 pdata->l5_dark_dim); 476 if (ret) 477 return ret; 478 479 ret = adp8870_write(client, ADP8870_L2TRP, pdata->l2_trip); 480 if (ret) 481 return ret; 482 483 ret = adp8870_write(client, ADP8870_L2HYS, pdata->l2_hyst); 484 if (ret) 485 return ret; 486 487 ret = adp8870_write(client, ADP8870_L3TRP, pdata->l3_trip); 488 if (ret) 489 return ret; 490 491 ret = adp8870_write(client, ADP8870_L3HYS, pdata->l3_hyst); 492 if (ret) 493 return ret; 494 495 ret = adp8870_write(client, ADP8870_L4TRP, pdata->l4_trip); 496 if (ret) 497 return ret; 498 499 ret = adp8870_write(client, ADP8870_L4HYS, pdata->l4_hyst); 500 if (ret) 501 return ret; 502 503 ret = adp8870_write(client, ADP8870_L5TRP, pdata->l5_trip); 504 if (ret) 505 return ret; 506 507 ret = adp8870_write(client, ADP8870_L5HYS, pdata->l5_hyst); 508 if (ret) 509 return ret; 510 511 ret = adp8870_write(client, ADP8870_ALS1_EN, L5_EN | L4_EN | 512 L3_EN | L2_EN); 513 if (ret) 514 return ret; 515 516 ret = adp8870_write(client, ADP8870_CMP_CTL, 517 ALS_CMPR_CFG_VAL(pdata->abml_filt)); 518 if (ret) 519 return ret; 520 } 521 522 ret = adp8870_write(client, ADP8870_CFGR, 523 BL_CFGR_VAL(pdata->bl_fade_law, 0)); 524 if (ret) 525 return ret; 526 527 ret = adp8870_write(client, ADP8870_BLFR, FADE_VAL(pdata->bl_fade_in, 528 pdata->bl_fade_out)); 529 if (ret) 530 return ret; 531 /* 532 * ADP8870 Rev0 requires GDWN_DIS bit set 533 */ 534 535 ret = adp8870_set_bits(client, ADP8870_MDCR, BLEN | DIM_EN | NSTBY | 536 (data->revid == 0 ? GDWN_DIS : 0)); 537 538 return ret; 539} 540 541static ssize_t adp8870_show(struct device *dev, char *buf, int reg) 542{ 543 struct adp8870_bl *data = dev_get_drvdata(dev); 544 int error; 545 uint8_t reg_val; 546 547 mutex_lock(&data->lock); 548 error = adp8870_read(data->client, reg, &reg_val); 549 mutex_unlock(&data->lock); 550 551 if (error < 0) 552 return error; 553 554 return sprintf(buf, "%u\n", reg_val); 555} 556 557static ssize_t adp8870_store(struct device *dev, const char *buf, 558 size_t count, int reg) 559{ 560 struct adp8870_bl *data = dev_get_drvdata(dev); 561 unsigned long val; 562 int ret; 563 564 ret = kstrtoul(buf, 10, &val); 565 if (ret) 566 return ret; 567 568 mutex_lock(&data->lock); 569 adp8870_write(data->client, reg, val); 570 mutex_unlock(&data->lock); 571 572 return count; 573} 574 575static ssize_t adp8870_bl_l5_dark_max_show(struct device *dev, 576 struct device_attribute *attr, char *buf) 577{ 578 return adp8870_show(dev, buf, ADP8870_BLMX5); 579} 580 581static ssize_t adp8870_bl_l5_dark_max_store(struct device *dev, 582 struct device_attribute *attr, const char *buf, size_t count) 583{ 584 return adp8870_store(dev, buf, count, ADP8870_BLMX5); 585} 586static DEVICE_ATTR(l5_dark_max, 0664, adp8870_bl_l5_dark_max_show, 587 adp8870_bl_l5_dark_max_store); 588 589 590static ssize_t adp8870_bl_l4_indoor_max_show(struct device *dev, 591 struct device_attribute *attr, char *buf) 592{ 593 return adp8870_show(dev, buf, ADP8870_BLMX4); 594} 595 596static ssize_t adp8870_bl_l4_indoor_max_store(struct device *dev, 597 struct device_attribute *attr, const char *buf, size_t count) 598{ 599 return adp8870_store(dev, buf, count, ADP8870_BLMX4); 600} 601static DEVICE_ATTR(l4_indoor_max, 0664, adp8870_bl_l4_indoor_max_show, 602 adp8870_bl_l4_indoor_max_store); 603 604 605static ssize_t adp8870_bl_l3_office_max_show(struct device *dev, 606 struct device_attribute *attr, char *buf) 607{ 608 return adp8870_show(dev, buf, ADP8870_BLMX3); 609} 610 611static ssize_t adp8870_bl_l3_office_max_store(struct device *dev, 612 struct device_attribute *attr, const char *buf, size_t count) 613{ 614 return adp8870_store(dev, buf, count, ADP8870_BLMX3); 615} 616 617static DEVICE_ATTR(l3_office_max, 0664, adp8870_bl_l3_office_max_show, 618 adp8870_bl_l3_office_max_store); 619 620static ssize_t adp8870_bl_l2_bright_max_show(struct device *dev, 621 struct device_attribute *attr, char *buf) 622{ 623 return adp8870_show(dev, buf, ADP8870_BLMX2); 624} 625 626static ssize_t adp8870_bl_l2_bright_max_store(struct device *dev, 627 struct device_attribute *attr, const char *buf, size_t count) 628{ 629 return adp8870_store(dev, buf, count, ADP8870_BLMX2); 630} 631static DEVICE_ATTR(l2_bright_max, 0664, adp8870_bl_l2_bright_max_show, 632 adp8870_bl_l2_bright_max_store); 633 634static ssize_t adp8870_bl_l1_daylight_max_show(struct device *dev, 635 struct device_attribute *attr, char *buf) 636{ 637 return adp8870_show(dev, buf, ADP8870_BLMX1); 638} 639 640static ssize_t adp8870_bl_l1_daylight_max_store(struct device *dev, 641 struct device_attribute *attr, const char *buf, size_t count) 642{ 643 struct adp8870_bl *data = dev_get_drvdata(dev); 644 int ret = kstrtoul(buf, 10, &data->cached_daylight_max); 645 646 if (ret) 647 return ret; 648 649 return adp8870_store(dev, buf, count, ADP8870_BLMX1); 650} 651static DEVICE_ATTR(l1_daylight_max, 0664, adp8870_bl_l1_daylight_max_show, 652 adp8870_bl_l1_daylight_max_store); 653 654static ssize_t adp8870_bl_l5_dark_dim_show(struct device *dev, 655 struct device_attribute *attr, char *buf) 656{ 657 return adp8870_show(dev, buf, ADP8870_BLDM5); 658} 659 660static ssize_t adp8870_bl_l5_dark_dim_store(struct device *dev, 661 struct device_attribute *attr, 662 const char *buf, size_t count) 663{ 664 return adp8870_store(dev, buf, count, ADP8870_BLDM5); 665} 666static DEVICE_ATTR(l5_dark_dim, 0664, adp8870_bl_l5_dark_dim_show, 667 adp8870_bl_l5_dark_dim_store); 668 669static ssize_t adp8870_bl_l4_indoor_dim_show(struct device *dev, 670 struct device_attribute *attr, char *buf) 671{ 672 return adp8870_show(dev, buf, ADP8870_BLDM4); 673} 674 675static ssize_t adp8870_bl_l4_indoor_dim_store(struct device *dev, 676 struct device_attribute *attr, 677 const char *buf, size_t count) 678{ 679 return adp8870_store(dev, buf, count, ADP8870_BLDM4); 680} 681static DEVICE_ATTR(l4_indoor_dim, 0664, adp8870_bl_l4_indoor_dim_show, 682 adp8870_bl_l4_indoor_dim_store); 683 684 685static ssize_t adp8870_bl_l3_office_dim_show(struct device *dev, 686 struct device_attribute *attr, char *buf) 687{ 688 return adp8870_show(dev, buf, ADP8870_BLDM3); 689} 690 691static ssize_t adp8870_bl_l3_office_dim_store(struct device *dev, 692 struct device_attribute *attr, 693 const char *buf, size_t count) 694{ 695 return adp8870_store(dev, buf, count, ADP8870_BLDM3); 696} 697static DEVICE_ATTR(l3_office_dim, 0664, adp8870_bl_l3_office_dim_show, 698 adp8870_bl_l3_office_dim_store); 699 700static ssize_t adp8870_bl_l2_bright_dim_show(struct device *dev, 701 struct device_attribute *attr, char *buf) 702{ 703 return adp8870_show(dev, buf, ADP8870_BLDM2); 704} 705 706static ssize_t adp8870_bl_l2_bright_dim_store(struct device *dev, 707 struct device_attribute *attr, 708 const char *buf, size_t count) 709{ 710 return adp8870_store(dev, buf, count, ADP8870_BLDM2); 711} 712static DEVICE_ATTR(l2_bright_dim, 0664, adp8870_bl_l2_bright_dim_show, 713 adp8870_bl_l2_bright_dim_store); 714 715static ssize_t adp8870_bl_l1_daylight_dim_show(struct device *dev, 716 struct device_attribute *attr, char *buf) 717{ 718 return adp8870_show(dev, buf, ADP8870_BLDM1); 719} 720 721static ssize_t adp8870_bl_l1_daylight_dim_store(struct device *dev, 722 struct device_attribute *attr, 723 const char *buf, size_t count) 724{ 725 return adp8870_store(dev, buf, count, ADP8870_BLDM1); 726} 727static DEVICE_ATTR(l1_daylight_dim, 0664, adp8870_bl_l1_daylight_dim_show, 728 adp8870_bl_l1_daylight_dim_store); 729 730#ifdef ADP8870_EXT_FEATURES 731static ssize_t adp8870_bl_ambient_light_level_show(struct device *dev, 732 struct device_attribute *attr, char *buf) 733{ 734 struct adp8870_bl *data = dev_get_drvdata(dev); 735 int error; 736 uint8_t reg_val; 737 uint16_t ret_val; 738 739 mutex_lock(&data->lock); 740 error = adp8870_read(data->client, ADP8870_PH1LEVL, &reg_val); 741 if (error < 0) { 742 mutex_unlock(&data->lock); 743 return error; 744 } 745 ret_val = reg_val; 746 error = adp8870_read(data->client, ADP8870_PH1LEVH, &reg_val); 747 mutex_unlock(&data->lock); 748 749 if (error < 0) 750 return error; 751 752 /* Return 13-bit conversion value for the first light sensor */ 753 ret_val += (reg_val & 0x1F) << 8; 754 755 return sprintf(buf, "%u\n", ret_val); 756} 757static DEVICE_ATTR(ambient_light_level, 0444, 758 adp8870_bl_ambient_light_level_show, NULL); 759 760static ssize_t adp8870_bl_ambient_light_zone_show(struct device *dev, 761 struct device_attribute *attr, char *buf) 762{ 763 struct adp8870_bl *data = dev_get_drvdata(dev); 764 int error; 765 uint8_t reg_val; 766 767 mutex_lock(&data->lock); 768 error = adp8870_read(data->client, ADP8870_CFGR, &reg_val); 769 mutex_unlock(&data->lock); 770 771 if (error < 0) 772 return error; 773 774 return sprintf(buf, "%u\n", 775 ((reg_val >> CFGR_BLV_SHIFT) & CFGR_BLV_MASK) + 1); 776} 777 778static ssize_t adp8870_bl_ambient_light_zone_store(struct device *dev, 779 struct device_attribute *attr, 780 const char *buf, size_t count) 781{ 782 struct adp8870_bl *data = dev_get_drvdata(dev); 783 unsigned long val; 784 uint8_t reg_val; 785 int ret; 786 787 ret = kstrtoul(buf, 10, &val); 788 if (ret) 789 return ret; 790 791 if (val == 0) { 792 /* Enable automatic ambient light sensing */ 793 adp8870_set_bits(data->client, ADP8870_MDCR, CMP_AUTOEN); 794 } else if ((val > 0) && (val < 6)) { 795 /* Disable automatic ambient light sensing */ 796 adp8870_clr_bits(data->client, ADP8870_MDCR, CMP_AUTOEN); 797 798 /* Set user supplied ambient light zone */ 799 mutex_lock(&data->lock); 800 ret = adp8870_read(data->client, ADP8870_CFGR, &reg_val); 801 if (!ret) { 802 reg_val &= ~(CFGR_BLV_MASK << CFGR_BLV_SHIFT); 803 reg_val |= (val - 1) << CFGR_BLV_SHIFT; 804 adp8870_write(data->client, ADP8870_CFGR, reg_val); 805 } 806 mutex_unlock(&data->lock); 807 } 808 809 return count; 810} 811static DEVICE_ATTR(ambient_light_zone, 0664, 812 adp8870_bl_ambient_light_zone_show, 813 adp8870_bl_ambient_light_zone_store); 814#endif 815 816static struct attribute *adp8870_bl_attributes[] = { 817 &dev_attr_l5_dark_max.attr, 818 &dev_attr_l5_dark_dim.attr, 819 &dev_attr_l4_indoor_max.attr, 820 &dev_attr_l4_indoor_dim.attr, 821 &dev_attr_l3_office_max.attr, 822 &dev_attr_l3_office_dim.attr, 823 &dev_attr_l2_bright_max.attr, 824 &dev_attr_l2_bright_dim.attr, 825 &dev_attr_l1_daylight_max.attr, 826 &dev_attr_l1_daylight_dim.attr, 827#ifdef ADP8870_EXT_FEATURES 828 &dev_attr_ambient_light_level.attr, 829 &dev_attr_ambient_light_zone.attr, 830#endif 831 NULL 832}; 833 834static const struct attribute_group adp8870_bl_attr_group = { 835 .attrs = adp8870_bl_attributes, 836}; 837 838static int adp8870_probe(struct i2c_client *client) 839{ 840 const struct i2c_device_id *id = i2c_client_get_device_id(client); 841 struct backlight_properties props; 842 struct backlight_device *bl; 843 struct adp8870_bl *data; 844 struct adp8870_backlight_platform_data *pdata = 845 dev_get_platdata(&client->dev); 846 uint8_t reg_val; 847 int ret; 848 849 if (!i2c_check_functionality(client->adapter, 850 I2C_FUNC_SMBUS_BYTE_DATA)) { 851 dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); 852 return -EIO; 853 } 854 855 if (!pdata) { 856 dev_err(&client->dev, "no platform data?\n"); 857 return -EINVAL; 858 } 859 860 ret = adp8870_read(client, ADP8870_MFDVID, &reg_val); 861 if (ret < 0) 862 return -EIO; 863 864 if (ADP8870_MANID(reg_val) != ADP8870_MANUFID) { 865 dev_err(&client->dev, "failed to probe\n"); 866 return -ENODEV; 867 } 868 869 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 870 if (data == NULL) 871 return -ENOMEM; 872 873 data->revid = ADP8870_DEVID(reg_val); 874 data->client = client; 875 data->pdata = pdata; 876 data->id = id->driver_data; 877 data->current_brightness = 0; 878 i2c_set_clientdata(client, data); 879 880 mutex_init(&data->lock); 881 882 memset(&props, 0, sizeof(props)); 883 props.type = BACKLIGHT_RAW; 884 props.max_brightness = props.brightness = ADP8870_MAX_BRIGHTNESS; 885 bl = devm_backlight_device_register(&client->dev, 886 dev_driver_string(&client->dev), 887 &client->dev, data, &adp8870_bl_ops, &props); 888 if (IS_ERR(bl)) { 889 dev_err(&client->dev, "failed to register backlight\n"); 890 return PTR_ERR(bl); 891 } 892 893 data->bl = bl; 894 895 if (pdata->en_ambl_sens) { 896 ret = sysfs_create_group(&bl->dev.kobj, 897 &adp8870_bl_attr_group); 898 if (ret) { 899 dev_err(&client->dev, "failed to register sysfs\n"); 900 return ret; 901 } 902 } 903 904 ret = adp8870_bl_setup(bl); 905 if (ret) { 906 ret = -EIO; 907 goto out; 908 } 909 910 backlight_update_status(bl); 911 912 dev_info(&client->dev, "Rev.%d Backlight\n", data->revid); 913 914 if (pdata->num_leds) 915 adp8870_led_probe(client); 916 917 return 0; 918 919out: 920 if (data->pdata->en_ambl_sens) 921 sysfs_remove_group(&data->bl->dev.kobj, 922 &adp8870_bl_attr_group); 923 924 return ret; 925} 926 927static void adp8870_remove(struct i2c_client *client) 928{ 929 struct adp8870_bl *data = i2c_get_clientdata(client); 930 931 adp8870_clr_bits(client, ADP8870_MDCR, NSTBY); 932 933 if (data->led) 934 adp8870_led_remove(client); 935 936 if (data->pdata->en_ambl_sens) 937 sysfs_remove_group(&data->bl->dev.kobj, 938 &adp8870_bl_attr_group); 939} 940 941#ifdef CONFIG_PM_SLEEP 942static int adp8870_i2c_suspend(struct device *dev) 943{ 944 struct i2c_client *client = to_i2c_client(dev); 945 946 adp8870_clr_bits(client, ADP8870_MDCR, NSTBY); 947 948 return 0; 949} 950 951static int adp8870_i2c_resume(struct device *dev) 952{ 953 struct i2c_client *client = to_i2c_client(dev); 954 955 adp8870_set_bits(client, ADP8870_MDCR, NSTBY | BLEN); 956 957 return 0; 958} 959#endif 960 961static SIMPLE_DEV_PM_OPS(adp8870_i2c_pm_ops, adp8870_i2c_suspend, 962 adp8870_i2c_resume); 963 964static const struct i2c_device_id adp8870_id[] = { 965 { "adp8870" }, 966 { } 967}; 968MODULE_DEVICE_TABLE(i2c, adp8870_id); 969 970static struct i2c_driver adp8870_driver = { 971 .driver = { 972 .name = KBUILD_MODNAME, 973 .pm = &adp8870_i2c_pm_ops, 974 }, 975 .probe = adp8870_probe, 976 .remove = adp8870_remove, 977 .id_table = adp8870_id, 978}; 979 980module_i2c_driver(adp8870_driver); 981 982MODULE_LICENSE("GPL v2"); 983MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>"); 984MODULE_DESCRIPTION("ADP8870 Backlight driver");