驱动专题:第三章 Spi及spiflash驱动 5. Linux下的spi驱动

内核版本:linux2.6.32.2 
硬件资源:s3c2440
参考:  韦东山SPI视频教程


内容概括:
    1、I2C 驱动框架回顾
    2、SPI 框架简单介绍
    3、master 驱动框架

        3.1 驱动侧
        3.2 设备侧

    4、SPI 设备驱动框架

         4.1 设备册
        4.2 驱动侧

    5、设备驱动程序实例

1、I2C 驱动框架回顾
    在前面学习 I2C 驱动程序的时候我们知道,I2C 驱动框架分为两层,一层是控制器驱动程序 i2c_adapter,它一般是由芯片厂商写好的,主要提供一个 algorithm 底层的 i2c 协议的收发函数。i2c_adapter 驱动是基于 platform 模型,在driver侧的probe函数里,取出资源信息进行设置,最后将adapter注册到i2c_bus_type,注册时会调用 i2c_scan_static_board_info,扫描并使用 i2c_new_device 创建设备(设备层的设备)。我们还提到了4种创建device的方式。

    另一层是设备驱动层,基于 i2c_bus_type ,这个就很简单了,在设备驱动层 device 只需要提供一个从设备地址和名字,在 driver 里使用 i2c_smbus_read_byte_data 等类似的函数进行收发即可了,i2c_smbus_read_byte_data 等函数最终就会调用到 我们的 i2c_adapter->algorithm 里的收发函数进行收发。

2、SPI 框架简单介绍
    对于SPI的大框架,与I2C是完全一致的,也分为两层,控制器驱动程序层叫 spi_master ,主要提供transfer函数,进行spi协议的收发。spi_master 也是基于 Platform 模型的,注册 spi_master 时也会扫描一个链表进行注册设备,简直太相似了。

    另一层是设备驱动层,基于 spi_bus_type,相比 i2c 在device中需要提供的信息多一些,需要有名字、片选、最大速率、模式、中断号等等,在driver里则使用spi_read、spi_writer 等函数,最终也会调用到 master->transfer 函数进行发送接收。

    相比 I2C ,SPI驱动的框架是要简单的,因为它少了两种注册device的方式,另外它不需要像I2C一样去发送Start信号和设备地址去探测设备,SPI只需要片选选中就行了。但是它的底层收发的控制,相对I2C要复杂一点,毕竟4根线。

3、master 驱动框架
    之前,分析的驱动程序都是 S3C2410\S3C2440 平台的,由于我的开发板 Mini2440 没有SPI设备,因此厂商带的内核里关于 SPI 驱动部分不完整,而且在s3c23xx_spi_probe函数里注册master的时候写的十分复杂,干扰信息太多,不适合分析学习,因此,我搜索了一下其他平台的代码,发现 atmel_spi.c (drivers\spi),里 atmel 实现的底层控制器驱动简单清晰多了,因此就拿它开刀,分析Master驱动框架。

  3.1 驱动侧

    前面简介里,我提到 master 驱动框架是基于 platform 平台的(我分析的这俩都是,其它的不清楚),那么肯定就要注册platform_driver了,下面我们就开看看。

分配一个platfrom_driver结构

  1. static struct platform_driver atmel_spi_driver = {
  2. .driver = {
  3. .name = "atmel_spi",
  4. .owner = THIS_MODULE,
  5. },
  6. .suspend = atmel_spi_suspend,
  7. .resume = atmel_spi_resume,
  8. .remove = __exit_p(atmel_spi_remove),
  9. };

    将 atmel_spi_driver 注册到 platform_bus_type ,匹配设备 probe

  1. static int __ init atmel_spi_init(void)
  2. {
  3. return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);
  4. }

    我们之前都是将 probe 函数,直接放在driver结构体里,这里不是,而是调用了 platform_driver_probe ,就不贴代码了,还看段函数介绍,大致了解下什么意思。
