加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

设备树学习之(十)spi flash

发布时间:2020-12-15 19:55:37 所属栏目:百科 来源:网络整理
导读:开发板:tiny4412SDK + S702 + 4GB Flash? 要移植的内核版本:Linux-4.4.0 (支持device tree)? u-boot版本:友善之臂自带的 U-Boot 2010.12? busybox版本:busybox 1.25 目标:? 驱动外接的8M的 spi flash,注册为块设备。 设备树: 1 2 3 4 5 6 7 8 9 10

开发板:tiny4412SDK + S702 + 4GB Flash?
要移植的内核版本:Linux-4.4.0 (支持device tree)?
u-boot版本:友善之臂自带的 U-Boot 2010.12?
busybox版本:busybox 1.25

目标:?
驱动外接的8M的 spi flash,注册为块设备。

设备树:

 
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
&spi_0 { status = "okay"; cs-gpios = <&gpb 1 GPIO_ACTIVE_HIGH>; spi_flash@0 { compatible "tiny4412,spi_flash"; spi-max-frequency <10000000>; reg 0>; controller-data { samsung,spi-feedback-delay >; }; }; };

这里指定的 reg = <0> 表示的该 spi 设备引用第一个 cs-gpios?
spi-max-frequency = <10000000>;表示最大速率

代码:

#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/media.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/videodev2.h>
#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-mediabus.h>
#include <media/s5c73m3.h>
#include <media/v4l2-of.h>
#include <linux/mtd/mtd.h>

/* 参考: * driversmtddevicesmtdram.c * drivers/mtd/devices/m25p80.c */

static struct spi_device *spi_flash;

void SPIFlashReadID(int *pMID,int *pDID)
{
    unsigned char tx_buf[4];
    char rx_buf[2];
    //printk("%sn",__func__);
    tx_buf[0] = 0x90;
    tx_buf[1] = 0;
    tx_buf[2] = 3] = 0;
    spi_write_then_read(spi_flash,tx_buf,4,rx_buf,102); box-sizing: border-box;">2);
    *pMID = rx_buf[0];
    *pDID = rx_buf[1];
}

void SPIFlashWriteEnable(int enable)
{
    char val = enable ? 0x06 : 0x04;
    1);
}

char SPIFlashReadStatusReg1(void)
{
    char val;
    char cmd = 0x05;
    1,102); box-sizing: border-box;">1);
    return val;
}

char SPIFlashReadStatusReg2(0x35;
    void SPIFlashWaitWhenBusy(void)
{
    while (SPIFlashReadStatusReg1() & 1)
    {
        /* 休眠一段时间 */
        /* Sector erase time : 60ms * Page program time : 0.7ms * Write status reg time : 10ms */
        set_current_state(TASK_INTERRUPTIBLE);
        schedule_timeout(HZ / 100); /* 休眠10MS后再次判断 */
    }
}

void SPIFlashWriteStatusReg(char reg1,136); box-sizing: border-box;">char reg2)
{
    4];
    1);
    tx_buf[0x01;
    tx_buf[1] = reg1;
    tx_buf[2] = reg2;
    spi_write(spi_flash,102); box-sizing: border-box;">3);
    SPIFlashWaitWhenBusy();
}

void SPIFlashClearProtectForStatusReg(1 << 7);
    reg2 &= ~(0);
    SPIFlashWriteStatusReg(reg1,reg2);
}


void SPIFlashClearProtectForData(/* cmp=0,bp2,1,0=0b000 */
    7 << 2);
    reg2 &= ~(6);
    SPIFlashWriteStatusReg(reg1,reg2);
}

/* erase 4K */
void SPIFlashEraseSector(int addr)
{
    0x20;
    tx_buf[1] = addr >> 16;
    tx_buf[2] = addr >> 8;
    tx_buf[3] = addr & 0xff;
    SPIFlashWriteEnable(1);
    spi_write(spi_flash,102); box-sizing: border-box;">4);
    SPIFlashWaitWhenBusy();
}

