1 // SPDX-License-Identifier: GPL-2.0-only
3 * tegra20_ac97.c - Tegra20 AC97 platform driver
5 * Copyright (c) 2012 Lucas Stach <dev@lynxeye.de>
7 * Partly based on code copyright/by:
9 * Copyright (c) 2011,2012 Toradex Inc.
12 #include <linux/clk.h>
13 #include <linux/delay.h>
14 #include <linux/device.h>
15 #include <linux/gpio/consumer.h>
17 #include <linux/jiffies.h>
18 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/regmap.h>
22 #include <linux/reset.h>
23 #include <linux/slab.h>
24 #include <sound/core.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include <sound/soc.h>
28 #include <sound/dmaengine_pcm.h>
30 #include "tegra20_ac97.h"
32 #define DRV_NAME "tegra20-ac97"
34 static struct tegra20_ac97
*workdata
;
36 static void tegra20_ac97_codec_reset(struct snd_ac97
*ac97
)
39 unsigned long timeout
;
42 * The reset line is not driven by DAC pad group, have to toggle GPIO.
43 * The RESET line is active low but this is abstracted by the GPIO
46 gpiod_set_value(workdata
->reset_gpio
, 1);
49 gpiod_set_value(workdata
->reset_gpio
, 0);
52 timeout
= jiffies
+ msecs_to_jiffies(100);
55 regmap_read(workdata
->regmap
, TEGRA20_AC97_STATUS1
, &readback
);
56 if (readback
& TEGRA20_AC97_STATUS1_CODEC1_RDY
)
58 usleep_range(1000, 2000);
59 } while (!time_after(jiffies
, timeout
));
62 static void tegra20_ac97_codec_warm_reset(struct snd_ac97
*ac97
)
65 unsigned long timeout
;
68 * although sync line is driven by the DAC pad group warm reset using
69 * the controller cmd is not working, have to toggle sync line
72 gpiod_direction_output(workdata
->sync_gpio
, 1);
74 gpiod_set_value(workdata
->sync_gpio
, 0);
77 timeout
= jiffies
+ msecs_to_jiffies(100);
80 regmap_read(workdata
->regmap
, TEGRA20_AC97_STATUS1
, &readback
);
81 if (readback
& TEGRA20_AC97_STATUS1_CODEC1_RDY
)
83 usleep_range(1000, 2000);
84 } while (!time_after(jiffies
, timeout
));
87 static unsigned short tegra20_ac97_codec_read(struct snd_ac97
*ac97_snd
,
91 unsigned long timeout
;
93 regmap_write(workdata
->regmap
, TEGRA20_AC97_CMD
,
94 (((reg
| 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT
) &
95 TEGRA20_AC97_CMD_CMD_ADDR_MASK
) |
96 TEGRA20_AC97_CMD_BUSY
);
98 timeout
= jiffies
+ msecs_to_jiffies(100);
101 regmap_read(workdata
->regmap
, TEGRA20_AC97_STATUS1
, &readback
);
102 if (readback
& TEGRA20_AC97_STATUS1_STA_VALID1
)
104 usleep_range(1000, 2000);
105 } while (!time_after(jiffies
, timeout
));
107 return ((readback
& TEGRA20_AC97_STATUS1_STA_DATA1_MASK
) >>
108 TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT
);
111 static void tegra20_ac97_codec_write(struct snd_ac97
*ac97_snd
,
112 unsigned short reg
, unsigned short val
)
115 unsigned long timeout
;
117 regmap_write(workdata
->regmap
, TEGRA20_AC97_CMD
,
118 ((reg
<< TEGRA20_AC97_CMD_CMD_ADDR_SHIFT
) &
119 TEGRA20_AC97_CMD_CMD_ADDR_MASK
) |
120 ((val
<< TEGRA20_AC97_CMD_CMD_DATA_SHIFT
) &
121 TEGRA20_AC97_CMD_CMD_DATA_MASK
) |
122 TEGRA20_AC97_CMD_BUSY
);
124 timeout
= jiffies
+ msecs_to_jiffies(100);
127 regmap_read(workdata
->regmap
, TEGRA20_AC97_CMD
, &readback
);
128 if (!(readback
& TEGRA20_AC97_CMD_BUSY
))
130 usleep_range(1000, 2000);
131 } while (!time_after(jiffies
, timeout
));
134 static struct snd_ac97_bus_ops tegra20_ac97_ops
= {
135 .read
= tegra20_ac97_codec_read
,
136 .write
= tegra20_ac97_codec_write
,
137 .reset
= tegra20_ac97_codec_reset
,
138 .warm_reset
= tegra20_ac97_codec_warm_reset
,
141 static inline void tegra20_ac97_start_playback(struct tegra20_ac97
*ac97
)
143 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
144 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN
,
145 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN
);
147 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_CTRL
,
148 TEGRA20_AC97_CTRL_PCM_DAC_EN
|
149 TEGRA20_AC97_CTRL_STM_EN
,
150 TEGRA20_AC97_CTRL_PCM_DAC_EN
|
151 TEGRA20_AC97_CTRL_STM_EN
);
154 static inline void tegra20_ac97_stop_playback(struct tegra20_ac97
*ac97
)
156 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
157 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN
, 0);
159 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_CTRL
,
160 TEGRA20_AC97_CTRL_PCM_DAC_EN
, 0);
163 static inline void tegra20_ac97_start_capture(struct tegra20_ac97
*ac97
)
165 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
166 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN
,
167 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN
);
170 static inline void tegra20_ac97_stop_capture(struct tegra20_ac97
*ac97
)
172 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
173 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN
, 0);
176 static int tegra20_ac97_trigger(struct snd_pcm_substream
*substream
, int cmd
,
177 struct snd_soc_dai
*dai
)
179 struct tegra20_ac97
*ac97
= snd_soc_dai_get_drvdata(dai
);
182 case SNDRV_PCM_TRIGGER_START
:
183 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
184 case SNDRV_PCM_TRIGGER_RESUME
:
185 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
186 tegra20_ac97_start_playback(ac97
);
188 tegra20_ac97_start_capture(ac97
);
190 case SNDRV_PCM_TRIGGER_STOP
:
191 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
192 case SNDRV_PCM_TRIGGER_SUSPEND
:
193 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
194 tegra20_ac97_stop_playback(ac97
);
196 tegra20_ac97_stop_capture(ac97
);
205 static int tegra20_ac97_probe(struct snd_soc_dai
*dai
)
207 struct tegra20_ac97
*ac97
= snd_soc_dai_get_drvdata(dai
);
209 snd_soc_dai_init_dma_data(dai
, &ac97
->playback_dma_data
,
210 &ac97
->capture_dma_data
);
215 static const struct snd_soc_dai_ops tegra20_ac97_dai_ops
= {
216 .probe
= tegra20_ac97_probe
,
217 .trigger
= tegra20_ac97_trigger
,
220 static struct snd_soc_dai_driver tegra20_ac97_dai
= {
221 .name
= "tegra-ac97-pcm",
223 .stream_name
= "PCM Playback",
226 .rates
= SNDRV_PCM_RATE_8000_48000
,
227 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
230 .stream_name
= "PCM Capture",
233 .rates
= SNDRV_PCM_RATE_8000_48000
,
234 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
236 .ops
= &tegra20_ac97_dai_ops
,
239 static const struct snd_soc_component_driver tegra20_ac97_component
= {
241 .legacy_dai_naming
= 1,
244 static bool tegra20_ac97_wr_rd_reg(struct device
*dev
, unsigned int reg
)
247 case TEGRA20_AC97_CTRL
:
248 case TEGRA20_AC97_CMD
:
249 case TEGRA20_AC97_STATUS1
:
250 case TEGRA20_AC97_FIFO1_SCR
:
251 case TEGRA20_AC97_FIFO_TX1
:
252 case TEGRA20_AC97_FIFO_RX1
:
261 static bool tegra20_ac97_volatile_reg(struct device
*dev
, unsigned int reg
)
264 case TEGRA20_AC97_STATUS1
:
265 case TEGRA20_AC97_FIFO1_SCR
:
266 case TEGRA20_AC97_FIFO_TX1
:
267 case TEGRA20_AC97_FIFO_RX1
:
276 static bool tegra20_ac97_precious_reg(struct device
*dev
, unsigned int reg
)
279 case TEGRA20_AC97_FIFO_TX1
:
280 case TEGRA20_AC97_FIFO_RX1
:
289 static const struct regmap_config tegra20_ac97_regmap_config
= {
293 .max_register
= TEGRA20_AC97_FIFO_RX1
,
294 .writeable_reg
= tegra20_ac97_wr_rd_reg
,
295 .readable_reg
= tegra20_ac97_wr_rd_reg
,
296 .volatile_reg
= tegra20_ac97_volatile_reg
,
297 .precious_reg
= tegra20_ac97_precious_reg
,
298 .cache_type
= REGCACHE_FLAT
,
301 static int tegra20_ac97_platform_probe(struct platform_device
*pdev
)
303 struct tegra20_ac97
*ac97
;
304 struct resource
*mem
;
308 ac97
= devm_kzalloc(&pdev
->dev
, sizeof(struct tegra20_ac97
),
314 dev_set_drvdata(&pdev
->dev
, ac97
);
316 ac97
->reset
= devm_reset_control_get_exclusive(&pdev
->dev
, "ac97");
317 if (IS_ERR(ac97
->reset
)) {
318 dev_err(&pdev
->dev
, "Can't retrieve ac97 reset\n");
319 ret
= PTR_ERR(ac97
->reset
);
323 ac97
->clk_ac97
= devm_clk_get(&pdev
->dev
, NULL
);
324 if (IS_ERR(ac97
->clk_ac97
)) {
325 dev_err(&pdev
->dev
, "Can't retrieve ac97 clock\n");
326 ret
= PTR_ERR(ac97
->clk_ac97
);
330 regs
= devm_platform_get_and_ioremap_resource(pdev
, 0, &mem
);
336 ac97
->regmap
= devm_regmap_init_mmio(&pdev
->dev
, regs
,
337 &tegra20_ac97_regmap_config
);
338 if (IS_ERR(ac97
->regmap
)) {
339 dev_err(&pdev
->dev
, "regmap init failed\n");
340 ret
= PTR_ERR(ac97
->regmap
);
344 /* Obtain RESET de-asserted */
345 ac97
->reset_gpio
= devm_gpiod_get(&pdev
->dev
,
346 "nvidia,codec-reset",
348 if (IS_ERR(ac97
->reset_gpio
)) {
349 ret
= PTR_ERR(ac97
->reset_gpio
);
350 dev_err(&pdev
->dev
, "no RESET GPIO supplied: %d\n", ret
);
353 gpiod_set_consumer_name(ac97
->reset_gpio
, "codec-reset");
355 ac97
->sync_gpio
= devm_gpiod_get(&pdev
->dev
,
358 if (IS_ERR(ac97
->sync_gpio
)) {
359 ret
= PTR_ERR(ac97
->sync_gpio
);
360 dev_err(&pdev
->dev
, "no codec-sync GPIO supplied: %d\n", ret
);
363 gpiod_set_consumer_name(ac97
->sync_gpio
, "codec-sync");
365 ac97
->capture_dma_data
.addr
= mem
->start
+ TEGRA20_AC97_FIFO_RX1
;
366 ac97
->capture_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
367 ac97
->capture_dma_data
.maxburst
= 4;
369 ac97
->playback_dma_data
.addr
= mem
->start
+ TEGRA20_AC97_FIFO_TX1
;
370 ac97
->playback_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
371 ac97
->playback_dma_data
.maxburst
= 4;
373 ret
= reset_control_assert(ac97
->reset
);
375 dev_err(&pdev
->dev
, "Failed to assert AC'97 reset: %d\n", ret
);
379 ret
= clk_prepare_enable(ac97
->clk_ac97
);
381 dev_err(&pdev
->dev
, "clk_enable failed: %d\n", ret
);
385 usleep_range(10, 100);
387 ret
= reset_control_deassert(ac97
->reset
);
389 dev_err(&pdev
->dev
, "Failed to deassert AC'97 reset: %d\n", ret
);
390 goto err_clk_disable_unprepare
;
393 ret
= snd_soc_set_ac97_ops(&tegra20_ac97_ops
);
395 dev_err(&pdev
->dev
, "Failed to set AC'97 ops: %d\n", ret
);
396 goto err_clk_disable_unprepare
;
399 ret
= snd_soc_register_component(&pdev
->dev
, &tegra20_ac97_component
,
400 &tegra20_ac97_dai
, 1);
402 dev_err(&pdev
->dev
, "Could not register DAI: %d\n", ret
);
404 goto err_clk_disable_unprepare
;
407 ret
= tegra_pcm_platform_register(&pdev
->dev
);
409 dev_err(&pdev
->dev
, "Could not register PCM: %d\n", ret
);
410 goto err_unregister_component
;
413 /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
418 err_unregister_component
:
419 snd_soc_unregister_component(&pdev
->dev
);
420 err_clk_disable_unprepare
:
421 clk_disable_unprepare(ac97
->clk_ac97
);
424 snd_soc_set_ac97_ops(NULL
);
428 static void tegra20_ac97_platform_remove(struct platform_device
*pdev
)
430 struct tegra20_ac97
*ac97
= dev_get_drvdata(&pdev
->dev
);
432 tegra_pcm_platform_unregister(&pdev
->dev
);
433 snd_soc_unregister_component(&pdev
->dev
);
435 clk_disable_unprepare(ac97
->clk_ac97
);
437 snd_soc_set_ac97_ops(NULL
);
440 static const struct of_device_id tegra20_ac97_of_match
[] = {
441 { .compatible
= "nvidia,tegra20-ac97", },
445 static struct platform_driver tegra20_ac97_driver
= {
448 .of_match_table
= tegra20_ac97_of_match
,
450 .probe
= tegra20_ac97_platform_probe
,
451 .remove
= tegra20_ac97_platform_remove
,
453 module_platform_driver(tegra20_ac97_driver
);
455 MODULE_AUTHOR("Lucas Stach");
456 MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver");
457 MODULE_LICENSE("GPL v2");
458 MODULE_ALIAS("platform:" DRV_NAME
);
459 MODULE_DEVICE_TABLE(of
, tegra20_ac97_of_match
);