All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-04  5:11 ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: john.cooper, alsa-devel, chasedouglas, Ryan Mallon, r&d4,
	hartleys, lrg, marshall, buytenh, dhuggins

The following patch series adds support for i2s audio on the ep93xx,
with the Snapper CL15 used as an example implementation.

This version fixes a number of things from the previous round:
 - Removed unused #defines
 - Set symmetric rates for the cpu dai
 - Fixed the sdiv/lrdiv calculation loop
 - Moved the cpu dai registration
 - Removed empty ep93xx_pcm_prepare callback
 - Fixed enable/disable when both capture and playback are running
 
Capture still does not work. The dma is running, but the captured data
is all zeros (tested used arecord and loopback). I have a 2.6.20
kernel with ep93xx i2s audio working an capture works there on the
same hardware. I have spent sometime looking into this, but can't see
the problem. Would appreciate if someone can lend some insight as to
what I have done wrong.

Ryan Mallon (3):
  ep93xx i2s core support
  ep93xx i2s audio driver
  Snapper cl15 audio support

 arch/arm/mach-ep93xx/clock.c                    |   69 ++++-
 arch/arm/mach-ep93xx/core.c                     |   31 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
 arch/arm/mach-ep93xx/snappercl15.c              |    1 +
 sound/soc/Kconfig                               |    1 +
 sound/soc/Makefile                              |    1 +
 sound/soc/ep93xx/Kconfig                        |   18 +
 sound/soc/ep93xx/Makefile                       |   11 +
 sound/soc/ep93xx/ep93xx-i2s.c                   |  487 +++++++++++++++++++++++
 sound/soc/ep93xx/ep93xx-i2s.h                   |   18 +
 sound/soc/ep93xx/ep93xx-pcm.c                   |  319 +++++++++++++++
 sound/soc/ep93xx/ep93xx-pcm.h                   |   22 +
 sound/soc/ep93xx/snappercl15.c                  |  143 +++++++
 14 files changed, 1131 insertions(+), 1 deletions(-)
 create mode 100644 sound/soc/ep93xx/Kconfig
 create mode 100644 sound/soc/ep93xx/Makefile
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.c
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.h
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.c
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.h
 create mode 100644 sound/soc/ep93xx/snappercl15.c

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-04  5:11 ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel

The following patch series adds support for i2s audio on the ep93xx,
with the Snapper CL15 used as an example implementation.

This version fixes a number of things from the previous round:
 - Removed unused #defines
 - Set symmetric rates for the cpu dai
 - Fixed the sdiv/lrdiv calculation loop
 - Moved the cpu dai registration
 - Removed empty ep93xx_pcm_prepare callback
 - Fixed enable/disable when both capture and playback are running
 
Capture still does not work. The dma is running, but the captured data
is all zeros (tested used arecord and loopback). I have a 2.6.20
kernel with ep93xx i2s audio working an capture works there on the
same hardware. I have spent sometime looking into this, but can't see
the problem. Would appreciate if someone can lend some insight as to
what I have done wrong.

Ryan Mallon (3):
  ep93xx i2s core support
  ep93xx i2s audio driver
  Snapper cl15 audio support

 arch/arm/mach-ep93xx/clock.c                    |   69 ++++-
 arch/arm/mach-ep93xx/core.c                     |   31 ++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +
 arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
 arch/arm/mach-ep93xx/snappercl15.c              |    1 +
 sound/soc/Kconfig                               |    1 +
 sound/soc/Makefile                              |    1 +
 sound/soc/ep93xx/Kconfig                        |   18 +
 sound/soc/ep93xx/Makefile                       |   11 +
 sound/soc/ep93xx/ep93xx-i2s.c                   |  487 +++++++++++++++++++++++
 sound/soc/ep93xx/ep93xx-i2s.h                   |   18 +
 sound/soc/ep93xx/ep93xx-pcm.c                   |  319 +++++++++++++++
 sound/soc/ep93xx/ep93xx-pcm.h                   |   22 +
 sound/soc/ep93xx/snappercl15.c                  |  143 +++++++
 14 files changed, 1131 insertions(+), 1 deletions(-)
 create mode 100644 sound/soc/ep93xx/Kconfig
 create mode 100644 sound/soc/ep93xx/Makefile
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.c
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.h
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.c
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.h
 create mode 100644 sound/soc/ep93xx/snappercl15.c

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 1/3] ep93xx i2s core support
  2010-06-04  5:11 ` Ryan Mallon
@ 2010-06-04  5:11   ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: john.cooper, alsa-devel, chasedouglas, Ryan Mallon, r&d4,
	hartleys, lrg, marshall, buytenh, dhuggins

Add ep93xx core support for i2s audio

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
---
 arch/arm/mach-ep93xx/clock.c                    |   69 ++++++++++++++++++++++-
 arch/arm/mach-ep93xx/core.c                     |   31 ++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +++
 arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
 4 files changed, 110 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092..503d430 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
 
 static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
 static int set_div_rate(struct clk *clk, unsigned long rate);
-
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
 
 static struct clk clk_xtali = {
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -108,6 +109,31 @@ static struct clk clk_video = {
 	.set_rate	= set_div_rate,
 };
 
+static struct clk clk_i2s_mclk = {
+	.sw_locked	= 1,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= (EP93XX_SYSCON_CLKDIV_ENABLE  |
+			   EP93XX_SYSCON_I2SCLKDIV_SPOL |
+			   EP93XX_SYSCON_I2SCLKDIV_ORIDE),
+	.set_rate	= set_div_rate,
+};
+
+static struct clk clk_i2s_sclk = {
+	.sw_locked	= 1,
+	.parent		= &clk_i2s_mclk,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
+	.set_rate	= set_i2s_sclk_rate,
+};
+
+static struct clk clk_i2s_lrclk = {
+	.sw_locked	= 1,
+	.parent		= &clk_i2s_sclk,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
+	.set_rate	= set_i2s_lrclk_rate,
+};
+
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
 	.parent		= &clk_h,
@@ -186,6 +212,9 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
+	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),
+	INIT_CK("ep93xx-i2s",		"sclk",		&clk_i2s_sclk),
+	INIT_CK("ep93xx-i2s",		"lrclk",	&clk_i2s_lrclk),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -396,6 +425,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
 	return 0;
 }
 
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned val = __raw_readl(clk->enable_reg);
+
+	if (rate == clk_i2s_mclk.rate / 2)
+		ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, 
+					     clk->enable_reg);
+	else if (rate == clk_i2s_mclk.rate / 4)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, 
+					     clk->enable_reg);
+	else
+		return -EINVAL;
+
+	clk_i2s_sclk.rate = rate;
+	return 0;
+}
+
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned val = __raw_readl(clk->enable_reg) & 
+		~EP93XX_I2SCLKDIV_LRDIV_MASK;
+	
+	if (rate == clk_i2s_sclk.rate / 32)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
+					     clk->enable_reg);
+	else if (rate == clk_i2s_sclk.rate / 64)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
+					     clk->enable_reg);
+	else if (rate == clk_i2s_sclk.rate / 128)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
+					     clk->enable_reg);
+	else
+		return -EINVAL;
+
+	clk_i2s_lrclk.rate = rate;
+	return 0;
+}
+
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	if (clk->set_rate)
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591..c04fd6f 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -617,6 +617,37 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
 }
 EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
 
+/*************************************************************************
+ * EP93xx I2S audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_i2s_resource[] = {
+	{
+		.start	= EP93XX_I2S_PHYS_BASE,
+		.end	= EP93XX_I2S_PHYS_BASE + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ep93xx_i2s_device = {
+	.name		= "ep93xx-i2s",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_i2s_resource),
+	.resource	= ep93xx_i2s_resource,
+};
+
+void __init ep93xx_register_i2s(unsigned pins)
+{
+	if (pins != EP93XX_SYSCON_DEVCFG_I2SONSSP &&
+	    pins != EP93XX_SYSCON_DEVCFG_I2SONAC97) {
+		pr_err("Invalid I2S pin configuration - not registering\n");
+		return;
+	}
+
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP |
+				 EP93XX_SYSCON_DEVCFG_I2SONAC97);
+	ep93xx_devcfg_set_bits(pins);
+	platform_device_register(&ep93xx_i2s_device);
+}
 
 extern void ep93xx_gpio_init(void);
 
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc..3fbb095 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -93,6 +93,7 @@
 /* APB peripherals */
 #define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
 
+#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
 #define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
 
 #define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
@@ -193,6 +194,15 @@
 #define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
 #define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
 #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
+#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
+#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
+#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128 	(2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK 	(3 << 17)
 #define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14d..9252adf 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -43,6 +43,7 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
 void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
 int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
 void ep93xx_keypad_release_gpio(struct platform_device *pdev);
+void ep93xx_register_i2s(unsigned pins);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
-- 
1.5.5.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 1/3] ep93xx i2s core support
@ 2010-06-04  5:11   ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel

Add ep93xx core support for i2s audio

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
---
 arch/arm/mach-ep93xx/clock.c                    |   69 ++++++++++++++++++++++-
 arch/arm/mach-ep93xx/core.c                     |   31 ++++++++++
 arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +++
 arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
 4 files changed, 110 insertions(+), 1 deletions(-)

diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
index 5f80092..503d430 100644
--- a/arch/arm/mach-ep93xx/clock.c
+++ b/arch/arm/mach-ep93xx/clock.c
@@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
 
 static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
 static int set_div_rate(struct clk *clk, unsigned long rate);
-
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
 
 static struct clk clk_xtali = {
 	.rate		= EP93XX_EXT_CLK_RATE,
@@ -108,6 +109,31 @@ static struct clk clk_video = {
 	.set_rate	= set_div_rate,
 };
 
+static struct clk clk_i2s_mclk = {
+	.sw_locked	= 1,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= (EP93XX_SYSCON_CLKDIV_ENABLE  |
+			   EP93XX_SYSCON_I2SCLKDIV_SPOL |
+			   EP93XX_SYSCON_I2SCLKDIV_ORIDE),
+	.set_rate	= set_div_rate,
+};
+
+static struct clk clk_i2s_sclk = {
+	.sw_locked	= 1,
+	.parent		= &clk_i2s_mclk,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
+	.set_rate	= set_i2s_sclk_rate,
+};
+
+static struct clk clk_i2s_lrclk = {
+	.sw_locked	= 1,
+	.parent		= &clk_i2s_sclk,
+	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
+	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
+	.set_rate	= set_i2s_lrclk_rate,
+};
+
 /* DMA Clocks */
 static struct clk clk_m2p0 = {
 	.parent		= &clk_h,
@@ -186,6 +212,9 @@ static struct clk_lookup clocks[] = {
 	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
 	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
 	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
+	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),
+	INIT_CK("ep93xx-i2s",		"sclk",		&clk_i2s_sclk),
+	INIT_CK("ep93xx-i2s",		"lrclk",	&clk_i2s_lrclk),
 	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
 	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
 	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
@@ -396,6 +425,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
 	return 0;
 }
 
+static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned val = __raw_readl(clk->enable_reg);
+
+	if (rate == clk_i2s_mclk.rate / 2)
+		ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, 
+					     clk->enable_reg);
+	else if (rate == clk_i2s_mclk.rate / 4)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, 
+					     clk->enable_reg);
+	else
+		return -EINVAL;
+
+	clk_i2s_sclk.rate = rate;
+	return 0;
+}
+
+static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned val = __raw_readl(clk->enable_reg) & 
+		~EP93XX_I2SCLKDIV_LRDIV_MASK;
+	
+	if (rate == clk_i2s_sclk.rate / 32)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
+					     clk->enable_reg);
+	else if (rate == clk_i2s_sclk.rate / 64)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
+					     clk->enable_reg);
+	else if (rate == clk_i2s_sclk.rate / 128)
+		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
+					     clk->enable_reg);
+	else
+		return -EINVAL;
+
+	clk_i2s_lrclk.rate = rate;
+	return 0;
+}
+
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
 	if (clk->set_rate)
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
index 90fb591..c04fd6f 100644
--- a/arch/arm/mach-ep93xx/core.c
+++ b/arch/arm/mach-ep93xx/core.c
@@ -617,6 +617,37 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
 }
 EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
 
+/*************************************************************************
+ * EP93xx I2S audio peripheral handling
+ *************************************************************************/
+static struct resource ep93xx_i2s_resource[] = {
+	{
+		.start	= EP93XX_I2S_PHYS_BASE,
+		.end	= EP93XX_I2S_PHYS_BASE + 0x100 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ep93xx_i2s_device = {
+	.name		= "ep93xx-i2s",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(ep93xx_i2s_resource),
+	.resource	= ep93xx_i2s_resource,
+};
+
+void __init ep93xx_register_i2s(unsigned pins)
+{
+	if (pins != EP93XX_SYSCON_DEVCFG_I2SONSSP &&
+	    pins != EP93XX_SYSCON_DEVCFG_I2SONAC97) {
+		pr_err("Invalid I2S pin configuration - not registering\n");
+		return;
+	}
+
+	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP |
+				 EP93XX_SYSCON_DEVCFG_I2SONAC97);
+	ep93xx_devcfg_set_bits(pins);
+	platform_device_register(&ep93xx_i2s_device);
+}
 
 extern void ep93xx_gpio_init(void);
 
diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
index 93e2ecc..3fbb095 100644
--- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
+++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
@@ -93,6 +93,7 @@
 /* APB peripherals */
 #define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
 
+#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
 #define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
 
 #define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
@@ -193,6 +194,15 @@
 #define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
 #define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
 #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
+#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
+#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
+#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
+#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
+#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
+#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV128 	(2 << 17)
+#define EP93XX_I2SCLKDIV_LRDIV_MASK 	(3 << 17)
 #define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
 #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
index c6dc14d..9252adf 100644
--- a/arch/arm/mach-ep93xx/include/mach/platform.h
+++ b/arch/arm/mach-ep93xx/include/mach/platform.h
@@ -43,6 +43,7 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
 void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
 int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
 void ep93xx_keypad_release_gpio(struct platform_device *pdev);
+void ep93xx_register_i2s(unsigned pins);
 
 void ep93xx_init_devices(void);
 extern struct sys_timer ep93xx_timer;
-- 
1.5.5.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 2/3] ep93xx i2s audio driver
  2010-06-04  5:11   ` Ryan Mallon
