All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] S3C64XX DSP: Added base and register defines for PCM controllers
@ 2009-11-02  2:09 jassisinghbrar
  2009-11-02  2:09 ` [PATCH 2/4] S3C64XX DSP: Added PCLK clock source for the " jassisinghbrar
  0 siblings, 1 reply; 11+ messages in thread
From: jassisinghbrar @ 2009-11-02  2:09 UTC (permalink / raw)
  To: linux-samsung-soc; +Cc: Jassi Brar

From: Jassi Brar <jassi.brar@samsung.com>

Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
---
 arch/arm/mach-s3c6400/include/mach/map.h      |    2 +
 arch/arm/plat-s3c64xx/include/plat/regs-pcm.h |   94 +++++++++++++++++++++++++
 2 files changed, 96 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s3c64xx/include/plat/regs-pcm.h

diff --git a/arch/arm/mach-s3c6400/include/mach/map.h b/arch/arm/mach-s3c6400/include/mach/map.h
index fc8b223..866be31 100644
--- a/arch/arm/mach-s3c6400/include/mach/map.h
+++ b/arch/arm/mach-s3c6400/include/mach/map.h
@@ -48,6 +48,8 @@
 #define S3C64XX_PA_IIS1		(0x7F003000)
 #define S3C64XX_PA_TIMER	(0x7F006000)
 #define S3C64XX_PA_IIC0		(0x7F004000)
+#define S3C64XX_PA_PCM0		(0x7F009000)
+#define S3C64XX_PA_PCM1		(0x7F00A000)
 #define S3C64XX_PA_IISV4	(0x7F00D000)
 #define S3C64XX_PA_IIC1		(0x7F00F000)
 
diff --git a/arch/arm/plat-s3c64xx/include/plat/regs-pcm.h b/arch/arm/plat-s3c64xx/include/plat/regs-pcm.h
new file mode 100644
index 0000000..2a5fec9
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/include/plat/regs-pcm.h
@@ -0,0 +1,95 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/regs-pcm.h
+ *
+ * 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.
+ *
+ * S3C64XX PCM controller register definitions
+*/
+
+#ifndef __REGS_PCM_H
+#define __REGS_PCM_H
+
+/*Register Offsets */
+#define S3C64XX_PCM_CTL	(0x00)
+#define S3C64XX_PCM_CLKCTL	(0x04)
+#define S3C64XX_PCM_TXFIFO	(0x08)
+#define S3C64XX_PCM_RXFIFO	(0x0C)
+#define S3C64XX_PCM_IRQCTL	(0x10)
+#define S3C64XX_PCM_IRQSTAT	(0x14)
+#define S3C64XX_PCM_FIFOSTAT	(0x18)
+#define S3C64XX_PCM_CLRINT	(0x20)
+
+/* PCM_CTL Bit-Fields */
+#define S3C64XX_PCM_CTL_TXDIPSTICK_MASK		(0x3f)
+#define S3C64XX_PCM_CTL_TXDIPSTICK_SHIFT	(13)
+#define S3C64XX_PCM_CTL_RXDIPSTICK_MSK		(0x3f<<7)
+#define S3C64XX_PCM_CTL_TXDMA_EN		(0x1<<6)
+#define S3C64XX_PCM_CTL_RXDMA_EN		(0x1<<5)
+#define S3C64XX_PCM_CTL_TXMSB_AFTER_FSYNC	(0x1<<4)
+#define S3C64XX_PCM_CTL_RXMSB_AFTER_FSYNC	(0x1<<3)
+#define S3C64XX_PCM_CTL_TXFIFO_EN		(0x1<<2)
+#define S3C64XX_PCM_CTL_RXFIFO_EN		(0x1<<1)
+#define S3C64XX_PCM_CTL_ENABLE			(0x1<<0)
+
+/* PCM_CLKCTL Bit-Fields */
+#define S3C64XX_PCM_CLKCTL_SERCLK_EN		(0x1<<19)
+#define S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK	(0x1<<18)
+#define S3C64XX_PCM_CLKCTL_SCLKDIV_MASK		(0x1ff)
+#define S3C64XX_PCM_CLKCTL_SYNCDIV_MASK		(0x1ff)
+#define S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT	(9)
+#define S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT	(0)
+
+/* PCM_TXFIFO Bit-Fields */
+#define S3C64XX_PCM_TXFIFO_DVALID	(0x1<<16)
+#define S3C64XX_PCM_TXFIFO_DATA_MSK	(0xffff<<0)
+
+/* PCM_RXFIFO Bit-Fields */
+#define S3C64XX_PCM_RXFIFO_DVALID	(0x1<<16)
+#define S3C64XX_PCM_RXFIFO_DATA_MSK	(0xffff<<0)
+
+/* PCM_IRQCTL Bit-Fields */
+#define S3C64XX_PCM_IRQCTL_IRQEN		(0x1<<14)
+#define S3C64XX_PCM_IRQCTL_WRDEN		(0x1<<12)
+#define S3C64XX_PCM_IRQCTL_TXEMPTYEN		(0x1<<11)
+#define S3C64XX_PCM_IRQCTL_TXALMSTEMPTYEN	(0x1<<10)
+#define S3C64XX_PCM_IRQCTL_TXFULLEN		(0x1<<9)
+#define S3C64XX_PCM_IRQCTL_TXALMSTFULLEN	(0x1<<8)
+#define S3C64XX_PCM_IRQCTL_TXSTARVEN		(0x1<<7)
+#define S3C64XX_PCM_IRQCTL_TXERROVRFLEN		(0x1<<6)
+#define S3C64XX_PCM_IRQCTL_RXEMPTEN		(0x1<<5)
+#define S3C64XX_PCM_IRQCTL_RXALMSTEMPTEN	(0x1<<4)
+#define S3C64XX_PCM_IRQCTL_RXFULLEN		(0x1<<3)
+#define S3C64XX_PCM_IRQCTL_RXALMSTFULLEN	(0x1<<2)
+#define S3C64XX_PCM_IRQCTL_RXSTARVEN		(0x1<<1)
+#define S3C64XX_PCM_IRQCTL_RXERROVRFLEN		(0x1<<0)
+
+/* PCM_IRQSTAT Bit-Fields */
+#define S3C64XX_PCM_IRQSTAT_IRQPND		(0x1<<13)
+#define S3C64XX_PCM_IRQSTAT_WRD_XFER		(0x1<<12)
+#define S3C64XX_PCM_IRQSTAT_TXEMPTY		(0x1<<11)
+#define S3C64XX_PCM_IRQSTAT_TXALMSTEMPTY	(0x1<<10)
+#define S3C64XX_PCM_IRQSTAT_TXFULL		(0x1<<9)
+#define S3C64XX_PCM_IRQSTAT_TXALMSTFULL		(0x1<<8)
+#define S3C64XX_PCM_IRQSTAT_TXSTARV		(0x1<<7)
+#define S3C64XX_PCM_IRQSTAT_TXERROVRFL		(0x1<<6)
+#define S3C64XX_PCM_IRQSTAT_RXEMPT		(0x1<<5)
+#define S3C64XX_PCM_IRQSTAT_RXALMSTEMPT		(0x1<<4)
+#define S3C64XX_PCM_IRQSTAT_RXFULL		(0x1<<3)
+#define S3C64XX_PCM_IRQSTAT_RXALMSTFULL		(0x1<<2)
+#define S3C64XX_PCM_IRQSTAT_RXSTARV		(0x1<<1)
+#define S3C64XX_PCM_IRQSTAT_RXERROVRFL		(0x1<<0)
+
+/* PCM_FIFOSTAT Bit-Fields */
+#define S3C64XX_PCM_FIFOSTAT_TXCNT_MSK		(0x3f<<14)
+#define S3C64XX_PCM_FIFOSTAT_TXFIFOEMPTY	(0x1<<13)
+#define S3C64XX_PCM_FIFOSTAT_TXFIFOALMSTEMPTY	(0x1<<12)
+#define S3C64XX_PCM_FIFOSTAT_TXFIFOFULL		(0x1<<11)
+#define S3C64XX_PCM_FIFOSTAT_TXFIFOALMSTFULL	(0x1<<10)
+#define S3C64XX_PCM_FIFOSTAT_RXCNT_MSK		(0x3f<<4)
+#define S3C64XX_PCM_FIFOSTAT_RXFIFOEMPTY	(0x1<<3)
+#define S3C64XX_PCM_FIFOSTAT_RXFIFOALMSTEMPTY	(0x1<<2)
+#define S3C64XX_PCM_FIFOSTAT_RXFIFOFULL		(0x1<<1)
+#define S3C64XX_PCM_FIFOSTAT_RXFIFOALMSTFULL	(0x1<<0)
+
+#endif /* __REGS_PCM_H */
-- 
1.6.2.5

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

* [PATCH 2/4] S3C64XX DSP: Added PCLK clock source for the PCM controllers
  2009-11-02  2:09 [PATCH 1/4] S3C64XX DSP: Added base and register defines for PCM controllers jassisinghbrar
@ 2009-11-02  2:09 ` jassisinghbrar
  2009-11-02  2:09   ` [PATCH 3/4] S3C64XX DSP: Defined PCM controller platform devices jassisinghbrar
  0 siblings, 1 reply; 11+ messages in thread
From: jassisinghbrar @ 2009-11-02  2:09 UTC (permalink / raw)
  To: linux-samsung-soc; +Cc: Jassi Brar

From: Jassi Brar <jassi.brar@samsung.com>

Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
---
 arch/arm/plat-s3c64xx/clock.c |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c
index 7a36e89..3ab564e 100644
--- a/arch/arm/plat-s3c64xx/clock.c
+++ b/arch/arm/plat-s3c64xx/clock.c
@@ -129,6 +129,18 @@ static struct clk init_clocks_disable[] = {
 		.enable		= s3c64xx_pclk_ctrl,
 		.ctrlbit	= S3C_CLKCON_PCLK_IIS1,
 	}, {
+		.name		= "pcm",
+		.id		= 0,
+		.parent		= &clk_p,
+		.enable		= s3c64xx_pclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_PCLK_PCM0,
+	}, {
+		.name		= "pcm",
+		.id		= 1,
+		.parent		= &clk_p,
+		.enable		= s3c64xx_pclk_ctrl,
+		.ctrlbit	= S3C_CLKCON_PCLK_PCM1,
+	}, {
 		.name		= "spi",
 		.id		= 0,
 		.parent		= &clk_p,
-- 
1.6.2.5

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

* [PATCH 3/4] S3C64XX DSP: Defined PCM controller platform devices
  2009-11-02  2:09 ` [PATCH 2/4] S3C64XX DSP: Added PCLK clock source for the " jassisinghbrar
