nuc972一个spi口接两片flash

nuc972一个spi口接两片flash

nuc972的spi支持两个从设备选择线,挂载两个spi flash后可以实现自动切换,不需要手动的拉低片选,功能已经在源码中做好了,需要我们在make menuconfig中配置好,还要在arch/arm/mach-nuc970/dev.c中添加设备数据,这样就支持两片flash正常工作了。最后添加Quad模式。具体操作如下

在文件drivers/spi/spi-nuc970-p0.c中控制spi从设备的代码部分如下

static inline void nuc970_slave_select(struct spi_device *spi, unsigned int ssr)
{
	struct nuc970_spi *hw = (struct nuc970_spi *)to_hw(spi);
	unsigned int val;
	unsigned int cs = spi->mode & SPI_CS_HIGH ? 1 : 0;
	unsigned long flags;

	spin_lock_irqsave(&hw->lock, flags);

	val = __raw_readl(hw->regs + REG_SSR);
			   
	if (!cs)
		val &= ~SELECTLEV;
	else
		val |= SELECTLEV;

	if(spi->chip_select == 0) {        
		if (!ssr)
			val &= ~SELECTSLAVE0;
		else
			val |= SELECTSLAVE0;
	} else {
		if (!ssr)
			val &= ~SELECTSLAVE1;
		else
			val |= SELECTSLAVE1;
	}

	__raw_writel(val, hw->regs + REG_SSR);

	spin_unlock_irqrestore(&hw->lock, flags);
}

static inline void nuc970_spi0_chipsel(struct spi_device *spi, int value)
{
	switch (value) {
	case BITBANG_CS_INACTIVE:
		nuc970_slave_select(spi, 0);
		break;

	case BITBANG_CS_ACTIVE:
		nuc970_slave_select(spi, 1);
		break;
	}
}

通过向SSR寄存器写入数据选择使用哪个spi flash,nuc970_spi0_chipsel函数控制slave device失能还是使能。nuc970_slave_select函数控制选择哪个设备,具体由spi->chip_select 的值决定。

在arch/arm/mach-nuc970/dev.c中添加设备信息

#if defined(CONFIG_SPI_NUC970_P0) || defined(CONFIG_SPI_NUC970_P0_MODULE)
/* spi device, spi flash info */
#ifdef CONFIG_MTD_M25P80
static struct mtd_partition nuc970_spi0_flash_partitions[] = {
 #ifdef CONFIG_BOARD_ETH2UART
         {
                .name = "kernel",
                .size = 0x0800000,
                .offset = 0x1000000,
        },
        {
                .name = "rootfs",
                .size = 0x0800000,
                .offset = 0x1800000,
        },
 #else
       /* {
                .name = "kernel",
                .size = 0x0400000,
                .offset = 0x200000,
        },
        {
                .name = "rootfs",
                .size = 0x0200000,
                .offset = 0x0600000,
        },*/
        {
                .name = "data",
                .size = 0x1000000,
                .offset = 0x0F00000,
        },
 #endif
};
static struct mtd_partition nuc970_spi0_1_flash_partitions[] = {
#ifdef CONFIG_BOARD_ETH2UART
         {
                .name = "kernel",
                .size = 0x0800000,
                .offset = 0x1000000,
        },
        {
                .name = "rootfs",
                .size = 0x0800000,
                .offset = 0x1800000,
        },
#else 
	{
		.name = "app_data",
		.size = 0x2000000,
		.offset = 0,
	},
#endif
};
static struct flash_platform_data nuc970_spi0_flash_data = {
/*#if 0
        .name = "m25p80",
        .parts =  nuc970_spi0_flash_partitions,
        .nr_parts = ARRAY_SIZE(nuc970_spi0_flash_partitions),
        .type = "w25q128",   
#endif*/
#if 1
        .name = "m25p80",
        .parts =  nuc970_spi0_flash_partitions,
        .nr_parts = ARRAY_SIZE(nuc970_spi0_flash_partitions),
        .type = "gd25q256d",     
#endif
};
static struct flash_platform_data nuc970_spi0_1_flash_data = {
        .name = "m25p80",
        .parts =  nuc970_spi0_1_flash_partitions,
        .nr_parts = ARRAY_SIZE(nuc970_spi0_1_flash_partitions),
        .type = "gd25q256d",     
};
#endif

