OpenHarmony HDF 平台驱动框架介绍——I2C模块适配

技术探索者
发布于 2022-3-16 17:27
浏览
1收藏

上篇指南:OpenHarmony HDF 平台驱动框架介绍及驱动适配指导 

 

I2C模块适配

 

I2C模块适配的核心环节是I2cCntlr对象的创建、初始化及注册。

I2C采用的是统一服务模式,需要一个设备服务来作为I2C模块的管理器,统一处理外部访问。

 


1、 device_info.hcs配置

device_i2c :: device {

    device0 :: deviceNode {

        policy = 2;

        priority = 50;

        permission = 0644;

        moduleName = "HDF_PLATFORM_I2C_MANAGER";

        serviceName = "HDF_PLATFORM_I2C_MANAGER";

        deviceMatchAttr = "hdf_platform_i2c_manager";

    }

    device1 :: deviceNode {

        policy = 0;

        priority = 55;

        permission = 0644;

        moduleName = "hi35xx_i2c_driver";

        serviceName = "HI35XX_I2C_DRIVER";

        deviceMatchAttr = "hisilicon_hi35xx_i2c";

    }

}

 

首先第一个设备节点必须是I2C管理器,其各项参数必须如上一样设置。其中:

policy:这个同UART,具体配置为1或2取决于是否对用户态可见

moduleName: 固定为HDF_PLATFORM_I2C_MANAGER

serviceName: 固定为HDF_PLATFORM_I2C_MANAGER

deviceMatchAttr: 没有使用,可忽略

而从第二个设备节点开始,配置具体I2C控制器信息。这里device1 并不表示某一路I2C控制器,而是一个资源性质设备,用于描述一类I2C控制器的信息。

服务policy等于0,不需要发布服务;

moduleName用于指定驱动成语,需要与期望的驱动Entry中的moduleName一致;

ServiceName不需要使用,可忽略;

deviceMatchAttr用于配置控制器私有数据,要与i2c_config.hcs中对应控制器保持

同样,具体的控制器信息在i2c_config.hcs中,由具体产品在hdf.hcs中导入。

 


2、i2c_config.hcs中可配置多个控制器信息

root {

    platform {

        i2c_config {

            match_attr = "hisilicon_hi35xx_i2c";

 

            template i2c_controller {

                bus = 0;

                reg_pbase = 0x120b0000;

                reg_size = 0xd1;

                irq = 0;

                freq = 400000;

                clk = 50000000;

            }

            controller_0x120b0000 :: i2c_controller {

                bus = 0;

            }

            controller_0x120b1000 :: i2c_controller {

                bus = 1;

                reg_pbase = 0x120b1000;

            }

        }

    }

}

 

可以看到,这里配置了多个控制器的信息,而这些信息将在驱动程序员进行逐一解析、处理,生成对应的I2cCntlr对象。

 


3、I2C管理器服务的驱动由核心层实现

struct HdfDriverEntry g_i2cManagerEntry = {

    .moduleVersion = 1,

    .Bind = I2cManagerBind,

    .Init = I2cManagerInit,

    .Release = I2cManagerRelease,

    .moduleName = "HDF_PLATFORM_I2C_MANAGER",

};

HDF_INIT(g_i2cManagerEntry);

 

驱动适配人员无需关注这个驱动的实现,有兴趣的可以去阅读源码。

drivers/framework/support/platform/src/i2c_core.c

 

 

4、适配驱动Entry只需要实现Init方法

struct HdfDriverEntry g_i2cDriverEntry = {

.moduleVersion = 1,

    .Init = Hi35xxI2cInit,

    .Release = Hi35xxI2cRelease,

    .moduleName = "hi35xx_i2c_driver",

};

HDF_INIT(g_i2cDriverEntry);

static int32_t Hi35xxI2cInit(struct HdfDeviceObject *device)

{

int32_t ret;

    const struct DeviceResourceNode *childNode = NULL;

    ret = HDF_SUCCESS;

    DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) {

        ret = Hi35xxI2cParseAndInit(device, childNode);

        if (ret != HDF_SUCCESS) {

            break;

        }

    }

    return ret;

}

 

在Init方法中会将i2c_config.hcs中定义的每一个节点取出,分别进行初始化

 

5、Hi35xxI2cParseAndInit里面很自由

static int32_t Hi35xxI2cParseAndInit(struct HdfDeviceObject *device, const struct DeviceResourceNode *node)

{

    int32_t ret;

    struct Hi35xxI2cCntlr *hi35xx = NULL;

    (void)device;

 

    hi35xx = (struct Hi35xxI2cCntlr *)OsalMemCalloc(sizeof(*hi35xx));

    ret = Hi35xxI2cReadDrs(hi35xx, node);

    hi35xx->regBase = OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize);

    Hi35xxI2cCntlrInit(hi35xx);

 

    hi35xx->cntlr.priv = (void *)node;

    hi35xx->cntlr.busId = hi35xx->bus;

    hi35xx->cntlr.ops = &g_method;

    hi35xx->cntlr.lockOps = &g_lockOps;

    (void)OsalSpinInit(&hi35xx->spin);

    ret = I2cCntlrAdd(&hi35xx->cntlr);

    ....

}

 

Hi35xxI2cParseAndInit会处理一个具体的I2C控制器的初始化工作,包括:

1)I2cCntlr对象的分配,Hi35xxI2cCntlr头部内嵌了一个I2cCntlr,这是一种继承。

 

struct Hi35xxI2cCntlr {

    struct I2cCntlr cntlr;

    OsalSpinlock spin;

    volatile unsigned char  *regBase;

    uint16_t regSize;

    int16_t bus;

    uint32_t clk;

    uint32_t freq;

    uint32_t irq;

    uint32_t regBasePhy;

};

 

2)在Hi35xxI2cReadDrs中完成节点属性的读取,并填充进hi35xx对象

3)映射寄存器基地址OsalIoRemap(hi35xx->regBasePhy, hi35xx->regSize);

4)调用Hi35xxI2cCntlrInit完成控制器的初始化

5)I2cCntlr对象的填充及调用I2cCntlrAdd注册

这里唯一形式化约束是必须创建一个合法的I2cCntlr并调用I2cCntlrAdd注册到核心层。其他Hi35xx开头的函数都是驱动适配者自由封装的,并无形式化要求。

 

 

 

 

总结

采用统一服务模式,其优点是不用为每一个I2C控制器定义一个设备节点,控制器对象的创建和注册比较自由;而缺点是要创建一个I2C管理器服务,以及一个虚拟的资源描述设备。

 

说明

I2C模块适配涉及到的代码示例片段来自device/hisilicon/drivers/i2c/

 

 

 

已于2022-3-16 17:27:37修改
收藏 1
回复
举报
回复
    相关推荐