msm7630: Add support for 7630 fluid LCD panel

Change-Id: Ia6e8ecfe2c9e299717ad7db4e58d3fd5d7e5710b
diff --git a/platform/msm7x30/panel_sharp_wvga.c b/platform/msm7x30/panel_sharp_wvga.c
new file mode 100644
index 0000000..d4c05f0
--- /dev/null
+++ b/platform/msm7x30/panel_sharp_wvga.c
@@ -0,0 +1,321 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *  * Neither the name of Code Aurora nor
+ *    the names of its contributors may be used to endorse or promote
+ *    products derived from this software without specific prior written
+ *    permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <debug.h>
+#include <dev/gpio.h>
+#include <kernel/thread.h>
+#include "gpio_hw.h"
+#include "panel.h"
+#include <dev/lcdc.h>
+
+
+#define VEE_RESET              20
+#define LCD_RESET              180
+
+#define GPIO26_GPIO_CNTRL 0x169  /* backlight */
+
+struct sharp_spi_data {
+	unsigned addr;
+	unsigned data;
+};
+
+static struct sharp_spi_data init_sequence[] = {
+	{  15, 0x01 },
+	{   5, 0x01 },
+	{   7, 0x10 },
+	{   9, 0x1E },
+	{  10, 0x04 },
+	{  17, 0xFF },
+	{  21, 0x8A },
+	{  22, 0x00 },
+	{  23, 0x82 },
+	{  24, 0x24 },
+	{  25, 0x22 },
+	{  26, 0x6D },
+	{  27, 0xEB },
+	{  28, 0xB9 },
+	{  29, 0x3A },
+	{  49, 0x1A },
+	{  50, 0x16 },
+	{  51, 0x05 },
+	{  55, 0x7F },
+	{  56, 0x15 },
+	{  57, 0x7B },
+	{  60, 0x05 },
+	{  61, 0x0C },
+	{  62, 0x80 },
+	{  63, 0x00 },
+	{  92, 0x90 },
+	{  97, 0x01 },
+	{  98, 0xFF },
+	{ 113, 0x11 },
+	{ 114, 0x02 },
+	{ 115, 0x08 },
+	{ 123, 0xAB },
+	{ 124, 0x04 },
+	{   6, 0x02 },
+	{ 133, 0x00 },
+	{ 134, 0xFE },
+	{ 135, 0x22 },
+	{ 136, 0x0B },
+	{ 137, 0xFF },
+	{ 138, 0x0F },
+	{ 139, 0x00 },
+	{ 140, 0xFE },
+	{ 141, 0x22 },
+	{ 142, 0x0B },
+	{ 143, 0xFF },
+	{ 144, 0x0F },
+	{ 145, 0x00 },
+	{ 146, 0xFE },
+	{ 147, 0x22 },
+	{ 148, 0x0B },
+	{ 149, 0xFF },
+	{ 150, 0x0F },
+	{ 202, 0x30 },
+	{  30, 0x01 },
+	{   4, 0x01 },
+	{  31, 0x41 }
+};
+
+static unsigned char bit_shift[8] = { (1 << 7), /* MSB */
+	(1 << 6),
+	(1 << 5),
+	(1 << 4),
+	(1 << 3),
+	(1 << 2),
+	(1 << 1),
+	(1 << 0)                               /* LSB */
+};
+
+static unsigned vee_reset_gpio =
+GPIO_CFG(VEE_RESET, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA);
+
+static unsigned lcd_reset_gpio =
+GPIO_CFG(LCD_RESET, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_2MA);
+
+
+static int sharp_display_common_power(int on)
+{
+	int rc = 0, flag_on = !!on;
+	static int display_common_power_save_on;
+	unsigned int vreg_ldo12, vreg_ldo15, vreg_ldo20, vreg_ldo16, vreg_ldo8;
+	if (display_common_power_save_on == flag_on)
+		return 0;
+
+	display_common_power_save_on = flag_on;
+
+	if (on) {
+		/* set LCD reset */
+		rc = gpio_tlmm_config(lcd_reset_gpio, GPIO_ENABLE);
+		if (rc) {
+			return rc;
+		}
+
+		gpio_set(LCD_RESET, 0);   /* bring reset line low to hold reset */
+
+		/* set VEE reset */
+		rc = gpio_tlmm_config(vee_reset_gpio, GPIO_ENABLE);
+
+		if (rc) {
+			return rc;
+		}
+
+		gpio_set(VEE_RESET, 1);
+		gpio_set(VEE_RESET, 0);   /* bring reset line low to hold reset */
+		mdelay(10);
+	}
+
+	/* Set LD008 to 1.8V - VEE (VCC, VDDIO, pullups) */
+	pmic_write(LDO08_CNTRL, 0x06 | LDO_LOCAL_EN_BMSK);
+
+	/* Set LD012 to 1.8V - display (VDDIO) */
+	pmic_write(LDO12_CNTRL, 0x06 | LDO_LOCAL_EN_BMSK);
+
+	/* Set LD015 to 3.0V - display (VCC), VEE (VLP) */
+	pmic_write(LDO15_CNTRL, 0x1E | LDO_LOCAL_EN_BMSK);
+
+	/* wait for power to stabilize */
+	mdelay(10);
+
+	gpio_config(VEE_RESET, 0); /*disable VEE_RESET, rely on pullups to bring it high */
+	mdelay(5);
+
+	gpio_set(LCD_RESET, 1);   /* bring reset line high */
+	mdelay(10); /* 10 msec before IO can be accessed */
+
+	return rc;
+}
+
+static struct msm_gpio sharp_lcd_panel_gpios[] = {
+	{ GPIO_CFG(45, 0, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "spi_clk" },
+	{ GPIO_CFG(46, 0, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "spi_cs0" },
+	{ GPIO_CFG(47, 0, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "spi_mosi" },
+	{ GPIO_CFG(48, 0, GPIO_INPUT,  GPIO_NO_PULL, GPIO_2MA), "spi_miso" },
+	{ GPIO_CFG(22, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_blu2" },
+	{ GPIO_CFG(25, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_red2" },
+	{ GPIO_CFG(90, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_pclk" },
+	{ GPIO_CFG(91, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_en" },
+	{ GPIO_CFG(92, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_vsync" },
+	{ GPIO_CFG(93, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_hsync" },
+	{ GPIO_CFG(94, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_grn2" },
+	{ GPIO_CFG(95, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_grn3" },
+	{ GPIO_CFG(96, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_grn4" },
+	{ GPIO_CFG(97, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_grn5" },
+	{ GPIO_CFG(98, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_grn6" },
+	{ GPIO_CFG(99, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_grn7" },
+	{ GPIO_CFG(100, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_blu3" },
+	{ GPIO_CFG(101, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_blu4" },
+	{ GPIO_CFG(102, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_blu5" },
+	{ GPIO_CFG(103, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_blu6" },
+	{ GPIO_CFG(104, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_blu7" },
+	{ GPIO_CFG(105, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_red3" },
+	{ GPIO_CFG(106, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_red4" },
+	{ GPIO_CFG(107, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_red5" },
+	{ GPIO_CFG(108, 1, GPIO_OUTPUT,  GPIO_NO_PULL, GPIO_2MA), "lcdc_red6" },
+};
+
+int sharp_lcdc_panel_power(int on)
+{
+	int rc, i;
+	struct msm_gpio *gp;
+
+	rc = sharp_display_common_power(on);
+	if (rc < 0) {
+		return rc;
+	}
+
+	if (on) {
+		rc = platform_gpios_enable(sharp_lcd_panel_gpios,
+		ARRAY_SIZE(sharp_lcd_panel_gpios));
+		if(rc)
+		{
+			return rc;
+		}
+	} else {    /* off */
+		gp = sharp_lcd_panel_gpios;
+		for (i = 0; i < ARRAY_SIZE(sharp_lcd_panel_gpios); i++) {
+			/* ouput low */
+			gpio_set(GPIO_PIN(gp->gpio_cfg), 0);
+			gp++;
+		}
+	}
+	return rc;
+}
+
+
+static void sharp_spi_write_byte(unsigned val)
+{
+	int i;
+
+	/* Clock should be Low before entering */
+	for (i = 0; i < 8; i++) {
+		/* #1: Drive the Data (High or Low) */
+		if (val & bit_shift[i])
+			gpio_set(SPI_MOSI, 1);
+		else
+			gpio_set(SPI_MOSI, 0);
+
+		/* #2: Drive the Clk High and then Low */
+		gpio_set(SPI_SCLK, 1);
+		gpio_set(SPI_SCLK, 0);
+	}
+}
+
+static int serigo(unsigned reg, unsigned data)
+{
+	/* Enable the Chip Select - low */
+	gpio_set(SPI_CS, 0);
+	udelay(1);
+
+	/* Transmit register address first, then data */
+	sharp_spi_write_byte(reg);
+
+	/* Idle state of MOSI is Low */
+	gpio_set(SPI_MOSI, 0);
+	udelay(1);
+	sharp_spi_write_byte(data);
+
+	gpio_set(SPI_MOSI, 0);
+	gpio_set(SPI_CS, 1);
+	return 0;
+}
+
+void sharp_lcdc_disp_on (void)
+{
+	unsigned i;
+	gpio_set(SPI_CS, 1);
+	gpio_set(SPI_SCLK, 1);
+	gpio_set(SPI_MOSI, 0);
+	gpio_set(SPI_MISO, 0);
+
+	for (i = 0; i < ARRAY_SIZE(init_sequence); i++) {
+		serigo(init_sequence[i].addr, init_sequence[i].data);
+	}
+	mdelay(10);
+	serigo(31, 0xC1);
+	mdelay(10);
+	serigo(31, 0xD9);
+	serigo(31, 0xDF);
+}
+
+void sharp_lcdc_on(void)
+{
+	lcdc_clock_init(27648000);
+	sharp_lcdc_panel_power(1);
+
+	/*enable backlight, open up gpio, use default for LPG */
+	pmic_write(GPIO26_GPIO_CNTRL,0x81);  /* Write, Bank0, VIN0=VPH, Mode selection enabled */
+	pmic_write(GPIO26_GPIO_CNTRL,0x99);  /* Write, Bank1, OutOn/InOff, CMOS, Invert Output (GPIO High) */
+	pmic_write(GPIO26_GPIO_CNTRL,0xAA);  /* Write, Bank2, GPIO no pull */
+	pmic_write(GPIO26_GPIO_CNTRL,0xB4);  /* Write, Bank3, high drv strength */
+	pmic_write(GPIO26_GPIO_CNTRL,0xC6);  /* Write, Bank4, Src: Special Function 2 */
+
+	sharp_lcdc_disp_on();
+}
+
+static struct lcdc_timing_parameters param = {
+	.lcdc_fb_width                     = 480,
+	.lcdc_fb_height                    = 800,
+	.lcdc_hsync_pulse_width_dclk       = 10,
+	.lcdc_hsync_back_porch_dclk        = 20,
+	.lcdc_hsync_front_porch_dclk       = 10,
+	.lcdc_hsync_skew_dclk              = 0,
+
+	.lcdc_vsync_pulse_width_lines      = 2,
+	.lcdc_vsync_back_porch_lines       = 2,
+	.lcdc_vsync_front_porch_lines      = 2,
+};
+
+struct lcdc_timing_parameters *sharp_timing_param()
+{
+	return &param;
+}