1 From 89aa6dd15306a1ce11da0f2cb67bda74999e178e Mon Sep 17 00:00:00 2001
2 From: Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
3 Date: Tue, 24 Nov 2009 21:49:24 +0530
4 Subject: [PATCH] ARM: Kirkwood: Sound: Sound driver added
6 The driver is based on the Marvell kirkwood sound driver available in
9 Signed-off-by: Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
11 arch/arm/mach-kirkwood/common.c | 39 +
12 arch/arm/mach-kirkwood/common.h | 2 +
13 arch/arm/mach-kirkwood/include/mach/kirkwood.h | 3 +
14 arch/arm/mach-kirkwood/openrd_client-setup.c | 27 +
15 include/linux/mv88fx_audio.h | 111 ++
16 sound/soc/Kconfig | 1 +
17 sound/soc/Makefile | 1 +
18 sound/soc/kirkwood/Kconfig | 29 +
19 sound/soc/kirkwood/Makefile | 7 +
20 sound/soc/kirkwood/cs42l51.c | 304 +++++
21 sound/soc/kirkwood/cs42l51.h | 59 +
22 sound/soc/kirkwood/kirkwood_audio_hal.c | 821 +++++++++++++
23 sound/soc/kirkwood/kirkwood_audio_hal.h | 109 ++
24 sound/soc/kirkwood/kirkwood_audio_regs.h | 310 +++++
25 sound/soc/kirkwood/kirkwood_pcm.c | 1505 ++++++++++++++++++++++++
26 15 files changed, 3328 insertions(+), 0 deletions(-)
27 create mode 100644 include/linux/mv88fx_audio.h
28 create mode 100644 sound/soc/kirkwood/Kconfig
29 create mode 100644 sound/soc/kirkwood/Makefile
30 create mode 100644 sound/soc/kirkwood/cs42l51.c
31 create mode 100644 sound/soc/kirkwood/cs42l51.h
32 create mode 100644 sound/soc/kirkwood/kirkwood_audio_hal.c
33 create mode 100644 sound/soc/kirkwood/kirkwood_audio_hal.h
34 create mode 100644 sound/soc/kirkwood/kirkwood_audio_regs.h
35 create mode 100644 sound/soc/kirkwood/kirkwood_pcm.c
37 diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
38 index 0acb61f..4d66c06 100644
39 --- a/arch/arm/mach-kirkwood/common.c
40 +++ b/arch/arm/mach-kirkwood/common.c
42 #include <linux/mbus.h>
43 #include <linux/mv643xx_eth.h>
44 #include <linux/mv643xx_i2c.h>
45 +#include <linux/mv88fx_audio.h>
46 #include <linux/ata_platform.h>
47 #include <linux/mtd/nand.h>
48 #include <linux/spi/orion_spi.h>
49 @@ -969,3 +970,41 @@ static int __init kirkwood_clock_gate(void)
52 late_initcall(kirkwood_clock_gate);
54 +/*****************************************************************************
56 + ****************************************************************************/
58 +static struct resource kirkwood_audio_resources[] = {
60 + .start = AUDIO_PHYS_BASE,
61 + .end = AUDIO_PHYS_BASE + SZ_16K - 1,
62 + .flags = IORESOURCE_MEM,
65 + .start = IRQ_KIRKWOOD_I2S,
66 + .end = IRQ_KIRKWOOD_I2S,
67 + .flags = IORESOURCE_IRQ,
71 +static u64 kirkwood_audio_dmamask = 0xFFFFFFFFUL;
73 +static struct platform_device kirkwood_audio = {
74 + .name = MV88FX_AUDIO_NAME,
76 + .num_resources = ARRAY_SIZE(kirkwood_audio_resources),
77 + .resource = kirkwood_audio_resources,
79 + .dma_mask = &kirkwood_audio_dmamask,
80 + .coherent_dma_mask = 0xffffffff,
84 +void __init kirkwood_audio_init(struct mv88fx_snd_platform_data *audio_data)
86 + kirkwood_clk_ctrl |= CGC_AUDIO;
87 + kirkwood_audio.dev.platform_data = audio_data;
89 + platform_device_register(&kirkwood_audio);
91 diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
92 index d7de434..b79a25c 100644
93 --- a/arch/arm/mach-kirkwood/common.h
94 +++ b/arch/arm/mach-kirkwood/common.h
95 @@ -16,6 +16,7 @@ struct mv643xx_eth_platform_data;
96 struct mv_sata_platform_data;
97 struct mvsdio_platform_data;
99 +struct mv88fx_snd_platform_data;
102 * Basic Kirkwood init functions used early by machine-setup.
103 @@ -41,6 +42,7 @@ void kirkwood_i2c_init(void);
104 void kirkwood_uart0_init(void);
105 void kirkwood_uart1_init(void);
106 void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
107 +void kirkwood_audio_init(struct mv88fx_snd_platform_data *audio_data);
109 extern int kirkwood_tclk;
110 extern struct sys_timer kirkwood_timer;
111 diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
112 index 54c1327..90ced65 100644
113 --- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
114 +++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
117 #define SDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x90000)
119 +#define AUDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
120 +#define AUDIO_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
123 * Supported devices and revisions.
125 diff --git a/arch/arm/mach-kirkwood/openrd_client-setup.c b/arch/arm/mach-kirkwood/openrd_client-setup.c
126 index a55a1bc..72acc22 100644
127 --- a/arch/arm/mach-kirkwood/openrd_client-setup.c
128 +++ b/arch/arm/mach-kirkwood/openrd_client-setup.c
130 #include <linux/mtd/partitions.h>
131 #include <linux/ata_platform.h>
132 #include <linux/mv643xx_eth.h>
133 +#include <linux/mv88fx_audio.h>
134 #include <linux/gpio.h>
135 #include <asm/mach-types.h>
136 #include <asm/mach/arch.h>
137 #include <mach/kirkwood.h>
138 #include <plat/mvsdio.h>
139 +#include <linux/autoconf.h>
143 @@ -59,6 +61,21 @@ static unsigned int openrd_client_mpp_config[] __initdata = {
147 +static struct mv88fx_snd_platform_data openrd_client_audio_data = {
149 + .i2c_address = 0x4A,
150 +/* 0 - NA, 1 - mono, 2 - stereo */
151 +#ifdef CONFIG_SND_MV88FX_SOC_I2S
158 + .dram = &kirkwood_mbus_dram_info,
159 + .base_offset = AUDIO_PHYS_BASE - KIRKWOOD_REGS_PHYS_BASE,
162 static void __init openrd_client_init(void)
165 @@ -78,6 +95,16 @@ static void __init openrd_client_init(void)
167 kirkwood_sata_init(&openrd_client_sata_data);
168 kirkwood_sdio_init(&openrd_client_mvsdio_data);
170 + /* initialize i2c */
171 + kirkwood_i2c_init();
173 +#if defined(CONFIG_SND_MV88FX_SOC) || defined(CONFIG_SND_MV88FX_SOC_MODULE)
174 + /* If built as a part of kernel or as a module
175 + * initialize audio */
176 + openrd_client_audio_data.tclk = kirkwood_tclk,
177 + kirkwood_audio_init(&openrd_client_audio_data);
181 MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
182 diff --git a/include/linux/mv88fx_audio.h b/include/linux/mv88fx_audio.h
184 index 0000000..6d36a3f
186 +++ b/include/linux/mv88fx_audio.h
190 + * Marvell Orion Alsa Sound driver
192 + * Author: Maen Suleiman
193 + * Copyright (C) 2008 Marvell Ltd.
196 + * This program is free software; you can redistribute it and/or modify
197 + * it under the terms of the GNU General Public License version 2 as
198 + * published by the Free Software Foundation.
202 +#ifndef __LINUX_MV88FX_SND_H
203 +#define __LINUX_MV88FX_SND_H
205 +#include <linux/mbus.h>
207 +#define MV88FX_AUDIO_NAME "mv88fx_snd"
209 +#undef MV88FX_SND_DEBUG
210 +#ifdef MV88FX_SND_DEBUG
211 +#define mv88fx_snd_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
213 + #define mv88fx_snd_debug(a...)
216 +#define MV_AUDIO_MAX_ADDR_DECODE_WIN 2
217 +#define MV_AUDIO_RECORD_WIN_NUM 0
218 +#define MV_AUDIO_PLAYBACK_WIN_NUM 1
220 +#define MV_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3))
221 +#define MV_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3))
223 +struct mv88fx_snd_platform_data {
232 + struct mbus_dram_target_info *dram;
235 +struct mv88fx_snd_stream {
236 + struct snd_pcm_substream *substream;
237 + struct device *dev;
238 + int direction; /* playback or capture */
241 + unsigned int dig_mode; /* i2s,spdif,both */
244 + int stereo; /* mono, stereo */
245 + int mono_mode; /* both mono, left mono, right mono */
246 + #define MONO_BOTH 0
247 + #define MONO_LEFT 1
248 + #define MONO_RIGHT 2
250 + #define DCO_CLOCK 0
251 + #define SPCR_CLOCK 1
252 + #define EXTERN_CLOCK 2
254 + int stat_mem; /* Channel status source*/
256 + #define SAMPLE_32IN32 0
257 + #define SAMPLE_24IN32 1
258 + #define SAMPLE_20IN32 2
259 + #define SAMPLE_16IN32 3
260 + #define SAMPLE_16IN16 4
261 + unsigned int dma_addr;
262 + unsigned int dma_size;
263 + unsigned int period_size;
264 + unsigned int spdif_status[4]; /* SPDIF status */
265 + unsigned char *area; /* virtual pointer */
266 + dma_addr_t addr; /* physical address */
269 +struct mv88fx_snd_chip {
270 + struct mv88fx_snd_stream *stream[2]; /* run time values*/
271 + struct mv88fx_snd_stream *stream_defaults[2]; /* default values*/
272 + spinlock_t reg_lock; /* Register access spinlock */
273 + struct resource *res; /* resource for IRQ and base*/
274 + void __iomem *base; /* Audio base address of the host */
275 + unsigned int audio_offset; /* Offset to audio base register
276 + * from internal base register */
278 + int loopback; /* When Loopback is enabled, playback
279 + * data is looped back to be recorded */
280 + int ch_stat_valid; /* Playback SPDIF channel validity bit
281 + * value when REG selected */
282 + int burst; /* DMA Burst Size */
284 + #define SPDIF_MEM_STAT 0
285 + #define SPDIF_REG_STAT 1
286 + unsigned int dco_ctrl_offst;
287 + int pcm_mode; /* pcm, nonpcm*/
293 +#define MV88FX_SND_MIN_PERIODS 8
294 +#define MV88FX_SND_MAX_PERIODS 16
295 +#define MV88FX_SND_MIN_PERIOD_BYTES 0x4000
296 +#define MV88FX_SND_MAX_PERIOD_BYTES 0x4000
298 +#endif /* __LINUX_MV88FX_SND_H */
299 diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
300 index b1749bc..9fc88d8 100644
301 --- a/sound/soc/Kconfig
302 +++ b/sound/soc/Kconfig
303 @@ -36,6 +36,7 @@ source "sound/soc/s3c24xx/Kconfig"
304 source "sound/soc/s6000/Kconfig"
305 source "sound/soc/sh/Kconfig"
306 source "sound/soc/txx9/Kconfig"
307 +source "sound/soc/kirkwood/Kconfig"
310 source "sound/soc/codecs/Kconfig"
311 diff --git a/sound/soc/Makefile b/sound/soc/Makefile
312 index 0c5eac0..664850d 100644
313 --- a/sound/soc/Makefile
314 +++ b/sound/soc/Makefile
315 @@ -14,3 +14,4 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/
316 obj-$(CONFIG_SND_SOC) += s6000/
317 obj-$(CONFIG_SND_SOC) += sh/
318 obj-$(CONFIG_SND_SOC) += txx9/
319 +obj-$(CONFIG_SND_SOC) += kirkwood/
320 diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
322 index 0000000..d6a7e2f
324 +++ b/sound/soc/kirkwood/Kconfig
326 +config SND_MV88FX_SOC
327 + tristate "SoC Audio for the Marvell 88FX chip"
328 + depends on ARCH_KIRKWOOD
330 + Say Y or M if you want to add support for codecs attached to
331 + the MV88FX I2S or SPD interface. You will also need
332 + to select the audio interfaces to support below.
335 + prompt "Audio Interface"
336 + default SND_MV88FX_SOC_I2S
337 + depends on SND_MV88FX_SOC
339 +config SND_MV88FX_SOC_I2S
342 +config SND_MV88FX_SOC_SPDIF
349 + default SND_SOC_CS42L51
350 + depends on SND_MV88FX_SOC
352 +config SND_SOC_CS42L51
355 diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
357 index 0000000..57674ad
359 +++ b/sound/soc/kirkwood/Makefile
362 +snd-soc-kirkwood-objs := kirkwood_pcm.o kirkwood_audio_hal.o
363 +ifdef CONFIG_SND_SOC_CS42L51
364 +snd-soc-kirkwood-objs += cs42l51.o
367 +obj-$(CONFIG_SND_MV88FX_SOC) += snd-soc-kirkwood.o
368 diff --git a/sound/soc/kirkwood/cs42l51.c b/sound/soc/kirkwood/cs42l51.c
370 index 0000000..f5a22f9
372 +++ b/sound/soc/kirkwood/cs42l51.c
376 + * Marvell Orion Alsa Sound driver
378 + * Author: Maen Suleiman
379 + * Copyright (C) 2008 Marvell Ltd.
382 + * This program is free software; you can redistribute it and/or modify
383 + * it under the terms of the GNU General Public License version 2 as
384 + * published by the Free Software Foundation.
387 +#include <linux/ioport.h>
388 +#include <linux/platform_device.h>
389 +#include <linux/init.h>
390 +#include <linux/slab.h>
391 +#include <linux/version.h>
392 +#include <linux/i2c.h>
393 +#include <sound/core.h>
394 +#include <sound/initval.h>
395 +#include <sound/control.h>
396 +#include <sound/pcm.h>
397 +#include <sound/asoundef.h>
398 +#include <sound/asound.h>
400 +#include "cs42l51.h"
402 +/* FIXME: This code is not written in driver module style. This is written as
403 + * helper for SOC driver */
405 +struct i2c_client *client;
407 +static int cs42l51_add_i2c_device(unsigned char i2c_bus_no,
408 + unsigned short i2c_add)
410 + struct i2c_board_info info;
411 + struct i2c_adapter *adapter;
413 + memset(&info, 0, sizeof(struct i2c_board_info));
414 + info.addr = i2c_add;
415 + strlcpy(info.type, "cs42l51", I2C_NAME_SIZE);
417 + adapter = i2c_get_adapter(i2c_bus_no);
419 + snd_printk("can't get i2c adapter\n");
423 + client = i2c_new_device(adapter, &info);
424 + i2c_put_adapter(adapter);
426 + snd_printk("can't add i2c device\n");
433 +void cs42l51_del_i2c_device(void)
436 + i2c_unregister_device(client);
441 + * offset: Register offset to start reading with
442 + * buf : Pointer to the buffer to store the read data
443 + * num : Number of registers to read
445 + * Returns -ve errorno else number of registers read
448 +int cs42l51_reg_read(unsigned char offset, unsigned char *buf, int num)
452 + /* Set autoincrement bit */
453 + offset |= CODEC_INCR_ADDR;
455 + /* Send register offset */
456 + ret = i2c_master_send(client, &offset, 1);
458 + snd_printd("Could not write register offset\n");
462 + return i2c_master_recv(client, buf, num);
466 + * offset: Register offset to write
467 + * data : Data to be written
469 + * Returns -ve errorno else number of registers written (=1)
472 +int cs42l51_reg_write(unsigned char offset, unsigned char data)
475 + unsigned char buf[2];
480 + /* Send register offset & data */
481 + ret = i2c_master_send(client, &buf[0], 2);
483 + return (ret == 2) ? 1 : ret;
486 +int codec_init(int adc_mode, int digital_if_format,
487 + unsigned char i2c_bus_no, unsigned short i2c_add)
489 + unsigned char reg_data;
491 + if (cs42l51_add_i2c_device(i2c_bus_no, i2c_add))
494 + if (cs42l51_reg_read(CODEC_ID_REG, ®_data, 1) < 0)
495 + goto codec_init_error;
497 + if (CODEC_CHIP_ID != (reg_data >> 3) ||
498 + CODEC_REV_ID != (reg_data & 0x7)) {
499 + snd_printd("Error: Invalid Cirrus Logic chip/rev ID!\n");
503 + if (cs42l51_reg_read(CODEC_IF_CTRL_REG, ®_data, 1) < 0)
504 + goto codec_init_error;
506 + reg_data = (reg_data & ~(0x7<<3)) | (digital_if_format << 3);
508 + if (LEFT_JUSTIFIED_MODE == adc_mode)
509 + reg_data &= (~0x4);
513 + if (cs42l51_reg_write(CODEC_IF_CTRL_REG, reg_data) < 0)
514 + goto codec_init_error;
519 + snd_printd("I2C error\n");
524 + * Initialize the audio decoder.
527 +int cs42l51_init(int adc_mode, int digital_if_format, int rec,
528 + unsigned char i2c_bus_no, unsigned short i2c_add)
530 + if (codec_init(adc_mode, digital_if_format, i2c_bus_no, i2c_add)) {
531 + snd_printk("Error: Audio Codec init failed\n");
535 + /* Use the signal processor */
536 + if (cs42l51_reg_write(0x9, 0x40) < 0)
539 + /* Unmute PCM-A & PCM-B and set default */
540 + if (cs42l51_reg_write(0x10, 0x60) < 0)
542 + if (cs42l51_reg_write(0x11, 0x60) < 0)
545 + /* default for AOUTx */
546 + if (cs42l51_reg_write(0x16, 0x05) < 0)
548 + if (cs42l51_reg_write(0x17, 0x05) < 0)
551 + /* swap channels */
552 + if (cs42l51_reg_write(0x18, 0xff) < 0)
555 + /* MIC Power Control: power down mIC in channel B, power on channel A
556 + * Recommended seq. in datasheet:
557 + * 1. Enable the PDN bit
558 + * 2. Enable power-down for the selected channels
559 + * 3. Disable the PDN bit */
561 + /* Note: Tested for mono recording only */
563 + /* Enable power down */
564 + if (cs42l51_reg_write(0x2, 0x11) < 0)
567 + /* No record - Power down both channels */
568 + if (cs42l51_reg_write(0x2, 0x17) < 0)
571 + /* Disable power down */
572 + if (cs42l51_reg_write(0x2, 0x16) < 0)
576 + /* Setreo recording - by default both channels are up */
578 + /* MIC In channel selection - Select channel 3
579 + * unmute both channels */
580 + if (cs42l51_reg_write(0x7, 0xF0) < 0)
583 + /* Power up mic pre-amplifier for both channels */
584 + if (cs42l51_reg_write(0x3, 0xA0) < 0)
587 + /* Enable power down */
588 + if (cs42l51_reg_write(0x2, 0x11) < 0)
591 + /* Mono recording - Power down Channel B */
592 + if (cs42l51_reg_write(0x2, 0x15) < 0)
595 + /* Disable power down */
596 + if (cs42l51_reg_write(0x2, 0x14) < 0)
599 + /* MIC In channel selection - Select channel 3
600 + * Mute Channel B */
601 + if (cs42l51_reg_write(0x7, 0xF2) < 0)
604 + /* Power down mic pre-amplifier for Channel B*/
605 + if (cs42l51_reg_write(0x3, 0xA8) < 0)
612 + snd_printk("I2C error\n");
616 +#define AUD_NUM_VOLUME_STEPS (40)
617 +static unsigned char auddec_volume_mapping[AUD_NUM_VOLUME_STEPS] =
619 + 0x19, 0xB2, 0xB7, 0xBD, 0xC3, 0xC9, 0xCF, 0xD5,
620 + 0xD8, 0xE1, 0xE7, 0xED, 0xF3, 0xF9, 0xFF, 0x00,
621 + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
622 + 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
623 + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
628 + * Get the audio decoder volume for both channels.
629 + * 0 is lowest volume, AUD_NUM_VOLUME_STEPS-1 is the highest volume.
632 +void cs42l51_vol_get(unsigned char *vol_list)
634 + unsigned char reg_data[2];
635 + unsigned char i, vol_idx = 0;
637 + if (cs42l51_reg_read(0x16 + vol_idx, reg_data, 2) < 0) {
638 + snd_printd("I2C error\n");
639 + snd_printk("Couldn't get volume\n");
643 + for (; vol_idx < 2; vol_idx++) {
644 + /* Look for the index that mapps to this dB value. */
645 + for (i = 0; i < AUD_NUM_VOLUME_STEPS; i++) {
646 + if (reg_data[vol_idx] == auddec_volume_mapping[i])
648 + if ((auddec_volume_mapping[i] >
649 + auddec_volume_mapping[AUD_NUM_VOLUME_STEPS-1])
650 + && (reg_data[vol_idx] > auddec_volume_mapping[i])
651 + && (reg_data[vol_idx] < auddec_volume_mapping[i+1]))
654 + vol_list[vol_idx] = i;
659 + * Set the audio decoder volume for both channels.
660 + * 0 is lowest volume, AUD_NUM_VOLUME_STEPS-1 is the highest volume.
662 +void cs42l51_vol_set(unsigned char *vol_list)
664 + unsigned int vol_idx;
666 + for (vol_idx = 0; vol_idx < 2; vol_idx++) {
667 + if (vol_list[vol_idx] >= AUD_NUM_VOLUME_STEPS)
668 + vol_list[vol_idx] = AUD_NUM_VOLUME_STEPS - 1;
670 + if (cs42l51_reg_write(0x16 + vol_idx,
671 + auddec_volume_mapping[vol_list[vol_idx]]) < 0) {
672 + snd_printd("I2C error\n");
673 + snd_printk("Couldn't set volume\n");
678 diff --git a/sound/soc/kirkwood/cs42l51.h b/sound/soc/kirkwood/cs42l51.h
680 index 0000000..f4e7951
682 +++ b/sound/soc/kirkwood/cs42l51.h
685 + * Audio codec CS42L51 data definition file
691 +#define CODEC_CHIP_ID 0x1B
692 +#define CODEC_REV_ID 0x1
694 +#define CODEC_ID_REG 0x1
695 +#define CODEC_IF_CTRL_REG 0x4
696 +#define CODEC_ADC_INPUT_INV_MUTE_REG 0x7
697 +#define CODEC_DAC_OUTPUT_CTRL_REG 0x8
698 +#define CODEC_DAC_CTRL_REG 0x9
699 +#define CODEC_PGAA_VOL_CTRL_REG 0xa
700 +#define CODEC_TONE_CTRL_REG 0x15
701 +#define CODEC_VOL_OUTA_CTRL_REG 0x16
703 +/* Set bit # 7 to 1 to get into auto incremental addressing mode */
704 +#define CODEC_INCR_ADDR 0x80
709 +/* Selects the digital interface format used for the data in on SDIN. */
710 +enum dac_digital_if_format {
711 + L_JUSTIFIED_UP_TO_24_BIT,
713 + R_JUSTIFIED_UP_TO_24_BIT,
714 + R_JUSTIFIED_20_BIT,
715 + R_JUSTIFIED_18_BIT,
720 +/* Selects either the I2S or Left-Justified digital interface format for the
723 + LEFT_JUSTIFIED_MODE,
727 +/* Initialize the Cirrus Logic device */
728 +int cs42l51_init(int adc_mode, int digital_if_format, int rec,
729 + unsigned char i2c_bus_no, unsigned short i2c_add);
731 +/* Function to control output volume (playback) */
732 +void cs42l51_vol_get(unsigned char *vol_list);
733 +void cs42l51_vol_set(unsigned char *vol_list);
735 +/* Function to access the Cirrus Logic CODEC registers */
736 +int cs42l51_reg_read(unsigned char offset, unsigned char *buf, int num);
737 +int cs42l51_reg_write(unsigned char offset, unsigned char data);
740 +void cs42l51_del_i2c_device(void);
741 +#endif /* _CS42L51_H_ */
743 diff --git a/sound/soc/kirkwood/kirkwood_audio_hal.c b/sound/soc/kirkwood/kirkwood_audio_hal.c
745 index 0000000..28305e3
747 +++ b/sound/soc/kirkwood/kirkwood_audio_hal.c
750 + * Sound driver for Marvell Kirkwood family SOCs
752 + * This program is free software; you can redistribute it and/or
753 + * modify it under the terms of the GNU General Public License
754 + * as published by the Free Software Foundation; either version 2
755 + * of the License, or (at your option) any later version.
757 + * This program is distributed in the hope that it will be useful,
758 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
759 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
760 + * GNU General Public License for more details.
762 + * You should have received a copy of the GNU General Public License
763 + * along with this program; if not, write to the Free Software
764 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
767 +#include <linux/io.h>
768 +#include <sound/core.h>
769 +#include <sound/pcm.h>
770 +#include <linux/spinlock.h>
771 +#include <linux/mv88fx_audio.h>
772 +#include "kirkwood_audio_hal.h"
774 +static void mv_audio_init(void __iomem *base);
775 +static void audio_setup_wins(void __iomem *base,
776 + struct mbus_dram_target_info *dram);
777 +static int set_window_as_per_baseadd(void __iomem *base, unsigned int baseadd,
778 + unsigned int audio_offset, int win_num);
780 +/* Clocks Control and Status related*/
781 +static int mv_audio_dco_ctrl_set(struct mv_audio_freq_data *dcoCtrl,
782 + void __iomem *base);
784 +/* Audio PlayBack related*/
785 +static int mv_audio_playback_control_set(void __iomem *base, unsigned int
786 + audio_offset, struct mv_audio_playback_ctrl *ctrl);
788 +/* Audio SPDIF PlayBack related*/
789 +static void mv_spdif_playback_ctrl_set(void __iomem *base,
790 + struct mv_spdif_playback_ctrl *ctrl);
792 +/* Audio I2S PlayBack related*/
793 +static int mv_i2s_playback_ctrl_set(void __iomem *base,
794 + struct mv_i2s_playback_ctrl *ctrl);
796 +/* Audio Recording*/
797 +static int mv_audio_record_control_set(struct mv_audio_record_ctrl *ctrl,
798 + unsigned int audio_offset, void __iomem *base);
800 +/* SPDIF Recording Related*/
801 +static int spdif_record_tclock_set(void __iomem *base, unsigned int tclk);
803 +/* I2S Recording Related*/
804 +static int mv_i2s_record_cntrl_set(struct mv_i2s_record_ctrl *ctrl,
805 + void __iomem *base);
807 +static inline int audio_burst_bytes_num_get(int burst)
810 + case AUDIO_32BYTE_BURST:
812 + case AUDIO_128BYTE_BURST:
819 +int mv88fx_snd_hw_init(struct snd_card *card)
821 + void __iomem *base = chip->base;
822 + struct mv88fx_snd_platform_data *platform_data =
823 + card->dev->platform_data;
825 + if (platform_data->i2s_rec || platform_data->i2s_play)
826 + if (codec_init(I2S_MODE, I2S_UP_TO_24_BIT,
827 + platform_data->i2s_rec, platform_data->i2c_bus_no,
828 + platform_data->i2c_address)) {
829 + snd_printk("Initializing CS42L51 failed\n");
833 + writel(0xffffffff, (base + MV_AUDIO_INT_CAUSE_REG));
834 + writel(0, (base + MV_AUDIO_INT_MASK_REG));
835 + writel(0, (base + MV_AUDIO_SPDIF_REC_INT_CAUSE_MASK_REG));
837 + mv_audio_init(base);
839 + audio_setup_wins(base, platform_data->dram);
841 + /* Disable all playback/recording */
842 + writel(readl(base + MV_AUDIO_PLAYBACK_CTRL_REG) &
843 + (~(APCR_PLAY_I2S_ENABLE_MASK | APCR_PLAY_SPDIF_ENABLE_MASK)),
844 + (base + MV_AUDIO_PLAYBACK_CTRL_REG));
846 + writel(readl(base + MV_AUDIO_RECORD_CTRL_REG) &
847 + (~(ARCR_RECORD_SPDIF_EN_MASK | ARCR_RECORD_I2S_EN_MASK)),
848 + (base + MV_AUDIO_RECORD_CTRL_REG));
850 + if (spdif_record_tclock_set(base, platform_data->tclk)) {
851 + snd_printk("Marvell ALSA driver ERR. SPDIF clock set failed\n");
858 +int mv88fx_snd_hw_playback_set(struct mv88fx_snd_chip *chip)
860 + struct mv88fx_snd_stream *audio_stream = chip->stream[PLAYBACK];
861 + struct snd_pcm_substream *substream = audio_stream->substream;
862 + struct snd_pcm_runtime *runtime = substream->runtime;
864 + struct mv_audio_playback_ctrl pcm_play_ctrl;
865 + struct mv_i2s_playback_ctrl i2s_play_ctrl;
866 + struct mv_spdif_playback_ctrl spdif_play_ctrl;
867 + struct mv_audio_freq_data dco_ctrl;
869 + dco_ctrl.offset = chip->dco_ctrl_offst;
871 + switch (audio_stream->rate) {
873 + dco_ctrl.baseFreq = AUDIO_FREQ_44_1KH;
876 + dco_ctrl.baseFreq = AUDIO_FREQ_48KH;
879 + dco_ctrl.baseFreq = AUDIO_FREQ_96KH;
882 + snd_printk("Requested rate %d is not supported\n",
883 + runtime->rate); return -1;
886 + pcm_play_ctrl.burst = (chip->burst == 128) ? AUDIO_128BYTE_BURST :
887 + AUDIO_32BYTE_BURST;
889 + pcm_play_ctrl.loopBack = chip->loopback;
891 + if (audio_stream->stereo) {
892 + pcm_play_ctrl.monoMode = AUDIO_PLAY_MONO_OFF;
894 + switch (audio_stream->mono_mode) {
896 + pcm_play_ctrl.monoMode = AUDIO_PLAY_LEFT_MONO;
899 + pcm_play_ctrl.monoMode = AUDIO_PLAY_RIGHT_MONO;
903 + pcm_play_ctrl.monoMode = AUDIO_PLAY_BOTH_MONO;
908 + if (audio_stream->format == SAMPLE_16IN16) {
909 + pcm_play_ctrl.sampleSize = SAMPLE_16BIT;
910 + i2s_play_ctrl.sampleSize = SAMPLE_16BIT;
911 + } else if (audio_stream->format == SAMPLE_24IN32) {
912 + pcm_play_ctrl.sampleSize = SAMPLE_24BIT;
913 + i2s_play_ctrl.sampleSize = SAMPLE_24BIT;
914 + } else if (audio_stream->format == SAMPLE_32IN32) {
915 + pcm_play_ctrl.sampleSize = SAMPLE_32BIT;
916 + i2s_play_ctrl.sampleSize = SAMPLE_32BIT;
918 + snd_printk("Requested format %d is not supported\n",
923 + /* buffer and period sizes in frame */
924 + pcm_play_ctrl.bufferPhyBase = audio_stream->dma_addr;
925 + pcm_play_ctrl.bufferSize = audio_stream->dma_size;
926 + pcm_play_ctrl.intByteCount = audio_stream->period_size;
928 + /* I2S playback streem stuff */
929 + /*i2s_play_ctrl.sampleSize = pcm_play_ctrl.sampleSize;*/
930 + i2s_play_ctrl.justification = I2S_JUSTIFIED;
931 + i2s_play_ctrl.sendLastFrame = 0;
933 + spdif_play_ctrl.nonPcm = FALSE;
935 + spdif_play_ctrl.validity = chip->ch_stat_valid;
937 + if (audio_stream->stat_mem) {
938 + spdif_play_ctrl.userBitsFromMemory = TRUE;
939 + spdif_play_ctrl.validityFromMemory = TRUE;
940 + spdif_play_ctrl.blockStartInternally = FALSE;
942 + spdif_play_ctrl.userBitsFromMemory = FALSE;
943 + spdif_play_ctrl.validityFromMemory = FALSE;
944 + spdif_play_ctrl.blockStartInternally = TRUE;
947 + /* If this is non-PCM sound, mute I2S channel */
948 + spin_lock_irq(&chip->reg_lock);
950 + if (!(readl(chip->base + MV_AUDIO_PLAYBACK_CTRL_REG) &
951 + (APCR_PLAY_I2S_ENABLE_MASK | APCR_PLAY_SPDIF_ENABLE_MASK))) {
953 + if (mv_audio_dco_ctrl_set(&dco_ctrl, chip->base)) {
954 + snd_printk("Failed to initialize DCO clock control.\n");
959 + if (audio_stream->clock_src == DCO_CLOCK)
960 + while ((readl(chip->base + MV_AUDIO_SPCR_DCO_STATUS_REG) &
961 + ASDSR_DCO_LOCK_MASK) == 0)
963 + else if (audio_stream->clock_src == SPCR_CLOCK)
964 + while ((readl(chip->base + MV_AUDIO_SPCR_DCO_STATUS_REG) &
965 + ASDSR_SPCR_LOCK_MASK) == 0)
968 + if (mv_audio_playback_control_set(chip->base, chip->audio_offset,
970 + snd_printk("Failed to initialize PCM playback control.\n");
974 + if (mv_i2s_playback_ctrl_set(chip->base, &i2s_play_ctrl)) {
975 + snd_printk("Failed to initialize I2S playback control.\n");
979 + mv_spdif_playback_ctrl_set(chip->base, &spdif_play_ctrl);
981 + spin_unlock_irq(&chip->reg_lock);
985 + spin_unlock_irq(&chip->reg_lock);
989 +int mv88fx_snd_hw_capture_set(struct mv88fx_snd_chip *chip)
991 + struct mv88fx_snd_stream *audio_stream = chip->stream[CAPTURE];
992 + struct snd_pcm_substream *substream = audio_stream->substream;
993 + struct snd_pcm_runtime *runtime = substream->runtime;
995 + struct mv_audio_record_ctrl pcm_rec_ctrl;
996 + struct mv_i2s_record_ctrl i2s_rec_ctrl;
997 + struct mv_audio_freq_data dco_ctrl;
999 + dco_ctrl.offset = chip->dco_ctrl_offst;
1001 + switch (audio_stream->rate) {
1003 + dco_ctrl.baseFreq = AUDIO_FREQ_44_1KH;
1006 + dco_ctrl.baseFreq = AUDIO_FREQ_48KH;
1009 + dco_ctrl.baseFreq = AUDIO_FREQ_96KH;
1012 + snd_printk("Requested rate %d is not supported\n",
1013 + runtime->rate); return -1;
1016 + pcm_rec_ctrl.burst = (chip->burst == 128) ? AUDIO_128BYTE_BURST :
1017 + AUDIO_32BYTE_BURST;
1019 + if (audio_stream->format == SAMPLE_16IN16) {
1020 + pcm_rec_ctrl.sampleSize = SAMPLE_16BIT;
1021 + } else if (audio_stream->format == SAMPLE_24IN32) {
1022 + pcm_rec_ctrl.sampleSize = SAMPLE_24BIT;
1023 + } else if (audio_stream->format == SAMPLE_32IN32) {
1024 + pcm_rec_ctrl.sampleSize = SAMPLE_32BIT;
1026 + snd_printk("Requested format %d is not supported\n",
1031 + /* If request for tereo record comes on the boards that doesn't
1032 + * support stereo recording */
1033 + if ((!chip->stereo) && audio_stream->stereo) {
1034 + snd_printk("Stereo recording is not supported\n");
1038 + pcm_rec_ctrl.mono = (audio_stream->stereo) ? FALSE : TRUE;
1040 + if (pcm_rec_ctrl.mono) {
1041 + switch (audio_stream->mono_mode) {
1043 + pcm_rec_ctrl.monoChannel = AUDIO_REC_LEFT_MONO;
1047 + pcm_rec_ctrl.monoChannel = AUDIO_REC_RIGHT_MONO;
1052 + pcm_rec_ctrl.monoChannel = AUDIO_REC_LEFT_MONO;
1056 + pcm_rec_ctrl.bufferPhyBase = audio_stream->dma_addr;
1057 + pcm_rec_ctrl.bufferSize = audio_stream->dma_size;
1059 + pcm_rec_ctrl.intByteCount = audio_stream->period_size;
1061 + /* I2S record streem stuff */
1062 + i2s_rec_ctrl.sample = pcm_rec_ctrl.sampleSize;
1063 + i2s_rec_ctrl.justf = I2S_JUSTIFIED;
1065 + spin_lock_irq(&chip->reg_lock);
1067 + /* set clock only if record is not enabled*/
1068 + if (!(readl(chip->base + MV_AUDIO_RECORD_CTRL_REG) &
1069 + (ARCR_RECORD_SPDIF_EN_MASK | ARCR_RECORD_I2S_EN_MASK))) {
1071 + if (mv_audio_dco_ctrl_set(&dco_ctrl, chip->base)) {
1072 + snd_printk("Failed to initialize DCO clock control.\n");
1077 + if (mv_audio_record_control_set(&pcm_rec_ctrl, chip->audio_offset,
1079 + snd_printk("Failed to initialize PCM record control.\n");
1083 + if (mv_i2s_record_cntrl_set(&i2s_rec_ctrl, chip->base)) {
1084 + snd_printk("Failed to initialize I2S record control.\n");
1087 + spin_unlock_irq(&chip->reg_lock);
1092 +static void mv_audio_init(void __iomem *base)
1094 + int timeout = 10000000;
1095 + unsigned int reg_data;
1097 + reg_data = readl(base + 0x1200);
1098 + reg_data &= (~(0x333FF8));
1099 + reg_data |= 0x111D18;
1101 + writel(reg_data, base + 0x1200);
1105 + } while (timeout);
1107 + reg_data = readl(base + 0x1200);
1108 + reg_data &= (~(0x333FF8));
1109 + reg_data |= 0x111D18;
1111 + writel(reg_data, base + 0x1200);
1114 +static void audio_setup_wins(void __iomem *base,
1115 + struct mbus_dram_target_info *dram)
1119 + /* First disable and clear windows */
1120 + for (win_num = 0; win_num < MV_AUDIO_MAX_ADDR_DECODE_WIN; win_num++) {
1121 + writel(0, base + MV_AUDIO_WIN_CTRL_REG(win_num));
1122 + writel(0, base + MV_AUDIO_WIN_BASE_REG(win_num));
1125 + /* Setup windows for DDR */
1126 + for (win_num = 0; win_num < MV_AUDIO_MAX_ADDR_DECODE_WIN; win_num++) {
1127 + /* We will set the Window to DRAM_CS1 in default */
1128 + struct mbus_dram_window *cs = &dram->cs[1];
1130 + writel(cs->base & 0xffff0000,
1131 + base + MV_AUDIO_WIN_BASE_REG(win_num));
1132 + writel(((cs->size - 1) & 0xffff0000) |
1133 + (cs->mbus_attr << 8) |
1134 + (dram->mbus_dram_target_id << 4) | 1,
1135 + base + MV_AUDIO_WIN_CTRL_REG(win_num));
1139 +#define MV_BOARD_TCLK_133MHZ 133333333
1140 +#define MV_BOARD_TCLK_150MHZ 150000000
1141 +#define MV_BOARD_TCLK_166MHZ 166666667
1142 +#define MV_BOARD_TCLK_200MHZ 200000000
1144 +static int spdif_record_tclock_set(void __iomem *base, unsigned int tclk)
1146 + unsigned int reg_data;
1148 + reg_data = readl(base + MV_AUDIO_SPDIF_REC_GEN_REG);
1151 + case MV_BOARD_TCLK_133MHZ:
1152 + reg_data |= ASRGR_CORE_CLK_FREQ_133MHZ;
1154 + case MV_BOARD_TCLK_150MHZ:
1155 + reg_data |= ASRGR_CORE_CLK_FREQ_150MHZ;
1157 + case MV_BOARD_TCLK_166MHZ:
1158 + reg_data |= ASRGR_CORE_CLK_FREQ_166MHZ;
1160 + case MV_BOARD_TCLK_200MHZ:
1161 + reg_data |= ASRGR_CORE_CLK_FREQ_200MHZ;
1164 + snd_printk("Not supported core clock %d\n", tclk);
1168 + writel(reg_data, base + MV_AUDIO_SPDIF_REC_GEN_REG);
1173 +static int mv_audio_record_control_set(struct mv_audio_record_ctrl *ctrl,
1174 + unsigned int audio_offset, void __iomem *base)
1176 + unsigned int reg, buff_start, buff_end;
1177 + unsigned int win_base, win_size;
1179 + if (ctrl->monoChannel > AUDIO_REC_RIGHT_MONO) {
1180 + snd_printk("Error: Illegal monoChannel %x\n",
1181 + ctrl->monoChannel);
1186 + if ((ctrl->burst != AUDIO_32BYTE_BURST) &&
1187 + (ctrl->burst != AUDIO_128BYTE_BURST)) {
1188 + snd_printk("Error: Illegal burst %x\n",
1194 + if (ctrl->bufferPhyBase & (MV_AUDIO_BUFFER_MIN_ALIGN - 1)) {
1195 + snd_printk("Error bufferPhyBase is not aligned to 0x%x"\
1196 + " bytes\n", MV_AUDIO_BUFFER_MIN_ALIGN);
1201 + if ((ctrl->bufferSize <= audio_burst_bytes_num_get(ctrl->burst)) |
1202 + (ctrl->bufferSize & (audio_burst_bytes_num_get(ctrl->burst) - 1)) ||
1203 + (ctrl->bufferSize > AUDIO_REG_TO_SIZE(APBBCR_SIZE_MAX))) {
1204 + snd_printk("Error bufferSize smaller than or not multiple "\
1205 + "of 0x%x bytes or larger than 0x%x\n",
1206 + audio_burst_bytes_num_get(ctrl->burst),
1207 + AUDIO_REG_TO_SIZE(APBBCR_SIZE_MAX));
1212 + reg = readl(base + MV_AUDIO_RECORD_CTRL_REG);
1213 + reg &= ~(ARCR_RECORD_BURST_SIZE_MASK | ARCR_RECORDED_MONO_CHNL_MASK |
1214 + ARCR_RECORD_SAMPLE_SIZE_MASK);
1216 + switch (ctrl->sampleSize) {
1217 + case SAMPLE_16BIT:
1218 + case SAMPLE_16BIT_NON_COMPACT:
1219 + case SAMPLE_20BIT:
1220 + case SAMPLE_24BIT:
1221 + case SAMPLE_32BIT:
1222 + reg |= ctrl->sampleSize << ARCR_RECORD_SAMPLE_SIZE_OFFS;
1225 + snd_printk("Error: Illegal sampleSize %x\n",
1226 + ctrl->sampleSize);
1231 + reg |= ctrl->burst << ARCR_RECORD_BURST_SIZE_OFFS;
1232 + reg |= ctrl->monoChannel << ARCR_RECORDED_MONO_CHNL_OFFS;
1235 + reg |= ARCR_RECORD_MONO_MASK;
1237 + reg &= (~ARCR_RECORD_MONO_MASK);
1239 + writel(reg, base + MV_AUDIO_RECORD_CTRL_REG);
1241 + /* Get the details of the Record address window*/
1242 + win_base = readl(base + MV_AUDIO_WIN_BASE_REG(MV_AUDIO_RECORD_WIN_NUM));
1243 + win_size = readl(base + MV_AUDIO_WIN_CTRL_REG(MV_AUDIO_RECORD_WIN_NUM));
1245 + /* Window size bits are 31:16. Where size =
1246 + * (2 ^ no of ones) * 64 KB. e.g. 0x0FF says 16MB */
1247 + win_size = ((win_size >> 16) + 1) << 16;
1249 + buff_start = ctrl->bufferPhyBase;
1250 + buff_end = buff_start + ctrl->bufferSize - 1;
1252 + /* If buffer address is not within window boundries then try to set a
1253 + * new value to the Record window by geting the target of where the
1254 + * buffer exist, if the buffer is within the window of the new target
1255 + * then set the Record window to that target else return Fail
1258 + if (!(((buff_start >= win_base) &&
1259 + (buff_start <= (win_base + win_size - 1))) ||
1260 + ((buff_end >= win_base) &&
1261 + (buff_end <= (win_base + win_size - 1))))) {
1262 + snd_printd("Audio record buffer is not within window");
1264 + /* Set the window for the buffer that user require
1265 + for the palyback\recording window to the target window */
1266 + if (set_window_as_per_baseadd(base, ctrl->bufferPhyBase,
1267 + audio_offset, MV_AUDIO_RECORD_WIN_NUM)) {
1268 + snd_printk("Playback buffer (%#x) is not "
1269 + "within a valid target\n",
1270 + ctrl->bufferPhyBase);
1275 + /* Set the interrupt byte count */
1276 + reg = ctrl->intByteCount & ARBCI_BYTE_COUNT_MASK;
1277 + writel(reg, base + MV_AUDIO_RECORD_BYTE_CNTR_INT_REG);
1279 + writel(ctrl->bufferPhyBase, base + MV_AUDIO_RECORD_START_ADDR_REG);
1280 + writel(AUDIO_SIZE_TO_REG(ctrl->bufferSize),
1281 + base + MV_AUDIO_RECORD_BUFF_SIZE_REG);
1287 +static int mv_i2s_record_cntrl_set(struct mv_i2s_record_ctrl *ctrl,
1288 + void __iomem *base)
1292 + reg = readl(base + MV_AUDIO_I2S_REC_CTRL_REG);
1293 + reg &= ~(AIRCR_I2S_RECORD_JUSTF_MASK|AIRCR_I2S_SAMPLE_SIZE_MASK);
1295 + switch (ctrl->justf) {
1296 + case I2S_JUSTIFIED:
1297 + case LEFT_JUSTIFIED:
1298 + case RIGHT_JUSTIFIED:
1299 + case RISE_BIT_CLCK_JUSTIFIED:
1300 + reg |= ctrl->justf << AIRCR_I2S_RECORD_JUSTF_OFFS;
1306 + reg |= ctrl->sample << AIRCR_I2S_SAMPLE_SIZE_OFFS;
1308 + writel(reg, base + MV_AUDIO_I2S_REC_CTRL_REG);
1312 +/* We trust the value set in the window registers and don't check them.
1313 + * As there is some value already present in the register, we assume
1314 + * base and size are aligned */
1316 +static int set_window_as_per_baseadd(void __iomem *base, unsigned int baseadd,
1317 + unsigned int audio_offset, int win_num)
1320 + unsigned int win_base, win_size, size;
1321 + unsigned char dram_attr[4] = {0x0E, 0x0D, 0x0B, 0x07};
1323 + /* Base passed is Audio base address. Audio base address is
1324 + * Internal register base address + audio_offset */
1325 + void __iomem *internal_reg_base = base - audio_offset;
1327 + for (dram_cs = 0; dram_cs < 4; dram_cs++) {
1328 + win_base = readl(internal_reg_base + 0x1500 + (8 * dram_cs));
1329 + win_size = readl(internal_reg_base + 0x1504 + (8 * dram_cs));
1331 + /* skip if window is disabled */
1332 + if (!(win_size & 1))
1335 + /* Window size bits are 31:24. Where size =
1336 + * (2 ^ no of ones) * 16 MB. e.g. 0x0F says 256MB */
1337 + size = ((win_size >> 24) + 1) << 24;
1339 + if ((baseadd >= win_base) && (baseadd < (win_base + size))) {
1340 + snd_printd("DRAM window %d set for %s window",
1341 + dram_cs, win_num ? "plaback" : "record");
1343 + base + MV_AUDIO_WIN_BASE_REG(win_num));
1345 + /* DRAM window ctrl regs are bit different than Audio
1346 + * Set size, attribute and target ID */
1347 + win_size = ((size - 1) & 0xffff0000) | 1;
1348 + win_size |= (dram_attr[dram_cs] << 8); /* Atribute */
1349 + win_size &= (~(0xF << 4)); /* Target ID */
1352 + base + MV_AUDIO_WIN_CTRL_REG(win_num));
1353 + snd_printd("win_base 0x%08x\twin_size 0x%08x",
1354 + win_base, win_size);
1359 + for (win = 0; win < 8; win++) {
1360 + win_base = readl(internal_reg_base + 0x2004 + (0x10 * win));
1361 + win_size = readl(internal_reg_base + 0x2008 + (0x10 * win));
1363 + /* skip if window is disabled */
1364 + if (!(win_size & 1))
1367 + /* Window size bits are 31:16. Where size =
1368 + * (2 ^ no of ones) * 64 KB. e.g. 0x0FF says 16MB */
1369 + size = ((win_size >> 16) + 1) << 16;
1370 + if ((baseadd >= win_base) && (baseadd < (win_base + size))) {
1371 + snd_printd("CPU window %d set for %s window",
1372 + win_base, win_num ? "plaback" : "record");
1374 + base + MV_AUDIO_WIN_BASE_REG(win_num));
1376 + base + MV_AUDIO_WIN_CTRL_REG(win_num));
1384 +static int mv_audio_playback_control_set(void __iomem *base, unsigned int
1385 + audio_offset, struct mv_audio_playback_ctrl *ctrl)
1387 + unsigned int reg, buff_start, buff_end;
1388 + unsigned int win_base, win_size;
1390 + if (ctrl->monoMode >= AUDIO_PLAY_OTHER_MONO) {
1391 + snd_printk("Error: Illegal monoMode %x\n", ctrl->monoMode);
1395 + if ((ctrl->burst != AUDIO_32BYTE_BURST) &&
1396 + (ctrl->burst != AUDIO_128BYTE_BURST)) {
1397 + snd_printk("Error: Illegal burst %x\n", ctrl->burst);
1401 + if (ctrl->bufferPhyBase & (MV_AUDIO_BUFFER_MIN_ALIGN - 1)) {
1402 + snd_printk("Error, bufferPhyBase is not aligned to 0x%x "\
1403 + "bytes\n", MV_AUDIO_BUFFER_MIN_ALIGN);
1407 + if ((ctrl->bufferSize <= audio_burst_bytes_num_get(ctrl->burst)) ||
1408 + (ctrl->bufferSize & (audio_burst_bytes_num_get(ctrl->burst) - 1)) ||
1409 + (ctrl->bufferSize > AUDIO_REG_TO_SIZE(APBBCR_SIZE_MAX))) {
1410 + snd_printk("Error, bufferSize smaller than or not multiple "\
1411 + "of 0x%x bytes or larger than 0x%x",
1412 + audio_burst_bytes_num_get(ctrl->burst),
1413 + AUDIO_REG_TO_SIZE(APBBCR_SIZE_MAX));
1417 + reg = readl(base + MV_AUDIO_PLAYBACK_CTRL_REG);
1418 + reg &= ~(APCR_PLAY_BURST_SIZE_MASK | APCR_LOOPBACK_MASK |
1419 + APCR_PLAY_MONO_MASK | APCR_PLAY_SAMPLE_SIZE_MASK);
1420 + reg |= ctrl->burst << APCR_PLAY_BURST_SIZE_OFFS;
1421 + reg |= ctrl->loopBack << APCR_LOOPBACK_OFFS;
1422 + reg |= ctrl->monoMode << APCR_PLAY_MONO_OFFS;
1423 + reg |= ctrl->sampleSize << APCR_PLAY_SAMPLE_SIZE_OFFS;
1424 + writel(reg, base + MV_AUDIO_PLAYBACK_CTRL_REG);
1426 + /* Get the details of the Playback address window*/
1427 + win_base = readl(base +
1428 + MV_AUDIO_WIN_BASE_REG(MV_AUDIO_PLAYBACK_WIN_NUM));
1429 + win_size = readl(base +
1430 + MV_AUDIO_WIN_CTRL_REG(MV_AUDIO_PLAYBACK_WIN_NUM));
1432 + /* Window size bits are 31:16. Where size =
1433 + * (2 ^ no of ones) * 64 KB. e.g. 0x0FF says 16MB */
1434 + win_size = ((win_size >> 16) + 1) << 16;
1436 + buff_start = ctrl->bufferPhyBase;
1437 + buff_end = buff_start + ctrl->bufferSize - 1;
1439 + /* If Playback window is not enabled or buffer address is not within
1440 + * window boundries then try to set a new value to the Playback window*/
1442 + if (!(((buff_start >= win_base) &&
1443 + (buff_start <= (win_base + win_size - 1))) ||
1444 + ((buff_end >= win_base) &&
1445 + (buff_end <= (win_base + win_size - 1))))) {
1446 + snd_printd("Audio playback buffer is not within window\n");
1448 + /* Set the window for the buffer that user require
1449 + for the palyback\recording window to the target window */
1450 + if (set_window_as_per_baseadd(base, ctrl->bufferPhyBase,
1451 + audio_offset, MV_AUDIO_PLAYBACK_WIN_NUM)) {
1452 + snd_printk("Record buffer (%#x) is not "
1453 + "within a valid target\n",
1454 + ctrl->bufferPhyBase);
1459 + /* Set the interrupt byte count */
1460 + reg = ctrl->intByteCount & APBCI_BYTE_COUNT_MASK;
1461 + writel(reg, base + MV_AUDIO_PLAYBACK_BYTE_CNTR_INT_REG);
1463 + writel(ctrl->bufferPhyBase,
1464 + base + MV_AUDIO_PLAYBACK_BUFF_START_REG);
1465 + writel(AUDIO_SIZE_TO_REG(ctrl->bufferSize),
1466 + base + MV_AUDIO_PLAYBACK_BUFF_SIZE_REG);
1471 +static int mv_i2s_playback_ctrl_set(void __iomem *base,
1472 + struct mv_i2s_playback_ctrl *ctrl)
1474 + unsigned int reg_data;
1476 + reg_data = readl(base + MV_AUDIO_I2S_PLAY_CTRL_REG);
1477 + reg_data &= ~(AIPCR_I2S_PB_JUSTF_MASK | AIPCR_I2S_PB_SAMPLE_SIZE_MASK);
1479 + if (ctrl->sampleSize > SAMPLE_16BIT) {
1480 + snd_printk("Illigal sample size\n");
1484 + reg_data |= ctrl->sampleSize << AIPCR_I2S_PB_SAMPLE_SIZE_OFFS;
1486 + if (ctrl->sendLastFrame)
1487 + reg_data |= AIPCR_I2S_SEND_LAST_FRM_MASK;
1489 + reg_data &= ~AIPCR_I2S_SEND_LAST_FRM_MASK;
1491 + switch (ctrl->justification) {
1492 + case I2S_JUSTIFIED:
1493 + case LEFT_JUSTIFIED:
1494 + case RIGHT_JUSTIFIED:
1495 + reg_data |= ctrl->justification << AIPCR_I2S_PB_JUSTF_OFFS;
1498 + snd_printk("Illigal justification value\n");
1502 + writel(reg_data, base + MV_AUDIO_I2S_PLAY_CTRL_REG);
1507 +static void mv_spdif_playback_ctrl_set(void __iomem *base,
1508 + struct mv_spdif_playback_ctrl *ctrl)
1510 + unsigned int reg_data;
1512 + reg_data = readl(base + MV_AUDIO_SPDIF_PLAY_CTRL_REG);
1514 + if (ctrl->blockStartInternally)
1515 + reg_data |= ASPCR_SPDIF_BLOCK_START_MASK;
1517 + reg_data &= ~ASPCR_SPDIF_BLOCK_START_MASK;
1519 + if (ctrl->validityFromMemory)
1520 + reg_data |= ASPCR_SPDIF_PB_EN_MEM_VALIDITY_MASK;
1522 + reg_data &= ~ASPCR_SPDIF_PB_EN_MEM_VALIDITY_MASK;
1524 + if (ctrl->userBitsFromMemory)
1525 + reg_data |= ASPCR_SPDIF_PB_MEM_USR_EN_MASK;
1527 + reg_data &= ~ASPCR_SPDIF_PB_MEM_USR_EN_MASK;
1529 + if (ctrl->validity)
1530 + reg_data |= ASPCR_SPDIF_PB_REG_VALIDITY_MASK;
1532 + reg_data &= ~ASPCR_SPDIF_PB_REG_VALIDITY_MASK;
1535 + reg_data |= ASPCR_SPDIF_PB_NONPCM_MASK;
1537 + reg_data &= ~ASPCR_SPDIF_PB_NONPCM_MASK;
1539 + writel(reg_data, base + MV_AUDIO_SPDIF_PLAY_CTRL_REG);
1542 +static int mv_audio_dco_ctrl_set(struct mv_audio_freq_data *dcoCtrl,
1543 + void __iomem *base)
1547 + /* Check parameters*/
1548 + if (dcoCtrl->baseFreq > AUDIO_FREQ_96KH) {
1549 + snd_printk("dcoCtrl->baseFreq value (0x%x) invalid\n",
1550 + dcoCtrl->baseFreq);
1554 + if ((dcoCtrl->offset > 0xFD0) || (dcoCtrl->offset < 0x20)) {
1555 + snd_printk("dcoCtrl->offset value (0x%x) invalid\n",
1556 + dcoCtrl->baseFreq);
1560 + reg = readl(base + MV_AUDIO_DCO_CTRL_REG);
1562 + reg &= ~(ADCR_DCO_CTRL_FS_MASK | ADCR_DCO_CTRL_OFFSET_MASK);
1563 + reg |= ((dcoCtrl->baseFreq << ADCR_DCO_CTRL_FS_OFFS) |
1564 + (dcoCtrl->offset << ADCR_DCO_CTRL_OFFSET_OFFS));
1566 + writel(reg, base + MV_AUDIO_DCO_CTRL_REG);
1570 diff --git a/sound/soc/kirkwood/kirkwood_audio_hal.h b/sound/soc/kirkwood/kirkwood_audio_hal.h
1571 new file mode 100644
1572 index 0000000..ce08102
1574 +++ b/sound/soc/kirkwood/kirkwood_audio_hal.h
1577 + * Sound driver data definition file for Marvell Kirkwood family SOCs
1580 +#ifndef __AUDIO_HAL_H
1581 +#define __AUDIO_HAL_H
1583 +#include "kirkwood_audio_regs.h"
1585 +#ifdef CONFIG_SND_SOC_CS42L51
1586 +#include "cs42l51.h"
1588 +#define codec_init cs42l51_init
1589 +#define codec_vol_get cs42l51_vol_get
1590 +#define codec_vol_set cs42l51_vol_set
1591 +#define codec_del_i2c_device cs42l51_del_i2c_device
1594 +#define CODEC_I2C_BUS_NO 0
1595 +#define CODEC_I2C_ADD 0x4A
1597 +/*********************************/
1598 +/* General enums and structures */
1599 +/*******************************/
1600 +/* Type of Audio operations*/
1601 +enum mv_audio_operation {
1602 + AUDIO_PLAYBACK = 0,
1606 +struct mv_audio_freq_data{
1607 + int baseFreq; /* Control FS, selects the base frequency
1609 + u32 offset; /* Offset control in which each step equals to
1614 +/***********************************/
1615 +/* Play Back related structures */
1616 +/*********************************/
1618 +struct mv_audio_playback_ctrl {
1619 + int burst; /* Specifies the Burst Size of the DMA */
1620 + bool loopBack; /* When Loopback is enabled, playback data
1621 + * is looped back to be recorded */
1622 + int monoMode; /* Mono Mode is used */
1623 + unsigned int bufferPhyBase; /* Physical Address of DMA buffer */
1624 + unsigned int bufferSize; /* Size of DMA buffer */
1625 + unsigned int intByteCount; /* Number of bytes after which an
1626 + * interrupt will be issued.*/
1627 + int sampleSize; /* Playback Sample Size*/
1630 +struct mv_spdif_playback_ctrl {
1631 + bool nonPcm; /* PCM or non-PCM mode*/
1632 + bool validity; /* Validity bit value when using
1633 + * registers (userBitsFromMemory=0) */
1634 + bool underrunData; /* If true send last frame on mute/pause/
1635 + * underrun otherwise send 24 binary */
1636 + bool userBitsFromMemory; /* otherwise from intenal registers */
1637 + bool validityFromMemory; /* otherwise from internal registers */
1638 + bool blockStartInternally; /* When user and valid bits are form
1639 + * registers then this bit should be zero */
1642 +struct mv_i2s_playback_ctrl {
1644 + int justification;
1645 + bool sendLastFrame; /* If true send last frame on
1646 + * mute/pause/underrun
1647 + * otherwise send 64 binary*/
1651 +/*********************************/
1652 +/* Recording related structures */
1653 +/*********************************/
1655 +struct mv_audio_record_ctrl {
1656 + int burst; /* Recording DMA Burst Size */
1657 + int sampleSize; /*Recording Sample Size */
1658 + bool mono; /* If true then recording mono else
1659 + * recording stereo */
1660 + int monoChannel; /* Left or right moono */
1661 + u32 bufferPhyBase; /* Physical Address of DMA buffer */
1662 + u32 bufferSize; /* Size of DMA buffer */
1664 + u32 intByteCount; /* Number of bytes after which an
1665 + * interrupt will be issued.*/
1669 +struct mv_i2s_record_ctrl {
1670 + int sample; /* I2S Recording Sample Size*/
1674 +/******************/
1675 +/* Functions API */
1678 +extern struct mv88fx_snd_chip *chip;
1680 +int mv88fx_snd_hw_init(struct snd_card *card);
1681 +int mv88fx_snd_hw_capture_set(struct mv88fx_snd_chip *chip);
1682 +int mv88fx_snd_hw_playback_set(struct mv88fx_snd_chip *chip);
1685 diff --git a/sound/soc/kirkwood/kirkwood_audio_regs.h b/sound/soc/kirkwood/kirkwood_audio_regs.h
1686 new file mode 100644
1687 index 0000000..1d3df15
1689 +++ b/sound/soc/kirkwood/kirkwood_audio_regs.h
1692 + * Audio registers for Marvell Kirkwood family SOCs
1695 +#ifndef __KW_AUDIO_REGS_H
1696 +#define __KW_AUDIO_REGS_H
1698 +enum mv_audio_freq {
1699 + AUDIO_FREQ_44_1KH = 0, /* 11.2896Mhz */
1700 + AUDIO_FREQ_48KH = 1, /* 12.288Mhz */
1701 + AUDIO_FREQ_96KH = 2, /* 24.576Mhz */
1702 + AUDIO_FREQ_LOWER_44_1KH = 3 , /* Lower than 11.2896MHz */
1703 + AUDIO_FREQ_HIGHER_96KH = 4, /* Higher than 24.576MHz */
1704 + AUDIO_FREQ_OTHER = 7, /* Other frequency */
1707 +enum mv_audio_burst_size {
1708 + AUDIO_32BYTE_BURST = 1,
1709 + AUDIO_128BYTE_BURST = 2,
1712 +enum mv_audio_playback_mono {
1713 + AUDIO_PLAY_MONO_OFF = 0,
1714 + AUDIO_PLAY_LEFT_MONO = 1,
1715 + AUDIO_PLAY_RIGHT_MONO = 2,
1716 + AUDIO_PLAY_BOTH_MONO = 3,
1717 + AUDIO_PLAY_OTHER_MONO = 4
1720 +enum mv_audio_record_mono {
1721 + AUDIO_REC_LEFT_MONO = 0,
1722 + AUDIO_REC_RIGHT_MONO = 1,
1725 +enum mv_audio_sample_size {
1730 + SAMPLE_16BIT_NON_COMPACT = 7
1733 +enum mv_audio_i2s_justification {
1734 + LEFT_JUSTIFIED = 0,
1735 + I2S_JUSTIFIED = 5,
1736 + RISE_BIT_CLCK_JUSTIFIED = 7,
1737 + RIGHT_JUSTIFIED = 8,
1740 +#define APBBCR_SIZE_MAX 0x3FFFFF
1741 +#define APBBCR_SIZE_SHIFT 0x2
1743 +#define AUDIO_REG_TO_SIZE(reg) (((reg) + 1) << APBBCR_SIZE_SHIFT)
1744 +#define AUDIO_SIZE_TO_REG(size) (((size) >> APBBCR_SIZE_SHIFT) - 1)
1746 +#define MV_AUDIO_BUFFER_MIN_ALIGN 0x8
1748 +/********************/
1749 +/* Clocking Control*/
1750 +/*******************/
1752 +#define MV_AUDIO_DCO_CTRL_REG 0x1204
1753 +#define MV_AUDIO_SPCR_DCO_STATUS_REG 0x120c
1754 +#define MV_AUDIO_SAMPLE_CNTR_CTRL_REG 0x1220
1755 +#define MV_AUDIO_PLAYBACK_SAMPLE_CNTR_REG 0x1224
1756 +#define MV_AUDIO_RECORD_SAMPLE_CNTR_REG 0x1228
1757 +#define MV_AUDIO_CLOCK_CTRL_REG 0x1230
1759 +/* MV_AUDIO_DCO_CTRL_REG */
1760 +#define ADCR_DCO_CTRL_FS_OFFS 0
1761 +#define ADCR_DCO_CTRL_FS_MASK (0x3 << ADCR_DCO_CTRL_FS_OFFS)
1762 +#define ADCR_DCO_CTRL_FS_44_1KHZ (0x0 << ADCR_DCO_CTRL_FS_OFFS)
1763 +#define ADCR_DCO_CTRL_FS_48KHZ (0x1 << ADCR_DCO_CTRL_FS_OFFS)
1764 +#define ADCR_DCO_CTRL_FS_96KHZ (0x2 << ADCR_DCO_CTRL_FS_OFFS)
1767 +#define ADCR_DCO_CTRL_OFFSET_OFFS 2
1768 +#define ADCR_DCO_CTRL_OFFSET_MASK (0xfff << ADCR_DCO_CTRL_OFFSET_OFFS)
1770 +/* MV_AUDIO_SPCR_DCO_STATUS_REG */
1771 +#define ASDSR_SPCR_CTRLFS_OFFS 0
1772 +#define ASDSR_SPCR_CTRLFS_MASK (0x7 << ASDSR_SPCR_CTRLFS_OFFS)
1773 +#define ASDSR_SPCR_CTRLFS_44_1KHZ (0x0 << ASDSR_SPCR_CTRLFS_OFFS)
1774 +#define ASDSR_SPCR_CTRLFS_48KHZ (0x1 << ASDSR_SPCR_CTRLFS_OFFS)
1775 +#define ASDSR_SPCR_CTRLFS_96KHZ (0x2 << ASDSR_SPCR_CTRLFS_OFFS)
1776 +#define ASDSR_SPCR_CTRLFS_44_1KHZ_LESS (0x3 << ASDSR_SPCR_CTRLFS_OFFS)
1777 +#define ASDSR_SPCR_CTRLFS_96KHZ_MORE (0x4 << ASDSR_SPCR_CTRLFS_OFFS)
1778 +#define ASDSR_SPCR_CTRLFS_OTHER (0x7 << ASDSR_SPCR_CTRLFS_OFFS)
1781 +#define ASDSR_SPCR_CTRLOFFSET_OFFS 3
1782 +#define ASDSR_SPCR_CTRLOFFSET_MASK (0xfff << ASDSR_SPCR_CTRLOFFSET_OFFS)
1784 +#define ASDSR_SPCR_LOCK_OFFS 15
1785 +#define ASDSR_SPCR_LOCK_MASK (0x1 << ASDSR_SPCR_LOCK_OFFS)
1787 +#define ASDSR_DCO_LOCK_OFFS 16
1788 +#define ASDSR_DCO_LOCK_MASK (0x1 << ASDSR_DCO_LOCK_OFFS)
1790 +#define ASDSR_PLL_LOCK_OFFS 17
1791 +#define ASDSR_PLL_LOCK_MASK (0x1 << ASDSR_PLL_LOCK_OFFS)
1793 +/*MV_AUDIO_SAMPLE_CNTR_CTRL_REG */
1795 +#define ASCCR_CLR_PLAY_CNTR_OFFS 9
1796 +#define ASCCR_CLR_PLAY_CNTR_MASK (0x1 << ASCCR_CLR_PLAY_CNTR_OFFS)
1798 +#define ASCCR_CLR_REC_CNTR_OFFS 8
1799 +#define ASCCR_CLR_REC_CNTR_MASK (0x1 << ASCCR_CLR_REC_CNTR_OFFS)
1801 +#define ASCCR_ACTIVE_PLAY_CNTR_OFFS 1
1802 +#define ASCCR_ACTIVE_PLAY_CNTR_MASK (0x1 << ASCCR_ACTIVE_PLAY_CNTR_OFFS)
1804 +#define ASCCR_ACTIVE_REC_CNTR_OFFS 0
1805 +#define ASCCR_ACTIVE_REC_CNTR_MASK (0x1 << ASCCR_ACTIVE_REC_CNTR_OFFS)
1807 +/* MV_AUDIO_CLOCK_CTRL_REG */
1808 +#define ACCR_MCLK_SOURCE_OFFS 0
1809 +#define ACCR_MCLK_SOURCE_MASK (0x3 << ACCR_MCLK_SOURCE_OFFS)
1810 +#define ACCR_MCLK_SOURCE_DCO (0x0 << ACCR_MCLK_SOURCE_OFFS)
1811 +#define ACCR_MCLK_SOURCE_SPCR (0x2 << ACCR_MCLK_SOURCE_OFFS)
1812 +#define ACCR_MCLK_SOURCE_EXT (0x3 << ACCR_MCLK_SOURCE_OFFS)
1815 +/*********************/
1817 +/*******************/
1818 +#define MV_AUDIO_ERROR_CAUSE_REG 0x1300
1819 +#define MV_AUDIO_ERROR_MASK_REG 0x1304
1820 +#define MV_AUDIO_INT_CAUSE_REG 0x1308
1821 +#define MV_AUDIO_INT_MASK_REG 0x130C
1822 +#define MV_AUDIO_RECORD_BYTE_CNTR_INT_REG 0x1310
1823 +#define MV_AUDIO_PLAYBACK_BYTE_CNTR_INT_REG 0x1314
1825 +/* MV_AUDIO_INT_CAUSE_REG*/
1826 +#define AICR_RECORD_BYTES_INT (0x1 << 13)
1827 +#define AICR_PLAY_BYTES_INT (0x1 << 14)
1829 +#define ARBCI_BYTE_COUNT_MASK 0xFFFFFF
1830 +#define APBCI_BYTE_COUNT_MASK 0xFFFFFF
1832 +/*********************/
1833 +/* Audio Playback */
1834 +/*******************/
1836 +#define MV_AUDIO_PLAYBACK_CTRL_REG 0x1100
1837 +#define MV_AUDIO_PLAYBACK_BUFF_START_REG 0x1104
1838 +#define MV_AUDIO_PLAYBACK_BUFF_SIZE_REG 0x1108
1839 +#define MV_AUDIO_PLAYBACK_BUFF_BYTE_CNTR_REG 0x110c
1842 +#define MV_AUDIO_SPDIF_PLAY_CTRL_REG 0x2204
1843 +#define MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(ind) \
1844 + (0x2280 + (ind << 2))
1845 +#define MV_AUDIO_SPDIF_PLAY_CH_STATUS_RIGHT_REG(ind) \
1846 + (0x22a0 + (ind << 2))
1847 +#define MV_AUDIO_SPDIF_PLAY_USR_BITS_LEFT_REG(ind) \
1848 + (0x22c0 + (ind << 2))
1849 +#define MV_AUDIO_SPDIF_PLAY_USR_BITS_RIGHT_REG(ind) \
1850 + (0x22e0 + (ind << 2))
1853 +#define MV_AUDIO_I2S_PLAY_CTRL_REG 0x2508
1856 +/* MV_AUDIO_PLAYBACK_CTRL_REG */
1857 +#define APCR_PLAY_SAMPLE_SIZE_OFFS 0
1858 +#define APCR_PLAY_SAMPLE_SIZE_MASK (0x7 << APCR_PLAY_SAMPLE_SIZE_OFFS)
1860 +#define APCR_PLAY_I2S_ENABLE_OFFS 3
1861 +#define APCR_PLAY_I2S_ENABLE_MASK (0x1 << APCR_PLAY_I2S_ENABLE_OFFS)
1863 +#define APCR_PLAY_SPDIF_ENABLE_OFFS 4
1864 +#define APCR_PLAY_SPDIF_ENABLE_MASK (0x1 << APCR_PLAY_SPDIF_ENABLE_OFFS)
1866 +#define APCR_PLAY_MONO_OFFS 5
1867 +#define APCR_PLAY_MONO_MASK (0x3 << APCR_PLAY_MONO_OFFS)
1869 +#define APCR_PLAY_I2S_MUTE_OFFS 7
1870 +#define APCR_PLAY_I2S_MUTE_MASK (0x1 << APCR_PLAY_I2S_MUTE_OFFS)
1872 +#define APCR_PLAY_SPDIF_MUTE_OFFS 8
1873 +#define APCR_PLAY_SPDIF_MUTE_MASK (0x1 << APCR_PLAY_SPDIF_MUTE_OFFS)
1875 +#define APCR_PLAY_PAUSE_OFFS 9
1876 +#define APCR_PLAY_PAUSE_MASK (0x1 << APCR_PLAY_PAUSE_OFFS)
1878 +#define APCR_LOOPBACK_OFFS 10
1879 +#define APCR_LOOPBACK_MASK (0x1 << APCR_LOOPBACK_OFFS)
1881 +#define APCR_PLAY_BURST_SIZE_OFFS 11
1882 +#define APCR_PLAY_BURST_SIZE_MASK (0x3 << APCR_PLAY_BURST_SIZE_OFFS)
1884 +#define APCR_PLAY_BUSY_OFFS 16
1885 +#define APCR_PLAY_BUSY_MASK (0x1 << APCR_PLAY_BUSY_OFFS)
1887 +/* MV_AUDIO_PLAYBACK_BUFF_BYTE_CNTR_REG */
1888 +#define APBBCR_SIZE_MAX 0x3FFFFF
1889 +#define APBBCR_SIZE_SHIFT 0x2
1892 +/* MV_AUDIO_SPDIF_PLAY_CTRL_REG */
1893 +#define ASPCR_SPDIF_BLOCK_START_OFFS 0x0
1894 +#define ASPCR_SPDIF_BLOCK_START_MASK (0x1 << ASPCR_SPDIF_BLOCK_START_OFFS)
1896 +#define ASPCR_SPDIF_PB_EN_MEM_VALIDITY_OFFS 0x1
1897 +#define ASPCR_SPDIF_PB_EN_MEM_VALIDITY_MASK (0x1 << \
1898 + ASPCR_SPDIF_PB_EN_MEM_VALIDITY_OFFS)
1900 +#define ASPCR_SPDIF_PB_MEM_USR_EN_OFFS 0x2
1901 +#define ASPCR_SPDIF_PB_MEM_USR_EN_MASK (0x1 << ASPCR_SPDIF_PB_MEM_USR_EN_OFFS)
1903 +#define ASPCR_SPDIF_UNDERRUN_DATA_OFFS 0x5
1904 +#define ASPCR_SPDIF_UNDERRUN_DATA_MASK (0x1 << ASPCR_SPDIF_UNDERRUN_DATA_OFFS)
1906 +#define ASPCR_SPDIF_PB_REG_VALIDITY_OFFS 16
1907 +#define ASPCR_SPDIF_PB_REG_VALIDITY_MASK (0x1 << \
1908 + ASPCR_SPDIF_PB_REG_VALIDITY_OFFS)
1910 +#define ASPCR_SPDIF_PB_NONPCM_OFFS 17
1911 +#define ASPCR_SPDIF_PB_NONPCM_MASK (0x1 << ASPCR_SPDIF_PB_NONPCM_OFFS)
1914 +/* MV_AUDIO_I2S_PLAY_CTRL_REG */
1915 +#define AIPCR_I2S_SEND_LAST_FRM_OFFS 23
1916 +#define AIPCR_I2S_SEND_LAST_FRM_MASK (1 << AIPCR_I2S_SEND_LAST_FRM_OFFS)
1918 +#define AIPCR_I2S_PB_JUSTF_OFFS 26
1919 +#define AIPCR_I2S_PB_JUSTF_MASK (0xf << AIPCR_I2S_PB_JUSTF_OFFS)
1921 +#define AIPCR_I2S_PB_SAMPLE_SIZE_OFFS 30
1922 +#define AIPCR_I2S_PB_SAMPLE_SIZE_MASK (0x3 << AIPCR_I2S_PB_SAMPLE_SIZE_OFFS)
1924 +/*********************/
1925 +/* Audio Recordnig */
1926 +/*******************/
1928 +#define MV_AUDIO_RECORD_CTRL_REG 0x1000
1929 +#define MV_AUDIO_RECORD_START_ADDR_REG 0x1004
1930 +#define MV_AUDIO_RECORD_BUFF_SIZE_REG 0x1008
1931 +#define MV_AUDIO_RECORD_BUF_BYTE_CNTR_REG 0x100C
1934 +#define MV_AUDIO_SPDIF_REC_GEN_REG 0x2004
1935 +#define MV_AUDIO_SPDIF_REC_INT_CAUSE_MASK_REG 0x2008
1936 +#define MV_AUDIO_SPDIF_REC_CH_STATUS_LEFT_REG(ind) \
1937 + (0x2180 + ((ind) << 2))
1938 +#define MV_AUDIO_SPDIF_REC_CH_STATUS_RIGHT_REG(ind) \
1939 + (0x21a0 + ((ind) << 2))
1940 +#define MV_AUDIO_SPDIF_REC_USR_BITS_LEFT_REG(ind) \
1941 + (0x21c0 + ((ind) << 2))
1942 +#define MV_AUDIO_SPDIF_REC_USR_BITS_RIGHT_REG(ind) \
1943 + (0x21e0 + ((ind) << 2))
1946 +#define MV_AUDIO_I2S_REC_CTRL_REG 0x2408
1949 +/* MV_AUDIO_RECORD_CTRL_REG*/
1950 +#define ARCR_RECORD_SAMPLE_SIZE_OFFS 0
1951 +#define ARCR_RECORD_SAMPLE_SIZE_MASK (0x7 << ARCR_RECORD_SAMPLE_SIZE_OFFS)
1953 +#define ARCR_RECORDED_MONO_CHNL_OFFS 3
1954 +#define ARCR_RECORDED_MONO_CHNL_MASK (0x1 << ARCR_RECORDED_MONO_CHNL_OFFS)
1956 +#define ARCR_RECORD_MONO_OFFS 4
1957 +#define ARCR_RECORD_MONO_MASK (0x1 << ARCR_RECORD_MONO_OFFS)
1959 +#define ARCR_RECORD_BURST_SIZE_OFFS 5
1960 +#define ARCR_RECORD_BURST_SIZE_MASK (0x3 << ARCR_RECORD_BURST_SIZE_OFFS)
1962 +#define ARCR_RECORD_MUTE_OFFS 8
1963 +#define ARCR_RECORD_MUTE_MASK (0x1 << ARCR_RECORD_MUTE_OFFS)
1965 +#define ARCR_RECORD_PAUSE_OFFS 9
1966 +#define ARCR_RECORD_PAUSE_MASK (0x1 << ARCR_RECORD_PAUSE_OFFS)
1968 +#define ARCR_RECORD_I2S_EN_OFFS 10
1969 +#define ARCR_RECORD_I2S_EN_MASK (0x1 << ARCR_RECORD_I2S_EN_OFFS)
1971 +#define ARCR_RECORD_SPDIF_EN_OFFS 11
1972 +#define ARCR_RECORD_SPDIF_EN_MASK (0x1 << ARCR_RECORD_SPDIF_EN_OFFS)
1975 +/* MV_AUDIO_SPDIF_REC_GEN_REG*/
1976 +#define ASRGR_CORE_CLK_FREQ_OFFS 1
1977 +#define ASRGR_CORE_CLK_FREQ_MASK (0x3 << ASRGR_CORE_CLK_FREQ_OFFS)
1978 +#define ASRGR_CORE_CLK_FREQ_133MHZ (0x0 << ASRGR_CORE_CLK_FREQ_OFFS)
1979 +#define ASRGR_CORE_CLK_FREQ_150MHZ (0x1 << ASRGR_CORE_CLK_FREQ_OFFS)
1980 +#define ASRGR_CORE_CLK_FREQ_166MHZ (0x2 << ASRGR_CORE_CLK_FREQ_OFFS)
1981 +#define ASRGR_CORE_CLK_FREQ_200MHZ (0x3 << ASRGR_CORE_CLK_FREQ_OFFS)
1983 +#define ASRGR_VALID_PCM_INFO_OFFS 7
1984 +#define ASRGR_VALID_PCM_INFO_MASK (0x1 << ASRGR_VALID_PCM_INFO_OFFS)
1986 +#define ASRGR_SAMPLE_FREQ_OFFS 8
1987 +#define ASRGR_SAMPLE_FREQ_MASK (0xf << ASRGR_SAMPLE_FREQ_OFFS)
1989 +#define ASRGR_NON_PCM_OFFS 14
1990 +#define ASRGR_NON_PCM_MASK (1 << ASRGR_NON_PCM_OFFS)
1992 +/* MV_AUDIO_I2S_REC_CTRL_REG*/
1993 +#define AIRCR_I2S_RECORD_JUSTF_OFFS 26
1994 +#define AIRCR_I2S_RECORD_JUSTF_MASK (0xf << AIRCR_I2S_RECORD_JUSTF_OFFS)
1996 +#define AIRCR_I2S_SAMPLE_SIZE_OFFS 30
1997 +#define AIRCR_I2S_SAMPLE_SIZE_MASK (0x3 << AIRCR_I2S_SAMPLE_SIZE_OFFS)
1999 +#endif /* __KW_AUDIO_REGS_H */
2001 diff --git a/sound/soc/kirkwood/kirkwood_pcm.c b/sound/soc/kirkwood/kirkwood_pcm.c
2002 new file mode 100644
2003 index 0000000..ed35851
2005 +++ b/sound/soc/kirkwood/kirkwood_pcm.c
2009 + * Marvell Orion Alsa Sound driver
2011 + * Author: Maen Suleiman
2012 + * Copyright (C) 2008 Marvell Ltd.
2015 + * This program is free software; you can redistribute it and/or modify
2016 + * it under the terms of the GNU General Public License version 2 as
2017 + * published by the Free Software Foundation.
2021 +#include <linux/interrupt.h>
2022 +#include <linux/dma-mapping.h>
2023 +#include <linux/platform_device.h>
2024 +#include <linux/mv88fx_audio.h>
2026 +#include <sound/core.h>
2027 +#include <sound/control.h>
2028 +#include <sound/pcm.h>
2029 +#include <sound/asoundef.h>
2031 +#include "kirkwood_audio_hal.h"
2033 +struct mv88fx_snd_chip *chip;
2035 +static int test_memory(struct mbus_dram_target_info *dram_info,
2036 + unsigned int base, unsigned int size)
2040 + for (i = 0; i <= dram_info->num_cs; i++) {
2042 + /* check if we get to end */
2043 + if ((dram_info->cs[i].base == 0) &&
2044 + (dram_info->cs[i].size == 0))
2047 + /* check if we fit into one memory window only */
2048 + if ((base >= dram_info->cs[i].base) &&
2049 + ((base + size) <= dram_info->cs[i].base +
2050 + dram_info->cs[i].size))
2057 +static void devdma_hw_free(struct device *dev, struct snd_pcm_substream
2060 + struct snd_pcm_runtime *runtime = substream->runtime;
2061 + struct snd_dma_buffer *buf = runtime->dma_buffer_p;
2063 + if (runtime->dma_area == NULL)
2066 + if (buf != &substream->dma_buffer)
2067 + kfree(runtime->dma_buffer_p);
2069 + snd_pcm_set_runtime_buffer(substream, NULL);
2072 +static int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream
2073 + *substream, size_t size)
2075 + struct snd_pcm_runtime *runtime = substream->runtime;
2076 + struct snd_dma_buffer *buf = runtime->dma_buffer_p;
2077 + struct mv88fx_snd_stream *audio_stream =
2078 + snd_pcm_substream_chip(substream);
2083 + if (buf->bytes >= size) {
2084 + snd_printd("buf->bytes >= size\n");
2087 + devdma_hw_free(dev, substream);
2090 + if (substream->dma_buffer.area != NULL &&
2091 + substream->dma_buffer.bytes >= size) {
2092 + buf = &substream->dma_buffer;
2094 + buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
2096 + snd_printk("buf == NULL\n");
2100 + buf->dev.type = SNDRV_DMA_TYPE_DEV;
2101 + buf->dev.dev = dev;
2102 + buf->area = audio_stream->area;
2103 + buf->addr = audio_stream->addr;
2104 + buf->bytes = size;
2105 + buf->private_data = NULL;
2108 + snd_printk("buf->area == NULL\n");
2113 + snd_pcm_set_runtime_buffer(substream, buf);
2116 + runtime->dma_bytes = size;
2125 +static int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream,
2126 + struct vm_area_struct *vma)
2128 + struct snd_pcm_runtime *runtime = substream->runtime;
2129 + return dma_mmap_coherent(dev, vma, runtime->dma_area,
2130 + runtime->dma_addr, runtime->dma_bytes);
2134 + * hw preparation for spdif
2137 +static int mv88fx_snd_spdif_mask_info(struct snd_kcontrol *kcontrol,
2138 + struct snd_ctl_elem_info *uinfo)
2140 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
2145 +static int mv88fx_snd_spdif_mask_get(struct snd_kcontrol *kcontrol,
2146 + struct snd_ctl_elem_value *ucontrol)
2148 + ucontrol->value.iec958.status[0] = 0xff;
2149 + ucontrol->value.iec958.status[1] = 0xff;
2150 + ucontrol->value.iec958.status[2] = 0xff;
2151 + ucontrol->value.iec958.status[3] = 0xff;
2155 +static struct snd_kcontrol_new mv88fx_snd_spdif_mask = {
2156 + .access = SNDRV_CTL_ELEM_ACCESS_READ,
2157 + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
2158 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK),
2159 + .info = mv88fx_snd_spdif_mask_info,
2160 + .get = mv88fx_snd_spdif_mask_get,
2163 +static int mv88fx_snd_spdif_stream_info(struct snd_kcontrol *kcontrol,
2164 + struct snd_ctl_elem_info *uinfo)
2166 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
2171 +static int mv88fx_snd_spdif_stream_get(struct snd_kcontrol *kcontrol,
2172 + struct snd_ctl_elem_value *ucontrol)
2174 + struct mv88fx_snd_chip *chip = snd_kcontrol_chip(kcontrol);
2177 + spin_lock_irq(&chip->reg_lock);
2179 + for (word = 0; word < 4; word++) {
2180 + chip->stream[PLAYBACK]->spdif_status[word] =
2181 + readl(chip->base +
2182 + MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(word));
2184 + for (i = 0; i < 4; i++)
2185 + ucontrol->value.iec958.status[word + i] =
2186 + (chip->stream[PLAYBACK]->spdif_status[word] >>
2190 + spin_unlock_irq(&chip->reg_lock);
2194 +static int mv88fx_snd_spdif_stream_put(struct snd_kcontrol *kcontrol,
2195 + struct snd_ctl_elem_value *ucontrol)
2197 + struct mv88fx_snd_chip *chip = snd_kcontrol_chip(kcontrol);
2198 + int i, change = 0, word;
2200 + spin_lock_irq(&chip->reg_lock);
2202 + for (word = 0; word < 4; word++) {
2203 + for (i = 0; i < 4; i++) {
2204 + chip->stream[PLAYBACK]->spdif_status[word] |=
2205 + ucontrol->value.iec958.status[word + i] << (i * 8);
2208 + writel(chip->stream[PLAYBACK]->spdif_status[word],
2209 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(word));
2211 + writel(chip->stream[PLAYBACK]->spdif_status[word],
2212 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_RIGHT_REG(word));
2215 + if (chip->stream[PLAYBACK]->spdif_status[0] & IEC958_AES0_NONAUDIO)
2216 + chip->pcm_mode = NON_PCM;
2218 + spin_unlock_irq(&chip->reg_lock);
2223 +static struct snd_kcontrol_new mv88fx_snd_spdif_stream = {
2224 + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
2225 + SNDRV_CTL_ELEM_ACCESS_INACTIVE,
2226 + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
2227 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM),
2228 + .info = mv88fx_snd_spdif_stream_info,
2229 + .get = mv88fx_snd_spdif_stream_get,
2230 + .put = mv88fx_snd_spdif_stream_put
2234 +static int mv88fx_snd_spdif_default_info(struct snd_kcontrol *kcontrol,
2235 + struct snd_ctl_elem_info *uinfo)
2237 + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
2242 +static int mv88fx_snd_spdif_default_get(struct snd_kcontrol *kcontrol,
2243 + struct snd_ctl_elem_value *ucontrol)
2245 + struct mv88fx_snd_chip *chip = snd_kcontrol_chip(kcontrol);
2248 + spin_lock_irq(&chip->reg_lock);
2250 + for (word = 0; word < 4; word++) {
2251 + chip->stream_defaults[PLAYBACK]->spdif_status[word] =
2252 + readl(chip->base +
2253 + MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(word));
2255 + for (i = 0; i < 4; i++)
2256 + ucontrol->value.iec958.status[word + i] =
2257 + (chip->stream_defaults[PLAYBACK]->spdif_status[word] >>
2261 + spin_unlock_irq(&chip->reg_lock);
2266 +static int mv88fx_snd_spdif_default_put(struct snd_kcontrol *kcontrol,
2267 + struct snd_ctl_elem_value *ucontrol)
2269 + struct mv88fx_snd_chip *chip = snd_kcontrol_chip(kcontrol);
2270 + int i, change = 0, word;
2272 + spin_lock_irq(&chip->reg_lock);
2274 + for (word = 0; word < 4; word++) {
2275 + for (i = 0; i < 4; i++) {
2276 + chip->stream_defaults[PLAYBACK]->spdif_status[word] |=
2277 + ucontrol->value.iec958.status[word + i] << (i * 8);
2280 + writel(chip->stream_defaults[PLAYBACK]->spdif_status[word],
2281 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(word));
2283 + writel(chip->stream_defaults[PLAYBACK]->spdif_status[word],
2284 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_RIGHT_REG(word));
2287 + if (chip->stream_defaults[PLAYBACK]->spdif_status[0] &
2288 + IEC958_AES0_NONAUDIO)
2289 + chip->pcm_mode = NON_PCM;
2291 + spin_unlock_irq(&chip->reg_lock);
2296 +/* static struct snd_kcontrol_new mv88fx_snd_spdif_default __devinitdata = */
2297 +static struct snd_kcontrol_new mv88fx_snd_spdif_default = {
2298 + .iface = SNDRV_CTL_ELEM_IFACE_PCM,
2299 + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
2300 + .info = mv88fx_snd_spdif_default_info,
2301 + .get = mv88fx_snd_spdif_default_get,
2302 + .put = mv88fx_snd_spdif_default_put
2305 +unsigned char mv88fx_snd_vol[2];
2307 +static int mv88fx_snd_mixer_vol_info(struct snd_kcontrol *kcontrol,
2308 + struct snd_ctl_elem_info *uinfo)
2310 + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2312 + uinfo->value.integer.min = 0;
2313 + uinfo->value.integer.max = 39;
2317 +static int mv88fx_snd_mixer_vol_get(struct snd_kcontrol *kcontrol,
2318 + struct snd_ctl_elem_value *ucontrol)
2320 + codec_vol_get(mv88fx_snd_vol);
2322 + ucontrol->value.integer.value[0] = (long)mv88fx_snd_vol[0];
2323 + ucontrol->value.integer.value[1] = (long)mv88fx_snd_vol[1];
2328 +static int mv88fx_snd_mixer_vol_put(struct snd_kcontrol *kcontrol,
2329 + struct snd_ctl_elem_value *ucontrol)
2331 + mv88fx_snd_vol[0] = (unsigned char)ucontrol->value.integer.value[0];
2332 + mv88fx_snd_vol[1] = (unsigned char)ucontrol->value.integer.value[1];
2334 + codec_vol_set(mv88fx_snd_vol);
2339 +static struct snd_kcontrol_new mv88fx_snd_dac_vol = {
2340 + .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2341 + .name = "Playback DAC Volume",
2342 + .info = mv88fx_snd_mixer_vol_info,
2343 + .get = mv88fx_snd_mixer_vol_get,
2344 + .put = mv88fx_snd_mixer_vol_put
2347 +struct mv88fx_snd_mixer_enum {
2348 + char **names; /* enum names*/
2349 + int *values; /* values to be updated*/
2350 + int count; /* number of elements */
2351 + void *rec; /* field to be updated*/
2354 +int mv88fx_snd_mixer_enum_info(struct snd_kcontrol *kcontrol,
2355 + struct snd_ctl_elem_info *uinfo)
2357 + struct mv88fx_snd_mixer_enum *mixer_enum =
2358 + (struct mv88fx_snd_mixer_enum *)kcontrol->private_value;
2360 + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2362 + uinfo->value.enumerated.items = mixer_enum->count;
2364 + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
2365 + uinfo->value.enumerated.item--;
2367 + strcpy(uinfo->value.enumerated.name,
2368 + mixer_enum->names[uinfo->value.enumerated.item]);
2373 +int mv88fx_snd_mixer_enum_get(struct snd_kcontrol *kcontrol,
2374 + struct snd_ctl_elem_value *ucontrol)
2376 + struct mv88fx_snd_mixer_enum *mixer_enum =
2377 + (struct mv88fx_snd_mixer_enum *)kcontrol->private_value;
2381 + val = *(unsigned int *)mixer_enum->rec;
2383 + for (i = 0; i < mixer_enum->count; i++) {
2385 + if (val == (unsigned int)mixer_enum->values[i]) {
2386 + ucontrol->value.enumerated.item[0] = i;
2394 +int mv88fx_snd_mixer_enum_put(struct snd_kcontrol *kcontrol,
2395 + struct snd_ctl_elem_value *ucontrol)
2397 + unsigned int val, *rec;
2398 + struct mv88fx_snd_mixer_enum *mixer_enum =
2399 + (struct mv88fx_snd_mixer_enum *)kcontrol->private_value;
2402 + rec = (unsigned int *)mixer_enum->rec;
2403 + val = ucontrol->value.enumerated.item[0];
2407 + if (val > mixer_enum->count)
2408 + val = mixer_enum->count;
2410 + for (i = 0; i < mixer_enum->count; i++) {
2413 + *rec = (unsigned int)mixer_enum->values[i];
2421 +#define MV88FX_PCM_MIXER_ENUM(xname, xindex, value) \
2422 +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
2424 + .index = xindex, \
2425 + .info = mv88fx_snd_mixer_enum_info, \
2426 + .get = mv88fx_snd_mixer_enum_get, \
2427 + .put = mv88fx_snd_mixer_enum_put, \
2428 + .private_value = (unsigned long)value, \
2431 +char *playback_src_mixer_names[] = {"SPDIF", "I2S", "SPDIF And I2S"};
2432 +int playback_src_mixer_values[] = { SPDIF, I2S, (SPDIF | I2S)};
2434 +struct mv88fx_snd_mixer_enum playback_src_mixer = {
2435 + .names = playback_src_mixer_names,
2436 + .values = playback_src_mixer_values,
2440 +char *playback_mono_mixer_names[] = {"Mono Both", "Mono Left", "Mono Right"};
2441 +int playback_mono_mixer_values[] = { MONO_BOTH, MONO_LEFT, MONO_RIGHT};
2443 +struct mv88fx_snd_mixer_enum playback_mono_mixer = {
2444 + .names = playback_mono_mixer_names,
2445 + .values = playback_mono_mixer_values,
2449 +char *capture_src_mixer_names[] = {"SPDIF", "I2S"};
2450 +int capture_src_mixer_values[] = { SPDIF, I2S};
2452 +struct mv88fx_snd_mixer_enum capture_src_mixer = {
2453 + .names = capture_src_mixer_names,
2454 + .values = capture_src_mixer_values,
2458 +char *capture_mono_mixer_names[] = {"Mono Left", "Mono Right"};
2459 +int capture_mono_mixer_values[] = { MONO_LEFT, MONO_RIGHT};
2461 +struct mv88fx_snd_mixer_enum capture_mono_mixer = {
2462 + .names = capture_mono_mixer_names,
2463 + .values = capture_mono_mixer_values,
2467 +static struct snd_kcontrol_new mv88fx_snd_mixers[] = {
2468 + MV88FX_PCM_MIXER_ENUM("Playback output type", 0, &playback_src_mixer),
2470 + MV88FX_PCM_MIXER_ENUM("Playback mono type", 0, &playback_mono_mixer),
2472 + MV88FX_PCM_MIXER_ENUM("Capture input Type", 0, &capture_src_mixer),
2474 + MV88FX_PCM_MIXER_ENUM("Capture mono type", 0, &capture_mono_mixer),
2477 +#define PLAYBACK_MIX_INDX 0
2478 +#define PLAYBACK_MONO_MIX_INDX 1
2479 +#define CAPTURE_MIX_INDX 2
2480 +#define CAPTURE_MONO_MIX_INDX 3
2482 +static int mv88fx_snd_ctrl_new(struct snd_card *card)
2484 + struct mv88fx_snd_platform_data *pdata = card->dev->platform_data;
2487 + playback_src_mixer.rec = &chip->stream_defaults[PLAYBACK]->dig_mode;
2488 + playback_mono_mixer.rec = &chip->stream_defaults[PLAYBACK]->mono_mode;
2490 + capture_src_mixer.rec = &chip->stream_defaults[CAPTURE]->dig_mode;
2491 + capture_mono_mixer.rec = &chip->stream_defaults[CAPTURE]->mono_mode;
2493 + if ((pdata->i2s_play) && (pdata->spdif_play)) {
2494 + err = snd_ctl_add(card,
2495 + snd_ctl_new1(&mv88fx_snd_mixers[PLAYBACK_MIX_INDX],
2501 + err = snd_ctl_add(card,
2502 + snd_ctl_new1(&mv88fx_snd_mixers[PLAYBACK_MONO_MIX_INDX], chip));
2506 + if ((pdata->i2s_rec) && (pdata->spdif_rec)) {
2507 + err = snd_ctl_add(card,
2508 + snd_ctl_new1(&mv88fx_snd_mixers[CAPTURE_MIX_INDX], chip));
2513 + err = snd_ctl_add(card, snd_ctl_new1(
2514 + &mv88fx_snd_mixers[CAPTURE_MONO_MIX_INDX], chip));
2518 + if (pdata->i2s_play) {
2519 + err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_dac_vol,
2525 + err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_spdif_mask,
2530 + err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_spdif_default,
2535 + err = snd_ctl_add(card, snd_ctl_new1(&mv88fx_snd_spdif_stream,
2540 +static struct snd_pcm_hardware mv88fx_snd_capture_hw = {
2541 + .info = (SNDRV_PCM_INFO_INTERLEAVED |
2542 + SNDRV_PCM_INFO_MMAP |
2543 + SNDRV_PCM_INFO_MMAP_VALID |
2544 + SNDRV_PCM_INFO_BLOCK_TRANSFER |
2545 + SNDRV_PCM_INFO_PAUSE),
2547 + .formats = (SNDRV_PCM_FMTBIT_S16_LE |
2548 + SNDRV_PCM_FMTBIT_S24_LE |
2549 + SNDRV_PCM_FMTBIT_S32_LE),
2551 + .rates = (SNDRV_PCM_RATE_44100 |
2552 + SNDRV_PCM_RATE_48000 |
2553 + SNDRV_PCM_RATE_96000),
2555 + .rate_min = 44100,
2556 + .rate_max = 96000,
2557 + .channels_min = 1,
2558 + .channels_max = 2,
2559 + .buffer_bytes_max = (16*1024*1024),
2560 + .period_bytes_min = MV88FX_SND_MIN_PERIOD_BYTES,
2561 + .period_bytes_max = MV88FX_SND_MAX_PERIOD_BYTES,
2562 + .periods_min = MV88FX_SND_MIN_PERIODS,
2563 + .periods_max = MV88FX_SND_MAX_PERIODS,
2567 +static int mv88fx_snd_capture_open(struct snd_pcm_substream *substream)
2571 + chip->stream_defaults[CAPTURE]->substream = substream;
2572 + chip->stream_defaults[CAPTURE]->direction = CAPTURE;
2573 + substream->private_data = chip->stream_defaults[CAPTURE];
2574 + substream->runtime->hw = mv88fx_snd_capture_hw;
2576 + if (chip->stream_defaults[CAPTURE]->dig_mode & SPDIF)
2577 + substream->runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_S32_LE;
2579 + /* check if playback is already running with specific rate */
2580 + if (chip->stream[PLAYBACK]->rate) {
2581 + switch (chip->stream[PLAYBACK]->rate) {
2583 + substream->runtime->hw.rates = SNDRV_PCM_RATE_44100;
2586 + substream->runtime->hw.rates = SNDRV_PCM_RATE_48000;
2589 + substream->runtime->hw.rates = SNDRV_PCM_RATE_96000;
2594 + err = snd_pcm_hw_constraint_minmax(substream->runtime,
2595 + SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
2597 + AUDIO_REG_TO_SIZE(APBBCR_SIZE_MAX));
2601 + err = snd_pcm_hw_constraint_step(substream->runtime, 0,
2602 + SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
2607 + err = snd_pcm_hw_constraint_step(substream->runtime, 0,
2608 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
2613 + err = snd_pcm_hw_constraint_minmax(substream->runtime,
2614 + SNDRV_PCM_HW_PARAM_PERIODS,
2615 + MV88FX_SND_MIN_PERIODS,
2616 + MV88FX_SND_MAX_PERIODS);
2620 + err = snd_pcm_hw_constraint_integer(substream->runtime,
2621 + SNDRV_PCM_HW_PARAM_PERIODS);
2628 +static int mv88fx_snd_capture_close(struct snd_pcm_substream *substream)
2630 + chip->stream_defaults[CAPTURE]->substream = NULL;
2631 + memset(chip->stream[CAPTURE], 0, sizeof(struct mv88fx_snd_stream));
2636 +static int mv88fx_snd_capture_hw_params(struct snd_pcm_substream *substream,
2637 + struct snd_pcm_hw_params *params)
2639 + struct mv88fx_snd_stream *audio_stream =
2640 + snd_pcm_substream_chip(substream);
2642 + return devdma_hw_alloc(audio_stream->dev, substream,
2643 + params_buffer_bytes(params));
2646 +static int mv88fx_snd_capture_hw_free(struct snd_pcm_substream *substream)
2648 + struct mv88fx_snd_stream *audio_stream =
2649 + snd_pcm_substream_chip(substream);
2652 + * Clear out the DMA and any allocated buffers.
2654 + devdma_hw_free(audio_stream->dev, substream);
2658 +static int mv88fx_snd_capture_prepare(struct snd_pcm_substream *substream)
2660 + struct snd_pcm_runtime *runtime = substream->runtime;
2662 + struct mv88fx_snd_stream *audio_stream =
2663 + snd_pcm_substream_chip(substream);
2665 + audio_stream->rate = runtime->rate;
2666 + audio_stream->stereo = (runtime->channels == 1) ? 0 : 1;
2668 + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
2669 + audio_stream->format = SAMPLE_16IN16;
2670 + } else if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) {
2671 + audio_stream->format = SAMPLE_24IN32;
2672 + } else if (runtime->format == SNDRV_PCM_FORMAT_S32_LE) {
2673 + audio_stream->format = SAMPLE_32IN32;
2675 + snd_printk("Requested format %d is not supported\n",
2680 + /* buffer and period sizes in frame */
2681 + audio_stream->dma_addr = runtime->dma_addr;
2682 + audio_stream->dma_size = frames_to_bytes(runtime, runtime->buffer_size);
2683 + audio_stream->period_size =
2684 + frames_to_bytes(runtime, runtime->period_size);
2686 + memcpy(chip->stream[CAPTURE], chip->stream_defaults[CAPTURE],
2687 + sizeof(struct mv88fx_snd_stream));
2689 + return mv88fx_snd_hw_capture_set(chip);
2692 +static int mv88fx_snd_capture_trigger(struct snd_pcm_substream *substream,
2695 + struct mv88fx_snd_stream *audio_stream =
2696 + snd_pcm_substream_chip(substream);
2698 + unsigned int reg_data;
2700 + spin_lock(chip->reg_lock);
2702 + case SNDRV_PCM_TRIGGER_START:
2703 + /* FIXME: should check if busy before */
2705 + /* make sure the dma in pause state*/
2706 + reg_data = readl(chip->base + MV_AUDIO_RECORD_CTRL_REG);
2707 + reg_data |= ARCR_RECORD_PAUSE_MASK;
2708 + writel(reg_data, chip->base + MV_AUDIO_RECORD_CTRL_REG);
2710 + /* enable interrupt */
2711 + reg_data = readl(chip->base + MV_AUDIO_INT_MASK_REG);
2712 + reg_data |= AICR_RECORD_BYTES_INT;
2713 + writel(reg_data, chip->base + MV_AUDIO_INT_MASK_REG);
2715 + reg_data = readl(chip->base + MV_AUDIO_RECORD_CTRL_REG);
2718 + if (audio_stream->dig_mode & I2S)
2719 + reg_data |= ARCR_RECORD_I2S_EN_MASK;
2721 + if (audio_stream->dig_mode & SPDIF)
2722 + reg_data |= ARCR_RECORD_SPDIF_EN_MASK;
2725 + reg_data &= (~ARCR_RECORD_PAUSE_MASK);
2726 + writel(reg_data, chip->base + MV_AUDIO_RECORD_CTRL_REG);
2729 + case SNDRV_PCM_TRIGGER_STOP:
2731 + /* make sure the dma in pause state */
2732 + reg_data = readl(chip->base + MV_AUDIO_RECORD_CTRL_REG);
2733 + reg_data |= ARCR_RECORD_PAUSE_MASK;
2734 + writel(reg_data, chip->base + MV_AUDIO_RECORD_CTRL_REG);
2736 + /* disable interrupt */
2737 + reg_data = readl(chip->base + MV_AUDIO_INT_MASK_REG);
2738 + reg_data &= (~AICR_RECORD_BYTES_INT);
2739 + writel(reg_data, chip->base + MV_AUDIO_INT_MASK_REG);
2741 + /* always stop both I2S and SPDIF */
2742 + reg_data = readl(chip->base + MV_AUDIO_RECORD_CTRL_REG);
2743 + reg_data &= (~(ARCR_RECORD_I2S_EN_MASK |
2744 + ARCR_RECORD_SPDIF_EN_MASK));
2745 + writel(reg_data, chip->base + MV_AUDIO_RECORD_CTRL_REG);
2747 + /* FIXME: should check if busy after */
2751 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
2752 + case SNDRV_PCM_TRIGGER_SUSPEND:
2753 + reg_data = readl(chip->base + MV_AUDIO_RECORD_CTRL_REG);
2754 + reg_data |= ARCR_RECORD_PAUSE_MASK;
2755 + writel(reg_data, chip->base + MV_AUDIO_RECORD_CTRL_REG);
2758 + case SNDRV_PCM_TRIGGER_RESUME:
2759 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
2760 + reg_data = readl(chip->base + MV_AUDIO_RECORD_CTRL_REG);
2761 + reg_data &= (~ARCR_RECORD_PAUSE_MASK);
2762 + writel(reg_data, chip->base + MV_AUDIO_RECORD_CTRL_REG);
2770 + spin_unlock(&chip->reg_lock);
2774 +static snd_pcm_uframes_t mv88fx_snd_capture_pointer(struct snd_pcm_substream
2777 + return bytes_to_frames(substream->runtime,
2778 + (ssize_t)readl(chip->base + MV_AUDIO_RECORD_BUF_BYTE_CNTR_REG));
2781 +int mv88fx_snd_capture_mmap(struct snd_pcm_substream *substream,
2782 + struct vm_area_struct *vma)
2784 + return devdma_mmap(NULL, substream, vma);
2787 +static struct snd_pcm_ops mv88fx_snd_capture_ops = {
2788 + .open = mv88fx_snd_capture_open,
2789 + .close = mv88fx_snd_capture_close,
2790 + .ioctl = snd_pcm_lib_ioctl,
2791 + .hw_params = mv88fx_snd_capture_hw_params,
2792 + .hw_free = mv88fx_snd_capture_hw_free,
2793 + .prepare = mv88fx_snd_capture_prepare,
2794 + .trigger = mv88fx_snd_capture_trigger,
2795 + .pointer = mv88fx_snd_capture_pointer,
2796 + .mmap = mv88fx_snd_capture_mmap,
2799 +struct snd_pcm_hardware mv88fx_snd_playback_hw = {
2800 + .info = (SNDRV_PCM_INFO_INTERLEAVED |
2801 + SNDRV_PCM_INFO_MMAP |
2802 + SNDRV_PCM_INFO_MMAP_VALID |
2803 + SNDRV_PCM_INFO_BLOCK_TRANSFER |
2804 + SNDRV_PCM_INFO_PAUSE),
2805 + .formats = (SNDRV_PCM_FMTBIT_S16_LE |
2806 + SNDRV_PCM_FMTBIT_S24_LE |
2807 + SNDRV_PCM_FMTBIT_S32_LE),
2808 + .rates = (SNDRV_PCM_RATE_44100 |
2809 + SNDRV_PCM_RATE_48000 |
2810 + SNDRV_PCM_RATE_96000),
2812 + .rate_min = 44100,
2813 + .rate_max = 96000,
2814 + .channels_min = 1,
2815 + .channels_max = 2,
2816 + .buffer_bytes_max = (16*1024*1024),
2817 + .period_bytes_min = MV88FX_SND_MIN_PERIOD_BYTES,
2818 + .period_bytes_max = MV88FX_SND_MAX_PERIOD_BYTES,
2819 + .periods_min = MV88FX_SND_MIN_PERIODS,
2820 + .periods_max = MV88FX_SND_MAX_PERIODS,
2824 +int mv88fx_snd_playback_open(struct snd_pcm_substream *substream)
2828 + chip->stream_defaults[PLAYBACK]->substream = substream;
2829 + chip->stream_defaults[PLAYBACK]->direction = PLAYBACK;
2830 + substream->private_data = chip->stream_defaults[PLAYBACK];
2831 + substream->runtime->hw = mv88fx_snd_playback_hw;
2833 + if (chip->stream_defaults[PLAYBACK]->dig_mode & SPDIF)
2834 + substream->runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_S32_LE;
2836 + /* check if capture is already running with specific rate */
2837 + if (chip->stream[CAPTURE]->rate) {
2838 + switch (chip->stream[CAPTURE]->rate) {
2840 + substream->runtime->hw.rates = SNDRV_PCM_RATE_44100;
2843 + substream->runtime->hw.rates = SNDRV_PCM_RATE_48000;
2846 + substream->runtime->hw.rates = SNDRV_PCM_RATE_96000;
2852 + err = snd_pcm_hw_constraint_minmax(substream->runtime,
2853 + SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
2855 + AUDIO_REG_TO_SIZE(APBBCR_SIZE_MAX));
2859 + err = snd_pcm_hw_constraint_step(substream->runtime, 0,
2860 + SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
2865 + err = snd_pcm_hw_constraint_step(substream->runtime, 0,
2866 + SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
2871 + err = snd_pcm_hw_constraint_minmax(substream->runtime,
2872 + SNDRV_PCM_HW_PARAM_PERIODS,
2873 + MV88FX_SND_MIN_PERIODS,
2874 + MV88FX_SND_MAX_PERIODS);
2878 + err = snd_pcm_hw_constraint_integer(substream->runtime,
2879 + SNDRV_PCM_HW_PARAM_PERIODS);
2887 +int mv88fx_snd_playback_close(struct snd_pcm_substream *substream)
2891 + chip->stream_defaults[PLAYBACK]->substream = NULL;
2892 + chip->pcm_mode = PCM;
2894 + for (i = 0; i < 4; i++) {
2895 + chip->stream_defaults[PLAYBACK]->spdif_status[i] = 0;
2896 + chip->stream[PLAYBACK]->spdif_status[i] = 0;
2898 + writel(chip->stream_defaults[PLAYBACK]->spdif_status[i],
2899 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(i));
2900 + writel(chip->stream_defaults[PLAYBACK]->spdif_status[i],
2901 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_RIGHT_REG(i));
2904 + memset(chip->stream[PLAYBACK], 0, sizeof(struct mv88fx_snd_stream));
2909 +int mv88fx_snd_playback_hw_params(struct snd_pcm_substream *substream,
2910 + struct snd_pcm_hw_params *params)
2912 + struct mv88fx_snd_stream *audio_stream =
2913 + snd_pcm_substream_chip(substream);
2915 + return devdma_hw_alloc(audio_stream->dev, substream,
2916 + params_buffer_bytes(params));
2919 +int mv88fx_snd_playback_hw_free(struct snd_pcm_substream *substream)
2921 + struct mv88fx_snd_stream *audio_stream =
2922 + snd_pcm_substream_chip(substream);
2925 + * Clear out the DMA and any allocated buffers.
2927 + devdma_hw_free(audio_stream->dev, substream);
2931 +int mv88fx_snd_playback_prepare(struct snd_pcm_substream *substream)
2933 + struct snd_pcm_runtime *runtime = substream->runtime;
2935 + struct mv88fx_snd_stream *audio_stream =
2936 + snd_pcm_substream_chip(substream);
2938 + if ((audio_stream->dig_mode == I2S) &&
2939 + (chip->pcm_mode == NON_PCM))
2942 + audio_stream->rate = runtime->rate;
2943 + audio_stream->stereo = (runtime->channels == 1) ? 0 : 1;
2945 + if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
2946 + audio_stream->format = SAMPLE_16IN16;
2947 + } else if (runtime->format == SNDRV_PCM_FORMAT_S24_LE) {
2948 + audio_stream->format = SAMPLE_24IN32;
2949 + } else if (runtime->format == SNDRV_PCM_FORMAT_S32_LE) {
2950 + audio_stream->format = SAMPLE_32IN32;
2952 + snd_printk("Requested format %d is not supported\n",
2957 + /* buffer and period sizes in frame */
2958 + audio_stream->dma_addr = runtime->dma_addr;
2959 + audio_stream->dma_size = frames_to_bytes(runtime, runtime->buffer_size);
2960 + audio_stream->period_size =
2961 + frames_to_bytes(runtime, runtime->period_size);
2963 + memcpy(chip->stream[PLAYBACK], chip->stream_defaults[PLAYBACK],
2964 + sizeof(struct mv88fx_snd_stream));
2966 + return mv88fx_snd_hw_playback_set(chip);
2969 +int mv88fx_snd_playback_trigger(struct snd_pcm_substream *substream,
2972 + struct mv88fx_snd_stream *audio_stream =
2973 + snd_pcm_substream_chip(substream);
2975 + unsigned int reg_data;
2977 + spin_lock(chip->reg_lock);
2979 + case SNDRV_PCM_TRIGGER_START:
2980 + /* enable interrupt */
2981 + reg_data = readl(chip->base + MV_AUDIO_INT_MASK_REG);
2982 + reg_data |= AICR_PLAY_BYTES_INT;
2983 + writel(reg_data, chip->base + MV_AUDIO_INT_MASK_REG);
2985 + /* make sure the dma in pause state*/
2986 + reg_data = readl(chip->base +
2987 + MV_AUDIO_PLAYBACK_CTRL_REG);
2988 + reg_data |= APCR_PLAY_PAUSE_MASK;
2989 + writel(reg_data, chip->base +
2990 + MV_AUDIO_PLAYBACK_CTRL_REG);
2993 + if ((audio_stream->dig_mode & I2S) &&
2994 + (chip->pcm_mode == PCM))
2995 + reg_data |= APCR_PLAY_I2S_ENABLE_MASK;
2997 + if (audio_stream->dig_mode & SPDIF)
2998 + reg_data |= APCR_PLAY_SPDIF_ENABLE_MASK;
3001 + reg_data &= (~APCR_PLAY_PAUSE_MASK);
3002 + writel(reg_data, chip->base + MV_AUDIO_PLAYBACK_CTRL_REG);
3006 + case SNDRV_PCM_TRIGGER_STOP:
3008 + /* disable interrupt */
3009 + reg_data = readl(chip->base + MV_AUDIO_INT_MASK_REG);
3010 + reg_data &= (~AICR_PLAY_BYTES_INT);
3011 + writel(reg_data, chip->base + MV_AUDIO_INT_MASK_REG);
3013 + /* make sure the dma in pause state*/
3014 + reg_data = readl(chip->base +
3015 + MV_AUDIO_PLAYBACK_CTRL_REG);
3016 + reg_data |= APCR_PLAY_PAUSE_MASK;
3018 + /* always stop both I2S and SPDIF*/
3019 + reg_data &= (~(APCR_PLAY_I2S_ENABLE_MASK |
3020 + APCR_PLAY_SPDIF_ENABLE_MASK));
3021 + writel(reg_data, chip->base +
3022 + MV_AUDIO_PLAYBACK_CTRL_REG);
3024 + /* check if busy twice*/
3025 + while (readl(chip->base + MV_AUDIO_PLAYBACK_CTRL_REG) &
3026 + APCR_PLAY_BUSY_MASK)
3028 + while (readl(chip->base + MV_AUDIO_PLAYBACK_CTRL_REG) &
3029 + APCR_PLAY_BUSY_MASK)
3033 + case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3034 + case SNDRV_PCM_TRIGGER_SUSPEND:
3035 + reg_data = readl(chip->base +
3036 + MV_AUDIO_PLAYBACK_CTRL_REG);
3037 + reg_data |= APCR_PLAY_PAUSE_MASK;
3038 + writel(reg_data, chip->base +
3039 + MV_AUDIO_PLAYBACK_CTRL_REG);
3042 + case SNDRV_PCM_TRIGGER_RESUME:
3043 + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3044 + reg_data = readl(chip->base +
3045 + MV_AUDIO_PLAYBACK_CTRL_REG);
3046 + reg_data &= (~APCR_PLAY_PAUSE_MASK);
3047 + writel(reg_data, chip->base +
3048 + MV_AUDIO_PLAYBACK_CTRL_REG);
3056 + spin_unlock(&chip->reg_lock);
3061 +snd_pcm_uframes_t mv88fx_snd_playback_pointer(struct snd_pcm_substream
3064 + return bytes_to_frames(substream->runtime,
3065 + (ssize_t)readl(chip->base + MV_AUDIO_PLAYBACK_BUFF_BYTE_CNTR_REG));
3068 +int mv88fx_snd_playback_mmap(struct snd_pcm_substream *substream,
3069 + struct vm_area_struct *vma)
3071 + return devdma_mmap(NULL, substream, vma);
3075 +struct snd_pcm_ops mv88fx_snd_playback_ops = {
3076 + .open = mv88fx_snd_playback_open,
3077 + .close = mv88fx_snd_playback_close,
3078 + .ioctl = snd_pcm_lib_ioctl,
3079 + .hw_params = mv88fx_snd_playback_hw_params,
3080 + .hw_free = mv88fx_snd_playback_hw_free,
3081 + .prepare = mv88fx_snd_playback_prepare,
3082 + .trigger = mv88fx_snd_playback_trigger,
3083 + .pointer = mv88fx_snd_playback_pointer,
3084 + .mmap = mv88fx_snd_playback_mmap,
3087 +int __init mv88fx_snd_pcm_new(struct snd_card *card)
3089 + struct snd_pcm *pcm;
3090 + struct mv88fx_snd_platform_data *pdata = card->dev->platform_data;
3093 + snd_printd("card->dev=0x%x\n", (unsigned int)card->dev);
3095 + err = snd_pcm_new(card, "Marvell mv88fx_snd IEC958 and I2S", 0, 1, 1,
3100 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
3101 + &mv88fx_snd_playback_ops);
3103 + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
3104 + &mv88fx_snd_capture_ops);
3106 + if ((pdata->i2s_play) && (pdata->spdif_play))
3107 + chip->stream_defaults[PLAYBACK]->dig_mode = (SPDIF | I2S);
3108 + else if (pdata->i2s_play)
3109 + chip->stream_defaults[PLAYBACK]->dig_mode = I2S;
3110 + else if (pdata->spdif_play)
3111 + chip->stream_defaults[PLAYBACK]->dig_mode = SPDIF;
3113 + chip->stream_defaults[PLAYBACK]->dig_mode = 0;
3115 + chip->stream_defaults[PLAYBACK]->mono_mode = MONO_BOTH;
3116 + chip->pcm_mode = PCM;
3117 + chip->stream_defaults[PLAYBACK]->stat_mem = 0;
3118 + chip->stream_defaults[PLAYBACK]->clock_src = DCO_CLOCK;
3120 + if (pdata->i2s_rec)
3121 + chip->stream_defaults[CAPTURE]->dig_mode = I2S;
3122 + else if (pdata->spdif_rec)
3123 + chip->stream_defaults[CAPTURE]->dig_mode = SPDIF;
3125 + chip->stream_defaults[CAPTURE]->dig_mode = 0;
3127 + chip->stream_defaults[CAPTURE]->mono_mode = MONO_LEFT;
3128 + chip->pcm_mode = PCM;
3129 + chip->stream_defaults[CAPTURE]->stat_mem = 0;
3130 + chip->stream_defaults[CAPTURE]->clock_src = DCO_CLOCK;
3132 + for (i = 0; i < 4; i++) {
3133 + chip->stream_defaults[PLAYBACK]->spdif_status[i] = 0;
3134 + chip->stream[PLAYBACK]->spdif_status[i] = 0;
3136 + writel(chip->stream_defaults[PLAYBACK]->spdif_status[i],
3137 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_LEFT_REG(i));
3139 + writel(chip->stream_defaults[PLAYBACK]->spdif_status[i],
3140 + chip->base + MV_AUDIO_SPDIF_PLAY_CH_STATUS_RIGHT_REG(i));
3142 + writel(0, chip->base +
3143 + MV_AUDIO_SPDIF_PLAY_USR_BITS_LEFT_REG(i));
3145 + writel(0, chip->base +
3146 + MV_AUDIO_SPDIF_PLAY_USR_BITS_RIGHT_REG(i));
3149 + pcm->private_data = chip;
3150 + pcm->info_flags = 0;
3151 + strcpy(pcm->name, "Marvell mv88fx_snd IEC958 and I2S");
3156 +irqreturn_t mv88fx_snd_interrupt(int irq, void *dev_id)
3158 + struct mv88fx_snd_chip *chip = dev_id;
3159 + struct mv88fx_snd_stream *play_stream = chip->stream_defaults[PLAYBACK];
3160 + struct mv88fx_snd_stream *capture_stream =
3161 + chip->stream_defaults[CAPTURE];
3163 + unsigned int status, mask;
3165 + spin_lock(&chip->reg_lock);
3167 + /* read the active interrupt */
3168 + mask = readl(chip->base + MV_AUDIO_INT_MASK_REG);
3169 + status = readl(chip->base + MV_AUDIO_INT_CAUSE_REG) & mask;
3172 + if (status & ~(AICR_RECORD_BYTES_INT|AICR_PLAY_BYTES_INT)) {
3173 + spin_unlock(&chip->reg_lock);
3174 + snd_BUG(); /* FIXME: should enable error interrupts*/
3178 + /* acknowledge interrupt */
3179 + writel(status, chip->base + MV_AUDIO_INT_CAUSE_REG);
3181 + /* This is record event */
3182 + if (status & AICR_RECORD_BYTES_INT)
3183 + snd_pcm_period_elapsed(capture_stream->substream);
3185 + /* This is play event */
3186 + if (status & AICR_PLAY_BYTES_INT)
3187 + snd_pcm_period_elapsed(play_stream->substream);
3189 + /* read the active interrupt */
3190 + mask = readl(chip->base + MV_AUDIO_INT_MASK_REG);
3191 + status = readl(chip->base + MV_AUDIO_INT_CAUSE_REG) & mask;
3194 + spin_unlock(&chip->reg_lock);
3196 + return IRQ_HANDLED;
3199 +void mv88fx_snd_free(struct snd_card *card)
3201 + struct mv88fx_snd_chip *chip = card->private_data;
3204 + free_irq(chip->irq, (void *)chip);
3206 + snd_printd("chip->res =0x%x\n", (unsigned int)chip->res);
3209 + iounmap(chip->base);
3212 + release_resource(chip->res);
3216 + /* Free memory allocated for streems */
3217 + if (chip->stream_defaults[PLAYBACK]->area)
3218 + dma_free_coherent(card->dev,
3219 + MV88FX_SND_MAX_PERIODS * MV88FX_SND_MAX_PERIOD_BYTES,
3220 + chip->stream_defaults[PLAYBACK]->area,
3221 + chip->stream_defaults[PLAYBACK]->addr);
3223 + if (chip->stream_defaults[CAPTURE]->area)
3224 + dma_free_coherent(card->dev,
3225 + MV88FX_SND_MAX_PERIODS * MV88FX_SND_MAX_PERIOD_BYTES,
3226 + chip->stream_defaults[CAPTURE]->area,
3227 + chip->stream_defaults[CAPTURE]->addr);
3229 + kfree(chip->stream_defaults[PLAYBACK]);
3230 + chip->stream_defaults[PLAYBACK] = NULL;
3232 + kfree(chip->stream[PLAYBACK]);
3233 + chip->stream[PLAYBACK] = NULL;
3235 + kfree(chip->stream_defaults[CAPTURE]);
3236 + chip->stream_defaults[CAPTURE] = NULL;
3238 + kfree(chip->stream[CAPTURE]);
3239 + chip->stream[CAPTURE] = NULL;
3244 +int mv88fx_snd_probe(struct platform_device *dev)
3246 + int err = 0, irq = NO_IRQ;
3247 + struct snd_card *card = NULL;
3248 + struct resource *r = NULL;
3249 + static struct snd_device_ops ops = {
3252 + struct mv88fx_snd_platform_data *pdata = NULL;
3254 + err = snd_card_create(-1, "mv88fx_snd", THIS_MODULE,
3255 + sizeof(struct mv88fx_snd_chip), &card);
3258 + snd_printk("snd_card_create failed\n");
3262 + card->dev = &dev->dev;
3263 + chip = card->private_data;
3264 + card->private_free = mv88fx_snd_free;
3266 + pdata = (struct mv88fx_snd_platform_data *)dev->dev.platform_data;
3268 + if (pdata->i2s_rec == 2 || pdata->spdif_rec == 2)
3273 + chip->audio_offset = pdata->base_offset;
3275 + r = platform_get_resource(dev, IORESOURCE_MEM, 0);
3277 + snd_printk("platform_get_resource failed\n");
3282 + snd_printd("chip->res =0x%x\n", (unsigned int)chip->res);
3284 + r = request_mem_region(r->start, SZ_16K, MV88FX_AUDIO_NAME);
3286 + snd_printk("request_mem_region failed\n");
3292 + chip->base = ioremap(r->start, SZ_16K);
3294 + if (!chip->base) {
3295 + snd_printk("ioremap failed\n");
3300 + snd_printd("chip->base=0x%x r->start0x%x\n",
3301 + (unsigned int)chip->base, r->start);
3303 + irq = platform_get_irq(dev, 0);
3304 + if (irq == NO_IRQ) {
3305 + snd_printk("platform_get_irq failed\n");
3310 + snd_printd("card = 0x%x dev 0x%x\n",
3311 + (unsigned int)card, (unsigned int)dev);
3312 + strncpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
3314 + /* Allocate memory for our device */
3315 + chip->stream_defaults[PLAYBACK] =
3316 + kzalloc(sizeof(struct mv88fx_snd_stream), GFP_KERNEL);
3318 + if (chip->stream_defaults[PLAYBACK] == NULL) {
3319 + snd_printk("kzalloc failed for default playback\n");
3324 + chip->stream_defaults[PLAYBACK]->direction = PLAYBACK;
3325 + chip->stream_defaults[PLAYBACK]->dev = card->dev;
3327 + chip->stream[PLAYBACK] = kzalloc(sizeof(struct mv88fx_snd_stream),
3330 + if (chip->stream[PLAYBACK] == NULL) {
3331 + snd_printk("kzalloc failed for runtime playback\n");
3336 + chip->stream_defaults[CAPTURE] =
3337 + kzalloc(sizeof(struct mv88fx_snd_stream), GFP_KERNEL);
3339 + if (chip->stream_defaults[CAPTURE] == NULL) {
3340 + snd_printk("kzalloc failed for capture\n");
3345 + chip->stream_defaults[CAPTURE]->direction = CAPTURE;
3346 + chip->stream_defaults[CAPTURE]->dev = card->dev;
3348 + chip->stream[CAPTURE] = kzalloc(sizeof(struct mv88fx_snd_stream),
3351 + if (chip->stream[CAPTURE] == NULL) {
3352 + snd_printk("kzalloc failed for runtime capture\n");
3358 + chip->stream_defaults[PLAYBACK]->area =
3359 + dma_alloc_coherent(&dev->dev,
3360 + MV88FX_SND_MAX_PERIODS * MV88FX_SND_MAX_PERIOD_BYTES,
3361 + &chip->stream_defaults[PLAYBACK]->addr,
3364 + if (!chip->stream_defaults[PLAYBACK]->area) {
3365 + snd_printk("dma_alloc_coherent failed for playback buffer\n");
3370 + if (0 == test_memory(pdata->dram,
3371 + (unsigned int)chip->stream_defaults[PLAYBACK]->addr,
3372 + (unsigned int)MV88FX_SND_MAX_PERIODS * MV88FX_SND_MAX_PERIOD_BYTES)) {
3374 + snd_printk("error: playback buffer not in one memory window\n");
3379 + chip->stream_defaults[CAPTURE]->area =
3380 + dma_alloc_coherent(&dev->dev,
3381 + MV88FX_SND_MAX_PERIODS * MV88FX_SND_MAX_PERIOD_BYTES,
3382 + &chip->stream_defaults[CAPTURE]->addr,
3385 + if (!chip->stream_defaults[CAPTURE]->area) {
3386 + snd_printk("dma_alloc_coherent failed for capture buffer\n");
3391 + if (0 == test_memory(pdata->dram,
3392 + (unsigned int)chip->stream_defaults[CAPTURE]->addr,
3393 + (unsigned int)MV88FX_SND_MAX_PERIODS * MV88FX_SND_MAX_PERIOD_BYTES)) {
3395 + snd_printk("error: playback buffer not in one memory window\n");
3400 + if (request_irq(chip->irq, mv88fx_snd_interrupt, 0, MV88FX_AUDIO_NAME,
3403 + snd_printk("Unable to grab IRQ %d\n", chip->irq);
3408 + chip->ch_stat_valid = 1;
3409 + chip->burst = 128;
3410 + chip->loopback = 0;
3411 + chip->dco_ctrl_offst = 0x800;
3413 + err = mv88fx_snd_hw_init(card);
3415 + snd_printk("mv88fx_snd_hw_init failed\n");
3420 + /* Set default values */
3421 + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
3423 + snd_printk("Creating chip device failed.\n");
3428 + /* create pcm devices */
3429 + err = mv88fx_snd_pcm_new(card);
3431 + snd_printk("Creating PCM device failed.\n");
3435 + /* create controll interfaces & switches */
3436 + err = mv88fx_snd_ctrl_new(card);
3438 + snd_printk("Creating non-PCM device failed.\n");
3443 + strcpy(card->driver, "mv88fx_snd");
3444 + strcpy(card->shortname, "Marvell mv88fx_snd");
3445 + sprintf(card->longname, "Marvell mv88fx_snd ALSA driver");
3447 + err = snd_card_register(card);
3449 + snd_printk("Card registeration failed.\n");
3454 + /* if (dma_set_mask(&dev->dev, 0xFFFFFFUL) < 0) { */
3455 + if (dma_set_mask(&dev->dev, 0xFFFFFFFFUL) < 0) {
3456 + snd_printk("Could not set DMA mask\n");
3460 + platform_set_drvdata(dev, card);
3464 + snd_card_free(card);
3465 + platform_set_drvdata(dev, NULL);
3469 +int mv88fx_snd_remove(struct platform_device *dev)
3471 + struct snd_card *card = platform_get_drvdata(dev);
3474 + snd_card_free(card);
3476 + /* FIXME: Once "../codecs/cs42l51.c" is fixed to behave as a module
3477 + * this should be removed */
3478 + codec_del_i2c_device();
3480 + platform_set_drvdata(dev, NULL);
3484 +#define mv88fx_snd_resume NULL
3485 +#define mv88fx_snd_suspend NULL
3487 +struct platform_driver mv88fx_snd_driver = {
3488 + .probe = mv88fx_snd_probe,
3489 + .remove = mv88fx_snd_remove,
3490 + .suspend = mv88fx_snd_suspend,
3491 + .resume = mv88fx_snd_resume,
3492 + .driver = { .name = MV88FX_AUDIO_NAME,},
3495 +int __init mv88fx_snd_init(void)
3497 + return platform_driver_register(&mv88fx_snd_driver);
3500 +void __exit mv88fx_snd_exit(void)
3502 + platform_driver_unregister(&mv88fx_snd_driver);
3505 +MODULE_AUTHOR("Maen Suleiman <maen@marvell.com>");
3506 +MODULE_DESCRIPTION("Marvell MV88Fx Alsa Sound driver");
3507 +MODULE_LICENSE("GPL");
3509 +module_init(mv88fx_snd_init);
3510 +module_exit(mv88fx_snd_exit);