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

pcm3060.c (8330B)


      1// SPDX-License-Identifier: GPL-2.0
      2//
      3// PCM3060 codec driver
      4//
      5// Copyright (C) 2018 Kirill Marinushkin <kmarinushkin@birdec.com>
      6
      7#include <linux/module.h>
      8#include <sound/pcm_params.h>
      9#include <sound/soc.h>
     10#include <sound/tlv.h>
     11
     12#include "pcm3060.h"
     13
     14/* dai */
     15
     16static int pcm3060_set_sysclk(struct snd_soc_dai *dai, int clk_id,
     17			      unsigned int freq, int dir)
     18{
     19	struct snd_soc_component *comp = dai->component;
     20	struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
     21	unsigned int reg;
     22	unsigned int val;
     23
     24	if (dir != SND_SOC_CLOCK_IN) {
     25		dev_err(comp->dev, "unsupported sysclock dir: %d\n", dir);
     26		return -EINVAL;
     27	}
     28
     29	switch (clk_id) {
     30	case PCM3060_CLK_DEF:
     31		val = 0;
     32		break;
     33
     34	case PCM3060_CLK1:
     35		val = (dai->id == PCM3060_DAI_ID_DAC ? PCM3060_REG_CSEL : 0);
     36		break;
     37
     38	case PCM3060_CLK2:
     39		val = (dai->id == PCM3060_DAI_ID_DAC ? 0 : PCM3060_REG_CSEL);
     40		break;
     41
     42	default:
     43		dev_err(comp->dev, "unsupported sysclock id: %d\n", clk_id);
     44		return -EINVAL;
     45	}
     46
     47	if (dai->id == PCM3060_DAI_ID_DAC)
     48		reg = PCM3060_REG67;
     49	else
     50		reg = PCM3060_REG72;
     51
     52	regmap_update_bits(priv->regmap, reg, PCM3060_REG_CSEL, val);
     53
     54	priv->dai[dai->id].sclk_freq = freq;
     55
     56	return 0;
     57}
     58
     59static int pcm3060_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
     60{
     61	struct snd_soc_component *comp = dai->component;
     62	struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
     63	unsigned int reg;
     64	unsigned int val;
     65
     66	if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) {
     67		dev_err(comp->dev, "unsupported DAI polarity: 0x%x\n", fmt);
     68		return -EINVAL;
     69	}
     70
     71	switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
     72	case SND_SOC_DAIFMT_CBP_CFP:
     73		priv->dai[dai->id].is_provider = true;
     74		break;
     75	case SND_SOC_DAIFMT_CBC_CFC:
     76		priv->dai[dai->id].is_provider = false;
     77		break;
     78	default:
     79		dev_err(comp->dev, "unsupported DAI mode: 0x%x\n", fmt);
     80		return -EINVAL;
     81	}
     82
     83	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
     84	case SND_SOC_DAIFMT_I2S:
     85		val = PCM3060_REG_FMT_I2S;
     86		break;
     87	case SND_SOC_DAIFMT_RIGHT_J:
     88		val = PCM3060_REG_FMT_RJ;
     89		break;
     90	case SND_SOC_DAIFMT_LEFT_J:
     91		val = PCM3060_REG_FMT_LJ;
     92		break;
     93	default:
     94		dev_err(comp->dev, "unsupported DAI format: 0x%x\n", fmt);
     95		return -EINVAL;
     96	}
     97
     98	if (dai->id == PCM3060_DAI_ID_DAC)
     99		reg = PCM3060_REG67;
    100	else
    101		reg = PCM3060_REG72;
    102
    103	regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_FMT, val);
    104
    105	return 0;
    106}
    107
    108static int pcm3060_hw_params(struct snd_pcm_substream *substream,
    109			     struct snd_pcm_hw_params *params,
    110			     struct snd_soc_dai *dai)
    111{
    112	struct snd_soc_component *comp = dai->component;
    113	struct pcm3060_priv *priv = snd_soc_component_get_drvdata(comp);
    114	unsigned int rate;
    115	unsigned int ratio;
    116	unsigned int reg;
    117	unsigned int val;
    118
    119	if (!priv->dai[dai->id].is_provider) {
    120		val = PCM3060_REG_MS_S;
    121		goto val_ready;
    122	}
    123
    124	rate = params_rate(params);
    125	if (!rate) {
    126		dev_err(comp->dev, "rate is not configured\n");
    127		return -EINVAL;
    128	}
    129
    130	ratio = priv->dai[dai->id].sclk_freq / rate;
    131
    132	switch (ratio) {
    133	case 768:
    134		val = PCM3060_REG_MS_M768;
    135		break;
    136	case 512:
    137		val = PCM3060_REG_MS_M512;
    138		break;
    139	case 384:
    140		val = PCM3060_REG_MS_M384;
    141		break;
    142	case 256:
    143		val = PCM3060_REG_MS_M256;
    144		break;
    145	case 192:
    146		val = PCM3060_REG_MS_M192;
    147		break;
    148	case 128:
    149		val = PCM3060_REG_MS_M128;
    150		break;
    151	default:
    152		dev_err(comp->dev, "unsupported ratio: %d\n", ratio);
    153		return -EINVAL;
    154	}
    155
    156val_ready:
    157	if (dai->id == PCM3060_DAI_ID_DAC)
    158		reg = PCM3060_REG67;
    159	else
    160		reg = PCM3060_REG72;
    161
    162	regmap_update_bits(priv->regmap, reg, PCM3060_REG_MASK_MS, val);
    163
    164	return 0;
    165}
    166
    167static const struct snd_soc_dai_ops pcm3060_dai_ops = {
    168	.set_sysclk = pcm3060_set_sysclk,
    169	.set_fmt = pcm3060_set_fmt,
    170	.hw_params = pcm3060_hw_params,
    171};
    172
    173#define PCM3060_DAI_RATES_ADC	(SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_32000 | \
    174				 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
    175				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000)
    176
    177#define PCM3060_DAI_RATES_DAC	(PCM3060_DAI_RATES_ADC | \
    178				 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
    179
    180static struct snd_soc_dai_driver pcm3060_dai[] = {
    181	{
    182		.name = "pcm3060-dac",
    183		.id = PCM3060_DAI_ID_DAC,
    184		.playback = {
    185			.stream_name = "Playback",
    186			.channels_min = 2,
    187			.channels_max = 2,
    188			.rates = PCM3060_DAI_RATES_DAC,
    189			.formats = SNDRV_PCM_FMTBIT_S24_LE,
    190		},
    191		.ops = &pcm3060_dai_ops,
    192	},
    193	{
    194		.name = "pcm3060-adc",
    195		.id = PCM3060_DAI_ID_ADC,
    196		.capture = {
    197			.stream_name = "Capture",
    198			.channels_min = 2,
    199			.channels_max = 2,
    200			.rates = PCM3060_DAI_RATES_ADC,
    201			.formats = SNDRV_PCM_FMTBIT_S24_LE,
    202		},
    203		.ops = &pcm3060_dai_ops,
    204	},
    205};
    206
    207/* dapm */
    208
    209static DECLARE_TLV_DB_SCALE(pcm3060_dapm_tlv, -10050, 50, 1);
    210
    211static const struct snd_kcontrol_new pcm3060_dapm_controls[] = {
    212	SOC_DOUBLE_R_RANGE_TLV("Master Playback Volume",
    213			       PCM3060_REG65, PCM3060_REG66, 0,
    214			       PCM3060_REG_AT2_MIN, PCM3060_REG_AT2_MAX,
    215			       0, pcm3060_dapm_tlv),
    216	SOC_DOUBLE("Master Playback Switch", PCM3060_REG68,
    217		   PCM3060_REG_SHIFT_MUT21, PCM3060_REG_SHIFT_MUT22, 1, 1),
    218
    219	SOC_DOUBLE_R_RANGE_TLV("Master Capture Volume",
    220			       PCM3060_REG70, PCM3060_REG71, 0,
    221			       PCM3060_REG_AT1_MIN, PCM3060_REG_AT1_MAX,
    222			       0, pcm3060_dapm_tlv),
    223	SOC_DOUBLE("Master Capture Switch", PCM3060_REG73,
    224		   PCM3060_REG_SHIFT_MUT11, PCM3060_REG_SHIFT_MUT12, 1, 1),
    225};
    226
    227static const struct snd_soc_dapm_widget pcm3060_dapm_widgets[] = {
    228	SND_SOC_DAPM_DAC("DAC", "Playback", PCM3060_REG64,
    229			 PCM3060_REG_SHIFT_DAPSV, 1),
    230
    231	SND_SOC_DAPM_OUTPUT("OUTL"),
    232	SND_SOC_DAPM_OUTPUT("OUTR"),
    233
    234	SND_SOC_DAPM_INPUT("INL"),
    235	SND_SOC_DAPM_INPUT("INR"),
    236
    237	SND_SOC_DAPM_ADC("ADC", "Capture", PCM3060_REG64,
    238			 PCM3060_REG_SHIFT_ADPSV, 1),
    239};
    240
    241static const struct snd_soc_dapm_route pcm3060_dapm_map[] = {
    242	{ "OUTL", NULL, "DAC" },
    243	{ "OUTR", NULL, "DAC" },
    244
    245	{ "ADC", NULL, "INL" },
    246	{ "ADC", NULL, "INR" },
    247};
    248
    249/* soc component */
    250
    251static const struct snd_soc_component_driver pcm3060_soc_comp_driver = {
    252	.controls = pcm3060_dapm_controls,
    253	.num_controls = ARRAY_SIZE(pcm3060_dapm_controls),
    254	.dapm_widgets = pcm3060_dapm_widgets,
    255	.num_dapm_widgets = ARRAY_SIZE(pcm3060_dapm_widgets),
    256	.dapm_routes = pcm3060_dapm_map,
    257	.num_dapm_routes = ARRAY_SIZE(pcm3060_dapm_map),
    258	.endianness = 1,
    259};
    260
    261/* regmap */
    262
    263static bool pcm3060_reg_writeable(struct device *dev, unsigned int reg)
    264{
    265	return (reg >= PCM3060_REG64);
    266}
    267
    268static bool pcm3060_reg_readable(struct device *dev, unsigned int reg)
    269{
    270	return (reg >= PCM3060_REG64);
    271}
    272
    273static bool pcm3060_reg_volatile(struct device *dev, unsigned int reg)
    274{
    275	/* PCM3060_REG64 is volatile */
    276	return (reg == PCM3060_REG64);
    277}
    278
    279static const struct reg_default pcm3060_reg_defaults[] = {
    280	{ PCM3060_REG64,  0xF0 },
    281	{ PCM3060_REG65,  0xFF },
    282	{ PCM3060_REG66,  0xFF },
    283	{ PCM3060_REG67,  0x00 },
    284	{ PCM3060_REG68,  0x00 },
    285	{ PCM3060_REG69,  0x00 },
    286	{ PCM3060_REG70,  0xD7 },
    287	{ PCM3060_REG71,  0xD7 },
    288	{ PCM3060_REG72,  0x00 },
    289	{ PCM3060_REG73,  0x00 },
    290};
    291
    292const struct regmap_config pcm3060_regmap = {
    293	.reg_bits = 8,
    294	.val_bits = 8,
    295	.writeable_reg = pcm3060_reg_writeable,
    296	.readable_reg = pcm3060_reg_readable,
    297	.volatile_reg = pcm3060_reg_volatile,
    298	.max_register = PCM3060_REG73,
    299	.reg_defaults = pcm3060_reg_defaults,
    300	.num_reg_defaults = ARRAY_SIZE(pcm3060_reg_defaults),
    301	.cache_type = REGCACHE_RBTREE,
    302};
    303EXPORT_SYMBOL(pcm3060_regmap);
    304
    305/* device */
    306
    307static void pcm3060_parse_dt(const struct device_node *np,
    308			     struct pcm3060_priv *priv)
    309{
    310	priv->out_se = of_property_read_bool(np, "ti,out-single-ended");
    311}
    312
    313int pcm3060_probe(struct device *dev)
    314{
    315	int rc;
    316	struct pcm3060_priv *priv = dev_get_drvdata(dev);
    317
    318	/* soft reset */
    319	rc = regmap_update_bits(priv->regmap, PCM3060_REG64,
    320				PCM3060_REG_MRST, 0);
    321	if (rc) {
    322		dev_err(dev, "failed to reset component, rc=%d\n", rc);
    323		return rc;
    324	}
    325
    326	if (dev->of_node)
    327		pcm3060_parse_dt(dev->of_node, priv);
    328
    329	if (priv->out_se)
    330		regmap_update_bits(priv->regmap, PCM3060_REG64,
    331				   PCM3060_REG_SE, PCM3060_REG_SE);
    332
    333	rc = devm_snd_soc_register_component(dev, &pcm3060_soc_comp_driver,
    334					     pcm3060_dai,
    335					     ARRAY_SIZE(pcm3060_dai));
    336	if (rc) {
    337		dev_err(dev, "failed to register component, rc=%d\n", rc);
    338		return rc;
    339	}
    340
    341	return 0;
    342}
    343EXPORT_SYMBOL(pcm3060_probe);
    344
    345MODULE_DESCRIPTION("PCM3060 codec driver");
    346MODULE_AUTHOR("Kirill Marinushkin <kmarinushkin@birdec.com>");
    347MODULE_LICENSE("GPL v2");