18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * SiRF USP in I2S/DSP mode 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/module.h> 88c2ecf20Sopenharmony_ci#include <linux/io.h> 98c2ecf20Sopenharmony_ci#include <linux/of.h> 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 128c2ecf20Sopenharmony_ci#include <sound/soc.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 148c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "sirf-usp.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistruct sirf_usp { 198c2ecf20Sopenharmony_ci struct regmap *regmap; 208c2ecf20Sopenharmony_ci struct clk *clk; 218c2ecf20Sopenharmony_ci u32 mode1_reg; 228c2ecf20Sopenharmony_ci u32 mode2_reg; 238c2ecf20Sopenharmony_ci int daifmt_format; 248c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback_dma_data; 258c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture_dma_data; 268c2ecf20Sopenharmony_ci}; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic void sirf_usp_tx_enable(struct sirf_usp *usp) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_FIFO_OP, 318c2ecf20Sopenharmony_ci USP_TX_FIFO_RESET, USP_TX_FIFO_RESET); 328c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_TX_FIFO_OP, 0); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_FIFO_OP, 358c2ecf20Sopenharmony_ci USP_TX_FIFO_START, USP_TX_FIFO_START); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE, 388c2ecf20Sopenharmony_ci USP_TX_ENA, USP_TX_ENA); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic void sirf_usp_tx_disable(struct sirf_usp *usp) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE, 448c2ecf20Sopenharmony_ci USP_TX_ENA, ~USP_TX_ENA); 458c2ecf20Sopenharmony_ci /* FIFO stop */ 468c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_TX_FIFO_OP, 0); 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic void sirf_usp_rx_enable(struct sirf_usp *usp) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_RX_FIFO_OP, 528c2ecf20Sopenharmony_ci USP_RX_FIFO_RESET, USP_RX_FIFO_RESET); 538c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_RX_FIFO_OP, 0); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_RX_FIFO_OP, 568c2ecf20Sopenharmony_ci USP_RX_FIFO_START, USP_RX_FIFO_START); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE, 598c2ecf20Sopenharmony_ci USP_RX_ENA, USP_RX_ENA); 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic void sirf_usp_rx_disable(struct sirf_usp *usp) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_RX_ENABLE, 658c2ecf20Sopenharmony_ci USP_RX_ENA, ~USP_RX_ENA); 668c2ecf20Sopenharmony_ci /* FIFO stop */ 678c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_RX_FIFO_OP, 0); 688c2ecf20Sopenharmony_ci} 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_dai_probe(struct snd_soc_dai *dai) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai); 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &usp->playback_dma_data, 758c2ecf20Sopenharmony_ci &usp->capture_dma_data); 768c2ecf20Sopenharmony_ci return 0; 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai, 808c2ecf20Sopenharmony_ci unsigned int fmt) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai); 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* set master/slave audio interface */ 858c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 868c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_CBM_CFM: 878c2ecf20Sopenharmony_ci break; 888c2ecf20Sopenharmony_ci default: 898c2ecf20Sopenharmony_ci dev_err(dai->dev, "Only CBM and CFM supported\n"); 908c2ecf20Sopenharmony_ci return -EINVAL; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 948c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 958c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 968c2ecf20Sopenharmony_ci usp->daifmt_format = (fmt & SND_SOC_DAIFMT_FORMAT_MASK); 978c2ecf20Sopenharmony_ci break; 988c2ecf20Sopenharmony_ci default: 998c2ecf20Sopenharmony_ci dev_err(dai->dev, "Only I2S and DSP_A format supported\n"); 1008c2ecf20Sopenharmony_ci return -EINVAL; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 1048c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 1078c2ecf20Sopenharmony_ci usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK); 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci default: 1108c2ecf20Sopenharmony_ci return -EINVAL; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic void sirf_usp_i2s_init(struct sirf_usp *usp) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci /* Configure RISC mode */ 1198c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_RISC_DSP_MODE, 1208c2ecf20Sopenharmony_ci USP_RISC_DSP_SEL, ~USP_RISC_DSP_SEL); 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Configure DMA IO Length register 1248c2ecf20Sopenharmony_ci * Set no limit, USP can receive data continuously until it is diabled 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_TX_DMA_IO_LEN, 0); 1278c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_RX_DMA_IO_LEN, 0); 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci /* Configure Mode2 register */ 1308c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_MODE2, (1 << USP_RXD_DELAY_LEN_OFFSET) | 1318c2ecf20Sopenharmony_ci (0 << USP_TXD_DELAY_LEN_OFFSET) | 1328c2ecf20Sopenharmony_ci USP_TFS_CLK_SLAVE_MODE | USP_RFS_CLK_SLAVE_MODE); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* Configure Mode1 register */ 1358c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_MODE1, 1368c2ecf20Sopenharmony_ci USP_SYNC_MODE | USP_EN | USP_TXD_ACT_EDGE_FALLING | 1378c2ecf20Sopenharmony_ci USP_RFS_ACT_LEVEL_LOGIC1 | USP_TFS_ACT_LEVEL_LOGIC1 | 1388c2ecf20Sopenharmony_ci USP_TX_UFLOW_REPEAT_ZERO | USP_CLOCK_MODE_SLAVE); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* Configure RX DMA IO Control register */ 1418c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_RX_DMA_IO_CTRL, 0); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Congiure RX FIFO Control register */ 1448c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_RX_FIFO_CTRL, 1458c2ecf20Sopenharmony_ci (USP_RX_FIFO_THRESHOLD << USP_RX_FIFO_THD_OFFSET) | 1468c2ecf20Sopenharmony_ci (USP_TX_RX_FIFO_WIDTH_DWORD << USP_RX_FIFO_WIDTH_OFFSET)); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Congiure RX FIFO Level Check register */ 1498c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_RX_FIFO_LEVEL_CHK, 1508c2ecf20Sopenharmony_ci RX_FIFO_SC(0x04) | RX_FIFO_LC(0x0E) | RX_FIFO_HC(0x1B)); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* Configure TX DMA IO Control register*/ 1538c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_TX_DMA_IO_CTRL, 0); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci /* Configure TX FIFO Control register */ 1568c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_TX_FIFO_CTRL, 1578c2ecf20Sopenharmony_ci (USP_TX_FIFO_THRESHOLD << USP_TX_FIFO_THD_OFFSET) | 1588c2ecf20Sopenharmony_ci (USP_TX_RX_FIFO_WIDTH_DWORD << USP_TX_FIFO_WIDTH_OFFSET)); 1598c2ecf20Sopenharmony_ci /* Congiure TX FIFO Level Check register */ 1608c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_TX_FIFO_LEVEL_CHK, 1618c2ecf20Sopenharmony_ci TX_FIFO_SC(0x1B) | TX_FIFO_LC(0x0E) | TX_FIFO_HC(0x04)); 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, 1658c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai); 1688c2ecf20Sopenharmony_ci u32 data_len, frame_len, shifter_len; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci switch (params_format(params)) { 1718c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 1728c2ecf20Sopenharmony_ci data_len = 16; 1738c2ecf20Sopenharmony_ci frame_len = 16; 1748c2ecf20Sopenharmony_ci break; 1758c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 1768c2ecf20Sopenharmony_ci data_len = 24; 1778c2ecf20Sopenharmony_ci frame_len = 32; 1788c2ecf20Sopenharmony_ci break; 1798c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 1808c2ecf20Sopenharmony_ci data_len = 24; 1818c2ecf20Sopenharmony_ci frame_len = 24; 1828c2ecf20Sopenharmony_ci break; 1838c2ecf20Sopenharmony_ci default: 1848c2ecf20Sopenharmony_ci dev_err(dai->dev, "Format unsupported\n"); 1858c2ecf20Sopenharmony_ci return -EINVAL; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci shifter_len = data_len; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) { 1918c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 1928c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, 1938c2ecf20Sopenharmony_ci USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG); 1948c2ecf20Sopenharmony_ci break; 1958c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 1968c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, 1978c2ecf20Sopenharmony_ci USP_I2S_SYNC_CHG, 0); 1988c2ecf20Sopenharmony_ci frame_len = data_len * params_channels(params); 1998c2ecf20Sopenharmony_ci data_len = frame_len; 2008c2ecf20Sopenharmony_ci break; 2018c2ecf20Sopenharmony_ci default: 2028c2ecf20Sopenharmony_ci dev_err(dai->dev, "Only support I2S and DSP_A mode\n"); 2038c2ecf20Sopenharmony_ci return -EINVAL; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) { 2078c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 2088c2ecf20Sopenharmony_ci break; 2098c2ecf20Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 2108c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_MODE1, 2118c2ecf20Sopenharmony_ci USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING, 2128c2ecf20Sopenharmony_ci USP_RXD_ACT_EDGE_FALLING); 2138c2ecf20Sopenharmony_ci break; 2148c2ecf20Sopenharmony_ci default: 2158c2ecf20Sopenharmony_ci return -EINVAL; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2198c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL, 2208c2ecf20Sopenharmony_ci USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK 2218c2ecf20Sopenharmony_ci | USP_TXC_SHIFTER_LEN_MASK | USP_TXC_SLAVE_CLK_SAMPLE, 2228c2ecf20Sopenharmony_ci ((data_len - 1) << USP_TXC_DATA_LEN_OFFSET) 2238c2ecf20Sopenharmony_ci | ((frame_len - 1) << USP_TXC_FRAME_LEN_OFFSET) 2248c2ecf20Sopenharmony_ci | ((shifter_len - 1) << USP_TXC_SHIFTER_LEN_OFFSET) 2258c2ecf20Sopenharmony_ci | USP_TXC_SLAVE_CLK_SAMPLE); 2268c2ecf20Sopenharmony_ci else 2278c2ecf20Sopenharmony_ci regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, 2288c2ecf20Sopenharmony_ci USP_RXC_DATA_LEN_MASK | USP_RXC_FRAME_LEN_MASK 2298c2ecf20Sopenharmony_ci | USP_RXC_SHIFTER_LEN_MASK | USP_SINGLE_SYNC_MODE, 2308c2ecf20Sopenharmony_ci ((data_len - 1) << USP_RXC_DATA_LEN_OFFSET) 2318c2ecf20Sopenharmony_ci | ((frame_len - 1) << USP_RXC_FRAME_LEN_OFFSET) 2328c2ecf20Sopenharmony_ci | ((shifter_len - 1) << USP_RXC_SHIFTER_LEN_OFFSET) 2338c2ecf20Sopenharmony_ci | USP_SINGLE_SYNC_MODE); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_trigger(struct snd_pcm_substream *substream, int cmd, 2398c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct sirf_usp *usp = snd_soc_dai_get_drvdata(dai); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci switch (cmd) { 2448c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 2458c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 2468c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 2478c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2488c2ecf20Sopenharmony_ci sirf_usp_tx_enable(usp); 2498c2ecf20Sopenharmony_ci else 2508c2ecf20Sopenharmony_ci sirf_usp_rx_enable(usp); 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 2538c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 2548c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 2558c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2568c2ecf20Sopenharmony_ci sirf_usp_tx_disable(usp); 2578c2ecf20Sopenharmony_ci else 2588c2ecf20Sopenharmony_ci sirf_usp_rx_disable(usp); 2598c2ecf20Sopenharmony_ci break; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops sirf_usp_pcm_dai_ops = { 2668c2ecf20Sopenharmony_ci .trigger = sirf_usp_pcm_trigger, 2678c2ecf20Sopenharmony_ci .set_fmt = sirf_usp_pcm_set_dai_fmt, 2688c2ecf20Sopenharmony_ci .hw_params = sirf_usp_pcm_hw_params, 2698c2ecf20Sopenharmony_ci}; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver sirf_usp_pcm_dai = { 2728c2ecf20Sopenharmony_ci .probe = sirf_usp_pcm_dai_probe, 2738c2ecf20Sopenharmony_ci .name = "sirf-usp-pcm", 2748c2ecf20Sopenharmony_ci .id = 0, 2758c2ecf20Sopenharmony_ci .playback = { 2768c2ecf20Sopenharmony_ci .stream_name = "SiRF USP PCM Playback", 2778c2ecf20Sopenharmony_ci .channels_min = 1, 2788c2ecf20Sopenharmony_ci .channels_max = 2, 2798c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 2808c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 2818c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE, 2828c2ecf20Sopenharmony_ci }, 2838c2ecf20Sopenharmony_ci .capture = { 2848c2ecf20Sopenharmony_ci .stream_name = "SiRF USP PCM Capture", 2858c2ecf20Sopenharmony_ci .channels_min = 1, 2868c2ecf20Sopenharmony_ci .channels_max = 2, 2878c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 2888c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | 2898c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE, 2908c2ecf20Sopenharmony_ci }, 2918c2ecf20Sopenharmony_ci .ops = &sirf_usp_pcm_dai_ops, 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_runtime_suspend(struct device *dev) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct sirf_usp *usp = dev_get_drvdata(dev); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci clk_disable_unprepare(usp->clk); 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_runtime_resume(struct device *dev) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct sirf_usp *usp = dev_get_drvdata(dev); 3058c2ecf20Sopenharmony_ci int ret; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ret = clk_prepare_enable(usp->clk); 3088c2ecf20Sopenharmony_ci if (ret) { 3098c2ecf20Sopenharmony_ci dev_err(dev, "clk_enable failed: %d\n", ret); 3108c2ecf20Sopenharmony_ci return ret; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci sirf_usp_i2s_init(usp); 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 3178c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_suspend(struct device *dev) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct sirf_usp *usp = dev_get_drvdata(dev); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(dev)) { 3228c2ecf20Sopenharmony_ci regmap_read(usp->regmap, USP_MODE1, &usp->mode1_reg); 3238c2ecf20Sopenharmony_ci regmap_read(usp->regmap, USP_MODE2, &usp->mode2_reg); 3248c2ecf20Sopenharmony_ci sirf_usp_pcm_runtime_suspend(dev); 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_resume(struct device *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct sirf_usp *usp = dev_get_drvdata(dev); 3328c2ecf20Sopenharmony_ci int ret; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(dev)) { 3358c2ecf20Sopenharmony_ci ret = sirf_usp_pcm_runtime_resume(dev); 3368c2ecf20Sopenharmony_ci if (ret) 3378c2ecf20Sopenharmony_ci return ret; 3388c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_MODE1, usp->mode1_reg); 3398c2ecf20Sopenharmony_ci regmap_write(usp->regmap, USP_MODE2, usp->mode2_reg); 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci#endif 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver sirf_usp_component = { 3468c2ecf20Sopenharmony_ci .name = "sirf-usp", 3478c2ecf20Sopenharmony_ci}; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic const struct regmap_config sirf_usp_regmap_config = { 3508c2ecf20Sopenharmony_ci .reg_bits = 32, 3518c2ecf20Sopenharmony_ci .reg_stride = 4, 3528c2ecf20Sopenharmony_ci .val_bits = 32, 3538c2ecf20Sopenharmony_ci .max_register = USP_RX_FIFO_DATA, 3548c2ecf20Sopenharmony_ci .cache_type = REGCACHE_NONE, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_probe(struct platform_device *pdev) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci int ret; 3608c2ecf20Sopenharmony_ci struct sirf_usp *usp; 3618c2ecf20Sopenharmony_ci void __iomem *base; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci usp = devm_kzalloc(&pdev->dev, sizeof(struct sirf_usp), 3648c2ecf20Sopenharmony_ci GFP_KERNEL); 3658c2ecf20Sopenharmony_ci if (!usp) 3668c2ecf20Sopenharmony_ci return -ENOMEM; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, usp); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 3718c2ecf20Sopenharmony_ci if (IS_ERR(base)) 3728c2ecf20Sopenharmony_ci return PTR_ERR(base); 3738c2ecf20Sopenharmony_ci usp->regmap = devm_regmap_init_mmio(&pdev->dev, base, 3748c2ecf20Sopenharmony_ci &sirf_usp_regmap_config); 3758c2ecf20Sopenharmony_ci if (IS_ERR(usp->regmap)) 3768c2ecf20Sopenharmony_ci return PTR_ERR(usp->regmap); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci usp->clk = devm_clk_get(&pdev->dev, NULL); 3798c2ecf20Sopenharmony_ci if (IS_ERR(usp->clk)) { 3808c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Get clock failed.\n"); 3818c2ecf20Sopenharmony_ci return PTR_ERR(usp->clk); 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 3858c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 3868c2ecf20Sopenharmony_ci ret = sirf_usp_pcm_runtime_resume(&pdev->dev); 3878c2ecf20Sopenharmony_ci if (ret) 3888c2ecf20Sopenharmony_ci return ret; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &sirf_usp_component, 3928c2ecf20Sopenharmony_ci &sirf_usp_pcm_dai, 1); 3938c2ecf20Sopenharmony_ci if (ret) { 3948c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Register Audio SoC dai failed.\n"); 3958c2ecf20Sopenharmony_ci return ret; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_cistatic int sirf_usp_pcm_remove(struct platform_device *pdev) 4018c2ecf20Sopenharmony_ci{ 4028c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) 4038c2ecf20Sopenharmony_ci sirf_usp_pcm_runtime_suspend(&pdev->dev); 4048c2ecf20Sopenharmony_ci else 4058c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 4068c2ecf20Sopenharmony_ci return 0; 4078c2ecf20Sopenharmony_ci} 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_cistatic const struct of_device_id sirf_usp_pcm_of_match[] = { 4108c2ecf20Sopenharmony_ci { .compatible = "sirf,prima2-usp-pcm", }, 4118c2ecf20Sopenharmony_ci {} 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sirf_usp_pcm_of_match); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic const struct dev_pm_ops sirf_usp_pcm_pm_ops = { 4168c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(sirf_usp_pcm_runtime_suspend, 4178c2ecf20Sopenharmony_ci sirf_usp_pcm_runtime_resume, NULL) 4188c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(sirf_usp_pcm_suspend, sirf_usp_pcm_resume) 4198c2ecf20Sopenharmony_ci}; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic struct platform_driver sirf_usp_pcm_driver = { 4228c2ecf20Sopenharmony_ci .driver = { 4238c2ecf20Sopenharmony_ci .name = "sirf-usp-pcm", 4248c2ecf20Sopenharmony_ci .of_match_table = sirf_usp_pcm_of_match, 4258c2ecf20Sopenharmony_ci .pm = &sirf_usp_pcm_pm_ops, 4268c2ecf20Sopenharmony_ci }, 4278c2ecf20Sopenharmony_ci .probe = sirf_usp_pcm_probe, 4288c2ecf20Sopenharmony_ci .remove = sirf_usp_pcm_remove, 4298c2ecf20Sopenharmony_ci}; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cimodule_platform_driver(sirf_usp_pcm_driver); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SiRF SoC USP PCM bus driver"); 4348c2ecf20Sopenharmony_ciMODULE_AUTHOR("RongJun Ying <Rongjun.Ying@csr.com>"); 4358c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 436