zoukankan      html  css  js  c++  java
  • 多功能设备mfd驱动

    一、概述

    mfd是Multifunction device的简称,即多功能设备,是许多有共性的设备的集合,mfd由核心层(core)以及其下的“子设备”组成。从下文将会看到,mfd只是将设备注册到platform总线——因此,其子设备属于platform设备。它并没有对涉及到的设备或驱动做实质性改变。但是,因为某些设备的共性,所以可以在mfd中提供共同的函数给其下子设备进行调用。

    本文提到的hisi_fmc驱动就是如此:

    下面就分析mfd设备注册过程,并结合1个实例讲解。

    内核配置(make menuconfig)信息如下:

    在里面可以选中自己需要的器件;

    .config文件中配置CONFIG_MFD_CORE=y

    二、mfd设备添加

    mfd核心代码位于drivers/mfd/mfd-core.c文件中。对外提供添加设备和删除设备的接口:mfd_add_devices、mfd_remove_devices。设备添加函数原型如下:

    int mfd_add_devices(struct device *parent, int id,
    		    const struct mfd_cell *cells, int n_devs,
    		    struct resource *mem_base,
    		    int irq_base, struct irq_domain *domain)
    
    • id:即设备ID号。它指示着设备的个数。一般可以设置为-1。即表示系统有且仅有一个这样的设备。如果有多个foo设备,则需要使用id来区别。

    在/sys/bus/platform/devices目录下会产生foo.0,foo.1等设备。详情可以看platform设备添加函数过程。

    • cells:即mfd_cell结构体数组,n_devs为其数组大小,即设备数量。

    • mem_base:资源resource结构体。如果没有,可置为NULL。

    描述mfd设备单元称为“cell”,mfd_cell定义如下:

    /*
     * This struct describes the MFD part ("cell").
     * After registration the copy of this structure will become the platform data
     * of the resulting platform_device
     */
    struct mfd_cell {
    	const char		*name;
    	int			id;
     
    	/* refcounting for multiple drivers to use a single cell */
    	atomic_t		*usage_count;
    	int			(*enable)(struct platform_device *dev);
    	int			(*disable)(struct platform_device *dev);
     
    	int			(*suspend)(struct platform_device *dev);
    	int			(*resume)(struct platform_device *dev);
     
    	/* platform data passed to the sub devices drivers */
    	void			*platform_data;
    	size_t			pdata_size;
    	/*
    	 * Device Tree compatible string
    	 * See: Documentation/devicetree/usage-model.txt Chapter 2.2 for details
    	 */
    	const char		*of_compatible;
     
    	/*
    	 * These resources can be specified relative to the parent device.
    	 * For accessing hardware you should use resources from the platform dev
    	 */
    	int			num_resources;
    	const struct resource	*resources;
     
    	/* don't check for resource conflicts */
    	bool			ignore_resource_conflicts;
     
    	/*
    	 * Disable runtime PM callbacks for this subdevice - see
    	 * pm_runtime_no_callbacks().
    	 */
    	bool			pm_runtime_no_callbacks;
     
    	/* A list of regulator supplies that should be mapped to the MFD
    	 * device rather than the child device when requested
    	 */
    	const char * const	*parent_supplies;
    	int			num_parent_supplies;
    };
    

    部分常见的成员介绍如下:

    • name:设备平台。
    • platform_data:平台私有数据指针,数据大小使用pdata_size表示。
    • resources:资源结构体,资源数量使用num_resources表示。
    • ignore_resource_conflicts:为true表示不检查资源冲突。
    • of_compatible:设备树匹配compatible的字符串(具体参考Documentation/devicetree/usage-model.txt Chapter 2.2)这个根据我的理解,是用于platform device的,只是写在了mfd设备上;

    至此,mfd设备的添加就完成了,最终调用驱动的probe函数。从这个过程中知道,mfd实质上就是封装一个接口,将一些可以归纳到一起的platform设备注册到platform总线上。它就是一个收纳盒子。里面的设备该是怎样处理就怎样处理。

    三、mfd实例

    下面介绍hisi_fmc驱动的实例:

    
    static int hisi_fmc_probe(struct platform_device *pdev)
    {
    	struct hisi_fmc *fmc;
    	struct resource *res;
    	struct device *dev = &pdev->dev;
    	int ret;
    
    	pr_err("hisi_fmc_probe successfully!
    ");
    	fmc = devm_kzalloc(dev, sizeof(*fmc), GFP_KERNEL);
    	if (!fmc)
    		return -ENOMEM;
    
    	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "control");
    	fmc->regbase = devm_ioremap_resource(dev, res);
    	if (IS_ERR(fmc->regbase))
    		return PTR_ERR(fmc->regbase);
    
    	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
    	fmc->iobase = devm_ioremap_resource(dev, res);
    	if (IS_ERR(fmc->iobase))
    		return PTR_ERR(fmc->iobase);
    
    	fmc->clk = devm_clk_get(dev, NULL);
    	if (IS_ERR(fmc->clk))
    		return PTR_ERR(fmc->clk);
    
    	if (of_property_read_u32(dev->of_node, "max-dma-size", &fmc->dma_len)) {
    		dev_err(dev, "Please set the suitable max-dma-size value !!!
    ");
    		return -ENOMEM;
    	}
    
    	ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
    	if (ret) {
    		dev_warn(dev, "Unable to set dma mask
    ");
    		return ret;
    	}
    
    	fmc->buffer = dmam_alloc_coherent(dev, fmc->dma_len,
    			&fmc->dma_buffer, GFP_KERNEL);
    	if (IS_ERR(fmc->buffer))
    		return PTR_ERR(fmc->buffer);
    
    	mutex_init(&fmc->lock);
    
    	platform_set_drvdata(pdev, fmc);
    
    	ret = mfd_add_devices(dev, 0, hisi_fmc_devs,
    			ARRAY_SIZE(hisi_fmc_devs), NULL, 0, NULL);
    	if (ret) {
    		dev_err(dev, "add mfd devices failed: %d
    ", ret);
    		return ret;
    	}
    
    	return 0;
    }
    
    1. 读取fmc的reg_base、io_base;
    2. 获取最大的max-dma-size
    3. 添加mfd设备
    ret = mfd_add_devices(dev, 0, hisi_fmc_devs,
    			ARRAY_SIZE(hisi_fmc_devs), NULL, 0, NULL);
    
  • 相关阅读:
    30-语言入门-30-分数加减法
    29-语言入门-29-两点距离
    bootstrapcss3触屏滑块轮播图
    input输入样式,动画
    HTML5夜空烟花绽放动画效果
    精美留言、评论框,带微博表情
    Sublime Text 3汉化中文版
    直播英国脱欧各国反应?谁将是最大赢家?
    品牌关键字的重要性?是什么呢
    网站收录之网络推广
  • 原文地址:https://www.cnblogs.com/linhaostudy/p/10712956.html
Copyright © 2011-2022 走看看