blob: 6db59bdc261041ad0d5bc8993078b5210236c0bd [file] [log] [blame]
#include "asrfb.h"
#include "spi_drv.h"
static struct s_spi_ctx g_spi_ctx;
static void spi_set_dcx(u8 flag)
{
#ifdef CONFIG_FB_ASR_SPI_DCX_GPIO
gpio_direction_output(CONFIG_FB_ASR_SPI_DCX_GPIO, flag);
#else
lcd_write_bits(LCD_SPI_CTRL, flag, MASK1, 31);
#endif
}
static int set_spi_clk(unsigned int src_clk, unsigned int spi_clk)
{
unsigned int dividor;
dividor = src_clk / spi_clk;
if (dividor > 0xFF) {
printf("%s: src_clk/clk can't large than 0xFF\n", __func__);
return -1;
}
lcd_write_bits(LCD_SPI_CTRL, dividor, MASK8, 24);
return 0;
}
static void set_spi_path(struct s_spi_ctx *spi_ctx, unsigned int path)
{
if (path == SPI_PATH_IMAGE)
lcd_set_bits(LCD_MISC_CNTL, BIT_0);
else
lcd_clear_bits(LCD_MISC_CNTL, BIT_0);
spi_ctx->cur_path = path;
}
static void trigger_spi(void)
{
/* polling mode */
u32 reg = 0;
int count = 0;
lcd_set_bits(LCD_SPI_CTRL, BIT_0);
reg = lcd_read(SPU_IRQ_ISR_RAW);
while (!(reg & IRQ_SPI_DONE)) {
count++;
if (count >= 100) {
printf("%s: wait to finish timeout!\n", __func__);
break;
}
udelay(10);
reg = lcd_read(SPU_IRQ_ISR_RAW);
}
lcd_write(SPU_IRQ_ISR_RAW, ~IRQ_SPI_DONE);
lcd_clear_bits(LCD_SPI_CTRL, BIT_0);
}
struct s_spi_ctx *spi_init(unsigned int sclk, struct spi_info *info)
{
int ret;
int dividor;
struct s_spi_ctx *spi_ctx = &g_spi_ctx;
int reg = 0;
if ((info->format != SPI_FORMAT_RGB565) &&
(info->format != SPI_FORMAT_RGB666) && (info->data_lane_num == 1)) {
printf("%s: Format error!\n", __func__);
return NULL;
}
dividor = sclk / info->timing->rclk;
if ((dividor > 0xFF) || (dividor < 2)) {
printf("%s: Invalid read timing!(s:%d, r:%d)\n",
__func__, sclk, info->timing->rclk);
return NULL;
}
dividor = sclk / info->timing->wclk;
if ((dividor > 0xFF) || (dividor < 2)) {
printf("%s: Invalid write timing!(s:%d, w:%d)\n",
__func__, sclk, info->timing->wclk);
return NULL;
}
memset(spi_ctx, 0, sizeof(struct s_spi_ctx));
spi_ctx->base_addr = CONFIG_FB_ASR_REG_BASE;
spi_ctx->sclk = sclk;
memcpy(&spi_ctx->info, info, sizeof(struct spi_info));
if (info->interface_id == 1)
reg |= BIT_1;
if (info->device_id == 1)
reg |= BIT_2;
if (info->endian == SPI_ENDIAN_LSB)
reg |= BIT_5 | BIT_4;
if (info->sample_edge == SPI_EDGE_FALLING)
reg |= BIT_7;
/* enable spi */
reg |= BIT_3;
lcd_write(LCD_SPI_CTRL, reg);
reg = 0;
if (info->line_num == 3)
reg |= BIT_3;
if (info->data_lane_num == 2)
reg |= BIT_2;
reg |= BIT_1; /* should be set, otherwith, color will error */
if (info->format == SPI_FORMAT_RGB666_2_3)
reg |= BIT_5;
else if (info->format == SPI_FORMAT_RGB888_2_3)
reg |= BIT_4;
lcd_write(LCD_MISC_CNTL, reg);
if (info->line_num == 4)
spi_set_dcx(0);
/* spi need set bit13, otherwith will lost some data */
/* spi need set bit6, otherwith color will error */
/* spi need open mcu, otherwidth can't send image data */
//lcd_set_bits(SMPN_CTRL, BIT_13 | BIT_6 | BIT_0);
lcd_set_bits(LCD_SMPN_CTRL, BIT_13 | BIT_0);
switch (info->format) {
case SPI_FORMAT_RGB565:
if (info->data_lane_num == 2) {
lcd_write_bits(LCD_SMPN_CTRL, 5, MASK4, 8);
}
else {
lcd_write_bits(LCD_SMPN_CTRL, 2, MASK4, 8);
}
break;
case SPI_FORMAT_RGB666:
if (info->data_lane_num == 2) {
lcd_write_bits(LCD_SMPN_CTRL, 4, MASK4, 8);
}
else {
lcd_write_bits(LCD_SMPN_CTRL, 1, MASK4, 8);
}
break;
case SPI_FORMAT_RGB666_2_3:
lcd_write_bits(LCD_SMPN_CTRL, 6, MASK4, 8);
break;
case SPI_FORMAT_RGB888:
lcd_write_bits(LCD_SMPN_CTRL, 3, MASK4, 8);
break;
case SPI_FORMAT_RGB888_2_3:
lcd_write_bits(LCD_SMPN_CTRL, 0, MASK4, 8);
break;
default:
printf("%s: Invalid format!\n", __func__);
return NULL;
}
/* set write clk as default */
ret = set_spi_clk(sclk, info->timing->wclk);
if (-1 == ret) {
printf("%s: set spi clk error!\n", __func__);
return NULL;
}
/*set register path as default*/
set_spi_path(spi_ctx, SPI_PATH_REGISTER);
spi_ctx->status = SPI_STATUS_INIT;
return spi_ctx;
}
int spi_set_cs(struct s_spi_ctx *spi_ctx, unsigned int enable)
{
if (spi_ctx->info.force_cs == 0) {
printf("%s: Not force CS mode, can't set CS!\n", __func__);
return -1;
}
if (enable)
lcd_set_bits(LCD_SPI_CTRL, BIT_6);
else
lcd_clear_bits(LCD_SPI_CTRL, BIT_6);
spi_ctx->cur_cs = enable;
return 0;
}
int spi_write_cmd(struct s_spi_ctx *spi_ctx, unsigned int cmd, unsigned int bits)
{
unsigned int wcmd, wbits;
if (spi_ctx->info.force_cs == 1 && spi_ctx->cur_cs == 0) {
printf("%s: Invalid CS status\n", __func__);
return -1;
}
if (spi_ctx->cur_path == SPI_PATH_IMAGE)
set_spi_path(spi_ctx, SPI_PATH_REGISTER);
if (3 == spi_ctx->info.line_num) { /* 3 line mode */
if (bits == 32) {
printf("%s: too many write bits for 3 line mode!\n", __func__);
return -1;
}
wbits = bits + 1;
wcmd = cmd; /* 0 - command, 1 - data */
}
else { /* 4 line mode */
wbits = bits;
wcmd = cmd;
}
if (4 == spi_ctx->info.line_num)
spi_set_dcx(0);
lcd_write(LCD_SPI_TXDATA, wcmd);
lcd_write_bits(LCD_SPI_CTRL, wbits - 1, MASK16, 8);
trigger_spi();
return 0;
}
int spi_write_data(struct s_spi_ctx *spi_ctx, unsigned int data, unsigned int bits)
{
unsigned int wdata, wbits;
if (spi_ctx->info.force_cs == 1 && spi_ctx->cur_cs == 0) {
printf("%s: Invalid CS status\n", __func__);
return -1;
}
if (spi_ctx->cur_path == SPI_PATH_IMAGE)
set_spi_path(spi_ctx, SPI_PATH_REGISTER);
if (3 == spi_ctx->info.line_num) {
if (bits == 32) {
printf("%s: too many write bits for 3 line mode!\n", __func__);
return -1;
}
wbits = bits + 1;
wdata = (1 << bits) | data; /* 0 - command, 1 - data */
}
else { /*4 line mode*/
wbits = bits;
wdata = data;
}
if (4 == spi_ctx->info.line_num)
spi_set_dcx(1);
lcd_write(LCD_SPI_TXDATA, wdata);
lcd_write_bits(LCD_SPI_CTRL, wbits - 1, MASK16, 8);
trigger_spi();
return 0;
}
int spi_read_data(struct s_spi_ctx *spi_ctx, unsigned int cmd, unsigned int cmd_bits,
unsigned int *data, unsigned int data_bits)
{
unsigned int wcmd, wbits, rbits;
int ret;
if (spi_ctx->info.force_cs == 1 && spi_ctx->cur_cs == 0) {
printf("%s: Invalid CS status\n", __func__);
return -1;
}
ret = set_spi_clk(spi_ctx->sclk, spi_ctx->info.timing->rclk);
if (-1 == ret) {
printf("%s: set spi clk error!\n", __func__);
return -1;
}
if (spi_ctx->cur_path == SPI_PATH_IMAGE)
set_spi_path(spi_ctx, SPI_PATH_REGISTER);
if (data_bits > 8)
rbits = data_bits;
else
rbits = data_bits - 1;
if (3 == spi_ctx->info.line_num) {
if (cmd == 32) {
printf("%s: too many write bits for 3 line mode!\n", __func__);
return -1;
}
wbits = cmd_bits;
wcmd = cmd; /* 0 -command, 1-data */
}
else { /* 4 line mode */
wbits = cmd_bits - 1;
wcmd = cmd;
}
if (4 == spi_ctx->info.line_num)
spi_set_dcx(0);
lcd_write(LCD_SPI_TXDATA, wcmd);
lcd_write_bits(LCD_SPI_CTRL, wbits, MASK8, 8);
lcd_write_bits(LCD_SPI_CTRL, rbits, MASK8, 16);
trigger_spi();
*data = lcd_read(LCD_SPI_RXDATA);
/* set write clk as default */
ret = set_spi_clk(spi_ctx->sclk, spi_ctx->info.timing->wclk);
if (-1 == ret) {
printf("%s: spi_read_data, set spi clk error!\n", __func__);
return -1;
}
return 0;
}
int spi_before_refresh(struct s_spi_ctx *spi_ctx)
{
if (spi_ctx->cur_path != SPI_PATH_IMAGE)
set_spi_path(spi_ctx, SPI_PATH_IMAGE);
if (2 == spi_ctx->info.data_lane_num) {
/* 2 data lane */
switch (spi_ctx->info.format) {
case SPI_FORMAT_RGB565:
lcd_write_bits(LCD_SPI_CTRL, 15, MASK8, 8);
break;
case SPI_FORMAT_RGB666:
lcd_write_bits(LCD_SPI_CTRL, 17, MASK8, 8);
break;
case SPI_FORMAT_RGB666_2_3:
lcd_write_bits(LCD_SPI_CTRL, 11, MASK8, 8);
break;
case SPI_FORMAT_RGB888:
lcd_write_bits(LCD_SPI_CTRL, 23, MASK8, 8);
break;
case SPI_FORMAT_RGB888_2_3:
lcd_write_bits(LCD_SPI_CTRL, 15, MASK8, 8);
break;
}
}
else{
/* 1 data lane */
lcd_write_bits(LCD_SPI_CTRL, 7, MASK8, 8);
}
if (4 == spi_ctx->info.line_num)
spi_set_dcx(1);
return 0;
}
int spi_after_refresh(struct s_spi_ctx *spi_ctx)
{
if (spi_ctx->cur_path != SPI_PATH_REGISTER)
set_spi_path(spi_ctx, SPI_PATH_REGISTER);
return 0;
}
void spi_uninit(struct s_spi_ctx *spi_ctx)
{
lcd_write(LCD_SPI_CTRL, 0);
lcd_write(LCD_MISC_CNTL, 0);
spi_ctx->status = SPI_STATUS_UNINIT;
}