303 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.4 *5 * Author: Nicolas Pitre6 * Created: Dec 02, 20047 * Copyright: MontaVista Software Inc.8 */9 10#include <linux/init.h>11#include <linux/io.h>12#include <linux/module.h>13#include <linux/platform_device.h>14#include <linux/dmaengine.h>15#include <linux/dma/pxa-dma.h>16 17#include <sound/ac97/controller.h>18#include <sound/core.h>19#include <sound/ac97_codec.h>20#include <sound/soc.h>21#include <sound/pxa2xx-lib.h>22#include <sound/dmaengine_pcm.h>23 24#include <linux/platform_data/asoc-pxa.h>25 26#define PCDR 0x0040 /* PCM FIFO Data Register */27#define MODR 0x0140 /* Modem FIFO Data Register */28#define MCDR 0x0060 /* Mic-in FIFO Data Register */29 30static void pxa2xx_ac97_warm_reset(struct ac97_controller *adrv)31{32 pxa2xx_ac97_try_warm_reset();33 34 pxa2xx_ac97_finish_reset();35}36 37static void pxa2xx_ac97_cold_reset(struct ac97_controller *adrv)38{39 pxa2xx_ac97_try_cold_reset();40 41 pxa2xx_ac97_finish_reset();42}43 44static int pxa2xx_ac97_read_actrl(struct ac97_controller *adrv, int slot,45 unsigned short reg)46{47 return pxa2xx_ac97_read(slot, reg);48}49 50static int pxa2xx_ac97_write_actrl(struct ac97_controller *adrv, int slot,51 unsigned short reg, unsigned short val)52{53 return pxa2xx_ac97_write(slot, reg, val);54}55 56static struct ac97_controller_ops pxa2xx_ac97_ops = {57 .read = pxa2xx_ac97_read_actrl,58 .write = pxa2xx_ac97_write_actrl,59 .warm_reset = pxa2xx_ac97_warm_reset,60 .reset = pxa2xx_ac97_cold_reset,61};62 63static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_in = {64 .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,65 .chan_name = "pcm_pcm_stereo_in",66 .maxburst = 32,67};68 69static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_stereo_out = {70 .addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,71 .chan_name = "pcm_pcm_stereo_out",72 .maxburst = 32,73};74 75static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_out = {76 .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,77 .chan_name = "pcm_aux_mono_out",78 .maxburst = 16,79};80 81static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_aux_mono_in = {82 .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,83 .chan_name = "pcm_aux_mono_in",84 .maxburst = 16,85};86 87static struct snd_dmaengine_dai_dma_data pxa2xx_ac97_pcm_mic_mono_in = {88 .addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,89 .chan_name = "pcm_aux_mic_mono",90 .maxburst = 16,91};92 93static int pxa2xx_ac97_hifi_startup(struct snd_pcm_substream *substream,94 struct snd_soc_dai *cpu_dai)95{96 struct snd_dmaengine_dai_dma_data *dma_data;97 98 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)99 dma_data = &pxa2xx_ac97_pcm_stereo_out;100 else101 dma_data = &pxa2xx_ac97_pcm_stereo_in;102 103 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);104 105 return 0;106}107 108static int pxa2xx_ac97_aux_startup(struct snd_pcm_substream *substream,109 struct snd_soc_dai *cpu_dai)110{111 struct snd_dmaengine_dai_dma_data *dma_data;112 113 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)114 dma_data = &pxa2xx_ac97_pcm_aux_mono_out;115 else116 dma_data = &pxa2xx_ac97_pcm_aux_mono_in;117 118 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);119 120 return 0;121}122 123static int pxa2xx_ac97_mic_startup(struct snd_pcm_substream *substream,124 struct snd_soc_dai *cpu_dai)125{126 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)127 return -ENODEV;128 snd_soc_dai_set_dma_data(cpu_dai, substream,129 &pxa2xx_ac97_pcm_mic_mono_in);130 131 return 0;132}133 134#define PXA2XX_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\135 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_44100 | \136 SNDRV_PCM_RATE_48000)137 138static const struct snd_soc_dai_ops pxa_ac97_hifi_dai_ops = {139 .startup = pxa2xx_ac97_hifi_startup,140};141 142static const struct snd_soc_dai_ops pxa_ac97_aux_dai_ops = {143 .startup = pxa2xx_ac97_aux_startup,144};145 146static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {147 .startup = pxa2xx_ac97_mic_startup,148};149 150/*151 * There is only 1 physical AC97 interface for pxa2xx, but it152 * has extra fifo's that can be used for aux DACs and ADCs.153 */154static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {155{156 .name = "pxa2xx-ac97",157 .playback = {158 .stream_name = "AC97 Playback",159 .channels_min = 2,160 .channels_max = 2,161 .rates = PXA2XX_AC97_RATES,162 .formats = SNDRV_PCM_FMTBIT_S16_LE,},163 .capture = {164 .stream_name = "AC97 Capture",165 .channels_min = 2,166 .channels_max = 2,167 .rates = PXA2XX_AC97_RATES,168 .formats = SNDRV_PCM_FMTBIT_S16_LE,},169 .ops = &pxa_ac97_hifi_dai_ops,170},171{172 .name = "pxa2xx-ac97-aux",173 .playback = {174 .stream_name = "AC97 Aux Playback",175 .channels_min = 1,176 .channels_max = 1,177 .rates = PXA2XX_AC97_RATES,178 .formats = SNDRV_PCM_FMTBIT_S16_LE,},179 .capture = {180 .stream_name = "AC97 Aux Capture",181 .channels_min = 1,182 .channels_max = 1,183 .rates = PXA2XX_AC97_RATES,184 .formats = SNDRV_PCM_FMTBIT_S16_LE,},185 .ops = &pxa_ac97_aux_dai_ops,186},187{188 .name = "pxa2xx-ac97-mic",189 .capture = {190 .stream_name = "AC97 Mic Capture",191 .channels_min = 1,192 .channels_max = 1,193 .rates = PXA2XX_AC97_RATES,194 .formats = SNDRV_PCM_FMTBIT_S16_LE,},195 .ops = &pxa_ac97_mic_dai_ops,196},197};198 199static const struct snd_soc_component_driver pxa_ac97_component = {200 .name = "pxa-ac97",201 .pcm_construct = pxa2xx_soc_pcm_new,202 .open = pxa2xx_soc_pcm_open,203 .close = pxa2xx_soc_pcm_close,204 .hw_params = pxa2xx_soc_pcm_hw_params,205 .prepare = pxa2xx_soc_pcm_prepare,206 .trigger = pxa2xx_soc_pcm_trigger,207 .pointer = pxa2xx_soc_pcm_pointer,208};209 210#ifdef CONFIG_OF211static const struct of_device_id pxa2xx_ac97_dt_ids[] = {212 { .compatible = "marvell,pxa250-ac97", },213 { .compatible = "marvell,pxa270-ac97", },214 { .compatible = "marvell,pxa300-ac97", },215 { }216};217MODULE_DEVICE_TABLE(of, pxa2xx_ac97_dt_ids);218 219#endif220 221static int pxa2xx_ac97_dev_probe(struct platform_device *pdev)222{223 int ret;224 struct ac97_controller *ctrl;225 pxa2xx_audio_ops_t *pdata = pdev->dev.platform_data;226 struct resource *regs;227 void **codecs_pdata;228 229 if (pdev->id != -1) {230 dev_err(&pdev->dev, "PXA2xx has only one AC97 port.\n");231 return -ENXIO;232 }233 234 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);235 if (!regs)236 return -ENXIO;237 238 pxa2xx_ac97_pcm_stereo_in.addr = regs->start + PCDR;239 pxa2xx_ac97_pcm_stereo_out.addr = regs->start + PCDR;240 pxa2xx_ac97_pcm_aux_mono_out.addr = regs->start + MODR;241 pxa2xx_ac97_pcm_aux_mono_in.addr = regs->start + MODR;242 pxa2xx_ac97_pcm_mic_mono_in.addr = regs->start + MCDR;243 244 ret = pxa2xx_ac97_hw_probe(pdev);245 if (ret) {246 dev_err(&pdev->dev, "PXA2xx AC97 hw probe error (%d)\n", ret);247 return ret;248 }249 250 codecs_pdata = pdata ? pdata->codec_pdata : NULL;251 ctrl = snd_ac97_controller_register(&pxa2xx_ac97_ops, &pdev->dev,252 AC97_SLOTS_AVAILABLE_ALL,253 codecs_pdata);254 if (IS_ERR(ctrl))255 return PTR_ERR(ctrl);256 257 platform_set_drvdata(pdev, ctrl);258 /* Punt most of the init to the SoC probe; we may need the machine259 * driver to do interesting things with the clocking to get us up260 * and running.261 */262 return devm_snd_soc_register_component(&pdev->dev, &pxa_ac97_component,263 pxa_ac97_dai_driver, ARRAY_SIZE(pxa_ac97_dai_driver));264}265 266static void pxa2xx_ac97_dev_remove(struct platform_device *pdev)267{268 struct ac97_controller *ctrl = platform_get_drvdata(pdev);269 270 snd_ac97_controller_unregister(ctrl);271 pxa2xx_ac97_hw_remove(pdev);272}273 274static int pxa2xx_ac97_dev_suspend(struct device *dev)275{276 return pxa2xx_ac97_hw_suspend();277}278 279static int pxa2xx_ac97_dev_resume(struct device *dev)280{281 return pxa2xx_ac97_hw_resume();282}283 284static DEFINE_SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops,285 pxa2xx_ac97_dev_suspend, pxa2xx_ac97_dev_resume);286 287static struct platform_driver pxa2xx_ac97_driver = {288 .probe = pxa2xx_ac97_dev_probe,289 .remove = pxa2xx_ac97_dev_remove,290 .driver = {291 .name = "pxa2xx-ac97",292 .pm = &pxa2xx_ac97_pm_ops,293 .of_match_table = of_match_ptr(pxa2xx_ac97_dt_ids),294 },295};296 297module_platform_driver(pxa2xx_ac97_driver);298 299MODULE_AUTHOR("Nicolas Pitre");300MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");301MODULE_LICENSE("GPL");302MODULE_ALIAS("platform:pxa2xx-ac97");303