@ 2010-06-04  5:11     ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: john.cooper, alsa-devel, chasedouglas, Ryan Mallon, r&d4,
	hartleys, lrg, marshall, buytenh, dhuggins

Add ep93xx i2s audio driver

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
---
 sound/soc/Kconfig             |    1 +
 sound/soc/Makefile            |    1 +
 sound/soc/ep93xx/Kconfig      |    9 +
 sound/soc/ep93xx/Makefile     |    8 +
 sound/soc/ep93xx/ep93xx-i2s.c |  487 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/ep93xx/ep93xx-i2s.h |   18 ++
 sound/soc/ep93xx/ep93xx-pcm.c |  319 +++++++++++++++++++++++++++
 sound/soc/ep93xx/ep93xx-pcm.h |   22 ++
 8 files changed, 865 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/ep93xx/Kconfig
 create mode 100644 sound/soc/ep93xx/Makefile
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.c
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.h
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.c
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.h

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc..f7cb451 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -28,6 +28,7 @@ source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/davinci/Kconfig"
+source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
 source "sound/soc/omap/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1470141..55b711a 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= davinci/
+obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= omap/
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
new file mode 100644
index 0000000..ba66ac8
--- /dev/null
+++ b/sound/soc/ep93xx/Kconfig
@@ -0,0 +1,9 @@
+config SND_EP93XX_SOC
+	tristate "SoC Audio support for the Cirrus Logic EP93xx series"
+	depends on ARCH_EP93XX && SND_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the EP93xx I2S interface.
+
+config SND_EP93XX_SOC_I2S
+	tristate
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
new file mode 100644
index 0000000..0239da3
--- /dev/null
+++ b/sound/soc/ep93xx/Makefile
@@ -0,0 +1,8 @@
+# EP93xx Platform Support
+snd-soc-ep93xx-objs				:= ep93xx-pcm.o
+snd-soc-ep93xx-i2s-objs	 			:= ep93xx-i2s.o
+
+obj-$(CONFIG_SND_EP93XX_SOC)			+= snd-soc-ep93xx.o
+obj-$(CONFIG_SND_EP93XX_SOC_I2S)		+= snd-soc-ep93xx-i2s.o
+
+# EP93XX Machine Support
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
new file mode 100644
index 0000000..00b9466
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -0,0 +1,487 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.c
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * Based on the original driver by:
+ *   Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
+ *   Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+#include <mach/dma.h>
+
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define EP93XX_I2S_TXCLKCFG		0x00
+#define EP93XX_I2S_RXCLKCFG		0x04
+#define EP93XX_I2S_GLCTRL		0x0C
+
+#define EP93XX_I2S_TXLINCTRLDATA	0x28
+#define EP93XX_I2S_TXCTRL		0x2C
+#define EP93XX_I2S_TXWRDLEN		0x30
+#define EP93XX_I2S_TX0EN		0x34
+
+#define EP93XX_I2S_RXLINCTRLDATA	0x58
+#define EP93XX_I2S_RXCTRL		0x5C
+#define EP93XX_I2S_RXWRDLEN		0x60
+#define EP93XX_I2S_RX0EN		0x64
+
+#define EP93XX_I2S_WRDLEN_16		(0 << 0)
+#define EP93XX_I2S_WRDLEN_24		(1 << 0)
+#define EP93XX_I2S_WRDLEN_32		(2 << 0)
+
+#define EP93XX_I2S_LINCTRLDATA_R_JUST	(1 << 2) /* Right justify */
+
+#define EP93XX_I2S_CLKCFG_LRS		(1 << 0) /* lrclk polarity */
+#define EP93XX_I2S_CLKCFG_CKP		(1 << 1) /* Bit clock polarity */
+#define EP93XX_I2S_CLKCFG_REL		(1 << 2) /* First bit transition */
+#define EP93XX_I2S_CLKCFG_MASTER	(1 << 3) /* Master mode */
+#define EP93XX_I2S_CLKCFG_NBCG		(1 << 4) /* Not bit clock gating */
+
+struct ep93xx_i2s_info {
+	struct clk			*mclk;
+	struct clk			*sclk;
+	struct clk			*lrclk;
+	struct ep93xx_pcm_dma_params	*dma_params;
+	struct resource			*mem;
+	void __iomem			*regs;
+};
+
+struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
+	[SNDRV_PCM_STREAM_PLAYBACK] = {
+		.name		= "i2s-pcm-out",
+		.dma_port	= EP93XX_DMA_M2P_PORT_I2S1,
+	},
+	[SNDRV_PCM_STREAM_CAPTURE] = {
+		.name		= "i2s-pcm-in",
+		.dma_port	= EP93XX_DMA_M2P_PORT_I2S1,
+	},
+};
+
+static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
+					unsigned reg, unsigned val)
+{
+	__raw_writel(val, info->regs + reg);
+}
+
+static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+					   unsigned reg)
+{
+	return __raw_readl(info->regs + reg);
+}
+
+static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+{
+	unsigned base_reg;
+	int i;
+
+	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+		/* Enable clocks */
+		clk_enable(info->mclk);
+		clk_enable(info->sclk);
+		clk_enable(info->lrclk);
+
+		/* Enable i2s */
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+	}
+
+	/* Enable fifos */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		base_reg = EP93XX_I2S_TX0EN;
+	else
+		base_reg = EP93XX_I2S_RX0EN;
+	for (i = 0; i < 3; i++)
+		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
+}
+
+static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+{
+	unsigned base_reg;
+	int i;
+
+	/* Disable fifos */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		base_reg = EP93XX_I2S_TX0EN;
+	else
+		base_reg = EP93XX_I2S_RX0EN;
+	for (i = 0; i < 3; i++)
+		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
+
+	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+		/* Disable i2s */
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
+
+		/* Disable clocks */
+		clk_disable(info->lrclk);
+		clk_disable(info->sclk);
+		clk_disable(info->mclk);
+	}
+}
+
+static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream,
+				 &info->dma_params[substream->stream]);
+	return 0;
+}
+
+static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+	ep93xx_i2s_disable(info, substream->stream);
+}
+
+static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+				  unsigned int fmt)
+{
+	struct ep93xx_i2s_info *info = cpu_dai->private_data;
+	unsigned int clk_cfg, lin_ctrl;
+
+	clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
+	lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+		break;
+
+	case SND_SOC_DAIFMT_RIGHT_J:
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
+		break;
+
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Codec is master */
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		/* Negative bit clock, lrclk low on left word */
+		clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
+		break;
+
+	case SND_SOC_DAIFMT_NB_IF:
+		/* Negative bit clock, lrclk low on right word */
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
+		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		/* Positive bit clock, lrclk low on left word */
+		clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		break;
+
+	case SND_SOC_DAIFMT_IB_IF:
+		/* Positive bit clock, lrclk low on right word */
+		clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
+		break;
+	}
+
+	/* Write new register values */
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
+	return 0;
+}
+
+static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct ep93xx_i2s_info *info = cpu_dai->private_data;
+	unsigned word_len, div, sdiv, lrdiv;
+	int found = 0, err;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		word_len = EP93XX_I2S_WRDLEN_16;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		word_len = EP93XX_I2S_WRDLEN_24;
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		word_len = EP93XX_I2S_WRDLEN_32;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
+	else
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
+
+	/*
+	 * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
+	 * If the lrclk is pulse length is larger than the word size, then the
+	 * bit clock will be gated for the unused bits.
+	 */
+	div = (clk_get_rate(info->mclk) / params_rate(params)) *
+		params_channels(params);
+	for (sdiv = 2; sdiv <= 4; sdiv += 2)
+		for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
+			if (sdiv * lrdiv == div) {
+				found = 1;
+				goto out;
+			}
+out:
+	if (!found)
+		return -EINVAL;
+
+	err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
+	if (err)
+		return err;
+
+	err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
+	if (err)
+		return err;
+
+	ep93xx_i2s_enable(info, substream->stream);
+	return 0;
+}
+
+static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct ep93xx_i2s_info *info = cpu_dai->private_data;
+
+	if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
+		return -EINVAL;
+
+	return clk_set_rate(info->mclk, freq);
+}
+
+#ifdef CONFIG_PM
+static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
+{
+	struct ep93xx_i2s_info *info = dai->private_data;
+
+	if (!dai->active)
+		return;
+
+	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
+	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
+{
+	struct ep93xx_i2s_info *info = dai->private_data;
+
+	if (!dai->active)
+		return;
+
+	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+#else
+#define ep93xx_i2s_suspend	NULL
+#define ep93xx_i2s_resume	NULL
+#endif
+
+static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+	.startup	= ep93xx_i2s_startup,
+	.shutdown	= ep93xx_i2s_shutdown,
+	.hw_params	= ep93xx_i2s_hw_params,
+	.set_sysclk	= ep93xx_i2s_set_sysclk,
+	.set_fmt	= ep93xx_i2s_set_dai_fmt,
+};
+
+#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			    SNDRV_PCM_FMTBIT_S24_LE | \
+			    SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai ep93xx_i2s_dai = {
+	.name		= "ep93xx-i2s",
+	.id		= 0,
+	.symmetric_rates= 1,
+	.suspend	= ep93xx_i2s_suspend,
+	.resume		= ep93xx_i2s_resume,
+	.playback	= {
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= SNDRV_PCM_RATE_8000_48000,
+		.formats	= EP93XX_I2S_FORMATS,
+	},
+	.capture	= {
+		 .channels_min	= 2,
+		 .channels_max	= 2,
+		 .rates		= SNDRV_PCM_RATE_8000_48000,
+		 .formats	= EP93XX_I2S_FORMATS,
+	},
+	.ops		= &ep93xx_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
+
+static int ep93xx_i2s_probe(struct platform_device *pdev)
+{
+	struct ep93xx_i2s_info *info;
+	struct resource *res;
+	int err;
+
+	info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
+	if (!info) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	ep93xx_i2s_dai.dev = &pdev->dev;
+	ep93xx_i2s_dai.private_data = info;
+	info->dma_params = ep93xx_i2s_dma_params;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENODEV;
+		goto fail;
+	}
+
+	info->mem = request_mem_region(res->start, resource_size(res),
+				       pdev->name);
+	if (!info->mem) {
+		err = -EBUSY;
+		goto fail;
+	}
+
+	info->regs = ioremap(info->mem->start, resource_size(info->mem));
+	if (!info->regs) {
+		err = -ENXIO;
+		goto fail_release_mem;
+	}
+
+	info->mclk = clk_get(&pdev->dev, "mclk");
+	if (IS_ERR(info->mclk)) {
+		err = PTR_ERR(info->mclk);
+		goto fail_unmap_mem;
+	}
+
+	info->sclk = clk_get(&pdev->dev, "sclk");
+	if (IS_ERR(info->sclk)) {
+		err = PTR_ERR(info->sclk);
+		goto fail_put_mclk;
+	}
+
+	info->lrclk = clk_get(&pdev->dev, "lrclk");
+	if (IS_ERR(info->lrclk)) {
+		err = PTR_ERR(info->lrclk);
+		goto fail_put_sclk;
+	}
+
+	err = snd_soc_register_dai(&ep93xx_i2s_dai);
+	if (err)
+		goto fail_put_lrclk;
+
+	return 0;
+
+fail_put_lrclk:
+	clk_put(info->lrclk);
+fail_put_sclk:
+	clk_put(info->sclk);
+fail_put_mclk:
+	clk_put(info->mclk);
+fail_unmap_mem:
+	iounmap(info->regs);
+fail_release_mem:
+	release_mem_region(info->mem->start, resource_size(info->mem));
+	kfree(info);
+fail:
+	return err;
+}
+
+static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
+{
+	struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+
+	snd_soc_unregister_dai(&ep93xx_i2s_dai);
+	clk_put(info->lrclk);
+	clk_put(info->sclk);
+	clk_put(info->mclk);
+	iounmap(info->regs);
+	release_mem_region(info->mem->start, resource_size(info->mem));
+	kfree(info);
+	return 0;
+}
+
+static struct platform_driver ep93xx_i2s_driver = {
+	.probe	= ep93xx_i2s_probe,
+	.remove	= __devexit_p(ep93xx_i2s_remove),
+	.driver	= {
+		.name	= "ep93xx-i2s",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ep93xx_i2s_init(void)
+{
+	return platform_driver_register(&ep93xx_i2s_driver);
+}
+
+static void __exit ep93xx_i2s_exit(void)
+{
+	platform_driver_unregister(&ep93xx_i2s_driver);
+}
+
+module_init(ep93xx_i2s_init);
+module_exit(ep93xx_i2s_exit);
+
+MODULE_ALIAS("platform:ep93xx-i2s");
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93XX I2S driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
new file mode 100644
index 0000000..3bd4ebf
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.h
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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.
+ *
+ */
+
+#ifndef _EP93XX_SND_SOC_I2S_H
+#define _EP93XX_SND_SOC_I2S_H
+
+extern struct snd_soc_dai ep93xx_i2s_dai;
+
+#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
new file mode 100644
index 0000000..4ba9384
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -0,0 +1,319 @@
+/*
+ * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
+ *   Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.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/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+
+#include "ep93xx-pcm.h"
+
+static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
+	.info			= (SNDRV_PCM_INFO_MMAP		|
+				   SNDRV_PCM_INFO_MMAP_VALID	|
+				   SNDRV_PCM_INFO_INTERLEAVED	|
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER),
+				   
+	.rates			= SNDRV_PCM_RATE_8000_48000,
+	.rate_min		= SNDRV_PCM_RATE_8000,
+	.rate_max		= SNDRV_PCM_RATE_48000,
+	
+	.formats		= (SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE),
+	
+	.buffer_bytes_max	= 131072,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 32768,
+	.periods_min		= 1,
+	.periods_max		= 32,
+	.fifo_size		= 32,
+};
+
+struct ep93xx_runtime_data
+{
+	struct ep93xx_dma_m2p_client	cl;
+	struct ep93xx_pcm_dma_params	*params;
+	int				pointer_bytes;
+	struct tasklet_struct		period_tasklet;
+	int				periods;
+	struct ep93xx_dma_buffer	buf[32];
+};
+
+static void ep93xx_pcm_period_elapsed(unsigned long data)
+{
+	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+	snd_pcm_period_elapsed(substream);
+}
+
+static void ep93xx_pcm_buffer_started(void *cookie,
+				      struct ep93xx_dma_buffer *buf)
+{
+}
+
+static void ep93xx_pcm_buffer_finished(void *cookie, 
+				       struct ep93xx_dma_buffer *buf, 
+				       int bytes, int error)
+{
+	struct snd_pcm_substream *substream = cookie;
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+	if (buf == rtd->buf + rtd->periods - 1)
+		rtd->pointer_bytes = 0;
+	else
+		rtd->pointer_bytes += buf->size;
+
+	if (!error) {
+		ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
+		tasklet_schedule(&rtd->period_tasklet);
+	} else {
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+	}
+}
+
+static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+	struct ep93xx_pcm_dma_params *dma_params;
+	struct ep93xx_runtime_data *rtd;    
+	int ret;
+
+	dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
+	snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
+
+	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+	if (!rtd) 
+		return -ENOMEM;
+
+	memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
+	rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
+	rtd->period_tasklet.data = (unsigned long)substream;
+
+	rtd->cl.name = dma_params->name;
+	rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
+		((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		 EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
+	rtd->cl.cookie = substream;
+	rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
+	rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
+	ret = ep93xx_dma_m2p_client_register(&rtd->cl);
+	if (ret < 0) {
+		kfree(rtd);
+		return ret;
+	}
+	
+	substream->runtime->private_data = rtd;
+	return 0;
+}
+
+static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+	ep93xx_dma_m2p_client_unregister(&rtd->cl);
+	kfree(rtd);
+	return 0;
+}
+
+static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ep93xx_runtime_data *rtd = runtime->private_data;
+	size_t totsize = params_buffer_bytes(params);
+	size_t period = params_period_bytes(params);
+	int i;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = totsize;
+
+	rtd->periods = (totsize + period - 1) / period;
+	for (i = 0; i < rtd->periods; i++) {
+		rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
+		rtd->buf[i].size = period;
+		if ((i + 1) * period > totsize)
+			rtd->buf[i].size = totsize - (i * period);
+	}
+
+	return 0;
+}
+
+static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+	int ret;
+	int i;
+
+	ret = 0;
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		rtd->pointer_bytes = 0;
+		for (i = 0; i < rtd->periods; i++)
+			ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ep93xx_dma_m2p_flush(&rtd->cl);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+	/* FIXME: implement this with sub-period granularity */
+	return bytes_to_frames(runtime, rtd->pointer_bytes);
+}
+
+static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
+			   struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ep93xx_pcm_ops = {
+	.open		= ep93xx_pcm_open,
+	.close		= ep93xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= ep93xx_pcm_hw_params,
+	.hw_free	= ep93xx_pcm_hw_free,
+	.trigger	= ep93xx_pcm_trigger,
+	.pointer	= ep93xx_pcm_pointer,
+	.mmap		= ep93xx_pcm_mmap,
+};
+
+static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	buf->bytes = size;
+
+	return (buf->area == NULL) ? -ENOMEM : 0;
+}
+
+static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {		
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+		
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
+				      buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 ep93xx_pcm_dmamask = 0xffffffff;
+
+static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+			  struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &ep93xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+					SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+					SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct snd_soc_platform ep93xx_soc_platform = {
+	.name		= "ep93xx-audio",
+	.pcm_ops	= &ep93xx_pcm_ops,
+	.pcm_new	= &ep93xx_pcm_new,
+	.pcm_free	= &ep93xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __init ep93xx_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&ep93xx_soc_platform);
+}
+
+static void __exit ep93xx_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&ep93xx_soc_platform);
+}
+
+module_init(ep93xx_soc_platform_init);
+module_exit(ep93xx_soc_platform_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
new file mode 100644
index 0000000..4ffdd3f
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -0,0 +1,22 @@
+/*
+ * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * 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.
+ */
+
+#ifndef _EP93XX_SND_SOC_PCM_H
+#define _EP93XX_SND_SOC_PCM_H
+
+struct ep93xx_pcm_dma_params {
+	char	*name;
+	int	dma_port;
+};
+
+extern struct snd_soc_platform ep93xx_soc_platform;
+
+#endif /* _EP93XX_SND_SOC_PCM_H */
-- 
1.5.5.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 2/3] ep93xx i2s audio driver
@ 2010-06-04  5:11     ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel

Add ep93xx i2s audio driver

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
---
 sound/soc/Kconfig             |    1 +
 sound/soc/Makefile            |    1 +
 sound/soc/ep93xx/Kconfig      |    9 +
 sound/soc/ep93xx/Makefile     |    8 +
 sound/soc/ep93xx/ep93xx-i2s.c |  487 +++++++++++++++++++++++++++++++++++++++++
 sound/soc/ep93xx/ep93xx-i2s.h |   18 ++
 sound/soc/ep93xx/ep93xx-pcm.c |  319 +++++++++++++++++++++++++++
 sound/soc/ep93xx/ep93xx-pcm.h |   22 ++
 8 files changed, 865 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/ep93xx/Kconfig
 create mode 100644 sound/soc/ep93xx/Makefile
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.c
 create mode 100644 sound/soc/ep93xx/ep93xx-i2s.h
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.c
 create mode 100644 sound/soc/ep93xx/ep93xx-pcm.h

diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index b1749bc..f7cb451 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -28,6 +28,7 @@ source "sound/soc/atmel/Kconfig"
 source "sound/soc/au1x/Kconfig"
 source "sound/soc/blackfin/Kconfig"
 source "sound/soc/davinci/Kconfig"
+source "sound/soc/ep93xx/Kconfig"
 source "sound/soc/fsl/Kconfig"
 source "sound/soc/imx/Kconfig"
 source "sound/soc/omap/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 1470141..55b711a 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_SND_SOC)	+= atmel/
 obj-$(CONFIG_SND_SOC)	+= au1x/
 obj-$(CONFIG_SND_SOC)	+= blackfin/
 obj-$(CONFIG_SND_SOC)	+= davinci/
