| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 1 | /* | 
 | 2 |  * bf5xx-ac97.c -- AC97 support for the ADI blackfin chip. | 
 | 3 |  * | 
 | 4 |  * Author:	Roy Huang | 
 | 5 |  * Created:	11th. June 2007 | 
 | 6 |  * Copyright:	Analog Device Inc. | 
 | 7 |  * | 
 | 8 |  * This program is free software; you can redistribute it and/or modify | 
 | 9 |  * it under the terms of the GNU General Public License version 2 as | 
 | 10 |  * published by the Free Software Foundation. | 
 | 11 |  */ | 
 | 12 |  | 
 | 13 | #include <linux/init.h> | 
 | 14 | #include <linux/module.h> | 
 | 15 | #include <linux/platform_device.h> | 
 | 16 | #include <linux/interrupt.h> | 
 | 17 | #include <linux/wait.h> | 
 | 18 | #include <linux/delay.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 19 | #include <linux/slab.h> | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 20 |  | 
 | 21 | #include <sound/core.h> | 
 | 22 | #include <sound/pcm.h> | 
 | 23 | #include <sound/ac97_codec.h> | 
 | 24 | #include <sound/initval.h> | 
 | 25 | #include <sound/soc.h> | 
 | 26 |  | 
 | 27 | #include <asm/irq.h> | 
 | 28 | #include <asm/portmux.h> | 
 | 29 | #include <linux/mutex.h> | 
 | 30 | #include <linux/gpio.h> | 
 | 31 |  | 
 | 32 | #include "bf5xx-sport.h" | 
 | 33 | #include "bf5xx-ac97.h" | 
 | 34 |  | 
