Linux SPI框架 (2)

     上节介绍了SPI子系统中的一些重要数据结构和SPI子系统初始化的第一步,也就是注册SPI总线。这节介绍针对于s3c24xx平台的SPI子系统初始化,在看具体的代码之前,先上一张自己画的图,帮助理清初始化的主要步骤

 

显然,SPI是一种平台特定的资源,所以它是以platform平台设备的方式注册进内核的,因此它的struct platform_device结构是已经静态定义好了的,现在只待它的struct platform_driver注册,然后和platform_device匹配。

 

初始化的入口:

[html]  view plain copy
  1. static int __init s3c24xx_spi_init(void)  
  2. {  
  3.         return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);  
  4. }  


platform_driver_probe()会调用platform_driver_register()来注册驱动,然后在注册的过程中寻求匹配的platform_device,一旦匹配成功,便会调用probe函数,也就是s3c24xx_spi_probe(),在看这个函数之前,还得介绍几个相关的数据结构。

struct s3c2410_spi_info是一个板级结构,也是在移植时就定义好的,在初始化spi_master时用到,platform_device-->dev-->platform_data会指向这个结构。

[cpp]  view plain copy
  1. struct s3c2410_spi_info {  
  2.     int          pin_cs;    /* simple gpio cs */  
  3.     unsigned int         num_cs;    /* total chipselects */  
  4.     int          bus_num;/* bus number to use. */  
  5.   
  6.     void (*gpio_setup)(struct s3c2410_spi_info *spi, int enable);  
  7.     void (*set_cs)(struct s3c2410_spi_info *spi, int cs, int pol);  
  8. };  

 

struct s3c24xx_spi用来具体描述s3c24xx平台上一个SPI控制器

[cpp]  view plain copy
  1. struct s3c24xx_spi {  
  2.     /* bitbang has to be first */  
  3.     struct spi_bitbang   bitbang;  
  4.     struct completion    done;  
  5.   
  6.     void __iomem        *regs;  
  7.     int          irq;  
  8.     int          len;  
  9.     int          count;  
  10.   
  11.     void            (*set_cs)(struct s3c2410_spi_info *spi,  
  12.                       int cs, int pol);  
  13.   
  14.     /* data buffers */  
  15.     const unsigned char *tx;  
  16.     unsigned char       *rx;  
  17.   
  18.     struct clk      *clk;  
  19.     struct resource     *ioarea;  
  20.     struct spi_master   *master;  
  21.     struct spi_device   *curdev;  
  22.     struct device       *dev;  
  23.     struct s3c2410_spi_info *pdata;  
  24. };  


struct spi_bitbang用于控制实际的数据传输

[cpp]  view plain copy
  1. struct spi_bitbang {  
  2.     struct workqueue_struct *workqueue;  /*工作队列*/  
  3.     struct work_struct  work;  
  4.   
  5.     spinlock_t      lock;  
  6.     struct list_head    queue;  
  7.     u8          busy;  
  8.     u8          use_dma;  
  9.     u8          flags;      /* extra spi->mode support */  
  10.   
  11.     struct spi_master   *master;         /*bitbang所属的master*/  
  12.   
  13.      /*用于设置设备传输时的时钟,字长等*/  
  14.     int (*setup_transfer)(struct spi_device *spi,  
  15.             struct spi_transfer *t);  
  16.   
  17.     void    (*chipselect)(struct spi_device *spi, int is_on);  
  18. #define BITBANG_CS_ACTIVE   1   /* normally nCS, active low */  
  19. #define BITBANG_CS_INACTIVE 0  
  20.   
  21.     /*针对于平台的传输控制函数*/  
  22.     int (*txrx_bufs)(struct spi_device *spi, struct spi_transfer *t);  
  23.   
  24.     /* txrx_word[SPI_MODE_*]() just looks like a shift register */  
  25.     u32 (*txrx_word[4])(struct spi_device *spi,  
  26.             unsigned nsecs,  
  27.             u32 word, u8 bits);  
  28. };  

 

下面来看s3c24xx_spi_probe()函数的实现

