RK3229 MS8416 MS8406调试

1、I2S做从机模式,音频芯片做主模式

由于音频芯片做从模式声音可能会失真,所以必须使得I2S1做从模式,音频芯片做主模式

+	ms84x6 {
+		compatible = "rockchip,ms84x6";
+		pinctrl-0 = <&lk_ms84x6_io>;
+		//ms84x6_sda = <&gpio2 GPIO_A3 GPIO_ACTIVE_HIGH>;//<&gpio0 GPIO_A6 GPIO_ACTIVE_HIGH>;//<&gpio0 GPIO_A3 GPIO_ACTIVE_HIGH>;
+		//ms84x6_scl = <&gpio0 GPIO_D1 GPIO_ACTIVE_HIGH>;//<&gpio0 GPIO_A7 GPIO_ACTIVE_HIGH>;//<&gpio0 GPIO_A2 GPIO_ACTIVE_HIGH>;
+		ms84x6_sda = <&gpio0 GPIO_A3 GPIO_ACTIVE_HIGH>;
+		ms84x6_scl = <&gpio0 GPIO_A2 GPIO_ACTIVE_HIGH>;
+		ms84x6_reset= <&gpio3 GPIO_A0 GPIO_ACTIVE_HIGH>;
+		status = "okay";
+	};&i2s1 {
+   pinctrl-names = "default";
+   pinctrl-0 = <&i2s_mclk
+				&i2s_sclk
+				&i2s_lrckrx
+				&i2s_lrcktx
+				&i2s_sdi
+				&i2s_sdo0>;status = "okay";};pcm_audio {status = "okay";compatible = "rockchip,rk322x-audio";dais {dai0 {audio-codec = <&pcm_codec>;audio-controller = <&i2s2>;format = "i2s";};};};

修改驱动使其为从机模式:

diff --git a/sound/soc/rockchip/rk_i2s.c b/sound/soc/rockchip/rk_i2s.c
index 8eca3f30a8df..1929dc84e4bf 100755
--- a/sound/soc/rockchip/rk_i2s.c
+++ b/sound/soc/rockchip/rk_i2s.c
@@ -45,7 +45,7 @@#include "rk_i2s.h"#define CLK_SET_LATER
-#define I2S_DEFAULT_FREQ	(11289600)
+#define I2S_DEFAULT_FREQ	(12288000)#define I2S_DMA_BURST_SIZE	(16) /* size * width: 16*4 = 64 bytes */static DEFINE_SPINLOCK(lock);@@ -64,6 +64,7 @@ struct rk_i2s_dev {bool tx_start;bool rx_start;int xfer_mode; /* 0: i2s, 1: pcm */
+	int i2s_num; // 0-i2s0 , 1-i2s1, 2-i2s1bool tx_always_on;#ifdef CLK_SET_LATERstruct delayed_work clk_delayed_work;
@@ -109,7 +110,7 @@ static void rockchip_snd_xfer_stop(struct rk_i2s_dev *i2s)static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on){unsigned long flags;
-
+	spin_lock_irqsave(&lock, flags);dev_dbg(i2s->dev, "%s: %d: on: %d\n", __func__, __LINE__, on);
@@ -129,7 +130,6 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)regmap_update_bits(i2s->regmap, I2S_DMACR,I2S_DMACR_TDE_MASK, I2S_DMACR_TDE_DISABLE);
-#if 0if (!i2s->rx_start) {regmap_update_bits(i2s->regmap, I2S_XFER,
@@ -235,22 +235,27 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai,spin_lock_irqsave(&lock, flags);mask = I2S_CKR_MSS_MASK;
-	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-	case SND_SOC_DAIFMT_CBS_CFS:
-		/* Codec is slave, so set cpu master */
-		val = I2S_CKR_MSS_MASTER;
-		break;
-	case SND_SOC_DAIFMT_CBM_CFM:
-		/* Codec is master, so set cpu slave */
+	printk("wzh i2s->xfer_mode == %d\n", i2s->xfer_mode);
+	
+	if (i2s->i2s_num == 1) {val = I2S_CKR_MSS_SLAVE;
-		break;
-	default:
-		ret = -EINVAL;
-		goto err_fmt;
+		printk("i2s->i2s_num == 1\n");
+	} else {
+		switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+		case SND_SOC_DAIFMT_CBS_CFS:
+			/* Codec is slave, so set cpu master */
+			val = I2S_CKR_MSS_MASTER;
+			break;
+		case SND_SOC_DAIFMT_CBM_CFM:
+			/* Codec is master, so set cpu slave */
+			val = I2S_CKR_MSS_SLAVE;
+			break;
+		default:
+			ret = -EINVAL;
+			goto err_fmt;
+		}}
-regmap_update_bits(i2s->regmap, I2S_CKR, mask, val);
-mask = I2S_TXCR_IBM_MASK;switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {case SND_SOC_DAIFMT_RIGHT_J:
@@ -606,8 +611,8 @@ static const struct regmap_config rockchip_i2s_regmap_config = {static int rockchip_i2s_probe(struct platform_device *pdev){
-	struct device_node *node = pdev->dev.of_node;struct rk_i2s_dev *i2s;
+	struct device_node *node = pdev->dev.of_node;struct snd_soc_dai_driver *soc_dai;struct resource *res;void __iomem *regs;
@@ -620,7 +625,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)ret = -EINVAL;goto err;}
-
+	if (soc_is_rk3126b()) {int sdi_src = 0;@@ -653,6 +658,8 @@ static int rockchip_i2s_probe(struct platform_device *pdev)goto err;}+	i2s->i2s_num = pdev->id;
+	i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk");if (IS_ERR(i2s->hclk)) {dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n");
@@ -701,7 +708,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)ret = PTR_ERR(i2s->regmap);goto err;}
-
+	i2s->playback_dma_data.addr = res->start + I2S_TXDR;i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;i2s->playback_dma_data.maxburst = I2S_DMA_BURST_SIZE;
@@ -759,7 +766,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)ret = of_property_read_u32(node, "rockchip,xfer-mode", &i2s->xfer_mode);if (ret < 0)i2s->xfer_mode = I2S_XFER_MODE;
-
+	if (PCM_XFER_MODE == i2s->xfer_mode) {regmap_update_bits(i2s->regmap, I2S_TXCR,I2S_TXCR_TFS_MASK,
@@ -768,7 +775,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)I2S_RXCR_TFS_MASK,I2S_RXCR_TFS_PCM);}
-
+	rockchip_snd_txctrl(i2s, 0);rockchip_snd_rxctrl(i2s, 0);

注意ms8416需要获取采样率时其25脚必须提供外部时钟,这个时钟用的是I2S的MCLK 12.28M;

