📄 gspi_io.c
字号:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include "gspi_io.h"
#define FCR_SOC_SPI_BASE 0x1f004000
#define REG_SPCR 0x00
#define REG_SPSR 0x01
#define REG_SPDR 0x02
#define REG_SPER 0x03
#define GPIO_I_23_16 (*((volatile unsigned char *)0xbf004112))
#define GPIO_O_23_16 (*((volatile unsigned char *)0xbf004122))
#define LPB_MISC_CFG (*((volatile unsigned char *)0xbf004140)) //bit 0 ---spi enable
#define GPIO_OE_23_16 (*((volatile unsigned char *)0xbf004102))
#define REG_GPIO_15_8 (*((volatile unsigned char *)0xbf004101))
#define REG_INT_POL (*((volatile unsigned int *)0xbf00320c))
unsigned cached_gpio=0;
gspihost_info_p G_gspiinfo;
int g_dummy_clk_reg = 0x00;
EXPORT_SYMBOL(g_dummy_clk_reg);
int g_dummy_clk_ioport = 0x00;
EXPORT_SYMBOL(g_dummy_clk_ioport);
int g_bus_mode_reg = 0x02;
EXPORT_SYMBOL(g_bus_mode_reg);
#define SPI_DMA_CHAN 1
#define MAX_DMA_SIZE 32768
#define MAX_TIMEOUT 0xff
#define SSP_IRQ 22
#define SFRM_DOWN 0
#define SFRM_UP 1
//1----4 uS
static void my_delay_us(unsigned int count)
{
int i,j;
for(i=0; i<count; i++)
for(j=0; j<400; j++)
;
}
inline void set_cs(int bit)
{
if(bit)
cached_gpio|=(1<<(23-16));
else
cached_gpio &=~(1<<(23-16));
GPIO_O_23_16=cached_gpio;
cached_gpio=GPIO_O_23_16; //flush write to pin
}
static unsigned char spi_writeb(unsigned char value, struct s3c24xx_spi *spi)
{
writeb(value, spi->regs+REG_SPDR);
while ((*(volatile unsigned char *)(0xbf004001))&0x01);
return readb(spi->regs+REG_SPDR);
}
static unsigned char spi_readb(unsigned char value, struct s3c24xx_spi *spi)
{
return spi_writeb(value, spi);
}
//---------------------------------------------------
static inline void
ssp_sfrm(int updown)
{
if (updown == SFRM_DOWN)
GPIO_O_23_16 &= ~(1 << 7); ///Pull SFRM signal down
else
GPIO_O_23_16 |= (1 << 7); ///Pull SFRM signal up
return;
}
/*************************************************************************/
int gspi_read_data_direct(gspi_card_rec_p cardp, u8 * data, u16 reg, u16 n)
{
struct s3c24xx_spi *spi = cardp->ctrlr;
int dummy_clk = g_dummy_clk_reg;
int i;
disable_irq(spi->irq);
ssp_sfrm(SFRM_DOWN);
writeb(0x5c, spi->regs+REG_SPCR); //rising edge send data
{
spi->dma_map[0] = reg >> 8;
spi->dma_map[1] = reg & 0xff;
}
wmb();
{
int i;
for (i = 0; i < 2; i++) {
spi_writeb(spi->dma_map[i], spi);
my_delay_us(2);
//udelay(2);
}
}
my_delay_us(2);
//udelay(2);
writeb(0x58, spi->regs+REG_SPCR); //falling edge sample signal
{ int i;
int count = ((n - 1) * 2);
for (i = 0; i < count; i++) {
spi->dma_map[i] = spi_readb(0xff, spi);
}
}
ssp_sfrm(SFRM_UP);
enable_irq(spi->irq);
for (i = 0; i < (n + dummy_clk - 1); i++) {
*data++ = spi->dma_map[(dummy_clk + i) * 2 + 1];
*data++ = spi->dma_map[(dummy_clk + i) * 2];
}
return 0;
}
EXPORT_SYMBOL(gspi_read_data_direct);
int gspi_write_data_direct(gspi_card_rec_p cardp, u8 * data, u16 reg, u16 n)
{
struct s3c24xx_spi *spi = cardp->ctrlr;
reg |= 0x8000;
disable_irq(spi->irq);
ssp_sfrm(SFRM_DOWN);
writeb(0x5c, spi->regs+REG_SPCR); //rising edge send data
reg |= 0x8000;
{
int i;
spi->dma_map[0] = reg >> 8;
spi->dma_map[1] = reg & 0xff;
for (i = 0; i < (n - 1); i++) {
spi->dma_map[i * 2 + 3] = *data++;
spi->dma_map[i * 2 + 2] = *data++;
}
}
wmb();
{
int i;
n = n * 2;
for (i = 0; i < n; i++) {
spi_writeb(spi->dma_map[i], spi);
}
}
ssp_sfrm(SFRM_UP);
enable_irq(spi->irq);
return 0;
}
EXPORT_SYMBOL(gspi_write_data_direct);
int gspi_read_reg(gspi_card_rec_p cardp, u16 reg, u16 * val)
{
gspi_read_data_direct(cardp, (u8 *)val, reg, 2);
return 0;
}
EXPORT_SYMBOL(gspi_read_reg);
int gspi_write_reg(gspi_card_rec_p cardp, u16 reg, u16 val)
{
gspi_write_data_direct(cardp, (u8 *)&val, reg, 2);
return 0;
}
EXPORT_SYMBOL(gspi_write_reg);
int gspi_register_irq(gspihost_info_p gspiinfo)
{
unsigned int reg;
unsigned char tmp;
int err;
gspi_card_rec_p cardp = gspiinfo->card;
//init irq GPIO-13,
reg = REG_INT_POL; //pole controle register
reg &= ~(1<<22); //low level triger
REG_INT_POL = reg;
tmp = REG_GPIO_15_8; //pin function extint
tmp &= ~(1<<5);
REG_GPIO_15_8 = tmp;
gspiinfo->irq = SSP_IRQ;
err = request_irq(gspiinfo->irq, cardp->user_isr, SA_SHIRQ, "W8686 interrupt", cardp->user_arg);
if (err) {
printk("Cannot claim IRQ %d\n", gspiinfo->irq);
return -1;
}
schedule_timeout(3 * HZ);
return 0;
}
EXPORT_SYMBOL(gspi_register_irq);
void gspi_unregister_irq(gspihost_info_p gspihost)
{
gspi_card_rec_p cardp = gspihost->card;
free_irq(gspihost->irq, cardp->user_arg);
}
EXPORT_SYMBOL(gspi_unregister_irq);
gspi_notifier_rec_p register_user(gspi_notifier_rec_p notifierp)
{
gspi_notifier_rec_p ret;
gspihost_info_p gspiinfo = G_gspiinfo;
gspi_card_rec_p cardp = gspiinfo->card;
if (!notifierp) {
ret = NULL;
goto done;
}
if (!notifierp->add || !notifierp->remove || !notifierp->user_isr) {
ret = NULL;
goto done;
}
cardp->add = notifierp->add;
cardp->remove = notifierp->remove;
cardp->user_isr = notifierp->user_isr;
if (notifierp->add(cardp)) {
ret = NULL;
goto done;
}
ret = notifierp;
done:
return ret;
}
EXPORT_SYMBOL(register_user);
void unregister_user(gspi_notifier_rec_p notifierp)
{
gspihost_info_p gspiinfo = G_gspiinfo;
gspi_card_rec_p cardp = gspiinfo->card;
if (notifierp->add == cardp->add) {
cardp->remove(cardp);
cardp->add = NULL;
cardp->remove = NULL;
cardp->user_isr = NULL;
cardp->user_arg = NULL;
}
}
EXPORT_SYMBOL(unregister_user);
void gspi_reset(void)
{
}
EXPORT_SYMBOL(gspi_reset);
/*************************************************************************/
static int __init
gspihost_module_init(void)
{
int counter=0;
//------------------------------
struct s3c24xx_spi *spi;
gspi_card_rec_p cardp;
int err = 0;
unsigned char tmp;
static int front=0,back=0,i=0,new=0,old=0;
static struct timeval current_tv ={0,0};
int temp[20],test[20];
spi = kmalloc(sizeof(*spi), GFP_KERNEL);
if (spi == NULL){
printk("No memory for spi info\n");
err = -ENOMEM;
goto err_no_mem;
}
G_gspiinfo = spi;
cardp = kmalloc(sizeof(io_card_rec_t), GFP_KERNEL);
if (cardp == NULL){
printk("No memory for card record\n");
err = -ENOMEM;
goto err_no_card_mem;
}
memset(cardp, 0, sizeof(io_card_rec_t));
memcpy(cardp->magic, "GSPI", 4);
cardp->ctrlr = spi;
spi->card = cardp;
//------------------------------
spi->ioarea = request_mem_region(FCR_SOC_SPI_BASE,
4,
"gc3210_spi");
if (spi->ioarea == NULL) {
printk("Cannot reserve region\n");
err = -ENXIO;
goto err_no_iores;
}
spi->regs = ioremap(FCR_SOC_SPI_BASE, 4);
if(spi->regs == NULL) {
err = -ENXIO;
goto err_no_iomap;
}
//printk("spi_base : 0x%x\n", spi->regs);
//fcr_3210 Pin function---SPI
//tmp = GPIO_OE_23_16;
//tmp |= (0x0f<<4);
//GPIO_OE_23_16 = tmp;
tmp=GPIO_OE_23_16;
tmp|=(3<<(20-16))|(1<<(23-16));
tmp&=~(1<<(22-16));
GPIO_OE_23_16=tmp;
cached_gpio=GPIO_O_23_16;
set_cs(1);
//SPI control regsister
writeb(0x5c | 2, spi->regs+REG_SPCR); //disable spi interrupt, mode--0, PH clock=25MHZ
writeb(0, spi->regs+REG_SPER); //25MHZ/2=12.5MHZ
LPB_MISC_CFG |= (1<<0); //SPI controler enabel
//int flag;
//local_irq_save(flag);
printk("<0>new udelay-----%ld\n",cpu_data[0].udelay_val);
while(1) {
writeb(0xff, spi->regs+REG_SPDR);
readb(spi->regs+REG_SPDR);
do_gettimeofday(¤t_tv);
front=current_tv.tv_usec;
udelay(200);
do_gettimeofday(¤t_tv);
back=current_tv.tv_usec;
if(back>front)
{ i=back-front; } //printk(KERN_ALERT "i:%d\n",i);
else
{ i=(1000000+front)-back; }
test[counter]=i;
writeb(0x00, spi->regs+REG_SPDR);
readb(spi->regs+REG_SPDR);
{ do_gettimeofday(¤t_tv);
front=current_tv.tv_usec;
udelay(400);
do_gettimeofday(¤t_tv);
back=current_tv.tv_usec;
if(back>front)
{ i=back-front; } //printk(KERN_ALERT "i:%d\n",i);
else
{ i=(1000000+front)-back; } //printk(KERN_ALERT "i:%d\n",i);
}
temp[counter]=i;
counter++;
if(counter>=10)
break;
}
//local_irq_restore(flag);
for(counter=0;counter<10;counter++)
printk(KERN_ALERT "test[%d]:%d\n",counter,test[counter]);
for(counter=0;counter<10;counter++)
printk(KERN_ALERT "temp[%d]:%d\n",counter,temp[counter]);
ssp_sfrm(SFRM_UP); //SPI_CS H
//------------------------------------
spi->dma_map = kmalloc(MAX_DMA_SIZE, GFP_KERNEL);
if (!spi->dma_map) {
printk("not enough dma memory!\n");
goto err_no_dma_mem;
}
return 0;
err_no_dma_mem:
err_no_iomap:
release_resource(spi->ioarea);
kfree(spi->ioarea);
err_no_iores:
kfree(cardp);
err_no_card_mem:
kfree(spi);
err_no_mem:
return err;
}
static void
gspihost_exit(gspihost_info_t * gspiinfo)
{
struct s3c24xx_spi *spi = G_gspiinfo;
if (spi) {
kfree(spi->dma_map);
iounmap(spi->regs);
release_resource(spi->ioarea);
kfree(spi->ioarea);
kfree(spi->card);
kfree(spi);
}
//fcr_3210
LPB_MISC_CFG &= ~(1<<0); //SPI disbale
}
static void __exit
gspihost_module_exit(void)
{
gspihost_exit(G_gspiinfo);
printk("GSPI Host Controller Driver for Linux removed.\n");
}
module_init(gspihost_module_init);
module_exit(gspihost_module_exit);
MODULE_DESCRIPTION("Marvell 88W8686 on GC3210M Driver");
MODULE_AUTHOR("grandchips");
MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -