driver-platform-pin-develop.md 20.2 KB
Newer Older
1
# PIN
2 3


4
## 概述
5

6
### 功能简介
J
jiaziyang 已提交
7
PIN即管脚控制器,用于统一管理各SoC厂商管脚资源,对外提供管脚复用功能。
8

9
### 基本概念
J
jiaziyang 已提交
10 11 12 13 14 15 16 17 18 19 20

PIN是一个软件层面的概念,目的是为了统一各SoC厂商PIN管脚管理,对外提供管脚复用功能,配置PIN管脚的电气特性。

- SoC(System on Chip)

  系统级芯片,也有称作片上系统,通常是面向特定用途将微处理器、模拟IP核、数字IP核和存储器集成在单一芯片的标准产品。

- 管脚复用

  由于芯片自身的引脚数量有限,无法满足日益增多的外接需求。此时可以通过软件层面的寄存器设置,让引脚工作在不同的状态,从而实现相同引脚完成不同功能的目的。

21
### 运作机制
J
jiaziyang 已提交
22

D
duangavin123 已提交
23
在HDF框架中,PIN模块暂不支持用户态,所以不需要发布服务,接口适配模式采用无服务模式(如图1所示),用于不需要在用户态提供API的设备类型,或者没有用户态和内核区分的OS系统,其关联方式是DevHandle直接指向设备对象内核态地址(DevHandle是一个void类型指针)。
J
jiaziyang 已提交
24 25 26 27

PIN模块各分层作用:接口层提供获取PIN管脚、设置PIN管脚推拉方式、获取PIN管脚推拉方式、设置PIN管脚推拉强度、获取PIN管脚推拉强度、设置PIN管脚功能、获取PIN管脚功能、释放PIN管脚的接口。核心层主要提供PIN管脚资源匹配,PIN管脚控制器的添加、移除以及管理的能力,通过钩子函数与适配层交互。适配层主要是将钩子函数的功能实例化,实现具体的功能。

**图 1**  无服务模式结构图
D
duangavin123 已提交
28

29
![无服务模式结构图](figures/无服务模式结构图.png)
30

31
### 约束与限制
J
jiaziyang 已提交
32

33
PIN模块目前仅支持轻量和小型系统内核(LiteOS)。
J
jiaziyang 已提交
34

35
## 开发指导
J
jiaziyang 已提交
36

37
### 场景介绍
38

J
jiaziyang 已提交
39 40
PIN模块主要用于管脚资源管理。在各SoC厂商对接HDF框架时,需要来适配PIN驱动。

41
### 接口说明
J
jiaziyang 已提交
42 43

通过以下PinCntlrMethod中的函数调用PIN驱动对应的函数。
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
PinCntlrMethod定义:

```c
struct PinCntlrMethod {
    int32_t (*SetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType pullType);
    int32_t (*GetPinPull)(struct PinCntlr *cntlr, uint32_t index, enum PinPullType *pullType);
    int32_t (*SetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t strength);
    int32_t (*GetPinStrength)(struct PinCntlr *cntlr, uint32_t index, uint32_t *strength);
    int32_t (*SetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char *funcName);
    int32_t (*GetPinFunc)(struct PinCntlr *cntlr, uint32_t index, const char **funcName);
};
```

**表 1**  PinCntlrMethod成员的回调函数功能说明