所以上面也修改了输出时钟是12.28M;

2、ms8416驱动

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/input-polldev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
#include <linux/timex.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
//#include <linux/ec.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>#include <linux/wakelock.h>//#include <linux/pwm.h>//static struct pwm_device	*pwm;typedef unsigned char  uchar;
typedef char           schar;
typedef unsigned char  uint8;
typedef signed char    int8;
typedef unsigned short uint16;
typedef short          int16;
typedef unsigned int   uint32;
typedef int            int32;#define ES7243_IIC_DATA_MAX_NUM    256
#define MS8416_I2C_ADDRESS 0x20  //0x26struct ms8416_iic_data {uint32_t devAddress;uint32_t regAddress;uint8_t  index;uint8_t  Flag16bit;uint8_t  data[ES7243_IIC_DATA_MAX_NUM];uint16_t  len;
};#define VIDIOC_MS8416_READ		_IOWR('V', 5, struct ms8416_iic_data)
#define VIDIOC_MS8416_WRITE		_IOWR('V', 6, struct ms8416_iic_data)
#define VIDIOC_MS8416_CONFIG		_IOWR('V', 7, struct ms8416_iic_data)
#define MS8416_READ_SAMPLE_RATE	_IOR('S', 0x01, int)static int gpio_scl;
static int gpio_sda;
static int gpio_rst;#define MANI2CFREQ     1#define SET_SCL0_1     gpio_direction_output(gpio_scl,1)
#define SET_SDA0_1    gpio_direction_output(gpio_sda,1)
#define SET_SCL1_1     
#define SET_SDA1_1     
#define SET_SCL2_1     
#define SET_SDA2_1     
#define SET_SCL0_0     gpio_direction_output(gpio_scl,0)
#define SET_SDA0_0    gpio_direction_output(gpio_sda,0)
#define SET_SCL1_0     
#define SET_SDA1_0     
#define SET_SCL2_0     
#define SET_SDA2_0    
#define GET_SDA0       gpio_get_value(gpio_sda)
#define GET_SDA1       (0) // Pin INOUT_SDA
#define GET_SDA2       (0) // Pin EEPROM_SDA
#define SCL0_IN        
#define SCL0_OUT       
#define SDA0_IN        gpio_direction_input(gpio_sda)
#define SDA0_OUT       
#define SCL1_IN        
#define SCL1_OUT      
#define SDA1_IN        
#define SDA1_OUT       
#define SCL2_IN        
#define SCL2_OUT      
#define SDA2_IN       
#define SDA2_OUT #define MS8416_REG_CONTROL0 0x00
#define MS8416_REG_CONTROL1 0x01
#define MS8416_REG_CONTROL2 0x02
#define MS8416_REG_CONTROL3 0x03
#define MS8416_REG_CONTROL4 0x04
#define MS8416_REG_CONTROL5 0x05
#define MS8416_REG_CONTROL6 0x06static void I2CDelay(uint16 delay)
{udelay(delay);return;
}
// #define I2CDelay(us)       delay_us(us)
// #define I2CDelay(us)       /*
PB0-1: index 0 I2C 0:SDA, 1:SCL
PB2-3: index 1 I2C 2:SDA, 3:SCL
PB4-5: index 2 I2C 4:SDA, 5:SCL
*/static void ManReleaseScl(uint8 index)
{switch(index){case 0:SCL0_IN;break;case 1:SCL1_IN;break;case 2:SCL2_IN;break;}}static void ManDriveScl(uint8 index)
{switch(index){case 0:SCL0_OUT;break;case 1:SCL1_OUT;break;case 2:SCL2_OUT;break;}}static void ManReleaseSda(uint8 index)
{switch(index){case 0:SDA0_IN;break;case 1:SDA1_IN;break;case 2:SDA2_IN;break;}}static void ManDriveSda(uint8 index)
{switch(index){case 0:SDA0_OUT;break;case 1:SDA1_OUT;break;case 2:SDA2_OUT;break;}}static void ManSclHigh(uint8 index)
{switch(index){case 0:SET_SCL0_1;break;case 1:SET_SCL1_1;break;case 2:SET_SCL2_1;break;}
}static void ManSclLow(uint8 index)
{switch(index){case 0:SET_SCL0_0;break;case 1:SET_SCL1_0;break;case 2:SET_SCL2_0;break;}
}static void ManSdaHigh(uint8 index)
{switch(index){case 0:SET_SDA0_1;break;case 1:SET_SDA1_1;break;case 2:SET_SDA2_1;break;}
}static void ManSdaLow(uint8 index)
{switch(index){case 0:SET_SDA0_0;break;case 1:SET_SDA1_0;break;case 2:SET_SDA2_0;break;}
}static uint8 GetSdaValue(uint8 index)
{uint8 value = 0;switch(index){case 0:value = GET_SDA0;break;case 1:value = GET_SDA1;break;case 2:value = GET_SDA2;break;}return value;
}static uint8 ManGetAck(uint8 index)
{uint8 value = 0;I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);ManReleaseSda(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);value = GetSdaValue(index);I2CDelay(MANI2CFREQ);ManSclLow(index);if(value == 0)ManSdaLow(index);elseManSdaHigh(index);I2CDelay(MANI2CFREQ);ManDriveSda(index);I2CDelay(MANI2CFREQ);return value;
}static void ManSetAck(uint8 index, uint8 i2cdata)
{I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);if(i2cdata != 0)ManSdaHigh(index);elseManSdaLow(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(2*MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);
}static void ManI2cStart(uint8 index)
{ManDriveScl(index);ManDriveSda(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);}static void ManI2cStop(uint8 index)
{I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManReleaseScl(index);ManReleaseSda(index);}static void ManI2cRestart(uint8 index)
{I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);}static uint8 ManI2cSendByte(uint8 index, uint8 i2cdata)
{uint8  i;uint32 value;uint8  ack;/* Send byte */for(i=0;i<8;i++){I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);value = (i2cdata>>(7-i))&0x01;if(value == 0)ManSdaLow(index);elseManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);}I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);/* Release Sda to get ACK */ManReleaseSda(index);ack = ManGetAck(index);ManDriveSda(index);return ack;
}static uint8 ManI2cReadByte(uint8 index, uint8 FinalByte)
{uint8  i;uint32 value = 0;uint8  i2cdata = 0;ManReleaseSda(index);for(i=0;i<8;i++){ManSclLow(index);I2CDelay(2*MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);value = GetSdaValue(index);if(value != 0){i2cdata = (i2cdata<<1)+1;printk("1\n");}else {i2cdata = i2cdata<<1;printk("0\n");}I2CDelay(MANI2CFREQ);}ManSclLow(index);I2CDelay(MANI2CFREQ);ManDriveSda(index);I2CDelay(MANI2CFREQ);if(FinalByte == 0x0)ManSetAck(index,0);elseManSetAck(index,1);return i2cdata;
}static uint8 ManI2cWrite(uint32 devAddress, uint32 regAddress, uint8 *i2cdata, uint16 count, uint8 index, uint8 Flag16bit)
{uint8  value;uint8  ack = 1;uint16 i;ManI2cStart(index);value = devAddress & 0xfe;ack = ManI2cSendByte(index, value);if(Flag16bit == 1){value = (regAddress>>8) & 0xff;ManI2cSendByte(index, value);}value = regAddress & 0xff;ManI2cSendByte(index, value);for(i=0;i<count;i++){if(i==count-1)ManI2cSendByte(index, i2cdata[i]);elseManI2cSendByte(index, i2cdata[i]);}ManI2cStop(index);//I2CDelay(0x3f);if(ack == 0)return 0;elsereturn 1;
}static uint8 ManI2cRead(uint32 devAddress, uint32 regAddress, uint8 *i2cdata, uint16 count, uint8 index, uint8 Flag16bit)
{uint8  value;uint8  ack = 1;uint16 i;ManI2cStart(index);value = devAddress & 0xfe;ack = ManI2cSendByte(index,value);//if(Flag16bit == 1){value = (regAddress>>8) & 0xff;ManI2cSendByte(index, value);}value = regAddress & 0xff;ManI2cSendByte(index,value);ManI2cStop(index);ManI2cStart(index);//ManI2cRestart(index);value = (devAddress & 0xff) | 0x01;ManI2cSendByte(index,value);for(i=0;i<count;i++){if(i==count-1)i2cdata[i] = ManI2cReadByte(index, 1);elsei2cdata[i] = ManI2cReadByte(index, 0);}ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);	ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);	ManI2cStop(index);//I2CDelay(0x3f);if(ack == 0)return 0;elsereturn 1;
}static void I2CWRNBYTE_CODEC(unsigned int regAddress,unsigned char data)
{ManI2cWrite(MS8416_I2C_ADDRESS, regAddress, &data, 1, 0, 0);
}static void codec_write(unsigned int devAddress,unsigned int regAddress,unsigned char data)
{//ManI2cWrite(I2C_1, devAddress, regAddress,&data, 1, 0);ManI2cWrite(MS8416_I2C_ADDRESS, regAddress, &data, 1, 0, 0);
}static void codec_read(unsigned int regAddress,unsigned char *data)
{ManI2cRead(MS8416_I2C_ADDRESS, regAddress, data, 1, 0, 0);
}static int ms8416_open(struct inode *inode, struct file *file)
{return 0;
}static int ms8416_release(struct inode *inode, struct file *file)
{return 0;
}#if 0
static int gsv_read(struct inode *inode, struct file *file)
{//ManI2cRead(gdevAddress, gregAddress, data, count, gindex, gFlag16bit);return 0;
}static int gsv_write(struct inode *inode, struct file *file)
{//ManI2cWrite(gdevAddress, gregAddress, data, count, gindex, gFlag16bit);return 0;
}
#endif/************************************
获取当前音频流采样率
SR_NOW 根据RMCK的频率和OMCK的比例得到
以OMCK=24.576M为例
************************************/
typedef enum _tagSampleRate
{SR_32=32,SR_44=44,SR_48=48,SR_64=64,SR_88=88,SR_96=96,SR_128=128,SR_176=176,SR_192=192,SR_OFF=0xFF,SR_NONE=0xFF,
}SampleRate;SampleRate DAC_ReadSPDIFSampleRate(void)
{uint8_t  data[3]={0};//SR_NOW = DAC_I2C_ReadByte(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL24);ManI2cRead(MS8416_I2C_ADDRESS, 0x18, &data[0], 1, 0, 0);printk("22ms8416_READ 0x18 : 0x%x \n", data[0]);data[0] = ( data[0] + 1 ) & 0XFC ;switch( data[0]){	//24.576 case	0x2F:case	0x30:case	0x31:	printk("128khz\n");return SR_128;case	0x5F:case	0x60:case	0x61:	printk("64khz\n");return SR_64;case	0xBF:case	0xC0:case	0xC1:	printk("32khz\n");return SR_32;case	0x1F:case	0x20:case	0x21:	printk("192khz\n");return SR_192;case	0x3F:case	0x40:case	0x41:	printk("96khz\n");return SR_96;case	0x7F:case	0x80:case	0x81:	printk("48khz\n");return SR_48;case	0x22:case	0x23:case	0x24:	printk("176khz\n");return SR_176;case	0x45:case	0x46:case	0x47:printk("88khz\n");return SR_88;case	0x8B:case	0x8C:case	0x8D:case	0x8E:	printk("44khz\n");return SR_44;default:	printk("0khz\n");return SR_NONE;}
}static long ms8416_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{int rate = 0;int ret = 0;switch (cmd) {case MS8416_READ_SAMPLE_RATE:rate = DAC_ReadSPDIFSampleRate();if (copy_to_user((int __user *)arg, &rate, sizeof(int))) {ret = -EFAULT;}default:break;}return ret;
}static ssize_t ms8416_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {uint8_t  data[3]={0};ManI2cRead(0x20, 0x0B, &data[0], 1, 0, 0);printk("22ms8416_READ 0x0B : 0x%x \n", data[0]);ManI2cRead(0x20, 0x0D, &data[0], 1, 0, 0);printk("22ms8416_READ 0x0D : 0x%x \n", data[0]);ManI2cRead(0x20, 0x18, &data[0], 1, 0, 0);printk("22ms8416_READ 0x18 : 0x%x \n", data[0]);DAC_ReadSPDIFSampleRate();return 0;
}
static struct file_operations ms8416_fops = {.owner = THIS_MODULE,.open = ms8416_open,.release = ms8416_release,.unlocked_ioctl = ms8416_ioctl,.read = ms8416_read,//.write = ms8416_write,
};static struct miscdevice ms8416_device = {.minor = MISC_DYNAMIC_MINOR,.name = "_ms",.fops = &ms8416_fops,
};
extern void set_slave_mode();
static int  ms8416_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;int ret;int err;uint8_t  data[3]={0};uint8_t reg;uint8_t i;//int period;printk("====ms8416_probe==\n");gpio_scl = of_get_named_gpio(np, "ms84x6_scl", 0);if (!gpio_is_valid(gpio_scl)) {dev_err(&pdev->dev, "invalid host gpio%d\n", gpio_scl);} else {err = devm_gpio_request(&pdev->dev, gpio_scl, "ms84x6_scl");if (err) {dev_err(&pdev->dev,"failed to request GPIO%d for ms84x6_scl\n",gpio_scl);ret = err;}gpio_direction_output(gpio_scl, 1);}	gpio_sda = of_get_named_gpio(np, "ms84x6_sda", 0);if (!gpio_is_valid(gpio_sda)) {dev_err(&pdev->dev, "invalid host gpio%d\n", gpio_sda);} else {err = devm_gpio_request(&pdev->dev, gpio_sda, "ms84x6_sda");if (err) {dev_err(&pdev->dev,"failed to request GPIO%d for ms84x6_sda\n",gpio_sda);ret = err;}gpio_direction_output(gpio_sda, 1);}gpio_rst = of_get_named_gpio(np, "ms84x6_reset", 0);if (!gpio_is_valid(gpio_rst)) {dev_err(&pdev->dev, "invalid host gpio%d\n", gpio_rst);} else {err = devm_gpio_request(&pdev->dev, gpio_rst, "ms84x6_reset");if (err) {dev_err(&pdev->dev,"failed to request GPIO%d for ms84x6_reset\n",gpio_rst);ret = err;}}ret = misc_register(&ms8416_device);if (ret) {pr_err("gsv_probe: ms8416_device register failed\n");goto misc_register_failed;}int value = -1;value = gpio_direction_input(gpio_sda);if (value >= 0 ){printk("value = %d gpio_direction_input(gpio_sda);\n",value);}value = gpio_get_value(gpio_sda);printk("wzh gpio_sda value = %d\n", value);value = gpio_direction_input(gpio_scl);if (value >= 0) {printk("value = %d gpio_direction_input(gpio_scl);\n",value);}value = gpio_get_value(gpio_scl);printk("wzh gpio_scl value = %d\n", value);//reset chipgpio_direction_output(gpio_rst, 0);usleep_range(5000, 5100);gpio_direction_output(gpio_rst, 1);usleep_range(500, 510);ManI2cRead(0x20, 0x7f, &data[0], 1, 0, 0);	//检查IIC是否连通,地址设置是否正确。printk("ms8416_READ 0x20 : 0x%x \n", data[0]);usleep_range(500, 510);ManI2cRead(0x20, 0x7f, &data[0], 1, 0, 0);	//检查IIC是否连通,地址设置是否正确。printk("22ms8416_READ 0x20 : 0x%x \n", data[0]);#if 1codec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL0,0x00);codec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL1,0x84);		//0x84没有输入时候	RMCK自动切换到OMCK	SDOUT=0codec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL2,0x40);		//去加重设为自动codec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL3,0x00);		//GPIO均没有使用#if 0//Standbycodec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL4,0x40);		//RMCK =Zcodec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL5,0x05);		//BC=Z LRCK=Z (Slave mode)#else//workcodec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL4,0x80|(0<<3)); //RXP0codec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL5,0x85);		//z1模式#endifcodec_write(MS8416_I2C_ADDRESS,MS8416_REG_CONTROL6,0x7F);		//异常报错全开#endifusleep_range(5000, 5100);ManI2cRead(0x20, MS8416_REG_CONTROL0, &data[0], 1, 0, 0);	printk("22ms8416_READ MS8416_REG_CONTROL0 : 0x%x \n", data[0]);ManI2cRead(0x20, MS8416_REG_CONTROL1, &data[0], 1, 0, 0);	printk("22ms8416_READ MS8416_REG_CONTROL1 : 0x%x \n", data[0]);ManI2cRead(0x20, MS8416_REG_CONTROL2, &data[0], 1, 0, 0);	printk("22ms8416_READ MS8416_REG_CONTROL2 : 0x%x \n", data[0]);ManI2cRead(0x20, MS8416_REG_CONTROL3, &data[0], 1, 0, 0);	printk("22ms8416_READ MS8416_REG_CONTROL3 : 0x%x \n", data[0]);ManI2cRead(0x20, MS8416_REG_CONTROL4, &data[0], 1, 0, 0);	printk("22ms8416_READ MS8416_REG_CONTROL4 : 0x%x \n", data[0]);ManI2cRead(0x20, MS8416_REG_CONTROL5, &data[0], 1, 0, 0);	printk("22ms8416_READ MS8416_REG_CONTROL5 : 0x%x \n", data[0]);printk(KERN_INFO "ms8416  driver registered.\n");return 0;
misc_register_failed:misc_deregister(&ms8416_device);gpio_free(gpio_scl);gpio_free(gpio_sda);return -1;
}static int  ms8416_remove(struct platform_device *pdev)
{misc_deregister(&ms8416_device);gpio_free(gpio_scl);gpio_free(gpio_sda);return 0;
}static struct of_device_id ms8416_of_match[] = {{ .compatible = "rockchip,_ms" },{ }
};static struct platform_driver ms8416_driver = {.probe = ms8416_probe,.remove		= ms8416_remove, .driver		= {.name	= "_ms", .of_match_table = of_match_ptr(ms8416_of_match),.owner	= THIS_MODULE,},
};static int ms8416_init(void)
{int retval = 0;retval = platform_driver_register(&ms8416_driver);if (retval < 0) {printk(KERN_ERR "%s retval=%d\n", __func__, retval);return retval;}return 0;
}static void ms8416_exit(void)
{platform_driver_unregister(&ms8416_driver);
}module_init(ms8416_init); 
module_exit(ms8416_exit);MODULE_AUTHOR("xxx,Inc.");
MODULE_DESCRIPTION("ms8416 driver");
MODULE_LICENSE("GPL");