| Sonic Zhang | cf485da | 2009-06-02 00:18:57 -0400 | [diff] [blame] | 35 | /* Anomaly notes: | 
 | 36 |  *  05000250 -	AD1980 is running in TDM mode and RFS/TFS are generated by SPORT | 
 | 37 |  *		contrtoller. But, RFSDIV and TFSDIV are always set to 16*16-1, | 
 | 38 |  *		while the max AC97 data size is 13*16. The DIV is always larger | 
 | 39 |  *		than data size. AD73311 and ad2602 are not running in TDM mode. | 
 | 40 |  *		AD1836 and AD73322 depend on external RFS/TFS only. So, this | 
 | 41 |  *		anomaly does not affect blackfin sound drivers. | 
 | 42 | */ | 
 | 43 |  | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 44 | static struct sport_device *ac97_sport_handle; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 45 |  | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 46 | void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, | 
 | 47 | 		size_t count, unsigned int chan_mask) | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 48 | { | 
 | 49 | 	while (count--) { | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 50 | 		dst->ac97_tag = TAG_VALID; | 
 | 51 | 		if (chan_mask & SP_FL) { | 
 | 52 | 			dst->ac97_pcm_r = *src++; | 
 | 53 | 			dst->ac97_tag |= TAG_PCM_RIGHT; | 
 | 54 | 		} | 
 | 55 | 		if (chan_mask & SP_FR) { | 
 | 56 | 			dst->ac97_pcm_l = *src++; | 
 | 57 | 			dst->ac97_tag |= TAG_PCM_LEFT; | 
 | 58 |  | 
 | 59 | 		} | 
 | 60 | #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) | 
 | 61 | 		if (chan_mask & SP_SR) { | 
 | 62 | 			dst->ac97_sl = *src++; | 
 | 63 | 			dst->ac97_tag |= TAG_PCM_SL; | 
 | 64 | 		} | 
 | 65 | 		if (chan_mask & SP_SL) { | 
 | 66 | 			dst->ac97_sr = *src++; | 
 | 67 | 			dst->ac97_tag |= TAG_PCM_SR; | 
 | 68 | 		} | 
 | 69 | 		if (chan_mask & SP_LFE) { | 
 | 70 | 			dst->ac97_lfe = *src++; | 
 | 71 | 			dst->ac97_tag |= TAG_PCM_LFE; | 
 | 72 | 		} | 
 | 73 | 		if (chan_mask & SP_FC) { | 
 | 74 | 			dst->ac97_center = *src++; | 
 | 75 | 			dst->ac97_tag |= TAG_PCM_CENTER; | 
 | 76 | 		} | 
 | 77 | #endif | 
 | 78 | 		dst++; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 79 | 	} | 
 | 80 | } | 
 | 81 | EXPORT_SYMBOL(bf5xx_pcm_to_ac97); | 
 | 82 |  | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 83 | void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 84 | 		size_t count) | 
 | 85 | { | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 86 | 	while (count--) { | 
 | 87 | 		*(dst++) = src->ac97_pcm_l; | 
 | 88 | 		*(dst++) = src->ac97_pcm_r; | 
 | 89 | 		src++; | 
 | 90 | 	} | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 91 | } | 
 | 92 | EXPORT_SYMBOL(bf5xx_ac97_to_pcm); | 
 | 93 |  | 
 | 94 | static unsigned int sport_tx_curr_frag(struct sport_device *sport) | 
 | 95 | { | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 96 | 	return sport->tx_curr_frag = sport_curr_offset_tx(sport) / | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 97 | 			sport->tx_fragsize; | 
 | 98 | } | 
 | 99 |  | 
 | 100 | static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) | 
 | 101 | { | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 102 | 	struct sport_device *sport = ac97_sport_handle; | 
 | 103 | 	int *cmd_count = sport->private_data; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 104 | 	int nextfrag = sport_tx_curr_frag(sport); | 
 | 105 | 	struct ac97_frame *nextwrite; | 
 | 106 |  | 
 | 107 | 	sport_incfrag(sport, &nextfrag, 1); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 108 |  | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 109 | 	nextwrite = (struct ac97_frame *)(sport->tx_buf + | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 110 | 			nextfrag * sport->tx_fragsize); | 
 | 111 | 	pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", | 
 | 112 | 		sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); | 
 | 113 | 	nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD; | 
 | 114 | 	nextwrite[cmd_count[nextfrag]].ac97_addr = addr; | 
 | 115 | 	nextwrite[cmd_count[nextfrag]].ac97_data = data; | 
 | 116 | 	++cmd_count[nextfrag]; | 
 | 117 | 	pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n", | 
 | 118 | 			addr >> 8, data, nextfrag); | 
 | 119 | } | 
 | 120 |  | 
 | 121 | static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97, | 
 | 122 | 	unsigned short reg) | 
 | 123 | { | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 124 | 	struct sport_device *sport_handle = ac97_sport_handle; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 125 | 	struct ac97_frame out_frame[2], in_frame[2]; | 
 | 126 |  | 
 | 127 | 	pr_debug("%s enter 0x%x\n", __func__, reg); | 
 | 128 |  | 
 | 129 | 	/* When dma descriptor is enabled, the register should not be read */ | 
 | 130 | 	if (sport_handle->tx_run || sport_handle->rx_run) { | 
 | 131 | 		pr_err("Could you send a mail to cliff.cai@analog.com " | 
 | 132 | 				"to report this?\n"); | 
 | 133 | 		return -EFAULT; | 
 | 134 | 	} | 
 | 135 |  | 
 | 136 | 	memset(&out_frame, 0, 2 * sizeof(struct ac97_frame)); | 
 | 137 | 	memset(&in_frame, 0, 2 * sizeof(struct ac97_frame)); | 
 | 138 | 	out_frame[0].ac97_tag = TAG_VALID | TAG_CMD; | 
 | 139 | 	out_frame[0].ac97_addr = ((reg << 8) | 0x8000); | 
 | 140 | 	sport_send_and_recv(sport_handle, (unsigned char *)&out_frame, | 
 | 141 | 			(unsigned char *)&in_frame, | 
 | 142 | 			2 * sizeof(struct ac97_frame)); | 
 | 143 | 	return in_frame[1].ac97_data; | 
 | 144 | } | 
 | 145 |  | 
 | 146 | void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, | 
 | 147 | 	unsigned short val) | 
 | 148 | { | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 149 | 	struct sport_device *sport_handle = ac97_sport_handle; | 
 | 150 |  | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 151 | 	pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val); | 
 | 152 |  | 
 | 153 | 	if (sport_handle->tx_run) { | 
 | 154 | 		enqueue_cmd(ac97, (reg << 8), val); /* write */ | 
 | 155 | 		enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */ | 
 | 156 | 	} else { | 
 | 157 | 		struct ac97_frame frame; | 
 | 158 | 		memset(&frame, 0, sizeof(struct ac97_frame)); | 
 | 159 | 		frame.ac97_tag = TAG_VALID | TAG_CMD; | 
 | 160 | 		frame.ac97_addr = (reg << 8); | 
 | 161 | 		frame.ac97_data = val; | 
 | 162 | 		sport_send_and_recv(sport_handle, (unsigned char *)&frame, \ | 
 | 163 | 				NULL, sizeof(struct ac97_frame)); | 
 | 164 | 	} | 
 | 165 | } | 
 | 166 |  | 
 | 167 | static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97) | 
 | 168 | { | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 169 | 	struct sport_device *sport_handle = ac97_sport_handle; | 
 | 170 | 	u16 gpio = P_IDENT(sport_handle->pin_req[3]); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 171 |  | 
 | 172 | 	pr_debug("%s enter\n", __func__); | 
 | 173 |  | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 174 | 	peripheral_free_list(sport_handle->pin_req); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 175 | 	gpio_request(gpio, "bf5xx-ac97"); | 
 | 176 | 	gpio_direction_output(gpio, 1); | 
 | 177 | 	udelay(2); | 
 | 178 | 	gpio_set_value(gpio, 0); | 
 | 179 | 	udelay(1); | 
 | 180 | 	gpio_free(gpio); | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 181 | 	peripheral_request_list(sport_handle->pin_req, "soc-audio"); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 182 | } | 
 | 183 |  | 
 | 184 | static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97) | 
 | 185 | { | 
 | 186 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 
 | 187 | 	pr_debug("%s enter\n", __func__); | 
 | 188 |  | 
 | 189 | 	/* It is specified for bf548-ezkit */ | 
 | 190 | 	gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0); | 
 | 191 | 	/* Keep reset pin low for 1 ms */ | 
 | 192 | 	mdelay(1); | 
 | 193 | 	gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); | 
 | 194 | 	/* Wait for bit clock recover */ | 
 | 195 | 	mdelay(1); | 
 | 196 | #else | 
 | 197 | 	pr_info("%s: Not implemented\n", __func__); | 
 | 198 | #endif | 
 | 199 | } | 
 | 200 |  | 
 | 201 | struct snd_ac97_bus_ops soc_ac97_ops = { | 
 | 202 | 	.read	= bf5xx_ac97_read, | 
 | 203 | 	.write	= bf5xx_ac97_write, | 
 | 204 | 	.warm_reset	= bf5xx_ac97_warm_reset, | 
 | 205 | 	.reset	= bf5xx_ac97_cold_reset, | 
 | 206 | }; | 
 | 207 | EXPORT_SYMBOL_GPL(soc_ac97_ops); | 
 | 208 |  | 
 | 209 | #ifdef CONFIG_PM | 
