如何基于OF系统和DTB配置文件编写设备驱动

先来看看DTB在系统中被使用的过程。

setup_machine_fdt()
直接在dtb中解析根节点的一些属性和子节点给系统早期使用。
解析”/”节点的model”属性给machine_desc赋值;
解析”/chosen”node中的”bootargs”属性给boot_command_line;
解析”/”节点的”#size-cells”、”#address-cells”属性;
解析”/memory”node中的”reg”属性,并将memory区域加入到系统;

unflatten_device_tree()
将DTB完全递归解析为内核使用的的device_node、property结构:

struct device_node,struct property
/* node和node之间树形结构的创建 */
        if (dad != NULL) {  
            np->parent = dad;
            np->sibling = dad->child;
            dad->child = np;
        }
    }

property->name:指针指向dtb strings blcok区域中的属性name
property->value:指针指向dtb stucture block区域中的属性data
根据"name"、 "device_type"属性,来给device_node结构中的name、type成员赋值
如果还有子node的存在,递归解析

of_platform_populate()
递归创建platform_device。
root节点下的第1级子节点创建成platform device
对root节点下的第1级子节点,如果有”compatible”属性创建对应platform device;
如果”compatible”属性等于of_default_bus_match_table(“simple-bus”/”simple-mfd”/”arm,amba-bus”)中任意一种,继续对其子节点进行platform device创建。

const struct of_device_id of_default_bus_match_table[]

获取dts中的root node
对root node的child node进行platform device创建
struct platform_device *dev;
void *platform_data = NULL;
递归对本node的child node进行platform device创建

of_platform_device_create_pdata()
分配node对应的platform_device结构,并且解析node中的"reg"、"interrupts"属性,作为platform_device->resource
device对应的bus为platform_bus_type

struct platform_device *dev;
dev->dev.bus = &platform_bus_type;
dev->dev.platform_data = platform_data;

注册platform_device->dev为标准的device
platform_device_put(dev);
根据device能够找到of node

struct device_node *np;
struct platform_device *dev;
dev->dev.of_node = of_node_get(np);

给resource分配空间并解析值

dev->num_resources = num_reg + num_irq;
dev->resource = res;

因为第1级子节点会被注册成platform device,例如i2c/spi控制器,那么对应也需要注册platform driver。

i2c控制器驱动为例:
首先会创建对应platform driver,把adapter注册成i2c device;
adapter的probe过程中,会调用of_i2c_register_devices()函数遍历控制器下挂的i2c设备的DTS节点,并将其注册成i2c_client;

static const struct of_device_id mtk_i2c_of_match[]
static struct platform_driver mt_i2c_driver = {
    .probe = mt_i2c_probe,
    .remove = mt_i2c_remove,
    .driver = {
        .name = I2C_DRV_NAME,
        .owner = THIS_MODULE,
        .of_match_table = of_match_ptr(mtk_i2c_of_match),
    },
};

static int mt_i2c_probe(struct platform_device *pdev)
{
struct platform_device *pdev;
struct mt_i2c *i2c;
struct resource *res;
const struct of_device_id *of_id;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->base))
        return PTR_ERR(i2c->base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c->pdmabase))
return PTR_ERR(i2c->pdmabase);
i2c->irqnr = platform_get_irq(pdev, 0);
i2c_set_adapdata(&i2c->adap, i2c);
ret = i2c_add_numbered_adapter(&i2c->adap);
if (ret) {
        dev_err(&pdev->dev, "Failed to add i2c bus to i2c core\n");
        return ret;
    }
}

注册adapter为i2c_bus上的device

static int i2c_register_adapter(struct i2c_adapter *adap)
{
struct i2c_adapter *adap;
res = device_register(&adap->dev);
}

遍历adapter node下的子node,并创建标准的i2c bus的device

static void of_i2c_register_devices(struct i2c_adapter *adap)
{
	struct device_node *node;
	of_i2c_register_device(adap, node);
}
static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
                         struct device_node *node)
{
	struct i2c_client *result;
	struct i2c_board_info info;
	struct dev_archdata dev_ad;
	addr_be = of_get_property(node, "reg", &len);
	addr = be32_to_cpup(addr_be);
	dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n";

}

具体的I2c设备驱动,在总线驱动使用of_i2c_register_devices()创建设备以后,就可以适配工作了。

i2c1: i2c@11090000 {
        compatible = "mediatek,mt6799-i2c";
        id = <1>;
        reg = <0 0x11090000 0 0x1000>,
            <0 0x11000100 0 0x80>;
        interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_LOW>;
        clocks = <&pericfg CLK_PERICFG_RG_I2C1_BCLK>, <&pericfg CLK_PERICFG_RG_AP_DM>;
        clock-names = "main", "dma";
        clock-div = <5>;
    };
&i2c1 {
    apds9922:apds9922@53 {
        compatible = "mediatek,apds9922";
        interrupt-parent = <&eintc>;
        interrupts = < 8 IRQ_TYPE_EDGE_FALLING>;
        debounce = <8 0>;
        gpio = < 8 >;
        reg = <0x53>;
        status = "okay";
    };
}
static const struct i2c_device_id mz_mag_id[] = {
    {"mediatek,mmc3530", 0 },
    {"mediatek,akm09911", 1 },
    { }
};
static struct i2c_driver mz_mag_driver = {
    .probe     = mz_mag_probe,
    .id_table  = mz_mag_id,
    .driver = {
        .name  = MZ_MAG_DEV_NAME,
        .owner = THIS_MODULE,
        #ifdef CONFIG_OF
        .of_match_table = of_match_ptr(msensor_of_match),
        #endif
    },
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值