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

s3c24xx_uda134x.c (6699B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// Modifications by Christian Pellegrin <chripell@evolware.org>
      4//
      5// s3c24xx_uda134x.c - S3C24XX_UDA134X ALSA SoC Audio board driver
      6//
      7// Copyright 2007 Dension Audio Systems Ltd.
      8// Author: Zoltan Devai
      9
     10#include <linux/clk.h>
     11#include <linux/gpio.h>
     12#include <linux/module.h>
     13
     14#include <sound/soc.h>
     15#include <sound/s3c24xx_uda134x.h>
     16
     17#include "regs-iis.h"
     18#include "s3c24xx-i2s.h"
     19
     20struct s3c24xx_uda134x {
     21	struct clk *xtal;
     22	struct clk *pclk;
     23	struct mutex clk_lock;
     24	int clk_users;
     25};
     26
     27/* #define ENFORCE_RATES 1 */
     28/*
     29  Unfortunately the S3C24XX in master mode has a limited capacity of
     30  generating the clock for the codec. If you define this only rates
     31  that are really available will be enforced. But be careful, most
     32  user level application just want the usual sampling frequencies (8,
     33  11.025, 22.050, 44.1 kHz) and anyway resampling is a costly
     34  operation for embedded systems. So if you aren't very lucky or your
     35  hardware engineer wasn't very forward-looking it's better to leave
     36  this undefined. If you do so an approximate value for the requested
     37  sampling rate in the range -/+ 5% will be chosen. If this in not
     38  possible an error will be returned.
     39*/
     40
     41static unsigned int rates[33 * 2];
     42#ifdef ENFORCE_RATES
     43static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
     44	.count	= ARRAY_SIZE(rates),
     45	.list	= rates,
     46	.mask	= 0,
     47};
     48#endif
     49
     50static int s3c24xx_uda134x_startup(struct snd_pcm_substream *substream)
     51{
     52	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
     53	struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
     54	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
     55	int ret = 0;
     56
     57	mutex_lock(&priv->clk_lock);
     58
     59	if (priv->clk_users == 0) {
     60		priv->xtal = clk_get(rtd->dev, "xtal");
     61		if (IS_ERR(priv->xtal)) {
     62			dev_err(rtd->dev, "%s cannot get xtal\n", __func__);
     63			ret = PTR_ERR(priv->xtal);
     64		} else {
     65			priv->pclk = clk_get(cpu_dai->dev, "iis");
     66			if (IS_ERR(priv->pclk)) {
     67				dev_err(rtd->dev, "%s cannot get pclk\n",
     68					__func__);
     69				clk_put(priv->xtal);
     70				ret = PTR_ERR(priv->pclk);
     71			}
     72		}
     73		if (!ret) {
     74			int i, j;
     75
     76			for (i = 0; i < 2; i++) {
     77				int fs = i ? 256 : 384;
     78
     79				rates[i*33] = clk_get_rate(priv->xtal) / fs;
     80				for (j = 1; j < 33; j++)
     81					rates[i*33 + j] = clk_get_rate(priv->pclk) /
     82						(j * fs);
     83			}
     84		}
     85	}
     86	priv->clk_users += 1;
     87	mutex_unlock(&priv->clk_lock);
     88
     89	if (!ret) {
     90#ifdef ENFORCE_RATES
     91		ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
     92						 SNDRV_PCM_HW_PARAM_RATE,
     93						 &hw_constraints_rates);
     94		if (ret < 0)
     95			dev_err(rtd->dev, "%s cannot set constraints\n",
     96				__func__);
     97#endif
     98	}
     99	return ret;
    100}
    101
    102static void s3c24xx_uda134x_shutdown(struct snd_pcm_substream *substream)
    103{
    104	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    105	struct s3c24xx_uda134x *priv = snd_soc_card_get_drvdata(rtd->card);
    106
    107	mutex_lock(&priv->clk_lock);
    108	priv->clk_users -= 1;
    109	if (priv->clk_users == 0) {
    110		clk_put(priv->xtal);
    111		priv->xtal = NULL;
    112		clk_put(priv->pclk);
    113		priv->pclk = NULL;
    114	}
    115	mutex_unlock(&priv->clk_lock);
    116}
    117
    118static int s3c24xx_uda134x_hw_params(struct snd_pcm_substream *substream,
    119					struct snd_pcm_hw_params *params)
    120{
    121	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    122	struct snd_soc_dai *codec_dai = asoc_rtd_to_codec(rtd, 0);
    123	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(rtd, 0);
    124	unsigned int clk = 0;
    125	int ret = 0;
    126	int clk_source, fs_mode;
    127	unsigned long rate = params_rate(params);
    128	long err, cerr;
    129	unsigned int div;
    130	int i, bi;
    131
    132	err = 999999;
    133	bi = 0;
    134	for (i = 0; i < 2*33; i++) {
    135		cerr = rates[i] - rate;
    136		if (cerr < 0)
    137			cerr = -cerr;
    138		if (cerr < err) {
    139			err = cerr;
    140			bi = i;
    141		}
    142	}
    143	if (bi / 33 == 1)
    144		fs_mode = S3C2410_IISMOD_256FS;
    145	else
    146		fs_mode = S3C2410_IISMOD_384FS;
    147	if (bi % 33 == 0) {
    148		clk_source = S3C24XX_CLKSRC_MPLL;
    149		div = 1;
    150	} else {
    151		clk_source = S3C24XX_CLKSRC_PCLK;
    152		div = bi % 33;
    153	}
    154
    155	dev_dbg(rtd->dev, "%s desired rate %lu, %d\n", __func__, rate, bi);
    156
    157	clk = (fs_mode == S3C2410_IISMOD_384FS ? 384 : 256) * rate;
    158
    159	dev_dbg(rtd->dev, "%s will use: %s %s %d sysclk %d err %ld\n", __func__,
    160		fs_mode == S3C2410_IISMOD_384FS ? "384FS" : "256FS",
    161		clk_source == S3C24XX_CLKSRC_MPLL ? "MPLLin" : "PCLK",
    162		div, clk, err);
    163
    164	if ((err * 100 / rate) > 5) {
    165		dev_err(rtd->dev, "effective frequency too different "
    166				  "from desired (%ld%%)\n", err * 100 / rate);
    167		return -EINVAL;
    168	}
    169
    170	ret = snd_soc_dai_set_sysclk(cpu_dai, clk_source , clk,
    171			SND_SOC_CLOCK_IN);
    172	if (ret < 0)
    173		return ret;
    174
    175	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_MCLK, fs_mode);
    176	if (ret < 0)
    177		return ret;
    178
    179	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_BCLK,
    180			S3C2410_IISMOD_32FS);
    181	if (ret < 0)
    182		return ret;
    183
    184	ret = snd_soc_dai_set_clkdiv(cpu_dai, S3C24XX_DIV_PRESCALER,
    185			S3C24XX_PRESCALE(div, div));
    186	if (ret < 0)
    187		return ret;
    188
    189	/* set the codec system clock for DAC and ADC */
    190	ret = snd_soc_dai_set_sysclk(codec_dai, 0, clk,
    191			SND_SOC_CLOCK_OUT);
    192	if (ret < 0)
    193		return ret;
    194
    195	return 0;
    196}
    197
    198static const struct snd_soc_ops s3c24xx_uda134x_ops = {
    199	.startup = s3c24xx_uda134x_startup,
    200	.shutdown = s3c24xx_uda134x_shutdown,
    201	.hw_params = s3c24xx_uda134x_hw_params,
    202};
    203
    204SND_SOC_DAILINK_DEFS(uda134x,
    205	DAILINK_COMP_ARRAY(COMP_CPU("s3c24xx-iis")),
    206	DAILINK_COMP_ARRAY(COMP_CODEC("uda134x-codec", "uda134x-hifi")),
    207	DAILINK_COMP_ARRAY(COMP_PLATFORM("s3c24xx-iis")));
    208
    209static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
    210	.name = "UDA134X",
    211	.stream_name = "UDA134X",
    212	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
    213		   SND_SOC_DAIFMT_CBS_CFS,
    214	.ops = &s3c24xx_uda134x_ops,
    215	SND_SOC_DAILINK_REG(uda134x),
    216};
    217
    218static struct snd_soc_card snd_soc_s3c24xx_uda134x = {
    219	.name = "S3C24XX_UDA134X",
    220	.owner = THIS_MODULE,
    221	.dai_link = &s3c24xx_uda134x_dai_link,
    222	.num_links = 1,
    223};
    224
    225static int s3c24xx_uda134x_probe(struct platform_device *pdev)
    226{
    227	struct snd_soc_card *card = &snd_soc_s3c24xx_uda134x;
    228	struct s3c24xx_uda134x *priv;
    229	int ret;
    230
    231	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    232	if (!priv)
    233		return -ENOMEM;
    234
    235	mutex_init(&priv->clk_lock);
    236
    237	card->dev = &pdev->dev;
    238	snd_soc_card_set_drvdata(card, priv);
    239
    240	ret = devm_snd_soc_register_card(&pdev->dev, card);
    241	if (ret)
    242		dev_err(&pdev->dev, "failed to register card: %d\n", ret);
    243
    244	return ret;
    245}
    246
    247static struct platform_driver s3c24xx_uda134x_driver = {
    248	.probe  = s3c24xx_uda134x_probe,
    249	.driver = {
    250		.name = "s3c24xx_uda134x",
    251	},
    252};
    253module_platform_driver(s3c24xx_uda134x_driver);
    254
    255MODULE_AUTHOR("Zoltan Devai, Christian Pellegrin <chripell@evolware.org>");
    256MODULE_DESCRIPTION("S3C24XX_UDA134X ALSA SoC audio driver");
    257MODULE_LICENSE("GPL");