526 lines
11 KiB
C
526 lines
11 KiB
C
/* extdrv/interface/ssp/hi_ssp.c
|
||
*
|
||
* Copyright (c) 2006 Hisilicon Co., Ltd.
|
||
*
|
||
* 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;
|
||
*
|
||
* History:
|
||
* 21-April-2006 create this file
|
||
*/
|
||
|
||
#include <linux/kernel.h>
|
||
#include <linux/version.h>
|
||
#include <linux/module.h>
|
||
#include <linux/types.h>
|
||
#include <linux/errno.h>
|
||
#include <linux/fcntl.h>
|
||
#include <linux/mm.h>
|
||
#include <linux/proc_fs.h>
|
||
#include <linux/fs.h>
|
||
#include <linux/slab.h>
|
||
#include <linux/init.h>
|
||
#include <asm/uaccess.h>
|
||
#include <asm/io.h>
|
||
#include <asm/system.h>
|
||
#include <linux/miscdevice.h>
|
||
#include <linux/delay.h>
|
||
|
||
#include <linux/proc_fs.h>
|
||
#include <linux/poll.h>
|
||
|
||
#include <asm/bitops.h>
|
||
#include <asm/uaccess.h>
|
||
#include <asm/irq.h>
|
||
|
||
#include <linux/moduleparam.h>
|
||
#include <linux/ioport.h>
|
||
#include <linux/interrupt.h>
|
||
|
||
|
||
#include "hi_ssp.h"
|
||
|
||
#define ssp_readw(addr,ret) (ret =(*(volatile unsigned int *)(addr)))
|
||
#define ssp_writew(addr,value) ((*(volatile unsigned int *)(addr)) = (value))
|
||
|
||
#define HI_REG_READ(addr,ret) (ret =(*(volatile unsigned int *)(addr)))
|
||
#define HI_REG_WRITE(addr,value) ((*(volatile unsigned int *)(addr)) = (value))
|
||
|
||
#define SSP_BASE 0x200E0000
|
||
#define SSP_SIZE 0x10000 // 64KB
|
||
#define SSP_INT 65 // Interrupt No.
|
||
|
||
void __iomem* reg_ssp_base_va;
|
||
#define IO_ADDRESS_VERIFY(x) (reg_ssp_base_va + ((x)-(SSP_BASE)))
|
||
|
||
/* SSP register definition .*/
|
||
#define SSP_CR0 IO_ADDRESS_VERIFY(SSP_BASE + 0x00)
|
||
#define SSP_CR1 IO_ADDRESS_VERIFY(SSP_BASE + 0x04)
|
||
#define SSP_DR IO_ADDRESS_VERIFY(SSP_BASE + 0x08)
|
||
#define SSP_SR IO_ADDRESS_VERIFY(SSP_BASE + 0x0C)
|
||
#define SSP_CPSR IO_ADDRESS_VERIFY(SSP_BASE + 0x10)
|
||
#define SSP_IMSC IO_ADDRESS_VERIFY(SSP_BASE + 0x14)
|
||
#define SSP_RIS IO_ADDRESS_VERIFY(SSP_BASE + 0x18)
|
||
#define SSP_MIS IO_ADDRESS_VERIFY(SSP_BASE + 0x1C)
|
||
#define SSP_ICR IO_ADDRESS_VERIFY(SSP_BASE + 0x20)
|
||
#define SSP_DMACR IO_ADDRESS_VERIFY(SSP_BASE + 0x24)
|
||
|
||
|
||
|
||
|
||
void hi_ssp_writeOnly(int bWriteOnly)
|
||
{
|
||
int ret = 0;
|
||
|
||
bWriteOnly = 0;
|
||
|
||
ssp_readw(SSP_CR1, ret);
|
||
|
||
if (bWriteOnly)
|
||
{
|
||
ret = ret | (0x1 << 5);
|
||
}
|
||
else
|
||
{
|
||
ret = ret & (~(0x1 << 5));
|
||
}
|
||
|
||
ssp_writew(SSP_CR1, ret);
|
||
}
|
||
|
||
|
||
void hi_ssp_enable(void)
|
||
{
|
||
int ret = 0;
|
||
ssp_readw(SSP_CR1, ret);
|
||
ret = (ret & 0xFFFD) | 0x2;
|
||
|
||
ret = ret | (0x1 << 4); /* big/little end, 1: little, 0: big */
|
||
|
||
ret = ret | (0x1 << 15); /* wait en */
|
||
|
||
ssp_writew(SSP_CR1, ret);
|
||
|
||
hi_ssp_writeOnly(0);
|
||
}
|
||
|
||
|
||
void hi_ssp_disable(void)
|
||
{
|
||
int ret = 0;
|
||
ssp_readw(SSP_CR1, ret);
|
||
ret = ret & (~(0x1 << 1));
|
||
ssp_writew(SSP_CR1, ret);
|
||
}
|
||
|
||
int hi_ssp_set_frameform(unsigned char framemode, unsigned char spo, unsigned char sph, unsigned char datawidth)
|
||
{
|
||
int ret = 0;
|
||
ssp_readw(SSP_CR0, ret);
|
||
if (framemode > 3)
|
||
{
|
||
printk("set frame parameter err.\n");
|
||
return -1;
|
||
}
|
||
ret = (ret & 0xFFCF) | (framemode << 4);
|
||
if ((ret & 0x30) == 0)
|
||
{
|
||
if (spo > 1)
|
||
{
|
||
printk("set spo parameter err.\n");
|
||
return -1;
|
||
}
|
||
if (sph > 1)
|
||
{
|
||
printk("set sph parameter err.\n");
|
||
return -1;
|
||
}
|
||
ret = (ret & 0xFF3F) | (sph << 7) | (spo << 6);
|
||
}
|
||
if ((datawidth > 16) || (datawidth < 4))
|
||
{
|
||
printk("set datawidth parameter err.\n");
|
||
return -1;
|
||
}
|
||
ret = (ret & 0xFFF0) | (datawidth - 1);
|
||
ssp_writew(SSP_CR0, ret);
|
||
return 0;
|
||
}
|
||
|
||
|
||
int hi_ssp_set_serialclock(unsigned char scr, unsigned char cpsdvsr)
|
||
{
|
||
int ret = 0;
|
||
ssp_readw(SSP_CR0, ret);
|
||
ret = (ret & 0xFF) | (scr << 8);
|
||
ssp_writew(SSP_CR0, ret);
|
||
if ((cpsdvsr & 0x1))
|
||
{
|
||
printk("set cpsdvsr parameter err.\n");
|
||
return -1;
|
||
}
|
||
ssp_writew(SSP_CPSR, cpsdvsr);
|
||
return 0;
|
||
}
|
||
|
||
int hi_ssp_alt_mode_set(int enable)
|
||
{
|
||
int ret = 0;
|
||
|
||
ssp_readw(SSP_CR1, ret);
|
||
if (enable)
|
||
{
|
||
ret = ret & (~0x40);
|
||
}
|
||
else
|
||
{
|
||
ret = (ret & 0xFF) | 0x40;
|
||
}
|
||
ssp_writew(SSP_CR1, ret);
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
void hi_ssp_writedata(unsigned short sdata)
|
||
{
|
||
ssp_writew(SSP_DR, sdata);
|
||
udelay(2);
|
||
}
|
||
|
||
int hi_ssp_readdata(void)
|
||
{
|
||
int ret = 0;
|
||
ssp_readw(SSP_DR, ret);
|
||
return ret;
|
||
}
|
||
|
||
|
||
static void spi_enable(void)
|
||
{
|
||
HI_REG_WRITE(SSP_CR1, 0x42);
|
||
}
|
||
|
||
static void spi_disable(void)
|
||
{
|
||
HI_REG_WRITE(SSP_CR1, 0x40);
|
||
}
|
||
|
||
|
||
int hi_ssp_lcd_init_cfg(void)
|
||
{
|
||
unsigned char framemode = 0;
|
||
unsigned char spo = 1;
|
||
unsigned char sph = 1;
|
||
unsigned char datawidth = 9;
|
||
|
||
#ifdef HI_FPGA
|
||
unsigned char scr = 1;
|
||
unsigned char cpsdvsr = 2;
|
||
#else
|
||
unsigned char scr = 8;
|
||
unsigned char cpsdvsr = 8;
|
||
#endif
|
||
|
||
spi_disable();
|
||
|
||
hi_ssp_set_frameform(framemode, spo, sph, datawidth);
|
||
|
||
hi_ssp_set_serialclock(scr, cpsdvsr);
|
||
|
||
hi_ssp_alt_mode_set(1);
|
||
|
||
hi_ssp_enable();
|
||
|
||
return 0;
|
||
}
|
||
|
||
void spi_write_a9byte(unsigned char cmd_dat, unsigned char dat)
|
||
{
|
||
unsigned short spi_data = 0;
|
||
|
||
if (cmd_dat)
|
||
{
|
||
spi_data = 1 << 8;
|
||
}
|
||
else
|
||
{
|
||
spi_data = 0 << 8;
|
||
}
|
||
|
||
spi_data = spi_data | dat;
|
||
spi_enable();
|
||
//hi_ssp_writedata(spi_data);
|
||
ssp_writew(SSP_DR, spi_data);
|
||
printk("spi_data:0x%x\n", spi_data);
|
||
msleep(10);
|
||
spi_disable();
|
||
}
|
||
|
||
void spi_write_a16byte(unsigned short spi_dat)
|
||
{
|
||
spi_enable();
|
||
//hi_ssp_writedata(spi_data);
|
||
ssp_writew(SSP_DR, spi_dat);
|
||
printk("spi_data:0x%x\n", spi_dat);
|
||
msleep(10);
|
||
spi_disable();
|
||
}
|
||
|
||
void ssp_write_dat(unsigned char dat)
|
||
{
|
||
spi_write_a9byte(1, dat);
|
||
}
|
||
|
||
void ssp_write_cmd(unsigned char dat)
|
||
{
|
||
spi_write_a9byte(0, dat);
|
||
}
|
||
|
||
long ssp_lcd_ioctl(struct file* file, unsigned int cmd, unsigned long arg)
|
||
{
|
||
unsigned char val;
|
||
unsigned short val_16;
|
||
|
||
switch (cmd)
|
||
{
|
||
case SSP_LCD_READ_ALT:
|
||
|
||
break;
|
||
|
||
case SSP_LCD_WRITE_CMD:
|
||
val = *(unsigned int*)arg;
|
||
spi_write_a9byte(0, val);
|
||
//printk("SSP_LCD_WRITE_CMD!\n");
|
||
break;
|
||
|
||
case SSP_LCD_WRITE_DAT:
|
||
val = *(unsigned int*)arg;
|
||
spi_write_a9byte(1, val);
|
||
break;
|
||
|
||
case SSP_LCD_WRITE_CMD16:
|
||
val_16 = *(unsigned int*)arg;
|
||
spi_write_a16byte(val_16);
|
||
break;
|
||
|
||
default:
|
||
{
|
||
printk("Kernel: No such ssp command %#x!\n", cmd);
|
||
return -1;
|
||
}
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
int ssp_lcd_open(struct inode* inode, struct file* file)
|
||
{
|
||
return 0;
|
||
}
|
||
int ssp_lcd_close(struct inode* inode, struct file* file)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
|
||
static struct file_operations ssp_lcd_fops =
|
||
{
|
||
.owner = THIS_MODULE,
|
||
.unlocked_ioctl = ssp_lcd_ioctl,
|
||
.open = ssp_lcd_open,
|
||
.release = ssp_lcd_close
|
||
};
|
||
|
||
|
||
static struct miscdevice ssp_lcd_dev =
|
||
{
|
||
.minor = MISC_DYNAMIC_MINOR,
|
||
.name = "ssp_lcd",
|
||
.fops = &ssp_lcd_fops,
|
||
};
|
||
|
||
void lcd_ili9342c_init_horizontal_all(void)
|
||
{
|
||
/*spi_9bit_setting*/
|
||
unsigned char framemode = 0;
|
||
unsigned char spo = 1;
|
||
unsigned char sph = 1;
|
||
unsigned char datawidth = 9;
|
||
#ifdef HI_FPGA
|
||
unsigned char scr = 1;
|
||
unsigned char cpsdvsr = 2;
|
||
#else
|
||
unsigned char scr = 8;
|
||
unsigned char cpsdvsr = 8;
|
||
#endif
|
||
spi_disable();
|
||
hi_ssp_set_frameform(framemode, spo, sph, datawidth);
|
||
hi_ssp_set_serialclock(scr, cpsdvsr);
|
||
hi_ssp_alt_mode_set(1);
|
||
hi_ssp_enable();
|
||
ssp_write_cmd(0xC8); //Set EXTC
|
||
ssp_write_dat(0xFF);
|
||
ssp_write_dat(0x93);
|
||
ssp_write_dat(0x42);
|
||
|
||
ssp_write_cmd(0xB6);
|
||
ssp_write_dat(0x0a);
|
||
ssp_write_dat(0xE0);//SS GS
|
||
|
||
ssp_write_cmd(0x36); //Memory Access Control
|
||
ssp_write_dat(0xc8); //MY,MX,MV,ML,BGR,MH c8
|
||
|
||
ssp_write_cmd(0xC0); //Power Control 1
|
||
ssp_write_dat(0x12); //VRH[5:0]
|
||
ssp_write_dat(0x10); //VC[3:0]
|
||
|
||
ssp_write_cmd(0xC1); //Power Control 2
|
||
ssp_write_dat(0x35); //SAP[2:0],BT[3:0]
|
||
|
||
ssp_write_cmd(0xC5); //VCOM
|
||
ssp_write_dat(0XE8); //C8++
|
||
|
||
ssp_write_cmd(0xB1);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x1C);
|
||
|
||
ssp_write_cmd(0xB4);
|
||
ssp_write_dat(0x02);
|
||
|
||
|
||
|
||
//*****************GAMMA*****************
|
||
ssp_write_cmd(0xE0);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x05);
|
||
ssp_write_dat(0x05);
|
||
ssp_write_dat(0x05);
|
||
ssp_write_dat(0x13);
|
||
ssp_write_dat(0x0A);
|
||
ssp_write_dat(0x30);
|
||
ssp_write_dat(0x9A);
|
||
ssp_write_dat(0x43);
|
||
ssp_write_dat(0x08);
|
||
ssp_write_dat(0x0F);
|
||
ssp_write_dat(0x0B);
|
||
ssp_write_dat(0x16);
|
||
ssp_write_dat(0x1A);
|
||
ssp_write_dat(0x0F);
|
||
|
||
|
||
ssp_write_cmd(0xE1);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x25);
|
||
ssp_write_dat(0x29);
|
||
ssp_write_dat(0x04);
|
||
ssp_write_dat(0x11);
|
||
ssp_write_dat(0x07);
|
||
ssp_write_dat(0x3D);
|
||
ssp_write_dat(0x57);
|
||
ssp_write_dat(0x4F);
|
||
ssp_write_dat(0x05);
|
||
ssp_write_dat(0x0C);
|
||
ssp_write_dat(0x0A);
|
||
ssp_write_dat(0x3A);
|
||
ssp_write_dat(0x3A);
|
||
ssp_write_dat(0x0F);
|
||
|
||
//*************RGB interface set**************
|
||
ssp_write_cmd(0x3A); //Pixel Format Set
|
||
ssp_write_dat(0x66); //18BIT 55 16bit
|
||
|
||
ssp_write_cmd(0xB0); //<2F>˼Ĵ<CBBC><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD>DEN<45><4E>DOCLK<4C><4B>HSYNC<4E><43>VSYNC<4E>ļ<EFBFBD><C4BC>ԣ<EFBFBD><D4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>кܴ<D0BA><DCB4><EFBFBD><EFBFBD><EFBFBD>ϵ,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><D4BC>и<EFBFBD><D0B8><EFBFBD>IC<49><43><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؽ<EFBFBD><D8BD>е<EFBFBD><D0B5><EFBFBD>.
|
||
ssp_write_dat(0xEC);//40,42,60,62,cc<63><63>C0<43><30><EFBFBD>˷<EFBFBD>ӳOK<4F><4B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>PCLK<4C><4B>ʱ<EFBFBD><CAB1>û<EFBFBD><C3BB><EFBFBD><EFBFBD><EFBFBD>Ϻ<EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>صģ<D8B5><C4A3><EFBFBD>ô<EFBFBD>ҵ<EFBFBD>Ϊ<EFBFBD>½<EFBFBD><C2BD><EFBFBD>.
|
||
|
||
ssp_write_cmd(0x0c);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0xd5);
|
||
|
||
ssp_write_cmd(0xF6);//<2F>˼Ĵ<CBBC><C4B4><EFBFBD><EFBFBD><EFBFBD>RGBģʽ<C4A3><CABD>VSYNCģʽ<C4A3>ӿڣ<D3BF>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>16<31><36>18BIT <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||
ssp_write_dat(0x01);//01
|
||
ssp_write_dat(0x10);
|
||
ssp_write_dat(0x07);//08
|
||
|
||
ssp_write_cmd(0xB5);//<2F>˼Ĵ<CBBC><C4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>LCD<43><44><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݵĵ<DDB5>һλ<D2BB><CEBB>ʲô<CAB2><C3B4>RGB<47><42>ѡ
|
||
ssp_write_dat(0x02);
|
||
ssp_write_dat(0x02);
|
||
ssp_write_dat(0x0a);
|
||
ssp_write_dat(0x12);//HBP<42><50><EFBFBD><EFBFBD>һλ<D2BB><CEBB><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1>RGB<47><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һλ
|
||
|
||
//********Window(<28><><EFBFBD><EFBFBD>/<2F><>ַ)****************
|
||
ssp_write_cmd(0x2A); //320
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x01);
|
||
ssp_write_dat(0x3F);
|
||
|
||
ssp_write_cmd(0x2B); //240
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0x00);
|
||
ssp_write_dat(0xEF);
|
||
//******************************
|
||
ssp_write_cmd(0x11);//Exit Sleep
|
||
msleep(120);
|
||
ssp_write_cmd(0x29);//Display On
|
||
ssp_write_cmd(0x2c);
|
||
|
||
}
|
||
|
||
|
||
|
||
static int __init hi_ssp_lcd_init(void)
|
||
{
|
||
int ret;
|
||
|
||
reg_ssp_base_va = ioremap_nocache((unsigned long)SSP_BASE, (unsigned long)SSP_SIZE);
|
||
if (!reg_ssp_base_va)
|
||
{
|
||
printk("Kernel: ioremap ssp base failed!\n");
|
||
return -ENOMEM;
|
||
}
|
||
|
||
ret = misc_register(&ssp_lcd_dev);
|
||
if (0 != ret)
|
||
{
|
||
printk("Kernel: register ssp_0 device failed!\n");
|
||
return -1;
|
||
}
|
||
|
||
printk("lcd is ili9342 horizontal!\n");
|
||
lcd_ili9342c_init_horizontal_all();
|
||
printk("Kernel: ssp_lcd initial ok!\n");
|
||
|
||
return 0;
|
||
|
||
}
|
||
|
||
static void __exit hi_ssp_lcd_exit(void)
|
||
{
|
||
|
||
hi_ssp_disable();
|
||
|
||
iounmap((void*)reg_ssp_base_va);
|
||
|
||
misc_deregister(&ssp_lcd_dev);
|
||
}
|
||
|
||
|
||
|
||
module_init(hi_ssp_lcd_init);
|
||
module_exit(hi_ssp_lcd_exit);
|
||
|
||
MODULE_LICENSE("GPL");
|
||
|