J
jiaziyang 已提交
59 60 61 62 63 64 65 66 67
| 成员函数     | 入参                                        | 出参                                   | 返回值 | 功能 |
| ------------ | ------------------------------------------- | ------ | ---- | ---- |
| SetPinPull | **cntlr**:结构体指针,核心层Pin控制器;<br>**index**:uint32_t变量,管脚索引号;<br/>**pullType**:枚举常量,Pin管脚推拉方式; | 无 |HDF_STATUS相关状态|PIN设置管脚推拉方式|
| GetPinPull | **cntlr**:结构体指针,核心层Pin控制器;<br/>**index**:uint32_t变量,管脚索引号; | **pullType**:枚举常量指针,传出Pin管脚推拉方式; | HDF_STATUS相关状态 | PIN获取管脚推拉方式 |
| SetPinStrength | **cntlr**:结构体指针,核心层Pin控制器;<br/>**index**:uint32_t变量,管脚索引号;<br/>**strength**:uint32_t变量,Pin推拉强度; | 无 | HDF_STATUS相关状态 | PIN设置推拉强度 |
| GetPinStrength | **cntlr**:结构体指针,核心层Pin控制器;<br/>**index**:uint32_t变量,管脚索引号; | **strength**:uint32_t变量指针,传出Pin推拉强度; | HDF_STATUS相关状态 | PIN获取推拉强度 |
| SetPinFunc | **cntlr**:结构体指针,核心层Pin控制器;<br/>**index**:uint32_t变量,管脚索引号;<br/>**funcName**:char指针常量,传入Pin管脚功能; | 无 | HDF_STATUS相关状态 | PIN设置管脚功能 |
| GetPinFunc | **cntlr**:结构体指针,核心层Pin控制器;<br/>**index**:uint32_t变量,管脚索引号; | **funcName**:char双重指针常量,传出Pin管脚功能; | HDF_STATUS相关状态 | PIN获取管脚功能 |

68
### 开发步骤
69

J
jiaziyang 已提交
70
PIN模块适配包含以下四个步骤:
71

J
jiaziyang 已提交
72 73 74 75
- 实例化驱动入口。
- 配置属性文件。
- 实例化核心层接口函数。
- 驱动调试。
76

Y
modify  
yinshuqing 已提交
77
1. **实例化驱动入口:**
J
jiaziyang 已提交
78

79
   - 实例化HdfDriverEntry结构体成员。
80
     驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf_device_desc.h 中定义)类型的全局变量,且moduleName要和device_info.hcs中保持一致。
J
jiaziyang 已提交
81

82
   - 调用HDF_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
J
jiaziyang 已提交
83 84 85 86 87 88 89 90 91 92 93 94
     一般在加载驱动时HDF会先调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。

        ```c
        static struct HdfDriverEntry g_hi35xxPinDriverEntry = {
            .moduleVersion = 1,
            .Bind = Hi35xxPinBind,
            .Init = Hi35xxPinInit,
            .Release = Hi35xxPinRelease,
            .moduleName = "hi35xx_pin_driver", // 【必要且与HCS文件中里面的moduleName匹配】
        };
        HDF_INIT(g_hi35xxPinDriverEntry); // 调用HDF_INIT将驱动入口注册到HDF框架中
        ```
95

J
jiaziyang 已提交
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
2. **配置属性文件:**
   - 在vendor/hisilicon/hispark_taurus/hdf_config/device_info/device_info.hcs文件中添加deviceNode描述。
        ```c
        root {
            device_info { 
                platform :: host {
                    hostName = "platform_host";
                    priority = 50;
                    device_pin :: device {
                        device0 :: deviceNode {   // 为每一个Pin控制器配置一个HDF设备节点,存在多个时须添加,否则不用
                            policy = 0;			  // 2:用户态可见,1:内核态可见,0:不需要发布服务
                            priority = 10;        // 驱动启动优先级
                            permission = 0644;    // 驱动创建设备节点权限
                            /* 【必要】用于指定驱动名称,需要与期望的驱动Entry中的moduleName一致 */
                            moduleName = "hi35xx_pin_driver";
                            /* 【必要】用于配置控制器私有数据,要与pin_config.hcs中对应控制器保持一致,具体的控制器信息在pin_config.hcs中 */
                            deviceMatchAttr = "hisilicon_hi35xx_pin_0";
                        }
                        device1 :: deviceNode {
                            policy = 0;
                            priority = 10;
                            permission = 0644;
                            moduleName = "hi35xx_pin_driver";
                            deviceMatchAttr = "hisilicon_hi35xx_pin_1";
                        }
                        ......
                    }
                }
            }
        }
        ```
   - 添加pin_config.hcs器件属性文件。
     在device/soc/hisilicon/hi3516dv300/sdk_liteos/hdf_config/pin/pin_config.hcs目录下配置器件属性 ,其中配置参数如下:
        ```c
        root {
            platform {
                pin_config_hi35xx {
                    template pin_controller {    // 【必要】模板配置,继承该模板的节点如果使用模板中的默认值,则节点字段可以缺省
                        number = 0;              // 【必要】controller编号
                        regStartBasePhy = 0;     // 【必要】寄存器物理基地址起始地址
                        regSize = 0;             // 【必要】寄存器位宽
                        pinCount = 0;            // 【必要】管脚数量
                        match_attr = "";
                        template pin_desc {
                            pinName = "";        // 【必要】管脚名称
                            init = 0;            // 【必要】寄存器默认值
                            F0 = "";             // 【必要】功能0
                            F1 = "";             // 功能1
                            F2 = "";             // 功能2
                            F3 = "";             // 功能3
                            F4 = "";             // 功能4
                            F5 = "";             // 功能5
                        }
                    }
                    controller_0 :: pin_controller {
                        number = 0;
                        regStartBasePhy = 0x10FF0000;
                        regSize = 0x48;
                        pinCount = 18;
                        match_attr = "hisilicon_hi35xx_pin_0";
                        T1 :: pin_desc {
                            pinName = "T1";
                            init = 0x0600;
                            F0 = "EMMC_CLK";
                            F1 = "SFC_CLK";
                            F2 = "SFC_BOOT_MODE";
                        }
                        ...... // 对应管脚控制器下的每个管脚,按实际添加
                    }
                    ......//每个管脚控制器对应一个controller节点,如存在多个Pin控制器,请依次添加对应的controller节点。
                }
            }
        }
        ```
