summaryrefslogtreecommitdiffstats
path: root/drivers/video/backlight
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-10-06 03:09:16 +0900
committerLinus Torvalds <torvalds@linux-foundation.org>2012-10-06 03:09:16 +0900
commit11126c611e10abb18b6f1ed0300c0548c3906b54 (patch)
tree246227ad730c1e68f5a9c03db57cd4592abe7687 /drivers/video/backlight
parent67966e088b0c7dc926f4ce19565ebf208e18d058 (diff)
parent33e2a4227ddff7c18921ac175fae3ab0e3ff8a76 (diff)
downloadlinux-stable-11126c611e10abb18b6f1ed0300c0548c3906b54.tar.gz
linux-stable-11126c611e10abb18b6f1ed0300c0548c3906b54.tar.bz2
linux-stable-11126c611e10abb18b6f1ed0300c0548c3906b54.zip
Merge branch 'akpm' (Andrew's patch-bomb)
Merge misc patches from Andrew Morton: "The MM tree is rather stuck while I wait to find out what the heck is happening with sched/numa. Probably I'll need to route around all the code which was added to -next, sigh. So this is "everything else", or at least most of it - other small bits are still awaiting resolutions of various kinds." * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (180 commits) lib/decompress.c add __init to decompress_method and data kernel/resource.c: fix stack overflow in __reserve_region_with_split() omfs: convert to use beXX_add_cpu() taskstats: cgroupstats_user_cmd() may leak on error aoe: update aoe-internal version number to 50 aoe: update documentation to better reflect aoe-plus-udev usage aoe: remove unused code aoe: make dynamic block minor numbers the default aoe: update and specify AoE address guards and error messages aoe: retain static block device numbers for backwards compatibility aoe: support more AoE addresses with dynamic block device minor numbers aoe: update documentation with new URL and VM settings reference aoe: update copyright year in touched files aoe: update internal version number to 49 aoe: remove unused code and add cosmetic improvements aoe: increase net_device reference count while using it aoe: associate frames with the AoE storage target aoe: disallow unsupported AoE minor addresses aoe: do revalidation steps in order aoe: failover remote interface based on aoe_deadsecs parameter ...
Diffstat (limited to 'drivers/video/backlight')
-rw-r--r--drivers/video/backlight/Kconfig23
-rw-r--r--drivers/video/backlight/Makefile3
-rw-r--r--drivers/video/backlight/da9052_bl.c4
-rw-r--r--drivers/video/backlight/kb3886_bl.c4
-rw-r--r--drivers/video/backlight/lm3630_bl.c475
-rw-r--r--drivers/video/backlight/lm3639_bl.c437
-rw-r--r--drivers/video/backlight/ltv350qv.c6
-rw-r--r--drivers/video/backlight/platform_lcd.c10
-rw-r--r--drivers/video/backlight/progear_bl.c162
9 files changed, 946 insertions, 178 deletions
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 63cee2e9d622..c101697a4ba7 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -229,13 +229,6 @@ config BACKLIGHT_HP700
If you have an HP Jornada 700 series,
say Y to include backlight control driver.
-config BACKLIGHT_PROGEAR
- tristate "Frontpath ProGear Backlight Driver"
- depends on PCI && X86
- help
- If you have a Frontpath ProGear say Y to enable the
- backlight driver.
-
config BACKLIGHT_CARILLO_RANCH
tristate "Intel Carillo Ranch Backlight Driver"
depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578
@@ -352,6 +345,22 @@ config BACKLIGHT_AAT2870
If you have a AnalogicTech AAT2870 say Y to enable the
backlight driver.
+config BACKLIGHT_LM3630
+ tristate "Backlight Driver for LM3630"
+ depends on BACKLIGHT_CLASS_DEVICE && I2C
+ select REGMAP_I2C
+ help
+ This supports TI LM3630 Backlight Driver
+
+config BACKLIGHT_LM3639
+ tristate "Backlight Driver for LM3639"
+ depends on BACKLIGHT_CLASS_DEVICE && I2C
+ select REGMAP_I2C
+ select NEW_LEDS
+ select LEDS_CLASS
+ help
+ This supports TI LM3639 Backlight + 1.5A Flash LED Driver
+
config BACKLIGHT_LP855X
tristate "Backlight driver for TI LP855X"
depends on BACKLIGHT_CLASS_DEVICE && I2C
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 00223a62ec12..e7ce7291635d 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -23,10 +23,11 @@ obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o
obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o
obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o
+obj-$(CONFIG_BACKLIGHT_LM3630) += lm3630_bl.o
+obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o
obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o
obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o
obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o
-obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o
obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o
obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o
diff --git a/drivers/video/backlight/da9052_bl.c b/drivers/video/backlight/da9052_bl.c
index b628d68f5162..ac196181fe45 100644
--- a/drivers/video/backlight/da9052_bl.c
+++ b/drivers/video/backlight/da9052_bl.c
@@ -72,7 +72,7 @@ static int da9052_adjust_wled_brightness(struct da9052_bl *wleds)
if (ret < 0)
return ret;
- msleep(10);
+ usleep_range(10000, 11000);
if (wleds->brightness) {
ret = da9052_reg_write(wleds->da9052, wled_bank[wleds->led_reg],
@@ -129,7 +129,6 @@ static int da9052_backlight_probe(struct platform_device *pdev)
&da9052_backlight_ops, &props);
if (IS_ERR(bl)) {
dev_err(&pdev->dev, "Failed to register backlight\n");
- devm_kfree(&pdev->dev, wleds);
return PTR_ERR(bl);
}
@@ -149,7 +148,6 @@ static int da9052_backlight_remove(struct platform_device *pdev)
wleds->state = DA9052_WLEDS_OFF;
da9052_adjust_wled_brightness(wleds);
backlight_device_unregister(bl);
- devm_kfree(&pdev->dev, wleds);
return 0;
}
diff --git a/drivers/video/backlight/kb3886_bl.c b/drivers/video/backlight/kb3886_bl.c
index 72dd5556a35b..6c5ed6b242cc 100644
--- a/drivers/video/backlight/kb3886_bl.c
+++ b/drivers/video/backlight/kb3886_bl.c
@@ -34,9 +34,9 @@ static void kb3886_bl_set_intensity(int intensity)
mutex_lock(&bl_mutex);
intensity = intensity&0xff;
outb(KB3886_ADC_DAC_PWM, KB3886_PARENT);
- msleep(10);
+ usleep_range(10000, 11000);
outb(KB3886_PWM0_WRITE, KB3886_IO);
- msleep(10);
+ usleep_range(10000, 11000);
outb(intensity, KB3886_IO);
mutex_unlock(&bl_mutex);
}
diff --git a/drivers/video/backlight/lm3630_bl.c b/drivers/video/backlight/lm3630_bl.c
new file mode 100644
index 000000000000..dc191441796f
--- /dev/null
+++ b/drivers/video/backlight/lm3630_bl.c
@@ -0,0 +1,475 @@
+/*
+* Simple driver for Texas Instruments LM3630 Backlight driver chip
+* Copyright (C) 2012 Texas Instruments
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+*/
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/lm3630_bl.h>
+
+#define REG_CTRL 0x00
+#define REG_CONFIG 0x01
+#define REG_BRT_A 0x03
+#define REG_BRT_B 0x04
+#define REG_INT_STATUS 0x09
+#define REG_INT_EN 0x0A
+#define REG_FAULT 0x0B
+#define REG_PWM_OUTLOW 0x12
+#define REG_PWM_OUTHIGH 0x13
+#define REG_MAX 0x1F
+
+#define INT_DEBOUNCE_MSEC 10
+
+enum lm3630_leds {
+ BLED_ALL = 0,
+ BLED_1,
+ BLED_2
+};
+
+static const char *bled_name[] = {
+ [BLED_ALL] = "lm3630_bled", /*Bank1 controls all string */
+ [BLED_1] = "lm3630_bled1", /*Bank1 controls bled1 */
+ [BLED_2] = "lm3630_bled2", /*Bank1 or 2 controls bled2 */
+};
+
+struct lm3630_chip_data {
+ struct device *dev;
+ struct delayed_work work;
+ int irq;
+ struct workqueue_struct *irqthread;
+ struct lm3630_platform_data *pdata;
+ struct backlight_device *bled1;
+ struct backlight_device *bled2;
+ struct regmap *regmap;
+};
+
+/* initialize chip */
+static int __devinit lm3630_chip_init(struct lm3630_chip_data *pchip)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3630_platform_data *pdata = pchip->pdata;
+
+ /*pwm control */
+ reg_val = ((pdata->pwm_active & 0x01) << 2) | (pdata->pwm_ctrl & 0x03);
+ ret = regmap_update_bits(pchip->regmap, REG_CONFIG, 0x07, reg_val);
+ if (ret < 0)
+ goto out;
+
+ /* bank control */
+ reg_val = ((pdata->bank_b_ctrl & 0x01) << 1) |
+ (pdata->bank_a_ctrl & 0x07);
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x07, reg_val);
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
+ if (ret < 0)
+ goto out;
+
+ /* set initial brightness */
+ if (pdata->bank_a_ctrl != BANK_A_CTRL_DISABLE) {
+ ret = regmap_write(pchip->regmap,
+ REG_BRT_A, pdata->init_brt_led1);
+ if (ret < 0)
+ goto out;
+ }
+
+ if (pdata->bank_b_ctrl != BANK_B_CTRL_DISABLE) {
+ ret = regmap_write(pchip->regmap,
+ REG_BRT_B, pdata->init_brt_led2);
+ if (ret < 0)
+ goto out;
+ }
+ return ret;
+
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return ret;
+}
+
+/* interrupt handling */
+static void lm3630_delayed_func(struct work_struct *work)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3630_chip_data *pchip;
+
+ pchip = container_of(work, struct lm3630_chip_data, work.work);
+
+ ret = regmap_read(pchip->regmap, REG_INT_STATUS, &reg_val);
+ if (ret < 0) {
+ dev_err(pchip->dev,
+ "i2c failed to access REG_INT_STATUS Register\n");
+ return;
+ }
+
+ dev_info(pchip->dev, "REG_INT_STATUS Register is 0x%x\n", reg_val);
+}
+
+static irqreturn_t lm3630_isr_func(int irq, void *chip)
+{
+ int ret;
+ struct lm3630_chip_data *pchip = chip;
+ unsigned long delay = msecs_to_jiffies(INT_DEBOUNCE_MSEC);
+
+ queue_delayed_work(pchip->irqthread, &pchip->work, delay);
+
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
+ if (ret < 0)
+ goto out;
+
+ return IRQ_HANDLED;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return IRQ_HANDLED;
+}
+
+static int lm3630_intr_config(struct lm3630_chip_data *pchip)
+{
+ INIT_DELAYED_WORK(&pchip->work, lm3630_delayed_func);
+ pchip->irqthread = create_singlethread_workqueue("lm3630-irqthd");
+ if (!pchip->irqthread) {
+ dev_err(pchip->dev, "create irq thread fail...\n");
+ return -1;
+ }
+ if (request_threaded_irq
+ (pchip->irq, NULL, lm3630_isr_func,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "lm3630_irq", pchip)) {
+ dev_err(pchip->dev, "request threaded irq fail..\n");
+ return -1;
+ }
+ return 0;
+}
+
+static bool
+set_intensity(struct backlight_device *bl, struct lm3630_chip_data *pchip)
+{
+ if (!pchip->pdata->pwm_set_intensity)
+ return false;
+ pchip->pdata->pwm_set_intensity(bl->props.brightness - 1,
+ pchip->pdata->pwm_period);
+ return true;
+}
+
+/* update and get brightness */
+static int lm3630_bank_a_update_status(struct backlight_device *bl)
+{
+ int ret;
+ struct lm3630_chip_data *pchip = bl_get_data(bl);
+ enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
+
+ /* brightness 0 means disable */
+ if (!bl->props.brightness) {
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x04, 0x00);
+ if (ret < 0)
+ goto out;
+ return bl->props.brightness;
+ }
+
+ /* pwm control */
+ if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) {
+ if (!set_intensity(bl, pchip))
+ dev_err(pchip->dev, "No pwm control func. in plat-data\n");
+ } else {
+
+ /* i2c control */
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
+ if (ret < 0)
+ goto out;
+ mdelay(1);
+ ret = regmap_write(pchip->regmap,
+ REG_BRT_A, bl->props.brightness - 1);
+ if (ret < 0)
+ goto out;
+ }
+ return bl->props.brightness;
+out:
+ dev_err(pchip->dev, "i2c failed to access REG_CTRL\n");
+ return bl->props.brightness;
+}
+
+static int lm3630_bank_a_get_brightness(struct backlight_device *bl)
+{
+ unsigned int reg_val;
+ int brightness, ret;
+ struct lm3630_chip_data *pchip = bl_get_data(bl);
+ enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
+
+ if (pwm_ctrl == PWM_CTRL_BANK_A || pwm_ctrl == PWM_CTRL_BANK_ALL) {
+ ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, &reg_val);
+ if (ret < 0)
+ goto out;
+ brightness = reg_val & 0x01;
+ ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, &reg_val);
+ if (ret < 0)
+ goto out;
+ brightness = ((brightness << 8) | reg_val) + 1;
+ } else {
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
+ if (ret < 0)
+ goto out;
+ mdelay(1);
+ ret = regmap_read(pchip->regmap, REG_BRT_A, &reg_val);
+ if (ret < 0)
+ goto out;
+ brightness = reg_val + 1;
+ }
+ bl->props.brightness = brightness;
+ return bl->props.brightness;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return 0;
+}
+
+static const struct backlight_ops lm3630_bank_a_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = lm3630_bank_a_update_status,
+ .get_brightness = lm3630_bank_a_get_brightness,
+};
+
+static int lm3630_bank_b_update_status(struct backlight_device *bl)
+{
+ int ret;
+ struct lm3630_chip_data *pchip = bl_get_data(bl);
+ enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
+
+ if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) {
+ if (!set_intensity(bl, pchip))
+ dev_err(pchip->dev,
+ "no pwm control func. in plat-data\n");
+ } else {
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
+ if (ret < 0)
+ goto out;
+ mdelay(1);
+ ret = regmap_write(pchip->regmap,
+ REG_BRT_B, bl->props.brightness - 1);
+ }
+ return bl->props.brightness;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return bl->props.brightness;
+}
+
+static int lm3630_bank_b_get_brightness(struct backlight_device *bl)
+{
+ unsigned int reg_val;
+ int brightness, ret;
+ struct lm3630_chip_data *pchip = bl_get_data(bl);
+ enum lm3630_pwm_ctrl pwm_ctrl = pchip->pdata->pwm_ctrl;
+
+ if (pwm_ctrl == PWM_CTRL_BANK_B || pwm_ctrl == PWM_CTRL_BANK_ALL) {
+ ret = regmap_read(pchip->regmap, REG_PWM_OUTHIGH, &reg_val);
+ if (ret < 0)
+ goto out;
+ brightness = reg_val & 0x01;
+ ret = regmap_read(pchip->regmap, REG_PWM_OUTLOW, &reg_val);
+ if (ret < 0)
+ goto out;
+ brightness = ((brightness << 8) | reg_val) + 1;
+ } else {
+ ret = regmap_update_bits(pchip->regmap, REG_CTRL, 0x80, 0x00);
+ if (ret < 0)
+ goto out;
+ mdelay(1);
+ ret = regmap_read(pchip->regmap, REG_BRT_B, &reg_val);
+ if (ret < 0)
+ goto out;
+ brightness = reg_val + 1;
+ }
+ bl->props.brightness = brightness;
+
+ return bl->props.brightness;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return bl->props.brightness;
+}
+
+static const struct backlight_ops lm3630_bank_b_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = lm3630_bank_b_update_status,
+ .get_brightness = lm3630_bank_b_get_brightness,
+};
+
+static int lm3630_backlight_register(struct lm3630_chip_data *pchip,
+ enum lm3630_leds ledno)
+{
+ const char *name = bled_name[ledno];
+ struct backlight_properties props;
+ struct lm3630_platform_data *pdata = pchip->pdata;
+
+ props.type = BACKLIGHT_RAW;
+ switch (ledno) {
+ case BLED_1:
+ case BLED_ALL:
+ props.brightness = pdata->init_brt_led1;
+ props.max_brightness = pdata->max_brt_led1;
+ pchip->bled1 =
+ backlight_device_register(name, pchip->dev, pchip,
+ &lm3630_bank_a_ops, &props);
+ if (IS_ERR(pchip->bled1))
+ return -EIO;
+ break;
+ case BLED_2:
+ props.brightness = pdata->init_brt_led2;
+ props.max_brightness = pdata->max_brt_led2;
+ pchip->bled2 =
+ backlight_device_register(name, pchip->dev, pchip,
+ &lm3630_bank_b_ops, &props);
+ if (IS_ERR(pchip->bled2))
+ return -EIO;
+ break;
+ }
+ return 0;
+}
+
+static void lm3630_backlight_unregister(struct lm3630_chip_data *pchip)
+{
+ if (pchip->bled1)
+ backlight_device_unregister(pchip->bled1);
+ if (pchip->bled2)
+ backlight_device_unregister(pchip->bled2);
+}
+
+static const struct regmap_config lm3630_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+static int __devinit lm3630_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct lm3630_platform_data *pdata = client->dev.platform_data;
+ struct lm3630_chip_data *pchip;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "fail : i2c functionality check...\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "fail : no platform data.\n");
+ return -ENODATA;
+ }
+
+ pchip = devm_kzalloc(&client->dev, sizeof(struct lm3630_chip_data),
+ GFP_KERNEL);
+ if (!pchip)
+ return -ENOMEM;
+ pchip->pdata = pdata;
+ pchip->dev = &client->dev;
+
+ pchip->regmap = devm_regmap_init_i2c(client, &lm3630_regmap);
+ if (IS_ERR(pchip->regmap)) {
+ ret = PTR_ERR(pchip->regmap);
+ dev_err(&client->dev, "fail : allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, pchip);
+
+ /* chip initialize */
+ ret = lm3630_chip_init(pchip);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail : init chip\n");
+ goto err_chip_init;
+ }
+
+ switch (pdata->bank_a_ctrl) {
+ case BANK_A_CTRL_ALL:
+ ret = lm3630_backlight_register(pchip, BLED_ALL);
+ pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE;
+ break;
+ case BANK_A_CTRL_LED1:
+ ret = lm3630_backlight_register(pchip, BLED_1);
+ break;
+ case BANK_A_CTRL_LED2:
+ ret = lm3630_backlight_register(pchip, BLED_2);
+ pdata->bank_b_ctrl = BANK_B_CTRL_DISABLE;
+ break;
+ default:
+ break;
+ }
+
+ if (ret < 0)
+ goto err_bl_reg;
+
+ if (pdata->bank_b_ctrl && pchip->bled2 == NULL) {
+ ret = lm3630_backlight_register(pchip, BLED_2);
+ if (ret < 0)
+ goto err_bl_reg;
+ }
+
+ /* interrupt enable : irq 0 is not allowed for lm3630 */
+ pchip->irq = client->irq;
+ if (pchip->irq)
+ lm3630_intr_config(pchip);
+
+ dev_info(&client->dev, "LM3630 backlight register OK.\n");
+ return 0;
+
+err_bl_reg:
+ dev_err(&client->dev, "fail : backlight register.\n");
+ lm3630_backlight_unregister(pchip);
+err_chip_init:
+ return ret;
+}
+
+static int __devexit lm3630_remove(struct i2c_client *client)
+{
+ int ret;
+ struct lm3630_chip_data *pchip = i2c_get_clientdata(client);
+
+ ret = regmap_write(pchip->regmap, REG_BRT_A, 0);
+ if (ret < 0)
+ dev_err(pchip->dev, "i2c failed to access register\n");
+
+ ret = regmap_write(pchip->regmap, REG_BRT_B, 0);
+ if (ret < 0)
+ dev_err(pchip->dev, "i2c failed to access register\n");
+
+ lm3630_backlight_unregister(pchip);
+ if (pchip->irq) {
+ free_irq(pchip->irq, pchip);
+ flush_workqueue(pchip->irqthread);
+ destroy_workqueue(pchip->irqthread);
+ }
+ return 0;
+}
+
+static const struct i2c_device_id lm3630_id[] = {
+ {LM3630_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3630_id);
+
+static struct i2c_driver lm3630_i2c_driver = {
+ .driver = {
+ .name = LM3630_NAME,
+ },
+ .probe = lm3630_probe,
+ .remove = __devexit_p(lm3630_remove),
+ .id_table = lm3630_id,
+};
+
+module_i2c_driver(lm3630_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Backlight driver for LM3630");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/lm3639_bl.c b/drivers/video/backlight/lm3639_bl.c
new file mode 100644
index 000000000000..c6915c6c3cd1
--- /dev/null
+++ b/drivers/video/backlight/lm3639_bl.c
@@ -0,0 +1,437 @@
+/*
+* Simple driver for Texas Instruments LM3639 Backlight + Flash LED driver chip
+* Copyright (C) 2012 Texas Instruments
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+*/
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/leds.h>
+#include <linux/backlight.h>
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/regmap.h>
+#include <linux/platform_data/lm3639_bl.h>
+
+#define REG_DEV_ID 0x00
+#define REG_CHECKSUM 0x01
+#define REG_BL_CONF_1 0x02
+#define REG_BL_CONF_2 0x03
+#define REG_BL_CONF_3 0x04
+#define REG_BL_CONF_4 0x05
+#define REG_FL_CONF_1 0x06
+#define REG_FL_CONF_2 0x07
+#define REG_FL_CONF_3 0x08
+#define REG_IO_CTRL 0x09
+#define REG_ENABLE 0x0A
+#define REG_FLAG 0x0B
+#define REG_MAX REG_FLAG
+
+struct lm3639_chip_data {
+ struct device *dev;
+ struct lm3639_platform_data *pdata;
+
+ struct backlight_device *bled;
+ struct led_classdev cdev_flash;
+ struct led_classdev cdev_torch;
+ struct regmap *regmap;
+
+ unsigned int bled_mode;
+ unsigned int bled_map;
+ unsigned int last_flag;
+};
+
+/* initialize chip */
+static int __devinit lm3639_chip_init(struct lm3639_chip_data *pchip)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3639_platform_data *pdata = pchip->pdata;
+
+ /* input pins config. */
+ ret =
+ regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x08,
+ pdata->pin_pwm);
+ if (ret < 0)
+ goto out;
+
+ reg_val = (pdata->pin_pwm & 0x40) | pdata->pin_strobe | pdata->pin_tx;
+ ret = regmap_update_bits(pchip->regmap, REG_IO_CTRL, 0x7C, reg_val);
+ if (ret < 0)
+ goto out;
+
+ /* init brightness */
+ ret = regmap_write(pchip->regmap, REG_BL_CONF_4, pdata->init_brt_led);
+ if (ret < 0)
+ goto out;
+
+ ret = regmap_write(pchip->regmap, REG_BL_CONF_3, pdata->init_brt_led);
+ if (ret < 0)
+ goto out;
+
+ /* output pins config. */
+ if (!pdata->init_brt_led)
+ reg_val = pdata->fled_pins | pdata->bled_pins;
+ else
+ reg_val = pdata->fled_pins | pdata->bled_pins | 0x01;
+
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x79, reg_val);
+ if (ret < 0)
+ goto out;
+
+ return ret;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return ret;
+}
+
+/* update and get brightness */
+static int lm3639_bled_update_status(struct backlight_device *bl)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3639_chip_data *pchip = bl_get_data(bl);
+ struct lm3639_platform_data *pdata = pchip->pdata;
+
+ ret = regmap_read(pchip->regmap, REG_FLAG, &reg_val);
+ if (ret < 0)
+ goto out;
+
+ if (reg_val != 0)
+ dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
+
+ /* pwm control */
+ if (pdata->pin_pwm) {
+ if (pdata->pwm_set_intensity)
+ pdata->pwm_set_intensity(bl->props.brightness,
+ pdata->max_brt_led);
+ else
+ dev_err(pchip->dev,
+ "No pwm control func. in plat-data\n");
+ return bl->props.brightness;
+ }
+
+ /* i2c control and set brigtness */
+ ret = regmap_write(pchip->regmap, REG_BL_CONF_4, bl->props.brightness);
+ if (ret < 0)
+ goto out;
+ ret = regmap_write(pchip->regmap, REG_BL_CONF_3, bl->props.brightness);
+ if (ret < 0)
+ goto out;
+
+ if (!bl->props.brightness)
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x00);
+ else
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x01, 0x01);
+ if (ret < 0)
+ goto out;
+
+ return bl->props.brightness;
+out:
+ dev_err(pchip->dev, "i2c failed to access registers\n");
+ return bl->props.brightness;
+}
+
+static int lm3639_bled_get_brightness(struct backlight_device *bl)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3639_chip_data *pchip = bl_get_data(bl);
+ struct lm3639_platform_data *pdata = pchip->pdata;
+
+ if (pdata->pin_pwm) {
+ if (pdata->pwm_get_intensity)
+ bl->props.brightness = pdata->pwm_get_intensity();
+ else
+ dev_err(pchip->dev,
+ "No pwm control func. in plat-data\n");
+ return bl->props.brightness;
+ }
+
+ ret = regmap_read(pchip->regmap, REG_BL_CONF_1, &reg_val);
+ if (ret < 0)
+ goto out;
+ if (reg_val & 0x10)
+ ret = regmap_read(pchip->regmap, REG_BL_CONF_4, &reg_val);
+ else
+ ret = regmap_read(pchip->regmap, REG_BL_CONF_3, &reg_val);
+ if (ret < 0)
+ goto out;
+ bl->props.brightness = reg_val;
+
+ return bl->props.brightness;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return bl->props.brightness;
+}
+
+static const struct backlight_ops lm3639_bled_ops = {
+ .options = BL_CORE_SUSPENDRESUME,
+ .update_status = lm3639_bled_update_status,
+ .get_brightness = lm3639_bled_get_brightness,
+};
+
+/* backlight mapping mode */
+static ssize_t lm3639_bled_mode_store(struct device *dev,
+ struct device_attribute *devAttr,
+ const char *buf, size_t size)
+{
+ ssize_t ret;
+ struct lm3639_chip_data *pchip = dev_get_drvdata(dev);
+ unsigned int state;
+
+ ret = kstrtouint(buf, 10, &state);
+ if (ret)
+ goto out_input;
+
+ if (!state)
+ ret =
+ regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10,
+ 0x00);
+ else
+ ret =
+ regmap_update_bits(pchip->regmap, REG_BL_CONF_1, 0x10,
+ 0x10);
+
+ if (ret < 0)
+ goto out;
+
+ return size;
+
+out:
+ dev_err(pchip->dev, "%s:i2c access fail to register\n", __func__);
+ return size;
+
+out_input:
+ dev_err(pchip->dev, "%s:input conversion fail\n", __func__);
+ return size;
+
+}
+
+static DEVICE_ATTR(bled_mode, 0666, NULL, lm3639_bled_mode_store);
+
+/* torch */
+static void lm3639_torch_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3639_chip_data *pchip;
+
+ pchip = container_of(cdev, struct lm3639_chip_data, cdev_torch);
+
+ ret = regmap_read(pchip->regmap, REG_FLAG, &reg_val);
+ if (ret < 0)
+ goto out;
+ if (reg_val != 0)
+ dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
+
+ /* brightness 0 means off state */
+ if (!brightness) {
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00);
+ if (ret < 0)
+ goto out;
+ return;
+ }
+
+ ret = regmap_update_bits(pchip->regmap,
+ REG_FL_CONF_1, 0x70, (brightness - 1) << 4);
+ if (ret < 0)
+ goto out;
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x02);
+ if (ret < 0)
+ goto out;
+
+ return;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return;
+}
+
+/* flash */
+static void lm3639_flash_brightness_set(struct led_classdev *cdev,
+ enum led_brightness brightness)
+{
+ int ret;
+ unsigned int reg_val;
+ struct lm3639_chip_data *pchip;
+
+ pchip = container_of(cdev, struct lm3639_chip_data, cdev_flash);
+
+ ret = regmap_read(pchip->regmap, REG_FLAG, &reg_val);
+ if (ret < 0)
+ goto out;
+ if (reg_val != 0)
+ dev_info(pchip->dev, "last flag is 0x%x\n", reg_val);
+
+ /* torch off before flash control */
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x00);
+ if (ret < 0)
+ goto out;
+
+ /* brightness 0 means off state */
+ if (!brightness)
+ return;
+
+ ret = regmap_update_bits(pchip->regmap,
+ REG_FL_CONF_1, 0x0F, brightness - 1);
+ if (ret < 0)
+ goto out;
+ ret = regmap_update_bits(pchip->regmap, REG_ENABLE, 0x06, 0x06);
+ if (ret < 0)
+ goto out;
+
+ return;
+out:
+ dev_err(pchip->dev, "i2c failed to access register\n");
+ return;
+}
+
+static const struct regmap_config lm3639_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = REG_MAX,
+};
+
+static int __devinit lm3639_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct lm3639_chip_data *pchip;
+ struct lm3639_platform_data *pdata = client->dev.platform_data;
+ struct backlight_properties props;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+ dev_err(&client->dev, "i2c functionality check fail.\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pdata == NULL) {
+ dev_err(&client->dev, "Needs Platform Data.\n");
+ return -ENODATA;
+ }
+
+ pchip = devm_kzalloc(&client->dev,
+ sizeof(struct lm3639_chip_data), GFP_KERNEL);
+ if (!pchip)
+ return -ENOMEM;
+
+ pchip->pdata = pdata;
+ pchip->dev = &client->dev;
+
+ pchip->regmap = devm_regmap_init_i2c(client, &lm3639_regmap);
+ if (IS_ERR(pchip->regmap)) {
+ ret = PTR_ERR(pchip->regmap);
+ dev_err(&client->dev, "fail : allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+ i2c_set_clientdata(client, pchip);
+
+ /* chip initialize */
+ ret = lm3639_chip_init(pchip);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail : chip init\n");
+ goto err_out;
+ }
+
+ /* backlight */
+ props.type = BACKLIGHT_RAW;
+ props.brightness = pdata->init_brt_led;
+ props.max_brightness = pdata->max_brt_led;
+ pchip->bled =
+ backlight_device_register("lm3639_bled", pchip->dev, pchip,
+ &lm3639_bled_ops, &props);
+ if (IS_ERR(pchip->bled)) {
+ dev_err(&client->dev, "fail : backlight register\n");
+ ret = -EIO;
+ goto err_out;
+ }
+
+ ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
+ if (ret < 0) {
+ dev_err(&client->dev, "failed : add sysfs entries\n");
+ ret = -EIO;
+ goto err_bled_mode;
+ }
+
+ /* flash */
+ pchip->cdev_flash.name = "lm3639_flash";
+ pchip->cdev_flash.max_brightness = 16;
+ pchip->cdev_flash.brightness_set = lm3639_flash_brightness_set;
+ ret = led_classdev_register((struct device *)
+ &client->dev, &pchip->cdev_flash);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail : flash register\n");
+ ret = -EIO;
+ goto err_flash;
+ }
+
+ /* torch */
+ pchip->cdev_torch.name = "lm3639_torch";
+ pchip->cdev_torch.max_brightness = 8;
+ pchip->cdev_torch.brightness_set = lm3639_torch_brightness_set;
+ ret = led_classdev_register((struct device *)
+ &client->dev, &pchip->cdev_torch);
+ if (ret < 0) {
+ dev_err(&client->dev, "fail : torch register\n");
+ ret = -EIO;
+ goto err_torch;
+ }
+
+ return 0;
+
+err_torch:
+ led_classdev_unregister(&pchip->cdev_flash);
+err_flash:
+ device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
+err_bled_mode:
+ backlight_device_unregister(pchip->bled);
+err_out:
+ return ret;
+}
+
+static int __devexit lm3639_remove(struct i2c_client *client)
+{
+ struct lm3639_chip_data *pchip = i2c_get_clientdata(client);
+
+ regmap_write(pchip->regmap, REG_ENABLE, 0x00);
+
+ if (&pchip->cdev_torch)
+ led_classdev_unregister(&pchip->cdev_torch);
+ if (&pchip->cdev_flash)
+ led_classdev_unregister(&pchip->cdev_flash);
+ if (pchip->bled) {
+ device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
+ backlight_device_unregister(pchip->bled);
+ }
+ return 0;
+}
+
+static const struct i2c_device_id lm3639_id[] = {
+ {LM3639_NAME, 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, lm3639_id);
+static struct i2c_driver lm3639_i2c_driver = {
+ .driver = {
+ .name = LM3639_NAME,
+ },
+ .probe = lm3639_probe,
+ .remove = __devexit_p(lm3639_remove),
+ .id_table = lm3639_id,
+};
+
+module_i2c_driver(lm3639_i2c_driver);
+
+MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
+MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
+MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/backlight/ltv350qv.c b/drivers/video/backlight/ltv350qv.c
index 6c0f1ac0d32a..4066a5bbd826 100644
--- a/drivers/video/backlight/ltv350qv.c
+++ b/drivers/video/backlight/ltv350qv.c
@@ -75,7 +75,7 @@ static int ltv350qv_power_on(struct ltv350qv *lcd)
/* Power On Reset Display off State */
if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, 0x0000))
goto err;
- msleep(15);
+ usleep_range(15000, 16000);
/* Power Setting Function 1 */
if (ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE))
@@ -153,7 +153,7 @@ err_settings:
err_power2:
err_power1:
ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
- msleep(1);
+ usleep_range(1000, 1100);
err:
ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
return -EIO;
@@ -175,7 +175,7 @@ static int ltv350qv_power_off(struct ltv350qv *lcd)
ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL2, 0x0000);
/* Wait at least 1 ms */
- msleep(1);
+ usleep_range(1000, 1100);
/* Power down setting 2 */
ret |= ltv350qv_write_reg(lcd, LTV_PWRCTL1, LTV_VCOM_DISABLE);
diff --git a/drivers/video/backlight/platform_lcd.c b/drivers/video/backlight/platform_lcd.c
index b6672340d6c7..ca4f5d70fe10 100644
--- a/drivers/video/backlight/platform_lcd.c
+++ b/drivers/video/backlight/platform_lcd.c
@@ -16,6 +16,7 @@
#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/lcd.h>
+#include <linux/of.h>
#include <linux/slab.h>
#include <video/platform_lcd.h>
@@ -145,6 +146,14 @@ static SIMPLE_DEV_PM_OPS(platform_lcd_pm_ops, platform_lcd_suspend,
platform_lcd_resume);
#endif
+#ifdef CONFIG_OF
+static const struct of_device_id platform_lcd_of_match[] = {
+ { .compatible = "platform-lcd" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, platform_lcd_of_match);
+#endif
+
static struct platform_driver platform_lcd_driver = {
.driver = {
.name = "platform-lcd",
@@ -152,6 +161,7 @@ static struct platform_driver platform_lcd_driver = {
#ifdef CONFIG_PM
.pm = &platform_lcd_pm_ops,
#endif
+ .of_match_table = of_match_ptr(platform_lcd_of_match),
},
.probe = platform_lcd_probe,
.remove = __devexit_p(platform_lcd_remove),
diff --git a/drivers/video/backlight/progear_bl.c b/drivers/video/backlight/progear_bl.c
deleted file mode 100644
index 69b35f02929e..000000000000
--- a/drivers/video/backlight/progear_bl.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Backlight Driver for Frontpath ProGear HX1050+
- *
- * Copyright (c) 2006 Marcin Juszkiewicz
- *
- * Based on Progear LCD driver by M Schacht
- * <mschacht at alumni dot washington dot edu>
- *
- * Based on Sharp's Corgi Backlight Driver
- * Based on Backlight Driver for HP Jornada 680
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mutex.h>
-#include <linux/fb.h>
-#include <linux/backlight.h>
-#include <linux/pci.h>
-
-#define PMU_LPCR 0xB0
-#define SB_MPS1 0x61
-#define HW_LEVEL_MAX 0x77
-#define HW_LEVEL_MIN 0x4f
-
-static struct pci_dev *pmu_dev = NULL;
-static struct pci_dev *sb_dev = NULL;
-
-static int progearbl_set_intensity(struct backlight_device *bd)
-{
- int intensity = bd->props.brightness;
-
- if (bd->props.power != FB_BLANK_UNBLANK)
- intensity = 0;
- if (bd->props.fb_blank != FB_BLANK_UNBLANK)
- intensity = 0;
-
- pci_write_config_byte(pmu_dev, PMU_LPCR, intensity + HW_LEVEL_MIN);
-
- return 0;
-}
-
-static int progearbl_get_intensity(struct backlight_device *bd)
-{
- u8 intensity;
- pci_read_config_byte(pmu_dev, PMU_LPCR, &intensity);
-
- return intensity - HW_LEVEL_MIN;
-}
-
-static const struct backlight_ops progearbl_ops = {
- .get_brightness = progearbl_get_intensity,
- .update_status = progearbl_set_intensity,
-};
-
-static int progearbl_probe(struct platform_device *pdev)
-{
- struct backlight_properties props;
- u8 temp;
- struct backlight_device *progear_backlight_device;
- int ret;
-
- pmu_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, NULL);
- if (!pmu_dev) {
- pr_err("ALI M7101 PMU not found.\n");
- return -ENODEV;
- }
-
- sb_dev = pci_get_device(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533, NULL);
- if (!sb_dev) {
- pr_err("ALI 1533 SB not found.\n");
- ret = -ENODEV;
- goto put_pmu;
- }
-
- /* Set SB_MPS1 to enable brightness control. */
- pci_read_config_byte(sb_dev, SB_MPS1, &temp);
- pci_write_config_byte(sb_dev, SB_MPS1, temp | 0x20);
-
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_RAW;
- props.max_brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
- progear_backlight_device = backlight_device_register("progear-bl",
- &pdev->dev, NULL,
- &progearbl_ops,
- &props);
- if (IS_ERR(progear_backlight_device)) {
- ret = PTR_ERR(progear_backlight_device);
- goto put_sb;
- }
-
- platform_set_drvdata(pdev, progear_backlight_device);
-
- progear_backlight_device->props.power = FB_BLANK_UNBLANK;
- progear_backlight_device->props.brightness = HW_LEVEL_MAX - HW_LEVEL_MIN;
- progearbl_set_intensity(progear_backlight_device);
-
- return 0;
-put_sb:
- pci_dev_put(sb_dev);
-put_pmu:
- pci_dev_put(pmu_dev);
- return ret;
-}
-
-static int progearbl_remove(struct platform_device *pdev)
-{
- struct backlight_device *bd = platform_get_drvdata(pdev);
- backlight_device_unregister(bd);
-
- return 0;
-}
-
-static struct platform_driver progearbl_driver = {
- .probe = progearbl_probe,
- .remove = progearbl_remove,
- .driver = {
- .name = "progear-bl",
- },
-};
-
-static struct platform_device *progearbl_device;
-
-static int __init progearbl_init(void)
-{
- int ret = platform_driver_register(&progearbl_driver);
-
- if (ret)
- return ret;
- progearbl_device = platform_device_register_simple("progear-bl", -1,
- NULL, 0);
- if (IS_ERR(progearbl_device)) {
- platform_driver_unregister(&progearbl_driver);
- return PTR_ERR(progearbl_device);
- }
-
- return 0;
-}
-
-static void __exit progearbl_exit(void)
-{
- pci_dev_put(pmu_dev);
- pci_dev_put(sb_dev);
-
- platform_device_unregister(progearbl_device);
- platform_driver_unregister(&progearbl_driver);
-}
-
-module_init(progearbl_init);
-module_exit(progearbl_exit);
-
-MODULE_AUTHOR("Marcin Juszkiewicz <linux@hrw.one.pl>");
-MODULE_DESCRIPTION("ProGear Backlight Driver");
-MODULE_LICENSE("GPL");