/* program */
void SPIFlashProgram(int addr,136); box-sizing: border-box;">char *buf,136); box-sizing: border-box;">int len)
{
    struct spi_transfer t[] =
    {
        {
            .tx_buf     = tx_buf,.len        = struct spi_message  m;
    0x02;
    tx_buf[1);
    spi_message_init(&m);
    spi_message_add_tail(&t[0],&m);
    spi_message_add_tail(&t[1],&m);
    spi_sync(spi_flash,&m);
    SPIFlashWaitWhenBusy();
}

void SPIFlashRead(int len)
{
    /* spi_write_then_read规定了tx_cnt+rx_cnt < 32 * 所以对于大量数据的读取,不能使用该函数 */

    0x03;
    tx_buf[0xff;
    spi_message_init(&m);
    spi_message_add_tail(&t[void SPIFlashInit(void)
{
    SPIFlashClearProtectForStatusReg();
    SPIFlashClearProtectForData();
}




/* 构造注册一个mtd_info * mtd_device_register(master,parts,nr_parts) * */


/* 首先: 构造注册spi_driver * 然后: 在spi_driver的probe函数里构造注册mtd_info */


struct mtd_info spi_flash_dev;

int spi_flash_erase(struct mtd_info *mtd,136); box-sizing: border-box;">struct erase_info *instr)
{
    int addr = instr->addr;
    int len  = 0;

    //判断参数 
    if ((addr & (spi_flash_dev.erasesize - 1)) || (instr->len & (spi_flash_dev.erasesize - 1)))
    {
        printk("spi_flash_erase addr/len is not aligned %x %xn",(int)instr->addr,136); box-sizing: border-box;">int)instr->len);
        return -EINVAL;
    }

    for (len = 0; len < instr->len; len += 4096)
    {
        SPIFlashEraseSector(addr);
        addr += 4096;
    }

    instr->state = MTD_ERASE_DONE;
    mtd_erase_callback(instr);
    return 0;
}

int spi_flash_read(int spi_flash_write(const u_char *buf)
{
    int addr = to;
    int wlen  = 0;
    int i;

    //判断参数
    if ((to & (spi_flash_dev.erasesize - "spi_flash_write addr/len is not aligned %x %xn",136); box-sizing: border-box;">int)to,136); box-sizing: border-box;">int)len);
        return -EINVAL;
    }
    if (len <= 256)
    {
        SPIFlashProgram(addr,136); box-sizing: border-box;">char *)buf,len);
    }
    else
    {
        for (i = 0; i < len / 256; i ++)
        {
            SPIFlashProgram(addr,102); box-sizing: border-box;">256);
            addr += 256;
            buf += 256;
        }
        if (len % 256 != 0)
        {
            SPIFlashProgram(addr,len % 256);
        }
    }

    *retlen = len;
    0;
}


int spi_flash_probe(struct spi_device *spi)
{
    int mid,did,ret;
    spi_flash = spi;
    spi->mode = SPI_MODE_0;
    ret = spi_setup(spi);
    if (ret < 0)
    {
        printk("spi_setup errorn");
    }
    printk("%sn",__func__);


    //s3c2410_gpio_cfgpin(spi->chip_select,S3C2410_GPIO_OUTPUT);
    SPIFlashInit();
    SPIFlashReadID(&mid,&did);
    printk("SPI Flash ID: %02x %02xn",mid,did);

    memset(&spi_flash_dev,102); box-sizing: border-box;">0,136); box-sizing: border-box;">sizeof(spi_flash_dev));

    //Setup the MTD structure
    spi_flash_dev.name = "spi_flash";
    spi_flash_dev.type = MTD_NORFLASH;
    spi_flash_dev.flags = MTD_CAP_NORFLASH;
    spi_flash_dev.size = 0x800000; 
    spi_flash_dev.writesize = 1;
    spi_flash_dev.writebufsize = 4096; 
    spi_flash_dev.erasesize = 4096; 
    spi_flash_dev.owner = THIS_MODULE;
    spi_flash_dev._erase = spi_flash_erase;
    spi_flash_dev._read  = spi_flash_read;
    spi_flash_dev._write = spi_flash_write;
    mtd_device_register(&spi_flash_dev,NULL,102); box-sizing: border-box;">0);

    int spi_flash_remove(struct spi_device *spi)
{
    mtd_device_unregister(&spi_flash_dev);
    const struct of_device_id spi_flash_ids[] = {
    { .compatible =  },{ }
};



struct spi_driver spi_flash_drv =
{
    .driver = {
        .name   = "spi_flash",.probe      = spi_flash_probe,.remove     = spi_flash_remove,};


int spi_flash_init(void)
{
    printk("initn");
    return spi_register_driver(&spi_flash_drv);
}

void spi_flash_exit(void)
{
    spi_unregister_driver(&spi_flash_drv);
}

module_init(spi_flash_init);
module_exit(spi_flash_exit);
MODULE_LICENSE("GPL");

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读