ep93xx-i2s.c 10.9 KB
Newer Older
R
Ryan Mallon 已提交
1 2 3 4
/*
 * linux/sound/soc/ep93xx-i2s.c
 * EP93xx I2S driver
 *
5
 * Copyright (C) 2010 Ryan Mallon
R
Ryan Mallon 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
 *
 * Based on the original driver by:
 *   Copyright (C) 2007 Chase Douglas <chasedouglas@gmail>
 *   Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
 *
 * 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/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/io.h>

#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc.h>

#include <mach/hardware.h>
#include <mach/ep93xx-regs.h>
31
#include <linux/platform_data/dma-ep93xx.h>
R
Ryan Mallon 已提交
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

#define EP93XX_I2S_TXCLKCFG		0x00
#define EP93XX_I2S_RXCLKCFG		0x04
#define EP93XX_I2S_GLCTRL		0x0C

#define EP93XX_I2S_TXLINCTRLDATA	0x28
#define EP93XX_I2S_TXCTRL		0x2C
#define EP93XX_I2S_TXWRDLEN		0x30
#define EP93XX_I2S_TX0EN		0x34

#define EP93XX_I2S_RXLINCTRLDATA	0x58
#define EP93XX_I2S_RXCTRL		0x5C
#define EP93XX_I2S_RXWRDLEN		0x60
#define EP93XX_I2S_RX0EN		0x64

#define EP93XX_I2S_WRDLEN_16		(0 << 0)
#define EP93XX_I2S_WRDLEN_24		(1 << 0)
#define EP93XX_I2S_WRDLEN_32		(2 << 0)

#define EP93XX_I2S_LINCTRLDATA_R_JUST	(1 << 2) /* Right justify */

#define EP93XX_I2S_CLKCFG_LRS		(1 << 0) /* lrclk polarity */
#define EP93XX_I2S_CLKCFG_CKP		(1 << 1) /* Bit clock polarity */
#define EP93XX_I2S_CLKCFG_REL		(1 << 2) /* First bit transition */
#define EP93XX_I2S_CLKCFG_MASTER	(1 << 3) /* Master mode */
#define EP93XX_I2S_CLKCFG_NBCG		(1 << 4) /* Not bit clock gating */

struct ep93xx_i2s_info {
	struct clk			*mclk;
	struct clk			*sclk;
	struct clk			*lrclk;
63
	struct ep93xx_dma_data		*dma_data;
R
Ryan Mallon 已提交
64 65 66
	void __iomem			*regs;
};

67
struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
R
Ryan Mallon 已提交
68 69
	[SNDRV_PCM_STREAM_PLAYBACK] = {
		.name		= "i2s-pcm-out",
70
		.dma_port	= EP93XX_DMA_I2S1,
71
		.direction	= DMA_MEM_TO_DEV,
R
Ryan Mallon 已提交
72 73 74
	},
	[SNDRV_PCM_STREAM_CAPTURE] = {
		.name		= "i2s-pcm-in",
75
		.dma_port	= EP93XX_DMA_I2S1,
76
		.direction	= DMA_DEV_TO_MEM,
R
Ryan Mallon 已提交
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 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
	},
};

static inline void ep93xx_i2s_write_reg(struct ep93xx_i2s_info *info,
					unsigned reg, unsigned val)
{
	__raw_writel(val, info->regs + reg);
}

static inline unsigned ep93xx_i2s_read_reg(struct ep93xx_i2s_info *info,
					   unsigned reg)
{
	return __raw_readl(info->regs + reg);
}

static void ep93xx_i2s_enable(struct ep93xx_i2s_info *info, int stream)
{
	unsigned base_reg;
	int i;

	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
		/* Enable clocks */
		clk_enable(info->mclk);
		clk_enable(info->sclk);
		clk_enable(info->lrclk);

		/* Enable i2s */
		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 1);
	}

	/* Enable fifos */
	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
		base_reg = EP93XX_I2S_TX0EN;
	else
		base_reg = EP93XX_I2S_RX0EN;
	for (i = 0; i < 3; i++)
		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 1);
}