/**
 * platform_driver_probe - register driver for non-hotpluggable device
 * @drv: platform driver structure
 * @probe: the driver probe routine, probably from an __init section
 *
 * Use this instead of platform_driver_register() when you know the device
 * is not hotpluggable and has already been registered, and you want to
 * remove its run-once probe() infrastructure from memory after the driver
 * has bound to the device.
 *
 * One typical use for this would be with drivers for controllers integrated
 * into system-on-chip processors, where the controller devices have been
 * configured as part of board setup.
 *
 * Returns zero if the driver registered and bound to a device, else returns
 * a negative error code and with the driver not registered.
 */
    1、适用于非热插拔设备
    2、通常Probe位于__init段3、当你知道device是非热拔插的,而且设备已经被注册了,而且你想在probe函数调用一次之后就销毁它节省空间,使用 platform_driver_probe 而非 platform_driver_register。
    4、一个典型的应用是,用在完整的控制器驱动,控制器设备被当作 board setup 的一部分(在板子初始化的时候,设备就已经被注册了,放在board_info里)
    5、返回0 ,如果driver注册成功且匹配到一个device ,以后再也无法被别的device probe了。
    6、否则,返回一个错误,且driver未注册。
    显然,我们写的正式一个控制器驱动程序,设备侧确实是早已注册(后边会讲)。
    疑问:有人说使用 platform_driver_probe 时 driver 只能被一个 device 匹配绑定,之后再也无法被别的device probe,难道说,我有俩spi控制器还需要写两个控制器驱动程序么?我认为这种说法是不对的,我猜大概是driver注册时,会匹配一遍device链表,把能支持的device都probe,之后再有deivce注册进来就不行了。这个有待验证。

    i2c驱动框架里,是在driver->probe 分配设置注册adapter,想必spi也是在driver->probe里分配设置注册master。

  1. static int __ init atmel_spi_probe(struct platform_device *pdev)
  2. {
  3. struct resource *regs;
  4. int irq;
  5. struct clk *clk;
  6. int ret;
  7. struct spi_master *master;
  8. struct atmel_spi *as;
  9. /* 获取 device 侧提供的Io内存以及中断 */
  10. regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  11. irq = platform_get_irq(pdev, 0);
  12. /* 获取 spi 时钟,一会好使能它 */
  13. clk = clk_get(&pdev->dev, "spi_clk");
  14. /* 分配一个spi_master结构 额外加上一个 atmel_spi 用来存放其它信息 */
  15. master = spi_alloc_master(&pdev->dev, sizeof *as);
  16. /* 设置 master */
  17. master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; // 所支持的模式
  18. master->bus_num = pdev->id; // 控制器编号,用于分辨外围spi设备是连接在哪一个控制器上
  19. master->num_chipselect = 4; // 片选最大值+1,spi设备的片选值要小于它
  20. master->setup = atmel_spi_setup; // 一个控制器上可能接有多个spi设备,它们的频率和模式是不一样的,用于设备之间切换时设置这些信息。
  21. master->transfer = atmel_spi_transfer; // 最重要的发送函数
  22. master->cleanup = atmel_spi_cleanup;
  23. /* 将 Master 放入 pdev->dev->p->driver_data 里*/
  24. platform_set_drvdata(pdev, master);
  25. /* as 指向 master->dev->p->driver_data ,填充多出来那个 atmel_spi 结构 */
  26. as = spi_master_get_devdata(master);
  27. as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
  28. &as->buffer_dma, GFP_KERNEL);
  29. spin_lock_init(&as->lock);
  30. INIT_LIST_HEAD(&as-> queue);
  31. as->pdev = pdev;
  32. as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
  33. as->irq = irq;
  34. as->clk = clk;
  35. /* 注册中断 使能时钟 */
  36. ret = request_irq(irq, atmel_spi_interrupt, 0,
  37. dev_name(&pdev->dev), master);
  38. clk_enable(clk);
  39. /* 设置硬件寄存器 */
  40. spi_writel(as, CR, SPI_BIT(SWRST));
  41. spi_writel(as, CR, SPI_BIT(SWRST)); /* AT91SAM9263 Rev B workaround */
  42. spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
  43. spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
  44. spi_writel(as, CR, SPI_BIT(SPIEN));
  45. /* 注册master */
  46. ret = spi_register_master(master);
  47. return 0;
  48. }

    对于master的设置过程注释已经说的很明白了,我们还得看看分配和注册过程。

  1. struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
  2. {
  3. struct spi_master *master;
  4. master = kzalloc(size + sizeof *master, GFP_KERNEL);
  5. device_initialize(&master->dev); // 初始化设备
  6. master->dev.class = &spi_master_class;
  7. master->dev.parent = get_device(dev); // 在 sysfs 平台设备xxx目录下创建目录
  8. spi_master_set_devdata(master, &master[ 1]);
  9. return master;
  10. }

    1、spi_alloc_master 实际申请的内存大小为一个struct master + struct atmel_spi,并用master->dev->p->driver_data 指向这个多出来的 struct atmel_spi 空间,用来存放 master 的中断 、寄存器等东西。

    2、初始化 master->dev ,设置它的父设备等。

  1. int spi_register_master(struct spi_master *master)
  2. {
  3. /* 将master注册到内核中去 */
  4. dev_set_name(&master->dev, "spi%u", master->bus_num);
  5. status = device_add(&master->dev);
  6. /* 扫描spi设备信息,创建设备 */
  7. scan_boardinfo(master);
  8. }

    1、设置 master->dev 的名字,例如 spi0、spi1 ...

    2、device_add 注册设备

    3、扫描spi设备信息:scan_boardinfo(master)

  1. static void scan_boardinfo(struct spi_master *master)
  2. {
  3. struct boardinfo *bi;
  4. mutex_lock(&board_lock);
  5. list_for_each_entry(bi, &board_list, list) {
  6. struct spi_board_info *chip = bi->board_info;
  7. unsigned n;
  8. /* 如果说 board_info 提供的bus_num 和 master—>bus_num 一致,则调用 spi_new_device */
  9. for (n = bi->n_board_info; n > 0; n--, chip++) {
  10. if (chip->bus_num != master->bus_num)
  11. continue;
  12. ( void) spi_new_device(master, chip); // 我们放到设备驱动层,在分析它
  13. }
  14. }
  15. mutex_unlock(&board_lock);
  16. }

    扫描 board_list ,取出每一个 boardinfo ,比对,如果 boardinfo 里的 bus_num 和 master 的 bus_num 相等,则认为这个spi设备在硬件物理连接上是接到这个控制器的,则使用 spi_new_device 创建 spi 设备。这个过程和i2c是多么的相似。至于在哪里填充的 board_list ,到后边设备层驱动框架时再说不迟。


  3.2 设备侧
    有 platform_driver 必然有 platform_device 与之对应,At91sam9260_devices.c 中定义

  1. static struct resource spi0_resources[] = {
  2. [ 0] = {
  3. .start = AT91SAM9260_BASE_SPI0,
  4. .end = AT91SAM9260_BASE_SPI0 + SZ_16K - 1,
  5. .flags = IORESOURCE_MEM,
  6. },
  7. [ 1] = {
  8. .start = AT91SAM9260_ID_SPI0,
  9. .end = AT91SAM9260_ID_SPI0,
  10. .flags = IORESOURCE_IRQ,
  11. },
  12. };

    资源文件,提供寄存器范围,spi中断。

  1. static struct platform_device at91sam9260_spi0_device = {
  2. .name = "atmel_spi", // 名字与driver一致
  3. .id = 0,
  4. .dev = {
  5. .dma_mask = &spi_dmamask,
  6. .coherent_dma_mask = DMA_BIT_MASK( 32),
  7. },
  8. .resource = spi0_resources, // 资源文件
  9. .num_resources = ARRAY_SIZE(spi0_resources),
  10. };

    与 driver 所配对的设备,显然名字是一样的。一般会有两个spi控制器,at91sam9260_spi1_device 和 at91sam9260_spi0_device 一样一样的,这里就不贴代码了。

    既然分配了 platform_device 那么肯定会在某个地方调用 platform_device_register 将它注册到 platform_bus_type , 就是在 at91_add_device_spi 。

  1. void __ init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
  2. {
  3. ...
  4. spi_register_board_info(devices, nr_devices);
  5. /* Configure SPI bus(es) */
  6. if (enable_spi0) {
  7. ...
  8. platform_device_register(&at91sam9260_spi0_device);
  9. }
  10. if (enable_spi1) {
  11. ...
  12. platform_device_register(&at91sam9260_spi1_device);
  13. }
  14. }

    1、添加 spi 设备信息,这应该是在设备驱动层要说的东西~就是前边的填充 Board_list 链表。

    2、将我们的 master 的设备侧 at91sam9260_spi0_device 注册到 platform_bus_type

    思考:这样做有什么好处呢?

        这样可以保证,master driver 与 device 匹配成功调用 probe 函数 scan_boardinfo 时,spi设备已经被添加到board_list中去~!如果先注册成功了 master 驱动,再添加spi设备信息就无用了。根 i2c 也是一样的。

    至此,Master 驱动的框架就分析完了,至于 master 的那些设置,我们到下篇文件写 master 驱动里细究。


