1/* 2 * linux/sound/soc/ep93xx-i2s.c 3 * EP93xx I2S driver 4 * 5 * Copyright (C) 2010 Ryan Mallon <ryan@bluewatersys.com> 6 * 7 * Based on the original driver by: 8 * Copyright (C) 2007 Chase Douglas <chasedouglas@gmail> 9 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org> 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 * 15 */ 16 17#include <linux/module.h> 18#include <linux/init.h> 19#include <linux/slab.h> 20#include <linux/clk.h> 21#include <linux/io.h> 22 23#include <sound/core.h> 24#include <sound/pcm.h> 25#include <sound/pcm_params.h> 26#include <sound/initval.h> 27#include <sound/soc.h> 28 29#include <mach/hardware.h> 30#include <mach/ep93xx-regs.h> 31#include <mach/dma.h> 32 33#include "ep93xx-pcm.h" 34#include "ep93xx-i2s.h" 35 36#define EP93XX_I2S_TXCLKCFG 0x00 37#define EP93XX_I2S_RXCLKCFG 0x04 38#define EP93XX_I2S_GLCTRL 0x0C 39 40#define EP93XX_I2S_TXLINCTRLDATA 0x28 41#define EP93XX_I2S_TXCTRL 0x2C 42#define EP93XX_I2S_TXWRDLEN 0x30 43#define EP93XX_I2S_TX0EN 0x34 44 45#define EP93XX_I2S_RXLINCTRLDATA 0x58 46#define EP93XX_I2S_RXCTRL 0x5C 47#define EP93XX_I2S_RXWRDLEN 0x60 48#define EP93XX_I2S_RX0EN 0x64 49 50#define EP93XX_I2S_WRDLEN_16 (0 << 0) 51#define EP93XX_I2S_WRDLEN_24 (1 << 0) 52#define EP93XX_I2S_WRDLEN_32 (2 << 0) 53 54#define EP93XX_I2S_LINCTRLDATA_R_JUST (1 << 2) /* Right justify */ 55 56#define EP93XX_I2S_CLKCFG_LRS (1 << 0) /* lrclk polarity */ 57#define EP93XX_I2S_CLKCFG_CKP (1 << 1) /* Bit clock polarity */ 58#define EP93XX_I2S_CLKCFG_REL (1 << 2) /* First bit transition */ 59#define EP93XX_I2S_CLKCFG_MASTER (1 << 3) /* Master mode */ 60#define EP93XX_I2S_CLKCFG_NBCG (1 << 4) /* Not bit clock gating */ 61 62struct ep93xx_i2s_info { 63 struct clk *mclk; 64 struct clk *sclk; 65 struct clk *lrclk; 66 struct ep93xx_pcm_dma_params *dma_params; 67 struct resource *mem; 68 void __iomem *regs; 69}; 70 71struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { 72 [SNDRV_PCM_STREAM_PLAYBACK] = { 73 .name = "i2s-pcm-out", 74 .dma_port = EP93XX_DMA_M2P_PORT_I2S1, 75 }, 76 [SNDRV_PCM_STREAM_CAPTURE] = { 77 .name = "i2s-pcm-in", 78 .dma_port = EP93XX_DMA_M2P_PORT_I2S1, 79 }, 80}; 81 82static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info, 83 unsigned reg, unsigned val) 84{ 85 __raw_writel(val, info->regs + reg); 86} 87 88static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info, 89 unsigned reg) 90{ 91 return __raw_readl(info->regs + reg); 92} 93 94static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream) 95{ 96 unsigned base_reg; 97 int i; 98 99 if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 && 100 (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) { 101 /* Enable clocks */ 102 clk_enable(info->mclk); 103 clk_enable(info->sclk); 104 clk_enable(info->lrclk); 105 106 /* Enable i2s */ 107 ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1); 108 } 109 110 /* Enable fifos */ 111 if (stream == SNDRV_PCM_STREAM_PLAYBACK) 112 base_reg = EP93XX_I2S_TX0EN; 113 else 114 base_reg = EP93XX_I2S_RX0EN; 115 for (i = 0; i < 3; i++) 116 ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1); 117} 118 119static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream) 120{ 121 unsigned base_reg; 122 int i; 123 124 /* Disable fifos */ 125 if (stream == SNDRV_PCM_STREAM_PLAYBACK) 126 base_reg = EP93XX_I2S_TX0EN; 127 else 128 base_reg = EP93XX_I2S_RX0EN; 129 for (i = 0; i < 3; i++) 130 ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0); 131 132 if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 && 133 (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) { 134 /* Disable i2s */ 135 ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0); 136 137 /* Disable clocks */ 138 clk_disable(info->lrclk); 139 clk_disable(info->sclk); 140 clk_disable(info->mclk); 141 } 142} 143 144static int ep93xx_i2s_startup(struct snd_pcm_substream *substream, 145 struct snd_soc_dai *dai) 146{ 147 struct snd_soc_pcm_runtime *rtd = substream->private_data; 148 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 149 struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data; 150 151 snd_soc_dai_set_dma_data(cpu_dai, substream, 152 &info->dma_params[substream->stream]); 153 return 0; 154} 155 156static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream, 157 struct snd_soc_dai *dai) 158{ 159 struct snd_soc_pcm_runtime *rtd = substream->private_data; 160 struct ep93xx_i2s_info *info = rtd->dai->cpu_dai->private_data; 161 162 ep93xx_i2s_disable(info, substream->stream); 163} 164 165static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai, 166 unsigned int fmt) 167{ 168 struct ep93xx_i2s_info *info = cpu_dai->private_data; 169 unsigned int clk_cfg, lin_ctrl; 170 171 clk_cfg = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG); 172 lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA); 173 174 switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 175 case SND_SOC_DAIFMT_I2S: 176 clk_cfg |= EP93XX_I2S_CLKCFG_REL; 177 lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; 178 break; 179 180 case SND_SOC_DAIFMT_LEFT_J: 181 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; 182 lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST; 183 break; 184 185 case SND_SOC_DAIFMT_RIGHT_J: 186 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; 187 lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST; 188 break; 189 190 default: 191 return -EINVAL; 192 } 193 194 switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 195 case SND_SOC_DAIFMT_CBS_CFS: 196 /* CPU is master */ 197 clk_cfg |= EP93XX_I2S_CLKCFG_MASTER; 198 break; 199 200 case SND_SOC_DAIFMT_CBM_CFM: 201 /* Codec is master */ 202 clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER; 203 break; 204 205 default: 206 return -EINVAL; 207 } 208 209 switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 210 case SND_SOC_DAIFMT_NB_NF: 211 /* Negative bit clock, lrclk low on left word */ 212 clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL); 213 break; 214 215 case SND_SOC_DAIFMT_NB_IF: 216 /* Negative bit clock, lrclk low on right word */ 217 clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP; 218 clk_cfg |= EP93XX_I2S_CLKCFG_REL; 219 break; 220 221 case SND_SOC_DAIFMT_IB_NF: 222 /* Positive bit clock, lrclk low on left word */ 223 clk_cfg |= EP93XX_I2S_CLKCFG_CKP; 224 clk_cfg &= ~EP93XX_I2S_CLKCFG_REL; 225 break; 226 227 case SND_SOC_DAIFMT_IB_IF: 228 /* Positive bit clock, lrclk low on right word */ 229 clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL; 230 break; 231 } 232 233 /* Write new register values */ 234 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg); 235 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg); 236 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl); 237 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl); 238 return 0; 239} 240 241static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream, 242 struct snd_pcm_hw_params *params, 243 struct snd_soc_dai *dai) 244{ 245 struct snd_soc_pcm_runtime *rtd = substream->private_data; 246 struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; 247 struct ep93xx_i2s_info *info = cpu_dai->private_data; 248 unsigned word_len, div, sdiv, lrdiv; 249 int found = 0, err; 250 251 switch (params_format(params)) { 252 case SNDRV_PCM_FORMAT_S16_LE: 253 word_len = EP93XX_I2S_WRDLEN_16; 254 break; 255 256 case SNDRV_PCM_FORMAT_S24_LE: 257 word_len = EP93XX_I2S_WRDLEN_24; 258 break; 259 260 case SNDRV_PCM_FORMAT_S32_LE: 261 word_len = EP93XX_I2S_WRDLEN_32; 262 break; 263 264 default: 265 return -EINVAL; 266 } 267 268 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 269 ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len); 270 else 271 ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len); 272 273 /* 274 * Calculate the sdiv (bit clock) and lrdiv (left/right clock) values. 275 * If the lrclk is pulse length is larger than the word size, then the 276 * bit clock will be gated for the unused bits. 277 */ 278 div = (clk_get_rate(info->mclk) / params_rate(params)) * 279 params_channels(params); 280 for (sdiv = 2; sdiv <= 4; sdiv += 2) 281 for (lrdiv = 32; lrdiv <= 128; lrdiv <<= 1) 282 if (sdiv * lrdiv == div) { 283 found = 1; 284 goto out; 285 } 286out: 287 if (!found) 288 return -EINVAL; 289 290 err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv); 291 if (err) 292 return err; 293 294 err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv); 295 if (err) 296 return err; 297 298 ep93xx_i2s_enable(info, substream->stream); 299 return 0; 300} 301 302static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, 303 unsigned int freq, int dir) 304{ 305 struct ep93xx_i2s_info *info = cpu_dai->private_data; 306 307 if (dir == SND_SOC_CLOCK_IN || clk_id != 0) 308 return -EINVAL; 309 310 return clk_set_rate(info->mclk, freq); 311} 312 313#ifdef CONFIG_PM 314static int ep93xx_i2s_suspend(struct snd_soc_dai *dai) 315{ 316 struct ep93xx_i2s_info *info = dai->private_data; 317 318 if (!dai->active) 319 return; 320 321 ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK); 322 ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE); 323} 324 325static int ep93xx_i2s_resume(struct snd_soc_dai *dai) 326{ 327 struct ep93xx_i2s_info *info = dai->private_data; 328 329 if (!dai->active) 330 return; 331 332 ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK); 333 ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE); 334} 335#else 336#define ep93xx_i2s_suspend NULL 337#define ep93xx_i2s_resume NULL 338#endif 339 340static struct snd_soc_dai_ops ep93xx_i2s_dai_ops = { 341 .startup = ep93xx_i2s_startup, 342 .shutdown = ep93xx_i2s_shutdown, 343 .hw_params = ep93xx_i2s_hw_params, 344 .set_sysclk = ep93xx_i2s_set_sysclk, 345 .set_fmt = ep93xx_i2s_set_dai_fmt, 346}; 347 348#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 349 SNDRV_PCM_FMTBIT_S24_LE | \ 350 SNDRV_PCM_FMTBIT_S32_LE) 351 352struct snd_soc_dai ep93xx_i2s_dai = { 353 .name = "ep93xx-i2s", 354 .id = 0, 355 .symmetric_rates= 1, 356 .suspend = ep93xx_i2s_suspend, 357 .resume = ep93xx_i2s_resume, 358 .playback = { 359 .channels_min = 2, 360 .channels_max = 2, 361 .rates = SNDRV_PCM_RATE_8000_48000, 362 .formats = EP93XX_I2S_FORMATS, 363 }, 364 .capture = { 365 .channels_min = 2, 366 .channels_max = 2, 367 .rates = SNDRV_PCM_RATE_8000_48000, 368 .formats = EP93XX_I2S_FORMATS, 369 }, 370 .ops = &ep93xx_i2s_dai_ops, 371}; 372EXPORT_SYMBOL_GPL(ep93xx_i2s_dai); 373 374static int ep93xx_i2s_probe(struct platform_device *pdev) 375{ 376 struct ep93xx_i2s_info *info; 377 struct resource *res; 378 int err; 379 380 info = kzalloc(sizeof(struct ep93xx_i2s_info), GFP_KERNEL); 381 if (!info) { 382 err = -ENOMEM; 383 goto fail; 384 } 385 386 ep93xx_i2s_dai.dev = &pdev->dev; 387 ep93xx_i2s_dai.private_data = info; 388 info->dma_params = ep93xx_i2s_dma_params; 389 390 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 391 if (!res) { 392 err = -ENODEV; 393 goto fail; 394 } 395 396 info->mem = request_mem_region(res->start, resource_size(res), 397 pdev->name); 398 if (!info->mem) { 399 err = -EBUSY; 400 goto fail; 401 } 402 403 info->regs = ioremap(info->mem->start, resource_size(info->mem)); 404 if (!info->regs) { 405 err = -ENXIO; 406 goto fail_release_mem; 407 } 408 409 info->mclk = clk_get(&pdev->dev, "mclk"); 410 if (IS_ERR(info->mclk)) { 411 err = PTR_ERR(info->mclk); 412 goto fail_unmap_mem; 413 } 414 415 info->sclk = clk_get(&pdev->dev, "sclk"); 416 if (IS_ERR(info->sclk)) { 417 err = PTR_ERR(info->sclk); 418 goto fail_put_mclk; 419 } 420 421 info->lrclk = clk_get(&pdev->dev, "lrclk"); 422 if (IS_ERR(info->lrclk)) { 423 err = PTR_ERR(info->lrclk); 424 goto fail_put_sclk; 425 } 426 427 err = snd_soc_register_dai(&ep93xx_i2s_dai); 428 if (err) 429 goto fail_put_lrclk; 430 431 return 0; 432 433fail_put_lrclk: 434 clk_put(info->lrclk); 435fail_put_sclk: 436 clk_put(info->sclk); 437fail_put_mclk: 438 clk_put(info->mclk); 439fail_unmap_mem: 440 iounmap(info->regs); 441fail_release_mem: 442 release_mem_region(info->mem->start, resource_size(info->mem)); 443 kfree(info); 444fail: 445 return err; 446} 447 448static int __devexit ep93xx_i2s_remove(struct platform_device *pdev) 449{ 450 struct ep93xx_i2s_info *info = ep93xx_i2s_dai.private_data; 451 452 snd_soc_unregister_dai(&ep93xx_i2s_dai); 453 clk_put(info->lrclk); 454 clk_put(info->sclk); 455 clk_put(info->mclk); 456 iounmap(info->regs); 457 release_mem_region(info->mem->start, resource_size(info->mem)); 458 kfree(info); 459 return 0; 460} 461 462static struct platform_driver ep93xx_i2s_driver = { 463 .probe = ep93xx_i2s_probe, 464 .remove = __devexit_p(ep93xx_i2s_remove), 465 .driver = { 466 .name = "ep93xx-i2s", 467 .owner = THIS_MODULE, 468 }, 469}; 470 471static int __init ep93xx_i2s_init(void) 472{ 473 return platform_driver_register(&ep93xx_i2s_driver); 474} 475 476static void __exit ep93xx_i2s_exit(void) 477{ 478 platform_driver_unregister(&ep93xx_i2s_driver); 479} 480 481module_init(ep93xx_i2s_init); 482module_exit(ep93xx_i2s_exit); 483 484MODULE_ALIAS("platform:ep93xx-i2s"); 485MODULE_AUTHOR("Ryan Mallon <ryan@bluewatersys.com>"); 486MODULE_DESCRIPTION("EP93XX I2S driver"); 487MODULE_LICENSE("GPL"); 488