18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * This file is part of STM32 DFSDM ASoC DAI driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 68c2ecf20Sopenharmony_ci * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> 78c2ecf20Sopenharmony_ci * Olivier Moysan <olivier.moysan@st.com> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/mutex.h> 138c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/iio/iio.h> 178c2ecf20Sopenharmony_ci#include <linux/iio/consumer.h> 188c2ecf20Sopenharmony_ci#include <linux/iio/adc/stm32-dfsdm-adc.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include <sound/pcm.h> 218c2ecf20Sopenharmony_ci#include <sound/soc.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define STM32_ADFSDM_DRV_NAME "stm32-adfsdm" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define DFSDM_MAX_PERIOD_SIZE (PAGE_SIZE / 2) 268c2ecf20Sopenharmony_ci#define DFSDM_MAX_PERIODS 6 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct stm32_adfsdm_priv { 298c2ecf20Sopenharmony_ci struct snd_soc_dai_driver dai_drv; 308c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 318c2ecf20Sopenharmony_ci struct device *dev; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci /* IIO */ 348c2ecf20Sopenharmony_ci struct iio_channel *iio_ch; 358c2ecf20Sopenharmony_ci struct iio_cb_buffer *iio_cb; 368c2ecf20Sopenharmony_ci bool iio_active; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci /* PCM buffer */ 398c2ecf20Sopenharmony_ci unsigned char *pcm_buff; 408c2ecf20Sopenharmony_ci unsigned int pos; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci struct mutex lock; /* protect against race condition on iio state */ 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware stm32_adfsdm_pcm_hw = { 468c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | 478c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_PAUSE, 488c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE, 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci .channels_min = 1, 518c2ecf20Sopenharmony_ci .channels_max = 1, 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci .periods_min = 2, 548c2ecf20Sopenharmony_ci .periods_max = DFSDM_MAX_PERIODS, 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci .period_bytes_max = DFSDM_MAX_PERIOD_SIZE, 578c2ecf20Sopenharmony_ci .buffer_bytes_max = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistatic void stm32_adfsdm_shutdown(struct snd_pcm_substream *substream, 618c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 668c2ecf20Sopenharmony_ci if (priv->iio_active) { 678c2ecf20Sopenharmony_ci iio_channel_stop_all_cb(priv->iio_cb); 688c2ecf20Sopenharmony_ci priv->iio_active = false; 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int stm32_adfsdm_dai_prepare(struct snd_pcm_substream *substream, 748c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 758c2ecf20Sopenharmony_ci{ 768c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); 778c2ecf20Sopenharmony_ci int ret; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci mutex_lock(&priv->lock); 808c2ecf20Sopenharmony_ci if (priv->iio_active) { 818c2ecf20Sopenharmony_ci iio_channel_stop_all_cb(priv->iio_cb); 828c2ecf20Sopenharmony_ci priv->iio_active = false; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci ret = iio_write_channel_attribute(priv->iio_ch, 868c2ecf20Sopenharmony_ci substream->runtime->rate, 0, 878c2ecf20Sopenharmony_ci IIO_CHAN_INFO_SAMP_FREQ); 888c2ecf20Sopenharmony_ci if (ret < 0) { 898c2ecf20Sopenharmony_ci dev_err(dai->dev, "%s: Failed to set %d sampling rate\n", 908c2ecf20Sopenharmony_ci __func__, substream->runtime->rate); 918c2ecf20Sopenharmony_ci goto out; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (!priv->iio_active) { 958c2ecf20Sopenharmony_ci ret = iio_channel_start_all_cb(priv->iio_cb); 968c2ecf20Sopenharmony_ci if (!ret) 978c2ecf20Sopenharmony_ci priv->iio_active = true; 988c2ecf20Sopenharmony_ci else 998c2ecf20Sopenharmony_ci dev_err(dai->dev, "%s: IIO channel start failed (%d)\n", 1008c2ecf20Sopenharmony_ci __func__, ret); 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ciout: 1048c2ecf20Sopenharmony_ci mutex_unlock(&priv->lock); 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci return ret; 1078c2ecf20Sopenharmony_ci} 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_cistatic int stm32_adfsdm_set_sysclk(struct snd_soc_dai *dai, int clk_id, 1108c2ecf20Sopenharmony_ci unsigned int freq, int dir) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(dai); 1138c2ecf20Sopenharmony_ci ssize_t size; 1148c2ecf20Sopenharmony_ci char str_freq[10]; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci dev_dbg(dai->dev, "%s: Enter for freq %d\n", __func__, freq); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* Set IIO frequency if CODEC is master as clock comes from SPI_IN */ 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci snprintf(str_freq, sizeof(str_freq), "%d\n", freq); 1218c2ecf20Sopenharmony_ci size = iio_write_channel_ext_info(priv->iio_ch, "spi_clk_freq", 1228c2ecf20Sopenharmony_ci str_freq, sizeof(str_freq)); 1238c2ecf20Sopenharmony_ci if (size != sizeof(str_freq)) { 1248c2ecf20Sopenharmony_ci dev_err(dai->dev, "%s: Failed to set SPI clock\n", 1258c2ecf20Sopenharmony_ci __func__); 1268c2ecf20Sopenharmony_ci return -EINVAL; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops stm32_adfsdm_dai_ops = { 1328c2ecf20Sopenharmony_ci .shutdown = stm32_adfsdm_shutdown, 1338c2ecf20Sopenharmony_ci .prepare = stm32_adfsdm_dai_prepare, 1348c2ecf20Sopenharmony_ci .set_sysclk = stm32_adfsdm_set_sysclk, 1358c2ecf20Sopenharmony_ci}; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_driver stm32_adfsdm_dai = { 1388c2ecf20Sopenharmony_ci .capture = { 1398c2ecf20Sopenharmony_ci .channels_min = 1, 1408c2ecf20Sopenharmony_ci .channels_max = 1, 1418c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | 1428c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE, 1438c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_CONTINUOUS, 1448c2ecf20Sopenharmony_ci .rate_min = 8000, 1458c2ecf20Sopenharmony_ci .rate_max = 48000, 1468c2ecf20Sopenharmony_ci }, 1478c2ecf20Sopenharmony_ci .ops = &stm32_adfsdm_dai_ops, 1488c2ecf20Sopenharmony_ci}; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver stm32_adfsdm_dai_component = { 1518c2ecf20Sopenharmony_ci .name = "stm32_dfsdm_audio", 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic void stm32_memcpy_32to16(void *dest, const void *src, size_t n) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci unsigned int i = 0; 1578c2ecf20Sopenharmony_ci u16 *d = (u16 *)dest, *s = (u16 *)src; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci s++; 1608c2ecf20Sopenharmony_ci for (i = n >> 1; i > 0; i--) { 1618c2ecf20Sopenharmony_ci *d++ = *s++; 1628c2ecf20Sopenharmony_ci s++; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int stm32_afsdm_pcm_cb(const void *data, size_t size, void *private) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = private; 1698c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(priv->substream); 1708c2ecf20Sopenharmony_ci u8 *pcm_buff = priv->pcm_buff; 1718c2ecf20Sopenharmony_ci u8 *src_buff = (u8 *)data; 1728c2ecf20Sopenharmony_ci unsigned int old_pos = priv->pos; 1738c2ecf20Sopenharmony_ci size_t buff_size = snd_pcm_lib_buffer_bytes(priv->substream); 1748c2ecf20Sopenharmony_ci size_t period_size = snd_pcm_lib_period_bytes(priv->substream); 1758c2ecf20Sopenharmony_ci size_t cur_size, src_size = size; 1768c2ecf20Sopenharmony_ci snd_pcm_format_t format = priv->substream->runtime->format; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (format == SNDRV_PCM_FORMAT_S16_LE) 1798c2ecf20Sopenharmony_ci src_size >>= 1; 1808c2ecf20Sopenharmony_ci cur_size = src_size; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci dev_dbg(rtd->dev, "%s: buff_add :%pK, pos = %d, size = %zu\n", 1838c2ecf20Sopenharmony_ci __func__, &pcm_buff[priv->pos], priv->pos, src_size); 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci if ((priv->pos + src_size) > buff_size) { 1868c2ecf20Sopenharmony_ci if (format == SNDRV_PCM_FORMAT_S16_LE) 1878c2ecf20Sopenharmony_ci stm32_memcpy_32to16(&pcm_buff[priv->pos], src_buff, 1888c2ecf20Sopenharmony_ci buff_size - priv->pos); 1898c2ecf20Sopenharmony_ci else 1908c2ecf20Sopenharmony_ci memcpy(&pcm_buff[priv->pos], src_buff, 1918c2ecf20Sopenharmony_ci buff_size - priv->pos); 1928c2ecf20Sopenharmony_ci cur_size -= buff_size - priv->pos; 1938c2ecf20Sopenharmony_ci priv->pos = 0; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (format == SNDRV_PCM_FORMAT_S16_LE) 1978c2ecf20Sopenharmony_ci stm32_memcpy_32to16(&pcm_buff[priv->pos], 1988c2ecf20Sopenharmony_ci &src_buff[src_size - cur_size], cur_size); 1998c2ecf20Sopenharmony_ci else 2008c2ecf20Sopenharmony_ci memcpy(&pcm_buff[priv->pos], &src_buff[src_size - cur_size], 2018c2ecf20Sopenharmony_ci cur_size); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci priv->pos = (priv->pos + cur_size) % buff_size; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci if (cur_size != src_size || (old_pos && (old_pos % period_size < size))) 2068c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(priv->substream); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci return 0; 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int stm32_adfsdm_trigger(struct snd_soc_component *component, 2128c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, int cmd) 2138c2ecf20Sopenharmony_ci{ 2148c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2158c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = 2168c2ecf20Sopenharmony_ci snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci switch (cmd) { 2198c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2208c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2218c2ecf20Sopenharmony_ci priv->pos = 0; 2228c2ecf20Sopenharmony_ci return stm32_dfsdm_get_buff_cb(priv->iio_ch->indio_dev, 2238c2ecf20Sopenharmony_ci stm32_afsdm_pcm_cb, priv); 2248c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 2258c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2268c2ecf20Sopenharmony_ci return stm32_dfsdm_release_buff_cb(priv->iio_ch->indio_dev); 2278c2ecf20Sopenharmony_ci } 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return -EINVAL; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int stm32_adfsdm_pcm_open(struct snd_soc_component *component, 2338c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2368c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 2378c2ecf20Sopenharmony_ci int ret; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci ret = snd_soc_set_runtime_hwparams(substream, &stm32_adfsdm_pcm_hw); 2408c2ecf20Sopenharmony_ci if (!ret) 2418c2ecf20Sopenharmony_ci priv->substream = substream; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci return ret; 2448c2ecf20Sopenharmony_ci} 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_cistatic int stm32_adfsdm_pcm_close(struct snd_soc_component *component, 2478c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2508c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = 2518c2ecf20Sopenharmony_ci snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci priv->substream = NULL; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci return 0; 2568c2ecf20Sopenharmony_ci} 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t stm32_adfsdm_pcm_pointer( 2598c2ecf20Sopenharmony_ci struct snd_soc_component *component, 2608c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream) 2618c2ecf20Sopenharmony_ci{ 2628c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2638c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = 2648c2ecf20Sopenharmony_ci snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci return bytes_to_frames(substream->runtime, priv->pos); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int stm32_adfsdm_pcm_hw_params(struct snd_soc_component *component, 2708c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream, 2718c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params) 2728c2ecf20Sopenharmony_ci{ 2738c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 2748c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = 2758c2ecf20Sopenharmony_ci snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci priv->pcm_buff = substream->runtime->dma_area; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return iio_channel_cb_set_buffer_watermark(priv->iio_cb, 2808c2ecf20Sopenharmony_ci params_period_size(params)); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int stm32_adfsdm_pcm_new(struct snd_soc_component *component, 2848c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci struct snd_pcm *pcm = rtd->pcm; 2878c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv = 2888c2ecf20Sopenharmony_ci snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 2898c2ecf20Sopenharmony_ci unsigned int size = DFSDM_MAX_PERIODS * DFSDM_MAX_PERIOD_SIZE; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, 2928c2ecf20Sopenharmony_ci priv->dev, size, size); 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic struct snd_soc_component_driver stm32_adfsdm_soc_platform = { 2978c2ecf20Sopenharmony_ci .open = stm32_adfsdm_pcm_open, 2988c2ecf20Sopenharmony_ci .close = stm32_adfsdm_pcm_close, 2998c2ecf20Sopenharmony_ci .hw_params = stm32_adfsdm_pcm_hw_params, 3008c2ecf20Sopenharmony_ci .trigger = stm32_adfsdm_trigger, 3018c2ecf20Sopenharmony_ci .pointer = stm32_adfsdm_pcm_pointer, 3028c2ecf20Sopenharmony_ci .pcm_construct = stm32_adfsdm_pcm_new, 3038c2ecf20Sopenharmony_ci}; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic const struct of_device_id stm32_adfsdm_of_match[] = { 3068c2ecf20Sopenharmony_ci {.compatible = "st,stm32h7-dfsdm-dai"}, 3078c2ecf20Sopenharmony_ci {} 3088c2ecf20Sopenharmony_ci}; 3098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_adfsdm_of_match); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic int stm32_adfsdm_probe(struct platform_device *pdev) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci struct stm32_adfsdm_priv *priv; 3148c2ecf20Sopenharmony_ci struct snd_soc_component *component; 3158c2ecf20Sopenharmony_ci int ret; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 3188c2ecf20Sopenharmony_ci if (!priv) 3198c2ecf20Sopenharmony_ci return -ENOMEM; 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 3228c2ecf20Sopenharmony_ci priv->dai_drv = stm32_adfsdm_dai; 3238c2ecf20Sopenharmony_ci mutex_init(&priv->lock); 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, priv); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 3288c2ecf20Sopenharmony_ci &stm32_adfsdm_dai_component, 3298c2ecf20Sopenharmony_ci &priv->dai_drv, 1); 3308c2ecf20Sopenharmony_ci if (ret < 0) 3318c2ecf20Sopenharmony_ci return ret; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci /* Associate iio channel */ 3348c2ecf20Sopenharmony_ci priv->iio_ch = devm_iio_channel_get_all(&pdev->dev); 3358c2ecf20Sopenharmony_ci if (IS_ERR(priv->iio_ch)) 3368c2ecf20Sopenharmony_ci return PTR_ERR(priv->iio_ch); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci priv->iio_cb = iio_channel_get_all_cb(&pdev->dev, NULL, NULL); 3398c2ecf20Sopenharmony_ci if (IS_ERR(priv->iio_cb)) 3408c2ecf20Sopenharmony_ci return PTR_ERR(priv->iio_cb); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci component = devm_kzalloc(&pdev->dev, sizeof(*component), GFP_KERNEL); 3438c2ecf20Sopenharmony_ci if (!component) 3448c2ecf20Sopenharmony_ci return -ENOMEM; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci ret = snd_soc_component_initialize(component, 3478c2ecf20Sopenharmony_ci &stm32_adfsdm_soc_platform, 3488c2ecf20Sopenharmony_ci &pdev->dev); 3498c2ecf20Sopenharmony_ci if (ret < 0) 3508c2ecf20Sopenharmony_ci return ret; 3518c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 3528c2ecf20Sopenharmony_ci component->debugfs_prefix = "pcm"; 3538c2ecf20Sopenharmony_ci#endif 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci ret = snd_soc_add_component(component, NULL, 0); 3568c2ecf20Sopenharmony_ci if (ret < 0) 3578c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", 3588c2ecf20Sopenharmony_ci __func__); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return ret; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic int stm32_adfsdm_remove(struct platform_device *pdev) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci snd_soc_unregister_component(&pdev->dev); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic struct platform_driver stm32_adfsdm_driver = { 3718c2ecf20Sopenharmony_ci .driver = { 3728c2ecf20Sopenharmony_ci .name = STM32_ADFSDM_DRV_NAME, 3738c2ecf20Sopenharmony_ci .of_match_table = stm32_adfsdm_of_match, 3748c2ecf20Sopenharmony_ci }, 3758c2ecf20Sopenharmony_ci .probe = stm32_adfsdm_probe, 3768c2ecf20Sopenharmony_ci .remove = stm32_adfsdm_remove, 3778c2ecf20Sopenharmony_ci}; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cimodule_platform_driver(stm32_adfsdm_driver); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("stm32 DFSDM DAI driver"); 3828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); 3838c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 3848c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:" STM32_ADFSDM_DRV_NAME); 385