Blame view

sound/arm/pxa2xx-ac97.c 6.91 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
2
3
4
5
6
7
  /*
   * linux/sound/pxa2xx-ac97.c -- AC97 support for the Intel PXA2xx chip.
   *
   * Author:	Nicolas Pitre
   * Created:	Dec 02, 2004
   * Copyright:	MontaVista Software Inc.
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
8
9
10
   */
  
  #include <linux/init.h>
23019a733   Rob Herring   ARM: pxa: use com...
11
  #include <linux/io.h>
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
12
  #include <linux/module.h>
d052d1bef   Russell King   Create platform_d...
13
  #include <linux/platform_device.h>
d65a14587   Daniel Mack   ASoC: pxa: use sn...
14
  #include <linux/dmaengine.h>
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
15
  #include <linux/dma-mapping.h>
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
16

2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
17
18
19
20
  #include <sound/core.h>
  #include <sound/pcm.h>
  #include <sound/ac97_codec.h>
  #include <sound/initval.h>
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
21
  #include <sound/pxa2xx-lib.h>
d65a14587   Daniel Mack   ASoC: pxa: use sn...
22
  #include <sound/dmaengine_pcm.h>
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
23

1f017a996   Eric Miao   [ARM] pxa: move A...
24
  #include <mach/regs-ac97.h>
a09e64fbc   Russell King   [ARM] Move includ...
25
  #include <mach/audio.h>
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
26

6f8acad64   Robert Jarzmik   ASoC: arm: make p...
27
  static void pxa2xx_ac97_legacy_reset(struct snd_ac97 *ac97)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
28
  {
6f8acad64   Robert Jarzmik   ASoC: arm: make p...
29
30
  	if (!pxa2xx_ac97_try_cold_reset())
  		pxa2xx_ac97_try_warm_reset();
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
31

6f8acad64   Robert Jarzmik   ASoC: arm: make p...
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
  	pxa2xx_ac97_finish_reset();
  }
  
  static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
  					      unsigned short reg)
  {
  	int ret;
  
  	ret = pxa2xx_ac97_read(ac97->num, reg);
  	if (ret < 0)
  		return 0;
  	else
  		return (unsigned short)(ret & 0xffff);
  }
  
  static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
  				     unsigned short reg, unsigned short val)
  {
  	int __always_unused ret;
  
  	ret = pxa2xx_ac97_write(ac97->num, reg, val);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
53
  }
74d2bae34   Takashi Iwai   ALSA: arm: Consti...
54
  static const struct snd_ac97_bus_ops pxa2xx_ac97_ops = {
6f8acad64   Robert Jarzmik   ASoC: arm: make p...
55
56
57
  	.read	= pxa2xx_ac97_legacy_read,
  	.write	= pxa2xx_ac97_legacy_write,
  	.reset	= pxa2xx_ac97_legacy_reset,
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
58
  };
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
59
60
  static struct snd_pcm *pxa2xx_ac97_pcm;
  static struct snd_ac97 *pxa2xx_ac97_ac97;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
61

95acb005f   Daniel Mack   ASoC: fold pxa2xx...
62
  static int pxa2xx_ac97_pcm_open(struct snd_pcm_substream *substream)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
63
  {
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
64
  	struct snd_pcm_runtime *runtime = substream->runtime;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
65
  	pxa2xx_audio_ops_t *platform_ops;
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
66
  	int ret, i;
a7160670b   Daniel Mack   ASoC: pxa: clean ...
67
  	ret = pxa2xx_pcm_open(substream);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
68
69
  	if (ret)
  		return ret;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
70
71
72
  
  	runtime->hw.channels_min = 2;
  	runtime->hw.channels_max = 2;
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
73
74
75
  	i = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
  		AC97_RATES_FRONT_DAC : AC97_RATES_ADC;
  	runtime->hw.rates = pxa2xx_ac97_ac97->rates[i];
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
76
  	snd_pcm_limit_hw_rates(runtime);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
77
78
79
80
  	platform_ops = substream->pcm->card->dev->platform_data;
  	if (platform_ops && platform_ops->startup) {
  		ret = platform_ops->startup(substream, platform_ops->priv);
  		if (ret < 0)
a7160670b   Daniel Mack   ASoC: pxa: clean ...
81
  			pxa2xx_pcm_close(substream);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
82
83
84
  	}
  
  	return ret;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
85
  }
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
86
  static int pxa2xx_ac97_pcm_close(struct snd_pcm_substream *substream)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
87
88
  {
  	pxa2xx_audio_ops_t *platform_ops;
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
89
  	platform_ops = substream->pcm->card->dev->platform_data;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
90
91
  	if (platform_ops && platform_ops->shutdown)
  		platform_ops->shutdown(substream, platform_ops->priv);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
92
93
  
  	return 0;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
94
  }
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
95
  static int pxa2xx_ac97_pcm_prepare(struct snd_pcm_substream *substream)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