static struct spi_board_info nuc970_spi0_board_info[] __initdata = {
#ifdef CONFIG_MTD_M25P80        
     {
                .modalias = "m25p80",
                .max_speed_hz = 15000000,
                .bus_num = 0,
                .chip_select = 0,       //use SS0
                .platform_data = &nuc970_spi0_flash_data,
 #if defined(CONFIG_SPI_NUC970_P0_NORMAL)
                .mode = (SPI_MODE_0 | SPI_RX_DUAL | SPI_TX_DUAL),
 #elif defined(CONFIG_SPI_NUC970_P0_QUAD) 
                .mode = (SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD),
 #endif
    },
	{
                .modalias = "m25p80",
                .max_speed_hz = 15000000,
                .bus_num = 0,
                .chip_select = 1,       //use SS0
                .platform_data = &nuc970_spi0_1_flash_data,
 #if defined(CONFIG_SPI_NUC970_P0_NORMAL)
                .mode = (SPI_MODE_0 | SPI_RX_DUAL | SPI_TX_DUAL),
 #elif defined(CONFIG_SPI_NUC970_P0_QUAD) 
                .mode = (SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD),
 #endif 
	},
 #endif	
#ifdef CONFIG_SPI_SPIDEV
        {
                .modalias = "spidev",
                .max_speed_hz = 75000000,
                .bus_num = 0,
                .chip_select = 1,       //use SS1
                .mode = SPI_MODE_0,
        },
#endif
};

static struct nuc970_spi_info nuc970_spi0_platform_data = {
        .num_cs		= 2,
        .lsb		= 0,
        .txneg		= 1,
        .rxneg		= 0,
        .divider	= 4,
        .sleep		= 0,
        .txnum		= 0,
        .txbitlen	= 8,
        .bus_num	= 0,
};

static struct resource nuc970_spi0_resource[] = {
        [0] = {
                .start = NUC970_PA_SPI0,
                .end   = NUC970_PA_SPI0 + NUC970_SZ_SPI0 - 1,
                .flags = IORESOURCE_MEM,
        },
        [1] = {
                .start = IRQ_SPI0,
                .end   = IRQ_SPI0,
                .flags = IORESOURCE_IRQ,
        }
};

nuc970_spi0_1_flash_partitions、nuc970_spi0_1_flash_data这两部分和下面这部分是我自己的添加的(就是把以前存在的复制出来修改修改就可以了)

{
                .modalias = "m25p80",
                .max_speed_hz = 15000000,
                .bus_num = 0,
                .chip_select = 1,       //use SS0
                .platform_data = &nuc970_spi0_1_flash_data,
 #if defined(CONFIG_SPI_NUC970_P0_NORMAL)
                .mode = (SPI_MODE_0 | SPI_RX_DUAL | SPI_TX_DUAL),
 #elif defined(CONFIG_SPI_NUC970_P0_QUAD) 
                .mode = (SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD),
 #endif 
	}

到这基本就完成了,这次踩了个坑,开始把spi驱动编译成模块的时候,第二片选引脚的不能使能,导致第二片选一直是高电平,后来尝试了一下编译进内核,既然就可以了。在程序中也就是要执行这个p = devm_pinctrl_get_select(&pdev->dev, “spi0-ss1-PH”)才可以。此次使用的是PH12。

#if defined(CONFIG_OF)
	p = devm_pinctrl_get_select_default(&pdev->dev);
#else
 #if defined(CONFIG_SPI_NUC970_P0_NORMAL) && !defined(CONFIG_SPI_NUC970_P0_SS1)
	p = devm_pinctrl_get_select(&pdev->dev, "spi0");
 #elif defined(CONFIG_SPI_NUC970_P0_NORMAL) && defined(CONFIG_SPI_NUC970_P0_SS1_PB0)
	p = devm_pinctrl_get_select(&pdev->dev, "spi0-ss1-PB");
 #elif defined(CONFIG_SPI_NUC970_P0_NORMAL) && defined(CONFIG_SPI_NUC970_P0_SS1_PH12)
	p = devm_pinctrl_get_select(&pdev->dev, "spi0-ss1-PH");
 #elif defined(CONFIG_SPI_NUC970_P0_QUAD) && !defined(CONFIG_SPI_NUC970_P0_SS1)
	p = devm_pinctrl_get_select(&pdev->dev, "spi0-quad");	
 #elif defined(CONFIG_SPI_NUC970_P0_QUAD) && defined(CONFIG_SPI_NUC970_P0_SS1_PB0)
	p = devm_pinctrl_get_select(&pdev->dev, "spi0-quad-ss1-PB");
 #elif defined(CONFIG_SPI_NUC970_P0_QUAD) && defined(CONFIG_SPI_NUC970_P0_SS1_PH12)
	p = devm_pinctrl_get_select(&pdev->dev, "spi0-quad-ss1-PH");
 #endif
