Blame view

sound/atmel/ac97c.c 21.9 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
2
  /*
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
3
   * Driver for Atmel AC97C
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
4
5
   *
   * Copyright (C) 2005-2009 Atmel Corporation
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
6
7
8
9
   */
  #include <linux/clk.h>
  #include <linux/delay.h>
  #include <linux/bitmap.h>
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
10
  #include <linux/device.h>
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
11
  #include <linux/atmel_pdc.h>
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
12
  #include <linux/gpio/consumer.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
13
14
15
16
17
  #include <linux/init.h>
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/mutex.h>
e2b35f3db   Viresh Kumar   dmaengine/dw_dmac...
18
  #include <linux/types.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
19
  #include <linux/io.h>
b2d8957f2   Alexander Stein   ALSA: sound/atmel...
20
  #include <linux/of.h>
b2d8957f2   Alexander Stein   ALSA: sound/atmel...
21
  #include <linux/of_device.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
22
23
24
25
26
27
  
  #include <sound/core.h>
  #include <sound/initval.h>
  #include <sound/pcm.h>
  #include <sound/pcm_params.h>
  #include <sound/ac97_codec.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
28
  #include <sound/memalloc.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
29
  #include "ac97c.h"
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
30
31
  /* Serialize access to opened variable */
  static DEFINE_MUTEX(opened_mutex);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
32
33
34
  struct atmel_ac97c {
  	struct clk			*pclk;
  	struct platform_device		*pdev;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
35
36
37
38
39
40
41
42
43
44
  
  	struct snd_pcm_substream	*playback_substream;
  	struct snd_pcm_substream	*capture_substream;
  	struct snd_card			*card;
  	struct snd_pcm			*pcm;
  	struct snd_ac97			*ac97;
  	struct snd_ac97_bus		*ac97_bus;
  
  	u64				cur_format;
  	unsigned int			cur_rate;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
45
  	int				playback_period, capture_period;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
46
47
48
  	/* Serialize access to opened variable */
  	spinlock_t			lock;
  	void __iomem			*regs;
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
49
  	int				irq;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
50
  	int				opened;
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
51
  	struct gpio_desc		*reset_pin;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
52
53
54
55
56
57
58
59
  };
  
  #define get_chip(card) ((struct atmel_ac97c *)(card)->private_data)
  
  #define ac97c_writel(chip, reg, val)			\
  	__raw_writel((val), (chip)->regs + AC97C_##reg)
  #define ac97c_readl(chip, reg)				\
  	__raw_readl((chip)->regs + AC97C_##reg)
85ab37384   Bhumika Goyal   ALSA: atmel: make...
60
  static const struct snd_pcm_hardware atmel_ac97c_hw = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  	.info			= (SNDRV_PCM_INFO_MMAP
  				  | SNDRV_PCM_INFO_MMAP_VALID
  				  | SNDRV_PCM_INFO_INTERLEAVED
  				  | SNDRV_PCM_INFO_BLOCK_TRANSFER
  				  | SNDRV_PCM_INFO_JOINT_DUPLEX
  				  | SNDRV_PCM_INFO_RESUME
  				  | SNDRV_PCM_INFO_PAUSE),
  	.formats		= (SNDRV_PCM_FMTBIT_S16_BE
  				  | SNDRV_PCM_FMTBIT_S16_LE),
  	.rates			= (SNDRV_PCM_RATE_CONTINUOUS),
  	.rate_min		= 4000,
  	.rate_max		= 48000,
  	.channels_min		= 1,
  	.channels_max		= 2,
c42eec0f1   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
75
  	.buffer_bytes_max	= 2 * 2 * 64 * 2048,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
76
77
  	.period_bytes_min	= 4096,
  	.period_bytes_max	= 4096,
c42eec0f1   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
78
  	.periods_min		= 6,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
  	.periods_max		= 64,
  };
  
  static int atmel_ac97c_playback_open(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  
  	mutex_lock(&opened_mutex);
  	chip->opened++;
  	runtime->hw = atmel_ac97c_hw;
  	if (chip->cur_rate) {
  		runtime->hw.rate_min = chip->cur_rate;
  		runtime->hw.rate_max = chip->cur_rate;
  	}
  	if (chip->cur_format)
74c34ca1c   Eldad Zack   ALSA: pcm_format_...
95
  		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
  	mutex_unlock(&opened_mutex);
  	chip->playback_substream = substream;
  	return 0;
  }
  
  static int atmel_ac97c_capture_open(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
  
  	mutex_lock(&opened_mutex);
  	chip->opened++;
  	runtime->hw = atmel_ac97c_hw;
  	if (chip->cur_rate) {
  		runtime->hw.rate_min = chip->cur_rate;
  		runtime->hw.rate_max = chip->cur_rate;
  	}
  	if (chip->cur_format)
74c34ca1c   Eldad Zack   ALSA: pcm_format_...
114
  		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
  	mutex_unlock(&opened_mutex);
  	chip->capture_substream = substream;
  	return 0;
  }
  
  static int atmel_ac97c_playback_close(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
  
  	mutex_lock(&opened_mutex);
  	chip->opened--;
  	if (!chip->opened) {
  		chip->cur_rate = 0;
  		chip->cur_format = 0;
  	}
  	mutex_unlock(&opened_mutex);
  
  	chip->playback_substream = NULL;
  
  	return 0;
  }
  
  static int atmel_ac97c_capture_close(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
  
  	mutex_lock(&opened_mutex);
  	chip->opened--;
  	if (!chip->opened) {
  		chip->cur_rate = 0;
  		chip->cur_format = 0;
  	}
  	mutex_unlock(&opened_mutex);
  
  	chip->capture_substream = NULL;
  
  	return 0;
  }
  
  static int atmel_ac97c_playback_hw_params(struct snd_pcm_substream *substream,
  		struct snd_pcm_hw_params *hw_params)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
158

4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
159
160
161
162
163
  	/* Set restrictions to params. */
  	mutex_lock(&opened_mutex);
  	chip->cur_rate = params_rate(hw_params);
  	chip->cur_format = params_format(hw_params);
  	mutex_unlock(&opened_mutex);
37b9b9a50   Takashi Iwai   ALSA: atmel: Use ...
164
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
165
166
167
168
169
170
  }
  
  static int atmel_ac97c_capture_hw_params(struct snd_pcm_substream *substream,
  		struct snd_pcm_hw_params *hw_params)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
