⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 linux-at91rm9200-i2s.c

📁 基于at91rm9200-arm920t下的录放音程序
💻 C
📖 第 1 页 / 共 5 页
字号:
+	snd_soc_dapm_set_endpoint(codec, "Ext Spk", 1);
+
+	snd_soc_dapm_sync_endpoints(codec);
+
+	return 0;
+}
+
+unsigned int eti_b1_config_sysclk(struct snd_soc_pcm_runtime *rtd,
+	struct snd_soc_clock_info *info)
+{
+	if(info->bclk_master & SND_SOC_DAIFMT_CBS_CFS) {
+		return rtd->codec_dai->config_sysclk(rtd->codec_dai, info, 12000000);
+	}
+	return 0;
+}
+
+static struct snd_soc_dai_link eti_b1_dai = {
+	.name = "WM8731",
+	.stream_name = "WM8731",
+	.cpu_dai = &at91_i2s_dai[1],
+	.codec_dai = &wm8731_dai,
+	.init = eti_b1_wm8731_init,
+	.config_sysclk = eti_b1_config_sysclk,
+};
+
+static struct snd_soc_machine snd_soc_machine_eti_b1 = {
+	.name = "ETI_B1",
+	.dai_link = &eti_b1_dai,
+	.num_links = 1,
+	.ops = &eti_b1_ops,
+};
+
+static struct wm8731_setup_data eti_b1_wm8731_setup = {
+	.i2c_address = 0x1a,
+};
+
+static struct snd_soc_device eti_b1_snd_devdata = {
+	.machine = &snd_soc_machine_eti_b1,
+	.platform = &at91_soc_platform,
+	.codec_dev = &soc_codec_dev_wm8731,
+	.codec_data = &eti_b1_wm8731_setup,
+};
+
+static struct platform_device *eti_b1_snd_device;
+
+static int __init eti_b1_init(void)
+{
+	int ret;
+	u32 ssc_pio_lines;
+	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
+
+	if (!request_mem_region(AT91RM9200_BASE_SSC1, SZ_16K, "soc-audio")) {
+		DBG("SSC1 memory region is busy\n");
+		return -EBUSY;
+	}
+
+	ssc->base = ioremap(AT91RM9200_BASE_SSC1, SZ_16K);
+	if (!ssc->base) {
+		DBG("SSC1 memory ioremap failed\n");
+		ret = -ENOMEM;
+		goto fail_release_mem;
+	}
+
+	ssc->pid = AT91RM9200_ID_SSC1;
+
+	eti_b1_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!eti_b1_snd_device) {
+		DBG("platform device allocation failed\n");
+		ret = -ENOMEM;
+		goto fail_io_unmap;
+	}
+
+	platform_set_drvdata(eti_b1_snd_device, &eti_b1_snd_devdata);
+	eti_b1_snd_devdata.dev = &eti_b1_snd_device->dev;
+
+	ret = platform_device_add(eti_b1_snd_device);
+	if (ret) {
+		DBG("platform device add failed\n");
+		platform_device_put(eti_b1_snd_device);
+		goto fail_io_unmap;
+	}
+
+ 	ssc_pio_lines = AT91_PIO_TF1 | AT91_PIO_TK1 | AT91_PIO_TD1
+			| AT91_PIO_RD1 /* | AT91_PIO_RK1 | AT91_PIO_RF1 */;
+
+	/* Reset all PIO registers and assign lines to peripheral A */
+ 	at91_sys_write(AT91_PIOB + PIO_PDR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_ODR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_IFDR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_CODR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_IDR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_MDDR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_PUDR, ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_ASR,  ssc_pio_lines);
+ 	at91_sys_write(AT91_PIOB + PIO_OWDR, ssc_pio_lines);
+
+	/*
+	 * Set PCK1 parent to PLLB and its rate to 12 Mhz.
+	 */
+	pllb_clk = clk_get(NULL, "pllb");
+	pck1_clk = clk_get(NULL, "pck1");
+
+	clk_set_parent(pck1_clk, pllb_clk);
+	clk_set_rate(pck1_clk, 12000000);
+
+	DBG("MCLK rate %luHz\n", clk_get_rate(pck1_clk));
+
+	/* assign the GPIO pin to PCK1 */
+	at91_set_B_periph(AT91_PIN_PA24, 0);
+
+	return ret;
+
+fail_io_unmap:
+	iounmap(ssc->base);
+fail_release_mem:
+	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
+	return ret;
+}
+
+static void __exit eti_b1_exit(void)
+{
+	struct at91_ssc_periph *ssc = eti_b1_dai.cpu_dai->private_data;
+
+	clk_put(pck1_clk);
+	clk_put(pllb_clk);
+
+	platform_device_unregister(eti_b1_snd_device);
+
+	iounmap(ssc->base);
+	release_mem_region(AT91RM9200_BASE_SSC1, SZ_16K);
+}
+
+module_init(eti_b1_init);
+module_exit(eti_b1_exit);
+#endif
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
new file mode 100644
index 0000000..8151b45
--- /dev/null
+++ b/sound/soc/codecs/wm8731.c
@@ -0,0 +1,886 @@
+/*
+ * wm8731.c  --  WM8731 ALSA SoC Audio driver
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <richard@openedhand.com>
+ *
+ * Based on wm8753.c by Liam Girdwood
+ *
+ * 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 <sound/driver.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 "wm8731.h"
+
+#define AUDIO_NAME "wm8731"
+#define WM8731_VERSION "0.12"
+
+/*
+ * Debug
+ */
+
+#define WM8731_DEBUG 0
+
+#ifdef WM8731_DEBUG
+#define dbg(format, arg...) \
+	printk(KERN_DEBUG AUDIO_NAME ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+#define err(format, arg...) \
+	printk(KERN_ERR AUDIO_NAME ": " format "\n" , ## arg)
+#define info(format, arg...) \
+	printk(KERN_INFO AUDIO_NAME ": " format "\n" , ## arg)
+#define warn(format, arg...) \
+	printk(KERN_WARNING AUDIO_NAME ": " format "\n" , ## arg)
+
+struct snd_soc_codec_device soc_codec_dev_wm8731;
+
+/*
+ * wm8731 register cache
+ * We can't read the WM8731 register space when we are
+ * using 2 wire for device control, so we cache them instead.
+ * There is no point in caching the reset register
+ */
+static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
+    0x0097, 0x0097, 0x0079, 0x0079,
+    0x000a, 0x0008, 0x009f, 0x000a,
+    0x0000, 0x0000
+};
+
+#define WM8731_DAIFMT \
+	(SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_RIGHT_J | \
+	SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_IB_NF | \
+	SND_SOC_DAIFMT_IB_IF)
+
+#define WM8731_DIR \
+	(SND_SOC_DAIDIR_PLAYBACK | SND_SOC_DAIDIR_CAPTURE)
+
+#define WM8731_RATES \
+	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
+	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
+
+#define WM8731_HIFI_BITS \
+	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
+	SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_mode wm8731_modes[] = {
+	/* codec frame and clock master modes */
+	/* 8k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 1536,
+		.bfs = 64,
+	},
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 2304,
+		.bfs = 64,
+	},
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 1408,
+		.bfs = 64,
+	},
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 2112,
+		.bfs = 64,
+	},
+
+	/* 32k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_32000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 384,
+		.bfs = 64,
+	},
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_32000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 576,
+		.bfs = 64,
+	},
+
+	/* 44.1k & 48k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 256,
+		.bfs = 64,
+	},
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 384,
+		.bfs = 64,
+	},
+
+	/* 88.2 & 96k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 128,
+		.bfs = 64,
+	},
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_RATE,
+		.fs = 192,
+		.bfs = 64,
+	},
+
+	/* USB codec frame and clock master modes */
+	/* 8k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_8000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 1500,
+		.bfs = SND_SOC_FSBD(1),
+	},
+
+	/* 44.1k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_44100,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 272,
+		.bfs = SND_SOC_FSBD(1),
+	},
+
+	/* 48k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_48000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 250,
+		.bfs = SND_SOC_FSBD(1),
+	},
+
+	/* 88.2k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_88200,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 136,
+		.bfs = SND_SOC_FSBD(1),
+	},
+
+	/* 96k */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBM_CFM,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = SNDRV_PCM_RATE_96000,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = 125,
+		.bfs = SND_SOC_FSBD(1),
+	},
+
+	/* codec frame and clock slave modes */
+	{
+		.fmt = WM8731_DAIFMT | SND_SOC_DAIFMT_CBS_CFS,
+		.pcmfmt = WM8731_HIFI_BITS,
+		.pcmrate = WM8731_RATES,
+		.pcmdir = WM8731_DIR,
+		.flags = SND_SOC_DAI_BFS_DIV,
+		.fs = SND_SOC_FS_ALL,
+		.bfs = SND_SOC_FSB_ALL,
+	},
+};
+
+/*
+ * read wm8731 register cache
+ */
+static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec,
+	unsigned int reg)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg == WM8731_RESET)
+		return 0;
+	if (reg >= WM8731_CACHEREGNUM)
+		return -1;
+	return cache[reg];
+}
+
+/*
+ * write wm8731 register cache
+ */
+static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec,
+	u16 reg, unsigned int value)
+{
+	u16 *cache = codec->reg_cache;
+	if (reg >= WM8731_CACHEREGNUM)
+		return;
+	cache[reg] = value;
+}
+
+/*
+ * write to the WM8731 register space
+ */
+static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg,
+	unsigned int value)
+{
+	u8 data[2];
+
+	/* data is
+	 *   D15..D9 WM8731 register offset
+	 *   D8...D0 register data
+	 */
+	data[0] = (reg << 1) | ((value >> 8) & 0x0001);
+	data[1] = value & 0x00ff;
+
+	wm8731_write_reg_cache (codec, reg, value);
+	if (codec->hw_write(codec->control_data, data, 2) == 2)
+		return 0;
+	else
+		return -EIO;
+}
+
+#define wm8731_reset(c)	wm8731_write(c, WM8731_RESET, 0)
+
+static const char *wm8731_input_select[] = {"Line In", "Mic"};
+static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
+
+static const struct soc_enum wm8731_enum[] = {
+	SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
+	SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
+};
+
+static const struct snd_kcontrol_new wm8731_snd_controls[] = {
+
+SOC_DOUBLE_R("Master Playback Volume", WM8731_LOUT1V, WM8731_ROUT1V,
+	0, 127, 0),
+SOC_DOUBLE_R("Master Playback ZC Switch", WM8731_LOUT1V, WM8731_ROUT1V,
+	7, 1, 0),
+
+SOC_DOUBLE_R("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0),
+SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
+
+SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
+SOC_SINGLE("Capture Mic Switch", WM8731_APANA, 1, 1, 1),
+
+SOC_SINGLE("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1),
+
+SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
+SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
+
+SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
+};
+
+/* add non dapm controls */
+static int wm8731_add_controls(struct snd_soc_codec *codec)
+{
+	int err, i;
+
+	for (i = 0; i < ARRAY_SIZE(wm8731_snd_controls); i++) {
+		if ((err = snd_ctl_add(codec->card,
+				snd_soc_cnew(&wm8731_snd_controls[i],codec, NULL))) < 0)
+			return err;
+	}
+
+	return 0;
+}
+

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -