| /* Copyright (c) 2009, 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 |
| * 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. |
| * |
| * 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., 51 Franklin Street, Fifth Floor, Boston, MA |
| * 02110-1301, USA. |
| */ |
| |
| #include <linux/delay.h> |
| #include <mach/gpio.h> |
| #include "msm_fb.h" |
| |
| /* registers */ |
| #define GORDON_REG_NOP 0x00 |
| #define GORDON_REG_IMGCTL1 0x10 |
| #define GORDON_REG_IMGCTL2 0x11 |
| #define GORDON_REG_IMGSET1 0x12 |
| #define GORDON_REG_IMGSET2 0x13 |
| #define GORDON_REG_IVBP1 0x14 |
| #define GORDON_REG_IHBP1 0x15 |
| #define GORDON_REG_IVNUM1 0x16 |
| #define GORDON_REG_IHNUM1 0x17 |
| #define GORDON_REG_IVBP2 0x18 |
| #define GORDON_REG_IHBP2 0x19 |
| #define GORDON_REG_IVNUM2 0x1A |
| #define GORDON_REG_IHNUM2 0x1B |
| #define GORDON_REG_LCDIFCTL1 0x30 |
| #define GORDON_REG_VALTRAN 0x31 |
| #define GORDON_REG_AVCTL 0x33 |
| #define GORDON_REG_LCDIFCTL2 0x34 |
| #define GORDON_REG_LCDIFCTL3 0x35 |
| #define GORDON_REG_LCDIFSET1 0x36 |
| #define GORDON_REG_PCCTL 0x3C |
| #define GORDON_REG_TPARAM1 0x40 |
| #define GORDON_REG_TLCDIF1 0x41 |
| #define GORDON_REG_TSSPB_ST1 0x42 |
| #define GORDON_REG_TSSPB_ED1 0x43 |
| #define GORDON_REG_TSCK_ST1 0x44 |
| #define GORDON_REG_TSCK_WD1 0x45 |
| #define GORDON_REG_TGSPB_VST1 0x46 |
| #define GORDON_REG_TGSPB_VED1 0x47 |
| #define GORDON_REG_TGSPB_CH1 0x48 |
| #define GORDON_REG_TGCK_ST1 0x49 |
| #define GORDON_REG_TGCK_ED1 0x4A |
| #define GORDON_REG_TPCTL_ST1 0x4B |
| #define GORDON_REG_TPCTL_ED1 0x4C |
| #define GORDON_REG_TPCHG_ED1 0x4D |
| #define GORDON_REG_TCOM_CH1 0x4E |
| #define GORDON_REG_THBP1 0x4F |
| #define GORDON_REG_TPHCTL1 0x50 |
| #define GORDON_REG_EVPH1 0x51 |
| #define GORDON_REG_EVPL1 0x52 |
| #define GORDON_REG_EVNH1 0x53 |
| #define GORDON_REG_EVNL1 0x54 |
| #define GORDON_REG_TBIAS1 0x55 |
| #define GORDON_REG_TPARAM2 0x56 |
| #define GORDON_REG_TLCDIF2 0x57 |
| #define GORDON_REG_TSSPB_ST2 0x58 |
| #define GORDON_REG_TSSPB_ED2 0x59 |
| #define GORDON_REG_TSCK_ST2 0x5A |
| #define GORDON_REG_TSCK_WD2 0x5B |
| #define GORDON_REG_TGSPB_VST2 0x5C |
| #define GORDON_REG_TGSPB_VED2 0x5D |
| #define GORDON_REG_TGSPB_CH2 0x5E |
| #define GORDON_REG_TGCK_ST2 0x5F |
| #define GORDON_REG_TGCK_ED2 0x60 |
| #define GORDON_REG_TPCTL_ST2 0x61 |
| #define GORDON_REG_TPCTL_ED2 0x62 |
| #define GORDON_REG_TPCHG_ED2 0x63 |
| #define GORDON_REG_TCOM_CH2 0x64 |
| #define GORDON_REG_THBP2 0x65 |
| #define GORDON_REG_TPHCTL2 0x66 |
| #define GORDON_REG_POWCTL 0x80 |
| |
| static int lcdc_gordon_panel_off(struct platform_device *pdev); |
| |
| static int spi_cs; |
| static int spi_sclk; |
| static int spi_sdo; |
| static int spi_sdi; |
| static int spi_dac; |
| static unsigned char bit_shift[8] = { (1 << 7), /* MSB */ |
| (1 << 6), |
| (1 << 5), |
| (1 << 4), |
| (1 << 3), |
| (1 << 2), |
| (1 << 1), |
| (1 << 0) /* LSB */ |
| }; |
| |
| struct gordon_state_type{ |
| boolean disp_initialized; |
| boolean display_on; |
| boolean disp_powered_up; |
| }; |
| |
| static struct gordon_state_type gordon_state = { 0 }; |
| static struct msm_panel_common_pdata *lcdc_gordon_pdata; |
| |
| static void serigo(uint16 reg, uint8 data) |
| { |
| unsigned int tx_val = ((0x00FF & reg) << 8) | data; |
| unsigned char i, val = 0; |
| |
| /* Enable the Chip Select */ |
| gpio_set_value(spi_cs, 1); |
| udelay(33); |
| |
| /* Transmit it in two parts, Higher Byte first, then Lower Byte */ |
| val = (unsigned char)((tx_val & 0xFF00) >> 8); |
| |
| /* 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_value(spi_sdi, 1); |
| else |
| gpio_set_value(spi_sdi, 0); |
| |
| /* #2: Drive the Clk High and then Low */ |
| udelay(33); |
| gpio_set_value(spi_sclk, 1); |
| udelay(33); |
| gpio_set_value(spi_sclk, 0); |
| } |
| |
| /* Idle state of SDO (MOSI) is Low */ |
| gpio_set_value(spi_sdi, 0); |
| /* ..then Lower Byte */ |
| val = (uint8) (tx_val & 0x00FF); |
| /* Before we enter here the Clock should be Low ! */ |
| |
| for (i = 0; i < 8; i++) { |
| /* #1: Drive the Data (High or Low) */ |
| if (val & bit_shift[i]) |
| gpio_set_value(spi_sdi, 1); |
| else |
| gpio_set_value(spi_sdi, 0); |
| |
| /* #2: Drive the Clk High and then Low */ |
| udelay(33); |
| |
| gpio_set_value(spi_sclk, 1); |
| udelay(33); |
| gpio_set_value(spi_sclk, 0); |
| } |
| |
| /* Idle state of SDO (MOSI) is Low */ |
| gpio_set_value(spi_sdi, 0); |
| |
| /* Now Disable the Chip Select */ |
| udelay(33); |
| gpio_set_value(spi_cs, 0); |
| } |
| |
| static void spi_init(void) |
| { |
| /* Setting the Default GPIO's */ |
| spi_sclk = *(lcdc_gordon_pdata->gpio_num); |
| spi_cs = *(lcdc_gordon_pdata->gpio_num + 1); |
| spi_sdi = *(lcdc_gordon_pdata->gpio_num + 2); |
| spi_sdo = *(lcdc_gordon_pdata->gpio_num + 3); |
| |
| /* Set the output so that we dont disturb the slave device */ |
| gpio_set_value(spi_sclk, 0); |
| gpio_set_value(spi_sdi, 0); |
| |
| /* Set the Chip Select De-asserted */ |
| gpio_set_value(spi_cs, 0); |
| |
| } |
| |
| static void gordon_disp_powerup(void) |
| { |
| if (!gordon_state.disp_powered_up && !gordon_state.display_on) { |
| /* Reset the hardware first */ |
| /* Include DAC power up implementation here */ |
| gordon_state.disp_powered_up = TRUE; |
| } |
| } |
| |
| static void gordon_init(void) |
| { |
| /* Image interface settings */ |
| serigo(GORDON_REG_IMGCTL2, 0x00); |
| serigo(GORDON_REG_IMGSET1, 0x00); |
| |
| /* Exchange the RGB signal for J510(Softbank mobile) */ |
| serigo(GORDON_REG_IMGSET2, 0x12); |
| serigo(GORDON_REG_LCDIFSET1, 0x00); |
| |
| /* Pre-charge settings */ |
| serigo(GORDON_REG_PCCTL, 0x09); |
| serigo(GORDON_REG_LCDIFCTL2, 0x7B); |
| |
| mdelay(1); |
| } |
| |
| static void gordon_disp_on(void) |
| { |
| if (gordon_state.disp_powered_up && !gordon_state.display_on) { |
| gordon_init(); |
| mdelay(20); |
| /* gordon_dispmode setting */ |
| serigo(GORDON_REG_TPARAM1, 0x30); |
| serigo(GORDON_REG_TLCDIF1, 0x00); |
| serigo(GORDON_REG_TSSPB_ST1, 0x8B); |
| serigo(GORDON_REG_TSSPB_ED1, 0x93); |
| serigo(GORDON_REG_TSCK_ST1, 0x88); |
| serigo(GORDON_REG_TSCK_WD1, 0x00); |
| serigo(GORDON_REG_TGSPB_VST1, 0x01); |
| serigo(GORDON_REG_TGSPB_VED1, 0x02); |
| serigo(GORDON_REG_TGSPB_CH1, 0x5E); |
| serigo(GORDON_REG_TGCK_ST1, 0x80); |
| serigo(GORDON_REG_TGCK_ED1, 0x3C); |
| serigo(GORDON_REG_TPCTL_ST1, 0x50); |
| serigo(GORDON_REG_TPCTL_ED1, 0x74); |
| serigo(GORDON_REG_TPCHG_ED1, 0x78); |
| serigo(GORDON_REG_TCOM_CH1, 0x50); |
| serigo(GORDON_REG_THBP1, 0x84); |
| serigo(GORDON_REG_TPHCTL1, 0x00); |
| serigo(GORDON_REG_EVPH1, 0x70); |
| serigo(GORDON_REG_EVPL1, 0x64); |
| serigo(GORDON_REG_EVNH1, 0x56); |
| serigo(GORDON_REG_EVNL1, 0x48); |
| serigo(GORDON_REG_TBIAS1, 0x88); |
| |
| /* QVGA settings */ |
| serigo(GORDON_REG_TPARAM2, 0x28); |
| serigo(GORDON_REG_TLCDIF2, 0x14); |
| serigo(GORDON_REG_TSSPB_ST2, 0x49); |
| serigo(GORDON_REG_TSSPB_ED2, 0x4B); |
| serigo(GORDON_REG_TSCK_ST2, 0x4A); |
| serigo(GORDON_REG_TSCK_WD2, 0x02); |
| serigo(GORDON_REG_TGSPB_VST2, 0x02); |
| serigo(GORDON_REG_TGSPB_VED2, 0x03); |
| serigo(GORDON_REG_TGSPB_CH2, 0x2F); |
| serigo(GORDON_REG_TGCK_ST2, 0x40); |
| serigo(GORDON_REG_TGCK_ED2, 0x1E); |
| serigo(GORDON_REG_TPCTL_ST2, 0x2C); |
| serigo(GORDON_REG_TPCTL_ED2, 0x3A); |
| serigo(GORDON_REG_TPCHG_ED2, 0x3C); |
| serigo(GORDON_REG_TCOM_CH2, 0x28); |
| serigo(GORDON_REG_THBP2, 0x4D); |
| serigo(GORDON_REG_TPHCTL2, 0x1A); |
| |
| /* VGA settings */ |
| serigo(GORDON_REG_IVBP1, 0x02); |
| serigo(GORDON_REG_IHBP1, 0x90); |
| serigo(GORDON_REG_IVNUM1, 0xA0); |
| serigo(GORDON_REG_IHNUM1, 0x78); |
| |
| /* QVGA settings */ |
| serigo(GORDON_REG_IVBP2, 0x02); |
| serigo(GORDON_REG_IHBP2, 0x48); |
| serigo(GORDON_REG_IVNUM2, 0x50); |
| serigo(GORDON_REG_IHNUM2, 0x3C); |
| |
| /* Gordon Charge pump settings and ON */ |
| serigo(GORDON_REG_POWCTL, 0x03); |
| mdelay(15); |
| serigo(GORDON_REG_POWCTL, 0x07); |
| mdelay(15); |
| |
| serigo(GORDON_REG_POWCTL, 0x0F); |
| mdelay(15); |
| |
| serigo(GORDON_REG_AVCTL, 0x03); |
| mdelay(15); |
| |
| serigo(GORDON_REG_POWCTL, 0x1F); |
| mdelay(15); |
| |
| serigo(GORDON_REG_POWCTL, 0x5F); |
| mdelay(15); |
| |
| serigo(GORDON_REG_POWCTL, 0x7F); |
| mdelay(15); |
| |
| serigo(GORDON_REG_LCDIFCTL1, 0x02); |
| mdelay(15); |
| |
| serigo(GORDON_REG_IMGCTL1, 0x00); |
| mdelay(15); |
| |
| serigo(GORDON_REG_LCDIFCTL3, 0x00); |
| mdelay(15); |
| |
| serigo(GORDON_REG_VALTRAN, 0x01); |
| mdelay(15); |
| |
| serigo(GORDON_REG_LCDIFCTL1, 0x03); |
| mdelay(1); |
| gordon_state.display_on = TRUE; |
| } |
| } |
| |
| static int lcdc_gordon_panel_on(struct platform_device *pdev) |
| { |
| if (!gordon_state.disp_initialized) { |
| /* Configure reset GPIO that drives DAC */ |
| lcdc_gordon_pdata->panel_config_gpio(1); |
| spi_dac = *(lcdc_gordon_pdata->gpio_num + 4); |
| gpio_set_value(spi_dac, 0); |
| udelay(15); |
| gpio_set_value(spi_dac, 1); |
| spi_init(); /* LCD needs SPI */ |
| gordon_disp_powerup(); |
| gordon_disp_on(); |
| gordon_state.disp_initialized = TRUE; |
| } |
| return 0; |
| } |
| |
| static int lcdc_gordon_panel_off(struct platform_device *pdev) |
| { |
| if (gordon_state.disp_powered_up && gordon_state.display_on) { |
| serigo(GORDON_REG_LCDIFCTL2, 0x7B); |
| serigo(GORDON_REG_VALTRAN, 0x01); |
| serigo(GORDON_REG_LCDIFCTL1, 0x02); |
| serigo(GORDON_REG_LCDIFCTL3, 0x01); |
| mdelay(20); |
| serigo(GORDON_REG_VALTRAN, 0x01); |
| serigo(GORDON_REG_IMGCTL1, 0x01); |
| serigo(GORDON_REG_LCDIFCTL1, 0x00); |
| mdelay(20); |
| |
| serigo(GORDON_REG_POWCTL, 0x1F); |
| mdelay(40); |
| |
| serigo(GORDON_REG_POWCTL, 0x07); |
| mdelay(40); |
| |
| serigo(GORDON_REG_POWCTL, 0x03); |
| mdelay(40); |
| |
| serigo(GORDON_REG_POWCTL, 0x00); |
| mdelay(40); |
| lcdc_gordon_pdata->panel_config_gpio(0); |
| gordon_state.display_on = FALSE; |
| gordon_state.disp_initialized = FALSE; |
| } |
| return 0; |
| } |
| |
| static void lcdc_gordon_set_backlight(struct msm_fb_data_type *mfd) |
| { |
| int bl_level = mfd->bl_level; |
| |
| if (bl_level <= 1) { |
| /* keep back light OFF */ |
| serigo(GORDON_REG_LCDIFCTL2, 0x0B); |
| udelay(15); |
| serigo(GORDON_REG_VALTRAN, 0x01); |
| } else { |
| /* keep back light ON */ |
| serigo(GORDON_REG_LCDIFCTL2, 0x7B); |
| udelay(15); |
| serigo(GORDON_REG_VALTRAN, 0x01); |
| } |
| } |
| |
| static int __init gordon_probe(struct platform_device *pdev) |
| { |
| if (pdev->id == 0) { |
| lcdc_gordon_pdata = pdev->dev.platform_data; |
| return 0; |
| } |
| msm_fb_add_device(pdev); |
| return 0; |
| } |
| |
| static struct platform_driver this_driver = { |
| .probe = gordon_probe, |
| .driver = { |
| .name = "lcdc_gordon_vga", |
| }, |
| }; |
| |
| static struct msm_fb_panel_data gordon_panel_data = { |
| .on = lcdc_gordon_panel_on, |
| .off = lcdc_gordon_panel_off, |
| .set_backlight = lcdc_gordon_set_backlight, |
| }; |
| |
| static struct platform_device this_device = { |
| .name = "lcdc_gordon_vga", |
| .id = 1, |
| .dev = { |
| .platform_data = &gordon_panel_data, |
| } |
| }; |
| |
| static int __init lcdc_gordon_panel_init(void) |
| { |
| int ret; |
| struct msm_panel_info *pinfo; |
| |
| #ifdef CONFIG_FB_MSM_TRY_MDDI_CATCH_LCDC_PRISM |
| if (msm_fb_detect_client("lcdc_gordon_vga")) |
| return 0; |
| #endif |
| ret = platform_driver_register(&this_driver); |
| if (ret) |
| return ret; |
| |
| pinfo = &gordon_panel_data.panel_info; |
| pinfo->xres = 480; |
| pinfo->yres = 640; |
| pinfo->type = LCDC_PANEL; |
| pinfo->pdest = DISPLAY_1; |
| pinfo->wait_cycle = 0; |
| pinfo->bpp = 24; |
| pinfo->fb_num = 2; |
| pinfo->clk_rate = 24500000; |
| pinfo->bl_max = 4; |
| pinfo->bl_min = 1; |
| |
| pinfo->lcdc.h_back_porch = 84; |
| pinfo->lcdc.h_front_porch = 33; |
| pinfo->lcdc.h_pulse_width = 60; |
| pinfo->lcdc.v_back_porch = 0; |
| pinfo->lcdc.v_front_porch = 2; |
| pinfo->lcdc.v_pulse_width = 2; |
| pinfo->lcdc.border_clr = 0; /* blk */ |
| pinfo->lcdc.underflow_clr = 0xff; /* blue */ |
| pinfo->lcdc.hsync_skew = 0; |
| |
| ret = platform_device_register(&this_device); |
| if (ret) |
| platform_driver_unregister(&this_driver); |
| |
| return ret; |
| } |
| |
| module_init(lcdc_gordon_panel_init); |