/* * pxa-ssp.c -- ALSA Soc Audio Layer * * Copyright 2005,2008 Wolfson Microelectronics PLC. * Author: Liam Girdwood * Mark Brown <broonie@opensource.wolfsonmicro.com> * * 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. * * TODO: * o Test network mode for > 16bit sample size */ #include <linux/init.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> #include <linux/pxa2xx_ssp.h> #include <linux/of.h> #include <linux/dmaengine.h> #include <asm/irq.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/initval.h> #include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/pxa2xx-lib.h> #include <sound/dmaengine_pcm.h> #include "../../arm/pxa2xx-pcm.h" #include "pxa-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 }; static void dump_registers(struct ssp_device *ssp) { dev_dbg(&ssp->pdev->dev, "SSCR0 0x%08x SSCR1 0x%08x SSTO 0x%08x\n", pxa_ssp_read_reg(ssp, SSCR0), pxa_ssp_read_reg(ssp, SSCR1), pxa_ssp_read_reg(ssp, SSTO)); dev_dbg(&ssp->pdev->dev, "SSPSP 0x%08x SSSR 0x%08x SSACD 0x%08x\n", pxa_ssp_read_reg(ssp, SSPSP), pxa_ssp_read_reg(ssp, SSSR), pxa_ssp_read_reg(ssp, SSACD)); } static void pxa_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 pxa_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 void pxa_ssp_set_dma_params(struct ssp_device *ssp, int width4, int out, struct snd_dmaengine_dai_dma_data *dma) { dma->addr_width = width4 ? DMA_SLAVE_BUSWIDTH_4_BYTES : DMA_SLAVE_BUSWIDTH_2_BYTES; dma->maxburst = 16; dma->addr = ssp->phys_base + SSDR; } static int pxa_ssp_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *ssp = priv->ssp; struct snd_dmaengine_dai_dma_data *dma; int ret = 0; if (!cpu_dai->active) { clk_prepare_enable(ssp->clk); pxa_ssp_disable(ssp); } dma = kzalloc(sizeof(struct snd_dmaengine_dai_dma_data), GFP_KERNEL); if (!dma) return -ENOMEM; dma->filter_data = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &ssp->drcmr_tx : &ssp->drcmr_rx; snd_soc_dai_set_dma_data(cpu_dai, substream, dma); return ret; } static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *ssp = priv->ssp; if (!cpu_dai->active) { pxa_ssp_disable(ssp); clk_disable_unprepare(ssp->clk); } kfree(snd_soc_dai_get_dma_data(cpu_dai, substream)); snd_soc_dai_set_dma_data(cpu_dai, substream, NULL); } #ifdef CONFIG_PM static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *ssp = priv->ssp; if (!cpu_dai->active) clk_prepare_enable(ssp->clk); 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); pxa_ssp_disable(ssp); clk_disable_unprepare(ssp->clk); return 0; } static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *ssp = priv->ssp; uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE; clk_prepare_enable(ssp->clk); __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); if (cpu_dai->active) pxa_ssp_enable(ssp); else clk_disable_unprepare(ssp->clk); return 0; } #else #define pxa_ssp_suspend NULL #define pxa_ssp_resume NULL #endif /** * ssp_set_clkdiv - set SSP clock divider * @div: serial clock rate divider */ static void pxa_ssp_set_scr(struct ssp_device *ssp, u32 div) { u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0); if (ssp->type == PXA25x_SSP) { sscr0 &= ~0x0000ff00; sscr0 |= ((div - 2)/2) << 8; /* 2..512 */ } else { sscr0 &= ~0x000fff00; sscr0 |= (div - 1) << 8; /* 1..4096 */ } pxa_ssp_write_reg(ssp, SSCR0, sscr0); } /** * pxa_ssp_get_clkdiv - get SSP clock divider */ static u32 pxa_ssp_get_scr(struct ssp_device *ssp) { u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0); u32 div; if (ssp->type == PXA25x_SSP) div = ((sscr0 >> 8) & 0xff) * 2 + 2; else div = ((sscr0 >> 8) & 0xfff) + 1; return div; } /* * Set the SSP ports SYSCLK. */ 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 = snd_soc_dai_get_drvdata(cpu_dai); struct ssp_device *ssp = priv->ssp; int val; u32 sscr0 = pxa_ssp_read_reg(ssp, SSCR0) & ~(SSCR0_ECS | SSCR0_NCS | SSCR0_MOD | SSCR0_ACS); dev_dbg(&ssp->pdev->dev, "pxa_ssp_set_dai_sysclk id: %d, clk_id %d, freq %u\n", cpu_dai->id, clk_id, freq); switch (clk_id) { case PXA_SSP_CLK_NET_PLL: sscr0 |= SSCR0_MOD; break; case PXA_SSP_CLK_PLL: /* Internal PLL is fixed */ if (ssp->type == PXA25x_SSP) priv->sysclk = 1843200; else priv->sysclk = 13000000; break; case PXA_SSP_CLK_EXT: priv->sysclk = freq; sscr0 |= SSCR0_ECS; break; case PXA_SSP_CLK_NET: priv->sysclk = freq; sscr0 |= SSCR0_NCS | SSCR0_MOD; break; case PXA_S<style> @media only all and (prefers-color-scheme: dark) { .highlight .hll { background-color: #49483e } .highlight .c { color: #75715e } /* Comment */ .highlight .err { color: #960050; background-color: #1e0010 } /* Error */ .highlight .k { color: #66d9ef } /* Keyword */ .highlight .l { color: #ae81ff } /* Literal */ .highlight .n { color: #f8f8f2 } /* Name */ .highlight .o { color: #f92672 } /* Operator */ .highlight .p { color: #f8f8f2 } /* Punctuation */ .highlight .ch { color: #75715e } /* Comment.Hashbang */ .highlight .cm { color: #75715e } /* Comment.Multiline */ .highlight .cp { color: #75715e } /* Comment.Preproc */ .highlight .cpf { color: #75715e } /* Comment.PreprocFile */ .highlight .c1 { color: #75715e } /* Comment.Single */ .highlight .cs { color: #75715e } /* Comment.Special */ .highlight .gd { color: #f92672 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gi { color: #a6e22e } /* Generic.Inserted */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #75715e } /* Generic.Subheading */ .highlight .kc { color: #66d9ef } /* Keyword.Constant */ .highlight .kd { color: #66d9ef } /* Keyword.Declaration */ .highlight .kn { color: #f92672 } /* Keyword.Namespace */ .highlight .kp { color: #66d9ef } /* Keyword.Pseudo */ .highlight .kr { color: #66d9ef } /* Keyword.Reserved */ .highlight .kt { color: #66d9ef } /* Keyword.Type */ .highlight .ld { color: #e6db74 } /* Literal.Date */ .highlight .m { color: #ae81ff } /* Literal.Number */ .highlight .s { color: #e6db74 } /* Literal.String */ .highlight .na { color: #a6e22e } /* Name.Attribute */ .highlight .nb { color: #f8f8f2 } /* Name.Builtin */ .highlight .nc { color: #a6e22e } /* Name.Class */ .highlight .no { color: #66d9ef } /* Name.Constant */ .highlight .nd { color: #a6e22e } /* Name.Decorator */ .highlight .ni { color: #f8f8f2 } /* Name.Entity */ .highlight .ne { color: #a6e22e } /* Name.Exception */ .highlight .nf { color: #a6e22e } /* Name.Function */ .highlight .nl { color: #f8f8f2 } /* Name.Label */ .highlight .nn { color: #f8f8f2 } /* Name.Namespace */ .highlight .nx { color: #a6e22e } /* Name.Other */ .highlight .py { color: #f8f8f2 } /* Name.Property */ .highlight .nt { color: #f92672 } /* Name.Tag */ .highlight .nv { color: #f8f8f2 } /* Name.Variable */ .highlight .ow { color: #f92672 } /* Operator.Word */ .highlight .w { color: #f8f8f2 } /* Text.Whitespace */ .highlight .mb { color: #ae81ff } /* Literal.Number.Bin */ .highlight .mf { color: #ae81ff } /* Literal.Number.Float */ .highlight .mh { color: #ae81ff } /* Literal.Number.Hex */ .highlight .mi { color: #ae81ff } /* Literal.Number.Integer */ .highlight .mo { color: #ae81ff } /* Literal.Number.Oct */ .highlight .sa { color: #e6db74 } /* Literal.String.Affix */ .highlight .sb { color: #e6db74 } /* Literal.String.Backtick */ .highlight .sc { color: #e6db74 } /* Literal.String.Char */ .highlight .dl { color: #e6db74 } /* Literal.String.Delimiter */ .highlight .sd { color: #e6db74 } /* Literal.String.Doc */ .highlight .s2 { color: #e6db74 } /* Literal.String.Double */ .highlight .se { color: #ae81ff } /* Literal.String.Escape */ .highlight .sh { color: #e6db74 } /* Literal.String.Heredoc */ .highlight .si { color: #e6db74 } /* Literal.String.Interpol */ .highlight .sx { color: #e6db74 } /* Literal.String.Other */ .highlight .sr { color: #e6db74 } /* Literal.String.Regex */ .highlight .s1 { color: #e6db74 } /* Literal.String.Single */ .highlight .ss { color: #e6db74 } /* Literal.String.Symbol */ .highlight .bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #a6e22e } /* Name.Function.Magic */ .highlight .vc { color: #f8f8f2 } /* Name.Variable.Class */ .highlight .vg { color: #f8f8f2 } /* Name.Variable.Global */ .highlight .vi { color: #f8f8f2 } /* Name.Variable.Instance */ .highlight .vm { color: #f8f8f2 } /* Name.Variable.Magic */ .highlight .il { color: #ae81ff } /* Literal.Number.Integer.Long */ } @media (prefers-color-scheme: light) { .highlight .hll { background-color: #ffffcc } .highlight .c { color: #888888 } /* Comment */ .highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ .highlight .k { color: #008800; font-weight: bold } /* Keyword */ .highlight .ch { color: #888888 } /* Comment.Hashbang */ .highlight .cm { color: #888888 } /* Comment.Multiline */ .highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */ .highlight .cpf { color: #888888 } /* Comment.PreprocFile */ .highlight .c1 { color: #888888 } /* Comment.Single */ .highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */ .highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #aa0000 } /* Generic.Error */ .highlight .gh { color: #333333 } /* Generic.Heading */ .highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ .highlight .go { color: #888888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ } </style><div class="highlight"><pre><span></span><span class="c1"># Copyright (c) 2016-2017 Intel Corporation</span> <span class="c1">#</span> <span class="c1"># Licensed under the Apache License, Version 2.0 (the "License");</span> <span class="c1"># you may not use this file except in compliance with the License.</span> <span class="c1"># You may obtain a copy of the License at</span> <span class="c1">#</span> <span class="c1"># http://www.apache.org/licenses/LICENSE-2.0</span> <span class="c1">#</span> <span class="c1"># Unless required by applicable law or agreed to in writing, software</span> <span class="c1"># distributed under the License is distributed on an "AS IS" BASIS,</span> <span class="c1"># WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.</span> <span class="c1"># See the License for the specific language governing permissions and</span> <span class="c1"># limitations under the License.</span> <span class="k">[PIPELINE0]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">MASTER</span> <span class="na">core</span> <span class="o">=</span> <span class="s">0</span> <span class="k">[PIPELINE1]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">ARPICMP</span> <span class="na">core</span> <span class="o">=</span> <span class="s">1</span> <span class="na">pktq_in</span> <span class="o">=</span> <span class="s">SWQ4</span> <span class="na">pktq_out</span> <span class="o">=</span> <span class="s">TXQ0.0 TXQ1.0 TXQ2.0 TXQ3.0</span> <span class="na">pktq_in_prv</span> <span class="o">=</span> <span class="s">RXQ0.0</span> <span class="na">prv_to_pub_map</span> <span class="o">=</span> <span class="s">(0,1)</span> <span class="k">[PIPELINE2]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">TXRX</span> <span class="na">core</span> <span class="o">=</span> <span class="s">2</span> <span class="na">pipeline_txrx_type</span> <span class="o">=</span> <span class="s">RXRX</span> <span class="na">dest_if_offset</span> <span class="o">=</span> <span class="s">176</span> <span class="na">pktq_in</span> <span class="o">=</span> <span class="s">RXQ0.0 RXQ1.0 RXQ2.0 RXQ3.0</span> <span class="na">pktq_out</span> <span class="o">=</span> <span class="s">SWQ0 SWQ1 SWQ2 SWQ3 SWQ4</span> <span class="k">[PIPELINE3]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">LOADB</span> <span class="na">core</span> <span class="o">=</span> <span class="s">3</span> <span class="na">pktq_in</span> <span class="o">=</span> <span class="s">SWQ0 SWQ1 SWQ2 SWQ3</span> <span class="na">pktq_out</span> <span class="o">=</span> <span class="s">SWQ4 SWQ5 SWQ6 SWQ7 SWQ8 SWQ9 SWQ10 SWQ11</span> <span class="na">outport_offset</span> <span class="o">=</span> <span class="s">136</span> <span class="na">n_vnf_threads</span> <span class="o">=</span> <span class="s">2</span> <span class="na">n_lb_tuples</span> <span class="o">=</span> <span class="s">5</span> <span class="na">loadb_debug</span> <span class="o">=</span> <span class="s">0</span> <span class="na">lib_arp_debug</span> <span class="o">=</span> <span class="s">0</span> <span class="k">[PIPELINE4]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">VFW</span> <span class="na">core</span> <span class="o">=</span> <span class="s">4</span> <span class="na">pktq_in</span> <span class="o">=</span> <span class="s">SWQ2 SWQ3</span> <span class="na">pktq_out</span> <span class="o">=</span> <span class="s">SWQ4 SWQ5</span> <span class="na">n_rules</span> <span class="o">=</span> <span class="s">10</span> <span class="na">prv_que_handler</span> <span class="o">=</span> <span class="s">(0)</span> <span class="na">n_flows</span> <span class="o">=</span> <span class="s">2000000</span> <span class="na">traffic_type</span> <span class="o">=</span> <span class="s">4</span> <span class="na">pkt_type</span> <span class="o">=</span> <span class="s">ipv4</span> <span class="na">tcp_be_liberal</span> <span class="o">=</span> <span class="s">0</span> <span class="k">[PIPELINE5]</span> <span class="na">type</span> <span class="o">=</span> <span class="s">TXRX</span> <span class="na">core</span> <span class="o">=</span> <span class="s">5</span> <span class="na">pipeline_txrx_type</span> <span class="o">=</span> <span class="s">TXTX</span> <span class="na">dest_if_offset</span> <span class="o">=</span> <span class="s">176</span> <span class="na">pktq_in</span> <span class="o">=</span> <span class="s">SWQ8 SWQ9 SWQ10 SWQ11 SWQ12 SWQ13</span> <span class="na">pktq_out</span> <span class="o">=</span> <span class="s">TXQ0.0 TXQ1.0 TXQ0.1 TXQ1.1 TXQ0.2 TXQ1.2</span> </pre></div> </code></pre></td></tr></table> </div> <!-- class=content --> <div id="lfcollabprojects-footer"> <div class="gray-diagonal"> <div class="footer-inner"> <p> © 2015 <a href="https://opnfv.org/">Open Platform for NFV Project, Inc</a>., a Linux Foundation Collaborative Project. All Rights Reserved. </p> <p> Open Platform for NFV and OPNFV are trademarks of the Open Platform for NFV Project, Inc. </p> <p> Linux Foundation is a registered trademark of The Linux Foundation. Linux is a registered