4、SPI 设备驱动框架

    设备驱动层,参考韦东山老师的 SPI Flash 驱动来分析,设备驱动层,device driver 都是注册到spi_bus_type的,因此,我们现在看看 spi_bus_type->match 函数,看看它们如何匹配。

  1. static int spi_match_device(struct device *dev, struct device_driver *drv)
  2. {
  3. const struct spi_device *spi = to_spi_device(dev);
  4. const struct spi_driver *sdrv = to_spi_driver(drv);
  5. if (sdrv->id_table)
  6. return !!spi_match_id(sdrv->id_table, spi);
  7. return strcmp(spi->modalias, drv->name) == 0;
  8. }

    如果,driver里有id_table,则根据id_table进行匹配,没有就根据 spi->moadlias (设备名),和 driver->name 进行比较了。一样则配对成功。

  4.1 设备层

    设备层比较简单,先来分析它吧,目的只有一个分配 spi_board_info 设置 注册。

  1. static struct spi_board_info spi_info_jz2440[] = {
  2. {
  3. .modalias = "100ask_spi_flash", /* 对应的spi_driver名字也是"oled" */
  4. .max_speed_hz = 80000000, /* max spi clock (SCK) speed in HZ */
  5. .bus_num = 1, /* jz2440里OLED接在SPI CONTROLLER 1 */
  6. .mode = SPI_MODE_0,
  7. .chip_select = S3C2410_GPG( 2), /* flash_cs, 它的含义由spi_master确定 */
  8. }
  9. };

  1. static int spi_info_jz2440_init(void)
  2. {
  3. return spi_register_board_info(spi_info_jz2440, ARRAY_SIZE(spi_info_jz2440)); // list_add_tail(&bi->list, &board_list);
  4. }

    注册 list_add_tail(&spi_info_jz2440->list, &board_list) 

    前面我们提到,master注册成功时会扫描 board_list 注册 spi 设备,现在来看看 spi 设备的注册过程,虽然没有啥重要的。

  1. struct spi_device *spi_new_device(struct spi_master *master,
  2. struct spi_board_info *chip)
  3. {
  4. struct spi_device *proxy;
  5. int status;
  6. proxy = spi_alloc_device(master);
  7. proxy->chip_select = chip->chip_select;
  8. proxy->max_speed_hz = chip->max_speed_hz;
  9. proxy->mode = chip->mode;
  10. proxy->irq = chip->irq;
  11. strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
  12. proxy->dev.platform_data = ( void *) chip->platform_data;
  13. proxy->controller_data = chip->controller_data;
  14. proxy->controller_state = NULL;
  15. status = spi_add_device(proxy);
  16. return proxy;
  17. }
  18. struct spi_device *spi_alloc_device(struct spi_master *master)
  19. {
  20. struct spi_device *spi;
  21. struct device *dev = master->dev.parent;
  22. spi = kzalloc( sizeof *spi, GFP_KERNEL);
  23. spi->master = master;
  24. spi->dev.parent = dev;
  25. spi->dev.bus = &spi_bus_type;
  26. spi->dev.release = spidev_release;
  27. device_initialize(&spi->dev);
  28. return spi;
  29. }
  30. int spi_add_device(struct spi_device *spi)
  31. {
  32. static DEFINE_MUTEX(spi_add_lock);
  33. struct device *dev = spi->master->dev.parent;
  34. int status;
  35. /* 片选限制 */
  36. if (spi->chip_select >= spi->master->num_chipselect) {
  37. dev_err(dev, "cs%d >= max %d\n",
  38. spi->chip_select,
  39. spi->master->num_chipselect);
  40. return -EINVAL;
  41. }
  42. /* Set the bus ID string */
  43. dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
  44. spi->chip_select);
  45. status = spi_setup(spi);
  46. /*
  47. if (!spi->bits_per_word)
  48. spi->bits_per_word = 8;
  49. status = spi->master->setup(spi);
  50. */
  51. status = device_add(&spi->dev);
  52. }

    有一点,需要留意的吧,我们在写 master 驱动时,master->num_chipselect 要大于我们将要注册进来的spi设备的 chip_select 。


  4.2 驱动侧

  1. static struct spi_driver spi_flash_drv = {
  2. .driver = {
  3. .name = "100ask_spi_flash",
  4. .owner = THIS_MODULE,
  5. },
  6. .probe = spi_flash_probe,
  7. .remove = __devexit_p(spi_flash_remove),
  8. };

    分配一个 spi_driver ,没有 id_table ,要根据名字进行匹配了,显然跟前面的设备是一样的。

  1. static int spi_flash_init(void)
  2. {
  3. return spi_register_driver(&spi_flash_drv);
  4. }

    注册到 spi_bus_type ,匹配成功好调用 probe 函数,韦东山老师是将spi flash 作为一个mtd设备来使用的,因此在probe函数中分配、设置、注册 mtd_info 

  1. static int __ devinit spi_flash_probe(struct spi_device *spi)
  2. {
  3. int mid, did;
  4. spi_flash = spi;
  5. s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);
  6. SPIFlashInit();
  7. SPIFlashReadID(&mid, &did);
  8. printk( "SPI Flash ID: %02x %02x\n", mid, did);
  9. memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));
  10. /* 构造注册一个mtd_info
  11. * mtd_device_register(master, parts, nr_parts)
  12. *
  13. */
  14. /* Setup the MTD structure */
  15. spi_flash_dev.name = "100ask_spi_flash";
  16. spi_flash_dev.type = MTD_NORFLASH;
  17. spi_flash_dev.flags = MTD_CAP_NORFLASH;
  18. spi_flash_dev.size = 0x200000; /* 2M */
  19. spi_flash_dev.writesize = 1;
  20. spi_flash_dev.writebufsize = 4096; /* 没有用到 */
  21. spi_flash_dev.erasesize = 4096; /* 擦除的最小单位 */
  22. spi_flash_dev.owner = THIS_MODULE;
  23. spi_flash_dev._erase = spi_flash_erase;
  24. spi_flash_dev._read = spi_flash_read;
  25. spi_flash_dev._write = spi_flash_write;
  26. mtd_device_register(&spi_flash_dev, NULL, 0);
  27. return 0;
  28. }

    在 i2c 设备驱动程序中,我们使用 i2c_read 等函数调用 adapter 里的底层收发函数进行与i2c设备通信,spi肯定也有相应的函数,例如 spi_read、spi_write ,下面我们来仔细看看,这个很重要~不然我们怎么写设备驱动呢,光写个框架不能收发那不白扯么。
  1. static inline int spi_write(struct spi_device *spi, const u8 *buf, size_t len)
  2. {
  3. struct spi_transfer t = {
  4. .tx_buf = buf,
  5. .len = len,
  6. };
  7. struct spi_message m;
  8. spi_message_init(&m);
  9. spi_message_add_tail(&t, &m);
  10. return spi_sync(spi, &m);
  11. }
    以 spi_write 为例,看看它是如何调用到底层收发函数的。它构造了一个 spi_message 并由 spi_transfer组成,然后调用 spi_sync(spi, &m)->spi_async(spi,&m)->master->transfer(spi, &m).过程我们了解了,那么如何组织 spi_messgae ,它对应于时序图怎样的一个过程我们还不明白。

    还记得,i2c 是通过构造 i2c_msg ,然后传递多个 i2c_msg 给底层的发送函数,多个i2c_msg 组成start信号和p信号之间的发送过程,每一个i2c_msg 都有一个start信号。大概 i2c_msg 就类比于spi里的 spi_transfer ,但是通常情况下,整个 spi_messgae 传输过程我们只片选一次就够了。下面看个实例分析。

    上图是 spi flash 读取任意字节的时序图,片选选中之后,我们要先发送一个0x03 命令(1字节),再发送24bit(3字节)地址(先发送高位),然后读取len,最后取消片选。

  1. void SPIFlashRead(unsigned int addr, unsigned char *buf, int len)
  2. {
  3. unsigned char tx_buf[ 4];
  4. struct spi_transfer t[] = {
  5. {
  6. .tx_buf = tx_buf,
  7. .len = 4,
  8. },
  9. {
  10. .rx_buf = buf,
  11. .len = len,
  12. },
  13. };
  14. struct spi_message m;
  15. tx_buf[ 0] = 0x03;
  16. tx_buf[ 1] = addr >> 16;
  17. tx_buf[ 2] = addr >> 8;
  18. tx_buf[ 3] = addr & 0xff;
  19. spi_message_init(&m);
  20. spi_message_add_tail(&t[ 0], &m);
  21. spi_message_add_tail(&t[ 1], &m);
  22. spi_sync(spi_flash, &m);
  23. }

    韦老大的程序里,构造一个 struct spi_transfer 类型的数组,两个成员,第一个有一个tx_buf(表示写),长度为4,用来发送1字节命令和3字节地址。第二个成员 有一个rx_buf(表示读),长度由参数决定,用来读取长度len字节的内容。然后分配一个struct spi_message 并使用 spi_message_init 进行初始化,然后将 spi_transfer 数组成员依次添加到 spi_message 中去,最后 spi_sync(spi_flash, &m)

    纸上谈兵一大堆,现在来看看,我们在写一个spi设备驱动的时候需要做哪些工作。
    设备侧:
      1、分配一个 spi_board_info 结构体
      2、设置 spi_board_info 里的名字、最大频率、控制器编号、模式、片选
      3、注册 spi_register_board_info 
    驱动侧:
      1、分配一个 spi_driver 结构
      2、设置名字、probe等函数
      3、注册 spi_register_driver
      4、使用spi_write等系统调用,搞明白 spi_transfer spi_message ,会使用它们进行收发

   一个 spi_message 对应于一个不可打断的spi传输过程,可以理解为片选选中直到取消选中的过程(特殊情况下,一个spi_message里面是可以取消片选再选中的),而 spi_message 由 spi_transfer 组成,根据 tx_buf  rx_buf 是否为空来判断是 写还是读 操作。

    至此,整个 spi 的框架分析完毕


