⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gspi_io.c

📁 linux 基于mips 架构cpu 的红外驱动
💻 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(&current_tv);
        	front=current_tv.tv_usec;

		udelay(200);

 		do_gettimeofday(&current_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(&current_tv);

        	front=current_tv.tv_usec;

		udelay(400);	

 		do_gettimeofday(&current_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 + -