tizen 2.3.1 release
[platform/kernel/u-boot.git] / drivers / video / ld9040.c
index 23fe783..ca3a8f3 100644 (file)
 /*
- * ld9040 AMOLED LCD panel driver.
+ * LCD panel driver for Board based on S5PC100 and S5PC110. 
  *
- * Copyright (C) 2012 Samsung Electronics
- * Donghwa Lee <dh09.lee@samsung.com>
+ * Author: Donghwa Lee  <dh09.lee@samsung.com>
  *
- * SPDX-License-Identifier:    GPL-2.0+
+ * Derived from drivers/video/omap/lcd-apollon.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
 #include <spi.h>
 
+enum ld9040_panel_type {
+       TYPE_M2,
+       TYPE_SM2_A1,
+       TYPE_SM2_A2,
+};
+
+static enum ld9040_panel_type panel_type;
+/* these machine specific platform data would be setting at universal.c */
+struct spi_platform_data *ld9040;
+
 static const unsigned char SEQ_SWRESET[] = {
-       0x01,
+       0x01, COMMAND_ONLY,
 };
 
 static const unsigned char SEQ_USER_SETTING[] = {
-       0xF0, 0x5A, 0x5A
+       0xF0, 0x5A,
+
+       DATA_ONLY, 0x5A,
 };
 
 static const unsigned char SEQ_ELVSS_ON[] = {
-       0xB1, 0x0D, 0x00, 0x16,
+       0xB1, 0x0D,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x16,
+};
+
+static const unsigned short SEQ_ELVSS_ON_SM2[] = {
+       0xB1, 0x0F,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x16,
+
+       0xB2, 0x1F,
+       DATA_ONLY, 0x1F,
+       DATA_ONLY, 0x1F,
+       DATA_ONLY, 0x1F,
 };
 
 static const unsigned char SEQ_TEMP_SWIRE[] = {
-       0xB2, 0x06, 0x06, 0x06, 0x06,
+       0xB2, 0x06,
+
+       DATA_ONLY, 0x06,
+       DATA_ONLY, 0x06,
+       DATA_ONLY, 0x06,
 };
 
 static const unsigned char SEQ_GTCON[] = {
-       0xF7, 0x09, 0x00, 0x00,
+       0xF7, 0x09,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+};
+
+static const unsigned char SEQ_GTCON_REV[] = {
+       0xF7, 0x07,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
 };
 
 static const unsigned char SEQ_PANEL_CONDITION[] = {
-       0xF8, 0x05, 0x65, 0x96, 0x71, 0x7D, 0x19, 0x3B,
-       0x0D, 0x19, 0x7E, 0x0D, 0xE2, 0x00, 0x00, 0x7E,
-       0x7D, 0x07, 0x07, 0x20, 0x20, 0x20, 0x02, 0x02,
+       0xF8, 0x05,
+
+       DATA_ONLY, 0x65,
+       DATA_ONLY, 0x96,
+       DATA_ONLY, 0x71,
+       DATA_ONLY, 0x7D,
+       DATA_ONLY, 0x19,
+       DATA_ONLY, 0x3B,
+       DATA_ONLY, 0x0D,
+       DATA_ONLY, 0x19,
+       DATA_ONLY, 0x7E,
+       DATA_ONLY, 0x0D,
+       DATA_ONLY, 0xE2,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x7E,
+       DATA_ONLY, 0x7D,
+       DATA_ONLY, 0x07,
+       DATA_ONLY, 0x07,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x20,
+       DATA_ONLY, 0x02,
+       DATA_ONLY, 0x02,
 };
 
 static const unsigned char SEQ_GAMMA_SET1[] = {
-       0xF9, 0x00, 0xA7, 0xB4, 0xAE, 0xBF, 0x00, 0x91,
-       0x00, 0xB2, 0xB4, 0xAA, 0xBB, 0x00, 0xAC, 0x00,
-       0xB3, 0xB1, 0xAA, 0xBC, 0x00, 0xB3,
+       0xF9, 0x00,
+
+       DATA_ONLY, 0xA7,
+       DATA_ONLY, 0xB5,
+       DATA_ONLY, 0xAE,
+       DATA_ONLY, 0xBF,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x91,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xB2,
+       DATA_ONLY, 0xB4,
+       DATA_ONLY, 0xAA,
+       DATA_ONLY, 0xBB,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xAC,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xB3,
+       DATA_ONLY, 0xB1,
+       DATA_ONLY, 0xAA,
+       DATA_ONLY, 0xBC,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0xB3,
 };
 
 static const unsigned char SEQ_GAMMA_CTRL[] = {
-       0xFB, 0x02, 0x5A,
+       0xFB, 0x02,
+
+       DATA_ONLY, 0x5A,
 };
 
 static const unsigned char SEQ_APON[] = {
-       0xF3, 0x00, 0x00, 0x00, 0x0A, 0x02,
+       0xF3, 0x00,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x0A,
+       DATA_ONLY, 0x02,
 };
 
 static const unsigned char SEQ_DISPCTL[] = {
-       0xF2, 0x02, 0x08, 0x08, 0x10, 0x10,
+       0xF2, 0x02,
+
+       DATA_ONLY, 0x08,
+       DATA_ONLY, 0x08,
+       DATA_ONLY, 0x10,
+       DATA_ONLY, 0x10,
 };
 
 static const unsigned char SEQ_MANPWR[] = {
@@ -59,70 +169,332 @@ static const unsigned char SEQ_MANPWR[] = {
 };
 
 static const unsigned char SEQ_PWR_CTRL[] = {
-       0xF4, 0x0A, 0x87, 0x25, 0x6A, 0x44, 0x02, 0x88,
+       0xF4, 0x0A,
+
+       DATA_ONLY, 0x87,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x6A,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x02,
+       DATA_ONLY, 0x88,
+};
+
+static const unsigned char SEQ_PWR_CTRL_SM2_A1[] = {
+       0xF4, 0x0A,
+
+       DATA_ONLY, 0x87,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x6A,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x02,
+ };
+
+static const unsigned char SEQ_PWR_CTRL_SM2_A2[] = {
+       0xF4, 0x0A,
+
+       DATA_ONLY, 0xA7,
+       DATA_ONLY, 0x25,
+       DATA_ONLY, 0x6A,
+       DATA_ONLY, 0x44,
+       DATA_ONLY, 0x02,
 };
 
 static const unsigned char SEQ_SLPOUT[] = {
-       0x11,
+       0x11, COMMAND_ONLY,
 };
 
 static const unsigned char SEQ_SLPIN[] = {
-       0x10,
+       0x10, COMMAND_ONLY,
 };
 
 static const unsigned char SEQ_DISPON[] = {
-       0x29,
+       0x29, COMMAND_ONLY,
 };
 
 static const unsigned char SEQ_DISPOFF[] = {
-       0x28,
+       0x28, COMMAND_ONLY,
+};
+
+static const unsigned char SEQ_VCI1_1ST_EN[] = {
+       0xF3, 0x10,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VL1_EN[] = {
+       0xF3, 0x11,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VL2_EN[] = {
+       0xF3, 0x13,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VCI1_2ND_EN[] = {
+       0xF3, 0x33,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VL3_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VREG1_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x01,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VGH_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x11,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VGL_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0x31,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x02,
+};
+
+static const unsigned char SEQ_VMOS_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xB1,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+};
+
+static const unsigned char SEQ_VINT_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xF1,
+       /* DATA_ONLY, 0x71,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+};
+
+static const unsigned char SEQ_VBH_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xF9,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+};
+
+static const unsigned char SEQ_VBL_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFD,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+};
+
+static const unsigned char SEQ_GAM_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+};
+
+static const unsigned char SEQ_SD_AMP_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x80,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+};
+
+static const unsigned char SEQ_GLS_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x81,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+};
+
+static const unsigned char SEQ_ELS_EN[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x83,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+};
+
+static const unsigned char SEQ_EL_ON[] = {
+       0xF3, 0x37,
+
+       DATA_ONLY, 0xFF,
+       /* DATA_ONLY, 0x73,     VMOS/VBL/VBH not used */
+       DATA_ONLY, 0x87,
+       DATA_ONLY, 0x00,
+       DATA_ONLY, 0x03,
+       /* DATA_ONLY, 0x02,     VMOS/VBL/VBH not used */
+};
+
+static const unsigned char SEQ_ID1[] = {
+       0xDA, COMMAND_ONLY,
+};
+
+static const unsigned char SEQ_ID2[] = {
+       0xDB, COMMAND_ONLY,
+};
+static const unsigned char SEQ_ID3[] = {
+       0xDC, COMMAND_ONLY,
 };
 
-static void ld9040_spi_write(const unsigned char *wbuf, unsigned int size_cmd)
+static void ld9040_spi_write(unsigned char address, unsigned char command)
+{
+       if (address != DATA_ONLY)
+               spi_gpio_write(ld9040, (unsigned int) 0x0, (unsigned int) address);
+
+       if (command != COMMAND_ONLY)
+               spi_gpio_write(ld9040, (unsigned int) 0x1, (unsigned int) command);
+}
+
+static void ld9040_panel_send_sequence(const unsigned char *wbuf, unsigned int size_cmd)
 {
        int i = 0;
 
-       /*
-        * Data are transmitted in 9-bit words:
-        * the first bit is command/parameter, the other are the value.
-        * The value's LSB is shifted to MSB position, to be sent as 9th bit
-        */
-
-       unsigned int data_out = 0, data_in = 0;
-       for (i = 0; i < size_cmd; i++) {
-               data_out = wbuf[i] >> 1;
-               if (i != 0)
-                       data_out += 0x0080;
-               if (wbuf[i] & 0x01)
-                       data_out += 0x8000;
-               spi_xfer(NULL, 9, &data_out, &data_in, SPI_XFER_BEGIN);
+       while (i < size_cmd) {
+               ld9040_spi_write(wbuf[i], wbuf[i+1]);
+               i += 2;
        }
 }
 
-void ld9040_cfg_ldo(void)
+static int ld9040_spi_read(const unsigned char *wbuf, unsigned int size_cmd)
+{
+       ld9040_panel_send_sequence(wbuf, size_cmd);
+       return spi_gpio_read(ld9040);
+}
+
+static int ld9040_panel_read_id(void)
 {
-       udelay(10);
+       unsigned char id[3];
+
+       id[0] = ld9040_spi_read(SEQ_ID1, ARRAY_SIZE(SEQ_ID1));
+       if (id[0]) {
+               id[1] = ld9040_spi_read(SEQ_ID2, ARRAY_SIZE(SEQ_ID2));
+               id[2] = ld9040_spi_read(SEQ_ID3, ARRAY_SIZE(SEQ_ID3));
+               printf("OLED Module manufacturer : \t%x\n", id[0]);
+               printf("OLED Module/driver version : \t%x\n", id[1]);
+               printf("OLED module/driver : \t\t%x\n", id[2]);
+       }
 
-       ld9040_spi_write(SEQ_USER_SETTING,
+       switch (id[0]) {
+       case 0xa2:
+               panel_type = TYPE_SM2_A2;
+               break;
+       case 0xa1:
+               panel_type = TYPE_SM2_A1;
+               break;
+       default:
+               panel_type = TYPE_M2;
+               break;
+       }
+}
+
+void ld9040_cfg_ldo(void)
+{
+       ld9040_panel_send_sequence(SEQ_USER_SETTING,
                                        ARRAY_SIZE(SEQ_USER_SETTING));
-       ld9040_spi_write(SEQ_PANEL_CONDITION,
+       ld9040_panel_send_sequence(SEQ_DISPCTL, ARRAY_SIZE(SEQ_DISPCTL));
+       if (ld9040->set_rev)
+               ld9040_panel_send_sequence(SEQ_GTCON_REV, ARRAY_SIZE(SEQ_GTCON_REV));
+       else
+               ld9040_panel_send_sequence(SEQ_GTCON, ARRAY_SIZE(SEQ_GTCON));
+       ld9040_panel_send_sequence(SEQ_PANEL_CONDITION,
                                        ARRAY_SIZE(SEQ_PANEL_CONDITION));
-       ld9040_spi_write(SEQ_DISPCTL, ARRAY_SIZE(SEQ_DISPCTL));
-       ld9040_spi_write(SEQ_MANPWR, ARRAY_SIZE(SEQ_MANPWR));
-       ld9040_spi_write(SEQ_PWR_CTRL, ARRAY_SIZE(SEQ_PWR_CTRL));
-       ld9040_spi_write(SEQ_ELVSS_ON, ARRAY_SIZE(SEQ_ELVSS_ON));
-       ld9040_spi_write(SEQ_GTCON, ARRAY_SIZE(SEQ_GTCON));
-       ld9040_spi_write(SEQ_GAMMA_SET1, ARRAY_SIZE(SEQ_GAMMA_SET1));
-       ld9040_spi_write(SEQ_GAMMA_CTRL, ARRAY_SIZE(SEQ_GAMMA_CTRL));
-       ld9040_spi_write(SEQ_SLPOUT, ARRAY_SIZE(SEQ_SLPOUT));
-
-       udelay(120);
+
+       ld9040_panel_read_id();
+
+       switch (panel_type) {
+       case TYPE_SM2_A1:
+               ld9040_panel_send_sequence(SEQ_ELVSS_ON_SM2, ARRAY_SIZE(SEQ_ELVSS_ON_SM2));
+               ld9040_panel_send_sequence(SEQ_PWR_CTRL_SM2_A1, ARRAY_SIZE(SEQ_PWR_CTRL_SM2_A1));
+               break;
+       case TYPE_SM2_A2:
+               ld9040_panel_send_sequence(SEQ_ELVSS_ON_SM2, ARRAY_SIZE(SEQ_ELVSS_ON_SM2));
+               ld9040_panel_send_sequence(SEQ_PWR_CTRL_SM2_A2, ARRAY_SIZE(SEQ_PWR_CTRL_SM2_A2));
+               break;
+       case TYPE_M2:
+               /* fall through */
+       default:
+               ld9040_panel_send_sequence(SEQ_MANPWR, ARRAY_SIZE(SEQ_MANPWR));
+               ld9040_panel_send_sequence(SEQ_PWR_CTRL, ARRAY_SIZE(SEQ_PWR_CTRL));
+               ld9040_panel_send_sequence(SEQ_ELVSS_ON, ARRAY_SIZE(SEQ_ELVSS_ON));
+               break;
+       }
+
+       ld9040_panel_send_sequence(SEQ_GAMMA_SET1, ARRAY_SIZE(SEQ_GAMMA_SET1));
+       ld9040_panel_send_sequence(SEQ_GAMMA_CTRL, ARRAY_SIZE(SEQ_GAMMA_CTRL));
+       ld9040_panel_send_sequence(SEQ_SLPOUT, ARRAY_SIZE(SEQ_SLPOUT));
+
+       udelay(120 * 1000);
 }
 
-void ld9040_enable_ldo(unsigned int onoff)
+void ld9040_enable_ldo(unsigned int on)
 {
-       if (onoff)
-               ld9040_spi_write(SEQ_DISPON, ARRAY_SIZE(SEQ_DISPON));
-       else
-               ld9040_spi_write(SEQ_DISPOFF, ARRAY_SIZE(SEQ_DISPOFF));
+       if (on)
+               ld9040_panel_send_sequence(SEQ_DISPON, ARRAY_SIZE(SEQ_DISPON));
 }
+
+/* this function would be called at universal.c */
+void ld9040_set_platform_data(struct spi_platform_data *pd)
+{
+       if (pd == NULL) {
+               puts("pd is NULL.\n");
+               return;
+       }
+
+       ld9040 = pd;
+}
+