+obj-$(CONFIG_SND_SOC)	+= ep93xx/
 obj-$(CONFIG_SND_SOC)	+= fsl/
 obj-$(CONFIG_SND_SOC)   += imx/
 obj-$(CONFIG_SND_SOC)	+= omap/
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
new file mode 100644
index 0000000..ba66ac8
--- /dev/null
+++ b/sound/soc/ep93xx/Kconfig
@@ -0,0 +1,9 @@
+config SND_EP93XX_SOC
+	tristate "SoC Audio support for the Cirrus Logic EP93xx series"
+	depends on ARCH_EP93XX && SND_SOC
+	help
+	  Say Y or M if you want to add support for codecs attached to
+	  the EP93xx I2S interface.
+
+config SND_EP93XX_SOC_I2S
+	tristate
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
new file mode 100644
index 0000000..0239da3
--- /dev/null
+++ b/sound/soc/ep93xx/Makefile
@@ -0,0 +1,8 @@
+# EP93xx Platform Support
+snd-soc-ep93xx-objs				:= ep93xx-pcm.o
+snd-soc-ep93xx-i2s-objs	 			:= ep93xx-i2s.o
+
+obj-$(CONFIG_SND_EP93XX_SOC)			+= snd-soc-ep93xx.o
+obj-$(CONFIG_SND_EP93XX_SOC_I2S)		+= snd-soc-ep93xx-i2s.o
+
+# EP93XX Machine Support
diff --git a/sound/soc/ep93xx/ep93xx-i2s.c b/sound/soc/ep93xx/ep93xx-i2s.c
new file mode 100644
index 0000000..00b9466
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.c
@@ -0,0 +1,487 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.c
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com>
+ *
+ * Based on the original driver by:
+ *   Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
+ *   Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ *
+ * 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/init.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/initval.h>
+#include <sound/soc.h>
+
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+#include <mach/dma.h>
+
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define EP93XX_I2S_TXCLKCFG		0x00
+#define EP93XX_I2S_RXCLKCFG		0x04
+#define EP93XX_I2S_GLCTRL		0x0C
+
+#define EP93XX_I2S_TXLINCTRLDATA	0x28
+#define EP93XX_I2S_TXCTRL		0x2C
+#define EP93XX_I2S_TXWRDLEN		0x30
+#define EP93XX_I2S_TX0EN		0x34
+
+#define EP93XX_I2S_RXLINCTRLDATA	0x58
+#define EP93XX_I2S_RXCTRL		0x5C
+#define EP93XX_I2S_RXWRDLEN		0x60
+#define EP93XX_I2S_RX0EN		0x64
+
+#define EP93XX_I2S_WRDLEN_16		(0 << 0)
+#define EP93XX_I2S_WRDLEN_24		(1 << 0)
+#define EP93XX_I2S_WRDLEN_32		(2 << 0)
+
+#define EP93XX_I2S_LINCTRLDATA_R_JUST	(1 << 2) /* Right justify */
+
+#define EP93XX_I2S_CLKCFG_LRS		(1 << 0) /* lrclk polarity */
+#define EP93XX_I2S_CLKCFG_CKP		(1 << 1) /* Bit clock polarity */
+#define EP93XX_I2S_CLKCFG_REL		(1 << 2) /* First bit transition */
+#define EP93XX_I2S_CLKCFG_MASTER	(1 << 3) /* Master mode */
+#define EP93XX_I2S_CLKCFG_NBCG		(1 << 4) /* Not bit clock gating */
+
+struct ep93xx_i2s_info {
+	struct clk			*mclk;
+	struct clk			*sclk;
+	struct clk			*lrclk;
+	struct ep93xx_pcm_dma_params	*dma_params;
+	struct resource			*mem;
+	void __iomem			*regs;
+};
+
+struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = {
+	[SNDRV_PCM_STREAM_PLAYBACK] = {
+		.name		= "i2s-pcm-out",
+		.dma_port	= EP93XX_DMA_M2P_PORT_I2S1,
+	},
+	[SNDRV_PCM_STREAM_CAPTURE] = {
+		.name		= "i2s-pcm-in",
+		.dma_port	= EP93XX_DMA_M2P_PORT_I2S1,
+	},
+};
+
+static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
+					unsigned reg, unsigned val)
+{
+	__raw_writel(val, info->regs + reg);
+}
+
+static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
+					   unsigned reg)
+{
+	return __raw_readl(info->regs + reg);
+}
+
+static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
+{
+	unsigned base_reg;
+	int i;
+
+	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+		/* Enable clocks */
+		clk_enable(info->mclk);
+		clk_enable(info->sclk);
+		clk_enable(info->lrclk);
+
+		/* Enable i2s */
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
+	}
+
+	/* Enable fifos */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		base_reg = EP93XX_I2S_TX0EN;
+	else
+		base_reg = EP93XX_I2S_RX0EN;
+	for (i = 0; i < 3; i++)
+		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
+}
+
+static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
+{
+	unsigned base_reg;
+	int i;
+
+	/* Disable fifos */
+	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
+		base_reg = EP93XX_I2S_TX0EN;
+	else
+		base_reg = EP93XX_I2S_RX0EN;
+	for (i = 0; i < 3; i++)
+		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);
+
+	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
+	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
+		/* Disable i2s */
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);
+
+		/* Disable clocks */
+		clk_disable(info->lrclk);
+		clk_disable(info->sclk);
+		clk_disable(info->mclk);
+	}
+}
+
+static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
+			      struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+	snd_soc_dai_set_dma_data(cpu_dai, substream,
+				 &info->dma_params[substream->stream]);
+	return 0;
+}
+
+static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data;
+
+	ep93xx_i2s_disable(info, substream->stream);
+}
+
+static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+				  unsigned int fmt)
+{
+	struct ep93xx_i2s_info *info = cpu_dai->private_data;
+	unsigned int clk_cfg, lin_ctrl;
+
+	clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
+	lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+		break;
+
+	case SND_SOC_DAIFMT_LEFT_J:
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
+		break;
+
+	case SND_SOC_DAIFMT_RIGHT_J:
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* CPU is master */
+		clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
+		break;
+
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Codec is master */
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		/* Negative bit clock, lrclk low on left word */
+		clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
+		break;
+
+	case SND_SOC_DAIFMT_NB_IF:
+		/* Negative bit clock, lrclk low on right word */
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
+		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
+		break;
+
+	case SND_SOC_DAIFMT_IB_NF:
+		/* Positive bit clock, lrclk low on left word */
+		clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
+		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
+		break;
+
+	case SND_SOC_DAIFMT_IB_IF:
+		/* Positive bit clock, lrclk low on right word */
+		clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
+		break;
+	}
+
+	/* Write new register values */
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
+	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
+	return 0;
+}
+
+static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params,
+				struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	struct ep93xx_i2s_info *info = cpu_dai->private_data;
+	unsigned word_len, div, sdiv, lrdiv;
+	int found = 0, err;
+
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		word_len = EP93XX_I2S_WRDLEN_16;
+		break;
+
+	case SNDRV_PCM_FORMAT_S24_LE:
+		word_len = EP93XX_I2S_WRDLEN_24;
+		break;
+
+	case SNDRV_PCM_FORMAT_S32_LE:
+		word_len = EP93XX_I2S_WRDLEN_32;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
+	else
+		ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);
+
+	/*
+	 * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values.
+	 * If the lrclk is pulse length is larger than the word size, then the
+	 * bit clock will be gated for the unused bits.
+	 */
+	div = (clk_get_rate(info->mclk) / params_rate(params)) *
+		params_channels(params);
+	for (sdiv = 2; sdiv <= 4; sdiv += 2)
+		for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1)
+			if (sdiv * lrdiv == div) {
+				found = 1;
+				goto out;
+			}
+out:
+	if (!found)
+		return -EINVAL;
+
+	err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
+	if (err)
+		return err;
+
+	err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
+	if (err)
+		return err;
+
+	ep93xx_i2s_enable(info, substream->stream);
+	return 0;
+}
+
+static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
+				 unsigned int freq, int dir)
+{
+	struct ep93xx_i2s_info *info = cpu_dai->private_data;
+
+	if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
+		return -EINVAL;
+
+	return clk_set_rate(info->mclk, freq);
+}
+
+#ifdef CONFIG_PM
+static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
+{
+	struct ep93xx_i2s_info *info = dai->private_data;
+
+	if (!dai->active)
+		return;
+
+	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
+	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+
+static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
+{
+	struct ep93xx_i2s_info *info = dai->private_data;
+
+	if (!dai->active)
+		return;
+
+	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
+	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
+}
+#else
+#define ep93xx_i2s_suspend	NULL
+#define ep93xx_i2s_resume	NULL
+#endif
+
+static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
+	.startup	= ep93xx_i2s_startup,
+	.shutdown	= ep93xx_i2s_shutdown,
+	.hw_params	= ep93xx_i2s_hw_params,
+	.set_sysclk	= ep93xx_i2s_set_sysclk,
+	.set_fmt	= ep93xx_i2s_set_dai_fmt,
+};
+
+#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+			    SNDRV_PCM_FMTBIT_S24_LE | \
+			    SNDRV_PCM_FMTBIT_S32_LE)
+
+struct snd_soc_dai ep93xx_i2s_dai = {
+	.name		= "ep93xx-i2s",
+	.id		= 0,
+	.symmetric_rates= 1,
+	.suspend	= ep93xx_i2s_suspend,
+	.resume		= ep93xx_i2s_resume,
+	.playback	= {
+		.channels_min	= 2,
+		.channels_max	= 2,
+		.rates		= SNDRV_PCM_RATE_8000_48000,
+		.formats	= EP93XX_I2S_FORMATS,
+	},
+	.capture	= {
+		 .channels_min	= 2,
+		 .channels_max	= 2,
+		 .rates		= SNDRV_PCM_RATE_8000_48000,
+		 .formats	= EP93XX_I2S_FORMATS,
+	},
+	.ops		= &ep93xx_i2s_dai_ops,
+};
+EXPORT_SYMBOL_GPL(ep93xx_i2s_dai);
+
+static int ep93xx_i2s_probe(struct platform_device *pdev)
+{
+	struct ep93xx_i2s_info *info;
+	struct resource *res;
+	int err;
+
+	info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL);
+	if (!info) {
+		err = -ENOMEM;
+		goto fail;
+	}
+
+	ep93xx_i2s_dai.dev = &pdev->dev;
+	ep93xx_i2s_dai.private_data = info;
+	info->dma_params = ep93xx_i2s_dma_params;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		err = -ENODEV;
+		goto fail;
+	}
+
+	info->mem = request_mem_region(res->start, resource_size(res),
+				       pdev->name);
+	if (!info->mem) {
+		err = -EBUSY;
+		goto fail;
+	}
+
+	info->regs = ioremap(info->mem->start, resource_size(info->mem));
+	if (!info->regs) {
+		err = -ENXIO;
+		goto fail_release_mem;
+	}
+
+	info->mclk = clk_get(&pdev->dev, "mclk");
+	if (IS_ERR(info->mclk)) {
+		err = PTR_ERR(info->mclk);
+		goto fail_unmap_mem;
+	}
+
+	info->sclk = clk_get(&pdev->dev, "sclk");
+	if (IS_ERR(info->sclk)) {
+		err = PTR_ERR(info->sclk);
+		goto fail_put_mclk;
+	}
+
+	info->lrclk = clk_get(&pdev->dev, "lrclk");
+	if (IS_ERR(info->lrclk)) {
+		err = PTR_ERR(info->lrclk);
+		goto fail_put_sclk;
+	}
+
+	err = snd_soc_register_dai(&ep93xx_i2s_dai);
+	if (err)
+		goto fail_put_lrclk;
+
+	return 0;
+
+fail_put_lrclk:
+	clk_put(info->lrclk);
+fail_put_sclk:
+	clk_put(info->sclk);
+fail_put_mclk:
+	clk_put(info->mclk);
+fail_unmap_mem:
+	iounmap(info->regs);
+fail_release_mem:
+	release_mem_region(info->mem->start, resource_size(info->mem));
+	kfree(info);
+fail:
+	return err;
+}
+
+static int __devexit ep93xx_i2s_remove(struct platform_device *pdev)
+{
+	struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data;
+
+	snd_soc_unregister_dai(&ep93xx_i2s_dai);
+	clk_put(info->lrclk);
+	clk_put(info->sclk);
+	clk_put(info->mclk);
+	iounmap(info->regs);
+	release_mem_region(info->mem->start, resource_size(info->mem));
+	kfree(info);
+	return 0;
+}
+
+static struct platform_driver ep93xx_i2s_driver = {
+	.probe	= ep93xx_i2s_probe,
+	.remove	= __devexit_p(ep93xx_i2s_remove),
+	.driver	= {
+		.name	= "ep93xx-i2s",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init ep93xx_i2s_init(void)
+{
+	return platform_driver_register(&ep93xx_i2s_driver);
+}
+
+static void __exit ep93xx_i2s_exit(void)
+{
+	platform_driver_unregister(&ep93xx_i2s_driver);
+}
+
+module_init(ep93xx_i2s_init);
+module_exit(ep93xx_i2s_exit);
+
+MODULE_ALIAS("platform:ep93xx-i2s");
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93XX I2S driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-i2s.h b/sound/soc/ep93xx/ep93xx-i2s.h
new file mode 100644
index 0000000..3bd4ebf
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-i2s.h
@@ -0,0 +1,18 @@
+/*
+ * linux/sound/soc/ep93xx-i2s.h
+ * EP93xx I2S driver
+ *
+ * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.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.
+ *
+ */
+
+#ifndef _EP93XX_SND_SOC_I2S_H
+#define _EP93XX_SND_SOC_I2S_H
+
+extern struct snd_soc_dai ep93xx_i2s_dai;
+
+#endif /* _EP93XX_SND_SOC_I2S_H */
diff --git a/sound/soc/ep93xx/ep93xx-pcm.c b/sound/soc/ep93xx/ep93xx-pcm.c
new file mode 100644
index 0000000..4ba9384
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.c
@@ -0,0 +1,319 @@
+/*
+ * linux/sound/arm/ep93xx-pcm.c - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * Rewritten for the SoC audio subsystem (Based on PXA2xx code):
+ *   Copyright (c) 2008 Ryan Mallon <ryan@bluewatersys.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/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+
+#include <mach/dma.h>
+#include <mach/hardware.h>
+#include <mach/ep93xx-regs.h>
+
+#include "ep93xx-pcm.h"
+
+static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
+	.info			= (SNDRV_PCM_INFO_MMAP		|
+				   SNDRV_PCM_INFO_MMAP_VALID	|
+				   SNDRV_PCM_INFO_INTERLEAVED	|
+				   SNDRV_PCM_INFO_BLOCK_TRANSFER),
+				   
+	.rates			= SNDRV_PCM_RATE_8000_48000,
+	.rate_min		= SNDRV_PCM_RATE_8000,
+	.rate_max		= SNDRV_PCM_RATE_48000,
+	
+	.formats		= (SNDRV_PCM_FMTBIT_S16_LE |
+				   SNDRV_PCM_FMTBIT_S24_LE |
+				   SNDRV_PCM_FMTBIT_S32_LE),
+	
+	.buffer_bytes_max	= 131072,
+	.period_bytes_min	= 32,
+	.period_bytes_max	= 32768,
+	.periods_min		= 1,
+	.periods_max		= 32,
+	.fifo_size		= 32,
+};
+
+struct ep93xx_runtime_data
+{
+	struct ep93xx_dma_m2p_client	cl;
+	struct ep93xx_pcm_dma_params	*params;
+	int				pointer_bytes;
+	struct tasklet_struct		period_tasklet;
+	int				periods;
+	struct ep93xx_dma_buffer	buf[32];
+};
+
+static void ep93xx_pcm_period_elapsed(unsigned long data)
+{
+	struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
+	snd_pcm_period_elapsed(substream);
+}
+
+static void ep93xx_pcm_buffer_started(void *cookie,
+				      struct ep93xx_dma_buffer *buf)
+{
+}
+
+static void ep93xx_pcm_buffer_finished(void *cookie, 
+				       struct ep93xx_dma_buffer *buf, 
+				       int bytes, int error)
+{
+	struct snd_pcm_substream *substream = cookie;
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+	if (buf == rtd->buf + rtd->periods - 1)
+		rtd->pointer_bytes = 0;
+	else
+		rtd->pointer_bytes += buf->size;
+
+	if (!error) {
+		ep93xx_dma_m2p_submit_recursive(&rtd->cl, buf);
+		tasklet_schedule(&rtd->period_tasklet);
+	} else {
+		snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+	}
+}
+
+static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *soc_rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = soc_rtd->dai->cpu_dai;
+	struct ep93xx_pcm_dma_params *dma_params;
+	struct ep93xx_runtime_data *rtd;    
+	int ret;
+
+	dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
+	snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
+
+	rtd = kmalloc(sizeof(*rtd), GFP_KERNEL);
+	if (!rtd) 
+		return -ENOMEM;
+
+	memset(&rtd->period_tasklet, 0, sizeof(rtd->period_tasklet));
+	rtd->period_tasklet.func = ep93xx_pcm_period_elapsed;
+	rtd->period_tasklet.data = (unsigned long)substream;
+
+	rtd->cl.name = dma_params->name;
+	rtd->cl.flags = dma_params->dma_port | EP93XX_DMA_M2P_IGNORE_ERROR |
+		((substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
+		 EP93XX_DMA_M2P_TX : EP93XX_DMA_M2P_RX);
+	rtd->cl.cookie = substream;
+	rtd->cl.buffer_started = ep93xx_pcm_buffer_started;
+	rtd->cl.buffer_finished = ep93xx_pcm_buffer_finished;
+	ret = ep93xx_dma_m2p_client_register(&rtd->cl);
+	if (ret < 0) {
+		kfree(rtd);
+		return ret;
+	}
+	
+	substream->runtime->private_data = rtd;
+	return 0;
+}
+
+static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
+{
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+	ep93xx_dma_m2p_client_unregister(&rtd->cl);
+	kfree(rtd);
+	return 0;
+}
+
+static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
+				struct snd_pcm_hw_params *params)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ep93xx_runtime_data *rtd = runtime->private_data;
+	size_t totsize = params_buffer_bytes(params);
+	size_t period = params_period_bytes(params);
+	int i;
+
+	snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
+	runtime->dma_bytes = totsize;
+
+	rtd->periods = (totsize + period - 1) / period;
+	for (i = 0; i < rtd->periods; i++) {
+		rtd->buf[i].bus_addr = runtime->dma_addr + (i * period);
+		rtd->buf[i].size = period;
+		if ((i + 1) * period > totsize)
+			rtd->buf[i].size = totsize - (i * period);
+	}
+
+	return 0;
+}
+
+static int ep93xx_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+	snd_pcm_set_runtime_buffer(substream, NULL);
+	return 0;
+}
+
+static int ep93xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+	int ret;
+	int i;
+
+	ret = 0;
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		rtd->pointer_bytes = 0;
+		for (i = 0; i < rtd->periods; i++)
+			ep93xx_dma_m2p_submit(&rtd->cl, rtd->buf + i);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ep93xx_dma_m2p_flush(&rtd->cl);
+		break;
+
+	default:
+		ret = -EINVAL;
+		break;
+	}
+
+	return ret;
+}
+
+static snd_pcm_uframes_t ep93xx_pcm_pointer(struct snd_pcm_substream *substream)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct ep93xx_runtime_data *rtd = substream->runtime->private_data;
+
+	/* FIXME: implement this with sub-period granularity */
+	return bytes_to_frames(runtime, rtd->pointer_bytes);
+}
+
+static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
+			   struct vm_area_struct *vma)
+{
+	struct snd_pcm_runtime *runtime = substream->runtime;
+
+	return dma_mmap_writecombine(substream->pcm->card->dev, vma,
+				     runtime->dma_area,
+				     runtime->dma_addr,
+				     runtime->dma_bytes);
+}
+
+static struct snd_pcm_ops ep93xx_pcm_ops = {
+	.open		= ep93xx_pcm_open,
+	.close		= ep93xx_pcm_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= ep93xx_pcm_hw_params,
+	.hw_free	= ep93xx_pcm_hw_free,
+	.trigger	= ep93xx_pcm_trigger,
+	.pointer	= ep93xx_pcm_pointer,
+	.mmap		= ep93xx_pcm_mmap,
+};
+
+static int ep93xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
+{
+	struct snd_pcm_substream *substream = pcm->streams[stream].substream;
+	struct snd_dma_buffer *buf = &substream->dma_buffer;
+	size_t size = ep93xx_pcm_hardware.buffer_bytes_max;
+
+	buf->dev.type = SNDRV_DMA_TYPE_DEV;
+	buf->dev.dev = pcm->card->dev;
+	buf->private_data = NULL;
+	buf->area = dma_alloc_writecombine(pcm->card->dev, size,
+					   &buf->addr, GFP_KERNEL);
+	buf->bytes = size;
+
+	return (buf->area == NULL) ? -ENOMEM : 0;
+}
+
+static void ep93xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
+{
+	struct snd_pcm_substream *substream;
+	struct snd_dma_buffer *buf;
+	int stream;
+
+	for (stream = 0; stream < 2; stream++) {		
+		substream = pcm->streams[stream].substream;
+		if (!substream)
+			continue;
+		
+		buf = &substream->dma_buffer;
+		if (!buf->area)
+			continue;
+
+		dma_free_writecombine(pcm->card->dev, buf->bytes, buf->area,
+				      buf->addr);
+		buf->area = NULL;
+	}
+}
+
+static u64 ep93xx_pcm_dmamask = 0xffffffff;
+
+static int ep93xx_pcm_new(struct snd_card *card, struct snd_soc_dai *dai,
+			  struct snd_pcm *pcm)
+{
+	int ret = 0;
+
+	if (!card->dev->dma_mask)
+		card->dev->dma_mask = &ep93xx_pcm_dmamask;
+	if (!card->dev->coherent_dma_mask)
+		card->dev->coherent_dma_mask = 0xffffffff;
+
+	if (dai->playback.channels_min) {
+		ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+					SNDRV_PCM_STREAM_PLAYBACK);
+		if (ret)
+			return ret;
+	}
+
+	if (dai->capture.channels_min) {
+		ret = ep93xx_pcm_preallocate_dma_buffer(pcm,
+					SNDRV_PCM_STREAM_CAPTURE);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+struct snd_soc_platform ep93xx_soc_platform = {
+	.name		= "ep93xx-audio",
+	.pcm_ops	= &ep93xx_pcm_ops,
+	.pcm_new	= &ep93xx_pcm_new,
+	.pcm_free	= &ep93xx_pcm_free_dma_buffers,
+};
+EXPORT_SYMBOL_GPL(ep93xx_soc_platform);
+
+static int __init ep93xx_soc_platform_init(void)
+{
+	return snd_soc_register_platform(&ep93xx_soc_platform);
+}
+
+static void __exit ep93xx_soc_platform_exit(void)
+{
+	snd_soc_unregister_platform(&ep93xx_soc_platform);
+}
+
+module_init(ep93xx_soc_platform_init);
+module_exit(ep93xx_soc_platform_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("EP93xx ALSA PCM interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/ep93xx/ep93xx-pcm.h b/sound/soc/ep93xx/ep93xx-pcm.h
new file mode 100644
index 0000000..4ffdd3f
--- /dev/null
+++ b/sound/soc/ep93xx/ep93xx-pcm.h
@@ -0,0 +1,22 @@
+/*
+ * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
+ *
+ * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
+ * Copyright (C) 2006 Applied Data Systems
+ *
+ * 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.
+ */
+
+#ifndef _EP93XX_SND_SOC_PCM_H
+#define _EP93XX_SND_SOC_PCM_H
+
+struct ep93xx_pcm_dma_params {
+	char	*name;
+	int	dma_port;
+};
+
+extern struct snd_soc_platform ep93xx_soc_platform;
+
+#endif /* _EP93XX_SND_SOC_PCM_H */
-- 
1.5.5.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 3/3] Snapper cl15 audio support
  2010-06-04  5:11     ` Ryan Mallon
@ 2010-06-04  5:11       ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: john.cooper, alsa-devel, chasedouglas, Ryan Mallon, r&d4,
	hartleys, lrg, marshall, buytenh, dhuggins

Added Snapper CL15 i2s audio support

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
---
 arch/arm/mach-ep93xx/snappercl15.c |    1 +
 sound/soc/ep93xx/Kconfig           |    9 ++
 sound/soc/ep93xx/Makefile          |    3 +
 sound/soc/ep93xx/snappercl15.c     |  143 ++++++++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/ep93xx/snappercl15.c

diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index 51134b0..d4ca5cc 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -157,6 +157,7 @@ static void __init snappercl15_init_machine(void)
 	ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
 			    ARRAY_SIZE(snappercl15_i2c_data));
 	ep93xx_register_fb(&snappercl15_fb_info);
+	ep93xx_register_i2s(EP93XX_SYSCON_DEVCFG_I2SONAC97);
 	platform_device_register(&snappercl15_nand_device);
 }
 
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index ba66ac8..f617f56 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -7,3 +7,12 @@ config SND_EP93XX_SOC
 
 config SND_EP93XX_SOC_I2S
 	tristate
+
+config SND_EP93XX_SOC_SNAPPERCL15
+        tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
+        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+        select SND_EP93XX_SOC_I2S
+        select SND_SOC_TLV320AIC23
+        help
+          Say Y or M here if you want to add support for I2S audio on the
+          Bluewater Systems Snapper CL15 module.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
index 0239da3..272e60f 100644
--- a/sound/soc/ep93xx/Makefile
+++ b/sound/soc/ep93xx/Makefile
@@ -6,3 +6,6 @@ obj-$(CONFIG_SND_EP93XX_SOC)			+= snd-soc-ep93xx.o
 obj-$(CONFIG_SND_EP93XX_SOC_I2S)		+= snd-soc-ep93xx-i2s.o
 
 # EP93XX Machine Support
+snd-soc-snappercl15-objs			:= snappercl15.o
+
+obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15)	+= snd-soc-snappercl15.o
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
new file mode 100644
index 0000000..645a7fb
--- /dev/null
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -0,0 +1,143 @@
+/*
+ * snappercl15.c -- SoC audio for Bluewater Systems Snapper CL15 module
+ *
+ * Copyright (C) 2008 Bluewater Systems Ltd
+ * Author: Ryan Mallon <ryan@bluewatersys.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define CODEC_CLOCK 5644800
+
+static int snappercl15_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;
+	int err;
+
+	err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+				  SND_SOC_DAIFMT_NB_IF |
+				  SND_SOC_DAIFMT_CBS_CFS);
+
+	err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 
+				  SND_SOC_DAIFMT_NB_IF |		  
+				  SND_SOC_DAIFMT_CBS_CFS);
+	if (err)
+		return err;
+
+	err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, 
+				     SND_SOC_CLOCK_IN);
+	if (err)
+		return err;
+
+	err = snd_soc_dai_set_sysclk(cpu_dai, 0, CODEC_CLOCK, 
+				     SND_SOC_CLOCK_OUT);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static struct snd_soc_ops snappercl15_ops = {
+	.hw_params	= snappercl15_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	{"LLINEIN", NULL, "Line In"},
+	{"RLINEIN", NULL, "Line In"},
+
+	{"MICIN", NULL, "Mic Jack"},
+};
+
+static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+	return 0;
+}
+
+static struct snd_soc_dai_link snappercl15_dai = {
+	.name		= "tlv320aic23",
+	.stream_name	= "AIC23",
+	.cpu_dai	= &ep93xx_i2s_dai,
+	.codec_dai	= &tlv320aic23_dai,
+	.init		= snappercl15_tlv320aic23_init,
+	.ops		= &snappercl15_ops,
+};
+
+static struct snd_soc_card snd_soc_snappercl15 = {
+	.name		= "Snapper CL15",
+	.platform	= &ep93xx_soc_platform,
+	.dai_link	= &snappercl15_dai,
+	.num_links	= 1,
+};
+
+static struct snd_soc_device snappercl15_snd_devdata = {
+	.card		= &snd_soc_snappercl15,
+	.codec_dev	= &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *snappercl15_snd_device;
+
+static int __init snappercl15_init(void)
+{
+	int ret;
+
+	if (!machine_is_snapper_cl15())
+		return -ENODEV;
+
+	snappercl15_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!snappercl15_snd_device)
+		return -ENOMEM;
+	
+	platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
+	snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+	ret = platform_device_add(snappercl15_snd_device);
+	if (ret)
+		platform_device_put(snappercl15_snd_device);
+
+	return ret;
+}
+
+static void __exit snappercl15_exit(void)
+{
+	platform_device_unregister(snappercl15_snd_device);
+}
+
+module_init(snappercl15_init);
+module_exit(snappercl15_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
+MODULE_LICENSE("GPL");
+
-- 
1.5.5.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 3/3] Snapper cl15 audio support
@ 2010-06-04  5:11       ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-04  5:11 UTC (permalink / raw)
  To: linux-arm-kernel

Added Snapper CL15 i2s audio support

Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
---
 arch/arm/mach-ep93xx/snappercl15.c |    1 +
 sound/soc/ep93xx/Kconfig           |    9 ++
 sound/soc/ep93xx/Makefile          |    3 +
 sound/soc/ep93xx/snappercl15.c     |  143 ++++++++++++++++++++++++++++++++++++
 4 files changed, 156 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/ep93xx/snappercl15.c

diff --git a/arch/arm/mach-ep93xx/snappercl15.c b/arch/arm/mach-ep93xx/snappercl15.c
index 51134b0..d4ca5cc 100644
--- a/arch/arm/mach-ep93xx/snappercl15.c
+++ b/arch/arm/mach-ep93xx/snappercl15.c
@@ -157,6 +157,7 @@ static void __init snappercl15_init_machine(void)
 	ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
 			    ARRAY_SIZE(snappercl15_i2c_data));
 	ep93xx_register_fb(&snappercl15_fb_info);
+	ep93xx_register_i2s(EP93XX_SYSCON_DEVCFG_I2SONAC97);
 	platform_device_register(&snappercl15_nand_device);
 }
 
diff --git a/sound/soc/ep93xx/Kconfig b/sound/soc/ep93xx/Kconfig
index ba66ac8..f617f56 100644
--- a/sound/soc/ep93xx/Kconfig
+++ b/sound/soc/ep93xx/Kconfig
@@ -7,3 +7,12 @@ config SND_EP93XX_SOC
 
 config SND_EP93XX_SOC_I2S
 	tristate
+
+config SND_EP93XX_SOC_SNAPPERCL15
+        tristate "SoC Audio support for Bluewater Systems Snapper CL15 module"
+        depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15
+        select SND_EP93XX_SOC_I2S
+        select SND_SOC_TLV320AIC23
+        help
+          Say Y or M here if you want to add support for I2S audio on the
+          Bluewater Systems Snapper CL15 module.
diff --git a/sound/soc/ep93xx/Makefile b/sound/soc/ep93xx/Makefile
index 0239da3..272e60f 100644
--- a/sound/soc/ep93xx/Makefile
+++ b/sound/soc/ep93xx/Makefile
@@ -6,3 +6,6 @@ obj-$(CONFIG_SND_EP93XX_SOC)			+= snd-soc-ep93xx.o
 obj-$(CONFIG_SND_EP93XX_SOC_I2S)		+= snd-soc-ep93xx-i2s.o
 
 # EP93XX Machine Support
+snd-soc-snappercl15-objs			:= snappercl15.o
+
+obj-$(CONFIG_SND_EP93XX_SOC_SNAPPERCL15)	+= snd-soc-snappercl15.o
diff --git a/sound/soc/ep93xx/snappercl15.c b/sound/soc/ep93xx/snappercl15.c
new file mode 100644
index 0000000..645a7fb
--- /dev/null
+++ b/sound/soc/ep93xx/snappercl15.c
@@ -0,0 +1,143 @@
+/*
+ * snappercl15.c -- SoC audio for Bluewater Systems Snapper CL15 module
+ *
+ * Copyright (C) 2008 Bluewater Systems Ltd
+ * Author: Ryan Mallon <ryan@bluewatersys.com>
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <asm/mach-types.h>
+#include <mach/hardware.h>
+
+#include "../codecs/tlv320aic23.h"
+#include "ep93xx-pcm.h"
+#include "ep93xx-i2s.h"
+
+#define CODEC_CLOCK 5644800
+
+static int snappercl15_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;
+	int err;
+
+	err = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
+				  SND_SOC_DAIFMT_NB_IF |
+				  SND_SOC_DAIFMT_CBS_CFS);
+
+	err = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | 
+				  SND_SOC_DAIFMT_NB_IF |		  
+				  SND_SOC_DAIFMT_CBS_CFS);
+	if (err)
+		return err;
+
+	err = snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, 
+				     SND_SOC_CLOCK_IN);
+	if (err)
+		return err;
+
+	err = snd_soc_dai_set_sysclk(cpu_dai, 0, CODEC_CLOCK, 
+				     SND_SOC_CLOCK_OUT);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static struct snd_soc_ops snappercl15_ops = {
+	.hw_params	= snappercl15_hw_params,
+};
+
+static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphone Jack", NULL),
+	SND_SOC_DAPM_LINE("Line In", NULL),
+	SND_SOC_DAPM_MIC("Mic Jack", NULL),
+};
+
+static const struct snd_soc_dapm_route audio_map[] = {
+	{"Headphone Jack", NULL, "LHPOUT"},
+	{"Headphone Jack", NULL, "RHPOUT"},
+
+	{"LLINEIN", NULL, "Line In"},
+	{"RLINEIN", NULL, "Line In"},
+
+	{"MICIN", NULL, "Mic Jack"},
+};
+
+static int snappercl15_tlv320aic23_init(struct snd_soc_codec *codec)
+{
+	snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
+				  ARRAY_SIZE(tlv320aic23_dapm_widgets));
+
+	snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+	return 0;
+}
+
+static struct snd_soc_dai_link snappercl15_dai = {
+	.name		= "tlv320aic23",
+	.stream_name	= "AIC23",
+	.cpu_dai	= &ep93xx_i2s_dai,
+	.codec_dai	= &tlv320aic23_dai,
+	.init		= snappercl15_tlv320aic23_init,
+	.ops		= &snappercl15_ops,
+};
+
+static struct snd_soc_card snd_soc_snappercl15 = {
+	.name		= "Snapper CL15",
+	.platform	= &ep93xx_soc_platform,
+	.dai_link	= &snappercl15_dai,
+	.num_links	= 1,
+};
+
+static struct snd_soc_device snappercl15_snd_devdata = {
+	.card		= &snd_soc_snappercl15,
+	.codec_dev	= &soc_codec_dev_tlv320aic23,
+};
+
+static struct platform_device *snappercl15_snd_device;
+
+static int __init snappercl15_init(void)
+{
+	int ret;
+
+	if (!machine_is_snapper_cl15())
+		return -ENODEV;
+
+	snappercl15_snd_device = platform_device_alloc("soc-audio", -1);
+	if (!snappercl15_snd_device)
+		return -ENOMEM;
+	
+	platform_set_drvdata(snappercl15_snd_device, &snappercl15_snd_devdata);
+	snappercl15_snd_devdata.dev = &snappercl15_snd_device->dev;
+	ret = platform_device_add(snappercl15_snd_device);
+	if (ret)
+		platform_device_put(snappercl15_snd_device);
+
+	return ret;
+}
+
+static void __exit snappercl15_exit(void)
+{
+	platform_device_unregister(snappercl15_snd_device);
+}
+
+module_init(snappercl15_init);
+module_exit(snappercl15_exit);
+
+MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>");
+MODULE_DESCRIPTION("ALSA SoC Snapper CL15");
+MODULE_LICENSE("GPL");
+
-- 
1.5.5.1

^ permalink raw reply related	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 0/3] ep93xx i2s audio
  2010-06-04  5:11 ` Ryan Mallon
@ 2010-06-07 12:45   ` Liam Girdwood
  -1 siblings, 0 replies; 24+ messages in thread
From: Liam Girdwood @ 2010-06-07 12:45 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: john.cooper, alsa-devel, chasedouglas, buytenh, r&d4,
	hartleys, marshall, linux-arm-kernel, dhuggins

On Fri, 2010-06-04 at 17:11 +1200, Ryan Mallon wrote:
> The following patch series adds support for i2s audio on the ep93xx,
> with the Snapper CL15 used as an example implementation.
> 
> This version fixes a number of things from the previous round:
>  - Removed unused #defines
>  - Set symmetric rates for the cpu dai
>  - Fixed the sdiv/lrdiv calculation loop
>  - Moved the cpu dai registration
>  - Removed empty ep93xx_pcm_prepare callback
>  - Fixed enable/disable when both capture and playback are running
>  
> Capture still does not work. The dma is running, but the captured data
> is all zeros (tested used arecord and loopback). I have a 2.6.20
> kernel with ep93xx i2s audio working an capture works there on the
> same hardware. I have spent sometime looking into this, but can't see
> the problem. Would appreciate if someone can lend some insight as to
> what I have done wrong.
> 
> Ryan Mallon (3):
>   ep93xx i2s core support
>   ep93xx i2s audio driver
>   Snapper cl15 audio support

All

Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [alsa-devel] [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-07 12:45   ` Liam Girdwood
  0 siblings, 0 replies; 24+ messages in thread
From: Liam Girdwood @ 2010-06-07 12:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, 2010-06-04 at 17:11 +1200, Ryan Mallon wrote:
> The following patch series adds support for i2s audio on the ep93xx,
> with the Snapper CL15 used as an example implementation.
> 
> This version fixes a number of things from the previous round:
>  - Removed unused #defines
>  - Set symmetric rates for the cpu dai
>  - Fixed the sdiv/lrdiv calculation loop
>  - Moved the cpu dai registration
>  - Removed empty ep93xx_pcm_prepare callback
>  - Fixed enable/disable when both capture and playback are running
>  
> Capture still does not work. The dma is running, but the captured data
> is all zeros (tested used arecord and loopback). I have a 2.6.20
> kernel with ep93xx i2s audio working an capture works there on the
> same hardware. I have spent sometime looking into this, but can't see
> the problem. Would appreciate if someone can lend some insight as to
> what I have done wrong.
> 
> Ryan Mallon (3):
>   ep93xx i2s core support
>   ep93xx i2s audio driver
>   Snapper cl15 audio support

All

Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>
-- 
Freelance Developer, SlimLogic Ltd
ASoC and Voltage Regulator Maintainer.
http://www.slimlogic.co.uk

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 0/3] ep93xx i2s audio
  2010-06-04  5:11 ` Ryan Mallon
@ 2010-06-07 13:26   ` Mark Brown
  -1 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2010-06-07 13:26 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: john.cooper, alsa-devel, chasedouglas, buytenh, r&d4,
	hartleys, dhuggins, marshall, linux-arm-kernel, lrg

On Fri, Jun 04, 2010 at 05:11:22PM +1200, Ryan Mallon wrote:
> The following patch series adds support for i2s audio on the ep93xx,
> with the Snapper CL15 used as an example implementation.

Please do remember to CC maintainers on patches.  I've had to remind you
about this before, it's really not helpful to drop the people you're
expecting to review the patches - it'll tend to delay things or lead to
the patches getting missed.  From a code point of view this looks fine
but we'll need an arch maintainer to sign off on that bit of the code.
I've applied 2/3 since that has no arch/arm elements.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [alsa-devel] [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-07 13:26   ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2010-06-07 13:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Jun 04, 2010 at 05:11:22PM +1200, Ryan Mallon wrote:
> The following patch series adds support for i2s audio on the ep93xx,
> with the Snapper CL15 used as an example implementation.

Please do remember to CC maintainers on patches.  I've had to remind you
about this before, it's really not helpful to drop the people you're
expecting to review the patches - it'll tend to delay things or lead to
the patches getting missed.  From a code point of view this looks fine
but we'll need an arch maintainer to sign off on that bit of the code.
I've applied 2/3 since that has no arch/arm elements.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 0/3] ep93xx i2s audio
  2010-06-07 13:26   ` [alsa-devel] " Mark Brown
@ 2010-06-07 20:35     ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-07 20:35 UTC (permalink / raw)
  To: Mark Brown
  Cc: john.cooper, alsa-devel, chasedouglas, buytenh, r&d4,
	hartleys, dhuggins, marshall, linux-arm-kernel, lrg

Mark Brown wrote:
> On Fri, Jun 04, 2010 at 05:11:22PM +1200, Ryan Mallon wrote:
>> The following patch series adds support for i2s audio on the ep93xx,
>> with the Snapper CL15 used as an example implementation.
> 
> Please do remember to CC maintainers on patches.  I've had to remind you
> about this before, it's really not helpful to drop the people you're
> expecting to review the patches - it'll tend to delay things or lead to
> the patches getting missed.  From a code point of view this looks fine
> but we'll need an arch maintainer to sign off on that bit of the code.
> I've applied 2/3 since that has no arch/arm elements.

Sorry, again. I copied the CC list from the last series I sent. I must
have missed you accidentally.

Thanks for picking this up.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [alsa-devel] [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-07 20:35     ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-07 20:35 UTC (permalink / raw)
  To: linux-arm-kernel

Mark Brown wrote:
> On Fri, Jun 04, 2010 at 05:11:22PM +1200, Ryan Mallon wrote:
>> The following patch series adds support for i2s audio on the ep93xx,
>> with the Snapper CL15 used as an example implementation.
> 
> Please do remember to CC maintainers on patches.  I've had to remind you
> about this before, it's really not helpful to drop the people you're
> expecting to review the patches - it'll tend to delay things or lead to
> the patches getting missed.  From a code point of view this looks fine
> but we'll need an arch maintainer to sign off on that bit of the code.
> I've applied 2/3 since that has no arch/arm elements.

Sorry, again. I copied the CC list from the last series I sent. I must
have missed you accidentally.

Thanks for picking this up.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 0/3] ep93xx i2s audio
  2010-06-07 12:45   ` [alsa-devel] " Liam Girdwood
@ 2010-06-07 20:38     ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-07 20:38 UTC (permalink / raw)
  To: Liam Girdwood, Russell King, Mark Brown
  Cc: john.cooper, alsa-devel, chasedouglas, buytenh, r&d4,
	hartleys, marshall, linux-arm-kernel, dhuggins

Liam Girdwood wrote:
> On Fri, 2010-06-04 at 17:11 +1200, Ryan Mallon wrote:
>> The following patch series adds support for i2s audio on the ep93xx,
>> with the Snapper CL15 used as an example implementation.
>>
>> This version fixes a number of things from the previous round:
>>  - Removed unused #defines
>>  - Set symmetric rates for the cpu dai
>>  - Fixed the sdiv/lrdiv calculation loop
>>  - Moved the cpu dai registration
>>  - Removed empty ep93xx_pcm_prepare callback
>>  - Fixed enable/disable when both capture and playback are running
>>  
>> Capture still does not work. The dma is running, but the captured data
>> is all zeros (tested used arecord and loopback). I have a 2.6.20
>> kernel with ep93xx i2s audio working an capture works there on the
>> same hardware. I have spent sometime looking into this, but can't see
>> the problem. Would appreciate if someone can lend some insight as to
>> what I have done wrong.
>>
>> Ryan Mallon (3):
>>   ep93xx i2s core support
>>   ep93xx i2s audio driver
>>   Snapper cl15 audio support
> 
> All
> 
> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>

Russell, Mark has picked up patch 2/3 via the alsa tree. Should I submit
1/3 and 3/3 via the arm patch system with Liam's ack?

Thanks,
~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [alsa-devel] [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-07 20:38     ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-07 20:38 UTC (permalink / raw)
  To: linux-arm-kernel

Liam Girdwood wrote:
> On Fri, 2010-06-04 at 17:11 +1200, Ryan Mallon wrote:
>> The following patch series adds support for i2s audio on the ep93xx,
>> with the Snapper CL15 used as an example implementation.
>>
>> This version fixes a number of things from the previous round:
>>  - Removed unused #defines
>>  - Set symmetric rates for the cpu dai
>>  - Fixed the sdiv/lrdiv calculation loop
>>  - Moved the cpu dai registration
>>  - Removed empty ep93xx_pcm_prepare callback
>>  - Fixed enable/disable when both capture and playback are running
>>  
>> Capture still does not work. The dma is running, but the captured data
>> is all zeros (tested used arecord and loopback). I have a 2.6.20
>> kernel with ep93xx i2s audio working an capture works there on the
>> same hardware. I have spent sometime looking into this, but can't see
>> the problem. Would appreciate if someone can lend some insight as to
>> what I have done wrong.
>>
>> Ryan Mallon (3):
>>   ep93xx i2s core support
>>   ep93xx i2s audio driver
>>   Snapper cl15 audio support
> 
> All
> 
> Acked-by: Liam Girdwood <lrg@slimlogic.co.uk>

Russell, Mark has picked up patch 2/3 via the alsa tree. Should I submit
1/3 and 3/3 via the arm patch system with Liam's ack?

Thanks,
~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* RE: [RFC PATCH v3 1/3] ep93xx i2s core support
  2010-06-04  5:11   ` Ryan Mallon
@ 2010-06-07 21:55     ` H Hartley Sweeten
  -1 siblings, 0 replies; 24+ messages in thread
From: H Hartley Sweeten @ 2010-06-07 21:55 UTC (permalink / raw)
  To: Ryan Mallon, linux-arm-kernel
  Cc: john.cooper, alsa-devel, chasedouglas, r&d4, lrg, marshall,
	buytenh, dhuggins

On Thursday, June 03, 2010 10:11 PM, Ryan Mallon wrote:
> Add ep93xx core support for i2s audio
> 
> Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
> ---
>  arch/arm/mach-ep93xx/clock.c                    |   69 ++++++++++++++++++++++-
>  arch/arm/mach-ep93xx/core.c                     |   31 ++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +++
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
>  4 files changed, 110 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 5f80092..503d430 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
>  
>  static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
>  static int set_div_rate(struct clk *clk, unsigned long rate);
> -
> +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
> +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
>  
>  static struct clk clk_xtali = {
>  	.rate		= EP93XX_EXT_CLK_RATE,
> @@ -108,6 +109,31 @@ static struct clk clk_video = {
>  	.set_rate	= set_div_rate,
>  };
>  
> +static struct clk clk_i2s_mclk = {
> +	.sw_locked	= 1,
> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
> +	.enable_mask	= (EP93XX_SYSCON_CLKDIV_ENABLE  |
> +			   EP93XX_SYSCON_I2SCLKDIV_SPOL |
> +			   EP93XX_SYSCON_I2SCLKDIV_ORIDE),

Setting the SPOL and ORIDE bits here might cause problems in the future.
Granted, your i2s driver is currently the only user so its probably ok
for now.

But, you might want to move the setting of those two bits along with the
SLAVE and DROP bits to the core registration function.  The clock support
should only be enabling/disabling and setting the rates for the clocks.

> +	.set_rate	= set_div_rate,

By calling the set_div_rate routine your only updating the master clock
rate.  Should the new rate be pushed down to the children?  Actually the
new rates for the children will be established automatically when the
master clock rate is changed.  But a clk_get_rate for the children will
return an incorrect value.  Maybe just add a get_rate method for the
children?

> +};
> +
> +static struct clk clk_i2s_sclk = {
> +	.sw_locked	= 1,
> +	.parent		= &clk_i2s_mclk,
> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
> +	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
> +	.set_rate	= set_i2s_sclk_rate,
> +};
> +
> +static struct clk clk_i2s_lrclk = {
> +	.sw_locked	= 1,
> +	.parent		= &clk_i2s_sclk,
> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
> +	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
> +	.set_rate	= set_i2s_lrclk_rate,
> +};
> +
>  /* DMA Clocks */
>  static struct clk clk_m2p0 = {
>  	.parent		= &clk_h,
> @@ -186,6 +212,9 @@ static struct clk_lookup clocks[] = {
>  	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
>  	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
>  	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
> +	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),
> +	INIT_CK("ep93xx-i2s",		"sclk",		&clk_i2s_sclk),
> +	INIT_CK("ep93xx-i2s",		"lrclk",	&clk_i2s_lrclk),
>  	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
>  	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
>  	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
> @@ -396,6 +425,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
>  	return 0;
>  }
>  
> +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
> +{
> +	unsigned val = __raw_readl(clk->enable_reg);
> +
> +	if (rate == clk_i2s_mclk.rate / 2)
> +		ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, 
> +					     clk->enable_reg);
> +	else if (rate == clk_i2s_mclk.rate / 4)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, 
> +					     clk->enable_reg);
> +	else
> +		return -EINVAL;
> +
> +	clk_i2s_sclk.rate = rate;
> +	return 0;
> +}
> +
> +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
> +{
> +	unsigned val = __raw_readl(clk->enable_reg) & 
> +		~EP93XX_I2SCLKDIV_LRDIV_MASK;
> +	
> +	if (rate == clk_i2s_sclk.rate / 32)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
> +					     clk->enable_reg);
> +	else if (rate == clk_i2s_sclk.rate / 64)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
> +					     clk->enable_reg);
> +	else if (rate == clk_i2s_sclk.rate / 128)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
> +					     clk->enable_reg);
> +	else
> +		return -EINVAL;
> +
> +	clk_i2s_lrclk.rate = rate;
> +	return 0;
> +}
> +
>  int clk_set_rate(struct clk *clk, unsigned long rate)
>  {
>  	if (clk->set_rate)
> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..c04fd6f 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -617,6 +617,37 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
>  }
>  EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
>  
> +/*************************************************************************
> + * EP93xx I2S audio peripheral handling
> + *************************************************************************/
> +static struct resource ep93xx_i2s_resource[] = {
> +	{
> +		.start	= EP93XX_I2S_PHYS_BASE,
> +		.end	= EP93XX_I2S_PHYS_BASE + 0x100 - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +};
> +
> +static struct platform_device ep93xx_i2s_device = {
> +	.name		= "ep93xx-i2s",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(ep93xx_i2s_resource),
> +	.resource	= ep93xx_i2s_resource,
> +};
> +
> +void __init ep93xx_register_i2s(unsigned pins)
> +{
> +	if (pins != EP93XX_SYSCON_DEVCFG_I2SONSSP &&
> +	    pins != EP93XX_SYSCON_DEVCFG_I2SONAC97) {
> +		pr_err("Invalid I2S pin configuration - not registering\n");
> +		return;
> +	}
> +
> +	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP |
> +				 EP93XX_SYSCON_DEVCFG_I2SONAC97);
> +	ep93xx_devcfg_set_bits(pins);
> +	platform_device_register(&ep93xx_i2s_device);
> +}
>  
>  extern void ep93xx_gpio_init(void);
>  
> diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> index 93e2ecc..3fbb095 100644
> --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> @@ -93,6 +93,7 @@
>  /* APB peripherals */
>  #define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
>  
> +#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
>  #define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
>  
>  #define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
> @@ -193,6 +194,15 @@
>  #define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
>  #define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
>  #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
> +#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
> +#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
> +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
> +#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
> +#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
> +#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV128 	(2 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV_MASK 	(3 << 17)
>  #define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
>  #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
>  #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index c6dc14d..9252adf 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -43,6 +43,7 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
>  void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
>  int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
>  void ep93xx_keypad_release_gpio(struct platform_device *pdev);
> +void ep93xx_register_i2s(unsigned pins);
>  
>  void ep93xx_init_devices(void);
>  extern struct sys_timer ep93xx_timer;

