S5P4418: ESP8323音频驱动移植

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 背景

因项目需求,要将 esp8323 音频驱动移植到 S5P4418 开发板,内核版本为 linux-3.4.y。

3. 驱动移植

3.1 驱动代码目录、编译配置

驱动源原件列表如下
在这里插入图片描述
(1) 将codec的驱动代码es8323.hes8323.c放到linux内核源码目录:

sound/soc/codecs/es8323.h
sound/soc/codecs/es8323.c

(2) 修改文件 sound/soc/codecs/Makefile,在其中增加如下内容:

obj-$(CONFIG_SND_SOC_ES8323) += snd-soc-es8323.o

(3) 修改文件 sound/soc/codecs/Kconfig,在其中增加如下内容:

config SND_SOC_ALL_CODECS
	tristate “Build all AsoC CODEC drivers”
	...
	select SND_SOC_ES8323 if I2C

config SND_SOC_ES8323
	tristate

(4) 运行如下命令:

cp sound/soc/nexell/nxp-es8316.c sound/soc/nexell/nxp-es8323.c

(5) 修改sound/soc/nexell/Makefile,增加如下内容:

obj-$(CONFIG_SND_CODEC_ES8323)  += nxp-snd-es8323.o
nxp-snd-es8323-objs := nxp-es8323.o

目的是将文件nxp-es8323.c加入编译。
(6) 修改文件sound/soc/nexell/Kconfig,增加配置项SND_CODEC_ES8323

config SND_CODEC_ES8323
	tristate “es8323 I2S audio codec.”
	depends on SND_NXP_I2S
	select SND_SOC_ES8323

到此,ES8323音频解码器的驱动代码目录,代码编译,配置选项已经搭建完成。

3.2 修改代码适配到目标平台

(1) 修改文件 sound/soc/codecs/es8323.c

/*#include 
#include 
#include */

/* 增加头文件包含行 */
#include 

/* 增加如下内容 */
#define SPK_CON 		(PAD_GPIO_B + 24)
#define HP_DET		(PAD_GPIO_B + 27)
#define GPIO_LOW  0
#define GPIO_HIGH 1

#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...) do {} while (0)
#endif

int es8323_jack_insert = 0;

extern int es8323_spk_on(int enable);

void es8323_mono_en(int enable)
{
	struct snd_soc_codec *codec;

	codec = es8323_codec;
	if (enable) {
		snd_soc_write(codec, ES8323_DACPOWER, 0x05);
		snd_soc_write(codec, ES8323_DACCONTROL7, 0x20);
	} else {
		snd_soc_write(codec, ES8323_DACCONTROL7, 0x07);
		snd_soc_write(codec, ES8323_DACPOWER, 0x00);
	}
}
EXPORT_SYMBOL(es8323_mono_en);

/* 将函数es8323_off_amp的内容注释掉,只保留函数体 */
static void es8323_off_amp(bool on)
{	
#if 0
	int oldlevel = gpio_get_value(SPK_CON);
	int newlevel = (on) ? GPIO_LOW : GPIO_HIGH;

	printk("%s: entering...", __func__);

	if (oldlevel != newlevel) {
		gpio_set_value(SPK_CON, newlevel);
	printk("%s: Amplifier turn %s\n", __func__, on ? "on" : "off");
	dev_dbg(es8323_codec->dev, "Amplifier turn %s\n", on ? "off" : "on");
	}
#endif
}

/* 
 * 将函数 
 * es8323_digital_mute()
 * es8323_i2c_suspend()
 * es8323_i2c_resume()
 * 注释掉。
 * 并将相应结构体es8323_ops ,es8323_i2c_driver 中相应结构中的赋
 * 值去掉。
 */

