Merge "msm_fb: Add backlight support using both GPIO 96 and PWM" into msm-3.4
diff --git a/arch/arm/mach-msm/board-msm7627a-display.c b/arch/arm/mach-msm/board-msm7627a-display.c
index 8740186..3da68ad 100644
--- a/arch/arm/mach-msm/board-msm7627a-display.c
+++ b/arch/arm/mach-msm/board-msm7627a-display.c
@@ -577,90 +577,98 @@
 };
 #endif
 
-static int evb_backlight_control(int level)
+static int evb_backlight_control(int level, int mode)
 {
 
 	int i = 0;
-	int remainder;
+	int remainder, ret = 0;
+
 	/* device address byte = 0x72 */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(33);
-	gpio_set_value(96, 1);
-	udelay(67);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+	if (!mode) {
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(33);
+		gpio_set_value(96, 1);
+		udelay(67);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* t-EOS and t-start */
-	gpio_set_value(96, 0);
-	ndelay(4200);
-	gpio_set_value(96, 1);
-	ndelay(9000);
+		/* t-EOS and t-start */
+		gpio_set_value(96, 0);
+		ndelay(4200);
+		gpio_set_value(96, 1);
+		ndelay(9000);
 
-	/* data byte */
-	/* RFA = 0 */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+		/* data byte */
+		/* RFA = 0 */
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* Address bits */
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
-	gpio_set_value(96, 0);
-	udelay(67);
-	gpio_set_value(96, 1);
-	udelay(33);
+		/* Address bits */
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
+		gpio_set_value(96, 0);
+		udelay(67);
+		gpio_set_value(96, 1);
+		udelay(33);
 
-	/* Data bits */
-	for (i = 0; i < 5; i++) {
-		remainder = (level) & (16);
-		if (remainder) {
-			gpio_set_value(96, 0);
-			udelay(33);
-			gpio_set_value(96, 1);
-			udelay(67);
-		} else {
-			gpio_set_value(96, 0);
-			udelay(67);
-			gpio_set_value(96, 1);
-			udelay(33);
+		/* Data bits */
+		for (i = 0; i < 5; i++) {
+			remainder = (level) & (16);
+			if (remainder) {
+				gpio_set_value(96, 0);
+				udelay(33);
+				gpio_set_value(96, 1);
+				udelay(67);
+			} else {
+				gpio_set_value(96, 0);
+				udelay(67);
+				gpio_set_value(96, 1);
+				udelay(33);
+			}
+			level = level << 1;
 		}
-		level = level << 1;
+
+		/* t-EOS */
+		gpio_set_value(96, 0);
+		ndelay(12000);
+		gpio_set_value(96, 1);
+	} else {
+		ret = pmapp_disp_backlight_set_brightness(level);
+		 if (ret)
+			pr_err("%s: can't set lcd backlight!\n", __func__);
 	}
 
-	/* t-EOS */
-	gpio_set_value(96, 0);
-	ndelay(12000);
-	gpio_set_value(96, 1);
-	return 0;
+	return ret;
 }
 
 static int mipi_NT35510_rotate_panel(void)
@@ -685,7 +693,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35510_pdata = {
-	.pmic_backlight = evb_backlight_control,
+	.backlight    = evb_backlight_control,
 	.rotate_panel = mipi_NT35510_rotate_panel,
 };
 
@@ -698,7 +706,7 @@
 };
 
 static struct msm_panel_common_pdata mipi_NT35516_pdata = {
-	.pmic_backlight = evb_backlight_control,
+	.backlight = evb_backlight_control,
 };
 
 static struct platform_device mipi_dsi_NT35516_panel_device = {
@@ -1141,6 +1149,7 @@
 	static struct regulator *gpio_reg_2p85v, *gpio_reg_1p8v;
 
 	if (!qrd3_dsi_gpio_initialized) {
+		pmapp_disp_backlight_init();
 		rc = gpio_request(GPIO_QRD3_LCD_BACKLIGHT_EN,
 			"qrd3_gpio_bkl_en");
 		if (rc < 0)
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 8c1d5b7..243b488 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -389,6 +389,7 @@
 	int (*backlight_level)(int level, int max, int min);
 	int (*pmic_backlight)(int level);
 	int (*rotate_panel)(void);
+	int (*backlight) (int level, int mode);
 	int (*panel_num)(void);
 	void (*panel_config_gpio)(int);
 	int (*vga_switch)(int select_vga);
diff --git a/drivers/video/msm/mipi_NT35510.c b/drivers/video/msm/mipi_NT35510.c
index edbc952..e605aed 100644
--- a/drivers/video/msm/mipi_NT35510.c
+++ b/drivers/video/msm/mipi_NT35510.c
@@ -19,6 +19,8 @@
 static struct dsi_buf nt35510_tx_buf;
 static struct dsi_buf nt35510_rx_buf;
 
+static int mipi_nt35510_bl_ctrl;
+
 #define NT35510_SLEEP_OFF_DELAY 150
 #define NT35510_DISPLAY_ON_DELAY 150
 
@@ -528,8 +530,63 @@
 	return 0;
 }
 
+static ssize_t mipi_nt35510_wta_bl_ctrl(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err;
+
+	err =  kstrtoint(buf, 0, &mipi_nt35510_bl_ctrl);
+	if (err)
+		return ret;
+
+	pr_info("%s: bl ctrl set to %d\n", __func__, mipi_nt35510_bl_ctrl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_nt35510_wta_bl_ctrl);
+
+static struct attribute *mipi_nt35510_fs_attrs[] = {
+	&dev_attr_bl_ctrl.attr,
+	NULL,
+};
+
+static struct attribute_group mipi_nt35510_fs_attr_group = {
+	.attrs = mipi_nt35510_fs_attrs,
+};
+
+static int mipi_nt35510_create_sysfs(struct platform_device *pdev)
+{
+	int rc;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd) {
+		pr_err("%s: mfd not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi) {
+		pr_err("%s: mfd->fbi not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi->dev) {
+		pr_err("%s: mfd->fbi->dev not found\n", __func__);
+		return -ENODEV;
+	}
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+		&mipi_nt35510_fs_attr_group);
+	if (rc) {
+		pr_err("%s: sysfs group creation failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
 static int __devinit mipi_nt35510_lcd_probe(struct platform_device *pdev)
 {
+	struct platform_device *pthisdev = NULL;
 	pr_debug("%s\n", __func__);
 
 	if (pdev->id == 0) {
@@ -539,7 +596,8 @@
 		return 0;
 	}
 
-	msm_fb_add_device(pdev);
+	pthisdev = msm_fb_add_device(pdev);
+	mipi_nt35510_create_sysfs(pthisdev);
 
 	return 0;
 }
@@ -551,6 +609,8 @@
 	},
 };
 
+static int old_bl_level;
+
 static void mipi_nt35510_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int bl_level;
@@ -558,11 +618,33 @@
 	bl_level = mfd->bl_level;
 
 	if (mipi_nt35510_pdata->bl_lock) {
-		spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock, flags);
-		mipi_nt35510_pdata->pmic_backlight(bl_level);
-		spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock, flags);
-	} else
-		mipi_nt35510_pdata->pmic_backlight(bl_level);
+		if (!mipi_nt35510_bl_ctrl) {
+			/* Level received is of range 1 to bl_max,
+			   We need to convert the levels to 1
+			   to 31 */
+			bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+					/(2 * mfd->panel_info.bl_max);
+			if (bl_level == old_bl_level)
+				return;
+
+			if (bl_level == 0)
+				mipi_nt35510_pdata->backlight(0, 1);
+
+			if (old_bl_level == 0)
+				mipi_nt35510_pdata->backlight(50, 1);
+
+			spin_lock_irqsave(&mipi_nt35510_pdata->bl_spinlock,
+						flags);
+			mipi_nt35510_pdata->backlight(bl_level, 0);
+			spin_unlock_irqrestore(&mipi_nt35510_pdata->bl_spinlock,
+						flags);
+			old_bl_level = bl_level;
+		} else {
+			mipi_nt35510_pdata->backlight(bl_level, 1);
+		}
+	} else {
+		mipi_nt35510_pdata->backlight(bl_level, mipi_nt35510_bl_ctrl);
+	}
 }
 
 static struct msm_fb_panel_data nt35510_panel_data = {
diff --git a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
index f052e93..1524ce6 100644
--- a/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_cmd_wvga_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
index 4e97d99..8a364ba 100644
--- a/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
+++ b/drivers/video/msm/mipi_NT35510_video_wvga_pt.c
@@ -59,7 +59,7 @@
 	delayed from VSYNC active edge */
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 499000000;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
index 7f5ac70..2ebfad4 100644
--- a/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_cmd_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -93,7 +93,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
index e826773..144d9ff 100644
--- a/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
+++ b/drivers/video/msm/mipi_renesas_video_fwvga_pt.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+/* Copyright (c) 2011-2012, Code Aurora Forum. 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
@@ -105,7 +105,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 100;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e.c b/drivers/video/msm/mipi_truly_tft540960_1_e.c
index e465d46..98b24b1 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e.c
@@ -19,6 +19,8 @@
 static struct dsi_buf truly_tx_buf;
 static struct dsi_buf truly_rx_buf;
 
+static int mipi_truly_bl_ctrl;
+
 #define TRULY_CMD_DELAY 0
 #define MIPI_SETTING_DELAY 10
 #define TRULY_SLEEP_OFF_DELAY 150
@@ -720,8 +722,64 @@
 	return 0;
 }
 
+static ssize_t mipi_truly_wta_bl_ctrl(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	ssize_t ret = strnlen(buf, PAGE_SIZE);
+	int err;
+
+	err =  kstrtoint(buf, 0, &mipi_truly_bl_ctrl);
+	if (err)
+		return ret;
+
+	pr_info("%s: bl ctrl set to %d\n", __func__, mipi_truly_bl_ctrl);
+
+	return ret;
+}
+
+static DEVICE_ATTR(bl_ctrl, S_IWUSR, NULL, mipi_truly_wta_bl_ctrl);
+
+static struct attribute *mipi_truly_fs_attrs[] = {
+	&dev_attr_bl_ctrl.attr,
+	NULL,
+};
+
+static struct attribute_group mipi_truly_fs_attr_group = {
+	.attrs = mipi_truly_fs_attrs,
+};
+
+static int mipi_truly_create_sysfs(struct platform_device *pdev)
+{
+	int rc;
+	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);
+
+	if (!mfd) {
+		pr_err("%s: mfd not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi) {
+		pr_err("%s: mfd->fbi not found\n", __func__);
+		return -ENODEV;
+	}
+	if (!mfd->fbi->dev) {
+		pr_err("%s: mfd->fbi->dev not found\n", __func__);
+		return -ENODEV;
+	}
+	rc = sysfs_create_group(&mfd->fbi->dev->kobj,
+		&mipi_truly_fs_attr_group);
+	if (rc) {
+		pr_err("%s: sysfs group creation failed, rc=%d\n",
+			__func__, rc);
+		return rc;
+	}
+
+	return 0;
+}
+
+
 static int __devinit mipi_truly_lcd_probe(struct platform_device *pdev)
 {
+	struct platform_device *pthisdev = NULL;
 	int rc = 0;
 
 	if (pdev->id == 0) {
@@ -731,7 +789,8 @@
 		return rc;
 	}
 
-	msm_fb_add_device(pdev);
+	pthisdev = msm_fb_add_device(pdev);
+	mipi_truly_create_sysfs(pthisdev);
 
 	return rc;
 }
@@ -743,6 +802,8 @@
 	},
 };
 
+static int old_bl_level;
+
 static void mipi_truly_set_backlight(struct msm_fb_data_type *mfd)
 {
 	int bl_level;
@@ -750,11 +811,33 @@
 	bl_level = mfd->bl_level;
 
 	if (mipi_truly_pdata->bl_lock) {
-		spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock, flags);
-		mipi_truly_pdata->pmic_backlight(bl_level);
-		spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock, flags);
-	} else
-		mipi_truly_pdata->pmic_backlight(bl_level);
+		if (!mipi_truly_bl_ctrl) {
+			/* Level received is of range 1 to bl_max,
+			   We need to convert the levels to 1
+			   to 31 */
+			bl_level = (2 * bl_level * 31 + mfd->panel_info.bl_max)
+					/(2 * mfd->panel_info.bl_max);
+			if (bl_level == old_bl_level)
+				return;
+
+			if (bl_level == 0)
+				mipi_truly_pdata->backlight(0, 1);
+
+			if (old_bl_level == 0)
+				mipi_truly_pdata->backlight(50, 1);
+
+			spin_lock_irqsave(&mipi_truly_pdata->bl_spinlock,
+						flags);
+			mipi_truly_pdata->backlight(bl_level, 0);
+			spin_unlock_irqrestore(&mipi_truly_pdata->bl_spinlock,
+						flags);
+			old_bl_level = bl_level;
+		} else {
+			mipi_truly_pdata->backlight(bl_level, 1);
+		}
+	} else {
+		mipi_truly_pdata->backlight(bl_level, mipi_truly_bl_ctrl);
+	}
 }
 
 static struct msm_fb_panel_data truly_panel_data = {
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
index de98177..3423241 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_cmd_qhd_pt.c
@@ -56,7 +56,7 @@
 	pinfo.lcdc.border_clr = 0;	/* blk */
 	pinfo.lcdc.underflow_clr = 0xff;	/* blue */
 	pinfo.lcdc.hsync_skew = 0;
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;
 
diff --git a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
index ea2ff47..3c0c0b7 100644
--- a/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
+++ b/drivers/video/msm/mipi_truly_tft540960_1_e_video_qhd_pt.c
@@ -59,7 +59,7 @@
 	pinfo.lcdc.hsync_skew = 0;
 	pinfo.clk_rate = 699000000;
 	pinfo.lcd.refx100 = 6000; /* FB driver calc FPS based on this value */
-	pinfo.bl_max = 31;
+	pinfo.bl_max = 255;
 	pinfo.bl_min = 1;
 	pinfo.fb_num = 2;