| Mark Brown | dc7d7b8 | 2008-12-03 18:21:52 +0000 | [diff] [blame] | 210 | static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 211 | { | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 212 | 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 213 |  | 
 | 214 | 	pr_debug("%s : sport %d\n", __func__, dai->id); | 
 | 215 | 	if (!dai->active) | 
 | 216 | 		return 0; | 
| Mike Frysinger | e9c2048 | 2011-01-11 19:57:33 -0500 | [diff] [blame] | 217 | 	if (dai->capture_active) | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 218 | 		sport_rx_stop(sport); | 
| Mike Frysinger | e9c2048 | 2011-01-11 19:57:33 -0500 | [diff] [blame] | 219 | 	if (dai->playback_active) | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 220 | 		sport_tx_stop(sport); | 
 | 221 | 	return 0; | 
 | 222 | } | 
 | 223 |  | 
| Mark Brown | dc7d7b8 | 2008-12-03 18:21:52 +0000 | [diff] [blame] | 224 | static int bf5xx_ac97_resume(struct snd_soc_dai *dai) | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 225 | { | 
 | 226 | 	int ret; | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 227 | 	struct sport_device *sport = snd_soc_dai_get_drvdata(dai); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 228 |  | 
 | 229 | 	pr_debug("%s : sport %d\n", __func__, dai->id); | 
 | 230 | 	if (!dai->active) | 
 | 231 | 		return 0; | 
 | 232 |  | 
| Cliff Cai | 79dfc96 | 2009-09-16 20:25:08 -0400 | [diff] [blame] | 233 | #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) | 
 | 234 | 	ret = sport_set_multichannel(sport, 16, 0x3FF, 1); | 
 | 235 | #else | 
| Cliff Cai | 18d02bc | 2009-07-14 10:01:39 -0400 | [diff] [blame] | 236 | 	ret = sport_set_multichannel(sport, 16, 0x1F, 1); | 
| Cliff Cai | 79dfc96 | 2009-09-16 20:25:08 -0400 | [diff] [blame] | 237 | #endif | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 238 | 	if (ret) { | 
 | 239 | 		pr_err("SPORT is busy!\n"); | 
 | 240 | 		return -EBUSY; | 
 | 241 | 	} | 
 | 242 |  | 