/* 修改以下函数内容: */
static int es8323_set_bias_level(struct snd_soc_codec *codec,
				 				enum snd_soc_bias_level level)
{
	switch (level) {case SND_SOC_BIAS_PREPARE:if (es8323_jack_insert) {
			snd_soc_write(codec, ES8323_DACCONTROL7, 0x07);
		} else {
			snd_soc_write(codec, ES8323_DACCONTROL7, 0x20);
		}if (es8323_jack_insert) {
			snd_soc_write(codec, ES8323_DACPOWER, 0x00);
		} else {
			snd_soc_write(codec, ES8323_DACPOWER, 0x05);
			es8323_spk_on(1);
		}	
		DBG("%s: jack_insert %d\n", __func__, es8323_jack_insert);
		break;

	case SND_SOC_BIAS_STANDBY:if (es8323_jack_insert) {
			snd_soc_write(codec, ES8323_DACCONTROL7, 0x07);
		} else {
			snd_soc_write(codec, ES8323_DACCONTROL7, 0x20);
		}if (es8323_jack_insert) {
			snd_soc_write(codec, ES8323_DACPOWER, 0x00);
		} else {
			snd_soc_write(codec, ES8323_DACPOWER, 0x05);
			es8323_spk_on(0);
		}	
		break;}

/* 修改函数 */
static void det_initalize(void)
{
	if (gpio_request(HP_DET, "hp_det")) {
		pr_err("%s %d request error", __func__, __LINE__);
		return;
	}
	
	det_initalized = false;
	schedule_delayed_work(&det_work, msecs_to_jiffies(100));
	return;
}

/* 修改函数 */
static int es8323_probe(struct snd_soc_codec *codec)
{
	…
	ret = gpio_request(SPK_CON, "spk_con");
	if (ret != 0) {
		pr_err("%s %d request error", __func__, __LINE__);
		goto err;
	}
	gpio_set_value(SPK_CON, GPIO_LOW);
	//es8323_off_amp(true);
	msleep(30);es8323_init_regs(codec);
	es8323_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
	codec->dapm.idle_bias_off = 0;
	ret = snd_soc_add_codec_controls(codec, es8323_snd_controls, 
					ARRAY_SIZE(es8323_snd_controls));
	/*ret = snd_soc_add_controls(codec, es8323_snd_controls,
			     ARRAY_SIZE(es8323_snd_controls));*/}

至此,文件的es8323.c的修改完成主要是适应耳机、喇叭的切换,以及去掉不适应的平台的多余代码。
(2) 修改文件sound/soc/nexell/nxp-es8323.c,将文件中变量名、函数名,字串中包含的es8316字串全部替换为es8323;字串ES8316全部替换为ES8323。关于ES8323 I2C从设的设备地址修改,很关键,如果不正确,系统将无法使ES8323正常工作。

static struct snd_soc_dai_link es8323_dai_link = {
	.name 			= "ASOC-ES8323",
	.stream_name 	= "es8323 HiFi",
	.cpu_dai_name 	= str_dai_name, /* nxp_snd_i2s_driver name */
	.platform_name  = DEV_NAME_PCM,	/* nxp_snd_pcm_driver name */
	.codec_dai_name = "ES8323 HiFi",	/* es8323_dai's name */
	.codec_name 	= "ES8323.0-0010",/* es8323_i2c_driver name + '.' + bus + '-' + address(7bit) */
	.ops 		= &es8323_ops,
	.symmetric_rates = 1,
	.init		= es8323_dai_init,
};

(3) 修改文件arch/arm/plat-s5p4418/nanopi2/include/cfg_gpio.h。 ES8323用到了I2C0和I2S0,以及耳机检测,喇叭声音控制等PIN脚,所以要缺确保这些GPIO的正确配置。具体配置如下:

/* I2C 0配置 */
#define PAD_GPIOD2  (PAD_MODE_ALT | PAD_FUNC_ALT1 | 
PAD_LEVEL_LOW  | PAD_PULL_OFF | 
PAD_STRENGTH_1)     
#define PAD_GPIOD3   (PAD_MODE_ALT | PAD_FUNC_ALT1 | 
PAD_LEVEL_LOW  | PAD_PULL_OFF | 
PAD_STRENGTH_1)

/* I2S 0配置 */
#define PAD_GPIOD9      (PAD_MODE_ALT | PAD_FUNC_ALT1 | PAD_LEVEL_LOW  | PAD_PULL_OFF | 
PAD_STRENGTH_0)
#define PAD_GPIOD10     (PAD_MODE_ALT | PAD_FUNC_ALT1 | 
			      PAD_LEVEL_LOW  | PAD_PULL_OFF | 
			      PAD_STRENGTH_0)

/* 耳机插入检测GPIOB27,耳机声音输出使能GPIOC0,喇叭声音输出使能
GPIOB24的配置 */
#define PAD_GPIOB27     (PAD_MODE_IN  | PAD_FUNC_ALT1 | 
			      PAD_LEVEL_LOW  | PAD_PULL_OFF | PAD_LEVEL_LOW  | PAD_PULL_OFF | 
PAD_STRENGTH_0)
#define PAD_GPIOD10     (PAD_MODE_ALT | PAD_FUNC_ALT1 | 
			      PAD_LEVEL_LOW  | PAD_PULL_OFF | 
			      PAD_STRENGTH_0)

