summaryrefslogtreecommitdiffstats
path: root/sound/soc/pxa
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/pxa')
-rw-r--r--sound/soc/pxa/Kconfig9
-rw-r--r--sound/soc/pxa/Makefile2
-rw-r--r--sound/soc/pxa/pxa-ssp.c135
-rw-r--r--sound/soc/pxa/spitz.c43
-rw-r--r--sound/soc/pxa/z2.c246
5 files changed, 360 insertions, 75 deletions
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 376e14a9c27..e30c8325f35 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -23,6 +23,7 @@ config SND_PXA2XX_SOC_I2S
config SND_PXA_SOC_SSP
tristate
+ select PXA_SSP
config SND_PXA2XX_SOC_CORGI
tristate "SoC Audio support for Sharp Zaurus SL-C7x0"
@@ -42,6 +43,14 @@ config SND_PXA2XX_SOC_SPITZ
Say Y if you want to add support for SoC audio on Sharp
Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita).
+config SND_PXA2XX_SOC_Z2
+ tristate "SoC Audio support for Zipit Z2"
+ depends on SND_PXA2XX_SOC && MACH_ZIPIT2
+ select SND_PXA2XX_SOC_I2S
+ select SND_SOC_WM8750
+ help
+ Say Y if you want to add support for SoC audio on Zipit Z2.
+
config SND_PXA2XX_SOC_POODLE
tristate "SoC Audio support for Poodle"
depends on SND_PXA2XX_SOC && MACH_POODLE
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index f3e08fd40ca..caa03d8f478 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -22,6 +22,7 @@ snd-soc-palm27x-objs := palm27x.o
snd-soc-zylonite-objs := zylonite.o
snd-soc-magician-objs := magician.o
snd-soc-mioa701-objs := mioa701_wm9713.o
+snd-soc-z2-objs := z2.o
snd-soc-imote2-objs := imote2.o
snd-soc-raumfeld-objs := raumfeld.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
+obj-$(CONFIG_SND_PXA2XX_SOC_Z2) += snd-soc-z2.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index 544fd9566f4..a1fd23e0e3d 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -32,9 +32,8 @@
#include <mach/hardware.h>
#include <mach/dma.h>
-#include <mach/regs-ssp.h>
#include <mach/audio.h>
-#include <mach/ssp.h>
+#include <plat/ssp.h>
#include "pxa2xx-pcm.h"
#include "pxa-ssp.h"
@@ -57,15 +56,15 @@ struct ssp_priv {
static void dump_registers(struct ssp_device *ssp)
{
dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
- ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1),
- ssp_read_reg(ssp, SSTO));
+ pxa_ssp_read_reg(ssp, SSCR0), pxa_ssp_read_reg(ssp, SSCR1),
+ pxa_ssp_read_reg(ssp, SSTO));
dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n",
- ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR),
- ssp_read_reg(ssp, SSACD));
+ pxa_ssp_read_reg(ssp, SSPSP), pxa_ssp_read_reg(ssp, SSSR),
+ pxa_ssp_read_reg(ssp, SSACD));
}
-static void ssp_enable(struct ssp_device *ssp)
+static void pxa_ssp_enable(struct ssp_device *ssp)
{
uint32_t sscr0;
@@ -73,7 +72,7 @@ static void ssp_enable(struct ssp_device *ssp)
__raw_writel(sscr0, ssp->mmio_base + SSCR0);
}
-static void ssp_disable(struct ssp_device *ssp)
+static void pxa_ssp_disable(struct ssp_device *ssp)
{
uint32_t sscr0;
@@ -87,7 +86,7 @@ struct pxa2xx_pcm_dma_data {
};
static struct pxa2xx_pcm_dma_params *
-ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+pxa_ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
{
struct pxa2xx_pcm_dma_data *dma;
@@ -119,7 +118,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
if (!cpu_dai->active) {
clk_enable(ssp->clk);
- ssp_disable(ssp);
+ pxa_ssp_disable(ssp);
}
kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
@@ -137,7 +136,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
struct ssp_device *ssp = priv->ssp;
if (!cpu_dai->active) {
- ssp_disable(ssp);
+ pxa_ssp_disable(ssp);
clk_disable(ssp->clk);
}
@@ -160,7 +159,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
priv->to = __raw_readl(ssp->mmio_base + SSTO);
priv->psp = __raw_readl(ssp->mmio_base + SSPSP);
- ssp_disable(ssp);
+ pxa_ssp_disable(ssp);
clk_disable(ssp->clk);
return 0;
}
@@ -180,7 +179,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
__raw_writel(priv->psp, ssp->mmio_base + SSPSP);
if (cpu_dai->active)
- ssp_enable(ssp);
+ pxa_ssp_enable(ssp);
else
clk_disable(ssp->clk);
@@ -196,9 +195,9 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
* ssp_set_clkdiv - set SSP clock divider
* @div: serial clock rate divider
*/
-static void ssp_set_scr(struct ssp_device *ssp, u32 div)
+static void pxa_ssp_set_scr(struct ssp_device *ssp, u32 div)
{
- u32 sscr0 = ssp_read_reg(ssp, SSCR0);
+ u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
if (cpu_is_pxa25x() && ssp->type == PXA25x_SSP) {
sscr0 &= ~0x0000ff00;
@@ -207,15 +206,15 @@ static void ssp_set_scr(struct ssp_device *ssp, u32 div)
sscr0 &= ~0x000fff00;
sscr0 |= (div - 1) << 8; /* 1..4096 */
}
- ssp_write_reg(ssp, SSCR0, sscr0);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0);
}
/**
- * ssp_get_clkdiv - get SSP clock divider
+ * pxa_ssp_get_clkdiv - get SSP clock divider
*/
-static u32 ssp_get_scr(struct ssp_device *ssp)
+static u32 pxa_ssp_get_scr(struct ssp_device *ssp)
{
- u32 sscr0 = ssp_read_reg(ssp, SSCR0);
+ u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
u32 div;
if (cpu_is_pxa25x() && ssp->type == PXA25x_SSP)
@@ -235,7 +234,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
struct ssp_device *ssp = priv->ssp;
int val;
- u32 sscr0 = ssp_read_reg(ssp, SSCR0) &
+ u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
dev_dbg(&ssp->pdev->dev,
@@ -263,7 +262,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
break;
case PXA_SSP_CLK_AUDIO:
priv->sysclk = 0;
- ssp_set_scr(ssp, 1);
+ pxa_ssp_set_scr(ssp, 1);
sscr0 |= SSCR0_ACS;
break;
default:
@@ -274,8 +273,8 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
* on PXA2xx. On PXA3xx it must be enabled when doing so. */
if (!cpu_is_pxa3xx())
clk_disable(ssp->clk);
- val = ssp_read_reg(ssp, SSCR0) | sscr0;
- ssp_write_reg(ssp, SSCR0, val);
+ val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0;
+ pxa_ssp_write_reg(ssp, SSCR0, val);
if (!cpu_is_pxa3xx())
clk_enable(ssp->clk);
@@ -294,11 +293,11 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
switch (div_id) {
case PXA_SSP_AUDIO_DIV_ACDS:
- val = (ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div);
- ssp_write_reg(ssp, SSACD, val);
+ val = (pxa_ssp_read_reg(ssp, SSACD) & ~0x7) | SSACD_ACDS(div);
+ pxa_ssp_write_reg(ssp, SSACD, val);
break;
case PXA_SSP_AUDIO_DIV_SCDB:
- val = ssp_read_reg(ssp, SSACD);
+ val = pxa_ssp_read_reg(ssp, SSACD);
val &= ~SSACD_SCDB;
#if defined(CONFIG_PXA3xx)
if (cpu_is_pxa3xx())
@@ -321,10 +320,10 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
default:
return -EINVAL;
}
- ssp_write_reg(ssp, SSACD, val);
+ pxa_ssp_write_reg(ssp, SSACD, val);
break;
case PXA_SSP_DIV_SCR:
- ssp_set_scr(ssp, div);
+ pxa_ssp_set_scr(ssp, div);
break;
default:
return -ENODEV;
@@ -341,11 +340,11 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
{
struct ssp_priv *priv = cpu_dai->private_data;
struct ssp_device *ssp = priv->ssp;
- u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70;
+ u32 ssacd = pxa_ssp_read_reg(ssp, SSACD) & ~0x70;
#if defined(CONFIG_PXA3xx)
if (cpu_is_pxa3xx())
- ssp_write_reg(ssp, SSACDD, 0);
+ pxa_ssp_write_reg(ssp, SSACDD, 0);
#endif
switch (freq_out) {
@@ -383,7 +382,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
val = tmp;
val = (val << 16) | 64;
- ssp_write_reg(ssp, SSACDD, val);
+ pxa_ssp_write_reg(ssp, SSACDD, val);
ssacd |= (0x6 << 4);
@@ -397,7 +396,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id,
return -EINVAL;
}
- ssp_write_reg(ssp, SSACD, ssacd);
+ pxa_ssp_write_reg(ssp, SSACD, ssacd);
return 0;
}
@@ -412,7 +411,7 @@ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
struct ssp_device *ssp = priv->ssp;
u32 sscr0;
- sscr0 = ssp_read_reg(ssp, SSCR0);
+ sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(8) | SSCR0_EDSS | SSCR0_DSS);
/* set slot width */
@@ -429,10 +428,10 @@ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai,
sscr0 |= SSCR0_SlotsPerFrm(slots);
/* set active slot mask */
- ssp_write_reg(ssp, SSTSA, tx_mask);
- ssp_write_reg(ssp, SSRSA, rx_mask);
+ pxa_ssp_write_reg(ssp, SSTSA, tx_mask);
+ pxa_ssp_write_reg(ssp, SSRSA, rx_mask);
}
- ssp_write_reg(ssp, SSCR0, sscr0);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0);
return 0;
}
@@ -447,12 +446,12 @@ static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
struct ssp_device *ssp = priv->ssp;
u32 sscr1;
- sscr1 = ssp_read_reg(ssp, SSCR1);
+ sscr1 = pxa_ssp_read_reg(ssp, SSCR1);
if (tristate)
sscr1 &= ~SSCR1_TTE;
else
sscr1 |= SSCR1_TTE;
- ssp_write_reg(ssp, SSCR1, sscr1);
+ pxa_ssp_write_reg(ssp, SSCR1, sscr1);
return 0;
}
@@ -476,14 +475,14 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return 0;
/* we can only change the settings if the port is not in use */
- if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
+ if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE) {
dev_err(&ssp->pdev->dev,
"can't change hardware dai format: stream is in use");
return -EINVAL;
}
/* reset port settings */
- sscr0 = ssp_read_reg(ssp, SSCR0) &
+ sscr0 = pxa_ssp_read_reg(ssp, SSCR0) &
(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
sscr1 = SSCR1_RxTresh(8) | SSCR1_TxTresh(7);
sspsp = 0;
@@ -535,9 +534,9 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
return -EINVAL;
}
- ssp_write_reg(ssp, SSCR0, sscr0);
- ssp_write_reg(ssp, SSCR1, sscr1);
- ssp_write_reg(ssp, SSPSP, sspsp);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0);
+ pxa_ssp_write_reg(ssp, SSCR1, sscr1);
+ pxa_ssp_write_reg(ssp, SSPSP, sspsp);
dump_registers(ssp);
@@ -566,7 +565,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
u32 sscr0;
u32 sspsp;
int width = snd_pcm_format_physical_width(params_format(params));
- int ttsa = ssp_read_reg(ssp, SSTSA) & 0xf;
+ int ttsa = pxa_ssp_read_reg(ssp, SSTSA) & 0xf;
struct pxa2xx_pcm_dma_params *dma_data;
dma_data = snd_soc_dai_get_dma_data(dai, substream);
@@ -578,22 +577,22 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
* to force 16-bit frame width on the wire (for S16_LE), even
* with two channels. Use 16-bit DMA transfers for this case.
*/
- dma_data = ssp_get_dma_params(ssp,
+ dma_data = pxa_ssp_get_dma_params(ssp,
((chn == 2) && (ttsa != 1)) || (width == 32),
substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
snd_soc_dai_set_dma_data(dai, substream, dma_data);
/* we can only change the settings if the port is not in use */
- if (ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
+ if (pxa_ssp_read_reg(ssp, SSCR0) & SSCR0_SSE)
return 0;
/* clear selected SSP bits */
- sscr0 = ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
- ssp_write_reg(ssp, SSCR0, sscr0);
+ sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_DSS | SSCR0_EDSS);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0);
/* bit size */
- sscr0 = ssp_read_reg(ssp, SSCR0);
+ sscr0 = pxa_ssp_read_reg(ssp, SSCR0);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
#ifdef CONFIG_PXA3xx
@@ -609,13 +608,13 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
sscr0 |= (SSCR0_EDSS | SSCR0_DataSize(16));
break;
}
- ssp_write_reg(ssp, SSCR0, sscr0);
+ pxa_ssp_write_reg(ssp, SSCR0, sscr0);
switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
- sspsp = ssp_read_reg(ssp, SSPSP);
+ sspsp = pxa_ssp_read_reg(ssp, SSPSP);
- if ((ssp_get_scr(ssp) == 4) && (width == 16)) {
+ if ((pxa_ssp_get_scr(ssp) == 4) && (width == 16)) {
/* This is a special case where the bitclk is 64fs
* and we're not dealing with 2*32 bits of audio
* samples.
@@ -649,7 +648,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream,
sspsp |= SSPSP_DMYSTRT(1);
}
- ssp_write_reg(ssp, SSPSP, sspsp);
+ pxa_ssp_write_reg(ssp, SSPSP, sspsp);
break;
default:
break;
@@ -680,45 +679,45 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
- ssp_enable(ssp);
+ pxa_ssp_enable(ssp);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- val = ssp_read_reg(ssp, SSCR1);
+ val = pxa_ssp_read_reg(ssp, SSCR1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
val |= SSCR1_TSRE;
else
val |= SSCR1_RSRE;
- ssp_write_reg(ssp, SSCR1, val);
- val = ssp_read_reg(ssp, SSSR);
- ssp_write_reg(ssp, SSSR, val);
+ pxa_ssp_write_reg(ssp, SSCR1, val);
+ val = pxa_ssp_read_reg(ssp, SSSR);
+ pxa_ssp_write_reg(ssp, SSSR, val);
break;
case SNDRV_PCM_TRIGGER_START:
- val = ssp_read_reg(ssp, SSCR1);
+ val = pxa_ssp_read_reg(ssp, SSCR1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
val |= SSCR1_TSRE;
else
val |= SSCR1_RSRE;
- ssp_write_reg(ssp, SSCR1, val);
- ssp_enable(ssp);
+ pxa_ssp_write_reg(ssp, SSCR1, val);
+ pxa_ssp_enable(ssp);
break;
case SNDRV_PCM_TRIGGER_STOP:
- val = ssp_read_reg(ssp, SSCR1);
+ val = pxa_ssp_read_reg(ssp, SSCR1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
val &= ~SSCR1_TSRE;
else
val &= ~SSCR1_RSRE;
- ssp_write_reg(ssp, SSCR1, val);
+ pxa_ssp_write_reg(ssp, SSCR1, val);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- ssp_disable(ssp);
+ pxa_ssp_disable(ssp);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- val = ssp_read_reg(ssp, SSCR1);
+ val = pxa_ssp_read_reg(ssp, SSCR1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
val &= ~SSCR1_TSRE;
else
val &= ~SSCR1_RSRE;
- ssp_write_reg(ssp, SSCR1, val);
+ pxa_ssp_write_reg(ssp, SSCR1, val);
break;
default:
@@ -740,7 +739,7 @@ static int pxa_ssp_probe(struct platform_device *pdev,
if (!priv)
return -ENOMEM;
- priv->ssp = ssp_request(dai->id + 1, "SoC audio");
+ priv->ssp = pxa_ssp_request(dai->id + 1, "SoC audio");
if (priv->ssp == NULL) {
ret = -ENODEV;
goto err_priv;
@@ -760,7 +759,7 @@ static void pxa_ssp_remove(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
struct ssp_priv *priv = dai->private_data;
- ssp_free(priv->ssp);
+ pxa_ssp_free(priv->ssp);
}
#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index c4cd2acaacb..1941a357e8c 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -322,19 +322,44 @@ static struct snd_soc_card snd_soc_spitz = {
.num_links = 1,
};
-/* spitz audio private data */
-static struct wm8750_setup_data spitz_wm8750_setup = {
- .i2c_bus = 0,
- .i2c_address = 0x1b,
-};
-
/* spitz audio subsystem */
static struct snd_soc_device spitz_snd_devdata = {
.card = &snd_soc_spitz,
.codec_dev = &soc_codec_dev_wm8750,
- .codec_data = &spitz_wm8750_setup,
};
+/*
+ * FIXME: This is a temporary bodge to avoid cross-tree merge issues.
+ * New drivers should register the wm8750 I2C device in the machine
+ * setup code (under arch/arm for ARM systems).
+ */
+static int wm8750_i2c_register(void)
+{
+ struct i2c_board_info info;
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = 0x1b;
+ strlcpy(info.type, "wm8750", I2C_NAME_SIZE);
+
+ adapter = i2c_get_adapter(0);
+ if (!adapter) {
+ printk(KERN_ERR "can't get i2c adapter 0\n");
+ return -ENODEV;
+ }
+
+ client = i2c_new_device(adapter, &info);
+ i2c_put_adapter(adapter);
+ if (!client) {
+ printk(KERN_ERR "can't add i2c device at 0x%x\n",
+ (unsigned int)info.addr);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static struct platform_device *spitz_snd_device;
static int __init spitz_init(void)
@@ -344,6 +369,10 @@ static int __init spitz_init(void)
if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
return -ENODEV;
+ ret = wm8750_i2c_setup();
+ if (ret != 0)
+ return ret;
+
spitz_snd_device = platform_device_alloc("soc-audio", -1);
if (!spitz_snd_device)
return -ENOMEM;
diff --git a/sound/soc/pxa/z2.c b/sound/soc/pxa/z2.c
new file mode 100644
index 00000000000..4e4d2fa8ddc
--- /dev/null
+++ b/sound/soc/pxa/z2.c
@@ -0,0 +1,246 @@
+/*
+ * linux/sound/soc/pxa/z2.c
+ *
+ * SoC Audio driver for Aeronix Zipit Z2
+ *
+ * Copyright (C) 2009 Ken McGuire <kenm@desertweyr.com>
+ * Copyright (C) 2010 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * 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/timer.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/jack.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+#include <mach/audio.h>
+#include <mach/z2.h>
+
+#include "../codecs/wm8750.h"
+#include "pxa2xx-pcm.h"
+#include "pxa2xx-i2s.h"
+
+static struct snd_soc_card snd_soc_z2;
+
+static int z2_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int clk = 0;
+ int ret = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ case 16000:
+ case 48000:
+ case 96000:
+ clk = 12288000;
+ break;
+ case 11025:
+ case 22050:
+ case 44100:
+ clk = 11289600;
+ break;
+ }
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
+ SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8750_SYSCLK, clk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set the I2S system clock as input (unused) */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA2XX_I2S_SYSCLK, 0,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_jack hs_jack;
+
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin hs_jack_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+/* Headset jack detection gpios */
+static struct snd_soc_jack_gpio hs_jack_gpios[] = {
+ {
+ .gpio = GPIO37_ZIPITZ2_HEADSET_DETECT,
+ .name = "hsdet-gpio",
+ .report = SND_JACK_HEADSET,
+ .debounce_time = 200,
+ },
+};
+
+/* z2 machine dapm widgets */
+static const struct snd_soc_dapm_widget wm8750_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
+ SND_SOC_DAPM_MIC("Mic Jack", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+
+ /* headset is a mic and mono headphone */
+ SND_SOC_DAPM_HP("Headset Jack", NULL),
+};
+
+/* Z2 machine audio_map */
+static const struct snd_soc_dapm_route audio_map[] = {
+
+ /* headphone connected to LOUT1, ROUT1 */
+ {"Headphone Jack", NULL, "LOUT1"},
+ {"Headphone Jack", NULL, "ROUT1"},
+
+ /* ext speaker connected to LOUT2, ROUT2 */
+ {"Ext Spk", NULL , "ROUT2"},
+ {"Ext Spk", NULL , "LOUT2"},
+
+ /* mic is connected to R input 2 - with bias */
+ {"RINPUT2", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Mic Jack"},
+};
+
+/*
+ * Logic for a wm8750 as connected on a Z2 Device
+ */
+static int z2_wm8750_init(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ /* NC codec pins */
+ snd_soc_dapm_disable_pin(codec, "LINPUT3");
+ snd_soc_dapm_disable_pin(codec, "RINPUT3");
+ snd_soc_dapm_disable_pin(codec, "OUT3");
+ snd_soc_dapm_disable_pin(codec, "MONO");
+
+ /* Add z2 specific widgets */
+ snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
+ ARRAY_SIZE(wm8750_dapm_widgets));
+
+ /* Set up z2 specific audio paths */
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ ret = snd_soc_dapm_sync(codec);
+ if (ret)
+ goto err;
+
+ /* Jack detection API stuff */
+ ret = snd_soc_jack_new(&snd_soc_z2, "Headset Jack", SND_JACK_HEADSET,
+ &hs_jack);
+ if (ret)
+ goto err;
+
+ ret = snd_soc_jack_add_pins(&hs_jack, ARRAY_SIZE(hs_jack_pins),
+ hs_jack_pins);
+ if (ret)
+ goto err;
+
+ ret = snd_soc_jack_add_gpios(&hs_jack, ARRAY_SIZE(hs_jack_gpios),
+ hs_jack_gpios);
+ if (ret)
+ goto err;
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static struct snd_soc_ops z2_ops = {
+ .hw_params = z2_hw_params,
+};
+
+/* z2 digital audio interface glue - connects codec <--> CPU */
+static struct snd_soc_dai_link z2_dai = {
+ .name = "wm8750",
+ .stream_name = "WM8750",
+ .cpu_dai = &pxa_i2s_dai,
+ .codec_dai = &wm8750_dai,
+ .init = z2_wm8750_init,
+ .ops = &z2_ops,
+};
+
+/* z2 audio machine driver */
+static struct snd_soc_card snd_soc_z2 = {
+ .name = "Z2",
+ .platform = &pxa2xx_soc_platform,
+ .dai_link = &z2_dai,
+ .num_links = 1,
+};
+
+/* z2 audio subsystem */
+static struct snd_soc_device z2_snd_devdata = {
+ .card = &snd_soc_z2,
+ .codec_dev = &soc_codec_dev_wm8750,
+};
+
+static struct platform_device *z2_snd_device;
+
+static int __init z2_init(void)
+{
+ int ret;
+
+ if (!machine_is_zipit2())
+ return -ENODEV;
+
+ z2_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!z2_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(z2_snd_device, &z2_snd_devdata);
+ z2_snd_devdata.dev = &z2_snd_device->dev;
+ ret = platform_device_add(z2_snd_device);
+
+ if (ret)
+ platform_device_put(z2_snd_device);
+
+ return ret;
+}
+
+static void __exit z2_exit(void)
+{
+ platform_device_unregister(z2_snd_device);
+}
+
+module_init(z2_init);
+module_exit(z2_exit);
+
+MODULE_AUTHOR("Ken McGuire <kenm@desertweyr.com>, "
+ "Marek Vasut <marek.vasut@gmail.com>");
+MODULE_DESCRIPTION("ALSA SoC ZipitZ2");
+MODULE_LICENSE("GPL");