Blame view

sound/atmel/ac97c.c 22.7 KB
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
1
  /*
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
2
   * Driver for Atmel AC97C
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
3
4
5
6
7
8
9
10
11
12
   *
   * Copyright (C) 2005-2009 Atmel Corporation
   *
   * This program is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 as published by
   * the Free Software Foundation.
   */
  #include <linux/clk.h>
  #include <linux/delay.h>
  #include <linux/bitmap.h>
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
13
  #include <linux/device.h>
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
14
  #include <linux/atmel_pdc.h>
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
15
  #include <linux/gpio/consumer.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
16
17
18
19
20
  #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...
21
  #include <linux/types.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
22
  #include <linux/io.h>
b2d8957f2   Alexander Stein   ALSA: sound/atmel...
23
  #include <linux/of.h>
b2d8957f2   Alexander Stein   ALSA: sound/atmel...
24
  #include <linux/of_device.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
25
26
27
28
29
30
  
  #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...
31
  #include <sound/memalloc.h>
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
32
  #include "ac97c.h"
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
33
34
  /* Serialize access to opened variable */
  static DEFINE_MUTEX(opened_mutex);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
35
36
37
  struct atmel_ac97c {
  	struct clk			*pclk;
  	struct platform_device		*pdev;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
38
39
40
41
42
43
44
45
46
47
  
  	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...
48
  	int				playback_period, capture_period;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
49
50
51
  	/* Serialize access to opened variable */
  	spinlock_t			lock;
  	void __iomem			*regs;
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
52
  	int				irq;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
53
  	int				opened;
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
54
  	struct gpio_desc		*reset_pin;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
55
56
57
58
59
60
61
62
  };
  
  #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...
63
  static const struct snd_pcm_hardware atmel_ac97c_hw = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
64
65
66
67
68
69
70
71
72
73
74
75
76
77
  	.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...
78
  	.buffer_bytes_max	= 2 * 2 * 64 * 2048,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
79
80
  	.period_bytes_min	= 4096,
  	.period_bytes_max	= 4096,
c42eec0f1   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
81
  	.periods_min		= 6,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
  	.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_...
98
  		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  	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_...
117
  		runtime->hw.formats = pcm_format_to_bits(chip->cur_format);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
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
158
159
160
161
162
163
164
165
166
  	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);
  	int retval;
  
  	retval = snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
  	if (retval < 0)
  		return retval;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
167

4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  	/* 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);
  
  	return retval;
  }
  
  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);
  	int retval;
  
  	retval = snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
  	if (retval < 0)
  		return retval;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
187
188
189
190
191
192
193
194
195
  
  	/* 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);
  
  	return retval;
  }
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
196
197
198
199
  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...
200
  	int block_size = frames_to_bytes(runtime, runtime->period_size);
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
201
  	unsigned long word = ac97c_readl(chip, OCA);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
202
  	int retval;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
203
  	chip->playback_period = 0;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
204
  	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
205
206
207
208
209
210
211
212
213
214
215
216
  	/* 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...
217
218
219
220
  	}
  	ac97c_writel(chip, OCA, word);
  
  	/* configure sample format and size */
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
221
222
223
224
225
  	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...
226
227
228
  
  	switch (runtime->format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
229
230
  		break;
  	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
231
232
  		word &= ~(AC97C_CMR_CEM_LITTLE);
  		break;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
233
234
235
236
237
  	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...
238
  	}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
239
240
  	/* Enable underrun interrupt on channel A */
  	word |= AC97C_CSR_UNRUN;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
241
  	ac97c_writel(chip, CAMR, word);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
242
243
244
245
  	/* 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...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  	/* 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...
263
264
265
266
267
  	/* 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...
268
269
270
271
272
273
274
275
  
  	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...
276
  	int block_size = frames_to_bytes(runtime, runtime->period_size);
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
277
  	unsigned long word = ac97c_readl(chip, ICA);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
278
  	int retval;
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
279
  	chip->capture_period = 0;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
280
  	word &= ~(AC97C_CH_MASK(PCM_LEFT) | AC97C_CH_MASK(PCM_RIGHT));
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
281
282
283
284
285
286
287
288
289
290
291
292
  	/* 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...
293
294
295
296
  	}
  	ac97c_writel(chip, ICA, word);
  
  	/* configure sample format and size */
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
297
298
299
300
301
  	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...
302
303
304
  
  	switch (runtime->format) {
  	case SNDRV_PCM_FORMAT_S16_LE:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
305
306
  		break;
  	case SNDRV_PCM_FORMAT_S16_BE: /* fall through */
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
307
308
  		word &= ~(AC97C_CMR_CEM_LITTLE);
  		break;
128ed6a92   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
309
310
311
312
313
  	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...
314
  	}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
