Lines Matching +full:led +full:- +full:backlight
1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Backlight driver for Analog Devices ADP8870 Backlight Devices
5 * Copyright 2009-2011 Analog Devices Inc.
15 #include <linux/backlight.h>
30 #define ADP8870_BLSEL 0x05 /* Sink enable backlight or independent */
32 #define ADP8870_BLOFF 0x07 /* Backlight off timeout */
33 #define ADP8870_BLDIM 0x08 /* Backlight dim timeout */
34 #define ADP8870_BLFR 0x09 /* Backlight fade in and out rates */
35 #define ADP8870_BLMX1 0x0A /* Backlight (Brightness Level 1-daylight) maximum current */
36 #define ADP8870_BLDM1 0x0B /* Backlight (Brightness Level 1-daylight) dim current */
37 #define ADP8870_BLMX2 0x0C /* Backlight (Brightness Level 2-bright) maximum current */
38 #define ADP8870_BLDM2 0x0D /* Backlight (Brightness Level 2-bright) dim current */
39 #define ADP8870_BLMX3 0x0E /* Backlight (Brightness Level 3-office) maximum current */
40 #define ADP8870_BLDM3 0x0F /* Backlight (Brightness Level 3-office) dim current */
41 #define ADP8870_BLMX4 0x10 /* Backlight (Brightness Level 4-indoor) maximum current */
42 #define ADP8870_BLDM4 0x11 /* Backlight (Brightness Level 4-indoor) dim current */
43 #define ADP8870_BLMX5 0x12 /* Backlight (Brightness Level 5-dark) maximum current */
44 #define ADP8870_BLDM5 0x13 /* Backlight (Brightness Level 5-dark) dim current */
47 #define ADP8870_ISCT1 0x1C /* Independent Sink Current Timer Register LED[7:5] */
48 #define ADP8870_ISCT2 0x1D /* Independent Sink Current Timer Register LED[4:1] */
56 #define ADP8870_ISC7 0x25 /* Independent Sink Current LED7 (Brightness Level 1-daylight) */
57 #define ADP8870_ISC7_L2 0x26 /* Independent Sink Current LED7 (Brightness Level 2-bright) */
58 #define ADP8870_ISC7_L3 0x27 /* Independent Sink Current LED7 (Brightness Level 3-office) */
59 #define ADP8870_ISC7_L4 0x28 /* Independent Sink Current LED7 (Brightness Level 4-indoor) */
60 #define ADP8870_ISC7_L5 0x29 /* Independent Sink Current LED7 (Brightness Level 5-dark) */
74 #define ADP8870_PH1LEVL 0x40 /* First phototransistor ambient light level-low byte register */
75 #define ADP8870_PH1LEVH 0x41 /* First phototransistor ambient light level-high byte register */
76 #define ADP8870_PH2LEVL 0x42 /* Second phototransistor ambient light level-low byte register */
77 #define ADP8870_PH2LEVH 0x43 /* Second phototransistor ambient light level-high byte register */
110 struct adp8870_led *led; member
134 dev_err(&client->dev, "failed reading at 0x%02x\n", reg); in adp8870_read()
148 dev_err(&client->dev, "failed to write\n"); in adp8870_write()
159 mutex_lock(&data->lock); in adp8870_set_bits()
168 mutex_unlock(&data->lock); in adp8870_set_bits()
178 mutex_lock(&data->lock); in adp8870_clr_bits()
187 mutex_unlock(&data->lock); in adp8870_clr_bits()
192 * Independent sink / LED
197 struct adp8870_led *led = container_of(work, struct adp8870_led, work); in adp8870_led_work() local
199 adp8870_write(led->client, ADP8870_ISC1 + led->id - 1, in adp8870_led_work()
200 led->new_brightness >> 1); in adp8870_led_work()
206 struct adp8870_led *led; in adp8870_led_set() local
208 led = container_of(led_cdev, struct adp8870_led, cdev); in adp8870_led_set()
209 led->new_brightness = value; in adp8870_led_set()
213 schedule_work(&led->work); in adp8870_led_set()
216 static int adp8870_led_setup(struct adp8870_led *led) in adp8870_led_setup() argument
218 struct i2c_client *client = led->client; in adp8870_led_setup()
221 ret = adp8870_write(client, ADP8870_ISC1 + led->id - 1, 0); in adp8870_led_setup()
225 ret = adp8870_set_bits(client, ADP8870_ISCC, 1 << (led->id - 1)); in adp8870_led_setup()
229 if (led->id > 4) in adp8870_led_setup()
231 (led->flags & 0x3) << ((led->id - 5) * 2)); in adp8870_led_setup()
234 (led->flags & 0x3) << ((led->id - 1) * 2)); in adp8870_led_setup()
242 dev_get_platdata(&client->dev); in adp8870_led_probe()
244 struct adp8870_led *led, *led_dat; in adp8870_led_probe() local
248 led = devm_kcalloc(&client->dev, pdata->num_leds, sizeof(*led), in adp8870_led_probe()
250 if (led == NULL) in adp8870_led_probe()
251 return -ENOMEM; in adp8870_led_probe()
253 ret = adp8870_write(client, ADP8870_ISCLAW, pdata->led_fade_law); in adp8870_led_probe()
258 (pdata->led_on_time & 0x3) << 6); in adp8870_led_probe()
263 FADE_VAL(pdata->led_fade_in, pdata->led_fade_out)); in adp8870_led_probe()
267 for (i = 0; i < pdata->num_leds; ++i) { in adp8870_led_probe()
268 cur_led = &pdata->leds[i]; in adp8870_led_probe()
269 led_dat = &led[i]; in adp8870_led_probe()
271 led_dat->id = cur_led->flags & ADP8870_FLAG_LED_MASK; in adp8870_led_probe()
273 if (led_dat->id > 7 || led_dat->id < 1) { in adp8870_led_probe()
274 dev_err(&client->dev, "Invalid LED ID %d\n", in adp8870_led_probe()
275 led_dat->id); in adp8870_led_probe()
276 ret = -EINVAL; in adp8870_led_probe()
280 if (pdata->bl_led_assign & (1 << (led_dat->id - 1))) { in adp8870_led_probe()
281 dev_err(&client->dev, "LED %d used by Backlight\n", in adp8870_led_probe()
282 led_dat->id); in adp8870_led_probe()
283 ret = -EBUSY; in adp8870_led_probe()
287 led_dat->cdev.name = cur_led->name; in adp8870_led_probe()
288 led_dat->cdev.default_trigger = cur_led->default_trigger; in adp8870_led_probe()
289 led_dat->cdev.brightness_set = adp8870_led_set; in adp8870_led_probe()
290 led_dat->cdev.brightness = LED_OFF; in adp8870_led_probe()
291 led_dat->flags = cur_led->flags >> FLAG_OFFT_SHIFT; in adp8870_led_probe()
292 led_dat->client = client; in adp8870_led_probe()
293 led_dat->new_brightness = LED_OFF; in adp8870_led_probe()
294 INIT_WORK(&led_dat->work, adp8870_led_work); in adp8870_led_probe()
296 ret = led_classdev_register(&client->dev, &led_dat->cdev); in adp8870_led_probe()
298 dev_err(&client->dev, "failed to register LED %d\n", in adp8870_led_probe()
299 led_dat->id); in adp8870_led_probe()
305 dev_err(&client->dev, "failed to write\n"); in adp8870_led_probe()
311 data->led = led; in adp8870_led_probe()
316 for (i = i - 1; i >= 0; --i) { in adp8870_led_probe()
317 led_classdev_unregister(&led[i].cdev); in adp8870_led_probe()
318 cancel_work_sync(&led[i].work); in adp8870_led_probe()
327 dev_get_platdata(&client->dev); in adp8870_led_remove()
331 for (i = 0; i < pdata->num_leds; i++) { in adp8870_led_remove()
332 led_classdev_unregister(&data->led[i].cdev); in adp8870_led_remove()
333 cancel_work_sync(&data->led[i].work); in adp8870_led_remove()
353 struct i2c_client *client = data->client; in adp8870_bl_set()
356 if (data->pdata->en_ambl_sens) { in adp8870_bl_set()
368 * MAX_BRIGHTNESS -> Enable Ambient Light auto adjust in adp8870_bl_set()
372 data->cached_daylight_max); in adp8870_bl_set()
387 if (data->current_brightness && brightness == 0) in adp8870_bl_set()
390 else if (data->current_brightness == 0 && brightness) in adp8870_bl_set()
395 data->current_brightness = brightness; in adp8870_bl_set()
409 return data->current_brightness; in adp8870_bl_get_brightness()
420 struct i2c_client *client = data->client; in adp8870_bl_setup()
421 struct adp8870_backlight_platform_data *pdata = data->pdata; in adp8870_bl_setup()
424 ret = adp8870_write(client, ADP8870_BLSEL, ~pdata->bl_led_assign); in adp8870_bl_setup()
428 ret = adp8870_write(client, ADP8870_PWMLED, pdata->pwm_assign); in adp8870_bl_setup()
432 ret = adp8870_write(client, ADP8870_BLMX1, pdata->l1_daylight_max); in adp8870_bl_setup()
436 ret = adp8870_write(client, ADP8870_BLDM1, pdata->l1_daylight_dim); in adp8870_bl_setup()
440 if (pdata->en_ambl_sens) { in adp8870_bl_setup()
441 data->cached_daylight_max = pdata->l1_daylight_max; in adp8870_bl_setup()
443 pdata->l2_bright_max); in adp8870_bl_setup()
447 pdata->l2_bright_dim); in adp8870_bl_setup()
452 pdata->l3_office_max); in adp8870_bl_setup()
456 pdata->l3_office_dim); in adp8870_bl_setup()
461 pdata->l4_indoor_max); in adp8870_bl_setup()
466 pdata->l4_indor_dim); in adp8870_bl_setup()
471 pdata->l5_dark_max); in adp8870_bl_setup()
476 pdata->l5_dark_dim); in adp8870_bl_setup()
480 ret = adp8870_write(client, ADP8870_L2TRP, pdata->l2_trip); in adp8870_bl_setup()
484 ret = adp8870_write(client, ADP8870_L2HYS, pdata->l2_hyst); in adp8870_bl_setup()
488 ret = adp8870_write(client, ADP8870_L3TRP, pdata->l3_trip); in adp8870_bl_setup()
492 ret = adp8870_write(client, ADP8870_L3HYS, pdata->l3_hyst); in adp8870_bl_setup()
496 ret = adp8870_write(client, ADP8870_L4TRP, pdata->l4_trip); in adp8870_bl_setup()
500 ret = adp8870_write(client, ADP8870_L4HYS, pdata->l4_hyst); in adp8870_bl_setup()
504 ret = adp8870_write(client, ADP8870_L5TRP, pdata->l5_trip); in adp8870_bl_setup()
508 ret = adp8870_write(client, ADP8870_L5HYS, pdata->l5_hyst); in adp8870_bl_setup()
518 ALS_CMPR_CFG_VAL(pdata->abml_filt)); in adp8870_bl_setup()
524 BL_CFGR_VAL(pdata->bl_fade_law, 0)); in adp8870_bl_setup()
528 ret = adp8870_write(client, ADP8870_BLFR, FADE_VAL(pdata->bl_fade_in, in adp8870_bl_setup()
529 pdata->bl_fade_out)); in adp8870_bl_setup()
537 (data->revid == 0 ? GDWN_DIS : 0)); in adp8870_bl_setup()
548 mutex_lock(&data->lock); in adp8870_show()
549 error = adp8870_read(data->client, reg, ®_val); in adp8870_show()
550 mutex_unlock(&data->lock); in adp8870_show()
569 mutex_lock(&data->lock); in adp8870_store()
570 adp8870_write(data->client, reg, val); in adp8870_store()
571 mutex_unlock(&data->lock); in adp8870_store()
645 int ret = kstrtoul(buf, 10, &data->cached_daylight_max); in adp8870_bl_l1_daylight_max_store()
740 mutex_lock(&data->lock); in adp8870_bl_ambient_light_level_show()
741 error = adp8870_read(data->client, ADP8870_PH1LEVL, ®_val); in adp8870_bl_ambient_light_level_show()
743 mutex_unlock(&data->lock); in adp8870_bl_ambient_light_level_show()
747 error = adp8870_read(data->client, ADP8870_PH1LEVH, ®_val); in adp8870_bl_ambient_light_level_show()
748 mutex_unlock(&data->lock); in adp8870_bl_ambient_light_level_show()
753 /* Return 13-bit conversion value for the first light sensor */ in adp8870_bl_ambient_light_level_show()
768 mutex_lock(&data->lock); in adp8870_bl_ambient_light_zone_show()
769 error = adp8870_read(data->client, ADP8870_CFGR, ®_val); in adp8870_bl_ambient_light_zone_show()
770 mutex_unlock(&data->lock); in adp8870_bl_ambient_light_zone_show()
794 adp8870_set_bits(data->client, ADP8870_MDCR, CMP_AUTOEN); in adp8870_bl_ambient_light_zone_store()
797 adp8870_clr_bits(data->client, ADP8870_MDCR, CMP_AUTOEN); in adp8870_bl_ambient_light_zone_store()
800 mutex_lock(&data->lock); in adp8870_bl_ambient_light_zone_store()
801 ret = adp8870_read(data->client, ADP8870_CFGR, ®_val); in adp8870_bl_ambient_light_zone_store()
804 reg_val |= (val - 1) << CFGR_BLV_SHIFT; in adp8870_bl_ambient_light_zone_store()
805 adp8870_write(data->client, ADP8870_CFGR, reg_val); in adp8870_bl_ambient_light_zone_store()
807 mutex_unlock(&data->lock); in adp8870_bl_ambient_light_zone_store()
846 dev_get_platdata(&client->dev); in adp8870_probe()
850 if (!i2c_check_functionality(client->adapter, in adp8870_probe()
852 dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); in adp8870_probe()
853 return -EIO; in adp8870_probe()
857 dev_err(&client->dev, "no platform data?\n"); in adp8870_probe()
858 return -EINVAL; in adp8870_probe()
863 return -EIO; in adp8870_probe()
866 dev_err(&client->dev, "failed to probe\n"); in adp8870_probe()
867 return -ENODEV; in adp8870_probe()
870 data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); in adp8870_probe()
872 return -ENOMEM; in adp8870_probe()
874 data->revid = ADP8870_DEVID(reg_val); in adp8870_probe()
875 data->client = client; in adp8870_probe()
876 data->pdata = pdata; in adp8870_probe()
877 data->id = id->driver_data; in adp8870_probe()
878 data->current_brightness = 0; in adp8870_probe()
881 mutex_init(&data->lock); in adp8870_probe()
886 bl = devm_backlight_device_register(&client->dev, in adp8870_probe()
887 dev_driver_string(&client->dev), in adp8870_probe()
888 &client->dev, data, &adp8870_bl_ops, &props); in adp8870_probe()
890 dev_err(&client->dev, "failed to register backlight\n"); in adp8870_probe()
894 data->bl = bl; in adp8870_probe()
896 if (pdata->en_ambl_sens) { in adp8870_probe()
897 ret = sysfs_create_group(&bl->dev.kobj, in adp8870_probe()
900 dev_err(&client->dev, "failed to register sysfs\n"); in adp8870_probe()
907 ret = -EIO; in adp8870_probe()
913 dev_info(&client->dev, "Rev.%d Backlight\n", data->revid); in adp8870_probe()
915 if (pdata->num_leds) in adp8870_probe()
921 if (data->pdata->en_ambl_sens) in adp8870_probe()
922 sysfs_remove_group(&data->bl->dev.kobj, in adp8870_probe()
934 if (data->led) in adp8870_remove()
937 if (data->pdata->en_ambl_sens) in adp8870_remove()
938 sysfs_remove_group(&data->bl->dev.kobj, in adp8870_remove()
985 MODULE_DESCRIPTION("ADP8870 Backlight driver");