[alsa-devel] [RFC PATCH 3/5] pxa: clean up the legacy SSP API
Eric Miao
eric.y.miao at gmail.com
Thu Apr 23 07:06:12 CEST 2009
Actually, due to the number of possible SSP configurations, it's quite a
difficult job to maintain an API that can be well re-used. The guideline
here is to keep only a list of SSP devices and their basic information,
and it's up to the user driver (like SPI or Audio SSP) to configure the
SSP in a desired way.
Now that the legacy 'struct ssp_dev' based APIs are removed, and only the
functions below are kept, modified a little bit to make them aware of the
new 'struct ssp_device':
ssp_enable()
ssp_disable()
ssp_save_state()
ssp_restore_state()
And finally, ssp_{save,restore}_state() can be merged into the suspend()
and resume() interface of the SSP's platform_driver, thus saving the user
driver from doing some similar things in common.
Signed-off-by: Eric Miao <eric.miao at marvell.com>
---
arch/arm/mach-pxa/include/mach/ssp.h | 32 +----
arch/arm/mach-pxa/ssp.c | 240 +---------------------------------
sound/soc/pxa/pxa-ssp.c | 65 +++++-----
3 files changed, 45 insertions(+), 292 deletions(-)
diff --git a/arch/arm/mach-pxa/include/mach/ssp.h
b/arch/arm/mach-pxa/include/mach/ssp.h
index cb5cb76..e431685 100644
--- a/arch/arm/mach-pxa/include/mach/ssp.h
+++ b/arch/arm/mach-pxa/include/mach/ssp.h
@@ -58,26 +58,10 @@ struct ssp_state {
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);
+void ssp_enable(struct ssp_device *ssp);
+void ssp_disable(struct ssp_device *ssp);
+void ssp_save_state(struct ssp_device *ssp, struct ssp_state *);
+void ssp_restore_state(struct ssp_device *ssp, struct ssp_state *);
/**
* ssp_write_reg - Write to a SSP register
@@ -86,9 +70,9 @@ void ssp_exit(struct ssp_dev *dev);
* @reg: Register to write to
* @val: Value to be written.
*/
-static inline void ssp_write_reg(struct ssp_device *dev, u32 reg, u32 val)
+static inline void ssp_write_reg(struct ssp_device *ssp, u32 reg, u32 val)
{
- __raw_writel(val, dev->mmio_base + reg);
+ __raw_writel(val, ssp->mmio_base + reg);
}
/**
@@ -97,9 +81,9 @@ static inline void ssp_write_reg(struct ssp_device
*dev, u32 reg, u32 val)
* @dev: SSP device to access
* @reg: Register to read from
*/
-static inline u32 ssp_read_reg(struct ssp_device *dev, u32 reg)
+static inline u32 ssp_read_reg(struct ssp_device *ssp, u32 reg)
{
- return __raw_readl(dev->mmio_base + reg);
+ return __raw_readl(ssp->mmio_base + reg);
}
struct ssp_device *ssp_request(int port, const char *label);
diff --git a/arch/arm/mach-pxa/ssp.c b/arch/arm/mach-pxa/ssp.c
index 965e38c..f48807a 100644
--- a/arch/arm/mach-pxa/ssp.c
+++ b/arch/arm/mach-pxa/ssp.c
@@ -35,153 +35,25 @@
#include <mach/ssp.h>
#include <mach/regs-ssp.h>
-#define TIMEOUT 100000
-
-static irqreturn_t ssp_interrupt(int irq, void *dev_id)
+void ssp_enable(struct ssp_device *ssp)
{
- 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);
}
+EXPORT_SYMBOL(ssp_enable);
-/**
- * ssp_disable - shut down the SSP port
- *
- * Turn off the SSP port, optionally powering it down.
- */
-void ssp_disable(struct ssp_dev *dev)
+void ssp_disable(struct ssp_device *ssp)
{
- 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);
}
+EXPORT_SYMBOL(ssp_disable);
/**
* ssp_save_state - save the SSP configuration
@@ -189,16 +61,12 @@ void ssp_disable(struct ssp_dev *dev)
*
* Save the configured SSP state for suspend.
*/
-void ssp_save_state(struct ssp_dev *dev, struct ssp_state *state)
+void ssp_save_state(struct ssp_device *ssp, 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);
}
/**
@@ -207,9 +75,8 @@ void ssp_save_state(struct ssp_dev *dev, struct
ssp_state *state)
*
* Restore the SSP configuration saved previously by ssp_save_state.
*/
-void ssp_restore_state(struct ssp_dev *dev, struct ssp_state *state)
+void ssp_restore_state(struct ssp_device *ssp, 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);
@@ -221,89 +88,6 @@ void ssp_restore_state(struct ssp_dev *dev, struct
ssp_state *state)
__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);
-}
-
static DEFINE_MUTEX(ssp_lock);
static LIST_HEAD(ssp_list);
@@ -531,18 +315,6 @@ static void __exit pxa_ssp_exit(void)
arch_initcall(pxa_ssp_init);
module_exit(pxa_ssp_exit);
-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);
-
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 308a657..a65993c 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -42,7 +42,7 @@
* SSP audio private data
*/
struct ssp_priv {
- struct ssp_dev dev;
+ struct ssp_device *ssp;
unsigned int sysclk;
int dai_fmt;
#ifdef CONFIG_PM
@@ -222,10 +222,8 @@ static int pxa_ssp_startup(struct
snd_pcm_substream *substream,
int ret = 0;
if (!cpu_dai->active) {
- priv->dev.port = cpu_dai->id + 1;
- priv->dev.irq = NO_IRQ;
- clk_enable(priv->dev.ssp->clk);
- ssp_disable(&priv->dev);
+ clk_enable(priv->ssp->clk);
+ ssp_disable(priv->ssp);
}
return ret;
}
@@ -238,8 +236,8 @@ static void pxa_ssp_shutdown(struct
snd_pcm_substream *substream,
struct ssp_priv *priv = cpu_dai->private_data;
if (!cpu_dai->active) {
- ssp_disable(&priv->dev);
- clk_disable(priv->dev.ssp->clk);
+ ssp_disable(priv->ssp);
+ clk_disable(priv->ssp->clk);
}
}
@@ -252,8 +250,9 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
if (!cpu_dai->active)
return 0;
- ssp_save_state(&priv->dev, &priv->state);
- clk_disable(priv->dev.ssp->clk);
+ ssp_save_state(priv->ssp, &priv->state);
+ ssp_disable(priv->ssp);
+ clk_disable(priv->ssp->clk);
return 0;
}
@@ -264,10 +263,9 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
if (!cpu_dai->active)
return 0;
- clk_enable(priv->dev.ssp->clk);
- ssp_restore_state(&priv->dev, &priv->state);
- ssp_enable(&priv->dev);
-
+ clk_enable(priv->ssp->clk);
+ ssp_restore_state(priv->ssp, &priv->state);
+ ssp_enable(priv->ssp);
return 0;
}
@@ -280,10 +278,9 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
* ssp_set_clkdiv - set SSP clock divider
* @div: serial clock rate divider
*/
-static void ssp_set_scr(struct ssp_dev *dev, u32 div)
+static void ssp_set_scr(struct ssp_device *ssp, u32 div)
{
- struct ssp_device *ssp = dev->ssp;
- u32 sscr0 = ssp_read_reg(dev->ssp, SSCR0) & ~SSCR0_SCR;
+ u32 sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SCR;
ssp_write_reg(ssp, SSCR0, (sscr0 | SSCR0_SerClkDiv(div)));
}
@@ -295,7 +292,7 @@ static int pxa_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->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
int val;
u32 sscr0 = ssp_read_reg(ssp, SSCR0) &
@@ -326,7 +323,7 @@ static int pxa_ssp_set_dai_sysclk(struct
snd_soc_dai *cpu_dai,
break;
case PXA_SSP_CLK_AUDIO:
priv->sysclk = 0;
- ssp_set_scr(&priv->dev, 1);
+ ssp_set_scr(priv->ssp, 1);
sscr0 |= SSCR0_ACS;
break;
default:
@@ -336,11 +333,11 @@ static int pxa_ssp_set_dai_sysclk(struct
snd_soc_dai *cpu_dai,
/* The SSP clock must be disabled when changing SSP clock mode
* on PXA2xx. On PXA3xx it must be enabled when doing so. */
if (!cpu_is_pxa3xx())
- clk_disable(priv->dev.ssp->clk);
+ clk_disable(priv->ssp->clk);
val = ssp_read_reg(ssp, SSCR0) | sscr0;
ssp_write_reg(ssp, SSCR0, val);
if (!cpu_is_pxa3xx())
- clk_enable(priv->dev.ssp->clk);
+ clk_enable(priv->ssp->clk);
return 0;
}
@@ -352,7 +349,7 @@ static int pxa_ssp_set_dai_clkdiv(struct
snd_soc_dai *cpu_dai,
int div_id, int div)
{
struct ssp_priv *priv = cpu_dai->private_data;
- struct ssp_device *ssp = priv->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
int val;
switch (div_id) {
@@ -387,7 +384,7 @@ static int pxa_ssp_set_dai_clkdiv(struct
snd_soc_dai *cpu_dai,
ssp_write_reg(ssp, SSACD, val);
break;
case PXA_SSP_DIV_SCR:
- ssp_set_scr(&priv->dev, div);
+ ssp_set_scr(ssp, div);
break;
default:
return -ENODEV;
@@ -403,7 +400,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai,
int pll_id, unsigned int freq_in, unsigned int freq_out)
{
struct ssp_priv *priv = cpu_dai->private_data;
- struct ssp_device *ssp = priv->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70;
#if defined(CONFIG_PXA3xx)
@@ -472,7 +469,7 @@ static int pxa_ssp_set_dai_tdm_slot(struct
snd_soc_dai *cpu_dai,
unsigned int mask, int slots)
{
struct ssp_priv *priv = cpu_dai->private_data;
- struct ssp_device *ssp = priv->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
u32 sscr0;
sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7);
@@ -494,7 +491,7 @@ static int pxa_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->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
u32 sscr1;
sscr1 = ssp_read_reg(ssp, SSCR1);
@@ -516,7 +513,7 @@ static int pxa_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->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
u32 sscr0;
u32 sscr1;
u32 sspsp;
@@ -622,7 +619,7 @@ static int pxa_ssp_hw_params(struct
snd_pcm_substream *substream,
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->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
int dma = 0, chn = params_channels(params);
u32 sscr0;
u32 sspsp;
@@ -735,12 +732,12 @@ static int pxa_ssp_trigger(struct
snd_pcm_substream *substream, int cmd,
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->dev.ssp;
+ struct ssp_device *ssp = priv->ssp;
int val;
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
- ssp_enable(&priv->dev);
+ ssp_enable(ssp);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
val = ssp_read_reg(ssp, SSCR1);
@@ -759,7 +756,7 @@ static int pxa_ssp_trigger(struct
snd_pcm_substream *substream, int cmd,
else
val |= SSCR1_RSRE;
ssp_write_reg(ssp, SSCR1, val);
- ssp_enable(&priv->dev);
+ ssp_enable(ssp);
break;
case SNDRV_PCM_TRIGGER_STOP:
val = ssp_read_reg(ssp, SSCR1);
@@ -770,7 +767,7 @@ static int pxa_ssp_trigger(struct
snd_pcm_substream *substream, int cmd,
ssp_write_reg(ssp, SSCR1, val);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- ssp_disable(&priv->dev);
+ ssp_disable(ssp);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
val = ssp_read_reg(ssp, SSCR1);
@@ -800,8 +797,8 @@ static int pxa_ssp_probe(struct platform_device *pdev,
if (!priv)
return -ENOMEM;
- priv->dev.ssp = ssp_request(dai->id + 1, "SoC audio");
- if (priv->dev.ssp == NULL) {
+ priv->ssp = ssp_request(dai->id + 1, "SoC audio");
+ if (priv->ssp == NULL) {
ret = -ENODEV;
goto err_priv;
}
@@ -819,7 +816,7 @@ static void pxa_ssp_remove(struct platform_device *pdev,
struct snd_soc_dai *dai)
{
struct ssp_priv *priv = dai->private_data;
- ssp_free(priv->dev.ssp);
+ ssp_free(priv->ssp);
}
#define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
--
1.6.0.4
More information about the Alsa-devel
mailing list