@ 2009-11-02  2:09   ` jassisinghbrar
  2009-11-02  2:09     ` [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers jassisinghbrar
  0 siblings, 1 reply; 11+ messages in thread
From: jassisinghbrar @ 2009-11-02  2:09 UTC (permalink / raw)
  To: linux-samsung-soc; +Cc: Jassi Brar

From: Jassi Brar <jassi.brar@samsung.com>

Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
---
 arch/arm/plat-s3c64xx/Makefile                    |    1 +
 arch/arm/plat-s3c64xx/dev-pcm.c                   |   50 +++++++++++++++++++++
 arch/arm/plat-s3c64xx/include/plat/s3c64xx-devs.h |   18 +++++++
 3 files changed, 69 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/plat-s3c64xx/dev-pcm.c
 create mode 100644 arch/arm/plat-s3c64xx/include/plat/s3c64xx-devs.h

diff --git a/arch/arm/plat-s3c64xx/Makefile b/arch/arm/plat-s3c64xx/Makefile
index b85b435..83c5bf1 100644
--- a/arch/arm/plat-s3c64xx/Makefile
+++ b/arch/arm/plat-s3c64xx/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_S3C64XX_SETUP_I2C1) += setup-i2c1.o
 obj-$(CONFIG_S3C64XX_SETUP_FB_24BPP) += setup-fb-24bpp.o
 obj-$(CONFIG_S3C64XX_SETUP_SDHCI_GPIO) += setup-sdhci-gpio.o
 obj-$(CONFIG_SND_S3C24XX_SOC) += dev-audio.o
+obj-$(CONFIG_SND_S3C64XX_SOC_DSP) += dev-pcm.o
diff --git a/arch/arm/plat-s3c64xx/dev-pcm.c b/arch/arm/plat-s3c64xx/dev-pcm.c
new file mode 100644
index 0000000..f8f483a
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/dev-pcm.c
@@ -0,0 +1,50 @@
+/* linux/arch/arm/plat-s3c64xx/dev-pcm.c
+ *
+ *  Copyright (c) 2009 Samsung Electronics Co. Ltd
+ *  Author: Jaswinder Singh <jassi.brar@samsung.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/kernel.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+
+#include <mach/irqs.h>
+#include <mach/map.h>
+
+#include <plat/devs.h>
+
+static struct resource s3c64xx_pcm0_resource[] = {
+	[0] = {
+		.start = S3C64XX_PA_PCM0,
+		.end   = S3C64XX_PA_PCM0 + 0x100 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device s3c64xx_device_pcm0 = {
+	.name		  = "s3c64xx-dsp",
+	.id		  = 0,
+	.num_resources	  = ARRAY_SIZE(s3c64xx_pcm0_resource),
+	.resource	  = s3c64xx_pcm0_resource,
+};
+EXPORT_SYMBOL(s3c64xx_device_pcm0);
+
+static struct resource s3c64xx_pcm1_resource[] = {
+	[0] = {
+		.start = S3C64XX_PA_PCM1,
+		.end   = S3C64XX_PA_PCM1 + 0x100 - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device s3c64xx_device_pcm1 = {
+	.name		  = "s3c64xx-dsp",
+	.id		  = 1,
+	.num_resources	  = ARRAY_SIZE(s3c64xx_pcm1_resource),
+	.resource	  = s3c64xx_pcm1_resource,
+};
+EXPORT_SYMBOL(s3c64xx_device_pcm1);
diff --git a/arch/arm/plat-s3c64xx/include/plat/s3c64xx-devs.h b/arch/arm/plat-s3c64xx/include/plat/s3c64xx-devs.h
new file mode 100644
index 0000000..d828869
--- /dev/null
+++ b/arch/arm/plat-s3c64xx/include/plat/s3c64xx-devs.h
@@ -0,0 +1,18 @@
+/* linux/arch/arm/plat-s3c64xx/include/plat/s3c64xx-devs.h
+ *
+ * Header file for s3c64xx specific platform devices
+ *
+ * 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 __PLAT_S3C64XX_DEVS_H
+#define __PLAT_S3C64XX_DEVS_H
+
+#include <linux/platform_device.h>
+
+extern struct platform_device s3c64xx_device_pcm0;
+extern struct platform_device s3c64xx_device_pcm1;
+
+#endif /* __PLAT_S3C64XX_DEVS_H */
-- 
1.6.2.5

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

