pl080-DMA控制器代码分析

这个DMA 控制器是PL080,代码分析如下:

1. 子系统 init/exit

static int __init pl080_dma_init(void)
{
        return amba_driver_register(&pl080_dma_driver);  //这是添加在amba总线上的一个控制器
}

static void __exit pl080_dma_exit(void)
{
        amba_driver_unregister(&pl080_dma_driver);
}

subsys_initcall(pl080_dma_init);
module_exit(pl080_dma_exit);

pl080_dma_driver 驱动结构体如下:

static struct amba_driver pl080_dma_driver = {
        .drv = {
                .name   = "pl080-dmac",  //驱动名字pl080-dmac
                .owner  = THIS_MODULE,   
        },
        .probe          = pl080_dma_probe,     //添加完该驱动后,就会自动运行probe,进行探测有没有dma设备。
        .remove         = __devexit_p(pl080_dma_remove),
        .suspend        = pl080_dma_suspend,
        .resume         = pl080_dma_resume,
        .id_table       = pl080_dma_ids,     //这个不知道干啥用的
};

pl080_dma_ids 定义如下:

static struct amba_id pl080_dma_ids[] __initdata = {
        {
                .id     = 0x8A280080,
                .mask   = 0xFFFFFFFF,
        },
        { 0, 0 },
};
pl080_dma_suspend()/pl080_dma_resume(), 是电源管理相关函数,定义如下:

#ifdef CONFIG_PM
static int pl080_dma_suspend(struct amba_device *dev, pm_message_t state)
{
        struct pl080_dma *pdma = amba_get_drvdata(dev);

        /* TODO: to be updated */

        pl080_dma_reset(pdma);
        clk_disable(pdma->clk);

        return 0;
}

static int pl080_dma_resume(struct amba_device *dev)
{
        struct pl080_dma *pdma = amba_get_drvdata(dev);

        /* TODO: to be updated */

        clk_enable(pdma->clk);

        return 0;
}
#else
#define pl080_dma_suspend       NULL
#define pl080_dma_resume        NULL
#endif
2. pl080_dma_probe() --- probe函数, 代码有点长:

static int __devinit pl080_dma_probe(struct amba_device *dev, struct amba_id *id)
{
        struct pl080_dma_platform_data *plat = dev->dev.platform_data;
        struct pl080_dma *pdma;
        struct clk *clk;
        int i, ret;

        /* must have platform data */
        if (!plat) {                                             //platform 相关数据
                dev_err(&dev->dev, "missing platform data\n");
                return -EINVAL;
        }

        /* sanity check on configuration parameters */
        if (!dev->res.start || !dev->res.end || dev->irq[0] < 0) {    //amba_device 相关的内容
                dev_err(&dev->dev, "device configuration error\n");
                return -EINVAL;
        }

        if (plat->nr_channels > MAX_NR_CHANNELS) {                                  //通道数
                dev_err(&dev->dev, "too many channels, max %d\n", MAX_NR_CHANNELS);
                return -EINVAL;
        }

        /* request all memory regions associated with this device */
        ret = amba_request_regions(dev, NULL);                             //申请 amba_device 内存
        if (ret) {
                dev_err(&dev->dev, "unable to get device memory regions\n");
                return ret;
        }

        /* get reference to device clock and enable it */
        clk = clk_get(&dev->dev, NULL);               
        if (IS_ERR(clk)) {
                dev_err(&dev->dev, "unable to get reference to device clock\n");
                ret = PTR_ERR(clk);
                goto exit_release;
        }

        ret = clk_enable(clk);
        if (ret) {
                dev_err(&dev->dev, "failed to enable device clock\n");
                goto exit_clk_put;
        }

        /* allocate and save driver context */
        pdma = kzalloc(sizeof(struct pl080_dma), GFP_KERNEL);
        if (!pdma) {
                dev_err(&dev->dev, "not enough memory for DMA controller status\n");
                ret = -ENOMEM;
                goto exit_clk_disable;
        }

        amba_set_drvdata(dev, pdma);                 //给 dev 赋值 pdma;

        tasklet_init(&pdma->tasklet, pl080_dma_tasklet, (unsigned long)pdma);   //初始化tasklet

        /* initialize DMA controller status */
        pdma->base = ioremap(dev->res.start, resource_size(&dev->res));
        pdma->irq = dev->irq[0];
        pdma->clk = clk;
        pdma->ahb_master_memory = plat->ahb_master_memory;                 //内存
        pdma->nr_descs_per_channel = plat->nr_descs_per_channel;           //通道数
        if (pdma->nr_descs_per_channel == 0)
                pdma->nr_descs_per_channel = NR_DESCS_PER_CHANNEL;

        pdma->all_chan_mask = (1 << plat->nr_channels) - 1;

        pdma->dma.chancnt = plat->nr_channels;

        INIT_LIST_HEAD(&pdma->dma.channels);                      //初始化dma通道队列

        for (i = 0; i < plat->nr_channels; i++) {
                struct pl080_dma_chan *pdc = &pdma->chan[i];

                pdc->chan.device = &pdma->dma;
                pdc->chan.cookie = pdc->completed = 0;
                pdc->chan.chan_id = i;

                list_add_tail(&pdc->chan.device_node, &
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值