#endif

编译烧录进内核就可以看到 多了“Creating MTD partitions on “m25p80””,加粗部分是添加后打印的。
nuc970-spi0 nuc970-spi0: master is unqueued, this is deprecated
m25p80: Enable Quad Mode
m25p80 spi0.0: gd25q256d (32768 Kbytes)
Creating 1 MTD partitions on “m25p80”:
0x000001000000-0x000002000000 : “app_data”
m25p80: Enable Quad Mode
m25p80 spi0.1: gd25q256d (32768 Kbytes)
Creating 1 MTD partitions on “m25p80”:
0x000000000000-0x000002000000 : "log_data"

spi-flash驱动还是用到了这些文件drivers/mtd/devices/m25p80.c,这个主要是添加自己所使用flash的信息。
完成上面的工作之后,开机可以在/dev/下能看到mtdblock的块分区,但是挂载时提示无效的参数,虽然看到设备节点了但还没有正确的驱动Flash。做如下修改,在drivers/mtd/devices/m25p80.c的set_quad_mode和set_4byte中添加GD25Q256D的代码
完整的set_4byte(gagiDevice部分为添加内容,CFI_MFR_GD定义在include\linux\mtd\cfi.h)

static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
{
	switch (JEDEC_MFR(jedec_id)) {
	case CFI_MFR_MACRONIX:
	case 0xEF /* winbond */:
	case CFI_MFR_EON: /* cFeon */
	case CFI_MFR_GD:/*Gagi device*/
		flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
		return spi_write(flash->spi, flash->command, 1);
	default:
		/* Spansion style */
		flash->command[0] = OPCODE_BRWR;
		flash->command[1] = enable << 7;
		return spi_write(flash->spi, flash->command, 2);
	}
}

完整的set_quad_mode

static int set_quad_mode(struct m25p *flash, u32 jedec_id)
{
    int status;

    switch (JEDEC_MFR(jedec_id)) {
	case CFI_MFR_GD: /*Gagidevice*/
	    status = gigadevice_quad_enable(flash);
	    if(status) {
	       dev_err(&flash->spi->dev,"giga quad-read not enabled\n");
	       return -EINVAL;
	    }
        case 0xEF:  /* Winbond */
            status = winbond_quad_enable(flash);
            if (status) {
                dev_err(&flash->spi->dev,
                    "Winbond quad-read not enabled\n");
                return -EINVAL;
            }
        default:
            status = winbond_quad_enable(flash);
            if (status) {
                dev_err(&flash->spi->dev,
                    "Winbond quad-read not enabled\n");
                return -EINVAL;
            }
        return status;
    }
}

上面代码使用到了gigadevice_quad_enable,复制winbond_quad_enable的内容到gigadevice_quad_enable如下:

static int gigadevice_quad_enable(struct m25p *flash)
{
    int ret, val;
    u8 cmd[3];
    u8 code;

    /* write enable for volatile status register */
    code = OPCODE_WRSR_VOL;
    spi_write(flash->spi,&code ,1);

    /* write status register */
    cmd[0] = OPCODE_RDSR2;
    val = read_sr2_winbond(flash);
    cmd[1] = val | SR_QUAD_EN_WB;
    spi_write(flash->spi, &cmd, 2);

    if(wait_till_ready(flash))
        return	1;
    ret = read_sr2_winbond(flash);
    if(!(ret > 0 &&(ret & SR_QUAD_EN_WB))) {
      dev_err(&flash->spi->dev,"gagidevice Quad bit not set\n");
      return -EINVAL;
    }

    write_disable(flash);

    return 0;
}

重新烧录挂载,成功。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值