mxc gpio: CONFIG_ARCH_* -> cpu_is_*()
[safe/jmp/linux-2.6] / sound / soc / s3c24xx / s3c24xx-i2s.c
index ff99b76..556e35f 100644 (file)
@@ -4,7 +4,7 @@
  * (c) 2006 Wolfson Microelectronics PLC.
  * Graeme Gregory graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com
  *
- * (c) 2004-2005 Simtec Electronics
+ * Copyright 2004-2005 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
  *
  *  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.
- *
- *
- *  Revision history
- *    11th Dec 2006   Merged with Simtec driver
- *    10th Nov 2006   Initial version.
  */
 
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/clk.h>
 #include <linux/jiffies.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
 #include <sound/core.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/initval.h>
 #include <sound/soc.h>
 
-#include <asm/hardware.h>
-#include <asm/io.h>
-#include <asm/arch/regs-gpio.h>
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/audio.h>
+#include <mach/hardware.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <plat/audio.h>
 #include <asm/dma.h>
-#include <asm/arch/dma.h>
+#include <mach/dma.h>
 
-#include <asm/plat-s3c24xx/regs-iis.h>
+#include <plat/regs-iis.h>
 
 #include "s3c24xx-pcm.h"
 #include "s3c24xx-i2s.h"
 
-#define S3C24XX_I2S_DEBUG 0
-#if S3C24XX_I2S_DEBUG
-#define DBG(x...) printk(KERN_DEBUG x)
-#else
-#define DBG(x...)
-#endif
-
 static struct s3c2410_dma_client s3c24xx_dma_client_out = {
        .name = "I2S PCM Stereo out"
 };
@@ -76,6 +66,10 @@ static struct s3c24xx_pcm_dma_params s3c24xx_i2s_pcm_stereo_in = {
 struct s3c24xx_i2s_info {
        void __iomem    *regs;
        struct clk      *iis_clk;
+       u32             iiscon;
+       u32             iismod;
+       u32             iisfcon;
+       u32             iispsr;
 };
 static struct s3c24xx_i2s_info s3c24xx_i2s;
 
@@ -85,13 +79,13 @@ static void s3c24xx_snd_txctrl(int on)
        u32 iiscon;
        u32 iismod;
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
        iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
        iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-       DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 
        if (on) {
                iisfcon |= S3C2410_IISFCON_TXDMA | S3C2410_IISFCON_TXENABLE;
@@ -121,7 +115,7 @@ static void s3c24xx_snd_txctrl(int on)
                writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
        }
 
-       DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 }
 
 static void s3c24xx_snd_rxctrl(int on)
@@ -130,13 +124,13 @@ static void s3c24xx_snd_rxctrl(int on)
        u32 iiscon;
        u32 iismod;
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
        iiscon  = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
        iismod  = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-       DBG("r: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("r: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 
        if (on) {
                iisfcon |= S3C2410_IISFCON_RXDMA | S3C2410_IISFCON_RXENABLE;
@@ -155,10 +149,10 @@ static void s3c24xx_snd_rxctrl(int on)
                 * DMA engine will simply freeze randomly.
                 */
 
-        iisfcon &= ~S3C2410_IISFCON_RXENABLE;
-        iisfcon &= ~S3C2410_IISFCON_RXDMA;
-        iiscon  |= S3C2410_IISCON_RXIDLE;
-        iiscon  &= ~S3C2410_IISCON_RXDMAEN;
+               iisfcon &= ~S3C2410_IISFCON_RXENABLE;
+               iisfcon &= ~S3C2410_IISFCON_RXDMA;
+               iiscon  |= S3C2410_IISCON_RXIDLE;
+               iiscon  &= ~S3C2410_IISCON_RXDMAEN;
                iismod  &= ~S3C2410_IISMOD_RXMODE;
 
                writel(iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
@@ -166,7 +160,7 @@ static void s3c24xx_snd_rxctrl(int on)
                writel(iismod,  s3c24xx_i2s.regs + S3C2410_IISMOD);
        }
 
-       DBG("w: IISCON: %lx IISMOD: %lx IISFCON: %lx\n", iiscon, iismod, iisfcon);
+       pr_debug("w: IISCON: %x IISMOD: %x IISFCON: %x\n", iiscon, iismod, iisfcon);
 }
 
 /*
@@ -176,17 +170,18 @@ static void s3c24xx_snd_rxctrl(int on)
 static int s3c24xx_snd_lrsync(void)
 {
        u32 iiscon;
-       unsigned long timeout = jiffies + msecs_to_jiffies(5);
+       int timeout = 50; /* 5ms */
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        while (1) {
                iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
                if (iiscon & S3C2410_IISCON_LRINDEX)
                        break;
 
-               if (time_after(jiffies, timeout))
+               if (!timeout--)
                        return -ETIMEDOUT;
+               udelay(100);
        }
 
        return 0;
@@ -197,7 +192,7 @@ static int s3c24xx_snd_lrsync(void)
  */
 static inline int s3c24xx_snd_is_clkmaster(void)
 {
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        return (readl(s3c24xx_i2s.regs + S3C2410_IISMOD) & S3C2410_IISMOD_SLAVE) ? 0:1;
 }
@@ -205,21 +200,22 @@ static inline int s3c24xx_snd_is_clkmaster(void)
 /*
  * Set S3C24xx I2S DAI format
  */
-static int s3c24xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c24xx_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
                unsigned int fmt)
 {
        u32 iismod;
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params r: IISMOD: %lx \n", iismod);
+       pr_debug("hw_params r: IISMOD: %x \n", iismod);
 
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
        case SND_SOC_DAIFMT_CBM_CFM:
                iismod |= S3C2410_IISMOD_SLAVE;
                break;
        case SND_SOC_DAIFMT_CBS_CFS:
+               iismod &= ~S3C2410_IISMOD_SLAVE;
                break;
        default:
                return -EINVAL;
@@ -230,23 +226,25 @@ static int s3c24xx_i2s_set_fmt(struct snd_soc_cpu_dai *cpu_dai,
                iismod |= S3C2410_IISMOD_MSB;
                break;
        case SND_SOC_DAIFMT_I2S:
+               iismod &= ~S3C2410_IISMOD_MSB;
                break;
        default:
                return -EINVAL;
        }
 
        writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params w: IISMOD: %lx \n", iismod);
+       pr_debug("hw_params w: IISMOD: %x \n", iismod);
        return 0;
 }
 
 static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