static void ep93xx_i2s_disable(struct ep93xx_i2s_info *info, int stream)
{
	unsigned base_reg;
	int i;

	/* Disable fifos */
	if (stream == SNDRV_PCM_STREAM_PLAYBACK)
		base_reg = EP93XX_I2S_TX0EN;
	else
		base_reg = EP93XX_I2S_RX0EN;
	for (i = 0; i < 3; i++)
		ep93xx_i2s_write_reg(info, base_reg + (i * 4), 0);

	if ((ep93xx_i2s_read_reg(info, EP93XX_I2S_TX0EN) & 0x1) == 0 &&
	    (ep93xx_i2s_read_reg(info, EP93XX_I2S_RX0EN) & 0x1) == 0) {
		/* Disable i2s */
		ep93xx_i2s_write_reg(info, EP93XX_I2S_GLCTRL, 0);

		/* Disable clocks */
		clk_disable(info->lrclk);
		clk_disable(info->sclk);
		clk_disable(info->mclk);
	}
}

static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
			      struct snd_soc_dai *dai)
{
	struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 147
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
R
Ryan Mallon 已提交
148 149

	snd_soc_dai_set_dma_data(cpu_dai, substream,
150
				 &info->dma_data[substream->stream]);
R
Ryan Mallon 已提交
151 152 153 154 155 156
	return 0;
}

static void ep93xx_i2s_shutdown(struct snd_pcm_substream *substream,
				struct snd_soc_dai *dai)
{
157
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
R
Ryan Mallon 已提交
158 159 160 161 162 163 164

	ep93xx_i2s_disable(info, substream->stream);
}

static int ep93xx_i2s_set_dai_fmt(struct snd_soc_dai *cpu_dai,
				  unsigned int fmt)
{
165
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
R
Ryan Mallon 已提交
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
	unsigned int clk_cfg, lin_ctrl;

	clk_cfg  = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXCLKCFG);
	lin_ctrl = ep93xx_i2s_read_reg(info, EP93XX_I2S_RXLINCTRLDATA);

	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
	case SND_SOC_DAIFMT_I2S:
		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
		break;

	case SND_SOC_DAIFMT_LEFT_J:
		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
		lin_ctrl &= ~EP93XX_I2S_LINCTRLDATA_R_JUST;
		break;

	case SND_SOC_DAIFMT_RIGHT_J:
		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
		lin_ctrl |= EP93XX_I2S_LINCTRLDATA_R_JUST;
		break;

	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
	case SND_SOC_DAIFMT_CBS_CFS:
		/* CPU is master */
		clk_cfg |= EP93XX_I2S_CLKCFG_MASTER;
		break;

	case SND_SOC_DAIFMT_CBM_CFM:
		/* Codec is master */
		clk_cfg &= ~EP93XX_I2S_CLKCFG_MASTER;
		break;

	default:
		return -EINVAL;
	}

	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
	case SND_SOC_DAIFMT_NB_NF:
		/* Negative bit clock, lrclk low on left word */
		clk_cfg &= ~(EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL);
		break;

	case SND_SOC_DAIFMT_NB_IF:
		/* Negative bit clock, lrclk low on right word */
		clk_cfg &= ~EP93XX_I2S_CLKCFG_CKP;
		clk_cfg |= EP93XX_I2S_CLKCFG_REL;
		break;

	case SND_SOC_DAIFMT_IB_NF:
		/* Positive bit clock, lrclk low on left word */
		clk_cfg |= EP93XX_I2S_CLKCFG_CKP;
		clk_cfg &= ~EP93XX_I2S_CLKCFG_REL;
		break;

	case SND_SOC_DAIFMT_IB_IF:
		/* Positive bit clock, lrclk low on right word */
		clk_cfg |= EP93XX_I2S_CLKCFG_CKP | EP93XX_I2S_CLKCFG_REL;
		break;
	}

	/* Write new register values */
	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXCLKCFG, clk_cfg);
	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXCLKCFG, clk_cfg);
	ep93xx_i2s_write_reg(info, EP93XX_I2S_RXLINCTRLDATA, lin_ctrl);
	ep93xx_i2s_write_reg(info, EP93XX_I2S_TXLINCTRLDATA, lin_ctrl);
	return 0;
}

