brintos

brintos / linux-shallow public Read only

0
0
Text · 7.8 KiB · 78f5003 Raw
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