blob: ff1ea69e9d09cae89a9059c7d36857494b7cdbc9 [file] [log] [blame]
/*
* drivers/display/lcd/lcd_extern/spi_LD070WS2.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 named License,
* or 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.
*
*/
#include <common.h>
#include <malloc.h>
#include <asm/arch/gpio.h>
#ifdef CONFIG_OF_LIBFDT
#include <libfdt.h>
#endif
#include <amlogic/aml_lcd.h>
#include <amlogic/aml_lcd_extern.h>
#include "lcd_extern.h"
#include "../aml_lcd_common.h"
#include "../aml_lcd_reg.h"
#define LCD_EXTERN_INDEX 1
#define LCD_EXTERN_NAME "spi_LD070WS2"
#define LCD_EXTERN_TYPE LCD_EXTERN_SPI
#define GPIO_SPI_CS 0 /* index */
#define GPIO_SPI_CLK 1 /* index */
#define GPIO_SPI_DATA 2 /* index */
#define SPI_DELAY 30 //unit: us
static struct lcd_extern_config_s *ext_config;
#define LCD_EXTERN_CMD_SIZE 4
static unsigned char init_on_table[] = {
0x00, 0x00, 0x21, 0x00, /* reset */
0x00, 0x00, 0xa5, 0x00, /* standby */
0x00, 0x01, 0x30, 0x00, /* enable FRC/Dither */
0x00, 0x02, 0x40, 0x00, /* enable normally black */
0x00, 0x0e, 0x5f, 0x00, /* enable test mode1 */
0x00, 0x0f, 0xa4, 0x00, /* enable test mode2 */
0x00, 0x0d, 0x00, 0x00, /* enable SDRRS, enlarge OE width */
0x00, 0x02, 0x43, 0x00, /* adjust charge sharing time */
0x00, 0x0a, 0x28, 0x00, /* trigger bias reduction */
0x00, 0x10, 0x41, 50, /* adopt 2 line/1 dot */ /* delay 50ms */
0x00, 0x00, 0xad, 0x00, /* display on */
0xff, 0x00, 0x00, 0x00, /* ending flag */
};
static unsigned char init_off_table[] = {
0x00, 0x00, 0xa5, 0x00, /* standby */
0xff, 0x00, 0x00, 0x00, /* ending flag */
};
static void lcd_extern_set_csb(unsigned v)
{
aml_lcd_extern_set_gpio(ext_config->spi_gpio_cs, v);
udelay(SPI_DELAY);
}
static void lcd_extern_set_scl(unsigned v)
{
aml_lcd_extern_set_gpio(ext_config->spi_gpio_clk, v);
udelay(SPI_DELAY);
}
static void lcd_extern_set_sda(unsigned v)
{
aml_lcd_extern_set_gpio(ext_config->spi_gpio_data, v);
udelay(SPI_DELAY);
}
static void spi_gpio_init(void)
{
lcd_extern_set_csb(1);
lcd_extern_set_scl(1);
lcd_extern_set_sda(1);
}
static void spi_gpio_off(void)
{
lcd_extern_set_sda(0);
lcd_extern_set_scl(0);
lcd_extern_set_csb(0);
}
static void spi_write_8(unsigned char addr, unsigned char data)
{
int i;
unsigned int sdata;
sdata = (unsigned int)(addr & 0x3f);
sdata <<= 10;
sdata |= (data & 0xff);
sdata &= ~(1<<9); //write flag
lcd_extern_set_csb(1);
lcd_extern_set_scl(1);
lcd_extern_set_sda(1);
lcd_extern_set_csb(0);
for (i = 0; i < 16; i++) {
lcd_extern_set_scl(0);
if (sdata & 0x8000)
lcd_extern_set_sda(1);
else
lcd_extern_set_sda(0);
sdata <<= 1;
lcd_extern_set_scl(1);
}
lcd_extern_set_csb(1);
lcd_extern_set_scl(1);
lcd_extern_set_sda(1);
udelay(SPI_DELAY);
}
static int lcd_extern_spi_write(unsigned char *buf, int len)
{
if (len != 2) {
EXTERR("%s: len %d error\n", __func__, len);
return -1;
}
spi_write_8(buf[0], buf[1]);
return 0;
}
static int lcd_extern_power_cmd(unsigned char *init_table, int flag)
{
int i = 0, max_len, step = 0;
unsigned char type, cmd_size;
int ret = 0;
cmd_size = ext_config->cmd_size;
if (cmd_size < 1) {
EXTERR("%s: cmd_size %d is invalid\n", __func__, cmd_size);
return -1;
}
if (cmd_size == LCD_EXTERN_CMD_SIZE_DYNAMIC) {
EXTPR("%s: cmd_size dynamic length to do\n", __func__);
return -1;
}
if (init_table == NULL) {
EXTERR("%s: init_table %d is NULL\n", __func__, flag);
return -1;
}
if (flag)
max_len = LCD_EXTERN_INIT_ON_MAX;
else
max_len = LCD_EXTERN_INIT_OFF_MAX;
while (i <= max_len) {
type = init_table[i];
if (type == LCD_EXTERN_INIT_END)
break;
if (lcd_debug_print_flag) {
EXTPR("%s: step %d: type=0x%02x, cmd_size=%d\n",
__func__, step, type, cmd_size);
}
if (type == LCD_EXTERN_INIT_NONE) {
//do nothing, only for delay
} else if (type == LCD_EXTERN_INIT_GPIO) {
aml_lcd_extern_set_gpio(init_table[i+1], init_table[i+2]);
} else if (type == LCD_EXTERN_INIT_CMD) {
ret = lcd_extern_spi_write(&init_table[i+1], (cmd_size-2));
} else {
EXTERR("%s(%d: %s): pwoer_type %d is invalid\n",
__func__, ext_config->index,
ext_config->name, ext_config->type);
}
if (init_table[i+cmd_size-1] > 0)
mdelay(init_table[i+cmd_size-1]);
step++;
i += cmd_size;
}
return ret;
}
static int lcd_extern_power_ctrl(int flag)
{
int ret = 0;
spi_gpio_init();
if (flag)
ret = lcd_extern_power_cmd(ext_config->table_init_on, 1);
else
ret = lcd_extern_power_cmd(ext_config->table_init_off, 0);
mdelay(10);
spi_gpio_off();
EXTPR("%s(%d: %s): %d\n",
__func__, ext_config->index, ext_config->name, flag);
return ret;
}
static int lcd_extern_power_on(void)
{
int ret;
ret = lcd_extern_power_ctrl(1);
return ret;
}
static int lcd_extern_power_off(void)
{
int ret;
ret = lcd_extern_power_ctrl(0);
return ret;
}
static int lcd_extern_driver_update(struct aml_lcd_extern_driver_s *ext_drv)
{
if (ext_drv == NULL) {
EXTERR("%s driver is null\n", LCD_EXTERN_NAME);
return -1;
}
if (ext_drv->config->type == LCD_EXTERN_MAX) { //default for no dt
ext_drv->config->index = LCD_EXTERN_INDEX;
ext_drv->config->type = LCD_EXTERN_TYPE;
strcpy(ext_drv->config->name, LCD_EXTERN_NAME);
ext_drv->config->spi_gpio_cs = GPIO_SPI_CS;
ext_drv->config->spi_gpio_clk = GPIO_SPI_CLK;
ext_drv->config->spi_gpio_data = GPIO_SPI_DATA;
}
if (ext_drv->config->table_init_loaded == 0) {
ext_drv->config->table_init_on = init_on_table;
ext_drv->config->table_init_off = init_off_table;
}
ext_drv->power_on = lcd_extern_power_on;
ext_drv->power_off = lcd_extern_power_off;
return 0;
}
int aml_lcd_extern_spi_LD070WS2_get_default_index(void)
{
return LCD_EXTERN_INDEX;
}
int aml_lcd_extern_spi_LD070WS2_probe(struct aml_lcd_extern_driver_s *ext_drv)
{
int ret = 0;
ext_config = ext_drv->config;
ret = lcd_extern_driver_update(ext_drv);
if (lcd_debug_print_flag)
EXTPR("%s: %d\n", __func__, ret);
return ret;
}