Commit 1fab79b8 authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'for-2.6.36' of...

Merge branch 'for-2.6.36' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound-2.6 into topic/asoc
parents c876ae3e 37a5ddf4
......@@ -25,6 +25,7 @@
#include <asm/mach/time.h>
#include <mach/kirkwood.h>
#include <mach/bridge-regs.h>
#include <plat/audio.h>
#include <plat/cache-feroceon-l2.h>
#include <plat/ehci-orion.h>
#include <plat/mvsdio.h>
......@@ -864,6 +865,42 @@ struct sys_timer kirkwood_timer = {
.init = kirkwood_timer_init,
};
/*****************************************************************************
* Audio
****************************************************************************/
static struct resource kirkwood_i2s_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 struct kirkwood_asoc_platform_data kirkwood_i2s_data = {
.dram = &kirkwood_mbus_dram_info,
.burst = 128,
};
static struct platform_device kirkwood_i2s_device = {
.name = "kirkwood-i2s",
.id = -1,
.num_resources = ARRAY_SIZE(kirkwood_i2s_resources),
.resource = kirkwood_i2s_resources,
.dev = {
.platform_data = &kirkwood_i2s_data,
},
};
void __init kirkwood_audio_init(void)
{
kirkwood_clk_ctrl |= CGC_AUDIO;
platform_device_register(&kirkwood_i2s_device);
}
/*****************************************************************************
* General
......@@ -923,6 +960,7 @@ void __init kirkwood_init(void)
kirkwood_spi_plat_data.tclk = kirkwood_tclk;
kirkwood_uart0_data[0].uartclk = kirkwood_tclk;
kirkwood_uart1_data[0].uartclk = kirkwood_tclk;
kirkwood_i2s_data.tclk = kirkwood_tclk;
/*
* Disable propagation of mbus errors to the CPU local bus,
......
......@@ -17,6 +17,7 @@ struct mv_sata_platform_data;
struct mvsdio_platform_data;
struct mtd_partition;
struct mtd_info;
struct kirkwood_asoc_platform_data;
/*
* Basic Kirkwood init functions used early by machine-setup.
......@@ -43,6 +44,7 @@ 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_nand_init_rnb(struct mtd_partition *parts, int nr_parts, int (*dev_ready)(struct mtd_info *));
void kirkwood_audio_init(void);
extern int kirkwood_tclk;
extern struct sys_timer kirkwood_timer;
......
......@@ -96,6 +96,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.
*/
......
......@@ -15,6 +15,7 @@
#include <linux/mtd/partitions.h>
#include <linux/ata_platform.h>
#include <linux/mv643xx_eth.h>
#include <linux/i2c.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <mach/kirkwood.h>
......@@ -60,6 +61,12 @@ static unsigned int openrd_mpp_config[] __initdata = {
0
};
static struct i2c_board_info i2c_board_info[] __initdata = {
{
I2C_BOARD_INFO("cs42l51", 0x4a),
},
};
static void __init openrd_init(void)
{
/*
......@@ -80,6 +87,12 @@ static void __init openrd_init(void)
kirkwood_sdio_init(&openrd_mvsdio_data);
kirkwood_i2c_init();
if (machine_is_openrd_client()) {
i2c_register_board_info(0, i2c_board_info,
ARRAY_SIZE(i2c_board_info));
kirkwood_audio_init();
}
}
static int __init openrd_pci_init(void)
......
#ifndef __PLAT_AUDIO_H
#define __PLAT_AUDIO_H
#include <linux/mbus.h>
struct kirkwood_asoc_platform_data {
u32 tclk;
struct mbus_dram_target_info *dram;
int burst;
};
#endif
......@@ -273,6 +273,8 @@
#define SND_SOC_DAPM_POST_PMD 0x8 /* after widget power down */
#define SND_SOC_DAPM_PRE_REG 0x10 /* before audio path setup */
#define SND_SOC_DAPM_POST_REG 0x20 /* after audio path setup */
#define SND_SOC_DAPM_PRE_POST_PMD \
(SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD)
/* convenience event type detection */
#define SND_SOC_DAPM_EVENT_ON(e) \
......
......@@ -170,6 +170,21 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&xenum }
#define SOC_DOUBLE_R_SX_TLV(xname, xreg_left, xreg_right, xshift,\
xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_2r_sx, \
.get = snd_soc_get_volsw_2r_sx, \
.put = snd_soc_put_volsw_2r_sx, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg_left, \
.rreg = xreg_right, .shift = xshift, \
.min = xmin, .max = xmax} }
/*
* Simplified versions of above macros, declaring a struct and calculating
* ARRAY_SIZE internally
......@@ -329,6 +344,12 @@ int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max);
int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
/**
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
......
......@@ -30,7 +30,9 @@ source "sound/soc/blackfin/Kconfig"
source "sound/soc/davinci/Kconfig"
source "sound/soc/fsl/Kconfig"
source "sound/soc/imx/Kconfig"
source "sound/soc/nuc900/Kconfig"
source "sound/soc/omap/Kconfig"
source "sound/soc/kirkwood/Kconfig"
source "sound/soc/pxa/Kconfig"
source "sound/soc/s3c24xx/Kconfig"
source "sound/soc/s6000/Kconfig"
......
......@@ -8,7 +8,9 @@ obj-$(CONFIG_SND_SOC) += blackfin/
obj-$(CONFIG_SND_SOC) += davinci/
obj-$(CONFIG_SND_SOC) += fsl/
obj-$(CONFIG_SND_SOC) += imx/
obj-$(CONFIG_SND_SOC) += nuc900/
obj-$(CONFIG_SND_SOC) += omap/
obj-$(CONFIG_SND_SOC) += kirkwood/
obj-$(CONFIG_SND_SOC) += pxa/
obj-$(CONFIG_SND_SOC) += s3c24xx/
obj-$(CONFIG_SND_SOC) += s6000/
......
......@@ -22,6 +22,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4642 if I2C
select SND_SOC_AK4671 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS42L51 if I2C
select SND_SOC_CS4270 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_DA7210 if I2C
......@@ -120,6 +121,9 @@ config SND_SOC_AK4671
config SND_SOC_CQ0093VC
tristate
config SND_SOC_CS42L51
tristate
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
......
......@@ -9,6 +9,7 @@ snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
......@@ -74,6 +75,7 @@ obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
......
......@@ -24,6 +24,7 @@
/* codec private data */
struct ad193x_priv {
unsigned int sysclk;
struct snd_soc_codec codec;
u8 reg_cache[AD193X_NUM_REGS];
};
......@@ -251,15 +252,32 @@ static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0;
}
static int ad193x_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
switch (freq) {
case 12288000:
case 18432000:
case 24576000:
case 36864000:
ad193x->sysclk = freq;
return 0;
}
return -EINVAL;
}
static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
int word_len = 0, reg = 0;
int word_len = 0, reg = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
/* bit size */
switch (params_format(params)) {
......@@ -275,6 +293,25 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
break;
}
switch (ad193x->sysclk) {
case 12288000:
master_rate = AD193X_PLL_INPUT_256;
break;
case 18432000:
master_rate = AD193X_PLL_INPUT_384;
break;
case 24576000:
master_rate = AD193X_PLL_INPUT_512;
break;
case 36864000:
master_rate = AD193X_PLL_INPUT_768;
break;
}
reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0);
reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate;
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
......@@ -348,6 +385,7 @@ static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
/* pll input: mclki/xi */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
ad193x->sysclk = 12288000;
ret = snd_soc_register_codec(codec);
if (ret != 0) {
......@@ -383,6 +421,7 @@ static struct snd_soc_dai_ops ad193x_dai_ops = {
.hw_params = ad193x_hw_params,
.digital_mute = ad193x_mute,
.set_tdm_slot = ad193x_set_tdm_slot,
.set_sysclk = ad193x_set_dai_sysclk,
.set_fmt = ad193x_set_dai_fmt,
};
......
......@@ -11,6 +11,11 @@
#define AD193X_PLL_CLK_CTRL0 0x800
#define AD193X_PLL_POWERDOWN 0x01
#define AD193X_PLL_INPUT_MASK (~0x6)
#define AD193X_PLL_INPUT_256 (0 << 1)
#define AD193X_PLL_INPUT_384 (1 << 1)
#define AD193X_PLL_INPUT_512 (2 << 1)
#define AD193X_PLL_INPUT_768 (3 << 1)
#define AD193X_PLL_CLK_CTRL1 0x801
#define AD193X_DAC_CTRL0 0x802
#define AD193X_DAC_POWERDOWN 0x01
......
This diff is collapsed.
/*
* cs42l51.h
*
* ASoC Driver for Cirrus Logic CS42L51 codecs
*
* Copyright (c) 2010 Arnaud Patard <apatard@mandriva.com>
*
* 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.
*/
#ifndef _CS42L51_H
#define _CS42L51_H
#define CS42L51_CHIP_ID 0x1B
#define CS42L51_CHIP_REV_A 0x00
#define CS42L51_CHIP_REV_B 0x01
#define CS42L51_CHIP_REV_ID 0x01
#define CS42L51_MK_CHIP_REV(a, b) ((a)<<3|(b))
#define CS42L51_POWER_CTL1 0x02
#define CS42L51_POWER_CTL1_PDN_DACB (1<<6)
#define CS42L51_POWER_CTL1_PDN_DACA (1<<5)
#define CS42L51_POWER_CTL1_PDN_PGAB (1<<4)
#define CS42L51_POWER_CTL1_PDN_PGAA (1<<3)
#define CS42L51_POWER_CTL1_PDN_ADCB (1<<2)
#define CS42L51_POWER_CTL1_PDN_ADCA (1<<1)
#define CS42L51_POWER_CTL1_PDN (1<<0)
#define CS42L51_MIC_POWER_CTL 0x03
#define CS42L51_MIC_POWER_CTL_AUTO (1<<7)
#define CS42L51_MIC_POWER_CTL_SPEED(x) (((x)&3)<<5)
#define CS42L51_QSM_MODE 3
#define CS42L51_HSM_MODE 2
#define CS42L51_SSM_MODE 1
#define CS42L51_DSM_MODE 0
#define CS42L51_MIC_POWER_CTL_3ST_SP (1<<4)
#define CS42L51_MIC_POWER_CTL_PDN_MICB (1<<3)
#define CS42L51_MIC_POWER_CTL_PDN_MICA (1<<2)
#define CS42L51_MIC_POWER_CTL_PDN_BIAS (1<<1)
#define CS42L51_MIC_POWER_CTL_MCLK_DIV2 (1<<0)
#define CS42L51_INTF_CTL 0x04
#define CS42L51_INTF_CTL_LOOPBACK (1<<7)
#define CS42L51_INTF_CTL_MASTER (1<<6)
#define CS42L51_INTF_CTL_DAC_FORMAT(x) (((x)&7)<<3)
#define CS42L51_DAC_DIF_LJ24 0x00
#define CS42L51_DAC_DIF_I2S 0x01
#define CS42L51_DAC_DIF_RJ24 0x02
#define CS42L51_DAC_DIF_RJ20 0x03
#define CS42L51_DAC_DIF_RJ18 0x04
#define CS42L51_DAC_DIF_RJ16 0x05
#define CS42L51_INTF_CTL_ADC_I2S (1<<2)
#define CS42L51_INTF_CTL_DIGMIX (1<<1)
#define CS42L51_INTF_CTL_MICMIX (1<<0)
#define CS42L51_MIC_CTL 0x05
#define CS42L51_MIC_CTL_ADC_SNGVOL (1<<7)
#define CS42L51_MIC_CTL_ADCD_DBOOST (1<<6)
#define CS42L51_MIC_CTL_ADCA_DBOOST (1<<5)
#define CS42L51_MIC_CTL_MICBIAS_SEL (1<<4)
#define CS42L51_MIC_CTL_MICBIAS_LVL(x) (((x)&3)<<2)
#define CS42L51_MIC_CTL_MICB_BOOST (1<<1)
#define CS42L51_MIC_CTL_MICA_BOOST (1<<0)
#define CS42L51_ADC_CTL 0x06
#define CS42L51_ADC_CTL_ADCB_HPFEN (1<<7)
#define CS42L51_ADC_CTL_ADCB_HPFRZ (1<<6)
#define CS42L51_ADC_CTL_ADCA_HPFEN (1<<5)
#define CS42L51_ADC_CTL_ADCA_HPFRZ (1<<4)
#define CS42L51_ADC_CTL_SOFTB (1<<3)
#define CS42L51_ADC_CTL_ZCROSSB (1<<2)
#define CS42L51_ADC_CTL_SOFTA (1<<1)
#define CS42L51_ADC_CTL_ZCROSSA (1<<0)
#define CS42L51_ADC_INPUT 0x07
#define CS42L51_ADC_INPUT_AINB_MUX(x) (((x)&3)<<6)
#define CS42L51_ADC_INPUT_AINA_MUX(x) (((x)&3)<<4)
#define CS42L51_ADC_INPUT_INV_ADCB (1<<3)
#define CS42L51_ADC_INPUT_INV_ADCA (1<<2)
#define CS42L51_ADC_INPUT_ADCB_MUTE (1<<1)
#define CS42L51_ADC_INPUT_ADCA_MUTE (1<<0)
#define CS42L51_DAC_OUT_CTL 0x08
#define CS42L51_DAC_OUT_CTL_HP_GAIN(x) (((x)&7)<<5)
#define CS42L51_DAC_OUT_CTL_DAC_SNGVOL (1<<4)
#define CS42L51_DAC_OUT_CTL_INV_PCMB (1<<3)
#define CS42L51_DAC_OUT_CTL_INV_PCMA (1<<2)
#define CS42L51_DAC_OUT_CTL_DACB_MUTE (1<<1)
#define CS42L51_DAC_OUT_CTL_DACA_MUTE (1<<0)
#define CS42L51_DAC_CTL 0x09
#define CS42L51_DAC_CTL_DATA_SEL(x) (((x)&3)<<6)
#define CS42L51_DAC_CTL_FREEZE (1<<5)
#define CS42L51_DAC_CTL_DEEMPH (1<<3)
#define CS42L51_DAC_CTL_AMUTE (1<<2)
#define CS42L51_DAC_CTL_DACSZ(x) (((x)&3)<<0)
#define CS42L51_ALC_PGA_CTL 0x0A
#define CS42L51_ALC_PGB_CTL 0x0B
#define CS42L51_ALC_PGX_ALCX_SRDIS (1<<7)
#define CS42L51_ALC_PGX_ALCX_ZCDIS (1<<6)
#define CS42L51_ALC_PGX_PGX_VOL(x) (((x)&0x1f)<<0)
#define CS42L51_ADCA_ATT 0x0C
#define CS42L51_ADCB_ATT 0x0D
#define CS42L51_ADCA_VOL 0x0E
#define CS42L51_ADCB_VOL 0x0F
#define CS42L51_PCMA_VOL 0x10
#define CS42L51_PCMB_VOL 0x11
#define CS42L51_MIX_MUTE_ADCMIX (1<<7)
#define CS42L51_MIX_VOLUME(x) (((x)&0x7f)<<0)
#define CS42L51_BEEP_FREQ 0x12
#define CS42L51_BEEP_VOL 0x13
#define CS42L51_BEEP_CONF 0x14
#define CS42L51_TONE_CTL 0x15
#define CS42L51_TONE_CTL_TREB(x) (((x)&0xf)<<4)
#define CS42L51_TONE_CTL_BASS(x) (((x)&0xf)<<0)
#define CS42L51_AOUTA_VOL 0x16
#define CS42L51_AOUTB_VOL 0x17
#define CS42L51_PCM_MIXER 0x18
#define CS42L51_LIMIT_THRES_DIS 0x19
#define CS42L51_LIMIT_REL 0x1A
#define CS42L51_LIMIT_ATT 0x1B
#define CS42L51_ALC_EN 0x1C
#define CS42L51_ALC_REL 0x1D
#define CS42L51_ALC_THRES 0x1E
#define CS42L51_NOISE_CONF 0x1F
#define CS42L51_STATUS 0x20
#define CS42L51_STATUS_SP_CLKERR (1<<6)
#define CS42L51_STATUS_SPEA_OVFL (1<<5)
#define CS42L51_STATUS_SPEB_OVFL (1<<4)
#define CS42L51_STATUS_PCMA_OVFL (1<<3)
#define CS42L51_STATUS_PCMB_OVFL (1<<2)
#define CS42L51_STATUS_ADCA_OVFL (1<<1)
#define CS42L51_STATUS_ADCB_OVFL (1<<0)
#define CS42L51_CHARGE_FREQ 0x21
#define CS42L51_FIRSTREG 0x01
/*
* Hack: with register 0x21, it makes 33 registers. Looks like someone in the
* i2c layer doesn't like i2c smbus block read of 33 regs. Workaround by using
* 32 regs
*/
#define CS42L51_LASTREG 0x20
#define CS42L51_NUMREGS (CS42L51_LASTREG - CS42L51_FIRSTREG + 1)
extern struct snd_soc_dai cs42l51_dai;
extern struct snd_soc_codec_device soc_codec_device_cs42l51;
#endif
......@@ -16,8 +16,10 @@
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/pcm.h>
#include <sound/initval.h>
#include "spdif_transciever.h"
......@@ -26,6 +28,48 @@ MODULE_LICENSE("GPL");
#define STUB_RATES SNDRV_PCM_RATE_8000_96000
#define STUB_FORMATS SNDRV_PCM_FMTBIT_S16_LE
static struct snd_soc_codec *spdif_dit_codec;
static int spdif_dit_codec_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
int ret;
if (spdif_dit_codec == NULL) {
dev_err(&pdev->dev, "Codec device not registered\n");
return -ENODEV;
}
socdev->card->codec = spdif_dit_codec;
codec = spdif_dit_codec;
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
goto err_create_pcms;
}
return 0;
err_create_pcms:
return ret;
}
static int spdif_dit_codec_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
snd_soc_free_pcms(socdev);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_spdif_dit = {
.probe = spdif_dit_codec_probe,
.remove = spdif_dit_codec_remove,
}; EXPORT_SYMBOL_GPL(soc_codec_dev_spdif_dit);
struct snd_soc_dai dit_stub_dai = {
.name = "DIT",
.playback = {
......@@ -40,13 +84,61 @@ EXPORT_SYMBOL_GPL(dit_stub_dai);
static int spdif_dit_probe(struct platform_device *pdev)
{
struct snd_soc_codec *codec;
int ret;
if (spdif_dit_codec) {
dev_err(&pdev->dev, "Another Codec is registered\n");
ret = -EINVAL;
goto err_reg_codec;
}
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;
codec->dev = &pdev->dev;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->name = "spdif-dit";
codec->owner = THIS_MODULE;
codec->dai = &dit_stub_dai;
codec->num_dai = 1;
spdif_dit_codec = codec;
ret = snd_soc_register_codec(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
goto err_reg_codec;
}
dit_stub_dai.dev = &pdev->dev;
return snd_soc_register_dai(&dit_stub_dai);
ret = snd_soc_register_dai(&dit_stub_dai);
if (ret < 0) {
dev_err(codec->dev, "Failed to register dai: %d\n", ret);
goto err_reg_dai;
}
return 0;
err_reg_dai:
snd_soc_unregister_codec(codec);
err_reg_codec:
kfree(spdif_dit_codec);
return ret;
}
static int spdif_dit_remove(struct platform_device *pdev)
{
snd_soc_unregister_dai(&dit_stub_dai);
snd_soc_unregister_codec(spdif_dit_codec);
kfree(spdif_dit_codec);
spdif_dit_codec = NULL;
return 0;
}
......
......@@ -12,6 +12,7 @@
#ifndef CODEC_STUBS_H
#define CODEC_STUBS_H
extern struct snd_soc_codec_device soc_codec_dev_spdif_dit;
extern struct snd_soc_dai dit_stub_dai;
#endif /* CODEC_STUBS_H */
......@@ -30,8 +30,6 @@
#include "wm8990.h"
#define WM8990_VERSION "0.2"
/* codec private data */
struct wm8990_priv {
unsigned int sysclk;
......@@ -1511,8 +1509,6 @@ static int wm8990_probe(struct platform_device *pdev)
struct wm8990_priv *wm8990;
int ret;
pr_info("WM8990 Audio Codec %s\n", WM8990_VERSION);
setup = socdev->codec_data;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
......
config SND_KIRKWOOD_SOC
tristate "SoC Audio for the Marvell Kirkwood chip"
depends on ARCH_KIRKWOOD
help
Say Y or M if you want to add support for codecs attached to
the Kirkwood I2S interface. You will also need to select the
audio interfaces to support below.
config SND_KIRKWOOD_SOC_I2S
tristate
config SND_KIRKWOOD_SOC_OPENRD
tristate "SoC Audio support for Kirkwood Openrd Client"
depends on SND_KIRKWOOD_SOC && MACH_OPENRD_CLIENT
select SND_KIRKWOOD_SOC_I2S
select SND_SOC_CS42L51
help
Say Y if you want to add support for SoC audio on
Openrd Client.
snd-soc-kirkwood-objs := kirkwood-dma.o
snd-soc-kirkwood-i2s-objs := kirkwood-i2s.o
obj-$(CONFIG_SND_KIRKWOOD_SOC) += snd-soc-kirkwood.o
obj-$(CONFIG_SND_KIRKWOOD_SOC_I2S) += snd-soc-kirkwood-i2s.o
snd-soc-openrd-objs := kirkwood-openrd.o
obj-$(CONFIG_SND_KIRKWOOD_SOC_OPENRD) += snd-soc-openrd.o
This diff is collapsed.
/*
* kirkwood-dma.h
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
*
* 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.
*/
#ifndef _KIRKWOOD_DMA_H
#define _KIRKWOOD_DMA_H
extern struct snd_soc_platform kirkwood_soc_platform;
#endif
This diff is collapsed.
/*
* kirkwood-i2s.h
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
*
* 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.
*/
#ifndef _KIRKWOOD_I2S_H
#define _KIRKWOOD_I2S_H
extern struct snd_soc_dai kirkwood_i2s_dai;
#endif
/*
* kirkwood-openrd.c
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
*
* 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.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <mach/kirkwood.h>
#include <plat/audio.h>
#include <asm/mach-types.h>
#include "kirkwood-i2s.h"
#include "kirkwood-dma.h"
#include "../codecs/cs42l51.h"
static int openrd_client_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
int ret;
unsigned int freq, fmt;
fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS;
ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
if (ret < 0)
return ret;
ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret < 0)
return ret;
switch (params_rate(params)) {
default:
case 44100:
freq = 11289600;
break;
case 48000:
freq = 12288000;
break;
case 96000:
freq = 24576000;
break;
}
return snd_soc_dai_set_sysclk(codec_dai, 0, freq, SND_SOC_CLOCK_IN);
}
static struct snd_soc_ops openrd_client_ops = {
.hw_params = openrd_client_hw_params,
};
static struct snd_soc_dai_link openrd_client_dai[] = {
{
.name = "CS42L51",
.stream_name = "CS42L51 HiFi",
.cpu_dai = &kirkwood_i2s_dai,
.codec_dai = &cs42l51_dai,
.ops = &openrd_client_ops,
},
};
static struct snd_soc_card openrd_client = {
.name = "OpenRD Client",
.platform = &kirkwood_soc_platform,
.dai_link = openrd_client_dai,
.num_links = ARRAY_SIZE(openrd_client_dai),
};
static struct snd_soc_device openrd_client_snd_devdata = {
.card = &openrd_client,
.codec_dev = &soc_codec_device_cs42l51,
};
static struct platform_device *openrd_client_snd_device;
static int __init openrd_client_init(void)
{
int ret;
if (!machine_is_openrd_client())
return 0;
openrd_client_snd_device = platform_device_alloc("soc-audio", -1);
if (!openrd_client_snd_device)
return -ENOMEM;
platform_set_drvdata(openrd_client_snd_device,
&openrd_client_snd_devdata);
openrd_client_snd_devdata.dev = &openrd_client_snd_device->dev;
ret = platform_device_add(openrd_client_snd_device);
if (ret) {
printk(KERN_ERR "%s: platform_device_add failed\n", __func__);
platform_device_put(openrd_client_snd_device);
}
return ret;
}
static void __exit openrd_client_exit(void)
{
platform_device_unregister(openrd_client_snd_device);
}
module_init(openrd_client_init);
module_exit(openrd_client_exit);
/* Module information */
MODULE_AUTHOR("Arnaud Patard <apatard@mandriva.com>");
MODULE_DESCRIPTION("ALSA SoC OpenRD Client");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:soc-audio");
/*
* kirkwood.h
*
* (c) 2010 Arnaud Patard <apatard@mandriva.com>
*
* 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.
*/
#ifndef _KIRKWOOD_AUDIO_H
#define _KIRKWOOD_AUDIO_H
#define KIRKWOOD_RECORD_WIN 0
#define KIRKWOOD_PLAYBACK_WIN 1
#define KIRKWOOD_MAX_AUDIO_WIN 2
#define KIRKWOOD_AUDIO_WIN_BASE_REG(win) (0xA00 + ((win)<<3))
#define KIRKWOOD_AUDIO_WIN_CTRL_REG(win) (0xA04 + ((win)<<3))
#define KIRKWOOD_RECCTL 0x1000
#define KIRKWOOD_RECCTL_SPDIF_EN (1<<11)
#define KIRKWOOD_RECCTL_I2S_EN (1<<10)
#define KIRKWOOD_RECCTL_PAUSE (1<<9)
#define KIRKWOOD_RECCTL_MUTE (1<<8)
#define KIRKWOOD_RECCTL_BURST_MASK (3<<5)
#define KIRKWOOD_RECCTL_BURST_128 (2<<5)
#define KIRKWOOD_RECCTL_BURST_32 (1<<5)
#define KIRKWOOD_RECCTL_MONO (1<<4)
#define KIRKWOOD_RECCTL_MONO_CHAN_RIGHT (1<<3)
#define KIRKWOOD_RECCTL_MONO_CHAN_LEFT (0<<3)
#define KIRKWOOD_RECCTL_SIZE_MASK (7<<0)
#define KIRKWOOD_RECCTL_SIZE_16 (7<<0)
#define KIRKWOOD_RECCTL_SIZE_16_C (3<<0)
#define KIRKWOOD_RECCTL_SIZE_20 (2<<0)
#define KIRKWOOD_RECCTL_SIZE_24 (1<<0)
#define KIRKWOOD_RECCTL_SIZE_32 (0<<0)
#define KIRKWOOD_REC_BUF_ADDR 0x1004
#define KIRKWOOD_REC_BUF_SIZE 0x1008
#define KIRKWOOD_REC_BYTE_COUNT 0x100C
#define KIRKWOOD_PLAYCTL 0x1100
#define KIRKWOOD_PLAYCTL_PLAY_BUSY (1<<16)
#define KIRKWOOD_PLAYCTL_BURST_MASK (3<<11)
#define KIRKWOOD_PLAYCTL_BURST_128 (2<<11)
#define KIRKWOOD_PLAYCTL_BURST_32 (1<<11)
#define KIRKWOOD_PLAYCTL_PAUSE (1<<9)
#define KIRKWOOD_PLAYCTL_SPDIF_MUTE (1<<8)
#define KIRKWOOD_PLAYCTL_I2S_MUTE (1<<7)
#define KIRKWOOD_PLAYCTL_SPDIF_EN (1<<4)
#define KIRKWOOD_PLAYCTL_I2S_EN (1<<3)
#define KIRKWOOD_PLAYCTL_SIZE_MASK (7<<0)
#define KIRKWOOD_PLAYCTL_SIZE_16 (7<<0)
#define KIRKWOOD_PLAYCTL_SIZE_16_C (3<<0)
#define KIRKWOOD_PLAYCTL_SIZE_20 (2<<0)
#define KIRKWOOD_PLAYCTL_SIZE_24 (1<<0)
#define KIRKWOOD_PLAYCTL_SIZE_32 (0<<0)
#define KIRKWOOD_PLAY_BUF_ADDR 0x1104
#define KIRKWOOD_PLAY_BUF_SIZE 0x1108
#define KIRKWOOD_PLAY_BYTE_COUNT 0x110C
#define KIRKWOOD_DCO_CTL 0x1204
#define KIRKWOOD_DCO_CTL_OFFSET_MASK (0xFFF<<2)
#define KIRKWOOD_DCO_CTL_OFFSET_0 (0x800<<2)
#define KIRKWOOD_DCO_CTL_FREQ_MASK (3<<0)
#define KIRKWOOD_DCO_CTL_FREQ_11 (0<<0)
#define KIRKWOOD_DCO_CTL_FREQ_12 (1<<0)
#define KIRKWOOD_DCO_CTL_FREQ_24 (2<<0)
#define KIRKWOOD_DCO_SPCR_STATUS 0x120c
#define KIRKWOOD_DCO_SPCR_STATUS_DCO_LOCK (1<<16)
#define KIRKWOOD_ERR_CAUSE 0x1300
#define KIRKWOOD_ERR_MASK 0x1304
#define KIRKWOOD_INT_CAUSE 0x1308
#define KIRKWOOD_INT_MASK 0x130C
#define KIRKWOOD_INT_CAUSE_PLAY_BYTES (1<<14)
#define KIRKWOOD_INT_CAUSE_REC_BYTES (1<<13)
#define KIRKWOOD_INT_CAUSE_DMA_PLAY_END (1<<7)
#define KIRKWOOD_INT_CAUSE_DMA_PLAY_3Q (1<<6)
#define KIRKWOOD_INT_CAUSE_DMA_PLAY_HALF (1<<5)
#define KIRKWOOD_INT_CAUSE_DMA_PLAY_1Q (1<<4)
#define KIRKWOOD_INT_CAUSE_DMA_REC_END (1<<3)
#define KIRKWOOD_INT_CAUSE_DMA_REC_3Q (1<<2)
#define KIRKWOOD_INT_CAUSE_DMA_REC_HALF (1<<1)
#define KIRKWOOD_INT_CAUSE_DMA_REC_1Q (1<<0)
#define KIRKWOOD_REC_BYTE_INT_COUNT 0x1310
#define KIRKWOOD_PLAY_BYTE_INT_COUNT 0x1314
#define KIRKWOOD_BYTE_INT_COUNT_MASK 0xffffff
#define KIRKWOOD_I2S_PLAYCTL 0x2508
#define KIRKWOOD_I2S_RECCTL 0x2408
#define KIRKWOOD_I2S_CTL_JUST_MASK (0xf<<26)
#define KIRKWOOD_I2S_CTL_LJ (0<<26)
#define KIRKWOOD_I2S_CTL_I2S (5<<26)
#define KIRKWOOD_I2S_CTL_RJ (8<<26)
#define KIRKWOOD_I2S_CTL_SIZE_MASK (3<<30)
#define KIRKWOOD_I2S_CTL_SIZE_16 (3<<30)
#define KIRKWOOD_I2S_CTL_SIZE_20 (2<<30)
#define KIRKWOOD_I2S_CTL_SIZE_24 (1<<30)
#define KIRKWOOD_I2S_CTL_SIZE_32 (0<<30)
#define KIRKWOOD_AUDIO_BUF_MAX (16*1024*1024)
/* Theses values come from the marvell alsa driver */
/* need to find where they come from */
#define KIRKWOOD_SND_MIN_PERIODS 8
#define KIRKWOOD_SND_MAX_PERIODS 16
#define KIRKWOOD_SND_MIN_PERIOD_BYTES 0x4000
#define KIRKWOOD_SND_MAX_PERIOD_BYTES 0x4000
struct kirkwood_dma_data {
struct resource *mem;
void __iomem *io;
int irq;
int burst;
struct mbus_dram_target_info *dram;
};
#endif
##
## NUC900 series AC97 API
##
config SND_SOC_NUC900
tristate "SoC Audio for NUC900 series"
depends on ARCH_W90X900
help
This option enables support for AC97 mode on the NUC900 SoC.
config SND_SOC_NUC900_AC97
tristate
select AC97_BUS
select SND_AC97_CODEC
select SND_SOC_AC97_BUS
##
## Boards
##
config SND_SOC_NUC900EVB
tristate "NUC900 AC97 support for demo board"
depends on SND_SOC_NUC900
select SND_SOC_NUC900_AC97
select SND_SOC_AC97_CODEC
help
Select this option to enable audio (AC97) on the
NUC900 demoboard.
# NUC900 series audio
snd-soc-nuc900-pcm-objs := nuc900-pcm.o
snd-soc-nuc900-ac97-objs := nuc900-ac97.o
obj-$(CONFIG_SND_SOC_NUC900) += snd-soc-nuc900-pcm.o
obj-$(CONFIG_SND_SOC_NUC900_AC97) += snd-soc-nuc900-ac97.o
# Boards
snd-soc-nuc900-audio-objs := nuc900-audio.o
obj-$(CONFIG_SND_SOC_NUC900EVB) += snd-soc-nuc900-audio.o
This diff is collapsed.
/*
* Copyright (c) 2010 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*
* 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;version 2 of the License.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "../codecs/ac97.h"
#include "nuc900-auido.h"
static struct snd_soc_dai_link nuc900evb_ac97_dai = {
.name = "AC97",
.stream_name = "AC97 HiFi",
.cpu_dai = &nuc900_ac97_dai,
.codec_dai = &ac97_dai,
};
static struct snd_soc_card nuc900evb_audio_machine = {
.name = "NUC900EVB_AC97",
.dai_link = &nuc900evb_ac97_dai,
.num_links = 1,
.platform = &nuc900_soc_platform,
};
static struct snd_soc_device nuc900evb_ac97_devdata = {
.card = &nuc900evb_audio_machine,
.codec_dev = &soc_codec_dev_ac97,
};
static struct platform_device *nuc900evb_asoc_dev;
static int __init nuc900evb_audio_init(void)
{
int ret;
ret = -ENOMEM;
nuc900evb_asoc_dev = platform_device_alloc("soc-audio", -1);
if (!nuc900evb_asoc_dev)
goto out;
/* nuc900 board audio device */
platform_set_drvdata(nuc900evb_asoc_dev, &nuc900evb_ac97_devdata);
nuc900evb_ac97_devdata.dev = &nuc900evb_asoc_dev->dev;
ret = platform_device_add(nuc900evb_asoc_dev);
if (ret) {
platform_device_put(nuc900evb_asoc_dev);
nuc900evb_asoc_dev = NULL;
}
out:
return ret;
}
static void __exit nuc900evb_audio_exit(void)
{
platform_device_unregister(nuc900evb_asoc_dev);
}
module_init(nuc900evb_audio_init);
module_exit(nuc900evb_audio_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("NUC900 Series ASoC audio support");
MODULE_AUTHOR("Wan ZongShun");
/*
* Copyright (c) 2010 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*
* 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;version 2 of the License.
*
*/
#ifndef _NUC900_AUDIO_H
#define _NUC900_AUDIO_H
#include <linux/io.h>
/* Audio Control Registers */
#define ACTL_CON 0x00
#define ACTL_RESET 0x04
#define ACTL_RDSTB 0x08
#define ACTL_RDST_LENGTH 0x0C
#define ACTL_RDSTC 0x10
#define ACTL_RSR 0x14
#define ACTL_PDSTB 0x18
#define ACTL_PDST_LENGTH 0x1C
#define ACTL_PDSTC 0x20
#define ACTL_PSR 0x24
#define ACTL_IISCON 0x28
#define ACTL_ACCON 0x2C
#define ACTL_ACOS0 0x30
#define ACTL_ACOS1 0x34
#define ACTL_ACOS2 0x38
#define ACTL_ACIS0 0x3C
#define ACTL_ACIS1 0x40
#define ACTL_ACIS2 0x44
#define ACTL_COUNTER 0x48
/* bit definition of REG_ACTL_CON register */
#define R_DMA_IRQ 0x1000
#define T_DMA_IRQ 0x0800
#define IIS_AC_PIN_SEL 0x0100
#define FIFO_TH 0x0080
#define ADC_EN 0x0010
#define M80_EN 0x0008
#define ACLINK_EN 0x0004
#define IIS_EN 0x0002
/* bit definition of REG_ACTL_RESET register */
#define W5691_PLAY 0x20000
#define ACTL_RESET_BIT 0x10000
#define RECORD_RIGHT_CHNNEL 0x08000
#define RECORD_LEFT_CHNNEL 0x04000
#define PLAY_RIGHT_CHNNEL 0x02000
#define PLAY_LEFT_CHNNEL 0x01000
#define DAC_PLAY 0x00800
#define ADC_RECORD 0x00400
#define M80_PLAY 0x00200
#define AC_RECORD 0x00100
#define AC_PLAY 0x00080
#define IIS_RECORD 0x00040
#define IIS_PLAY 0x00020
#define DAC_RESET 0x00010
#define ADC_RESET 0x00008
#define M80_RESET 0x00004
#define AC_RESET 0x00002
#define IIS_RESET 0x00001
/* bit definition of REG_ACTL_ACCON register */
#define AC_BCLK_PU_EN 0x20
#define AC_R_FINISH 0x10
#define AC_W_FINISH 0x08
#define AC_W_RES 0x04
#define AC_C_RES 0x02
/* bit definition of ACTL_RSR register */
#define R_FIFO_EMPTY 0x04
#define R_DMA_END_IRQ 0x02
#define R_DMA_MIDDLE_IRQ 0x01
/* bit definition of ACTL_PSR register */
#define P_FIFO_EMPTY 0x04
#define P_DMA_END_IRQ 0x02
#define P_DMA_MIDDLE_IRQ 0x01
/* bit definition of ACTL_ACOS0 register */
#define SLOT1_VALID 0x01
#define SLOT2_VALID 0x02
#define SLOT3_VALID 0x04
#define SLOT4_VALID 0x08
#define VALID_FRAME 0x10
/* bit definition of ACTL_ACOS1 register */
#define R_WB 0x80
#define CODEC_READY 0x10
#define RESET_PRSR 0x00
#define AUDIO_WRITE(addr, val) __raw_writel(val, addr)
#define AUDIO_READ(addr) __raw_readl(addr)
#define PCM_TX 0
#define PCM_RX 1
#define SUBSTREAM_TYPE(substream) \
((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
struct nuc900_audio {
void __iomem *mmio;
spinlock_t lock;
dma_addr_t dma_addr[2];
unsigned long buffersize[2];
unsigned long irq_num;
struct snd_pcm_substream *substream;
struct resource *res;
struct clk *clk;
struct device *dev;
};
extern struct nuc900_audio *nuc900_ac97_data;
extern struct snd_soc_dai nuc900_ac97_dai;
extern struct snd_soc_platform nuc900_soc_platform;
#endif /*end _NUC900_AUDIO_H */
/*
* Copyright (c) 2010 Nuvoton technology corporation.
*
* Wan ZongShun <mcuos.com@gmail.com>
*
* 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;version 2 of the License.
*
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <mach/hardware.h>
#include "nuc900-auido.h"
static const struct snd_pcm_hardware nuc900_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
.channels_min = 1,
.channels_max = 2,
.buffer_bytes_max = 4*1024,
.period_bytes_min = 1*1024,
.period_bytes_max = 4*1024,
.periods_min = 1,
.periods_max = 1024,
};
static int nuc900_dma_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
unsigned long flags, stype = SUBSTREAM_TYPE(substream);
int ret = 0;
spin_lock_irqsave(&nuc900_audio->lock, flags);
ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
if (ret < 0)
return ret;
nuc900_audio->substream = substream;
nuc900_audio->dma_addr[stype] = runtime->dma_addr;
nuc900_audio->buffersize[stype] = params_buffer_bytes(params);
spin_unlock_irqrestore(&nuc900_audio->lock, flags);
return ret;
}
static void nuc900_update_dma_register(struct snd_pcm_substream *substream,
dma_addr_t dma_addr, size_t count)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
void __iomem *mmio_addr, *mmio_len;
if (SUBSTREAM_TYPE(substream) == PCM_TX) {
mmio_addr = nuc900_audio->mmio + ACTL_PDSTB;
mmio_len = nuc900_audio->mmio + ACTL_PDST_LENGTH;
} else {
mmio_addr = nuc900_audio->mmio + ACTL_RDSTB;
mmio_len = nuc900_audio->mmio + ACTL_RDST_LENGTH;
}
AUDIO_WRITE(mmio_addr, dma_addr);
AUDIO_WRITE(mmio_len, count);
}
static void nuc900_dma_start(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
unsigned long val;
val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
val |= (T_DMA_IRQ | R_DMA_IRQ);
AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
}
static void nuc900_dma_stop(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
unsigned long val;
val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
val &= ~(T_DMA_IRQ | R_DMA_IRQ);
AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val);
}
static irqreturn_t nuc900_dma_interrupt(int irq, void *dev_id)
{
struct snd_pcm_substream *substream = dev_id;
struct nuc900_audio *nuc900_audio = substream->runtime->private_data;
unsigned long val;
spin_lock(&nuc900_audio->lock);
val = AUDIO_READ(nuc900_audio->mmio + ACTL_CON);
if (val & R_DMA_IRQ) {
AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | R_DMA_IRQ);
val = AUDIO_READ(nuc900_audio->mmio + ACTL_RSR);
if (val & R_DMA_MIDDLE_IRQ) {
val |= R_DMA_MIDDLE_IRQ;
AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
}
if (val & R_DMA_END_IRQ) {
val |= R_DMA_END_IRQ;
AUDIO_WRITE(nuc900_audio->mmio + ACTL_RSR, val);
}
} else if (val & T_DMA_IRQ) {
AUDIO_WRITE(nuc900_audio->mmio + ACTL_CON, val | T_DMA_IRQ);
val = AUDIO_READ(nuc900_audio->mmio + ACTL_PSR);
if (val & P_DMA_MIDDLE_IRQ) {
val |= P_DMA_MIDDLE_IRQ;
AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
}
if (val & P_DMA_END_IRQ) {
val |= P_DMA_END_IRQ;
AUDIO_WRITE(nuc900_audio->mmio + ACTL_PSR, val);
}
} else {
dev_err(nuc900_audio->dev, "Wrong DMA interrupt status!\n");
spin_unlock(&nuc900_audio->lock);
return IRQ_HANDLED;
}
spin_unlock(&nuc900_audio->lock);
snd_pcm_period_elapsed(substream);
return IRQ_HANDLED;
}
static int nuc900_dma_hw_free(struct snd_pcm_substream *substream)
{
snd_pcm_lib_free_pages(substream);
return 0;
}
static int nuc900_dma_prepare(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
unsigned long flags, val, stype = SUBSTREAM_TYPE(substream);;
spin_lock_irqsave(&nuc900_audio->lock, flags);
nuc900_update_dma_register(substream,
nuc900_audio->dma_addr[stype], nuc900_audio->buffersize[stype]);
val = AUDIO_READ(nuc900_audio->mmio + ACTL_RESET);
switch (runtime->channels) {
case 1:
if (PCM_TX == stype) {
val &= ~(PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
val |= PLAY_RIGHT_CHNNEL;
} else {
val &= ~(RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
val |= RECORD_RIGHT_CHNNEL;
}
AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
break;
case 2:
if (PCM_TX == stype)
val |= (PLAY_LEFT_CHNNEL | PLAY_RIGHT_CHNNEL);
else
val |= (RECORD_LEFT_CHNNEL | RECORD_RIGHT_CHNNEL);
AUDIO_WRITE(nuc900_audio->mmio + ACTL_RESET, val);
break;
default:
return -EINVAL;
}
spin_unlock_irqrestore(&nuc900_audio->lock, flags);
return 0;
}
static int nuc900_dma_trigger(struct snd_pcm_substream *substream, int cmd)
{
int ret = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME:
nuc900_dma_start(substream);
break;
case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND:
nuc900_dma_stop(substream);
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
int nuc900_dma_getposition(struct snd_pcm_substream *substream,
dma_addr_t *src, dma_addr_t *dst)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
if (src != NULL)
*src = AUDIO_READ(nuc900_audio->mmio + ACTL_PDSTC);
if (dst != NULL)
*dst = AUDIO_READ(nuc900_audio->mmio + ACTL_RDSTC);
return 0;
}
static snd_pcm_uframes_t nuc900_dma_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
dma_addr_t src, dst;
unsigned long res;
nuc900_dma_getposition(substream, &src, &dst);
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
res = dst - runtime->dma_addr;
else
res = src - runtime->dma_addr;
return bytes_to_frames(substream->runtime, res);
}
static int nuc900_dma_open(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio;
snd_soc_set_runtime_hwparams(substream, &nuc900_pcm_hardware);
nuc900_audio = nuc900_ac97_data;
if (request_irq(nuc900_audio->irq_num, nuc900_dma_interrupt,
IRQF_DISABLED, "nuc900-dma", substream))
return -EBUSY;
runtime->private_data = nuc900_audio;
return 0;
}
static int nuc900_dma_close(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct nuc900_audio *nuc900_audio = runtime->private_data;
free_irq(nuc900_audio->irq_num, substream);
return 0;
}
static int nuc900_dma_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *vma)
{
struct snd_pcm_runtime *runtime = substream->runtime;
return dma_mmap_writecombine(substream->pcm->card->dev, vma,
runtime->dma_area,
runtime->dma_addr,
runtime->dma_bytes);
}
static struct snd_pcm_ops nuc900_dma_ops = {
.open = nuc900_dma_open,
.close = nuc900_dma_close,
.ioctl = snd_pcm_lib_ioctl,
.hw_params = nuc900_dma_hw_params,
.hw_free = nuc900_dma_hw_free,
.prepare = nuc900_dma_prepare,
.trigger = nuc900_dma_trigger,
.pointer = nuc900_dma_pointer,
.mmap = nuc900_dma_mmap,
};
static void nuc900_dma_free_dma_buffers(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
}
static u64 nuc900_pcm_dmamask = DMA_BIT_MASK(32);
static int nuc900_dma_new(struct snd_card *card,
struct snd_soc_dai *dai, struct snd_pcm *pcm)
{
if (!card->dev->dma_mask)
card->dev->dma_mask = &nuc900_pcm_dmamask;
if (!card->dev->coherent_dma_mask)
card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
card->dev, 4 * 1024, (4 * 1024) - 1);
return 0;
}
struct snd_soc_platform nuc900_soc_platform = {
.name = "nuc900-dma",
.pcm_ops = &nuc900_dma_ops,
.pcm_new = nuc900_dma_new,
.pcm_free = nuc900_dma_free_dma_buffers,
}
EXPORT_SYMBOL_GPL(nuc900_soc_platform);
static int __init nuc900_soc_platform_init(void)
{
return snd_soc_register_platform(&nuc900_soc_platform);
}
static void __exit nuc900_soc_platform_exit(void)
{
snd_soc_unregister_platform(&nuc900_soc_platform);
}
module_init(nuc900_soc_platform_init);
module_exit(nuc900_soc_platform_exit);
MODULE_AUTHOR("Wan ZongShun, <mcuos.com@gmail.com>");
MODULE_DESCRIPTION("nuc900 Audio DMA module");
MODULE_LICENSE("GPL");
config SND_S3C24XX_SOC
tristate "SoC Audio for the Samsung S3CXXXX chips"
depends on ARCH_S3C2410 || ARCH_S3C64XX
depends on ARCH_S3C2410 || ARCH_S3C64XX || ARCH_S5PC100 || ARCH_S5PV210
select S3C64XX_DMA if ARCH_S3C64XX
help
Say Y or M if you want to add support for codecs attached to
......@@ -120,7 +120,7 @@ config SND_S3C24XX_SOC_SIMTEC_HERMES
config SND_SOC_SMDK_WM9713
tristate "SoC AC97 Audio support for SMDK with WM9713"
depends on SND_S3C24XX_SOC && MACH_SMDK6410
depends on SND_S3C24XX_SOC && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110)
select SND_SOC_WM9713
select SND_S3C_SOC_AC97
help
......
......@@ -25,6 +25,9 @@ static struct snd_soc_card smdk;
* Default CFG switch settings to use this driver:
*
* SMDK6410: Set CFG1 1-3 On, CFG2 1-4 Off
* SMDKC100: Set CFG6 1-3 On, CFG7 1 On
* SMDKC110: Set CFGB10 1-2 Off, CFGB12 1-3 On
* SMDKV210: Set CFGB10 1-2 Off, CFGB12 1-3 On
*/
/*
......
......@@ -2352,6 +2352,101 @@ int snd_soc_limit_volume(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
/**
* snd_soc_info_volsw_2r_sx - double with tlv and variable data size
* mixer info callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Returns 0 for success.
*/
int snd_soc_info_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
int max = mc->max;
int min = mc->min;
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->count = 2;
uinfo->value.integer.min = 0;
uinfo->value.integer.max = max-min;
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_info_volsw_2r_sx);
/**
* snd_soc_get_volsw_2r_sx - double with tlv and variable data size
* mixer get callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Returns 0 for success.
*/
int snd_soc_get_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int mask = (1<<mc->shift)-1;
int min = mc->min;
int val = snd_soc_read(codec, mc->reg) & mask;
int valr = snd_soc_read(codec, mc->rreg) & mask;
ucontrol->value.integer.value[0] = ((val & 0xff)-min);
ucontrol->value.integer.value[1] = ((valr & 0xff)-min);
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_get_volsw_2r_sx);
/**
* snd_soc_put_volsw_2r_sx - double with tlv and variable data size
* mixer put callback
* @kcontrol: mixer control
* @uinfo: control element information
*
* Returns 0 for success.
*/
int snd_soc_put_volsw_2r_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
unsigned int mask = (1<<mc->shift)-1;
int min = mc->min;
int ret;
unsigned int val, valr, oval, ovalr;
val = ((ucontrol->value.integer.value[0]+min) & 0xff);
val &= mask;
valr = ((ucontrol->value.integer.value[1]+min) & 0xff);
valr &= mask;
oval = snd_soc_read(codec, mc->reg) & mask;
ovalr = snd_soc_read(codec, mc->rreg) & mask;
ret = 0;
if (oval != val) {
ret = snd_soc_write(codec, mc->reg, val);
if (ret < 0)
return 0;
ret = 1;
}
if (ovalr != valr) {
ret = snd_soc_write(codec, mc->rreg, valr);
if (ret < 0)
return 0;
ret = 1;
}
return 0;
}
EXPORT_SYMBOL_GPL(snd_soc_put_volsw_2r_sx);
/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment