123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- /* Copyright (c) 2013, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/init.h>
- #include <linux/leds.h>
- #include <linux/platform_device.h>
- #include <linux/of_gpio.h>
- #include <linux/gpio.h>
- #include <linux/of.h>
- #include <linux/printk.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #define LED_GPIO_BACKLIGHT_DRIVER_NAME "sec,leds-gpio-bkl"
- #define LED_TRIGGER_DEFAULT "none"
- struct led_brt_value {
- int os_value; /* Platform setting values*/
- int ic_value; /* Chip Setting values*/
- };
- struct led_gpio_bkl_data {
- int led_ctrl;
- int brightness;
- int max_brt_value, min_brt_value, dimming_value, max_brt_in_blu;
- int brt_table_len;
- int easyscale_addr;
- const char* control_type;
- struct led_brt_value *brt_table;
- struct led_classdev cdev;
- #ifdef CONFIG_BACKLIGHT_KTD2801
- int express_wire;
- #endif
- };
- static struct of_device_id led_gpio_bkl_of_match[] = {
- {.compatible = LED_GPIO_BACKLIGHT_DRIVER_NAME,},
- {},
- };
- static DEFINE_SPINLOCK(bl_ctrl_lock);
- #if defined(CONFIG_GET_LCD_ATTACHED)
- extern int get_lcd_attached(void);
- #endif
- #ifdef CONFIG_BACKLIGHT_KTD2801
- #define MAX_BRIGHTNESS 255
- #define DEFAULT_BRIGHTNESS 122
- #define MAX_BRIGHTNESS_IN_BLU 32
- #define KTD2801_DATA_BITS 8
- #define KTD2801_T_OFF 5
- #define KTD2801_T_EW_DET 300
- #define KTD2801_T_EW_DELAY 200
- #define KTD2801_T_EW_WIN 1
- #define KTD2801_T_DS 5
- #define KTD2801_T_EOD_H 400
- #define KTD2801_T_EOD_L 30
- #define KTD2801_T_H_LB 30
- #define KTD2801_T_L_LB 70
- #define KTD2801_T_H_HB 70
- #define KTD2801_T_L_HB 30
- #define MAX_BRIGHTNESS_IN_BLU 32
- static int easy_scale_send_bit (unsigned gpio, bool bit)
- {
- if (!bit) { /* Send bit 0 */
- gpio_direction_output(gpio, 0);
- udelay(KTD2801_T_L_LB);
- gpio_direction_output(gpio, 1);
- udelay(KTD2801_T_H_LB);
- return 0;
- } else { /* Send bit 1 */
- gpio_direction_output(gpio, 0);
- udelay(KTD2801_T_L_HB);
- gpio_direction_output(gpio, 1);
- udelay(KTD2801_T_H_HB);
- return 0;
- }
- }
- static void easy_scale_type_set_brightness(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
- struct led_gpio_bkl_data *bkl_led =
- container_of(led_cdev, struct led_gpio_bkl_data, cdev);
- int brightness_idx = 0;
- if (value > 255 || value < 0 ) {
- pr_info("BL : Error level = %d\n", value);
- return; /* Add Exception over 255 */
- }
- if (value > 0) {
- for (brightness_idx = 0; brightness_idx < bkl_led->brt_table_len; brightness_idx++) {
- if (value <= bkl_led->brt_table[brightness_idx].os_value)
- break;
- }
- } else {
- gpio_direction_output(bkl_led->led_ctrl, 0);
- mdelay(KTD2801_T_OFF);
- bkl_led->express_wire = 0;
- pr_info("KTD2801 BL : level = %d, index = %d\n", value, brightness_idx);
- bkl_led->brightness = brightness_idx;
- return;
- }
- pr_info("KTD2801 BL : level = %d, index = %d\n", value, brightness_idx);
- if (bkl_led->brightness != brightness_idx) {
- int i = 0;
- if(!bkl_led->express_wire) /* express wire dimming */
- {
- gpio_direction_output(bkl_led->led_ctrl, 0);
- mdelay(KTD2801_T_OFF);
- gpio_direction_output(bkl_led->led_ctrl, 1);
- udelay(KTD2801_T_EW_DELAY);
- gpio_direction_output(bkl_led->led_ctrl, 0);
- udelay(KTD2801_T_EW_DET);
- gpio_direction_output(bkl_led->led_ctrl, 1);
- mdelay(KTD2801_T_EW_WIN);
- bkl_led->express_wire = 1;
- }
- gpio_direction_output(bkl_led->led_ctrl, 1); /* Data start */
- udelay(KTD2801_T_DS);
- for (i = 0; i < KTD2801_DATA_BITS ; i++) /* Send DATA */
- easy_scale_send_bit(bkl_led->led_ctrl, bkl_led->brt_table[brightness_idx].ic_value & (0x1 << (7-i)));
- gpio_direction_output(bkl_led->led_ctrl, 0); /* EOD */
- udelay(KTD2801_T_EOD_L);
- gpio_direction_output(bkl_led->led_ctrl, 1);
- udelay(KTD2801_T_EOD_H);
- }
- bkl_led->brightness = brightness_idx;
- return ;
- }
- #else
- #define MAX_BRIGHTNESS 255
- #define DEFAULT_BRIGHTNESS 122
- #define MAX_BRIGHTNESS_IN_BLU 32
- #define TPS61158_DATA_BITS 8
- #define TPS61158_ADDRESS_BITS 8
- #define TPS61158_TIME_T_EOS 300
- #define TPS61158_TIME_ES_DET_DELAY 150
- #define TPS61158_TIME_ES_DET_TIME 500
- #define TPS61158_TIME_T_START 10
- #define TPS61158_TIME_DATA_DELAY_SHORT 180
- #define TPS61158_TIME_DATA_DELAY_LONG 400
- #define MAX_BRIGHTNESS_IN_BLU 32
- static int easy_scale_send_bit (unsigned gpio, bool bit)
- {
- if (bit) { /* Send bit 1 */
- gpio_direction_output(gpio, 0);
- udelay(TPS61158_TIME_DATA_DELAY_SHORT);
- gpio_direction_output(gpio, 1);
- udelay(TPS61158_TIME_DATA_DELAY_LONG);
- return 0;
- } else { /* Send bit 0 */
- gpio_direction_output(gpio, 0);
- udelay(TPS61158_TIME_DATA_DELAY_LONG);
- gpio_direction_output(gpio, 1);
- udelay(TPS61158_TIME_DATA_DELAY_SHORT);
- return 0;
- }
- }
- static void easy_scale_type_set_brightness(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
- struct led_gpio_bkl_data *bkl_led =
- container_of(led_cdev, struct led_gpio_bkl_data, cdev);
- int brightness_idx = 0;
- if (value > 255 || value < 0 ) {
- pr_info("BL : Error level = %d\n", value);
- return; /* Add Exception over 255 */
- }
- if (value > 0) {
- for (brightness_idx = 0; brightness_idx < bkl_led->brt_table_len; brightness_idx++) {
- if (value <= bkl_led->brt_table[brightness_idx].os_value)
- break;
- }
- } else {
- gpio_direction_output(bkl_led->led_ctrl, 0);
- mdelay(3);
- pr_info("BL : level = %d, index = %d\n", value, brightness_idx);
- bkl_led->brightness = brightness_idx;
- return;
- }
- pr_info("BL : level = %d, index = %d\n", value, brightness_idx);
- if (bkl_led->brightness != brightness_idx) {
- int i = 0;
- gpio_direction_output(bkl_led->led_ctrl, 0);
- udelay(TPS61158_TIME_T_EOS);
- gpio_direction_output(bkl_led->led_ctrl, 1);
- udelay(TPS61158_TIME_ES_DET_DELAY);
- gpio_direction_output(bkl_led->led_ctrl, 0);
- udelay(TPS61158_TIME_ES_DET_TIME);
- gpio_direction_output(bkl_led->led_ctrl, 1);
- mdelay(3);
- udelay(500); /* ES window time */
- for (i = 0; i < TPS61158_DATA_BITS ; i++) /* Send DATA */
- easy_scale_send_bit(bkl_led->led_ctrl, bkl_led->easyscale_addr & (0x1 << i));
- gpio_direction_output(bkl_led->led_ctrl, 0); /* 2nd FLAG */
- udelay(TPS61158_TIME_T_EOS);
- gpio_direction_output(bkl_led->led_ctrl, 1);
- udelay(TPS61158_TIME_T_START);
- for (i = 0; i < TPS61158_DATA_BITS ; i++) /* Send DATA */
- easy_scale_send_bit(bkl_led->led_ctrl, bkl_led->brt_table[brightness_idx].ic_value & (0x1 << i));
- gpio_direction_output(bkl_led->led_ctrl, 0); /* 3rd FLAG */
- udelay(TPS61158_TIME_T_EOS);
- gpio_direction_output(bkl_led->led_ctrl, 1); /* BL brightness enable */
- }
- bkl_led->brightness = brightness_idx;
- return ;
- }
- #endif
- static void gpio_swing_type_set_brightness(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
- struct led_gpio_bkl_data *bkl_led =
- container_of(led_cdev, struct led_gpio_bkl_data, cdev);
- int brightness_idx = 0;
- #if defined(CONFIG_GET_LCD_ATTACHED)
- if(get_lcd_attached() == 0)
- {
- pr_info("%s: get_lcd_attached(0)! Backlight IC off\n",__func__);
- gpio_set_value(bkl_led->led_ctrl, 0);
- mdelay(50);
- return;
- }
- #endif
- if (value > 255 || value < 0 ) {
- pr_info("BL : Error level = %d\n", value);
- return; /* Add Exception over 255 */
- }
- if (value > 0) {
- if(value < bkl_led->min_brt_value) {
- brightness_idx = bkl_led->dimming_value;
- } else if(value >= bkl_led->max_brt_value) {
- brightness_idx = bkl_led->brt_table[bkl_led->brt_table_len-1].ic_value;
- } else {
- int i;
-
- for (i = 0; i < bkl_led->brt_table_len; i++) {
- if (value <= bkl_led->brt_table[i].os_value) {
- brightness_idx = bkl_led->brt_table[i].ic_value;
- break;
- }
- }
- }
- } else {
- gpio_set_value(bkl_led->led_ctrl, 0);
- mdelay(3);
- pr_info("BL : level = %d, index = %d\n", value, brightness_idx);
- bkl_led->brightness = brightness_idx;
- return;
- }
- pr_info("BL : level = %d, index = %d\n", value, brightness_idx);
- if(bkl_led->brightness != brightness_idx)
- {
- if (!brightness_idx) {
- gpio_set_value(bkl_led->led_ctrl, 0);
- mdelay(50);
- } else {
- int pulse;
- if (unlikely(bkl_led->brightness < 0)) {
- int val = gpio_get_value(bkl_led->led_ctrl);
- if (val) {
- bkl_led->brightness = 0;
- gpio_set_value(bkl_led->led_ctrl, 0);
- mdelay(50);
- pr_info("BL : LCD Baklight init in boot time on kernel\n");
- }
- }
- if (!bkl_led->brightness) {
- gpio_set_value(bkl_led->led_ctrl, 1);
- udelay(100);
- bkl_led->brightness = bkl_led->max_brt_in_blu;
- }
- pulse = (brightness_idx - bkl_led->brightness + bkl_led->max_brt_in_blu) % bkl_led->max_brt_in_blu;
- pr_debug("BL : ctrl_pls = %d, cur_pls = %d, bef_pls = %d\n", pulse, brightness_idx, bkl_led->brightness);
- for (; pulse > 0; pulse--) {
- gpio_set_value(bkl_led->led_ctrl, 0);
- udelay(2);
- gpio_set_value(bkl_led->led_ctrl, 1);
- udelay(2);
- }
- }
- bkl_led->brightness = brightness_idx;
- }
-
- mdelay(1);
- }
- static void led_gpio_brightness_set(struct led_classdev *led_cdev,
- enum led_brightness value)
- {
- struct led_gpio_bkl_data *bkl_led =
- container_of(led_cdev, struct led_gpio_bkl_data, cdev);
- spin_lock(&bl_ctrl_lock);
- if(!strcmp("easy_scale", bkl_led->control_type)) {
- easy_scale_type_set_brightness(led_cdev, value);
- } else if(!strcmp("gpio_swing", bkl_led->control_type)) {
- gpio_swing_type_set_brightness(led_cdev, value);
- } else {
- dev_err(bkl_led->cdev.dev, "%s:%d control type is not supported\n",
- __func__, __LINE__);
- }
- spin_unlock(&bl_ctrl_lock);
- }
- static enum led_brightness led_gpio_brightness_get(struct led_classdev
- *led_cdev)
- {
- struct led_gpio_bkl_data *bkl_led =
- container_of(led_cdev, struct led_gpio_bkl_data, cdev);
- return bkl_led->brightness;
- }
- int __devinit led_gpio_bkl_probe(struct platform_device *pdev)
- {
- int rc = 0, i;
- u32 tmp;
- const char *temp_str;
- struct led_gpio_bkl_data *bkl_led = NULL;
- struct device_node *node = pdev->dev.of_node;
- bkl_led = devm_kzalloc(&pdev->dev, sizeof(struct led_gpio_bkl_data),
- GFP_KERNEL);
- if (bkl_led == NULL) {
- dev_err(&pdev->dev, "%s:%d Unable to allocate memory\n",
- __func__, __LINE__);
- return -ENOMEM;
- }
- bkl_led->cdev.default_trigger = LED_TRIGGER_DEFAULT;
- rc = of_property_read_string(node, "linux,default-trigger", &temp_str);
- if (!rc)
- bkl_led->cdev.default_trigger = temp_str;
- bkl_led->led_ctrl = of_get_named_gpio(node, "sec,led-ctrl", 0);
- if (bkl_led->led_ctrl < 0) {
- dev_err(&pdev->dev,
- "Looking up %s property in node %s failed. rc = %d\n",
- "flash-en", node->full_name, bkl_led->led_ctrl);
- goto error;
- } else {
- rc = gpio_request(bkl_led->led_ctrl, "led_ctrl");
- if (rc) {
- dev_err(&pdev->dev,
- "%s: Failed to request gpio %d,rc = %d\n",
- __func__, bkl_led->led_ctrl, rc);
- goto error;
- }
- }
- bkl_led->control_type = of_get_property(node,
- "sec,control-type", NULL);
- rc = of_property_read_u32(node,
- "sec,brightness-table-len", &tmp);
- bkl_led->brt_table_len = (!rc ? tmp : false);
- bkl_led->brightness = -1;
- bkl_led->brt_table = (struct led_brt_value *)kzalloc(sizeof(struct led_brt_value) * bkl_led->brt_table_len, GFP_KERNEL);
- rc = of_property_read_u32_array(node, "sec,brightness-table", (u32 *)bkl_led->brt_table, bkl_led->brt_table_len*2);
- for (i = 0 ; i < bkl_led->brt_table_len; i++ ) {
- pr_debug("BL : [%d] %d %d\n",i, bkl_led->brt_table[i].os_value, bkl_led->brt_table[i].ic_value);
- }
- rc = of_property_read_u32(node,
- "sec,max-brightness-value", &tmp);
- bkl_led->max_brt_value = (!rc ? tmp : false);
- rc = of_property_read_u32(node,
- "sec,min-brightness-value", &tmp);
- bkl_led->min_brt_value = (!rc ? tmp : false);
- rc = of_property_read_u32(node,
- "sec,dimming-value", &tmp);
- bkl_led->dimming_value = (!rc ? tmp : false);
- rc = of_property_read_u32(node,
- "sec,max-brightness-in-blu-value", &tmp);
- bkl_led->max_brt_in_blu = (!rc ? tmp : false);
- rc = of_property_read_u32(node,
- "sec,easyscale-address", &tmp);
- bkl_led->easyscale_addr = (!rc ? tmp : false);
- gpio_tlmm_config(GPIO_CFG(bkl_led->led_ctrl, 0,
- GPIO_CFG_OUTPUT, GPIO_CFG_NO_PULL,
- GPIO_CFG_2MA), GPIO_CFG_ENABLE);
- platform_set_drvdata(pdev, bkl_led);
- bkl_led->cdev.max_brightness = LED_FULL;
- bkl_led->cdev.brightness_set = led_gpio_brightness_set;
- bkl_led->cdev.brightness_get = led_gpio_brightness_get;
- #ifdef CONFIG_BACKLIGHT_KTD2801
- bkl_led->express_wire = 0;
- #endif
- rc = led_classdev_register(&pdev->dev, &bkl_led->cdev);
- if (rc) {
- dev_err(&pdev->dev, "%s: Failed to register led dev. rc = %d\n",
- __func__, rc);
- goto error;
- }
- return 0;
- error:
- devm_kfree(&pdev->dev, bkl_led);
- return rc;
- }
- int __devexit led_gpio_bkl_remove(struct platform_device *pdev)
- {
- struct led_gpio_bkl_data *bkl_led =
- (struct led_gpio_bkl_data *)platform_get_drvdata(pdev);
- led_classdev_unregister(&bkl_led->cdev);
- devm_kfree(&pdev->dev, bkl_led);
- return 0;
- }
- static struct platform_driver led_gpio_bkl_driver = {
- .probe = led_gpio_bkl_probe,
- .remove = __devexit_p(led_gpio_bkl_remove),
- .driver = {
- .name = LED_GPIO_BACKLIGHT_DRIVER_NAME,
- .owner = THIS_MODULE,
- .of_match_table = led_gpio_bkl_of_match,
- }
- };
- static int __init led_gpio_bkl_init(void)
- {
- return platform_driver_register(&led_gpio_bkl_driver);
- }
- static void __exit led_gpio_bkl_exit(void)
- {
- return platform_driver_unregister(&led_gpio_bkl_driver);
- }
- late_initcall(led_gpio_bkl_init);
- module_exit(led_gpio_bkl_exit);
- MODULE_DESCRIPTION("QCOM GPIO LEDs driver");
- MODULE_LICENSE("GPL v2");
- MODULE_ALIAS("leds:leds-msm-gpio-flash");
|