1/* 2 * File: sound/soc/blackfin/bf5xx-ad73311.c 3 * Author: Cliff Cai <Cliff.Cai@analog.com> 4 * 5 * Created: Thur Sep 25 2008 6 * Description: Board driver for ad73311 sound chip 7 * 8 * Modified: 9 * Copyright 2008 Analog Devices Inc. 10 * 11 * Bugs: Enter bugs at http://blackfin.uclinux.org/ 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2 of the License, or 16 * (at your option) any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, see the file COPYING, or write 25 * to the Free Software Foundation, Inc., 26 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 27 */ 28 29#include <linux/module.h> 30#include <linux/moduleparam.h> 31#include <linux/device.h> 32#include <linux/delay.h> 33#include <linux/gpio.h> 34 35#include <sound/core.h> 36#include <sound/pcm.h> 37#include <sound/soc.h> 38#include <sound/pcm_params.h> 39 40#include <asm/blackfin.h> 41#include <asm/cacheflush.h> 42#include <asm/irq.h> 43#include <asm/dma.h> 44#include <asm/portmux.h> 45 46#include "../codecs/ad73311.h" 47#include "bf5xx-sport.h" 48 49#if CONFIG_SND_BF5XX_SPORT_NUM == 0 50#define bfin_write_SPORT_TCR1 bfin_write_SPORT0_TCR1 51#define bfin_read_SPORT_TCR1 bfin_read_SPORT0_TCR1 52#define bfin_write_SPORT_TCR2 bfin_write_SPORT0_TCR2 53#define bfin_write_SPORT_TX16 bfin_write_SPORT0_TX16 54#define bfin_read_SPORT_STAT bfin_read_SPORT0_STAT 55#else 56#define bfin_write_SPORT_TCR1 bfin_write_SPORT1_TCR1 57#define bfin_read_SPORT_TCR1 bfin_read_SPORT1_TCR1 58#define bfin_write_SPORT_TCR2 bfin_write_SPORT1_TCR2 59#define bfin_write_SPORT_TX16 bfin_write_SPORT1_TX16 60#define bfin_read_SPORT_STAT bfin_read_SPORT1_STAT 61#endif 62 63#define GPIO_SE CONFIG_SND_BFIN_AD73311_SE 64 65static struct snd_soc_card bf5xx_ad73311; 66 67static int snd_ad73311_startup(void) 68{ 69 pr_debug("%s enter\n", __func__); 70 71 /* Pull up SE pin on AD73311L */ 72 gpio_set_value(GPIO_SE, 1); 73 return 0; 74} 75 76static int snd_ad73311_configure(void) 77{ 78 unsigned short ctrl_regs[6]; 79 unsigned short status = 0; 80 int count = 0; 81 82 /* DMCLK = MCLK = 16.384 MHz 83 * SCLK = DMCLK/8 = 2.048 MHz 84 * Sample Rate = DMCLK/2048 = 8 KHz 85 */ 86 ctrl_regs[0] = AD_CONTROL | AD_WRITE | CTRL_REG_B | REGB_MCDIV(0) | \ 87 REGB_SCDIV(0) | REGB_DIRATE(0); 88 ctrl_regs[1] = AD_CONTROL | AD_WRITE | CTRL_REG_C | REGC_PUDEV | \ 89 REGC_PUADC | REGC_PUDAC | REGC_PUREF | REGC_REFUSE ; 90 ctrl_regs[2] = AD_CONTROL | AD_WRITE | CTRL_REG_D | REGD_OGS(2) | \ 91 REGD_IGS(2); 92 ctrl_regs[3] = AD_CONTROL | AD_WRITE | CTRL_REG_E | REGE_DA(0x1f); 93 ctrl_regs[4] = AD_CONTROL | AD_WRITE | CTRL_REG_F | REGF_SEEN ; 94 ctrl_regs[5] = AD_CONTROL | AD_WRITE | CTRL_REG_A | REGA_MODE_DATA; 95 96 local_irq_disable(); 97 snd_ad73311_startup(); 98 udelay(1); 99 100 bfin_write_SPORT_TCR1(TFSR); 101 bfin_write_SPORT_TCR2(0xF); 102 SSYNC(); 103 104 /* SPORT Tx Register is a 8 x 16 FIFO, all the data can be put to 105 * FIFO before enable SPORT to transfer the data 106 */ 107 for (count = 0; count < 6; count++) 108 bfin_write_SPORT_TX16(ctrl_regs[count]); 109 SSYNC(); 110 bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() | TSPEN); 111 SSYNC(); 112 113 /* When TUVF is set, the data is already send out */ 114 while (!(status & TUVF) && ++count < 10000) { 115 udelay(1); 116 status = bfin_read_SPORT_STAT(); 117 SSYNC(); 118 } 119 bfin_write_SPORT_TCR1(bfin_read_SPORT_TCR1() & ~TSPEN); 120 SSYNC(); 121 local_irq_enable(); 122 123 if (count >= 10000) { 124 printk(KERN_ERR "ad73311: failed to configure codec\n"); 125 return -1; 126 } 127 return 0; 128} 129 130static int bf5xx_probe(struct snd_soc_card *card) 131{ 132 int err; 133 if (gpio_request(GPIO_SE, "AD73311_SE")) { 134 printk(KERN_ERR "%s: Failed ro request GPIO_%d\n", __func__, GPIO_SE); 135 return -EBUSY; 136 } 137 138 gpio_direction_output(GPIO_SE, 0); 139 140 err = snd_ad73311_configure(); 141 if (err < 0) 142 return -EFAULT; 143 144 return 0; 145} 146 147#define BF5XX_AD7311_DAI_FMT (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | \ 148 SND_SOC_DAIFMT_CBM_CFM) 149 150static struct snd_soc_dai_link bf5xx_ad73311_dai[] = { 151 { 152 .name = "ad73311", 153 .stream_name = "AD73311", 154 .cpu_dai_name = "bfin-i2s.0", 155 .codec_dai_name = "ad73311-hifi", 156 .platform_name = "bfin-i2s-pcm-audio", 157 .codec_name = "ad73311", 158 .dai_fmt = BF5XX_AD7311_DAI_FMT, 159 }, 160 { 161 .name = "ad73311", 162 .stream_name = "AD73311", 163 .cpu_dai_name = "bfin-i2s.1", 164 .codec_dai_name = "ad73311-hifi", 165 .platform_name = "bfin-i2s-pcm-audio", 166 .codec_name = "ad73311", 167 .dai_fmt = BF5XX_AD7311_DAI_FMT, 168 }, 169}; 170 171static struct snd_soc_card bf5xx_ad73311 = { 172 .name = "bfin-ad73311", 173 .owner = THIS_MODULE, 174 .probe = bf5xx_probe, 175 .dai_link = &bf5xx_ad73311_dai[CONFIG_SND_BF5XX_SPORT_NUM], 176 .num_links = 1, 177}; 178 179static struct platform_device *bf5xx_ad73311_snd_device; 180 181static int __init bf5xx_ad73311_init(void) 182{ 183 int ret; 184 185 pr_debug("%s enter\n", __func__); 186 bf5xx_ad73311_snd_device = platform_device_alloc("soc-audio", -1); 187 if (!bf5xx_ad73311_snd_device) 188 return -ENOMEM; 189 190 platform_set_drvdata(bf5xx_ad73311_snd_device, &bf5xx_ad73311); 191 ret = platform_device_add(bf5xx_ad73311_snd_device); 192 193 if (ret) 194 platform_device_put(bf5xx_ad73311_snd_device); 195 196 return ret; 197} 198 199static void __exit bf5xx_ad73311_exit(void) 200{ 201 pr_debug("%s enter\n", __func__); 202 platform_device_unregister(bf5xx_ad73311_snd_device); 203} 204 205module_init(bf5xx_ad73311_init); 206module_exit(bf5xx_ad73311_exit); 207 208/* Module information */ 209MODULE_AUTHOR("Cliff Cai"); 210MODULE_DESCRIPTION("ALSA SoC AD73311 Blackfin"); 211MODULE_LICENSE("GPL"); 212 213