96
  {
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
97
  	struct snd_pcm_runtime *runtime = substream->runtime;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
98
99
  	int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
  		  AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
100
  	int ret;
a7160670b   Daniel Mack   ASoC: pxa: clean ...
101
  	ret = pxa2xx_pcm_prepare(substream);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
102
103
  	if (ret < 0)
  		return ret;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
104
105
  	return snd_ac97_set_rate(pxa2xx_ac97_ac97, reg, runtime->rate);
  }
d34e4e00a   Takashi Iwai   ALSA: platform: C...
106
  #ifdef CONFIG_PM_SLEEP
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
107

284e7ca75   Takashi Iwai   ALSA: convert PM ...
108
  static int pxa2xx_ac97_do_suspend(struct snd_card *card)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
109
  {
792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
110
111
112
  	pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3cold);
792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
113
114
115
  	snd_ac97_suspend(pxa2xx_ac97_ac97);
  	if (platform_ops && platform_ops->suspend)
  		platform_ops->suspend(platform_ops->priv);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
116

9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
117
  	return pxa2xx_ac97_hw_suspend();
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
118
  }
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
119
  static int pxa2xx_ac97_do_resume(struct snd_card *card)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
120
  {
792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
121
  	pxa2xx_audio_ops_t *platform_ops = card->dev->platform_data;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
122
123
124
125
126
  	int rc;
  
  	rc = pxa2xx_ac97_hw_resume();
  	if (rc)
  		return rc;
792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
127

792a6c518   Takashi Iwai   [ALSA] Fix PM sup...
128
129
130
131
  	if (platform_ops && platform_ops->resume)
  		platform_ops->resume(platform_ops->priv);
  	snd_ac97_resume(pxa2xx_ac97_ac97);
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
132
133
134
  
  	return 0;
  }
2ba9fd0d1   Mike Rapoport   [ARM] pxa: update...
135
  static int pxa2xx_ac97_suspend(struct device *dev)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
136
  {
2ba9fd0d1   Mike Rapoport   [ARM] pxa: update...
137
  	struct snd_card *card = dev_get_drvdata(dev);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
138
  	int ret = 0;
9480e307c   Russell King   [PATCH] DRIVER MO...
139
  	if (card)
284e7ca75   Takashi Iwai   ALSA: convert PM ...
140
  		ret = pxa2xx_ac97_do_suspend(card);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
141
142
143
  
  	return ret;
  }
2ba9fd0d1   Mike Rapoport   [ARM] pxa: update...
144
  static int pxa2xx_ac97_resume(struct device *dev)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
