SPI驱动:(Linux驱动7)

时间:2021-08-31 23:37:22

说明:

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部分均可以套用.