3、ms8406驱动

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <linux/i2c.h>
#include <linux/err.h>
#include <linux/input-polldev.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
#include <linux/timex.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
//#include <linux/ec.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>#include <linux/wakelock.h>//#include <linux/pwm.h>//static struct pwm_device	*pwm;typedef unsigned char  uchar;
typedef char           schar;
typedef unsigned char  uint8;
typedef signed char    int8;
typedef unsigned short uint16;
typedef short          int16;
typedef unsigned int   uint32;
typedef int            int32;#define ES7243_IIC_DATA_MAX_NUM    256
#define MS8406_I2C_ADDRESS 0x2C  struct ms8406_iic_data {uint32_t devAddress;uint32_t regAddress;uint8_t  index;uint8_t  Flag16bit;uint8_t  data[ES7243_IIC_DATA_MAX_NUM];uint16_t  len;
};#define VIDIOC_ms8406_READ		_IOWR('V', 5, struct ms8406_iic_data)
#define VIDIOC_ms8406_WRITE		_IOWR('V', 6, struct ms8406_iic_data)
#define VIDIOC_ms8406_CONFIG		_IOWR('V', 7, struct ms8406_iic_data)static int gpio_scl;
static int gpio_sda;
static int gpio_rst;#define MANI2CFREQ     1#define SET_SCL0_1     gpio_direction_output(gpio_scl,1)
#define SET_SDA0_1    gpio_direction_output(gpio_sda,1)
#define SET_SCL1_1     
#define SET_SDA1_1     
#define SET_SCL2_1     
#define SET_SDA2_1     
#define SET_SCL0_0     gpio_direction_output(gpio_scl,0)
#define SET_SDA0_0    gpio_direction_output(gpio_sda,0)
#define SET_SCL1_0     
#define SET_SDA1_0     
#define SET_SCL2_0     
#define SET_SDA2_0    
#define GET_SDA0       gpio_get_value(gpio_sda)
#define GET_SDA1       (0) // Pin INOUT_SDA
#define GET_SDA2       (0) // Pin EEPROM_SDA
#define SCL0_IN        
#define SCL0_OUT       
#define SDA0_IN        gpio_direction_input(gpio_sda)
#define SDA0_OUT       
#define SCL1_IN        
#define SCL1_OUT      
#define SDA1_IN        
#define SDA1_OUT       
#define SCL2_IN        
#define SCL2_OUT      
#define SDA2_IN       
#define SDA2_OUT #define MS8406_REG_CONTROL0 0x00
#define MS8406_REG_CONTROL1 0x01
#define MS8406_REG_CONTROL2 0x02
#define MS8406_REG_CONTROL3 0x03
#define MS8406_REG_CONTROL4 0x04
#define MS8406_REG_CONTROL5 0x05
#define MS8406_REG_CONTROL6 0x06#define EC_EN 		0#if EC_EN#endifstatic void I2CDelay(uint16 delay)
{udelay(delay);return;
}
// #define I2CDelay(us)       delay_us(us)
// #define I2CDelay(us)       /*
PB0-1: index 0 I2C 0:SDA, 1:SCL
PB2-3: index 1 I2C 2:SDA, 3:SCL
PB4-5: index 2 I2C 4:SDA, 5:SCL
*/static void ManReleaseScl(uint8 index)
{switch(index){case 0:SCL0_IN;break;case 1:SCL1_IN;break;case 2:SCL2_IN;break;}}static void ManDriveScl(uint8 index)
{switch(index){case 0:SCL0_OUT;break;case 1:SCL1_OUT;break;case 2:SCL2_OUT;break;}}static void ManReleaseSda(uint8 index)
{switch(index){case 0:SDA0_IN;break;case 1:SDA1_IN;break;case 2:SDA2_IN;break;}}static void ManDriveSda(uint8 index)
{switch(index){case 0:SDA0_OUT;break;case 1:SDA1_OUT;break;case 2:SDA2_OUT;break;}}static void ManSclHigh(uint8 index)
{switch(index){case 0:SET_SCL0_1;break;case 1:SET_SCL1_1;break;case 2:SET_SCL2_1;break;}
}static void ManSclLow(uint8 index)
{switch(index){case 0:SET_SCL0_0;break;case 1:SET_SCL1_0;break;case 2:SET_SCL2_0;break;}
}static void ManSdaHigh(uint8 index)
{switch(index){case 0:SET_SDA0_1;break;case 1:SET_SDA1_1;break;case 2:SET_SDA2_1;break;}
}static void ManSdaLow(uint8 index)
{switch(index){case 0:SET_SDA0_0;break;case 1:SET_SDA1_0;break;case 2:SET_SDA2_0;break;}
}static uint8 GetSdaValue(uint8 index)
{uint8 value = 0;switch(index){case 0:value = GET_SDA0;break;case 1:value = GET_SDA1;break;case 2:value = GET_SDA2;break;}return value;
}static uint8 ManGetAck(uint8 index)
{uint8 value = 0;I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);ManReleaseSda(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);value = GetSdaValue(index);I2CDelay(MANI2CFREQ);ManSclLow(index);if(value == 0)ManSdaLow(index);elseManSdaHigh(index);I2CDelay(MANI2CFREQ);ManDriveSda(index);I2CDelay(MANI2CFREQ);return value;
}static void ManSetAck(uint8 index, uint8 i2cdata)
{I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);if(i2cdata != 0)ManSdaHigh(index);elseManSdaLow(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(2*MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);
}static void ManI2cStart(uint8 index)
{ManDriveScl(index);ManDriveSda(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);}static void ManI2cStop(uint8 index)
{I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManReleaseScl(index);ManReleaseSda(index);}static void ManI2cRestart(uint8 index)
{I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);}static uint8 ManI2cSendByte(uint8 index, uint8 i2cdata)
{uint8  i;uint32 value;uint8  ack;/* Send byte */for(i=0;i<8;i++){I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);value = (i2cdata>>(7-i))&0x01;if(value == 0)ManSdaLow(index);elseManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);}I2CDelay(MANI2CFREQ);ManSclLow(index);I2CDelay(MANI2CFREQ);/* Release Sda to get ACK */ManReleaseSda(index);ack = ManGetAck(index);ManDriveSda(index);return ack;
}static uint8 ManI2cReadByte(uint8 index, uint8 FinalByte)
{uint8  i;uint32 value = 0;uint8  i2cdata = 0;ManReleaseSda(index);for(i=0;i<8;i++){ManSclLow(index);I2CDelay(2*MANI2CFREQ);ManSclHigh(index);I2CDelay(MANI2CFREQ);value = GetSdaValue(index);if(value != 0){i2cdata = (i2cdata<<1)+1;printk("1\n");}else {i2cdata = i2cdata<<1;printk("0\n");}I2CDelay(MANI2CFREQ);}ManSclLow(index);I2CDelay(MANI2CFREQ);ManDriveSda(index);I2CDelay(MANI2CFREQ);if(FinalByte == 0x0)ManSetAck(index,0);elseManSetAck(index,1);return i2cdata;
}static uint8 ManI2cWrite(uint32 devAddress, uint32 regAddress, uint8 *i2cdata, uint16 count, uint8 index, uint8 Flag16bit)
{uint8  value;uint8  ack = 1;uint16 i;ManI2cStart(index);value = devAddress & 0xfe;ack = ManI2cSendByte(index, value);if(Flag16bit == 1){value = (regAddress>>8) & 0xff;ManI2cSendByte(index, value);}value = regAddress & 0xff;ManI2cSendByte(index, value);for(i=0;i<count;i++){if(i==count-1)ManI2cSendByte(index, i2cdata[i]);elseManI2cSendByte(index, i2cdata[i]);}ManI2cStop(index);//I2CDelay(0x3f);if(ack == 0)return 0;elsereturn 1;
}static uint8 ManI2cRead(uint32 devAddress, uint32 regAddress, uint8 *i2cdata, uint16 count, uint8 index, uint8 Flag16bit)
{uint8  value;uint8  ack = 1;uint16 i;ManI2cStart(index);value = devAddress & 0xfe;ack = ManI2cSendByte(index,value);//if(Flag16bit == 1){value = (regAddress>>8) & 0xff;ManI2cSendByte(index, value);}value = regAddress & 0xff;ManI2cSendByte(index,value);ManI2cStop(index);ManI2cStart(index);//ManI2cRestart(index);value = (devAddress & 0xff) | 0x01;ManI2cSendByte(index,value);for(i=0;i<count;i++){if(i==count-1)i2cdata[i] = ManI2cReadByte(index, 1);elsei2cdata[i] = ManI2cReadByte(index, 0);}ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);	ManSdaHigh(index);I2CDelay(MANI2CFREQ);ManSdaLow(index);I2CDelay(MANI2CFREQ);	ManI2cStop(index);//I2CDelay(0x3f);if(ack == 0)return 0;elsereturn 1;
}static void I2CWRNBYTE_CODEC(unsigned int regAddress,unsigned char data)
{ManI2cWrite(MS8406_I2C_ADDRESS, regAddress, &data, 1, 0, 0);
}static void codec_write(unsigned int devAddress,unsigned int regAddress,unsigned char data)
{//ManI2cWrite(I2C_1, devAddress, regAddress,&data, 1, 0);ManI2cWrite(MS8406_I2C_ADDRESS, regAddress, &data, 1, 0, 0);
}static void codec_read(unsigned int regAddress,unsigned char *data)
{ManI2cRead(MS8406_I2C_ADDRESS, regAddress, data, 1, 0, 0);
}static int ms8406_open(struct inode *inode, struct file *file)
{return 0;
}static int ms8406_release(struct inode *inode, struct file *file)
{return 0;
}#if 0
static int gsv_read(struct inode *inode, struct file *file)
{//ManI2cRead(gdevAddress, gregAddress, data, count, gindex, gFlag16bit);return 0;
}static int gsv_write(struct inode *inode, struct file *file)
{//ManI2cWrite(gdevAddress, gregAddress, data, count, gindex, gFlag16bit);return 0;
}
#endif
static long ms8406_ioctl(struct file * file, unsigned int cmd, unsigned long arg)
{struct ms8406_iic_data iic_data;memset(&iic_data, 0, sizeof(iic_data));if (copy_from_user(&iic_data, (void __user *)arg, sizeof(iic_data))){printk("VIDIOC_ms8406_READ copy_from_user error \n");return -EFAULT;	}switch (cmd) {case VIDIOC_ms8406_CONFIG:			//printk("CNF devAddr:%d,regAddr:%d,index:%d,flag16:%d\n",iic_data.devAddress,iic_data.regAddress,iic_data.index,iic_data.Flag16bit);break;case VIDIOC_ms8406_READ:	if(iic_data.len>ES7243_IIC_DATA_MAX_NUM){printk("VIDIOC_GSV_READ error len:%d \n", iic_data.len);return -EINVAL;}else{if(ManI2cRead(iic_data.devAddress, iic_data.regAddress, iic_data.data, iic_data.len, iic_data.index, iic_data.Flag16bit)!=0) {printk("VIDIOC_ms8406_READ error\n");return -EINVAL;}else{if (copy_to_user((void __user *)arg,&iic_data,sizeof(iic_data))){printk("VIDIOC_ms8406_READ copy_to_user error \n");return -EFAULT;}}}//printk("READ devAddr:%d,regAddr:%d,index:%d,flag16:%d\n",iic_data.devAddress,iic_data.regAddress,iic_data.index,iic_data.Flag16bit);break;case VIDIOC_ms8406_WRITE:			if(iic_data.len>ES7243_IIC_DATA_MAX_NUM){printk("VIDIOC_ms8406_WRITE error len:%d \n", iic_data.len);return -EINVAL;}else{if(ManI2cWrite(iic_data.devAddress, iic_data.regAddress, iic_data.data, iic_data.len, iic_data.index, iic_data.Flag16bit)!=0) {printk("VIDIOC_ms8406_WRITE error\n");return -EINVAL;}}//printk("WRITE devAddr:%d,regAddr:%d,index:%d,flag16:%d\n",iic_data.devAddress,iic_data.regAddress,iic_data.index,iic_data.Flag16bit);break;default:break;}return 0;
}
static ssize_t ms8406_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) {uint8_t  data[3]={0};codec_write(MS8406_I2C_ADDRESS, 0x04, 0x00); usleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x04, 0x20); //512Fsusleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x04, 0x40|0x20); //bit6:runusleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x05, 0xA5);ManI2cRead(MS8406_I2C_ADDRESS, 0x04, &data[0], 1, 0, 0);	printk("22ms8406_READ 0x04 : 0x%x \n", data[0]);usleep_range(5000, 5100);ManI2cRead(MS8406_I2C_ADDRESS, 0x05, &data[0], 1, 0, 0);	printk("22ms8406_READ 0x05 : 0x%x \n", data[0]);usleep_range(5000, 5100);ManI2cRead(MS8406_I2C_ADDRESS, 0x7f, &data[0], 1, 0, 0);	//读版本号printk("ms8406_READ 0x7F : 0x%x \n", data[0]);return 0;
}static struct file_operations ms8406_fops = {.owner = THIS_MODULE,.open = ms8406_open,.release = ms8406_release,.unlocked_ioctl = ms8406_ioctl,.read = ms8406_read,//.write = ms8406_write,
};static struct miscdevice ms8406_device = {.minor = MISC_DYNAMIC_MINOR,.name = "_ms",.fops = &ms8406_fops,
};static int  ms8406_probe(struct platform_device *pdev)
{struct device_node *np = pdev->dev.of_node;int ret;int err;uint8_t  data[3]={0};uint8_t reg;uint8_t i;//int period;printk("====ms8406_probe==\n");gpio_scl = of_get_named_gpio(np, "ms84x6_scl", 0);if (!gpio_is_valid(gpio_scl)) {dev_err(&pdev->dev, "invalid host gpio%d\n", gpio_scl);} else {err = devm_gpio_request(&pdev->dev, gpio_scl, "ms84x6_scl");if (err) {dev_err(&pdev->dev,"failed to request GPIO%d for ms84x6_scl\n",gpio_scl);ret = err;}gpio_direction_output(gpio_scl, 1);}	gpio_sda = of_get_named_gpio(np, "ms84x6_sda", 0);if (!gpio_is_valid(gpio_sda)) {dev_err(&pdev->dev, "invalid host gpio%d\n", gpio_sda);} else {err = devm_gpio_request(&pdev->dev, gpio_sda, "ms84x6_sda");if (err) {dev_err(&pdev->dev,"failed to request GPIO%d for ms84x6_sda\n",gpio_sda);ret = err;}gpio_direction_output(gpio_sda, 1);}gpio_rst = of_get_named_gpio(np, "ms84x6_reset", 0);if (!gpio_is_valid(gpio_rst)) {dev_err(&pdev->dev, "invalid host gpio%d\n", gpio_rst);} else {err = devm_gpio_request(&pdev->dev, gpio_rst, "ms84x6_reset");if (err) {dev_err(&pdev->dev,"failed to request GPIO%d for ms84x6_reset\n",gpio_rst);ret = err;}}ret = misc_register(&ms8406_device);if (ret) {pr_err("gsv_probe: ms8406_device register failed\n");goto misc_register_failed;}int value = -1;value = gpio_direction_input(gpio_sda);if (value >= 0 ){printk("value = %d gpio_direction_input(gpio_sda);\n",value);}value = gpio_get_value(gpio_sda);printk("wzh gpio_sda value = %d\n", value);value = gpio_direction_input(gpio_scl);if (value >= 0) {printk("value = %d gpio_direction_input(gpio_scl);\n",value);}value = gpio_get_value(gpio_scl);printk("wzh gpio_scl value = %d\n", value);#if EC_ENret = DrvSoftLockDecode();if(ret) {printk("ec DrvSoftLockDecode_failed\n");//goto DrvSoftLockDecode_failed;}wake_lock_init(&wake_lock_sleep, WAKE_LOCK_SUSPEND, "wake_lock_sleep");wake_lock(&wake_lock_sleep);#endif//reset chipgpio_direction_output(gpio_rst, 0);usleep_range(5000, 5100);gpio_direction_output(gpio_rst, 1);usleep_range(500, 510);ManI2cRead(MS8406_I2C_ADDRESS, 0x7f, &data[0], 1, 0, 0);	//读版本号printk("ms8406_READ 0x7F : 0x%x \n", data[0]);#if 1usleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x04, 0x00); usleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x04, 0x20); //512Fsusleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x04, 0x40|0x20); //bit6:runusleep_range(500, 510);codec_write(MS8406_I2C_ADDRESS, 0x05, 0xA5); // BIT7:主模式 BIT5,BIT4:16BIT  bit2:i2s模式 bit0:1 - 当 ILRCK 为高电平时,SDIN 数据用于正确的通道usleep_range(500, 510);ManI2cRead(MS8406_I2C_ADDRESS, 0x04, &data[0], 1, 0, 0);	printk("22ms8406_READ 0x04 : 0x%x \n", data[0]);usleep_range(500, 510);ManI2cRead(MS8406_I2C_ADDRESS, 0x05, &data[0], 1, 0, 0);	printk("22ms8406_READ 0x05 : 0x%x \n", data[0]);usleep_range(500, 510);ManI2cRead(MS8406_I2C_ADDRESS, 0x7f, &data[0], 1, 0, 0);	//读版本号printk("ms8406_READ 0x7F : 0x%x \n", data[0]);#endifusleep_range(5000, 5100);printk(KERN_INFO "ms8406  driver registered.\n");return 0;
misc_register_failed:misc_deregister(&ms8406_device);gpio_free(gpio_scl);gpio_free(gpio_sda);return -1;
}static int  ms8406_remove(struct platform_device *pdev)
{misc_deregister(&ms8406_device);gpio_free(gpio_scl);gpio_free(gpio_sda);return 0;
}static struct of_device_id ms8406_of_match[] = {{ .compatible = "rockchip,_ms" },{ }
};static struct platform_driver ms8406_driver = {.probe = ms8406_probe,.remove		= ms8406_remove, .driver		= {.name	= "_ms", .of_match_table = of_match_ptr(ms8406_of_match),.owner	= THIS_MODULE,},
};static int ms8406_init(void)
{int retval = 0;retval = platform_driver_register(&ms8406_driver);if (retval < 0) {printk(KERN_ERR "%s retval=%d\n", __func__, retval);return retval;}return 0;
}static void ms8406_exit(void)
{platform_driver_unregister(&ms8406_driver);
}module_init(ms8406_init); 
module_exit(ms8406_exit);MODULE_AUTHOR("xxx,Inc.");
MODULE_DESCRIPTION("ms8406 driver");
MODULE_LICENSE("GPL");

4、遇到的问题

1、配置i2s为从机模式


参考第一点的内容,下面是其手册对从机模式的描述

2、ms8416读取采样率的时候,25脚OMCK应该接外部时钟,以供参考

3、ms8416 RMCK/OLRCK/OSCLK 频率是多少?

12.288M,3.072M,48K


4、调试工具

tinyplay /dev/2024-04-29_171929.wav -D 0 -d 0 -r 48000 
tinycap /dev/output.wav -D 0 -d 0 -c 2 -r 48000 -b 16 -t 10

5、录音遇到分区空间不足,导致声音混乱失真

刚开始是录制在data分区的,就是声音都失真了,导致调试好久都找不到原因,后面录制在/dev分区问题解决

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1544577.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

目标检测系列(三)yolov2的全面讲解

YOLOv2&#xff08;论文原名《YOLO9000: Better, Faster, Stronger》&#xff09;作为该系列的第二个版本&#xff0c;对原始YOLO进行了显著的改进&#xff0c;进一步提高了检测速度和准确度。在精度上利用一些列训练技巧&#xff0c;在速度上应用了新的网络模型DarkNet19&…

小阿轩yx-Ansible部署与应用基础

小阿轩yx-Ansible部署与应用基础 前言 由于互联网的快速发展导致产品更新换代速度逐步增长&#xff0c;运维人员每天都要进行大量的维护操作&#xff0c;按照传统方式进行维护使得工作效率低下。这时部署自动化运维就可以尽可能安全、高效的完成这些工作。 Ansible 概述 什…