170

Y
modify  
yinshuqing 已提交
171
3. **实例化PIN控制器对象:**
172
   - 初始化PinCntlr成员。
J
jiaziyang 已提交
173
     在Hi35xxPinCntlrInit函数中对PinCntlr成员进行初始化操作。
174

J
jiaziyang 已提交
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265
        ```c
        struct Hi35xxPinDesc {
            // 管脚名
            const char *pinName;
            // 初始化值
            uint32_t init;
            // 管脚索引
            uint32_t index;
            // 管脚推拉方式
            int32_t pullType;
            // 管脚推拉强度
            int32_t strength;
            // 管脚功能名字符串数组
            const char *func[HI35XX_PIN_FUNC_MAX];
        };
        
        struct Hi35xxPinCntlr {
            // 管脚控制器
            struct PinCntlr cntlr;
            // 管脚描述结构体指针
            struct Hi35xxPinDesc *desc;
            // 寄存器映射地址
            volatile unsigned char *regBase;
            // 管脚控制器编号
            uint16_t number;
            // 寄存器物理基地址起始地址
            uint32_t regStartBasePhy;
            // 寄存器位宽
            uint32_t regSize;
            // 管脚数量
            uint32_t pinCount;
        };
        
        // PinCntlr是核心层控制器,其中的成员在init函数中会被赋值
        struct PinCntlr {
            struct IDeviceIoService service;
            struct HdfDeviceObject *device;
            struct PinCntlrMethod *method;
            struct DListHead node;  // 链表节点
            OsalSpinlock spin;      // 自旋锁
            uint16_t number;        // 管脚控制器编号
            uint16_t pinCount;      // 管脚数量
            struct PinDesc *pins;
            void *priv;             // 私有数据
        };
        
        // PinCntlr管脚控制器初始化
        static int32_t Hi35xxPinCntlrInit(struct HdfDeviceObject *device, struct Hi35xxPinCntlr *hi35xx)
        {
            struct DeviceResourceIface *drsOps = NULL;
            int32_t ret;
            // 从hcs文件读取管脚控制器相关属性
            drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
            if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetUint16 == NULL) {
                HDF_LOGE("%s: invalid drs ops fail!", __func__);
                return HDF_FAILURE;
            }
            ret = drsOps->GetUint16(device->property, "number", &hi35xx->number, 0);
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read number failed", __func__);
                return ret;
            }
            
            ret = drsOps->GetUint32(device->property, "regStartBasePhy", &hi35xx->regStartBasePhy, 0);
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read regStartBasePhy failed", __func__);
                return ret;
            }
            ret = drsOps->GetUint32(device->property, "regSize", &hi35xx->regSize, 0);
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read regSize failed", __func__);
                return ret;
            }
            ret = drsOps->GetUint32(device->property, "pinCount", &hi35xx->pinCount, 0);
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read pinCount failed", __func__);
                return ret;
            }
            // 将读取的值赋值给管脚控制器的成员,完成管脚控制器初始化
            hi35xx->cntlr.pinCount = hi35xx->pinCount;
            hi35xx->cntlr.number = hi35xx->number;
            hi35xx->regBase = OsalIoRemap(hi35xx->regStartBasePhy, hi35xx->regSize);  // 管脚控制器映射
            if (hi35xx->regBase == NULL) {
                HDF_LOGE("%s: remap Pin base failed", __func__);
                return HDF_ERR_IO;
            }
            hi35xx->desc = (struct Hi35xxPinDesc *)OsalMemCalloc(sizeof(struct Hi35xxPinDesc) * hi35xx->pinCount);
            hi35xx->cntlr.pins = (struct PinDesc *)OsalMemCalloc(sizeof(struct PinDesc) * hi35xx->pinCount);
            return HDF_SUCCESS;
        }
        ```
