Alsa-devel
Threads by month
- ----- 2024 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
March 2010
- 110 participants
- 232 discussions
[alsa-devel] [PATCH] ASoC: DaVinci: Add hw_param callback for S/PDIF DIT link
by Chaithrika U S 10 Mar '10
by Chaithrika U S 10 Mar '10
10 Mar '10
On TI DM6467 EVM, S/PDIF DIT codec fails to open as it is unable to install
hardware params. This dummy codec has no set_fmt and set_sysclk implementations
and calls from the application to these functions cause errors. This patch adds
a new hardware params callback function for S/PDIF transciever codec.
Signed-off-by: Chaithrika U S <chaithrika(a)ti.com>
Tested-by: Anuj Aggarwal <anuj.aggarwal(a)ti.com>
---
This patch has been re-worked upon based on the review comments for
http://mailman.alsa-project.org/pipermail/alsa-devel/2010-January/024621.ht…
Applies to ALSA GIT tree on branch topic/asoc at
http://git.kernel.org/?p=linux/kernel/git/tiwai/sound-2.6.git;a=shortlog;
h=topic/asoc
sound/soc/davinci/davinci-evm.c | 16 +++++++++++++++-
1 files changed, 15 insertions(+), 1 deletions(-)
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c
index 7ccbe66..dba6651 100644
--- a/sound/soc/davinci/davinci-evm.c
+++ b/sound/soc/davinci/davinci-evm.c
@@ -81,10 +81,24 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
return 0;
}
+static int evm_spdif_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 *cpu_dai = rtd->dai->cpu_dai;
+
+ /* set cpu DAI configuration */
+ return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
+}
+
static struct snd_soc_ops evm_ops = {
.hw_params = evm_hw_params,
};
+static struct snd_soc_ops evm_spdif_ops = {
+ .hw_params = evm_spdif_hw_params,
+};
+
/* davinci-evm machine dapm widgets */
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
SND_SOC_DAPM_HP("Headphone Jack", NULL),
@@ -165,7 +179,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
.stream_name = "spdif",
.cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
.codec_dai = &dit_stub_dai,
- .ops = &evm_ops,
+ .ops = &evm_spdif_ops,
},
};
static struct snd_soc_dai_link da8xx_evm_dai = {
--
1.5.6
3
2
Enable sound on aspenite. Hifi mode is supported.
Signed-off-by: Haojian Zhuang <haojian.zhuang(a)marvell.com>
---
arch/arm/mach-mmp/aspenite.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/arch/arm/mach-mmp/aspenite.c b/arch/arm/mach-mmp/aspenite.c
index a2d307e..244655d 100644
--- a/arch/arm/mach-mmp/aspenite.c
+++ b/arch/arm/mach-mmp/aspenite.c
@@ -59,6 +59,13 @@ static unsigned long common_pin_config[] __initdata = {
/* UART1 */
GPIO107_UART1_RXD,
GPIO108_UART1_TXD,
+
+ /* SSP1 */
+ GPIO113_I2S_MCLK,
+ GPIO114_I2S_FRM,
+ GPIO115_I2S_BCLK,
+ GPIO116_I2S_RXD,
+ GPIO117_I2S_TXD,
};
static struct smc91x_platdata smc91x_info = {
@@ -123,12 +130,18 @@ static struct pxa3xx_nand_platform_data
aspenite_nand_info = {
.nr_parts = ARRAY_SIZE(aspenite_nand_partitions),
};
+static struct i2c_board_info aspenite_i2c_info[] __initdata = {
+ { I2C_BOARD_INFO("wm8753", 0x1b), },
+};
+
static void __init common_init(void)
{
mfp_config(ARRAY_AND_SIZE(common_pin_config));
/* on-chip devices */
pxa168_add_uart(1);
+ pxa168_add_twsi(1, NULL, ARRAY_AND_SIZE(aspenite_i2c_info));
+ pxa168_add_ssp(1);
pxa168_add_nand(&aspenite_nand_info);
/* off-chip devices */
--
1.5.6.5
1
0
Support ssp in pxa168. The basic function of SSP is same as pxa, but clock
source and IRQ is changed.
Signed-off-by: Haojian Zhuang <haojian.zhuang(a)marvell.com>
---
arch/arm/mach-mmp/include/mach/irqs.h | 10 +-
arch/arm/mach-mmp/include/mach/pxa168.h | 21 ++++
arch/arm/mach-mmp/include/mach/regs-apbc.h | 10 +-
arch/arm/mach-mmp/include/mach/regs-mpmu.h | 48 ++++++++++
arch/arm/mach-mmp/include/mach/regs-ssp.h | 141 ++++++++++++++++++++++++++++
arch/arm/mach-mmp/pxa168.c | 15 +++
arch/arm/plat-pxa/include/plat/ssp.h | 2 +
arch/arm/plat-pxa/ssp.c | 1 +
8 files changed, 238 insertions(+), 10 deletions(-)
create mode 100644 arch/arm/mach-mmp/include/mach/regs-mpmu.h
create mode 100644 arch/arm/mach-mmp/include/mach/regs-ssp.h
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h
b/arch/arm/mach-mmp/include/mach/irqs.h
index 0270119..b379cde 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -5,10 +5,10 @@
* Interrupt numbers for PXA168
*/
#define IRQ_PXA168_NONE (-1)
-#define IRQ_PXA168_SSP3 0
-#define IRQ_PXA168_SSP2 1
-#define IRQ_PXA168_SSP1 2
-#define IRQ_PXA168_SSP0 3
+#define IRQ_PXA168_SSP4 0
+#define IRQ_PXA168_SSP3 1
+#define IRQ_PXA168_SSP2 2
+#define IRQ_PXA168_SSP1 3
#define IRQ_PXA168_PMIC_INT 4
#define IRQ_PXA168_RTC_INT 5
#define IRQ_PXA168_RTC_ALARM 6
@@ -20,7 +20,7 @@
#define IRQ_PXA168_TIMER2 14
#define IRQ_PXA168_TIMER3 15
#define IRQ_PXA168_CMU 16
-#define IRQ_PXA168_SSP4 17
+#define IRQ_PXA168_SSP5 17
#define IRQ_PXA168_MSP_WAKEUP 19
#define IRQ_PXA168_CF_WAKEUP 20
#define IRQ_PXA168_XD_WAKEUP 21
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h
b/arch/arm/mach-mmp/include/mach/pxa168.h
index 3ad612c..3b2bd5d 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -14,6 +14,11 @@ extern struct pxa_device_desc pxa168_device_pwm1;
extern struct pxa_device_desc pxa168_device_pwm2;
extern struct pxa_device_desc pxa168_device_pwm3;
extern struct pxa_device_desc pxa168_device_pwm4;
+extern struct pxa_device_desc pxa168_device_ssp1;
+extern struct pxa_device_desc pxa168_device_ssp2;
+extern struct pxa_device_desc pxa168_device_ssp3;
+extern struct pxa_device_desc pxa168_device_ssp4;
+extern struct pxa_device_desc pxa168_device_ssp5;
extern struct pxa_device_desc pxa168_device_nand;
static inline int pxa168_add_uart(int id)
@@ -67,6 +72,22 @@ static inline int pxa168_add_pwm(int id)
return pxa_register_device(d, NULL, 0);
}
+static inline int pxa168_add_ssp(int id)
+{
+ struct pxa_device_desc *d = NULL;
+
+ switch (id) {
+ case 1: d = &pxa168_device_ssp1; break;
+ case 2: d = &pxa168_device_ssp2; break;
+ case 3: d = &pxa168_device_ssp3; break;
+ case 4: d = &pxa168_device_ssp4; break;
+ case 5: d = &pxa168_device_ssp5; break;
+ default:
+ return -EINVAL;
+ }
+ return pxa_register_device(d, NULL, 0);
+}
+
static inline int pxa168_add_nand(struct pxa3xx_nand_platform_data *info)
{
return pxa_register_device(&pxa168_device_nand, info, sizeof(*info));
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h
b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 712af03..1a96585 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -26,8 +26,6 @@
#define APBC_PXA168_PWM2 APBC_REG(0x010)
#define APBC_PXA168_PWM3 APBC_REG(0x014)
#define APBC_PXA168_PWM4 APBC_REG(0x018)
-#define APBC_PXA168_SSP1 APBC_REG(0x01c)
-#define APBC_PXA168_SSP2 APBC_REG(0x020)
#define APBC_PXA168_RTC APBC_REG(0x028)
#define APBC_PXA168_TWSI0 APBC_REG(0x02c)
#define APBC_PXA168_KPC APBC_REG(0x030)
@@ -35,14 +33,16 @@
#define APBC_PXA168_AIB APBC_REG(0x03c)
#define APBC_PXA168_SW_JTAG APBC_REG(0x040)
#define APBC_PXA168_ONEWIRE APBC_REG(0x048)
-#define APBC_PXA168_SSP3 APBC_REG(0x04c)
#define APBC_PXA168_ASFAR APBC_REG(0x050)
#define APBC_PXA168_ASSAR APBC_REG(0x054)
-#define APBC_PXA168_SSP4 APBC_REG(0x058)
-#define APBC_PXA168_SSP5 APBC_REG(0x05c)
#define APBC_PXA168_TWSI1 APBC_REG(0x06c)
#define APBC_PXA168_UART3 APBC_REG(0x070)
#define APBC_PXA168_AC97 APBC_REG(0x084)
+#define APBC_PXA168_SSP1 APBC_REG(0x81c)
+#define APBC_PXA168_SSP2 APBC_REG(0x820)
+#define APBC_PXA168_SSP3 APBC_REG(0x84c)
+#define APBC_PXA168_SSP4 APBC_REG(0x858)
+#define APBC_PXA168_SSP5 APBC_REG(0x85c)
/*
* APB Clock register offsets for PXA910
diff --git a/arch/arm/mach-mmp/include/mach/regs-mpmu.h
b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
new file mode 100644
index 0000000..0d57236
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/arm/mach-mmp/include/mach/regs-mpmu.h
+ *
+ * Main Power Management Unit
+ *
+ * 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 __ASM_MACH_REGS_MPMU_H
+#define __ASM_MACH_REGS_MPMU_H
+
+#include <mach/addr-map.h>
+
+#define MPMU_VIRT_BASE (APB_VIRT_BASE + 0x50000)
+#define MPMU_REG(off) (MPMU_VIRT_BASE + (off))
+
+#define MPMU_CPCR MPMU_REG(0x0000)
+#define MPMU_FCCR MPMU_REG(0x0008)
+#define MPMU_POCR MPMU_REG(0x000c)
+#define MPMU_POSR MPMU_REG(0x0010)
+#define MPMU_SUCCR MPMU_REG(0x0014)
+#define MPMU_VRCR MPMU_REG(0x0018)
+#define MPMU_OHCR MPMU_REG(0x001c)
+#define MPMU_GPCR MPMU_REG(0x0030)
+#define MPMU_PLL2CR MPMU_REG(0x0034)
+#define MPMU_SCCR MPMU_REG(0x0038)
+#define MPMU_CWUCRM MPMU_REG(0x004c)
+#define MPMU_PLL1_REG1 MPMU_REG(0x0050)
+#define MPMU_PLL1_REG2 MPMU_REG(0x0054)
+#define MPMU_PLL1_SSC MPMU_REG(0x0058)
+#define MPMU_PLL2_REG1 MPMU_REG(0x0060)
+#define MPMU_PLL2_REG2 MPMU_REG(0x0064)
+#define MPMU_PLL2_SSC MPMU_REG(0x0068)
+#define MPMU_TS MPMU_REG(0x0080)
+#define MPMU_WDTPCR MPMU_REG(0x0200)
+#define MPMU_APCR MPMU_REG(0x1000)
+#define MPMU_APSR MPMU_REG(0x1004)
+#define MPMU_APRR MPMU_REG(0x1020)
+#define MPMU_ACGR MPMU_REG(0x1024)
+#define MPMU_ARSR MPMU_REG(0x1028)
+#define MPMU_AWUCRS MPMU_REG(0x1048)
+#define MPMU_AWUCRM MPMU_REG(0x104c)
+#define MPMU_ASYSDR MPMU_REG(0x1050)
+#define MPMU_ASSPDR MPMU_REG(0x1054)
+
+#endif /* __ASM_MACH_REGS_APMU_H */
diff --git a/arch/arm/mach-mmp/include/mach/regs-ssp.h
b/arch/arm/mach-mmp/include/mach/regs-ssp.h
new file mode 100644
index 0000000..7e16eeb
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-ssp.h
@@ -0,0 +1,141 @@
+#ifndef __ASM_ARCH_REGS_SSP_H
+#define __ASM_ARCH_REGS_SSP_H
+
+/*
+ * SSP Serial Port Registers
+ */
+
+#define SSCR0 (0x00) /* SSP Control Register 0 */
+#define SSCR1 (0x04) /* SSP Control Register 1 */
+#define SSSR (0x08) /* SSP Status Register */
+#define SSITR (0x0C) /* SSP Interrupt Test Register */
+#define SSDR (0x10) /* SSP Data Write/Data Read Register */
+
+#define SSTO (0x28) /* SSP Time Out Register */
+#define SSPSP (0x2C) /* SSP Programmable Serial Protocol */
+#define SSTSA (0x30) /* SSP Tx Timeslot Active */
+#define SSRSA (0x34) /* SSP Rx Timeslot Active */
+#define SSTSS (0x38) /* SSP Timeslot Status */
+
+#if defined(CONFIG_CPU_PXA910)
+#define SSACD (0x3C) /* SSP Audio Clock Divider */
+#define SSACDD (0x40) /* SSP Audio Clock Dither Divider */
+#endif
+
+/* Common bits first */
+#define SSCR0_DSS_MASK (0x0000000f) /* Data Size Select (mask) */
+#define SSCR0_DSS(x) ((x) - 1) /* Data Size Select [4..16] */
+#define SSCR0_FRF (0x3 << 4) /* FRame Format (mask) */
+#define SSCR0_Motorola (0x0 << 4) /* Motorola's Serial Peripheral
Interface (SPI) */
+#define SSCR0_TI (0x1 << 4) /* Texas Instruments' Synchronous Serial
Protocol (SSP) */
+#define SSCR0_National (0x2 << 4) /* National Microwire */
+#define SSCR0_PSP (0x3 << 4) /* Programmable Serial Protocol (PSP) */
+#define SSCR0_ECS (1 << 6) /* External clock select */
+#define SSCR0_SSE (1 << 7) /* Synchronous Serial Port Enable */
+
+#define SSCR0_SCR (0xfff << 8) /* Serial Clock Rate (mask) */
+#define SSCR0_SerClkDiv(x) (((x) - 1) << 8) /* Divisor [1..4096] */
+
+#define SSCR0_EDSS (1 << 20) /* Extended data size select */
+#define SSCR0_NCS (1 << 21) /* Network clock select */
+#define SSCR0_RIM (1 << 22) /* Receive FIFO overrrun interrupt mask */
+#define SSCR0_TIM (1 << 23) /* Transmit FIFO underrun interrupt mask */
+#define SSCR0_FRDC (0x7 << 24) /* Frame rate divider control (mask) */
+#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per
frame [1..8] */
+#define SSCR0_FPCKE (1 << 29) /* FIFO packing enable */
+#define SSCR0_ACS (1 << 30) /* Audio clock select */
+#define SSCR0_MOD (1 << 31) /* Mode (normal or network) */
+
+#if defined(CONFIG_CPU_PXA168) || defined(CONFIG_CPU_PXA910)
+#define SSCR0_MODE_52M (1 << 27) /* 52Mbps Mode */
+#endif
+
+#define SSCR1_RIE (1 << 0) /* Receive FIFO Interrupt Enable */
+#define SSCR1_TIE (1 << 1) /* Transmit FIFO Interrupt Enable */
+#define SSCR1_LBM (1 << 2) /* Loop-Back Mode */
+#define SSCR1_SPO (1 << 3) /* Motorola SPI SSPSCLK polarity setting */
+#define SSCR1_SPH (1 << 4) /* Motorola SPI SSPSCLK phase setting */
+#define SSCR1_TFT_MASK (0xf << 6) /* Transmit FIFO Threshold (mask) */
+#define SSCR1_TFT(x) (((x) - 1) << 6) /* level [1..16] */
+#define SSCR1_RFT_MASK (0xf << 10) /* Receive FIFO Threshold (mask) */
+#define SSCR1_RFT(x) (((x) - 1) << 10) /* level [1..16] */
+#define SSCR1_EFWR (1 << 14) /* Enable FIFO Write/read */
+#define SSCR1_STRF (1 << 15) /* Select FIFO for EFWR */
+#define SSCR1_IFS (1 << 16) /* Invert Frame Signal */
+#define SSCR1_PINTE (1 << 18) /* Peripheral Trailing Byte Interrupt Enable */
+#define SSCR1_TINTE (1 << 19) /* Receiver Timeout Interrupt Enable */
+#define SSCR1_RSRE (1 << 20) /* Receive Service Request Enable */
+#define SSCR1_TSRE (1 << 21) /* Transmit Service Request Enable */
+#define SSCR1_TRAIL (1 << 22) /* Trailing Byte */
+#define SSCR1_RWOT (1 << 23) /* Receive Without Transmit */
+#define SSCR1_SFRMDIR (1 << 24) /* SSP Frame (SSPSFRMx) Direction */
+#define SSCR1_SCLKDIR (1 << 25) /* SSP Serial Bit Rate Clock
(SSPSCLKx) Direction */
+#define SSCR1_ECRB (1 << 26) /* Enable Clock Request B */
+#define SSCR1_ECRA (1 << 27) /* Enable Clock Request A */
+#define SSCR1_SCFR (1 << 28) /* Slave Clock Free Running */
+#define SSCR1_EBCEI (1 << 29) /* Enable Bit Count Error Interrupt */
+#define SSCR1_TTE (1 << 30) /* TxD Three-state Enable */
+#define SSCR1_TTELP (1 << 31) /* TxD Three-state Enable On Last Phase */
+
+#if defined(CONFIG_CPU_PXA910)
+#define SSCR1_MWDS (1 << 5) /* Microwire Transmit Data Size */
+#endif
+
+#define SSSR_TNF (1 << 2) /* Transmit FIFO Not Full */
+#define SSSR_RNE (1 << 3) /* Receive FIFO Not Empty */
+#define SSSR_BSY (1 << 4) /* SSP Busy */
+#define SSSR_TFS (1 << 5) /* Transmit FIFO Service Request */
+#define SSSR_RFS (1 << 6) /* Receive FIFO Service Request */
+#define SSSR_ROR (1 << 7) /* Receive FIFO Overrun */
+#define SSSR_TFL_MASK (0xf << 8) /* Transmit FIFO Level (mask) */
+#define SSSR_TFL(x) ((x) << 8)
+#define SSSR_RFL_MASK (0xf << 12) /* Receive FIFO Level */
+#define SSSR_RFL(x) ((x) << 12)
+#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
+#define SSSR_TINT (1 << 19) /* Receiver Timeout Interrupt */
+#define SSSR_EOC (1 << 20) /* End of Chain */
+#define SSSR_TUR (1 << 21) /* Transmit FIFO Underrun */
+#define SSSR_CSS (1 << 22) /* Clock Synchronisation Status */
+#define SSSR_BCE (1 << 23) /* Bit Count Error */
+#define SSSR_TX_OSS (1 << 30) /* Tx FIFO Odd Sample Status */
+#define SSSR_OSS (1 << 31) /* Odd Sample Status */
+
+#define SSITR_TTFS (1 << 5) /* Test Tx FIFO Service Request */
+#define SSITR_TRFS (1 << 6) /* Test Rx FIFO Service Request */
+#define SSITR_TROR (1 << 7) /* Test Rx FIFO Overrun */
+
+#define SSPSP_SCMODE_MASK (0x3) /* Serial Bit Rate Clock Mode */
+#define SSPSP_SCMODE(x) ((x) << 0)
+#define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */
+#define SSPSP_ETDS (1 << 3) /* End of Transfer data State */
+#define SSPSP_STRTDLY_MASK (0x7 << 4) /* Start Delay */
+#define SSPSP_STRTDLY(x) ((x) << 4)
+#define SSPSP_DMYSTRT_MASK (0x3 << 7) /* Dummy Start */
+#define SSPSP_DMYSTRT(x) ((x) << 7)
+#define SSPSP_SFRMDLY_MASK (0x7f << 9) /* Serial Frame Delay */
+#define SSPSP_SFRMDLY(x) ((x) << 9)
+#define SSPSP_SFRMWDTH_MASK (0x3f << 16) /* Serial Frame Width */
+#define SSPSP_SFRMWDTH(x) ((x) << 16)
+#define SSPSP_DMYSTOP_MASK (0x3 << 23) /* Dummy Stop */
+#define SSPSP_DMYSTOP(x) ((x) << 23)
+#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
+#define SSPSP_EDMYSTRT_MASK (0x3 << 26) /* Extended Dummy Start */
+#define SSPSP_EDMYSTRT(x) ((x) << 26)
+#define SSPSP_EDMYSTOP_MASK (0x7 << 28) /* Extended Dummy Stop */
+#define SSPSP_EDMYSTOP(x) ((x) << 28)
+#define SSPSP_TIMING_MASK (SSPSP_STRTDLY_MASK | SSPSP_DMYSTRT_MASK \
+ | SSPSP_SFRMDLY_MASK | SSPSP_SFRMWDTH_MASK \
+ | SSPSP_DMYSTOP_MASK | SSPSP_EDMYSTRT_MASK \
+ | SSPSP_EDMYSTOP_MASK | SSPSP_FSRT)
+
+
+#if defined(CONFIG_CPU_PXA910)
+#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */
+#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */
+#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
+#define SSACD_SCDX8 (1 << 7) /* SYSCLK division ratio select */
+#endif
+
+
+#endif /* __ASM_ARCH_REGS_SSP_H */
+
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 37dbdde..5f1a4dd 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -72,6 +72,11 @@ static APBC_CLK(pwm1, PXA168_PWM1, 1, 13000000);
static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000);
static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000);
static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000);
+static APBC_CLK(ssp1, PXA168_SSP1, 4, 0);
+static APBC_CLK(ssp2, PXA168_SSP2, 4, 0);
+static APBC_CLK(ssp3, PXA168_SSP3, 4, 0);
+static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
+static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
static APMU_CLK(nand, NAND, 0x01db, 208000000);
@@ -85,6 +90,11 @@ static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
+ INIT_CLKREG(&clk_ssp1, "pxa168-ssp.0", NULL),
+ INIT_CLKREG(&clk_ssp2, "pxa168-ssp.1", NULL),
+ INIT_CLKREG(&clk_ssp3, "pxa168-ssp.2", NULL),
+ INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
+ INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
};
@@ -132,3 +142,8 @@ PXA168_DEVICE(pwm2, "pxa168-pwm", 1, NONE,
0xd401a400, 0x10);
PXA168_DEVICE(pwm3, "pxa168-pwm", 2, NONE, 0xd401a800, 0x10);
PXA168_DEVICE(pwm4, "pxa168-pwm", 3, NONE, 0xd401ac00, 0x10);
PXA168_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
+PXA168_DEVICE(ssp1, "pxa168-ssp", 0, SSP1, 0xd401b000, 0x40, 52, 53);
+PXA168_DEVICE(ssp2, "pxa168-ssp", 1, SSP2, 0xd401c000, 0x40, 54, 55);
+PXA168_DEVICE(ssp3, "pxa168-ssp", 2, SSP3, 0xd401f000, 0x40, 56, 57);
+PXA168_DEVICE(ssp4, "pxa168-ssp", 3, SSP4, 0xd4020000, 0x40, 58, 59);
+PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
diff --git a/arch/arm/plat-pxa/include/plat/ssp.h
b/arch/arm/plat-pxa/include/plat/ssp.h
index fc83ba7..06cffae 100644
--- a/arch/arm/plat-pxa/include/plat/ssp.h
+++ b/arch/arm/plat-pxa/include/plat/ssp.h
@@ -14,6 +14,7 @@
* PXA26x SSP, NSSP, ASSP
* PXA27x SSP1, SSP2, SSP3
* PXA3xx SSP1, SSP2, SSP3, SSP4
+ * PXA168 SSP1, SSP2, SSP3, SSP4, SSP5
*/
#ifndef __ASM_PLAT_SSP_H
@@ -27,6 +28,7 @@ enum pxa_ssp_type {
PXA25x_SSP, /* pxa 210, 250, 255, 26x */
PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
PXA27x_SSP,
+ PXA168_SSP,
};
struct ssp_device {
diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c
index d4a7673..4dc2ee6 100644
--- a/arch/arm/plat-pxa/ssp.c
+++ b/arch/arm/plat-pxa/ssp.c
@@ -465,6 +465,7 @@ static const struct platform_device_id ssp_id_table[] = {
{ "pxa25x-ssp", PXA25x_SSP },
{ "pxa25x-nssp", PXA25x_NSSP },
{ "pxa27x-ssp", PXA27x_SSP },
+ { "pxa168-ssp", PXA168_SSP },
{ },
};
--
1.5.6.5
1
0
Support ssp in pxa168. The basic function of SSP is same as pxa, but clock
source and IRQ is changed.
Signed-off-by: Haojian Zhuang <haojian.zhuang(a)marvell.com>
---
arch/arm/mach-mmp/include/mach/irqs.h | 10 +-
arch/arm/mach-mmp/include/mach/pxa168.h | 21 ++++
arch/arm/mach-mmp/include/mach/regs-apbc.h | 10 +-
arch/arm/mach-mmp/include/mach/regs-mpmu.h | 48 ++++++++++
arch/arm/mach-mmp/include/mach/regs-ssp.h | 141 ++++++++++++++++++++++++++++
arch/arm/mach-mmp/pxa168.c | 15 +++
arch/arm/plat-pxa/include/plat/ssp.h | 2 +
arch/arm/plat-pxa/ssp.c | 1 +
8 files changed, 238 insertions(+), 10 deletions(-)
create mode 100644 arch/arm/mach-mmp/include/mach/regs-mpmu.h
create mode 100644 arch/arm/mach-mmp/include/mach/regs-ssp.h
diff --git a/arch/arm/mach-mmp/include/mach/irqs.h
b/arch/arm/mach-mmp/include/mach/irqs.h
index 0270119..b379cde 100644
--- a/arch/arm/mach-mmp/include/mach/irqs.h
+++ b/arch/arm/mach-mmp/include/mach/irqs.h
@@ -5,10 +5,10 @@
* Interrupt numbers for PXA168
*/
#define IRQ_PXA168_NONE (-1)
-#define IRQ_PXA168_SSP3 0
-#define IRQ_PXA168_SSP2 1
-#define IRQ_PXA168_SSP1 2
-#define IRQ_PXA168_SSP0 3
+#define IRQ_PXA168_SSP4 0
+#define IRQ_PXA168_SSP3 1
+#define IRQ_PXA168_SSP2 2
+#define IRQ_PXA168_SSP1 3
#define IRQ_PXA168_PMIC_INT 4
#define IRQ_PXA168_RTC_INT 5
#define IRQ_PXA168_RTC_ALARM 6
@@ -20,7 +20,7 @@
#define IRQ_PXA168_TIMER2 14
#define IRQ_PXA168_TIMER3 15
#define IRQ_PXA168_CMU 16
-#define IRQ_PXA168_SSP4 17
+#define IRQ_PXA168_SSP5 17
#define IRQ_PXA168_MSP_WAKEUP 19
#define IRQ_PXA168_CF_WAKEUP 20
#define IRQ_PXA168_XD_WAKEUP 21
diff --git a/arch/arm/mach-mmp/include/mach/pxa168.h
b/arch/arm/mach-mmp/include/mach/pxa168.h
index 3ad612c..3b2bd5d 100644
--- a/arch/arm/mach-mmp/include/mach/pxa168.h
+++ b/arch/arm/mach-mmp/include/mach/pxa168.h
@@ -14,6 +14,11 @@ extern struct pxa_device_desc pxa168_device_pwm1;
extern struct pxa_device_desc pxa168_device_pwm2;
extern struct pxa_device_desc pxa168_device_pwm3;
extern struct pxa_device_desc pxa168_device_pwm4;
+extern struct pxa_device_desc pxa168_device_ssp1;
+extern struct pxa_device_desc pxa168_device_ssp2;
+extern struct pxa_device_desc pxa168_device_ssp3;
+extern struct pxa_device_desc pxa168_device_ssp4;
+extern struct pxa_device_desc pxa168_device_ssp5;
extern struct pxa_device_desc pxa168_device_nand;
static inline int pxa168_add_uart(int id)
@@ -67,6 +72,22 @@ static inline int pxa168_add_pwm(int id)
return pxa_register_device(d, NULL, 0);
}
+static inline int pxa168_add_ssp(int id)
+{
+ struct pxa_device_desc *d = NULL;
+
+ switch (id) {
+ case 1: d = &pxa168_device_ssp1; break;
+ case 2: d = &pxa168_device_ssp2; break;
+ case 3: d = &pxa168_device_ssp3; break;
+ case 4: d = &pxa168_device_ssp4; break;
+ case 5: d = &pxa168_device_ssp5; break;
+ default:
+ return -EINVAL;
+ }
+ return pxa_register_device(d, NULL, 0);
+}
+
static inline int pxa168_add_nand(struct pxa3xx_nand_platform_data *info)
{
return pxa_register_device(&pxa168_device_nand, info, sizeof(*info));
diff --git a/arch/arm/mach-mmp/include/mach/regs-apbc.h
b/arch/arm/mach-mmp/include/mach/regs-apbc.h
index 712af03..1a96585 100644
--- a/arch/arm/mach-mmp/include/mach/regs-apbc.h
+++ b/arch/arm/mach-mmp/include/mach/regs-apbc.h
@@ -26,8 +26,6 @@
#define APBC_PXA168_PWM2 APBC_REG(0x010)
#define APBC_PXA168_PWM3 APBC_REG(0x014)
#define APBC_PXA168_PWM4 APBC_REG(0x018)
-#define APBC_PXA168_SSP1 APBC_REG(0x01c)
-#define APBC_PXA168_SSP2 APBC_REG(0x020)
#define APBC_PXA168_RTC APBC_REG(0x028)
#define APBC_PXA168_TWSI0 APBC_REG(0x02c)
#define APBC_PXA168_KPC APBC_REG(0x030)
@@ -35,14 +33,16 @@
#define APBC_PXA168_AIB APBC_REG(0x03c)
#define APBC_PXA168_SW_JTAG APBC_REG(0x040)
#define APBC_PXA168_ONEWIRE APBC_REG(0x048)
-#define APBC_PXA168_SSP3 APBC_REG(0x04c)
#define APBC_PXA168_ASFAR APBC_REG(0x050)
#define APBC_PXA168_ASSAR APBC_REG(0x054)
-#define APBC_PXA168_SSP4 APBC_REG(0x058)
-#define APBC_PXA168_SSP5 APBC_REG(0x05c)
#define APBC_PXA168_TWSI1 APBC_REG(0x06c)
#define APBC_PXA168_UART3 APBC_REG(0x070)
#define APBC_PXA168_AC97 APBC_REG(0x084)
+#define APBC_PXA168_SSP1 APBC_REG(0x81c)
+#define APBC_PXA168_SSP2 APBC_REG(0x820)
+#define APBC_PXA168_SSP3 APBC_REG(0x84c)
+#define APBC_PXA168_SSP4 APBC_REG(0x858)
+#define APBC_PXA168_SSP5 APBC_REG(0x85c)
/*
* APB Clock register offsets for PXA910
diff --git a/arch/arm/mach-mmp/include/mach/regs-mpmu.h
b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
new file mode 100644
index 0000000..0d57236
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-mpmu.h
@@ -0,0 +1,48 @@
+/*
+ * linux/arch/arm/mach-mmp/include/mach/regs-mpmu.h
+ *
+ * Main Power Management Unit
+ *
+ * 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 __ASM_MACH_REGS_MPMU_H
+#define __ASM_MACH_REGS_MPMU_H
+
+#include <mach/addr-map.h>
+
+#define MPMU_VIRT_BASE (APB_VIRT_BASE + 0x50000)
+#define MPMU_REG(off) (MPMU_VIRT_BASE + (off))
+
+#define MPMU_CPCR MPMU_REG(0x0000)
+#define MPMU_FCCR MPMU_REG(0x0008)
+#define MPMU_POCR MPMU_REG(0x000c)
+#define MPMU_POSR MPMU_REG(0x0010)
+#define MPMU_SUCCR MPMU_REG(0x0014)
+#define MPMU_VRCR MPMU_REG(0x0018)
+#define MPMU_OHCR MPMU_REG(0x001c)
+#define MPMU_GPCR MPMU_REG(0x0030)
+#define MPMU_PLL2CR MPMU_REG(0x0034)
+#define MPMU_SCCR MPMU_REG(0x0038)
+#define MPMU_CWUCRM MPMU_REG(0x004c)
+#define MPMU_PLL1_REG1 MPMU_REG(0x0050)
+#define MPMU_PLL1_REG2 MPMU_REG(0x0054)
+#define MPMU_PLL1_SSC MPMU_REG(0x0058)
+#define MPMU_PLL2_REG1 MPMU_REG(0x0060)
+#define MPMU_PLL2_REG2 MPMU_REG(0x0064)
+#define MPMU_PLL2_SSC MPMU_REG(0x0068)
+#define MPMU_TS MPMU_REG(0x0080)
+#define MPMU_WDTPCR MPMU_REG(0x0200)
+#define MPMU_APCR MPMU_REG(0x1000)
+#define MPMU_APSR MPMU_REG(0x1004)
+#define MPMU_APRR MPMU_REG(0x1020)
+#define MPMU_ACGR MPMU_REG(0x1024)
+#define MPMU_ARSR MPMU_REG(0x1028)
+#define MPMU_AWUCRS MPMU_REG(0x1048)
+#define MPMU_AWUCRM MPMU_REG(0x104c)
+#define MPMU_ASYSDR MPMU_REG(0x1050)
+#define MPMU_ASSPDR MPMU_REG(0x1054)
+
+#endif /* __ASM_MACH_REGS_APMU_H */
diff --git a/arch/arm/mach-mmp/include/mach/regs-ssp.h
b/arch/arm/mach-mmp/include/mach/regs-ssp.h
new file mode 100644
index 0000000..7e16eeb
--- /dev/null
+++ b/arch/arm/mach-mmp/include/mach/regs-ssp.h
@@ -0,0 +1,141 @@
+#ifndef __ASM_ARCH_REGS_SSP_H
+#define __ASM_ARCH_REGS_SSP_H
+
+/*
+ * SSP Serial Port Registers
+ */
+
+#define SSCR0 (0x00) /* SSP Control Register 0 */
+#define SSCR1 (0x04) /* SSP Control Register 1 */
+#define SSSR (0x08) /* SSP Status Register */
+#define SSITR (0x0C) /* SSP Interrupt Test Register */
+#define SSDR (0x10) /* SSP Data Write/Data Read Register */
+
+#define SSTO (0x28) /* SSP Time Out Register */
+#define SSPSP (0x2C) /* SSP Programmable Serial Protocol */
+#define SSTSA (0x30) /* SSP Tx Timeslot Active */
+#define SSRSA (0x34) /* SSP Rx Timeslot Active */
+#define SSTSS (0x38) /* SSP Timeslot Status */
+
+#if defined(CONFIG_CPU_PXA910)
+#define SSACD (0x3C) /* SSP Audio Clock Divider */
+#define SSACDD (0x40) /* SSP Audio Clock Dither Divider */
+#endif
+
+/* Common bits first */
+#define SSCR0_DSS_MASK (0x0000000f) /* Data Size Select (mask) */
+#define SSCR0_DSS(x) ((x) - 1) /* Data Size Select [4..16] */
+#define SSCR0_FRF (0x3 << 4) /* FRame Format (mask) */
+#define SSCR0_Motorola (0x0 << 4) /* Motorola's Serial Peripheral
Interface (SPI) */
+#define SSCR0_TI (0x1 << 4) /* Texas Instruments' Synchronous Serial
Protocol (SSP) */
+#define SSCR0_National (0x2 << 4) /* National Microwire */
+#define SSCR0_PSP (0x3 << 4) /* Programmable Serial Protocol (PSP) */
+#define SSCR0_ECS (1 << 6) /* External clock select */
+#define SSCR0_SSE (1 << 7) /* Synchronous Serial Port Enable */
+
+#define SSCR0_SCR (0xfff << 8) /* Serial Clock Rate (mask) */
+#define SSCR0_SerClkDiv(x) (((x) - 1) << 8) /* Divisor [1..4096] */
+
+#define SSCR0_EDSS (1 << 20) /* Extended data size select */
+#define SSCR0_NCS (1 << 21) /* Network clock select */
+#define SSCR0_RIM (1 << 22) /* Receive FIFO overrrun interrupt mask */
+#define SSCR0_TIM (1 << 23) /* Transmit FIFO underrun interrupt mask */
+#define SSCR0_FRDC (0x7 << 24) /* Frame rate divider control (mask) */
+#define SSCR0_SlotsPerFrm(x) (((x) - 1) << 24) /* Time slots per
frame [1..8] */
+#define SSCR0_FPCKE (1 << 29) /* FIFO packing enable */
+#define SSCR0_ACS (1 << 30) /* Audio clock select */
+#define SSCR0_MOD (1 << 31) /* Mode (normal or network) */
+
+#if defined(CONFIG_CPU_PXA168) || defined(CONFIG_CPU_PXA910)
+#define SSCR0_MODE_52M (1 << 27) /* 52Mbps Mode */
+#endif
+
+#define SSCR1_RIE (1 << 0) /* Receive FIFO Interrupt Enable */
+#define SSCR1_TIE (1 << 1) /* Transmit FIFO Interrupt Enable */
+#define SSCR1_LBM (1 << 2) /* Loop-Back Mode */
+#define SSCR1_SPO (1 << 3) /* Motorola SPI SSPSCLK polarity setting */
+#define SSCR1_SPH (1 << 4) /* Motorola SPI SSPSCLK phase setting */
+#define SSCR1_TFT_MASK (0xf << 6) /* Transmit FIFO Threshold (mask) */
+#define SSCR1_TFT(x) (((x) - 1) << 6) /* level [1..16] */
+#define SSCR1_RFT_MASK (0xf << 10) /* Receive FIFO Threshold (mask) */
+#define SSCR1_RFT(x) (((x) - 1) << 10) /* level [1..16] */
+#define SSCR1_EFWR (1 << 14) /* Enable FIFO Write/read */
+#define SSCR1_STRF (1 << 15) /* Select FIFO for EFWR */
+#define SSCR1_IFS (1 << 16) /* Invert Frame Signal */
+#define SSCR1_PINTE (1 << 18) /* Peripheral Trailing Byte Interrupt Enable */
+#define SSCR1_TINTE (1 << 19) /* Receiver Timeout Interrupt Enable */
+#define SSCR1_RSRE (1 << 20) /* Receive Service Request Enable */
+#define SSCR1_TSRE (1 << 21) /* Transmit Service Request Enable */
+#define SSCR1_TRAIL (1 << 22) /* Trailing Byte */
+#define SSCR1_RWOT (1 << 23) /* Receive Without Transmit */
+#define SSCR1_SFRMDIR (1 << 24) /* SSP Frame (SSPSFRMx) Direction */
+#define SSCR1_SCLKDIR (1 << 25) /* SSP Serial Bit Rate Clock
(SSPSCLKx) Direction */
+#define SSCR1_ECRB (1 << 26) /* Enable Clock Request B */
+#define SSCR1_ECRA (1 << 27) /* Enable Clock Request A */
+#define SSCR1_SCFR (1 << 28) /* Slave Clock Free Running */
+#define SSCR1_EBCEI (1 << 29) /* Enable Bit Count Error Interrupt */
+#define SSCR1_TTE (1 << 30) /* TxD Three-state Enable */
+#define SSCR1_TTELP (1 << 31) /* TxD Three-state Enable On Last Phase */
+
+#if defined(CONFIG_CPU_PXA910)
+#define SSCR1_MWDS (1 << 5) /* Microwire Transmit Data Size */
+#endif
+
+#define SSSR_TNF (1 << 2) /* Transmit FIFO Not Full */
+#define SSSR_RNE (1 << 3) /* Receive FIFO Not Empty */
+#define SSSR_BSY (1 << 4) /* SSP Busy */
+#define SSSR_TFS (1 << 5) /* Transmit FIFO Service Request */
+#define SSSR_RFS (1 << 6) /* Receive FIFO Service Request */
+#define SSSR_ROR (1 << 7) /* Receive FIFO Overrun */
+#define SSSR_TFL_MASK (0xf << 8) /* Transmit FIFO Level (mask) */
+#define SSSR_TFL(x) ((x) << 8)
+#define SSSR_RFL_MASK (0xf << 12) /* Receive FIFO Level */
+#define SSSR_RFL(x) ((x) << 12)
+#define SSSR_PINT (1 << 18) /* Peripheral Trailing Byte Interrupt */
+#define SSSR_TINT (1 << 19) /* Receiver Timeout Interrupt */
+#define SSSR_EOC (1 << 20) /* End of Chain */
+#define SSSR_TUR (1 << 21) /* Transmit FIFO Underrun */
+#define SSSR_CSS (1 << 22) /* Clock Synchronisation Status */
+#define SSSR_BCE (1 << 23) /* Bit Count Error */
+#define SSSR_TX_OSS (1 << 30) /* Tx FIFO Odd Sample Status */
+#define SSSR_OSS (1 << 31) /* Odd Sample Status */
+
+#define SSITR_TTFS (1 << 5) /* Test Tx FIFO Service Request */
+#define SSITR_TRFS (1 << 6) /* Test Rx FIFO Service Request */
+#define SSITR_TROR (1 << 7) /* Test Rx FIFO Overrun */
+
+#define SSPSP_SCMODE_MASK (0x3) /* Serial Bit Rate Clock Mode */
+#define SSPSP_SCMODE(x) ((x) << 0)
+#define SSPSP_SFRMP (1 << 2) /* Serial Frame Polarity */
+#define SSPSP_ETDS (1 << 3) /* End of Transfer data State */
+#define SSPSP_STRTDLY_MASK (0x7 << 4) /* Start Delay */
+#define SSPSP_STRTDLY(x) ((x) << 4)
+#define SSPSP_DMYSTRT_MASK (0x3 << 7) /* Dummy Start */
+#define SSPSP_DMYSTRT(x) ((x) << 7)
+#define SSPSP_SFRMDLY_MASK (0x7f << 9) /* Serial Frame Delay */
+#define SSPSP_SFRMDLY(x) ((x) << 9)
+#define SSPSP_SFRMWDTH_MASK (0x3f << 16) /* Serial Frame Width */
+#define SSPSP_SFRMWDTH(x) ((x) << 16)
+#define SSPSP_DMYSTOP_MASK (0x3 << 23) /* Dummy Stop */
+#define SSPSP_DMYSTOP(x) ((x) << 23)
+#define SSPSP_FSRT (1 << 25) /* Frame Sync Relative Timing */
+#define SSPSP_EDMYSTRT_MASK (0x3 << 26) /* Extended Dummy Start */
+#define SSPSP_EDMYSTRT(x) ((x) << 26)
+#define SSPSP_EDMYSTOP_MASK (0x7 << 28) /* Extended Dummy Stop */
+#define SSPSP_EDMYSTOP(x) ((x) << 28)
+#define SSPSP_TIMING_MASK (SSPSP_STRTDLY_MASK | SSPSP_DMYSTRT_MASK \
+ | SSPSP_SFRMDLY_MASK | SSPSP_SFRMWDTH_MASK \
+ | SSPSP_DMYSTOP_MASK | SSPSP_EDMYSTRT_MASK \
+ | SSPSP_EDMYSTOP_MASK | SSPSP_FSRT)
+
+
+#if defined(CONFIG_CPU_PXA910)
+#define SSACD_SCDB (1 << 3) /* SSPSYSCLK Divider Bypass */
+#define SSACD_ACPS(x) ((x) << 4) /* Audio clock PLL select */
+#define SSACD_ACDS(x) ((x) << 0) /* Audio clock divider select */
+#define SSACD_SCDX8 (1 << 7) /* SYSCLK division ratio select */
+#endif
+
+
+#endif /* __ASM_ARCH_REGS_SSP_H */
+
diff --git a/arch/arm/mach-mmp/pxa168.c b/arch/arm/mach-mmp/pxa168.c
index 37dbdde..5f1a4dd 100644
--- a/arch/arm/mach-mmp/pxa168.c
+++ b/arch/arm/mach-mmp/pxa168.c
@@ -72,6 +72,11 @@ static APBC_CLK(pwm1, PXA168_PWM1, 1, 13000000);
static APBC_CLK(pwm2, PXA168_PWM2, 1, 13000000);
static APBC_CLK(pwm3, PXA168_PWM3, 1, 13000000);
static APBC_CLK(pwm4, PXA168_PWM4, 1, 13000000);
+static APBC_CLK(ssp1, PXA168_SSP1, 4, 0);
+static APBC_CLK(ssp2, PXA168_SSP2, 4, 0);
+static APBC_CLK(ssp3, PXA168_SSP3, 4, 0);
+static APBC_CLK(ssp4, PXA168_SSP4, 4, 0);
+static APBC_CLK(ssp5, PXA168_SSP5, 4, 0);
static APMU_CLK(nand, NAND, 0x01db, 208000000);
@@ -85,6 +90,11 @@ static struct clk_lookup pxa168_clkregs[] = {
INIT_CLKREG(&clk_pwm2, "pxa168-pwm.1", NULL),
INIT_CLKREG(&clk_pwm3, "pxa168-pwm.2", NULL),
INIT_CLKREG(&clk_pwm4, "pxa168-pwm.3", NULL),
+ INIT_CLKREG(&clk_ssp1, "pxa168-ssp.0", NULL),
+ INIT_CLKREG(&clk_ssp2, "pxa168-ssp.1", NULL),
+ INIT_CLKREG(&clk_ssp3, "pxa168-ssp.2", NULL),
+ INIT_CLKREG(&clk_ssp4, "pxa168-ssp.3", NULL),
+ INIT_CLKREG(&clk_ssp5, "pxa168-ssp.4", NULL),
INIT_CLKREG(&clk_nand, "pxa3xx-nand", NULL),
};
@@ -132,3 +142,8 @@ PXA168_DEVICE(pwm2, "pxa168-pwm", 1, NONE,
0xd401a400, 0x10);
PXA168_DEVICE(pwm3, "pxa168-pwm", 2, NONE, 0xd401a800, 0x10);
PXA168_DEVICE(pwm4, "pxa168-pwm", 3, NONE, 0xd401ac00, 0x10);
PXA168_DEVICE(nand, "pxa3xx-nand", -1, NAND, 0xd4283000, 0x80, 97, 99);
+PXA168_DEVICE(ssp1, "pxa168-ssp", 0, SSP1, 0xd401b000, 0x40, 52, 53);
+PXA168_DEVICE(ssp2, "pxa168-ssp", 1, SSP2, 0xd401c000, 0x40, 54, 55);
+PXA168_DEVICE(ssp3, "pxa168-ssp", 2, SSP3, 0xd401f000, 0x40, 56, 57);
+PXA168_DEVICE(ssp4, "pxa168-ssp", 3, SSP4, 0xd4020000, 0x40, 58, 59);
+PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
diff --git a/arch/arm/plat-pxa/include/plat/ssp.h
b/arch/arm/plat-pxa/include/plat/ssp.h
index fc83ba7..06cffae 100644
--- a/arch/arm/plat-pxa/include/plat/ssp.h
+++ b/arch/arm/plat-pxa/include/plat/ssp.h
@@ -14,6 +14,7 @@
* PXA26x SSP, NSSP, ASSP
* PXA27x SSP1, SSP2, SSP3
* PXA3xx SSP1, SSP2, SSP3, SSP4
+ * PXA168 SSP1, SSP2, SSP3, SSP4, SSP5
*/
#ifndef __ASM_PLAT_SSP_H
@@ -27,6 +28,7 @@ enum pxa_ssp_type {
PXA25x_SSP, /* pxa 210, 250, 255, 26x */
PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
PXA27x_SSP,
+ PXA168_SSP,
};
struct ssp_device {
diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c
index d4a7673..4dc2ee6 100644
--- a/arch/arm/plat-pxa/ssp.c
+++ b/arch/arm/plat-pxa/ssp.c
@@ -465,6 +465,7 @@ static const struct platform_device_id ssp_id_table[] = {
{ "pxa25x-ssp", PXA25x_SSP },
{ "pxa25x-nssp", PXA25x_NSSP },
{ "pxa27x-ssp", PXA27x_SSP },
+ { "pxa168-ssp", PXA168_SSP },
{ },
};
--
1.5.6.5
1
0
Since ssp is shared between pxa and mmp, move ssp driver into plat directory.
---
arch/arm/mach-mmp/Kconfig | 5 +
arch/arm/mach-pxa/Kconfig | 10 -
arch/arm/mach-pxa/Makefile | 3 -
arch/arm/mach-pxa/corgi_ssp.c | 2 +-
arch/arm/mach-pxa/include/mach/ssp.h | 109 --------
arch/arm/mach-pxa/littleton.c | 2 +-
arch/arm/mach-pxa/poodle.c | 4 +-
arch/arm/mach-pxa/pxa3xx.c | 2 +-
arch/arm/mach-pxa/ssp.c | 510 ----------------------------------
arch/arm/plat-pxa/Kconfig | 10 +
arch/arm/plat-pxa/Makefile | 1 +
arch/arm/plat-pxa/include/plat/ssp.h | 109 ++++++++
arch/arm/plat-pxa/ssp.c | 510 ++++++++++++++++++++++++++++++++++
sound/soc/pxa/pxa-ssp.c | 2 +-
14 files changed, 641 insertions(+), 638 deletions(-)
delete mode 100644 arch/arm/mach-pxa/include/mach/ssp.h
delete mode 100644 arch/arm/mach-pxa/ssp.c
create mode 100644 arch/arm/plat-pxa/include/plat/ssp.h
create mode 100644 arch/arm/plat-pxa/ssp.c
diff --git a/arch/arm/mach-mmp/Kconfig b/arch/arm/mach-mmp/Kconfig
index 6ab843e..06728b1 100644
--- a/arch/arm/mach-mmp/Kconfig
+++ b/arch/arm/mach-mmp/Kconfig
@@ -5,6 +5,7 @@ menu "Marvell PXA168/910/MMP2 Implmentations"
config MACH_ASPENITE
bool "Marvell's PXA168 Aspenite Development Board"
select CPU_PXA168
+ select PXA_SSP
help
Say 'Y' here if you want to support the Marvell PXA168-based
Aspenite Development Board.
@@ -12,6 +13,7 @@ config MACH_ASPENITE
config MACH_ZYLONITE2
bool "Marvell's PXA168 Zylonite2 Development Board"
select CPU_PXA168
+ select PXA_SSP
help
Say 'Y' here if you want to support the Marvell PXA168-based
Zylonite2 Development Board.
@@ -19,6 +21,7 @@ config MACH_ZYLONITE2
config MACH_AVENGERS_LITE
bool "Marvell's PXA168 Avengers Lite Development Board"
select CPU_PXA168
+ select PXA_SSP
help
Say 'Y' here if you want to support the Marvell PXA168-based
Avengers Lite Development Board.
@@ -26,6 +29,7 @@ config MACH_AVENGERS_LITE
config MACH_TAVOREVB
bool "Marvell's PXA910 TavorEVB Development Board"
select CPU_PXA910
+ select PXA_SSP
help
Say 'Y' here if you want to support the Marvell PXA910-based
TavorEVB Development Board.
@@ -33,6 +37,7 @@ config MACH_TAVOREVB
config MACH_TTC_DKB
bool "Marvell's PXA910 TavorEVB Development Board"
select CPU_PXA910
+ select PXA_SSP
help
Say 'Y' here if you want to support the Marvell PXA910-based
TTC_DKB Development Board.
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index 38fbd0a..ef8744a 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -654,16 +654,6 @@ config PXA_SHARP_Cxx00
help
Enable common support for Sharp Cxx00 models
-config PXA_SSP
- tristate
- help
- Enable support for PXA2xx SSP ports
-
-config PXA_SSP_LEGACY
- bool
- help
- Support of legacy SSP API
-
config TOSA_BT
tristate "Control the state of built-in bluetooth chip on Sharp SL-6000"
depends on MACH_TOSA
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 86bc87b..299d4f5 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -13,9 +13,6 @@ obj-$(CONFIG_PXA27x) += cpufreq-pxa2xx.o
obj-$(CONFIG_PXA3xx) += cpufreq-pxa3xx.o
endif
-# Generic drivers that other drivers may depend upon
-obj-$(CONFIG_PXA_SSP) += ssp.o
-
# SoC-specific code
obj-$(CONFIG_PXA25x) += mfp-pxa2xx.o pxa2xx.o pxa25x.o
obj-$(CONFIG_PXA27x) += mfp-pxa2xx.o pxa2xx.o pxa27x.o
diff --git a/arch/arm/mach-pxa/corgi_ssp.c b/arch/arm/mach-pxa/corgi_ssp.c
index a5ee707..4ebc8e8 100644
--- a/arch/arm/mach-pxa/corgi_ssp.c
+++ b/arch/arm/mach-pxa/corgi_ssp.c
@@ -19,9 +19,9 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
-#include <mach/ssp.h>
#include <mach/pxa2xx-gpio.h>
#include <mach/regs-ssp.h>
+#include <plat/ssp.h>
#include "sharpsl.h"
static DEFINE_SPINLOCK(corgi_ssp_lock);
diff --git a/arch/arm/mach-pxa/include/mach/ssp.h
b/arch/arm/mach-pxa/include/mach/ssp.h
deleted file mode 100644
index be1be5b..0000000
--- a/arch/arm/mach-pxa/include/mach/ssp.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * ssp.h
- *
- * Copyright (C) 2003 Russell King, All Rights Reserved.
- *
- * 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.
- *
- * This driver supports the following PXA CPU/SSP ports:-
- *
- * PXA250 SSP
- * PXA255 SSP, NSSP
- * PXA26x SSP, NSSP, ASSP
- * PXA27x SSP1, SSP2, SSP3
- * PXA3xx SSP1, SSP2, SSP3, SSP4
- */
-
-#ifndef __ASM_ARCH_SSP_H
-#define __ASM_ARCH_SSP_H
-
-#include <linux/list.h>
-#include <linux/io.h>
-
-enum pxa_ssp_type {
- SSP_UNDEFINED = 0,
- PXA25x_SSP, /* pxa 210, 250, 255, 26x */
- PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
- PXA27x_SSP,
-};
-
-struct ssp_device {
- struct platform_device *pdev;
- struct list_head node;
-
- struct clk *clk;
- void __iomem *mmio_base;
- unsigned long phys_base;
-
- const char *label;
- int port_id;
- int type;
- int use_count;
- int irq;
- int drcmr_rx;
- int drcmr_tx;
-};
-
-#ifdef CONFIG_PXA_SSP_LEGACY
-/*
- * SSP initialisation flags
- */
-#define SSP_NO_IRQ 0x1 /* don't register an irq handler in SSP driver */
-
-struct ssp_state {
- u32 cr0;
- u32 cr1;
- u32 to;
- u32 psp;
-};
-
-struct ssp_dev {
- struct ssp_device *ssp;
- u32 port;
- u32 mode;
- u32 flags;
- u32 psp_flags;
- u32 speed;
- int irq;
-};
-
-int ssp_write_word(struct ssp_dev *dev, u32 data);
-int ssp_read_word(struct ssp_dev *dev, u32 *data);
-int ssp_flush(struct ssp_dev *dev);
-void ssp_enable(struct ssp_dev *dev);
-void ssp_disable(struct ssp_dev *dev);
-void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp);
-void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp);
-int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags);
-int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32
psp_flags, u32 speed);
-void ssp_exit(struct ssp_dev *dev);
-#endif /* CONFIG_PXA_SSP_LEGACY */
-
-/**
- * ssp_write_reg - Write to a SSP register
- *
- * @dev: SSP device to access
- * @reg: Register to write to
- * @val: Value to be written.
- */
-static inline void ssp_write_reg(struct ssp_device *dev, u32 reg, u32 val)
-{
- __raw_writel(val, dev->mmio_base + reg);
-}
-
-/**
- * ssp_read_reg - Read from a SSP register
- *
- * @dev: SSP device to access
- * @reg: Register to read from
- */
-static inline u32 ssp_read_reg(struct ssp_device *dev, u32 reg)
-{
- return __raw_readl(dev->mmio_base + reg);
-}
-
-struct ssp_device *ssp_request(int port, const char *label);
-void ssp_free(struct ssp_device *);
-#endif /* __ASM_ARCH_SSP_H */
diff --git a/arch/arm/mach-pxa/littleton.c b/arch/arm/mach-pxa/littleton.c
index fa527b2..b9d3c20 100644
--- a/arch/arm/mach-pxa/littleton.c
+++ b/arch/arm/mach-pxa/littleton.c
@@ -41,12 +41,12 @@
#include <mach/pxa300.h>
#include <mach/pxafb.h>
-#include <mach/ssp.h>
#include <mach/mmc.h>
#include <mach/pxa2xx_spi.h>
#include <mach/pxa27x_keypad.h>
#include <mach/littleton.h>
#include <plat/i2c.h>
+#include <plat/ssp.h>
#include <plat/pxa3xx_nand.h>
#include "generic.h"
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index d58a524..90343c3 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -40,13 +40,13 @@
#include <mach/pxa25x.h>
#include <mach/mmc.h>
#include <mach/udc.h>
-#include <plat/i2c.h>
#include <mach/irda.h>
#include <mach/poodle.h>
#include <mach/pxafb.h>
#include <mach/sharpsl.h>
-#include <mach/ssp.h>
#include <mach/pxa2xx_spi.h>
+#include <plat/i2c.h>
+#include <plat/ssp.h>
#include <asm/hardware/scoop.h>
#include <asm/hardware/locomo.h>
diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
index fcb0721..bbb0b76 100644
--- a/arch/arm/mach-pxa/pxa3xx.c
+++ b/arch/arm/mach-pxa/pxa3xx.c
@@ -29,9 +29,9 @@
#include <mach/ohci.h>
#include <mach/pm.h>
#include <mach/dma.h>
-#include <mach/ssp.h>
#include <mach/regs-intc.h>
#include <plat/i2c.h>
+#include <plat/ssp.h>
#include "generic.h"
#include "devices.h"
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
deleted file mode 100644
index a81d6db..0000000
--- a/arch/arm/mach-pxa/ssp.c
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * linux/arch/arm/mach-pxa/ssp.c
- *
- * based on linux/arch/arm/mach-sa1100/ssp.c by Russell King
- *
- * Copyright (C) 2003 Russell King.
- * Copyright (C) 2003 Wolfson Microelectronics PLC
- *
- * 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.
- *
- * PXA2xx SSP driver. This provides the generic core for simple
- * IO-based SSP applications and allows easy port setup for DMA access.
- *
- * Author: Liam Girdwood <liam.girdwood(a)wolfsonmicro.com>
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
-
-#include <asm/irq.h>
-#include <mach/hardware.h>
-#include <mach/ssp.h>
-#include <mach/regs-ssp.h>
-
-#ifdef CONFIG_PXA_SSP_LEGACY
-
-#define TIMEOUT 100000
-
-static irqreturn_t ssp_interrupt(int irq, void *dev_id)
-{
- struct ssp_dev *dev = dev_id;
- struct ssp_device *ssp = dev->ssp;
- unsigned int status;
-
- status = __raw_readl(ssp->mmio_base + SSSR);
- __raw_writel(status, ssp->mmio_base + SSSR);
-
- if (status & SSSR_ROR)
- printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
-
- if (status & SSSR_TUR)
- printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port);
-
- if (status & SSSR_BCE)
- printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port);
-
- return IRQ_HANDLED;
-}
-
-/**
- * ssp_write_word - write a word to the SSP port
- * @data: 32-bit, MSB justified data to write.
- *
- * Wait for a free entry in the SSP transmit FIFO, and write a data
- * word to the SSP port.
- *
- * The caller is expected to perform the necessary locking.
- *
- * Returns:
- * %-ETIMEDOUT timeout occurred
- * 0 success
- */
-int ssp_write_word(struct ssp_dev *dev, u32 data)
-{
- struct ssp_device *ssp = dev->ssp;
- int timeout = TIMEOUT;
-
- while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_TNF)) {
- if (!--timeout)
- return -ETIMEDOUT;
- cpu_relax();
- }
-
- __raw_writel(data, ssp->mmio_base + SSDR);
-
- return 0;
-}
-
-/**
- * ssp_read_word - read a word from the SSP port
- *
- * Wait for a data word in the SSP receive FIFO, and return the
- * received data. Data is LSB justified.
- *
- * Note: Currently, if data is not expected to be received, this
- * function will wait for ever.
- *
- * The caller is expected to perform the necessary locking.
- *
- * Returns:
- * %-ETIMEDOUT timeout occurred
- * 32-bit data success
- */
-int ssp_read_word(struct ssp_dev *dev, u32 *data)
-{
- struct ssp_device *ssp = dev->ssp;
- int timeout = TIMEOUT;
-
- while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE)) {
- if (!--timeout)
- return -ETIMEDOUT;
- cpu_relax();
- }
-
- *data = __raw_readl(ssp->mmio_base + SSDR);
- return 0;
-}
-
-/**
- * ssp_flush - flush the transmit and receive FIFOs
- *
- * Wait for the SSP to idle, and ensure that the receive FIFO
- * is empty.
- *
- * The caller is expected to perform the necessary locking.
- */
-int ssp_flush(struct ssp_dev *dev)
-{
- struct ssp_device *ssp = dev->ssp;
- int timeout = TIMEOUT * 2;
-
- /* ensure TX FIFO is empty instead of not full */
- if (cpu_is_pxa3xx()) {
- while (__raw_readl(ssp->mmio_base + SSSR) & 0xf00) {
- if (!--timeout)
- return -ETIMEDOUT;
- cpu_relax();
- }
- timeout = TIMEOUT * 2;
- }
-
- do {
- while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE) {
- if (!--timeout)
- return -ETIMEDOUT;
- (void)__raw_readl(ssp->mmio_base + SSDR);
- }
- if (!--timeout)
- return -ETIMEDOUT;
- } while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_BSY);
-
- return 0;
-}
-
-/**
- * ssp_enable - enable the SSP port
- *
- * Turn on the SSP port.
- */
-void ssp_enable(struct ssp_dev *dev)
-{
- struct ssp_device *ssp = dev->ssp;
- uint32_t sscr0;
-
- sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
- sscr0 |= SSCR0_SSE;
- __raw_writel(sscr0, ssp->mmio_base + SSCR0);
-}
-
-/**
- * ssp_disable - shut down the SSP port
- *
- * Turn off the SSP port, optionally powering it down.
- */
-void ssp_disable(struct ssp_dev *dev)
-{
- struct ssp_device *ssp = dev->ssp;
- uint32_t sscr0;
-
- sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
- sscr0 &= ~SSCR0_SSE;
- __raw_writel(sscr0, ssp->mmio_base + SSCR0);
-}
-
-/**
- * ssp_save_state - save the SSP configuration
- * @ssp: pointer to structure to save SSP configuration
- *
- * Save the configured SSP state for suspend.
- */
-void ssp_save_state(struct ssp_dev *dev, struct ssp_state *state)
-{
- struct ssp_device *ssp = dev->ssp;
-
- state->cr0 = __raw_readl(ssp->mmio_base + SSCR0);
- state->cr1 = __raw_readl(ssp->mmio_base + SSCR1);
- state->to = __raw_readl(ssp->mmio_base + SSTO);
- state->psp = __raw_readl(ssp->mmio_base + SSPSP);
-
- ssp_disable(dev);
-}
-
-/**
- * ssp_restore_state - restore a previously saved SSP configuration
- * @ssp: pointer to configuration saved by ssp_save_state
- *
- * Restore the SSP configuration saved previously by ssp_save_state.
- */
-void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *state)
-{
- struct ssp_device *ssp = dev->ssp;
- uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
-
- __raw_writel(sssr, ssp->mmio_base + SSSR);
-
- __raw_writel(state->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0);
- __raw_writel(state->cr1, ssp->mmio_base + SSCR1);
- __raw_writel(state->to, ssp->mmio_base + SSTO);
- __raw_writel(state->psp, ssp->mmio_base + SSPSP);
- __raw_writel(state->cr0, ssp->mmio_base + SSCR0);
-}
-
-/**
- * ssp_config - configure SSP port settings
- * @mode: port operating mode
- * @flags: port config flags
- * @psp_flags: port PSP config flags
- * @speed: port speed
- *
- * Port MUST be disabled by ssp_disable before making any config changes.
- */
-int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32
psp_flags, u32 speed)
-{
- struct ssp_device *ssp = dev->ssp;
-
- dev->mode = mode;
- dev->flags = flags;
- dev->psp_flags = psp_flags;
- dev->speed = speed;
-
- /* set up port type, speed, port settings */
- __raw_writel((dev->speed | dev->mode), ssp->mmio_base + SSCR0);
- __raw_writel(dev->flags, ssp->mmio_base + SSCR1);
- __raw_writel(dev->psp_flags, ssp->mmio_base + SSPSP);
-
- return 0;
-}
-
-/**
- * ssp_init - setup the SSP port
- *
- * initialise and claim resources for the SSP port.
- *
- * Returns:
- * %-ENODEV if the SSP port is unavailable
- * %-EBUSY if the resources are already in use
- * %0 on success
- */
-int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
-{
- struct ssp_device *ssp;
- int ret;
-
- ssp = ssp_request(port, "SSP");
- if (ssp == NULL)
- return -ENODEV;
-
- dev->ssp = ssp;
- dev->port = port;
-
- /* do we need to get irq */
- if (!(init_flags & SSP_NO_IRQ)) {
- ret = request_irq(ssp->irq, ssp_interrupt,
- 0, "SSP", dev);
- if (ret)
- goto out_region;
- dev->irq = ssp->irq;
- } else
- dev->irq = NO_IRQ;
-
- /* turn on SSP port clock */
- clk_enable(ssp->clk);
- return 0;
-
-out_region:
- ssp_free(ssp);
- return ret;
-}
-
-/**
- * ssp_exit - undo the effects of ssp_init
- *
- * release and free resources for the SSP port.
- */
-void ssp_exit(struct ssp_dev *dev)
-{
- struct ssp_device *ssp = dev->ssp;
-
- ssp_disable(dev);
- if (dev->irq != NO_IRQ)
- free_irq(dev->irq, dev);
- clk_disable(ssp->clk);
- ssp_free(ssp);
-}
-#endif /* CONFIG_PXA_SSP_LEGACY */
-
-static DEFINE_MUTEX(ssp_lock);
-static LIST_HEAD(ssp_list);
-
-struct ssp_device *ssp_request(int port, const char *label)
-{
- struct ssp_device *ssp = NULL;
-
- mutex_lock(&ssp_lock);
-
- list_for_each_entry(ssp, &ssp_list, node) {
- if (ssp->port_id == port && ssp->use_count == 0) {
- ssp->use_count++;
- ssp->label = label;
- break;
- }
- }
-
- mutex_unlock(&ssp_lock);
-
- if (&ssp->node == &ssp_list)
- return NULL;
-
- return ssp;
-}
-EXPORT_SYMBOL(ssp_request);
-
-void ssp_free(struct ssp_device *ssp)
-{
- mutex_lock(&ssp_lock);
- if (ssp->use_count) {
- ssp->use_count--;
- ssp->label = NULL;
- } else
- dev_err(&ssp->pdev->dev, "device already free\n");
- mutex_unlock(&ssp_lock);
-}
-EXPORT_SYMBOL(ssp_free);
-
-static int __devinit ssp_probe(struct platform_device *pdev)
-{
- const struct platform_device_id *id = platform_get_device_id(pdev);
- struct resource *res;
- struct ssp_device *ssp;
- int ret = 0;
-
- ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
- if (ssp == NULL) {
- dev_err(&pdev->dev, "failed to allocate memory");
- return -ENOMEM;
- }
- ssp->pdev = pdev;
-
- ssp->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(ssp->clk)) {
- ret = PTR_ERR(ssp->clk);
- goto err_free;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no memory resource defined\n");
- ret = -ENODEV;
- goto err_free_clk;
- }
-
- res = request_mem_region(res->start, res->end - res->start + 1,
- pdev->name);
- if (res == NULL) {
- dev_err(&pdev->dev, "failed to request memory resource\n");
- ret = -EBUSY;
- goto err_free_clk;
- }
-
- ssp->phys_base = res->start;
-
- ssp->mmio_base = ioremap(res->start, res->end - res->start + 1);
- if (ssp->mmio_base == NULL) {
- dev_err(&pdev->dev, "failed to ioremap() registers\n");
- ret = -ENODEV;
- goto err_free_mem;
- }
-
- ssp->irq = platform_get_irq(pdev, 0);
- if (ssp->irq < 0) {
- dev_err(&pdev->dev, "no IRQ resource defined\n");
- ret = -ENODEV;
- goto err_free_io;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (res == NULL) {
- dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
- ret = -ENODEV;
- goto err_free_io;
- }
- ssp->drcmr_rx = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
- if (res == NULL) {
- dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
- ret = -ENODEV;
- goto err_free_io;
- }
- ssp->drcmr_tx = res->start;
-
- /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
- * starts from 0, do a translation here
- */
- ssp->port_id = pdev->id + 1;
- ssp->use_count = 0;
- ssp->type = (int)id->driver_data;
-
- mutex_lock(&ssp_lock);
- list_add(&ssp->node, &ssp_list);
- mutex_unlock(&ssp_lock);
-
- platform_set_drvdata(pdev, ssp);
- return 0;
-
-err_free_io:
- iounmap(ssp->mmio_base);
-err_free_mem:
- release_mem_region(res->start, res->end - res->start + 1);
-err_free_clk:
- clk_put(ssp->clk);
-err_free:
- kfree(ssp);
- return ret;
-}
-
-static int __devexit ssp_remove(struct platform_device *pdev)
-{
- struct resource *res;
- struct ssp_device *ssp;
-
- ssp = platform_get_drvdata(pdev);
- if (ssp == NULL)
- return -ENODEV;
-
- iounmap(ssp->mmio_base);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, res->end - res->start + 1);
-
- clk_put(ssp->clk);
-
- mutex_lock(&ssp_lock);
- list_del(&ssp->node);
- mutex_unlock(&ssp_lock);
-
- kfree(ssp);
- return 0;
-}
-
-static const struct platform_device_id ssp_id_table[] = {
- { "pxa25x-ssp", PXA25x_SSP },
- { "pxa25x-nssp", PXA25x_NSSP },
- { "pxa27x-ssp", PXA27x_SSP },
- { },
-};
-
-static struct platform_driver ssp_driver = {
- .probe = ssp_probe,
- .remove = __devexit_p(ssp_remove),
- .driver = {
- .owner = THIS_MODULE,
- .name = "pxa2xx-ssp",
- },
- .id_table = ssp_id_table,
-};
-
-static int __init pxa_ssp_init(void)
-{
- return platform_driver_register(&ssp_driver);
-}
-
-static void __exit pxa_ssp_exit(void)
-{
- platform_driver_unregister(&ssp_driver);
-}
-
-arch_initcall(pxa_ssp_init);
-module_exit(pxa_ssp_exit);
-
-#ifdef CONFIG_PXA_SSP_LEGACY
-EXPORT_SYMBOL(ssp_write_word);
-EXPORT_SYMBOL(ssp_read_word);
-EXPORT_SYMBOL(ssp_flush);
-EXPORT_SYMBOL(ssp_enable);
-EXPORT_SYMBOL(ssp_disable);
-EXPORT_SYMBOL(ssp_save_state);
-EXPORT_SYMBOL(ssp_restore_state);
-EXPORT_SYMBOL(ssp_init);
-EXPORT_SYMBOL(ssp_exit);
-EXPORT_SYMBOL(ssp_config);
-#endif
-
-MODULE_DESCRIPTION("PXA SSP driver");
-MODULE_AUTHOR("Liam Girdwood");
-MODULE_LICENSE("GPL");
-
diff --git a/arch/arm/plat-pxa/Kconfig b/arch/arm/plat-pxa/Kconfig
index b158e98..994f4b8 100644
--- a/arch/arm/plat-pxa/Kconfig
+++ b/arch/arm/plat-pxa/Kconfig
@@ -1,3 +1,13 @@
if PLAT_PXA
+config PXA_SSP
+ tristate
+ help
+ Enable support for PXA2xx SSP ports
+
+config PXA_SSP_LEGACY
+ bool
+ help
+ Support of legacy SSP API
+
endif
diff --git a/arch/arm/plat-pxa/Makefile b/arch/arm/plat-pxa/Makefile
index 0264bfb..4aacdd1 100644
--- a/arch/arm/plat-pxa/Makefile
+++ b/arch/arm/plat-pxa/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_PXA3xx) += mfp.o
obj-$(CONFIG_ARCH_MMP) += mfp.o
obj-$(CONFIG_HAVE_PWM) += pwm.o
+obj-$(CONFIG_PXA_SSP) += ssp.o
diff --git a/arch/arm/plat-pxa/include/plat/ssp.h
b/arch/arm/plat-pxa/include/plat/ssp.h
new file mode 100644
index 0000000..fc83ba7
--- /dev/null
+++ b/arch/arm/plat-pxa/include/plat/ssp.h
@@ -0,0 +1,109 @@
+/*
+ * ssp.h
+ *
+ * Copyright (C) 2003 Russell King, All Rights Reserved.
+ *
+ * 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.
+ *
+ * This driver supports the following PXA CPU/SSP ports:-
+ *
+ * PXA250 SSP
+ * PXA255 SSP, NSSP
+ * PXA26x SSP, NSSP, ASSP
+ * PXA27x SSP1, SSP2, SSP3
+ * PXA3xx SSP1, SSP2, SSP3, SSP4
+ */
+
+#ifndef __ASM_PLAT_SSP_H
+#define __ASM_PLAT_SSP_H
+
+#include <linux/list.h>
+#include <linux/io.h>
+
+enum pxa_ssp_type {
+ SSP_UNDEFINED = 0,
+ PXA25x_SSP, /* pxa 210, 250, 255, 26x */
+ PXA25x_NSSP, /* pxa 255, 26x (including ASSP) */
+ PXA27x_SSP,
+};
+
+struct ssp_device {
+ struct platform_device *pdev;
+ struct list_head node;
+
+ struct clk *clk;
+ void __iomem *mmio_base;
+ unsigned long phys_base;
+
+ const char *label;
+ int port_id;
+ int type;
+ int use_count;
+ int irq;
+ int drcmr_rx;
+ int drcmr_tx;
+};
+
+#ifdef CONFIG_PXA_SSP_LEGACY
+/*
+ * SSP initialisation flags
+ */
+#define SSP_NO_IRQ 0x1 /* don't register an irq handler in SSP driver */
+
+struct ssp_state {
+ u32 cr0;
+ u32 cr1;
+ u32 to;
+ u32 psp;
+};
+
+struct ssp_dev {
+ struct ssp_device *ssp;
+ u32 port;
+ u32 mode;
+ u32 flags;
+ u32 psp_flags;
+ u32 speed;
+ int irq;
+};
+
+int ssp_write_word(struct ssp_dev *dev, u32 data);
+int ssp_read_word(struct ssp_dev *dev, u32 *data);
+int ssp_flush(struct ssp_dev *dev);
+void ssp_enable(struct ssp_dev *dev);
+void ssp_disable(struct ssp_dev *dev);
+void ssp_save_state(struct ssp_dev *dev, struct ssp_state *ssp);
+void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *ssp);
+int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags);
+int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32
psp_flags, u32 speed);
+void ssp_exit(struct ssp_dev *dev);
+#endif /* CONFIG_PXA_SSP_LEGACY */
+
+/**
+ * ssp_write_reg - Write to a SSP register
+ *
+ * @dev: SSP device to access
+ * @reg: Register to write to
+ * @val: Value to be written.
+ */
+static inline void ssp_write_reg(struct ssp_device *dev, u32 reg, u32 val)
+{
+ __raw_writel(val, dev->mmio_base + reg);
+}
+
+/**
+ * ssp_read_reg - Read from a SSP register
+ *
+ * @dev: SSP device to access
+ * @reg: Register to read from
+ */
+static inline u32 ssp_read_reg(struct ssp_device *dev, u32 reg)
+{
+ return __raw_readl(dev->mmio_base + reg);
+}
+
+struct ssp_device *ssp_request(int port, const char *label);
+void ssp_free(struct ssp_device *);
+#endif /* __ASM_PLAT_SSP_H */
diff --git a/arch/arm/plat-pxa/ssp.c b/arch/arm/plat-pxa/ssp.c
new file mode 100644
index 0000000..d4a7673
--- /dev/null
+++ b/arch/arm/plat-pxa/ssp.c
@@ -0,0 +1,510 @@
+/*
+ * linux/arch/arm/mach-pxa/ssp.c
+ *
+ * based on linux/arch/arm/mach-sa1100/ssp.c by Russell King
+ *
+ * Copyright (C) 2003 Russell King.
+ * Copyright (C) 2003 Wolfson Microelectronics PLC
+ *
+ * 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.
+ *
+ * PXA2xx SSP driver. This provides the generic core for simple
+ * IO-based SSP applications and allows easy port setup for DMA access.
+ *
+ * Author: Liam Girdwood <liam.girdwood(a)wolfsonmicro.com>
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/mutex.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <mach/regs-ssp.h>
+#include <plat/ssp.h>
+
+#ifdef CONFIG_PXA_SSP_LEGACY
+
+#define TIMEOUT 100000
+
+static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+{
+ struct ssp_dev *dev = dev_id;
+ struct ssp_device *ssp = dev->ssp;
+ unsigned int status;
+
+ status = __raw_readl(ssp->mmio_base + SSSR);
+ __raw_writel(status, ssp->mmio_base + SSSR);
+
+ if (status & SSSR_ROR)
+ printk(KERN_WARNING "SSP(%d): receiver overrun\n", dev->port);
+
+ if (status & SSSR_TUR)
+ printk(KERN_WARNING "SSP(%d): transmitter underrun\n", dev->port);
+
+ if (status & SSSR_BCE)
+ printk(KERN_WARNING "SSP(%d): bit count error\n", dev->port);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ssp_write_word - write a word to the SSP port
+ * @data: 32-bit, MSB justified data to write.
+ *
+ * Wait for a free entry in the SSP transmit FIFO, and write a data
+ * word to the SSP port.
+ *
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ * %-ETIMEDOUT timeout occurred
+ * 0 success
+ */
+int ssp_write_word(struct ssp_dev *dev, u32 data)
+{
+ struct ssp_device *ssp = dev->ssp;
+ int timeout = TIMEOUT;
+
+ while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_TNF)) {
+ if (!--timeout)
+ return -ETIMEDOUT;
+ cpu_relax();
+ }
+
+ __raw_writel(data, ssp->mmio_base + SSDR);
+
+ return 0;
+}
+
+/**
+ * ssp_read_word - read a word from the SSP port
+ *
+ * Wait for a data word in the SSP receive FIFO, and return the
+ * received data. Data is LSB justified.
+ *
+ * Note: Currently, if data is not expected to be received, this
+ * function will wait for ever.
+ *
+ * The caller is expected to perform the necessary locking.
+ *
+ * Returns:
+ * %-ETIMEDOUT timeout occurred
+ * 32-bit data success
+ */
+int ssp_read_word(struct ssp_dev *dev, u32 *data)
+{
+ struct ssp_device *ssp = dev->ssp;
+ int timeout = TIMEOUT;
+
+ while (!(__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE)) {
+ if (!--timeout)
+ return -ETIMEDOUT;
+ cpu_relax();
+ }
+
+ *data = __raw_readl(ssp->mmio_base + SSDR);
+ return 0;
+}
+
+/**
+ * ssp_flush - flush the transmit and receive FIFOs
+ *
+ * Wait for the SSP to idle, and ensure that the receive FIFO
+ * is empty.
+ *
+ * The caller is expected to perform the necessary locking.
+ */
+int ssp_flush(struct ssp_dev *dev)
+{
+ struct ssp_device *ssp = dev->ssp;
+ int timeout = TIMEOUT * 2;
+
+ /* ensure TX FIFO is empty instead of not full */
+ if (cpu_is_pxa3xx()) {
+ while (__raw_readl(ssp->mmio_base + SSSR) & 0xf00) {
+ if (!--timeout)
+ return -ETIMEDOUT;
+ cpu_relax();
+ }
+ timeout = TIMEOUT * 2;
+ }
+
+ do {
+ while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_RNE) {
+ if (!--timeout)
+ return -ETIMEDOUT;
+ (void)__raw_readl(ssp->mmio_base + SSDR);
+ }
+ if (!--timeout)
+ return -ETIMEDOUT;
+ } while (__raw_readl(ssp->mmio_base + SSSR) & SSSR_BSY);
+
+ return 0;
+}
+
+/**
+ * ssp_enable - enable the SSP port
+ *
+ * Turn on the SSP port.
+ */
+void ssp_enable(struct ssp_dev *dev)
+{
+ struct ssp_device *ssp = dev->ssp;
+ uint32_t sscr0;
+
+ sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
+ sscr0 |= SSCR0_SSE;
+ __raw_writel(sscr0, ssp->mmio_base + SSCR0);
+}
+
+/**
+ * ssp_disable - shut down the SSP port
+ *
+ * Turn off the SSP port, optionally powering it down.
+ */
+void ssp_disable(struct ssp_dev *dev)
+{
+ struct ssp_device *ssp = dev->ssp;
+ uint32_t sscr0;
+
+ sscr0 = __raw_readl(ssp->mmio_base + SSCR0);
+ sscr0 &= ~SSCR0_SSE;
+ __raw_writel(sscr0, ssp->mmio_base + SSCR0);
+}
+
+/**
+ * ssp_save_state - save the SSP configuration
+ * @ssp: pointer to structure to save SSP configuration
+ *
+ * Save the configured SSP state for suspend.
+ */
+void ssp_save_state(struct ssp_dev *dev, struct ssp_state *state)
+{
+ struct ssp_device *ssp = dev->ssp;
+
+ state->cr0 = __raw_readl(ssp->mmio_base + SSCR0);
+ state->cr1 = __raw_readl(ssp->mmio_base + SSCR1);
+ state->to = __raw_readl(ssp->mmio_base + SSTO);
+ state->psp = __raw_readl(ssp->mmio_base + SSPSP);
+
+ ssp_disable(dev);
+}
+
+/**
+ * ssp_restore_state - restore a previously saved SSP configuration
+ * @ssp: pointer to configuration saved by ssp_save_state
+ *
+ * Restore the SSP configuration saved previously by ssp_save_state.
+ */
+void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *state)
+{
+ struct ssp_device *ssp = dev->ssp;
+ uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
+
+ __raw_writel(sssr, ssp->mmio_base + SSSR);
+
+ __raw_writel(state->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0);
+ __raw_writel(state->cr1, ssp->mmio_base + SSCR1);
+ __raw_writel(state->to, ssp->mmio_base + SSTO);
+ __raw_writel(state->psp, ssp->mmio_base + SSPSP);
+ __raw_writel(state->cr0, ssp->mmio_base + SSCR0);
+}
+
+/**
+ * ssp_config - configure SSP port settings
+ * @mode: port operating mode
+ * @flags: port config flags
+ * @psp_flags: port PSP config flags
+ * @speed: port speed
+ *
+ * Port MUST be disabled by ssp_disable before making any config changes.
+ */
+int ssp_config(struct ssp_dev *dev, u32 mode, u32 flags, u32
psp_flags, u32 speed)
+{
+ struct ssp_device *ssp = dev->ssp;
+
+ dev->mode = mode;
+ dev->flags = flags;
+ dev->psp_flags = psp_flags;
+ dev->speed = speed;
+
+ /* set up port type, speed, port settings */
+ __raw_writel((dev->speed | dev->mode), ssp->mmio_base + SSCR0);
+ __raw_writel(dev->flags, ssp->mmio_base + SSCR1);
+ __raw_writel(dev->psp_flags, ssp->mmio_base + SSPSP);
+
+ return 0;
+}
+
+/**
+ * ssp_init - setup the SSP port
+ *
+ * initialise and claim resources for the SSP port.
+ *
+ * Returns:
+ * %-ENODEV if the SSP port is unavailable
+ * %-EBUSY if the resources are already in use
+ * %0 on success
+ */
+int ssp_init(struct ssp_dev *dev, u32 port, u32 init_flags)
+{
+ struct ssp_device *ssp;
+ int ret;
+
+ ssp = ssp_request(port, "SSP");
+ if (ssp == NULL)
+ return -ENODEV;
+
+ dev->ssp = ssp;
+ dev->port = port;
+
+ /* do we need to get irq */
+ if (!(init_flags & SSP_NO_IRQ)) {
+ ret = request_irq(ssp->irq, ssp_interrupt,
+ 0, "SSP", dev);
+ if (ret)
+ goto out_region;
+ dev->irq = ssp->irq;
+ } else
+ dev->irq = NO_IRQ;
+
+ /* turn on SSP port clock */
+ clk_enable(ssp->clk);
+ return 0;
+
+out_region:
+ ssp_free(ssp);
+ return ret;
+}
+
+/**
+ * ssp_exit - undo the effects of ssp_init
+ *
+ * release and free resources for the SSP port.
+ */
+void ssp_exit(struct ssp_dev *dev)
+{
+ struct ssp_device *ssp = dev->ssp;
+
+ ssp_disable(dev);
+ if (dev->irq != NO_IRQ)
+ free_irq(dev->irq, dev);
+ clk_disable(ssp->clk);
+ ssp_free(ssp);
+}
+#endif /* CONFIG_PXA_SSP_LEGACY */
+
+static DEFINE_MUTEX(ssp_lock);
+static LIST_HEAD(ssp_list);
+
+struct ssp_device *ssp_request(int port, const char *label)
+{
+ struct ssp_device *ssp = NULL;
+
+ mutex_lock(&ssp_lock);
+
+ list_for_each_entry(ssp, &ssp_list, node) {
+ if (ssp->port_id == port && ssp->use_count == 0) {
+ ssp->use_count++;
+ ssp->label = label;
+ break;
+ }
+ }
+
+ mutex_unlock(&ssp_lock);
+
+ if (&ssp->node == &ssp_list)
+ return NULL;
+
+ return ssp;
+}
+EXPORT_SYMBOL(ssp_request);
+
+void ssp_free(struct ssp_device *ssp)
+{
+ mutex_lock(&ssp_lock);
+ if (ssp->use_count) {
+ ssp->use_count--;
+ ssp->label = NULL;
+ } else
+ dev_err(&ssp->pdev->dev, "device already free\n");
+ mutex_unlock(&ssp_lock);
+}
+EXPORT_SYMBOL(ssp_free);
+
+static int __devinit ssp_probe(struct platform_device *pdev)
+{
+ const struct platform_device_id *id = platform_get_device_id(pdev);
+ struct resource *res;
+ struct ssp_device *ssp;
+ int ret = 0;
+
+ ssp = kzalloc(sizeof(struct ssp_device), GFP_KERNEL);
+ if (ssp == NULL) {
+ dev_err(&pdev->dev, "failed to allocate memory");
+ return -ENOMEM;
+ }
+ ssp->pdev = pdev;
+
+ ssp->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(ssp->clk)) {
+ ret = PTR_ERR(ssp->clk);
+ goto err_free;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no memory resource defined\n");
+ ret = -ENODEV;
+ goto err_free_clk;
+ }
+
+ res = request_mem_region(res->start, res->end - res->start + 1,
+ pdev->name);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "failed to request memory resource\n");
+ ret = -EBUSY;
+ goto err_free_clk;
+ }
+
+ ssp->phys_base = res->start;
+
+ ssp->mmio_base = ioremap(res->start, res->end - res->start + 1);
+ if (ssp->mmio_base == NULL) {
+ dev_err(&pdev->dev, "failed to ioremap() registers\n");
+ ret = -ENODEV;
+ goto err_free_mem;
+ }
+
+ ssp->irq = platform_get_irq(pdev, 0);
+ if (ssp->irq < 0) {
+ dev_err(&pdev->dev, "no IRQ resource defined\n");
+ ret = -ENODEV;
+ goto err_free_io;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no SSP RX DRCMR defined\n");
+ ret = -ENODEV;
+ goto err_free_io;
+ }
+ ssp->drcmr_rx = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
+ if (res == NULL) {
+ dev_err(&pdev->dev, "no SSP TX DRCMR defined\n");
+ ret = -ENODEV;
+ goto err_free_io;
+ }
+ ssp->drcmr_tx = res->start;
+
+ /* PXA2xx/3xx SSP ports starts from 1 and the internal pdev->id
+ * starts from 0, do a translation here
+ */
+ ssp->port_id = pdev->id + 1;
+ ssp->use_count = 0;
+ ssp->type = (int)id->driver_data;
+
+ mutex_lock(&ssp_lock);
+ list_add(&ssp->node, &ssp_list);
+ mutex_unlock(&ssp_lock);
+
+ platform_set_drvdata(pdev, ssp);
+ return 0;
+
+err_free_io:
+ iounmap(ssp->mmio_base);
+err_free_mem:
+ release_mem_region(res->start, res->end - res->start + 1);
+err_free_clk:
+ clk_put(ssp->clk);
+err_free:
+ kfree(ssp);
+ return ret;
+}
+
+static int __devexit ssp_remove(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct ssp_device *ssp;
+
+ ssp = platform_get_drvdata(pdev);
+ if (ssp == NULL)
+ return -ENODEV;
+
+ iounmap(ssp->mmio_base);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ clk_put(ssp->clk);
+
+ mutex_lock(&ssp_lock);
+ list_del(&ssp->node);
+ mutex_unlock(&ssp_lock);
+
+ kfree(ssp);
+ return 0;
+}
+
+static const struct platform_device_id ssp_id_table[] = {
+ { "pxa25x-ssp", PXA25x_SSP },
+ { "pxa25x-nssp", PXA25x_NSSP },
+ { "pxa27x-ssp", PXA27x_SSP },
+ { },
+};
+
+static struct platform_driver ssp_driver = {
+ .probe = ssp_probe,
+ .remove = __devexit_p(ssp_remove),
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "pxa2xx-ssp",
+ },
+ .id_table = ssp_id_table,
+};
+
+static int __init pxa_ssp_init(void)
+{
+ return platform_driver_register(&ssp_driver);
+}
+
+static void __exit pxa_ssp_exit(void)
+{
+ platform_driver_unregister(&ssp_driver);
+}
+
+arch_initcall(pxa_ssp_init);
+module_exit(pxa_ssp_exit);
+
+#ifdef CONFIG_PXA_SSP_LEGACY
+EXPORT_SYMBOL(ssp_write_word);
+EXPORT_SYMBOL(ssp_read_word);
+EXPORT_SYMBOL(ssp_flush);
+EXPORT_SYMBOL(ssp_enable);
+EXPORT_SYMBOL(ssp_disable);
+EXPORT_SYMBOL(ssp_save_state);
+EXPORT_SYMBOL(ssp_restore_state);
+EXPORT_SYMBOL(ssp_init);
+EXPORT_SYMBOL(ssp_exit);
+EXPORT_SYMBOL(ssp_config);
+#endif
+
+MODULE_DESCRIPTION("PXA SSP driver");
+MODULE_AUTHOR("Liam Girdwood");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index cf00df9..ef75995 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -33,7 +33,7 @@
#include <mach/dma.h>
#include <mach/regs-ssp.h>
#include <mach/audio.h>
-#include <mach/ssp.h>
+#include <plat/ssp.h>
#include "pxa2xx-pcm.h"
#include "pxa-ssp.h"
--
1.5.6.5
1
0
Append ssp driver for pxa168 since PLL could be generated by a new way.
Append aspenite also that could support pxa168-ssp.
Signed-off-by: Haojian Zhuang <haojian.zhuang(a)marvell.com>
---
sound/soc/pxa/Kconfig | 21 ++
sound/soc/pxa/Makefile | 5 +
sound/soc/pxa/aspenite.c | 206 ++++++++++++++
sound/soc/pxa/pxa168-ssp.c | 645 ++++++++++++++++++++++++++++++++++++++++++++
sound/soc/pxa/pxa168-ssp.h | 29 ++
5 files changed, 906 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/pxa/aspenite.c
create mode 100644 sound/soc/pxa/pxa168-ssp.c
create mode 100644 sound/soc/pxa/pxa168-ssp.h
diff --git a/sound/soc/pxa/Kconfig b/sound/soc/pxa/Kconfig
index 376e14a..71778be 100644
--- a/sound/soc/pxa/Kconfig
+++ b/sound/soc/pxa/Kconfig
@@ -1,3 +1,15 @@
+config SND_PXA168_SOC
+ tristate "SoC Audio for the Marvell chip"
+ depends on ARCH_MMP
+ select SND_PXA2XX_LIB
+ help
+ Say Y or M if you want to add support for codecs attached to
+ the PXA168 I2S or SSP interface. You will also need
+ to select the audio interfaces to support below.
+
+config SND_PXA168_SOC_SSP
+ tristate
+
config SND_PXA2XX_SOC
tristate "SoC Audio for the Intel PXA2xx chip"
depends on ARCH_PXA
@@ -108,6 +120,15 @@ config SND_PXA2XX_SOC_PALM27X
Say Y if you want to add support for SoC audio on
Palm T|X, T5, E2 or LifeDrive handheld computer.
+config SND_SOC_ASPENITE
+ tristate "SoC Audio support for Marvell Aspenite"
+ depends on SND_PXA168_SOC && MACH_ASPENITE
+ select SND_PXA168_SOC_SSP
+ select SND_SOC_WM8753
+ help
+ Say Y if you want to add support for SoC audio on the
+ Marvell Aspenite reference platform.
+
config SND_SOC_ZYLONITE
tristate "SoC Audio support for Marvell Zylonite"
depends on SND_PXA2XX_SOC && MACH_ZYLONITE
diff --git a/sound/soc/pxa/Makefile b/sound/soc/pxa/Makefile
index f3e08fd..46e9334 100644
--- a/sound/soc/pxa/Makefile
+++ b/sound/soc/pxa/Makefile
@@ -3,13 +3,17 @@ snd-soc-pxa2xx-objs := pxa2xx-pcm.o
snd-soc-pxa2xx-ac97-objs := pxa2xx-ac97.o
snd-soc-pxa2xx-i2s-objs := pxa2xx-i2s.o
snd-soc-pxa-ssp-objs := pxa-ssp.o
+snd-soc-pxa168-ssp-objs := pxa168-ssp.o
obj-$(CONFIG_SND_PXA2XX_SOC) += snd-soc-pxa2xx.o
obj-$(CONFIG_SND_PXA2XX_SOC_AC97) += snd-soc-pxa2xx-ac97.o
obj-$(CONFIG_SND_PXA2XX_SOC_I2S) += snd-soc-pxa2xx-i2s.o
obj-$(CONFIG_SND_PXA_SOC_SSP) += snd-soc-pxa-ssp.o
+obj-$(CONFIG_SND_PXA168_SOC) += snd-soc-pxa2xx.o
+obj-$(CONFIG_SND_PXA168_SOC_SSP) += snd-soc-pxa168-ssp.o
# PXA Machine Support
+snd-soc-aspenite-objs := aspenite.o
snd-soc-corgi-objs := corgi.o
snd-soc-poodle-objs := poodle.o
snd-soc-tosa-objs := tosa.o
@@ -36,6 +40,7 @@ obj-$(CONFIG_SND_PXA2XX_SOC_EM_X270) += snd-soc-em-x270.o
obj-$(CONFIG_SND_PXA2XX_SOC_PALM27X) += snd-soc-palm27x.o
obj-$(CONFIG_SND_PXA2XX_SOC_MAGICIAN) += snd-soc-magician.o
obj-$(CONFIG_SND_PXA2XX_SOC_MIOA701) += snd-soc-mioa701.o
+obj-$(CONFIG_SND_SOC_ASPENITE) += snd-soc-aspenite.o
obj-$(CONFIG_SND_SOC_ZYLONITE) += snd-soc-zylonite.o
obj-$(CONFIG_SND_PXA2XX_SOC_IMOTE2) += snd-soc-imote2.o
obj-$(CONFIG_SND_SOC_RAUMFELD) += snd-soc-raumfeld.o
diff --git a/sound/soc/pxa/aspenite.c b/sound/soc/pxa/aspenite.c
new file mode 100644
index 0000000..12594fa
--- /dev/null
+++ b/sound/soc/pxa/aspenite.c
@@ -0,0 +1,206 @@
+/*
+ * aspenite.c -- SoC audio for Aspenite
+ *
+ * Copyright (C) 2009-2010 Marvell International Ltd.
+ * Haojian Zhuang <haojian.zhuang(a)marvell.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/module.h>
+#include <linux/device.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+
+#include <plat/ssp.h>
+
+#include "../codecs/wm8753.h"
+#include "pxa2xx-pcm.h"
+#include "pxa168-ssp.h"
+
+static struct snd_soc_card aspenite;
+
+/* aspenite machine dapm widgets */
+static const struct snd_soc_dapm_widget aspenite_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_SPK("Headset Speaker", NULL),
+ SND_SOC_DAPM_LINE("Line LIN", NULL),
+ SND_SOC_DAPM_LINE("Line RIN", NULL),
+};
+
+/* aspenite machine audio map */
+static const struct snd_soc_dapm_route audio_map[] = {
+ /* Headphone connected to LOUT1/ROUT1 */
+ {"Headphone", NULL, "LOUT1"},
+ {"Headphone", NULL, "ROUT1"},
+
+ /* Speaker connected to LOUT2/OUT4 & OUT3/ROUT2 */
+ {"Headset Speaker", NULL, "LOUT2"},
+ {"Headset Speaker", NULL, "OUT4"},
+ {"Headset Speaker", NULL, "OUT3"},
+ {"Headset Speaker", NULL, "ROUT2"},
+
+ /* Line connected to LINE1/LINE2 */
+ {"Line LIN", NULL, "LINE1"},
+ {"Line RIN", NULL, "LINE2"},
+
+ /* Mic */
+ {"MIC1", NULL, "Mic Bias"},
+ {"Mic Bias", NULL, "Headset Mic"},
+
+ /* Connect the ALC pins */
+ {"ACIN", NULL, "ACOP"},
+};
+
+static const struct snd_kcontrol_new wm8753_aspenite_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headset Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Line LIN"),
+ SOC_DAPM_PIN_SWITCH("Line RIN"),
+};
+
+static int aspenite_hifi_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ unsigned int rate, width, channel;
+ int index, mclk, ret;
+
+ rate = params_rate(params);
+ width = snd_pcm_format_physical_width(params_format(params));
+ channel = params_channels(params);
+ ret = seek_mclk_conf(rate, width, channel);
+ if (ret < 0)
+ return ret;
+ index = ret;
+ mclk = get_mclk(ret);
+
+ /* set codec DAI configuration */
+ ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_IF
+ | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu DAI configuration */
+ ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_IF
+ | SND_SOC_DAIFMT_CBS_CFS);
+ if (ret < 0)
+ return ret;
+
+ /* set the codec system clock for DAC and ADC */
+ ret = snd_soc_dai_set_sysclk(codec_dai, WM8753_MCLK, mclk,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0)
+ return ret;
+
+ /* set cpu system clock */
+ ret = snd_soc_dai_set_sysclk(cpu_dai, PXA168_ASYSCLK_MASTER, index,
+ SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int aspenite_hifi_hw_free(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static struct snd_soc_ops aspenite_hifi_ops = {
+ .hw_params = aspenite_hifi_hw_params,
+ .hw_free = aspenite_hifi_hw_free,
+};
+
+static int aspenite_wm8753_init(struct snd_soc_codec *codec)
+{
+ int ret;
+
+ /* set up NC codec pins */
+ snd_soc_dapm_nc_pin(codec, "MONO1");
+ snd_soc_dapm_nc_pin(codec, "MONO2");
+ snd_soc_dapm_nc_pin(codec, "RXP");
+ snd_soc_dapm_nc_pin(codec, "RXN");
+
+ snd_soc_dapm_new_controls(codec, aspenite_dapm_widgets,
+ ARRAY_SIZE(aspenite_dapm_widgets));
+ ret = snd_soc_add_controls(codec, wm8753_aspenite_controls,
+ ARRAY_SIZE(wm8753_aspenite_controls));
+ if (ret < 0)
+ return ret;
+
+ snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
+
+ /* Static setup for now */
+ snd_soc_dapm_enable_pin(codec, "Headset Speaker");
+ snd_soc_dapm_enable_pin(codec, "Headset Mic");
+ snd_soc_dapm_enable_pin(codec, "Headphone");
+
+ snd_soc_dapm_sync(codec);
+ return 0;
+}
+
+static struct snd_soc_dai_link aspenite_dai[] = {
+ {
+ .name = "WM8753 HiFi",
+ .stream_name = "WM8753 HiFi",
+ .cpu_dai = &pxa168_ssp_dai[PXA168_DAI_SSP1],
+ .codec_dai = &wm8753_dai[0],
+ .init = aspenite_wm8753_init,
+ .ops = &aspenite_hifi_ops,
+ },
+};
+
+static struct snd_soc_card aspenite = {
+ .name = "Aspenite",
+ .platform = &pxa2xx_soc_platform,
+ .dai_link = aspenite_dai,
+ .num_links = ARRAY_SIZE(aspenite_dai),
+};
+
+static struct snd_soc_device aspenite_snd_devdata = {
+ .card = &aspenite,
+ .codec_dev = &soc_codec_dev_wm8753,
+};
+
+static struct platform_device *aspenite_snd_device;
+
+static int __init aspenite_init(void)
+{
+ int ret;
+
+ aspenite_snd_device = platform_device_alloc("soc-audio", -1);
+ if (!aspenite_snd_device)
+ return -ENOMEM;
+
+ platform_set_drvdata(aspenite_snd_device, &aspenite_snd_devdata);
+ aspenite_snd_devdata.dev = &aspenite_snd_device->dev;
+
+ ret = platform_device_add(aspenite_snd_device);
+ if (ret)
+ platform_device_put(aspenite_snd_device);
+ return ret;
+}
+module_init(aspenite_init);
+
+static void __exit aspenite_exit(void)
+{
+ platform_device_unregister(aspenite_snd_device);
+}
+module_exit(aspenite_exit);
+
+MODULE_DESCRIPTION("ALSA SoC WM8753 Aspenite");
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang(a)marvell.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/pxa/pxa168-ssp.c b/sound/soc/pxa/pxa168-ssp.c
new file mode 100644
index 0000000..2b20979
--- /dev/null
+++ b/sound/soc/pxa/pxa168-ssp.c
@@ -0,0 +1,645 @@
+/*
+ * pxa168-ssp.c -- ALSA Soc Audio Layer
+ *
+ * Copyright 2009-2010 Marvell International Ltd.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+#include <sound/pxa2xx-lib.h>
+
+#include <mach/hardware.h>
+#include <mach/dma.h>
+#include <mach/regs-ssp.h>
+#include <mach/regs-apbc.h>
+#include <mach/regs-apmu.h>
+#include <mach/regs-mpmu.h>
+#include <plat/ssp.h>
+
+#include "pxa2xx-pcm.h"
+#include "pxa168-ssp.h"
+
+/*
+ * SSP audio private data
+ */
+struct ssp_priv {
+ struct ssp_device *ssp;
+ unsigned int sysclk;
+ int dai_fmt;
+#ifdef CONFIG_PM
+ uint32_t cr0;
+ uint32_t cr1;
+ uint32_t to;
+ uint32_t psp;
+#endif
+};
+
+struct pxa2xx_pcm_dma_data {
+ struct pxa2xx_pcm_dma_params params;
+ char name[20];
+};
+
+struct ssp_mclk {
+ unsigned int rate;
+ unsigned int format;
+ unsigned int channel;
+ unsigned int mclk;
+ unsigned int mclk_denom;
+ unsigned int mclk_num;
+ unsigned int bclk;
+ unsigned int bclk_denom;
+ unsigned int bclk_num;
+};
+
+/*
+ * This table is used while CPU is clock master.
+ * MCLK = 312MHz * (ASYSCLK_DENOM + 1) / ASYSCLK_NUM
+ * BCLK = 2 * MCLK * (SSPSCLK_DENOM + 1) / SSPSCLK_NUM
+ */
+static const struct ssp_mclk mclk_conf[] = {
+ /* rate, fmt, chn, mclk, den, num, bclk, den, num */
+ {96000, 16, 2, 12288000, 63, 1625, 3072000, 1, 2},
+ {96000, 16, 1, 12288000, 63, 1625, 3072000, 1, 8},
+ {88200, 16, 2, 11289600, 293, 8125, 2822400, 1, 2},
+ {88200, 16, 1, 11289600, 293, 8125, 2822400, 1, 8},
+ {48000, 16, 2, 12288000, 63, 1625, 1536000, 1, 4},
+ {48000, 16, 1, 12288000, 63, 1625, 1536000, 1, 16},
+ {44100, 16, 2, 11289600, 293, 8125, 1411200, 1, 4},
+ {44100, 16, 1, 11289600, 293, 8125, 1411200, 1, 16},
+ {32000, 16, 2, 12288000, 63, 1625, 1024000, 1, 6},
+ {32000, 16, 1, 12288000, 63, 1625, 1024000, 1, 24},
+ {22050, 16, 2, 11289600, 293, 8125, 705600, 1, 8},
+ {22050, 16, 1, 11289600, 293, 8125, 705600, 1, 32},
+ {16000, 16, 2, 12288000, 63, 1625, 512000, 1, 12},
+ {16000, 16, 1, 12288000, 63, 1625, 512000, 1, 48},
+ {11025, 16, 2, 11289600, 293, 8125, 352800, 1, 16},
+ {11025, 16, 1, 11289600, 293, 8125, 352800, 1, 64},
+ { 8000, 16, 2, 12288000, 63, 1625, 256000, 1, 24},
+ { 8000, 16, 1, 12288000, 63, 1625, 256000, 1, 96},
+};
+
+/* Seek the index of MCLK configuration table */
+int seek_mclk_conf(int rate, int format, int channel)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mclk_conf); i++) {
+ if ((mclk_conf[i].rate == rate)
+ && (mclk_conf[i].format == format)
+ && (mclk_conf[i].channel == channel))
+ return i;
+ }
+ return -EINVAL;
+}
+
+/* Get the MCLK frequency */
+int get_mclk(int i)
+{
+ if ((i < 0) || (i >= ARRAY_SIZE(mclk_conf)))
+ return -EINVAL;
+ return mclk_conf[i].mclk;
+}
+
+/* Get the BCLK frequency */
+int get_bclk(int i)
+{
+ if ((i < 0) || (i >= ARRAY_SIZE(mclk_conf)))
+ return -EINVAL;
+ return mclk_conf[i].bclk;
+}
+
+static void dump_registers(struct ssp_device *ssp)
+{
+ dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n",
+ ssp_read_reg(ssp, SSCR0), ssp_read_reg(ssp, SSCR1),
+ ssp_read_reg(ssp, SSTO));
+
+ dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x\n",
+ ssp_read_reg(ssp, SSPSP), ssp_read_reg(ssp, SSSR));
+}
+
+static void ssp_enable(struct ssp_device *ssp)
+{
+ uint32_t sscr0;
+
+ sscr0 = __raw_readl(ssp->mmio_base + SSCR0) | SSCR0_SSE;
+ __raw_writel(sscr0, ssp->mmio_base + SSCR0);
+}
+
+static void ssp_disable(struct ssp_device *ssp)
+{
+ uint32_t sscr0;
+
+ sscr0 = __raw_readl(ssp->mmio_base + SSCR0) & ~SSCR0_SSE;
+ __raw_writel(sscr0, ssp->mmio_base + SSCR0);
+}
+
+static struct pxa2xx_pcm_dma_params *
+ssp_get_dma_params(struct ssp_device *ssp, int width4, int out)
+{
+ struct pxa2xx_pcm_dma_data *dma;
+
+ dma = kzalloc(sizeof(struct pxa2xx_pcm_dma_data), GFP_KERNEL);
+ if (dma == NULL)
+ return NULL;
+
+ snprintf(dma->name, 20, "SSP%d PCM %s %s", ssp->port_id,
+ width4 ? "32-bit" : "16-bit", out ? "out" : "in");
+
+ dma->params.name = dma->name;
+ dma->params.drcmr = &DRCMR(out ? ssp->drcmr_tx : ssp->drcmr_rx);
+ dma->params.dcmd = (out ? (DCMD_INCSRCADDR | DCMD_FLOWTRG) :
+ (DCMD_INCTRGADDR | DCMD_FLOWSRC)) |
+ (width4 ? DCMD_WIDTH4 : DCMD_WIDTH2) | DCMD_BURST16;
+ dma->params.dev_addr = ssp->phys_base + SSDR;
+
+ return &dma->params;
+}
+
+static int pxa168_ssp_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 ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+ int ret = 0;
+
+ if (!cpu_dai->active) {
+ clk_enable(ssp->clk);
+ ssp_disable(ssp);
+ }
+ return ret;
+}
+
+static void pxa168_ssp_shutdown(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 ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+
+ if (!cpu_dai->active) {
+ ssp_disable(ssp);
+ clk_disable(ssp->clk);
+ }
+}
+
+#ifdef CONFIG_PM
+static int pxa168_ssp_suspend(struct snd_soc_dai *cpu_dai)
+{
+ struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+
+ if (!cpu_dai->active)
+ return 0;
+
+ priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0);
+ priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1);
+ priv->to = __raw_readl(ssp->mmio_base + SSTO);
+ priv->psp = __raw_readl(ssp->mmio_base + SSPSP);
+
+ ssp_disable(ssp);
+ clk_disable(ssp->clk);
+ return 0;
+}
+
+static int pxa168_ssp_resume(struct snd_soc_dai *cpu_dai)
+{
+ struct ssp_priv *priv = cpu_dai->private_data;
+
+ if (!cpu_dai->active)
+ return 0;
+
+ __raw_writel(sssr, ssp->mmio_base + SSSR);
+
+ __raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0);
+ __raw_writel(priv->cr1, ssp->mmio_base + SSCR1);
+ __raw_writel(priv->to, ssp->mmio_base + SSTO);
+ __raw_writel(priv->psp, ssp->mmio_base + SSPSP);
+ __raw_writel(priv->cr0 | SSCR0_SSE, ssp->mmio_base + SSCR0);
+ return 0;
+}
+
+#else
+#define pxa168_ssp_suspend NULL
+#define pxa168_ssp_resume NULL
+#endif
+
+/*
+ * Set the SSP ports SYSCLK only from Audio SYSCLK.
+ */
+static int pxa168_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
+ unsigned int freq, int dir)
+{
+ struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+ unsigned int sscr0, data, asysdr, asspdr;
+
+ dev_dbg(&ssp->pdev->dev, "%s id: %d, clk_id %d, freq %u\n",
+ __func__, cpu_dai->id, clk_id, freq);
+
+ switch (clk_id) {
+ case PXA168_ASYSCLK_MASTER:
+ case PXA168_ASYSCLK_SLAVE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* freq is the index of mclk_conf table */
+ if ((freq < 0) || (freq >= ARRAY_SIZE(mclk_conf))) {
+ dev_warn(&ssp->pdev->dev, "Wrong frequency index:%d\n", freq);
+ return -EINVAL;
+ }
+ asysdr = (mclk_conf[freq].mclk_num << 16)
+ | mclk_conf[freq].mclk_denom;
+ asspdr = 0;
+ if (clk_id == PXA168_ASYSCLK_MASTER)
+ asspdr = (mclk_conf[freq].bclk_num << 16)
+ | mclk_conf[freq].bclk_denom;
+
+ ssp_disable(ssp);
+ clk_disable(ssp->clk); /* SSP port internal clock */
+
+ /* clear ECS, NCS, MOD, ACS */
+ sscr0 = ssp_read_reg(ssp, SSCR0);
+ data = sscr0 & ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS);
+ if (sscr0 != data)
+ ssp_write_reg(ssp, SSCR0, data);
+
+ /* update divider register in MPMU */
+ __raw_writel(asysdr, MPMU_ASYSDR);
+ __raw_writel(asspdr, MPMU_ASSPDR);
+
+ clk_enable(ssp->clk); /* SSP port internal clock */
+ ssp_enable(ssp);
+ return 0;
+}
+
+/*
+ * Tristate the SSP DAI lines
+ */
+static int pxa168_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai,
+ int tristate)
+{
+ struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+ u32 sscr1;
+
+ sscr1 = ssp_read_reg(ssp, SSCR1);
+ if (tristate)
+ sscr1 &= ~SSCR1_TTE;
+ else
+ sscr1 |= SSCR1_TTE;
+ ssp_write_reg(ssp, SSCR1, sscr1);
+
+ return 0;
+}
+
+/*
+ * Set up the SSP DAI format.
+ * The SSP Port must be inactive before calling this function as the
+ * physical interface format is changed.
+ */
+static int pxa168_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
+ unsigned int fmt)
+{
+ struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+ u32 sscr0;
+ u32 sscr1;
+ u32 sspsp;
+
+ /* check if we need to change anything at all */
+ if (priv->dai_fmt == fmt)
+ return 0;
+
+ ssp_disable(ssp);
+
+ sscr0 = ssp_read_reg(ssp, SSCR0);
+ sscr1 = SSCR1_RFT(8) | SSCR1_TFT(7);
+ sspsp = 0;
+
+ /* we can only change the settings if the port is not in use */
+ if (sscr0 & SSCR0_SSE) {
+ dev_err(&ssp->pdev->dev,
+ "can't change hardware dai format: stream is in use");
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBM_CFM:
+ sscr1 |= SSCR1_SCLKDIR | SSCR1_SFRMDIR;
+ break;
+ case SND_SOC_DAIFMT_CBM_CFS:
+ sscr1 |= SSCR1_SCLKDIR;
+ break;
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ sspsp |= SSPSP_SFRMP;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ sspsp |= SSPSP_SCMODE(2);
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ sspsp |= SSPSP_SCMODE(2) | SSPSP_SFRMP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ sscr0 |= SSCR0_PSP;
+ sscr1 |= SSCR1_RWOT | SSCR1_TRAIL;
+ /* See hw_params() */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ ssp_write_reg(ssp, SSCR0, sscr0);
+ ssp_write_reg(ssp, SSCR1, sscr1);
+ ssp_write_reg(ssp, SSPSP, sspsp);
+ ssp_enable(ssp);
+
+ /* Since we are configuring the timings for the format by hand
+ * we have to defer some things until hw_params() where we
+ * know parameters like the sample size.
+ */
+ priv->dai_fmt = fmt;
+
+ dump_registers(ssp);
+
+ return 0;
+}
+
+static int pxa168_ssp_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 ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+ int width = snd_pcm_format_physical_width(params_format(params));
+ int channels = params_channels(params);
+ int dma_16b = 0, stream_out, data_size;
+ u32 sscr0, sspsp;
+
+ /* generate correct DMA params */
+ if (cpu_dai->dma_data)
+ kfree(cpu_dai->dma_data);
+
+ if ((width == 16) && (params_channels(params) == 1))
+ dma_16b = 1;
+ stream_out = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 1 : 0;
+ cpu_dai->dma_data = ssp_get_dma_params(ssp, dma_16b, stream_out);
+
+ /* clear selected SSP bits */
+ sscr0 = ssp_read_reg(ssp, SSCR0);
+ sscr0 &= ~(SSCR0_DSS_MASK | SSCR0_EDSS);
+
+ /* data_size should only be 16-bit or 32-bit because of DMA */
+ data_size = width * channels;
+ switch (data_size) {
+ case 16:
+ sscr0 |= SSCR0_DSS(16);
+ break;
+ case 32:
+ sscr0 |= (SSCR0_EDSS | SSCR0_DSS(16));
+ break;
+ }
+
+ ssp_disable(ssp);
+ sspsp = ssp_read_reg(ssp, SSPSP);
+ sspsp &= ~SSPSP_TIMING_MASK;
+ switch (priv->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ /* The polarity of frame sync should be inverted at here. */
+ sspsp |= SSPSP_SFRMWDTH(width);
+ if (channels == 1) {
+ sspsp |= SSPSP_DMYSTRT(1);
+ sspsp |= SSPSP_DMYSTOP((width - 1) & 0x3);
+ sspsp |= SSPSP_EDMYSTOP(((width - 1) >> 2) & 0x7);
+ } else if (channels == 2) {
+ if (width == 32) {
+ dev_err(&ssp->pdev->dev, "can't support %d-"
+ "data with %-channels in I2S mode\n",
+ width, channels);
+ return -EINVAL;
+ }
+ sspsp |= SSPSP_FSRT;
+ }
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ /* Right Justified mode doesn't support 32-bit data */
+ if (params_format(params) == SNDRV_PCM_FORMAT_S32_LE)
+ return -EINVAL;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ sspsp |= SSPSP_SFRMWDTH(width);
+ break;
+ }
+
+ /* update SSP register at the same time */
+ ssp_write_reg(ssp, SSCR0, sscr0);
+ ssp_write_reg(ssp, SSPSP, sspsp);
+ ssp_enable(ssp);
+
+ dump_registers(ssp);
+
+ return 0;
+}
+
+static int pxa168_ssp_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+ int ret = 0;
+ struct ssp_priv *priv = cpu_dai->private_data;
+ struct ssp_device *ssp = priv->ssp;
+ int val;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_RESUME:
+ ssp_enable(ssp);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ val = ssp_read_reg(ssp, SSCR1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ val |= SSCR1_TSRE;
+ else
+ val |= SSCR1_RSRE;
+ ssp_write_reg(ssp, SSCR1, val);
+ val = ssp_read_reg(ssp, SSSR);
+ ssp_write_reg(ssp, SSSR, val);
+ break;
+ case SNDRV_PCM_TRIGGER_START:
+ val = ssp_read_reg(ssp, SSCR1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ val |= SSCR1_TSRE;
+ else
+ val |= SSCR1_RSRE;
+ ssp_write_reg(ssp, SSCR1, val);
+ ssp_enable(ssp);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ val = ssp_read_reg(ssp, SSCR1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ val &= ~SSCR1_TSRE;
+ else
+ val &= ~SSCR1_RSRE;
+ ssp_write_reg(ssp, SSCR1, val);
+ break;
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ ssp_disable(ssp);
+ break;
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ val = ssp_read_reg(ssp, SSCR1);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ val &= ~SSCR1_TSRE;
+ else
+ val &= ~SSCR1_RSRE;
+ ssp_write_reg(ssp, SSCR1, val);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ dump_registers(ssp);
+
+ return ret;
+}
+
+static int pxa168_ssp_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct ssp_priv *priv;
+ int ret;
+
+ priv = kzalloc(sizeof(struct ssp_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->ssp = ssp_request(dai->id + 1, "SoC audio");
+ if (priv->ssp == NULL) {
+ ret = -ENODEV;
+ goto err_priv;
+ }
+
+ priv->dai_fmt = (unsigned int) -1;
+ dai->private_data = priv;
+
+ return 0;
+
+err_priv:
+ kfree(priv);
+ return ret;
+}
+
+static void pxa168_ssp_remove(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ struct ssp_priv *priv = dai->private_data;
+ ssp_free(priv->ssp);
+}
+
+#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | \
+ SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | \
+ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | \
+ SNDRV_PCM_RATE_96000)
+
+#define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE \
+ | SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_ops pxa168_ssp_dai_ops = {
+ .startup = pxa168_ssp_startup,
+ .shutdown = pxa168_ssp_shutdown,
+ .trigger = pxa168_ssp_trigger,
+ .hw_params = pxa168_ssp_hw_params,
+ .set_sysclk = pxa168_ssp_set_dai_sysclk,
+ .set_fmt = pxa168_ssp_set_dai_fmt,
+ .set_tristate = pxa168_ssp_set_dai_tristate,
+};
+
+#define PXA168_SSP_DAI(_id) \
+{ \
+ .name = "pxa168-ssp" #_id, \
+ .id = 0, \
+ .probe = pxa168_ssp_probe, \
+ .remove = pxa168_ssp_remove, \
+ .suspend = pxa168_ssp_suspend, \
+ .resume = pxa168_ssp_resume, \
+ .playback = { \
+ .channels_min = 1, \
+ .channels_max = 2, \
+ .rates = PXA_SSP_RATES, \
+ .formats = PXA_SSP_FORMATS, \
+ }, \
+ .capture = { \
+ .channels_min = 1, \
+ .channels_max = 2, \
+ .rates = PXA_SSP_RATES, \
+ .formats = PXA_SSP_FORMATS, \
+ }, \
+ .ops = &pxa168_ssp_dai_ops, \
+}
+
+struct snd_soc_dai pxa168_ssp_dai[] = {
+ PXA168_SSP_DAI(0),
+ PXA168_SSP_DAI(1),
+ PXA168_SSP_DAI(2),
+ PXA168_SSP_DAI(3),
+ PXA168_SSP_DAI(4),
+};
+EXPORT_SYMBOL_GPL(pxa168_ssp_dai);
+
+static int __init pxa168_ssp_init(void)
+{
+ return snd_soc_register_dais(pxa168_ssp_dai, ARRAY_SIZE(pxa168_ssp_dai));
+}
+module_init(pxa168_ssp_init);
+
+static void __exit pxa168_ssp_exit(void)
+{
+ snd_soc_unregister_dais(pxa168_ssp_dai, ARRAY_SIZE(pxa168_ssp_dai));
+}
+module_exit(pxa168_ssp_exit);
+
+/* Module information */
+MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang(a)marvell.com>");
+MODULE_DESCRIPTION("PXA168 SSP SoC Interface");
+MODULE_LICENSE("GPL");
+
diff --git a/sound/soc/pxa/pxa168-ssp.h b/sound/soc/pxa/pxa168-ssp.h
new file mode 100644
index 0000000..10131fc
--- /dev/null
+++ b/sound/soc/pxa/pxa168-ssp.h
@@ -0,0 +1,29 @@
+/*
+ * ASoC PXA168 SSP port support
+ *
+ * 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 _PXA168_SSP_H
+#define _PXA168_SSP_H
+
+/* pxa DAI SSP IDs */
+#define PXA168_DAI_SSP1 0
+#define PXA168_DAI_SSP2 1
+#define PXA168_DAI_SSP3 2
+#define PXA168_DAI_SSP4 3
+#define PXA168_DAI_SSP5 4
+
+/* PXA168 SSP SYSCLK source */
+#define PXA168_ASYSCLK_MASTER 0
+#define PXA168_ASYSCLK_SLAVE 1
+
+extern struct snd_soc_dai pxa168_ssp_dai[5];
+
+extern int seek_mclk_conf(int rate, int format, int channel);
+extern int get_mclk(int i);
+extern int get_bclk(int i);
+
+#endif
--
1.5.6.5
1
0
[alsa-devel] [PATCH 2/2] ASoC: da7210: Add 11025/22050/44100/88200 rate support
by Kuninori Morimoto 10 Mar '10
by Kuninori Morimoto 10 Mar '10
10 Mar '10
This driver USE PLL for 11025/22050/44100/88200 rate.
To enable switching to bypass mode, PLL is always turned on.
Special thanks to Phil
Signed-off-by: Phil Edworthy <Phil.Edworthy(a)renesas.com>
Signed-off-by: Kuninori Morimoto <morimoto.kuninori(a)renesas.com>
---
sound/soc/codecs/da7210.c | 87 ++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c
index 3bd867d..4083c7e 100644
--- a/sound/soc/codecs/da7210.c
+++ b/sound/soc/codecs/da7210.c
@@ -55,8 +55,14 @@
#define DA7210_DAI_SRC_SEL 0x25
#define DA7210_DAI_CFG1 0x26
#define DA7210_DAI_CFG3 0x28
+#define DA7210_PLL_DIV1 0x29
+#define DA7210_PLL_DIV2 0x2A
#define DA7210_PLL_DIV3 0x2B
#define DA7210_PLL 0x2C
+#define DA7210_A_HID_UNLOCK 0x8A
+#define DA7210_A_TEST_UNLOCK 0x8B
+#define DA7210_A_PLL1 0x90
+#define DA7210_A_CP_MODE 0xA7
/* STARTUP1 bit fields */
#define DA7210_SC_MST_EN (1 << 0)
@@ -124,13 +130,17 @@
/* PLL bit fields */
#define DA7210_PLL_FS_MASK (0xF << 0)
#define DA7210_PLL_FS_8000 (0x1 << 0)
+#define DA7210_PLL_FS_11025 (0x2 << 0)
#define DA7210_PLL_FS_12000 (0x3 << 0)
#define DA7210_PLL_FS_16000 (0x5 << 0)
+#define DA7210_PLL_FS_22050 (0x6 << 0)
#define DA7210_PLL_FS_24000 (0x7 << 0)
#define DA7210_PLL_FS_32000 (0x9 << 0)
+#define DA7210_PLL_FS_44100 (0xA << 0)
#define DA7210_PLL_FS_48000 (0xB << 0)
+#define DA7210_PLL_FS_88200 (0xE << 0)
#define DA7210_PLL_FS_96000 (0xF << 0)
-
+#define DA7210_PLL_EN (0x1 << 7)
#define DA7210_VERSION "0.0.1"
@@ -249,7 +259,7 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = socdev->card->codec;
u32 dai_cfg1;
u32 hpf_reg, hpf_mask, hpf_value;
- u32 fs;
+ u32 fs, bypass;
/* set DAI source to Left and Right ADC */
da7210_write(codec, DA7210_DAI_SRC_SEL,
@@ -281,38 +291,76 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
fs = DA7210_PLL_FS_8000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
+ bypass = DA7210_PLL_BYP;
+ break;
+ case 11025:
+ fs = DA7210_PLL_FS_11025;
+ hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
+ hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
+ bypass = 0;
break;
case 12000:
fs = DA7210_PLL_FS_12000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
+ bypass = DA7210_PLL_BYP;
break;
case 16000:
fs = DA7210_PLL_FS_16000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
+ bypass = DA7210_PLL_BYP;
+ break;
+ case 22050:
+ fs = DA7210_PLL_FS_22050;
+ hpf_mask = DA7210_VOICE_EN;
+ hpf_value = 0;
+ bypass = 0;
break;
case 32000:
fs = DA7210_PLL_FS_32000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
+ bypass = DA7210_PLL_BYP;
+ break;
+ case 44100:
+ fs = DA7210_PLL_FS_44100;
+ hpf_mask = DA7210_VOICE_EN;
+ hpf_value = 0;
+ bypass = 0;
break;
case 48000:
fs = DA7210_PLL_FS_48000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
+ bypass = DA7210_PLL_BYP;
+ break;
+ case 88200:
+ fs = DA7210_PLL_FS_88200;
+ hpf_mask = DA7210_VOICE_EN;
+ hpf_value = 0;
+ bypass = 0;
break;
case 96000:
fs = DA7210_PLL_FS_96000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
+ bypass = DA7210_PLL_BYP;
break;
default:
return -EINVAL;
}
+ /* Disable active mode */
+ snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
+
snd_soc_update_bits(codec, hpf_reg, hpf_mask, hpf_value);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
+ snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
+
+ /* Enable active mode */
+ snd_soc_update_bits(codec, DA7210_STARTUP1,
+ DA7210_SC_MST_EN, DA7210_SC_MST_EN);
return 0;
}
@@ -444,9 +492,23 @@ static int da7210_init(struct da7210_priv *da7210)
/* FIXME
*
* This driver use fixed value here
+ * And below settings expects MCLK = 12.288MHz
+ *
+ * When you select different MCLK, please check...
+ * DA7210_PLL_DIV1 val
+ * DA7210_PLL_DIV2 val
+ * DA7210_PLL_DIV3 val
+ * DA7210_PLL_DIV3 :: DA7210_MCLK_RANGExxx
*/
/*
+ * make sure that DA7210 use bypass mode before start up
+ */
+ da7210_write(codec, DA7210_STARTUP1, 0);
+ da7210_write(codec, DA7210_PLL_DIV3,
+ DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+
+ /*
* ADC settings
*/
@@ -482,9 +544,26 @@ static int da7210_init(struct da7210_priv *da7210)
/* Diable PLL and bypass it */
da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
- /* Bypass PLL and set MCLK freq rang to 10-20MHz */
- da7210_write(codec, DA7210_PLL_DIV3,
+ /*
+ * If 48kHz sound came, it use bypass mode,
+ * and when it is 44.1kHz, it use PLL.
+ *
+ * This time, this driver sets PLL always ON
+ * and controls bypass/PLL mode by switching
+ * DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
+ * see da7210_hw_params
+ */
+ da7210_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
+ da7210_write(codec, DA7210_PLL_DIV2, 0x99);
+ da7210_write(codec, DA7210_PLL_DIV3, 0x0A |
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
+ snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
+
+ /* As suggested by Dialog */
+ da7210_write(codec, DA7210_A_HID_UNLOCK, 0x8B);
+ da7210_write(codec, DA7210_A_TEST_UNLOCK, 0xB4);
+ da7210_write(codec, DA7210_A_PLL1, 0x01);
+ da7210_write(codec, DA7210_A_CP_MODE, 0x7C);
/* Activate all enabled subsystem */
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
--
1.6.3.3
2
3
[alsa-devel] [PATCH] alsa: provide a more useful get_unmapped_area handler for pcm
by Mike Frysinger 10 Mar '10
by Mike Frysinger 10 Mar '10
10 Mar '10
From: Daniel Glöckner <dg(a)emlix.com>
Shared memory mappings on nommu machines require a get_unmapped_area
file operation that suggests an address for the mapping. The current
implementation returns 0 and thus forces the driver to implement an
mmap handler that fixes up the start and end address of the vma.
This patch returns the address of the dma buffer, so it should work
out of the box for all drivers that use the snd_pcm_runtime->dma_area
pointer.
Addresses for mapping the status and control pages are returned as
well, but to make those work the conditional compilation of
snd_pcm_mmap_{status,control} would need to be revised.
URL: http://thread.gmane.org/gmane.linux.alsa.devel/61230
Signed-off-by: Daniel Glöckner <dg(a)emlix.com>
Signed-off-by: Cliff Cai <cliff.cai(a)analog.com>
Signed-off-by: Mike Frysinger <vapier(a)gentoo.org>
---
this has been posted before but didnt seem to get any feedback ...
sound/core/pcm_native.c | 30 ++++++++++++++++++++++--------
1 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 8728876..9681518 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -3434,14 +3434,28 @@ out:
#endif /* CONFIG_SND_SUPPORT_OLD_API */
#ifndef CONFIG_MMU
-unsigned long dummy_get_unmapped_area(struct file *file, unsigned long addr,
- unsigned long len, unsigned long pgoff,
- unsigned long flags)
-{
- return 0;
+static unsigned long snd_pcm_get_unmapped_area(struct file *file,
+ unsigned long addr,
+ unsigned long len,
+ unsigned long pgoff,
+ unsigned long flags)
+{
+ struct snd_pcm_file *pcm_file = file->private_data;
+ struct snd_pcm_substream *substream = pcm_file->substream;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ unsigned long offset = pgoff << PAGE_SHIFT;
+
+ switch (offset) {
+ case SNDRV_PCM_MMAP_OFFSET_STATUS:
+ return (unsigned long)runtime->status;
+ case SNDRV_PCM_MMAP_OFFSET_CONTROL:
+ return (unsigned long)runtime->control;
+ default:
+ return (unsigned long)runtime->dma_area + offset;
+ }
}
#else
-# define dummy_get_unmapped_area NULL
+# define snd_pcm_get_unmapped_area NULL
#endif
/*
@@ -3460,7 +3474,7 @@ const struct file_operations snd_pcm_f_ops[2] = {
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
- .get_unmapped_area = dummy_get_unmapped_area,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
},
{
.owner = THIS_MODULE,
@@ -3473,6 +3487,6 @@ const struct file_operations snd_pcm_f_ops[2] = {
.compat_ioctl = snd_pcm_ioctl_compat,
.mmap = snd_pcm_mmap,
.fasync = snd_pcm_fasync,
- .get_unmapped_area = dummy_get_unmapped_area,
+ .get_unmapped_area = snd_pcm_get_unmapped_area,
}
};
--
1.7.0.2
2
1
10 Mar '10
Switch the MACHINE driver to use IISv4 CPU dai.
Remove BROKEN dependency now that we have proper CPU driver available.
Also, disable build for SMDK6400, since the S3C6400 doesn't have IISv4
controller.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 7 +++----
sound/soc/s3c24xx/smdk64xx_wm8580.c | 6 ++----
2 files changed, 5 insertions(+), 8 deletions(-)
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index c0c7edf..2ac1f33 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -64,12 +64,11 @@ config SND_S3C24XX_SOC_JIVE_WM8750
config SND_S3C64XX_SOC_WM8580
tristate "SoC I2S Audio support for WM8580 on SMDK64XX"
- depends on SND_S3C24XX_SOC && (MACH_SMDK6400 || MACH_SMDK6410)
- depends on BROKEN
+ depends on SND_S3C24XX_SOC && MACH_SMDK6410
select SND_SOC_WM8580
- select SND_S3C64XX_SOC_I2S
+ select SND_S3C64XX_SOC_I2S_V4
help
- Sat Y if you want to add support for SoC audio on the SMDK64XX.
+ Say Y if you want to add support for SoC audio on the SMDK64XX.
config SND_S3C24XX_SOC_SMDK2443_WM9710
tristate "SoC AC97 Audio support for SMDK2443 - WM9710"
diff --git a/sound/soc/s3c24xx/smdk64xx_wm8580.c b/sound/soc/s3c24xx/smdk64xx_wm8580.c
index efe4901..07e8e51 100644
--- a/sound/soc/s3c24xx/smdk64xx_wm8580.c
+++ b/sound/soc/s3c24xx/smdk64xx_wm8580.c
@@ -22,8 +22,6 @@
#include "s3c-dma.h"
#include "s3c64xx-i2s.h"
-#define S3C64XX_I2S_V4 2
-
/* SMDK64XX has a 12MHZ crystal attached to WM8580 */
#define SMDK64XX_WM8580_FREQ 12000000
@@ -215,7 +213,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Playback i/f */
.name = "WM8580 PAIF RX",
.stream_name = "Playback",
- .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
+ .cpu_dai = &s3c64xx_i2s_v4_dai,
.codec_dai = &wm8580_dai[WM8580_DAI_PAIFRX],
.init = smdk64xx_wm8580_init_paifrx,
.ops = &smdk64xx_ops,
@@ -223,7 +221,7 @@ static struct snd_soc_dai_link smdk64xx_dai[] = {
{ /* Primary Capture i/f */
.name = "WM8580 PAIF TX",
.stream_name = "Capture",
- .cpu_dai = &s3c64xx_i2s_dai[S3C64XX_I2S_V4],
+ .cpu_dai = &s3c64xx_i2s_v4_dai,
.codec_dai = &wm8580_dai[WM8580_DAI_PAIFTX],
.init = smdk64xx_wm8580_init_paiftx,
.ops = &smdk64xx_ops,
--
1.6.2.5
1
0
Add the CPU driver for the IISv4 block found on S3C6410.
For now, the driver is almost a copy of s3c64xx-i2s.c but
it should diverge as more IISv4 specific stuff is added.
Signed-off-by: Jassi Brar <jassi.brar(a)samsung.com>
---
sound/soc/s3c24xx/Kconfig | 5 +
sound/soc/s3c24xx/Makefile | 2 +
sound/soc/s3c24xx/s3c64xx-i2s-v4.c | 206 ++++++++++++++++++++++++++++++++++++
sound/soc/s3c24xx/s3c64xx-i2s.h | 1 +
4 files changed, 214 insertions(+), 0 deletions(-)
create mode 100644 sound/soc/s3c24xx/s3c64xx-i2s-v4.c
diff --git a/sound/soc/s3c24xx/Kconfig b/sound/soc/s3c24xx/Kconfig
index 15fe57e..c0c7edf 100644
--- a/sound/soc/s3c24xx/Kconfig
+++ b/sound/soc/s3c24xx/Kconfig
@@ -24,6 +24,11 @@ config SND_S3C64XX_SOC_I2S
select SND_S3C_I2SV2_SOC
select S3C64XX_DMA
+config SND_S3C64XX_SOC_I2S_V4
+ tristate
+ select SND_S3C_I2SV2_SOC
+ select S3C64XX_DMA
+
config SND_S3C_SOC_PCM
tristate
diff --git a/sound/soc/s3c24xx/Makefile b/sound/soc/s3c24xx/Makefile
index df071a3..81d8dc5 100644
--- a/sound/soc/s3c24xx/Makefile
+++ b/sound/soc/s3c24xx/Makefile
@@ -4,6 +4,7 @@ snd-soc-s3c24xx-i2s-objs := s3c24xx-i2s.o
snd-soc-s3c2412-i2s-objs := s3c2412-i2s.o
snd-soc-s3c64xx-i2s-objs := s3c64xx-i2s.o
snd-soc-s3c-ac97-objs := s3c-ac97.o
+snd-soc-s3c64xx-i2s-v4-objs := s3c64xx-i2s-v4.o
snd-soc-s3c-i2s-v2-objs := s3c-i2s-v2.o
snd-soc-s3c-pcm-objs := s3c-pcm.o
@@ -12,6 +13,7 @@ obj-$(CONFIG_SND_S3C24XX_SOC_I2S) += snd-soc-s3c24xx-i2s.o
obj-$(CONFIG_SND_S3C_SOC_AC97) += snd-soc-s3c-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_S3C64XX_SOC_I2S_V4) += snd-soc-s3c64xx-i2s-v4.o
obj-$(CONFIG_SND_S3C_I2SV2_SOC) += snd-soc-s3c-i2s-v2.o
obj-$(CONFIG_SND_S3C_SOC_PCM) += snd-soc-s3c-pcm.o
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s-v4.c b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
new file mode 100644
index 0000000..d1fa837
--- /dev/null
+++ b/sound/soc/s3c24xx/s3c64xx-i2s-v4.c
@@ -0,0 +1,206 @@
+/* sound/soc/s3c24xx/s3c64xx-i2s-v4.c
+ *
+ * ALSA SoC Audio Layer - S3C64XX I2Sv4 driver
+ * Copyright (c) 2010 Samsung Electronics Co. Ltd
+ * Author: Jaswinder Singh <jassi.brar(a)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/clk.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+
+#include <plat/gpio-bank-c.h>
+#include <plat/gpio-bank-h.h>
+#include <plat/gpio-cfg.h>
+
+#include <mach/map.h>
+#include <mach/dma.h>
+
+#include "s3c-dma.h"
+#include "regs-i2s-v2.h"
+#include "s3c64xx-i2s.h"
+
+static struct s3c2410_dma_client s3c64xx_dma_client_out = {
+ .name = "I2Sv4 PCM Stereo out"
+};
+
+static struct s3c2410_dma_client s3c64xx_dma_client_in = {
+ .name = "I2Sv4 PCM Stereo in"
+};
+
+static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_out;
+static struct s3c_dma_params s3c64xx_i2sv4_pcm_stereo_in;
+static struct s3c_i2sv2_info s3c64xx_i2sv4;
+
+struct snd_soc_dai s3c64xx_i2s_v4_dai;
+EXPORT_SYMBOL_GPL(s3c64xx_i2s_v4_dai);
+
+static inline struct s3c_i2sv2_info *to_info(struct snd_soc_dai *cpu_dai)
+{
+ return cpu_dai->private_data;
+}
+
+static int s3c64xx_i2sv4_probe(struct platform_device *pdev,
+ struct snd_soc_dai *dai)
+{
+ /* configure GPIO for i2s port */
+ s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C64XX_GPC4_I2S_V40_DO0);
+ s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C64XX_GPC5_I2S_V40_DO1);
+ s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C64XX_GPC7_I2S_V40_DO2);
+ s3c_gpio_cfgpin(S3C64XX_GPH(6), S3C64XX_GPH6_I2S_V40_BCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPH(7), S3C64XX_GPH7_I2S_V40_CDCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPH(8), S3C64XX_GPH8_I2S_V40_LRCLK);
+ s3c_gpio_cfgpin(S3C64XX_GPH(9), S3C64XX_GPH9_I2S_V40_DI);
+
+ return 0;
+}
+
+static int s3c_i2sv4_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct s3c_i2sv2_info *i2s = to_info(cpu_dai);
+ u32 iismod;
+
+ dev_dbg(cpu_dai->dev, "Entered %s\n", __func__);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ cpu_dai->dma_data = i2s->dma_playback;
+ else
+ cpu_dai->dma_data = i2s->dma_capture;
+
+ iismod = readl(i2s->regs + S3C2412_IISMOD);
+ dev_dbg(cpu_dai->dev, "%s: r: IISMOD: %x\n", __func__, iismod);
+
+ iismod &= ~S3C64XX_IISMOD_BLC_MASK;
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ iismod |= S3C64XX_IISMOD_BLC_8BIT;
+ break;
+ case SNDRV_PCM_FORMAT_S16_LE:
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iismod |= S3C64XX_IISMOD_BLC_24BIT;
+ break;
+ }
+
+ writel(iismod, i2s->regs + S3C2412_IISMOD);
+ dev_dbg(cpu_dai->dev, "%s: w: IISMOD: %x\n", __func__, iismod);
+
+ return 0;
+}
+
+static struct snd_soc_dai_ops s3c64xx_i2sv4_dai_ops = {
+ .hw_params = s3c_i2sv4_hw_params,
+};
+
+static __devinit int s3c64xx_i2sv4_dev_probe(struct platform_device *pdev)
+{
+ struct s3c_i2sv2_info *i2s;
+ struct snd_soc_dai *dai;
+ int ret;
+
+ i2s = &s3c64xx_i2sv4;
+ dai = &s3c64xx_i2s_v4_dai;
+
+ if (dai->dev) {
+ dev_dbg(dai->dev, "%s: \
+ I2Sv4 instance already registered!\n", __func__);
+ return -EBUSY;
+ }
+
+ dai->dev = &pdev->dev;
+ dai->name = "s3c64xx-i2s-v4";
+ dai->id = 0;
+ dai->symmetric_rates = 1;
+ dai->playback.channels_min = 2;
+ dai->playback.channels_max = 2;
+ dai->playback.rates = S3C64XX_I2S_RATES;
+ dai->playback.formats = S3C64XX_I2S_FMTS;
+ dai->capture.channels_min = 2;
+ dai->capture.channels_max = 2;
+ dai->capture.rates = S3C64XX_I2S_RATES;
+ dai->capture.formats = S3C64XX_I2S_FMTS;
+ dai->probe = s3c64xx_i2sv4_probe;
+ dai->ops = &s3c64xx_i2sv4_dai_ops;
+
+ i2s->feature |= S3C_FEATURE_CDCLKCON;
+
+ i2s->dma_capture = &s3c64xx_i2sv4_pcm_stereo_in;
+ i2s->dma_playback = &s3c64xx_i2sv4_pcm_stereo_out;
+
+ i2s->dma_capture->channel = DMACH_HSI_I2SV40_RX;
+ i2s->dma_capture->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISRXD;
+ i2s->dma_playback->channel = DMACH_HSI_I2SV40_TX;
+ i2s->dma_playback->dma_addr = S3C64XX_PA_IISV4 + S3C2412_IISTXD;
+
+ i2s->dma_capture->client = &s3c64xx_dma_client_in;
+ i2s->dma_capture->dma_size = 4;
+ i2s->dma_playback->client = &s3c64xx_dma_client_out;
+ i2s->dma_playback->dma_size = 4;
+
+ i2s->iis_cclk = clk_get(&pdev->dev, "audio-bus");
+ if (IS_ERR(i2s->iis_cclk)) {
+ dev_err(&pdev->dev, "failed to get audio-bus\n");
+ ret = PTR_ERR(i2s->iis_cclk);
+ goto err;
+ }
+
+ clk_enable(i2s->iis_cclk);
+
+ ret = s3c_i2sv2_probe(pdev, dai, i2s, 0);
+ if (ret)
+ goto err_clk;
+
+ ret = s3c_i2sv2_register_dai(dai);
+ if (ret != 0)
+ goto err_i2sv2;
+
+ return 0;
+
+err_i2sv2:
+ /* Not implemented for I2Sv2 core yet */
+err_clk:
+ clk_put(i2s->iis_cclk);
+err:
+ return ret;
+}
+
+static __devexit int s3c64xx_i2sv4_dev_remove(struct platform_device *pdev)
+{
+ dev_err(&pdev->dev, "Device removal not yet supported\n");
+ return 0;
+}
+
+static struct platform_driver s3c64xx_i2sv4_driver = {
+ .probe = s3c64xx_i2sv4_dev_probe,
+ .remove = s3c64xx_i2sv4_dev_remove,
+ .driver = {
+ .name = "s3c64xx-iis-v4",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init s3c64xx_i2sv4_init(void)
+{
+ return platform_driver_register(&s3c64xx_i2sv4_driver);
+}
+module_init(s3c64xx_i2sv4_init);
+
+static void __exit s3c64xx_i2sv4_exit(void)
+{
+ platform_driver_unregister(&s3c64xx_i2sv4_driver);
+}
+module_exit(s3c64xx_i2sv4_exit);
+
+/* Module information */
+MODULE_AUTHOR("Jaswinder Singh, <jassi.brar(a)samsung.com>");
+MODULE_DESCRIPTION("S3C64XX I2Sv4 SoC Interface");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.h b/sound/soc/s3c24xx/s3c64xx-i2s.h
index f27ed50..7a40f43 100644
--- a/sound/soc/s3c24xx/s3c64xx-i2s.h
+++ b/sound/soc/s3c24xx/s3c64xx-i2s.h
@@ -37,5 +37,6 @@ struct clk;
SNDRV_PCM_FMTBIT_S24_LE)
extern struct snd_soc_dai s3c64xx_i2s_dai[];
+extern struct snd_soc_dai s3c64xx_i2s_v4_dai;
#endif /* __SND_SOC_S3C24XX_S3C64XX_I2S_H */
--
1.6.2.5
1
0