[cpp]  view plain copy
  1. static int __init s3c24xx_spi_probe(struct platform_device *pdev)  
  2. {  
  3.     struct s3c2410_spi_info *pdata;  
  4.     struct s3c24xx_spi *hw;  
  5.     struct spi_master *master;  
  6.     struct resource *res;  
  7.     int err = 0;  
  8.   
  9.     /*创建spi_master,并将spi_master->private_data指向s3c24xx_spi*/  
  10.     master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));  
  11.     if (master == NULL) {  
  12.         dev_err(&pdev->dev, "No memory for spi_master\n");  
  13.         err = -ENOMEM;  
  14.         goto err_nomem;  
  15.     }  
  16.   
  17.     hw = spi_master_get_devdata(master);//获取s3c24xx_spi  
  18.     memset(hw, 0, sizeof(struct s3c24xx_spi));  
  19.   
  20.     hw->master = spi_master_get(master);  
  21.     hw->pdata = pdata = pdev->dev.platform_data;  
  22.     hw->dev = &pdev->dev;  
  23.   
  24.     if (pdata == NULL) {  
  25.         dev_err(&pdev->dev, "No platform data supplied\n");  
  26.         err = -ENOENT;  
  27.         goto err_no_pdata;  
  28.     }  
  29.   
  30.     platform_set_drvdata(pdev, hw);  
  31.     init_completion(&hw->done);  
  32.   
  33.     /* setup the master state. */  
  34.          /*片选数和SPI主控制器编号是在platform_data中已经定义好了的*/  
  35.     master->num_chipselect = hw->pdata->num_cs;  
  36.     master->bus_num = pdata->bus_num;  
  37.   
  38.     /* setup the state for the bitbang driver */  
  39.   
  40.     /*设置bitbang的所属master和控制传输的相关函数*/  
  41.     hw->bitbang.master         = hw->master;  
  42.     hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;  
  43.     hw->bitbang.chipselect     = s3c24xx_spi_chipsel;  
  44.     hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;  
  45.     hw->bitbang.master->setup  = s3c24xx_spi_setup;  
  46.   
  47.     dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);  
  48.   
  49.     /* find and map our resources */  
  50.   
  51.     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  52.     if (res == NULL) {  
  53.         dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");  
  54.         err = -ENOENT;  
  55.         goto err_no_iores;  
  56.     }  
  57.   
  58.     hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,  
  59.                     pdev->name);  
  60.   
  61.     if (hw->ioarea == NULL) {  
  62.         dev_err(&pdev->dev, "Cannot reserve region\n");  
  63.         err = -ENXIO;  
  64.         goto err_no_iores;  
  65.     }  
  66.   
  67.     /*映射SPI控制寄存器*/  
  68.     hw->regs = ioremap(res->start, (res->end - res->start)+1);  
  69.     if (hw->regs == NULL) {  
  70.         dev_err(&pdev->dev, "Cannot map IO\n");  
  71.         err = -ENXIO;  
  72.         goto err_no_iomap;  
  73.     }  
  74.   
  75.     /*获取中断号*/  
  76.     hw->irq = platform_get_irq(pdev, 0);  
  77.     if (hw->irq < 0) {  
  78.         dev_err(&pdev->dev, "No IRQ specified\n");  
  79.         err = -ENOENT;  
  80.         goto err_no_irq;  
  81.     }  
  82.   
  83.     /*注册中断*/  
  84.     err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);  
  85.     if (err) {  
  86.         dev_err(&pdev->dev, "Cannot claim IRQ\n");  
  87.         goto err_no_irq;  
  88.     }  
  89.   
  90.     hw->clk = clk_get(&pdev->dev, "spi");  
  91.     if (IS_ERR(hw->clk)) {  
  92.         dev_err(&pdev->dev, "No clock for device\n");  
  93.         err = PTR_ERR(hw->clk);  
  94.         goto err_no_clk;  
  95.     }  
  96.   
  97.     /* setup any gpio we can */  
  98.   
  99.     if (!pdata->set_cs) {  
  100.         if (pdata->pin_cs < 0) {  
  101.             dev_err(&pdev->dev, "No chipselect pin\n");  
  102.             goto err_register;  
  103.         }  
  104.   
  105.         err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));  
  106.         if (err) {  
  107.             dev_err(&pdev->dev, "Failed to get gpio for cs\n");  
  108.             goto err_register;  
  109.         }  
  110.           
  111.         hw->set_cs = s3c24xx_spi_gpiocs;//设定片选函数  
  112.         gpio_direction_output(pdata->pin_cs, 1);  
  113.     } else  
  114.         hw->set_cs = pdata->set_cs;  
  115.   
  116.     s3c24xx_spi_initialsetup(hw);  
  117.   
  118.     /* register our spi controller */  
  119.          /* 注册主机SPI控制器 */  
  120.     err = spi_bitbang_start(&hw->bitbang);  
  121.     if (err) {  
  122.         dev_err(&pdev->dev, "Failed to register SPI master\n");  
  123.         goto err_register;  
  124.     }  
  125.   
  126.     return 0;  
  127.   
  128.  err_register:  
  129.     if (hw->set_cs == s3c24xx_spi_gpiocs)  
  130.         gpio_free(pdata->pin_cs);  
  131.   
  132.     clk_disable(hw->clk);  
  133.     clk_put(hw->clk);  
  134.   
  135.  err_no_clk:  
  136.     free_irq(hw->irq, hw);  
  137.   
  138.  err_no_irq:  
  139.     iounmap(hw->regs);  

