MTK SPI控制器驱动分析

一.SPI控制器驱动程序
Spi.c (kernel-3.18\drivers\spi\mediatek\mt6735)
   
static const struct of_device_id mt_spi_of_match[] = {
/*{.compatible = "mediatek,SPI1",},*/
{.compatible = "mediatek,mt6735-spi",},
{.compatible = "mediatek,mt6735m-spi",},
{.compatible = "mediatek,mt6753-spi",},
{.compatible = "mediatek,mt6797-spi",},
{},
};
 
MODULE_DEVICE_TABLE(of, mt_spi_of_match);
 
struct platform_driver mt_spi_driver = {
.driver = {
  .name = "mt-spi",
  .owner = THIS_MODULE,
  .of_match_table = mt_spi_of_match,
  },
.probe = mt_spi_probe,
.suspend = mt_spi_suspend,
.resume = mt_spi_resume,
.remove = __exit_p(mt_spi_remove),
};
    
 
mt_spi_init
    ret = platform_driver_register(&mt_spi_driver); //通过匹配DTS里面的{.compatible = "mediatek,mt6735-spi",},进入probe
 
 
mt_spi_probe
    master = spi_alloc_master(&pdev->dev, sizeof(struct mt_spi_t)); //分配mt_spi_t内存,allocate SPI master controller
    regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); //得到IO资源
    irq = platform_get_irq(pdev, 0); //得到平台的中断
    request_mem_region(regs->start, resource_size(regs), pdev->name) //申请内存
    ms->clk_main = devm_clk_get(&pdev->dev, "spi-main"); //得到SPI的clk
    master->mode_bits = (SPI_CPOL | SPI_CPHA); //给spi控制器属性赋值
    master->bus_num = pdev->id;
    master->setup = mt_spi_setup;
    master->transfer = mt_spi_transfer;
    master->cleanup = mt_spi_cleanup;
    ret = request_irq(irq, mt_spi_interrupt, IRQF_TRIGGER_LOW, dev_name(&pdev->dev), ms);//注册SPI控制器中断函数,单独分析1
    enable_clk(ms); //使能时钟
    reset_spi(ms); //重启SPI
    ret = spi_register_master(master); //注册SPI控制器,单独分析2
 
 
 
 
注册SPI控制器中断函数,单独分析1
mt_spi_interrupt
    xfer = ms->cur_transfer;
    msg = list_entry(ms->queue.next, struct spi_message, queue); //从队列获取spi_message
    /*Clear interrupt status first by reading the register */
    reg_val = spi_readl(ms, SPI_STATUS0_REG);
    if (is_fifo_read(msg) && xfer->rx_buf)  //如果是FIFO,读取数据
        reg_val = spi_readl(ms, SPI_RX_DATA_REG);/*get the data from rx */ 
    if (is_last_xfer(msg, xfer))  //如果是最后的spi_message数据 ,就停止读取
mt_spi_msg_done(ms, msg, 0); 
            list_del(&msg->queue); //删除队列
            spi_disable_dma(ms); //关闭DMA
            msg->complete(msg->context); //调用spi_message的complete函数
    else  //如果不是最后的spi_message数据
ms->cur_transfer = ms->next_transfer;
mt_spi_next_xfer(ms, msg); //读取下一个spi_message
            ms->next_transfer = list_entry(xfer->transfer_list.next, struct spi_transfer, transfer_list); //读取spi_transfer
            spi_disable_dma(ms);
            ret = spi_setup_packet(ms);
            /*Using DMA to send data */
    if ((mode == DMA_TRANSFER) || (mode == OTHER1) || (mode == OTHER2)) 
spi_enable_dma(ms, mode); //使能DMA
   
            
 
//注册SPI控制器,单独分析2
spi_register_master(master);
    status = device_add(&master->dev); //加入设备
    list_add_tail(&master->list, &spi_master_list); //加入spi_master_list链表
    list_for_each_entry(bi, &board_list, list) //spi_device的信息的集合,找到用这个设备控制器的设备
spi_match_master_to_boardinfo(master, &bi->board_info);
            if (master->bus_num != bi->bus_num) //如果有spi设备,就进入下一步
            dev = spi_new_device(master, bi); //new 一个spi设备,单独分析3
 
 
new 一个spi设备,单独分析3
spi_new_device
    proxy = spi_alloc_device(master); //分配一个SPI设备
        spi = kzalloc(sizeof(*spi), GFP_KERNEL); 
        spi->master = master;
spi->dev.parent = &master->dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
spi->cs_gpio = -ENOENT;
device_initialize(&spi->dev);
    proxy->chip_select = chip->chip_select; //设置这个设备的一些属性,由spi_device里面得到
    proxy->max_speed_hz = chip->max_speed_hz;
    proxy->mode = chip->mode;
    proxy->irq = chip->irq;
    status = spi_add_device(proxy); //加入设备
        status = spi_setup(spi); //setup SPI mode and clock rate
        /* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
                
     
posted @ 2020-11-25 15:26  luoyuna  阅读(942)  评论(0编辑  收藏  举报