Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * ALSA SoC SPDIF Out Audio Layer for spear processors
0003  *
0004  * Copyright (C) 2012 ST Microelectronics
0005  * Vipin Kumar <vipin.kumar@st.com>
0006  *
0007  * This file is licensed under the terms of the GNU General Public
0008  * License version 2. This program is licensed "as is" without any
0009  * warranty of any kind, whether express or implied.
0010  */
0011 
0012 #include <linux/clk.h>
0013 #include <linux/delay.h>
0014 #include <linux/device.h>
0015 #include <linux/kernel.h>
0016 #include <linux/init.h>
0017 #include <linux/io.h>
0018 #include <linux/ioport.h>
0019 #include <linux/module.h>
0020 #include <linux/platform_device.h>
0021 #include <sound/dmaengine_pcm.h>
0022 #include <sound/soc.h>
0023 #include <sound/spear_dma.h>
0024 #include <sound/spear_spdif.h>
0025 #include "spdif_out_regs.h"
0026 #include "spear_pcm.h"
0027 
0028 struct spdif_out_params {
0029     u32 rate;
0030     u32 core_freq;
0031     u32 mute;
0032 };
0033 
0034 struct spdif_out_dev {
0035     struct clk *clk;
0036     struct spear_dma_data dma_params;
0037     struct spdif_out_params saved_params;
0038     u32 running;
0039     void __iomem *io_base;
0040     struct snd_dmaengine_dai_dma_data dma_params_tx;
0041     struct snd_dmaengine_pcm_config config;
0042 };
0043 
0044 static void spdif_out_configure(struct spdif_out_dev *host)
0045 {
0046     writel(SPDIF_OUT_RESET, host->io_base + SPDIF_OUT_SOFT_RST);
0047     mdelay(1);
0048     writel(readl(host->io_base + SPDIF_OUT_SOFT_RST) & ~SPDIF_OUT_RESET,
0049             host->io_base + SPDIF_OUT_SOFT_RST);
0050 
0051     writel(SPDIF_OUT_FDMA_TRIG_16 | SPDIF_OUT_MEMFMT_16_16 |
0052             SPDIF_OUT_VALID_HW | SPDIF_OUT_USER_HW |
0053             SPDIF_OUT_CHNLSTA_HW | SPDIF_OUT_PARITY_HW,
0054             host->io_base + SPDIF_OUT_CFG);
0055 
0056     writel(0x7F, host->io_base + SPDIF_OUT_INT_STA_CLR);
0057     writel(0x7F, host->io_base + SPDIF_OUT_INT_EN_CLR);
0058 }
0059 
0060 static int spdif_out_startup(struct snd_pcm_substream *substream,
0061         struct snd_soc_dai *cpu_dai)
0062 {
0063     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
0064     int ret;
0065 
0066     if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0067         return -EINVAL;
0068 
0069     ret = clk_enable(host->clk);
0070     if (ret)
0071         return ret;
0072 
0073     host->running = true;
0074     spdif_out_configure(host);
0075 
0076     return 0;
0077 }
0078 
0079 static void spdif_out_shutdown(struct snd_pcm_substream *substream,
0080         struct snd_soc_dai *dai)
0081 {
0082     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
0083 
0084     if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0085         return;
0086 
0087     clk_disable(host->clk);
0088     host->running = false;
0089 }
0090 
0091 static void spdif_out_clock(struct spdif_out_dev *host, u32 core_freq,
0092         u32 rate)
0093 {
0094     u32 divider, ctrl;
0095 
0096     clk_set_rate(host->clk, core_freq);
0097     divider = DIV_ROUND_CLOSEST(clk_get_rate(host->clk), (rate * 128));
0098 
0099     ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
0100     ctrl &= ~SPDIF_DIVIDER_MASK;
0101     ctrl |= (divider << SPDIF_DIVIDER_SHIFT) & SPDIF_DIVIDER_MASK;
0102     writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
0103 }
0104 
0105 static int spdif_out_hw_params(struct snd_pcm_substream *substream,
0106         struct snd_pcm_hw_params *params,
0107         struct snd_soc_dai *dai)
0108 {
0109     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
0110     u32 rate, core_freq;
0111 
0112     if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0113         return -EINVAL;
0114 
0115     rate = params_rate(params);
0116 
0117     switch (rate) {
0118     case 8000:
0119     case 16000:
0120     case 32000:
0121     case 64000:
0122         /*
0123          * The clock is multiplied by 10 to bring it to feasible range
0124          * of frequencies for sscg
0125          */
0126         core_freq = 64000 * 128 * 10;   /* 81.92 MHz */
0127         break;
0128     case 5512:
0129     case 11025:
0130     case 22050:
0131     case 44100:
0132     case 88200:
0133     case 176400:
0134         core_freq = 176400 * 128;   /* 22.5792 MHz */
0135         break;
0136     case 48000:
0137     case 96000:
0138     case 192000:
0139     default:
0140         core_freq = 192000 * 128;   /* 24.576 MHz */
0141         break;
0142     }
0143 
0144     spdif_out_clock(host, core_freq, rate);
0145     host->saved_params.core_freq = core_freq;
0146     host->saved_params.rate = rate;
0147 
0148     return 0;
0149 }
0150 
0151 static int spdif_out_trigger(struct snd_pcm_substream *substream, int cmd,
0152         struct snd_soc_dai *dai)
0153 {
0154     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
0155     u32 ctrl;
0156     int ret = 0;
0157 
0158     if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
0159         return -EINVAL;
0160 
0161     switch (cmd) {
0162     case SNDRV_PCM_TRIGGER_START:
0163     case SNDRV_PCM_TRIGGER_RESUME:
0164     case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
0165             ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
0166             ctrl &= ~SPDIF_OPMODE_MASK;
0167             if (!host->saved_params.mute)
0168                 ctrl |= SPDIF_OPMODE_AUD_DATA |
0169                     SPDIF_STATE_NORMAL;
0170             else
0171                 ctrl |= SPDIF_OPMODE_MUTE_PCM;
0172             writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
0173         break;
0174 
0175     case SNDRV_PCM_TRIGGER_STOP:
0176     case SNDRV_PCM_TRIGGER_SUSPEND:
0177     case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
0178         ctrl = readl(host->io_base + SPDIF_OUT_CTRL);
0179         ctrl &= ~SPDIF_OPMODE_MASK;
0180         ctrl |= SPDIF_OPMODE_OFF;
0181         writel(ctrl, host->io_base + SPDIF_OUT_CTRL);
0182         break;
0183 
0184     default:
0185         ret = -EINVAL;
0186         break;
0187     }
0188     return ret;
0189 }
0190 
0191 static int spdif_mute(struct snd_soc_dai *dai, int mute, int direction)
0192 {
0193     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
0194     u32 val;
0195 
0196     host->saved_params.mute = mute;
0197     val = readl(host->io_base + SPDIF_OUT_CTRL);
0198     val &= ~SPDIF_OPMODE_MASK;
0199 
0200     if (mute)
0201         val |= SPDIF_OPMODE_MUTE_PCM;
0202     else {
0203         if (host->running)
0204             val |= SPDIF_OPMODE_AUD_DATA | SPDIF_STATE_NORMAL;
0205         else
0206             val |= SPDIF_OPMODE_OFF;
0207     }
0208 
0209     writel(val, host->io_base + SPDIF_OUT_CTRL);
0210     return 0;
0211 }
0212 
0213 static int spdif_mute_get(struct snd_kcontrol *kcontrol,
0214         struct snd_ctl_elem_value *ucontrol)
0215 {
0216     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0217     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
0218 
0219     ucontrol->value.integer.value[0] = host->saved_params.mute;
0220     return 0;
0221 }
0222 
0223 static int spdif_mute_put(struct snd_kcontrol *kcontrol,
0224         struct snd_ctl_elem_value *ucontrol)
0225 {
0226     struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
0227     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai);
0228 
0229     if (host->saved_params.mute == ucontrol->value.integer.value[0])
0230         return 0;
0231 
0232     spdif_mute(cpu_dai, ucontrol->value.integer.value[0],
0233            SNDRV_PCM_STREAM_PLAYBACK);
0234 
0235     return 1;
0236 }
0237 static const struct snd_kcontrol_new spdif_out_controls[] = {
0238     SOC_SINGLE_BOOL_EXT("IEC958 Playback Switch", 0,
0239             spdif_mute_get, spdif_mute_put),
0240 };
0241 
0242 static int spdif_soc_dai_probe(struct snd_soc_dai *dai)
0243 {
0244     struct spdif_out_dev *host = snd_soc_dai_get_drvdata(dai);
0245 
0246     host->dma_params_tx.filter_data = &host->dma_params;
0247     dai->playback_dma_data = &host->dma_params_tx;
0248 
0249     return snd_soc_add_dai_controls(dai, spdif_out_controls,
0250                 ARRAY_SIZE(spdif_out_controls));
0251 }
0252 
0253 static const struct snd_soc_dai_ops spdif_out_dai_ops = {
0254     .mute_stream    = spdif_mute,
0255     .startup    = spdif_out_startup,
0256     .shutdown   = spdif_out_shutdown,
0257     .trigger    = spdif_out_trigger,
0258     .hw_params  = spdif_out_hw_params,
0259     .no_capture_mute = 1,
0260 };
0261 
0262 static struct snd_soc_dai_driver spdif_out_dai = {
0263     .playback = {
0264         .channels_min = 2,
0265         .channels_max = 2,
0266         .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
0267                  SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
0268                  SNDRV_PCM_RATE_192000),
0269         .formats = SNDRV_PCM_FMTBIT_S16_LE,
0270     },
0271     .probe = spdif_soc_dai_probe,
0272     .ops = &spdif_out_dai_ops,
0273 };
0274 
0275 static const struct snd_soc_component_driver spdif_out_component = {
0276     .name           = "spdif-out",
0277     .legacy_dai_naming  = 1,
0278 };
0279 
0280 static int spdif_out_probe(struct platform_device *pdev)
0281 {
0282     struct spdif_out_dev *host;
0283     struct spear_spdif_platform_data *pdata;
0284     struct resource *res;
0285     int ret;
0286 
0287     host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
0288     if (!host)
0289         return -ENOMEM;
0290 
0291     host->io_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
0292     if (IS_ERR(host->io_base))
0293         return PTR_ERR(host->io_base);
0294 
0295     host->clk = devm_clk_get(&pdev->dev, NULL);
0296     if (IS_ERR(host->clk))
0297         return PTR_ERR(host->clk);
0298 
0299     pdata = dev_get_platdata(&pdev->dev);
0300 
0301     host->dma_params.data = pdata->dma_params;
0302     host->dma_params.addr = res->start + SPDIF_OUT_FIFO_DATA;
0303     host->dma_params.max_burst = 16;
0304     host->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
0305 
0306     dev_set_drvdata(&pdev->dev, host);
0307 
0308     ret = devm_snd_soc_register_component(&pdev->dev, &spdif_out_component,
0309                           &spdif_out_dai, 1);
0310     if (ret)
0311         return ret;
0312 
0313     return devm_spear_pcm_platform_register(&pdev->dev, &host->config,
0314                         pdata->filter);
0315 }
0316 
0317 #ifdef CONFIG_PM
0318 static int spdif_out_suspend(struct device *dev)
0319 {
0320     struct platform_device *pdev = to_platform_device(dev);
0321     struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
0322 
0323     if (host->running)
0324         clk_disable(host->clk);
0325 
0326     return 0;
0327 }
0328 
0329 static int spdif_out_resume(struct device *dev)
0330 {
0331     struct platform_device *pdev = to_platform_device(dev);
0332     struct spdif_out_dev *host = dev_get_drvdata(&pdev->dev);
0333 
0334     if (host->running) {
0335         clk_enable(host->clk);
0336         spdif_out_configure(host);
0337         spdif_out_clock(host, host->saved_params.core_freq,
0338                 host->saved_params.rate);
0339     }
0340     return 0;
0341 }
0342 
0343 static SIMPLE_DEV_PM_OPS(spdif_out_dev_pm_ops, spdif_out_suspend, \
0344         spdif_out_resume);
0345 
0346 #define SPDIF_OUT_DEV_PM_OPS (&spdif_out_dev_pm_ops)
0347 
0348 #else
0349 #define SPDIF_OUT_DEV_PM_OPS NULL
0350 
0351 #endif
0352 
0353 static struct platform_driver spdif_out_driver = {
0354     .probe      = spdif_out_probe,
0355     .driver     = {
0356         .name   = "spdif-out",
0357         .pm = SPDIF_OUT_DEV_PM_OPS,
0358     },
0359 };
0360 
0361 module_platform_driver(spdif_out_driver);
0362 
0363 MODULE_AUTHOR("Vipin Kumar <vipin.kumar@st.com>");
0364 MODULE_DESCRIPTION("SPEAr SPDIF OUT SoC Interface");
0365 MODULE_LICENSE("GPL");
0366 MODULE_ALIAS("platform:spdif_out");