• LINUX驱动开发(SPI)SPI主机驱动代码解析


    1. 驱动调用过程

    分析代码可以在内核中看相关驱动代码和驱动框架。

    1. 注册platform_driver结构体,填充成员函数;
    2. 驱动中的compatible属性与设备树中的compatible属性匹配成功后,调用probe函数;
    3. 在probe函数中注册和设置spi;
    4. 在remove函数中注销和释放spi;

    2. spi_master驱动框架

    static const struct of_device_id spi_virtual_dt_ids[] = {
    	{ .compatible = "my,spidev", },
    	{ /* sentinel */ }
    };
    
    static int spi_virtual_probe(struct platform_device *pdev)
    {
    	return 0;
    }
    
    static int spi_virtual_remove(struct platform_device *pdev)
    {
    	return 0;
    }
    
    
    static struct platform_driver spi_virtual_driver = {
    	.probe = spi_virtual_probe,
    	.remove = spi_virtual_remove,
    	.driver = {
    		.name = "virtual_spi",
    		.of_match_table = spi_virtual_dt_ids,
    	},
    };
    
    static int virtual_master_init(void)
    {
    	printk("***virtual_master_init***\r\n");
    	return platform_driver_register(&spi_virtual_driver);
    }
    
    static void virtual_master_exit(void)
    {
    	printk("***virtual_master_exit***\r\n");
    	platform_driver_unregister(&spi_virtual_driver);
    }
    
    module_init(virtual_master_init);
    module_exit(virtual_master_exit);
    
    MODULE_DESCRIPTION("Virtual SPI bus driver");
    MODULE_LICENSE("GPL");
    MODULE_AUTHOR("lljwork2021");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    2. 分配spi_master

    /* 针对ST芯片 */
    static struct completion g_xfer_done;
    
    static int spi_virtual_probe(struct platform_device *pdev)
    {
    	struct spi_master *master;
    	master = spi_alloc_master(&pdev->dev, sizeof(struct spi_bitbang));
    	init_completion(&g_xfer_done);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    /* 针对NXP芯片 */
    static struct spi_master *g_virtual_master;
    static struct spi_bitbang *g_virtual_bitbang;
    static struct completion g_xfer_done;
    
    static int spi_virtual_probe(struct platform_device *pdev)
    {
    	struct spi_master *master;
    	g_virtual_master = master = spi_alloc_master(&pdev->dev, sizeof(struct spi_bitbang));
    	if (!master)
    		return -ENOMEM;
    	g_virtual_bitbang  = spi_master_get_devdata(master);
    	init_completion(&g_xfer_done);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    3. 注册spi_master

    /* 
    * 针对ST芯片
    * linux/drivers/spi/spi-stm32.c 
    */
    /* 注册代码 */
    ret = spi_register_master(master); /* 注册函数 */
    if (ret) {
    	printk("spi_register_master fail\n");
    	spi_master_put(master); 
    	return ret;
    }
    	
    /* 注销代码 */
    spi_unregister_master(g_virtual_master); /* 注销函数 */
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    /* 
    * 方法二: 针对NXP芯片
    * linux-kernel/drivers/spi/spi-imx.c
    * linux-kernel/include/linux/spi/spi.h
    * linux-kernel/include/linux/spi/spi_bitbang.h
    * linux-kernel/drivers/spi/spi-bitbang.c
    */
    函数:
    int spi_bitbang_start(struct spi_bitbang *bitbang); /* 注册函数 */
    void spi_bitbang_stop(struct spi_bitbang *bitbang); /* 注销函数 */
    spi_master_put(_ctlr)	/* 释放内存 */
    #define spi_master_put(_ctlr)		spi_controller_put(_ctlr)
    static inline void spi_controller_put(struct spi_controller *ctlr)
    
    参考代码:
    /* 注册代码 */
    ret = spi_bitbang_start(g_virtual_bitbang);
    if (ret) {
    	printk("spi_bitbang_start fail\n");
    	return ret;
    
    /* 注销代码 */
    spi_bitbang_stop(g_virtual_bitbang);
    spi_master_put(g_virtual_master);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    4. 设置spi-master

    static int spi_virtual_transfer(struct spi_device *spi, struct spi_transfer *transfer)
    {
    	int timeout;
    	reinit_completion(&g_xfer_done);
    	complete(&g_xfer_done);
    	timeout = wait_for_completion_timeout(&g_xfer_done, 100);
    	if (!timeout) {
    		dev_err(&spi->dev, "I/O Error in PIO\n");
    		return -ETIMEDOUT;
    	}
    	return transfer->len;
    }
    
    static void	spi_virtual_chipselect(struct spi_device *spi, int is_on)
    {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    /* 针对NXP 
     * linux-kernel/include/linux/spi/spi_bitbang.h  
     */
    g_virtual_bitbang->master = master;
    g_virtual_bitbang->txrx_bufs  = spi_virtual_transfer;
    g_virtual_bitbang->chipselect = spi_virtual_chipselect;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    /*
    针对ST
    linux-kernel/include/spi/spi.h
    #define spi_master spi_controller
    struct spi_controller {
    ......
    }
    */
    master->dev.of_node = pdev->dev.of_node;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    5. 内核API

    /* linux-kernel/Documentation/scheduler/completion.rst */
    init_completion
    reinit_completion
    unsigned long wait_for_completion_timeout(struct completion *done, unsigned long timeout);
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    华为的网络模拟器eNSP
    Vue的数据控制-----计算属性(computed)&&侦听器(watch)
    【数据结构】排序6——桶排序、基数排序、计数排序
    前端面试题 10 个「有用」JavaScript 代码片段
    什么是集成测试?集成测试方法有哪些?
    解决一进页面就会触发trigger: “change“表单校验问题
    测试用例逻辑梳理
    记一次 .NET 某医院预约平台 非托管泄露分析
    Three.js使用ExtrudeGeometry拉伸模型
    NMEA0813协议简介
  • 原文地址:https://blog.csdn.net/qq_40723777/article/details/125608779