/* 耳机插入检测GPIOB27,耳机声音输出使能GPIOC0,喇叭声音输出使能
GPIOB24的配置 */
#define PAD_GPIOB27     (PAD_MODE_IN  | PAD_FUNC_ALT1 | 
			      PAD_LEVEL_LOW  | PAD_PULL_OFF | 

(4) 修改文件arch/arm/plat-s5p4418/nanopi2/device.c

/* 首先增加如下内容 */
#if defined(CONFIG_SND_CODEC_ES8323) || defined(CONFIG_SND_CODEC_ES8323_MODULE)
#define	ES8323_I2C_BUS		(0)

/* CODEC */
static struct i2c_board_info __initdata es8323_i2c_bdi = {
	.type	= "es8323",
	.addr	= (0x20>>1),		// 0x11 (7BIT), 0x22(8BIT)
};

/* DAI */
struct nxp_snd_dai_plat_data i2s_dai_data = {
	.i2s_ch	= 0,
	.sample_rate	= 48000,
.pcm_format = SNDRV_PCM_FMTBIT_S16_LE,
#if 1
	.hp_jack 		= {
		.support    	= 0,
		.detect_io		= PAD_GPIO_B + 27,
		.detect_level	= 1,
	},
#endif
};

static struct platform_device es8323_dai = {
	.name			= "es8323-audio",
	.id				= 0,
	.dev			= {
		.platform_data	= &i2s_dai_data,
	}
};
#endif

...

/* 同时在修改函数nxp_board_devices_register(),增加红色部分内容: */
void __init nxp_board_devices_register(void)
{#if defined(CONFIG_SND_CODEC_ES8316) || defined(CONFIG_SND_CODEC_ES8316_MODULE)
	if (board_with_es8316()) {
		printk("plat: add device asoc-es8316\n");
		if (board_is_nanopc() || \
			board_is_smart4418() || board_is_smart4418sdk())
i2s_dai_data.hp_jack.support = 1;
		i2c_register_board_info(ES8316_I2C_BUS, &es8316_i2c_bdi, 1);
		platform_device_register(&es8316_dai);
	}
#endif

#if defined(CONFIG_SND_CODEC_ES8323) || defined(CONFIG_SND_CODEC_ES8323_MODULE)
	//if (board_with_es8323()) {
		printk("plat: add device asoc-es8323\n");
		if (board_is_nanopc() || \
			board_is_smart4418() || board_is_smart4418sdk())
			i2s_dai_data.hp_jack.support = 1;
		i2c_register_board_info(ES8323_I2C_BUS, &es8323_i2c_bdi, 1);
		platform_device_register(&es8323_dai);
	//}
#endif}

以此将I2C的board info以及将平台的DAI设备注册到系统。
(5) 修改文件arch/arm/configs/nanopi2_linux_defconfig。修改该文件的目的是将ES8323音频解码选为nanopi2的默认配置,这一步并不是必须的。在文件中增加两行:

CONFIG_SND_CODEC_ES8323=y
CONFIG_SND_SOC_ES8323=y

至此,所有源代码,配置文件都已经修改完成,接下来就是编译测试。

3.3 编译、烧录、测试

3.3.1 编译

make menuconfig # 打开 ESP8323 相关配置
make uImage
. mkbootimage

3.3.2 烧录kernel.img到开发板

fastboot flash boot kernel.img

3.3.3 测试

系统启动后,可使用系统自带的aplay测试.wav文件,如:

aplay test.wav

用 mplayer 测试更多格式,如.wav和.mp3。

mplayer test.wav
mplayer test.mp3

测试时,正常情况下可以使用耳机和喇叭听到声音,当有耳机插入时,喇叭将不会发出声音,只有耳机有声音。

4. 修改文件索引列表

sound/soc/codecs/es8323.h
sound/soc/codecs/es8323.c
sound/soc/codecs/Makefile
sound/soc/codecs/Kconfig
sound/soc/nexell/nxp-es8323.c
sound/soc/nexell/Makefile
sound/soc/nexell/Kconfig
arch/arm/plat-s5p4418/nanopi2/include/cfg_gpio.h
arch/arm/plat-s5p4418/nanopi2/device.c
arch/arm/configs/nanopi2_linux_defconfig

5. 后记

本文基于多年前的开发笔记,或有错漏之处,请读者仔细分辨。

你可能感兴趣的:(#,声音,&,图像,音视频,linux)