Other than the comments above I'm ok with this.

Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 1/3] ep93xx i2s core support
@ 2010-06-07 21:55     ` H Hartley Sweeten
  0 siblings, 0 replies; 24+ messages in thread
From: H Hartley Sweeten @ 2010-06-07 21:55 UTC (permalink / raw)
  To: linux-arm-kernel

On Thursday, June 03, 2010 10:11 PM, Ryan Mallon wrote:
> Add ep93xx core support for i2s audio
> 
> Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
> ---
>  arch/arm/mach-ep93xx/clock.c                    |   69 ++++++++++++++++++++++-
>  arch/arm/mach-ep93xx/core.c                     |   31 ++++++++++
>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +++
>  arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
>  4 files changed, 110 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
> index 5f80092..503d430 100644
> --- a/arch/arm/mach-ep93xx/clock.c
> +++ b/arch/arm/mach-ep93xx/clock.c
> @@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
>  
>  static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
>  static int set_div_rate(struct clk *clk, unsigned long rate);
> -
> +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
> +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
>  
>  static struct clk clk_xtali = {
>  	.rate		= EP93XX_EXT_CLK_RATE,
> @@ -108,6 +109,31 @@ static struct clk clk_video = {
>  	.set_rate	= set_div_rate,
>  };
>  
> +static struct clk clk_i2s_mclk = {
> +	.sw_locked	= 1,
> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
> +	.enable_mask	= (EP93XX_SYSCON_CLKDIV_ENABLE  |
> +			   EP93XX_SYSCON_I2SCLKDIV_SPOL |
> +			   EP93XX_SYSCON_I2SCLKDIV_ORIDE),

Setting the SPOL and ORIDE bits here might cause problems in the future.
Granted, your i2s driver is currently the only user so its probably ok
for now.

But, you might want to move the setting of those two bits along with the
SLAVE and DROP bits to the core registration function.  The clock support
should only be enabling/disabling and setting the rates for the clocks.

> +	.set_rate	= set_div_rate,

By calling the set_div_rate routine your only updating the master clock
rate.  Should the new rate be pushed down to the children?  Actually the
new rates for the children will be established automatically when the
master clock rate is changed.  But a clk_get_rate for the children will
return an incorrect value.  Maybe just add a get_rate method for the
children?

> +};
> +
> +static struct clk clk_i2s_sclk = {
> +	.sw_locked	= 1,
> +	.parent		= &clk_i2s_mclk,
> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
> +	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
> +	.set_rate	= set_i2s_sclk_rate,
> +};
> +
> +static struct clk clk_i2s_lrclk = {
> +	.sw_locked	= 1,
> +	.parent		= &clk_i2s_sclk,
> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
> +	.enable_mask	= EP93XX_SYSCON_I2SCLKDIV_SENA,
> +	.set_rate	= set_i2s_lrclk_rate,
> +};
> +
>  /* DMA Clocks */
>  static struct clk clk_m2p0 = {
>  	.parent		= &clk_h,
> @@ -186,6 +212,9 @@ static struct clk_lookup clocks[] = {
>  	INIT_CK("ep93xx-ohci",		NULL,		&clk_usb_host),
>  	INIT_CK("ep93xx-keypad",	NULL,		&clk_keypad),
>  	INIT_CK("ep93xx-fb",		NULL,		&clk_video),
> +	INIT_CK("ep93xx-i2s",		"mclk",		&clk_i2s_mclk),
> +	INIT_CK("ep93xx-i2s",		"sclk",		&clk_i2s_sclk),
> +	INIT_CK("ep93xx-i2s",		"lrclk",	&clk_i2s_lrclk),
>  	INIT_CK(NULL,			"pwm_clk",	&clk_pwm),
>  	INIT_CK(NULL,			"m2p0",		&clk_m2p0),
>  	INIT_CK(NULL,			"m2p1",		&clk_m2p1),
> @@ -396,6 +425,44 @@ static int set_div_rate(struct clk *clk, unsigned long rate)
>  	return 0;
>  }
>  
> +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate)
> +{
> +	unsigned val = __raw_readl(clk->enable_reg);
> +
> +	if (rate == clk_i2s_mclk.rate / 2)
> +		ep93xx_syscon_swlocked_write(val & ~EP93XX_I2SCLKDIV_SDIV, 
> +					     clk->enable_reg);
> +	else if (rate == clk_i2s_mclk.rate / 4)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_SDIV, 
> +					     clk->enable_reg);
> +	else
> +		return -EINVAL;
> +
> +	clk_i2s_sclk.rate = rate;
> +	return 0;
> +}
> +
> +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate)
> +{
> +	unsigned val = __raw_readl(clk->enable_reg) & 
> +		~EP93XX_I2SCLKDIV_LRDIV_MASK;
> +	
> +	if (rate == clk_i2s_sclk.rate / 32)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV32,
> +					     clk->enable_reg);
> +	else if (rate == clk_i2s_sclk.rate / 64)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV64,
> +					     clk->enable_reg);
> +	else if (rate == clk_i2s_sclk.rate / 128)
> +		ep93xx_syscon_swlocked_write(val | EP93XX_I2SCLKDIV_LRDIV128,
> +					     clk->enable_reg);
> +	else
> +		return -EINVAL;
> +
> +	clk_i2s_lrclk.rate = rate;
> +	return 0;
> +}
> +
>  int clk_set_rate(struct clk *clk, unsigned long rate)
>  {
>  	if (clk->set_rate)
> diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c
> index 90fb591..c04fd6f 100644
> --- a/arch/arm/mach-ep93xx/core.c
> +++ b/arch/arm/mach-ep93xx/core.c
> @@ -617,6 +617,37 @@ void ep93xx_keypad_release_gpio(struct platform_device *pdev)
>  }
>  EXPORT_SYMBOL(ep93xx_keypad_release_gpio);
>  
> +/*************************************************************************
> + * EP93xx I2S audio peripheral handling
> + *************************************************************************/
> +static struct resource ep93xx_i2s_resource[] = {
> +	{
> +		.start	= EP93XX_I2S_PHYS_BASE,
> +		.end	= EP93XX_I2S_PHYS_BASE + 0x100 - 1,
> +		.flags	= IORESOURCE_MEM,
> +	},
> +};
> +
> +static struct platform_device ep93xx_i2s_device = {
> +	.name		= "ep93xx-i2s",
> +	.id		= -1,
> +	.num_resources	= ARRAY_SIZE(ep93xx_i2s_resource),
> +	.resource	= ep93xx_i2s_resource,
> +};
> +
> +void __init ep93xx_register_i2s(unsigned pins)
> +{
> +	if (pins != EP93XX_SYSCON_DEVCFG_I2SONSSP &&
> +	    pins != EP93XX_SYSCON_DEVCFG_I2SONAC97) {
> +		pr_err("Invalid I2S pin configuration - not registering\n");
> +		return;
> +	}
> +
> +	ep93xx_devcfg_clear_bits(EP93XX_SYSCON_DEVCFG_I2SONSSP |
> +				 EP93XX_SYSCON_DEVCFG_I2SONAC97);
> +	ep93xx_devcfg_set_bits(pins);
> +	platform_device_register(&ep93xx_i2s_device);
> +}
>  
>  extern void ep93xx_gpio_init(void);
>  
> diff --git a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> index 93e2ecc..3fbb095 100644
> --- a/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> +++ b/arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h
> @@ -93,6 +93,7 @@
>  /* APB peripherals */
>  #define EP93XX_TIMER_BASE		EP93XX_APB_IOMEM(0x00010000)
>  
> +#define EP93XX_I2S_PHYS_BASE		EP93XX_APB_PHYS(0x00020000)
>  #define EP93XX_I2S_BASE			EP93XX_APB_IOMEM(0x00020000)
>  
>  #define EP93XX_SECURITY_BASE		EP93XX_APB_IOMEM(0x00030000)
> @@ -193,6 +194,15 @@
>  #define EP93XX_SYSCON_CLKDIV_ESEL	(1<<14)
>  #define EP93XX_SYSCON_CLKDIV_PSEL	(1<<13)
>  #define EP93XX_SYSCON_CLKDIV_PDIV_SHIFT	8
> +#define EP93XX_SYSCON_I2SCLKDIV		EP93XX_SYSCON_REG(0x8c)
> +#define EP93XX_SYSCON_I2SCLKDIV_SENA	(1<<31)
> +#define EP93XX_SYSCON_I2SCLKDIV_ORIDE   (1<<29)
> +#define EP93XX_SYSCON_I2SCLKDIV_SPOL	(1<<19)
> +#define EP93XX_I2SCLKDIV_SDIV		(1 << 16)
> +#define EP93XX_I2SCLKDIV_LRDIV32	(0 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV64	(1 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV128 	(2 << 17)
> +#define EP93XX_I2SCLKDIV_LRDIV_MASK 	(3 << 17)
>  #define EP93XX_SYSCON_KEYTCHCLKDIV	EP93XX_SYSCON_REG(0x90)
>  #define EP93XX_SYSCON_KEYTCHCLKDIV_TSEN	(1<<31)
>  #define EP93XX_SYSCON_KEYTCHCLKDIV_ADIV	(1<<16)
> diff --git a/arch/arm/mach-ep93xx/include/mach/platform.h b/arch/arm/mach-ep93xx/include/mach/platform.h
> index c6dc14d..9252adf 100644
> --- a/arch/arm/mach-ep93xx/include/mach/platform.h
> +++ b/arch/arm/mach-ep93xx/include/mach/platform.h
> @@ -43,6 +43,7 @@ void ep93xx_pwm_release_gpio(struct platform_device *pdev);
>  void ep93xx_register_keypad(struct ep93xx_keypad_platform_data *data);
>  int ep93xx_keypad_acquire_gpio(struct platform_device *pdev);
>  void ep93xx_keypad_release_gpio(struct platform_device *pdev);
> +void ep93xx_register_i2s(unsigned pins);
>  
>  void ep93xx_init_devices(void);
>  extern struct sys_timer ep93xx_timer;

Other than the comments above I'm ok with this.

Acked-by: H Hartley Sweeten <hsweeten@visionengravers.com>

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 1/3] ep93xx i2s core support
  2010-06-07 21:55     ` H Hartley Sweeten