| Cliff Cai | 18d02bc | 2009-07-14 10:01:39 -0400 | [diff] [blame] | 243 | 	ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1)); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 244 | 	if (ret) { | 
 | 245 | 		pr_err("SPORT is busy!\n"); | 
 | 246 | 		return -EBUSY; | 
 | 247 | 	} | 
 | 248 |  | 
| Cliff Cai | 18d02bc | 2009-07-14 10:01:39 -0400 | [diff] [blame] | 249 | 	ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1)); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 250 | 	if (ret) { | 
 | 251 | 		pr_err("SPORT is busy!\n"); | 
 | 252 | 		return -EBUSY; | 
 | 253 | 	} | 
 | 254 |  | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 255 | 	return 0; | 
 | 256 | } | 
 | 257 |  | 
 | 258 | #else | 
 | 259 | #define bf5xx_ac97_suspend	NULL | 
 | 260 | #define bf5xx_ac97_resume	NULL | 
 | 261 | #endif | 
 | 262 |  | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 263 | static struct snd_soc_dai_driver bfin_ac97_dai = { | 
 | 264 | 	.ac97_control = 1, | 
 | 265 | 	.suspend = bf5xx_ac97_suspend, | 
 | 266 | 	.resume = bf5xx_ac97_resume, | 
 | 267 | 	.playback = { | 
 | 268 | 		.stream_name = "AC97 Playback", | 
 | 269 | 		.channels_min = 2, | 
 | 270 | #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) | 
 | 271 | 		.channels_max = 6, | 
 | 272 | #else | 
 | 273 | 		.channels_max = 2, | 
 | 274 | #endif | 
 | 275 | 		.rates = SNDRV_PCM_RATE_48000, | 
 | 276 | 		.formats = SNDRV_PCM_FMTBIT_S16_LE, }, | 
 | 277 | 	.capture = { | 
 | 278 | 		.stream_name = "AC97 Capture", | 
 | 279 | 		.channels_min = 2, | 
 | 280 | 		.channels_max = 2, | 
 | 281 | 		.rates = SNDRV_PCM_RATE_48000, | 
 | 282 | 		.formats = SNDRV_PCM_FMTBIT_S16_LE, }, | 
 | 283 | }; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 284 |  | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 285 | static int __devinit asoc_bfin_ac97_probe(struct platform_device *pdev) | 
 | 286 | { | 
 | 287 | 	struct sport_device *sport_handle; | 
 | 288 | 	int ret; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 289 |  | 
 | 290 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 
 | 291 | 	/* Request PB3 as reset pin */ | 
 | 292 | 	if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { | 
 | 293 | 		pr_err("Failed to request GPIO_%d for reset\n", | 
 | 294 | 				CONFIG_SND_BF5XX_RESET_GPIO_NUM); | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 295 | 		ret =  -1; | 
 | 296 | 		goto gpio_err; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 297 | 	} | 
 | 298 | 	gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); | 
 | 299 | #endif | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 300 |  | 
 | 301 | 	sport_handle = sport_init(pdev, 2, sizeof(struct ac97_frame), | 
 | 302 | 		PAGE_SIZE); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 303 | 	if (!sport_handle) { | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 304 | 		ret = -ENODEV; | 
 | 305 | 		goto sport_err; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 306 | 	} | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 307 |  | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 308 | 	/*SPORT works in TDM mode to simulate AC97 transfers*/ | 
| Cliff Cai | 79dfc96 | 2009-09-16 20:25:08 -0400 | [diff] [blame] | 309 | #if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) | 
 | 310 | 	ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1); | 
 | 311 | #else | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 312 | 	ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); | 
