155da0948SArnaud Pouliquen // SPDX-License-Identifier: GPL-2.0 255da0948SArnaud Pouliquen /* 355da0948SArnaud Pouliquen * This file is part of STM32 DFSDM ASoC DAI driver 455da0948SArnaud Pouliquen * 555da0948SArnaud Pouliquen * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 655da0948SArnaud Pouliquen * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> 755da0948SArnaud Pouliquen * Olivier Moysan <olivier.moysan@st.com> 855da0948SArnaud Pouliquen */ 955da0948SArnaud Pouliquen 1055da0948SArnaud Pouliquen #include <linux/clk.h> 1155da0948SArnaud Pouliquen #include <linux/module.h> 1219441e35SOlivier Moysan #include <linux/mutex.h> 1355da0948SArnaud Pouliquen #include <linux/platform_device.h> 1455da0948SArnaud Pouliquen #include <linux/slab.h> 1555da0948SArnaud Pouliquen 1655da0948SArnaud Pouliquen #include <linux/iio/iio.h> 1755da0948SArnaud Pouliquen #include <linux/iio/consumer.h> 1855da0948SArnaud Pouliquen #include <linux/iio/adc/stm32-dfsdm-adc.h> 1955da0948SArnaud Pouliquen 2055da0948SArnaud Pouliquen #include <sound/pcm.h> 2155da0948SArnaud Pouliquen #include <sound/soc.h> 2255da0948SArnaud Pouliquen 2355da0948SArnaud Pouliquen #define STM32_ADFSDM_DRV_NAME "stm32-adfsdm" 2455da0948SArnaud Pouliquen 2555da0948SArnaud Pouliquen #define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2) 2655da0948SArnaud Pouliquen #define DFSDM_MAX_PERIODS 6 2755da0948SArnaud Pouliquen 2855da0948SArnaud Pouliquen struct stm32_adfsdm_priv { 2955da0948SArnaud Pouliquen struct snd_soc_dai_driver dai_drv; 3055da0948SArnaud Pouliquen struct snd_pcm_substream *substream; 3155da0948SArnaud Pouliquen struct device *dev; 3255da0948SArnaud Pouliquen 3355da0948SArnaud Pouliquen /* IIO */ 3455da0948SArnaud Pouliquen struct iio_channel *iio_ch; 3555da0948SArnaud Pouliquen struct iio_cb_buffer *iio_cb; 3655da0948SArnaud Pouliquen bool iio_active; 3755da0948SArnaud Pouliquen 3855da0948SArnaud Pouliquen /* PCM buffer */ 3955da0948SArnaud Pouliquen unsigned char *pcm_buff; 4055da0948SArnaud Pouliquen unsigned int pos; 4119441e35SOlivier Moysan 4219441e35SOlivier Moysan struct mutex lock; /* protect against race condition on iio state */ 4355da0948SArnaud Pouliquen }; 4455da0948SArnaud Pouliquen 4555da0948SArnaud Pouliquen static const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = { 4655da0948SArnaud Pouliquen .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 47d151cf89SOlivier Moysan SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE, 481e7f6e1cSOlivier Moysan .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 4955da0948SArnaud Pouliquen 5055da0948SArnaud Pouliquen .rate_min = 8000, 5155da0948SArnaud Pouliquen .rate_max = 32000, 5255da0948SArnaud Pouliquen 5355da0948SArnaud Pouliquen .channels_min = 1, 5455da0948SArnaud Pouliquen .channels_max = 1, 5555da0948SArnaud Pouliquen 5655da0948SArnaud Pouliquen .periods_min = 2, 5755da0948SArnaud Pouliquen .periods_max = DFSDM_MAX_PERIODS, 5855da0948SArnaud Pouliquen 5955da0948SArnaud Pouliquen .period_bytes_max = DFSDM_MAX_PERIOD_SIZE, 6055da0948SArnaud Pouliquen .buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE 6155da0948SArnaud Pouliquen }; 6255da0948SArnaud Pouliquen 6355da0948SArnaud Pouliquen static void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream, 6455da0948SArnaud Pouliquen struct snd_soc_dai *dai) 6555da0948SArnaud Pouliquen { 6655da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); 6755da0948SArnaud Pouliquen 6819441e35SOlivier Moysan mutex_lock(&priv->lock); 6955da0948SArnaud Pouliquen if (priv->iio_active) { 7055da0948SArnaud Pouliquen iio_channel_stop_all_cb(priv->iio_cb); 7155da0948SArnaud Pouliquen priv->iio_active = false; 7255da0948SArnaud Pouliquen } 7319441e35SOlivier Moysan mutex_unlock(&priv->lock); 7455da0948SArnaud Pouliquen } 7555da0948SArnaud Pouliquen 7655da0948SArnaud Pouliquen static int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, 7755da0948SArnaud Pouliquen struct snd_soc_dai *dai) 7855da0948SArnaud Pouliquen { 7955da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); 8055da0948SArnaud Pouliquen int ret; 8155da0948SArnaud Pouliquen 8219441e35SOlivier Moysan mutex_lock(&priv->lock); 8319441e35SOlivier Moysan if (priv->iio_active) { 8419441e35SOlivier Moysan iio_channel_stop_all_cb(priv->iio_cb); 8519441e35SOlivier Moysan priv->iio_active = false; 8619441e35SOlivier Moysan } 8719441e35SOlivier Moysan 8855da0948SArnaud Pouliquen ret = iio_write_channel_attribute(priv->iio_ch, 8955da0948SArnaud Pouliquen substream->runtime->rate, 0, 9055da0948SArnaud Pouliquen IIO_CHAN_INFO_SAMP_FREQ); 9155da0948SArnaud Pouliquen if (ret < 0) { 9255da0948SArnaud Pouliquen dev_err(dai->dev, "%s: Failed to set %d sampling rate\n", 9355da0948SArnaud Pouliquen __func__, substream->runtime->rate); 9419441e35SOlivier Moysan goto out; 9555da0948SArnaud Pouliquen } 9655da0948SArnaud Pouliquen 9755da0948SArnaud Pouliquen if (!priv->iio_active) { 9855da0948SArnaud Pouliquen ret = iio_channel_start_all_cb(priv->iio_cb); 9955da0948SArnaud Pouliquen if (!ret) 10055da0948SArnaud Pouliquen priv->iio_active = true; 10155da0948SArnaud Pouliquen else 10255da0948SArnaud Pouliquen dev_err(dai->dev, "%s: IIO channel start failed (%d)\n", 10355da0948SArnaud Pouliquen __func__, ret); 10455da0948SArnaud Pouliquen } 10555da0948SArnaud Pouliquen 10619441e35SOlivier Moysan out: 10719441e35SOlivier Moysan mutex_unlock(&priv->lock); 10819441e35SOlivier Moysan 10955da0948SArnaud Pouliquen return ret; 11055da0948SArnaud Pouliquen } 11155da0948SArnaud Pouliquen 11255da0948SArnaud Pouliquen static int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id, 11355da0948SArnaud Pouliquen unsigned int freq, int dir) 11455da0948SArnaud Pouliquen { 11555da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); 11655da0948SArnaud Pouliquen ssize_t size; 11755da0948SArnaud Pouliquen char str_freq[10]; 11855da0948SArnaud Pouliquen 11955da0948SArnaud Pouliquen dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq); 12055da0948SArnaud Pouliquen 12155da0948SArnaud Pouliquen /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */ 12255da0948SArnaud Pouliquen 12355da0948SArnaud Pouliquen snprintf(str_freq, sizeof(str_freq), "%d\n", freq); 12455da0948SArnaud Pouliquen size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq", 12555da0948SArnaud Pouliquen str_freq, sizeof(str_freq)); 12655da0948SArnaud Pouliquen if (size != sizeof(str_freq)) { 12755da0948SArnaud Pouliquen dev_err(dai->dev, "%s: Failed to set SPI clock\n", 12855da0948SArnaud Pouliquen __func__); 12955da0948SArnaud Pouliquen return -EINVAL; 13055da0948SArnaud Pouliquen } 13155da0948SArnaud Pouliquen return 0; 13255da0948SArnaud Pouliquen } 13355da0948SArnaud Pouliquen 13455da0948SArnaud Pouliquen static const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = { 13555da0948SArnaud Pouliquen .shutdown = stm32_adfsdm_shutdown, 13655da0948SArnaud Pouliquen .prepare = stm32_adfsdm_dai_prepare, 13755da0948SArnaud Pouliquen .set_sysclk = stm32_adfsdm_set_sysclk, 13855da0948SArnaud Pouliquen }; 13955da0948SArnaud Pouliquen 14055da0948SArnaud Pouliquen static const struct snd_soc_dai_driver stm32_adfsdm_dai = { 14155da0948SArnaud Pouliquen .capture = { 14255da0948SArnaud Pouliquen .channels_min = 1, 14355da0948SArnaud Pouliquen .channels_max = 1, 1441e7f6e1cSOlivier Moysan .formats = SNDRV_PCM_FMTBIT_S16_LE | 1451e7f6e1cSOlivier Moysan SNDRV_PCM_FMTBIT_S32_LE, 14655da0948SArnaud Pouliquen .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | 14755da0948SArnaud Pouliquen SNDRV_PCM_RATE_32000), 14855da0948SArnaud Pouliquen }, 14955da0948SArnaud Pouliquen .ops = &stm32_adfsdm_dai_ops, 15055da0948SArnaud Pouliquen }; 15155da0948SArnaud Pouliquen 15255da0948SArnaud Pouliquen static const struct snd_soc_component_driver stm32_adfsdm_dai_component = { 15355da0948SArnaud Pouliquen .name = "stm32_dfsdm_audio", 15455da0948SArnaud Pouliquen }; 15555da0948SArnaud Pouliquen 1561e7f6e1cSOlivier Moysan static void memcpy_32to16(void *dest, const void *src, size_t n) 1571e7f6e1cSOlivier Moysan { 1581e7f6e1cSOlivier Moysan unsigned int i = 0; 1591e7f6e1cSOlivier Moysan u16 *d = (u16 *)dest, *s = (u16 *)src; 1601e7f6e1cSOlivier Moysan 1611e7f6e1cSOlivier Moysan s++; 1621e7f6e1cSOlivier Moysan for (i = n; i > 0; i--) { 1631e7f6e1cSOlivier Moysan *d++ = *s++; 1641e7f6e1cSOlivier Moysan s++; 1651e7f6e1cSOlivier Moysan } 1661e7f6e1cSOlivier Moysan } 1671e7f6e1cSOlivier Moysan 16855da0948SArnaud Pouliquen static int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private) 16955da0948SArnaud Pouliquen { 17055da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = private; 17155da0948SArnaud Pouliquen struct snd_soc_pcm_runtime *rtd = priv->substream->private_data; 17255da0948SArnaud Pouliquen u8 *pcm_buff = priv->pcm_buff; 17355da0948SArnaud Pouliquen u8 *src_buff = (u8 *)data; 17455da0948SArnaud Pouliquen unsigned int old_pos = priv->pos; 1751e7f6e1cSOlivier Moysan size_t buff_size = snd_pcm_lib_buffer_bytes(priv->substream); 1761e7f6e1cSOlivier Moysan size_t period_size = snd_pcm_lib_period_bytes(priv->substream); 1771e7f6e1cSOlivier Moysan size_t cur_size, src_size = size; 1781e7f6e1cSOlivier Moysan snd_pcm_format_t format = priv->substream->runtime->format; 1791e7f6e1cSOlivier Moysan 1801e7f6e1cSOlivier Moysan if (format == SNDRV_PCM_FORMAT_S16_LE) 1811e7f6e1cSOlivier Moysan src_size >>= 1; 1821e7f6e1cSOlivier Moysan cur_size = src_size; 18355da0948SArnaud Pouliquen 1848db339d6Sbenjamin.gaignard@linaro.org dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n", 1851e7f6e1cSOlivier Moysan __func__, &pcm_buff[priv->pos], priv->pos, src_size); 18655da0948SArnaud Pouliquen 1871e7f6e1cSOlivier Moysan if ((priv->pos + src_size) > buff_size) { 1881e7f6e1cSOlivier Moysan if (format == SNDRV_PCM_FORMAT_S16_LE) 1891e7f6e1cSOlivier Moysan memcpy_32to16(&pcm_buff[priv->pos], src_buff, 1901e7f6e1cSOlivier Moysan buff_size - priv->pos); 1911e7f6e1cSOlivier Moysan else 1921e7f6e1cSOlivier Moysan memcpy(&pcm_buff[priv->pos], src_buff, 1931e7f6e1cSOlivier Moysan buff_size - priv->pos); 19455da0948SArnaud Pouliquen cur_size -= buff_size - priv->pos; 19555da0948SArnaud Pouliquen priv->pos = 0; 19655da0948SArnaud Pouliquen } 19755da0948SArnaud Pouliquen 1981e7f6e1cSOlivier Moysan if (format == SNDRV_PCM_FORMAT_S16_LE) 1991e7f6e1cSOlivier Moysan memcpy_32to16(&pcm_buff[priv->pos], 2001e7f6e1cSOlivier Moysan &src_buff[src_size - cur_size], cur_size); 2011e7f6e1cSOlivier Moysan else 2021e7f6e1cSOlivier Moysan memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size], 2031e7f6e1cSOlivier Moysan cur_size); 2041e7f6e1cSOlivier Moysan 20555da0948SArnaud Pouliquen priv->pos = (priv->pos + cur_size) % buff_size; 20655da0948SArnaud Pouliquen 2071e7f6e1cSOlivier Moysan if (cur_size != src_size || (old_pos && (old_pos % period_size < size))) 20855da0948SArnaud Pouliquen snd_pcm_period_elapsed(priv->substream); 20955da0948SArnaud Pouliquen 21055da0948SArnaud Pouliquen return 0; 21155da0948SArnaud Pouliquen } 21255da0948SArnaud Pouliquen 21321499089SKuninori Morimoto static int stm32_adfsdm_trigger(struct snd_soc_component *component, 21421499089SKuninori Morimoto struct snd_pcm_substream *substream, int cmd) 21555da0948SArnaud Pouliquen { 21655da0948SArnaud Pouliquen struct snd_soc_pcm_runtime *rtd = substream->private_data; 21755da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = 21855da0948SArnaud Pouliquen snd_soc_dai_get_drvdata(rtd->cpu_dai); 21955da0948SArnaud Pouliquen 22055da0948SArnaud Pouliquen switch (cmd) { 22155da0948SArnaud Pouliquen case SNDRV_PCM_TRIGGER_START: 22255da0948SArnaud Pouliquen case SNDRV_PCM_TRIGGER_RESUME: 22355da0948SArnaud Pouliquen priv->pos = 0; 22455da0948SArnaud Pouliquen return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev, 22555da0948SArnaud Pouliquen stm32_afsdm_pcm_cb, priv); 22655da0948SArnaud Pouliquen case SNDRV_PCM_TRIGGER_SUSPEND: 22755da0948SArnaud Pouliquen case SNDRV_PCM_TRIGGER_STOP: 22855da0948SArnaud Pouliquen return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev); 22955da0948SArnaud Pouliquen } 23055da0948SArnaud Pouliquen 23155da0948SArnaud Pouliquen return -EINVAL; 23255da0948SArnaud Pouliquen } 23355da0948SArnaud Pouliquen 23421499089SKuninori Morimoto static int stm32_adfsdm_pcm_open(struct snd_soc_component *component, 23521499089SKuninori Morimoto struct snd_pcm_substream *substream) 23655da0948SArnaud Pouliquen { 23755da0948SArnaud Pouliquen struct snd_soc_pcm_runtime *rtd = substream->private_data; 23855da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); 23955da0948SArnaud Pouliquen int ret; 24055da0948SArnaud Pouliquen 24155da0948SArnaud Pouliquen ret = snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw); 24255da0948SArnaud Pouliquen if (!ret) 24355da0948SArnaud Pouliquen priv->substream = substream; 24455da0948SArnaud Pouliquen 24555da0948SArnaud Pouliquen return ret; 24655da0948SArnaud Pouliquen } 24755da0948SArnaud Pouliquen 24821499089SKuninori Morimoto static int stm32_adfsdm_pcm_close(struct snd_soc_component *component, 24921499089SKuninori Morimoto struct snd_pcm_substream *substream) 25055da0948SArnaud Pouliquen { 25155da0948SArnaud Pouliquen struct snd_soc_pcm_runtime *rtd = substream->private_data; 25255da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = 25355da0948SArnaud Pouliquen snd_soc_dai_get_drvdata(rtd->cpu_dai); 25455da0948SArnaud Pouliquen 25555da0948SArnaud Pouliquen snd_pcm_lib_free_pages(substream); 25655da0948SArnaud Pouliquen priv->substream = NULL; 25755da0948SArnaud Pouliquen 25855da0948SArnaud Pouliquen return 0; 25955da0948SArnaud Pouliquen } 26055da0948SArnaud Pouliquen 26155da0948SArnaud Pouliquen static snd_pcm_uframes_t stm32_adfsdm_pcm_pointer( 26221499089SKuninori Morimoto struct snd_soc_component *component, 26355da0948SArnaud Pouliquen struct snd_pcm_substream *substream) 26455da0948SArnaud Pouliquen { 26555da0948SArnaud Pouliquen struct snd_soc_pcm_runtime *rtd = substream->private_data; 26655da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = 26755da0948SArnaud Pouliquen snd_soc_dai_get_drvdata(rtd->cpu_dai); 26855da0948SArnaud Pouliquen 26955da0948SArnaud Pouliquen return bytes_to_frames(substream->runtime, priv->pos); 27055da0948SArnaud Pouliquen } 27155da0948SArnaud Pouliquen 27221499089SKuninori Morimoto static int stm32_adfsdm_pcm_hw_params(struct snd_soc_component *component, 27321499089SKuninori Morimoto struct snd_pcm_substream *substream, 27455da0948SArnaud Pouliquen struct snd_pcm_hw_params *params) 27555da0948SArnaud Pouliquen { 27655da0948SArnaud Pouliquen struct snd_soc_pcm_runtime *rtd = substream->private_data; 27755da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = 27855da0948SArnaud Pouliquen snd_soc_dai_get_drvdata(rtd->cpu_dai); 27955da0948SArnaud Pouliquen int ret; 28055da0948SArnaud Pouliquen 28155da0948SArnaud Pouliquen ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); 28255da0948SArnaud Pouliquen if (ret < 0) 28355da0948SArnaud Pouliquen return ret; 28455da0948SArnaud Pouliquen priv->pcm_buff = substream->runtime->dma_area; 28555da0948SArnaud Pouliquen 28655da0948SArnaud Pouliquen return iio_channel_cb_set_buffer_watermark(priv->iio_cb, 28755da0948SArnaud Pouliquen params_period_size(params)); 28855da0948SArnaud Pouliquen } 28955da0948SArnaud Pouliquen 29021499089SKuninori Morimoto static int stm32_adfsdm_pcm_hw_free(struct snd_soc_component *component, 29121499089SKuninori Morimoto struct snd_pcm_substream *substream) 29255da0948SArnaud Pouliquen { 29355da0948SArnaud Pouliquen snd_pcm_lib_free_pages(substream); 29455da0948SArnaud Pouliquen 29555da0948SArnaud Pouliquen return 0; 29655da0948SArnaud Pouliquen } 29755da0948SArnaud Pouliquen 29821499089SKuninori Morimoto static int stm32_adfsdm_pcm_new(struct snd_soc_component *component, 29921499089SKuninori Morimoto struct snd_soc_pcm_runtime *rtd) 30055da0948SArnaud Pouliquen { 30155da0948SArnaud Pouliquen struct snd_pcm *pcm = rtd->pcm; 30255da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv = 30355da0948SArnaud Pouliquen snd_soc_dai_get_drvdata(rtd->cpu_dai); 30455da0948SArnaud Pouliquen unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE; 30555da0948SArnaud Pouliquen 30618183edaSTakashi Iwai snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, 30755da0948SArnaud Pouliquen priv->dev, size, size); 30818183edaSTakashi Iwai return 0; 30955da0948SArnaud Pouliquen } 31055da0948SArnaud Pouliquen 31121499089SKuninori Morimoto static void stm32_adfsdm_pcm_free(struct snd_soc_component *component, 31221499089SKuninori Morimoto struct snd_pcm *pcm) 31355da0948SArnaud Pouliquen { 31455da0948SArnaud Pouliquen struct snd_pcm_substream *substream; 31555da0948SArnaud Pouliquen 31655da0948SArnaud Pouliquen substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; 31718127744SColin Ian King if (substream) 31855da0948SArnaud Pouliquen snd_pcm_lib_preallocate_free_for_all(pcm); 31955da0948SArnaud Pouliquen } 32055da0948SArnaud Pouliquen 32166bf428eSKuninori Morimoto static struct snd_soc_component_driver stm32_adfsdm_soc_platform = { 32221499089SKuninori Morimoto .open = stm32_adfsdm_pcm_open, 32321499089SKuninori Morimoto .close = stm32_adfsdm_pcm_close, 32421499089SKuninori Morimoto .hw_params = stm32_adfsdm_pcm_hw_params, 32521499089SKuninori Morimoto .hw_free = stm32_adfsdm_pcm_hw_free, 32621499089SKuninori Morimoto .trigger = stm32_adfsdm_trigger, 32721499089SKuninori Morimoto .pointer = stm32_adfsdm_pcm_pointer, 32821499089SKuninori Morimoto .pcm_construct = stm32_adfsdm_pcm_new, 32921499089SKuninori Morimoto .pcm_destruct = stm32_adfsdm_pcm_free, 33055da0948SArnaud Pouliquen }; 33155da0948SArnaud Pouliquen 33255da0948SArnaud Pouliquen static const struct of_device_id stm32_adfsdm_of_match[] = { 33355da0948SArnaud Pouliquen {.compatible = "st,stm32h7-dfsdm-dai"}, 33455da0948SArnaud Pouliquen {} 33555da0948SArnaud Pouliquen }; 33655da0948SArnaud Pouliquen MODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match); 33755da0948SArnaud Pouliquen 33855da0948SArnaud Pouliquen static int stm32_adfsdm_probe(struct platform_device *pdev) 33955da0948SArnaud Pouliquen { 34055da0948SArnaud Pouliquen struct stm32_adfsdm_priv *priv; 341c47255b6SOlivier Moysan struct snd_soc_component *component; 34255da0948SArnaud Pouliquen int ret; 34355da0948SArnaud Pouliquen 34455da0948SArnaud Pouliquen priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 34555da0948SArnaud Pouliquen if (!priv) 34655da0948SArnaud Pouliquen return -ENOMEM; 34755da0948SArnaud Pouliquen 34855da0948SArnaud Pouliquen priv->dev = &pdev->dev; 34955da0948SArnaud Pouliquen priv->dai_drv = stm32_adfsdm_dai; 35019441e35SOlivier Moysan mutex_init(&priv->lock); 35155da0948SArnaud Pouliquen 35255da0948SArnaud Pouliquen dev_set_drvdata(&pdev->dev, priv); 35355da0948SArnaud Pouliquen 35455da0948SArnaud Pouliquen ret = devm_snd_soc_register_component(&pdev->dev, 35555da0948SArnaud Pouliquen &stm32_adfsdm_dai_component, 35655da0948SArnaud Pouliquen &priv->dai_drv, 1); 35755da0948SArnaud Pouliquen if (ret < 0) 35855da0948SArnaud Pouliquen return ret; 35955da0948SArnaud Pouliquen 36055da0948SArnaud Pouliquen /* Associate iio channel */ 36155da0948SArnaud Pouliquen priv->iio_ch = devm_iio_channel_get_all(&pdev->dev); 36255da0948SArnaud Pouliquen if (IS_ERR(priv->iio_ch)) 36355da0948SArnaud Pouliquen return PTR_ERR(priv->iio_ch); 36455da0948SArnaud Pouliquen 36555da0948SArnaud Pouliquen priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL); 36655da0948SArnaud Pouliquen if (IS_ERR(priv->iio_cb)) 3676dee6722SWei Yongjun return PTR_ERR(priv->iio_cb); 36855da0948SArnaud Pouliquen 369c47255b6SOlivier Moysan component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL); 370c47255b6SOlivier Moysan if (!component) 371c47255b6SOlivier Moysan return -ENOMEM; 372c47255b6SOlivier Moysan #ifdef CONFIG_DEBUG_FS 373c47255b6SOlivier Moysan component->debugfs_prefix = "pcm"; 374c47255b6SOlivier Moysan #endif 375c47255b6SOlivier Moysan 376c47255b6SOlivier Moysan ret = snd_soc_add_component(&pdev->dev, component, 377c47255b6SOlivier Moysan &stm32_adfsdm_soc_platform, NULL, 0); 37855da0948SArnaud Pouliquen if (ret < 0) 37955da0948SArnaud Pouliquen dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", 38055da0948SArnaud Pouliquen __func__); 38155da0948SArnaud Pouliquen 38255da0948SArnaud Pouliquen return ret; 38355da0948SArnaud Pouliquen } 38455da0948SArnaud Pouliquen 385c47255b6SOlivier Moysan static int stm32_adfsdm_remove(struct platform_device *pdev) 386c47255b6SOlivier Moysan { 387c47255b6SOlivier Moysan snd_soc_unregister_component(&pdev->dev); 388c47255b6SOlivier Moysan 389c47255b6SOlivier Moysan return 0; 390c47255b6SOlivier Moysan } 391c47255b6SOlivier Moysan 39255da0948SArnaud Pouliquen static struct platform_driver stm32_adfsdm_driver = { 39355da0948SArnaud Pouliquen .driver = { 39455da0948SArnaud Pouliquen .name = STM32_ADFSDM_DRV_NAME, 39555da0948SArnaud Pouliquen .of_match_table = stm32_adfsdm_of_match, 39655da0948SArnaud Pouliquen }, 39755da0948SArnaud Pouliquen .probe = stm32_adfsdm_probe, 398c47255b6SOlivier Moysan .remove = stm32_adfsdm_remove, 39955da0948SArnaud Pouliquen }; 40055da0948SArnaud Pouliquen 40155da0948SArnaud Pouliquen module_platform_driver(stm32_adfsdm_driver); 40255da0948SArnaud Pouliquen 40355da0948SArnaud Pouliquen MODULE_DESCRIPTION("stm32 DFSDM DAI driver"); 40455da0948SArnaud Pouliquen MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); 40555da0948SArnaud Pouliquen MODULE_LICENSE("GPL v2"); 40655da0948SArnaud Pouliquen MODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME); 407