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分区问题解决