• SPI Flash(W25Q16DV) 驱动


    大体上可分为以下几个部分:

    1.注册设备驱动 spi_register_driver
    2.分配 mtd_info 结构体
    3.配置 mtd_info 结构体
    4.注册 mtd_info 结构体
    

    构建 spi_driver 并注册

    static struct spi_driver spi_flash_drv = {
    	.driver = {
    		.name	= "spi_flash",
    		.owner	= THIS_MODULE,
    	},
    	.probe		= spi_flash_probe,
    	.remove		= __devexit_p(spi_flash_remove),
    };
    
    static int spi_flash_init(void)
    {
        return spi_register_driver(&spi_flash_drv);
    }
    

    当内核中注册了同名的设备,会调用该驱动的 probe 程序

    /* 分配 mtd_info 结构体 */
    static struct mtd_info spi_flash_dev;
    
    static int __devinit spi_flash_probe(struct spi_device *spi)
    {
        int mid, did;
        
        spi_flash = spi;
    
        s3c2410_gpio_cfgpin(spi->chip_select, S3C2410_GPIO_OUTPUT);
        SPIFlashInit();
        SPIFlashReadID(&mid, &did);
        printk("SPI Flash ID: %02x %02x
    ", mid, did);
        memset(&spi_flash_dev, 0, sizeof(spi_flash_dev));
            
        /* 构造并注册这个 mtd_info
         * mtd_device_register(master, parts, nr_parts)
         */
    
    	/* 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 = 0x200000;  /* 2M */
    	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, 0);
         
        return 0;
    }
    

    spi_flash_dev._erase = spi_flash_erase;
    spi_flash_dev._read  = spi_flash_read;
    spi_flash_dev._write = spi_flash_write;
    

    这三个函数与前面一篇文章所调用的函数基本相同,只是 SPI 的发送我们需要调用内核中的函数来完成,程序如下(linux/spi.h):

    static inline int
    spi_write(struct spi_device *spi, const void *buf, size_t len)
    {
    	struct spi_transfer	t = {
    			.tx_buf		= buf,
    			.len		= len,
    		};
    	struct spi_message	m;
    
    	spi_message_init(&m);
    	spi_message_add_tail(&t, &m);
    	return spi_sync(spi, &m);
    }
    

    忙等待函数我们也要加以修改,避免浪费 CPU 资源,程序如下:

    static void SPIFlashWaitWhenBusy(void)
    {
        while (SPIFlashReadStatusReg1() & 1)
        {
            /* 休眠一段时间 */
    		set_current_state(TASK_INTERRUPTIBLE);
            schedule_timeout(HZ/100);  /* 休眠10MS后再次判断 */
        }
    }
    

    将进程设置为可中断的等待状态 TASK_INTERRUPTIBLE 。

    状态解释:进程被挂起(睡眠),直到某个条件变为真。产生一个硬件中断,释放进程正在等待的系统资源,或传递一个信号都是可以唤醒进程的条件 (把进程的状态放回到 TASK_RUNNING)。

    使用 schedule_timeout 函数,该方法会让需要延迟的任务睡眠到指定的延时时间后在重新运行。

  • 相关阅读:
    从安装、管理到防御_阿里云安骑士全向测评
    云架构师前(钱)景这么好_我们该如何转型?这有两位阿里云云架构总监多年心得
    Infrastructure_as_Code——Kubernetes一键编排实践
    大中华地区(含港澳台)空气质量接口参加阿里云API_as_a_Service_大赛
    E-MapReduce集群启停HDFS/YARN服务
    云服务器ECS还原安全组规则功能介绍_安全组规则的备份与还原
    E-MapReduce集群中HDFS服务集成Kerberos
    FastReport中如何加入自定义函数
    查找算法总结
    八大排序算法总结
  • 原文地址:https://www.cnblogs.com/GyForever1004/p/8542810.html
Copyright © 2020-2023  润新知