2 * tegra20_ac97.c - Tegra20 AC97 platform driver
4 * Copyright (c) 2012 Lucas Stach <dev@lynxeye.de>
6 * Partly based on code copyright/by:
8 * Copyright (c) 2011,2012 Toradex Inc.
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * version 2 as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
21 #include <linux/clk.h>
22 #include <linux/delay.h>
23 #include <linux/device.h>
24 #include <linux/gpio.h>
26 #include <linux/jiffies.h>
27 #include <linux/module.h>
29 #include <linux/of_gpio.h>
30 #include <linux/platform_device.h>
31 #include <linux/pm_runtime.h>
32 #include <linux/regmap.h>
33 #include <linux/slab.h>
34 #include <sound/core.h>
35 #include <sound/pcm.h>
36 #include <sound/pcm_params.h>
37 #include <sound/soc.h>
38 #include <sound/dmaengine_pcm.h>
40 #include "tegra_asoc_utils.h"
41 #include "tegra20_ac97.h"
43 #define DRV_NAME "tegra20-ac97"
45 static struct tegra20_ac97
*workdata
;
47 static void tegra20_ac97_codec_reset(struct snd_ac97
*ac97
)
50 unsigned long timeout
;
52 /* reset line is not driven by DAC pad group, have to toggle GPIO */
53 gpio_set_value(workdata
->reset_gpio
, 0);
56 gpio_set_value(workdata
->reset_gpio
, 1);
59 timeout
= jiffies
+ msecs_to_jiffies(100);
62 regmap_read(workdata
->regmap
, TEGRA20_AC97_STATUS1
, &readback
);
63 if (readback
& TEGRA20_AC97_STATUS1_CODEC1_RDY
)
65 usleep_range(1000, 2000);
66 } while (!time_after(jiffies
, timeout
));
69 static void tegra20_ac97_codec_warm_reset(struct snd_ac97
*ac97
)
72 unsigned long timeout
;
75 * although sync line is driven by the DAC pad group warm reset using
76 * the controller cmd is not working, have to toggle sync line
79 gpio_request(workdata
->sync_gpio
, "codec-sync");
81 gpio_direction_output(workdata
->sync_gpio
, 1);
84 gpio_set_value(workdata
->sync_gpio
, 0);
86 gpio_free(workdata
->sync_gpio
);
88 timeout
= jiffies
+ msecs_to_jiffies(100);
91 regmap_read(workdata
->regmap
, TEGRA20_AC97_STATUS1
, &readback
);
92 if (readback
& TEGRA20_AC97_STATUS1_CODEC1_RDY
)
94 usleep_range(1000, 2000);
95 } while (!time_after(jiffies
, timeout
));
98 static unsigned short tegra20_ac97_codec_read(struct snd_ac97
*ac97_snd
,
102 unsigned long timeout
;
104 regmap_write(workdata
->regmap
, TEGRA20_AC97_CMD
,
105 (((reg
| 0x80) << TEGRA20_AC97_CMD_CMD_ADDR_SHIFT
) &
106 TEGRA20_AC97_CMD_CMD_ADDR_MASK
) |
107 TEGRA20_AC97_CMD_BUSY
);
109 timeout
= jiffies
+ msecs_to_jiffies(100);
112 regmap_read(workdata
->regmap
, TEGRA20_AC97_STATUS1
, &readback
);
113 if (readback
& TEGRA20_AC97_STATUS1_STA_VALID1
)
115 usleep_range(1000, 2000);
116 } while (!time_after(jiffies
, timeout
));
118 return ((readback
& TEGRA20_AC97_STATUS1_STA_DATA1_MASK
) >>
119 TEGRA20_AC97_STATUS1_STA_DATA1_SHIFT
);
122 static void tegra20_ac97_codec_write(struct snd_ac97
*ac97_snd
,
123 unsigned short reg
, unsigned short val
)
126 unsigned long timeout
;
128 regmap_write(workdata
->regmap
, TEGRA20_AC97_CMD
,
129 ((reg
<< TEGRA20_AC97_CMD_CMD_ADDR_SHIFT
) &
130 TEGRA20_AC97_CMD_CMD_ADDR_MASK
) |
131 ((val
<< TEGRA20_AC97_CMD_CMD_DATA_SHIFT
) &
132 TEGRA20_AC97_CMD_CMD_DATA_MASK
) |
133 TEGRA20_AC97_CMD_BUSY
);
135 timeout
= jiffies
+ msecs_to_jiffies(100);
138 regmap_read(workdata
->regmap
, TEGRA20_AC97_CMD
, &readback
);
139 if (!(readback
& TEGRA20_AC97_CMD_BUSY
))
141 usleep_range(1000, 2000);
142 } while (!time_after(jiffies
, timeout
));
145 struct snd_ac97_bus_ops soc_ac97_ops
= {
146 .read
= tegra20_ac97_codec_read
,
147 .write
= tegra20_ac97_codec_write
,
148 .reset
= tegra20_ac97_codec_reset
,
149 .warm_reset
= tegra20_ac97_codec_warm_reset
,
151 EXPORT_SYMBOL_GPL(soc_ac97_ops
);
153 static inline void tegra20_ac97_start_playback(struct tegra20_ac97
*ac97
)
155 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
156 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN
,
157 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN
);
159 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_CTRL
,
160 TEGRA20_AC97_CTRL_PCM_DAC_EN
|
161 TEGRA20_AC97_CTRL_STM_EN
,
162 TEGRA20_AC97_CTRL_PCM_DAC_EN
|
163 TEGRA20_AC97_CTRL_STM_EN
);
166 static inline void tegra20_ac97_stop_playback(struct tegra20_ac97
*ac97
)
168 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
169 TEGRA20_AC97_FIFO_SCR_PB_QRT_MT_EN
, 0);
171 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_CTRL
,
172 TEGRA20_AC97_CTRL_PCM_DAC_EN
, 0);
175 static inline void tegra20_ac97_start_capture(struct tegra20_ac97
*ac97
)
177 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
178 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN
,
179 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN
);
182 static inline void tegra20_ac97_stop_capture(struct tegra20_ac97
*ac97
)
184 regmap_update_bits(ac97
->regmap
, TEGRA20_AC97_FIFO1_SCR
,
185 TEGRA20_AC97_FIFO_SCR_REC_FULL_EN
, 0);
188 static int tegra20_ac97_trigger(struct snd_pcm_substream
*substream
, int cmd
,
189 struct snd_soc_dai
*dai
)
191 struct tegra20_ac97
*ac97
= snd_soc_dai_get_drvdata(dai
);
194 case SNDRV_PCM_TRIGGER_START
:
195 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
196 case SNDRV_PCM_TRIGGER_RESUME
:
197 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
198 tegra20_ac97_start_playback(ac97
);
200 tegra20_ac97_start_capture(ac97
);
202 case SNDRV_PCM_TRIGGER_STOP
:
203 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
204 case SNDRV_PCM_TRIGGER_SUSPEND
:
205 if (substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
)
206 tegra20_ac97_stop_playback(ac97
);
208 tegra20_ac97_stop_capture(ac97
);
217 static const struct snd_soc_dai_ops tegra20_ac97_dai_ops
= {
218 .trigger
= tegra20_ac97_trigger
,
221 static int tegra20_ac97_probe(struct snd_soc_dai
*dai
)
223 struct tegra20_ac97
*ac97
= snd_soc_dai_get_drvdata(dai
);
225 dai
->capture_dma_data
= &ac97
->capture_dma_data
;
226 dai
->playback_dma_data
= &ac97
->playback_dma_data
;
231 static struct snd_soc_dai_driver tegra20_ac97_dai
= {
232 .name
= "tegra-ac97-pcm",
234 .probe
= tegra20_ac97_probe
,
236 .stream_name
= "PCM Playback",
239 .rates
= SNDRV_PCM_RATE_8000_48000
,
240 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
243 .stream_name
= "PCM Capture",
246 .rates
= SNDRV_PCM_RATE_8000_48000
,
247 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
249 .ops
= &tegra20_ac97_dai_ops
,
252 static const struct snd_soc_component_driver tegra20_ac97_component
= {
256 static bool tegra20_ac97_wr_rd_reg(struct device
*dev
, unsigned int reg
)
259 case TEGRA20_AC97_CTRL
:
260 case TEGRA20_AC97_CMD
:
261 case TEGRA20_AC97_STATUS1
:
262 case TEGRA20_AC97_FIFO1_SCR
:
263 case TEGRA20_AC97_FIFO_TX1
:
264 case TEGRA20_AC97_FIFO_RX1
:
273 static bool tegra20_ac97_volatile_reg(struct device
*dev
, unsigned int reg
)
276 case TEGRA20_AC97_STATUS1
:
277 case TEGRA20_AC97_FIFO1_SCR
:
278 case TEGRA20_AC97_FIFO_TX1
:
279 case TEGRA20_AC97_FIFO_RX1
:
288 static bool tegra20_ac97_precious_reg(struct device
*dev
, unsigned int reg
)
291 case TEGRA20_AC97_FIFO_TX1
:
292 case TEGRA20_AC97_FIFO_RX1
:
301 static const struct regmap_config tegra20_ac97_regmap_config
= {
305 .max_register
= TEGRA20_AC97_FIFO_RX1
,
306 .writeable_reg
= tegra20_ac97_wr_rd_reg
,
307 .readable_reg
= tegra20_ac97_wr_rd_reg
,
308 .volatile_reg
= tegra20_ac97_volatile_reg
,
309 .precious_reg
= tegra20_ac97_precious_reg
,
310 .cache_type
= REGCACHE_RBTREE
,
313 static int tegra20_ac97_platform_probe(struct platform_device
*pdev
)
315 struct tegra20_ac97
*ac97
;
316 struct resource
*mem
, *memregion
;
321 ac97
= devm_kzalloc(&pdev
->dev
, sizeof(struct tegra20_ac97
),
324 dev_err(&pdev
->dev
, "Can't allocate tegra20_ac97\n");
328 dev_set_drvdata(&pdev
->dev
, ac97
);
330 ac97
->clk_ac97
= clk_get(&pdev
->dev
, NULL
);
331 if (IS_ERR(ac97
->clk_ac97
)) {
332 dev_err(&pdev
->dev
, "Can't retrieve ac97 clock\n");
333 ret
= PTR_ERR(ac97
->clk_ac97
);
337 mem
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
339 dev_err(&pdev
->dev
, "No memory resource\n");
344 memregion
= devm_request_mem_region(&pdev
->dev
, mem
->start
,
345 resource_size(mem
), DRV_NAME
);
347 dev_err(&pdev
->dev
, "Memory region already claimed\n");
352 regs
= devm_ioremap(&pdev
->dev
, mem
->start
, resource_size(mem
));
354 dev_err(&pdev
->dev
, "ioremap failed\n");
359 ac97
->regmap
= devm_regmap_init_mmio(&pdev
->dev
, regs
,
360 &tegra20_ac97_regmap_config
);
361 if (IS_ERR(ac97
->regmap
)) {
362 dev_err(&pdev
->dev
, "regmap init failed\n");
363 ret
= PTR_ERR(ac97
->regmap
);
367 if (of_property_read_u32_array(pdev
->dev
.of_node
,
368 "nvidia,dma-request-selector",
370 dev_err(&pdev
->dev
, "No DMA resource\n");
375 ac97
->reset_gpio
= of_get_named_gpio(pdev
->dev
.of_node
,
376 "nvidia,codec-reset-gpio", 0);
377 if (gpio_is_valid(ac97
->reset_gpio
)) {
378 ret
= devm_gpio_request_one(&pdev
->dev
, ac97
->reset_gpio
,
379 GPIOF_OUT_INIT_HIGH
, "codec-reset");
381 dev_err(&pdev
->dev
, "could not get codec-reset GPIO\n");
385 dev_err(&pdev
->dev
, "no codec-reset GPIO supplied\n");
389 ac97
->sync_gpio
= of_get_named_gpio(pdev
->dev
.of_node
,
390 "nvidia,codec-sync-gpio", 0);
391 if (!gpio_is_valid(ac97
->sync_gpio
)) {
392 dev_err(&pdev
->dev
, "no codec-sync GPIO supplied\n");
396 ac97
->capture_dma_data
.addr
= mem
->start
+ TEGRA20_AC97_FIFO_RX1
;
397 ac97
->capture_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
398 ac97
->capture_dma_data
.maxburst
= 4;
399 ac97
->capture_dma_data
.slave_id
= of_dma
[1];
401 ac97
->playback_dma_data
.addr
= mem
->start
+ TEGRA20_AC97_FIFO_TX1
;
402 ac97
->capture_dma_data
.addr_width
= DMA_SLAVE_BUSWIDTH_4_BYTES
;
403 ac97
->capture_dma_data
.maxburst
= 4;
404 ac97
->capture_dma_data
.slave_id
= of_dma
[0];
406 ret
= snd_soc_register_component(&pdev
->dev
, &tegra20_ac97_component
,
407 &tegra20_ac97_dai
, 1);
409 dev_err(&pdev
->dev
, "Could not register DAI: %d\n", ret
);
414 ret
= tegra_pcm_platform_register(&pdev
->dev
);
416 dev_err(&pdev
->dev
, "Could not register PCM: %d\n", ret
);
417 goto err_unregister_component
;
420 ret
= tegra_asoc_utils_init(&ac97
->util_data
, &pdev
->dev
);
422 goto err_unregister_pcm
;
424 ret
= tegra_asoc_utils_set_ac97_rate(&ac97
->util_data
);
426 goto err_asoc_utils_fini
;
428 ret
= clk_prepare_enable(ac97
->clk_ac97
);
430 dev_err(&pdev
->dev
, "clk_enable failed: %d\n", ret
);
431 goto err_asoc_utils_fini
;
434 /* XXX: crufty ASoC AC97 API - only one AC97 codec allowed */
440 tegra_asoc_utils_fini(&ac97
->util_data
);
442 tegra_pcm_platform_unregister(&pdev
->dev
);
443 err_unregister_component
:
444 snd_soc_unregister_component(&pdev
->dev
);
446 clk_put(ac97
->clk_ac97
);
451 static int tegra20_ac97_platform_remove(struct platform_device
*pdev
)
453 struct tegra20_ac97
*ac97
= dev_get_drvdata(&pdev
->dev
);
455 tegra_pcm_platform_unregister(&pdev
->dev
);
456 snd_soc_unregister_component(&pdev
->dev
);
458 tegra_asoc_utils_fini(&ac97
->util_data
);
460 clk_disable_unprepare(ac97
->clk_ac97
);
461 clk_put(ac97
->clk_ac97
);
466 static const struct of_device_id tegra20_ac97_of_match
[] = {
467 { .compatible
= "nvidia,tegra20-ac97", },
471 static struct platform_driver tegra20_ac97_driver
= {
474 .owner
= THIS_MODULE
,
475 .of_match_table
= tegra20_ac97_of_match
,
477 .probe
= tegra20_ac97_platform_probe
,
478 .remove
= tegra20_ac97_platform_remove
,
480 module_platform_driver(tegra20_ac97_driver
);
482 MODULE_AUTHOR("Lucas Stach");
483 MODULE_DESCRIPTION("Tegra20 AC97 ASoC driver");
484 MODULE_LICENSE("GPL v2");
485 MODULE_ALIAS("platform:" DRV_NAME
);
486 MODULE_DEVICE_TABLE(of
, tegra20_ac97_of_match
);