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

sti-sas.c (12705B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) STMicroelectronics SA 2015
      4 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
      5 *          for STMicroelectronics.
      6 */
      7
      8#include <linux/io.h>
      9#include <linux/module.h>
     10#include <linux/regmap.h>
     11#include <linux/reset.h>
     12#include <linux/mfd/syscon.h>
     13
     14#include <sound/soc.h>
     15#include <sound/soc-dapm.h>
     16
     17/* DAC definitions */
     18
     19/* stih407 DAC registers */
     20/* sysconf 5041: Audio-Gue-Control */
     21#define STIH407_AUDIO_GLUE_CTRL 0x000000A4
     22/* sysconf 5042: Audio-DAC-Control */
     23#define STIH407_AUDIO_DAC_CTRL 0x000000A8
     24
     25/* DAC definitions */
     26#define STIH407_DAC_SOFTMUTE		0x0
     27#define STIH407_DAC_STANDBY_ANA		0x1
     28#define STIH407_DAC_STANDBY		0x2
     29
     30#define STIH407_DAC_SOFTMUTE_MASK	BIT(STIH407_DAC_SOFTMUTE)
     31#define STIH407_DAC_STANDBY_ANA_MASK    BIT(STIH407_DAC_STANDBY_ANA)
     32#define STIH407_DAC_STANDBY_MASK        BIT(STIH407_DAC_STANDBY)
     33
     34/* SPDIF definitions */
     35#define SPDIF_BIPHASE_ENABLE		0x6
     36#define SPDIF_BIPHASE_IDLE		0x7
     37
     38#define SPDIF_BIPHASE_ENABLE_MASK	BIT(SPDIF_BIPHASE_ENABLE)
     39#define SPDIF_BIPHASE_IDLE_MASK		BIT(SPDIF_BIPHASE_IDLE)
     40
     41enum {
     42	STI_SAS_DAI_SPDIF_OUT,
     43	STI_SAS_DAI_ANALOG_OUT,
     44};
     45
     46static const struct reg_default stih407_sas_reg_defaults[] = {
     47	{ STIH407_AUDIO_DAC_CTRL, 0x000000000 },
     48	{ STIH407_AUDIO_GLUE_CTRL, 0x00000040 },
     49};
     50
     51struct sti_dac_audio {
     52	struct regmap *regmap;
     53	struct regmap *virt_regmap;
     54	int mclk;
     55};
     56
     57struct sti_spdif_audio {
     58	struct regmap *regmap;
     59	int mclk;
     60};
     61
     62/* device data structure */
     63struct sti_sas_dev_data {
     64	const struct regmap_config *regmap;
     65	const struct snd_soc_dai_ops *dac_ops;  /* DAC function callbacks */
     66	const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */
     67	const int num_dapm_widgets; /* dapms declaration */
     68	const struct snd_soc_dapm_route *dapm_routes; /* route declaration */
     69	const int num_dapm_routes; /* route declaration */
     70};
     71
     72/* driver data structure */
     73struct sti_sas_data {
     74	struct device *dev;
     75	const struct sti_sas_dev_data *dev_data;
     76	struct sti_dac_audio dac;
     77	struct sti_spdif_audio spdif;
     78};
     79
     80/* Read a register from the sysconf reg bank */
     81static int sti_sas_read_reg(void *context, unsigned int reg,
     82			    unsigned int *value)
     83{
     84	struct sti_sas_data *drvdata = context;
     85	int status;
     86	u32 val;
     87
     88	status = regmap_read(drvdata->dac.regmap, reg, &val);
     89	*value = (unsigned int)val;
     90
     91	return status;
     92}
     93
     94/* Read a register from the sysconf reg bank */
     95static int sti_sas_write_reg(void *context, unsigned int reg,
     96			     unsigned int value)
     97{
     98	struct sti_sas_data *drvdata = context;
     99	int status;
    100
    101	status = regmap_write(drvdata->dac.regmap, reg, value);
    102
    103	return status;
    104}
    105
    106static int  sti_sas_init_sas_registers(struct snd_soc_component *component,
    107				       struct sti_sas_data *data)
    108{
    109	int ret;
    110	/*
    111	 * DAC and SPDIF are activated by default
    112	 * put them in IDLE to save power
    113	 */
    114
    115	/* Initialise bi-phase formatter to disabled */
    116	ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
    117				  SPDIF_BIPHASE_ENABLE_MASK, 0);
    118
    119	if (!ret)
    120		/* Initialise bi-phase formatter idle value to 0 */
    121		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
    122					  SPDIF_BIPHASE_IDLE_MASK, 0);
    123	if (ret < 0) {
    124		dev_err(component->dev, "Failed to update SPDIF registers\n");
    125		return ret;
    126	}
    127
    128	/* Init DAC configuration */
    129	/* init configuration */
    130	ret =  snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
    131				   STIH407_DAC_STANDBY_MASK,
    132				   STIH407_DAC_STANDBY_MASK);
    133
    134	if (!ret)
    135		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
    136					  STIH407_DAC_STANDBY_ANA_MASK,
    137					  STIH407_DAC_STANDBY_ANA_MASK);
    138	if (!ret)
    139		ret = snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
    140					  STIH407_DAC_SOFTMUTE_MASK,
    141					  STIH407_DAC_SOFTMUTE_MASK);
    142
    143	if (ret < 0) {
    144		dev_err(component->dev, "Failed to update DAC registers\n");
    145		return ret;
    146	}
    147
    148	return ret;
    149}
    150
    151/*
    152 * DAC
    153 */
    154static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
    155{
    156	/* Sanity check only */
    157	if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) != SND_SOC_DAIFMT_CBC_CFC) {
    158		dev_err(dai->component->dev,
    159			"%s: ERROR: Unsupported clocking 0x%x\n",
    160			__func__, fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK);
    161		return -EINVAL;
    162	}
    163
    164	return 0;
    165}
    166
    167static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = {
    168	SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL,
    169			     STIH407_DAC_STANDBY_ANA, 1, NULL, 0),
    170	SND_SOC_DAPM_DAC("DAC standby",  "dac_p", STIH407_AUDIO_DAC_CTRL,
    171			 STIH407_DAC_STANDBY, 1),
    172	SND_SOC_DAPM_OUTPUT("DAC Output"),
    173};
    174
    175static const struct snd_soc_dapm_route stih407_sas_route[] = {
    176	{"DAC Output", NULL, "DAC standby ana"},
    177	{"DAC standby ana", NULL, "DAC standby"},
    178};
    179
    180
    181static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream)
    182{
    183	struct snd_soc_component *component = dai->component;
    184
    185	if (mute) {
    186		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
    187					    STIH407_DAC_SOFTMUTE_MASK,
    188					    STIH407_DAC_SOFTMUTE_MASK);
    189	} else {
    190		return snd_soc_component_update_bits(component, STIH407_AUDIO_DAC_CTRL,
    191					    STIH407_DAC_SOFTMUTE_MASK,
    192					    0);
    193	}
    194}
    195
    196/*
    197 * SPDIF
    198 */
    199static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai,
    200				 unsigned int fmt)
    201{
    202	if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) {
    203		dev_err(dai->component->dev,
    204			"%s: ERROR: Unsupporter master mask 0x%x\n",
    205			__func__, fmt & SND_SOC_DAIFMT_MASTER_MASK);
    206		return -EINVAL;
    207	}
    208
    209	return 0;
    210}
    211
    212/*
    213 * sti_sas_spdif_trigger:
    214 * Trigger function is used to ensure that BiPhase Formater is disabled
    215 * before CPU dai is stopped.
    216 * This is mandatory to avoid that BPF is stalled
    217 */
    218static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd,
    219				 struct snd_soc_dai *dai)
    220{
    221	struct snd_soc_component *component = dai->component;
    222
    223	switch (cmd) {
    224	case SNDRV_PCM_TRIGGER_START:
    225	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
    226		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
    227					    SPDIF_BIPHASE_ENABLE_MASK,
    228					    SPDIF_BIPHASE_ENABLE_MASK);
    229	case SNDRV_PCM_TRIGGER_RESUME:
    230	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
    231	case SNDRV_PCM_TRIGGER_STOP:
    232	case SNDRV_PCM_TRIGGER_SUSPEND:
    233		return snd_soc_component_update_bits(component, STIH407_AUDIO_GLUE_CTRL,
    234					    SPDIF_BIPHASE_ENABLE_MASK,
    235					    0);
    236	default:
    237		return -EINVAL;
    238	}
    239}
    240
    241static bool sti_sas_volatile_register(struct device *dev, unsigned int reg)
    242{
    243	if (reg == STIH407_AUDIO_GLUE_CTRL)
    244		return true;
    245
    246	return false;
    247}
    248
    249/*
    250 * CODEC DAIS
    251 */
    252
    253/*
    254 * sti_sas_set_sysclk:
    255 * get MCLK input frequency to check that MCLK-FS ratio is coherent
    256 */
    257static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id,
    258			      unsigned int freq, int dir)
    259{
    260	struct snd_soc_component *component = dai->component;
    261	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
    262
    263	if (dir == SND_SOC_CLOCK_OUT)
    264		return 0;
    265
    266	if (clk_id != 0)
    267		return -EINVAL;
    268
    269	switch (dai->id) {
    270	case STI_SAS_DAI_SPDIF_OUT:
    271		drvdata->spdif.mclk = freq;
    272		break;
    273
    274	case STI_SAS_DAI_ANALOG_OUT:
    275		drvdata->dac.mclk = freq;
    276		break;
    277	}
    278
    279	return 0;
    280}
    281
    282static int sti_sas_prepare(struct snd_pcm_substream *substream,
    283			   struct snd_soc_dai *dai)
    284{
    285	struct snd_soc_component *component = dai->component;
    286	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
    287	struct snd_pcm_runtime *runtime = substream->runtime;
    288
    289	switch (dai->id) {
    290	case STI_SAS_DAI_SPDIF_OUT:
    291		if ((drvdata->spdif.mclk / runtime->rate) != 128) {
    292			dev_err(component->dev, "unexpected mclk-fs ratio\n");
    293			return -EINVAL;
    294		}
    295		break;
    296	case STI_SAS_DAI_ANALOG_OUT:
    297		if ((drvdata->dac.mclk / runtime->rate) != 256) {
    298			dev_err(component->dev, "unexpected mclk-fs ratio\n");
    299			return -EINVAL;
    300		}
    301		break;
    302	}
    303
    304	return 0;
    305}
    306
    307static const struct snd_soc_dai_ops stih407_dac_ops = {
    308	.set_fmt = sti_sas_dac_set_fmt,
    309	.mute_stream = stih407_sas_dac_mute,
    310	.prepare = sti_sas_prepare,
    311	.set_sysclk = sti_sas_set_sysclk,
    312};
    313
    314static const struct regmap_config stih407_sas_regmap = {
    315	.reg_bits = 32,
    316	.val_bits = 32,
    317	.fast_io = true,
    318	.max_register = STIH407_AUDIO_DAC_CTRL,
    319	.reg_defaults = stih407_sas_reg_defaults,
    320	.num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults),
    321	.volatile_reg = sti_sas_volatile_register,
    322	.cache_type = REGCACHE_RBTREE,
    323	.reg_read = sti_sas_read_reg,
    324	.reg_write = sti_sas_write_reg,
    325};
    326
    327static const struct sti_sas_dev_data stih407_data = {
    328	.regmap = &stih407_sas_regmap,
    329	.dac_ops = &stih407_dac_ops,
    330	.dapm_widgets = stih407_sas_dapm_widgets,
    331	.num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets),
    332	.dapm_routes =	stih407_sas_route,
    333	.num_dapm_routes = ARRAY_SIZE(stih407_sas_route),
    334};
    335
    336static struct snd_soc_dai_driver sti_sas_dai[] = {
    337	{
    338		.name = "sas-dai-spdif-out",
    339		.id = STI_SAS_DAI_SPDIF_OUT,
    340		.playback = {
    341			.stream_name = "spdif_p",
    342			.channels_min = 2,
    343			.channels_max = 2,
    344			.rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
    345				 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 |
    346				 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
    347				 SNDRV_PCM_RATE_192000,
    348			.formats = SNDRV_PCM_FMTBIT_S16_LE |
    349				   SNDRV_PCM_FMTBIT_S32_LE,
    350		},
    351		.ops = (struct snd_soc_dai_ops[]) {
    352			{
    353				.set_fmt = sti_sas_spdif_set_fmt,
    354				.trigger = sti_sas_spdif_trigger,
    355				.set_sysclk = sti_sas_set_sysclk,
    356				.prepare = sti_sas_prepare,
    357			}
    358		},
    359	},
    360	{
    361		.name = "sas-dai-dac",
    362		.id = STI_SAS_DAI_ANALOG_OUT,
    363		.playback = {
    364			.stream_name = "dac_p",
    365			.channels_min = 2,
    366			.channels_max = 2,
    367			.rates = SNDRV_PCM_RATE_8000_48000,
    368			.formats = SNDRV_PCM_FMTBIT_S16_LE |
    369				   SNDRV_PCM_FMTBIT_S32_LE,
    370		},
    371	},
    372};
    373
    374#ifdef CONFIG_PM_SLEEP
    375static int sti_sas_resume(struct snd_soc_component *component)
    376{
    377	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
    378
    379	return sti_sas_init_sas_registers(component, drvdata);
    380}
    381#else
    382#define sti_sas_resume NULL
    383#endif
    384
    385static int sti_sas_component_probe(struct snd_soc_component *component)
    386{
    387	struct sti_sas_data *drvdata = dev_get_drvdata(component->dev);
    388	int ret;
    389
    390	ret = sti_sas_init_sas_registers(component, drvdata);
    391
    392	return ret;
    393}
    394
    395static struct snd_soc_component_driver sti_sas_driver = {
    396	.probe			= sti_sas_component_probe,
    397	.resume			= sti_sas_resume,
    398	.idle_bias_on		= 1,
    399	.use_pmdown_time	= 1,
    400	.endianness		= 1,
    401	.non_legacy_dai_naming	= 1,
    402};
    403
    404static const struct of_device_id sti_sas_dev_match[] = {
    405	{
    406		.compatible = "st,stih407-sas-codec",
    407		.data = &stih407_data,
    408	},
    409	{},
    410};
    411MODULE_DEVICE_TABLE(of, sti_sas_dev_match);
    412
    413static int sti_sas_driver_probe(struct platform_device *pdev)
    414{
    415	struct device_node *pnode = pdev->dev.of_node;
    416	struct sti_sas_data *drvdata;
    417	const struct of_device_id *of_id;
    418
    419	/* Allocate device structure */
    420	drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data),
    421			       GFP_KERNEL);
    422	if (!drvdata)
    423		return -ENOMEM;
    424
    425	/* Populate data structure depending on compatibility */
    426	of_id = of_match_node(sti_sas_dev_match, pnode);
    427	if (!of_id->data) {
    428		dev_err(&pdev->dev, "data associated to device is missing\n");
    429		return -EINVAL;
    430	}
    431
    432	drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data;
    433
    434	/* Initialise device structure */
    435	drvdata->dev = &pdev->dev;
    436
    437	/* Request the DAC & SPDIF registers memory region */
    438	drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata,
    439						    drvdata->dev_data->regmap);
    440	if (IS_ERR(drvdata->dac.virt_regmap)) {
    441		dev_err(&pdev->dev, "audio registers not enabled\n");
    442		return PTR_ERR(drvdata->dac.virt_regmap);
    443	}
    444
    445	/* Request the syscon region */
    446	drvdata->dac.regmap =
    447		syscon_regmap_lookup_by_phandle(pnode, "st,syscfg");
    448	if (IS_ERR(drvdata->dac.regmap)) {
    449		dev_err(&pdev->dev, "syscon registers not available\n");
    450		return PTR_ERR(drvdata->dac.regmap);
    451	}
    452	drvdata->spdif.regmap = drvdata->dac.regmap;
    453
    454	sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops;
    455
    456	/* Set dapms*/
    457	sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets;
    458	sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets;
    459
    460	sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes;
    461	sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes;
    462
    463	/* Store context */
    464	dev_set_drvdata(&pdev->dev, drvdata);
    465
    466	return devm_snd_soc_register_component(&pdev->dev, &sti_sas_driver,
    467					sti_sas_dai,
    468					ARRAY_SIZE(sti_sas_dai));
    469}
    470
    471static struct platform_driver sti_sas_platform_driver = {
    472	.driver = {
    473		.name = "sti-sas-codec",
    474		.of_match_table = sti_sas_dev_match,
    475	},
    476	.probe = sti_sas_driver_probe,
    477};
    478
    479module_platform_driver(sti_sas_platform_driver);
    480
    481MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms");
    482MODULE_AUTHOR("Arnaud.pouliquen@st.com");
    483MODULE_LICENSE("GPL v2");