summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrans Meulenbroeks <fransmeulenbroeks@gmail.com>2010-01-06 21:32:39 +0100
committerFrans Meulenbroeks <fransmeulenbroeks@gmail.com>2010-01-06 21:32:39 +0100
commitb2a6f7304b70600e5c9b131c353b81346b82158d (patch)
tree4c355cc06586aece4351f2cc586f81e5e79d03ed
parentc7ed94a12cdcc4b8e98698683022ac1bd328ef0c (diff)
linux-kirkwood: moved kernel to 2.6.33-rc1
added patches for video and audio for openrd client made some configuration changes in defconfig to support those
-rw-r--r--recipes/linux/linux-kirkwood/0001-ARM-Kirkwood-Sound-Sound-driver-added.patch3514
-rw-r--r--recipes/linux/linux-kirkwood/0001-OpenRD-Client-PCIe-Initialize-PCI-express-and-i2c.patch36
-rw-r--r--recipes/linux/linux-kirkwood/0003-ARM-Kirkwood-Sound-Sound-driver-added.patch208
-rw-r--r--recipes/linux/linux-kirkwood/openrd-client/0002-OpenRD-Client-Volari-Z11-driver-added.patch29767
-rw-r--r--recipes/linux/linux-kirkwood/openrd-client/defconfig1292
-rw-r--r--recipes/linux/linux-kirkwood_2.6.33-rc1.bb (renamed from recipes/linux/linux-kirkwood_2.6.32-rc4.bb)13
6 files changed, 33753 insertions, 1077 deletions
diff --git a/recipes/linux/linux-kirkwood/0001-ARM-Kirkwood-Sound-Sound-driver-added.patch b/recipes/linux/linux-kirkwood/0001-ARM-Kirkwood-Sound-Sound-driver-added.patch
new file mode 100644
index 0000000000..fc17a089c5
--- /dev/null
+++ b/recipes/linux/linux-kirkwood/0001-ARM-Kirkwood-Sound-Sound-driver-added.patch
@@ -0,0 +1,3514 @@
+From 89aa6dd15306a1ce11da0f2cb67bda74999e178e Mon Sep 17 00:00:00 2001
+From: Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
+Date: Tue, 24 Nov 2009 21:49:24 +0530
+Subject: [PATCH] ARM: Kirkwood: Sound: Sound driver added
+
+The driver is based on the Marvell kirkwood sound driver available in
+2.6.22.18 kernel.
+
+Signed-off-by: Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
+---
+ arch/arm/mach-kirkwood/common.c | 39 +
+ arch/arm/mach-kirkwood/common.h | 2 +
+ arch/arm/mach-kirkwood/include/mach/kirkwood.h | 3 +
+ arch/arm/mach-kirkwood/openrd_client-setup.c | 27 +
+ include/linux/mv88fx_audio.h | 111 ++
+ sound/soc/Kconfig | 1 +
+ sound/soc/Makefile | 1 +
+ sound/soc/kirkwood/Kconfig | 29 +
+ sound/soc/kirkwood/Makefile | 7 +
+ sound/soc/kirkwood/cs42l51.c | 304 +++++
+ sound/soc/kirkwood/cs42l51.h | 59 +
+ sound/soc/kirkwood/kirkwood_audio_hal.c | 821 +++++++++++++
+ sound/soc/kirkwood/kirkwood_audio_hal.h | 109 ++
+ sound/soc/kirkwood/kirkwood_audio_regs.h | 310 +++++
+ sound/soc/kirkwood/kirkwood_pcm.c | 1505 ++++++++++++++++++++++++
+ 15 files changed, 3328 insertions(+), 0 deletions(-)
+ create mode 100644 include/linux/mv88fx_audio.h
+ create mode 100644 sound/soc/kirkwood/Kconfig
+ create mode 100644 sound/soc/kirkwood/Makefile
+ create mode 100644 sound/soc/kirkwood/cs42l51.c
+ create mode 100644 sound/soc/kirkwood/cs42l51.h
+ create mode 100644 sound/soc/kirkwood/kirkwood_audio_hal.c
+ create mode 100644 sound/soc/kirkwood/kirkwood_audio_hal.h
+ create mode 100644 sound/soc/kirkwood/kirkwood_audio_regs.h
+ create mode 100644 sound/soc/kirkwood/kirkwood_pcm.c
+
+diff --git a/arch/arm/mach-kirkwood/common.c b/arch/arm/mach-kirkwood/common.c
+index 0acb61f..4d66c06 100644
+--- a/arch/arm/mach-kirkwood/common.c
++++ b/arch/arm/mach-kirkwood/common.c
+@@ -15,6 +15,7 @@
+ #include <linux/mbus.h>
+ #include <linux/mv643xx_eth.h>
+ #include <linux/mv643xx_i2c.h>
++#include <linux/mv88fx_audio.h>
+ #include <linux/ata_platform.h>
+ #include <linux/mtd/nand.h>
+ #include <linux/spi/orion_spi.h>
+@@ -969,3 +970,41 @@ static int __init kirkwood_clock_gate(void)
+ return 0;
+ }
+ late_initcall(kirkwood_clock_gate);
++
++/*****************************************************************************
++ * Audio
++ ****************************************************************************/
++
++static struct resource kirkwood_audio_resources[] = {
++ [0] = {
++ .start = AUDIO_PHYS_BASE,
++ .end = AUDIO_PHYS_BASE + SZ_16K - 1,
++ .flags = IORESOURCE_MEM,
++ },
++ [1] = {
++ .start = IRQ_KIRKWOOD_I2S,
++ .end = IRQ_KIRKWOOD_I2S,
++ .flags = IORESOURCE_IRQ,
++ },
++};
++
++static u64 kirkwood_audio_dmamask = 0xFFFFFFFFUL;
++
++static struct platform_device kirkwood_audio = {
++ .name = MV88FX_AUDIO_NAME,
++ .id = -1,
++ .num_resources = ARRAY_SIZE(kirkwood_audio_resources),
++ .resource = kirkwood_audio_resources,
++ .dev = {
++ .dma_mask = &kirkwood_audio_dmamask,
++ .coherent_dma_mask = 0xffffffff,
++ },
++};
++
++void __init kirkwood_audio_init(struct mv88fx_snd_platform_data *audio_data)
++{
++ kirkwood_clk_ctrl |= CGC_AUDIO;
++ kirkwood_audio.dev.platform_data = audio_data;
++
++ platform_device_register(&kirkwood_audio);
++}
+diff --git a/arch/arm/mach-kirkwood/common.h b/arch/arm/mach-kirkwood/common.h
+index d7de434..b79a25c 100644
+--- a/arch/arm/mach-kirkwood/common.h
++++ b/arch/arm/mach-kirkwood/common.h
+@@ -16,6 +16,7 @@ struct mv643xx_eth_platform_data;
+ struct mv_sata_platform_data;
+ struct mvsdio_platform_data;
+ struct mtd_partition;
++struct mv88fx_snd_platform_data;
+
+ /*
+ * Basic Kirkwood init functions used early by machine-setup.
+@@ -41,6 +42,7 @@ void kirkwood_i2c_init(void);
+ void kirkwood_uart0_init(void);
+ void kirkwood_uart1_init(void);
+ void kirkwood_nand_init(struct mtd_partition *parts, int nr_parts, int delay);
++void kirkwood_audio_init(struct mv88fx_snd_platform_data *audio_data);
+
+ extern int kirkwood_tclk;
+ extern struct sys_timer kirkwood_timer;
+diff --git a/arch/arm/mach-kirkwood/include/mach/kirkwood.h b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+index 54c1327..90ced65 100644
+--- a/arch/arm/mach-kirkwood/include/mach/kirkwood.h
++++ b/arch/arm/mach-kirkwood/include/mach/kirkwood.h
+@@ -95,6 +95,9 @@
+
+ #define SDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0x90000)
+
++#define AUDIO_PHYS_BASE (KIRKWOOD_REGS_PHYS_BASE | 0xA0000)
++#define AUDIO_VIRT_BASE (KIRKWOOD_REGS_VIRT_BASE | 0xA0000)
++
+ /*
+ * Supported devices and revisions.
+ */
+diff --git a/arch/arm/mach-kirkwood/openrd_client-setup.c b/arch/arm/mach-kirkwood/openrd_client-setup.c
+index a55a1bc..72acc22 100644
+--- a/arch/arm/mach-kirkwood/openrd_client-setup.c
++++ b/arch/arm/mach-kirkwood/openrd_client-setup.c
+@@ -14,11 +14,13 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/ata_platform.h>
+ #include <linux/mv643xx_eth.h>
++#include <linux/mv88fx_audio.h>
+ #include <linux/gpio.h>
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+ #include <mach/kirkwood.h>
+ #include <plat/mvsdio.h>
++#include <linux/autoconf.h>
+ #include "common.h"
+ #include "mpp.h"
+
+@@ -59,6 +61,21 @@ static unsigned int openrd_client_mpp_config[] __initdata = {
+ 0
+ };
+
++static struct mv88fx_snd_platform_data openrd_client_audio_data = {
++ .i2c_bus_no = 0,
++ .i2c_address = 0x4A,
++/* 0 - NA, 1 - mono, 2 - stereo */
++#ifdef CONFIG_SND_MV88FX_SOC_I2S
++ .i2s_rec = 1,
++ .i2s_play = 2,
++#else
++ .spdif_rec = 1,
++ .spdif_play = 2,
++#endif
++ .dram = &kirkwood_mbus_dram_info,
++ .base_offset = AUDIO_PHYS_BASE - KIRKWOOD_REGS_PHYS_BASE,
++};
++
+ static void __init openrd_client_init(void)
+ {
+ /*
+@@ -78,6 +95,16 @@ static void __init openrd_client_init(void)
+
+ kirkwood_sata_init(&openrd_client_sata_data);
+ kirkwood_sdio_init(&openrd_client_mvsdio_data);
++
++ /* initialize i2c */
++ kirkwood_i2c_init();
++
++#if defined(CONFIG_SND_MV88FX_SOC) || defined(CONFIG_SND_MV88FX_SOC_MODULE)
++ /* If built as a part of kernel or as a module
++ * initialize audio */
++ openrd_client_audio_data.tclk = kirkwood_tclk,
++ kirkwood_audio_init(&openrd_client_audio_data);
++#endif
+ }
+
+ MACHINE_START(OPENRD_CLIENT, "Marvell OpenRD Client Board")
+diff --git a/include/linux/mv88fx_audio.h b/include/linux/mv88fx_audio.h
+new file mode 100644
+index 0000000..6d36a3f
+--- /dev/null
++++ b/include/linux/mv88fx_audio.h
+@@ -0,0 +1,111 @@
++/*
++ *
++ * Marvell Orion Alsa Sound driver
++ *
++ * Author: Maen Suleiman
++ * Copyright (C) 2008 Marvell Ltd.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++#ifndef __LINUX_MV88FX_SND_H
++#define __LINUX_MV88FX_SND_H
++
++#include <linux/mbus.h>
++
++#define MV88FX_AUDIO_NAME "mv88fx_snd"
++
++#undef MV88FX_SND_DEBUG
++#ifdef MV88FX_SND_DEBUG
++#define mv88fx_snd_debug(fmt, arg...) printk(KERN_DEBUG fmt, ##arg)
++#else
++ #define mv88fx_snd_debug(a...)
++#endif
++
++#define MV_AUDIO_MAX_ADDR_DECODE_WIN 2
++#define MV_AUDIO_RECORD_WIN_NUM 0
++#define MV_AUDIO_PLAYBACK_WIN_NUM 1
++
++#define MV_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3))
++#define MV_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3))
++
++struct mv88fx_snd_platform_data {
++ u8 i2c_bus_no;
++ u16 i2c_address;
++ u32 spdif_rec;
++ u32 spdif_play;
++ u32 i2s_rec;
++ u32 i2s_play;
++ u32 tclk;
++ u32 base_offset;
++ struct mbus_dram_target_info *dram;
++};
++
++struct mv88fx_snd_stream {
++ struct snd_pcm_substream *substream;
++ struct device *dev;
++ int direction; /* playback or capture */
++ #define PLAYBACK 0
++ #define CAPTURE 1
++ unsigned int dig_mode; /* i2s,spdif,both */
++ #define I2S 1
++ #define SPDIF 2
++ int stereo; /* mono, stereo */
++ int mono_mode; /* both mono, left mono, right mono */
++ #define MONO_BOTH 0
++ #define MONO_LEFT 1
++ #define MONO_RIGHT 2
++ int clock_src;
++ #define DCO_CLOCK 0
++ #define SPCR_CLOCK 1
++ #define EXTERN_CLOCK 2
++ int rate;
++ int stat_mem; /* Channel status source*/
++ int format;
++ #define SAMPLE_32IN32 0
++ #define SAMPLE_24IN32 1
++ #define SAMPLE_20IN32 2
++ #define SAMPLE_16IN32 3
++ #define SAMPLE_16IN16 4
++ unsigned int dma_addr;
++ unsigned int dma_size;
++ unsigned int period_size;
++ unsigned int spdif_status[4]; /* SPDIF status */
++ unsigned char *area; /* virtual pointer */
++ dma_addr_t addr; /* physical address */
++};
++
++struct mv88fx_snd_chip {
++ struct mv88fx_snd_stream *stream[2]; /* run time values*/
++ struct mv88fx_snd_stream *stream_defaults[2]; /* default values*/
++ spinlock_t reg_lock; /* Register access spinlock */
++ struct resource *res; /* resource for IRQ and base*/
++ void __iomem *base; /* Audio base address of the host */
++ unsigned int audio_offset; /* Offset to audio base register
++ * from internal base register */
++ int irq;
++ int loopback; /* When Loopback is enabled, playback
++ * data is looped back to be recorded */
++ int ch_stat_valid; /* Playback SPDIF channel validity bit
++ * value when REG selected */
++ int burst; /* DMA Burst Size */
++
++ #define SPDIF_MEM_STAT 0
++ #define SPDIF_REG_STAT 1
++ unsigned int dco_ctrl_offst;
++ int pcm_mode; /* pcm, nonpcm*/
++ #define PCM 0
++ #define NON_PCM 1
++ int stereo;
++};
++
++#define MV88FX_SND_MIN_PERIODS 8
++#define MV88FX_SND_MAX_PERIODS 16
++#define MV88FX_SND_MIN_PERIOD_BYTES 0x4000
++#define MV88FX_SND_MAX_PERIOD_BYTES 0x4000
++
++#endif /* __LINUX_MV88FX_SND_H */
+diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
+index b1749bc..9fc88d8 100644
+--- a/sound/soc/Kconfig
++++ b/sound/soc/Kconfig
+@@ -36,6 +36,7 @@ source "sound/soc/s3c24xx/Kconfig"
+ source "sound/soc/s6000/Kconfig"
+ source "sound/soc/sh/Kconfig"
+ source "sound/soc/txx9/Kconfig"
++source "sound/soc/kirkwood/Kconfig"
+
+ # Supported codecs
+ source "sound/soc/codecs/Kconfig"
+diff --git a/sound/soc/Makefile b/sound/soc/Makefile
+index 0c5eac0..664850d 100644
+--- a/sound/soc/Makefile
++++ b/sound/soc/Makefile
+@@ -14,3 +14,4 @@ obj-$(CONFIG_SND_SOC) += s3c24xx/
+ obj-$(CONFIG_SND_SOC) += s6000/
+ obj-$(CONFIG_SND_SOC) += sh/
+ obj-$(CONFIG_SND_SOC) += txx9/
++obj-$(CONFIG_SND_SOC) += kirkwood/
+diff --git a/sound/soc/kirkwood/Kconfig b/sound/soc/kirkwood/Kconfig
+new file mode 100644
+index 0000000..d6a7e2f
+--- /dev/null
++++ b/sound/soc/kirkwood/Kconfig
+@@ -0,0 +1,29 @@
++config SND_MV88FX_SOC
++ tristate "SoC Audio for the Marvell 88FX chip"
++ depends on ARCH_KIRKWOOD
++ help
++ Say Y or M if you want to add support for codecs attached to
++ the MV88FX I2S or SPD interface. You will also need
++ to select the audio interfaces to support below.
++
++choice
++ prompt "Audio Interface"
++ default SND_MV88FX_SOC_I2S
++ depends on SND_MV88FX_SOC
++
++config SND_MV88FX_SOC_I2S
++ bool "I2S"
++
++config SND_MV88FX_SOC_SPDIF
++ bool "SPDIF"
++
++endchoice
++
++choice
++ prompt "Codec IC"
++ default SND_SOC_CS42L51
++ depends on SND_MV88FX_SOC
++
++config SND_SOC_CS42L51
++ bool "CS42L51"
++endchoice
+diff --git a/sound/soc/kirkwood/Makefile b/sound/soc/kirkwood/Makefile
+new file mode 100644
+index 0000000..57674ad
+--- /dev/null
++++ b/sound/soc/kirkwood/Makefile
+@@ -0,0 +1,7 @@
++
++snd-soc-kirkwood-objs := kirkwood_pcm.o kirkwood_audio_hal.o
++ifdef CONFIG_SND_SOC_CS42L51
++snd-soc-kirkwood-objs += cs42l51.o
++endif
++
++obj-$(CONFIG_SND_MV88FX_SOC) += snd-soc-kirkwood.o
+diff --git a/sound/soc/kirkwood/cs42l51.c b/sound/soc/kirkwood/cs42l51.c
+new file mode 100644
+index 0000000..f5a22f9
+--- /dev/null
++++ b/sound/soc/kirkwood/cs42l51.c
+@@ -0,0 +1,304 @@
++/*
++ *
++ * Marvell Orion Alsa Sound driver
++ *
++ * Author: Maen Suleiman
++ * Copyright (C) 2008 Marvell Ltd.
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/version.h>
++#include <linux/i2c.h>
++#include <sound/core.h>
++#include <sound/initval.h>
++#include <sound/control.h>
++#include <sound/pcm.h>
++#include <sound/asoundef.h>
++#include <sound/asound.h>
++
++#include "cs42l51.h"
++
++/* FIXME: This code is not written in driver module style. This is written as
++ * helper for SOC driver */
++
++struct i2c_client *client;
++
++static int cs42l51_add_i2c_device(unsigned char i2c_bus_no,
++ unsigned short i2c_add)
++{
++ struct i2c_board_info info;
++ struct i2c_adapter *adapter;
++
++ memset(&info, 0, sizeof(struct i2c_board_info));
++ info.addr = i2c_add;
++ strlcpy(info.type, "cs42l51", I2C_NAME_SIZE);
++
++ adapter = i2c_get_adapter(i2c_bus_no);
++ if (!adapter) {
++ snd_printk("can't get i2c adapter\n");
++ return -ENODEV;
++ }
++
++ client = i2c_new_device(adapter, &info);
++ i2c_put_adapter(adapter);
++ if (!client) {
++ snd_printk("can't add i2c device\n");
++ return -ENODEV;
++ }
++
++ return 0;
++}
++
++void cs42l51_del_i2c_device(void)
++{
++ if (client)
++ i2c_unregister_device(client);
++ client = NULL;
++}
++
++/*
++ * offset: Register offset to start reading with
++ * buf : Pointer to the buffer to store the read data
++ * num : Number of registers to read
++ *
++ * Returns -ve errorno else number of registers read
++ */
++
++int cs42l51_reg_read(unsigned char offset, unsigned char *buf, int num)
++{
++ int ret = 0;
++
++ /* Set autoincrement bit */
++ offset |= CODEC_INCR_ADDR;
++
++ /* Send register offset */
++ ret = i2c_master_send(client, &offset, 1);
++ if (ret != 1) {
++ snd_printd("Could not write register offset\n");
++ return 0;
++ }
++
++ return i2c_master_recv(client, buf, num);
++}
++
++/*
++ * offset: Register offset to write
++ * data : Data to be written
++ *
++ * Returns -ve errorno else number of registers written (=1)
++ */
++
++int cs42l51_reg_write(unsigned char offset, unsigned char data)
++{
++ int ret = 0;
++ unsigned char buf[2];
++
++ buf[0] = offset;
++ buf[1] = data;
++
++ /* Send register offset & data */
++ ret = i2c_master_send(client, &buf[0], 2);
++
++ return (ret == 2) ? 1 : ret;
++}
++
++int codec_init(int adc_mode, int digital_if_format,
++ unsigned char i2c_bus_no, unsigned short i2c_add)
++{
++ unsigned char reg_data;
++
++ if (cs42l51_add_i2c_device(i2c_bus_no, i2c_add))
++ return 1;
++
++ if (cs42l51_reg_read(CODEC_ID_REG, &reg_data, 1) < 0)
++ goto codec_init_error;
++
++ if (CODEC_CHIP_ID != (reg_data >> 3) ||
++ CODEC_REV_ID != (reg_data & 0x7)) {
++ snd_printd("Error: Invalid Cirrus Logic chip/rev ID!\n");
++ return 1;
++ }
++
++ if (cs42l51_reg_read(CODEC_IF_CTRL_REG, &reg_data, 1) < 0)
++ goto codec_init_error;
++
++ reg_data = (reg_data & ~(0x7<<3)) | (digital_if_format << 3);
++
++ if (LEFT_JUSTIFIED_MODE == adc_mode)
++ reg_data &= (~0x4);
++ else
++ reg_data |= 0x4;
++
++ if (cs42l51_reg_write(CODEC_IF_CTRL_REG, reg_data) < 0)
++ goto codec_init_error;
++
++ return 0;
++
++codec_init_error:
++ snd_printd("I2C error\n");
++ return 1;
++}
++
++/*
++ * Initialize the audio decoder.
++ */
++
++int cs42l51_init(int adc_mode, int digital_if_format, int rec,
++ unsigned char i2c_bus_no, unsigned short i2c_add)
++{
++ if (codec_init(adc_mode, digital_if_format, i2c_bus_no, i2c_add)) {
++ snd_printk("Error: Audio Codec init failed\n");
++ return 1;
++ }
++
++ /* Use the signal processor */
++ if (cs42l51_reg_write(0x9, 0x40) < 0)
++ goto error;
++
++ /* Unmute PCM-A & PCM-B and set default */
++ if (cs42l51_reg_write(0x10, 0x60) < 0)
++ goto error;
++ if (cs42l51_reg_write(0x11, 0x60) < 0)
++ goto error;
++
++ /* default for AOUTx */
++ if (cs42l51_reg_write(0x16, 0x05) < 0)
++ goto error;
++ if (cs42l51_reg_write(0x17, 0x05) < 0)
++ goto error;
++
++ /* swap channels */
++ if (cs42l51_reg_write(0x18, 0xff) < 0)
++ goto error;
++
++ /* MIC Power Control: power down mIC in channel B, power on channel A
++ * Recommended seq. in datasheet:
++ * 1. Enable the PDN bit
++ * 2. Enable power-down for the selected channels
++ * 3. Disable the PDN bit */
++
++ /* Note: Tested for mono recording only */
++ if (!rec) {
++ /* Enable power down */
++ if (cs42l51_reg_write(0x2, 0x11) < 0)
++ goto error;
++
++ /* No record - Power down both channels */
++ if (cs42l51_reg_write(0x2, 0x17) < 0)
++ goto error;
++
++ /* Disable power down */
++ if (cs42l51_reg_write(0x2, 0x16) < 0)
++ goto error;
++ } else {
++ if (rec == 2) {
++ /* Setreo recording - by default both channels are up */
++
++ /* MIC In channel selection - Select channel 3
++ * unmute both channels */
++ if (cs42l51_reg_write(0x7, 0xF0) < 0)
++ goto error;
++
++ /* Power up mic pre-amplifier for both channels */
++ if (cs42l51_reg_write(0x3, 0xA0) < 0)
++ goto error;
++ } else {
++ /* Enable power down */
++ if (cs42l51_reg_write(0x2, 0x11) < 0)
++ goto error;
++
++ /* Mono recording - Power down Channel B */
++ if (cs42l51_reg_write(0x2, 0x15) < 0)
++ goto error;
++
++ /* Disable power down */
++ if (cs42l51_reg_write(0x2, 0x14) < 0)
++ goto error;
++
++ /* MIC In channel selection - Select channel 3
++ * Mute Channel B */
++ if (cs42l51_reg_write(0x7, 0xF2) < 0)
++ goto error;
++
++ /* Power down mic pre-amplifier for Channel B*/
++ if (cs42l51_reg_write(0x3, 0xA8) < 0)
++ goto error;
++ }
++ }
++
++ return 0;
++error:
++ snd_printk("I2C error\n");
++ return 1;
++}
++
++#define AUD_NUM_VOLUME_STEPS (40)
++static unsigned char auddec_volume_mapping[AUD_NUM_VOLUME_STEPS] =
++{
++ 0x19, 0xB2, 0xB7, 0xBD, 0xC3, 0xC9, 0xCF, 0xD5,
++ 0xD8, 0xE1, 0xE7, 0xED, 0xF3, 0xF9, 0xFF, 0x00,
++ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
++ 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10,
++ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18
++};
++
++
++/*
++ * Get the audio decoder volume for both channels.
++ * 0 is lowest volume, AUD_NUM_VOLUME_STEPS-1 is the highest volume.
++ */
++
++void cs42l51_vol_get(unsigned char *vol_list)
++{
++ unsigned char reg_data[2];
++ unsigned char i, vol_idx = 0;
++
++ if (cs42l51_reg_read(0x16 + vol_idx, reg_data, 2) < 0) {
++ snd_printd("I2C error\n");
++ snd_printk("Couldn't get volume\n");
++ return;
++ }
++
++ for (; vol_idx < 2; vol_idx++) {
++ /* Look for the index that mapps to this dB value. */
++ for (i = 0; i < AUD_NUM_VOLUME_STEPS; i++) {
++ if (reg_data[vol_idx] == auddec_volume_mapping[i])
++ break;
++ if ((auddec_volume_mapping[i] >
++ auddec_volume_mapping[AUD_NUM_VOLUME_STEPS-1])
++ && (reg_data[vol_idx] > auddec_volume_mapping[i])
++ && (reg_data[vol_idx] < auddec_volume_mapping[i+1]))
++ break;
++ }
++ vol_list[vol_idx] = i;
++ }
++}
++
++/*
++ * Set the audio decoder volume for both channels.
++ * 0 is lowest volume, AUD_NUM_VOLUME_STEPS-1 is the highest volume.
++ */
++void cs42l51_vol_set(unsigned char *vol_list)
++{
++ unsigned int vol_idx;
++
++ for (vol_idx = 0; vol_idx < 2; vol_idx++) {
++ if (vol_list[vol_idx] >= AUD_NUM_VOLUME_STEPS)
++ vol_list[vol_idx] = AUD_NUM_VOLUME_STEPS - 1;
++
++ if (cs42l51_reg_write(0x16 + vol_idx,
++ auddec_volume_mapping[vol_list[vol_idx]]) < 0) {
++ snd_printd("I2C error\n");
++ snd_printk("Couldn't set volume\n");
++ return;
++ }
++ }
++}
+diff --git a/sound/soc/kirkwood/cs42l51.h b/sound/soc/kirkwood/cs42l51.h
+new file mode 100644
+index 0000000..f4e7951
+--- /dev/null
++++ b/sound/soc/kirkwood/cs42l51.h
+@@ -0,0 +1,59 @@
++/*
++ * Audio codec CS42L51 data definition file
++ */
++
++#ifndef _CS42L51_H_
++#define _CS42L51_H_
++
++#define CODEC_CHIP_ID 0x1B
++#define CODEC_REV_ID 0x1
++
++#define CODEC_ID_REG 0x1
++#define CODEC_IF_CTRL_REG 0x4
++#define CODEC_ADC_INPUT_INV_MUTE_REG 0x7
++#define CODEC_DAC_OUTPUT_CTRL_REG 0x8
++#define CODEC_DAC_CTRL_REG 0x9
++#define CODEC_PGAA_VOL_CTRL_REG 0xa
++#define CODEC_TONE_CTRL_REG 0x15
++#define CODEC_VOL_OUTA_CTRL_REG 0x16
++
++/* Set bit # 7 to 1 to get into auto incremental addressing mode */
++#define CODEC_INCR_ADDR 0x80
++
++#define FALSE 0
++#define TRUE 1
++
++/* Selects the digital interface format used for the data in on SDIN. */
++enum dac_digital_if_format {
++ L_JUSTIFIED_UP_TO_24_BIT,
++ I2S_UP_TO_24_BIT,
++ R_JUSTIFIED_UP_TO_24_BIT,
++ R_JUSTIFIED_20_BIT,
++ R_JUSTIFIED_18_BIT,
++ R_JUSTIFIED_16_BIT
++
++};
++
++/* Selects either the I2S or Left-Justified digital interface format for the
++ data on SDOUT. */
++enum adc_mode {
++ LEFT_JUSTIFIED_MODE,
++ I2S_MODE
++};
++
++/* Initialize the Cirrus Logic device */
++int cs42l51_init(int adc_mode, int digital_if_format, int rec,
++ unsigned char i2c_bus_no, unsigned short i2c_add);
++
++/* Function to control output volume (playback) */
++void cs42l51_vol_get(unsigned char *vol_list);
++void cs42l51_vol_set(unsigned char *vol_list);
++
++/* Function to access the Cirrus Logic CODEC registers */
++int cs42l51_reg_read(unsigned char offset, unsigned char *buf, int num);
++int cs42l51_reg_write(unsigned char offset, unsigned char data);
++
++
++void cs42l51_del_i2c_device(void);
++#endif /* _CS42L51_H_ */
++
+diff --git a/sound/soc/kirkwood/kirkwood_audio_hal.c b/sound/soc/kirkwood/kirkwood_audio_hal.c
+new file mode 100644
+index 0000000..28305e3
+--- /dev/null
++++ b/sound/soc/kirkwood/kirkwood_audio_hal.c
+@@ -0,0 +1,821 @@
++/*
++ * Sound driver for Marvell Kirkwood family SOCs
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ */
++
++#include <linux/io.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <linux/spinlock.h>
++#include <linux/mv88fx_audio.h>
++#include "kirkwood_audio_hal.h"
++
++static void mv_audio_init(void __iomem *base);
++static void audio_setup_wins(void __iomem *base,
++ struct mbus_dram_target_info *dram);
++static int set_window_as_per_baseadd(void __iomem *base, unsigned int baseadd,
++ unsigned int audio_offset, int win_num);
++
++/* Clocks Control and Status related*/
++static int mv_audio_dco_ctrl_set(struct mv_audio_freq_data *dcoCtrl,
++ void __iomem *base);
++
++/* Audio PlayBack related*/
++static int mv_audio_playback_control_set(void __iomem *base, unsigned int
++ audio_offset, struct mv_audio_playback_ctrl *ctrl);
++
++/* Audio SPDIF PlayBack related*/
++static void mv_spdif_playback_ctrl_set(void __iomem *base,
++ struct mv_spdif_playback_ctrl *ctrl);
++
++/* Audio I2S PlayBack related*/
++static int mv_i2s_playback_ctrl_set(void __iomem *base,
++ struct mv_i2s_playback_ctrl *ctrl);
++
++/* Audio Recording*/
++static int mv_audio_record_control_set(struct mv_audio_record_ctrl *ctrl,
++ unsigned int audio_offset, void __iomem *base);
++
++/* SPDIF Recording Related*/
++static int spdif_record_tclock_set(void __iomem *base, unsigned int tclk);
++
++/* I2S Recording Related*/
++static int mv_i2s_record_cntrl_set(struct mv_i2s_record_ctrl *ctrl,
++ void __iomem *base);
++
++static inline int audio_burst_bytes_num_get(int burst)
++{
++ switch (burst) {
++ case AUDIO_32BYTE_BURST:
++ return 32;
++ case AUDIO_128BYTE_BURST:
++ return 128;
++ default:
++ return 0xffffffff;
++ }
++}
++
++int mv88fx_snd_hw_init(struct snd_card *card)
++{
++ void __iomem *base = chip->base;
++ struct mv88fx_snd_platform_data *platform_data =
++ card->dev->platform_data;
++
++ if (platform_data->i2s_rec || platform_data->i2s_play)
++ if (codec_init(I2S_MODE, I2S_UP_TO_24_BIT,
++ platform_data->i2s_rec, platform_data->i2c_bus_no,
++ platform_data->i2c_address)) {
++ snd_printk("Initializing CS42L51 failed\n");
++ return 1;
++ }
++
++ writel(0xffffffff, (base + MV_AUDIO_INT_CAUSE_REG));
++ writel(0, (base + MV_AUDIO_INT_MASK_REG));
++ writel(0, (base + MV_AUDIO_SPDIF_REC_INT_CAUSE_MASK_REG));
++
++ mv_audio_init(base);
++
++ audio_setup_wins(base, platform_data->dram);
++
++ /* Disable all playback/recording */
++ writel(readl(base + MV_AUDIO_PLAYBACK_CTRL_REG) &
++ (~(APCR_PLAY_I2S_ENABLE_MASK | APCR_PLAY_SPDIF_ENABLE_MASK)),
++ (base + MV_AUDIO_PLAYBACK_CTRL_REG));
++
++ writel(readl(base + MV_AUDIO_RECORD_CTRL_REG) &
++ (~(ARCR_RECORD_SPDIF_EN_MASK | ARCR_RECORD_I2S_EN_MASK)),
++ (base + MV_AUDIO_RECORD_CTRL_REG));
++
++ if (spdif_record_tclock_set(base, platform_data->tclk)) {
++ snd_printk("Marvell ALSA driver ERR. SPDIF clock set failed\n");
++ return 1;
++ }
++
++ return 0;
++}
++
++int mv88fx_snd_hw_playback_set(struct mv88fx_snd_chip *chip)
++{
++ struct mv88fx_snd_stream *audio_stream = chip->stream[PLAYBACK];
++ struct snd_pcm_substream *substream = audio_stream->substream;
++ struct snd_pcm_runtime *runtime = substream->runtime;
++
++ struct mv_audio_playback_ctrl pcm_play_ctrl;
++ struct mv_i2s_playback_ctrl i2s_play_ctrl;
++ struct mv_spdif_playback_ctrl spdif_play_ctrl;
++ struct mv_audio_freq_data dco_ctrl;
++
++ dco_ctrl.offset = chip->dco_ctrl_offst;
++
++ switch (audio_stream->rate) {
++ case 44100:
++ dco_ctrl.baseFreq = AUDIO_FREQ_44_1KH;
++ break;
++ case 48000:
++ dco_ctrl.baseFreq = AUDIO_FREQ_48KH;
++ break;
++ case 96000:
++ dco_ctrl.baseFreq = AUDIO_FREQ_96KH;
++ break;
++ default:
++ snd_printk("Requested rate %d is not supported\n",
++ runtime->rate); return -1;
++ }
++
++ pcm_play_ctrl.burst = (chip->burst == 128) ? AUDIO_128BYTE_BURST :
++ AUDIO_32BYTE_BURST;
++
++ pcm_play_ctrl.loopBack = chip->loopback;
++
++ if (audio_stream->stereo) {
++ pcm_play_ctrl.monoMode = AUDIO_PLAY_MONO_OFF;
++ } else {
++ switch (audio_stream->mono_mode) {
++ case MONO_LEFT:
++ pcm_play_ctrl.monoMode = AUDIO_PLAY_LEFT_MONO;
++ break;
++ case MONO_RIGHT:
++ pcm_play_ctrl.monoMode = AUDIO_PLAY_RIGHT_MONO;
++ break;
++ case MONO_BOTH:
++ default:
++ pcm_play_ctrl.monoMode = AUDIO_PLAY_BOTH_MONO;
++ break;
++ }
++ }
++
++ if (audio_stream->format == SAMPLE_16IN16) {
++ pcm_play_ctrl.sampleSize = SAMPLE_16BIT;
++ i2s_play_ctrl.sampleSize = SAMPLE_16BIT;
++ } else if (audio_stream->format == SAMPLE_24IN32) {
++ pcm_play_ctrl.sampleSize = SAMPLE_24BIT;
++ i2s_play_ctrl.sampleSize = SAMPLE_24BIT;
++ } else if (audio_stream->format == SAMPLE_32IN32) {
++ pcm_play_ctrl.sampleSize = SAMPLE_32BIT;
++ i2s_play_ctrl.sampleSize = SAMPLE_32BIT;
++ } else {
++ snd_printk("Requested format %d is not supported\n",
++ runtime->format);
++ return -1;
++ }
++
++ /* buffer and period sizes in frame */
++ pcm_play_ctrl.bufferPhyBase = audio_stream->dma_addr;
++ pcm_play_ctrl.bufferSize = audio_stream->dma_size;
++ pcm_play_ctrl.intByteCount = audio_stream->period_size;
++
++ /* I2S playback streem stuff */
++ /*i2s_play_ctrl.sampleSize = pcm_play_ctrl.sampleSize;*/
++ i2s_play_ctrl.justification = I2S_JUSTIFIED;
++ i2s_play_ctrl.sendLastFrame = 0;
++
++ spdif_play_ctrl.nonPcm = FALSE;
++
++ spdif_play_ctrl.validity = chip->ch_stat_valid;
++
++ if (audio_stream->stat_mem) {
++ spdif_play_ctrl.userBitsFromMemory = TRUE;
++ spdif_play_ctrl.validityFromMemory = TRUE;
++ spdif_play_ctrl.blockStartInternally = FALSE;
++ } else {
++ spdif_play_ctrl.userBitsFromMemory = FALSE;
++ spdif_play_ctrl.validityFromMemory = FALSE;
++ spdif_play_ctrl.blockStartInternally = TRUE;
++ }
++
++ /* If this is non-PCM sound, mute I2S channel */
++ spin_lock_irq(&chip->reg_lock);
++
++ if (!(readl(chip->base + MV_AUDIO_PLAYBACK_CTRL_REG) &
++ (APCR_PLAY_I2S_ENABLE_MASK | APCR_PLAY_SPDIF_ENABLE_MASK))) {
++
++ if (mv_audio_dco_ctrl_set(&dco_ctrl, chip->base)) {
++ snd_printk("Failed to initialize DCO clock control.\n");
++ goto error;
++ }
++ }
++
++ if (audio_stream->clock_src == DCO_CLOCK)
++ while ((readl(chip->base + MV_AUDIO_SPCR_DCO_STATUS_REG) &
++ ASDSR_DCO_LOCK_MASK) == 0)
++ cpu_relax();
++ else if (audio_stream->clock_src == SPCR_CLOCK)
++ while ((readl(chip->base + MV_AUDIO_SPCR_DCO_STATUS_REG) &
++ ASDSR_SPCR_LOCK_MASK) == 0)
++ cpu_relax();
++
++ if (mv_audio_playback_control_set(chip->base, chip->audio_offset,
++ &pcm_play_ctrl)) {
++ snd_printk("Failed to initialize PCM playback control.\n");
++ goto error;
++ }
++
++ if (mv_i2s_playback_ctrl_set(chip->base, &i2s_play_ctrl)) {
++ snd_printk("Failed to initialize I2S playback control.\n");
++ goto error;
++ }
++
++ mv_spdif_playback_ctrl_set(chip->base, &spdif_play_ctrl);
++
++ spin_unlock_irq(&chip->reg_lock);
++
++ return 0;
++error:
++ spin_unlock_irq(&chip->reg_lock);
++ return -1;
++}
++
++int mv88fx_snd_hw_capture_set(struct mv88fx_snd_chip *chip)
++{
++ struct mv88fx_snd_stream *audio_stream = chip->stream[CAPTURE];
++ struct snd_pcm_substream *substream = audio_stream->substream;
++ struct snd_pcm_runtime *runtime = substream->runtime;
++
++ struct mv_audio_record_ctrl pcm_rec_ctrl;
++ struct mv_i2s_record_ctrl i2s_rec_ctrl;
++ struct mv_audio_freq_data dco_ctrl;
++
++ dco_ctrl.offset = chip->dco_ctrl_offst;
++
++ switch (audio_stream->rate) {
++ case 44100:
++ dco_ctrl.baseFreq = AUDIO_FREQ_44_1KH;
++ break;
++ case 48000:
++ dco_ctrl.baseFreq = AUDIO_FREQ_48KH;
++ break;
++ case 96000:
++ dco_ctrl.baseFreq = AUDIO_FREQ_96KH;
++ break;
++ default:
++ snd_printk("Requested rate %d is not supported\n",
++ runtime->rate); return -1;
++ }
++
++ pcm_rec_ctrl.burst = (chip->burst == 128) ? AUDIO_128BYTE_BURST :
++ AUDIO_32BYTE_BURST;
++
++ if (audio_stream->format == SAMPLE_16IN16) {
++ pcm_rec_ctrl.sampleSize = SAMPLE_16BIT;
++ } else if (audio_stream->format == SAMPLE_24IN32) {
++ pcm_rec_ctrl.sampleSize = SAMPLE_24BIT;
++ } else if (audio_stream->format == SAMPLE_32IN32) {
++ pcm_rec_ctrl.sampleSize = SAMPLE_32BIT;
++ } else {
++ snd_printk("Requested format %d is not supported\n",
++ runtime->format);
++ return -1;
++ }
++
++ /* If request for tereo record comes on the boards that doesn't
++ * support stereo recording */
++ if ((!chip->stereo) && audio_stream->stereo) {
++ snd_printk("Stereo recording is not supported\n");
++ return -1;
++ }
++
++ pcm_rec_ctrl.mono = (audio_stream->stereo) ? FALSE : TRUE;
++
++ if (pcm_rec_ctrl.mono) {
++ switch (audio_stream->mono_mode) {
++ case MONO_LEFT:
++ pcm_rec_ctrl.monoChannel = AUDIO_REC_LEFT_MONO;
++ break;
++ default:
++ case MONO_RIGHT:
++ pcm_rec_ctrl.monoChannel = AUDIO_REC_RIGHT_MONO;
++ break;
++ }
++
++ } else {
++ pcm_rec_ctrl.monoChannel = AUDIO_REC_LEFT_MONO;
++ }
++
++
++ pcm_rec_ctrl.bufferPhyBase = audio_stream->dma_addr;
++ pcm_rec_ctrl.bufferSize = audio_stream->dma_size;
++
++ pcm_rec_ctrl.intByteCount = audio_stream->period_size;
++
++ /* I2S record streem stuff */
++ i2s_rec_ctrl