| Cliff Cai | 79dfc96 | 2009-09-16 20:25:08 -0400 | [diff] [blame] | 313 | #endif | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 314 | 	if (ret) { | 
 | 315 | 		pr_err("SPORT is busy!\n"); | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 316 | 		ret = -EBUSY; | 
 | 317 | 		goto sport_config_err; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 318 | 	} | 
 | 319 |  | 
 | 320 | 	ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); | 
 | 321 | 	if (ret) { | 
 | 322 | 		pr_err("SPORT is busy!\n"); | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 323 | 		ret = -EBUSY; | 
 | 324 | 		goto sport_config_err; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 325 | 	} | 
 | 326 |  | 
 | 327 | 	ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); | 
 | 328 | 	if (ret) { | 
 | 329 | 		pr_err("SPORT is busy!\n"); | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 330 | 		ret = -EBUSY; | 
 | 331 | 		goto sport_config_err; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 332 | 	} | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 333 |  | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 334 | 	ret = snd_soc_register_dai(&pdev->dev, &bfin_ac97_dai); | 
 | 335 | 	if (ret) { | 
 | 336 | 		pr_err("Failed to register DAI: %d\n", ret); | 
 | 337 | 		goto sport_config_err; | 
 | 338 | 	} | 
 | 339 |  | 
 | 340 | 	ac97_sport_handle = sport_handle; | 
 | 341 |  | 
| Michael Hennerich | 0cade26 | 2008-11-18 16:18:19 +0800 | [diff] [blame] | 342 | 	return 0; | 
 | 343 |  | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 344 | sport_config_err: | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 345 | 	sport_done(sport_handle); | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 346 | sport_err: | 
 | 347 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 
 | 348 | 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 349 | gpio_err: | 
| Mike Frysinger | 3465d93 | 2009-03-06 15:53:28 +0800 | [diff] [blame] | 350 | #endif | 
| Cliff Cai | 67f854b | 2008-11-18 16:18:17 +0800 | [diff] [blame] | 351 |  | 
 | 352 | 	return ret; | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 353 | } | 
 | 354 |  | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 355 | static int __devexit asoc_bfin_ac97_remove(struct platform_device *pdev) | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 356 | { | 
| Barry Song | 2c66cb9 | 2011-03-28 01:45:10 -0400 | [diff] [blame^] | 357 | 	struct sport_device *sport_handle = platform_get_drvdata(pdev); | 
 | 358 |  | 
 | 359 | 	snd_soc_unregister_dai(&pdev->dev); | 
 | 360 | 	sport_done(sport_handle); | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 361 | #ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET | 
 | 362 | 	gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); | 
 | 363 | #endif | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 364 |  | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 365 | 	return 0; | 
 | 366 | } | 
 | 367 |  | 
 | 368 | static struct platform_driver asoc_bfin_ac97_driver = { | 
 | 369 | 	.driver = { | 
 | 370 | 			.name = "bfin-ac97", | 
 | 371 | 			.owner = THIS_MODULE, | 
 | 372 | 	}, | 
 | 373 |  | 
 | 374 | 	.probe = asoc_bfin_ac97_probe, | 
 | 375 | 	.remove = __devexit_p(asoc_bfin_ac97_remove), | 
 | 376 | }; | 
 | 377 |  | 
| Takashi Iwai | c9b3a40 | 2008-12-10 07:47:22 +0100 | [diff] [blame] | 378 | static int __init bfin_ac97_init(void) | 
| Mark Brown | 3f4b783 | 2008-12-03 19:26:35 +0000 | [diff] [blame] | 379 | { | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 380 | 	return platform_driver_register(&asoc_bfin_ac97_driver); | 
| Mark Brown | 3f4b783 | 2008-12-03 19:26:35 +0000 | [diff] [blame] | 381 | } | 
 | 382 | module_init(bfin_ac97_init); | 
 | 383 |  | 
 | 384 | static void __exit bfin_ac97_exit(void) | 
 | 385 | { | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 386 | 	platform_driver_unregister(&asoc_bfin_ac97_driver); | 
| Mark Brown | 3f4b783 | 2008-12-03 19:26:35 +0000 | [diff] [blame] | 387 | } | 
 | 388 | module_exit(bfin_ac97_exit); | 
 | 389 |  | 
| Liam Girdwood | f0fba2a | 2010-03-17 20:15:21 +0000 | [diff] [blame] | 390 |  | 
| Cliff Cai | f202862 | 2008-09-05 18:21:37 +0800 | [diff] [blame] | 391 | MODULE_AUTHOR("Roy Huang"); | 
 | 392 | MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); | 
 | 393 | MODULE_LICENSE("GPL"); |