5、设备驱动程序实例

  1. #include <linux/init.h>
  2. #include <linux/fs.h>
  3. #include <linux/slab.h>
  4. #include <linux/module.h>
  5. #include <linux/kernel.h>
  6. #include <linux/device.h>
  7. #include <sound/core.h>
  8. #include <linux/spi/spi.h>
  9. #include <asm/uaccess.h>
  10. #include <linux/timer.h>
  11. #include <mach/hardware.h>
  12. #include <mach/regs-gpio.h>
  13. #include <linux/gpio.h>
  14. #include <plat/gpio-cfg.h>
  15. #include <linux/mtd/cfi.h>
  16. #include <linux/mtd/mtd.h>
  17. #include <linux/mtd/partitions.h>
  18. /* 参考:
  19. * drivers\mtd\devices\mtdram.c
  20. * drivers/mtd/devices/m25p80.c
  21. */
  22. static struct spi_device *spi_flash;
  23. /*
  24. *
  25. */
  26. void SPIFlashReadID(int *pMID, int *pDID)
  27. {
  28. unsigned char tx_buf[ 4];
  29. unsigned char rx_buf[ 2];
  30. tx_buf[ 0] = 0x90;
  31. tx_buf[ 1] = 0;
  32. tx_buf[ 2] = 0;
  33. tx_buf[ 3] = 0;
  34. spi_write_then_read(spi_flash, tx_buf, 4, rx_buf, 2);
  35. *pMID = rx_buf[ 0];
  36. *pDID = rx_buf[ 1];
  37. }
  38. static void SPIFlashWriteEnable(int enable)
  39. {
  40. unsigned char val = enable ? 0x06 : 0x04;
  41. spi_write(spi_flash, &val, 1);
  42. }
  43. static unsigned char SPIFlashReadStatusReg1(void)
  44. {
  45. unsigned char val;
  46. unsigned char cmd = 0x05;
  47. spi_write_then_read(spi_flash, &cmd, 1, &val, 1);
  48. return val;
  49. }
  50. static unsigned char SPIFlashReadStatusReg2(void)
  51. {
  52. unsigned char val;
  53. unsigned char cmd = 0x35;
  54. spi_write_then_read(spi_flash, &cmd, 1, &val, 1);
  55. return val;
  56. }
  57. static void SPIFlashWaitWhenBusy(void)
  58. {
  59. while (SPIFlashReadStatusReg1() & 1)
  60. {
  61. /* 休眠一段时间 */
  62. /* Sector erase time : 60ms
  63. * Page program time : 0.7ms
  64. * Write status reg time : 10ms
  65. */
  66. set_current_state(TASK_INTERRUPTIBLE);
  67. schedule_timeout(HZ/ 100); /* 休眠10MS后再次判断 */
  68. }
  69. }
  70. static void SPIFlashWriteStatusReg(unsigned char reg1, unsigned char reg2)
  71. {
  72. unsigned char tx_buf[ 4];
  73. SPIFlashWriteEnable( 1);
  74. tx_buf[ 0] = 0x01;
  75. tx_buf[ 1] = reg1;
  76. tx_buf[ 2] = reg2;
  77. spi_write(spi_flash, tx_buf, 3);
  78. SPIFlashWaitWhenBusy();
  79. }
  80. static void SPIFlashClearProtectForStatusReg(void)
  81. {
  82. unsigned char reg1, reg2;
  83. reg1 = SPIFlashReadStatusReg1();
  84. reg2 = SPIFlashReadStatusReg2();
  85. reg1 &= ~( 1<< 7);
  86. reg2 &= ~( 1<< 0);
  87. SPIFlashWriteStatusReg(reg1, reg2);
  88. }
  89. static void SPIFlashClearProtectForData(void)
  90. {
  91. /* cmp=0,bp2,1,0=0b000 */
  92. unsigned char reg1, reg2;
  93. reg1 = SPIFlashReadStatusReg1();
  94. reg2 = SPIFlashReadStatusReg2();
  95. reg1 &= ~( 7<< 2);
  96. reg2 &= ~( 1<< 6);
  97. SPIFlashWriteStatusReg(reg1, reg2);
  98. }
  99. /* erase 4K */
  100. void SPIFlashEraseSector(unsigned int addr)
  101. {
  102. unsigned char tx_buf[ 4];
  103. tx_buf[ 0] = 0x20;
  104. tx_buf[ 1] = addr >> 16;
  105. tx_buf[ 2] = addr >> 8;
  106. tx_buf[ 3] = addr & 0xff;
  107. SPIFlashWriteEnable( 1);
  108. spi_write(spi_flash, tx_buf, 4);
  109. SPIFlashWaitWhenBusy();
  110. }
  111. /* program */
  112. void SPIFlashProgram(unsigned int addr, unsigned char *buf, int len)
  113. {
  114. unsigned char tx_buf[ 4];
  115. struct spi_transfer t[] = {
  116. {
  117. .tx_buf = tx_buf,
  118. .len = 4,
  119. },
  120. {
  121. .tx_buf = buf,
  122. .len = len,
  123. },
  124. };
  125. struct spi_message m;
  126. tx_buf[ 0] = 0x02;
  127. tx_buf[ 1] = addr >> 16;
  128. tx_buf[ 2] = addr >> 8;
  129. tx_buf[ 3] = addr & 0xff;
  130. SPIFlashWriteEnable( 1);
  131. spi_message_init(&m);
  132. spi_message_add_tail(&t[ 0], &m);
  133. spi_message_add_tail(&t[ 1], &m);
  134. spi_sync(spi_flash, &m);
  135. SPIFlashWaitWhenBusy();
  136. }
  137. void SPIFlashRead(unsigned int addr, unsigned char *buf, int len)
  138. {
  139. /* spi_write_then_read规定了tx_cnt+rx_cnt < 32
  140. * 所以对于大量数据的读取,不能使用该函数
  141. */
  142. unsigned char tx_buf[ 4];
  143. struct spi_transfer t[] = {
  144. {
  145. .tx_buf = tx_buf,
  146. .len = 4,
  147. },
  148. {
  149. .rx_buf = buf,
  150. .len = len,
  151. },
  152. };
  153. struct spi_message m;
  154. tx_buf[ 0] = 0x03;
  155. tx_buf[ 1] = addr >> 16;
  156. tx_buf[ 2] = addr >> 8;
  157. tx_buf[ 3] = addr & 0xff;
  158. spi_message_init(&m);
  159. spi_message_add_tail(&t[ 0], &m);
  160. spi_message_add_tail(&t[ 1], &m);
  161. spi_sync(spi_flash, &m);
  162. }
  163. static void SPIFlashInit(void)
  164. {
  165. SPIFlashClearProtectForStatusReg();
  166. SPIFlashClearProtectForData();
  167. }
  168. /* 构造注册一个mtd_info
  169. * mtd_device_register(master, parts, nr_parts)
  170. *
  171. */
  172. /* 首先: 构造注册spi_driver
  173. * 然后: 在spi_driver的probe函数里构造注册mtd_info
  174. */
  175. static struct mtd_info spi_flash_dev;
  176. static int spi_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
  177. {
  178. unsigned int addr = instr->addr;
  179. unsigned int len = 0;
  180. /* 判断参数 */
  181. if ((addr & (spi_flash_dev.erasesize - 1)) || (instr->len & (spi_flash_dev.erasesize - 1)))
  182. {
  183. printk( "addr/len is not aligned\n");
  184. return -EINVAL;
  185. }
  186. for (len = 0; len < instr->len; len += 4096)
  187. {
  188. SPIFlashEraseSector(addr);
  189. addr += 4096;
  190. }
  191. instr->state = MTD_ERASE_DONE;
  192. mtd_erase_callback(instr);
  193. return 0;
  194. }
  195. static int spi_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
  196. size_t *retlen, u_char *buf)
  197. {
  198. SPIFlashRead(from, buf, len);
  199. *retlen = len;
  200. return 0;
  201. }
  202. static int spi_flash_write(struct mtd_info *mtd, loff_t to, size_t len,
  203. size_t *retlen, const u_char *buf)
  204. {
  205. unsigned int addr = to;
  206. unsigned int wlen = 0;
  207. /* 判断参数 */
  208. if ((to & (spi_flash_dev.erasesize - 1)) || (len & (spi_flash_dev.erasesize - 1)))
  209. {
  210. printk( "addr/len is not aligned\n");
  211. return -EINVAL;
  212. }
  213. for (wlen = 0; wlen < len; wlen += 256)
  214. {
  215. SPIFlashProgram(addr, ( unsigned char *)buf, 256);
  216. addr += 256;
  217. buf += 256;
  218. }
  219. *retlen = len;
  220. return 0;
  221. }
  222. static int __ devinit spi_flash_probe(struct spi_device *spi)
  223. {
  224. int mid, did;
  225. spi_flash = spi;
  226. s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);
  227. SPIFlashInit();
  228. SPIFlashReadID(&mid, &did);
  229. printk( "SPI Flash ID: %02x %02x\n", mid, did);
  230. memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));
  231. /* 构造注册一个mtd_info
  232. * mtd_device_register(master, parts, nr_parts)
  233. *
  234. */
  235. /* Setup the MTD structure */
  236. spi_flash_dev.name = "100ask_spi_flash";
  237. spi_flash_dev.type = MTD_NORFLASH;
  238. spi_flash_dev.flags = MTD_CAP_NORFLASH;
  239. spi_flash_dev.size = 0x200000; /* 2M */
  240. spi_flash_dev.writesize = 1;
  241. spi_flash_dev.writebufsize = 4096; /* 没有用到 */
  242. spi_flash_dev.erasesize = 4096; /* 擦除的最小单位 */
  243. spi_flash_dev.owner = THIS_MODULE;
  244. spi_flash_dev._erase = spi_flash_erase;
  245. spi_flash_dev._read = spi_flash_read;
  246. spi_flash_dev._write = spi_flash_write;
  247. mtd_device_register(&spi_flash_dev, NULL, 0);
  248. return 0;
  249. }
  250. static int __ devexit spi_flash_remove(struct spi_device *spi)
  251. {
  252. mtd_device_unregister(&spi_flash_dev);
  253. return 0;
  254. }
  255. static struct spi_driver spi_flash_drv = {
  256. .driver = {
  257. .name = "100ask_spi_flash",
  258. .owner = THIS_MODULE,
  259. },
  260. .probe = spi_flash_probe,
  261. .remove = __devexit_p(spi_flash_remove),
  262. };
  263. static int spi_flash_init(void)
  264. {
  265. return spi_register_driver(&spi_flash_drv);
  266. }
  267. static void spi_flash_exit(void)
  268. {
  269. spi_unregister_driver(&spi_flash_drv);
  270. }
  271. module_init(spi_flash_init);
  272. module_exit(spi_flash_exit);
  273. MODULE_DESCRIPTION( "Flash SPI Driver");
  274. MODULE_AUTHOR( "weidongshan@qq.com,www.100ask.net");
  275. MODULE_LICENSE( "GPL");
  276. <strong style= "color: rgb(255, 0, 0);">
  277. </strong>
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值