315
316
  	/* Enable overrun interrupt on channel A */
  	word |= AC97C_CSR_OVRUN;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
317
  	ac97c_writel(chip, CAMR, word);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
318
319
320
321
  	/* 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...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  	/* 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...
339
340
341
342
343
  	/* 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...
344
345
346
347
348
349
350
351
  
  	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...
352
  	unsigned long camr, ptcr = 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
353
354
355
356
357
358
359
  
  	camr = ac97c_readl(chip, CAMR);
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
  	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
  	case SNDRV_PCM_TRIGGER_START:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
360
  		ptcr = ATMEL_PDC_TXTEN;
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
361
  		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDTX;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
362
363
364
365
  		break;
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
  	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
  	case SNDRV_PCM_TRIGGER_STOP:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
366
  		ptcr |= ATMEL_PDC_TXTDIS;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
367
368
369
370
  		if (chip->opened <= 1)
  			camr &= ~AC97C_CMR_CENA;
  		break;
  	default:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
371
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
372
373
374
  	}
  
  	ac97c_writel(chip, CAMR, camr);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
375
376
  	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
377
378
379
380
381
382
  }
  
  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...
383
  	unsigned long camr, ptcr = 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
384
385
  
  	camr = ac97c_readl(chip, CAMR);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
386
  	ptcr = readl(chip->regs + ATMEL_PDC_PTSR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
387
388
389
390
391
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
  	case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
  	case SNDRV_PCM_TRIGGER_START:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
392
  		ptcr = ATMEL_PDC_RXTEN;
ec2755a93   Sedji Gaouaou   ALSA: AC97: add f...
393
  		camr |= AC97C_CMR_CENA | AC97C_CSR_ENDRX;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
394
395
396
397
  		break;
  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
  	case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
  	case SNDRV_PCM_TRIGGER_STOP:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
398
  		ptcr |= ATMEL_PDC_RXTDIS;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
399
400
401
402
  		if (chip->opened <= 1)
  			camr &= ~AC97C_CMR_CENA;
  		break;
  	default:
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
403
  		return -EINVAL;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
404
405
406
  	}
  
  	ac97c_writel(chip, CAMR, camr);
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
407
408
  	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
409
410
411
412
413
414
415
416
417
  }
  
  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...
418
  	bytes = readl(chip->regs + ATMEL_PDC_TPR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
  	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...
434
  	bytes = readl(chip->regs + ATMEL_PDC_RPR);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
435
436
437
438
439
440
441
  	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...
442
  static const struct snd_pcm_ops atmel_ac97_playback_ops = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
443
444
445
446
  	.open		= atmel_ac97c_playback_open,
  	.close		= atmel_ac97c_playback_close,
  	.ioctl		= snd_pcm_lib_ioctl,
  	.hw_params	= atmel_ac97c_playback_hw_params,
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
447
  	.hw_free	= snd_pcm_lib_free_pages,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
448
449
450
451
  	.prepare	= atmel_ac97c_playback_prepare,
  	.trigger	= atmel_ac97c_playback_trigger,
  	.pointer	= atmel_ac97c_playback_pointer,
  };
108637371   Arvind Yadav   ALSA: atmel: cons...
452
  static const struct snd_pcm_ops atmel_ac97_capture_ops = {
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
453
454
455
456
  	.open		= atmel_ac97c_capture_open,
  	.close		= atmel_ac97c_capture_close,
  	.ioctl		= snd_pcm_lib_ioctl,
  	.hw_params	= atmel_ac97c_capture_hw_params,
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
457
  	.hw_free	= snd_pcm_lib_free_pages,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
458
459
460
461
  	.prepare	= atmel_ac97c_capture_prepare,
  	.trigger	= atmel_ac97c_capture_trigger,
  	.pointer	= atmel_ac97c_capture_pointer,
  };
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
462
463
464
465
466
467
468
  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...
469
  	u32			camr   = ac97c_readl(chip, CAMR);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
470
471
  
  	if (sr & AC97C_SR_CAEVT) {
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
472
473
  		struct snd_pcm_runtime *runtime;
  		int offset, next_period, block_size;
f53411630   Yegor Yefremov   ALSA: atmel: set ...
474
475
  		dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s
  ",
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
476
477
478
479
480
481
  				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...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
  		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...
516
  		}
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
  		retval = IRQ_HANDLED;
  	}
  
  	if (sr & AC97C_SR_COEVT) {
  		dev_info(&chip->pdev->dev, "codec channel event%s%s%s%s%s
  ",
  				cosr & AC97C_CSR_OVRUN   ? " OVRUN"   : "",
  				cosr & AC97C_CSR_RXRDY   ? " RXRDY"   : "",
  				cosr & AC97C_CSR_TXEMPTY ? " TXEMPTY" : "",
  				cosr & AC97C_CSR_TXRDY   ? " TXRDY"   : "",
  				!cosr                    ? " NONE"    : "");
  		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...
539
  static const struct ac97_pcm at91_ac97_pcm_defs[] = {
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
  	/* 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...
566
  static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
567
568
569
  {
  	struct snd_pcm		*pcm;
  	struct snd_pcm_hardware	hw = atmel_ac97c_hw;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
570
  	int			retval;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
571

020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
572
573
574
575
576
  	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...
577

020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
578
  	retval = snd_pcm_new(chip->card, chip->card->shortname, 0, 1, 1, &pcm);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
579
580
  	if (retval)
  		return retval;
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
581
582
  	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...
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
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
  
  	retval = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
  			&chip->pdev->dev, hw.periods_min * hw.period_bytes_min,
  			hw.buffer_bytes_max);
  	if (retval)
  		return retval;
  
  	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...
673
674
  static void atmel_ac97c_reset(struct atmel_ac97c *chip)
  {
81baf3a7f   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
675
676
677
678
  	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...
679

5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
680
681
  	if (!IS_ERR(chip->reset_pin)) {
  		gpiod_set_value(chip->reset_pin, 0);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
682
  		/* AC97 v2.2 specifications says minimum 1 us. */
