175b41027SLiam Girdwood /* 275b41027SLiam Girdwood * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip. 375b41027SLiam Girdwood * 475b41027SLiam Girdwood * Author: Nicolas Pitre 575b41027SLiam Girdwood * Created: Dec 02, 2004 675b41027SLiam Girdwood * Copyright: MontaVista Software Inc. 775b41027SLiam Girdwood * 875b41027SLiam Girdwood * This program is free software; you can redistribute it and/or modify 975b41027SLiam Girdwood * it under the terms of the GNU General Public License version 2 as 1075b41027SLiam Girdwood * published by the Free Software Foundation. 1175b41027SLiam Girdwood */ 1275b41027SLiam Girdwood 1375b41027SLiam Girdwood #include <linux/init.h> 1423019a73SRob Herring #include <linux/io.h> 1575b41027SLiam Girdwood #include <linux/module.h> 1675b41027SLiam Girdwood #include <linux/platform_device.h> 17d65a1458SDaniel Mack #include <linux/dmaengine.h> 1858ceb57eSDaniel Mack #include <linux/dma/pxa-dma.h> 1975b41027SLiam Girdwood 201c8bc7b3SRobert Jarzmik #include <sound/ac97/controller.h> 2175b41027SLiam Girdwood #include <sound/core.h> 2275b41027SLiam Girdwood #include <sound/ac97_codec.h> 2375b41027SLiam Girdwood #include <sound/soc.h> 249c636342SDmitry Baryshkov #include <sound/pxa2xx-lib.h> 25d65a1458SDaniel Mack #include <sound/dmaengine_pcm.h> 2675b41027SLiam Girdwood 27a09e64fbSRussell King #include <mach/hardware.h> 281f017a99SEric Miao #include <mach/regs-ac97.h> 294ac0478fSMarek Vasut #include <mach/audio.h> 3075b41027SLiam Girdwood 311c8bc7b3SRobert Jarzmik static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv) 3275b41027SLiam Girdwood { 336f8acad6SRobert Jarzmik pxa2xx_ac97_try_warm_reset(); 3475b41027SLiam Girdwood 356f8acad6SRobert Jarzmik pxa2xx_ac97_finish_reset(); 3675b41027SLiam Girdwood } 3775b41027SLiam Girdwood 381c8bc7b3SRobert Jarzmik static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv) 3975b41027SLiam Girdwood { 406f8acad6SRobert Jarzmik pxa2xx_ac97_try_cold_reset(); 417a22323bSMark Brown 426f8acad6SRobert Jarzmik pxa2xx_ac97_finish_reset(); 436f8acad6SRobert Jarzmik } 446f8acad6SRobert Jarzmik 451c8bc7b3SRobert Jarzmik static int pxa2xx_ac97_read_actrl(struct ac97_controller *adrv, int slot, 466f8acad6SRobert Jarzmik unsigned short reg) 476f8acad6SRobert Jarzmik { 481c8bc7b3SRobert Jarzmik return pxa2xx_ac97_read(slot, reg); 496f8acad6SRobert Jarzmik } 506f8acad6SRobert Jarzmik 511c8bc7b3SRobert Jarzmik static int pxa2xx_ac97_write_actrl(struct ac97_controller *adrv, int slot, 526f8acad6SRobert Jarzmik unsigned short reg, unsigned short val) 536f8acad6SRobert Jarzmik { 541c8bc7b3SRobert Jarzmik return pxa2xx_ac97_write(slot, reg, val); 5575b41027SLiam Girdwood } 5675b41027SLiam Girdwood 571c8bc7b3SRobert Jarzmik static struct ac97_controller_ops pxa2xx_ac97_ops = { 581c8bc7b3SRobert Jarzmik .read = pxa2xx_ac97_read_actrl, 591c8bc7b3SRobert Jarzmik .write = pxa2xx_ac97_write_actrl, 6075b41027SLiam Girdwood .warm_reset = pxa2xx_ac97_warm_reset, 6175b41027SLiam Girdwood .reset = pxa2xx_ac97_cold_reset, 6275b41027SLiam Girdwood }; 6375b41027SLiam Girdwood 64d65a1458SDaniel Mack static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = { 65d65a1458SDaniel Mack .addr = __PREG(PCDR), 66d65a1458SDaniel Mack .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 678f54061dSRobert Jarzmik .chan_name = "pcm_pcm_stereo_in", 68d65a1458SDaniel Mack .maxburst = 32, 6958ceb57eSDaniel Mack }; 7058ceb57eSDaniel Mack 71d65a1458SDaniel Mack static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = { 72d65a1458SDaniel Mack .addr = __PREG(PCDR), 73d65a1458SDaniel Mack .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES, 748f54061dSRobert Jarzmik .chan_name = "pcm_pcm_stereo_out", 75d65a1458SDaniel Mack .maxburst = 32, 7675b41027SLiam Girdwood }; 7775b41027SLiam Girdwood 78d65a1458SDaniel Mack static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = { 79d65a1458SDaniel Mack .addr = __PREG(MODR), 80d65a1458SDaniel Mack .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, 818f54061dSRobert Jarzmik .chan_name = "pcm_aux_mono_out", 82d65a1458SDaniel Mack .maxburst = 16, 8375b41027SLiam Girdwood }; 8475b41027SLiam Girdwood 85d65a1458SDaniel Mack static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = { 86d65a1458SDaniel Mack .addr = __PREG(MODR), 87d65a1458SDaniel Mack .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, 888f54061dSRobert Jarzmik .chan_name = "pcm_aux_mono_in", 89d65a1458SDaniel Mack .maxburst = 16, 9075b41027SLiam Girdwood }; 9175b41027SLiam Girdwood 92d65a1458SDaniel Mack static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = { 93d65a1458SDaniel Mack .addr = __PREG(MCDR), 94d65a1458SDaniel Mack .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES, 958f54061dSRobert Jarzmik .chan_name = "pcm_aux_mic_mono", 96d65a1458SDaniel Mack .maxburst = 16, 9775b41027SLiam Girdwood }; 9875b41027SLiam Girdwood 9958ceb57eSDaniel Mack static int pxa2xx_ac97_hifi_startup(struct snd_pcm_substream *substream, 100f0fba2adSLiam Girdwood struct snd_soc_dai *cpu_dai) 10175b41027SLiam Girdwood { 102d65a1458SDaniel Mack struct snd_dmaengine_dai_dma_data *dma_data; 10375b41027SLiam Girdwood 10475b41027SLiam Girdwood if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1055f712b2bSDaniel Mack dma_data = &pxa2xx_ac97_pcm_stereo_out; 10675b41027SLiam Girdwood else 1075f712b2bSDaniel Mack dma_data = &pxa2xx_ac97_pcm_stereo_in; 1085f712b2bSDaniel Mack 1095f712b2bSDaniel Mack snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); 11075b41027SLiam Girdwood 11175b41027SLiam Girdwood return 0; 11275b41027SLiam Girdwood } 11375b41027SLiam Girdwood 11458ceb57eSDaniel Mack static int pxa2xx_ac97_aux_startup(struct snd_pcm_substream *substream, 115f0fba2adSLiam Girdwood struct snd_soc_dai *cpu_dai) 11675b41027SLiam Girdwood { 117d65a1458SDaniel Mack struct snd_dmaengine_dai_dma_data *dma_data; 11875b41027SLiam Girdwood 11975b41027SLiam Girdwood if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 1205f712b2bSDaniel Mack dma_data = &pxa2xx_ac97_pcm_aux_mono_out; 12175b41027SLiam Girdwood else 1225f712b2bSDaniel Mack dma_data = &pxa2xx_ac97_pcm_aux_mono_in; 1235f712b2bSDaniel Mack 1245f712b2bSDaniel Mack snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data); 12575b41027SLiam Girdwood 12675b41027SLiam Girdwood return 0; 12775b41027SLiam Girdwood } 12875b41027SLiam Girdwood 12958ceb57eSDaniel Mack static int pxa2xx_ac97_mic_startup(struct snd_pcm_substream *substream, 130f0fba2adSLiam Girdwood struct snd_soc_dai *cpu_dai) 13175b41027SLiam Girdwood { 13275b41027SLiam Girdwood if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 13375b41027SLiam Girdwood return -ENODEV; 1345f712b2bSDaniel Mack snd_soc_dai_set_dma_data(cpu_dai, substream, 1355f712b2bSDaniel Mack &pxa2xx_ac97_pcm_mic_mono_in); 13675b41027SLiam Girdwood 13775b41027SLiam Girdwood return 0; 13875b41027SLiam Girdwood } 13975b41027SLiam Girdwood 140596ce32bSLiam Girdwood #define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ 141596ce32bSLiam Girdwood SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \ 142596ce32bSLiam Girdwood SNDRV_PCM_RATE_48000) 143596ce32bSLiam Girdwood 14485e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = { 14558ceb57eSDaniel Mack .startup = pxa2xx_ac97_hifi_startup, 1466335d055SEric Miao }; 1476335d055SEric Miao 14885e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = { 14958ceb57eSDaniel Mack .startup = pxa2xx_ac97_aux_startup, 150852fd9e5SMark Brown }; 151852fd9e5SMark Brown 15285e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = { 15358ceb57eSDaniel Mack .startup = pxa2xx_ac97_mic_startup, 154852fd9e5SMark Brown }; 155852fd9e5SMark Brown 15675b41027SLiam Girdwood /* 15775b41027SLiam Girdwood * There is only 1 physical AC97 interface for pxa2xx, but it 15875b41027SLiam Girdwood * has extra fifo's that can be used for aux DACs and ADCs. 15975b41027SLiam Girdwood */ 160a3874196SAxel Lin static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = { 16175b41027SLiam Girdwood { 16275b41027SLiam Girdwood .name = "pxa2xx-ac97", 163bc263214SLars-Peter Clausen .bus_control = true, 16475b41027SLiam Girdwood .playback = { 16575b41027SLiam Girdwood .stream_name = "AC97 Playback", 16675b41027SLiam Girdwood .channels_min = 2, 167596ce32bSLiam Girdwood .channels_max = 2, 168596ce32bSLiam Girdwood .rates = PXA2XX_AC97_RATES, 169596ce32bSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 17075b41027SLiam Girdwood .capture = { 17175b41027SLiam Girdwood .stream_name = "AC97 Capture", 17275b41027SLiam Girdwood .channels_min = 2, 173596ce32bSLiam Girdwood .channels_max = 2, 174596ce32bSLiam Girdwood .rates = PXA2XX_AC97_RATES, 175596ce32bSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 176852fd9e5SMark Brown .ops = &pxa_ac97_hifi_dai_ops, 17775b41027SLiam Girdwood }, 17875b41027SLiam Girdwood { 17975b41027SLiam Girdwood .name = "pxa2xx-ac97-aux", 180bc263214SLars-Peter Clausen .bus_control = true, 18175b41027SLiam Girdwood .playback = { 18275b41027SLiam Girdwood .stream_name = "AC97 Aux Playback", 18375b41027SLiam Girdwood .channels_min = 1, 184596ce32bSLiam Girdwood .channels_max = 1, 185596ce32bSLiam Girdwood .rates = PXA2XX_AC97_RATES, 186596ce32bSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 18775b41027SLiam Girdwood .capture = { 18875b41027SLiam Girdwood .stream_name = "AC97 Aux Capture", 18975b41027SLiam Girdwood .channels_min = 1, 190596ce32bSLiam Girdwood .channels_max = 1, 191596ce32bSLiam Girdwood .rates = PXA2XX_AC97_RATES, 192596ce32bSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 193852fd9e5SMark Brown .ops = &pxa_ac97_aux_dai_ops, 19475b41027SLiam Girdwood }, 19575b41027SLiam Girdwood { 19675b41027SLiam Girdwood .name = "pxa2xx-ac97-mic", 197bc263214SLars-Peter Clausen .bus_control = true, 19875b41027SLiam Girdwood .capture = { 19975b41027SLiam Girdwood .stream_name = "AC97 Mic Capture", 20075b41027SLiam Girdwood .channels_min = 1, 201596ce32bSLiam Girdwood .channels_max = 1, 202596ce32bSLiam Girdwood .rates = PXA2XX_AC97_RATES, 203596ce32bSLiam Girdwood .formats = SNDRV_PCM_FMTBIT_S16_LE,}, 204852fd9e5SMark Brown .ops = &pxa_ac97_mic_dai_ops, 205596ce32bSLiam Girdwood }, 20675b41027SLiam Girdwood }; 20775b41027SLiam Girdwood 208ad53232cSKuninori Morimoto static const struct snd_soc_component_driver pxa_ac97_component = { 209ad53232cSKuninori Morimoto .name = "pxa-ac97", 210d767d3ceSDaniel Mack .ops = &pxa2xx_pcm_ops, 211d767d3ceSDaniel Mack .pcm_new = pxa2xx_soc_pcm_new, 212d767d3ceSDaniel Mack .pcm_free = pxa2xx_pcm_free_dma_buffers, 213ad53232cSKuninori Morimoto }; 214ad53232cSKuninori Morimoto 215a4519526SRobert Jarzmik #ifdef CONFIG_OF 216a4519526SRobert Jarzmik static const struct of_device_id pxa2xx_ac97_dt_ids[] = { 217a4519526SRobert Jarzmik { .compatible = "marvell,pxa250-ac97", }, 218a4519526SRobert Jarzmik { .compatible = "marvell,pxa270-ac97", }, 219a4519526SRobert Jarzmik { .compatible = "marvell,pxa300-ac97", }, 220a4519526SRobert Jarzmik { } 221a4519526SRobert Jarzmik }; 222a4519526SRobert Jarzmik MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids); 223a4519526SRobert Jarzmik 224a4519526SRobert Jarzmik #endif 225a4519526SRobert Jarzmik 226570f6fe1SBill Pemberton static int pxa2xx_ac97_dev_probe(struct platform_device *pdev) 2276b849bcfSMark Brown { 2287685e016SKevin Hilman int ret; 2291c8bc7b3SRobert Jarzmik struct ac97_controller *ctrl; 2301c8bc7b3SRobert Jarzmik pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data; 2311c8bc7b3SRobert Jarzmik void **codecs_pdata; 2327685e016SKevin Hilman 233f0fba2adSLiam Girdwood if (pdev->id != -1) { 2344ac0478fSMarek Vasut dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n"); 2354ac0478fSMarek Vasut return -ENXIO; 2364ac0478fSMarek Vasut } 2374ac0478fSMarek Vasut 238f62aa9b6SDmitry Eremin-Solenikov ret = pxa2xx_ac97_hw_probe(pdev); 239f62aa9b6SDmitry Eremin-Solenikov if (ret) { 240f62aa9b6SDmitry Eremin-Solenikov dev_err(&pdev->dev, "PXA2xx AC97 hw probe error (%d)\n", ret); 241f62aa9b6SDmitry Eremin-Solenikov return ret; 242f62aa9b6SDmitry Eremin-Solenikov } 243f62aa9b6SDmitry Eremin-Solenikov 2441c8bc7b3SRobert Jarzmik codecs_pdata = pdata ? pdata->codec_pdata : NULL; 2451c8bc7b3SRobert Jarzmik ctrl = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev, 2461c8bc7b3SRobert Jarzmik AC97_SLOTS_AVAILABLE_ALL, 2471c8bc7b3SRobert Jarzmik codecs_pdata); 2481c8bc7b3SRobert Jarzmik if (IS_ERR(ctrl)) 2491c8bc7b3SRobert Jarzmik return PTR_ERR(ctrl); 250b047e1ccSMark Brown 2511c8bc7b3SRobert Jarzmik platform_set_drvdata(pdev, ctrl); 2526b849bcfSMark Brown /* Punt most of the init to the SoC probe; we may need the machine 2536b849bcfSMark Brown * driver to do interesting things with the clocking to get us up 2546b849bcfSMark Brown * and running. 2556b849bcfSMark Brown */ 256ad53232cSKuninori Morimoto return snd_soc_register_component(&pdev->dev, &pxa_ac97_component, 257ad53232cSKuninori Morimoto pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver)); 2586b849bcfSMark Brown } 2596b849bcfSMark Brown 260570f6fe1SBill Pemberton static int pxa2xx_ac97_dev_remove(struct platform_device *pdev) 2616b849bcfSMark Brown { 2621c8bc7b3SRobert Jarzmik struct ac97_controller *ctrl = platform_get_drvdata(pdev); 2631c8bc7b3SRobert Jarzmik 264ad53232cSKuninori Morimoto snd_soc_unregister_component(&pdev->dev); 2651c8bc7b3SRobert Jarzmik snd_ac97_controller_unregister(ctrl); 266f62aa9b6SDmitry Eremin-Solenikov pxa2xx_ac97_hw_remove(pdev); 2676b849bcfSMark Brown return 0; 2686b849bcfSMark Brown } 2696b849bcfSMark Brown 270f62aa9b6SDmitry Eremin-Solenikov #ifdef CONFIG_PM_SLEEP 271f62aa9b6SDmitry Eremin-Solenikov static int pxa2xx_ac97_dev_suspend(struct device *dev) 272f62aa9b6SDmitry Eremin-Solenikov { 273f62aa9b6SDmitry Eremin-Solenikov return pxa2xx_ac97_hw_suspend(); 274f62aa9b6SDmitry Eremin-Solenikov } 275f62aa9b6SDmitry Eremin-Solenikov 276f62aa9b6SDmitry Eremin-Solenikov static int pxa2xx_ac97_dev_resume(struct device *dev) 277f62aa9b6SDmitry Eremin-Solenikov { 278f62aa9b6SDmitry Eremin-Solenikov return pxa2xx_ac97_hw_resume(); 279f62aa9b6SDmitry Eremin-Solenikov } 280f62aa9b6SDmitry Eremin-Solenikov 281f62aa9b6SDmitry Eremin-Solenikov static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, 282f62aa9b6SDmitry Eremin-Solenikov pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume); 283f62aa9b6SDmitry Eremin-Solenikov #endif 284f62aa9b6SDmitry Eremin-Solenikov 2856b849bcfSMark Brown static struct platform_driver pxa2xx_ac97_driver = { 2866b849bcfSMark Brown .probe = pxa2xx_ac97_dev_probe, 287570f6fe1SBill Pemberton .remove = pxa2xx_ac97_dev_remove, 2886b849bcfSMark Brown .driver = { 2896b849bcfSMark Brown .name = "pxa2xx-ac97", 290f62aa9b6SDmitry Eremin-Solenikov #ifdef CONFIG_PM_SLEEP 291f62aa9b6SDmitry Eremin-Solenikov .pm = &pxa2xx_ac97_pm_ops, 292f62aa9b6SDmitry Eremin-Solenikov #endif 293a4519526SRobert Jarzmik .of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids), 2946b849bcfSMark Brown }, 2956b849bcfSMark Brown }; 2966b849bcfSMark Brown 2972f702a19SAxel Lin module_platform_driver(pxa2xx_ac97_driver); 2983f4b783cSMark Brown 29975b41027SLiam Girdwood MODULE_AUTHOR("Nicolas Pitre"); 30075b41027SLiam Girdwood MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip"); 30175b41027SLiam Girdwood MODULE_LICENSE("GPL"); 302e5b7d71aSAndrea Adami MODULE_ALIAS("platform:pxa2xx-ac97"); 303