powerpc/mm/32: Remove the reserved memory hack
[linux-2.6-block.git] / sound / soc / zte / zx-tdm.c
CommitLineData
870e0ddc
BX
1/*
2 * ZTE's TDM driver
3 *
4 * Copyright (C) 2017 ZTE Ltd
5 *
6 * Author: Baoyou Xie <baoyou.xie@linaro.org>
7 *
8 * License terms: GNU General Public License (GPL) version 2
9 */
10
11#include <linux/clk.h>
12#include <linux/io.h>
13#include <linux/mfd/syscon.h>
14#include <linux/module.h>
15#include <sound/dmaengine_pcm.h>
16#include <sound/pcm_params.h>
17#include <sound/soc.h>
18#include <sound/soc-dai.h>
19
20#define REG_TIMING_CTRL 0x04
21#define REG_TX_FIFO_CTRL 0x0C
22#define REG_RX_FIFO_CTRL 0x10
23#define REG_INT_EN 0x1C
24#define REG_INT_STATUS 0x20
25#define REG_DATABUF 0x24
26#define REG_TS_MASK0 0x44
27#define REG_PROCESS_CTRL 0x54
28
29#define FIFO_CTRL_TX_RST BIT(0)
30#define FIFO_CTRL_RX_RST BIT(0)
31#define DEAGULT_FIFO_THRES GENMASK(4, 2)
32
33#define FIFO_CTRL_TX_DMA_EN BIT(1)
34#define FIFO_CTRL_RX_DMA_EN BIT(1)
35
36#define TX_FIFO_RST_MASK BIT(0)
37#define RX_FIFO_RST_MASK BIT(0)
38
39#define FIFOCTRL_TX_FIFO_RST BIT(0)
40#define FIFOCTRL_RX_FIFO_RST BIT(0)
41
42#define TXTH_MASK GENMASK(5, 2)
43#define RXTH_MASK GENMASK(5, 2)
44
45#define FIFOCTRL_THRESHOLD(x) ((x) << 2)
46
47#define TIMING_MS_MASK BIT(1)
48/*
49 * 00: 8 clk cycles every timeslot
50 * 01: 16 clk cycles every timeslot
51 * 10: 32 clk cycles every timeslot
52 */
53#define TIMING_SYNC_WIDTH_MASK GENMASK(6, 5)
54#define TIMING_WIDTH_SHIFT 5
55#define TIMING_DEFAULT_WIDTH 0
56#define TIMING_TS_WIDTH(x) ((x) << TIMING_WIDTH_SHIFT)
57#define TIMING_WIDTH_FACTOR 8
58
59#define TIMING_MASTER_MODE BIT(21)
60#define TIMING_LSB_FIRST BIT(20)
61#define TIMING_TS_NUM(x) (((x) - 1) << 7)
62#define TIMING_CLK_SEL_MASK GENMASK(2, 0)
63#define TIMING_CLK_SEL_DEF BIT(2)
64
65#define PROCESS_TX_EN BIT(0)
66#define PROCESS_RX_EN BIT(1)
67#define PROCESS_TDM_EN BIT(2)
68#define PROCESS_DISABLE_ALL 0
69
70#define INT_DISABLE_ALL 0
71#define INT_STATUS_MASK GENMASK(6, 0)
72
73struct zx_tdm_info {
74 struct snd_dmaengine_dai_dma_data dma_playback;
75 struct snd_dmaengine_dai_dma_data dma_capture;
76 resource_size_t phy_addr;
77 void __iomem *regbase;
78 struct clk *dai_wclk;
79 struct clk *dai_pclk;
80 int master;
81 struct device *dev;
82};
83
84static inline u32 zx_tdm_readl(struct zx_tdm_info *tdm, u16 reg)
85{
86 return readl_relaxed(tdm->regbase + reg);
87}
88
89static inline void zx_tdm_writel(struct zx_tdm_info *tdm, u16 reg, u32 val)
90{
91 writel_relaxed(val, tdm->regbase + reg);
92}
93
94static void zx_tdm_tx_en(struct zx_tdm_info *tdm, bool on)
95{
96 unsigned long val;
97
98 val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
99 if (on)
100 val |= PROCESS_TX_EN | PROCESS_TDM_EN;
101 else
102 val &= ~(PROCESS_TX_EN | PROCESS_TDM_EN);
103 zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
104}
105
106static void zx_tdm_rx_en(struct zx_tdm_info *tdm, bool on)
107{
108 unsigned long val;
109
110 val = zx_tdm_readl(tdm, REG_PROCESS_CTRL);
111 if (on)
112 val |= PROCESS_RX_EN | PROCESS_TDM_EN;
113 else
114 val &= ~(PROCESS_RX_EN | PROCESS_TDM_EN);
115 zx_tdm_writel(tdm, REG_PROCESS_CTRL, val);
116}
117
118static void zx_tdm_tx_dma_en(struct zx_tdm_info *tdm, bool on)
119{
120 unsigned long val;
121
122 val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
123 val |= FIFO_CTRL_TX_RST | DEAGULT_FIFO_THRES;
124 if (on)
125 val |= FIFO_CTRL_TX_DMA_EN;
126 else
127 val &= ~FIFO_CTRL_TX_DMA_EN;
128 zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
129}
130
131static void zx_tdm_rx_dma_en(struct zx_tdm_info *tdm, bool on)
132{
133 unsigned long val;
134
135 val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
136 val |= FIFO_CTRL_RX_RST | DEAGULT_FIFO_THRES;
137 if (on)
138 val |= FIFO_CTRL_RX_DMA_EN;
139 else
140 val &= ~FIFO_CTRL_RX_DMA_EN;
141 zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
142}
143
144#define ZX_TDM_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
145
146#define ZX_TDM_FMTBIT \
147 (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_MU_LAW | \
148 SNDRV_PCM_FORMAT_A_LAW)
149
150static int zx_tdm_dai_probe(struct snd_soc_dai *dai)
151{
152 struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
153
154 snd_soc_dai_set_drvdata(dai, zx_tdm);
155 zx_tdm->dma_playback.addr = zx_tdm->phy_addr + REG_DATABUF;
156 zx_tdm->dma_playback.maxburst = 16;
157 zx_tdm->dma_capture.addr = zx_tdm->phy_addr + REG_DATABUF;
158 zx_tdm->dma_capture.maxburst = 16;
159 snd_soc_dai_init_dma_data(dai, &zx_tdm->dma_playback,
160 &zx_tdm->dma_capture);
161 return 0;
162}
163
164static int zx_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
165{
166 struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(cpu_dai);
167 unsigned long val;
168
169 val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
170 val &= ~(TIMING_SYNC_WIDTH_MASK | TIMING_MS_MASK);
171 val |= TIMING_DEFAULT_WIDTH << TIMING_WIDTH_SHIFT;
172
173 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
174 case SND_SOC_DAIFMT_CBM_CFM:
175 tdm->master = 1;
176 val |= TIMING_MASTER_MODE;
177 break;
178 case SND_SOC_DAIFMT_CBS_CFS:
179 tdm->master = 0;
180 val &= ~TIMING_MASTER_MODE;
181 break;
182 default:
183 dev_err(cpu_dai->dev, "Unknown master/slave format\n");
184 return -EINVAL;
185 }
186
187
188 zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
189
190 return 0;
191}
192
193static int zx_tdm_hw_params(struct snd_pcm_substream *substream,
194 struct snd_pcm_hw_params *params,
195 struct snd_soc_dai *socdai)
196{
197 struct zx_tdm_info *tdm = snd_soc_dai_get_drvdata(socdai);
198 struct snd_dmaengine_dai_dma_data *dma_data;
199 unsigned int ts_width = TIMING_DEFAULT_WIDTH;
200 unsigned int ch_num = 32;
201 unsigned int mask = 0;
202 unsigned int ret = 0;
203 unsigned long val;
204
205 dma_data = snd_soc_dai_get_dma_data(socdai, substream);
206 dma_data->addr_width = ch_num >> 3;
207
208 switch (params_format(params)) {
209 case SNDRV_PCM_FORMAT_MU_LAW:
210 case SNDRV_PCM_FORMAT_A_LAW:
211 case SNDRV_PCM_FORMAT_S16_LE:
212 ts_width = 1;
213 break;
214 default:
215 ts_width = 0;
216 dev_err(socdai->dev, "Unknown data format\n");
217 return -EINVAL;
218 }
219
220 val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
221 val |= TIMING_TS_WIDTH(ts_width) | TIMING_TS_NUM(1);
222 zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
223 zx_tdm_writel(tdm, REG_TS_MASK0, mask);
224
225 if (tdm->master)
226 ret = clk_set_rate(tdm->dai_wclk,
227 params_rate(params) * TIMING_WIDTH_FACTOR * ch_num);
228
229 return ret;
230}
231
232static int zx_tdm_trigger(struct snd_pcm_substream *substream, int cmd,
233 struct snd_soc_dai *dai)
234{
235 int capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE);
236 struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
237 unsigned int val;
238 int ret = 0;
239
240 switch (cmd) {
241 case SNDRV_PCM_TRIGGER_START:
242 if (capture) {
243 val = zx_tdm_readl(zx_tdm, REG_RX_FIFO_CTRL);
244 val |= FIFOCTRL_RX_FIFO_RST;
245 zx_tdm_writel(zx_tdm, REG_RX_FIFO_CTRL, val);
246
247 zx_tdm_rx_dma_en(zx_tdm, true);
248 } else {
249 val = zx_tdm_readl(zx_tdm, REG_TX_FIFO_CTRL);
250 val |= FIFOCTRL_TX_FIFO_RST;
251 zx_tdm_writel(zx_tdm, REG_TX_FIFO_CTRL, val);
252
253 zx_tdm_tx_dma_en(zx_tdm, true);
254 }
255 break;
256 case SNDRV_PCM_TRIGGER_RESUME:
257 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
258 if (capture)
259 zx_tdm_rx_en(zx_tdm, true);
260 else
261 zx_tdm_tx_en(zx_tdm, true);
262 break;
263 case SNDRV_PCM_TRIGGER_STOP:
264 if (capture)
265 zx_tdm_rx_dma_en(zx_tdm, false);
266 else
267 zx_tdm_tx_dma_en(zx_tdm, false);
268 break;
269 case SNDRV_PCM_TRIGGER_SUSPEND:
270 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
271 if (capture)
272 zx_tdm_rx_en(zx_tdm, false);
273 else
274 zx_tdm_tx_en(zx_tdm, false);
275 break;
276 default:
277 ret = -EINVAL;
278 break;
279 }
280
281 return ret;
282}
283
284static int zx_tdm_startup(struct snd_pcm_substream *substream,
285 struct snd_soc_dai *dai)
286{
287 struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
288 int ret;
289
290 ret = clk_prepare_enable(zx_tdm->dai_wclk);
291 if (ret)
292 return ret;
293
294 ret = clk_prepare_enable(zx_tdm->dai_pclk);
295 if (ret) {
296 clk_disable_unprepare(zx_tdm->dai_wclk);
297 return ret;
298 }
299
300 return 0;
301}
302
303static void zx_tdm_shutdown(struct snd_pcm_substream *substream,
304 struct snd_soc_dai *dai)
305{
306 struct zx_tdm_info *zx_tdm = dev_get_drvdata(dai->dev);
307
308 clk_disable_unprepare(zx_tdm->dai_pclk);
309 clk_disable_unprepare(zx_tdm->dai_wclk);
310}
311
171dd516 312static const struct snd_soc_dai_ops zx_tdm_dai_ops = {
870e0ddc
BX
313 .trigger = zx_tdm_trigger,
314 .hw_params = zx_tdm_hw_params,
315 .set_fmt = zx_tdm_set_fmt,
316 .startup = zx_tdm_startup,
317 .shutdown = zx_tdm_shutdown,
318};
319
320static const struct snd_soc_component_driver zx_tdm_component = {
321 .name = "zx-tdm",
322};
323
324static void zx_tdm_init_state(struct zx_tdm_info *tdm)
325{
326 unsigned int val;
327
328 zx_tdm_writel(tdm, REG_PROCESS_CTRL, PROCESS_DISABLE_ALL);
329
330 val = zx_tdm_readl(tdm, REG_TIMING_CTRL);
331 val |= TIMING_LSB_FIRST;
332 val &= ~TIMING_CLK_SEL_MASK;
333 val |= TIMING_CLK_SEL_DEF;
334 zx_tdm_writel(tdm, REG_TIMING_CTRL, val);
335
336 zx_tdm_writel(tdm, REG_INT_EN, INT_DISABLE_ALL);
337 /*
338 * write INT_STATUS register to clear it.
339 */
340 zx_tdm_writel(tdm, REG_INT_STATUS, INT_STATUS_MASK);
341 zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, FIFOCTRL_RX_FIFO_RST);
342 zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, FIFOCTRL_TX_FIFO_RST);
343
344 val = zx_tdm_readl(tdm, REG_RX_FIFO_CTRL);
345 val &= ~(RXTH_MASK | RX_FIFO_RST_MASK);
346 val |= FIFOCTRL_THRESHOLD(8);
347 zx_tdm_writel(tdm, REG_RX_FIFO_CTRL, val);
348
349 val = zx_tdm_readl(tdm, REG_TX_FIFO_CTRL);
350 val &= ~(TXTH_MASK | TX_FIFO_RST_MASK);
351 val |= FIFOCTRL_THRESHOLD(8);
352 zx_tdm_writel(tdm, REG_TX_FIFO_CTRL, val);
353}
354
355static struct snd_soc_dai_driver zx_tdm_dai = {
356 .name = "zx-tdm-dai",
357 .id = 0,
358 .probe = zx_tdm_dai_probe,
359 .playback = {
360 .channels_min = 1,
361 .channels_max = 4,
362 .rates = ZX_TDM_RATES,
363 .formats = ZX_TDM_FMTBIT,
364 },
365 .capture = {
366 .channels_min = 1,
367 .channels_max = 4,
368 .rates = ZX_TDM_RATES,
369 .formats = ZX_TDM_FMTBIT,
370 },
371 .ops = &zx_tdm_dai_ops,
372};
373
374static int zx_tdm_probe(struct platform_device *pdev)
375{
376 struct device *dev = &pdev->dev;
377 struct of_phandle_args out_args;
378 unsigned int dma_reg_offset;
379 struct zx_tdm_info *zx_tdm;
380 unsigned int dma_mask;
381 struct resource *res;
382 struct regmap *regmap_sysctrl;
383 int ret;
384
385 zx_tdm = devm_kzalloc(&pdev->dev, sizeof(*zx_tdm), GFP_KERNEL);
386 if (!zx_tdm)
387 return -ENOMEM;
388
389 zx_tdm->dev = dev;
390
391 zx_tdm->dai_wclk = devm_clk_get(&pdev->dev, "wclk");
392 if (IS_ERR(zx_tdm->dai_wclk)) {
393 dev_err(&pdev->dev, "Fail to get wclk\n");
394 return PTR_ERR(zx_tdm->dai_wclk);
395 }
396
397 zx_tdm->dai_pclk = devm_clk_get(&pdev->dev, "pclk");
398 if (IS_ERR(zx_tdm->dai_pclk)) {
399 dev_err(&pdev->dev, "Fail to get pclk\n");
400 return PTR_ERR(zx_tdm->dai_pclk);
401 }
402
403 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
404 zx_tdm->phy_addr = res->start;
405 zx_tdm->regbase = devm_ioremap_resource(&pdev->dev, res);
406 if (IS_ERR(zx_tdm->regbase))
407 return PTR_ERR(zx_tdm->regbase);
408
409 ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
410 "zte,tdm-dma-sysctrl", 2, 0, &out_args);
411 if (ret) {
412 dev_err(&pdev->dev, "Fail to get zte,tdm-dma-sysctrl\n");
413 return ret;
414 }
415
416 dma_reg_offset = out_args.args[0];
417 dma_mask = out_args.args[1];
418 regmap_sysctrl = syscon_node_to_regmap(out_args.np);
419 if (IS_ERR(regmap_sysctrl)) {
420 of_node_put(out_args.np);
421 return PTR_ERR(regmap_sysctrl);
422 }
423
424 regmap_update_bits(regmap_sysctrl, dma_reg_offset, dma_mask, dma_mask);
425 of_node_put(out_args.np);
426
427 zx_tdm_init_state(zx_tdm);
428 platform_set_drvdata(pdev, zx_tdm);
429
430 ret = devm_snd_soc_register_component(&pdev->dev, &zx_tdm_component,
431 &zx_tdm_dai, 1);
432 if (ret) {
433 dev_err(&pdev->dev, "Register DAI failed: %d\n", ret);
434 return ret;
435 }
436
437 ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
438 if (ret)
439 dev_err(&pdev->dev, "Register platform PCM failed: %d\n", ret);
440
441 return ret;
442}
443
444static const struct of_device_id zx_tdm_dt_ids[] = {
445 { .compatible = "zte,zx296718-tdm", },
446 {}
447};
448MODULE_DEVICE_TABLE(of, zx_tdm_dt_ids);
449
450static struct platform_driver tdm_driver = {
451 .probe = zx_tdm_probe,
452 .driver = {
453 .name = "zx-tdm",
454 .of_match_table = zx_tdm_dt_ids,
455 },
456};
457module_platform_driver(tdm_driver);
458
459MODULE_AUTHOR("Baoyou Xie <baoyou.xie@linaro.org>");
460MODULE_DESCRIPTION("ZTE TDM DAI driver");
461MODULE_LICENSE("GPL v2");