自闭症寄宿学校陕西:提供综合发展的教育环境

星贝育园&#xff1a;自闭症儿童的综合发展摇篮 在自闭症儿童教育的广阔领域里&#xff0c;寄宿制学校以其独特的康复环境和全方位的支持体系&#xff0c;为这些特殊的孩子点亮了希望之灯。广州的星贝育园自闭症儿童寄宿制学校&#xff0c;正是这样一所充满爱心与专业的机构&a…

探索自闭症寄宿学校:为孩子的未来铺设坚实基石

探索自闭症寄宿学校&#xff1a;星贝育园——为孩子的未来铺设坚实基石 在自闭症儿童成长的道路上&#xff0c;选择一所合适的学校&#xff0c;无疑是为他们铺设坚实基石的关键一步。广州的星贝育园自闭症儿童寄宿制学校&#xff0c;以其专业的教育理念、全面的支持体系和温馨…

使用PLSQL Developer快速连接数据库

文章目录 前言一、定义设置方式二、固定用户设置方式三、连接设置方式总结前言 PLSQL Developer是一个集成开发环境,由Allround Automations公司开发,专门面向Oracle数据库存储的程序单元的开发。该工具提供了多种设置方式,便于使用者在不需要输入用户名称、密码的情况下,…

鸿蒙 如何退出 APP