171
172
173
174
175
176
  
  	/* Set restrictions to params. */
  	mutex_lock(&opened_mutex);
  	chip->cur_rate = params_rate(hw_params);
  	chip->cur_format = params_format(hw_params);
  	mutex_unlock(&opened_mutex);
37b9b9a50   Takashi Iwai   ALSA: atmel: Use ...
177
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
178
  }
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
179
180
181
182
  static int atmel_ac97c_playback_prepare(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
183
  	int block_size = frames_to_bytes(runtime, runtime->period_size);
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
184
  	unsigned long word = ac97c_readl(chip, OCA);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
185
  	int retval;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
186
  	chip->playback_period = 0;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
187
  	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
188
189
190
191
192
193
194
195
196
197
198
199
  	/* assign channels to AC97C channel A */
  	switch (runtime->channels) {
  	case 1:
  		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
  		break;
  	case 2:
  		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
  			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
  		break;
  	default:
  		/* TODO: support more than two channels */
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
200
201
202
203
  	}
  	ac97c_writel(chip, OCA, word);
  
  	/* configure sample format and size */
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
204
205
206
207
208
  	word = ac97c_readl(chip, CAMR);
  	if (chip->opened <= 1)
  		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
  	else
  		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
209
210
211
  
  	switch (runtime->format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
212
  		break;
4d6cd8f1b   Takashi Iwai   ALSA: atmel: Remo...
213
  	case SNDRV_PCM_FORMAT_S16_BE:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
214
215
  		word &= ~(AC97C_CMR_CEM_LITTLE);
  		break;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
216
217
218
219
220
  	default:
  		word = ac97c_readl(chip, OCA);
  		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
  		ac97c_writel(chip, OCA, word);
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
221
  	}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
222
223
  	/* Enable underrun interrupt on channel A */
  	word |= AC97C_CSR_UNRUN;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
224
  	ac97c_writel(chip, CAMR, word);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
225
226
227
228
  	/* Enable channel A event interrupt */
  	word = ac97c_readl(chip, IMR);
  	word |= AC97C_SR_CAEVT;
  	ac97c_writel(chip, IER, word);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
  	/* set variable rate if needed */
  	if (runtime->rate != 48000) {
  		word = ac97c_readl(chip, MR);
  		word |= AC97C_MR_VRA;
  		ac97c_writel(chip, MR, word);
  	} else {
  		word = ac97c_readl(chip, MR);
  		word &= ~(AC97C_MR_VRA);
  		ac97c_writel(chip, MR, word);
  	}
  
  	retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE,
  			runtime->rate);
  	if (retval)
  		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz
  ",
  				runtime->rate);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