81baf3a7f   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
683
  		udelay(2);
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
684
  		gpiod_set_value(chip->reset_pin, 1);
8015e3def   Bo Shen   ALSA: atmel/ac97c...
685
686
687
688
  	} 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...
689
  	}
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
690
  }
b2d8957f2   Alexander Stein   ALSA: sound/atmel...
691
692
693
694
695
  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...
696
  static int atmel_ac97c_probe(struct platform_device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
697
  {
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
698
  	struct device			*dev = &pdev->dev;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
699
700
701
  	struct snd_card			*card;
  	struct atmel_ac97c		*chip;
  	struct resource			*regs;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
702
703
704
705
706
707
  	struct clk			*pclk;
  	static struct snd_ac97_bus_ops	ops = {
  		.write	= atmel_ac97c_write,
  		.read	= atmel_ac97c_read,
  	};
  	int				retval;
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
708
  	int				irq;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
709
710
711
712
713
714
715
  
  	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...
716
717
  	irq = platform_get_irq(pdev, 0);
  	if (irq < 0) {
772011351   Gustavo A. R. Silva   ALSA: atmel: ac97...
718
719
720
  		dev_dbg(&pdev->dev, "could not get irq: %d
  ", irq);
  		return irq;
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
721
  	}
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
722
  	pclk = clk_get(&pdev->dev, "ac97_clk");
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
723
724
725
726
727
  	if (IS_ERR(pclk)) {
  		dev_dbg(&pdev->dev, "no peripheral clock
  ");
  		return PTR_ERR(pclk);
  	}
260ea95cc   Arvind Yadav   ASoC: atmel: ac97...
728
729
  	retval = clk_prepare_enable(pclk);
  	if (retval)
0515760fa   Christophe Jaillet   ALSA: ac97c: Fix ...
730
  		goto err_prepare_enable;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
731

a4f2473d3   Takashi Iwai   ALSA: atmel: Conv...
732
733
734
  	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...
735
736
737
738
739
740
741
  	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...
742
743
744
745
746
747
748
  	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...
749
750
751
752
753
754
755
756
757
  	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...
758
  	chip->regs = ioremap(regs->start, resource_size(regs));
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
759
760
761
762
  
  	if (!chip->regs) {
  		dev_dbg(&pdev->dev, "could not remap register memory
  ");
0c23e46eb   Julia Lawall   ALSA: sound/atmel...
763
  		retval = -ENOMEM;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
764
765
  		goto err_ioremap;
  	}
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
766
767
768
769
  	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...
770

81baf3a7f   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
771
  	atmel_ac97c_reset(chip);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
772
773
774
  	/* 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...
775
776
777
778
779
780
  	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...
781
782
783
784
785
786
  	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...
787
788
789
790
  	retval = atmel_ac97c_pcm_new(chip);
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not register ac97 pcm device
  ");
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
791
  		goto err_ac97_bus;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
792
793
794
795
796
797
  	}
  
  	retval = snd_card_register(card);
  	if (retval) {
  		dev_dbg(&pdev->dev, "could not register sound card
  ");
020c5260c   Andy Shevchenko   ALSA: atmel: Remo...
798
  		goto err_ac97_bus;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
799
800
801
  	}
  
  	platform_set_drvdata(pdev, card);
7177395fd   Sedji Gaouaou   ALSA: AC97: add A...
802
803
804
  	dev_info(&pdev->dev, "Atmel AC97 controller at 0x%p, irq = %d
  ",
  			chip->regs, irq);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
805
806
  
  	return 0;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
807
  err_ac97_bus:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
808
809
  	iounmap(chip->regs);
  err_ioremap:
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
810
811
  	free_irq(irq, chip);
  err_request_irq:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
812
813
  	snd_card_free(card);
  err_snd_card_new:
1132015b1   Alexander Stein   ALSA: sound/atmel...
814
  	clk_disable_unprepare(pclk);
0515760fa   Christophe Jaillet   ALSA: ac97c: Fix ...
815
  err_prepare_enable:
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
816
817
818
  	clk_put(pclk);
  	return retval;
  }
d34e4e00a   Takashi Iwai   ALSA: platform: C...
819
  #ifdef CONFIG_PM_SLEEP
284e7ca75   Takashi Iwai   ALSA: convert PM ...
820
  static int atmel_ac97c_suspend(struct device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
821
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
822
  	struct snd_card *card = dev_get_drvdata(pdev);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
823
  	struct atmel_ac97c *chip = card->private_data;
1132015b1   Alexander Stein   ALSA: sound/atmel...
824
  	clk_disable_unprepare(chip->pclk);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
825
826
  	return 0;
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
827
  static int atmel_ac97c_resume(struct device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
828
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
829
  	struct snd_card *card = dev_get_drvdata(pdev);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
830
  	struct atmel_ac97c *chip = card->private_data;
260ea95cc   Arvind Yadav   ASoC: atmel: ac97...
831
  	int ret = clk_prepare_enable(chip->pclk);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
832

260ea95cc   Arvind Yadav   ASoC: atmel: ac97...
833
  	return ret;
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
834
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
835
836
837
  
  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...
838
  #else
284e7ca75   Takashi Iwai   ALSA: convert PM ...
839
  #define ATMEL_AC97C_PM_OPS	NULL
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
840
  #endif
61dc674c3   Bill Pemberton   ALSA: atmel: remo...
841
  static int atmel_ac97c_remove(struct platform_device *pdev)
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
842
843
844
  {
  	struct snd_card *card = platform_get_drvdata(pdev);
  	struct atmel_ac97c *chip = get_chip(card);
bd74a1843   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
845
846
847
  	ac97c_writel(chip, CAMR, 0);
  	ac97c_writel(chip, COMR, 0);
  	ac97c_writel(chip, MR,   0);
1132015b1   Alexander Stein   ALSA: sound/atmel...
848
  	clk_disable_unprepare(chip->pclk);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
849
850
  	clk_put(chip->pclk);
  	iounmap(chip->regs);
df163587e   Hans-Christian Egtvedt   ALSA: snd-atmel-a...
851
  	free_irq(chip->irq, chip);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
852

4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
853
  	snd_card_free(card);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
854
855
856
857
  	return 0;
  }
  
  static struct platform_driver atmel_ac97c_driver = {
4b973ee05   Alexander Stein   ALSA: sound/atmel...
858
  	.probe		= atmel_ac97c_probe,
61dc674c3   Bill Pemberton   ALSA: atmel: remo...
859
  	.remove		= atmel_ac97c_remove,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
860
861
  	.driver		= {
  		.name	= "atmel_ac97c",
284e7ca75   Takashi Iwai   ALSA: convert PM ...
862
  		.pm	= ATMEL_AC97C_PM_OPS,
5f10e8493   Andy Shevchenko   ALSA: atmel: conv...
863
  		.of_match_table = atmel_ac97c_dt_ids,
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
864
  	},
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
865
  };
4b973ee05   Alexander Stein   ALSA: sound/atmel...
866
  module_platform_driver(atmel_ac97c_driver);
4ede028f8   Hans-Christian Egtvedt   ALSA: Add ALSA dr...
867
868
869
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Driver for Atmel AC97 controller");
0cfae7c93   Hans-Christian Egtvedt   ALSA: atmel - upd...
870
  MODULE_AUTHOR("Hans-Christian Egtvedt <egtvedt@samfundet.no>");