terminateSelf() 停止Ability自身 在EntryAbility中这么使用 this.context.terminateSelf()在Pages页面中这么使用 import { common } from kit.AbilityKit (getContext(this) as common.UIAbilityContext)?.terminateSelf() 也可以直接封装&#xff1a; import common f…

查了好几天的问题终于画上了句号

问题背景&#xff1a; 产品接到前方实施反馈9月02日有些订单查不到签名值&#xff0c;对于医院验签查不到签名值&#xff0c;就无法完成验签数据归档。 问题追踪过程&#xff1a; 1 首先查数据库&#xff0c;发现订单id确实查不到对应的detail数据&#xff1b; 第一直觉是否是…

如何使用ssm实现基于Java web的高校学生课堂考勤系统的设计与实现+vue

TOC ssm686基于Java web的高校学生课堂考勤系统的设计与实现vue 第一章 课题背景及研究内容 1.1 课题背景 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#x…

SpringBoot集成微信小程序Demo

一、前言 小程序是一种全新的连接用户与服务的方式&#xff0c;它可以在微信内被便捷地获取和传播&#xff0c;同时具有出色的使用体验。 微信小程序官方文档&#xff1a;https://developers.weixin.qq.com/miniprogram/dev/framework/ 二、技术栈 SpringBoot 2.0MyBatis-P…