* [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-02  2:09   ` [PATCH 3/4] S3C64XX DSP: Defined PCM controller platform devices jassisinghbrar
@ 2009-11-02  2:09     ` jassisinghbrar
  2009-11-02 11:17       ` Mark Brown
  0 siblings, 1 reply; 11+ messages in thread
From: jassisinghbrar @ 2009-11-02  2:09 UTC (permalink / raw)
  To: linux-samsung-soc; +Cc: Jassi Brar

From: Jassi Brar <jassi.brar@samsung.com>

Signed-off-by: Jassi Brar <jassi.brar@samsung.com>
---
 sound/soc/s3c24xx/Kconfig       |    4 +
 sound/soc/s3c24xx/Makefile      |    2 +
 sound/soc/s3c24xx/s3c64xx-dsp.c |  537 +++++++++++++++++++++++++++++++++++++++
 sound/soc/s3c24xx/s3c64xx-dsp.h |   41 +++
 4 files changed, 584 insertions(+), 0 deletions(-)
 create mode 100644 sound/soc/s3c24xx/s3c64xx-dsp.c
 create mode 100644 sound/soc/s3c24xx/s3c64xx-dsp.h

diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index d7912f1..ea00f8a 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -24,6 +24,10 @@ config SND_S3C64XX_SOC_I2S
 	select SND_S3C_I2SV2_SOC
 	select S3C64XX_DMA
 
+config SND_S3C64XX_SOC_DSP
+	tristate
+	select S3C64XX_DMA
+
 config SND_S3C2443_SOC_AC97
 	tristate
 	select S3C2410_DMA
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index 7790406..4241593 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -5,6 +5,7 @@ snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
 snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
 snd-soc-s3c2443-ac97-objs := s3c2443-ac97.o
 snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
+snd-soc-s3c64xx-dsp-objs := s3c64xx-dsp.o
 
 obj-$(CONFIG_SND_S3C24XX_SOC) += snd-soc-s3c24xx.o
 obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
@@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C2443_SOC_AC97) += snd-soc-s3c2443-ac97.o
 obj-$(CONFIG_SND_S3C2412_SOC_I2S) += snd-soc-s3c2412-i2s.o
 obj-$(CONFIG_SND_S3C64XX_SOC_I2S) += snd-soc-s3c64xx-i2s.o
 obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
+obj-$(CONFIG_SND_S3C64XX_SOC_DSP) += snd-soc-s3c64xx-dsp.o
 
 # S3C24XX Machine Support
 snd-soc-jive-wm8750-objs := jive_wm8750.o
diff --git a/sound/soc/s3c24xx/s3c64xx-dsp.c b/sound/soc/s3c24xx/s3c64xx-dsp.c
new file mode 100644
index 0000000..e8aff48
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-dsp.c
@@ -0,0 +1,537 @@
+/* sound/soc/s3c24xx/s3c64xx-dsp.c
+ *
+ * ALSA SoC Audio Layer - S3C64XX PCM-Controller driver
+ *
+ * Copyright (c) 2009 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar@samsung.com>
+ * based upon I2S drivers by Ben Dooks.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/gpio.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 <plat/regs-pcm.h>
+#include <plat/gpio-bank-d.h>
+#include <plat/gpio-bank-e.h>
+#include <plat/gpio-cfg.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+
+#include "s3c24xx-pcm.h"
+#include "s3c64xx-dsp.h"
+
+static struct s3c2410_dma_client s3c64xx_dma_client_out = {
+	.name		= "DSP Stereo out"
+};
+
+static struct s3c2410_dma_client s3c64xx_dma_client_in = {
+	.name		= "DSP Stereo in"
+};
+
+static struct s3c24xx_pcm_dma_params s3c64xx_pcm_stereo_out[] = {
+	[0] = {
+		.channel	= DMACH_PCM0_TX,
+		.client		= &s3c64xx_dma_client_out,
+		.dma_addr	= S3C64XX_PA_PCM0 + S3C64XX_PCM_TXFIFO,
+		.dma_size	= 4,
+	},
+	[1] = {
+		.channel	= DMACH_PCM1_TX,
+		.client		= &s3c64xx_dma_client_out,
+		.dma_addr	= S3C64XX_PA_PCM1 + S3C64XX_PCM_TXFIFO,
+		.dma_size	= 4,
+	},
+};
+
+static struct s3c24xx_pcm_dma_params s3c64xx_pcm_stereo_in[] = {
+	[0] = {
+		.channel	= DMACH_PCM0_RX,
+		.client		= &s3c64xx_dma_client_in,
+		.dma_addr	= S3C64XX_PA_PCM0 + S3C64XX_PCM_RXFIFO,
+		.dma_size	= 4,
+	},
+	[1] = {
+		.channel	= DMACH_PCM1_RX,
+		.client		= &s3c64xx_dma_client_in,
+		.dma_addr	= S3C64XX_PA_PCM1 + S3C64XX_PCM_RXFIFO,
+		.dma_size	= 4,
+	},
+};
+
+static struct s3c_dsp_info s3c64xx_dsp[2];
+
+static inline struct s3c_dsp_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+	return cpu_dai->private_data;
+}
+
+static void s3c64xx_dsp_snd_txctrl(struct s3c_dsp_info *dsp, int on)
+{
+	void __iomem *regs = dsp->regs;
+	u32 ctl, clkctl;
+
+	pr_debug("%s(%d)\n", __func__, on);
+
+	clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
+	ctl = readl(regs + S3C64XX_PCM_CTL);
+	ctl &= ~(S3C64XX_PCM_CTL_TXDIPSTICK_MASK
+			 << S3C64XX_PCM_CTL_TXDIPSTICK_SHIFT);
+
+	if (on) {
+		ctl |= S3C64XX_PCM_CTL_TXDMA_EN;
+		ctl |= S3C64XX_PCM_CTL_TXFIFO_EN;
+		ctl |= S3C64XX_PCM_CTL_ENABLE;
+		ctl |= (0x20<<S3C64XX_PCM_CTL_TXDIPSTICK_SHIFT);
+		clkctl |= S3C64XX_PCM_CLKCTL_SERCLK_EN;
+	} else {
+		ctl &= ~S3C64XX_PCM_CTL_TXDMA_EN;
+		ctl &= ~S3C64XX_PCM_CTL_TXFIFO_EN;
+
+		if (!(ctl & S3C64XX_PCM_CTL_RXFIFO_EN)) {
+			ctl &= ~S3C64XX_PCM_CTL_ENABLE;
+			if (!dsp->idleclk)
+				clkctl |= S3C64XX_PCM_CLKCTL_SERCLK_EN;
+		}
+	}
+
+	writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
+	writel(ctl, regs + S3C64XX_PCM_CTL);
+}
+
+static void s3c64xx_dsp_snd_rxctrl(struct s3c_dsp_info *dsp, int on)
+{
+	void __iomem *regs = dsp->regs;
+	u32 ctl, clkctl;
+
+	pr_debug("%s(%d)\n", __func__, on);
+
+	ctl = readl(regs + S3C64XX_PCM_CTL);
+	clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
+
+	if (on) {
+		ctl |= S3C64XX_PCM_CTL_RXDMA_EN;
+		ctl |= S3C64XX_PCM_CTL_RXFIFO_EN;
+		ctl |= S3C64XX_PCM_CTL_ENABLE;
+		clkctl |= S3C64XX_PCM_CLKCTL_SERCLK_EN;
+	} else {
+		ctl &= ~S3C64XX_PCM_CTL_RXDMA_EN;
+		ctl &= ~S3C64XX_PCM_CTL_RXFIFO_EN;
+
+		if (!(ctl & S3C64XX_PCM_CTL_TXFIFO_EN)) {
+			ctl &= ~S3C64XX_PCM_CTL_ENABLE;
+			if (!dsp->idleclk)
+				clkctl |= S3C64XX_PCM_CLKCTL_SERCLK_EN;
+		}
+	}
+
+	writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
+	writel(ctl, regs + S3C64XX_PCM_CTL);
+}
+
+static int s3c64xx_dsp_trigger(struct snd_pcm_substream *substream, int cmd,
+			       struct snd_soc_dai *dai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct s3c_dsp_info *dsp = to_info(rtd->dai->cpu_dai);
+	unsigned long irqs;
+
+	pr_debug("Entered %s\n", __func__);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		local_irq_save(irqs);
+
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			s3c64xx_dsp_snd_rxctrl(dsp, 1);
+		else
+			s3c64xx_dsp_snd_txctrl(dsp, 1);
+
+		local_irq_restore(irqs);
+		break;
+
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		local_irq_save(irqs);
+
+		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+			s3c64xx_dsp_snd_rxctrl(dsp, 0);
+		else
+			s3c64xx_dsp_snd_txctrl(dsp, 0);
+
+		local_irq_restore(irqs);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int s3c64xx_dsp_hw_params(struct snd_pcm_substream *substream,
+				 struct snd_pcm_hw_params *params,
+				 struct snd_soc_dai *socdai)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai_link *dai = rtd->dai;
+	struct s3c_dsp_info *dsp = to_info(dai->cpu_dai);
+
+	pr_debug("Entered %s\n", __func__);
+
+	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+		dai->cpu_dai->dma_data = dsp->dma_playback;
+	else
+		dai->cpu_dai->dma_data = dsp->dma_capture;
+
+	/* Strictly check for sample size */
+	switch (params_format(params)) {
+	case SNDRV_PCM_FORMAT_S16_LE:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int s3c64xx_dsp_set_fmt(struct snd_soc_dai *cpu_dai,
+			       unsigned int fmt)
+{
+	struct s3c_dsp_info *dsp = to_info(cpu_dai);
+	void __iomem *regs = dsp->regs;
+	u32 ctl;
+
+	pr_debug("Entered %s\n", __func__);
+
+	ctl = readl(regs + S3C64XX_PCM_CTL);
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		/* Nothing to do, NB_NF by default */
+		break;
+	default:
+		pr_err("Unsupported clock inversion!\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* Nothing to do, Master by default */
+		break;
+	default:
+		pr_err("Unsupported master/slave format!\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_CLOCK_MASK) {
+	case SND_SOC_DAIFMT_CONT:
+		dsp->idleclk = 1;
+		break;
+	case SND_SOC_DAIFMT_GATED:
+		dsp->idleclk = 0;
+		break;
+	default:
+		pr_err("Invalid Clock gating request!\n");
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_DSP_A:
+		ctl |= S3C64XX_PCM_CTL_TXMSB_AFTER_FSYNC;
+		ctl |= S3C64XX_PCM_CTL_RXMSB_AFTER_FSYNC;
+		break;
+	case SND_SOC_DAIFMT_DSP_B:
+		ctl &= ~S3C64XX_PCM_CTL_TXMSB_AFTER_FSYNC;
+		ctl &= ~S3C64XX_PCM_CTL_RXMSB_AFTER_FSYNC;
+		break;
+	default:
+		pr_err("Unsupported data format!\n");
+		return -EINVAL;
+	}
+
+	writel(ctl, regs + S3C64XX_PCM_CTL);
+
+	return 0;
+}
+
+static int s3c64xx_dsp_set_clkdiv(struct snd_soc_dai *cpu_dai,
+				  int div_id, int div)
+{
+	struct s3c_dsp_info *dsp = to_info(cpu_dai);
+	void __iomem *regs = dsp->regs;
+	u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
+
+	pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
+
+	switch (div_id) {
+	case S3C64XX_DSP_SCLK_DIV:
+		clkctl &= ~(S3C64XX_PCM_CLKCTL_SCLKDIV_MASK
+				<< S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
+		clkctl |= ((div & S3C64XX_PCM_CLKCTL_SCLKDIV_MASK)
+				<< S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
+		break;
+
+	case S3C64XX_DSP_SYNC_DIV:
+		clkctl &= ~(S3C64XX_PCM_CLKCTL_SYNCDIV_MASK
+				<< S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
+		clkctl |= ((div & S3C64XX_PCM_CLKCTL_SYNCDIV_MASK)
+				<< S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
+
+	return 0;
+}
+
+static int s3c64xx_dsp_set_sysclk(struct snd_soc_dai *cpu_dai,
+				  int clk_id, unsigned int freq, int dir)
+{
+	struct s3c_dsp_info *dsp = to_info(cpu_dai);
+	void __iomem *regs = dsp->regs;
+	u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
+
+	switch (clk_id) {
+	case S3C64XX_DSP_CLKSRC_PCLK:
+		clkctl |= S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
+		break;
+
+	case S3C64XX_DSP_CLKSRC_MUX:
+		clkctl &= ~S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
+
+		if (clk_get_rate(dsp->pcm_cclk) != freq)
+			clk_set_rate(dsp->pcm_cclk, freq);
+
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
+
+	return 0;
+}
+
+struct clk *s3c64xx_dsp_get_clock(struct snd_soc_dai *dai)
+{
+	struct s3c_dsp_info *dsp = to_info(dai);
+	void __iomem *regs = dsp->regs;
+	u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
+
+	if (clkctl & S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK)
+		return dsp->pcm_pclk;
+	else
+		return dsp->pcm_cclk;
+}
+EXPORT_SYMBOL_GPL(s3c64xx_dsp_get_clock);
+
+static int s3c64xx_dsp_probe(struct platform_device *pdev,
+			     struct snd_soc_dai *dai)
+{
+	/* configure GPIO for the PCM controller */
+	switch (dai->id) {
+	case 0:
+		s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
+		s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
+		s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
+		s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
+		s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
+		break;
+	case 1:
+		s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
+		s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
+		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
+		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
+		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
+		break;
+	default:
+		printk(KERN_DEBUG "Invalid PCM Controller number!");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_dai_ops s3c64xx_dsp_dai_ops = {
+	.set_sysclk	= s3c64xx_dsp_set_sysclk,
+	.trigger	= s3c64xx_dsp_trigger,
+	.hw_params	= s3c64xx_dsp_hw_params,
+	.set_fmt	= s3c64xx_dsp_set_fmt,
+	.set_clkdiv	= s3c64xx_dsp_set_clkdiv,
+};
+
+#define S3C64XX_DSP_RATES  SNDRV_PCM_RATE_8000_96000
+
+#define S3C64XX_DSP_DECLARE(n)			\
+{								\
+	.name		 = "s3c64xx-dsp",			\
+	.id		 = (n),				\
+	.symmetric_rates = 1,					\
+	.probe		 = s3c64xx_dsp_probe,			\
+	.ops = &s3c64xx_dsp_dai_ops,				\
+	.playback = {						\
+		.channels_min	= 2,				\
+		.channels_max	= 2,				\
+		.rates		= S3C64XX_DSP_RATES,		\
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE,	\
+	},							\
+	.capture = {						\
+		.channels_min	= 2,				\
+		.channels_max	= 2,				\
+		.rates		= S3C64XX_DSP_RATES,		\
+		.formats	= SNDRV_PCM_FMTBIT_S16_LE,	\
+	},							\
+}
+
+struct snd_soc_dai s3c64xx_dsp_dai[] = {
+	S3C64XX_DSP_DECLARE(0),
+	S3C64XX_DSP_DECLARE(1),
+};
+EXPORT_SYMBOL_GPL(s3c64xx_dsp_dai);
+
+static int s3c_dsp_probe(struct platform_device *pdev,
+		    struct snd_soc_dai *dai,
+		    struct s3c_dsp_info *dsp,
+		    unsigned long base)
+{
+	struct device *dev = &pdev->dev;
+
+	dsp->dev = dev;
+
+	/* record our dsp structure for later use in the callbacks */
+	dai->private_data = dsp;
+
+	if (!base) {
+		struct resource *res = platform_get_resource(pdev,
+							     IORESOURCE_MEM,
+							     0);
+		if (!res) {
+			dev_err(dev, "Unable to get register resource\n");
+			return -ENXIO;
+		}
+
+		if (!request_mem_region(res->start, resource_size(res),
+					"s3c64xx-dsp")) {
+			dev_err(dev, "Unable to request register region\n");
+			return -EBUSY;
+		}
+
+		base = res->start;
+	}
+
+	dsp->regs = ioremap(base, 0x100);
+	if (dsp->regs == NULL) {
+		dev_err(dev, "cannot ioremap registers\n");
+		return -ENXIO;
+	}
+
+	dsp->pcm_pclk = clk_get(dev, "pcm");
+	if (IS_ERR(dsp->pcm_pclk)) {
+		dev_err(dev, "failed to get pcm_clock\n");
+		iounmap(dsp->regs);
+		return -ENOENT;
+	}
+
+	clk_enable(dsp->pcm_pclk);
+
+	return 0;
+}
+
+static __devinit int s3c64xx_dsp_dev_probe(struct platform_device *pdev)
+{
+	struct s3c_dsp_info *dsp;
+	struct snd_soc_dai *dai;
+	int ret;
+
+	if (pdev->id >= ARRAY_SIZE(s3c64xx_dsp)) {
+		dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
+		return -EINVAL;
+	}
+
+	dsp = &s3c64xx_dsp[pdev->id];
+	dai = &s3c64xx_dsp_dai[pdev->id];
+	dai->dev = &pdev->dev;
+
+	dsp->dma_capture = &s3c64xx_pcm_stereo_in[pdev->id];
+	dsp->dma_playback = &s3c64xx_pcm_stereo_out[pdev->id];
+
+	dsp->pcm_cclk = clk_get(&pdev->dev, "audio-bus");
+	if (IS_ERR(dsp->pcm_cclk)) {
+		dev_err(&pdev->dev, "failed to get audio-bus\n");
+		ret = PTR_ERR(dsp->pcm_cclk);
+		goto err;
+	}
+	clk_enable(dsp->pcm_cclk);
+
+	ret = s3c_dsp_probe(pdev, dai, dsp, 0);
+	if (ret)
+		goto err_clk;
+
+	ret = snd_soc_register_dai(dai);
+	if (ret != 0)
+		goto err_dsp;
+
+	return 0;
+
+err_dsp:
+	/* Not implemented */
+err_clk:
+	clk_put(dsp->pcm_cclk);
+err:
+	return ret;
+}
+
+static __devexit int s3c64xx_dsp_dev_remove(struct platform_device *pdev)
+{
+	dev_err(&pdev->dev, "Device removal not yet supported\n");
+	return 0;
+}
+
+static struct platform_driver s3c64xx_dsp_driver = {
+	.probe  = s3c64xx_dsp_dev_probe,
+	.remove = s3c64xx_dsp_dev_remove,
+	.driver = {
+		.name = "s3c64xx-dsp",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init s3c64xx_dsp_init(void)
+{
+	return platform_driver_register(&s3c64xx_dsp_driver);
+}
+module_init(s3c64xx_dsp_init);
+
+static void __exit s3c64xx_dsp_exit(void)
+{
+	platform_driver_unregister(&s3c64xx_dsp_driver);
+}
+module_exit(s3c64xx_dsp_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
+MODULE_DESCRIPTION("S3C64XX PCM Controller Driver");
diff --git a/sound/soc/s3c24xx/s3c64xx-dsp.h b/sound/soc/s3c24xx/s3c64xx-dsp.h
new file mode 100644
index 0000000..cb92346
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-dsp.h
@@ -0,0 +1,41 @@
+/*  sound/soc/s3c24xx/s3c64xx-dsp.h
+ *
+ *  ALSA Soc Audio Layer - S3C64XX PCM Controller driver
+ *
+ *  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.
+ */
+
+#ifndef __SND_SOC_S3C64XX_PCM_H
+#define __SND_SOC_S3C64XX_PCM_H __FILE__
+
+#define S3C64XX_DSP_CLKSRC_PCLK	0
+#define S3C64XX_DSP_CLKSRC_MUX	1
+
+#define S3C64XX_DSP_SYNC_DIV	0
+#define S3C64XX_DSP_SCLK_DIV	1
+
+/**
+ * struct s3c_dsp_info - S3C PCM Controller information
+ * @dev: The parent device passed to use from the probe.
+ * @regs: The pointer to the device register block.
+ * @dma_playback: DMA information for playback channel.
+ * @dma_capture: DMA information for capture channel.
+ */
+struct s3c_dsp_info {
+	struct device	*dev;
+	void __iomem	*regs;
+
+	/* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
+	unsigned int idleclk;
+
+	struct clk	*pcm_pclk;
+	struct clk	*pcm_cclk;
+
+	struct s3c24xx_pcm_dma_params	*dma_playback;
+	struct s3c24xx_pcm_dma_params	*dma_capture;
+};
+
+#endif /* __SND_SOC_S3C64XX_PCM_H */
-- 
1.6.2.5

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-02  2:09     ` [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers jassisinghbrar
@ 2009-11-02 11:17       ` Mark Brown
  2009-11-02 11:39         ` Ben Dooks
  2009-11-03  2:42         ` jassi brar
  0 siblings, 2 replies; 11+ messages in thread
From: Mark Brown @ 2009-11-02 11:17 UTC (permalink / raw)
  To: jassisinghbrar; +Cc: linux-samsung-soc, Jassi Brar

On Mon, Nov 02, 2009 at 11:09:51AM +0900, jassisinghbrar@gmail.com wrote:

> +static int s3c64xx_dsp_trigger(struct snd_pcm_substream *substream, int cmd,
> +			       struct snd_soc_dai *dai)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct s3c_dsp_info *dsp = to_info(rtd->dai->cpu_dai);
> +	unsigned long irqs;
> +
> +	pr_debug("Entered %s\n", __func__);
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +		local_irq_save(irqs);

Why local_irq_save()?  On existing uniprocessor systems they should be
equivalent to a regular IRQ save and if there are future multi core
chips using the driver I can't imagine that a local IRQ save will be
enough.

> +	default:
> +		pr_err("Unsupported data format!\n");
> +		return -EINVAL;

Pretty much all the prints in the driver could be dev_ versions.

> +static int s3c64xx_dsp_set_clkdiv(struct snd_soc_dai *cpu_dai,
> +				  int div_id, int div)
> +{
> +	struct s3c_dsp_info *dsp = to_info(cpu_dai);
> +	void __iomem *regs = dsp->regs;
> +	u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
> +
> +	pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
> +
> +	switch (div_id) {
> +	case S3C64XX_DSP_SCLK_DIV:
> +		clkctl &= ~(S3C64XX_PCM_CLKCTL_SCLKDIV_MASK
> +				<< S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
> +		clkctl |= ((div & S3C64XX_PCM_CLKCTL_SCLKDIV_MASK)
> +				<< S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
> +		break;
> +
> +	case S3C64XX_DSP_SYNC_DIV:
> +		clkctl &= ~(S3C64XX_PCM_CLKCTL_SYNCDIV_MASK
> +				<< S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
> +		clkctl |= ((div & S3C64XX_PCM_CLKCTL_SYNCDIV_MASK)
> +				<< S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
> +		break;

You should really provide defaults for these - the overwhelming majority
of systems are going to want standard configurations and there's no
point in them all replicating the code to work those out.  Either
provide a function which takes the params and sets things up that
machine drivers can call from their hw_params() or just do that
automatically from the PCM driver hw_params() if the machine driver
didn't explicitly configure anything.

> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
> +
> +	return 0;
> +}
> +
> +static int s3c64xx_dsp_set_sysclk(struct snd_soc_dai *cpu_dai,
> +				  int clk_id, unsigned int freq, int dir)
> +{
> +	struct s3c_dsp_info *dsp = to_info(cpu_dai);
> +	void __iomem *regs = dsp->regs;
> +	u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
> +
> +	switch (clk_id) {
> +	case S3C64XX_DSP_CLKSRC_PCLK:
> +		clkctl |= S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
> +		break;
> +
> +	case S3C64XX_DSP_CLKSRC_MUX:
> +		clkctl &= ~S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
> +
> +		if (clk_get_rate(dsp->pcm_cclk) != freq)
> +			clk_set_rate(dsp->pcm_cclk, freq);
> +
> +		break;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
> +
> +	return 0;
> +}
> +
> +struct clk *s3c64xx_dsp_get_clock(struct snd_soc_dai *dai)
> +{
> +	struct s3c_dsp_info *dsp = to_info(dai);
> +	void __iomem *regs = dsp->regs;
> +	u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
> +
> +	if (clkctl & S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK)
> +		return dsp->pcm_pclk;
> +	else
> +		return dsp->pcm_cclk;
> +}
> +EXPORT_SYMBOL_GPL(s3c64xx_dsp_get_clock);
> +
> +static int s3c64xx_dsp_probe(struct platform_device *pdev,
> +			     struct snd_soc_dai *dai)
> +{
> +	/* configure GPIO for the PCM controller */
> +	switch (dai->id) {
> +	case 0:
> +		s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
> +		s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
> +		s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
> +		s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
> +		s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
> +		break;
> +	case 1:
> +		s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
> +		s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
> +		s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
> +		s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
> +		s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
> +		break;
> +	default:
> +		printk(KERN_DEBUG "Invalid PCM Controller number!");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct snd_soc_dai_ops s3c64xx_dsp_dai_ops = {
> +	.set_sysclk	= s3c64xx_dsp_set_sysclk,
> +	.trigger	= s3c64xx_dsp_trigger,
> +	.hw_params	= s3c64xx_dsp_hw_params,
> +	.set_fmt	= s3c64xx_dsp_set_fmt,
> +	.set_clkdiv	= s3c64xx_dsp_set_clkdiv,
> +};
> +
> +#define S3C64XX_DSP_RATES  SNDRV_PCM_RATE_8000_96000
> +
> +#define S3C64XX_DSP_DECLARE(n)			\
> +{								\
> +	.name		 = "s3c64xx-dsp",			\
> +	.id		 = (n),				\
> +	.symmetric_rates = 1,					\
> +	.probe		 = s3c64xx_dsp_probe,			\
> +	.ops = &s3c64xx_dsp_dai_ops,				\
> +	.playback = {						\
> +		.channels_min	= 2,				\
> +		.channels_max	= 2,				\
> +		.rates		= S3C64XX_DSP_RATES,		\
> +		.formats	= SNDRV_PCM_FMTBIT_S16_LE,	\
> +	},							\
> +	.capture = {						\
> +		.channels_min	= 2,				\
> +		.channels_max	= 2,				\
> +		.rates		= S3C64XX_DSP_RATES,		\
> +		.formats	= SNDRV_PCM_FMTBIT_S16_LE,	\
> +	},							\
> +}
> +
> +struct snd_soc_dai s3c64xx_dsp_dai[] = {
> +	S3C64XX_DSP_DECLARE(0),
> +	S3C64XX_DSP_DECLARE(1),
> +};
> +EXPORT_SYMBOL_GPL(s3c64xx_dsp_dai);
> +
> +static int s3c_dsp_probe(struct platform_device *pdev,
> +		    struct snd_soc_dai *dai,
> +		    struct s3c_dsp_info *dsp,
> +		    unsigned long base)
> +{
> +	struct device *dev = &pdev->dev;
> +
> +	dsp->dev = dev;
> +
> +	/* record our dsp structure for later use in the callbacks */
> +	dai->private_data = dsp;
> +
> +	if (!base) {
> +		struct resource *res = platform_get_resource(pdev,
> +							     IORESOURCE_MEM,
> +							     0);
> +		if (!res) {
> +			dev_err(dev, "Unable to get register resource\n");
> +			return -ENXIO;
> +		}
> +
> +		if (!request_mem_region(res->start, resource_size(res),
> +					"s3c64xx-dsp")) {
> +			dev_err(dev, "Unable to request register region\n");
> +			return -EBUSY;
> +		}
> +
> +		base = res->start;
> +	}
> +
> +	dsp->regs = ioremap(base, 0x100);
> +	if (dsp->regs == NULL) {
> +		dev_err(dev, "cannot ioremap registers\n");
> +		return -ENXIO;
> +	}
> +
> +	dsp->pcm_pclk = clk_get(dev, "pcm");
> +	if (IS_ERR(dsp->pcm_pclk)) {
> +		dev_err(dev, "failed to get pcm_clock\n");
> +		iounmap(dsp->regs);
> +		return -ENOENT;
> +	}
> +
> +	clk_enable(dsp->pcm_pclk);
> +
> +	return 0;
> +}
> +
> +static __devinit int s3c64xx_dsp_dev_probe(struct platform_device *pdev)
> +{
> +	struct s3c_dsp_info *dsp;
> +	struct snd_soc_dai *dai;
> +	int ret;
> +
> +	if (pdev->id >= ARRAY_SIZE(s3c64xx_dsp)) {
> +		dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
> +		return -EINVAL;
> +	}
> +
> +	dsp = &s3c64xx_dsp[pdev->id];
> +	dai = &s3c64xx_dsp_dai[pdev->id];
> +	dai->dev = &pdev->dev;
> +
> +	dsp->dma_capture = &s3c64xx_pcm_stereo_in[pdev->id];
> +	dsp->dma_playback = &s3c64xx_pcm_stereo_out[pdev->id];
> +
> +	dsp->pcm_cclk = clk_get(&pdev->dev, "audio-bus");
> +	if (IS_ERR(dsp->pcm_cclk)) {
> +		dev_err(&pdev->dev, "failed to get audio-bus\n");
> +		ret = PTR_ERR(dsp->pcm_cclk);
> +		goto err;
> +	}
> +	clk_enable(dsp->pcm_cclk);
> +
> +	ret = s3c_dsp_probe(pdev, dai, dsp, 0);
> +	if (ret)
> +		goto err_clk;
> +
> +	ret = snd_soc_register_dai(dai);
> +	if (ret != 0)
> +		goto err_dsp;
> +
> +	return 0;
> +
> +err_dsp:
> +	/* Not implemented */
> +err_clk:
> +	clk_put(dsp->pcm_cclk);
> +err:
> +	return ret;
> +}
> +
> +static __devexit int s3c64xx_dsp_dev_remove(struct platform_device *pdev)
> +{
> +	dev_err(&pdev->dev, "Device removal not yet supported\n");
> +	return 0;
> +}
> +
> +static struct platform_driver s3c64xx_dsp_driver = {
> +	.probe  = s3c64xx_dsp_dev_probe,
> +	.remove = s3c64xx_dsp_dev_remove,
> +	.driver = {
> +		.name = "s3c64xx-dsp",
> +		.owner = THIS_MODULE,
> +	},
> +};
> +
> +static int __init s3c64xx_dsp_init(void)
> +{
> +	return platform_driver_register(&s3c64xx_dsp_driver);
> +}
> +module_init(s3c64xx_dsp_init);
> +
> +static void __exit s3c64xx_dsp_exit(void)
> +{
> +	platform_driver_unregister(&s3c64xx_dsp_driver);
> +}
> +module_exit(s3c64xx_dsp_exit);
> +
> +/* Module information */
> +MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
> +MODULE_DESCRIPTION("S3C64XX PCM Controller Driver");
> diff --git a/sound/soc/s3c24xx/s3c64xx-dsp.h b/sound/soc/s3c24xx/s3c64xx-dsp.h
> new file mode 100644
> index 0000000..cb92346
> --- /dev/null
> +++ b/sound/soc/s3c24xx/s3c64xx-dsp.h
> @@ -0,0 +1,41 @@
> +/*  sound/soc/s3c24xx/s3c64xx-dsp.h
> + *
> + *  ALSA Soc Audio Layer - S3C64XX PCM Controller driver
> + *
> + *  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.
> + */
> +
> +#ifndef __SND_SOC_S3C64XX_PCM_H
> +#define __SND_SOC_S3C64XX_PCM_H __FILE__
> +
> +#define S3C64XX_DSP_CLKSRC_PCLK	0
> +#define S3C64XX_DSP_CLKSRC_MUX	1
> +
> +#define S3C64XX_DSP_SYNC_DIV	0
> +#define S3C64XX_DSP_SCLK_DIV	1
> +
> +/**
> + * struct s3c_dsp_info - S3C PCM Controller information
> + * @dev: The parent device passed to use from the probe.
> + * @regs: The pointer to the device register block.
> + * @dma_playback: DMA information for playback channel.
> + * @dma_capture: DMA information for capture channel.
> + */
> +struct s3c_dsp_info {
> +	struct device	*dev;
> +	void __iomem	*regs;
> +
> +	/* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
> +	unsigned int idleclk;
> +
> +	struct clk	*pcm_pclk;
> +	struct clk	*pcm_cclk;
> +
> +	struct s3c24xx_pcm_dma_params	*dma_playback;
> +	struct s3c24xx_pcm_dma_params	*dma_capture;
> +};
> +
> +#endif /* __SND_SOC_S3C64XX_PCM_H */
> -- 
> 1.6.2.5
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

-- 
"You grabbed my hand and we fell into it, like a daydream - or a fever."

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-02 11:17       ` Mark Brown
@ 2009-11-02 11:39         ` Ben Dooks
  2009-11-02 11:56           ` Mark Brown
  2009-11-03  6:59           ` jassi brar
  2009-11-03  2:42         ` jassi brar
  1 sibling, 2 replies; 11+ messages in thread
From: Ben Dooks @ 2009-11-02 11:39 UTC (permalink / raw)
  To: Mark Brown; +Cc: jassisinghbrar, linux-samsung-soc, Jassi Brar


> > +	dai->private_data = dsp;
> > +
> > +	if (!base) {
> > +		struct resource *res = platform_get_resource(pdev,
> > +							     IORESOURCE_MEM,
> > +							     0);
> > +		if (!res) {
> > +			dev_err(dev, "Unable to get register resource\n");
> > +			return -ENXIO;
> > +		}
> > +
> > +		if (!request_mem_region(res->start, resource_size(res),
> > +					"s3c64xx-dsp")) {
> > +			dev_err(dev, "Unable to request register region\n");
> > +			return -EBUSY;
> > +		}
> > +
> > +		base = res->start;
> > +	}

I would like to see platform_devices with their proper resources being
mandatory for new drivers. We could do with this lot proplerly following
the device driver model.

> > +/* Module information */
> > +MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
> > +MODULE_DESCRIPTION("S3C64XX PCM Controller Driver");

no module license.

-- 
Ben

Q:      What's a light-year?
A:      One-third less calories than a regular year.

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-02 11:39         ` Ben Dooks
@ 2009-11-02 11:56           ` Mark Brown
  2009-11-03  6:59           ` jassi brar
  1 sibling, 0 replies; 11+ messages in thread
From: Mark Brown @ 2009-11-02 11:56 UTC (permalink / raw)
  To: Ben Dooks; +Cc: jassisinghbrar, linux-samsung-soc, Jassi Brar

On Mon, Nov 02, 2009 at 11:39:32AM +0000, Ben Dooks wrote:

> I would like to see platform_devices with their proper resources being
> mandatory for new drivers. We could do with this lot proplerly following
> the device driver model.

Actually, from that point of view the whole probe function should just
be rolled into one anyway - there is exactly one caller of the sub
function.

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-02 11:17       ` Mark Brown
  2009-11-02 11:39         ` Ben Dooks
@ 2009-11-03  2:42         ` jassi brar
  2009-11-03  9:52           ` Mark Brown
  1 sibling, 1 reply; 11+ messages in thread
From: jassi brar @ 2009-11-03  2:42 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-samsung-soc, Jassi Brar

On Mon, Nov 2, 2009 at 8:17 PM, Mark Brown
<broonie@opensource.wolfsonmicro.com> wrote:
> On Mon, Nov 02, 2009 at 11:09:51AM +0900, jassisinghbrar@gmail.com wrote:
>
>> +static int s3c64xx_dsp_trigger(struct snd_pcm_substream *substream, int cmd,
>> +                            struct snd_soc_dai *dai)
>> +{
>> +     struct snd_soc_pcm_runtime *rtd = substream->private_data;
>> +     struct s3c_dsp_info *dsp = to_info(rtd->dai->cpu_dai);
>> +     unsigned long irqs;
>> +
>> +     pr_debug("Entered %s\n", __func__);
>> +
>> +     switch (cmd) {
>> +     case SNDRV_PCM_TRIGGER_START:
>> +     case SNDRV_PCM_TRIGGER_RESUME:
>> +     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +             local_irq_save(irqs);
>
> Why local_irq_save()?  On existing uniprocessor systems they should be
> equivalent to a regular IRQ save and if there are future multi core
> chips using the driver I can't imagine that a local IRQ save will be
> enough.
Don't we need to protect critical mode change in PCM control register?
Since the s3c64xx_dsp_snd_tx/rxctrl is small and non-blocking, I think
protection by simply enabling/disabling IRQs should be fine.

>> +     default:
>> +             pr_err("Unsupported data format!\n");
>> +             return -EINVAL;
>
> Pretty much all the prints in the driver could be dev_ versions.
okay, will change it.

>> +static int s3c64xx_dsp_set_clkdiv(struct snd_soc_dai *cpu_dai,
>> +                               int div_id, int div)
>> +{
>> +     struct s3c_dsp_info *dsp = to_info(cpu_dai);
>> +     void __iomem *regs = dsp->regs;
>> +     u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     pr_debug("%s(%p, %d, %d)\n", __func__, cpu_dai, div_id, div);
>> +
>> +     switch (div_id) {
>> +     case S3C64XX_DSP_SCLK_DIV:
>> +             clkctl &= ~(S3C64XX_PCM_CLKCTL_SCLKDIV_MASK
>> +                             << S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
>> +             clkctl |= ((div & S3C64XX_PCM_CLKCTL_SCLKDIV_MASK)
>> +                             << S3C64XX_PCM_CLKCTL_SCLKDIV_SHIFT);
>> +             break;
>> +
>> +     case S3C64XX_DSP_SYNC_DIV:
>> +             clkctl &= ~(S3C64XX_PCM_CLKCTL_SYNCDIV_MASK
>> +                             << S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
>> +             clkctl |= ((div & S3C64XX_PCM_CLKCTL_SYNCDIV_MASK)
>> +                             << S3C64XX_PCM_CLKCTL_SYNCDIV_SHIFT);
>> +             break;
>
> You should really provide defaults for these - the overwhelming majority
> of systems are going to want standard configurations and there's no
> point in them all replicating the code to work those out.  Either
> provide a function which takes the params and sets things up that
> machine drivers can call from their hw_params() or just do that
> automatically from the PCM driver hw_params() if the machine driver
> didn't explicitly configure anything.
okay, will change it

>> +
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     return 0;
>> +}
>> +
>> +static int s3c64xx_dsp_set_sysclk(struct snd_soc_dai *cpu_dai,
>> +                               int clk_id, unsigned int freq, int dir)
>> +{
>> +     struct s3c_dsp_info *dsp = to_info(cpu_dai);
>> +     void __iomem *regs = dsp->regs;
>> +     u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     switch (clk_id) {
>> +     case S3C64XX_DSP_CLKSRC_PCLK:
>> +             clkctl |= S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
>> +             break;
>> +
>> +     case S3C64XX_DSP_CLKSRC_MUX:
>> +             clkctl &= ~S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK;
>> +
>> +             if (clk_get_rate(dsp->pcm_cclk) != freq)
>> +                     clk_set_rate(dsp->pcm_cclk, freq);
>> +
>> +             break;
>> +
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +
>> +     writel(clkctl, regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     return 0;
>> +}
>> +
>> +struct clk *s3c64xx_dsp_get_clock(struct snd_soc_dai *dai)
>> +{
>> +     struct s3c_dsp_info *dsp = to_info(dai);
>> +     void __iomem *regs = dsp->regs;
>> +     u32 clkctl = readl(regs + S3C64XX_PCM_CLKCTL);
>> +
>> +     if (clkctl & S3C64XX_PCM_CLKCTL_SERCLKSEL_PCLK)
>> +             return dsp->pcm_pclk;
>> +     else
>> +             return dsp->pcm_cclk;
>> +}
>> +EXPORT_SYMBOL_GPL(s3c64xx_dsp_get_clock);
>> +
>> +static int s3c64xx_dsp_probe(struct platform_device *pdev,
>> +                          struct snd_soc_dai *dai)
>> +{
>> +     /* configure GPIO for the PCM controller */
>> +     switch (dai->id) {
>> +     case 0:
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(0), S3C64XX_GPD0_PCM0_SCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(1), S3C64XX_GPD1_PCM0_EXTCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(2), S3C64XX_GPD2_PCM0_FSYNC);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(3), S3C64XX_GPD3_PCM0_SIN);
>> +             s3c_gpio_cfgpin(S3C64XX_GPD(4), S3C64XX_GPD4_PCM0_SOUT);
>> +             break;
>> +     case 1:
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(0), S3C64XX_GPE0_PCM1_SCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(1), S3C64XX_GPE1_PCM1_EXTCLK);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(2), S3C64XX_GPE2_PCM1_FSYNC);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(3), S3C64XX_GPE3_PCM1_SIN);
>> +             s3c_gpio_cfgpin(S3C64XX_GPE(4), S3C64XX_GPE4_PCM1_SOUT);
>> +             break;
>> +     default:
>> +             printk(KERN_DEBUG "Invalid PCM Controller number!");
>> +             return -EINVAL;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static struct snd_soc_dai_ops s3c64xx_dsp_dai_ops = {
>> +     .set_sysclk     = s3c64xx_dsp_set_sysclk,
>> +     .trigger        = s3c64xx_dsp_trigger,
>> +     .hw_params      = s3c64xx_dsp_hw_params,
>> +     .set_fmt        = s3c64xx_dsp_set_fmt,
>> +     .set_clkdiv     = s3c64xx_dsp_set_clkdiv,
>> +};
>> +
>> +#define S3C64XX_DSP_RATES  SNDRV_PCM_RATE_8000_96000
>> +
>> +#define S3C64XX_DSP_DECLARE(n)                       \
>> +{                                                            \
>> +     .name            = "s3c64xx-dsp",                       \
>> +     .id              = (n),                         \
>> +     .symmetric_rates = 1,                                   \
>> +     .probe           = s3c64xx_dsp_probe,                   \
>> +     .ops = &s3c64xx_dsp_dai_ops,                            \
>> +     .playback = {                                           \
>> +             .channels_min   = 2,                            \
>> +             .channels_max   = 2,                            \
>> +             .rates          = S3C64XX_DSP_RATES,            \
>> +             .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
>> +     },                                                      \
>> +     .capture = {                                            \
>> +             .channels_min   = 2,                            \
>> +             .channels_max   = 2,                            \
>> +             .rates          = S3C64XX_DSP_RATES,            \
>> +             .formats        = SNDRV_PCM_FMTBIT_S16_LE,      \
>> +     },                                                      \
>> +}
>> +
>> +struct snd_soc_dai s3c64xx_dsp_dai[] = {
>> +     S3C64XX_DSP_DECLARE(0),
>> +     S3C64XX_DSP_DECLARE(1),
>> +};
>> +EXPORT_SYMBOL_GPL(s3c64xx_dsp_dai);
>> +
>> +static int s3c_dsp_probe(struct platform_device *pdev,
>> +                 struct snd_soc_dai *dai,
>> +                 struct s3c_dsp_info *dsp,
>> +                 unsigned long base)
>> +{
>> +     struct device *dev = &pdev->dev;
>> +
>> +     dsp->dev = dev;
>> +
>> +     /* record our dsp structure for later use in the callbacks */
>> +     dai->private_data = dsp;
>> +
>> +     if (!base) {
>> +             struct resource *res = platform_get_resource(pdev,
>> +                                                          IORESOURCE_MEM,
>> +                                                          0);
>> +             if (!res) {
>> +                     dev_err(dev, "Unable to get register resource\n");
>> +                     return -ENXIO;
>> +             }
>> +
>> +             if (!request_mem_region(res->start, resource_size(res),
>> +                                     "s3c64xx-dsp")) {
>> +                     dev_err(dev, "Unable to request register region\n");
>> +                     return -EBUSY;
>> +             }
>> +
>> +             base = res->start;
>> +     }
>> +
>> +     dsp->regs = ioremap(base, 0x100);
>> +     if (dsp->regs == NULL) {
>> +             dev_err(dev, "cannot ioremap registers\n");
>> +             return -ENXIO;
>> +     }
>> +
>> +     dsp->pcm_pclk = clk_get(dev, "pcm");
>> +     if (IS_ERR(dsp->pcm_pclk)) {
>> +             dev_err(dev, "failed to get pcm_clock\n");
>> +             iounmap(dsp->regs);
>> +             return -ENOENT;
>> +     }
>> +
>> +     clk_enable(dsp->pcm_pclk);
>> +
>> +     return 0;
>> +}
>> +
>> +static __devinit int s3c64xx_dsp_dev_probe(struct platform_device *pdev)
>> +{
>> +     struct s3c_dsp_info *dsp;
>> +     struct snd_soc_dai *dai;
>> +     int ret;
>> +
>> +     if (pdev->id >= ARRAY_SIZE(s3c64xx_dsp)) {
>> +             dev_err(&pdev->dev, "id %d out of range\n", pdev->id);
>> +             return -EINVAL;
>> +     }
>> +
>> +     dsp = &s3c64xx_dsp[pdev->id];
>> +     dai = &s3c64xx_dsp_dai[pdev->id];
>> +     dai->dev = &pdev->dev;
>> +
>> +     dsp->dma_capture = &s3c64xx_pcm_stereo_in[pdev->id];
>> +     dsp->dma_playback = &s3c64xx_pcm_stereo_out[pdev->id];
>> +
>> +     dsp->pcm_cclk = clk_get(&pdev->dev, "audio-bus");
>> +     if (IS_ERR(dsp->pcm_cclk)) {
>> +             dev_err(&pdev->dev, "failed to get audio-bus\n");
>> +             ret = PTR_ERR(dsp->pcm_cclk);
>> +             goto err;
>> +     }
>> +     clk_enable(dsp->pcm_cclk);
>> +
>> +     ret = s3c_dsp_probe(pdev, dai, dsp, 0);
>> +     if (ret)
>> +             goto err_clk;
>> +
>> +     ret = snd_soc_register_dai(dai);
>> +     if (ret != 0)
>> +             goto err_dsp;
>> +
>> +     return 0;
>> +
>> +err_dsp:
>> +     /* Not implemented */
>> +err_clk:
>> +     clk_put(dsp->pcm_cclk);
>> +err:
>> +     return ret;
>> +}
>> +
>> +static __devexit int s3c64xx_dsp_dev_remove(struct platform_device *pdev)
>> +{
>> +     dev_err(&pdev->dev, "Device removal not yet supported\n");
>> +     return 0;
>> +}
>> +
>> +static struct platform_driver s3c64xx_dsp_driver = {
>> +     .probe  = s3c64xx_dsp_dev_probe,
>> +     .remove = s3c64xx_dsp_dev_remove,
>> +     .driver = {
>> +             .name = "s3c64xx-dsp",
>> +             .owner = THIS_MODULE,
>> +     },
>> +};
>> +
>> +static int __init s3c64xx_dsp_init(void)
>> +{
>> +     return platform_driver_register(&s3c64xx_dsp_driver);
>> +}
>> +module_init(s3c64xx_dsp_init);
>> +
>> +static void __exit s3c64xx_dsp_exit(void)
>> +{
>> +     platform_driver_unregister(&s3c64xx_dsp_driver);
>> +}
>> +module_exit(s3c64xx_dsp_exit);
>> +
>> +/* Module information */
>> +MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
>> +MODULE_DESCRIPTION("S3C64XX PCM Controller Driver");
>> diff --git a/sound/soc/s3c24xx/s3c64xx-dsp.h b/sound/soc/s3c24xx/s3c64xx-dsp.h
>> new file mode 100644
>> index 0000000..cb92346
>> --- /dev/null
>> +++ b/sound/soc/s3c24xx/s3c64xx-dsp.h
>> @@ -0,0 +1,41 @@
>> +/*  sound/soc/s3c24xx/s3c64xx-dsp.h
>> + *
>> + *  ALSA Soc Audio Layer - S3C64XX PCM Controller driver
>> + *
>> + *  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.
>> + */
>> +
>> +#ifndef __SND_SOC_S3C64XX_PCM_H
>> +#define __SND_SOC_S3C64XX_PCM_H __FILE__
>> +
>> +#define S3C64XX_DSP_CLKSRC_PCLK      0
>> +#define S3C64XX_DSP_CLKSRC_MUX       1
>> +
>> +#define S3C64XX_DSP_SYNC_DIV 0
>> +#define S3C64XX_DSP_SCLK_DIV 1
>> +
>> +/**
>> + * struct s3c_dsp_info - S3C PCM Controller information
>> + * @dev: The parent device passed to use from the probe.
>> + * @regs: The pointer to the device register block.
>> + * @dma_playback: DMA information for playback channel.
>> + * @dma_capture: DMA information for capture channel.
>> + */
>> +struct s3c_dsp_info {
>> +     struct device   *dev;
>> +     void __iomem    *regs;
>> +
>> +     /* Whether to keep PCMSCLK enabled even when idle(no active xfer) */
>> +     unsigned int idleclk;
>> +
>> +     struct clk      *pcm_pclk;
>> +     struct clk      *pcm_cclk;
>> +
>> +     struct s3c24xx_pcm_dma_params   *dma_playback;
>> +     struct s3c24xx_pcm_dma_params   *dma_capture;
>> +};
>> +
>> +#endif /* __SND_SOC_S3C64XX_PCM_H */
>> --
>> 1.6.2.5
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-samsung-soc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>
> --
> "You grabbed my hand and we fell into it, like a daydream - or a fever."
>

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-02 11:39         ` Ben Dooks
  2009-11-02 11:56           ` Mark Brown
@ 2009-11-03  6:59           ` jassi brar
  2009-11-03  9:54             ` Mark Brown
  1 sibling, 1 reply; 11+ messages in thread
From: jassi brar @ 2009-11-03  6:59 UTC (permalink / raw)
  To: Ben Dooks; +Cc: Mark Brown, linux-samsung-soc, Jassi Brar

On Mon, Nov 2, 2009 at 8:39 PM, Ben Dooks <ben@trinity.fluff.org> wrote:
>
>> > +   dai->private_data = dsp;
>> > +
>> > +   if (!base) {
>> > +           struct resource *res = platform_get_resource(pdev,
>> > +                                                        IORESOURCE_MEM,
>> > +                                                        0);
>> > +           if (!res) {
>> > +                   dev_err(dev, "Unable to get register resource\n");
>> > +                   return -ENXIO;
>> > +           }
>> > +
>> > +           if (!request_mem_region(res->start, resource_size(res),
>> > +                                   "s3c64xx-dsp")) {
>> > +                   dev_err(dev, "Unable to request register region\n");
>> > +                   return -EBUSY;
>> > +           }
>> > +
>> > +           base = res->start;
>> > +   }
>
> I would like to see platform_devices with their proper resources being
> mandatory for new drivers. We could do with this lot proplerly following
> the device driver model.
sorry, i didn't get it. could u please clarify more?


>> > +/* Module information */
>> > +MODULE_AUTHOR("Jaswinder Singh, <jassi.brar@samsung.com>");
>> > +MODULE_DESCRIPTION("S3C64XX PCM Controller Driver");
>
> no module license.
I missed that, will add. thanks.

>
> --
> Ben
>
> Q:      What's a light-year?
> A:      One-third less calories than a regular year.
>
>

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-03  2:42         ` jassi brar
@ 2009-11-03  9:52           ` Mark Brown
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2009-11-03  9:52 UTC (permalink / raw)
  To: jassi brar; +Cc: linux-samsung-soc, Jassi Brar

On Tue, Nov 03, 2009 at 11:42:21AM +0900, jassi brar wrote:
> On Mon, Nov 2, 2009 at 8:17 PM, Mark Brown

> >> +             local_irq_save(irqs);

> > Why local_irq_save()?  On existing uniprocessor systems they should be

> Don't we need to protect critical mode change in PCM control register?
> Since the s3c64xx_dsp_snd_tx/rxctrl is small and non-blocking, I think
> protection by simply enabling/disabling IRQs should be fine.

Yes, but you're only disabling IRQs on the local CPU.  This means that a
future multi-core CPU variant won't get the benefit of the lock.  Since
the locking primitives are implemented so that the SMP-specifics compile
out there should be no performance overhead from being prepared for
that.

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

* Re: [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers
  2009-11-03  6:59           ` jassi brar
@ 2009-11-03  9:54             ` Mark Brown
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Brown @ 2009-11-03  9:54 UTC (permalink / raw)
  To: jassi brar; +Cc: Ben Dooks, linux-samsung-soc, Jassi Brar

On Tue, Nov 03, 2009 at 03:59:46PM +0900, jassi brar wrote:
> On Mon, Nov 2, 2009 at 8:39 PM, Ben Dooks <ben@trinity.fluff.org> wrote:

> >> > +   if (!base) {
> >> > +           struct resource *res = platform_get_resource(pdev,
> >> > +                                                        IORESOURCE_MEM,
> >> > +                                                        0);

> > I would like to see platform_devices with their proper resources being
> > mandatory for new drivers. We could do with this lot proplerly following
> > the device driver model.

> sorry, i didn't get it. could u please clarify more?

You should just be unconditionally using the resources obtained with
platform_get_resource() - the only reason the I2S driver permits the
base address to be passed in is to deal with the fact that the old
s3c24xx drivers didn't use the device model.  

Since you don't have the core code shared between multiple drivers like
I2S you could just roll this code into the main probe function too.

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

end of thread, other threads:[~2009-11-03  9:54 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-11-02  2:09 [PATCH 1/4] S3C64XX DSP: Added base and register defines for PCM controllers jassisinghbrar
2009-11-02  2:09 ` [PATCH 2/4] S3C64XX DSP: Added PCLK clock source for the " jassisinghbrar
2009-11-02  2:09   ` [PATCH 3/4] S3C64XX DSP: Defined PCM controller platform devices jassisinghbrar
2009-11-02  2:09     ` [PATCH 4/4] S3C64XX DSP: Added the CPU driver for PCM controllers jassisinghbrar
2009-11-02 11:17       ` Mark Brown
2009-11-02 11:39         ` Ben Dooks
2009-11-02 11:56           ` Mark Brown
2009-11-03  6:59           ` jassi brar
2009-11-03  9:54             ` Mark Brown
2009-11-03  2:42         ` jassi brar
2009-11-03  9:52           ` Mark Brown

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.