246
247
248
249
250
  	/* Initialize and start the PDC */
  	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
  	writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
  	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR);
  	writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
251
252
253
254
255
256
257
258
  
  	return retval;
  }
  
  static int atmel_ac97c_capture_prepare(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime *runtime = substream->runtime;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
259
  	int block_size = frames_to_bytes(runtime, runtime->period_size);
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
260
  	unsigned long word = ac97c_readl(chip, ICA);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
261
  	int retval;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
262
  	chip->capture_period = 0;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
263
  	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
264
265
266
267
268
269
270
271
272
273
274
275
  	/* assign channels to AC97C channel A */
  	switch (runtime->channels) {
  	case 1:
  		word |= AC97C_CH_ASSIGN(PCM_LEFT, A);
  		break;
  	case 2:
  		word |= AC97C_CH_ASSIGN(PCM_LEFT, A)
  			| AC97C_CH_ASSIGN(PCM_RIGHT, A);
  		break;
  	default:
  		/* TODO: support more than two channels */
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
276
277
278
279
  	}
  	ac97c_writel(chip, ICA, word);
  
  	/* configure sample format and size */
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
280
281
282
283
284
  	word = ac97c_readl(chip, CAMR);
  	if (chip->opened <= 1)
  		word = AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
  	else
  		word |= AC97C_CMR_DMAEN | AC97C_CMR_SIZE_16;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
285
286
287
  
  	switch (runtime->format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
288
  		break;
4d6cd8f1b   Takashi Iwai   ALSA: atmel: Remo...
289
  	case SNDRV_PCM_FORMAT_S16_BE:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
290
291
  		word &= ~(AC97C_CMR_CEM_LITTLE);
  		break;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
292
293
294
295
296
  	default:
  		word = ac97c_readl(chip, ICA);
  		word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
  		ac97c_writel(chip, ICA, word);
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
297
  	}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
298
299
  	/* Enable overrun interrupt on channel A */
  	word |= AC97C_CSR_OVRUN;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
300
  	ac97c_writel(chip, CAMR, word);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
301
302
303
304
  	/* Enable channel A event interrupt */
  	word = ac97c_readl(chip, IMR);
  	word |= AC97C_SR_CAEVT;
  	ac97c_writel(chip, IER, word);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
  	/* set variable rate if needed */
  	if (runtime->rate != 48000) {
  		word = ac97c_readl(chip, MR);
  		word |= AC97C_MR_VRA;
  		ac97c_writel(chip, MR, word);
  	} else {
  		word = ac97c_readl(chip, MR);
  		word &= ~(AC97C_MR_VRA);
  		ac97c_writel(chip, MR, word);
  	}
  
  	retval = snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE,
  			runtime->rate);
  	if (retval)
  		dev_dbg(&chip->pdev->dev, "could not set rate %d Hz
  ",
  				runtime->rate);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
322
323
324
325
326
  	/* Initialize and start the PDC */
  	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_RPR);
  	writel(block_size / 2, chip->regs + ATMEL_PDC_RCR);
  	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_RNPR);
  	writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
327
328
329
330
331
332
333
334
  
  	return retval;
  }
  
  static int
  atmel_ac97c_playback_trigger(struct snd_pcm_substream *substream, int cmd)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
335
  	unsigned long camr, ptcr = 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
336
337
338
339
  
  	camr = ac97c_readl(chip, CAMR);
  
  	switch (cmd) {
c0dbbdad4   Gustavo A. R. Silva   ALSA: Use fallthr...
340
341
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  	case SNDRV_PCM_TRIGGER_RESUME:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
342
  	case SNDRV_PCM_TRIGGER_START:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
343
  		ptcr = ATMEL_PDC_TXTEN;
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
344
  		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
345
  		break;
c0dbbdad4   Gustavo A. R. Silva   ALSA: Use fallthr...
346
347
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
348
  	case SNDRV_PCM_TRIGGER_STOP:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
349
  		ptcr |= ATMEL_PDC_TXTDIS;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
350
351
352
353
  		if (chip->opened <= 1)
  			camr &= ~AC97C_CMR_CENA;
  		break;
  	default:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
354
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
355
356
357
  	}
  
  	ac97c_writel(chip, CAMR, camr);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