不同类型的企业该如何挑选适合的供应商管理系统?

供应商管理对企业降低成本、维持稳定的货品来源起着重要的作用&#xff0c;在选择供应商管理系统时&#xff0c;需要考虑多重因素&#xff0c;正所谓没有最好只有最合适&#xff0c;需要结合企业自身需求进行多方面考量才能做出明智的决策。 本文将对国内外制造业都在使用的供…

找最小数 - 华为OD统一考试(E卷)

2024华为OD机试&#xff08;E卷D卷C卷&#xff09;最新题库【超值优惠】Java/Python/C合集 题目描述 给一个正整数NUM1&#xff0c;计算出新正整数NUM2&#xff0c;NUM2为NUM1中移除N位数字后的结果需要使得NUM2的值最小。 输入描述 输入的第一行为一个字符串&#xff0c;字…

一款前后端分离设计的企业级快速开发平台,支持单体服务与微服务之间灵活切换(附源码)

前言 当前软件开发面临诸多挑战&#xff0c;诸如开发效率低下、重复工作多、维护成-本高等问题&#xff0c;这些问题在一定程度上阻碍了项目的进展。针对这些痛点&#xff0c;我们迫切需要一款既能提升开发效率又能降低维护成-本的处理方案。由此&#xff0c;一款基于前后端分…

