[i.MX] i.mx536(cotex-a8核)的SPI驱动理解一(probe)

[复制链接]
1389|3
 楼主| quray1985 发表于 2015-7-3 10:38 | 显示全部楼层 |阅读模式
  1.     <pre name="code" class="cpp"><pre name="code" class="cpp"></pre><pre name="code" class="cpp">//整个probe主要包含以下几步,与其它的ARM芯片很相似  
  2.     //(1)填充三个结构体struct mxc_spi_master,struct spi_master,struct mxc_spi  
  3.     //(2)申请IO资源,中断  
  4.     //(3)SPI寄存器配置  
  5.     //(4)spi_bitbang_start(即调用spi_register_master)  
  6.     //(5)spi_new_device  
  7.     static int mxc_spi_probe(struct platform_device *pdev)  
  8.     {  
  9.         //spi私有数据结构体,imx芯片独有,主要存储板级配置文件中设置的一些参数  
  10.         //个人觉得这个结构体有点多余,还没弄清楚原因?  
  11.         struct mxc_spi_master *mxc_platform_info;  
  12.         //描述spi控制器结构体,spi驱动通用  
  13.         struct spi_master *master;  
  14.         struct mxc_spi *master_drv_data = NULL;  
  15.         //一般的ARM控制器的SPI驱动都会包含以上三个结构体(具体名称不用)  
  16.         struct resource *res;  
  17.         unsigned int spi_ver, wml;  
  18.         int ret = -ENODEV;  
  19.       
  20.         /* Get the platform specific data for this master device */  
  21.         //为什么这里可以强制转换struct platform_data为struct mxc_spi_master?  
  22.         //因为platform_data是一个void类型的指针  
  23.         mxc_platform_info = (struct mxc_spi_master *)pdev->dev.platform_data;  
  24.         if (!mxc_platform_info) {  
  25.             dev_err(&pdev->dev, "can't get the platform data for CSPI\n");  
  26.             return -EINVAL;  
  27.         }  
  28.       
  29.         /* Allocate SPI master controller */  
  30.         master = spi_alloc_master(&pdev->dev, sizeof(struct mxc_spi));  
  31.         if (!master) {  
  32.             dev_err(&pdev->dev, "can't alloc for spi_master\n");  
  33.             return -ENOMEM;  
  34.         }  
  35.       
  36.         /* Set this device's driver data to master */  
  37.         //保存master到pdev  
  38.         platform_set_drvdata(pdev, master);  
  39.       
  40.         /* Set this master's data from platform_info */  
  41.         //主机控制器编号,如果板子上有多个spi总线,靠这个域区分  
  42.         master->bus_num = pdev->id + 1;  
  43.         //支持spi设备个数  
  44.         master->num_chipselect = mxc_platform_info->maxchipselect;  
  45.         //模式标志位  
  46.         master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;  
  47.     #ifdef CONFIG_SPI_MXC_TEST_LOOPBACK  
  48.         master->num_chipselect += 1;  
  49.     #endif  
  50.         /* Set the master controller driver data for this master */  
  51.         //spi_master_get_devdata调用dev_set_drvdata获取设备私有数据  
  52.         //读取保存在master->dev中的私有数据  
  53.         //这个私有数据是在上面的spi_alloc_master中配置的。  
  54.         master_drv_data = spi_master_get_devdata(master);  
  55.         //mxc_bitbang是一个spi_bitbang结构体,struct spi_bitbang 是具体的负责数据传输的结构体  
  56.         master_drv_data->mxc_bitbang.master = spi_master_get(master);  
  57.         //把存储在mxc_platform_info中的一些参数(板级配置文件中设置)存储到master_drv_data  
  58.         if (mxc_platform_info->chipselect_active)  
  59.             master_drv_data->chipselect_active =  
  60.                 mxc_platform_info->chipselect_active;  
  61.         if (mxc_platform_info->chipselect_inactive)  
  62.             master_drv_data->chipselect_inactive =  
  63.                 mxc_platform_info->chipselect_inactive;  
  64.       
  65.         /* Identify SPI version */  
  66.         //根据扳级配置文件中设置的版本  
  67.         spi_ver = mxc_platform_info->spi_version;  
  68.         if (spi_ver == 7) {  
  69.             master_drv_data->spi_ver_def = &spi_ver_0_7;  
  70.         } else if (spi_ver == 5) {  
  71.             master_drv_data->spi_ver_def = &spi_ver_0_5;  
  72.         } else if (spi_ver == 4) {  
  73.             master_drv_data->spi_ver_def = &spi_ver_0_4;  
  74.         } else if (spi_ver == 0) {  
  75.             master_drv_data->spi_ver_def = &spi_ver_0_0;  
  76.         } else if (spi_ver == 23) {  
  77.             master_drv_data->spi_ver_def = &spi_ver_2_3;  
  78.         }  
  79.       
  80.         dev_dbg(&pdev->dev, "SPI_REV 0.%d\n", spi_ver);  
  81.       
  82.         /* Set the master bitbang data */  
  83.         //SPI传输的各个函数  
  84.         master_drv_data->mxc_bitbang.chipselect = mxc_spi_chipselect;  
  85.         master_drv_data->mxc_bitbang.txrx_bufs = mxc_spi_transfer;  
  86.         //该函数做一些初始化的工作  
  87.         master_drv_data->mxc_bitbang.master->setup = mxc_spi_setup;  
  88.         master_drv_data->mxc_bitbang.master->cleanup = mxc_spi_cleanup;  
  89.         master_drv_data->mxc_bitbang.setup_transfer = mxc_spi_setup_transfer;  
  90.       
  91.         /* Initialize the completion object */  
  92.         //completion是内核中一个轻量级机制,允许一个线程告诉另一个线程工作已完成  
  93.         init_completion(&master_drv_data->xfer_done);  
  94.       
  95.         /* Set the master controller register addresses and irqs */  
  96.         //获取板级配置文件中设置的资源  
  97.         master_drv_data->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  98.         if (!master_drv_data->res) {  
  99.             dev_err(&pdev->dev, "can't get platform resource for CSPI%d\n",  
  100.                 master->bus_num);  
  101.             ret = -ENOMEM;  
  102.             goto err;  
  103.         }  
  104.         //检测申请的资源是否可用,并把资源标志为已用  
  105.         if (!request_mem_region(master_drv_data->res->start,  
  106.                     master_drv_data->res->end -  
  107.                     master_drv_data->res->start + 1, pdev->name)) {  
  108.             dev_err(&pdev->dev, "request_mem_region failed for CSPI%d\n",  
  109.                 master->bus_num);  
  110.             ret = -ENOMEM;  
  111.             goto err;  
  112.         }  
  113.         //映射虚拟内存  
  114.         master_drv_data->base = ioremap(master_drv_data->res->start,  
  115.             master_drv_data->res->end - master_drv_data->res->start + 1);  
  116.         if (!master_drv_data->base) {  
  117.             dev_err(&pdev->dev, "invalid base address for CSPI%d\n",  
  118.                 master->bus_num);  
  119.             ret = -EINVAL;  
  120.             goto err1;  
  121.         }  
  122.         //获取板级配置文件中设置的中断号  
  123.         master_drv_data->irq = platform_get_irq(pdev, 0);  
  124.         if (master_drv_data->irq < 0) {  
  125.             dev_err(&pdev->dev, "can't get IRQ for CSPI%d\n",  
  126.                 master->bus_num);  
  127.             ret = -EINVAL;  
  128.             goto err1;  
  129.         }  
  130.       
  131.         /* Register for SPI Interrupt */  
  132.         //注册中断函数mxc_spi_isr  
  133.         ret = request_irq(master_drv_data->irq, mxc_spi_isr,  
  134.                   0, "CSPI_IRQ", master_drv_data);  
  135.         if (ret != 0) {  
  136.             dev_err(&pdev->dev, "request_irq failed for CSPI%d\n",  
  137.                 master->bus_num);  
  138.             goto err1;  
  139.         }  
  140.       
  141.         master_drv_data->dev = &pdev->dev;  
  142.         /* Setup the DMA */  
  143.         //如果设置了dma,(这个在我的板级配置文件中未配置)  
  144.         master_drv_data->usedma = 0;  
  145.         res = platform_get_resource(pdev, IORESOURCE_DMA, 0);  
  146.         if (res) {  
  147.             master_drv_data->dma_tx_id = res->start;  
  148.                 master_drv_data->dma_tx_id = res->start;  
  149.             if (pdev->dev.dma_mask == NULL)  
  150.                 dev_warn(&pdev->dev, "no dma mask\n");  
  151.             else  
  152.                 master_drv_data->usedma = 1;  
  153.         }  
  154.         if (master_drv_data->usedma) {  
  155.             master_drv_data->dma_tx_ch =  
  156.                 mxc_dma_request(master_drv_data->dma_tx_id, "mxc_spi");  
  157.             if (master_drv_data->dma_tx_ch < 0) {  
  158.                 dev_info(&pdev->dev, "Can't allocate RX DMA ch\n");  
  159.                 master_drv_data->usedma = 0;  
  160.                 ret = -ENXIO;  
  161.                 goto err_no_txdma;  
  162.             }  
  163.             mxc_dma_callback_set(master_drv_data->dma_tx_ch,  
  164.                     mxc_spi_dma_tx_callback,  
  165.                     (void *)master_drv_data);  
  166.       
  167.             /* Allocate tmp_buf for tx_buf */  
  168.             master_drv_data->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL);  
  169.             if (master_drv_data->tmp_buf == NULL) {  
  170.                 ret = -ENOMEM;  
  171.                 goto err_tmp_buf_alloc;  
  172.             }  
  173.         }  
  174.       
  175.         /* Setup any GPIO active */  
  176.         //配置SPI口IO,一般高级ARM芯片有多个SPI口,配置哪个由bus_num决定,bus_num是板级配置文件中设置  
  177.         gpio_spi_active(master->bus_num - 1);  
  178.       
  179.         /* Enable the CSPI Clock, CSPI Module, set as a master */  
  180.       
  181.         //i.mx536的SPI控制器的寄存器配置  
  182.         master_drv_data->ctrl_addr =  
  183.             master_drv_data->base + master_drv_data->spi_ver_def->ctrl_reg_addr;  
  184.         master_drv_data->dma_addr =  
  185.             master_drv_data->base + master_drv_data->spi_ver_def->dma_reg_addr;  
  186.         master_drv_data->stat_addr =  
  187.             master_drv_data->base + master_drv_data->spi_ver_def->stat_reg_addr;  
  188.         master_drv_data->period_addr =  
  189.             master_drv_data->base +  
  190.             master_drv_data->spi_ver_def->period_reg_addr;  
  191.         master_drv_data->test_addr =  
  192.             master_drv_data->base + master_drv_data->spi_ver_def->test_reg_addr;  
  193.         master_drv_data->reset_addr =  
  194.             master_drv_data->base +  
  195.             master_drv_data->spi_ver_def->reset_reg_addr;  
  196.         //开启SPI时钟  
  197.         master_drv_data->clk = clk_get(&pdev->dev, "cspi_clk");  
  198.         clk_enable(master_drv_data->clk);  
  199.         //获取时钟频率  
  200.         master_drv_data->spi_ipg_clk = clk_get_rate(master_drv_data->clk);  
  201.       
  202.          
  203.         __raw_writel(master_drv_data->spi_ver_def->reset_start,  
  204.                  master_drv_data->reset_addr);  
  205.         udelay(1);  
  206.         __raw_writel((master_drv_data->spi_ver_def->spi_enable +  
  207.                   master_drv_data->spi_ver_def->master_enable),  
  208.                  master_drv_data->base + MXC_CSPICTRL);  
  209.         __raw_writel(MXC_CSPIPERIOD_32KHZ, master_drv_data->period_addr);  
  210.         __raw_writel(0, MXC_CSPIINT + master_drv_data->ctrl_addr);  
  211.       
  212.         if (master_drv_data->usedma) {  
  213.             /* Set water mark level to be the half of fifo_size in DMA */  
  214.             wml = master_drv_data->spi_ver_def->fifo_size / 2;  
  215.             wml = wml << master_drv_data->spi_ver_def->tx_wml_shift;  
  216.             __raw_writel((__raw_readl(master_drv_data->dma_addr)  
  217.                     & ~master_drv_data->spi_ver_def->tx_wml_mask)  
  218.                     | wml,  
  219.                     master_drv_data->dma_addr);  
  220.         }  
  221.         /* Start the SPI Master Controller driver */  
  222.         //启动SPI控制器  
  223.         //最终调用spi_register_master来注册spi控制器  
  224.         ret = spi_bitbang_start(&master_drv_data->mxc_bitbang);  
  225.       
  226.         if (ret != 0)  
  227.             goto err2;  
  228.       
  229.         printk(KERN_INFO "CSPI: %s-%d probed\n", pdev->name, pdev->id);  
  230.       
  231.     #ifdef CONFIG_SPI_MXC_TEST_LOOPBACK  
  232.         {  
  233.             int i;  
  234.             struct spi_board_info *bi = &loopback_info[0];  
  235.             for (i = 0; i < ARRAY_SIZE(loopback_info); i++, bi++) {  
  236.                 if (bi->bus_num != master->bus_num)  
  237.                     continue;  
  238.       
  239.                 dev_info(&pdev->dev,  
  240.                      "registering loopback device '%s'\n",  
  241.                      bi->modalias);  
  242.       
  243.                 spi_new_device(master, bi);  
  244.             }  
  245.         }  
  246.     #endif  
  247.         clk_disable(master_drv_data->clk);  
  248.         return ret;  
  249.       
  250.           err2:  
  251.         gpio_spi_inactive(master->bus_num - 1);  
  252.         clk_disable(master_drv_data->clk);  
  253.         clk_put(master_drv_data->clk);  
  254.         if (master_drv_data->usedma)  
  255.             kfree(master_drv_data->tmp_buf);  
  256.     err_tmp_buf_alloc:  
  257.         if (master_drv_data->usedma)  
  258.             mxc_dma_free(master_drv_data->dma_tx_ch);  
  259.     err_no_txdma:  
  260.         free_irq(master_drv_data->irq, master_drv_data);  
  261.           err1:  
  262.         //最终调用free函数,释放内存  
  263.         iounmap(master_drv_data->base);  
  264.         release_mem_region(pdev->resource[0].start,  
  265.                    pdev->resource[0].end - pdev->resource[0].start + 1);  
  266.           err:  
  267.         spi_master_put(master);  
  268.         kfree(master);  
  269.         platform_set_drvdata(pdev, NULL);  
  270.         return ret;  
  271.     }</pre><br>  
  272.     <br>  
  273.     <pre></pre>  
  274.     <pre></pre>  
  275.     <pre></pre>  
  276.          
  277.             <div style="padding-top:20px">           
  278.                 <p style="font-size:12px;">版权声明:本文为博主原创**,未经博主允许不得转载。</p>  
  279.             </div>  
  280.     </pre>  


FSL_TICS_Rita 发表于 2015-7-9 17:25 | 显示全部楼层
好贴,赞
FSL_TICS_Rita 发表于 2015-7-9 17:25 | 显示全部楼层
非常感谢你关于i.mx的经验分享 !
mini1986 发表于 2015-7-13 13:21 | 显示全部楼层
//spi私有数据结构体,imx芯片独有,主要存储板级配置文件中设置的一些参数  
        //个人觉得这个结构体有点多余,还没弄清楚原因?  
        struct mxc_spi_master *mxc_platform_info;

靠这个来传输数据结构参数,怎么会多余呢?......
您需要登录后才可以回帖 登录 | 注册

本版积分规则

156

主题

1488

帖子

5

粉丝
快速回复 在线客服 返回列表 返回顶部