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

backlight: new driver for the ADP8870 backlight devices

Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Cc: Richard Purdie <rpurdie@rpsys.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Michael Hennerich and committed by
Linus Torvalds
a59ec1e7 7f81c889

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