【Day20240924】联邦学习中的方法 改进

文章目录 前言一、FedAvg二、FedProx三、MOON四、FedDyn五、FedAsync六、PORT七、ASO-Fed八、FedBuff九、FedSA 前言 几种异步的方法&#xff1a; FedAsync PORT ASO-Fed FedBuff FedSA 几种同步的方法&#xff1a; FedAvg FedProx MOON FedDyn 一、FedAvg FedAvg基本步骤&a…

大模型开发应用实战:真实项目实战对标各类大厂大模型算法岗技术

一、引言 在人工智能领域&#xff0c;大模型已经成为推动技术进步和应用创新的重要力量。随着技术的不断发展&#xff0c;各大厂商纷纷投入大量资源研发大模型&#xff0c;并尝试将其应用于各种实际场景中。为了培养具备大模型开发与应用能力的高级技术人才&#xff0c;我们组织…

cuda算子优化-transpose

transpose 参考链接 方法一&#xff1a;每个线程负责一个元素的转置 cuda代码实现 ncu分析&#xff08;矩阵维度采用m1024&#xff0c;n512&#xff1b;grid和block维度见下图最上方&#xff09; 这种方法对读global mem比较友好&#xff0c;可以做到合并访存&#xff0c;但…

知识产权 ABS 企业融资新渠道

在当今知识经济时代&#xff0c;知识产权作为企业的核心资产&#xff0c;其价值日益凸显。知识产权资产证券化&#xff08;Intellectual Property Asset-Backed Securitization&#xff0c;简称知识产权ABS&#xff09;作为一种创新的金融工具&#xff0c;为企业盘活知识产权资…

Cpp类和对象(下)(6)

文章目录 前言一、初始化列表概念使用注意实际运用explicit关键字初始化列表的总结 二、static成员static成员的概念static成员的特性static的一个实用场景 三、友元友元函数友元类 四、内部类概念特性 五、匿名对象六、再次理解封装和面向对象总结 前言 Hello&#xff0c;本篇…

【Oauth2整合gateway网关实现微服务单点登录】

文章目录 一.什么是单点登录&#xff1f;二.Oauth2整合网关实现微服务单点登录三.时序图四.代码实现思路1.基于OAuth2独立一个认证中心服务出来2.网关微服务3产品微服务4.订单微服务5.开始测试单点登录 一.什么是单点登录&#xff1f; 单点登录&#xff08;Single Sign On&…

权威期刊Cell Discovery新成果!上海交大洪亮团队提出CPDiffusion模型,超低成本、全自动设计功能型蛋白质

蛋白质是生命活动的主要执行者&#xff0c;其结构与功能之间的关系一直是生命科学领域研究的核心议题。近年来&#xff0c;随着深度学习的兴起&#xff0c;借助其强大的数据处理能力&#xff0c;让模型学习蛋白质序列、结构及其功能之间的映射关系&#xff0c;设计出具备更高稳…

prithvi WxC气象模型

NASA发布了prithvi WxC气象模型发布 Prithvi是NASA开源的模型&#xff0c;被誉为全球最大的开源地理空间大模型。昨天晚上逛X平台&#xff0c;我看到Prithvi模型又来了新成员&#xff1a;prithvi WxC。 NASA和IBM创建了一个基于MERRA-2数据的天气和气候AI基础模型—Prithvi Wx…