add es8323 codec for pcm modem

This commit is contained in:
陈金泉
2013-07-01 17:31:52 +08:00
parent d5db020589
commit 1dbd249045
6 changed files with 436 additions and 19 deletions

View File

@@ -23,9 +23,15 @@
#define DISABLE 0
static struct modem_sound_data *modem_sound;
int (*set_codec_for_pcm_modem)(int cmd) = NULL; /* Set the codec used only for PCM modem */
void (*set_codec_spk)(int on) = NULL;
#if defined(CONFIG_SND_RK_SOC_RK2928)|| defined(CONFIG_SND_RK29_SOC_RK610)
extern void call_set_spk(int on);
#endif
#ifdef CONFIG_SND_SOC_ES8323_PCM
extern int set_es8323(int cmd);
#endif
#define HP_MIC 0
#define MAIN_MIC 1
#if defined(CONFIG_MODEM_MIC_SWITCH)
@@ -86,14 +92,14 @@ static ssize_t modem_sound_read(struct file *filp, char __user *ptr, size_t size
static long modem_sound_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
long ret = 0;
int ret = 0, codec_pcm_cmd = -1, codec_cmd = -1, modem_spk_enable = -1;
struct modem_sound_data *pdata = modem_sound;
DBG("modem_sound_ioctl: cmd = %d arg = %ld\n",cmd, arg);
ret = down_interruptible(&pdata->power_sem);
if (ret < 0) {
printk("%s: down power_sem error ret = %ld\n", __func__, ret);
printk("%s: down power_sem error ret = %d\n", __func__, ret);
return ret;
}
@@ -101,47 +107,70 @@ static long modem_sound_ioctl(struct file *filp, unsigned int cmd, unsigned long
case IOCTL_MODEM_EAR_PHOEN:
DBG("modem_sound_ioctl: MODEM_EAR_PHONE\n");
Modem_Sound_Mic_switch(MAIN_MIC);
call_set_spk(3);
modem_sound_spkctl(DISABLE);
codec_cmd = 3;
codec_pcm_cmd = RCV;
modem_spk_enable = DISABLE;
break;
case IOCTL_MODEM_SPK_PHONE:
DBG("modem_sound_ioctl: MODEM_SPK_PHONE\n");
Modem_Sound_Mic_switch(MAIN_MIC);
call_set_spk(1);
modem_sound_spkctl(ENABLE);
codec_cmd = 1;
codec_pcm_cmd = SPK_PATH;
modem_spk_enable = ENABLE;
break;
case IOCTL_MODEM_HP_WITHMIC_PHONE:
DBG("modem_sound_ioctl: MODEM_HP_WITHMIC_PHONE\n");
Modem_Sound_Mic_switch(HP_MIC);
call_set_spk(2);
modem_sound_spkctl(DISABLE);
codec_cmd = 2;
codec_pcm_cmd = HP_PATH;
modem_spk_enable = DISABLE;
break;
case IOCTL_MODEM_BT_PHONE:
call_set_spk(3);
modem_sound_spkctl(DISABLE);
codec_cmd = 3;
codec_pcm_cmd = BT;
modem_spk_enable = DISABLE;
DBG("modem_sound_ioctl: MODEM_BT_PHONE\n");
break;
case IOCTL_MODEM_STOP_PHONE:
DBG("modem_sound_ioctl: MODEM_STOP_PHONE\n");
Modem_Sound_Mic_release();
call_set_spk(0);
modem_sound_spkctl(ENABLE);
codec_cmd = 0;
codec_pcm_cmd = OFF;
modem_spk_enable = ENABLE;
break;
case IOCTL_MODEM_HP_NOMIC_PHONE:
DBG("modem_sound_ioctl: MODEM_HP_NOMIC_PHONE\n");
Modem_Sound_Mic_switch(MAIN_MIC);
call_set_spk(2);
modem_sound_spkctl(DISABLE);
codec_cmd = 2;
codec_pcm_cmd = HP_NO_MIC;
modem_spk_enable = DISABLE;
break;
default:
printk("unknown ioctl cmd!\n");
ret = -EINVAL;
break;
}
if (set_codec_spk == NULL || set_codec_for_pcm_modem == NULL)
printk("modem_sound_ioctl(), %s %s\n",
set_codec_for_pcm_modem ? "" : "set_codec_for_pcm_modem is NULL",
set_codec_spk ? "" : "set_codec_spk is NULL");
if (ret >= 0) {
// close codec firstly for pop noise
if (codec_cmd == 0 && set_codec_spk)
set_codec_spk(codec_cmd);
if (set_codec_for_pcm_modem)
set_codec_for_pcm_modem(codec_pcm_cmd);
modem_sound_spkctl(modem_spk_enable);
// open codec lastly for pop noise
if (codec_cmd != 0 && set_codec_spk)
set_codec_spk(codec_cmd);
}
up(&pdata->power_sem);
return ret;
@@ -175,7 +204,7 @@ static int modem_sound_probe(struct platform_device *pdev)
struct modem_sound_data *pdata = pdev->dev.platform_data;
if(!pdata)
return -1;
ret = misc_register(&modem_sound_dev);
if (ret < 0){
printk("modem register err!\n");
@@ -188,6 +217,13 @@ static int modem_sound_probe(struct platform_device *pdev)
modem_sound = pdata;
printk("%s:modem sound initialized\n",__FUNCTION__);
#if defined(CONFIG_SND_RK_SOC_RK2928)|| defined(CONFIG_SND_RK29_SOC_RK610)
set_codec_spk = call_set_spk;
#endif
#ifdef CONFIG_SND_SOC_ES8323_PCM
set_codec_for_pcm_modem = set_es8323;
#endif
return ret;
}

View File

@@ -17,7 +17,15 @@
#define IOCTL_SET_HP_WITHMIC_VALUME _IO(MODEM_SOUND, 0x13)
#define IOCTL_SET_BT_VALUME _IO(MODEM_SOUND, 0x14)
#define IOCTL_SET_HP_NOMIC_PHONE _IO(MODEM_SOUND, 0x15)
enum {
OFF,
RCV,
SPK_PATH,
HP_PATH,
HP_NO_MIC,
BT,
};
struct modem_sound_data {
int spkctl_io;

View File

@@ -33,6 +33,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_DA7210 if I2C
select SND_SOC_DFBMCS320
select SND_SOC_ES8323 if SND_SOC_I2C_AND_SPI
select SND_SOC_ES8323_PCM if SND_SOC_I2C_AND_SPI
select SND_SOC_JZ4740_CODEC if SOC_JZ4740
select SND_SOC_LM4857 if I2C
select SND_SOC_MAX98088 if I2C

View File

@@ -19,6 +19,7 @@ snd-soc-da7210-objs := da7210.o
snd-soc-dfbmcs320-objs := dfbmcs320.o
snd-soc-dmic-objs := dmic.o
snd-soc-es8323-objs := es8323.o
snd-soc-es8323-pcm-objs := es8323_pcm.o
snd-soc-l3-objs := l3.o
snd-soc-max98088-objs := max98088.o
snd-soc-max98095-objs := max98095.o
@@ -133,6 +134,7 @@ obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
obj-$(CONFIG_SND_SOC_DFBMCS320) += snd-soc-dfbmcs320.o
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o
obj-$(CONFIG_SND_SOC_ES8323_PCM) += snd-soc-es8323-pcm.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o

363
sound/soc/codecs/es8323_pcm.c Executable file
View File

@@ -0,0 +1,363 @@
/*
* es8323.c -- es8323 ALSA SoC audio driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "es8323.h"
//#define ES8323_PROC
#ifdef ES8323_PROC
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
#endif
#if 1
#define DBG(x...) printk(KERN_INFO x)
#else
#define DBG(x...)
#endif
enum {
OFF,
RCV,
SPK_PATH,
HP_PATH,
HP_NO_MIC,
BT,
};
static struct i2c_client *i2c_client;
int es8323_codec_state = OFF;
static int codec_write(struct i2c_client *client, unsigned int reg,
unsigned int value)
{
u8 data[2];
data[0] = reg;
data[1] = value & 0x00ff;
//printk("%s: reg=0x%x value=0x%x\n",__func__,reg,value);
if (i2c_master_send(client, data, 2) == 2)
return 0;
else
return -EIO;
}
static unsigned int codec_read(struct i2c_client *client,
unsigned int r)
{
struct i2c_msg xfer[2];
u8 reg = r;
u16 data;
int ret;
/* Write register */
xfer[0].addr = client->addr;
xfer[0].flags = 0;
xfer[0].len = 1;
xfer[0].buf = &reg;
xfer[0].scl_rate = 100 * 1000;
/* Read data */
xfer[1].addr = client->addr;
xfer[1].flags = I2C_M_RD;
xfer[1].len = 2;
xfer[1].buf = (u8 *)&data;
xfer[1].scl_rate = 100 * 1000;
ret = i2c_transfer(client->adapter, xfer, 2);
if (ret != 2) {
dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
return 0;
}
//printk("%s: reg=0x%x value=0x%x\n",__func__,reg,(data >> 8) | ((data & 0xff) << 8));
return (data >> 8) | ((data & 0xff) << 8);
}
static int es8323_reg_init(struct i2c_client *client, bool main_mic)
{
if (es8323_codec_state != OFF) {
if (main_mic) {
codec_write(client, 0x0b,0x82); //ADC INPUT=LIN2/RIN2 //82
} else {
codec_write(client, 0x0b,0x02); //ADC INPUT=LIN1/RIN1 //02
}
DBG("es8323_reg_init() change to %s\n",
main_mic ? "main mic" : "headset mic");
return 0;
}
codec_write(client, 0x08, 0x00); //slave 0x00, master 0x80
codec_write(client, 0x02, 0xf3);
codec_write(client, 0x2b, 0x80); //use ADC LRCK, slave 0x80, master 0xc0
codec_write(client, 0x00, 0x36); //DACMCLK is the chip master clock source
codec_write(client, 0x01, 0x00); //all normal
codec_write(client, 0x03, 0x00); //all normal
codec_write(client, 0x04, 0x3c); //L/R DAC power up, L/R out1 enable
codec_write(client, 0x05, 0x00); //normal
codec_write(client, 0x06, 0x00); //normal
codec_write(client, 0x07, 0x7c);
codec_write(client, 0x09, 0x88); //MIC GAIN=24dB
codec_write(client, 0x0a, 0xf0); //L-R diff
if (main_mic) {
codec_write(client, 0x0b,0x82); //ADC INPUT=LIN2/RIN2 //82
} else {
codec_write(client, 0x0b,0x02); //ADC INPUT=LIN1/RIN1 //02
}
codec_write(client, 0x0c, 0x23); //PCM,16bit,2nd
codec_write(client, 0x0d, 0x02);
codec_write(client, 0x0f, 0xf0); //unmute ADC
codec_write(client, 0x10, 0x00);
codec_write(client, 0x11, 0x00);
codec_write(client, 0x12, 0x2a); //ALC off
codec_write(client, 0x13, 0xC0); //ALC
codec_write(client, 0x14, 0x05); //ALC
codec_write(client, 0x15, 0x06); //ALC
codec_write(client, 0x16, 0xb3); //ALC
codec_write(client, 0x17, 0x16); //PCM, 2nd,16bit
codec_write(client, 0x18, 0x02); // MCLK/256
codec_write(client, 0x19, 0x22);
codec_write(client, 0x1a, 0x00); //lout digital
codec_write(client, 0x1b, 0x00); //rout digital
codec_write(client, 0x26, 0x00);
codec_write(client, 0x27, 0xb8); //LD2LO to left mixer
codec_write(client, 0x28, 0x38);
codec_write(client, 0x29, 0x38);
codec_write(client, 0x2a, 0xb8); //RD2RO to right mixer
codec_write(client, 0x30, 0x19);
codec_write(client, 0x31, 0x19);
codec_write(client, 0x02, 0x00);
DBG("es8323_reg_init() set codec route with %s\n",
main_mic ? "main mic" : "headset mic");
return 0;
}
static int es8323_reset(struct i2c_client *client)
{
es8323_codec_state = OFF;
codec_write(client, ES8323_CONTROL1, 0x80);
return codec_write(client, ES8323_CONTROL1, 0x00);
}
int set_es8323(int cmd)
{
DBG("%s : set voice_call_path = %d\n", __func__,
cmd);
if (i2c_client == NULL) {
printk("%s : i2c_client is NULL!\n", __func__);
return -EINVAL;
}
switch (cmd) {
case OFF:
es8323_reset(i2c_client);
break;
case HP_PATH:
es8323_reg_init(i2c_client, 0);
break;
case RCV:
case SPK_PATH:
case HP_NO_MIC:
es8323_reg_init(i2c_client, 1);
break;
case BT:
break;
default:
return -EINVAL;
}
es8323_codec_state = cmd;
return 0;
}
EXPORT_SYMBOL(set_es8323);
static const struct i2c_device_id es8323_i2c_id[] = {
{ "es8323-pcm", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, es8323_i2c_id);
static int es8323_proc_init(void);
static int __devinit es8323_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
DBG("%s\n", __func__);
#ifdef ES8323_PROC
es8323_proc_init();
#endif
i2c_client = i2c;
es8323_reset(i2c);
return 0;
}
static int __devexit es8323_i2c_remove(struct i2c_client *i2c)
{
return 0;
}
struct i2c_driver es8323_i2c_driver = {
.driver = {
.name = "es8323-pcm",
.owner = THIS_MODULE,
},
.probe = es8323_i2c_probe,
.remove = __devexit_p(es8323_i2c_remove),
.id_table = es8323_i2c_id,
};
static int __init es8323_modinit(void)
{
return i2c_add_driver(&es8323_i2c_driver);
}
late_initcall(es8323_modinit);
static void __exit es8323_modexit(void)
{
i2c_del_driver(&es8323_i2c_driver);
}
module_exit(es8323_modexit);
MODULE_DESCRIPTION("ASoC ES8323 driver");
MODULE_AUTHOR("Jear");
MODULE_LICENSE("GPL");
#ifdef ES8323_PROC
static ssize_t es8323_proc_write(struct file *file, const char __user *buffer,
unsigned long len, void *data)
{
char *cookie_pot;
char *p;
int reg;
int value;
cookie_pot = (char *)vmalloc( len );
if (!cookie_pot)
{
return -ENOMEM;
}
else
{
if (copy_from_user( cookie_pot, buffer, len ))
return -EFAULT;
}
switch(cookie_pot[0])
{
case 'r':
case 'R':
printk("Read reg debug\n");
if(cookie_pot[1] ==':')
{
strsep(&cookie_pot,":");
while((p=strsep(&cookie_pot,",")))
{
reg = simple_strtol(p,NULL,16);
value = codec_read(i2c_client,reg);
printk("codec_read:0x%04x = 0x%04x\n",reg,value);
}
printk("\n");
}
else
{
printk("Error Read reg debug.\n");
printk("For example: echo r:22,23,24,25>es8323_ts\n");
}
break;
case 'w':
case 'W':
printk("Write reg debug\n");
if(cookie_pot[1] ==':')
{
strsep(&cookie_pot,":");
while((p=strsep(&cookie_pot,"=")))
{
reg = simple_strtol(p,NULL,16);
p=strsep(&cookie_pot,",");
value = simple_strtol(p,NULL,16);
codec_write(i2c_client,reg,value);
printk("codec_write:0x%04x = 0x%04x\n",reg,value);
}
printk("\n");
}
else
{
printk("Error Write reg debug.\n");
printk("For example: w:22=0,23=0,24=0,25=0>es8323_ts\n");
}
break;
case 'a':
printk("Dump reg \n");
for(reg = 0; reg < 0x6e; reg+=2)
{
value = codec_read(i2c_client,reg);
printk("codec_read:0x%04x = 0x%04x\n",reg,value);
}
break;
default:
printk("Help for es8323_ts .\n-->The Cmd list: \n");
printk("-->'d&&D' Open or Off the debug\n");
printk("-->'r&&R' Read reg debug,Example: echo 'r:22,23,24,25'>es8323_ts\n");
printk("-->'w&&W' Write reg debug,Example: echo 'w:22=0,23=0,24=0,25=0'>es8323_ts\n");
break;
}
return len;
}
static const struct file_operations es8323_proc_fops = {
.owner = THIS_MODULE,
};
static int es8323_proc_init(void)
{
struct proc_dir_entry *es8323_proc_entry;
es8323_proc_entry = create_proc_entry("driver/es8323_pcm_ts", 0777, NULL);
if(es8323_proc_entry != NULL)
{
es8323_proc_entry->write_proc = es8323_proc_write;
return 0;
}
else
{
printk("create proc error !\n");
return -1;
}
}
#endif

View File

@@ -95,6 +95,13 @@ config SND_RK29_SOC_ES8323
Say Y if you want to add support for SoC audio on rockchip
with the ES8323.
config SND_SOC_ES8323_PCM
tristate "SoC I2S Audio support for rockchip - ES8323 for PCM modem"
depends on SND_RK29_SOC
help
Say Y if you want to add support for SoC audio on rockchip
with the ES8323 for PCM modem.
config SND_RK29_SOC_WM8988
tristate "SoC I2S Audio support for rockchip - WM8988"
depends on SND_RK29_SOC