-                               struct snd_pcm_hw_params *params)
+                                struct snd_pcm_hw_params *params,
+                                struct snd_soc_dai *dai)
 {
        struct snd_soc_pcm_runtime *rtd = substream->private_data;
        u32 iismod;
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                rtd->dai->cpu_dai->dma_data = &s3c24xx_i2s_pcm_stereo_out;
@@ -255,26 +253,34 @@ static int s3c24xx_i2s_hw_params(struct snd_pcm_substream *substream,
 
        /* Working copies of register */
        iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params r: IISMOD: %lx\n", iismod);
+       pr_debug("hw_params r: IISMOD: %x\n", iismod);
 
        switch (params_format(params)) {
        case SNDRV_PCM_FORMAT_S8:
+               iismod &= ~S3C2410_IISMOD_16BIT;
+               ((struct s3c24xx_pcm_dma_params *)
+                 rtd->dai->cpu_dai->dma_data)->dma_size = 1;
                break;
        case SNDRV_PCM_FORMAT_S16_LE:
                iismod |= S3C2410_IISMOD_16BIT;
+               ((struct s3c24xx_pcm_dma_params *)
+                 rtd->dai->cpu_dai->dma_data)->dma_size = 2;
                break;
+       default:
+               return -EINVAL;
        }
 
        writel(iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
-       DBG("hw_params w: IISMOD: %lx\n", iismod);
+       pr_debug("hw_params w: IISMOD: %x\n", iismod);
        return 0;
 }
 
-static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd)
+static int s3c24xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
+                              struct snd_soc_dai *dai)
 {
        int ret = 0;
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_START:
@@ -311,12 +317,12 @@ exit_err:
 /*
  * Set S3C24xx Clock source
  */
-static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c24xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai,
        int clk_id, unsigned int freq, int dir)
 {
        u32 iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        iismod &= ~S3C2440_IISMOD_MPLL;
 
@@ -337,12 +343,12 @@ static int s3c24xx_i2s_set_sysclk(struct snd_soc_cpu_dai *cpu_dai,
 /*
  * Set S3C24xx Clock dividers
  */
-static int s3c24xx_i2s_set_clkdiv(struct snd_soc_cpu_dai *cpu_dai,
+static int s3c24xx_i2s_set_clkdiv(struct snd_soc_dai *cpu_dai,
        int div_id, int div)
 {
        u32 reg;
 
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        switch (div_id) {
        case S3C24XX_DIV_BCLK:
@@ -375,17 +381,18 @@ u32 s3c24xx_i2s_get_clockrate(void)
 }
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_get_clockrate);
 
-static int s3c24xx_i2s_probe(struct platform_device *pdev)
+static int s3c24xx_i2s_probe(struct platform_device *pdev,
+                            struct snd_soc_dai *dai)
 {
-       DBG("Entered %s\n", __FUNCTION__);
+       pr_debug("Entered %s\n", __func__);
 
        s3c24xx_i2s.regs = ioremap(S3C2410_PA_IIS, 0x100);
        if (s3c24xx_i2s.regs == NULL)
                return -ENXIO;
 
-       s3c24xx_i2s.iis_clk=clk_get(&pdev->dev, "iis");
+       s3c24xx_i2s.iis_clk = clk_get(&pdev->dev, "iis");
        if (s3c24xx_i2s.iis_clk == NULL) {
-               DBG("failed to get iis_clock\n");
+               pr_err("failed to get iis_clock\n");
                iounmap(s3c24xx_i2s.regs);
                return -ENODEV;
        }
@@ -406,16 +413,58 @@ static int s3c24xx_i2s_probe(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int s3c24xx_i2s_suspend(struct snd_soc_dai *cpu_dai)
+{
+       pr_debug("Entered %s\n", __func__);
+
+       s3c24xx_i2s.iiscon = readl(s3c24xx_i2s.regs + S3C2410_IISCON);
+       s3c24xx_i2s.iismod = readl(s3c24xx_i2s.regs + S3C2410_IISMOD);
+       s3c24xx_i2s.iisfcon = readl(s3c24xx_i2s.regs + S3C2410_IISFCON);
+       s3c24xx_i2s.iispsr = readl(s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+       clk_disable(s3c24xx_i2s.iis_clk);
+
+       return 0;
+}
+
+static int s3c24xx_i2s_resume(struct snd_soc_dai *cpu_dai)
+{
+       pr_debug("Entered %s\n", __func__);
+       clk_enable(s3c24xx_i2s.iis_clk);
+
+       writel(s3c24xx_i2s.iiscon, s3c24xx_i2s.regs + S3C2410_IISCON);
+       writel(s3c24xx_i2s.iismod, s3c24xx_i2s.regs + S3C2410_IISMOD);
+       writel(s3c24xx_i2s.iisfcon, s3c24xx_i2s.regs + S3C2410_IISFCON);
+       writel(s3c24xx_i2s.iispsr, s3c24xx_i2s.regs + S3C2410_IISPSR);
+
+       return 0;
+}
+#else
+#define s3c24xx_i2s_suspend NULL
+#define s3c24xx_i2s_resume NULL
+#endif
+
+
 #define S3C24XX_I2S_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)
 
-struct snd_soc_cpu_dai s3c24xx_i2s_dai = {
+static struct snd_soc_dai_ops s3c24xx_i2s_dai_ops = {
+       .trigger        = s3c24xx_i2s_trigger,
+       .hw_params      = s3c24xx_i2s_hw_params,
+       .set_fmt        = s3c24xx_i2s_set_fmt,
+       .set_clkdiv     = s3c24xx_i2s_set_clkdiv,
+       .set_sysclk     = s3c24xx_i2s_set_sysclk,
+};
+
+struct snd_soc_dai s3c24xx_i2s_dai = {
        .name = "s3c24xx-i2s",
        .id = 0,
-       .type = SND_SOC_DAI_I2S,
        .probe = s3c24xx_i2s_probe,
+       .suspend = s3c24xx_i2s_suspend,
+       .resume = s3c24xx_i2s_resume,
        .playback = {
                .channels_min = 2,
                .channels_max = 2,
@@ -426,17 +475,22 @@ struct snd_soc_cpu_dai s3c24xx_i2s_dai = {
                .channels_max = 2,
                .rates = S3C24XX_I2S_RATES,
                .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,},
-       .ops = {
-               .trigger = s3c24xx_i2s_trigger,
-               .hw_params = s3c24xx_i2s_hw_params,},
-       .dai_ops = {
-               .set_fmt = s3c24xx_i2s_set_fmt,
-               .set_clkdiv = s3c24xx_i2s_set_clkdiv,
-               .set_sysclk = s3c24xx_i2s_set_sysclk,
-       },
+       .ops = &s3c24xx_i2s_dai_ops,
 };
 EXPORT_SYMBOL_GPL(s3c24xx_i2s_dai);
 
+static int __init s3c24xx_i2s_init(void)
+{
+       return snd_soc_register_dai(&s3c24xx_i2s_dai);
+}
+module_init(s3c24xx_i2s_init);
+
+static void __exit s3c24xx_i2s_exit(void)
+{
+       snd_soc_unregister_dai(&s3c24xx_i2s_dai);
+}
+module_exit(s3c24xx_i2s_exit);
+
 /* Module information */
 MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
 MODULE_DESCRIPTION("s3c24xx I2S SoC Interface");