358
359
  	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
360
361
362
363
364
365
  }
  
  static int
  atmel_ac97c_capture_trigger(struct snd_pcm_substream *substream, int cmd)
  {
  	struct atmel_ac97c *chip = snd_pcm_substream_chip(substream);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
366
  	unsigned long camr, ptcr = 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
367
368
  
  	camr = ac97c_readl(chip, CAMR);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
369
  	ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
370
371
  
  	switch (cmd) {
c0dbbdad4   Gustavo A. R. Silva   ALSA: Use fallthr...
372
373
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
  	case SNDRV_PCM_TRIGGER_RESUME:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
374
  	case SNDRV_PCM_TRIGGER_START:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
375
  		ptcr = ATMEL_PDC_RXTEN;
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
376
  		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
377
  		break;
c0dbbdad4   Gustavo A. R. Silva   ALSA: Use fallthr...
378
379
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
380
  	case SNDRV_PCM_TRIGGER_STOP:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
381
  		ptcr |= ATMEL_PDC_RXTDIS;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
382
383
384
385
  		if (chip->opened <= 1)
  			camr &= ~AC97C_CMR_CENA;
  		break;
  	default:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
386
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
387
388
389
  	}
  
  	ac97c_writel(chip, CAMR, camr);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
390
391
  	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
392
393
394
395
396
397
398
399
400
  }
  
  static snd_pcm_uframes_t
  atmel_ac97c_playback_pointer(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c	*chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime	*runtime = substream->runtime;
  	snd_pcm_uframes_t	frames;
  	unsigned long		bytes;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
401
  	bytes = readl(chip->regs + ATMEL_PDC_TPR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  	bytes -= runtime->dma_addr;
  
  	frames = bytes_to_frames(runtime, bytes);
  	if (frames >= runtime->buffer_size)
  		frames -= runtime->buffer_size;
  	return frames;
  }
  
  static snd_pcm_uframes_t
  atmel_ac97c_capture_pointer(struct snd_pcm_substream *substream)
  {
  	struct atmel_ac97c	*chip = snd_pcm_substream_chip(substream);
  	struct snd_pcm_runtime	*runtime = substream->runtime;
  	snd_pcm_uframes_t	frames;
  	unsigned long		bytes;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
417
  	bytes = readl(chip->regs + ATMEL_PDC_RPR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
418
419
420
421
422
423
424
  	bytes -= runtime->dma_addr;
  
  	frames = bytes_to_frames(runtime, bytes);
  	if (frames >= runtime->buffer_size)
  		frames -= runtime->buffer_size;
  	return frames;
  }
108637371   Arvind Yadav   ALSA: atmel: cons...
425
  static const struct snd_pcm_ops atmel_ac97_playback_ops = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
426
427
  	.open		= atmel_ac97c_playback_open,
  	.close		= atmel_ac97c_playback_close,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
428
  	.hw_params	= atmel_ac97c_playback_hw_params,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
429
430
431
432
  	.prepare	= atmel_ac97c_playback_prepare,
  	.trigger	= atmel_ac97c_playback_trigger,
  	.pointer	= atmel_ac97c_playback_pointer,
  };
108637371   Arvind Yadav   ALSA: atmel: cons...
433
  static const struct snd_pcm_ops atmel_ac97_capture_ops = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
434
435
  	.open		= atmel_ac97c_capture_open,
  	.close		= atmel_ac97c_capture_close,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
436
  	.hw_params	= atmel_ac97c_capture_hw_params,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
437
438
439
440
  	.prepare	= atmel_ac97c_capture_prepare,
  	.trigger	= atmel_ac97c_capture_trigger,
  	.pointer	= atmel_ac97c_capture_pointer,
  };
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
441
442
443
444
445
446
447
  static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev)
  {
  	struct atmel_ac97c	*chip  = (struct atmel_ac97c *)dev;
  	irqreturn_t		retval = IRQ_NONE;
  	u32			sr     = ac97c_readl(chip, SR);
  	u32			casr   = ac97c_readl(chip, CASR);
  	u32			cosr   = ac97c_readl(chip, COSR);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
448
  	u32			camr   = ac97c_readl(chip, CAMR);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
449
450
  
  	if (sr & AC97C_SR_CAEVT) {
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
451
452
  		struct snd_pcm_runtime *runtime;
  		int offset, next_period, block_size;
f53411630   Yegor Yefremov   ALSA: atmel: set ...
453
454
  		dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s
  ",
a971b42cb   Pierre-Louis Bossart   ALSA: atmel: ac97...
455
456
457
458
459
460
  			(casr & AC97C_CSR_OVRUN)   ? " OVRUN"   : "",
  			(casr & AC97C_CSR_RXRDY)   ? " RXRDY"   : "",
  			(casr & AC97C_CSR_UNRUN)   ? " UNRUN"   : "",
  			(casr & AC97C_CSR_TXEMPTY) ? " TXEMPTY" : "",
  			(casr & AC97C_CSR_TXRDY)   ? " TXRDY"   : "",
  			!casr                      ? " NONE"    : "");
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
  		if ((casr & camr) & AC97C_CSR_ENDTX) {
  			runtime = chip->playback_substream->runtime;
  			block_size = frames_to_bytes(runtime, runtime->period_size);
  			chip->playback_period++;
  
  			if (chip->playback_period == runtime->periods)
  				chip->playback_period = 0;
  			next_period = chip->playback_period + 1;
  			if (next_period == runtime->periods)
  				next_period = 0;
  
  			offset = block_size * next_period;
  
  			writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_TNPR);
  			writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
  
  			snd_pcm_period_elapsed(chip->playback_substream);
  		}
  		if ((casr & camr) & AC97C_CSR_ENDRX) {
  			runtime = chip->capture_substream->runtime;
  			block_size = frames_to_bytes(runtime, runtime->period_size);
  			chip->capture_period++;
  
  			if (chip->capture_period == runtime->periods)
  				chip->capture_period = 0;
  			next_period = chip->capture_period + 1;
  			if (next_period == runtime->periods)
  				next_period = 0;
  
  			offset = block_size * next_period;
  
  			writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_RNPR);
  			writel(block_size / 2, chip->regs + ATMEL_PDC_RNCR);
  			snd_pcm_period_elapsed(chip->capture_substream);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
