| /* |
| * 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 ¶m; |
| } |