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> 19#include <linux/slab.h> 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 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 44static int *cmd_count; 45static int sport_num = CONFIG_SND_BF5XX_SPORT_NUM; 46 47#define SPORT_REQ(x) \ 48 [x] = {P_SPORT##x##_TFS, P_SPORT##x##_DTPRI, P_SPORT##x##_TSCLK, \ 49 P_SPORT##x##_RFS, P_SPORT##x##_DRPRI, P_SPORT##x##_RSCLK, 0} 50static u16 sport_req[][7] = { 51#ifdef SPORT0_TCR1 52 SPORT_REQ(0), 53#endif 54#ifdef SPORT1_TCR1 55 SPORT_REQ(1), 56#endif 57#ifdef SPORT2_TCR1 58 SPORT_REQ(2), 59#endif 60#ifdef SPORT3_TCR1 61 SPORT_REQ(3), 62#endif 63}; 64 65#define SPORT_PARAMS(x) \ 66 [x] = { \ 67 .dma_rx_chan = CH_SPORT##x##_RX, \ 68 .dma_tx_chan = CH_SPORT##x##_TX, \ 69 .err_irq = IRQ_SPORT##x##_ERROR, \ 70 .regs = (struct sport_register *)SPORT##x##_TCR1, \ 71 } 72static struct sport_param sport_params[4] = { 73#ifdef SPORT0_TCR1 74 SPORT_PARAMS(0), 75#endif 76#ifdef SPORT1_TCR1 77 SPORT_PARAMS(1), 78#endif 79#ifdef SPORT2_TCR1 80 SPORT_PARAMS(2), 81#endif 82#ifdef SPORT3_TCR1 83 SPORT_PARAMS(3), 84#endif 85}; 86 87void bf5xx_pcm_to_ac97(struct ac97_frame *dst, const __u16 *src, 88 size_t count, unsigned int chan_mask) 89{ 90 while (count--) { 91 dst->ac97_tag = TAG_VALID; 92 if (chan_mask & SP_FL) { 93 dst->ac97_pcm_r = *src++; 94 dst->ac97_tag |= TAG_PCM_RIGHT; 95 } 96 if (chan_mask & SP_FR) { 97 dst->ac97_pcm_l = *src++; 98 dst->ac97_tag |= TAG_PCM_LEFT; 99 100 } 101#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) 102 if (chan_mask & SP_SR) { 103 dst->ac97_sl = *src++; 104 dst->ac97_tag |= TAG_PCM_SL; 105 } 106 if (chan_mask & SP_SL) { 107 dst->ac97_sr = *src++; 108 dst->ac97_tag |= TAG_PCM_SR; 109 } 110 if (chan_mask & SP_LFE) { 111 dst->ac97_lfe = *src++; 112 dst->ac97_tag |= TAG_PCM_LFE; 113 } 114 if (chan_mask & SP_FC) { 115 dst->ac97_center = *src++; 116 dst->ac97_tag |= TAG_PCM_CENTER; 117 } 118#endif 119 dst++; 120 } 121} 122EXPORT_SYMBOL(bf5xx_pcm_to_ac97); 123 124void bf5xx_ac97_to_pcm(const struct ac97_frame *src, __u16 *dst, 125 size_t count) 126{ 127 while (count--) { 128 *(dst++) = src->ac97_pcm_l; 129 *(dst++) = src->ac97_pcm_r; 130 src++; 131 } 132} 133EXPORT_SYMBOL(bf5xx_ac97_to_pcm); 134 135static unsigned int sport_tx_curr_frag(struct sport_device *sport) 136{ 137 return sport->tx_curr_frag = sport_curr_offset_tx(sport) / 138 sport->tx_fragsize; 139} 140 141static void enqueue_cmd(struct snd_ac97 *ac97, __u16 addr, __u16 data) 142{ 143 struct sport_device *sport = sport_handle; 144 int nextfrag = sport_tx_curr_frag(sport); 145 struct ac97_frame *nextwrite; 146 147 sport_incfrag(sport, &nextfrag, 1); 148 149 nextwrite = (struct ac97_frame *)(sport->tx_buf + 150 nextfrag * sport->tx_fragsize); 151 pr_debug("sport->tx_buf:%p, nextfrag:0x%x nextwrite:%p, cmd_count:%d\n", 152 sport->tx_buf, nextfrag, nextwrite, cmd_count[nextfrag]); 153 nextwrite[cmd_count[nextfrag]].ac97_tag |= TAG_CMD; 154 nextwrite[cmd_count[nextfrag]].ac97_addr = addr; 155 nextwrite[cmd_count[nextfrag]].ac97_data = data; 156 ++cmd_count[nextfrag]; 157 pr_debug("ac97_sport: Inserting %02x/%04x into fragment %d\n", 158 addr >> 8, data, nextfrag); 159} 160 161static unsigned short bf5xx_ac97_read(struct snd_ac97 *ac97, 162 unsigned short reg) 163{ 164 struct ac97_frame out_frame[2], in_frame[2]; 165 166 pr_debug("%s enter 0x%x\n", __func__, reg); 167 168 /* When dma descriptor is enabled, the register should not be read */ 169 if (sport_handle->tx_run || sport_handle->rx_run) { 170 pr_err("Could you send a mail to cliff.cai@analog.com " 171 "to report this?\n"); 172 return -EFAULT; 173 } 174 175 memset(&out_frame, 0, 2 * sizeof(struct ac97_frame)); 176 memset(&in_frame, 0, 2 * sizeof(struct ac97_frame)); 177 out_frame[0].ac97_tag = TAG_VALID | TAG_CMD; 178 out_frame[0].ac97_addr = ((reg << 8) | 0x8000); 179 sport_send_and_recv(sport_handle, (unsigned char *)&out_frame, 180 (unsigned char *)&in_frame, 181 2 * sizeof(struct ac97_frame)); 182 return in_frame[1].ac97_data; 183} 184 185void bf5xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg, 186 unsigned short val) 187{ 188 pr_debug("%s enter 0x%x:0x%04x\n", __func__, reg, val); 189 190 if (sport_handle->tx_run) { 191 enqueue_cmd(ac97, (reg << 8), val); /* write */ 192 enqueue_cmd(ac97, (reg << 8) | 0x8000, 0); /* read back */ 193 } else { 194 struct ac97_frame frame; 195 memset(&frame, 0, sizeof(struct ac97_frame)); 196 frame.ac97_tag = TAG_VALID | TAG_CMD; 197 frame.ac97_addr = (reg << 8); 198 frame.ac97_data = val; 199 sport_send_and_recv(sport_handle, (unsigned char *)&frame, \ 200 NULL, sizeof(struct ac97_frame)); 201 } 202} 203 204static void bf5xx_ac97_warm_reset(struct snd_ac97 *ac97) 205{ 206#if defined(CONFIG_BF54x) || defined(CONFIG_BF561) || (defined(BF537_FAMILY) && \ 207 (CONFIG_SND_BF5XX_SPORT_NUM == 1)) 208 209#define CONCAT(a, b, c) a ## b ## c 210#define BFIN_SPORT_RFS(x) CONCAT(P_SPORT, x, _RFS) 211 212 u16 per = BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM); 213 u16 gpio = P_IDENT(BFIN_SPORT_RFS(CONFIG_SND_BF5XX_SPORT_NUM)); 214 215 pr_debug("%s enter\n", __func__); 216 217 peripheral_free(per); 218 gpio_request(gpio, "bf5xx-ac97"); 219 gpio_direction_output(gpio, 1); 220 udelay(2); 221 gpio_set_value(gpio, 0); 222 udelay(1); 223 gpio_free(gpio); 224 peripheral_request(per, "soc-audio"); 225#else 226 pr_info("%s: Not implemented\n", __func__); 227#endif 228} 229 230static void bf5xx_ac97_cold_reset(struct snd_ac97 *ac97) 231{ 232#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 233 pr_debug("%s enter\n", __func__); 234 235 /* It is specified for bf548-ezkit */ 236 gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 0); 237 /* Keep reset pin low for 1 ms */ 238 mdelay(1); 239 gpio_set_value(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); 240 /* Wait for bit clock recover */ 241 mdelay(1); 242#else 243 pr_info("%s: Not implemented\n", __func__); 244#endif 245} 246 247struct snd_ac97_bus_ops soc_ac97_ops = { 248 .read = bf5xx_ac97_read, 249 .write = bf5xx_ac97_write, 250 .warm_reset = bf5xx_ac97_warm_reset, 251 .reset = bf5xx_ac97_cold_reset, 252}; 253EXPORT_SYMBOL_GPL(soc_ac97_ops); 254 255#ifdef CONFIG_PM 256static int bf5xx_ac97_suspend(struct snd_soc_dai *dai) 257{ 258 struct sport_device *sport = dai->private_data; 259 260 pr_debug("%s : sport %d\n", __func__, dai->id); 261 if (!dai->active) 262 return 0; 263 if (dai->capture_active) 264 sport_rx_stop(sport); 265 if (dai->playback_active) 266 sport_tx_stop(sport); 267 return 0; 268} 269 270static int bf5xx_ac97_resume(struct snd_soc_dai *dai) 271{ 272 int ret; 273 struct sport_device *sport = dai->private_data; 274 275 pr_debug("%s : sport %d\n", __func__, dai->id); 276 if (!dai->active) 277 return 0; 278 279#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) 280 ret = sport_set_multichannel(sport, 16, 0x3FF, 1); 281#else 282 ret = sport_set_multichannel(sport, 16, 0x1F, 1); 283#endif 284 if (ret) { 285 pr_err("SPORT is busy!\n"); 286 return -EBUSY; 287 } 288 289 ret = sport_config_rx(sport, IRFS, 0xF, 0, (16*16-1)); 290 if (ret) { 291 pr_err("SPORT is busy!\n"); 292 return -EBUSY; 293 } 294 295 ret = sport_config_tx(sport, ITFS, 0xF, 0, (16*16-1)); 296 if (ret) { 297 pr_err("SPORT is busy!\n"); 298 return -EBUSY; 299 } 300 301 return 0; 302} 303 304#else 305#define bf5xx_ac97_suspend NULL 306#define bf5xx_ac97_resume NULL 307#endif 308 309static int bf5xx_ac97_probe(struct platform_device *pdev, 310 struct snd_soc_dai *dai) 311{ 312 int ret = 0; 313 cmd_count = (int *)get_zeroed_page(GFP_KERNEL); 314 if (cmd_count == NULL) 315 return -ENOMEM; 316 317 if (peripheral_request_list(sport_req[sport_num], "soc-audio")) { 318 pr_err("Requesting Peripherals failed\n"); 319 ret = -EFAULT; 320 goto peripheral_err; 321 } 322 323#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 324 /* Request PB3 as reset pin */ 325 if (gpio_request(CONFIG_SND_BF5XX_RESET_GPIO_NUM, "SND_AD198x RESET")) { 326 pr_err("Failed to request GPIO_%d for reset\n", 327 CONFIG_SND_BF5XX_RESET_GPIO_NUM); 328 ret = -1; 329 goto gpio_err; 330 } 331 gpio_direction_output(CONFIG_SND_BF5XX_RESET_GPIO_NUM, 1); 332#endif 333 sport_handle = sport_init(&sport_params[sport_num], 2, \ 334 sizeof(struct ac97_frame), NULL); 335 if (!sport_handle) { 336 ret = -ENODEV; 337 goto sport_err; 338 } 339 /*SPORT works in TDM mode to simulate AC97 transfers*/ 340#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) 341 ret = sport_set_multichannel(sport_handle, 16, 0x3FF, 1); 342#else 343 ret = sport_set_multichannel(sport_handle, 16, 0x1F, 1); 344#endif 345 if (ret) { 346 pr_err("SPORT is busy!\n"); 347 ret = -EBUSY; 348 goto sport_config_err; 349 } 350 351 ret = sport_config_rx(sport_handle, IRFS, 0xF, 0, (16*16-1)); 352 if (ret) { 353 pr_err("SPORT is busy!\n"); 354 ret = -EBUSY; 355 goto sport_config_err; 356 } 357 358 ret = sport_config_tx(sport_handle, ITFS, 0xF, 0, (16*16-1)); 359 if (ret) { 360 pr_err("SPORT is busy!\n"); 361 ret = -EBUSY; 362 goto sport_config_err; 363 } 364 365 return 0; 366 367sport_config_err: 368 kfree(sport_handle); 369sport_err: 370#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 371 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); 372gpio_err: 373#endif 374 peripheral_free_list(sport_req[sport_num]); 375peripheral_err: 376 free_page((unsigned long)cmd_count); 377 cmd_count = NULL; 378 379 return ret; 380} 381 382static void bf5xx_ac97_remove(struct platform_device *pdev, 383 struct snd_soc_dai *dai) 384{ 385 free_page((unsigned long)cmd_count); 386 cmd_count = NULL; 387 peripheral_free_list(sport_req[sport_num]); 388#ifdef CONFIG_SND_BF5XX_HAVE_COLD_RESET 389 gpio_free(CONFIG_SND_BF5XX_RESET_GPIO_NUM); 390#endif 391} 392 393struct snd_soc_dai bfin_ac97_dai = { 394 .name = "bf5xx-ac97", 395 .id = 0, 396 .ac97_control = 1, 397 .probe = bf5xx_ac97_probe, 398 .remove = bf5xx_ac97_remove, 399 .suspend = bf5xx_ac97_suspend, 400 .resume = bf5xx_ac97_resume, 401 .playback = { 402 .stream_name = "AC97 Playback", 403 .channels_min = 2, 404#if defined(CONFIG_SND_BF5XX_MULTICHAN_SUPPORT) 405 .channels_max = 6, 406#else 407 .channels_max = 2, 408#endif 409 .rates = SNDRV_PCM_RATE_48000, 410 .formats = SNDRV_PCM_FMTBIT_S16_LE, }, 411 .capture = { 412 .stream_name = "AC97 Capture", 413 .channels_min = 2, 414 .channels_max = 2, 415 .rates = SNDRV_PCM_RATE_48000, 416 .formats = SNDRV_PCM_FMTBIT_S16_LE, }, 417}; 418EXPORT_SYMBOL_GPL(bfin_ac97_dai); 419 420static int __init bfin_ac97_init(void) 421{ 422 return snd_soc_register_dai(&bfin_ac97_dai); 423} 424module_init(bfin_ac97_init); 425 426static void __exit bfin_ac97_exit(void) 427{ 428 snd_soc_unregister_dai(&bfin_ac97_dai); 429} 430module_exit(bfin_ac97_exit); 431 432MODULE_AUTHOR("Roy Huang"); 433MODULE_DESCRIPTION("AC97 driver for ADI Blackfin"); 434MODULE_LICENSE("GPL"); 435