495
  		}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
496
497
498
499
500
501
  		retval = IRQ_HANDLED;
  	}
  
  	if (sr & AC97C_SR_COEVT) {
  		dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s
  ",
a971b42cb   Pierre-Louis Bossart   ALSA: atmel: ac97...
502
503
504
505
506
  			 (cosr & AC97C_CSR_OVRUN)   ? " OVRUN"   : "",
  			 (cosr & AC97C_CSR_RXRDY)   ? " RXRDY"   : "",
  			 (cosr & AC97C_CSR_TXEMPTY) ? " TXEMPTY" : "",
  			 (cosr & AC97C_CSR_TXRDY)   ? " TXRDY"   : "",
  			 !cosr                      ? " NONE"    : "");
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
507
508
509
510
511
512
513
514
515
516
517
  		retval = IRQ_HANDLED;
  	}
  
  	if (retval == IRQ_NONE) {
  		dev_err(&chip->pdev->dev, "spurious interrupt sr 0x%08x "
  				"casr 0x%08x cosr 0x%08x
  ", sr, casr, cosr);
  	}
  
  	return retval;
  }
3ca8590be   Arvind Yadav   ALSA: ac97c: cons...
518
  static const struct ac97_pcm at91_ac97_pcm_defs[] = {
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  	/* Playback */
  	{
  		.exclusive = 1,
  		.r = { {
  			.slots = ((1 << AC97_SLOT_PCM_LEFT)
  				  | (1 << AC97_SLOT_PCM_RIGHT)),
  		} },
  	},
  	/* PCM in */
  	{
  		.stream = 1,
  		.exclusive = 1,
  		.r = { {
  			.slots = ((1 << AC97_SLOT_PCM_LEFT)
  					| (1 << AC97_SLOT_PCM_RIGHT)),
  		} }
  	},
  	/* Mic in */
  	{
  		.stream = 1,
  		.exclusive = 1,
  		.r = { {
  			.slots = (1<<AC97_SLOT_MIC),
  		} }
  	},
  };