[cpp]  view plain copy
  1. int spi_bitbang_start(struct spi_bitbang *bitbang)  
  2. {  
  3.     int status;  
  4.   
  5.     if (!bitbang->master || !bitbang->chipselect)  
  6.         return -EINVAL;  
  7.   
  8.     /*初始化一个struct work,处理函数为bitbang_work*/  
  9.     INIT_WORK(&bitbang->work, bitbang_work);  
  10.     spin_lock_init(&bitbang->lock);  
  11.     INIT_LIST_HEAD(&bitbang->queue);  
  12.   
  13.     /*检测bitbang中的函数是否都定义了,如果没定义,则默认使用spi_bitbang_xxx*/  
  14.     if (!bitbang->master->transfer)  
  15.         bitbang->master->transfer = spi_bitbang_transfer;  
  16.     if (!bitbang->txrx_bufs) {  
  17.         bitbang->use_dma = 0;  
  18.         bitbang->txrx_bufs = spi_bitbang_bufs;  
  19.         if (!bitbang->master->setup) {  
  20.             if (!bitbang->setup_transfer)  
  21.                 bitbang->setup_transfer =  
  22.                      spi_bitbang_setup_transfer;  
  23.             bitbang->master->setup = spi_bitbang_setup;  
  24.             bitbang->master->cleanup = spi_bitbang_cleanup;  
  25.         }  
  26.     } else if (!bitbang->master->setup)  
  27.         return -EINVAL;  
  28.   
  29.     /* this task is the only thing to touch the SPI bits */  
  30.     bitbang->busy = 0;  
  31.     /*创建bitbang的工作队列*/  
  32.     bitbang->workqueue = create_singlethread_workqueue(  
  33.             dev_name(bitbang->master->dev.parent));  
  34.     if (bitbang->workqueue == NULL) {  
  35.         status = -EBUSY;  
  36.         goto err1;  
  37.     }  
  38.   
  39.     /* driver may get busy before register() returns, especially 
  40.      * if someone registered boardinfo for devices 
  41.      */  
  42.      /*注册spi_master*/  
  43.     status = spi_register_master(bitbang->master);  
  44.     if (status < 0)  
  45.         goto err2;  
  46.   
  47.     return status;  
  48.   
  49. err2:  
  50.     destroy_workqueue(bitbang->workqueue);  
  51. err1:  
  52.     return status;  
  53. }  

 

下一个关键函数就是spi_register_master(),用于注册spi_master

