cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pxa2xx-i2s.c (11676B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * pxa2xx-i2s.c  --  ALSA Soc Audio Layer
      4 *
      5 * Copyright 2005 Wolfson Microelectronics PLC.
      6 * Author: Liam Girdwood
      7 *         lrg@slimlogic.co.uk
      8 */
      9
     10#include <linux/init.h>
     11#include <linux/module.h>
     12#include <linux/device.h>
     13#include <linux/delay.h>
     14#include <linux/clk.h>
     15#include <linux/platform_device.h>
     16#include <linux/io.h>
     17#include <sound/core.h>
     18#include <sound/pcm.h>
     19#include <sound/initval.h>
     20#include <sound/soc.h>
     21#include <sound/pxa2xx-lib.h>
     22#include <sound/dmaengine_pcm.h>
     23
     24#include <linux/platform_data/asoc-pxa.h>
     25
     26#include "pxa2xx-i2s.h"
     27
     28/*
     29 * I2S Controller Register and Bit Definitions
     30 */
     31#define SACR0		(0x0000)	/* Global Control Register */
     32#define SACR1		(0x0004)	/* Serial Audio I 2 S/MSB-Justified Control Register */
     33#define SASR0		(0x000C)	/* Serial Audio I 2 S/MSB-Justified Interface and FIFO Status Register */
     34#define SAIMR		(0x0014)	/* Serial Audio Interrupt Mask Register */
     35#define SAICR		(0x0018)	/* Serial Audio Interrupt Clear Register */
     36#define SADIV		(0x0060)	/* Audio Clock Divider Register. */
     37#define SADR		(0x0080)	/* Serial Audio Data Register (TX and RX FIFO access Register). */
     38
     39#define SACR0_RFTH(x)	((x) << 12)	/* Rx FIFO Interrupt or DMA Trigger Threshold */
     40#define SACR0_TFTH(x)	((x) << 8)	/* Tx FIFO Interrupt or DMA Trigger Threshold */
     41#define SACR0_STRF	(1 << 5)	/* FIFO Select for EFWR Special Function */
     42#define SACR0_EFWR	(1 << 4)	/* Enable EFWR Function  */
     43#define SACR0_RST	(1 << 3)	/* FIFO, i2s Register Reset */
     44#define SACR0_BCKD	(1 << 2)	/* Bit Clock Direction */
     45#define SACR0_ENB	(1 << 0)	/* Enable I2S Link */
     46#define SACR1_ENLBF	(1 << 5)	/* Enable Loopback */
     47#define SACR1_DRPL	(1 << 4)	/* Disable Replaying Function */
     48#define SACR1_DREC	(1 << 3)	/* Disable Recording Function */
     49#define SACR1_AMSL	(1 << 0)	/* Specify Alternate Mode */
     50
     51#define SASR0_I2SOFF	(1 << 7)	/* Controller Status */
     52#define SASR0_ROR	(1 << 6)	/* Rx FIFO Overrun */
     53#define SASR0_TUR	(1 << 5)	/* Tx FIFO Underrun */
     54#define SASR0_RFS	(1 << 4)	/* Rx FIFO Service Request */
     55#define SASR0_TFS	(1 << 3)	/* Tx FIFO Service Request */
     56#define SASR0_BSY	(1 << 2)	/* I2S Busy */
     57#define SASR0_RNE	(1 << 1)	/* Rx FIFO Not Empty */
     58#define SASR0_TNF	(1 << 0)	/* Tx FIFO Not Empty */
     59
     60#define SAICR_ROR	(1 << 6)	/* Clear Rx FIFO Overrun Interrupt */
     61#define SAICR_TUR	(1 << 5)	/* Clear Tx FIFO Underrun Interrupt */
     62
     63#define SAIMR_ROR	(1 << 6)	/* Enable Rx FIFO Overrun Condition Interrupt */
     64#define SAIMR_TUR	(1 << 5)	/* Enable Tx FIFO Underrun Condition Interrupt */
     65#define SAIMR_RFS	(1 << 4)	/* Enable Rx FIFO Service Interrupt */
     66#define SAIMR_TFS	(1 << 3)	/* Enable Tx FIFO Service Interrupt */
     67
     68struct pxa_i2s_port {
     69	u32 sadiv;
     70	u32 sacr0;
     71	u32 sacr1;
     72	u32 saimr;
     73	int master;
     74	u32 fmt;
     75};
     76static struct pxa_i2s_port pxa_i2s;
     77static struct clk *clk_i2s;
     78static int clk_ena = 0;
     79static void __iomem *i2s_reg_base;
     80
     81static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_out = {
     82	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
     83	.chan_name	= "tx",
     84	.maxburst	= 32,
     85};
     86
     87static struct snd_dmaengine_dai_dma_data pxa2xx_i2s_pcm_stereo_in = {
     88	.addr_width	= DMA_SLAVE_BUSWIDTH_4_BYTES,
     89	.chan_name	= "rx",
     90	.maxburst	= 32,
     91};
     92
     93static int pxa2xx_i2s_startup(struct snd_pcm_substream *substream,
     94			      struct snd_soc_dai *dai)
     95{
     96	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     97	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
     98
     99	if (IS_ERR(clk_i2s))
    100		return PTR_ERR(clk_i2s);
    101
    102	if (!snd_soc_dai_active(cpu_dai))
    103		writel(0, i2s_reg_base + SACR0);
    104
    105	return 0;
    106}
    107
    108/* wait for I2S controller to be ready */
    109static int pxa_i2s_wait(void)
    110{
    111	int i;
    112
    113	/* flush the Rx FIFO */
    114	for (i = 0; i < 16; i++)
    115		readl(i2s_reg_base + SADR);
    116	return 0;
    117}
    118
    119static int pxa2xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
    120		unsigned int fmt)
    121{
    122	/* interface format */
    123	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
    124	case SND_SOC_DAIFMT_I2S:
    125		pxa_i2s.fmt = 0;
    126		break;
    127	case SND_SOC_DAIFMT_LEFT_J:
    128		pxa_i2s.fmt = SACR1_AMSL;
    129		break;
    130	}
    131
    132	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
    133	case SND_SOC_DAIFMT_CBS_CFS:
    134		pxa_i2s.master = 1;
    135		break;
    136	case SND_SOC_DAIFMT_CBM_CFS:
    137		pxa_i2s.master = 0;
    138		break;
    139	default:
    140		break;
    141	}
    142	return 0;
    143}
    144
    145static int pxa2xx_i2s_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
    146		int clk_id, unsigned int freq, int dir)
    147{
    148	if (clk_id != PXA2XX_I2S_SYSCLK)
    149		return -ENODEV;
    150
    151	return 0;
    152}
    153
    154static int pxa2xx_i2s_hw_params(struct snd_pcm_substream *substream,
    155				struct snd_pcm_hw_params *params,
    156				struct snd_soc_dai *dai)
    157{
    158	struct snd_dmaengine_dai_dma_data *dma_data;
    159
    160	if (WARN_ON(IS_ERR(clk_i2s)))
    161		return -EINVAL;
    162	clk_prepare_enable(clk_i2s);
    163	clk_ena = 1;
    164	pxa_i2s_wait();
    165
    166	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    167		dma_data = &pxa2xx_i2s_pcm_stereo_out;
    168	else
    169		dma_data = &pxa2xx_i2s_pcm_stereo_in;
    170
    171	snd_soc_dai_set_dma_data(dai, substream, dma_data);
    172
    173	/* is port used by another stream */
    174	if (!(SACR0 & SACR0_ENB)) {
    175		writel(0, i2s_reg_base + SACR0);
    176		if (pxa_i2s.master)
    177			writel(readl(i2s_reg_base + SACR0) | (SACR0_BCKD), i2s_reg_base + SACR0);
    178
    179		writel(readl(i2s_reg_base + SACR0) | (SACR0_RFTH(14) | SACR0_TFTH(1)), i2s_reg_base + SACR0);
    180		writel(readl(i2s_reg_base + SACR1) | (pxa_i2s.fmt), i2s_reg_base + SACR1);
    181	}
    182	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    183		writel(readl(i2s_reg_base + SAIMR) | (SAIMR_TFS), i2s_reg_base + SAIMR);
    184	else
    185		writel(readl(i2s_reg_base + SAIMR) | (SAIMR_RFS), i2s_reg_base + SAIMR);
    186
    187	switch (params_rate(params)) {
    188	case 8000:
    189		writel(0x48, i2s_reg_base + SADIV);
    190		break;
    191	case 11025:
    192		writel(0x34, i2s_reg_base + SADIV);
    193		break;
    194	case 16000:
    195		writel(0x24, i2s_reg_base + SADIV);
    196		break;
    197	case 22050:
    198		writel(0x1a, i2s_reg_base + SADIV);
    199		break;
    200	case 44100:
    201		writel(0xd, i2s_reg_base + SADIV);
    202		break;
    203	case 48000:
    204		writel(0xc, i2s_reg_base + SADIV);
    205		break;
    206	case 96000: /* not in manual and possibly slightly inaccurate */
    207		writel(0x6, i2s_reg_base + SADIV);
    208		break;
    209	}
    210
    211	return 0;
    212}
    213
    214static int pxa2xx_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
    215			      struct snd_soc_dai *dai)
    216{
    217	int ret = 0;
    218
    219	switch (cmd) {
    220	case SNDRV_PCM_TRIGGER_START:
    221		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
    222			writel(readl(i2s_reg_base + SACR1) & (~SACR1_DRPL), i2s_reg_base + SACR1);
    223		else
    224			writel(readl(i2s_reg_base + SACR1) & (~SACR1_DREC), i2s_reg_base + SACR1);
    225		writel(readl(i2s_reg_base + SACR0) | (SACR0_ENB), i2s_reg_base + SACR0);
    226		break;
    227	case SNDRV_PCM_TRIGGER_RESUME:
    228	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    229	case SNDRV_PCM_TRIGGER_STOP:
    230	case SNDRV_PCM_TRIGGER_SUSPEND:
    231	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    232		break;
    233	default:
    234		ret = -EINVAL;
    235	}
    236
    237	return ret;
    238}
    239
    240static void pxa2xx_i2s_shutdown(struct snd_pcm_substream *substream,
    241				struct snd_soc_dai *dai)
    242{
    243	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
    244		writel(readl(i2s_reg_base + SACR1) | (SACR1_DRPL), i2s_reg_base + SACR1);
    245		writel(readl(i2s_reg_base + SAIMR) & (~SAIMR_TFS), i2s_reg_base + SAIMR);
    246	} else {
    247		writel(readl(i2s_reg_base + SACR1) | (SACR1_DREC), i2s_reg_base + SACR1);
    248		writel(readl(i2s_reg_base + SAIMR) & (~SAIMR_RFS), i2s_reg_base + SAIMR);
    249	}
    250
    251	if ((readl(i2s_reg_base + SACR1) & (SACR1_DREC | SACR1_DRPL)) == (SACR1_DREC | SACR1_DRPL)) {
    252		writel(readl(i2s_reg_base + SACR0) & (~SACR0_ENB), i2s_reg_base + SACR0);
    253		pxa_i2s_wait();
    254		if (clk_ena) {
    255			clk_disable_unprepare(clk_i2s);
    256			clk_ena = 0;
    257		}
    258	}
    259}
    260
    261#ifdef CONFIG_PM
    262static int pxa2xx_soc_pcm_suspend(struct snd_soc_component *component)
    263{
    264	/* store registers */
    265	pxa_i2s.sacr0 = readl(i2s_reg_base + SACR0);
    266	pxa_i2s.sacr1 = readl(i2s_reg_base + SACR1);
    267	pxa_i2s.saimr = readl(i2s_reg_base + SAIMR);
    268	pxa_i2s.sadiv = readl(i2s_reg_base + SADIV);
    269
    270	/* deactivate link */
    271	writel(readl(i2s_reg_base + SACR0) & (~SACR0_ENB), i2s_reg_base + SACR0);
    272	pxa_i2s_wait();
    273	return 0;
    274}
    275
    276static int pxa2xx_soc_pcm_resume(struct snd_soc_component *component)
    277{
    278	pxa_i2s_wait();
    279
    280	writel(pxa_i2s.sacr0 & ~SACR0_ENB, i2s_reg_base + SACR0);
    281	writel(pxa_i2s.sacr1, i2s_reg_base + SACR1);
    282	writel(pxa_i2s.saimr, i2s_reg_base + SAIMR);
    283	writel(pxa_i2s.sadiv, i2s_reg_base + SADIV);
    284
    285	writel(pxa_i2s.sacr0, i2s_reg_base + SACR0);
    286
    287	return 0;
    288}
    289
    290#else
    291#define pxa2xx_soc_pcm_suspend	NULL
    292#define pxa2xx_soc_pcm_resume	NULL
    293#endif
    294
    295static int pxa2xx_i2s_probe(struct snd_soc_dai *dai)
    296{
    297	clk_i2s = clk_get(dai->dev, "I2SCLK");
    298	if (IS_ERR(clk_i2s))
    299		return PTR_ERR(clk_i2s);
    300
    301	/*
    302	 * PXA Developer's Manual:
    303	 * If SACR0[ENB] is toggled in the middle of a normal operation,
    304	 * the SACR0[RST] bit must also be set and cleared to reset all
    305	 * I2S controller registers.
    306	 */
    307	writel(SACR0_RST, i2s_reg_base + SACR0);
    308	writel(0, i2s_reg_base + SACR0);
    309	/* Make sure RPL and REC are disabled */
    310	writel(SACR1_DRPL | SACR1_DREC, i2s_reg_base + SACR1);
    311	/* Along with FIFO servicing */
    312	writel(readl(i2s_reg_base + SAIMR) & (~(SAIMR_RFS | SAIMR_TFS)), i2s_reg_base + SAIMR);
    313
    314	snd_soc_dai_init_dma_data(dai, &pxa2xx_i2s_pcm_stereo_out,
    315		&pxa2xx_i2s_pcm_stereo_in);
    316
    317	return 0;
    318}
    319
    320static int  pxa2xx_i2s_remove(struct snd_soc_dai *dai)
    321{
    322	clk_put(clk_i2s);
    323	clk_i2s = ERR_PTR(-ENOENT);
    324	return 0;
    325}
    326
    327#define PXA2XX_I2S_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
    328		SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \
    329		SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000)
    330
    331static const struct snd_soc_dai_ops pxa_i2s_dai_ops = {
    332	.startup	= pxa2xx_i2s_startup,
    333	.shutdown	= pxa2xx_i2s_shutdown,
    334	.trigger	= pxa2xx_i2s_trigger,
    335	.hw_params	= pxa2xx_i2s_hw_params,
    336	.set_fmt	= pxa2xx_i2s_set_dai_fmt,
    337	.set_sysclk	= pxa2xx_i2s_set_dai_sysclk,
    338};
    339
    340static struct snd_soc_dai_driver pxa_i2s_dai = {
    341	.probe = pxa2xx_i2s_probe,
    342	.remove = pxa2xx_i2s_remove,
    343	.playback = {
    344		.channels_min = 2,
    345		.channels_max = 2,
    346		.rates = PXA2XX_I2S_RATES,
    347		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
    348	.capture = {
    349		.channels_min = 2,
    350		.channels_max = 2,
    351		.rates = PXA2XX_I2S_RATES,
    352		.formats = SNDRV_PCM_FMTBIT_S16_LE,},
    353	.ops = &pxa_i2s_dai_ops,
    354	.symmetric_rate = 1,
    355};
    356
    357static const struct snd_soc_component_driver pxa_i2s_component = {
    358	.name		= "pxa-i2s",
    359	.pcm_construct	= pxa2xx_soc_pcm_new,
    360	.open		= pxa2xx_soc_pcm_open,
    361	.close		= pxa2xx_soc_pcm_close,
    362	.hw_params	= pxa2xx_soc_pcm_hw_params,
    363	.prepare	= pxa2xx_soc_pcm_prepare,
    364	.trigger	= pxa2xx_soc_pcm_trigger,
    365	.pointer	= pxa2xx_soc_pcm_pointer,
    366	.suspend	= pxa2xx_soc_pcm_suspend,
    367	.resume		= pxa2xx_soc_pcm_resume,
    368};
    369
    370static int pxa2xx_i2s_drv_probe(struct platform_device *pdev)
    371{
    372	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    373
    374	if (!res) {
    375		dev_err(&pdev->dev, "missing MMIO resource\n");
    376		return -ENXIO;
    377	}
    378
    379	i2s_reg_base = devm_ioremap_resource(&pdev->dev, res);
    380	if (IS_ERR(i2s_reg_base)) {
    381		dev_err(&pdev->dev, "ioremap failed\n");
    382		return PTR_ERR(i2s_reg_base);
    383	}
    384
    385	pxa2xx_i2s_pcm_stereo_out.addr = res->start + SADR;
    386	pxa2xx_i2s_pcm_stereo_in.addr = res->start + SADR;
    387
    388	return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component,
    389					       &pxa_i2s_dai, 1);
    390}
    391
    392static struct platform_driver pxa2xx_i2s_driver = {
    393	.probe = pxa2xx_i2s_drv_probe,
    394
    395	.driver = {
    396		.name = "pxa2xx-i2s",
    397	},
    398};
    399
    400static int __init pxa2xx_i2s_init(void)
    401{
    402	clk_i2s = ERR_PTR(-ENOENT);
    403	return platform_driver_register(&pxa2xx_i2s_driver);
    404}
    405
    406static void __exit pxa2xx_i2s_exit(void)
    407{
    408	platform_driver_unregister(&pxa2xx_i2s_driver);
    409}
    410
    411module_init(pxa2xx_i2s_init);
    412module_exit(pxa2xx_i2s_exit);
    413
    414/* Module information */
    415MODULE_AUTHOR("Liam Girdwood, lrg@slimlogic.co.uk");
    416MODULE_DESCRIPTION("pxa2xx I2S SoC Interface");
    417MODULE_LICENSE("GPL");
    418MODULE_ALIAS("platform:pxa2xx-i2s");