61dc674c3   Bill Pemberton   ALSA: atmel: remo...
545
  static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
546
547
548
  {
  	struct snd_pcm		*pcm;
  	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
549
  	int			retval;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
550

020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
551
552
553
554
555
  	retval = snd_ac97_pcm_assign(chip->ac97_bus,
  				     ARRAY_SIZE(at91_ac97_pcm_defs),
  				     at91_ac97_pcm_defs);
  	if (retval)
  		return retval;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
556

020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
557
  	retval = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
558
559
  	if (retval)
  		return retval;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
560
561
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &atmel_ac97_capture_ops);
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &atmel_ac97_playback_ops);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
562

37b9b9a50   Takashi Iwai   ALSA: atmel: Use ...
563
  	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
564
565
  			&chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
  			hw.buffer_bytes_max);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
  
  	pcm->private_data = chip;
  	pcm->info_flags = 0;
  	strcpy(pcm->name, chip->card->shortname);
  	chip->pcm = pcm;
  
  	return 0;
  }
  
  static int atmel_ac97c_mixer_new(struct atmel_ac97c *chip)
  {
  	struct snd_ac97_template template;
  	memset(&template, 0, sizeof(template));
  	template.private_data = chip;
  	return snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
  }
  
  static void atmel_ac97c_write(struct snd_ac97 *ac97, unsigned short reg,
  		unsigned short val)
  {
  	struct atmel_ac97c *chip = get_chip(ac97);
  	unsigned long word;
  	int timeout = 40;
  
  	word = (reg & 0x7f) << 16 | val;
  
  	do {
  		if (ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) {
  			ac97c_writel(chip, COTHR, word);
  			return;
  		}
  		udelay(1);
  	} while (--timeout);
  
  	dev_dbg(&chip->pdev->dev, "codec write timeout
  ");
  }
  
  static unsigned short atmel_ac97c_read(struct snd_ac97 *ac97,
  		unsigned short reg)
  {
  	struct atmel_ac97c *chip = get_chip(ac97);
  	unsigned long word;
  	int timeout = 40;
  	int write = 10;
  
  	word = (0x80 | (reg & 0x7f)) << 16;
  
  	if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0)
  		ac97c_readl(chip, CORHR);
  
  retry_write:
  	timeout = 40;
  
  	do {
  		if ((ac97c_readl(chip, COSR) & AC97C_CSR_TXRDY) != 0) {
  			ac97c_writel(chip, COTHR, word);
  			goto read_reg;
  		}
  		udelay(10);
  	} while (--timeout);
  
  	if (!--write)
  		goto timed_out;
  	goto retry_write;
  
  read_reg:
  	do {
  		if ((ac97c_readl(chip, COSR) & AC97C_CSR_RXRDY) != 0) {
  			unsigned short val = ac97c_readl(chip, CORHR);
  			return val;
  		}
  		udelay(10);
  	} while (--timeout);
  
  	if (!--write)
  		goto timed_out;
  	goto retry_write;
  
  timed_out:
  	dev_dbg(&chip->pdev->dev, "codec read timeout
  ");
  	return 0xffff;
  }
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
650
651
  static void atmel_ac97c_reset(struct atmel_ac97c *chip)
  {
81baf3a7f   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
652
653
654
655
  	ac97c_writel(chip, MR,   0);
  	ac97c_writel(chip, MR,   AC97C_MR_ENA);
  	ac97c_writel(chip, CAMR, 0);
  	ac97c_writel(chip, COMR, 0);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
656

5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
657
658
  	if (!IS_ERR(chip->reset_pin)) {
  		gpiod_set_value(chip->reset_pin, 0);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
659
  		/* AC97 v2.2 specifications says minimum 1 us. */
81baf3a7f   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
660
  		udelay(2);
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
661
  		gpiod_set_value(chip->reset_pin, 1);
8015e3def   Bo Shen   ALSA: atmel/ac97c...
662
663
664
665
  	} else {
  		ac97c_writel(chip, MR, AC97C_MR_WRST | AC97C_MR_ENA);
  		udelay(2);
  		ac97c_writel(chip, MR, AC97C_MR_ENA);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
666
  	}
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
667
  }
b2d8957f2   Alexander Stein   ALSA: sound/atmel...
668
669
670
671
672
  static const struct of_device_id atmel_ac97c_dt_ids[] = {
  	{ .compatible = "atmel,at91sam9263-ac97c", },
  	{ }
  };
  MODULE_DEVICE_TABLE(of, atmel_ac97c_dt_ids);
61dc674c3   Bill Pemberton   ALSA: atmel: remo...
673
  static int atmel_ac97c_probe(struct platform_device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
674
  {
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
675
  	struct device			*dev = &pdev->dev;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
676
677
678
  	struct snd_card			*card;
  	struct atmel_ac97c		*chip;
  	struct resource			*regs;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
679
  	struct clk			*pclk;
3a3fac8b3   Takashi Iwai   ALSA: atmel: Cons...
680
  	static const struct snd_ac97_bus_ops	ops = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
681
682
683
684
  		.write	= atmel_ac97c_write,
  		.read	= atmel_ac97c_read,
  	};
  	int				retval;
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
685
  	int				irq;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
686
687
688
689
690
691
692
  
  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  	if (!regs) {
  		dev_dbg(&pdev->dev, "no memory resource
  ");
  		return -ENXIO;
  	}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
693
694
  	irq = platform_get_irq(pdev, 0);
  	if (irq < 0) {
772011351   Gustavo A. R. Silva   ALSA: atmel: ac97...
695
696
697
  		dev_dbg(&pdev->dev, "could not get irq: %d
  ", irq);
  		return irq;
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
698
  	}
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
699
  	pclk = clk_get(&pdev->dev, "ac97_clk");
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
700
701
702
703
704
  	if (IS_ERR(pclk)) {
  		dev_dbg(&pdev->dev, "no peripheral clock
  ");
  		return PTR_ERR(pclk);
  	}
260ea95cc   Arvind Yadav   ASoC: atmel: ac97...
705
706
  	retval = clk_prepare_enable(pclk);
  	if (retval)
0515760fa   Christophe Jaillet   ALSA: ac97c: Fix ...
707
  		goto err_prepare_enable;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
708

a4f2473d3   Takashi Iwai   ALSA: atmel: Conv...
709
710
711
  	retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
  			      SNDRV_DEFAULT_STR1, THIS_MODULE,
  			      sizeof(struct atmel_ac97c), &card);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
712
713
714
715
716
717
718
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not create sound card device
  ");
  		goto err_snd_card_new;
  	}
  
  	chip = get_chip(card);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
719
720
721
722
723
724
725
  	retval = request_irq(irq, atmel_ac97c_interrupt, 0, "AC97C", chip);
  	if (retval) {
  		dev_dbg(&pdev->dev, "unable to request irq %d
  ", irq);
  		goto err_request_irq;
  	}
  	chip->irq = irq;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
726
727
728
729
730
731
732
733
734
  	spin_lock_init(&chip->lock);
  
  	strcpy(card->driver, "Atmel AC97C");
  	strcpy(card->shortname, "Atmel AC97C");
  	sprintf(card->longname, "Atmel AC97 controller");
  
  	chip->card = card;
  	chip->pclk = pclk;
  	chip->pdev = pdev;
28f65c11f   Joe Perches   treewide: Convert...
735
  	chip->regs = ioremap(regs->start, resource_size(regs));
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
736
737
738
739
  
  	if (!chip->regs) {
  		dev_dbg(&pdev->dev, "could not remap register memory
  ");
0c23e46eb   Julia Lawall   ALSA: sound/atmel...
740
  		retval = -ENOMEM;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
741
742
  		goto err_ioremap;
  	}
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
743
744
745
746
  	chip->reset_pin = devm_gpiod_get_index(dev, "ac97", 2, GPIOD_OUT_HIGH);
  	if (IS_ERR(chip->reset_pin))
  		dev_dbg(dev, "reset pin not available
  ");
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
747

81baf3a7f   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
748
  	atmel_ac97c_reset(chip);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
749
750
751
  	/* Enable overrun interrupt from codec channel */
  	ac97c_writel(chip, COMR, AC97C_CSR_OVRUN);
  	ac97c_writel(chip, IER, ac97c_readl(chip, IMR) | AC97C_SR_COEVT);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
752
753
754
755
756
757
  	retval = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not register on ac97 bus
  ");
  		goto err_ac97_bus;
  	}
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
758
759
760
761
762
763
  	retval = atmel_ac97c_mixer_new(chip);
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not register ac97 mixer
  ");
  		goto err_ac97_bus;
  	}
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
764
765
766
767
  	retval = atmel_ac97c_pcm_new(chip);
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not register ac97 pcm device
  ");
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
768
  		goto err_ac97_bus;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
769
770
771
772
773
774
  	}
  
  	retval = snd_card_register(card);
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not register sound card
  ");
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
775
  		goto err_ac97_bus;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
776
777
778
  	}
  
  	platform_set_drvdata(pdev, card);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
779
780
781
  	dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d
  ",
  			chip->regs, irq);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
782
783
  
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
784
  err_ac97_bus:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
785
786
  	iounmap(chip->regs);
  err_ioremap:
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
787
788
  	free_irq(irq, chip);
  err_request_irq:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
789
790
  	snd_card_free(card);
  err_snd_card_new:
1132015b1   Alexander Stein   ALSA: sound/atmel...
791
  	clk_disable_unprepare(pclk);
0515760fa   Christophe Jaillet   ALSA: ac97c: Fix ...
792
  err_prepare_enable:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
793
794
795
  	clk_put(pclk);
  	return retval;
  }