[cpp]  view plain copy
  1. int spi_register_master(struct spi_master *master)  
  2. {  
  3.     static atomic_t     dyn_bus_id = ATOMIC_INIT((1<<15) - 1);  
  4.     struct device       *dev = master->dev.parent;  
  5.     int         status = -ENODEV;  
  6.     int         dynamic = 0;  
  7.   
  8.     if (!dev)  
  9.         return -ENODEV;  
  10.   
  11.     /* even if it's just one always-selected device, there must 
  12.      * be at least one chipselect 
  13.      */  
  14.     if (master->num_chipselect == 0)//片选数不能为0  
  15.         return -EINVAL;  
  16.   
  17.     /* convention:  dynamically assigned bus IDs count down from the max */  
  18.     if (master->bus_num < 0) {  
  19.         /* FIXME switch to an IDR based scheme, something like 
  20.          * I2C now uses, so we can't run out of "dynamic" IDs 
  21.          */  
  22.         master->bus_num = atomic_dec_return(&dyn_bus_id);  
  23.         dynamic = 1;  
  24.     }  
  25.   
  26.     /* register the device, then userspace will see it. 
  27.      * registration fails if the bus ID is in use. 
  28.      */  
  29.     dev_set_name(&master->dev, "spi%u", master->bus_num);  
  30.     status = device_add(&master->dev);//添加spi_master设备  
  31.     if (status < 0)  
  32.         goto done;  
  33.     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),  
  34.             dynamic ? " (dynamic)" : "");  
  35.   
  36.     /* populate children from any spi device tables */  
  37.     scan_boardinfo(master);//遍历板级信息,寻找可以挂接在该spi_master下的从设备  
  38.     status = 0;  
  39. done:  
  40.     return status;  
  41. }  


 

[cpp]  view plain copy
  1. static void scan_boardinfo(struct spi_master *master)  
  2. {  
  3.     struct boardinfo    *bi;  
  4.   
  5.     mutex_lock(&board_lock);  
  6.     list_for_each_entry(bi, &board_list, list) {  
  7.         struct spi_board_info   *chip = bi->board_info;  
  8.         unsigned        n;  
  9.   
  10.         for (n = bi->n_board_info; n > 0; n--, chip++) {  
  11.             if (chip->bus_num != master->bus_num)  
  12.                 continue;  
  13.             /* NOTE: this relies on spi_new_device to 
  14.              * issue diagnostics when given bogus inputs 
  15.              */  
  16.              /*bus_num相等则创建新设备*/  
  17.             (void) spi_new_device(master, chip);  
  18.         }  
  19.     }  
  20.     mutex_unlock(&board_lock);  
  21. }  


spi_board_info是板级信息,是在移植时就写好的,并且要将其注册

[cpp]  view plain copy
  1. struct spi_board_info {  
  2.     char        modalias[32];  /*名字*/  
  3.     const void  *platform_data;  
  4.     void        *controller_data;  
  5.     int     irq;          /*中断号*/  
  6.     u32     max_speed_hz; /*最高传输速率*/  
  7.     u16     bus_num;      /*所属的spi_master编号*/  
  8.     u16     chip_select;  /*片选号*/  
  9.   
  10.     u8      mode;         /*传输模式*/  
  11.   
  12. };  

 

最后一步就是将相应的从设备注册进内核

[cpp]  view plain copy
  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.   
  7.     /* NOTE:  caller did any chip->bus_num checks necessary. 
  8.      * 
  9.      * Also, unless we change the return value convention to use 
  10.      * error-or-pointer (not NULL-or-pointer), troubleshootability 
  11.      * suggests syslogged diagnostics are best here (ugh). 
  12.      */  
  13.   
  14.     /*创建SPI_device*/  
  15.     proxy = spi_alloc_device(master);  
  16.     if (!proxy)  
  17.         return NULL;  
  18.   
  19.     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));  
  20.   
  21.     /*初始化*/  
  22.     proxy->chip_select = chip->chip_select;  
  23.     proxy->max_speed_hz = chip->max_speed_hz;  
  24.     proxy->mode = chip->mode;  
  25.     proxy->irq = chip->irq;  
  26.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));  
  27.     proxy->dev.platform_data = (void *) chip->platform_data;  
  28.     proxy->controller_data = chip->controller_data;  
  29.     proxy->controller_state = NULL;  
  30.   
  31.     /*将新设备添加进内核*/  
  32.     status = spi_add_device(proxy);  
  33.     if (status < 0) {  
  34.         spi_dev_put(proxy);  
  35.         return NULL;  
  36.     }  
  37.   
  38.     return proxy;  
  39. }  

猜你喜欢

转载自blog.csdn.net/zhoutaopower/article/details/43460779
今日推荐