static int ep93xx_i2s_hw_params(struct snd_pcm_substream *substream,
				struct snd_pcm_hw_params *params,
				struct snd_soc_dai *dai)
{
242
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
R
Ryan Mallon 已提交
243
	unsigned word_len, div, sdiv, lrdiv;
244
	int err;
R
Ryan Mallon 已提交
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

	switch (params_format(params)) {
	case SNDRV_PCM_FORMAT_S16_LE:
		word_len = EP93XX_I2S_WRDLEN_16;
		break;

	case SNDRV_PCM_FORMAT_S24_LE:
		word_len = EP93XX_I2S_WRDLEN_24;
		break;

	case SNDRV_PCM_FORMAT_S32_LE:
		word_len = EP93XX_I2S_WRDLEN_32;
		break;

	default:
		return -EINVAL;
	}

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
		ep93xx_i2s_write_reg(info, EP93XX_I2S_TXWRDLEN, word_len);
	else
		ep93xx_i2s_write_reg(info, EP93XX_I2S_RXWRDLEN, word_len);

	/*
269 270 271 272 273 274
	 * EP93xx I2S module can be setup so SCLK / LRCLK value can be
	 * 32, 64, 128. MCLK / SCLK value can be 2 and 4.
	 * We set LRCLK equal to `rate' and minimum SCLK / LRCLK 
	 * value is 64, because our sample size is 32 bit * 2 channels.
	 * I2S standard permits us to transmit more bits than
	 * the codec uses.
R
Ryan Mallon 已提交
275
	 */
276
	div = clk_get_rate(info->mclk) / params_rate(params);
277 278 279 280 281 282 283 284
	sdiv = 4;
	if (div > (256 + 512) / 2) {
		lrdiv = 128;
	} else {
		lrdiv = 64;
		if (div < (128 + 256) / 2)
			sdiv = 2;
	}
R
Ryan Mallon 已提交
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300

	err = clk_set_rate(info->sclk, clk_get_rate(info->mclk) / sdiv);
	if (err)
		return err;

	err = clk_set_rate(info->lrclk, clk_get_rate(info->sclk) / lrdiv);
	if (err)
		return err;

	ep93xx_i2s_enable(info, substream->stream);
	return 0;
}

static int ep93xx_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id,
				 unsigned int freq, int dir)
{
301
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(cpu_dai);
R
Ryan Mallon 已提交
302 303 304 305 306 307 308 309 310 311

	if (dir == SND_SOC_CLOCK_IN || clk_id != 0)
		return -EINVAL;

	return clk_set_rate(info->mclk, freq);
}

#ifdef CONFIG_PM
static int ep93xx_i2s_suspend(struct snd_soc_dai *dai)
{
312
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
R
Ryan Mallon 已提交
313 314

	if (!dai->active)
315
		return 0;
R
Ryan Mallon 已提交
316 317 318

	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_PLAYBACK);
	ep93xx_i2s_disable(info, SNDRV_PCM_STREAM_CAPTURE);
319 320

	return 0;
R
Ryan Mallon 已提交
321 322 323 324
}

static int ep93xx_i2s_resume(struct snd_soc_dai *dai)
{
325
	struct ep93xx_i2s_info *info = snd_soc_dai_get_drvdata(dai);
R
Ryan Mallon 已提交
326 327

	if (!dai->active)
328
		return 0;
R
Ryan Mallon 已提交
329 330 331

	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_PLAYBACK);
	ep93xx_i2s_enable(info, SNDRV_PCM_STREAM_CAPTURE);
332 333

	return 0;
R
Ryan Mallon 已提交
334 335 336 337 338 339
}
#else
#define ep93xx_i2s_suspend	NULL
#define ep93xx_i2s_resume	NULL
#endif

340
static const struct snd_soc_dai_ops ep93xx_i2s_dai_ops = {
R
Ryan Mallon 已提交
341 342 343 344 345 346 347
	.startup	= ep93xx_i2s_startup,
	.shutdown	= ep93xx_i2s_shutdown,
	.hw_params	= ep93xx_i2s_hw_params,
	.set_sysclk	= ep93xx_i2s_set_sysclk,
	.set_fmt	= ep93xx_i2s_set_dai_fmt,
};

