海思平台gpio模拟spi驱动总结

1. 海思平台gpio如何映射到编号

#define GPIO_TO_PIN(bank, gpio)	(8 * (bank) + (gpio)) 

海思gpio引脚每组总是从0~7,而且引脚从头都有唯一编号;通过上面公式转换到对应编号;

2. spi引脚定义

引脚对应硬件原理图;

//#define GPIO_TO_PIN(bank, gpio)	(8 * (bank) + (gpio))
#include 
#include 

#define SPI_CSN     87     //  gpio10_7;
#define SPI_CLK     86     //  gpio10_6 
#define	SPI_MOSI     52     //  gpio6_4;
#define	SPI_MISO     53     //  gpio6_5;

#define	RESET	    51      //  gpio6_3

//gpio_direction_output为内核函数,参数1:引脚编号   参数2:值(1:输出高;0:输出低)
#define SET_CS_HIGH      gpio_direction_output(SPI_CSN, 1) 
#define SET_CS_LOW       gpio_direction_output(SPI_CSN, 0)

#define SET_SCK_HIGH     gpio_direction_output(SPI_CLK, 1)
#define SET_SCK_LOW      gpio_direction_output(SPI_CLK, 0)

#define SET_MOSI_HIGH     gpio_direction_output(SPI_MOSI, 1)
#define SET_MOSI_LOW      gpio_direction_output(SPI_MOSI, 0)

#define SET_RESET_HIGH	 gpio_direction_output(RESET, 1)	
#define SET_RESET_LOW	 gpio_direction_output(RESET, 0)	


#define GET_MISO         gpio_get_value(SPI_MISO)

3. gpio申请和释放接口

static int  spi_gpio_init(void)
{
    int err = 0;
	
    err = gpio_request(SPI_CSN, "SPI_CSN");
	if (err < 0) {
		printk("gpio failed to request SPI_CSN: %d\n", err);
		goto fail;
	}
	err = gpio_request(SPI_CLK, "SPI_CLK");
	if (err < 0) {
		printk("gpio failed to request SPI_CLK: %d\n", err);
		goto fail;
	}
    err = gpio_request(SPI_MOSI, "SPI_MOSI");
	if (err < 0) {
		printk("gpio failed to request SPI_MOSI: %d\n", err);
		goto fail;
	}
    err = gpio_request(SPI_MISO, "SPI_MISO");
	if (err < 0) {
		printk("gpio failed to request SPI_MISO: %d\n", err);
		goto fail;
	}
	err = gpio_request(RESET, "RESET");
	if (err < 0) {
		printk("gpio failed to request RESET: %d\n", err);
		goto fail;
	}	
	
fail:
	return err;
}

static void spi_gpio_free(void)
{
	gpio_free(SPI_CSN);
	gpio_free(SPI_CLK);
	gpio_free(SPI_MOSI);
	gpio_free(SPI_MISO);
	gpio_free(RESET);
}

4. 读写寄存器

硬件图:
海思平台gpio模拟spi驱动总结_第1张图片

1> 读写前认真分析时序图;弄清楚CPOL和CPHA对应的四种模式,这是读写寄存器实现的关键!!!
2> 读写时需查看是MSB还是LSB优先; 如0x1010 1100 若是LSB优先则先传输低位0;MSB优先则先传输高位1;算法处理不同;

本图以CPOL=1 CPHA=1 LSB first为例:
延时需按照图中st_SI 和hd_SI等给出值处理;

void delay_ms(unsigned int mscount)
{
	mdelay(mscount);		 
}

void delay_us(unsigned char uscount)
{
	  udelay(uscount);	
}

void delay_ns(unsigned char nscount)
{
	  ndelay(nscount);	
}

//CPOL=1 CPHA=1 LSB first
static void spi_send_data(unsigned char addr, unsigned char data)
{
	printk("send addr[%x] data[%x]\n",addr, data);
    unsigned int i;
    //SET_CS_HIGH;
    //SET_SCK_HIGH;
    //SET_MOSI_HIGH;
    //delay_us(20);
    SET_CS_LOW;
    //delay_us(20);
	for (i = 0; i < 8; ++i)
    {
        SET_SCK_LOW;
        //delay_us(10);
        delay_ns(400);
		if (addr & (0x01 << i))
        {
        	//printk("spi send addr high\n");
            SET_MOSI_HIGH;
        } 
        else
        {
        	//printk("spi send addr low\n");
            SET_MOSI_LOW;
        }
        //delay_us(10);
        delay_ns(400);
        SET_SCK_HIGH;
		delay_ns(400);
        //delay_us(10);
    }
	
    for (i = 0; i < 8; ++i)
    {
        SET_SCK_LOW;
        //delay_us(10);
        delay_ns(400);
		if (data & (0x01 << i))
        {
            SET_MOSI_HIGH;
			//printk("spi send data high\n");
        } 
        else
        {
            SET_MOSI_LOW;
			//printk("spi send data low\n");
        }

        //delay_us(10);
        delay_ns(400);
        SET_SCK_HIGH;
		delay_ns(400);
        //delay_us(10);
    }
    SET_CS_HIGH;
    SET_MOSI_HIGH;
}

static unsigned char spi_read_data(void)
{
    unsigned char i,j,front_data;
    unsigned char value = 0;

    SET_CS_HIGH;
    delay_us(20);
    SET_CS_LOW;
	delay_us(20);
	front_data = 0x81;
	for (i = 0; i < 8; ++i)
    {
        SET_SCK_LOW;
        //delay_us(10);
		delay_ns(400);
		if (front_data & (0x01 << i))
        {
            SET_MOSI_HIGH;
			//printk("spi rw addr high\n");
        } 
        else
        {
            SET_MOSI_LOW;
			//printk("spi rw addr low\n");
        }
        //delay_us(10);
        delay_ns(400);
        SET_SCK_HIGH;
        //delay_us(10);
        delay_ns(400);
    }    	
    delay_us(10);
    for(j=0; j<8; j++) // 8 Data
    {
        SET_SCK_LOW;
		delay_ns(400);
        //delay_us(10);
        SET_SCK_HIGH;
		delay_ns(400);
        //delay_us(10);

        printk("read sdi = %d\n", GET_MISO);
        value |= (GET_MISO << j);
		
        //delay_us(10);
        delay_ns(400);
    }
   SET_CS_HIGH;
   return value;      
}

测试时可先写后读,若一致则通信成功;
若通常失败:
(1)可单独控制各个引脚,逐步排查问题所在;
(2) 控制延时,示波器抓波形分析;

相对于ioremap方式,上述方式更简单;

额外补充: ioremap方式

static char* g_reg_crg_base    = 0; 
static char* g_reg_gpio_base   = 0; 

...
static int init_map_reg(void)
{
	g_reg_crg_base = (void*)ioremap(0x12010000, 0x10000);
    if (g_reg_crg_base == NULL) {
        return -1;
    }
    
	g_reg_gpio_base = (void*)ioremap(0x120D0000, 0x10000);
    if (g_reg_gpio_base == NULL) {
        return -1;
    }
}

static void exit_unmap_reg(void)
{
	if (g_reg_crg_base != NULL) {
        iounmap(g_reg_crg_base);
        g_reg_crg_base = 0;
    }
    
	if (g_reg_gpio_base != NULL) {
        iounmap(g_reg_gpio_base);
        g_reg_gpio_base = 0;
    }
}

int init_pin_mux(void)
{
	writel(0x00182c00, g_reg_crg_base + 0x00A0);
	...
	writel(0x20, g_reg_gpio_base + 0x0080);
	...
}

你可能感兴趣的:(海思,goio模拟spi,驱动)