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

stm32_adfsdm.c (10710B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * This file is part of STM32 DFSDM ASoC DAI driver
      4 *
      5 * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
      6 * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com>
      7 *          Olivier Moysan <olivier.moysan@st.com>
      8 */
      9
     10#include <linux/clk.h>
     11#include <linux/module.h>
     12#include <linux/mutex.h>
     13#include <linux/platform_device.h>
     14#include <linux/slab.h>
     15#include <linux/pm_runtime.h>
     16#include <linux/iio/iio.h>
     17#include <linux/iio/consumer.h>
     18#include <linux/iio/adc/stm32-dfsdm-adc.h>
     19
     20#include <sound/pcm.h>
     21#include <sound/soc.h>
     22
     23#define STM32_ADFSDM_DRV_NAME "stm32-adfsdm"
     24
     25#define DFSDM_MAX_PERIOD_SIZE	(PAGE_SIZE / 2)
     26#define DFSDM_MAX_PERIODS	6
     27
     28struct stm32_adfsdm_priv {
     29	struct snd_soc_dai_driver dai_drv;
     30	struct snd_pcm_substream *substream;
     31	struct device *dev;
     32
     33	/* IIO */
     34	struct iio_channel *iio_ch;
     35	struct iio_cb_buffer *iio_cb;
     36	bool iio_active;
     37
     38	/* PCM buffer */
     39	unsigned char *pcm_buff;
     40	unsigned int pos;
     41
     42	struct mutex lock; /* protect against race condition on iio state */
     43};
     44
     45static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = {
     46	.info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER |
     47		SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE,
     48	.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE,
     49
     50	.channels_min = 1,
     51	.channels_max = 1,
     52
     53	.periods_min = 2,
     54	.periods_max = DFSDM_MAX_PERIODS,
     55
     56	.period_bytes_max = DFSDM_MAX_PERIOD_SIZE,
     57	.buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE
     58};
     59
     60static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream,
     61				  struct snd_soc_dai *dai)
     62{
     63	struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
     64
     65	mutex_lock(&priv->lock);
     66	if (priv->iio_active) {
     67		iio_channel_stop_all_cb(priv->iio_cb);
     68		priv->iio_active = false;
     69	}
     70	mutex_unlock(&priv->lock);
     71}
     72
     73static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream,
     74				    struct snd_soc_dai *dai)
     75{
     76	struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
     77	int ret;
     78
     79	mutex_lock(&priv->lock);
     80	if (priv->iio_active) {
     81		iio_channel_stop_all_cb(priv->iio_cb);
     82		priv->iio_active = false;
     83	}
     84
     85	ret = iio_write_channel_attribute(priv->iio_ch,
     86					  substream->runtime->rate, 0,
     87					  IIO_CHAN_INFO_SAMP_FREQ);
     88	if (ret < 0) {
     89		dev_err(dai->dev, "%s: Failed to set %d sampling rate\n",
     90			__func__, substream->runtime->rate);
     91		goto out;
     92	}
     93
     94	if (!priv->iio_active) {
     95		ret = iio_channel_start_all_cb(priv->iio_cb);
     96		if (!ret)
     97			priv->iio_active = true;
     98		else
     99			dev_err(dai->dev, "%s: IIO channel start failed (%d)\n",
    100				__func__, ret);
    101	}
    102
    103out:
    104	mutex_unlock(&priv->lock);
    105
    106	return ret;
    107}
    108
    109static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id,
    110				   unsigned int freq, int dir)
    111{
    112	struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai);
    113	ssize_t size;
    114	char str_freq[10];
    115
    116	dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq);
    117
    118	/* Set IIO frequency if CODEC is master as clock comes from SPI_IN */
    119
    120	snprintf(str_freq, sizeof(str_freq), "%u\n", freq);
    121	size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq",
    122					  str_freq, sizeof(str_freq));
    123	if (size != sizeof(str_freq)) {
    124		dev_err(dai->dev, "%s: Failed to set SPI clock\n",
    125			__func__);
    126		return -EINVAL;
    127	}
    128	return 0;
    129}
    130
    131static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = {
    132	.shutdown = stm32_adfsdm_shutdown,
    133	.prepare = stm32_adfsdm_dai_prepare,
    134	.set_sysclk = stm32_adfsdm_set_sysclk,
    135};
    136
    137static const struct snd_soc_dai_driver stm32_adfsdm_dai = {
    138	.capture = {
    139		    .channels_min = 1,
    140		    .channels_max = 1,
    141		    .formats = SNDRV_PCM_FMTBIT_S16_LE |
    142			       SNDRV_PCM_FMTBIT_S32_LE,
    143		    .rates = SNDRV_PCM_RATE_CONTINUOUS,
    144		    .rate_min = 8000,
    145		    .rate_max = 48000,
    146		    },
    147	.ops = &stm32_adfsdm_dai_ops,
    148};
    149
    150static const struct snd_soc_component_driver stm32_adfsdm_dai_component = {
    151	.name = "stm32_dfsdm_audio",
    152};
    153
    154static void stm32_memcpy_32to16(void *dest, const void *src, size_t n)
    155{
    156	unsigned int i = 0;
    157	u16 *d = (u16 *)dest, *s = (u16 *)src;
    158
    159	s++;
    160	for (i = n >> 1; i > 0; i--) {
    161		*d++ = *s++;
    162		s++;
    163	}
    164}
    165
    166static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private)
    167{
    168	struct stm32_adfsdm_priv *priv = private;
    169	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(priv->substream);
    170	u8 *pcm_buff = priv->pcm_buff;
    171	u8 *src_buff = (u8 *)data;
    172	unsigned int old_pos = priv->pos;
    173	size_t buff_size = snd_pcm_lib_buffer_bytes(priv->substream);
    174	size_t period_size = snd_pcm_lib_period_bytes(priv->substream);
    175	size_t cur_size, src_size = size;
    176	snd_pcm_format_t format = priv->substream->runtime->format;
    177
    178	if (format == SNDRV_PCM_FORMAT_S16_LE)
    179		src_size >>= 1;
    180	cur_size = src_size;
    181
    182	dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n",
    183		__func__, &pcm_buff[priv->pos], priv->pos, src_size);
    184
    185	if ((priv->pos + src_size) > buff_size) {
    186		if (format == SNDRV_PCM_FORMAT_S16_LE)
    187			stm32_memcpy_32to16(&pcm_buff[priv->pos], src_buff,
    188					    buff_size - priv->pos);
    189		else
    190			memcpy(&pcm_buff[priv->pos], src_buff,
    191			       buff_size - priv->pos);
    192		cur_size -= buff_size - priv->pos;
    193		priv->pos = 0;
    194	}
    195
    196	if (format == SNDRV_PCM_FORMAT_S16_LE)
    197		stm32_memcpy_32to16(&pcm_buff[priv->pos],
    198				    &src_buff[src_size - cur_size], cur_size);
    199	else
    200		memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size],
    201		       cur_size);
    202
    203	priv->pos = (priv->pos + cur_size) % buff_size;
    204
    205	if (cur_size != src_size || (old_pos && (old_pos % period_size < size)))
    206		snd_pcm_period_elapsed(priv->substream);
    207
    208	return 0;
    209}
    210
    211static int stm32_adfsdm_trigger(struct snd_soc_component *component,
    212				struct snd_pcm_substream *substream, int cmd)
    213{
    214	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    215	struct stm32_adfsdm_priv *priv =
    216		snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    217
    218	switch (cmd) {
    219	case SNDRV_PCM_TRIGGER_START:
    220	case SNDRV_PCM_TRIGGER_RESUME:
    221		priv->pos = 0;
    222		return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev,
    223					       stm32_afsdm_pcm_cb, priv);
    224	case SNDRV_PCM_TRIGGER_SUSPEND:
    225	case SNDRV_PCM_TRIGGER_STOP:
    226		return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev);
    227	}
    228
    229	return -EINVAL;
    230}
    231
    232static int stm32_adfsdm_pcm_open(struct snd_soc_component *component,
    233				 struct snd_pcm_substream *substream)
    234{
    235	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    236	struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    237	int ret;
    238
    239	ret =  snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw);
    240	if (!ret)
    241		priv->substream = substream;
    242
    243	return ret;
    244}
    245
    246static int stm32_adfsdm_pcm_close(struct snd_soc_component *component,
    247				  struct snd_pcm_substream *substream)
    248{
    249	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    250	struct stm32_adfsdm_priv *priv =
    251		snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    252
    253	priv->substream = NULL;
    254
    255	return 0;
    256}
    257
    258static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer(
    259					    struct snd_soc_component *component,
    260					    struct snd_pcm_substream *substream)
    261{
    262	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    263	struct stm32_adfsdm_priv *priv =
    264		snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    265
    266	return bytes_to_frames(substream->runtime, priv->pos);
    267}
    268
    269static int stm32_adfsdm_pcm_hw_params(struct snd_soc_component *component,
    270				      struct snd_pcm_substream *substream,
    271				      struct snd_pcm_hw_params *params)
    272{
    273	struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
    274	struct stm32_adfsdm_priv *priv =
    275		snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    276
    277	priv->pcm_buff = substream->runtime->dma_area;
    278
    279	return iio_channel_cb_set_buffer_watermark(priv->iio_cb,
    280						   params_period_size(params));
    281}
    282
    283static int stm32_adfsdm_pcm_new(struct snd_soc_component *component,
    284				struct snd_soc_pcm_runtime *rtd)
    285{
    286	struct snd_pcm *pcm = rtd->pcm;
    287	struct stm32_adfsdm_priv *priv =
    288		snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
    289	unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE;
    290
    291	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
    292				       priv->dev, size, size);
    293	return 0;
    294}
    295
    296static int stm32_adfsdm_dummy_cb(const void *data, void *private)
    297{
    298	/*
    299	 * This dummmy callback is requested by iio_channel_get_all_cb() API,
    300	 * but the stm32_dfsdm_get_buff_cb() API is used instead, to optimize
    301	 * DMA transfers.
    302	 */
    303	return 0;
    304}
    305
    306static struct snd_soc_component_driver stm32_adfsdm_soc_platform = {
    307	.open		= stm32_adfsdm_pcm_open,
    308	.close		= stm32_adfsdm_pcm_close,
    309	.hw_params	= stm32_adfsdm_pcm_hw_params,
    310	.trigger	= stm32_adfsdm_trigger,
    311	.pointer	= stm32_adfsdm_pcm_pointer,
    312	.pcm_construct	= stm32_adfsdm_pcm_new,
    313};
    314
    315static const struct of_device_id stm32_adfsdm_of_match[] = {
    316	{.compatible = "st,stm32h7-dfsdm-dai"},
    317	{}
    318};
    319MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match);
    320
    321static int stm32_adfsdm_probe(struct platform_device *pdev)
    322{
    323	struct stm32_adfsdm_priv *priv;
    324	struct snd_soc_component *component;
    325	int ret;
    326
    327	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    328	if (!priv)
    329		return -ENOMEM;
    330
    331	priv->dev = &pdev->dev;
    332	priv->dai_drv = stm32_adfsdm_dai;
    333	mutex_init(&priv->lock);
    334
    335	dev_set_drvdata(&pdev->dev, priv);
    336
    337	pm_runtime_enable(&pdev->dev);
    338
    339	ret = devm_snd_soc_register_component(&pdev->dev,
    340					      &stm32_adfsdm_dai_component,
    341					      &priv->dai_drv, 1);
    342	if (ret < 0)
    343		return ret;
    344
    345	/* Associate iio channel */
    346	priv->iio_ch  = devm_iio_channel_get_all(&pdev->dev);
    347	if (IS_ERR(priv->iio_ch))
    348		return PTR_ERR(priv->iio_ch);
    349
    350	priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, &stm32_adfsdm_dummy_cb, NULL);
    351	if (IS_ERR(priv->iio_cb))
    352		return PTR_ERR(priv->iio_cb);
    353
    354	component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL);
    355	if (!component)
    356		return -ENOMEM;
    357
    358	ret = snd_soc_component_initialize(component,
    359					   &stm32_adfsdm_soc_platform,
    360					   &pdev->dev);
    361	if (ret < 0)
    362		return ret;
    363#ifdef CONFIG_DEBUG_FS
    364	component->debugfs_prefix = "pcm";
    365#endif
    366
    367	ret = snd_soc_add_component(component, NULL, 0);
    368	if (ret < 0)
    369		dev_err(&pdev->dev, "%s: Failed to register PCM platform\n",
    370			__func__);
    371
    372	return ret;
    373}
    374
    375static int stm32_adfsdm_remove(struct platform_device *pdev)
    376{
    377	snd_soc_unregister_component(&pdev->dev);
    378	pm_runtime_disable(&pdev->dev);
    379
    380	return 0;
    381}
    382
    383static struct platform_driver stm32_adfsdm_driver = {
    384	.driver = {
    385		   .name = STM32_ADFSDM_DRV_NAME,
    386		   .of_match_table = stm32_adfsdm_of_match,
    387		   },
    388	.probe = stm32_adfsdm_probe,
    389	.remove = stm32_adfsdm_remove,
    390};
    391
    392module_platform_driver(stm32_adfsdm_driver);
    393
    394MODULE_DESCRIPTION("stm32 DFSDM DAI driver");
    395MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>");
    396MODULE_LICENSE("GPL v2");
    397MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME);