diff --git a/zh-cn/device-dev/driver/Readme-CN.md b/zh-cn/device-dev/driver/Readme-CN.md
index 1db6007a4f7910b431d957c70cecc76c883c36b4..b021fe5cb3a35c32bdd0d2607f157405257fcc4b 100755
--- a/zh-cn/device-dev/driver/Readme-CN.md
+++ b/zh-cn/device-dev/driver/Readme-CN.md
@@ -22,6 +22,7 @@
- [SPI](driver-platform-spi-develop.md)
- [UART](driver-platform-uart-develop.md)
- [WatchDog](driver-platform-watchdog-develop.md)
+ - [I2S](driver-platform-i2s-develop.md)
- [平台驱动使用](driver-platform.md)
- [ADC](driver-platform-adc-des.md)
- [GPIO](driver-platform-gpio-des.md)
@@ -36,6 +37,7 @@
- [SPI](driver-platform-spi-des.md)
- [UART](driver-platform-uart-des.md)
- [WATCHDOG](driver-platform-watchdog-des.md)
+ - [I2S](driver-platform-i2s-des.md)
- [外设驱动使用](driver-peripherals.md)
- [LCD](driver-peripherals-lcd-des.md)
- [TOUCHSCREEN](driver-peripherals-touch-des.md)
diff --git a/zh-cn/device-dev/driver/driver-develop.md b/zh-cn/device-dev/driver/driver-develop.md
index e4cee0c88383f41bd46628a0b0dfd079876f805c..6162a4129fe5578cb1144bf35b3757239e5455d8 100644
--- a/zh-cn/device-dev/driver/driver-develop.md
+++ b/zh-cn/device-dev/driver/driver-develop.md
@@ -27,3 +27,5 @@
- **[UART](driver-platform-uart-develop.md)**
- **[WatchDog](driver-platform-watchdog-develop.md)**
+
+- **[I2S](driver-platform-i2s-develop.md)**
diff --git a/zh-cn/device-dev/driver/driver-platform-i2s-des.md b/zh-cn/device-dev/driver/driver-platform-i2s-des.md
new file mode 100755
index 0000000000000000000000000000000000000000..39863601e3dfe14be875298625f7fcde8279e021
--- /dev/null
+++ b/zh-cn/device-dev/driver/driver-platform-i2s-des.md
@@ -0,0 +1,684 @@
+# I2S
+
+- [概述](#section193356154511)
+- [接口说明](#section1325964832615)
+- [使用指导](#section71363452477)
+ - [使用流程](#section32846814820)
+ - [获取I2S设备句柄](#section1927265711481)
+ - [设置I2S设备属性](#section541133418493)
+ - [获取I2S设备属性](#section7870106145010)
+ - [使能I2S设备](#section13324155195013)
+ - [禁用I2S设备](#section19661632135117)
+ - [开始I2S设备读功能](#section19661632135118)
+
+ - [停止I2S设备读功能](#section19661632135119)
+ - [开始I2S设备写功能](#section19661632135120)
+ - [停止I2S设备写功能](#section19661632135121)
+ - [I2S读](#section19661632135122)
+ - [I2S写](#section19661632135123)
+ - [销毁I2S设备句柄](#section19661632135124)
+- [使用实例](#section06541058155120)
+
+## 概述
+
+- I2S(Inter-IC Sound)总线, 又称集成电路内置音频总线,是飞利浦半导体公司(现为恩智浦半导体公司)针对数字音频设备之间的音频数据传输而制定的一种总线标准。该总线专门用于音频设备之间的数据传输,广泛应用于各种多媒体系统。采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真。
+- I2S信号线,串行时钟SCK,也叫位时钟BCLK,对应数字音频的每一位数据。SCK的频率 = 声道数 * 采样频率 * 采样位数。字段选择信号WS,也叫LRCLK,用于切换左右声道的数据,字段选择信号WS表明了正在被传输的声道,WS为0,表示正在传输的是左声道的数据,WS为1,表示正在传输的是右声道的数据。WS的频率 = 采样频率。串行数据SD,就是用二进制补码表示的音频数据。I2S串行数据在传输的时候,由高位(MSB)到低位(LSB)依次进行传输。
+- 能够产生SCK和WS的信号端就是主设备,用MASTER表示,通信示意图如下:
+
+**图 1** master是transmitter时的通信示意图
+
+
+
+**图 2** master是receiver时的通信示意图
+
+
+
+**图 3** master是controller时的通信示意图
+
+
+
+## 接口说明
+
+**表 1** I2S驱动API接口功能介绍:
+
+
+
+
功能分类
+ |
+接口名
+ |
+描述
+ |
+
+
+I2S设备句柄获取、释放接口
+ |
+I2sOpen
+ |
+获取I2S设备句柄
+ |
+
+I2sClose
+ |
+释放I2S设备句柄
+ |
+
+I2S使能、禁用接口
+
+ |
+I2sEnable
+ |
+使能I2S设备
+ |
+
+I2sDisable
+ |
+禁用I2S设备
+ |
+
+I2S开始读、写接口
+
+ |
+I2sStartRead
+ |
+I2S开始读
+ |
+
+I2sStartWrite
+ |
+I2S开始写
+ |
+
+I2S停止读、写接口
+
+ |
+I2sStopRead
+ |
+I2S停止读
+ |
+
+I2sStopWrite
+ |
+I2S停止写
+ |
+
+I2S读写接口
+
+ |
+I2sRead
+ |
+I2S读
+ |
+
+I2sWrite
+ |
+I2S写
+ |
+
+I2S获取/设置设备属性
+
+ |
+I2sGetCfg
+ |
+I2S获取设备属性
+ |
+
+I2sSetCfg
+ |
+I2S设置设备属性
+ |
+
+
+
+
+> **说明:**
+>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。
+
+## 使用指导
+
+### 使用流程
+
+使用I2S的一般流程如[图4](#fig1586912310348)所示。
+
+**图 4** I2S使用流程图
+
+
+### 获取I2S设备句柄
+
+在使用I2S进行通信时,首先要调用I2sOpen获取I2S设备句柄,该函数会返回指定编号的I2S设备句柄。
+
+DevHandle I2sOpen(int16_t number);
+
+**表 2** I2sOpen参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+number
+ |
+I2S设备编号
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+NULL
+ |
+获取I2S设备句柄失败
+ |
+
+设备句柄
+ |
+对应的I2S设备句柄
+ |
+
+
+
+
+假设系统中存在8个I2S控制器,编号从0到7,获取3号控制器设备句柄示例如下:
+
+```c
+DevHandle i2sHandle = NULL; /* I2C控制器句柄 */
+/* 打开I2C控制器 */
+i2sHandle = I2sOpen(3);
+if (i2sHandle == NULL) {
+ HDF_LOGE("I2sOpen: failed\n");
+ return;
+}
+```
+
+### 设置[I2S]()设备属性
+
+在使用I2S进行通信前,需要调用I2sSetCfg设置I2S设备属性。设置I2S设备属性函数如下:
+
+void I2sSetCfg(DevHandle handle, struct I2sCfg *cfg);
+
+**表 3** I2sSetCfg参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+cfg
+ |
+I2S设备配置参数
+ |
+
+返回值
+ |
+返回值描述
+ |
+
+0
+ |
+获取配置成功
+ |
+
+负数
+ |
+获取配置失败
+ |
+
+
+
+
+```c
+struct I2sCfg cfg;
+ cfg.sampleRate = test->sampleRate;
+ cfg.type = test->type;
+ cfg.channelMode = test->channelMode;
+ cfg.samplePrecision = test->samplePrecision;
+ cfg.channelIfMode = test->channelIfMode;
+ cfg.mclk = test->mclk;
+ cfg.bclk = test->bclk;
+ cfg.writeChannel = test->writeChannel;
+ cfg.i2slFsSel = test->i2slFsSel;
+ cfg.width = I2S_WORDWIDTH_16BIT;
+ I2sSetCfg(test->handle, &cfg);
+```
+
+### 获取I2S设备属性
+
+设置I2S属性成功后,可以通过获取设备属性接口查看I2S设备属性。获取I2S设备属性的函数如下所示:
+
+void I2sGetCfg(DevHandle handle, struct I2sCfg *cfg);
+
+**表 4** I2sGetCfg参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+cfg
+ |
+I2S设备配置参数
+ |
+
+
+
+
+```c
+struct I2sCfg cfg;
+I2sGetCfg(test->handle, &cfg);
+HDF_LOGE("%s:sampleRate[%u], type[%u], channelMode[%u], samplePrecision[%u],\
+ channelIfMode[%u], mclk[%u], bclk[%u], writeChannel[%u], i2slFsSel[%u]", __func__,
+ test->sampleRate, test->type, test->channelMode, test->samplePrecision,
+ test->channelIfMode, test->mclk, test->bclk, test->writeChannel, test->i2slFsSel);
+```
+
+### 使能I2S设备
+
+- 在使用I2S进行通信前必须使能I2S设备,通过调用I2sEnable使能I2S设备。使能I2S设备的函数如下所示:
+
+void I2sEnable(DevHandle handle);
+
+**表 5** I2sEnable参数和返回值描述
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```c
+if (test == NULL || test->handle == NULL || test->wbuf == NULL) {
+ HDF_LOGE("%s: test null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+I2sEnable(test->handle);
+```
+
+### 禁用I2S设备
+
+需要禁用I2S设备时可以通过调用I2sDisable来实现。禁用I2S设备的函数如下所示:
+
+void I2sDisable(DevHandle handle) ;
+
+**表 6** I2sDisable参数描述
+
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```c
+if (test == NULL || test->handle == NULL || test->wbuf == NULL) {
+ HDF_LOGE("%s: test null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+I2sDisable(test->handle);
+```
+
+### 开始I2S读功能
+
+在进行读I2S从设备之前需要调用函数I2sStartRead向I2S从设备发送开始读命令来开始读的功能。开始I2S设备读的函数如下所示:
+
+void I2sStartRead(DevHandle handle);
+
+**表 7** I2sStartRead参数描述
+
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```c
+if (test == NULL || test->handle == NULL) {
+ HDF_LOGE("%s: test null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+HDF_LOGI("%s: rbuf[%p] wbuf[%p]\n", __func__, test->rbuf, test->wbuf);
+I2sStartRead(test->handle);
+```
+
+### 停止I2S读功能
+
+在读取从设备结束之前需要调用I2sStopRead函数发送停止读的命令来停止读功能。停止I2S设备读的函数如下所示:
+
+void I2sStopRead(DevHandle handle);
+
+**表 8** I2sStopRead参数描述
+
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```c
+if (test == NULL || test->handle == NULL) {
+ HDF_LOGE("%s: test null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+HDF_LOGI("%s: rbuf[%p] wbuf[%p]\n", __func__, test->rbuf, test->wbuf);
+I2sStopRead(test->handle);
+```
+
+### 开始I2S写功能
+
+在进行写I2S从设备之前需要调用函数I2sStartWrite向I2S从设备发送开始写命令来开始写功能。开始I2S写功能的函数如下所示:
+
+void I2sStartWrite(DevHandle handle);
+
+**表 9** I2sStartWrite参数描述
+
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```c
+if (test == NULL || test->handle == NULL) {
+ HDF_LOGE("%s: test null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+I2sStartWrite(test->handle);
+```
+
+### 停止I2S写功能
+
+在写从设备结束之前需要调用函数I2sStopWrite向I2S从设备发送停止写的命令来停止写功能。停止I2S写功能的函数如下所示:
+
+void I2sStopWrite(DevHandle handle);
+
+**表 10** I2sStopWrite参数描述
+
+
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```c
+if (test == NULL || test->handle == NULL) {
+ HDF_LOGE("%s: test null", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+I2sStopWrite(test->handle);
+```
+
+### I2S读
+
+通过调用函数I2sRead读取I2S从设备的数据,I2S读函数如下所示:
+
+int32_t I2sRead(DevHandle handle, uint8_t *buf, uint32_t len, uint32_t *pRlen) ;
+
+**表 11** I2sRead参数描述
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+buf
+ |
+接收读取数据的指针
+ |
+
+len
+ |
+读buffers的长度
+ |
+
+pRlen
+ |
+每次实际读的长度
+ |
+
+返回值
+ |
+返回值描述
+ |
HDF_SUCCESS
+ |
+表示读取成功
+ |
+
+HDF_FAILURE
+ |
+表示读取失败
+ |
+
+
+
+
+```c
+if (I2sRead(test->handle, test->rbuf, test->len, &test->len) != HDF_SUCCESS) {
+ HDF_LOGE("%s: I2sRead error \n", __func__);
+ return HDF_FAILURE;
+ }
+```
+
+### I2S写
+
+通过调用函数I2sWrite向I2S从设备写数据,I2S写的函数如下所示:
+
+int32_t I2sWrite(DevHandle handle, uint8_t *buf, uint32_t len, uint32_t *pWlen) ;
+
+**表 12** I2sWrite参数描述
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+buf
+ |
+写数据的指针
+ |
+
+len
+ |
+写buffers的长度
+ |
+
+pWlen
+ |
+每次实际写的长度
+ |
+
+返回值
+ |
+返回值描述
+ |
HDF_SUCCESS
+ |
+表示写成功
+ |
+
+HDF_FAILURE
+ |
+表示写失败
+ |
+
+
+
+
+```c
+if (I2sWrite(test->handle, test->wbuf, test->len, &test->len) != HDF_SUCCESS) {
+ HDF_LOGE("%s: I2sWriteTest error \n", __func__);
+ return HDF_FAILURE;
+ }
+```
+
+### 销毁I2S设备句柄
+
+在使用I2S通信结束后需要调用函数I2sClose销毁I2S设备句柄,销毁I2S设备句柄的函数如下所示:
+
+void I2sClose(DevHandle handle);
+
+**表 13** I2sClose参数描述
+
+参数
+ |
+参数描述
+ |
+
+handle
+ |
+I2S设备句柄
+ |
+
+
+
+
+```
+I2sClose(test->handle);
+```
+
+## 使用实例
+
+I2S设备完整的使用实例如下,首先需要获取I2S设备句柄,接着设置I2S设备属性、使能I2S设备,开始I2S读、写功能,进行I2S读、写,停止I2S读、写功能,禁用I2S设备,销毁I2S设备句柄。
+
+```c
+#include "hdf_log.h"
+#include "i2s_if.h"
+void I2sTestSample(void)
+{
+ int32_t ret;
+ int32_t i;
+ int16_t number;
+ DevHandle handle = NULL;
+ uint8_t wbuff[5] = { 1, 2, 3, 4, 5 };
+ uint8_t rbuff[5] = { 0 };
+ uint32_t wlen = 0;
+ uint32_t pRlen = 0;
+ struct I2sCfg cfg;
+ cfg.sampleRate = I2S_SAMPLE_RATE_44_1K; /* I2S采样速率,这里设置的是44.1k速率采样 */
+ cfg.type = I2S_PROTOCOL_I2S_MSB; /* I2S 协议传输类型 ,这里设置的协议类型是msb,先传输高字节后传输低字节 */
+ cfg.channelMode = I2S_CHANNEL_MODE_STEREO; /* I2S通道模式,这里设置的是立体声通道模式 */
+ cfg.samplePrecision = 8; /* I2S采样精度,这里设置的是8bit,位数越高声音的保真度越高 */
+ cfg.channelIfMode = I2S_CHANNEL_IF_MODE_I2S; /* I2S协议时序模式,这里设置的是I2S协议时序 */
+ cfg.mclk = 256; /* I2S同步时钟频率,这里设置的是256khz */
+ cfg.bclk = 32768; /* I2S串行时钟频率,这里设置的是32768hz */
+ cfg.writeChannel = I2S_WRITE_CHANNEL_AUDIO; /* I2S 写通道,这里设置的是音频通道 */
+ cfg.i2slFsSel = I2SL_FS_SEL_1024_FS /* I2S采样频率设置,这里设置的采样频率是1024hz */;
+ cfg.width = I2S_WORDWIDTH_16BIT; /* I2S传输的位宽,这里设置的是16bit */
+ number = 0; /* I2S设备号,要填写实际平台上的设备号 */
+ handle = I2sOpen(number); /* 获取I2S设备句柄 */
+ if (handle == NULL) {
+ HDF_LOGE("I2sOpen: failed!\n");
+ return;
+ }
+ /* 设置I2S设备属性 */
+ ret = I2sSetCfg(handle, &cfg);
+ if (ret != 0) {
+ HDF_LOGE("I2sSetCfg: failed, ret %d\n", ret);
+ goto _ERR;
+ }
+ /* 使能I2S设备 */
+ I2sEnable(handle);
+ /* 开始I2S写功能 */
+ I2sStartWrite(handle);
+ /* 向I2S设备写5字节的数据 */
+ ret = I2sWrite(handle, wbuff, 5, &wlen);
+ if (ret < 0) {
+ HDF_LOGE("I2sWrite: failed, ret %d\n", ret);
+ goto _ERR;
+ }
+ /* 停止I2S写功能 */
+ I2sStopWrite(handle);
+ /* 开始I2S读功能 */
+ I2sStartRead(handle);
+ /* 从I2S设备读5字节的数据 */
+ ret = I2sRead(handle, rbuff, 5, &pRlen);
+ if (ret < 0) {
+ HDF_LOGE("I2sRead: failed, ret %d\n", ret);
+ goto _ERR;
+ }
+ /* 停止I2S读功能 */
+ I2sStopRead(handle);
+ for (i = 0; i < 5; i++) {
+ HDF_LOGE("%s: rbuff[%d] = 0x%x", __func__, i, rbuff[i]);
+ }
+ /* 禁用I2S设备 */
+ I2sDisable(handle);
+_ERR:
+ /* 销毁I2S设备句柄 */
+ I2sClose(handle);
+}
+```
+
diff --git a/zh-cn/device-dev/driver/driver-platform-i2s-develop.md b/zh-cn/device-dev/driver/driver-platform-i2s-develop.md
new file mode 100755
index 0000000000000000000000000000000000000000..ea1d8e85de9b4dab8770369826c970922d2305db
--- /dev/null
+++ b/zh-cn/device-dev/driver/driver-platform-i2s-develop.md
@@ -0,0 +1,483 @@
+# I2S
+
+- [概述](#section84922229152909)
+- [接口说明](#section752964871810)
+- [开发步骤](#section799667984152909)
+- [开发实例](#section956157227152909)
+
+## 概述
+
+I2S(Inter—IC Sound)总线, 又称集成电路内置音频总线,在HDF框架中,I2S的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。
+
+**图 1** I2S独立服务模式结构图
+
+
+## 接口说明
+
+I2sCntlrMethod定义:
+
+```c
+struct I2sCntlrMethod {
+ int32_t (*GetCfg)(struct I2sCntlr *, struct I2sCfg *);
+ int32_t (*SetCfg)(struct I2sCntlr *, struct I2sCfg *);
+ int32_t (*Transfer)(struct I2sCntlr *, struct I2sMsg *);
+ int32_t (*Open)(struct I2sCntlr *);
+ int32_t (*Close)(struct I2sCntlr *);
+ int32_t (*Enable)(struct I2sCntlr *);
+ int32_t (*Disable)(struct I2sCntlr *);
+ int32_t (*StartWrite)(struct I2sCntlr *);
+ int32_t (*StopWrite)(struct I2sCntlr *);
+ int32_t (*StartRead)(struct I2sCntlr *);
+ int32_t (*StopRead)(struct I2sCntlr *);
+};
+```
+
+**表 1** I2sCntlrMethod结构体成员的回调函数功能说明
+
+
+
+成员函数
+ |
+入参
+ |
+出参
+ |
+返回值
+ |
+功能
+ |
+
+
+GetCfg
+ |
+Cntlr:结构体指针,核心层i2s控制器;
+ |
+
+Cfg:结构体指针,传出的属性值(见i2s_if.h中I2sCfg定义)
+ | HDF_STATUS相关状态
+ |
+获取属性值
+ |
+
+SetCfg
+ |
+Cfg:结构体指针,传入的属性值(见i2s_if.h中I2sCfg定义)
+ |
+Cntlr:结构体指针,核心层i2s控制器,传出的值
+ |
+HDF_STATUS相关状态
+ |
+设置控制器属性
+ |
+
+Transfer
+ |
+Cntlr:结构体指针,核心层i2s控制器;Msgs:消息结构体指针
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+i2s数据传输
+ |
+
+Open
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+打开I2S
+ |
+
+Close
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+关闭I2S
+ |
+
+Enable
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+使能I2S设备
+ |
+
+Disable
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+禁用I2S设备
+ |
+
+StartWrite
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+开始写
+ |
+
+StopWrite
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+停止写
+ |
+
+StartRead
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+开始读
+ |
+
+StopRead
+ |
+cntlr:结构体指针,核心层i2s控制器;
+ |
+无
+ |
+HDF_STATUS相关状态
+ |
+停止读
+ |
+
+
+
+
+## 开发步骤
+
+I2S模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。
+
+1. **实例化驱动入口:**
+ - 实例化HdfDriverEntry结构体成员。
+ - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。
+
+2. **配置属性文件:**
+ - 在device\_info.hcs文件中添加deviceNode描述。
+ - 【可选】添加i2s\_config.hcs器件属性文件。
+
+3. **实例化I2S控制器对象:**
+
+ - 初始化I2sCntlr成员。
+ - 实例化I2sCntlr成员I2sCntlrMethod。
+
+>  **说明:**
+> 实例化I2sCntlr成员I2sCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。
+
+
+4. **驱动调试:**
+
+ 【可选】针对新增驱动程序,建议验证驱动基本功能,例如设置I2S属性,获取I2S属性等。
+
+
+## 开发实例
+
+下方将以i2s_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。
+
+1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。
+
+ 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。
+
+ I2S驱动入口参考:
+
+ ```c
+ struct HdfDriverEntry g_hdfI2sDevice = {
+ .moduleVersion = 1,
+ .moduleName = "HDF_PLATFORM_I2S",//【必要且与 HCS 里面的名字匹配】
+ .Bind = HdfI2sDeviceBind,//见Bind参考
+ .Init = HdfI2sDeviceInit, //见Init参考
+ .Release = HdfI2sDeviceRelease, //见Release参考
+ };
+ //调用HDF_INIT将驱动入口注册到HDF框架中
+ HDF_INIT(g_hdfI2sDevice);
+ ```
+
+2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 i2s_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层I2sCntlr成员的默认值或限制范围有密切关系。
+
+ 本例只有一个I2S控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在i2s_config文件中增加对应的器件属性。
+
+ - device\_info.hcs 配置参考。
+
+ ```
+ root {
+ device_info {
+ match_attr = "hdf_manager";
+ platform :: host {
+ hostName = "platform_host";
+ priority = 50;
+ device_i2s :: device {
+ device0 :: deviceNode {
+ policy = 1;
+ priority = 60;
+ permission = 0644;
+ moduleName = "HDF_PLATFORM_I2S";
+ serviceName = "HDF_PLATFORM_I2S_0";
+ deviceMatchAttr = "hisilicon_hi35xx_i2s_0";
+ }
+ }
+
+ }
+ }
+ }
+ ```
+
+ - i2s_config.hcs 配置参考。
+
+ ```
+ root {
+ platform {
+ i2s_config {//每一个I2S控制器配置私有数据
+ template i2s_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省
+ serviceName = "";
+ match_attr = "";
+ busNum = 0; // 总线号
+ i2s_pad_enable = 1;
+ audio_enable = 0;
+ regBase = 0x113B0000;// 地址映射需要
+ PERI_CRG103 = 0xa;
+ MCLK = 12288; /* KHZ */
+ aiao_srst_req = 1; /* 1 reset-->RX0 channel reset */
+ aiao_cken = 0; /* 0 close MCLK/BCLK/WS clk gate */
+ BCLK = 3072; /* KHZ */
+ i2sl_fs_sel = 0x1a; /* MCLK=256fs */
+ irqNum = 0; // 中断号
+ }
+
+ controller_0x113b0000 :: i2s_controller {
+ busNum = 0; //【必要】总线号
+ regBase = 0x113B0000; // 地址映射需要
+ match_attr = "hisilicon_hi35xx_i2s_0";
+ irqNum = 87; // 中断号
+ }
+ ...
+ // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点
+ }
+ }
+ }
+ ```
+
+3. 完成驱动入口注册之后,最后一步就是以核心层I2sCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2sCntlr成员I2sCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。
+ - 自定义结构体参考
+
+ 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2s_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号、总线号等。
+
+ ```c
+ struct I2sConfigInfo {//对应于hcs中的参数
+ uint8_t i2sPadEnable;
+ uint8_t audioEnable;
+ uint32_t PERICRG103;
+ uint32_t I2sCfgCfg000;
+ uint32_t mclk; /**< KHZ */
+ uint32_t bclk; /**< KHZ */
+ struct I2sCfgCfg100 regCfg100;
+ struct RxIfAttr1Info regRxIfAttr1;
+ volatile unsigned char *phyBase;
+ volatile unsigned char *regBase;
+ enum I2sWriteChannel writeChannel;
+ enum I2sSampleRate sampleRate;
+ enum I2sWordWidth width;
+ enum I2sChannelIfMode channelIfMode;
+ enum I2sChannelMode channelMode;
+ enum I2sProtocolType type;
+ uint8_t samplePrecision;
+ uint16_t i2slFsSel;
+ DMA_ADDR_T rxData;
+ uint8_t *rxVirData;
+ uint32_t rxWptr;
+ uint32_t rxRptr;
+ uint32_t rxSize;
+ uint32_t rxTransSize;
+ DMA_ADDR_T txData;
+ uint8_t *txVirData;
+ uint32_t txWptr;
+ uint32_t txRptr;
+ uint32_t txSize;
+ uint32_t txTransSize;
+ volatile unsigned char *codecAddr;
+ volatile unsigned char *crg103Addr;
+ bool isplay;
+ bool txEn;
+ };
+
+ //I2sCntlr 是核心层控制器结构体,其中的成员在Init函数中会被赋值
+ struct I2sCntlr {
+ struct IDeviceIoService service;
+ struct HdfDeviceObject *device;
+ uint32_t busNum;
+ uint32_t irqNum;
+ struct OsalMutex lock;
+ struct I2sCntlrMethod *method;
+ void *priv; // private data
+ };
+ ```
+
+ - I2sCntlr 成员回调函数结构体I2sCntlrMethod的实例化,其他成员在Init函数中初始化。
+
+ ```c
+ struct I2sCntlrMethod g_i2sCntlrMethod = {// i2s_hi35xx.c 中的示例:钩子函数的实例化
+ .GetCfg = Hi35xxI2sGetCfg,
+ .SetCfg = Hi35xxI2sSetCfg,
+ .Transfer = Hi35xxI2sTransfer,
+ .Open = Hi35xxI2sOpen,
+ .Close = Hi35xxI2sClose,
+ .Enable = Hi35xxI2sEnable,
+ .Disable = Hi35xxI2sDisable,
+ .StartWrite = Hi35xxI2sStartWrite,
+ .StopWrite = Hi35xxI2sStopWrite,
+ .StartRead = Hi35xxI2sStartRead,
+ .StopRead = Hi35xxI2sStopRead,
+ };
+ ```
+
+ - Bind 函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态。
+
+ 函数说明:
+
+ 将 I2sCntlr 对象同 HdfDeviceObject 进行了关联。
+
+ ```c
+ static int32_t HdfI2sDeviceBind(struct HdfDeviceObject *device)
+ {
+ if (device == NULL) {
+ I2S_PRINT_LOG_ERR("%s: device NULL", __func__);
+ return HDF_ERR_INVALID_OBJECT;
+ }
+ return (I2sCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS;
+ }
+ struct I2sCntlr *I2sCntlrCreate(struct HdfDeviceObject *device)
+ {
+ struct I2sCntlr *cntlr = NULL;
+ ...
+ cntlr = (struct I2sCntlr *)OsalMemCalloc(sizeof(*cntlr));
+ if (cntlr == NULL) {
+ HDF_LOGE("%s: OsalMemCalloc error", __func__);
+ return NULL;
+ }
+ ...
+ cntlr->device = device;
+ device->service = &(cntlr->service);
+ (void)OsalMutexInit(&cntlr->lock);
+ cntlr->priv = NULL;
+ cntlr->method = NULL;
+ return cntlr;
+ }
+ ```
+
+ - Init函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见/drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。
+
+ **表 2** init函数入参和返回值
+
+
+
+ | 状态(值) | 问题描述 |
+ | ---------------------- | -------------- |
+ | HDF_ERR_INVALID_OBJECT | 控制器对象非法 |
+ | HDF_ERR_MALLOC_FAIL | 内存分配失败 |
+ | HDF_ERR_INVALID_PARAM | 参数非法 |
+ | HDF_ERR_IO | I/O 错误 |
+ | HDF_SUCCESS | 初始化成功 |
+ | HDF_FAILURE | 初始化失败 |
+
+ 函数说明:
+
+ 初始化自定义结构体对象,初始化I2sCntlr 成员。
+
+ ```c
+ static int32_t HdfI2sDeviceInit(struct HdfDeviceObject *device)
+ {
+ struct I2sCntlr *cntlr = NULL;
+ ...
+ cntlr = I2sCntlrFromDevice(device);
+ ...
+ int32_t ret = I2sInit(cntlr, device);
+ ...
+ return ret;
+ }
+ ```
+
+ - Release函数参考
+
+ 入参:
+
+ HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。
+
+ 返回值:
+
+ 无。
+
+ 函数说明:
+
+ 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。
+
+ ```c
+ static void HdfI2sDeviceRelease(struct HdfDeviceObject *device)
+ {
+ struct I2sCntlr *cntlr = NULL;
+ ...
+ cntlr = I2sCntlrFromDevice(device);
+ ...
+ if (cntlr->priv != NULL) {
+ struct I2sConfigInfo *configInfo = cntlr->priv;
+ if (configInfo->regBase != 0) {
+ OsalIoUnmap((void *)configInfo->regBase);
+ }
+ if (configInfo->codecAddr != 0) {
+ OsalIoUnmap((void *)configInfo->codecAddr);
+ }
+ if (configInfo->crg103Addr != 0) {
+ OsalIoUnmap((void *)configInfo->crg103Addr);
+ }
+ OsalMemFree(cntlr->priv);
+ }
+ I2sCntlrDestroy(cntlr);//释放cntlr对象
+ }
+ ```
+
+
+
+
+
diff --git a/zh-cn/device-dev/driver/driver-platform.md b/zh-cn/device-dev/driver/driver-platform.md
index 01fc51f6cd1717787c769e2c1f1f79bc7b67d2d3..b26773496a4d08134cbd46d81666533ee7b8fdf4 100644
--- a/zh-cn/device-dev/driver/driver-platform.md
+++ b/zh-cn/device-dev/driver/driver-platform.md
@@ -25,3 +25,5 @@
- **[UART](driver-platform-uart-des.md)**
- **[WATCHDOG](driver-platform-watchdog-des.md)**
+
+- **[I2S](driver-platform-i2s-des.md)**
diff --git "a/zh-cn/device-dev/driver/figures/I2S-master\346\230\257controller.png" "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257controller.png"
new file mode 100755
index 0000000000000000000000000000000000000000..c3684f735f8a68a198c3ced8a243b6674760272d
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257controller.png" differ
diff --git "a/zh-cn/device-dev/driver/figures/I2S-master\346\230\257receiver.png" "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257receiver.png"
new file mode 100755
index 0000000000000000000000000000000000000000..056e2b9178b380023228d9a9747d8fd4f02b14d8
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257receiver.png" differ
diff --git "a/zh-cn/device-dev/driver/figures/I2S-master\346\230\257transmiter.png" "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257transmiter.png"
new file mode 100755
index 0000000000000000000000000000000000000000..889c0c0ba5a11880ea41fdbbd8a00b5c2bd61e5e
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257transmiter.png" differ
diff --git "a/zh-cn/device-dev/driver/figures/I2S\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png" "b/zh-cn/device-dev/driver/figures/I2S\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png"
new file mode 100755
index 0000000000000000000000000000000000000000..92013eb57c9c4c5fa3bbbde4edd109cc441295e0
Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png" differ