@ 2010-06-07 22:21       ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-07 22:21 UTC (permalink / raw)
  To: H Hartley Sweeten
  Cc: john.cooper, alsa-devel, chasedouglas, buytenh, r&d4, lrg,
	marshall, linux-arm-kernel, dhuggins

H Hartley Sweeten wrote:
> On Thursday, June 03, 2010 10:11 PM, Ryan Mallon wrote:
>> Add ep93xx core support for i2s audio
>>
>> Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
>> ---
>>  arch/arm/mach-ep93xx/clock.c                    |   69 ++++++++++++++++++++++-
>>  arch/arm/mach-ep93xx/core.c                     |   31 ++++++++++
>>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +++
>>  arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
>>  4 files changed, 110 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
>> index 5f80092..503d430 100644
>> --- a/arch/arm/mach-ep93xx/clock.c
>> +++ b/arch/arm/mach-ep93xx/clock.c
>> @@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
>>  
>>  static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
>>  static int set_div_rate(struct clk *clk, unsigned long rate);
>> -
>> +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
>> +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
>>  
>>  static struct clk clk_xtali = {
>>  	.rate		= EP93XX_EXT_CLK_RATE,
>> @@ -108,6 +109,31 @@ static struct clk clk_video = {
>>  	.set_rate	= set_div_rate,
>>  };
>>  
>> +static struct clk clk_i2s_mclk = {
>> +	.sw_locked	= 1,
>> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
>> +	.enable_mask	= (EP93XX_SYSCON_CLKDIV_ENABLE  |
>> +			   EP93XX_SYSCON_I2SCLKDIV_SPOL |
>> +			   EP93XX_SYSCON_I2SCLKDIV_ORIDE),
> 
> Setting the SPOL and ORIDE bits here might cause problems in the future.
> Granted, your i2s driver is currently the only user so its probably ok
> for now.
> 
> But, you might want to move the setting of those two bits along with the
> SLAVE and DROP bits to the core registration function.  The clock support
> should only be enabling/disabling and setting the rates for the clocks.

Okay, sounds sensible. Possibly I should add acquire/release functions
in addition to the register, something like:

void __init ep93xx_register_i2s(void)
{
	platform_device_register(&ep93xx_i2s_device);
}

int ep93xx_i2s_acquire(unsigned pins, int override, int sclk_falling)
{
	unsigned set_bits = pins,
		 clear_bits = EP93XX_SYSCON_DEVCFG_I2SONSSP |
			      EP93XX_SYSCON_DEVCFG_I2SONAC97;

	if (pins != EP93XX_SYSCON_DEVCFG_I2SONSSP &&
	    pins != EP93XX_SYSCON_DEVCFG_I2SONAC97)
		return -EINVAL;

	if (override)
		set_bits |= EP93XX_SYSCON_I2SCLKDIV_ORIDE;
	else
		clear_bits |= EP93XX_SYSCON_I2SCLKDIV_ORIDE;

	if (sclk_falling)
		set_bits |= EP93XX_SYSCON_I2SCLKDIV_SPOL;
	else
		clear_bits |= EP93XX_SYSCON_I2SCLKDIV_SPOL;

	ep93xx_devcfg_clear_bits(clear_bits);
	ep93xx_devcfg_set_bits(set_bits);
	return 0;
}

>> +	.set_rate	= set_div_rate,
> 
> By calling the set_div_rate routine your only updating the master clock
> rate.  Should the new rate be pushed down to the children?  Actually the
> new rates for the children will be established automatically when the
> master clock rate is changed.  But a clk_get_rate for the children will
> return an incorrect value.  Maybe just add a get_rate method for the
> children?

The code basically assumes that the clocks will always be set in the
order: mclk, sclk, lrclk. Since the i2s driver is the only user, this
should be a valid assumption. Possibly a comment should be put in to
state that this assumption is made.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [RFC PATCH v3 1/3] ep93xx i2s core support
@ 2010-06-07 22:21       ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-07 22:21 UTC (permalink / raw)
  To: linux-arm-kernel

H Hartley Sweeten wrote:
> On Thursday, June 03, 2010 10:11 PM, Ryan Mallon wrote:
>> Add ep93xx core support for i2s audio
>>
>> Signed-off-by: Ryan Mallon <ryan@bluewatersys.com>
>> ---
>>  arch/arm/mach-ep93xx/clock.c                    |   69 ++++++++++++++++++++++-
>>  arch/arm/mach-ep93xx/core.c                     |   31 ++++++++++
>>  arch/arm/mach-ep93xx/include/mach/ep93xx-regs.h |   10 +++
>>  arch/arm/mach-ep93xx/include/mach/platform.h    |    1 +
>>  4 files changed, 110 insertions(+), 1 deletions(-)
>>
>> diff --git a/arch/arm/mach-ep93xx/clock.c b/arch/arm/mach-ep93xx/clock.c
>> index 5f80092..503d430 100644
>> --- a/arch/arm/mach-ep93xx/clock.c
>> +++ b/arch/arm/mach-ep93xx/clock.c
>> @@ -43,7 +43,8 @@ static unsigned long get_uart_rate(struct clk *clk);
>>  
>>  static int set_keytchclk_rate(struct clk *clk, unsigned long rate);
>>  static int set_div_rate(struct clk *clk, unsigned long rate);
>> -
>> +static int set_i2s_sclk_rate(struct clk *clk, unsigned long rate);
>> +static int set_i2s_lrclk_rate(struct clk *clk, unsigned long rate);
>>  
>>  static struct clk clk_xtali = {
>>  	.rate		= EP93XX_EXT_CLK_RATE,
>> @@ -108,6 +109,31 @@ static struct clk clk_video = {
>>  	.set_rate	= set_div_rate,
>>  };
>>  
>> +static struct clk clk_i2s_mclk = {
>> +	.sw_locked	= 1,
>> +	.enable_reg	= EP93XX_SYSCON_I2SCLKDIV,
>> +	.enable_mask	= (EP93XX_SYSCON_CLKDIV_ENABLE  |
>> +			   EP93XX_SYSCON_I2SCLKDIV_SPOL |
>> +			   EP93XX_SYSCON_I2SCLKDIV_ORIDE),
> 
> Setting the SPOL and ORIDE bits here might cause problems in the future.
> Granted, your i2s driver is currently the only user so its probably ok
> for now.
> 
> But, you might want to move the setting of those two bits along with the
> SLAVE and DROP bits to the core registration function.  The clock support
> should only be enabling/disabling and setting the rates for the clocks.

Okay, sounds sensible. Possibly I should add acquire/release functions
in addition to the register, something like:

void __init ep93xx_register_i2s(void)
{
	platform_device_register(&ep93xx_i2s_device);
}

int ep93xx_i2s_acquire(unsigned pins, int override, int sclk_falling)
{
	unsigned set_bits = pins,
		 clear_bits = EP93XX_SYSCON_DEVCFG_I2SONSSP |
			      EP93XX_SYSCON_DEVCFG_I2SONAC97;

	if (pins != EP93XX_SYSCON_DEVCFG_I2SONSSP &&
	    pins != EP93XX_SYSCON_DEVCFG_I2SONAC97)
		return -EINVAL;

	if (override)
		set_bits |= EP93XX_SYSCON_I2SCLKDIV_ORIDE;
	else
		clear_bits |= EP93XX_SYSCON_I2SCLKDIV_ORIDE;

	if (sclk_falling)
		set_bits |= EP93XX_SYSCON_I2SCLKDIV_SPOL;
	else
		clear_bits |= EP93XX_SYSCON_I2SCLKDIV_SPOL;

	ep93xx_devcfg_clear_bits(clear_bits);
	ep93xx_devcfg_set_bits(set_bits);
	return 0;
}

>> +	.set_rate	= set_div_rate,
> 
> By calling the set_div_rate routine your only updating the master clock
> rate.  Should the new rate be pushed down to the children?  Actually the
> new rates for the children will be established automatically when the
> master clock rate is changed.  But a clk_get_rate for the children will
> return an incorrect value.  Maybe just add a get_rate method for the
> children?

The code basically assumes that the clocks will always be set in the
order: mclk, sclk, lrclk. Since the i2s driver is the only user, this
should be a valid assumption. Possibly a comment should be put in to
state that this assumption is made.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 0/3] ep93xx i2s audio
  2010-06-07 20:38     ` [alsa-devel] " Ryan Mallon
@ 2010-06-07 23:52       ` Mark Brown
  -1 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2010-06-07 23:52 UTC (permalink / raw)
  To: Ryan Mallon
  Cc: john.cooper, chasedouglas, dhuggins, alsa-devel, Russell King,
	r&d4, hartleys, buytenh, marshall, linux-arm-kernel,
	Liam Girdwood

On 7 Jun 2010, at 21:38, Ryan Mallon wrote:

> Russell, Mark has picked up patch 2/3 via the alsa tree. Should I submit
> 1/3 and 3/3 via the arm patch system with Liam's ack?

At least 3/3 needs to go via the ASoC tree since it depends on 2/3. It may make sense for all of them to go that way, or perhaps 1/3 could go separately via the ARM tree (in which case I'd ack it too).

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [alsa-devel] [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-07 23:52       ` Mark Brown
  0 siblings, 0 replies; 24+ messages in thread
From: Mark Brown @ 2010-06-07 23:52 UTC (permalink / raw)
  To: linux-arm-kernel

On 7 Jun 2010, at 21:38, Ryan Mallon wrote:

> Russell, Mark has picked up patch 2/3 via the alsa tree. Should I submit
> 1/3 and 3/3 via the arm patch system with Liam's ack?

At least 3/3 needs to go via the ASoC tree since it depends on 2/3. It may make sense for all of them to go that way, or perhaps 1/3 could go separately via the ARM tree (in which case I'd ack it too).

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [RFC PATCH v3 0/3] ep93xx i2s audio
  2010-06-07 23:52       ` [alsa-devel] " Mark Brown
@ 2010-06-08  0:38         ` Ryan Mallon
  -1 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-08  0:38 UTC (permalink / raw)
  To: Mark Brown
  Cc: john.cooper, chasedouglas, dhuggins, alsa-devel, Russell King,
	r&d4, hartleys, buytenh, marshall, linux-arm-kernel,
	Liam Girdwood

Mark Brown wrote:
> On 7 Jun 2010, at 21:38, Ryan Mallon wrote:
> 
>> Russell, Mark has picked up patch 2/3 via the alsa tree. Should I submit
>> 1/3 and 3/3 via the arm patch system with Liam's ack?
> 
> At least 3/3 needs to go via the ASoC tree since it depends on 2/3. It may make sense for all of them to go that way, or perhaps 1/3 could go separately via the ARM tree (in which case I'd ack it too).

I really don't mind either way, unless Russell has objections to the
core patches going via the alsa tree.

I want to make a couple of changes suggested by Hartley to patches 1/3
and 3/3 which will cleanup the registration interface a little. I will
repost the patches hopefully later today.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan@bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [alsa-devel] [RFC PATCH v3 0/3] ep93xx i2s audio
@ 2010-06-08  0:38         ` Ryan Mallon
  0 siblings, 0 replies; 24+ messages in thread
From: Ryan Mallon @ 2010-06-08  0:38 UTC (permalink / raw)
  To: linux-arm-kernel

Mark Brown wrote:
> On 7 Jun 2010, at 21:38, Ryan Mallon wrote:
> 
>> Russell, Mark has picked up patch 2/3 via the alsa tree. Should I submit
>> 1/3 and 3/3 via the arm patch system with Liam's ack?
> 
> At least 3/3 needs to go via the ASoC tree since it depends on 2/3. It may make sense for all of them to go that way, or perhaps 1/3 could go separately via the ARM tree (in which case I'd ack it too).

I really don't mind either way, unless Russell has objections to the
core patches going via the alsa tree.

I want to make a couple of changes suggested by Hartley to patches 1/3
and 3/3 which will cleanup the registration interface a little. I will
repost the patches hopefully later today.

~Ryan

-- 
Bluewater Systems Ltd - ARM Technology Solution Centre

Ryan Mallon         		5 Amuri Park, 404 Barbadoes St
ryan at bluewatersys.com         	PO Box 13 889, Christchurch 8013
http://www.bluewatersys.com	New Zealand
Phone: +64 3 3779127		Freecall: Australia 1800 148 751
Fax:   +64 3 3779135			  USA 1800 261 2934

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2010-06-08  0:38 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-06-04  5:11 [RFC PATCH v3 0/3] ep93xx i2s audio Ryan Mallon
2010-06-04  5:11 ` Ryan Mallon
2010-06-04  5:11 ` [RFC PATCH v3 1/3] ep93xx i2s core support Ryan Mallon
2010-06-04  5:11   ` Ryan Mallon
2010-06-04  5:11   ` [RFC PATCH v3 2/3] ep93xx i2s audio driver Ryan Mallon
2010-06-04  5:11     ` Ryan Mallon
2010-06-04  5:11     ` [RFC PATCH v3 3/3] Snapper cl15 audio support Ryan Mallon
2010-06-04  5:11       ` Ryan Mallon
2010-06-07 21:55   ` [RFC PATCH v3 1/3] ep93xx i2s core support H Hartley Sweeten
2010-06-07 21:55     ` H Hartley Sweeten
2010-06-07 22:21     ` Ryan Mallon
2010-06-07 22:21       ` Ryan Mallon
2010-06-07 12:45 ` [RFC PATCH v3 0/3] ep93xx i2s audio Liam Girdwood
2010-06-07 12:45   ` [alsa-devel] " Liam Girdwood
2010-06-07 20:38   ` Ryan Mallon
2010-06-07 20:38     ` [alsa-devel] " Ryan Mallon
2010-06-07 23:52     ` Mark Brown
2010-06-07 23:52       ` [alsa-devel] " Mark Brown
2010-06-08  0:38       ` Ryan Mallon
2010-06-08  0:38         ` [alsa-devel] " Ryan Mallon
2010-06-07 13:26 ` Mark Brown
2010-06-07 13:26   ` [alsa-devel] " Mark Brown
2010-06-07 20:35   ` Ryan Mallon
2010-06-07 20:35     ` [alsa-devel] " Ryan Mallon

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.