145
  {
2ba9fd0d1   Mike Rapoport   [ARM] pxa: update...
146
  	struct snd_card *card = dev_get_drvdata(dev);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
147
  	int ret = 0;
9480e307c   Russell King   [PATCH] DRIVER MO...
148
  	if (card)
a55bfdc58   Dirk Opfer   [ALSA] Fix compil...
149
  		ret = pxa2xx_ac97_do_resume(card);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
150
151
152
  
  	return ret;
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
153
  static SIMPLE_DEV_PM_OPS(pxa2xx_ac97_pm_ops, pxa2xx_ac97_suspend, pxa2xx_ac97_resume);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
154
  #endif
7afd1b0b2   Daniel Mack   ASoC: pxa: move s...
155
  static const struct snd_pcm_ops pxa2xx_ac97_pcm_ops = {
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
156
157
  	.open		= pxa2xx_ac97_pcm_open,
  	.close		= pxa2xx_ac97_pcm_close,
a7160670b   Daniel Mack   ASoC: pxa: clean ...
158
159
  	.hw_params	= pxa2xx_pcm_hw_params,
  	.hw_free	= pxa2xx_pcm_hw_free,
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
  	.prepare	= pxa2xx_ac97_pcm_prepare,
  	.trigger	= pxa2xx_pcm_trigger,
  	.pointer	= pxa2xx_pcm_pointer,
  	.mmap		= pxa2xx_pcm_mmap,
  };
  
  
  static int pxa2xx_ac97_pcm_new(struct snd_card *card)
  {
  	struct snd_pcm *pcm;
  	int stream, ret;
  
  	ret = snd_pcm_new(card, "PXA2xx-PCM", 0, 1, 1, &pcm);
  	if (ret)
  		goto out;
  
  	pcm->private_free = pxa2xx_pcm_free_dma_buffers;
  
  	ret = dma_coerce_mask_and_coherent(card->dev, DMA_BIT_MASK(32));
  	if (ret)
  		goto out;
  
  	stream = SNDRV_PCM_STREAM_PLAYBACK;
7afd1b0b2   Daniel Mack   ASoC: pxa: move s...
183
  	snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
184
185
186
187
188
  	ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
  	if (ret)
  		goto out;
  
  	stream = SNDRV_PCM_STREAM_CAPTURE;
7afd1b0b2   Daniel Mack   ASoC: pxa: move s...
189
  	snd_pcm_set_ops(pcm, stream, &pxa2xx_ac97_pcm_ops);
95acb005f   Daniel Mack   ASoC: fold pxa2xx...
190
191
192
193
194
195
196
197
198
199
  	ret = pxa2xx_pcm_preallocate_dma_buffer(pcm, stream);
  	if (ret)
  		goto out;
  
  	pxa2xx_ac97_pcm = pcm;
  	ret = 0;
  
   out:
  	return ret;
  }
e21596bba   Bill Pemberton   ALSA: pxa2xx: rem...
200
  static int pxa2xx_ac97_probe(struct platform_device *dev)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
201
  {
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
202
203
204
  	struct snd_card *card;
  	struct snd_ac97_bus *ac97_bus;
  	struct snd_ac97_template ac97_template;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
205
  	int ret;
4ac0478f2   Marek Vasut   ALSA: Allow passi...
206
207
208
209
210
211
212
213
  	pxa2xx_audio_ops_t *pdata = dev->dev.platform_data;
  
  	if (dev->id >= 0) {
  		dev_err(&dev->dev, "PXA2xx has only one AC97 port.
  ");
  		ret = -ENXIO;
  		goto err_dev;
  	}
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
214

4a8755801   Takashi Iwai   ALSA: arm: Conver...
215
216
  	ret = snd_card_new(&dev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
  			   THIS_MODULE, 0, &card);
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
217
  	if (ret < 0)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
218
  		goto err;
57a4451d2   Takashi Iwai   ALSA: Use strlcpy...
219
  	strlcpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
220

95acb005f   Daniel Mack   ASoC: fold pxa2xx...
221
  	ret = pxa2xx_ac97_pcm_new(card);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
222
223
  	if (ret)
  		goto err;
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
224
225
  	ret = pxa2xx_ac97_hw_probe(dev);
  	if (ret)
93873fbfd   Mark Brown   [ARM] 4833/3: Con...
226
  		goto err;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
227
228
229
  
  	ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
  	if (ret)
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
230
  		goto err_remove;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
231
232
233
  	memset(&ac97_template, 0, sizeof(ac97_template));
  	ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
  	if (ret)
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
234
  		goto err_remove;
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
235
236
237
238
  
  	snprintf(card->shortname, sizeof(card->shortname),
  		 "%s", snd_ac97_get_short_name(pxa2xx_ac97_ac97));
  	snprintf(card->longname, sizeof(card->longname),
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
239
  		 "%s (%s)", dev->dev.driver->name, card->mixername);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
240

367da1527   Robert Schwebel   ASoC: fix pxa2xx-...
241
  	if (pdata && pdata->codec_pdata[0])
e2365bf31   Marek Vasut   ASoC: Pass correc...
242
  		snd_ac97_dev_add_pdata(ac97_bus->codec[0], pdata->codec_pdata[0]);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
243
244
  	ret = snd_card_register(card);
  	if (ret == 0) {
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
245
  		platform_set_drvdata(dev, card);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
246
247
  		return 0;
  	}
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
248
249
250
  err_remove:
  	pxa2xx_ac97_hw_remove(dev);
  err:
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
251
252
  	if (card)
  		snd_card_free(card);
4ac0478f2   Marek Vasut   ALSA: Allow passi...
253
  err_dev:
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
254
255
  	return ret;
  }
e21596bba   Bill Pemberton   ALSA: pxa2xx: rem...
256
  static int pxa2xx_ac97_remove(struct platform_device *dev)
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
257
  {
d18f83764   Takashi Iwai   [ALSA] Remove xxx...
258
  	struct snd_card *card = platform_get_drvdata(dev);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
259
260
261
  
  	if (card) {
  		snd_card_free(card);
9c6363422   Dmitry Eremin-Solenikov   ALSA: Separate co...
262
  		pxa2xx_ac97_hw_remove(dev);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
263
264
265
266
  	}
  
  	return 0;
  }
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
267
  static struct platform_driver pxa2xx_ac97_driver = {
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
268
  	.probe		= pxa2xx_ac97_probe,
e21596bba   Bill Pemberton   ALSA: pxa2xx: rem...
269
  	.remove		= pxa2xx_ac97_remove,
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
270
271
  	.driver		= {
  		.name	= "pxa2xx-ac97",
d34e4e00a   Takashi Iwai   ALSA: platform: C...
272
  #ifdef CONFIG_PM_SLEEP
2ba9fd0d1   Mike Rapoport   [ARM] pxa: update...
273
274
  		.pm	= &pxa2xx_ac97_pm_ops,
  #endif
3ae5eaec1   Russell King   [DRIVER MODEL] Co...
275
  	},
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
276
  };
a09452eeb   Axel Lin   ALSA: convert sou...
277
  module_platform_driver(pxa2xx_ac97_driver);
2c484df0d   Takashi Iwai   [ALSA] Add ARM PX...
278
279
280
281
  
  MODULE_AUTHOR("Nicolas Pitre");
  MODULE_DESCRIPTION("AC97 driver for the Intel PXA2xx chip");
  MODULE_LICENSE("GPL");
8b45a2099   Kay Sievers   [ALSA] sound: fix...
282
  MODULE_ALIAS("platform:pxa2xx-ac97");