348
#define EP93XX_I2S_FORMATS (SNDRV_PCM_FMTBIT_S32_LE)
R
Ryan Mallon 已提交
349

350
static struct snd_soc_dai_driver ep93xx_i2s_dai = {
R
Ryan Mallon 已提交
351 352 353 354 355 356
	.symmetric_rates= 1,
	.suspend	= ep93xx_i2s_suspend,
	.resume		= ep93xx_i2s_resume,
	.playback	= {
		.channels_min	= 2,
		.channels_max	= 2,
357
		.rates		= SNDRV_PCM_RATE_8000_192000,
R
Ryan Mallon 已提交
358 359 360 361 362
		.formats	= EP93XX_I2S_FORMATS,
	},
	.capture	= {
		 .channels_min	= 2,
		 .channels_max	= 2,
363
		 .rates		= SNDRV_PCM_RATE_8000_192000,
R
Ryan Mallon 已提交
364 365 366 367 368 369 370 371 372 373 374
		 .formats	= EP93XX_I2S_FORMATS,
	},
	.ops		= &ep93xx_i2s_dai_ops,
};

static int ep93xx_i2s_probe(struct platform_device *pdev)
{
	struct ep93xx_i2s_info *info;
	struct resource *res;
	int err;

375 376 377
	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;
R
Ryan Mallon 已提交
378 379

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
380 381
	if (!res)
		return -ENODEV;
R
Ryan Mallon 已提交
382

383 384 385
	info->regs = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(info->regs))
		return PTR_ERR(info->regs);
R
Ryan Mallon 已提交
386 387 388 389

	info->mclk = clk_get(&pdev->dev, "mclk");
	if (IS_ERR(info->mclk)) {
		err = PTR_ERR(info->mclk);
390
		goto fail;
R
Ryan Mallon 已提交
391 392 393 394 395 396 397 398 399 400 401 402 403 404
	}

	info->sclk = clk_get(&pdev->dev, "sclk");
	if (IS_ERR(info->sclk)) {
		err = PTR_ERR(info->sclk);
		goto fail_put_mclk;
	}

	info->lrclk = clk_get(&pdev->dev, "lrclk");
	if (IS_ERR(info->lrclk)) {
		err = PTR_ERR(info->lrclk);
		goto fail_put_sclk;
	}

405
	dev_set_drvdata(&pdev->dev, info);
406
	info->dma_data = ep93xx_i2s_dma_data;
407

408
	err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
R
Ryan Mallon 已提交
409 410 411 412 413 414
	if (err)
		goto fail_put_lrclk;

	return 0;

fail_put_lrclk:
415
	dev_set_drvdata(&pdev->dev, NULL);
R
Ryan Mallon 已提交
416 417 418 419 420 421 422 423 424
	clk_put(info->lrclk);
fail_put_sclk:
	clk_put(info->sclk);
fail_put_mclk:
	clk_put(info->mclk);
fail:
	return err;
}

425
static int ep93xx_i2s_remove(struct platform_device *pdev)
R
Ryan Mallon 已提交
426
{
427
	struct ep93xx_i2s_info *info = dev_get_drvdata(&pdev->dev);
R
Ryan Mallon 已提交
428

429
	snd_soc_unregister_dai(&pdev->dev);
430
	dev_set_drvdata(&pdev->dev, NULL);
R
Ryan Mallon 已提交
431 432 433 434 435 436 437 438
	clk_put(info->lrclk);
	clk_put(info->sclk);
	clk_put(info->mclk);
	return 0;
}

static struct platform_driver ep93xx_i2s_driver = {
	.probe	= ep93xx_i2s_probe,
439
	.remove	= ep93xx_i2s_remove,
R
Ryan Mallon 已提交
440 441 442 443 444 445
	.driver	= {
		.name	= "ep93xx-i2s",
		.owner	= THIS_MODULE,
	},
};

446
module_platform_driver(ep93xx_i2s_driver);
R
Ryan Mallon 已提交
447 448

MODULE_ALIAS("platform:ep93xx-i2s");
449
MODULE_AUTHOR("Ryan Mallon");
R
Ryan Mallon 已提交
450 451
MODULE_DESCRIPTION("EP93XX I2S driver");
MODULE_LICENSE("GPL");