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

s3c2412-i2s.c (6282B)


      1// SPDX-License-Identifier: GPL-2.0+
      2//
      3// ALSA Soc Audio Layer - S3C2412 I2S driver
      4//
      5// Copyright (c) 2006 Wolfson Microelectronics PLC.
      6//	Graeme Gregory graeme.gregory@wolfsonmicro.com
      7//	linux@wolfsonmicro.com
      8//
      9// Copyright (c) 2007, 2004-2005 Simtec Electronics
     10//	http://armlinux.simtec.co.uk/
     11//	Ben Dooks <ben@simtec.co.uk>
     12
     13#include <linux/delay.h>
     14#include <linux/gpio.h>
     15#include <linux/clk.h>
     16#include <linux/io.h>
     17#include <linux/module.h>
     18
     19#include <sound/soc.h>
     20#include <sound/pcm_params.h>
     21
     22#include "dma.h"
     23#include "regs-i2s-v2.h"
     24#include "s3c2412-i2s.h"
     25
     26#include <linux/platform_data/asoc-s3c.h>
     27
     28static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_out = {
     29	.chan_name	= "tx",
     30	.addr_width	= 4,
     31};
     32
     33static struct snd_dmaengine_dai_dma_data s3c2412_i2s_pcm_stereo_in = {
     34	.chan_name	= "rx",
     35	.addr_width	= 4,
     36};
     37
     38static struct s3c_i2sv2_info s3c2412_i2s;
     39
     40static int s3c2412_i2s_probe(struct snd_soc_dai *dai)
     41{
     42	int ret;
     43
     44	pr_debug("Entered %s\n", __func__);
     45
     46	snd_soc_dai_init_dma_data(dai, &s3c2412_i2s_pcm_stereo_out,
     47					&s3c2412_i2s_pcm_stereo_in);
     48
     49	ret = s3c_i2sv2_probe(dai, &s3c2412_i2s);
     50	if (ret)
     51		return ret;
     52
     53	s3c2412_i2s.dma_capture = &s3c2412_i2s_pcm_stereo_in;
     54	s3c2412_i2s.dma_playback = &s3c2412_i2s_pcm_stereo_out;
     55
     56	s3c2412_i2s.iis_cclk = devm_clk_get(dai->dev, "i2sclk");
     57	if (IS_ERR(s3c2412_i2s.iis_cclk)) {
     58		pr_err("failed to get i2sclk clock\n");
     59		ret = PTR_ERR(s3c2412_i2s.iis_cclk);
     60		goto err;
     61	}
     62
     63	/* Set MPLL as the source for IIS CLK */
     64
     65	clk_set_parent(s3c2412_i2s.iis_cclk, clk_get(NULL, "mpll"));
     66	ret = clk_prepare_enable(s3c2412_i2s.iis_cclk);
     67	if (ret)
     68		goto err;
     69
     70	return 0;
     71
     72err:
     73	s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
     74
     75	return ret;
     76}
     77
     78static int s3c2412_i2s_remove(struct snd_soc_dai *dai)
     79{
     80	clk_disable_unprepare(s3c2412_i2s.iis_cclk);
     81	s3c_i2sv2_cleanup(dai, &s3c2412_i2s);
     82
     83	return 0;
     84}
     85
     86static int s3c2412_i2s_hw_params(struct snd_pcm_substream *substream,
     87				 struct snd_pcm_hw_params *params,
     88				 struct snd_soc_dai *cpu_dai)
     89{
     90	struct s3c_i2sv2_info *i2s = snd_soc_dai_get_drvdata(cpu_dai);
     91	u32 iismod;
     92
     93	pr_debug("Entered %s\n", __func__);
     94
     95	iismod = readl(i2s->regs + S3C2412_IISMOD);
     96	pr_debug("%s: r: IISMOD: %x\n", __func__, iismod);
     97
     98	switch (params_width(params)) {
     99	case 8:
    100		iismod |= S3C2412_IISMOD_8BIT;
    101		break;
    102	case 16:
    103		iismod &= ~S3C2412_IISMOD_8BIT;
    104		break;
    105	}
    106
    107	writel(iismod, i2s->regs + S3C2412_IISMOD);
    108	pr_debug("%s: w: IISMOD: %x\n", __func__, iismod);
    109
    110	return 0;
    111}
    112
    113#ifdef CONFIG_PM
    114static int s3c2412_i2s_suspend(struct snd_soc_component *component)
    115{
    116	struct s3c_i2sv2_info *i2s = snd_soc_component_get_drvdata(component);
    117	u32 iismod;
    118
    119	if (component->active) {
    120		i2s->suspend_iismod = readl(i2s->regs + S3C2412_IISMOD);
    121		i2s->suspend_iiscon = readl(i2s->regs + S3C2412_IISCON);
    122		i2s->suspend_iispsr = readl(i2s->regs + S3C2412_IISPSR);
    123
    124		/* some basic suspend checks */
    125
    126		iismod = readl(i2s->regs + S3C2412_IISMOD);
    127
    128		if (iismod & S3C2412_IISCON_RXDMA_ACTIVE)
    129			pr_warn("%s: RXDMA active?\n", __func__);
    130
    131		if (iismod & S3C2412_IISCON_TXDMA_ACTIVE)
    132			pr_warn("%s: TXDMA active?\n", __func__);
    133
    134		if (iismod & S3C2412_IISCON_IIS_ACTIVE)
    135			pr_warn("%s: IIS active\n", __func__);
    136	}
    137
    138	return 0;
    139}
    140
    141static int s3c2412_i2s_resume(struct snd_soc_component *component)
    142{
    143	struct s3c_i2sv2_info *i2s = snd_soc_component_get_drvdata(component);
    144
    145	pr_info("component_active %d, IISMOD %08x, IISCON %08x\n",
    146		component->active, i2s->suspend_iismod, i2s->suspend_iiscon);
    147
    148	if (component->active) {
    149		writel(i2s->suspend_iiscon, i2s->regs + S3C2412_IISCON);
    150		writel(i2s->suspend_iismod, i2s->regs + S3C2412_IISMOD);
    151		writel(i2s->suspend_iispsr, i2s->regs + S3C2412_IISPSR);
    152
    153		writel(S3C2412_IISFIC_RXFLUSH | S3C2412_IISFIC_TXFLUSH,
    154		       i2s->regs + S3C2412_IISFIC);
    155
    156		ndelay(250);
    157		writel(0x0, i2s->regs + S3C2412_IISFIC);
    158	}
    159
    160	return 0;
    161}
    162#else
    163#define s3c2412_i2s_suspend NULL
    164#define s3c2412_i2s_resume  NULL
    165#endif
    166
    167#define S3C2412_I2S_RATES \
    168	(SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
    169	SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | \
    170	SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
    171
    172static const struct snd_soc_dai_ops s3c2412_i2s_dai_ops = {
    173	.hw_params	= s3c2412_i2s_hw_params,
    174};
    175
    176static struct snd_soc_dai_driver s3c2412_i2s_dai = {
    177	.probe		= s3c2412_i2s_probe,
    178	.remove	= s3c2412_i2s_remove,
    179	.playback = {
    180		.channels_min	= 2,
    181		.channels_max	= 2,
    182		.rates		= S3C2412_I2S_RATES,
    183		.formats	= SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
    184	},
    185	.capture = {
    186		.channels_min	= 2,
    187		.channels_max	= 2,
    188		.rates		= S3C2412_I2S_RATES,
    189		.formats	= SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE,
    190	},
    191	.ops = &s3c2412_i2s_dai_ops,
    192};
    193
    194static const struct snd_soc_component_driver s3c2412_i2s_component = {
    195	.name		= "s3c2412-i2s",
    196	.suspend	= s3c2412_i2s_suspend,
    197	.resume		= s3c2412_i2s_resume,
    198};
    199
    200static int s3c2412_iis_dev_probe(struct platform_device *pdev)
    201{
    202	int ret = 0;
    203	struct resource *res;
    204	struct s3c_audio_pdata *pdata = dev_get_platdata(&pdev->dev);
    205
    206	if (!pdata) {
    207		dev_err(&pdev->dev, "missing platform data");
    208		return -ENXIO;
    209	}
    210
    211	s3c2412_i2s.regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
    212	if (IS_ERR(s3c2412_i2s.regs))
    213		return PTR_ERR(s3c2412_i2s.regs);
    214
    215	s3c2412_i2s_pcm_stereo_out.addr = res->start + S3C2412_IISTXD;
    216	s3c2412_i2s_pcm_stereo_out.filter_data = pdata->dma_playback;
    217	s3c2412_i2s_pcm_stereo_in.addr = res->start + S3C2412_IISRXD;
    218	s3c2412_i2s_pcm_stereo_in.filter_data = pdata->dma_capture;
    219
    220	ret = samsung_asoc_dma_platform_register(&pdev->dev,
    221						 pdata->dma_filter,
    222						 "tx", "rx", NULL);
    223	if (ret) {
    224		pr_err("failed to register the DMA: %d\n", ret);
    225		return ret;
    226	}
    227
    228	ret = s3c_i2sv2_register_component(&pdev->dev, -1,
    229					   &s3c2412_i2s_component,
    230					   &s3c2412_i2s_dai);
    231	if (ret)
    232		pr_err("failed to register the dai\n");
    233
    234	return ret;
    235}
    236
    237static struct platform_driver s3c2412_iis_driver = {
    238	.probe  = s3c2412_iis_dev_probe,
    239	.driver = {
    240		.name = "s3c2412-iis",
    241	},
    242};
    243
    244module_platform_driver(s3c2412_iis_driver);
    245
    246/* Module information */
    247MODULE_AUTHOR("Ben Dooks, <ben@simtec.co.uk>");
    248MODULE_DESCRIPTION("S3C2412 I2S SoC Interface");
    249MODULE_LICENSE("GPL");
    250MODULE_ALIAS("platform:s3c2412-iis");