当前位置:   article > 正文

Openharmony - HDF平台驱动之I2C驱动和测试程序

Openharmony - HDF平台驱动之I2C驱动和测试程序

By: fulinux
E-mail: fulinux@sina.com
Blog: https://blog.csdn.net/fulinus
喜欢的盆友欢迎点赞和订阅!
你的喜欢就是我写作的动力!

在这里插入图片描述

概述

我们鸿蒙3.2设备上连接了sensor,如accel和gyro,是通过i2c总线连接的,在鸿蒙HDF的设备私有信息配置文件如下描述:

vendor/sprd/uis7885/hdf_config/khdf/sensor/accel/qmi8658_config.hcs
sensorBusConfig :: sensorBusInfo {
   
	busType = 0; // 0:i2c 1:spi
	busNum = 2;
	busAddr = 0x6b;
	regWidth = 1; // 1byte
}
sensorIdAttr :: sensorIdInfo {
   
    chipName = "qmi8658";
    chipIdRegister = 0x00;
    chipIdValue = 0x05;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

即总线是i2c2,从设备的sensor地址是0x6b,chip id的寄存器地址是0x00。chip id值是0x5。
我们先研究下如何通过测试程序来操作I2C,读取这个chip id值。

I2C平台驱动

鸿蒙标准系统中,使用的是Linux内核,这个没有官网上的I2C平台驱动中描述的这样需要编写I2C平台驱动。
使用这个I2C平台驱动文件:drivers/hdf_core/adapter/khdf/linux/platform/i2c/i2c_adapter.c
比如获取对应的I2C adapter:

static int LinuxI2cProbe(struct device *dev, void *data)
{
   
    int32_t ret;
    struct I2cCntlr *cntlr = NULL;
    struct i2c_adapter *adapter = NULL;

    (void)data;

    if (dev == NULL) {
   
        HDF_LOGE("%s: dev is null", __func__);
        return HDF_ERR_INVALID_OBJECT;
    }   

    if (dev->type != &i2c_adapter_type) {
   
        return HDF_SUCCESS; // continue probe
    }   

    HDF_LOGI("%s: Enter", __func__);
    adapter = to_i2c_adapter(dev); //获取i2c adapter
    cntlr = (struct I2cCntlr *)OsalMemCalloc(sizeof(*cntlr));
    if (cntlr == NULL) {
   
        HDF_LOGE("%s: malloc cntlr fail!", __func__);
        i2c_put_adapter(adapter);
        return HDF_ERR_MALLOC_FAIL;
    }   

    cntlr->busId = adapter->nr;
    cntlr->priv = adapter;
    cntlr->ops = &g_method;
    ret = I2cCntlrAdd(cntlr); //这个I2C控制器添加到HDF框架中,后面会在I2cOpen函数中调用I2cCntlrGet函数查找到对应的控制器
    if (ret != HDF_SUCCESS) {
   
        i2c_put_adapter(adapter);
        OsalMemFree(cntlr);
        cntlr = NULL;
        HDF_LOGE("%s: add controller fail:%d", __func__, ret);
        return ret;
    }   
    HDF_LOGI("%s: i2c adapter %d add success", __func__, cntlr->busId);
    return HDF_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

参考:http://docs.openharmony.cn/pages/v3.2/zh-cn/device-dev/guide/device-driver-demo.md/
上面我们提及to_i2c_adapter添加i2c 适配器,然后又将总线ID、适配器和操作方法等通过I2cCntlrAdd添加到HDF驱动框架中,后面在UHDF或KHDF中通过调用I2cOpen函数,间接调用了I2cCntlrGet函数,在HDF框架中找到对应的总线ID、适配器和操作方法等,然后就可以操作I2C总线了。
I2cCntlrAdd函数:

//drivers/hdf_core/framework/support/platform/src/i2c/i2c_core.c
int32_t I2cCntlrAdd(struct I2cCntlr *cntlr)
{
   
    int32_t ret;

    if (cntlr == NULL) {
   
        return HDF_ERR_INVALID_OBJECT;
    }   

    if (cntlr->ops == NULL) {
   
        HDF_LOGE("I2cCntlrAdd: no ops supplied!");
        return HDF_ERR_INVALID_OBJECT;
    }   

    if (cntlr->lockOps == NULL) {
   
        HDF_LOGI("I2cCntlrAdd: use default lock methods!");
        cntlr->lockOps = &g_i2cLockOpsDefault;
    }   

    if (OsalMutexInit(&cntlr->lock) != HDF_SUCCESS) {
   
        HDF_LOGE("I2cCntlrAdd: init lock fail!");
        return HDF_FAILURE;
    }   

    ret = I2cManagerAddCntlr(cntlr);
    if (ret != HDF_SUCCESS) {
   
        (void)OsalMutexDestroy(&cntlr->lock);
        return ret;
    }   
    return HDF_SUCCESS;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

I2cOpen函数:

DevHandle I2cOpen(int16_t number)
{
   
    return (DevHandle)I2cCntlrGet(number);
}
  • 1
  • 2
  • 3
  • 4
  • 5

I2cCntlrGet函数:

/*
 * Find an i2c controller by bus number, without ref count
 */
static struct I2cCntlr *I2cManagerFindCntlr(int16_t number)
{
   
    struct I2cCntlr *cntlr = NULL;
    struct I2cManager *manager = g_i2cManager;

    if (number < 0 || number >= I2C_BUS_MAX) {
   
        HDF_LOGE("I2cManagerFindCntlr: invalid busId:%hd!", number);
        return NULL;
    }

    if (manager == NULL) {
   
        HDF_LOGE("I2cManagerFindCntlr: get i2c manager fail!");
        return NULL;
    }

    if (OsalMutexLock(&manager->lock) != HDF_SUCCESS) {
   
        HDF_LOGE("I2cManagerFindCntlr: lock i2c manager fail!");
        return NULL;
    }
    cntlr = manager->cntlrs[number];
    (void)OsalMutexUnlock(&manager->lock);
    return cntlr;
}

/*
 * Find and return an i2c controller by number, with ref count
 */
struct I2cCntlr *I2cCntlrGet(int16_t number)
{
   
    return I2cManagerFindCntlr(number);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在drivers/hdf_core/framework/support/platform/src/i2c/i2c_core.c文件中,主要就是实现这个上述这些功能

I2C平台驱动HDF框架

I2C平台驱动既可以为其他HDF驱动提供接口,比如挂接在I2C总线上的sensor驱动,也可以为用户空间提供通用的操作接口。这些接口都是这些:I2cOpen(),I2cClose(),I2cTransfer()。所以可以在drivers/hdf_core/framework/support/platform/src/i2c/中看到有这两个文件:

drivers/hdf_core/framework/support/platform/src/i2c/i2c_if.c
drivers/hdf_core/framework/support/platform/src/i2c/i2c_if_u.c
  • 1
  • 2

其中i2c_if.c就是对其他HDF驱动提供接口的:

#include "i2c_if.h"
#include "devsvc_manager_clnt.h"
#include "hdf_base.h"
#include "hdf_log.h"
#include "i2c_core.h"
#include "osal_mem.h"
#include "securec.h"

#define HDF_LOG_TAG i2c_if

#define I2C_SERVICE_NAME "HDF_PLATFORM_I2C_MANAGER"

DevHandle I2cOpen(int16_t number)
{
   
    return (DevHandle)I2cCntlrGet(number);
}

void I2cClose(DevHandle handle)
{
   
    if (handle != NULL) {
   
        I2cCntlrPut((struct I2cCntlr *)handle);
    }
}

int32_t I2cTransfer(DevHandle handle, struct I2cMsg *msgs, int16_t count)
{
   
    if (handle == NULL) {
   
        return HDF_ERR_INVALID_OBJECT;
    }

    if (msgs == NULL || count <= 0) {
   
        HDF_LOGE("I2cTransfer: err params! msgs:%s, count:%hd",
            (msgs == NULL) ? "0" : "x", count);
        return HDF_ERR_INVALID_PARAM;
    }

    return I2cCntlrTransfer((struct I2cCntlr *)handle, msgs, count);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

其中i2c_if_u.c就是对用户空间提供通用的操作接口:

#include "hdf_base.h"
#include "hdf_io_service_if.h"
#include "hdf_log.h"
#include "i2c_if.h"
#include "i2c_service.h"
  • 1
  • 2
  • 3
  • 4
  • 5
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/179238
推荐阅读
相关标签
  

闽ICP备14008679号