d34e4e00a   Takashi Iwai   ALSA: platform: C...
796
  #ifdef CONFIG_PM_SLEEP
284e7ca75   Takashi Iwai   ALSA: convert PM ...
797
  static int atmel_ac97c_suspend(struct device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
798
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
799
  	struct snd_card *card = dev_get_drvdata(pdev);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
800
  	struct atmel_ac97c *chip = card->private_data;
1132015b1   Alexander Stein   ALSA: sound/atmel...
801
  	clk_disable_unprepare(chip->pclk);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
802
803
  	return 0;
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
804
  static int atmel_ac97c_resume(struct device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
805
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
806
  	struct snd_card *card = dev_get_drvdata(pdev);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
807
  	struct atmel_ac97c *chip = card->private_data;
260ea95cc   Arvind Yadav   ASoC: atmel: ac97...
808
  	int ret = clk_prepare_enable(chip->pclk);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
809

260ea95cc   Arvind Yadav   ASoC: atmel: ac97...
810
  	return ret;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
811
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
812
813
814
  
  static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume);
  #define ATMEL_AC97C_PM_OPS	&atmel_ac97c_pm
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
815
  #else
284e7ca75   Takashi Iwai   ALSA: convert PM ...
816
  #define ATMEL_AC97C_PM_OPS	NULL
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
817
  #endif
61dc674c3   Bill Pemberton   ALSA: atmel: remo...
818
  static int atmel_ac97c_remove(struct platform_device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
819
820
821
  {
  	struct snd_card *card = platform_get_drvdata(pdev);
  	struct atmel_ac97c *chip = get_chip(card);
bd74a1843   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
822
823
824
  	ac97c_writel(chip, CAMR, 0);
  	ac97c_writel(chip, COMR, 0);
  	ac97c_writel(chip, MR,   0);
1132015b1   Alexander Stein   ALSA: sound/atmel...
825
  	clk_disable_unprepare(chip->pclk);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
826
827
  	clk_put(chip->pclk);
  	iounmap(chip->regs);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
828
  	free_irq(chip->irq, chip);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
829

4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
830
  	snd_card_free(card);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
831
832
833
834
  	return 0;
  }
  
  static struct platform_driver atmel_ac97c_driver = {
4b973ee05   Alexander Stein   ALSA: sound/atmel...
835
  	.probe		= atmel_ac97c_probe,
61dc674c3   Bill Pemberton   ALSA: atmel: remo...
836
  	.remove		= atmel_ac97c_remove,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
837
838
  	.driver		= {
  		.name	= "atmel_ac97c",
284e7ca75   Takashi Iwai   ALSA: convert PM ...
839
  		.pm	= ATMEL_AC97C_PM_OPS,
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
840
  		.of_match_table = atmel_ac97c_dt_ids,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
841
  	},
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
842
  };
4b973ee05   Alexander Stein   ALSA: sound/atmel...
843
  module_platform_driver(atmel_ac97c_driver);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
844
845
846
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
0cfae7c93   Hans-Christian Egtvedt   ALSA: atmel - upd...
847
  MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");