SPI驱动:(Linux驱动7)

    xiaoxiao2021-03-25  77

    说明:

    spi,i2c,usb等总线,在cpu上均有相应的控制器,与之对应的数据结构是spi_master,i2c_adapter等.主机控制器和外设分离,外设用于 驱动不同的芯片,通过这样设计避免了外设驱动与控制器关联. spi驱动包括spi核心(/drivers/spi/spi.c),主要包括主机控制器,外设的注册,注销 driver和device的关系:driver用于将外设挂载到总线上,device描述设备的特性,与platform_device使用board_info来描述device类似, spi使用spi_board_info来描述spi_device.通过spi_driver将spi外设挂载到spi总线,在driver的probe函数中,注册spi所属本身设备驱动.

    变量:

    spi_master{//用于描述spi主机控制器 struct device dev; bus_num num_chipselect (setup)(struct spi_device) (transfer)(spi_device dev,spi_message *msg); (*cleanup)(spi_device *dev); }

    spi_driver{//用于描述外设,挂载外设驱动 probe remove shutdown suspend resume device_driver driver; }

    spi_device{//用于描述外设 struct device dev; struct spi_master *master; max_speed_hz; chip_select; mode; bits_per_word; irq; *controller_state; *controller_data; modalias[SPI_NAME_SIZE]; }

    spi_transfer{//用于描述传输数据 *tx_buf; *rx_buf; len dma_addr_t tx_dma; dma_addr_t rx_dma; cs_change; bits_per_word; delay_usecs; speed_hz; list_head transfer_list; }

    spi_message{//用于组织spi_transfer list_head transfers; spi_device *spi; is_dma_mapped; (*complete)(void*context); void *context; actual_length; status; list_head queue; void *state; }

    struct spi_board_info{//描述spi外设数据结构 modalias;外设驱动的名称 bus_num;//用到的spi主机控制器号 chip_select;//片选信号 max_speed_hz;//spi传输速率 plat_form_data;//平台数据,用在spi_device.dev.platform_data; controller_data;//用在spi_device.controller_data中 }

    函数:

    spi核心函数:

    spi外设函数

    (struct spi_device *) spi_alloc_device(struct spi_master* master);

    int spi_add_device(struct spi_device *dev);

    int spi_new_device(struct spi_device dev,struct spi_board_info info);//调用alloc_device和add_device

    void spi_unregister_device(struct spi_device *dev);

    int spi_register_board_info(struct spi_board_info* info,int nr);//将外设与master联系的函数,会调用spi_new_device

    int spi_register_driver(struct spi_driver *driver);

    int spi_unregister_driver(struct spi_driver *driver);

    spi控制器函数 struct spi_master * spi_alloc_master(stuct device *dev,int size); int spi_register_master(struct spi_master *master); int spi_unregister_master(struct spi_master *master); spi_master_get_dev_data(struct spi_master*master)//通常通过此函数获得用户定义的控制器的spi资源, xx_spi{ int irq; struct clk *clk; void *buf; … struct spi_device *dev; } spi_master_set_dev_data(struct spi_master *master,void *data);spi传输函数

    spi_message_init 初始化spi message

    spi_message_add_tail(struct spi_transfer *t,struct spi_message *msg)

    spi_sync(spi_device *spi,spi_message *msg)

    spi_write(spi_device *spi,char *buf,size_t len);

    spi_read(spi_device*spi,char *buf,size_t len);

    用法:

    spi适配器驱动实现:

    适配器驱动文件 xx_transfer(struct spi_device* dev,struct spi_message *msg){ } xx_setup(struct *spi_device *dev){ }

    int xx_probe(struct platform_device *dev){ 读取适配器资源,配置资源 spi_alloc_master(); … 填充spi_master中的setup,transfer等函数 spi_register_master(); }

    struct platform_driver xx_spi_driver={ .driver={ .name=”xx_spi_driver”; .owner=THIS_MODULE; } .probe=xx_probe; .remove=xx_remove; .resume=xx_resume; } xx_init(){ platform_driver_register(&xx_spi_driver); }

    xx_exit(){ platform_driver_unregister(&xx_spi_driver); } 或者 module_platform_driver(&xx_spi_driver);//不需要init,exit函数

    适配器资源描述 struct resources={ [0]={ .start .end .flags= } … } struct platform_device xx_spi_device={ [0]={ name=”xx_spi_driver”, resources=&xx_spi_resources; num_resorces= dev={ .platform_data=xx_spi_data; } } }

    合适的地方调用 platform_device_register(&xx_spi_device);

    spi外设驱动实现

    xx外设驱动文件 定义外设自身的驱动 xx_fun(); 定义外设driver函数 xx_probe(struct platform_device *pdev){ 注册外设功能函数 }

    定义driver xx_driver={ .probe=xx_probe; .remove=xx_remove; .driver={ .name=”xx_driver”; .owner=THIS_MODULE; } } xx_init(void){ spi_register_driver(&xx_driver); } xx_exit(void){ spi_unregister_driver(&xx_driver); }

    外设的资源描述,通常在板子的初始化文件中 描述spi外设,填充spi_board_info struct spi_board_info xx_spi_device={ .modalias=”xx_driver”;//对应的外设驱动名称 .bus_num .max_speed_hz .chip_select .platform_data .mode; … }

    在合适的地方调用

    spi_register_board_info(&xx_spi_device,ARRAY_SIZE(xx_spi_device));

    可以看出spi驱动与上面讲的rtc驱动很像,除了最后驱动注册函数不一样外,以上rtc部分均可以套用.

    转载请注明原文地址: https://ju.6miu.com/read-33841.html

    最新回复(0)