diff options
Diffstat (limited to 'sound/soc/zte/zx-tdm.c')
-rw-r--r-- | sound/soc/zte/zx-tdm.c | 458 |
1 files changed, 0 insertions, 458 deletions
diff --git a/sound/soc/zte/zx-tdm.c b/sound/soc/zte/zx-tdm.c deleted file mode 100644 index 4f787185d630..000000000000 --- a/sound/soc/zte/zx-tdm.c +++ /dev/null @@ -1,458 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * ZTE's TDM driver - * - * Copyright (C) 2017 ZTE Ltd - * - * Author: Baoyou Xie <baoyou.xie@linaro.org> - */ - -#include <linux/clk.h> -#include <linux/io.h> -#include <linux/mfd/syscon.h> -#include <linux/module.h> -#include <sound/dmaengine_pcm.h> -#include <sound/pcm_params.h> -#include <sound/soc.h> -#include <sound/soc-dai.h> - -#define REG_TIMING_CTRL 0x04 -#define REG_TX_FIFO_CTRL 0x0C -#define REG_RX_FIFO_CTRL 0x10 -#define REG_INT_EN 0x1C -#define REG_INT_STATUS 0x20 -#define REG_DATABUF 0x24 -#define REG_TS_MASK0 0x44 -#define REG_PROCESS_CTRL 0x54 - -#define FIFO_CTRL_TX_RST BIT(0) -#define FIFO_CTRL_RX_RST BIT(0) -#define DEAGULT_FIFO_THRES GENMASK(4, 2) - -#define FIFO_CTRL_TX_DMA_EN BIT(1) -#define FIFO_CTRL_RX_DMA_EN BIT(1) - -#define TX_FIFO_RST_MASK BIT(0) -#define RX_FIFO_RST_MASK BIT(0) - -#define FIFOCTRL_TX_FIFO_RST BIT(0) -#define FIFOCTRL_RX_FIFO_RST BIT(0) - -#define TXTH_MASK GENMASK(5, 2) -#define RXTH_MASK GENMASK(5, 2) - -#define FIFOCTRL_THRESHOLD(x) ((x) << 2) - -#define TIMING_MS_MASK BIT(1) -/* - * 00: 8 clk cycles every timeslot - * 01: 16 clk cycles every timeslot - * 10: 32 clk cycles every timeslot - */ -#define TIMING_SYNC_WIDTH_MASK GENMASK(6, 5) -#define TIMING_WIDTH_SHIFT 5 -#define TIMING_DEFAULT_WIDTH 0 -#define TIMING_TS_WIDTH(x) ((x) << TIMING_WIDTH_SHIFT) -#define TIMING_WIDTH_FACTOR 8 - -#define TIMING_MASTER_MODE BIT(21) -#define TIMING_LSB_FIRST BIT(20) -#define TIMING_TS_NUM(x) (((x) - 1) << 7) -#define TIMING_CLK_SEL_MASK GENMASK(2, 0) -#define TIMING_CLK_SEL_DEF BIT(2) - -#define PROCESS_TX_EN BIT(0) -#define PROCESS_RX_EN BIT(1) -#define PROCESS_TDM_EN BIT(2) -#define PROCESS_DISABLE_ALL 0 - -#define INT_DISABLE_ALL 0 -#define INT_STATUS_MASK GENMASK(6, 0) - -struct zx_tdm_info { - struct snd_dmaengine_dai_dma_data dma_playback; - struct snd_dmaengine_dai_dma_data dma_capture; - resource_size_t phy_addr; - void __iomem *regbase; - struct clk *dai_wclk; - struct clk *dai_pclk; - int master; - struct device *dev; -}; - -static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg) -{ - return readl_relaxed(tdm->regbase + reg); -} - -static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val) -{ - writel_relaxed(val, tdm->regbase + reg); -} - -static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on) -{ - unsigned long val; - - val = zx_tdm_readl(tdm, REG_PROCESS_CTRL); - if (on) - val |= PROCESS_TX_EN | PROCESS_TDM_EN; - else - val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN); - zx_tdm_writel(tdm, REG_PROCESS_CTRL, val); -} - -static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on) -{ - unsigned long val; - - val = zx_tdm_readl(tdm, REG_PROCESS_CTRL); - if (on) - val |= PROCESS_RX_EN | PROCESS_TDM_EN; - else - val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN); - zx_tdm_writel(tdm, REG_PROCESS_CTRL, val); -} - -static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on) -{ - unsigned long val; - - val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL); - val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES; - if (on) - val |= FIFO_CTRL_TX_DMA_EN; - else - val &= ~FIFO_CTRL_TX_DMA_EN; - zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val); -} - -static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on) -{ - unsigned long val; - - val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL); - val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES; - if (on) - val |= FIFO_CTRL_RX_DMA_EN; - else - val &= ~FIFO_CTRL_RX_DMA_EN; - zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val); -} - -#define ZX_TDM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000) - -#define ZX_TDM_FMTBIT \ - (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_MU_LAW | \ - SNDRV_PCM_FMTBIT_A_LAW) - -static int zx_tdm_dai_probe(struct snd_soc_dai *dai) -{ - struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); - - snd_soc_dai_set_drvdata(dai, zx_tdm); - zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF; - zx_tdm->dma_playback.maxburst = 16; - zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF; - zx_tdm->dma_capture.maxburst = 16; - snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback, - &zx_tdm->dma_capture); - return 0; -} - -static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) -{ - struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai); - unsigned long val; - - val = zx_tdm_readl(tdm, REG_TIMING_CTRL); - val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK); - val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT; - - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - tdm->master = 1; - val |= TIMING_MASTER_MODE; - break; - case SND_SOC_DAIFMT_CBS_CFS: - tdm->master = 0; - val &= ~TIMING_MASTER_MODE; - break; - default: - dev_err(cpu_dai->dev, "Unknown master/slave format\n"); - return -EINVAL; - } - - - zx_tdm_writel(tdm, REG_TIMING_CTRL, val); - - return 0; -} - -static int zx_tdm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_soc_dai *socdai) -{ - struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai); - struct snd_dmaengine_dai_dma_data *dma_data; - unsigned int ts_width = TIMING_DEFAULT_WIDTH; - unsigned int ch_num = 32; - unsigned int mask = 0; - unsigned int ret = 0; - unsigned long val; - - dma_data = snd_soc_dai_get_dma_data(socdai, substream); - dma_data->addr_width = ch_num >> 3; - - switch (params_format(params)) { - case SNDRV_PCM_FORMAT_MU_LAW: - case SNDRV_PCM_FORMAT_A_LAW: - case SNDRV_PCM_FORMAT_S16_LE: - ts_width = 1; - break; - default: - dev_err(socdai->dev, "Unknown data format\n"); - return -EINVAL; - } - - val = zx_tdm_readl(tdm, REG_TIMING_CTRL); - val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1); - zx_tdm_writel(tdm, REG_TIMING_CTRL, val); - zx_tdm_writel(tdm, REG_TS_MASK0, mask); - - if (tdm->master) - ret = clk_set_rate(tdm->dai_wclk, - params_rate(params) * TIMING_WIDTH_FACTOR * ch_num); - - return ret; -} - -static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd, - struct snd_soc_dai *dai) -{ - int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); - unsigned int val; - int ret = 0; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - if (capture) { - val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL); - val |= FIFOCTRL_RX_FIFO_RST; - zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val); - - zx_tdm_rx_dma_en(zx_tdm, true); - } else { - val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL); - val |= FIFOCTRL_TX_FIFO_RST; - zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val); - - zx_tdm_tx_dma_en(zx_tdm, true); - } - break; - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (capture) - zx_tdm_rx_en(zx_tdm, true); - else - zx_tdm_tx_en(zx_tdm, true); - break; - case SNDRV_PCM_TRIGGER_STOP: - if (capture) - zx_tdm_rx_dma_en(zx_tdm, false); - else - zx_tdm_tx_dma_en(zx_tdm, false); - break; - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (capture) - zx_tdm_rx_en(zx_tdm, false); - else - zx_tdm_tx_en(zx_tdm, false); - break; - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static int zx_tdm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); - int ret; - - ret = clk_prepare_enable(zx_tdm->dai_wclk); - if (ret) - return ret; - - ret = clk_prepare_enable(zx_tdm->dai_pclk); - if (ret) { - clk_disable_unprepare(zx_tdm->dai_wclk); - return ret; - } - - return 0; -} - -static void zx_tdm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev); - - clk_disable_unprepare(zx_tdm->dai_pclk); - clk_disable_unprepare(zx_tdm->dai_wclk); -} - -static const struct snd_soc_dai_ops zx_tdm_dai_ops = { - .trigger = zx_tdm_trigger, - .hw_params = zx_tdm_hw_params, - .set_fmt = zx_tdm_set_fmt, - .startup = zx_tdm_startup, - .shutdown = zx_tdm_shutdown, -}; - -static const struct snd_soc_component_driver zx_tdm_component = { - .name = "zx-tdm", -}; - -static void zx_tdm_init_state(struct zx_tdm_info *tdm) -{ - unsigned int val; - - zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL); - - val = zx_tdm_readl(tdm, REG_TIMING_CTRL); - val |= TIMING_LSB_FIRST; - val &= ~TIMING_CLK_SEL_MASK; - val |= TIMING_CLK_SEL_DEF; - zx_tdm_writel(tdm, REG_TIMING_CTRL, val); - - zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL); - /* - * write INT_STATUS register to clear it. - */ - zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK); - zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST); - zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST); - - val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL); - val &= ~(RXTH_MASK | RX_FIFO_RST_MASK); - val |= FIFOCTRL_THRESHOLD(8); - zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val); - - val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL); - val &= ~(TXTH_MASK | TX_FIFO_RST_MASK); - val |= FIFOCTRL_THRESHOLD(8); - zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val); -} - -static struct snd_soc_dai_driver zx_tdm_dai = { - .name = "zx-tdm-dai", - .id = 0, - .probe = zx_tdm_dai_probe, - .playback = { - .channels_min = 1, - .channels_max = 4, - .rates = ZX_TDM_RATES, - .formats = ZX_TDM_FMTBIT, - }, - .capture = { - .channels_min = 1, - .channels_max = 4, - .rates = ZX_TDM_RATES, - .formats = ZX_TDM_FMTBIT, - }, - .ops = &zx_tdm_dai_ops, -}; - -static int zx_tdm_probe(struct platform_device *pdev) -{ - struct of_phandle_args out_args; - unsigned int dma_reg_offset; - struct zx_tdm_info *zx_tdm; - unsigned int dma_mask; - struct resource *res; - struct regmap *regmap_sysctrl; - int ret; - - zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL); - if (!zx_tdm) - return -ENOMEM; - - zx_tdm->dev = &pdev->dev; - - zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk"); - if (IS_ERR(zx_tdm->dai_wclk)) { - dev_err(&pdev->dev, "Fail to get wclk\n"); - return PTR_ERR(zx_tdm->dai_wclk); - } - - zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk"); - if (IS_ERR(zx_tdm->dai_pclk)) { - dev_err(&pdev->dev, "Fail to get pclk\n"); - return PTR_ERR(zx_tdm->dai_pclk); - } - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - zx_tdm->phy_addr = res->start; - zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(zx_tdm->regbase)) - return PTR_ERR(zx_tdm->regbase); - - ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, - "zte,tdm-dma-sysctrl", 2, 0, &out_args); - if (ret) { - dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n"); - return ret; - } - - dma_reg_offset = out_args.args[0]; - dma_mask = out_args.args[1]; - regmap_sysctrl = syscon_node_to_regmap(out_args.np); - if (IS_ERR(regmap_sysctrl)) { - of_node_put(out_args.np); - return PTR_ERR(regmap_sysctrl); - } - - regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask); - of_node_put(out_args.np); - - zx_tdm_init_state(zx_tdm); - platform_set_drvdata(pdev, zx_tdm); - - ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component, - &zx_tdm_dai, 1); - if (ret) { - dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); - return ret; - } - - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); - if (ret) - dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret); - - return ret; -} - -static const struct of_device_id zx_tdm_dt_ids[] = { - { .compatible = "zte,zx296718-tdm", }, - {} -}; -MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids); - -static struct platform_driver tdm_driver = { - .probe = zx_tdm_probe, - .driver = { - .name = "zx-tdm", - .of_match_table = zx_tdm_dt_ids, - }, -}; -module_platform_driver(tdm_driver); - -MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>"); -MODULE_DESCRIPTION("ZTE TDM DAI driver"); -MODULE_LICENSE("GPL v2"); |