266

J
jiaziyang 已提交
267
   - PinCntlr成员回调函数结构体PinCntlrMethod的实例化,其他成员在Init函数中初始化。
268

J
jiaziyang 已提交
269 270 271 272 273 274 275 276 277 278 279
        ```c
        // PinCntlrMethod结构体成员都是回调函数,厂商需要根据表1完成相应的函数功能。
        static struct PinCntlrMethod g_method = {
            .SetPinPull = Hi35xxPinSetPull,              // 设置推拉方式
            .GetPinPull = Hi35xxPinGetPull,              // 获取推拉方式
            .SetPinStrength = Hi35xxPinSetStrength,      // 设置推拉强度
            .GetPinStrength = Hi35xxPinGetStrength,      // 获取推拉强度
            .SetPinFunc = Hi35xxPinSetFunc,              // 设置管脚功能
            .GetPinFunc = Hi35xxPinGetFunc,              // 获取管脚功能
        };
        ```
280

J
jiaziyang 已提交
281
   - Init函数
282

J
jiaziyang 已提交
283 284
        入参:
        HdfDeviceObject这个是整个驱动对外暴露的接口参数,具备HCS配置文件的信息。
285

J
jiaziyang 已提交
286
        返回值:
287
        HDF\_STATUS相关状态(下表为部分展示,如需使用其他状态,可见/drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
288
   
J
jiaziyang 已提交
289 290 291 292 293 294 295 296 297 298 299 300
        | **状态(值)**           | **问题描述**   |
        | ---------------------- | -------------- |
        | HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
        | HDF_ERR_MALLOC_FAIL    | 内存分配失败   |
        | HDF_ERR_INVALID_PARAM  | 参数非法       |
        | HDF_ERR_IO             | I/O 错误       |
        | HDF_SUCCESS            | 初始化成功     |
        | HDF_FAILURE            | 初始化失败     |
       
        函数说明:
        初始化自定义结构体对象和PinCntlr成员,并通过调用核心层PinCntlrAdd函数挂载Pin控制器。
        
Y
modify  
yinshuqing 已提交
301
        ```c
J
jiaziyang 已提交
302
        static int32_t Hi35xxPinReadFunc(struct Hi35xxPinDesc *desc, const struct DeviceResourceNode *node, struct DeviceResourceIface *drsOps)
Y
modify  
yinshuqing 已提交
303
        {
J
jiaziyang 已提交
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333
            int32_t ret;
            uint32_t funcNum = 0;
            // 从hcs中读取管脚控制器子节点管脚功能名
            ret = drsOps->GetString(node, "F0", &desc->func[funcNum], "NULL");
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read F0 failed", __func__);
                return ret;
            }

            funcNum++;
            ret = drsOps->GetString(node, "F1", &desc->func[funcNum], "NULL");
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read F1 failed", __func__);
                return ret;
            }

            funcNum++;
            ......
            return HDF_SUCCESS;
        }

        static int32_t Hi35xxPinParsePinNode(const struct DeviceResourceNode *node, struct Hi35xxPinCntlr *hi35xx, int32_t index)
        {
            int32_t ret;
            struct DeviceResourceIface *drsOps = NULL;
            // 从hcs中读取管脚控制器子节点管脚相关属性
            drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
            if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) {
                HDF_LOGE("%s: invalid drs ops fail!", __func__);
                return HDF_FAILURE;
Y
modify  
yinshuqing 已提交
334
            }
J
jiaziyang 已提交
335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
            ret = drsOps->GetString(node, "pinName", &hi35xx->desc[index].pinName, "NULL");
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read pinName failed", __func__);
                return ret;
            }
            ......
            ret = Hi35xxPinReadFunc(&hi35xx->desc[index], node, drsOps);
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s:Pin read Func failed", __func__);
                return ret;
            }
            hi35xx->cntlr.pins[index].pinName = hi35xx->desc[index].pinName;
            hi35xx->cntlr.pins[index].priv = (void *)node;
            ......
            return HDF_SUCCESS;
Y
modify  
yinshuqing 已提交
350
        }
J
jiaziyang 已提交
351 352

        static int32_t Hi35xxPinInit(struct HdfDeviceObject *device)
Y
modify  
yinshuqing 已提交
353
        {
J
jiaziyang 已提交
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370
            ......
            struct Hi35xxPinCntlr *hi35xx = NULL;
            ......
            ret = Hi35xxPinCntlrInit(device, hi35xx);    // 管脚控制器初始化
            ......
            DEV_RES_NODE_FOR_EACH_CHILD_NODE(device->property, childNode) { // 遍历管脚控制器的每个子节点
                ret = Hi35xxPinParsePinNode(childNode, hi35xx, index);    // 解析子节点
                ......
            }

            hi35xx->cntlr.method = &g_method;    // 实例化method
            ret = PinCntlrAdd(&hi35xx->cntlr);   // 挂载控制器
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: add Pin cntlr: failed", __func__);
                ret = HDF_FAILURE;
            }
            return HDF_SUCCESS;
Y
modify  
yinshuqing 已提交
371
        }
J
jiaziyang 已提交
372
        ```
373

J
jiaziyang 已提交
374
   - Release 函数
375

Y
modify  
yinshuqing 已提交
376
        入参:
377

Y
modify  
yinshuqing 已提交
378
        HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
J
jiaziyang 已提交
379
   
Y
modify  
yinshuqing 已提交
380
        返回值:
J
jiaziyang 已提交
381
   
Y
modify  
yinshuqing 已提交
382
        无。
J
jiaziyang 已提交
383
   
Y
modify  
yinshuqing 已提交
384
        函数说明:
J
jiaziyang 已提交
385
   
Y
modify  
yinshuqing 已提交
386
        释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。
387

Y
modify  
yinshuqing 已提交
388 389 390
        ```c
        static void Hi35xxPinRelease(struct HdfDeviceObject *device)
        {
J
jiaziyang 已提交
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
            int32_t ret;
            uint16_t number;
            struct PinCntlr *cntlr = NULL;
            struct Hi35xxPinCntlr *hi35xx = NULL;
            struct DeviceResourceIface *drsOps = NULL;
        
            if (device == NULL || device->property == NULL) {
                HDF_LOGE("%s: device or property is null", __func__);
                return;
            }
            // 从hcs文件中读取管脚控制器编号
            drsOps = DeviceResourceGetIfaceInstance(HDF_CONFIG_SOURCE);
            if (drsOps == NULL || drsOps->GetUint32 == NULL || drsOps->GetString == NULL) {   
                HDF_LOGE("%s: invalid drs ops", __func__);
                return;
            }
            ret = drsOps->GetUint16(device->property, "number", &number, 0);
            if (ret != HDF_SUCCESS) {
                HDF_LOGE("%s: read cntlr number failed", __func__);
                return;
            }
         
            cntlr = PinCntlrGetByNumber(number);   // 通过管脚控制器编号获取管脚控制器
            PinCntlrRemove(cntlr);
            hi35xx = (struct Hi35xxPinCntlr *)cntlr;
            if (hi35xx != NULL) {
                if (hi35xx->regBase != NULL) {
                    OsalIoUnmap((void *)hi35xx->regBase);
                }
                OsalMemFree(hi35xx);
            }
Y
modify  
yinshuqing 已提交
422 423
        }
        ```
J
jiaziyang 已提交
424 425
4. **驱动调试:**
   【可选】针对新增驱动程序,建议验证驱动基本功能,例如挂载后的信息反馈,数据传输的成功与否等。