Merge branch 'topic/asoc' into for-linus

This commit is contained in:
Takashi Iwai 2011-01-13 08:37:24 +01:00
commit 6db9a0f326
236 changed files with 22158 additions and 5629 deletions

View File

@ -5176,7 +5176,7 @@ SAMSUNG AUDIO (ASoC) DRIVERS
M: Jassi Brar <jassi.brar@samsung.com>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Supported
F: sound/soc/s3c24xx
F: sound/soc/samsung
TLG2300 VIDEO4LINUX-2 DRIVER
M: Huang Shijie <shijie8@gmail.com>

View File

@ -171,7 +171,7 @@ static void __init openrd_init(void)
kirkwood_i2c_init();
if (machine_is_openrd_client()) {
if (machine_is_openrd_client() || machine_is_openrd_ultimate()) {
i2c_register_board_info(0, i2c_board_info,
ARRAY_SIZE(i2c_board_info));
kirkwood_audio_init();

View File

@ -387,7 +387,7 @@ static struct platform_device *h1940_devices[] __initdata = {
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_pcm,
&samsung_asoc_dma,
&s3c_device_usbgadget,
&h1940_device_leds,
&h1940_device_bluetooth,

View File

@ -692,7 +692,7 @@ static struct platform_device *rx1950_devices[] __initdata = {
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
&s3c_device_pcm,
&samsung_asoc_dma,
&s3c_device_usbgadget,
&s3c_device_rtc,
&s3c_device_nand,

View File

@ -695,7 +695,7 @@ static struct clksrc_clk clksrcs[] = {
}, {
.clk = {
.name = "audio-bus",
.id = -1, /* There's only one IISv4 port */
.id = 2,
.ctrlbit = S3C6410_CLKCON_SCLK_AUDIO2,
.enable = s3c64xx_sclk_ctrl,
},

View File

@ -22,7 +22,12 @@
#include <plat/audio.h>
#include <plat/gpio-cfg.h>
static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
static const char *rclksrc[] = {
[0] = "iis",
[1] = "audio-bus",
};
static int s3c64xx_i2s_cfg_gpio(struct platform_device *pdev)
{
unsigned int base;
@ -33,6 +38,12 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
case 1:
base = S3C64XX_GPE(0);
break;
case 2:
s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
return 0;
default:
printk(KERN_DEBUG "Invalid I2S Controller number: %d\n",
pdev->id);
@ -44,16 +55,6 @@ static int s3c64xx_i2sv3_cfg_gpio(struct platform_device *pdev)
return 0;
}
static int s3c64xx_i2sv4_cfg_gpio(struct platform_device *pdev)
{
s3c_gpio_cfgpin(S3C64XX_GPC(4), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin(S3C64XX_GPC(5), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin(S3C64XX_GPC(7), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin_range(S3C64XX_GPH(6), 4, S3C_GPIO_SFN(5));
return 0;
}
static struct resource s3c64xx_iis0_resource[] = {
[0] = {
.start = S3C64XX_PA_IIS0,
@ -72,17 +73,22 @@ static struct resource s3c64xx_iis0_resource[] = {
},
};
static struct s3c_audio_pdata s3c_i2s0_pdata = {
.cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
static struct s3c_audio_pdata i2sv3_pdata = {
.cfg_gpio = s3c64xx_i2s_cfg_gpio,
.type = {
.i2s = {
.src_clk = rclksrc,
},
},
};
struct platform_device s3c64xx_device_iis0 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s3c64xx_iis0_resource),
.resource = s3c64xx_iis0_resource,
.dev = {
.platform_data = &s3c_i2s0_pdata,
.platform_data = &i2sv3_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iis0);
@ -105,17 +111,13 @@ static struct resource s3c64xx_iis1_resource[] = {
},
};
static struct s3c_audio_pdata s3c_i2s1_pdata = {
.cfg_gpio = s3c64xx_i2sv3_cfg_gpio,
};
struct platform_device s3c64xx_device_iis1 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s3c64xx_iis1_resource),
.resource = s3c64xx_iis1_resource,
.dev = {
.platform_data = &s3c_i2s1_pdata,
.platform_data = &i2sv3_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iis1);
@ -138,17 +140,23 @@ static struct resource s3c64xx_iisv4_resource[] = {
},
};
static struct s3c_audio_pdata s3c_i2sv4_pdata = {
.cfg_gpio = s3c64xx_i2sv4_cfg_gpio,
static struct s3c_audio_pdata i2sv4_pdata = {
.cfg_gpio = s3c64xx_i2s_cfg_gpio,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN,
.src_clk = rclksrc,
},
},
};
struct platform_device s3c64xx_device_iisv4 = {
.name = "s3c64xx-iis-v4",
.id = -1,
.name = "samsung-i2s",
.id = 2,
.num_resources = ARRAY_SIZE(s3c64xx_iisv4_resource),
.resource = s3c64xx_iisv4_resource,
.dev = {
.platform_data = &s3c_i2sv4_pdata,
.platform_data = &i2sv4_pdata,
},
};
EXPORT_SYMBOL(s3c64xx_device_iisv4);
@ -288,7 +296,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata;
static u64 s3c64xx_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s3c64xx_device_ac97 = {
.name = "s3c-ac97",
.name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s3c64xx_ac97_resource),
.resource = s3c64xx_ac97_resource,
@ -307,16 +315,3 @@ void __init s3c64xx_ac97_setup_gpio(int num)
else
s3c_ac97_pdata.cfg_gpio = s3c64xx_ac97_cfg_gpe;
}
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
struct platform_device s3c_device_pcm = {
.name = "s3c24xx-pcm-audio",
.id = -1,
.dev = {
.dma_mask = &s3c_device_audio_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_pcm);

View File

@ -283,7 +283,7 @@ static struct platform_device *smdk6410_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_ohci,
&s3c_device_usb_hsotg,
&s3c_device_pcm,
&samsung_asoc_dma,
&s3c64xx_device_iisv4,
&samsung_device_keypad,

View File

@ -29,7 +29,7 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
base = S5P6442_GPC1(0);
break;
case -1:
case 0:
base = S5P6442_GPC0(0);
break;
@ -42,8 +42,19 @@ static int s5p6442_cfg_i2s(struct platform_device *pdev)
return 0;
}
static struct s3c_audio_pdata s3c_i2s_pdata = {
static const char *rclksrc_v35[] = {
[0] = "busclk",
[1] = "i2sclk",
};
static struct s3c_audio_pdata i2sv35_pdata = {
.cfg_gpio = s5p6442_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
.src_clk = rclksrc_v35,
},
},
};
static struct resource s5p6442_iis0_resource[] = {
@ -62,15 +73,34 @@ static struct resource s5p6442_iis0_resource[] = {
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMACH_I2S0S_TX,
.end = DMACH_I2S0S_TX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5p6442_device_iis0 = {
.name = "s3c64xx-iis-v4",
.id = -1,
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s5p6442_iis0_resource),
.resource = s5p6442_iis0_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv35_pdata,
},
};
static const char *rclksrc_v3[] = {
[0] = "iis",
[1] = "sclk_audio",
};
static struct s3c_audio_pdata i2sv3_pdata = {
.cfg_gpio = s5p6442_cfg_i2s,
.type = {
.i2s = {
.src_clk = rclksrc_v3,
},
},
};
@ -93,12 +123,12 @@ static struct resource s5p6442_iis1_resource[] = {
};
struct platform_device s5p6442_device_iis1 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5p6442_iis1_resource),
.resource = s5p6442_iis1_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv3_pdata,
},
};

View File

@ -261,7 +261,7 @@ static struct clk init_clocks_disable[] = {
.enable = s5p64x0_pclk_ctrl,
.ctrlbit = (1 << 25),
}, {
.name = "i2s_v40",
.name = "iis",
.id = 0,
.parent = &clk_pclk_low.clk,
.enable = s5p64x0_pclk_ctrl,

View File

@ -256,7 +256,7 @@ static struct clk init_clocks_disable[] = {
.ctrlbit = (1 << 22),
}, {
.name = "iis",
.id = -1,
.id = 0,
.parent = &clk_pclk_low.clk,
.enable = s5p64x0_pclk_ctrl,
.ctrlbit = (1 << 26),

View File

@ -19,15 +19,19 @@
#include <mach/dma.h>
#include <mach/irqs.h>
static int s5p6440_cfg_i2s(struct platform_device *pdev)
static const char *rclksrc[] = {
[0] = "iis",
[1] = "sclk_audio2",
};
static int s5p64x0_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
case -1:
case 0:
s3c_gpio_cfgpin_range(S5P6440_GPR(4), 5, S3C_GPIO_SFN(5));
s3c_gpio_cfgpin_range(S5P6440_GPR(13), 2, S3C_GPIO_SFN(5));
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
@ -36,31 +40,14 @@ static int s5p6440_cfg_i2s(struct platform_device *pdev)
return 0;
}
static int s5p6450_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
case -1:
s3c_gpio_cfgpin(S5P6450_GPB(4), S3C_GPIO_SFN(5));
s3c_gpio_cfgpin_range(S5P6450_GPR(4), 5, S3C_GPIO_SFN(5));
s3c_gpio_cfgpin_range(S5P6450_GPR(13), 2, S3C_GPIO_SFN(5));
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
}
return 0;
}
static struct s3c_audio_pdata s5p6440_i2s_pdata = {
.cfg_gpio = s5p6440_cfg_i2s,
};
static struct s3c_audio_pdata s5p6450_i2s_pdata = {
.cfg_gpio = s5p6450_cfg_i2s,
static struct s3c_audio_pdata s5p64x0_i2s_pdata = {
.cfg_gpio = s5p64x0_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN,
.src_clk = rclksrc,
},
},
};
static struct resource s5p64x0_iis0_resource[] = {
@ -82,22 +69,22 @@ static struct resource s5p64x0_iis0_resource[] = {
};
struct platform_device s5p6440_device_iis = {
.name = "s3c64xx-iis-v4",
.id = -1,
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s5p64x0_iis0_resource),
.resource = s5p64x0_iis0_resource,
.dev = {
.platform_data = &s5p6440_i2s_pdata,
.platform_data = &s5p64x0_i2s_pdata,
},
};
struct platform_device s5p6450_device_iis0 = {
.name = "s3c64xx-iis-v4",
.id = -1,
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s5p64x0_iis0_resource),
.resource = s5p64x0_iis0_resource,
.dev = {
.platform_data = &s5p6450_i2s_pdata,
.platform_data = &s5p64x0_i2s_pdata,
},
};

View File

@ -23,17 +23,14 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
case 0: /* Dedicated pins */
break;
case 1:
s3c_gpio_cfgpin_range(S5PC100_GPC(0), 5, S3C_GPIO_SFN(2));
break;
case 2:
s3c_gpio_cfgpin_range(S5PC100_GPG3(0), 5, S3C_GPIO_SFN(4));
break;
case -1: /* Dedicated pins */
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
@ -42,8 +39,20 @@ static int s5pc100_cfg_i2s(struct platform_device *pdev)
return 0;
}
static struct s3c_audio_pdata s3c_i2s_pdata = {
static const char *rclksrc_v5[] = {
[0] = "iis",
[1] = "i2sclkd2",
};
static struct s3c_audio_pdata i2sv5_pdata = {
.cfg_gpio = s5pc100_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
| QUIRK_NEED_RSTCLR,
.src_clk = rclksrc_v5,
},
},
};
static struct resource s5pc100_iis0_resource[] = {
@ -62,15 +71,34 @@ static struct resource s5pc100_iis0_resource[] = {
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMACH_I2S0S_TX,
.end = DMACH_I2S0S_TX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pc100_device_iis0 = {
.name = "s3c64xx-iis-v4",
.id = -1,
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s5pc100_iis0_resource),
.resource = s5pc100_iis0_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv5_pdata,
},
};
static const char *rclksrc_v3[] = {
[0] = "iis",
[1] = "sclk_audio",
};
static struct s3c_audio_pdata i2sv3_pdata = {
.cfg_gpio = s5pc100_cfg_i2s,
.type = {
.i2s = {
.src_clk = rclksrc_v3,
},
},
};
@ -93,12 +121,12 @@ static struct resource s5pc100_iis1_resource[] = {
};
struct platform_device s5pc100_device_iis1 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5pc100_iis1_resource),
.resource = s5pc100_iis1_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv3_pdata,
},
};
@ -121,12 +149,12 @@ static struct resource s5pc100_iis2_resource[] = {
};
struct platform_device s5pc100_device_iis2 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 2,
.num_resources = ARRAY_SIZE(s5pc100_iis2_resource),
.resource = s5pc100_iis2_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv3_pdata,
},
};
@ -253,7 +281,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
static u64 s5pc100_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s5pc100_device_ac97 = {
.name = "s3c-ac97",
.name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s5pc100_ac97_resource),
.resource = s5pc100_ac97_resource,

View File

@ -96,6 +96,7 @@ static struct s3c2410_uartcfg smdkc100_uartcfgs[] __initdata = {
/* I2C0 */
static struct i2c_board_info i2c_devs0[] __initdata = {
{I2C_BOARD_INFO("wm8580", 0x1b),},
};
/* I2C1 */
@ -190,6 +191,7 @@ static struct platform_device *smdkc100_devices[] __initdata = {
&s3c_device_ts,
&s3c_device_wdt,
&smdkc100_lcd_powerdev,
&samsung_asoc_dma,
&s5pc100_device_iis0,
&samsung_device_keypad,
&s5pc100_device_ac97,

View File

@ -467,20 +467,20 @@ static struct clk init_clocks_disable[] = {
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<21),
}, {
.name = "i2s_v50",
.name = "iis",
.id = 0,
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1<<4),
}, {
.name = "i2s_v32",
.id = 0,
.name = "iis",
.id = 1,
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 5),
}, {
.name = "i2s_v32",
.id = 1,
.name = "iis",
.id = 2,
.parent = &clk_p,
.enable = s5pv210_clk_ip3_ctrl,
.ctrlbit = (1 << 6),

View File

@ -19,22 +19,24 @@
#include <mach/dma.h>
#include <mach/irqs.h>
static const char *rclksrc[] = {
[0] = "busclk",
[1] = "i2sclk",
};
static int s5pv210_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
case 0:
s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
break;
case 1:
s3c_gpio_cfgpin_range(S5PV210_GPC0(0), 5, S3C_GPIO_SFN(2));
break;
case 2:
s3c_gpio_cfgpin_range(S5PV210_GPC1(0), 5, S3C_GPIO_SFN(4));
break;
case -1:
s3c_gpio_cfgpin_range(S5PV210_GPI(0), 7, S3C_GPIO_SFN(2));
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
@ -43,8 +45,15 @@ static int s5pv210_cfg_i2s(struct platform_device *pdev)
return 0;
}
static struct s3c_audio_pdata s3c_i2s_pdata = {
static struct s3c_audio_pdata i2sv5_pdata = {
.cfg_gpio = s5pv210_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
| QUIRK_NEED_RSTCLR,
.src_clk = rclksrc,
},
},
};
static struct resource s5pv210_iis0_resource[] = {
@ -63,15 +72,34 @@ static struct resource s5pv210_iis0_resource[] = {
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMACH_I2S0S_TX,
.end = DMACH_I2S0S_TX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv210_device_iis0 = {
.name = "s3c64xx-iis-v4",
.id = -1,
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s5pv210_iis0_resource),
.resource = s5pv210_iis0_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv5_pdata,
},
};
static const char *rclksrc_v3[] = {
[0] = "iis",
[1] = "audio-bus",
};
static struct s3c_audio_pdata i2sv3_pdata = {
.cfg_gpio = s5pv210_cfg_i2s,
.type = {
.i2s = {
.src_clk = rclksrc_v3,
},
},
};
@ -94,12 +122,12 @@ static struct resource s5pv210_iis1_resource[] = {
};
struct platform_device s5pv210_device_iis1 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5pv210_iis1_resource),
.resource = s5pv210_iis1_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv3_pdata,
},
};
@ -122,12 +150,12 @@ static struct resource s5pv210_iis2_resource[] = {
};
struct platform_device s5pv210_device_iis2 = {
.name = "s3c64xx-iis",
.name = "samsung-i2s",
.id = 2,
.num_resources = ARRAY_SIZE(s5pv210_iis2_resource),
.resource = s5pv210_iis2_resource,
.dev = {
.platform_data = &s3c_i2s_pdata,
.platform_data = &i2sv3_pdata,
},
};
@ -283,7 +311,7 @@ static struct s3c_audio_pdata s3c_ac97_pdata = {
static u64 s5pv210_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s5pv210_device_ac97 = {
.name = "s3c-ac97",
.name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv210_ac97_resource),
.resource = s5pv210_ac97_resource,

View File

@ -11,6 +11,7 @@ if ARCH_S5PV310
config CPU_S5PV310
bool
select S3C_PL330_DMA
help
Enable S5PV310 CPU support

View File

@ -13,7 +13,7 @@ obj- :=
# Core support for S5PV310 system
obj-$(CONFIG_CPU_S5PV310) += cpu.o init.o clock.o irq-combiner.o
obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o
obj-$(CONFIG_CPU_S5PV310) += setup-i2c0.o time.o gpiolib.o irq-eint.o dma.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
@ -27,6 +27,7 @@ obj-$(CONFIG_MACH_UNIVERSAL_C210) += mach-universal_c210.o
# device support
obj-y += dev-audio.o
obj-$(CONFIG_S5PV310_SETUP_I2C1) += setup-i2c1.o
obj-$(CONFIG_S5PV310_SETUP_I2C2) += setup-i2c2.o
obj-$(CONFIG_S5PV310_SETUP_I2C3) += setup-i2c3.o

View File

@ -0,0 +1,364 @@
/* linux/arch/arm/mach-s5pv310/dev-audio.c
*
* Copyright (c) 2010 Samsung Electronics Co. Ltd
* Jaswinder Singh <jassi.brar@samsung.com>
*
* 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/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/gpio.h>
#include <plat/gpio-cfg.h>
#include <plat/audio.h>
#include <mach/map.h>
#include <mach/dma.h>
#include <mach/irqs.h>
static const char *rclksrc[] = {
[0] = "busclk",
[1] = "i2sclk",
};
static int s5pv310_cfg_i2s(struct platform_device *pdev)
{
/* configure GPIO for i2s port */
switch (pdev->id) {
case 0:
s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 7, S3C_GPIO_SFN(2));
break;
case 1:
s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(2));
break;
case 2:
s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(4));
break;
default:
printk(KERN_ERR "Invalid Device %d\n", pdev->id);
return -EINVAL;
}
return 0;
}
static struct s3c_audio_pdata i2sv5_pdata = {
.cfg_gpio = s5pv310_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI
| QUIRK_NEED_RSTCLR,
.src_clk = rclksrc,
},
},
};
static struct resource s5pv310_i2s0_resource[] = {
[0] = {
.start = S5PV310_PA_I2S0,
.end = S5PV310_PA_I2S0 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_I2S0_TX,
.end = DMACH_I2S0_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_I2S0_RX,
.end = DMACH_I2S0_RX,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMACH_I2S0S_TX,
.end = DMACH_I2S0S_TX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv310_device_i2s0 = {
.name = "samsung-i2s",
.id = 0,
.num_resources = ARRAY_SIZE(s5pv310_i2s0_resource),
.resource = s5pv310_i2s0_resource,
.dev = {
.platform_data = &i2sv5_pdata,
},
};
static const char *rclksrc_v3[] = {
[0] = "sclk_i2s",
[1] = "no_such_clock",
};
static struct s3c_audio_pdata i2sv3_pdata = {
.cfg_gpio = s5pv310_cfg_i2s,
.type = {
.i2s = {
.quirks = QUIRK_NO_MUXPSR,
.src_clk = rclksrc_v3,
},
},
};
static struct resource s5pv310_i2s1_resource[] = {
[0] = {
.start = S5PV310_PA_I2S1,
.end = S5PV310_PA_I2S1 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_I2S1_TX,
.end = DMACH_I2S1_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_I2S1_RX,
.end = DMACH_I2S1_RX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv310_device_i2s1 = {
.name = "samsung-i2s",
.id = 1,
.num_resources = ARRAY_SIZE(s5pv310_i2s1_resource),
.resource = s5pv310_i2s1_resource,
.dev = {
.platform_data = &i2sv3_pdata,
},
};
static struct resource s5pv310_i2s2_resource[] = {
[0] = {
.start = S5PV310_PA_I2S2,
.end = S5PV310_PA_I2S2 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_I2S2_TX,
.end = DMACH_I2S2_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_I2S2_RX,
.end = DMACH_I2S2_RX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv310_device_i2s2 = {
.name = "samsung-i2s",
.id = 2,
.num_resources = ARRAY_SIZE(s5pv310_i2s2_resource),
.resource = s5pv310_i2s2_resource,
.dev = {
.platform_data = &i2sv3_pdata,
},
};
/* PCM Controller platform_devices */
static int s5pv310_pcm_cfg_gpio(struct platform_device *pdev)
{
switch (pdev->id) {
case 0:
s3c_gpio_cfgpin_range(S5PV310_GPZ(0), 5, S3C_GPIO_SFN(3));
break;
case 1:
s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(3));
break;
case 2:
s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 5, S3C_GPIO_SFN(3));
break;
default:
printk(KERN_DEBUG "Invalid PCM Controller number!");
return -EINVAL;
}
return 0;
}
static struct s3c_audio_pdata s3c_pcm_pdata = {
.cfg_gpio = s5pv310_pcm_cfg_gpio,
};
static struct resource s5pv310_pcm0_resource[] = {
[0] = {
.start = S5PV310_PA_PCM0,
.end = S5PV310_PA_PCM0 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_PCM0_TX,
.end = DMACH_PCM0_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_PCM0_RX,
.end = DMACH_PCM0_RX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv310_device_pcm0 = {
.name = "samsung-pcm",
.id = 0,
.num_resources = ARRAY_SIZE(s5pv310_pcm0_resource),
.resource = s5pv310_pcm0_resource,
.dev = {
.platform_data = &s3c_pcm_pdata,
},
};
static struct resource s5pv310_pcm1_resource[] = {
[0] = {
.start = S5PV310_PA_PCM1,
.end = S5PV310_PA_PCM1 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_PCM1_TX,
.end = DMACH_PCM1_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_PCM1_RX,
.end = DMACH_PCM1_RX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv310_device_pcm1 = {
.name = "samsung-pcm",
.id = 1,
.num_resources = ARRAY_SIZE(s5pv310_pcm1_resource),
.resource = s5pv310_pcm1_resource,
.dev = {
.platform_data = &s3c_pcm_pdata,
},
};
static struct resource s5pv310_pcm2_resource[] = {
[0] = {
.start = S5PV310_PA_PCM2,
.end = S5PV310_PA_PCM2 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_PCM2_TX,
.end = DMACH_PCM2_TX,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_PCM2_RX,
.end = DMACH_PCM2_RX,
.flags = IORESOURCE_DMA,
},
};
struct platform_device s5pv310_device_pcm2 = {
.name = "samsung-pcm",
.id = 2,
.num_resources = ARRAY_SIZE(s5pv310_pcm2_resource),
.resource = s5pv310_pcm2_resource,
.dev = {
.platform_data = &s3c_pcm_pdata,
},
};
/* AC97 Controller platform devices */
static int s5pv310_ac97_cfg_gpio(struct platform_device *pdev)
{
return s3c_gpio_cfgpin_range(S5PV310_GPC0(0), 5, S3C_GPIO_SFN(4));
}
static struct resource s5pv310_ac97_resource[] = {
[0] = {
.start = S5PV310_PA_AC97,
.end = S5PV310_PA_AC97 + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_AC97_PCMOUT,
.end = DMACH_AC97_PCMOUT,
.flags = IORESOURCE_DMA,
},
[2] = {
.start = DMACH_AC97_PCMIN,
.end = DMACH_AC97_PCMIN,
.flags = IORESOURCE_DMA,
},
[3] = {
.start = DMACH_AC97_MICIN,
.end = DMACH_AC97_MICIN,
.flags = IORESOURCE_DMA,
},
[4] = {
.start = IRQ_AC97,
.end = IRQ_AC97,
.flags = IORESOURCE_IRQ,
},
};
static struct s3c_audio_pdata s3c_ac97_pdata = {
.cfg_gpio = s5pv310_ac97_cfg_gpio,
};
static u64 s5pv310_ac97_dmamask = DMA_BIT_MASK(32);
struct platform_device s5pv310_device_ac97 = {
.name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv310_ac97_resource),
.resource = s5pv310_ac97_resource,
.dev = {
.platform_data = &s3c_ac97_pdata,
.dma_mask = &s5pv310_ac97_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};
/* S/PDIF Controller platform_device */
static int s5pv310_spdif_cfg_gpio(struct platform_device *pdev)
{
s3c_gpio_cfgpin_range(S5PV310_GPC1(0), 2, S3C_GPIO_SFN(3));
return 0;
}
static struct resource s5pv310_spdif_resource[] = {
[0] = {
.start = S5PV310_PA_SPDIF,
.end = S5PV310_PA_SPDIF + 0x100 - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = DMACH_SPDIF,
.end = DMACH_SPDIF,
.flags = IORESOURCE_DMA,
},
};
static struct s3c_audio_pdata samsung_spdif_pdata = {
.cfg_gpio = s5pv310_spdif_cfg_gpio,
};
static u64 s5pv310_spdif_dmamask = DMA_BIT_MASK(32);
struct platform_device s5pv310_device_spdif = {
.name = "samsung-spdif",
.id = -1,
.num_resources = ARRAY_SIZE(s5pv310_spdif_resource),
.resource = s5pv310_spdif_resource,
.dev = {
.platform_data = &samsung_spdif_pdata,
.dma_mask = &s5pv310_spdif_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
},
};

168
arch/arm/mach-s5pv310/dma.c Normal file
View File

@ -0,0 +1,168 @@
/*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <plat/devs.h>
#include <plat/irqs.h>
#include <mach/map.h>
#include <mach/irqs.h>
#include <plat/s3c-pl330-pdata.h>
static u64 dma_dmamask = DMA_BIT_MASK(32);
static struct resource s5pv310_pdma0_resource[] = {
[0] = {
.start = S5PV310_PA_PDMA0,
.end = S5PV310_PA_PDMA0 + SZ_4K,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_PDMA0,
.end = IRQ_PDMA0,
.flags = IORESOURCE_IRQ,
},
};
static struct s3c_pl330_platdata s5pv310_pdma0_pdata = {
.peri = {
[0] = DMACH_PCM0_RX,
[1] = DMACH_PCM0_TX,
[2] = DMACH_PCM2_RX,
[3] = DMACH_PCM2_TX,
[4] = DMACH_MSM_REQ0,
[5] = DMACH_MSM_REQ2,
[6] = DMACH_SPI0_RX,
[7] = DMACH_SPI0_TX,
[8] = DMACH_SPI2_RX,
[9] = DMACH_SPI2_TX,
[10] = DMACH_I2S0S_TX,
[11] = DMACH_I2S0_RX,
[12] = DMACH_I2S0_TX,
[13] = DMACH_I2S2_RX,
[14] = DMACH_I2S2_TX,
[15] = DMACH_UART0_RX,
[16] = DMACH_UART0_TX,
[17] = DMACH_UART2_RX,
[18] = DMACH_UART2_TX,
[19] = DMACH_UART4_RX,
[20] = DMACH_UART4_TX,
[21] = DMACH_SLIMBUS0_RX,
[22] = DMACH_SLIMBUS0_TX,
[23] = DMACH_SLIMBUS2_RX,
[24] = DMACH_SLIMBUS2_TX,
[25] = DMACH_SLIMBUS4_RX,
[26] = DMACH_SLIMBUS4_TX,
[27] = DMACH_AC97_MICIN,
[28] = DMACH_AC97_PCMIN,
[29] = DMACH_AC97_PCMOUT,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
};
static struct platform_device s5pv310_device_pdma0 = {
.name = "s3c-pl330",
.id = 0,
.num_resources = ARRAY_SIZE(s5pv310_pdma0_resource),
.resource = s5pv310_pdma0_resource,
.dev = {
.dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &s5pv310_pdma0_pdata,
},
};
static struct resource s5pv310_pdma1_resource[] = {
[0] = {
.start = S5PV310_PA_PDMA1,
.end = S5PV310_PA_PDMA1 + SZ_4K,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_PDMA1,
.end = IRQ_PDMA1,
.flags = IORESOURCE_IRQ,
},
};
static struct s3c_pl330_platdata s5pv310_pdma1_pdata = {
.peri = {
[0] = DMACH_PCM0_RX,
[1] = DMACH_PCM0_TX,
[2] = DMACH_PCM1_RX,
[3] = DMACH_PCM1_TX,
[4] = DMACH_MSM_REQ1,
[5] = DMACH_MSM_REQ3,
[6] = DMACH_SPI1_RX,
[7] = DMACH_SPI1_TX,
[8] = DMACH_I2S0S_TX,
[9] = DMACH_I2S0_RX,
[10] = DMACH_I2S0_TX,
[11] = DMACH_I2S1_RX,
[12] = DMACH_I2S1_TX,
[13] = DMACH_UART0_RX,
[14] = DMACH_UART0_TX,
[15] = DMACH_UART1_RX,
[16] = DMACH_UART1_TX,
[17] = DMACH_UART3_RX,
[18] = DMACH_UART3_TX,
[19] = DMACH_SLIMBUS1_RX,
[20] = DMACH_SLIMBUS1_TX,
[21] = DMACH_SLIMBUS3_RX,
[22] = DMACH_SLIMBUS3_TX,
[23] = DMACH_SLIMBUS5_RX,
[24] = DMACH_SLIMBUS5_TX,
[25] = DMACH_SLIMBUS0AUX_RX,
[26] = DMACH_SLIMBUS0AUX_TX,
[27] = DMACH_SPDIF,
[28] = DMACH_MAX,
[29] = DMACH_MAX,
[30] = DMACH_MAX,
[31] = DMACH_MAX,
},
};
static struct platform_device s5pv310_device_pdma1 = {
.name = "s3c-pl330",
.id = 1,
.num_resources = ARRAY_SIZE(s5pv310_pdma1_resource),
.resource = s5pv310_pdma1_resource,
.dev = {
.dma_mask = &dma_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data = &s5pv310_pdma1_pdata,
},
};
static struct platform_device *s5pv310_dmacs[] __initdata = {
&s5pv310_device_pdma0,
&s5pv310_device_pdma1,
};
static int __init s5pv310_dma_init(void)
{
platform_add_devices(s5pv310_dmacs, ARRAY_SIZE(s5pv310_dmacs));
return 0;
}
arch_initcall(s5pv310_dma_init);

View File

@ -0,0 +1,26 @@
/*
* Copyright (C) 2010 Samsung Electronics Co. Ltd.
* Jaswinder Singh <jassi.brar@samsung.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.
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MACH_DMA_H
#define __MACH_DMA_H
/* This platform uses the common S3C DMA API driver for PL330 */
#include <plat/s3c-dma-pl330.h>
#endif /* __MACH_DMA_H */

View File

@ -54,6 +54,9 @@
#define COMBINER_GROUP(x) ((x) * MAX_IRQ_IN_COMBINER + IRQ_SPI(64))
#define COMBINER_IRQ(x, y) (COMBINER_GROUP(x) + y)
#define IRQ_PDMA0 COMBINER_IRQ(21, 0)
#define IRQ_PDMA1 COMBINER_IRQ(21, 1)
#define IRQ_TIMER0_VIC COMBINER_IRQ(22, 0)
#define IRQ_TIMER1_VIC COMBINER_IRQ(22, 1)
#define IRQ_TIMER2_VIC COMBINER_IRQ(22, 2)

View File

@ -52,6 +52,11 @@
#define S5PV310_PA_GIC_DIST (0x10501000)
#define S5PV310_PA_L2CC (0x10502000)
/* DMA */
#define S5PV310_PA_MDMA 0x10810000
#define S5PV310_PA_PDMA0 0x12680000
#define S5PV310_PA_PDMA1 0x12690000
#define S5PV310_PA_GPIO1 (0x11400000)
#define S5PV310_PA_GPIO2 (0x11000000)
#define S5PV310_PA_GPIO3 (0x03860000)
@ -60,6 +65,22 @@
#define S5PV310_PA_SROMC (0x12570000)
/* S/PDIF */
#define S5PV310_PA_SPDIF 0xE1100000
/* I2S */
#define S5PV310_PA_I2S0 0x03830000
#define S5PV310_PA_I2S1 0xE3100000
#define S5PV310_PA_I2S2 0xE2A00000
/* PCM */
#define S5PV310_PA_PCM0 0x03840000
#define S5PV310_PA_PCM1 0x13980000
#define S5PV310_PA_PCM2 0x13990000
/* AC97 */
#define S5PV310_PA_AC97 0x139A0000
#define S5PV310_PA_UART (0x13800000)
#define S5P_PA_UART(x) (S5PV310_PA_UART + ((x) * S3C_UART_OFFSET))

View File

@ -729,6 +729,10 @@ static struct platform_device fsi_device = {
},
};
static struct platform_device fsi_ak4643_device = {
.name = "sh_fsi2_a_ak4643",
};
static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
.clock_source = LCDC_CLK_EXTERNAL,
.ch[0] = {
@ -927,6 +931,7 @@ static struct platform_device *ap4evb_devices[] __initdata = {
&sdhi1_device,
&usb1_host_device,
&fsi_device,
&fsi_ak4643_device,
&sh_mmcif_device,
&lcdc1_device,
&lcdc_device,

View File

@ -259,21 +259,6 @@ struct platform_device s3c_device_iis = {
EXPORT_SYMBOL(s3c_device_iis);
/* ASoC PCM DMA */
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
struct platform_device s3c_device_pcm = {
.name = "s3c24xx-pcm-audio",
.id = -1,
.dev = {
.dma_mask = &s3c_device_audio_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
EXPORT_SYMBOL(s3c_device_pcm);
/* RTC */
static struct resource s3c_rtc_resource[] = {
@ -496,8 +481,10 @@ static struct resource s3c_ac97_resource[] = {
},
};
static u64 s3c_device_audio_dmamask = 0xffffffffUL;
struct platform_device s3c_device_ac97 = {
.name = "s3c-ac97",
.name = "samsung-ac97",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_ac97_resource),
.resource = s3c_ac97_resource,

View File

@ -17,6 +17,7 @@ obj-y += clock.o
obj-y += pwm-clock.o
obj-y += gpio.o
obj-y += gpio-config.o
obj-y += dev-asocdma.o
obj-$(CONFIG_SAMSUNG_GPIOLIB_4BIT) += gpiolib.o
obj-$(CONFIG_SAMSUNG_CLKSRC) += clock-clksrc.o

View File

@ -0,0 +1,25 @@
/* linux/arch/arm/plat-samsung/dev-asocdma.c
*
* Copyright (c) 2010 Samsung Electronics Co. Ltd
* Jaswinder Singh <jassi.brar@samsung.com>
*
* 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/platform_device.h>
#include <linux/dma-mapping.h>
#include <plat/devs.h>
static u64 audio_dmamask = DMA_BIT_MASK(32);
struct platform_device samsung_asoc_dma = {
.name = "samsung-audio",
.id = -1,
.dev = {
.dma_mask = &audio_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
EXPORT_SYMBOL(samsung_asoc_dma);

View File

@ -25,10 +25,34 @@ extern void s3c64xx_ac97_setup_gpio(int);
#define S5PC100_SPDIF_GPG3 1
extern void s5pc100_spdif_setup_gpio(int);
struct samsung_i2s {
/* If the Primary DAI has 5.1 Channels */
#define QUIRK_PRI_6CHAN (1 << 0)
/* If the I2S block has a Stereo Overlay Channel */
#define QUIRK_SEC_DAI (1 << 1)
/*
* If the I2S block has no internal prescalar or MUX (I2SMOD[10] bit)
* The Machine driver must provide suitably set clock to the I2S block.
*/
#define QUIRK_NO_MUXPSR (1 << 2)
#define QUIRK_NEED_RSTCLR (1 << 3)
/* Quirks of the I2S controller */
u32 quirks;
/*
* Array of clock names that can be used to generate I2S signals.
* Also corresponds to clocks of I2SMOD[10]
*/
const char **src_clk;
};
/**
* struct s3c_audio_pdata - common platform data for audio device drivers
* @cfg_gpio: Callback function to setup mux'ed pins in I2S/PCM/AC97 mode
*/
struct s3c_audio_pdata {
int (*cfg_gpio)(struct platform_device *);
union {
struct samsung_i2s i2s;
} type;
};

View File

@ -32,7 +32,7 @@ extern struct platform_device s3c64xx_device_iisv4;
extern struct platform_device s3c64xx_device_spi0;
extern struct platform_device s3c64xx_device_spi1;
extern struct platform_device s3c_device_pcm;
extern struct platform_device samsung_asoc_dma;
extern struct platform_device s3c64xx_device_pcm0;
extern struct platform_device s3c64xx_device_pcm1;
@ -96,6 +96,15 @@ extern struct platform_device s5pv210_device_iis1;
extern struct platform_device s5pv210_device_iis2;
extern struct platform_device s5pv210_device_spdif;
extern struct platform_device s5pv310_device_ac97;
extern struct platform_device s5pv310_device_pcm0;
extern struct platform_device s5pv310_device_pcm1;
extern struct platform_device s5pv310_device_pcm2;
extern struct platform_device s5pv310_device_i2s0;
extern struct platform_device s5pv310_device_i2s1;
extern struct platform_device s5pv310_device_i2s2;
extern struct platform_device s5pv310_device_spdif;
extern struct platform_device s5p6442_device_pcm0;
extern struct platform_device s5p6442_device_pcm1;
extern struct platform_device s5p6442_device_iis0;

View File

@ -318,6 +318,10 @@ static struct platform_device fsi_device = {
},
};
static struct platform_device fsi_ak4642_device = {
.name = "sh_fsi_a_ak4642",
};
/* KEYSC in SoC (Needs SW33-2 set to ON) */
static struct sh_keysc_info keysc_info = {
.mode = SH_KEYSC_MODE_1,
@ -590,6 +594,7 @@ static struct platform_device *ms7724se_devices[] __initdata = {
&sh7724_usb0_host_device,
&sh7724_usb1_gadget_device,
&fsi_device,
&fsi_ak4642_device,
&sdhi0_cn7_device,
&sdhi1_cn8_device,
&irda_device,

View File

@ -35,6 +35,29 @@ static inline struct wm8994_gpio *to_wm8994_gpio(struct gpio_chip *chip)
return container_of(chip, struct wm8994_gpio, gpio_chip);
}
static int wm8994_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
switch (wm8994->type) {
case WM8958:
switch (offset) {
case 1:
case 2:
case 3:
case 4:
case 6:
return -EINVAL;
}
break;
default:
break;
}
return 0;
}
static int wm8994_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
{
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
@ -136,6 +159,7 @@ static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
static struct gpio_chip template_chip = {
.label = "wm8994",
.owner = THIS_MODULE,
.request = wm8994_gpio_request,
.direction_input = wm8994_gpio_direction_in,
.get = wm8994_gpio_get,
.direction_output = wm8994_gpio_direction_out,

View File

@ -218,6 +218,18 @@ static const char *wm8994_main_supplies[] = {
"SPKVDD2",
};
static const char *wm8958_main_supplies[] = {
"DBVDD1",
"DBVDD2",
"DBVDD3",
"DCVDD",
"AVDD1",
"AVDD2",
"CPVDD",
"SPKVDD1",
"SPKVDD2",
};
#ifdef CONFIG_PM
static int wm8994_device_suspend(struct device *dev)
{
@ -239,7 +251,7 @@ static int wm8994_device_suspend(struct device *dev)
if (ret < 0)
dev_err(dev, "Failed to save LDO registers: %d\n", ret);
ret = regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
ret = regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(dev, "Failed to disable supplies: %d\n", ret);
@ -254,7 +266,7 @@ static int wm8994_device_resume(struct device *dev)
struct wm8994 *wm8994 = dev_get_drvdata(dev);
int ret;
ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
ret = regulator_bulk_enable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(dev, "Failed to enable supplies: %d\n", ret);
@ -305,9 +317,10 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo)
/*
* Instantiate the generic non-control parts of the device.
*/
static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
static int wm8994_device_init(struct wm8994 *wm8994, int irq)
{
struct wm8994_pdata *pdata = wm8994->dev->platform_data;
const char *devname;
int ret, i;
mutex_init(&wm8994->io_lock);
@ -323,25 +336,48 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
goto err;
}
switch (wm8994->type) {
case WM8994:
wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies);
break;
case WM8958:
wm8994->num_supplies = ARRAY_SIZE(wm8958_main_supplies);
break;
default:
BUG();
return -EINVAL;
}
wm8994->supplies = kzalloc(sizeof(struct regulator_bulk_data) *
ARRAY_SIZE(wm8994_main_supplies),
wm8994->num_supplies,
GFP_KERNEL);
if (!wm8994->supplies) {
ret = -ENOMEM;
goto err;
}
for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
wm8994->supplies[i].supply = wm8994_main_supplies[i];
ret = regulator_bulk_get(wm8994->dev, ARRAY_SIZE(wm8994_main_supplies),
switch (wm8994->type) {
case WM8994:
for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
wm8994->supplies[i].supply = wm8994_main_supplies[i];
break;
case WM8958:
for (i = 0; i < ARRAY_SIZE(wm8958_main_supplies); i++)
wm8994->supplies[i].supply = wm8958_main_supplies[i];
break;
default:
BUG();
return -EINVAL;
}
ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret);
goto err_supplies;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8994_main_supplies),
ret = regulator_bulk_enable(wm8994->num_supplies,
wm8994->supplies);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret);
@ -353,7 +389,22 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
dev_err(wm8994->dev, "Failed to read ID register\n");
goto err_enable;
}
if (ret != 0x8994) {
switch (ret) {
case 0x8994:
devname = "WM8994";
if (wm8994->type != WM8994)
dev_warn(wm8994->dev, "Device registered as type %d\n",
wm8994->type);
wm8994->type = WM8994;
break;
case 0x8958:
devname = "WM8958";
if (wm8994->type != WM8958)
dev_warn(wm8994->dev, "Device registered as type %d\n",
wm8994->type);
wm8994->type = WM8958;
break;
default:
dev_err(wm8994->dev, "Device is not a WM8994, ID is %x\n",
ret);
ret = -EINVAL;
@ -370,14 +421,16 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
switch (ret) {
case 0:
case 1:
dev_warn(wm8994->dev, "revision %c not fully supported\n",
'A' + ret);
if (wm8994->type == WM8994)
dev_warn(wm8994->dev,
"revision %c not fully supported\n",
'A' + ret);
break;
default:
dev_info(wm8994->dev, "revision %c\n", 'A' + ret);
break;
}
dev_info(wm8994->dev, "%s revision %c\n", devname, 'A' + ret);
if (pdata) {
wm8994->irq_base = pdata->irq_base;
@ -423,10 +476,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
err_irq:
wm8994_irq_exit(wm8994);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
err_supplies:
kfree(wm8994->supplies);
err:
@ -439,9 +492,9 @@ static void wm8994_device_exit(struct wm8994 *wm8994)
{
mfd_remove_devices(wm8994->dev);
wm8994_irq_exit(wm8994);
regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
regulator_bulk_disable(wm8994->num_supplies,
wm8994->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
regulator_bulk_free(wm8994->num_supplies, wm8994->supplies);
kfree(wm8994->supplies);
kfree(wm8994);
}
@ -506,8 +559,9 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
wm8994->read_dev = wm8994_i2c_read_device;
wm8994->write_dev = wm8994_i2c_write_device;
wm8994->irq = i2c->irq;
wm8994->type = id->driver_data;
return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
return wm8994_device_init(wm8994, i2c->irq);
}
static int wm8994_i2c_remove(struct i2c_client *i2c)
@ -535,7 +589,8 @@ static int wm8994_i2c_resume(struct i2c_client *i2c)
#endif
static const struct i2c_device_id wm8994_i2c_id[] = {
{ "wm8994", 0 },
{ "wm8994", WM8994 },
{ "wm8958", WM8958 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8994_i2c_id);

View File

@ -131,10 +131,19 @@ static struct regulator_ops wm8994_ldo1_ops = {
static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
unsigned int selector)
{
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
if (selector > WM8994_LDO2_MAX_SELECTOR)
return -EINVAL;
return (selector * 100000) + 900000;
switch (ldo->wm8994->type) {
case WM8994:
return (selector * 100000) + 900000;
case WM8958:
return (selector * 100000) + 1000000;
default:
return -EINVAL;
}
}
static int wm8994_ldo2_get_voltage(struct regulator_dev *rdev)
@ -157,7 +166,17 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
struct wm8994_ldo *ldo = rdev_get_drvdata(rdev);
int selector, v;
selector = (min_uV - 900000) / 100000;
switch (ldo->wm8994->type) {
case WM8994:
selector = (min_uV - 900000) / 100000;
break;
case WM8958:
selector = (min_uV - 1000000) / 100000;
break;
default:
return -EINVAL;
}
v = wm8994_ldo2_list_voltage(rdev, selector);
if (v < 0 || v > max_uV)
return -EINVAL;

View File

@ -22,6 +22,7 @@
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>

View File

@ -17,6 +17,11 @@
#include <linux/interrupt.h>
enum wm8994_type {
WM8994 = 0,
WM8958 = 1,
};
struct regulator_dev;
struct regulator_bulk_data;
@ -48,6 +53,8 @@ struct wm8994 {
struct mutex io_lock;
struct mutex irq_lock;
enum wm8994_type type;
struct device *dev;
int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
int bytes, void *dest);
@ -68,6 +75,7 @@ struct wm8994 {
u16 gpio_regs[WM8994_NUM_GPIO_REGS];
struct regulator_dev *dbvdd;
int num_supplies;
struct regulator_bulk_data *supplies;
};

View File

@ -30,6 +30,8 @@ struct wm8994_ldo_pdata {
#define WM8994_DRC_REGS 5
#define WM8994_EQ_REGS 20
#define WM8958_MBC_CUTOFF_REGS 20
#define WM8958_MBC_COEFF_REGS 48
/**
* DRC configurations are specified with a label and a set of register
@ -59,6 +61,18 @@ struct wm8994_retune_mobile_cfg {
u16 regs[WM8994_EQ_REGS];
};
/**
* Multiband compressor configurations are specified with a label and
* two sets of values to write. Configurations are expected to be
* generated using the multiband compressor configuration panel in
* WISCE - see http://www.wolfsonmicro.com/wisce/
*/
struct wm8958_mbc_cfg {
const char *name;
u16 cutoff_regs[WM8958_MBC_CUTOFF_REGS];
u16 coeff_regs[WM8958_MBC_COEFF_REGS];
};
struct wm8994_pdata {
int gpio_base;
@ -78,6 +92,9 @@ struct wm8994_pdata {
int num_retune_mobile_cfgs;
struct wm8994_retune_mobile_cfg *retune_mobile_cfgs;
int num_mbc_cfgs;
struct wm8958_mbc_cfg *mbc_cfgs;
/* LINEOUT can be differential or single ended */
unsigned int lineout1_diff:1;
unsigned int lineout2_diff:1;

View File

@ -64,12 +64,16 @@
#define WM8994_LDO_1 0x3B
#define WM8994_LDO_2 0x3C
#define WM8994_CHARGE_PUMP_1 0x4C
#define WM8958_CHARGE_PUMP_2 0x4D
#define WM8994_CLASS_W_1 0x51
#define WM8994_DC_SERVO_1 0x54
#define WM8994_DC_SERVO_2 0x55
#define WM8994_DC_SERVO_4 0x57
#define WM8994_DC_SERVO_READBACK 0x58
#define WM8994_ANALOGUE_HP_1 0x60
#define WM8958_MIC_DETECT_1 0xD0
#define WM8958_MIC_DETECT_2 0xD1
#define WM8958_MIC_DETECT_3 0xD2
#define WM8994_CHIP_REVISION 0x100
#define WM8994_CONTROL_INTERFACE 0x101
#define WM8994_WRITE_SEQUENCER_CTRL_1 0x110
@ -109,6 +113,10 @@
#define WM8994_AIF2DAC_LRCLK 0x315
#define WM8994_AIF2DAC_DATA 0x316
#define WM8994_AIF2ADC_DATA 0x317
#define WM8958_AIF3_CONTROL_1 0x320
#define WM8958_AIF3_CONTROL_2 0x321
#define WM8958_AIF3DAC_DATA 0x322
#define WM8958_AIF3ADC_DATA 0x323
#define WM8994_AIF1_ADC1_LEFT_VOLUME 0x400
#define WM8994_AIF1_ADC1_RIGHT_VOLUME 0x401
#define WM8994_AIF1_DAC1_LEFT_VOLUME 0x402
@ -242,6 +250,83 @@
#define WM8994_INTERRUPT_STATUS_2_MASK 0x739
#define WM8994_INTERRUPT_CONTROL 0x740
#define WM8994_IRQ_DEBOUNCE 0x748
#define WM8958_DSP2_PROGRAM 0x900
#define WM8958_DSP2_CONFIG 0x901
#define WM8958_DSP2_MAGICNUM 0xA00
#define WM8958_DSP2_RELEASEYEAR 0xA01
#define WM8958_DSP2_RELEASEMONTHDAY 0xA02
#define WM8958_DSP2_RELEASETIME 0xA03
#define WM8958_DSP2_VERMAJMIN 0xA04
#define WM8958_DSP2_VERBUILD 0xA05
#define WM8958_DSP2_EXECCONTROL 0xA0D
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_1 0x2200
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C1_2 0x2201
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_1 0x2202
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C2_2 0x2203
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C3_1 0x2204
#define WM8958_MBC_BAND_2_LOWER_CUTOFF_C3_2 0x2205
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C2_1 0x2206
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C2_2 0x2207
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C3_1 0x2208
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C3_2 0x2209
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C1_1 0x220A
#define WM8958_MBC_BAND_2_UPPER_CUTOFF_C1_2 0x220B
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C1_1 0x220C
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C1_2 0x220D
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C2_1 0x220E
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C2_2 0x220F
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C3_1 0x2210
#define WM8958_MBC_BAND_1_UPPER_CUTOFF_C3_2 0x2211
#define WM8958_MBC_BAND_1_LOWER_CUTOFF_1 0x2212
#define WM8958_MBC_BAND_1_LOWER_CUTOFF_2 0x2213
#define WM8958_MBC_BAND_1_K_1 0x2400
#define WM8958_MBC_BAND_1_K_2 0x2401
#define WM8958_MBC_BAND_1_N1_1 0x2402
#define WM8958_MBC_BAND_1_N1_2 0x2403
#define WM8958_MBC_BAND_1_N2_1 0x2404
#define WM8958_MBC_BAND_1_N2_2 0x2405
#define WM8958_MBC_BAND_1_N3_1 0x2406
#define WM8958_MBC_BAND_1_N3_2 0x2407
#define WM8958_MBC_BAND_1_N4_1 0x2408
#define WM8958_MBC_BAND_1_N4_2 0x2409
#define WM8958_MBC_BAND_1_N5_1 0x240A
#define WM8958_MBC_BAND_1_N5_2 0x240B
#define WM8958_MBC_BAND_1_X1_1 0x240C
#define WM8958_MBC_BAND_1_X1_2 0x240D
#define WM8958_MBC_BAND_1_X2_1 0x240E
#define WM8958_MBC_BAND_1_X2_2 0x240F
#define WM8958_MBC_BAND_1_X3_1 0x2410
#define WM8958_MBC_BAND_1_X3_2 0x2411
#define WM8958_MBC_BAND_1_ATTACK_1 0x2412
#define WM8958_MBC_BAND_1_ATTACK_2 0x2413
#define WM8958_MBC_BAND_1_DECAY_1 0x2414
#define WM8958_MBC_BAND_1_DECAY_2 0x2415
#define WM8958_MBC_BAND_2_K_1 0x2416
#define WM8958_MBC_BAND_2_K_2 0x2417
#define WM8958_MBC_BAND_2_N1_1 0x2418
#define WM8958_MBC_BAND_2_N1_2 0x2419
#define WM8958_MBC_BAND_2_N2_1 0x241A
#define WM8958_MBC_BAND_2_N2_2 0x241B
#define WM8958_MBC_BAND_2_N3_1 0x241C
#define WM8958_MBC_BAND_2_N3_2 0x241D
#define WM8958_MBC_BAND_2_N4_1 0x241E
#define WM8958_MBC_BAND_2_N4_2 0x241F
#define WM8958_MBC_BAND_2_N5_1 0x2420
#define WM8958_MBC_BAND_2_N5_2 0x2421
#define WM8958_MBC_BAND_2_X1_1 0x2422
#define WM8958_MBC_BAND_2_X1_2 0x2423
#define WM8958_MBC_BAND_2_X2_1 0x2424
#define WM8958_MBC_BAND_2_X2_2 0x2425
#define WM8958_MBC_BAND_2_X3_1 0x2426
#define WM8958_MBC_BAND_2_X3_2 0x2427
#define WM8958_MBC_BAND_2_ATTACK_1 0x2428
#define WM8958_MBC_BAND_2_ATTACK_2 0x2429
#define WM8958_MBC_BAND_2_DECAY_1 0x242A
#define WM8958_MBC_BAND_2_DECAY_2 0x242B
#define WM8958_MBC_B2_PG2_1 0x242C
#define WM8958_MBC_B2_PG2_2 0x242D
#define WM8958_MBC_B1_PG2_1 0x242E
#define WM8958_MBC_B1_PG2_2 0x242F
#define WM8994_WRITE_SEQUENCER_0 0x3000
#define WM8994_WRITE_SEQUENCER_1 0x3001
#define WM8994_WRITE_SEQUENCER_2 0x3002
@ -992,6 +1077,12 @@
/*
* R6 (0x06) - Power Management (6)
*/
#define WM8958_AIF3ADC_SRC_MASK 0x0600 /* AIF3ADC_SRC - [10:9] */
#define WM8958_AIF3ADC_SRC_SHIFT 9 /* AIF3ADC_SRC - [10:9] */
#define WM8958_AIF3ADC_SRC_WIDTH 2 /* AIF3ADC_SRC - [10:9] */
#define WM8958_AIF2DAC_SRC_MASK 0x0180 /* AIF2DAC_SRC - [8:7] */
#define WM8958_AIF2DAC_SRC_SHIFT 7 /* AIF2DAC_SRC - [8:7] */
#define WM8958_AIF2DAC_SRC_WIDTH 2 /* AIF2DAC_SRC - [8:7] */
#define WM8994_AIF3_TRI 0x0020 /* AIF3_TRI */
#define WM8994_AIF3_TRI_MASK 0x0020 /* AIF3_TRI */
#define WM8994_AIF3_TRI_SHIFT 5 /* AIF3_TRI */
@ -1835,6 +1926,14 @@
#define WM8994_CP_ENA_SHIFT 15 /* CP_ENA */
#define WM8994_CP_ENA_WIDTH 1 /* CP_ENA */
/*
* R77 (0x4D) - Charge Pump (2)
*/
#define WM8958_CP_DISCH 0x8000 /* CP_DISCH */
#define WM8958_CP_DISCH_MASK 0x8000 /* CP_DISCH */
#define WM8958_CP_DISCH_SHIFT 15 /* CP_DISCH */
#define WM8958_CP_DISCH_WIDTH 1 /* CP_DISCH */
/*
* R81 (0x51) - Class W (1)
*/
@ -1951,6 +2050,46 @@
#define WM8994_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */
#define WM8994_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */
/*
* R208 (0xD0) - Mic Detect 1
*/
#define WM8958_MICD_BIAS_STARTTIME_MASK 0xF000 /* MICD_BIAS_STARTTIME - [15:12] */
#define WM8958_MICD_BIAS_STARTTIME_SHIFT 12 /* MICD_BIAS_STARTTIME - [15:12] */
#define WM8958_MICD_BIAS_STARTTIME_WIDTH 4 /* MICD_BIAS_STARTTIME - [15:12] */
#define WM8958_MICD_RATE_MASK 0x0F00 /* MICD_RATE - [11:8] */
#define WM8958_MICD_RATE_SHIFT 8 /* MICD_RATE - [11:8] */
#define WM8958_MICD_RATE_WIDTH 4 /* MICD_RATE - [11:8] */
#define WM8958_MICD_DBTIME 0x0002 /* MICD_DBTIME */
#define WM8958_MICD_DBTIME_MASK 0x0002 /* MICD_DBTIME */
#define WM8958_MICD_DBTIME_SHIFT 1 /* MICD_DBTIME */
#define WM8958_MICD_DBTIME_WIDTH 1 /* MICD_DBTIME */
#define WM8958_MICD_ENA 0x0001 /* MICD_ENA */
#define WM8958_MICD_ENA_MASK 0x0001 /* MICD_ENA */
#define WM8958_MICD_ENA_SHIFT 0 /* MICD_ENA */
#define WM8958_MICD_ENA_WIDTH 1 /* MICD_ENA */
/*
* R209 (0xD1) - Mic Detect 2
*/
#define WM8958_MICD_LVL_SEL_MASK 0x00FF /* MICD_LVL_SEL - [7:0] */
#define WM8958_MICD_LVL_SEL_SHIFT 0 /* MICD_LVL_SEL - [7:0] */
#define WM8958_MICD_LVL_SEL_WIDTH 8 /* MICD_LVL_SEL - [7:0] */
/*
* R210 (0xD2) - Mic Detect 3
*/
#define WM8958_MICD_LVL_MASK 0x07FC /* MICD_LVL - [10:2] */
#define WM8958_MICD_LVL_SHIFT 2 /* MICD_LVL - [10:2] */
#define WM8958_MICD_LVL_WIDTH 9 /* MICD_LVL - [10:2] */
#define WM8958_MICD_VALID 0x0002 /* MICD_VALID */
#define WM8958_MICD_VALID_MASK 0x0002 /* MICD_VALID */
#define WM8958_MICD_VALID_SHIFT 1 /* MICD_VALID */
#define WM8958_MICD_VALID_WIDTH 1 /* MICD_VALID */
#define WM8958_MICD_STS 0x0001 /* MICD_STS */
#define WM8958_MICD_STS_MASK 0x0001 /* MICD_STS */
#define WM8958_MICD_STS_SHIFT 0 /* MICD_STS */
#define WM8958_MICD_STS_WIDTH 1 /* MICD_STS */
/*
* R256 (0x100) - Chip Revision
*/
@ -2069,6 +2208,14 @@
/*
* R520 (0x208) - Clocking (1)
*/
#define WM8958_DSP2CLK_ENA 0x4000 /* DSP2CLK_ENA */
#define WM8958_DSP2CLK_ENA_MASK 0x4000 /* DSP2CLK_ENA */
#define WM8958_DSP2CLK_ENA_SHIFT 14 /* DSP2CLK_ENA */
#define WM8958_DSP2CLK_ENA_WIDTH 1 /* DSP2CLK_ENA */
#define WM8958_DSP2CLK_SRC 0x1000 /* DSP2CLK_SRC */
#define WM8958_DSP2CLK_SRC_MASK 0x1000 /* DSP2CLK_SRC */
#define WM8958_DSP2CLK_SRC_SHIFT 12 /* DSP2CLK_SRC */
#define WM8958_DSP2CLK_SRC_WIDTH 1 /* DSP2CLK_SRC */
#define WM8994_TOCLK_ENA 0x0010 /* TOCLK_ENA */
#define WM8994_TOCLK_ENA_MASK 0x0010 /* TOCLK_ENA */
#define WM8994_TOCLK_ENA_SHIFT 4 /* TOCLK_ENA */
@ -2552,6 +2699,63 @@
#define WM8994_AIF2ADCR_DAT_INV_SHIFT 0 /* AIF2ADCR_DAT_INV */
#define WM8994_AIF2ADCR_DAT_INV_WIDTH 1 /* AIF2ADCR_DAT_INV */
/*
* R800 (0x320) - AIF3 Control (1)
*/
#define WM8958_AIF3_LRCLK_INV 0x0080 /* AIF3_LRCLK_INV */
#define WM8958_AIF3_LRCLK_INV_MASK 0x0080 /* AIF3_LRCLK_INV */
#define WM8958_AIF3_LRCLK_INV_SHIFT 7 /* AIF3_LRCLK_INV */
#define WM8958_AIF3_LRCLK_INV_WIDTH 1 /* AIF3_LRCLK_INV */
#define WM8958_AIF3_WL_MASK 0x0060 /* AIF3_WL - [6:5] */
#define WM8958_AIF3_WL_SHIFT 5 /* AIF3_WL - [6:5] */
#define WM8958_AIF3_WL_WIDTH 2 /* AIF3_WL - [6:5] */
#define WM8958_AIF3_FMT_MASK 0x0018 /* AIF3_FMT - [4:3] */
#define WM8958_AIF3_FMT_SHIFT 3 /* AIF3_FMT - [4:3] */
#define WM8958_AIF3_FMT_WIDTH 2 /* AIF3_FMT - [4:3] */
/*
* R801 (0x321) - AIF3 Control (2)
*/
#define WM8958_AIF3DAC_BOOST_MASK 0x0C00 /* AIF3DAC_BOOST - [11:10] */
#define WM8958_AIF3DAC_BOOST_SHIFT 10 /* AIF3DAC_BOOST - [11:10] */
#define WM8958_AIF3DAC_BOOST_WIDTH 2 /* AIF3DAC_BOOST - [11:10] */
#define WM8958_AIF3DAC_COMP 0x0010 /* AIF3DAC_COMP */
#define WM8958_AIF3DAC_COMP_MASK 0x0010 /* AIF3DAC_COMP */
#define WM8958_AIF3DAC_COMP_SHIFT 4 /* AIF3DAC_COMP */
#define WM8958_AIF3DAC_COMP_WIDTH 1 /* AIF3DAC_COMP */
#define WM8958_AIF3DAC_COMPMODE 0x0008 /* AIF3DAC_COMPMODE */
#define WM8958_AIF3DAC_COMPMODE_MASK 0x0008 /* AIF3DAC_COMPMODE */
#define WM8958_AIF3DAC_COMPMODE_SHIFT 3 /* AIF3DAC_COMPMODE */
#define WM8958_AIF3DAC_COMPMODE_WIDTH 1 /* AIF3DAC_COMPMODE */
#define WM8958_AIF3ADC_COMP 0x0004 /* AIF3ADC_COMP */
#define WM8958_AIF3ADC_COMP_MASK 0x0004 /* AIF3ADC_COMP */
#define WM8958_AIF3ADC_COMP_SHIFT 2 /* AIF3ADC_COMP */
#define WM8958_AIF3ADC_COMP_WIDTH 1 /* AIF3ADC_COMP */
#define WM8958_AIF3ADC_COMPMODE 0x0002 /* AIF3ADC_COMPMODE */
#define WM8958_AIF3ADC_COMPMODE_MASK 0x0002 /* AIF3ADC_COMPMODE */
#define WM8958_AIF3ADC_COMPMODE_SHIFT 1 /* AIF3ADC_COMPMODE */
#define WM8958_AIF3ADC_COMPMODE_WIDTH 1 /* AIF3ADC_COMPMODE */
#define WM8958_AIF3_LOOPBACK 0x0001 /* AIF3_LOOPBACK */
#define WM8958_AIF3_LOOPBACK_MASK 0x0001 /* AIF3_LOOPBACK */
#define WM8958_AIF3_LOOPBACK_SHIFT 0 /* AIF3_LOOPBACK */
#define WM8958_AIF3_LOOPBACK_WIDTH 1 /* AIF3_LOOPBACK */
/*
* R802 (0x322) - AIF3DAC Data
*/
#define WM8958_AIF3DAC_DAT_INV 0x0001 /* AIF3DAC_DAT_INV */
#define WM8958_AIF3DAC_DAT_INV_MASK 0x0001 /* AIF3DAC_DAT_INV */
#define WM8958_AIF3DAC_DAT_INV_SHIFT 0 /* AIF3DAC_DAT_INV */
#define WM8958_AIF3DAC_DAT_INV_WIDTH 1 /* AIF3DAC_DAT_INV */
/*
* R803 (0x323) - AIF3ADC Data
*/
#define WM8958_AIF3ADC_DAT_INV 0x0001 /* AIF3ADC_DAT_INV */
#define WM8958_AIF3ADC_DAT_INV_MASK 0x0001 /* AIF3ADC_DAT_INV */
#define WM8958_AIF3ADC_DAT_INV_SHIFT 0 /* AIF3ADC_DAT_INV */
#define WM8958_AIF3ADC_DAT_INV_WIDTH 1 /* AIF3ADC_DAT_INV */
/*
* R1024 (0x400) - AIF1 ADC1 Left Volume
*/
@ -4289,4 +4493,102 @@
#define WM8994_TEMP_SHUT_DB_SHIFT 0 /* TEMP_SHUT_DB */
#define WM8994_TEMP_SHUT_DB_WIDTH 1 /* TEMP_SHUT_DB */
/*
* R2304 (0x900) - DSP2_Program
*/
#define WM8958_DSP2_ENA 0x0001 /* DSP2_ENA */
#define WM8958_DSP2_ENA_MASK 0x0001 /* DSP2_ENA */
#define WM8958_DSP2_ENA_SHIFT 0 /* DSP2_ENA */
#define WM8958_DSP2_ENA_WIDTH 1 /* DSP2_ENA */
/*
* R2305 (0x901) - DSP2_Config
*/
#define WM8958_MBC_SEL_MASK 0x0030 /* MBC_SEL - [5:4] */
#define WM8958_MBC_SEL_SHIFT 4 /* MBC_SEL - [5:4] */
#define WM8958_MBC_SEL_WIDTH 2 /* MBC_SEL - [5:4] */
#define WM8958_MBC_ENA 0x0001 /* MBC_ENA */
#define WM8958_MBC_ENA_MASK 0x0001 /* MBC_ENA */
#define WM8958_MBC_ENA_SHIFT 0 /* MBC_ENA */
#define WM8958_MBC_ENA_WIDTH 1 /* MBC_ENA */
/*
* R2560 (0xA00) - DSP2_MagicNum
*/
#define WM8958_DSP2_MAGIC_NUM_MASK 0xFFFF /* DSP2_MAGIC_NUM - [15:0] */
#define WM8958_DSP2_MAGIC_NUM_SHIFT 0 /* DSP2_MAGIC_NUM - [15:0] */
#define WM8958_DSP2_MAGIC_NUM_WIDTH 16 /* DSP2_MAGIC_NUM - [15:0] */
/*
* R2561 (0xA01) - DSP2_ReleaseYear
*/
#define WM8958_DSP2_RELEASE_YEAR_MASK 0xFFFF /* DSP2_RELEASE_YEAR - [15:0] */
#define WM8958_DSP2_RELEASE_YEAR_SHIFT 0 /* DSP2_RELEASE_YEAR - [15:0] */
#define WM8958_DSP2_RELEASE_YEAR_WIDTH 16 /* DSP2_RELEASE_YEAR - [15:0] */
/*
* R2562 (0xA02) - DSP2_ReleaseMonthDay
*/
#define WM8958_DSP2_RELEASE_MONTH_MASK 0xFF00 /* DSP2_RELEASE_MONTH - [15:8] */
#define WM8958_DSP2_RELEASE_MONTH_SHIFT 8 /* DSP2_RELEASE_MONTH - [15:8] */
#define WM8958_DSP2_RELEASE_MONTH_WIDTH 8 /* DSP2_RELEASE_MONTH - [15:8] */
#define WM8958_DSP2_RELEASE_DAY_MASK 0x00FF /* DSP2_RELEASE_DAY - [7:0] */
#define WM8958_DSP2_RELEASE_DAY_SHIFT 0 /* DSP2_RELEASE_DAY - [7:0] */
#define WM8958_DSP2_RELEASE_DAY_WIDTH 8 /* DSP2_RELEASE_DAY - [7:0] */
/*
* R2563 (0xA03) - DSP2_ReleaseTime
*/
#define WM8958_DSP2_RELEASE_HOURS_MASK 0xFF00 /* DSP2_RELEASE_HOURS - [15:8] */
#define WM8958_DSP2_RELEASE_HOURS_SHIFT 8 /* DSP2_RELEASE_HOURS - [15:8] */
#define WM8958_DSP2_RELEASE_HOURS_WIDTH 8 /* DSP2_RELEASE_HOURS - [15:8] */
#define WM8958_DSP2_RELEASE_MINS_MASK 0x00FF /* DSP2_RELEASE_MINS - [7:0] */
#define WM8958_DSP2_RELEASE_MINS_SHIFT 0 /* DSP2_RELEASE_MINS - [7:0] */
#define WM8958_DSP2_RELEASE_MINS_WIDTH 8 /* DSP2_RELEASE_MINS - [7:0] */
/*
* R2564 (0xA04) - DSP2_VerMajMin
*/
#define WM8958_DSP2_MAJOR_VER_MASK 0xFF00 /* DSP2_MAJOR_VER - [15:8] */
#define WM8958_DSP2_MAJOR_VER_SHIFT 8 /* DSP2_MAJOR_VER - [15:8] */
#define WM8958_DSP2_MAJOR_VER_WIDTH 8 /* DSP2_MAJOR_VER - [15:8] */
#define WM8958_DSP2_MINOR_VER_MASK 0x00FF /* DSP2_MINOR_VER - [7:0] */
#define WM8958_DSP2_MINOR_VER_SHIFT 0 /* DSP2_MINOR_VER - [7:0] */
#define WM8958_DSP2_MINOR_VER_WIDTH 8 /* DSP2_MINOR_VER - [7:0] */
/*
* R2565 (0xA05) - DSP2_VerBuild
*/
#define WM8958_DSP2_BUILD_VER_MASK 0xFFFF /* DSP2_BUILD_VER - [15:0] */
#define WM8958_DSP2_BUILD_VER_SHIFT 0 /* DSP2_BUILD_VER - [15:0] */
#define WM8958_DSP2_BUILD_VER_WIDTH 16 /* DSP2_BUILD_VER - [15:0] */
/*
* R2573 (0xA0D) - DSP2_ExecControl
*/
#define WM8958_DSP2_STOPC 0x0020 /* DSP2_STOPC */
#define WM8958_DSP2_STOPC_MASK 0x0020 /* DSP2_STOPC */
#define WM8958_DSP2_STOPC_SHIFT 5 /* DSP2_STOPC */
#define WM8958_DSP2_STOPC_WIDTH 1 /* DSP2_STOPC */
#define WM8958_DSP2_STOPS 0x0010 /* DSP2_STOPS */
#define WM8958_DSP2_STOPS_MASK 0x0010 /* DSP2_STOPS */
#define WM8958_DSP2_STOPS_SHIFT 4 /* DSP2_STOPS */
#define WM8958_DSP2_STOPS_WIDTH 1 /* DSP2_STOPS */
#define WM8958_DSP2_STOPI 0x0008 /* DSP2_STOPI */
#define WM8958_DSP2_STOPI_MASK 0x0008 /* DSP2_STOPI */
#define WM8958_DSP2_STOPI_SHIFT 3 /* DSP2_STOPI */
#define WM8958_DSP2_STOPI_WIDTH 1 /* DSP2_STOPI */
#define WM8958_DSP2_STOP 0x0004 /* DSP2_STOP */
#define WM8958_DSP2_STOP_MASK 0x0004 /* DSP2_STOP */
#define WM8958_DSP2_STOP_SHIFT 2 /* DSP2_STOP */
#define WM8958_DSP2_STOP_WIDTH 1 /* DSP2_STOP */
#define WM8958_DSP2_RUNR 0x0002 /* DSP2_RUNR */
#define WM8958_DSP2_RUNR_MASK 0x0002 /* DSP2_RUNR */
#define WM8958_DSP2_RUNR_SHIFT 1 /* DSP2_RUNR */
#define WM8958_DSP2_RUNR_WIDTH 1 /* DSP2_RUNR */
#define WM8958_DSP2_RUN 0x0001 /* DSP2_RUN */
#define WM8958_DSP2_RUN_MASK 0x0001 /* DSP2_RUN */
#define WM8958_DSP2_RUN_SHIFT 0 /* DSP2_RUN */
#define WM8958_DSP2_RUN_WIDTH 1 /* DSP2_RUN */
#endif

15
include/sound/alc5623.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef _INCLUDE_SOUND_ALC5623_H
#define _INCLUDE_SOUND_ALC5623_H
struct alc5623_platform_data {
/* configure : */
/* Lineout/Speaker Amps Vmid ratio control */
/* enable/disable adc/dac high pass filters */
unsigned int add_ctrl;
/* configure : */
/* output to enable when jack is low */
/* output to enable when jack is high */
/* jack detect (gpio/nc/jack detect [12] */
unsigned int jack_det_ctrl;
};
#endif

View File

@ -16,8 +16,6 @@
#include <linux/list.h>
#include <sound/soc.h>
struct snd_pcm_substream;
/*
@ -205,7 +203,7 @@ struct snd_soc_dai_driver {
int (*resume)(struct snd_soc_dai *dai);
/* ops */
struct snd_soc_dai_ops *ops;
const struct snd_soc_dai_ops *ops;
/* DAI capabilities */
struct snd_soc_pcm_stream capture;

View File

@ -16,7 +16,6 @@
#include <linux/device.h>
#include <linux/types.h>
#include <sound/control.h>
#include <sound/soc.h>
/* widget has no PM register bit */
#define SND_SOC_NOPM -1
@ -72,6 +71,10 @@
wcontrols, wncontrols) \
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_OUT_DRV(wname, wreg, wshift, winvert,\
wcontrols, wncontrols) \
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols}
#define SND_SOC_DAPM_MIXER(wname, wreg, wshift, winvert, \
wcontrols, wncontrols)\
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
@ -90,6 +93,9 @@
#define SND_SOC_DAPM_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VIRT_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1}
#define SND_SOC_DAPM_VALUE_MUX(wname, wreg, wshift, winvert, wcontrols) \
{ .id = snd_soc_dapm_value_mux, .name = wname, .reg = wreg, \
.shift = wshift, .invert = winvert, .kcontrols = wcontrols, \
@ -116,6 +122,11 @@
{ .id = snd_soc_dapm_pga, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_OUT_DRV_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_out_drv, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = wncontrols, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_MIXER_E(wname, wreg, wshift, winvert, wcontrols, \
wncontrols, wevent, wflags) \
{ .id = snd_soc_dapm_mixer, .name = wname, .reg = wreg, .shift = wshift, \
@ -140,6 +151,11 @@
{ .id = snd_soc_dapm_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
#define SND_SOC_DAPM_VIRT_MUX_E(wname, wreg, wshift, winvert, wcontrols, \
wevent, wflags) \
{ .id = snd_soc_dapm_virt_mux, .name = wname, .reg = wreg, .shift = wshift, \
.invert = winvert, .kcontrols = wcontrols, .num_kcontrols = 1, \
.event = wevent, .event_flags = wflags}
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
#define SOC_PGA_E_ARRAY(wname, wreg, wshift, winvert, wcontrols, \
@ -219,13 +235,6 @@
.info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
#define SOC_DAPM_DOUBLE(xname, reg, shift_left, shift_right, max, invert, \
power) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
((max) << 16) | ((invert) << 24) }
#define SOC_DAPM_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, \
@ -233,15 +242,6 @@
.tlv.p = (tlv_array), \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
#define SOC_DAPM_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, \
power, 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, \
.get = snd_soc_dapm_get_volsw, .put = snd_soc_dapm_put_volsw, \
.private_value = (reg) | ((shift_left) << 8) | ((shift_right) << 12) |\
((max) << 16) | ((invert) << 24) }
#define SOC_DAPM_ENUM(xname, xenum) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_enum_double, \
@ -297,6 +297,7 @@ enum snd_soc_dapm_type;
struct snd_soc_dapm_path;
struct snd_soc_dapm_pin;
struct snd_soc_dapm_route;
struct snd_soc_dapm_context;
int dapm_reg_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
@ -324,16 +325,16 @@ int snd_soc_dapm_get_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uncontrol);
int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *uncontrol);
int snd_soc_dapm_new_control(struct snd_soc_codec *codec,
int snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget);
int snd_soc_dapm_new_controls(struct snd_soc_codec *codec,
int snd_soc_dapm_new_controls(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_widget *widget,
int num);
/* dapm path setup */
int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec);
void snd_soc_dapm_free(struct snd_soc_codec *codec);
int snd_soc_dapm_add_routes(struct snd_soc_codec *codec,
int snd_soc_dapm_new_widgets(struct snd_soc_dapm_context *dapm);
void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_add_routes(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route, int num);
/* dapm events */
@ -343,27 +344,33 @@ void snd_soc_dapm_shutdown(struct snd_soc_card *card);
/* dapm sys fs - used by the core */
int snd_soc_dapm_sys_add(struct device *dev);
void snd_soc_dapm_debugfs_init(struct snd_soc_codec *codec);
void snd_soc_dapm_debugfs_init(struct snd_soc_dapm_context *dapm);
/* dapm audio pin control and status */
int snd_soc_dapm_enable_pin(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_sync(struct snd_soc_codec *codec);
int snd_soc_dapm_force_enable_pin(struct snd_soc_codec *codec,
int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm,
const char *pin);
int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm,
const char *pin);
int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin);
int snd_soc_dapm_get_pin_status(struct snd_soc_dapm_context *dapm,
const char *pin);
int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm);
int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
const char *pin);
int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin);
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
const char *pin);
/* dapm widget types */
enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */
snd_soc_dapm_output, /* output pin */
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_virt_mux, /* virtual version of snd_soc_dapm_mux */
snd_soc_dapm_value_mux, /* selects 1 analog signal from many inputs */
snd_soc_dapm_mixer, /* mixes several analog signals together */
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
snd_soc_dapm_out_drv, /* output driver */
snd_soc_dapm_adc, /* analog to digital converter */
snd_soc_dapm_dac, /* digital to analog converter */
snd_soc_dapm_micbias, /* microphone bias (power) */
@ -425,6 +432,7 @@ struct snd_soc_dapm_widget {
char *sname; /* stream name */
struct snd_soc_codec *codec;
struct list_head list;
struct snd_soc_dapm_context *dapm;
/* dapm control */
short reg; /* negative reg = no direct dapm */
@ -461,4 +469,35 @@ struct snd_soc_dapm_widget {
struct list_head power_list;
};
struct snd_soc_dapm_update {
struct snd_soc_dapm_widget *widget;
struct snd_kcontrol *kcontrol;
int reg;
int mask;
int val;
};
/* DAPM context */
struct snd_soc_dapm_context {
int n_widgets; /* number of widgets in this context */
enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
struct snd_soc_dapm_update *update;
struct device *dev; /* from parent - for debug */
struct snd_soc_codec *codec; /* parent codec */
struct snd_soc_card *card; /* parent card */
/* used during DAPM updates */
int dev_power;
struct list_head list;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_dapm;
#endif
};
#endif

View File

@ -222,10 +222,8 @@ enum snd_soc_bias_level {
struct snd_jack;
struct snd_soc_card;
struct snd_soc_device;
struct snd_soc_pcm_stream;
struct snd_soc_ops;
struct snd_soc_dai_mode;
struct snd_soc_pcm_runtime;
struct snd_soc_dai;
struct snd_soc_dai_driver;
@ -235,9 +233,10 @@ struct snd_soc_platform_driver;
struct snd_soc_codec;
struct snd_soc_codec_driver;
struct soc_enum;
struct snd_soc_ac97_ops;
struct snd_soc_jack;
struct snd_soc_jack_pin;
struct snd_soc_cache_ops;
#include <sound/soc-dapm.h>
#ifdef CONFIG_GPIOLIB
struct snd_soc_jack_gpio;
@ -253,17 +252,30 @@ enum snd_soc_control_type {
SND_SOC_SPI,
};
enum snd_soc_compress_type {
SND_SOC_FLAT_COMPRESSION = 1,
SND_SOC_LZO_COMPRESSION,
SND_SOC_RBTREE_COMPRESSION
};
int snd_soc_register_platform(struct device *dev,
struct snd_soc_platform_driver *platform_drv);
void snd_soc_unregister_platform(struct device *dev);
int snd_soc_register_codec(struct device *dev,
struct snd_soc_codec_driver *codec_drv,
const struct snd_soc_codec_driver *codec_drv,
struct snd_soc_dai_driver *dai_drv, int num_dai);
void snd_soc_unregister_codec(struct device *dev);
int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg);
int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec,
int addr_bits, int data_bits,
enum snd_soc_control_type control);
int snd_soc_cache_sync(struct snd_soc_codec *codec);
int snd_soc_cache_init(struct snd_soc_codec *codec);
int snd_soc_cache_exit(struct snd_soc_codec *codec);
int snd_soc_cache_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int value);
int snd_soc_cache_read(struct snd_soc_codec *codec,
unsigned int reg, unsigned int *value);
/* Utility functions to get clock rates from various things */
int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots);
@ -420,23 +432,37 @@ struct snd_soc_ops {
int (*trigger)(struct snd_pcm_substream *, int);
};
/* SoC cache ops */
struct snd_soc_cache_ops {
const char *name;
enum snd_soc_compress_type id;
int (*init)(struct snd_soc_codec *codec);
int (*exit)(struct snd_soc_codec *codec);
int (*read)(struct snd_soc_codec *codec, unsigned int reg,
unsigned int *value);
int (*write)(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value);
int (*sync)(struct snd_soc_codec *codec);
};
/* SoC Audio Codec device */
struct snd_soc_codec {
const char *name;
const char *name_prefix;
int id;
struct device *dev;
struct snd_soc_codec_driver *driver;
const struct snd_soc_codec_driver *driver;
struct mutex mutex;
struct snd_soc_card *card;
struct list_head list;
struct list_head card_list;
int num_dai;
enum snd_soc_compress_type compress_type;
/* runtime */
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int active;
unsigned int idle_bias_off:1; /* Use BIAS_OFF instead of STANDBY */
unsigned int cache_only:1; /* Suppress writes to hardware */
unsigned int cache_sync:1; /* Cache needs to be synced to hardware */
unsigned int suspended:1; /* Codec is in suspend PM state */
@ -444,25 +470,25 @@ struct snd_soc_codec {
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
unsigned int cache_init:1; /* codec cache has been initialized */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
hw_write_t hw_write;
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
void *reg_cache;
const void *reg_def_copy;
const struct snd_soc_cache_ops *cache_ops;
struct mutex cache_rw_mutex;
/* dapm */
u32 pop_time;
struct list_head dapm_widgets;
struct list_head dapm_paths;
enum snd_soc_bias_level bias_level;
enum snd_soc_bias_level suspend_bias_level;
struct delayed_work delayed_work;
struct snd_soc_dapm_context dapm;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
struct dentry *debugfs_reg;
struct dentry *debugfs_pop_time;
struct dentry *debugfs_dapm;
#endif
};
@ -488,6 +514,7 @@ struct snd_soc_codec_driver {
short reg_cache_step;
short reg_word_size;
const void *reg_cache_default;
enum snd_soc_compress_type compress_type;
/* codec bias level */
int (*set_bias_level)(struct snd_soc_codec *,
@ -554,6 +581,30 @@ struct snd_soc_dai_link {
struct snd_soc_ops *ops;
};
struct snd_soc_codec_conf {
const char *dev_name;
/*
* optional map of kcontrol, widget and path name prefixes that are
* associated per device
*/
const char *name_prefix;
/*
* set this to the desired compression type if you want to
* override the one supplied in codec->driver->compress_type
*/
enum snd_soc_compress_type compress_type;
};
struct snd_soc_aux_dev {
const char *name; /* Codec name */
const char *codec_name; /* for multi-codec */
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_dapm_context *dapm);
};
/* SoC card */
struct snd_soc_card {
const char *name;
@ -579,6 +630,8 @@ struct snd_soc_card {
/* callbacks */
int (*set_bias_level)(struct snd_soc_card *,
enum snd_soc_bias_level level);
int (*set_bias_level_post)(struct snd_soc_card *,
enum snd_soc_bias_level level);
long pmdown_time;
@ -588,12 +641,35 @@ struct snd_soc_card {
struct snd_soc_pcm_runtime *rtd;
int num_rtd;
/* optional codec specific configuration */
struct snd_soc_codec_conf *codec_conf;
int num_configs;
/*
* optional auxiliary devices such as amplifiers or codecs with DAI
* link unused
*/
struct snd_soc_aux_dev *aux_dev;
int num_aux_devs;
struct snd_soc_pcm_runtime *rtd_aux;
int num_aux_rtd;
struct work_struct deferred_resume_work;
/* lists of probed devices belonging to this card */
struct list_head codec_dev_list;
struct list_head platform_dev_list;
struct list_head dai_dev_list;
struct list_head widgets;
struct list_head paths;
struct list_head dapm_list;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_card_root;
struct dentry *debugfs_pop_time;
#endif
u32 pop_time;
};
/* SoC machine DAI configuration, glues a codec and cpu DAI together */
@ -639,17 +715,9 @@ struct soc_enum {
};
/* codec IO */
static inline unsigned int snd_soc_read(struct snd_soc_codec *codec,
unsigned int reg)
{
return codec->driver->read(codec, reg);
}
static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val)
{
return codec->driver->write(codec, reg, val);
}
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
unsigned int snd_soc_write(struct snd_soc_codec *codec,
unsigned int reg, unsigned int val);
/* device driver data */

235
include/trace/events/asoc.h Normal file
View File

@ -0,0 +1,235 @@
#undef TRACE_SYSTEM
#define TRACE_SYSTEM asoc
#if !defined(_TRACE_ASOC_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_ASOC_H
#include <linux/ktime.h>
#include <linux/tracepoint.h>
struct snd_soc_jack;
struct snd_soc_codec;
struct snd_soc_card;
struct snd_soc_dapm_widget;
/*
* Log register events
*/
DECLARE_EVENT_CLASS(snd_soc_reg,
TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val),
TP_ARGS(codec, reg, val),
TP_STRUCT__entry(
__string( name, codec->name )
__field( int, id )
__field( unsigned int, reg )
__field( unsigned int, val )
),
TP_fast_assign(
__assign_str(name, codec->name);
__entry->id = codec->id;
__entry->reg = reg;
__entry->val = val;
),
TP_printk("codec=%s.%d reg=%x val=%x", __get_str(name),
(int)__entry->id, (unsigned int)__entry->reg,
(unsigned int)__entry->val)
);
DEFINE_EVENT(snd_soc_reg, snd_soc_reg_write,
TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val),
TP_ARGS(codec, reg, val)
);
DEFINE_EVENT(snd_soc_reg, snd_soc_reg_read,
TP_PROTO(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val),
TP_ARGS(codec, reg, val)
);
DECLARE_EVENT_CLASS(snd_soc_card,
TP_PROTO(struct snd_soc_card *card, int val),
TP_ARGS(card, val),
TP_STRUCT__entry(
__string( name, card->name )
__field( int, val )
),
TP_fast_assign(
__assign_str(name, card->name);
__entry->val = val;
),
TP_printk("card=%s val=%d", __get_str(name), (int)__entry->val)
);
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_start,
TP_PROTO(struct snd_soc_card *card, int val),
TP_ARGS(card, val)
);
DEFINE_EVENT(snd_soc_card, snd_soc_bias_level_done,
TP_PROTO(struct snd_soc_card *card, int val),
TP_ARGS(card, val)
);
DECLARE_EVENT_CLASS(snd_soc_dapm_basic,
TP_PROTO(struct snd_soc_card *card),
TP_ARGS(card),
TP_STRUCT__entry(
__string( name, card->name )
),
TP_fast_assign(
__assign_str(name, card->name);
),
TP_printk("card=%s", __get_str(name))
);
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_start,
TP_PROTO(struct snd_soc_card *card),
TP_ARGS(card)
);
DEFINE_EVENT(snd_soc_dapm_basic, snd_soc_dapm_done,
TP_PROTO(struct snd_soc_card *card),
TP_ARGS(card)
);
DECLARE_EVENT_CLASS(snd_soc_dapm_widget,
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
TP_ARGS(w, val),
TP_STRUCT__entry(
__string( name, w->name )
__field( int, val )
),
TP_fast_assign(
__assign_str(name, w->name);
__entry->val = val;
),
TP_printk("widget=%s val=%d", __get_str(name),
(int)__entry->val)
);
DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_power,
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
TP_ARGS(w, val)
);
DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_start,
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
TP_ARGS(w, val)
);
DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_done,
TP_PROTO(struct snd_soc_dapm_widget *w, int val),
TP_ARGS(w, val)
);
TRACE_EVENT(snd_soc_jack_irq,
TP_PROTO(const char *name),
TP_ARGS(name),
TP_STRUCT__entry(
__string( name, name )
),
TP_fast_assign(
__assign_str(name, name);
),
TP_printk("%s", __get_str(name))
);
TRACE_EVENT(snd_soc_jack_report,
TP_PROTO(struct snd_soc_jack *jack, int mask, int val),
TP_ARGS(jack, mask, val),
TP_STRUCT__entry(
__string( name, jack->jack->name )
__field( int, mask )
__field( int, val )
),
TP_fast_assign(
__assign_str(name, jack->jack->name);
__entry->mask = mask;
__entry->val = val;
),
TP_printk("jack=%s %x/%x", __get_str(name), (int)__entry->val,
(int)__entry->mask)
);
TRACE_EVENT(snd_soc_jack_notify,
TP_PROTO(struct snd_soc_jack *jack, int val),
TP_ARGS(jack, val),
TP_STRUCT__entry(
__string( name, jack->jack->name )
__field( int, val )
),
TP_fast_assign(
__assign_str(name, jack->jack->name);
__entry->val = val;
),
TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
);
#endif /* _TRACE_ASOC_H */
/* This part must be outside protection */
#include <trace/define_trace.h>

View File

@ -20,6 +20,21 @@ menuconfig SND_SOC
if SND_SOC
config SND_SOC_CACHE_LZO
bool "Support LZO compression for register caches"
select LZO_COMPRESS
select LZO_DECOMPRESS
---help---
Select this to enable LZO compression for register caches.
This will allow machine or CODEC drivers to compress register
caches in memory, reducing the memory consumption at the
expense of performance. If this is not present and is used
the system will fall back to uncompressed caches.
Usually it is safe to disable this option, where cache
compression in used the rbtree option will typically perform
better.
config SND_SOC_AC97_BUS
bool
@ -36,7 +51,7 @@ 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/samsung/Kconfig"
source "sound/soc/s6000/Kconfig"
source "sound/soc/sh/Kconfig"
source "sound/soc/txx9/Kconfig"

View File

@ -14,7 +14,7 @@ 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) += samsung/
obj-$(CONFIG_SND_SOC) += s6000/
obj-$(CONFIG_SND_SOC) += sh/
obj-$(CONFIG_SND_SOC) += txx9/

View File

@ -33,7 +33,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <mach/at32ap700x.h>
#include <mach/portmux.h>
@ -318,27 +317,28 @@ static const struct snd_soc_dapm_route intercon[] = {
static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int i;
/*
* Add DAPM widgets
*/
for (i = 0; i < ARRAY_SIZE(playpaq_dapm_widgets); i++)
snd_soc_dapm_new_control(codec, &playpaq_dapm_widgets[i]);
snd_soc_dapm_new_control(dapm, &playpaq_dapm_widgets[i]);
/*
* Setup audio path interconnects
*/
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
/* always connected pins */
snd_soc_dapm_enable_pin(codec, "Int Mic");
snd_soc_dapm_enable_pin(codec, "Ext Spk");
snd_soc_dapm_sync(codec);
snd_soc_dapm_enable_pin(dapm, "Int Mic");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_sync(dapm);

View File

@ -44,7 +44,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
@ -140,6 +139,7 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
printk(KERN_DEBUG
@ -154,25 +154,25 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
}
/* Add specific widgets */
snd_soc_dapm_new_controls(codec, at91sam9g20ek_dapm_widgets,
snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets,
ARRAY_SIZE(at91sam9g20ek_dapm_widgets));
/* Set up specific audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
/* not connected */
snd_soc_dapm_nc_pin(codec, "RLINEIN");
snd_soc_dapm_nc_pin(codec, "LLINEIN");
snd_soc_dapm_nc_pin(dapm, "RLINEIN");
snd_soc_dapm_nc_pin(dapm, "LLINEIN");
#ifdef ENABLE_MIC_INPUT
snd_soc_dapm_enable_pin(codec, "Int Mic");
snd_soc_dapm_enable_pin(dapm, "Int Mic");
#else
snd_soc_dapm_nc_pin(codec, "Int Mic");
snd_soc_dapm_nc_pin(dapm, "Int Mic");
#endif
/* always connected */
snd_soc_dapm_enable_pin(codec, "Ext Spk");
snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_sync(codec);
snd_soc_dapm_sync(dapm);
return 0;
}

View File

@ -30,7 +30,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/mach-types.h>
#include <mach/hardware.h>
@ -105,19 +104,20 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
struct snd_soc_dapm_context *dapm = &codec->dapm;
/* Add afeb9260 specific widgets */
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
/* Set up afeb9260 specific audio path audio_map */
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_enable_pin(codec, "Headphone Jack");
snd_soc_dapm_enable_pin(codec, "Line In");
snd_soc_dapm_enable_pin(codec, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Line In");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_sync(codec);
snd_soc_dapm_sync(dapm);
return 0;
}

View File

@ -13,7 +13,6 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <asm/mach-au1x00/au1000.h>
#include <asm/mach-au1x00/au1xxx_psc.h>
#include <asm/mach-au1x00/au1xxx_dbdma.h>

View File

@ -20,7 +20,6 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>

View File

@ -29,7 +29,6 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>

View File

@ -35,7 +35,6 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm_params.h>
#include <asm/blackfin.h>

View File

@ -33,7 +33,6 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/pcm_params.h>
#include <asm/dma.h>

View File

@ -19,10 +19,10 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <sound/jack.h>
#include <trace/events/asoc.h>
#include "88pm860x-codec.h"
@ -146,7 +146,6 @@ struct pm860x_priv {
int irq[4];
unsigned char name[4][MAX_NAME_LEN];
unsigned char reg_cache[REG_CACHE_SIZE];
};
/* -9450dB to 0dB in 150dB steps ( mute instead of -9450dB) */
@ -1172,7 +1171,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Enable Audio PLL & Audio section */
data = AUDIO_PLL | AUDIO_SECTION_RESET
| AUDIO_SECTION_ON;
@ -1185,7 +1184,7 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
pm860x_set_bits(codec->control_data, REG_MISC2, data, 0);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -1263,6 +1262,12 @@ static irqreturn_t pm860x_codec_handler(int irq, void *data)
mask = pm860x->det.hs_shrt | pm860x->det.hook_det | pm860x->det.lo_shrt
| pm860x->det.hp_det;
#ifndef CONFIG_SND_SOC_88PM860X_MODULE
if (status & (HEADSET_STATUS | MIC_STATUS | SHORT_HS1 | SHORT_HS2 |
SHORT_LO1 | SHORT_LO2))
trace_snd_soc_jack_irq(dev_name(pm860x->codec->dev));
#endif
if ((pm860x->det.hp_det & SND_JACK_HEADPHONE)
&& (status & HEADSET_STATUS))
report |= SND_JACK_HEADPHONE;
@ -1346,6 +1351,7 @@ EXPORT_SYMBOL_GPL(pm860x_mic_jack_detect);
static int pm860x_probe(struct snd_soc_codec *codec)
{
struct pm860x_priv *pm860x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int i, ret;
pm860x->codec = codec;
@ -1358,7 +1364,7 @@ static int pm860x_probe(struct snd_soc_codec *codec)
pm860x->name[i], pm860x);
if (ret < 0) {
dev_err(codec->dev, "Failed to request IRQ!\n");
goto out_irq;
goto out;
}
}
@ -1369,22 +1375,20 @@ static int pm860x_probe(struct snd_soc_codec *codec)
if (ret < 0) {
dev_err(codec->dev, "Failed to fill register cache: %d\n",
ret);
goto out_codec;
goto out;
}
snd_soc_add_controls(codec, pm860x_snd_controls,
ARRAY_SIZE(pm860x_snd_controls));
snd_soc_dapm_new_controls(codec, pm860x_dapm_widgets,
snd_soc_dapm_new_controls(dapm, pm860x_dapm_widgets,
ARRAY_SIZE(pm860x_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
out_codec:
i = 3;
out_irq:
for (; i >= 0; i--)
out:
while (--i >= 0)
free_irq(pm860x->irq[i], pm860x);
return -EINVAL;
return ret;
}
static int pm860x_remove(struct snd_soc_codec *codec)

View File

@ -22,6 +22,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_AK4535 if I2C
select SND_SOC_AK4642 if I2C
select SND_SOC_AK4671 if I2C
select SND_SOC_ALC5623 if I2C
select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS42L51 if I2C
select SND_SOC_CS4270 if I2C
@ -54,9 +55,11 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8727
select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8770 if SPI_MASTER
select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8804 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM8900 if I2C
@ -75,6 +78,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8990 if I2C
select SND_SOC_WM8993 if I2C
select SND_SOC_WM8994 if MFD_WM8994
select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI
select SND_SOC_WM9081 if I2C
select SND_SOC_WM9090 if I2C
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
@ -130,6 +134,9 @@ config SND_SOC_AK4642
config SND_SOC_AK4671
tristate
config SND_SOC_ALC5623
tristate
config SND_SOC_CQ0093VC
tristate
@ -160,6 +167,9 @@ config SND_SOC_L3
config SND_SOC_DA7210
tristate
config SND_SOC_DMIC
tristate
config SND_SOC_MAX98088
tristate
@ -231,6 +241,9 @@ config SND_SOC_WM8728
config SND_SOC_WM8731
tristate
config SND_SOC_WM8737
tristate
config SND_SOC_WM8741
tristate
@ -240,6 +253,9 @@ config SND_SOC_WM8750
config SND_SOC_WM8753
tristate
config SND_SOC_WM8770
tristate
config SND_SOC_WM8776
tristate
@ -294,6 +310,9 @@ config SND_SOC_WM8993
config SND_SOC_WM8994
tristate
config SND_SOC_WM8995
tristate
config SND_SOC_WM9081
tristate
@ -318,3 +337,4 @@ config SND_SOC_WM2000
config SND_SOC_WM9090
tristate

View File

@ -14,9 +14,11 @@ snd-soc-cs42l51-objs := cs42l51.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
snd-soc-dmic-objs := dmic.o
snd-soc-l3-objs := l3.o
snd-soc-max98088-objs := max98088.o
snd-soc-pcm3008-objs := pcm3008.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-spdif-objs := spdif_transciever.o
snd-soc-ssm2602-objs := ssm2602.o
snd-soc-stac9766-objs := stac9766.o
@ -38,9 +40,11 @@ snd-soc-wm8711-objs := wm8711.o
snd-soc-wm8727-objs := wm8727.o
snd-soc-wm8728-objs := wm8728.o
snd-soc-wm8731-objs := wm8731.o
snd-soc-wm8737-objs := wm8737.o
snd-soc-wm8741-objs := wm8741.o
snd-soc-wm8750-objs := wm8750.o
snd-soc-wm8753-objs := wm8753.o
snd-soc-wm8770-objs := wm8770.o
snd-soc-wm8776-objs := wm8776.o
snd-soc-wm8804-objs := wm8804.o
snd-soc-wm8900-objs := wm8900.o
@ -58,7 +62,8 @@ snd-soc-wm8985-objs := wm8985.o
snd-soc-wm8988-objs := wm8988.o
snd-soc-wm8990-objs := wm8990.o
snd-soc-wm8993-objs := wm8993.o
snd-soc-wm8994-objs := wm8994.o
snd-soc-wm8994-objs := wm8994.o wm8994-tables.o
snd-soc-wm8995-objs := wm8995.o
snd-soc-wm9081-objs := wm9081.o
snd-soc-wm9705-objs := wm9705.o
snd-soc-wm9712-objs := wm9712.o
@ -88,10 +93,12 @@ 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
obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o
obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o
obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o
obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
@ -113,9 +120,11 @@ obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o
obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o
obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o
obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o
obj-$(CONFIG_SND_SOC_WM8737) += snd-soc-wm8737.o
obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o
obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o
obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o
obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o
obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o
obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o
obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o
@ -134,6 +143,7 @@ obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o
obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o
obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o
obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o
obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o
obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o
obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o
obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o

View File

@ -27,7 +27,6 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/soc-dapm.h>
#include <linux/spi/spi.h>
#include "ad1836.h"
@ -220,6 +219,7 @@ static struct snd_soc_dai_driver ad1836_dai = {
static int ad1836_probe(struct snd_soc_codec *codec)
{
struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0;
codec->control_data = ad1836->control_data;
@ -227,7 +227,6 @@ static int ad1836_probe(struct snd_soc_codec *codec)
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n",
ret);
kfree(ad1836);
return ret;
}
@ -252,9 +251,9 @@ static int ad1836_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, ad1836_snd_controls,
ARRAY_SIZE(ad1836_snd_controls));
snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets,
snd_soc_dapm_new_controls(dapm, ad1836_dapm_widgets,
ARRAY_SIZE(ad1836_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
return ret;
}

View File

@ -19,12 +19,10 @@
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/soc-dapm.h>
#include "ad193x.h"
/* codec private data */
struct ad193x_priv {
u8 reg_cache[AD193X_NUM_REGS];
enum snd_soc_control_type bus_type;
void *control_data;
int sysclk;
@ -353,6 +351,7 @@ static struct snd_soc_dai_driver ad193x_dai = {
static int ad193x_probe(struct snd_soc_codec *codec)
{
struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
codec->control_data = ad193x->control_data;
@ -363,7 +362,6 @@ static int ad193x_probe(struct snd_soc_codec *codec)
if (ret < 0) {
dev_err(codec->dev, "failed to set cache I/O: %d\n",
ret);
kfree(ad193x);
return ret;
}
@ -385,9 +383,9 @@ static int ad193x_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, ad193x_snd_controls,
ARRAY_SIZE(ad193x_snd_controls));
snd_soc_dapm_new_controls(codec, ad193x_dapm_widgets,
snd_soc_dapm_new_controls(dapm, ad193x_dapm_widgets,
ARRAY_SIZE(ad193x_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
return ret;
}

View File

@ -29,7 +29,6 @@
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include "ad1980.h"

View File

@ -24,7 +24,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "ak4535.h"
@ -290,10 +289,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int ak4535_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, ak4535_dapm_widgets,
ARRAY_SIZE(ak4535_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, ak4535_dapm_widgets,
ARRAY_SIZE(ak4535_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -366,9 +366,9 @@ static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int ak4535_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
if (!mute)
ak4535_write(codec, AK4535_DAC, mute_reg);
ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
else
ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
return 0;
@ -381,11 +381,11 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
switch (level) {
case SND_SOC_BIAS_ON:
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
ak4535_write(codec, AK4535_DAC, mute_reg);
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
break;
case SND_SOC_BIAS_PREPARE:
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC) & 0xffdf;
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC);
ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
break;
case SND_SOC_BIAS_STANDBY:
@ -399,7 +399,7 @@ static int ak4535_set_bias_level(struct snd_soc_codec *codec,
ak4535_write(codec, AK4535_PM1, i & (~0x80));
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -26,7 +26,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/soc-dapm.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>

View File

@ -17,7 +17,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -28,7 +27,6 @@
struct ak4671_priv {
enum snd_soc_control_type control_type;
void *control_data;
u8 reg_cache[AK4671_CACHEREGNUM];
};
/* ak4671 register cache & default register settings */
@ -437,10 +435,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int ak4671_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, ak4671_dapm_widgets,
ARRAY_SIZE(ak4671_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, ak4671_dapm_widgets,
ARRAY_SIZE(ak4671_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -602,7 +601,7 @@ static int ak4671_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

1117
sound/soc/codecs/alc5623.c Normal file

File diff suppressed because it is too large Load Diff

161
sound/soc/codecs/alc5623.h Normal file
View File

@ -0,0 +1,161 @@
/*
* alc5623.h -- alc562[123] ALSA Soc Audio driver
*
* Copyright 2008 Realtek Microelectronics
* Copyright 2010 Arnaud Patard <arnaud.patard@rtp-net.org>
*
* Author: flove <flove@realtek.com>
* Arnaud Patard <arnaud.patard@rtp-net.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _ALC5623_H
#define _ALC5623_H
#define ALC5623_RESET 0x00
/* 5621 5622 5623 */
/* speaker output vol 2 2 */
/* line output vol 4 2 */
/* HP output vol 4 0 4 */
#define ALC5623_SPK_OUT_VOL 0x02
#define ALC5623_HP_OUT_VOL 0x04
#define ALC5623_MONO_AUX_OUT_VOL 0x06
#define ALC5623_AUXIN_VOL 0x08
#define ALC5623_LINE_IN_VOL 0x0A
#define ALC5623_STEREO_DAC_VOL 0x0C
#define ALC5623_MIC_VOL 0x0E
#define ALC5623_MIC_ROUTING_CTRL 0x10
#define ALC5623_ADC_REC_GAIN 0x12
#define ALC5623_ADC_REC_MIXER 0x14
#define ALC5623_SOFT_VOL_CTRL_TIME 0x16
/* ALC5623_OUTPUT_MIXER_CTRL : */
/* same remark as for reg 2 line vs speaker */
#define ALC5623_OUTPUT_MIXER_CTRL 0x1C
#define ALC5623_MIC_CTRL 0x22
#define ALC5623_DAI_CONTROL 0x34
#define ALC5623_DAI_SDP_MASTER_MODE (0 << 15)
#define ALC5623_DAI_SDP_SLAVE_MODE (1 << 15)
#define ALC5623_DAI_I2S_PCM_MODE (1 << 14)
#define ALC5623_DAI_MAIN_I2S_BCLK_POL_CTRL (1 << 7)
#define ALC5623_DAI_ADC_DATA_L_R_SWAP (1 << 5)
#define ALC5623_DAI_DAC_DATA_L_R_SWAP (1 << 4)
#define ALC5623_DAI_I2S_DL_MASK (3 << 2)
#define ALC5623_DAI_I2S_DL_32 (3 << 2)
#define ALC5623_DAI_I2S_DL_24 (2 << 2)
#define ALC5623_DAI_I2S_DL_20 (1 << 2)
#define ALC5623_DAI_I2S_DL_16 (0 << 2)
#define ALC5623_DAI_I2S_DF_PCM (3 << 0)
#define ALC5623_DAI_I2S_DF_LEFT (2 << 0)
#define ALC5623_DAI_I2S_DF_RIGHT (1 << 0)
#define ALC5623_DAI_I2S_DF_I2S (0 << 0)
#define ALC5623_STEREO_AD_DA_CLK_CTRL 0x36
#define ALC5623_COMPANDING_CTRL 0x38
#define ALC5623_PWR_MANAG_ADD1 0x3A
#define ALC5623_PWR_ADD1_MAIN_I2S_EN (1 << 15)
#define ALC5623_PWR_ADD1_ZC_DET_PD_EN (1 << 14)
#define ALC5623_PWR_ADD1_MIC1_BIAS_EN (1 << 11)
#define ALC5623_PWR_ADD1_SHORT_CURR_DET_EN (1 << 10)
#define ALC5623_PWR_ADD1_SOFTGEN_EN (1 << 8) /* rsvd on 5622 */
#define ALC5623_PWR_ADD1_DEPOP_BUF_HP (1 << 6) /* rsvd on 5622 */
#define ALC5623_PWR_ADD1_HP_OUT_AMP (1 << 5)
#define ALC5623_PWR_ADD1_HP_OUT_ENH_AMP (1 << 4) /* rsvd on 5622 */
#define ALC5623_PWR_ADD1_DEPOP_BUF_AUX (1 << 2)
#define ALC5623_PWR_ADD1_AUX_OUT_AMP (1 << 1)
#define ALC5623_PWR_ADD1_AUX_OUT_ENH_AMP (1 << 0) /* rsvd on 5622 */
#define ALC5623_PWR_MANAG_ADD2 0x3C
#define ALC5623_PWR_ADD2_LINEOUT (1 << 15) /* rt5623 */
#define ALC5623_PWR_ADD2_CLASS_AB (1 << 15) /* rt5621 */
#define ALC5623_PWR_ADD2_CLASS_D (1 << 14) /* rt5621 */
#define ALC5623_PWR_ADD2_VREF (1 << 13)
#define ALC5623_PWR_ADD2_PLL (1 << 12)
#define ALC5623_PWR_ADD2_DAC_REF_CIR (1 << 10)
#define ALC5623_PWR_ADD2_L_DAC_CLK (1 << 9)
#define ALC5623_PWR_ADD2_R_DAC_CLK (1 << 8)
#define ALC5623_PWR_ADD2_L_ADC_CLK_GAIN (1 << 7)
#define ALC5623_PWR_ADD2_R_ADC_CLK_GAIN (1 << 6)
#define ALC5623_PWR_ADD2_L_HP_MIXER (1 << 5)
#define ALC5623_PWR_ADD2_R_HP_MIXER (1 << 4)
#define ALC5623_PWR_ADD2_SPK_MIXER (1 << 3)
#define ALC5623_PWR_ADD2_MONO_MIXER (1 << 2)
#define ALC5623_PWR_ADD2_L_ADC_REC_MIXER (1 << 1)
#define ALC5623_PWR_ADD2_R_ADC_REC_MIXER (1 << 0)
#define ALC5623_PWR_MANAG_ADD3 0x3E
#define ALC5623_PWR_ADD3_MAIN_BIAS (1 << 15)
#define ALC5623_PWR_ADD3_AUXOUT_L_VOL_AMP (1 << 14)
#define ALC5623_PWR_ADD3_AUXOUT_R_VOL_AMP (1 << 13)
#define ALC5623_PWR_ADD3_SPK_OUT (1 << 12)
#define ALC5623_PWR_ADD3_HP_L_OUT_VOL (1 << 10)
#define ALC5623_PWR_ADD3_HP_R_OUT_VOL (1 << 9)
#define ALC5623_PWR_ADD3_LINEIN_L_VOL (1 << 7)
#define ALC5623_PWR_ADD3_LINEIN_R_VOL (1 << 6)
#define ALC5623_PWR_ADD3_AUXIN_L_VOL (1 << 5)
#define ALC5623_PWR_ADD3_AUXIN_R_VOL (1 << 4)
#define ALC5623_PWR_ADD3_MIC1_FUN_CTRL (1 << 3)
#define ALC5623_PWR_ADD3_MIC2_FUN_CTRL (1 << 2)
#define ALC5623_PWR_ADD3_MIC1_BOOST_AD (1 << 1)
#define ALC5623_PWR_ADD3_MIC2_BOOST_AD (1 << 0)
#define ALC5623_ADD_CTRL_REG 0x40
#define ALC5623_GLOBAL_CLK_CTRL_REG 0x42
#define ALC5623_GBL_CLK_SYS_SOUR_SEL_PLL (1 << 15)
#define ALC5623_GBL_CLK_SYS_SOUR_SEL_MCLK (0 << 15)
#define ALC5623_GBL_CLK_PLL_SOUR_SEL_BITCLK (1 << 14)
#define ALC5623_GBL_CLK_PLL_SOUR_SEL_MCLK (0 << 14)
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV8 (3 << 1)
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV4 (2 << 1)
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV2 (1 << 1)
#define ALC5623_GBL_CLK_PLL_DIV_RATIO_DIV1 (0 << 1)
#define ALC5623_GBL_CLK_PLL_PRE_DIV2 (1 << 0)
#define ALC5623_GBL_CLK_PLL_PRE_DIV1 (0 << 0)
#define ALC5623_PLL_CTRL 0x44
#define ALC5623_PLL_CTRL_N_VAL(n) (((n)&0xff) << 8)
#define ALC5623_PLL_CTRL_K_VAL(k) (((k)&0x7) << 4)
#define ALC5623_PLL_CTRL_M_VAL(m) ((m)&0xf)
#define ALC5623_GPIO_OUTPUT_PIN_CTRL 0x4A
#define ALC5623_GPIO_PIN_CONFIG 0x4C
#define ALC5623_GPIO_PIN_POLARITY 0x4E
#define ALC5623_GPIO_PIN_STICKY 0x50
#define ALC5623_GPIO_PIN_WAKEUP 0x52
#define ALC5623_GPIO_PIN_STATUS 0x54
#define ALC5623_GPIO_PIN_SHARING 0x56
#define ALC5623_OVER_CURR_STATUS 0x58
#define ALC5623_JACK_DET_CTRL 0x5A
#define ALC5623_MISC_CTRL 0x5E
#define ALC5623_MISC_DISABLE_FAST_VREG (1 << 15)
#define ALC5623_MISC_SPK_CLASS_AB_OC_PD (1 << 13) /* 5621 */
#define ALC5623_MISC_SPK_CLASS_AB_OC_DET (1 << 12) /* 5621 */
#define ALC5623_MISC_HP_DEPOP_MODE3_EN (1 << 10)
#define ALC5623_MISC_HP_DEPOP_MODE2_EN (1 << 9)
#define ALC5623_MISC_HP_DEPOP_MODE1_EN (1 << 8)
#define ALC5623_MISC_AUXOUT_DEPOP_MODE3_EN (1 << 6)
#define ALC5623_MISC_AUXOUT_DEPOP_MODE2_EN (1 << 5)
#define ALC5623_MISC_AUXOUT_DEPOP_MODE1_EN (1 << 4)
#define ALC5623_MISC_M_DAC_L_INPUT (1 << 3)
#define ALC5623_MISC_M_DAC_R_INPUT (1 << 2)
#define ALC5623_MISC_IRQOUT_INV_CTRL (1 << 0)
#define ALC5623_PSEDUEO_SPATIAL_CTRL 0x60
#define ALC5623_EQ_CTRL 0x62
#define ALC5623_EQ_MODE_ENABLE 0x66
#define ALC5623_AVC_CTRL 0x68
#define ALC5623_HID_CTRL_INDEX 0x6A
#define ALC5623_HID_CTRL_DATA 0x6C
#define ALC5623_VENDOR_ID1 0x7C
#define ALC5623_VENDOR_ID2 0x7E
#define ALC5623_PLL_FR_MCLK 0
#define ALC5623_PLL_FR_BCK 1
#endif

View File

@ -36,8 +36,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dai.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <mach/dm365.h>
@ -116,7 +114,7 @@ static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
DAVINCI_VC_REG12_POWER_ALL_OFF);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -106,6 +106,21 @@
#define CS4270_MUTE_DAC_A 0x01
#define CS4270_MUTE_DAC_B 0x02
/* Power-on default values for the registers
*
* This array contains the power-on default values of the registers, with the
* exception of the "CHIPID" register (01h). The lower four bits of that
* register contain the hardware revision, so it is treated as volatile.
*
* Also note that on the CS4270, the first readable register is 1, but ASoC
* assumes the first register is 0. Therfore, the array must have an entry for
* register 0, but we use cs4270_reg_is_readable() to tell ASoC that it can't
* be read.
*/
static const u8 cs4270_default_reg_cache[CS4270_LASTREG + 1] = {
0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x20, 0x00, 0x00
};
static const char *supply_names[] = {
"va", "vd", "vlc"
};
@ -114,7 +129,6 @@ static const char *supply_names[] = {
struct cs4270_private {
enum snd_soc_control_type control_type;
void *control_data;
u8 reg_cache[CS4270_NUMREGS];
unsigned int mclk; /* Input frequency of the MCLK pin */
unsigned int mode; /* The mode (I2S or left-justified) */
unsigned int slave_mode;
@ -179,6 +193,20 @@ static struct cs4270_mode_ratios cs4270_mode_ratios[] = {
/* The number of MCLK/LRCK ratios supported by the CS4270 */
#define NUM_MCLK_RATIOS ARRAY_SIZE(cs4270_mode_ratios)
static int cs4270_reg_is_readable(unsigned int reg)
{
return (reg >= CS4270_FIRSTREG) && (reg <= CS4270_LASTREG);
}
static int cs4270_reg_is_volatile(unsigned int reg)
{
/* Unreadable registers are considered volatile */
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
return 1;
return reg == CS4270_CHIPID;
}
/**
* cs4270_set_dai_sysclk - determine the CS4270 samples rates.
* @codec_dai: the codec DAI
@ -263,97 +291,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
return ret;
}
/**
* cs4270_fill_cache - pre-fill the CS4270 register cache.
* @codec: the codec for this CS4270
*
* This function fills in the CS4270 register cache by reading the register
* values from the hardware.
*
* This CS4270 registers are cached to avoid excessive I2C I/O operations.
* After the initial read to pre-fill the cache, the CS4270 never updates
* the register values, so we won't have a cache coherency problem.
*
* We use the auto-increment feature of the CS4270 to read all registers in
* one shot.
*/
static int cs4270_fill_cache(struct snd_soc_codec *codec)
{
u8 *cache = codec->reg_cache;
struct i2c_client *i2c_client = codec->control_data;
s32 length;
length = i2c_smbus_read_i2c_block_data(i2c_client,
CS4270_FIRSTREG | CS4270_I2C_INCR, CS4270_NUMREGS, cache);
if (length != CS4270_NUMREGS) {
dev_err(codec->dev, "i2c read failure, addr=0x%x\n",
i2c_client->addr);
return -EIO;
}
return 0;
}
/**
* cs4270_read_reg_cache - read from the CS4270 register cache.
* @codec: the codec for this CS4270
* @reg: the register to read
*
* This function returns the value for a given register. It reads only from
* the register cache, not the hardware itself.
*
* This CS4270 registers are cached to avoid excessive I2C I/O operations.
* After the initial read to pre-fill the cache, the CS4270 never updates
* the register values, so we won't have a cache coherency problem.
*/
static unsigned int cs4270_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u8 *cache = codec->reg_cache;
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
return -EIO;
return cache[reg - CS4270_FIRSTREG];
}
/**
* cs4270_i2c_write - write to a CS4270 register via the I2C bus.
* @codec: the codec for this CS4270
* @reg: the register to write
* @value: the value to write to the register
*
* This function writes the given value to the given CS4270 register, and
* also updates the register cache.
*
* Note that we don't use the hw_write function pointer of snd_soc_codec.
* That's because it's too clunky: the hw_write_t prototype does not match
* i2c_smbus_write_byte_data(), and it's just another layer of overhead.
*/
static int cs4270_i2c_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 *cache = codec->reg_cache;
if ((reg < CS4270_FIRSTREG) || (reg > CS4270_LASTREG))
return -EIO;
/* Only perform an I2C operation if the new value is different */
if (cache[reg - CS4270_FIRSTREG] != value) {
struct i2c_client *client = codec->control_data;
if (i2c_smbus_write_byte_data(client, reg, value)) {
dev_err(codec->dev, "i2c write failed\n");
return -EIO;
}
/* We've written to the hardware, so update the cache */
cache[reg - CS4270_FIRSTREG] = value;
}
return 0;
}
/**
* cs4270_hw_params - program the CS4270 with the given hardware parameters.
* @substream: the audio stream
@ -551,15 +488,16 @@ static struct snd_soc_dai_driver cs4270_dai = {
static int cs4270_probe(struct snd_soc_codec *codec)
{
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int i, ret, reg;
int i, ret;
codec->control_data = cs4270->control_data;
/* The I2C interface is set up, so pre-fill our register cache */
ret = cs4270_fill_cache(codec);
/* Tell ASoC what kind of I/O to use to read the registers. ASoC will
* then do the I2C transactions itself.
*/
ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs4270->control_type);
if (ret < 0) {
dev_err(codec->dev, "failed to fill register cache\n");
dev_err(codec->dev, "failed to set cache I/O (ret=%i)\n", ret);
return ret;
}
@ -568,10 +506,7 @@ static int cs4270_probe(struct snd_soc_codec *codec)
* this feature disabled by default. An application (e.g. alsactl) can
* re-enabled it by using the controls.
*/
reg = cs4270_read_reg_cache(codec, CS4270_MUTE);
reg &= ~CS4270_MUTE_AUTO;
ret = cs4270_i2c_write(codec, CS4270_MUTE, reg);
ret = snd_soc_update_bits(codec, CS4270_MUTE, CS4270_MUTE_AUTO, 0);
if (ret < 0) {
dev_err(codec->dev, "i2c write failed\n");
return ret;
@ -582,10 +517,8 @@ static int cs4270_probe(struct snd_soc_codec *codec)
* playback has started. An application (e.g. alsactl) can
* re-enabled it by using the controls.
*/
reg = cs4270_read_reg_cache(codec, CS4270_TRANS);
reg &= ~(CS4270_TRANS_SOFT | CS4270_TRANS_ZERO);
ret = cs4270_i2c_write(codec, CS4270_TRANS, reg);
ret = snd_soc_update_bits(codec, CS4270_TRANS,
CS4270_TRANS_SOFT | CS4270_TRANS_ZERO, 0);
if (ret < 0) {
dev_err(codec->dev, "i2c write failed\n");
return ret;
@ -708,15 +641,16 @@ static int cs4270_soc_resume(struct snd_soc_codec *codec)
* Assign this variable to the codec_dev field of the machine driver's
* snd_soc_device structure.
*/
static struct snd_soc_codec_driver soc_codec_device_cs4270 = {
.probe = cs4270_probe,
.remove = cs4270_remove,
.suspend = cs4270_soc_suspend,
.resume = cs4270_soc_resume,
.read = cs4270_read_reg_cache,
.write = cs4270_i2c_write,
.reg_cache_size = CS4270_NUMREGS,
.reg_word_size = sizeof(u8),
static const struct snd_soc_codec_driver soc_codec_device_cs4270 = {
.probe = cs4270_probe,
.remove = cs4270_remove,
.suspend = cs4270_soc_suspend,
.resume = cs4270_soc_resume,
.volatile_register = cs4270_reg_is_volatile,
.readable_register = cs4270_reg_is_readable,
.reg_cache_size = CS4270_LASTREG + 1,
.reg_word_size = sizeof(u8),
.reg_cache_default = cs4270_default_reg_cache,
};
/**

View File

@ -26,7 +26,6 @@
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <sound/pcm_params.h>
@ -47,7 +46,6 @@ struct cs42l51_private {
unsigned int mclk;
unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func;
u8 reg_cache[CS42L51_NUMREGS];
};
#define CS42L51_FORMATS ( \
@ -519,6 +517,7 @@ static struct snd_soc_dai_driver cs42l51_dai = {
static int cs42l51_probe(struct snd_soc_codec *codec)
{
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret, reg;
codec->control_data = cs42l51->control_data;
@ -550,9 +549,9 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, cs42l51_snd_controls,
ARRAY_SIZE(cs42l51_snd_controls));
snd_soc_dapm_new_controls(codec, cs42l51_dapm_widgets,
snd_soc_dapm_new_controls(dapm, cs42l51_dapm_widgets,
ARRAY_SIZE(cs42l51_dapm_widgets));
snd_soc_dapm_add_routes(codec, cs42l51_routes,
snd_soc_dapm_add_routes(dapm, cs42l51_routes,
ARRAY_SIZE(cs42l51_routes));
return 0;

View File

@ -18,7 +18,7 @@
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/soc-dapm.h>
#include <sound/soc.h>
#include "cx20442.h"
@ -26,7 +26,6 @@
struct cx20442_priv {
enum snd_soc_control_type control_type;
void *control_data;
u8 reg_cache[1];
};
#define CX20442_PM 0x0
@ -89,10 +88,11 @@ static const struct snd_soc_dapm_route cx20442_audio_map[] = {
static int cx20442_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, cx20442_dapm_widgets,
ARRAY_SIZE(cx20442_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, cx20442_audio_map,
snd_soc_dapm_new_controls(dapm, cx20442_dapm_widgets,
ARRAY_SIZE(cx20442_dapm_widgets));
snd_soc_dapm_add_routes(dapm, cx20442_audio_map,
ARRAY_SIZE(cx20442_audio_map));
return 0;
@ -263,7 +263,7 @@ static void v253_close(struct tty_struct *tty)
/* Prevent the codec driver from further accessing the modem */
codec->hw_write = NULL;
cx20442->control_data = NULL;
codec->pop_time = 0;
codec->card->pop_time = 0;
}
/* Line discipline .hangup() */
@ -291,7 +291,7 @@ static void v253_receive(struct tty_struct *tty,
/* Set up codec driver access to modem controls */
cx20442->control_data = tty;
codec->hw_write = (hw_write_t)tty->ops->write;
codec->pop_time = 1;
codec->card->pop_time = 1;
}
}
@ -348,7 +348,7 @@ static int cx20442_codec_probe(struct snd_soc_codec *codec)
cx20442->control_data = NULL;
codec->hw_write = NULL;
codec->pop_time = 0;
codec->card->pop_time = 0;
return 0;
}

View File

@ -21,7 +21,7 @@
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>

81
sound/soc/codecs/dmic.c Normal file
View File

@ -0,0 +1,81 @@
/*
* dmic.c -- SoC audio for Generic Digital MICs
*
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
*
* 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.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
static struct snd_soc_dai_driver dmic_dai = {
.name = "dmic-hifi",
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,
.rates = SNDRV_PCM_RATE_CONTINUOUS,
.formats = SNDRV_PCM_FMTBIT_S32_LE
| SNDRV_PCM_FMTBIT_S24_LE
| SNDRV_PCM_FMTBIT_S16_LE,
},
};
static struct snd_soc_codec_driver soc_dmic = {};
static int __devinit dmic_dev_probe(struct platform_device *pdev)
{
return snd_soc_register_codec(&pdev->dev,
&soc_dmic, &dmic_dai, 1);
}
static int __devexit dmic_dev_remove(struct platform_device *pdev)
{
snd_soc_unregister_codec(&pdev->dev);
return 0;
}
MODULE_ALIAS("platform:dmic-codec");
static struct platform_driver dmic_driver = {
.driver = {
.name = "dmic-codec",
.owner = THIS_MODULE,
},
.probe = dmic_dev_probe,
.remove = __devexit_p(dmic_dev_remove),
};
static int __init dmic_init(void)
{
return platform_driver_register(&dmic_driver);
}
module_init(dmic_init);
static void __exit dmic_exit(void)
{
platform_driver_unregister(&dmic_driver);
}
module_exit(dmic_exit);
MODULE_DESCRIPTION("Generic DMIC driver");
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_LICENSE("GPL");

View File

@ -22,7 +22,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/soc-dapm.h>
#include <sound/soc.h>
#define JZ4740_REG_CODEC_1 0x0
@ -266,7 +265,7 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
/* The only way to clear the suspend flag is to reset the codec */
if (codec->bias_level == SND_SOC_BIAS_OFF)
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
jz4740_codec_wakeup(codec);
mask = JZ4740_CODEC_1_VREF_DISABLE |
@ -288,23 +287,25 @@ static int jz4740_codec_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
static int jz4740_codec_dev_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_update_bits(codec, JZ4740_REG_CODEC_1,
JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE);
snd_soc_add_controls(codec, jz4740_codec_controls,
ARRAY_SIZE(jz4740_codec_controls));
snd_soc_dapm_new_controls(codec, jz4740_codec_dapm_widgets,
snd_soc_dapm_new_controls(dapm, jz4740_codec_dapm_widgets,
ARRAY_SIZE(jz4740_codec_dapm_widgets));
snd_soc_dapm_add_routes(codec, jz4740_codec_dapm_routes,
snd_soc_dapm_add_routes(dapm, jz4740_codec_dapm_routes,
ARRAY_SIZE(jz4740_codec_dapm_routes));
snd_soc_dapm_new_widgets(codec);

View File

@ -20,7 +20,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <linux/slab.h>
@ -1229,15 +1228,17 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int max98088_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, max98088_dapm_widgets,
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, max98088_dapm_widgets,
ARRAY_SIZE(max98088_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
snd_soc_add_controls(codec, max98088_snd_controls,
ARRAY_SIZE(max98088_snd_controls));
snd_soc_dapm_new_widgets(codec);
snd_soc_dapm_new_widgets(dapm);
return 0;
}
@ -1622,7 +1623,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF)
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
max98088_sync_cache(codec);
snd_soc_update_bits(codec, M98088_REG_4C_PWR_EN_IN,
@ -1635,7 +1636,7 @@ static int max98088_set_bias_level(struct snd_soc_codec *codec,
codec->cache_sync = 1;
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -38,7 +38,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "ssm2602.h"
@ -207,10 +206,11 @@ static const struct snd_soc_dapm_route audio_conn[] = {
static int ssm2602_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, ssm2602_dapm_widgets,
ARRAY_SIZE(ssm2602_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_conn, ARRAY_SIZE(audio_conn));
snd_soc_dapm_new_controls(dapm, ssm2602_dapm_widgets,
ARRAY_SIZE(ssm2602_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_conn, ARRAY_SIZE(audio_conn));
return 0;
}
@ -493,7 +493,7 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -236,7 +236,7 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
stac9766_ac97_write(codec, AC97_POWERDOWN, 0xffff);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -30,7 +30,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/initval.h>
@ -391,11 +390,12 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
static int tlv320aic23_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, tlv320aic23_dapm_widgets,
ARRAY_SIZE(tlv320aic23_dapm_widgets));
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -574,7 +574,7 @@ static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -18,7 +18,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "tlv320aic26.h"
@ -31,7 +30,6 @@ MODULE_LICENSE("GPL");
struct aic26 {
struct spi_device *spi;
struct snd_soc_codec codec;
u16 reg_cache[AIC26_NUM_REGS]; /* shadow registers */
int master;
int datfm;
int mclk;
@ -355,7 +353,6 @@ static DEVICE_ATTR(keyclick, 0644, aic26_keyclick_show, aic26_keyclick_set);
*/
static int aic26_probe(struct snd_soc_codec *codec)
{
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
int ret, err, i, reg;
dev_info(codec->dev, "Probing AIC26 SoC CODEC driver\n");
@ -373,7 +370,7 @@ static int aic26_probe(struct snd_soc_codec *codec)
aic26_reg_write(codec, AIC26_REG_AUDIO_CTRL3, reg);
/* Fill register cache */
for (i = 0; i < ARRAY_SIZE(aic26->reg_cache); i++)
for (i = 0; i < codec->driver->reg_cache_size; i++)
aic26_reg_read(codec, i);
/* Register the sysfs files for debugging */

View File

@ -46,7 +46,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/tlv320aic3x.h>
@ -61,6 +60,8 @@ static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"DRVDD", /* ADC Analog and Output Driver Voltage */
};
static LIST_HEAD(reset_list);
struct aic3x_priv;
struct aic3x_disable_nb {
@ -77,6 +78,7 @@ struct aic3x_priv {
struct aic3x_setup_data *setup;
void *control_data;
unsigned int sysclk;
struct list_head list;
int master;
int gpio_reset;
int power;
@ -183,7 +185,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
if (snd_soc_test_bits(widget->codec, reg, val_mask, val)) {
/* find dapm widget path assoc with kcontrol */
list_for_each_entry(path, &widget->codec->dapm_paths, list) {
list_for_each_entry(path, &widget->dapm->card->paths, list) {
if (path->kcontrol != kcontrol)
continue;
@ -199,7 +201,7 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
}
if (found)
snd_soc_dapm_sync(widget->codec);
snd_soc_dapm_sync(widget->dapm);
}
ret = snd_soc_update_bits(widget->codec, reg, val_mask, val);
@ -788,17 +790,19 @@ static const struct snd_soc_dapm_route intercon_3007[] = {
static int aic3x_add_widgets(struct snd_soc_codec *codec)
{
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(codec, aic3x_dapm_widgets,
snd_soc_dapm_new_controls(dapm, aic3x_dapm_widgets,
ARRAY_SIZE(aic3x_dapm_widgets));
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
if (aic3x->model == AIC3X_MODEL_3007) {
snd_soc_dapm_new_controls(codec, aic3007_dapm_widgets,
snd_soc_dapm_new_controls(dapm, aic3007_dapm_widgets,
ARRAY_SIZE(aic3007_dapm_widgets));
snd_soc_dapm_add_routes(codec, intercon_3007, ARRAY_SIZE(intercon_3007));
snd_soc_dapm_add_routes(dapm, intercon_3007,
ARRAY_SIZE(intercon_3007));
}
return 0;
@ -1075,7 +1079,7 @@ static int aic3x_regulator_event(struct notifier_block *nb,
* Put codec to reset and require cache sync as at least one
* of the supplies was disabled
*/
if (aic3x->gpio_reset >= 0)
if (gpio_is_valid(aic3x->gpio_reset))
gpio_set_value(aic3x->gpio_reset, 0);
aic3x->codec->cache_sync = 1;
}
@ -1102,7 +1106,7 @@ static int aic3x_set_power(struct snd_soc_codec *codec, int power)
if (!codec->cache_sync)
goto out;
if (aic3x->gpio_reset >= 0) {
if (gpio_is_valid(aic3x->gpio_reset)) {
udelay(1);
gpio_set_value(aic3x->gpio_reset, 1);
}
@ -1135,7 +1139,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
if (codec->bias_level == SND_SOC_BIAS_STANDBY &&
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY &&
aic3x->master) {
/* enable pll */
reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
@ -1146,7 +1150,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
if (!aic3x->power)
aic3x_set_power(codec, 1);
if (codec->bias_level == SND_SOC_BIAS_PREPARE &&
if (codec->dapm.bias_level == SND_SOC_BIAS_PREPARE &&
aic3x->master) {
/* disable pll */
reg = snd_soc_read(codec, AIC3X_PLL_PROGA_REG);
@ -1159,7 +1163,7 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
aic3x_set_power(codec, 0);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -1344,14 +1348,28 @@ static int aic3x_init(struct snd_soc_codec *codec)
return 0;
}
static bool aic3x_is_shared_reset(struct aic3x_priv *aic3x)
{
struct aic3x_priv *a;
list_for_each_entry(a, &reset_list, list) {
if (gpio_is_valid(aic3x->gpio_reset) &&
aic3x->gpio_reset == a->gpio_reset)
return true;
}
return false;
}
static int aic3x_probe(struct snd_soc_codec *codec)
{
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int ret, i;
INIT_LIST_HEAD(&aic3x->list);
codec->control_data = aic3x->control_data;
aic3x->codec = codec;
codec->idle_bias_off = 1;
codec->dapm.idle_bias_off = 1;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, aic3x->control_type);
if (ret != 0) {
@ -1359,7 +1377,8 @@ static int aic3x_probe(struct snd_soc_codec *codec)
return ret;
}
if (aic3x->gpio_reset >= 0) {
if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x)) {
ret = gpio_request(aic3x->gpio_reset, "tlv320aic3x reset");
if (ret != 0)
goto err_gpio;
@ -1405,6 +1424,7 @@ static int aic3x_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, &aic3x_classd_amp_gain_ctrl, 1);
aic3x_add_widgets(codec);
list_add(&aic3x->list, &reset_list);
return 0;
@ -1414,10 +1434,10 @@ err_notif:
&aic3x->disable_nb[i].nb);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
err_get:
if (aic3x->gpio_reset >= 0)
if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x))
gpio_free(aic3x->gpio_reset);
err_gpio:
kfree(aic3x);
return ret;
}
@ -1427,7 +1447,9 @@ static int aic3x_remove(struct snd_soc_codec *codec)
int i;
aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
if (aic3x->gpio_reset >= 0) {
list_del(&aic3x->list);
if (gpio_is_valid(aic3x->gpio_reset) &&
!aic3x_is_shared_reset(aic3x)) {
gpio_set_value(aic3x->gpio_reset, 0);
gpio_free(aic3x->gpio_reset);
}
@ -1523,21 +1545,6 @@ static struct i2c_driver aic3x_i2c_driver = {
.remove = aic3x_i2c_remove,
.id_table = aic3x_i2c_id,
};
static inline void aic3x_i2c_init(void)
{
int ret;
ret = i2c_add_driver(&aic3x_i2c_driver);
if (ret)
printk(KERN_ERR "%s: error regsitering i2c driver, %d\n",
__func__, ret);
}
static inline void aic3x_i2c_exit(void)
{
i2c_del_driver(&aic3x_i2c_driver);
}
#endif
static int __init aic3x_modinit(void)

View File

@ -36,21 +36,21 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/tlv320dac33-plat.h>
#include "tlv320dac33.h"
#define DAC33_BUFFER_SIZE_BYTES 24576 /* bytes, 12288 16 bit words,
* 6144 stereo */
#define DAC33_BUFFER_SIZE_SAMPLES 6144
#define NSAMPLE_MAX 5700
#define MODE7_LTHR 10
#define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10)
/*
* The internal FIFO is 24576 bytes long
* It can be configured to hold 16bit or 24bit samples
* In 16bit configuration the FIFO can hold 6144 stereo samples
* In 24bit configuration the FIFO can hold 4096 stereo samples
*/
#define DAC33_FIFO_SIZE_16BIT 6144
#define DAC33_FIFO_SIZE_24BIT 4096
#define DAC33_MODE7_MARGIN 10 /* Safety margin for FIFO in Mode7 */
#define BURST_BASEFREQ_HZ 49152000
@ -100,16 +100,11 @@ struct tlv320dac33_priv {
unsigned int refclk;
unsigned int alarm_threshold; /* set to be half of LATENCY_TIME_MS */
unsigned int nsample_min; /* nsample should not be lower than
* this */
unsigned int nsample_max; /* nsample should not be higher than
* this */
enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
unsigned int fifo_size; /* Size of the FIFO in samples */
unsigned int nsample; /* burst read amount from host */
int mode1_latency; /* latency caused by the i2c writes in
* us */
int auto_fifo_config; /* Configure the FIFO based on the
* period size */
u8 burst_bclkdiv; /* BCLK divider value in burst mode */
unsigned int burst_rate; /* Interface speed in Burst modes */
@ -303,7 +298,6 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
if (unlikely(!dac33->chip_power))
return;
/* 44-46: DAC Control Registers */
/* A : DAC sample rate Fsref/1.5 */
dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
/* B : DAC src=normal, not muted */
@ -316,8 +310,6 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
clock source = internal osc (?) */
dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
/* Restore only selected registers (gains mostly) */
dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL,
dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL));
@ -328,6 +320,10 @@ static void dac33_init_chip(struct snd_soc_codec *codec)
dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL));
dac33_write(codec, DAC33_LINER_TO_RLO_VOL,
dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
dac33_write(codec, DAC33_OUT_AMP_CTRL,
dac33_read_reg_cache(codec, DAC33_OUT_AMP_CTRL));
}
static inline int dac33_read_id(struct snd_soc_codec *codec)
@ -357,6 +353,21 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
dac33_write(codec, DAC33_PWR_CTRL, reg);
}
static inline void dac33_disable_digital(struct snd_soc_codec *codec)
{
u8 reg;
/* Stop the DAI clock */
reg = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_B);
reg &= ~DAC33_BCLKON;
dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_B, reg);
/* Power down the Oscillator, and DACs */
reg = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
reg &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
dac33_write(codec, DAC33_PWR_CTRL, reg);
}
static int dac33_hard_power(struct snd_soc_codec *codec, int power)
{
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
@ -405,7 +416,7 @@ exit:
return ret;
}
static int playback_event(struct snd_soc_dapm_widget *w,
static int dac33_playback_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
@ -417,77 +428,13 @@ static int playback_event(struct snd_soc_dapm_widget *w,
dac33_prepare_chip(dac33->substream);
}
break;
case SND_SOC_DAPM_POST_PMD:
dac33_disable_digital(w->codec);
break;
}
return 0;
}
static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = dac33->nsample;
return 0;
}
static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
if (dac33->nsample == ucontrol->value.integer.value[0])
return 0;
if (ucontrol->value.integer.value[0] < dac33->nsample_min ||
ucontrol->value.integer.value[0] > dac33->nsample_max) {
ret = -EINVAL;
} else {
dac33->nsample = ucontrol->value.integer.value[0];
/* Re calculate the burst time */
dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
dac33->nsample);
}
return ret;
}
static int dac33_get_uthr(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.integer.value[0] = dac33->uthr;
return 0;
}
static int dac33_set_uthr(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
if (dac33->substream)
return -EBUSY;
if (dac33->uthr == ucontrol->value.integer.value[0])
return 0;
if (ucontrol->value.integer.value[0] < (MODE7_LTHR + 10) ||
ucontrol->value.integer.value[0] > MODE7_UTHR)
ret = -EINVAL;
else
dac33->uthr = ucontrol->value.integer.value[0];
return ret;
}
static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@ -572,13 +519,6 @@ static const struct snd_kcontrol_new dac33_mode_snd_controls[] = {
dac33_get_fifo_mode, dac33_set_fifo_mode),
};
static const struct snd_kcontrol_new dac33_fifo_snd_controls[] = {
SOC_SINGLE_EXT("nSample", 0, 0, 5900, 0,
dac33_get_nsample, dac33_set_nsample),
SOC_SINGLE_EXT("UTHR", 0, 0, MODE7_UTHR, 0,
dac33_get_uthr, dac33_set_uthr),
};
/* Analog bypass */
static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
SOC_DAPM_SINGLE("Switch", DAC33_LINEL_TO_LLO_VOL, 7, 1, 1);
@ -586,6 +526,25 @@ static const struct snd_kcontrol_new dac33_dapm_abypassl_control =
static const struct snd_kcontrol_new dac33_dapm_abypassr_control =
SOC_DAPM_SINGLE("Switch", DAC33_LINER_TO_RLO_VOL, 7, 1, 1);
/* LOP L/R invert selection */
static const char *dac33_lr_lom_texts[] = {"DAC", "LOP"};
static const struct soc_enum dac33_left_lom_enum =
SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 3,
ARRAY_SIZE(dac33_lr_lom_texts),
dac33_lr_lom_texts);
static const struct snd_kcontrol_new dac33_dapm_left_lom_control =
SOC_DAPM_ENUM("Route", dac33_left_lom_enum);
static const struct soc_enum dac33_right_lom_enum =
SOC_ENUM_SINGLE(DAC33_OUT_AMP_CTRL, 2,
ARRAY_SIZE(dac33_lr_lom_texts),
dac33_lr_lom_texts);
static const struct snd_kcontrol_new dac33_dapm_right_lom_control =
SOC_DAPM_ENUM("Route", dac33_right_lom_enum);
static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("LEFT_LO"),
SND_SOC_DAPM_OUTPUT("RIGHT_LO"),
@ -593,8 +552,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("LINEL"),
SND_SOC_DAPM_INPUT("LINER"),
SND_SOC_DAPM_DAC("DACL", "Left Playback", DAC33_LDAC_PWR_CTRL, 2, 0),
SND_SOC_DAPM_DAC("DACR", "Right Playback", DAC33_RDAC_PWR_CTRL, 2, 0),
SND_SOC_DAPM_DAC("DACL", "Left Playback", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_DAC("DACR", "Right Playback", SND_SOC_NOPM, 0, 0),
/* Analog bypass */
SND_SOC_DAPM_SWITCH("Analog Left Bypass", SND_SOC_NOPM, 0, 0,
@ -602,12 +561,30 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
SND_SOC_DAPM_SWITCH("Analog Right Bypass", SND_SOC_NOPM, 0, 0,
&dac33_dapm_abypassr_control),
SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amp Power",
SND_SOC_DAPM_MUX("Left LOM Inverted From", SND_SOC_NOPM, 0, 0,
&dac33_dapm_left_lom_control),
SND_SOC_DAPM_MUX("Right LOM Inverted From", SND_SOC_NOPM, 0, 0,
&dac33_dapm_right_lom_control),
/*
* For DAPM path, when only the anlog bypass path is enabled, and the
* LOP inverted from the corresponding DAC side.
* This is needed, so we can attach the DAC power supply in this case.
*/
SND_SOC_DAPM_PGA("Left Bypass PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Right Bypass PGA", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Left Amplifier",
DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amplifier",
DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
SND_SOC_DAPM_PRE("Prepare Playback", playback_event),
SND_SOC_DAPM_SUPPLY("Left DAC Power",
DAC33_LDAC_PWR_CTRL, 2, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Right DAC Power",
DAC33_RDAC_PWR_CTRL, 2, 0, NULL, 0),
SND_SOC_DAPM_PRE("Pre Playback", dac33_playback_event),
SND_SOC_DAPM_POST("Post Playback", dac33_playback_event),
};
static const struct snd_soc_dapm_route audio_map[] = {
@ -615,24 +592,39 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Analog Left Bypass", "Switch", "LINEL"},
{"Analog Right Bypass", "Switch", "LINER"},
{"Output Left Amp Power", NULL, "DACL"},
{"Output Right Amp Power", NULL, "DACR"},
{"Output Left Amplifier", NULL, "DACL"},
{"Output Right Amplifier", NULL, "DACR"},
{"Output Left Amp Power", NULL, "Analog Left Bypass"},
{"Output Right Amp Power", NULL, "Analog Right Bypass"},
{"Left Bypass PGA", NULL, "Analog Left Bypass"},
{"Right Bypass PGA", NULL, "Analog Right Bypass"},
{"Left LOM Inverted From", "DAC", "Left Bypass PGA"},
{"Right LOM Inverted From", "DAC", "Right Bypass PGA"},
{"Left LOM Inverted From", "LOP", "Analog Left Bypass"},
{"Right LOM Inverted From", "LOP", "Analog Right Bypass"},
{"Output Left Amplifier", NULL, "Left LOM Inverted From"},
{"Output Right Amplifier", NULL, "Right LOM Inverted From"},
{"DACL", NULL, "Left DAC Power"},
{"DACR", NULL, "Right DAC Power"},
{"Left Bypass PGA", NULL, "Left DAC Power"},
{"Right Bypass PGA", NULL, "Right DAC Power"},
/* output */
{"LEFT_LO", NULL, "Output Left Amp Power"},
{"RIGHT_LO", NULL, "Output Right Amp Power"},
{"LEFT_LO", NULL, "Output Left Amplifier"},
{"RIGHT_LO", NULL, "Output Right Amplifier"},
};
static int dac33_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, dac33_dapm_widgets,
ARRAY_SIZE(dac33_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, dac33_dapm_widgets,
ARRAY_SIZE(dac33_dapm_widgets));
/* set up audio path interconnects */
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -640,16 +632,18 @@ static int dac33_add_widgets(struct snd_soc_codec *codec)
static int dac33_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) {
case SND_SOC_BIAS_ON:
dac33_soft_power(codec, 1);
if (!dac33->substream)
dac33_soft_power(codec, 1);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Coming from OFF, switch on the codec */
ret = dac33_hard_power(codec, 1);
if (ret != 0)
@ -660,14 +654,14 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_OFF:
/* Do not power off, when the codec is already off */
if (codec->bias_level == SND_SOC_BIAS_OFF)
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
return 0;
ret = dac33_hard_power(codec, 0);
if (ret != 0)
return ret;
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -705,7 +699,7 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
spin_unlock_irq(&dac33->lock);
dac33_write16(codec, DAC33_PREFILL_MSB,
DAC33_THRREG(MODE7_LTHR));
DAC33_THRREG(DAC33_MODE7_MARGIN));
/* Enable Upper Threshold IRQ */
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
@ -815,6 +809,8 @@ static int dac33_startup(struct snd_pcm_substream *substream,
/* Stream started, save the substream pointer */
dac33->substream = substream;
snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
return 0;
}
@ -826,18 +822,17 @@ static void dac33_shutdown(struct snd_pcm_substream *substream,
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
dac33->substream = NULL;
/* Reset the nSample restrictions */
dac33->nsample_min = 0;
dac33->nsample_max = NSAMPLE_MAX;
}
#define CALC_BURST_RATE(bclkdiv, bclk_per_sample) \
(BURST_BASEFREQ_HZ / bclkdiv / bclk_per_sample)
static int dac33_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
/* Check parameters for validity */
switch (params_rate(params)) {
@ -852,6 +847,12 @@ static int dac33_hw_params(struct snd_pcm_substream *substream,
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
dac33->fifo_size = DAC33_FIFO_SIZE_16BIT;
dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 32);
break;
case SNDRV_PCM_FORMAT_S32_LE:
dac33->fifo_size = DAC33_FIFO_SIZE_24BIT;
dac33->burst_rate = CALC_BURST_RATE(dac33->burst_bclkdiv, 64);
break;
default:
dev_err(codec->dev, "unsupported format %d\n",
@ -906,6 +907,9 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
aictrl_a |= (DAC33_NCYCL_16 | DAC33_WLEN_16);
fifoctrl_a |= DAC33_WIDTH;
break;
case SNDRV_PCM_FORMAT_S32_LE:
aictrl_a |= (DAC33_NCYCL_32 | DAC33_WLEN_24);
break;
default:
dev_err(codec->dev, "unsupported format %d\n",
substream->runtime->format);
@ -1040,7 +1044,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C,
dac33->burst_bclkdiv);
else
dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
if (substream->runtime->format == SNDRV_PCM_FORMAT_S16_LE)
dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 32);
else
dac33_write(codec, DAC33_SER_AUDIOIF_CTRL_C, 16);
switch (dac33->fifo_mode) {
case DAC33_FIFO_MODE1:
@ -1053,7 +1060,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
* at the bottom, and also at the top of the FIFO
*/
dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(dac33->uthr));
dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
dac33_write16(codec, DAC33_LTHR_MSB,
DAC33_THRREG(DAC33_MODE7_MARGIN));
break;
default:
break;
@ -1082,42 +1090,21 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
/* Number of samples under i2c latency */
dac33->alarm_threshold = US_TO_SAMPLES(rate,
dac33->mode1_latency);
nsample_limit = DAC33_BUFFER_SIZE_SAMPLES -
dac33->alarm_threshold;
nsample_limit = dac33->fifo_size - dac33->alarm_threshold;
if (dac33->auto_fifo_config) {
if (period_size <= dac33->alarm_threshold)
/*
* Configure nSamaple to number of periods,
* which covers the latency requironment.
*/
dac33->nsample = period_size *
((dac33->alarm_threshold / period_size) +
(dac33->alarm_threshold % period_size ?
1 : 0));
else if (period_size > nsample_limit)
dac33->nsample = nsample_limit;
else
dac33->nsample = period_size;
} else {
/* nSample time shall not be shorter than i2c latency */
dac33->nsample_min = dac33->alarm_threshold;
if (period_size <= dac33->alarm_threshold)
/*
* nSample should not be bigger than alsa buffer minus
* size of one period to avoid overruns
* Configure nSamaple to number of periods,
* which covers the latency requironment.
*/
dac33->nsample_max = substream->runtime->buffer_size -
period_size;
if (dac33->nsample_max > nsample_limit)
dac33->nsample_max = nsample_limit;
/* Correct the nSample if it is outside of the ranges */
if (dac33->nsample < dac33->nsample_min)
dac33->nsample = dac33->nsample_min;
if (dac33->nsample > dac33->nsample_max)
dac33->nsample = dac33->nsample_max;
}
dac33->nsample = period_size *
((dac33->alarm_threshold / period_size) +
(dac33->alarm_threshold % period_size ?
1 : 0));
else if (period_size > nsample_limit)
dac33->nsample = nsample_limit;
else
dac33->nsample = period_size;
dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
dac33->nsample);
@ -1125,19 +1112,16 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
dac33->t_stamp2 = 0;
break;
case DAC33_FIFO_MODE7:
if (dac33->auto_fifo_config) {
dac33->uthr = UTHR_FROM_PERIOD_SIZE(
period_size,
rate,
dac33->burst_rate) + 9;
if (dac33->uthr > MODE7_UTHR)
dac33->uthr = MODE7_UTHR;
if (dac33->uthr < (MODE7_LTHR + 10))
dac33->uthr = (MODE7_LTHR + 10);
}
dac33->uthr = UTHR_FROM_PERIOD_SIZE(period_size, rate,
dac33->burst_rate) + 9;
if (dac33->uthr > (dac33->fifo_size - DAC33_MODE7_MARGIN))
dac33->uthr = dac33->fifo_size - DAC33_MODE7_MARGIN;
if (dac33->uthr < (DAC33_MODE7_MARGIN + 10))
dac33->uthr = (DAC33_MODE7_MARGIN + 10);
dac33->mode7_us_to_lthr =
SAMPLES_TO_US(substream->runtime->rate,
dac33->uthr - MODE7_LTHR + 1);
dac33->uthr - DAC33_MODE7_MARGIN + 1);
dac33->t_stamp1 = 0;
break;
default:
@ -1255,8 +1239,8 @@ static snd_pcm_sframes_t dac33_dai_delay(
samples += (samples_in - samples_out);
if (likely(samples > 0))
delay = samples > DAC33_BUFFER_SIZE_SAMPLES ?
DAC33_BUFFER_SIZE_SAMPLES : samples;
delay = samples > dac33->fifo_size ?
dac33->fifo_size : samples;
else
delay = 0;
}
@ -1308,7 +1292,7 @@ static snd_pcm_sframes_t dac33_dai_delay(
samples_in = US_TO_SAMPLES(
dac33->burst_rate,
time_delta);
delay = MODE7_LTHR + samples_in - samples_out;
delay = DAC33_MODE7_MARGIN + samples_in - samples_out;
if (unlikely(delay > uthr))
delay = uthr;
@ -1415,7 +1399,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
codec->control_data = dac33->control_data;
codec->hw_write = (hw_write_t) i2c_master_send;
codec->idle_bias_off = 1;
codec->dapm.idle_bias_off = 1;
dac33->codec = codec;
/* Read the tlv320dac33 ID registers */
@ -1459,14 +1443,10 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
snd_soc_add_controls(codec, dac33_snd_controls,
ARRAY_SIZE(dac33_snd_controls));
/* Only add the FIFO controls, if we have valid IRQ number */
if (dac33->irq >= 0) {
if (dac33->irq >= 0)
snd_soc_add_controls(codec, dac33_mode_snd_controls,
ARRAY_SIZE(dac33_mode_snd_controls));
/* FIFO usage controls only, if autoio config is not selected */
if (!dac33->auto_fifo_config)
snd_soc_add_controls(codec, dac33_fifo_snd_controls,
ARRAY_SIZE(dac33_fifo_snd_controls));
}
dac33_add_widgets(codec);
err_power:
@ -1515,7 +1495,7 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \
SNDRV_PCM_RATE_48000)
#define DAC33_FORMATS SNDRV_PCM_FMTBIT_S16_LE
#define DAC33_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops dac33_dai_ops = {
.startup = dac33_startup,
@ -1563,17 +1543,11 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
dac33->power_gpio = pdata->power_gpio;
dac33->burst_bclkdiv = pdata->burst_bclkdiv;
/* Pre calculate the burst rate */
dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32;
dac33->keep_bclk = pdata->keep_bclk;
dac33->auto_fifo_config = pdata->auto_fifo_config;
dac33->mode1_latency = pdata->mode1_latency;
if (!dac33->mode1_latency)
dac33->mode1_latency = 10000; /* 10ms */
dac33->irq = client->irq;
dac33->nsample = NSAMPLE_MAX;
dac33->nsample_max = NSAMPLE_MAX;
dac33->uthr = MODE7_UTHR;
/* Disable FIFO use by default */
dac33->fifo_mode = DAC33_FIFO_BYPASS;

View File

@ -29,7 +29,6 @@
#include <linux/slab.h>
#include <sound/tpa6130a2-plat.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include "tpa6130a2.h"
@ -42,7 +41,7 @@ struct tpa6130a2_data {
unsigned char regs[TPA6130A2_CACHEREGNUM];
struct regulator *supply;
int power_gpio;
unsigned char power_state;
u8 power_state:1;
enum tpa_model id;
};
@ -117,7 +116,7 @@ static int tpa6130a2_initialize(void)
return ret;
}
static int tpa6130a2_power(int power)
static int tpa6130a2_power(u8 power)
{
struct tpa6130a2_data *data;
u8 val;
@ -127,17 +126,19 @@ static int tpa6130a2_power(int power)
data = i2c_get_clientdata(tpa6130a2_client);
mutex_lock(&data->mutex);
if (power && !data->power_state) {
/* Power on */
if (data->power_gpio >= 0)
gpio_set_value(data->power_gpio, 1);
if (power == data->power_state)
goto exit;
if (power) {
ret = regulator_enable(data->supply);
if (ret != 0) {
dev_err(&tpa6130a2_client->dev,
"Failed to enable supply: %d\n", ret);
goto exit;
}
/* Power on */
if (data->power_gpio >= 0)
gpio_set_value(data->power_gpio, 1);
data->power_state = 1;
ret = tpa6130a2_initialize();
@ -150,12 +151,7 @@ static int tpa6130a2_power(int power)
data->power_state = 0;
goto exit;
}
/* Clear SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
val &= ~TPA6130A2_SWS;
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
} else if (!power && data->power_state) {
} else {
/* set SWS */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
val |= TPA6130A2_SWS;
@ -300,6 +296,7 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
/* Enable amplifier */
val = tpa6130a2_read(TPA6130A2_REG_CONTROL);
val |= channel;
val &= ~TPA6130A2_SWS;
tpa6130a2_i2c_write(TPA6130A2_REG_CONTROL, val);
/* Unmute channel */
@ -320,72 +317,24 @@ static void tpa6130a2_channel_enable(u8 channel, int enable)
}
}
static int tpa6130a2_left_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
case SND_SOC_DAPM_POST_PMU:
tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 1);
break;
case SND_SOC_DAPM_POST_PMD:
tpa6130a2_channel_enable(TPA6130A2_HP_EN_L, 0);
break;
}
return 0;
}
static int tpa6130a2_right_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
switch (event) {
case SND_SOC_DAPM_POST_PMU:
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 1);
break;
case SND_SOC_DAPM_POST_PMD:
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R, 0);
break;
}
return 0;
}
static int tpa6130a2_supply_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable)
{
int ret = 0;
switch (event) {
case SND_SOC_DAPM_POST_PMU:
if (enable) {
ret = tpa6130a2_power(1);
break;
case SND_SOC_DAPM_POST_PMD:
if (ret < 0)
return ret;
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
1);
} else {
tpa6130a2_channel_enable(TPA6130A2_HP_EN_R | TPA6130A2_HP_EN_L,
0);
ret = tpa6130a2_power(0);
break;
}
return ret;
}
static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
SND_SOC_DAPM_PGA_E("TPA6130A2 Left", SND_SOC_NOPM,
0, 0, NULL, 0, tpa6130a2_left_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_PGA_E("TPA6130A2 Right", SND_SOC_NOPM,
0, 0, NULL, 0, tpa6130a2_right_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("TPA6130A2 Enable", SND_SOC_NOPM,
0, 0, tpa6130a2_supply_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
/* Outputs */
SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Left"),
SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Right"),
};
static const struct snd_soc_dapm_route audio_map[] = {
{"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Left"},
{"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Right"},
{"TPA6130A2 Headphone Left", NULL, "TPA6130A2 Enable"},
{"TPA6130A2 Headphone Right", NULL, "TPA6130A2 Enable"},
};
EXPORT_SYMBOL_GPL(tpa6130a2_stereo_enable);
int tpa6130a2_add_controls(struct snd_soc_codec *codec)
{
@ -396,18 +345,12 @@ int tpa6130a2_add_controls(struct snd_soc_codec *codec)
data = i2c_get_clientdata(tpa6130a2_client);
snd_soc_dapm_new_controls(codec, tpa6130a2_dapm_widgets,
ARRAY_SIZE(tpa6130a2_dapm_widgets));
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
if (data->id == TPA6140A2)
return snd_soc_add_controls(codec, tpa6140a2_controls,
ARRAY_SIZE(tpa6140a2_controls));
else
return snd_soc_add_controls(codec, tpa6130a2_controls,
ARRAY_SIZE(tpa6130a2_controls));
}
EXPORT_SYMBOL_GPL(tpa6130a2_add_controls);

View File

@ -57,5 +57,6 @@
#define TPA6130A2_VERSION_MASK (0x0f)
extern int tpa6130a2_add_controls(struct snd_soc_codec *codec);
extern int tpa6130a2_stereo_enable(struct snd_soc_codec *codec, int enable);
#endif /* __TPA6130A2_H__ */

View File

@ -32,7 +32,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -233,6 +232,16 @@ static int twl4030_write(struct snd_soc_codec *codec,
return 0;
}
static inline void twl4030_wait_ms(int time)
{
if (time < 60) {
time *= 1000;
usleep_range(time, time + 500);
} else {
msleep(time);
}
}
static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
@ -338,10 +347,14 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
twl4030_write(codec, TWL4030_REG_ANAMICL,
reg | TWL4030_CNCL_OFFSET_START);
/* wait for offset cancellation to complete */
/*
* Wait for offset cancellation to complete.
* Since this takes a while, do not slam the i2c.
* Start polling the status after ~20ms.
*/
msleep(20);
do {
/* this takes a little while, so don't slam i2c */
udelay(2000);
usleep_range(1000, 2000);
twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte,
TWL4030_REG_ANAMICL);
} while ((i++ < 100) &&
@ -725,9 +738,12 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
/* Base values for ramp delay calculation: 2^19 - 2^26 */
unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
8388608, 16777216, 33554432, 67108864};
unsigned int delay;
hs_gain = twl4030_read_reg_cache(codec, TWL4030_REG_HS_GAIN_SET);
hs_pop = twl4030_read_reg_cache(codec, TWL4030_REG_HS_POPN_SET);
delay = (ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
twl4030->sysclk) + 1;
/* Enable external mute control, this dramatically reduces
* the pop-noise */
@ -751,16 +767,14 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
hs_pop |= TWL4030_RAMP_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Wait ramp delay time + 1, so the VMID can settle */
mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
twl4030->sysclk) + 1);
twl4030_wait_ms(delay);
} else {
/* Headset ramp-down _not_ according to
* the TRM, but in a way that it is working */
hs_pop &= ~TWL4030_RAMP_EN;
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
/* Wait ramp delay time + 1, so the VMID can settle */
mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
twl4030->sysclk) + 1);
twl4030_wait_ms(delay);
/* Bypass the reg_cache to mute the headset */
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
hs_gain & (~0x0f),
@ -835,7 +849,7 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
if (twl4030->digimic_delay)
mdelay(twl4030->digimic_delay);
twl4030_wait_ms(twl4030->digimic_delay);
return 0;
}
@ -1621,10 +1635,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int twl4030_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, twl4030_dapm_widgets,
ARRAY_SIZE(twl4030_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, twl4030_dapm_widgets,
ARRAY_SIZE(twl4030_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -1638,14 +1653,14 @@ static int twl4030_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF)
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
twl4030_codec_enable(codec, 1);
break;
case SND_SOC_BIAS_OFF:
twl4030_codec_enable(codec, 0);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -1709,6 +1724,7 @@ static int twl4030_startup(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec;
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24);
if (twl4030->master_substream) {
twl4030->slave_substream = substream;
/* The DAI has one configuration for playback and capture, so
@ -1833,7 +1849,7 @@ static int twl4030_hw_params(struct snd_pcm_substream *substream,
case SNDRV_PCM_FORMAT_S16_LE:
format |= TWL4030_DATA_WIDTH_16S_16W;
break;
case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S32_LE:
format |= TWL4030_DATA_WIDTH_32S_24W;
break;
default:
@ -2166,7 +2182,7 @@ static int twl4030_voice_set_tristate(struct snd_soc_dai *dai, int tristate)
}
#define TWL4030_RATES (SNDRV_PCM_RATE_8000_48000)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE)
#define TWL4030_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops twl4030_dai_hifi_ops = {
.startup = twl4030_startup,
@ -2245,7 +2261,7 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, twl4030);
/* Set the defaults, and power up the codec */
twl4030->sysclk = twl4030_codec_get_mclk() / 1000;
codec->idle_bias_off = 1;
codec->dapm.idle_bias_off = 1;
twl4030_init_chip(codec);
@ -2257,9 +2273,12 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
static int twl4030_soc_remove(struct snd_soc_codec *codec)
{
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
/* Reset registers to their chip default before leaving */
twl4030_reset_registers(codec);
twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
kfree(twl4030);
return 0;
}
@ -2291,10 +2310,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
static int __devexit twl4030_codec_remove(struct platform_device *pdev)
{
struct twl4030_priv *twl4030 = dev_get_drvdata(&pdev->dev);
snd_soc_unregister_codec(&pdev->dev);
kfree(twl4030);
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -79,6 +79,7 @@
/* INTMR (0x04) fields */
#define TWL6040_PLUGMSK 0x02
#define TWL6040_READYMSK 0x40
#define TWL6040_ALLINT_MSK 0x7B
@ -135,4 +136,11 @@
#define TWL6040_HPPLL_ID 1
#define TWL6040_LPPLL_ID 2
/* STATUS (0x2E) fields */
#define TWL6040_PLUGCOMP 0x02
void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, int report);
#endif /* End of __TWL6040_H__ */

View File

@ -19,7 +19,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/uda134x.h>
@ -389,7 +388,7 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec,
pd->power(0);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -27,7 +27,6 @@
#include <sound/control.h>
#include <sound/initval.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/uda1380.h>
@ -36,7 +35,6 @@
/* codec private data */
struct uda1380_priv {
struct snd_soc_codec *codec;
u16 reg_cache[UDA1380_CACHEREGNUM];
unsigned int dac_clk;
struct work_struct work;
void *control_data;
@ -414,10 +412,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int uda1380_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, uda1380_dapm_widgets,
ARRAY_SIZE(uda1380_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, uda1380_dapm_widgets,
ARRAY_SIZE(uda1380_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -603,7 +602,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
int reg;
struct uda1380_platform_data *pdata = codec->dev->platform_data;
if (codec->bias_level == level)
if (codec->dapm.bias_level == level)
return 0;
switch (level) {
@ -613,7 +612,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
uda1380_write(codec, UDA1380_PM, R02_PON_BIAS | pm);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
if (gpio_is_valid(pdata->gpio_power)) {
gpio_set_value(pdata->gpio_power, 1);
mdelay(1);
@ -636,7 +635,7 @@ static int uda1380_set_bias_level(struct snd_soc_codec *codec,
for (reg = UDA1380_MVOL; reg < UDA1380_CACHEREGNUM; reg++)
set_bit(reg - 0x10, &uda1380_cache_dirty);
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -25,8 +25,7 @@
#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc-dai.h>
#include <sound/soc-dapm.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include "wl1273.h"

View File

@ -36,7 +36,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -705,6 +704,7 @@ static const struct snd_soc_dapm_route audio_map[] = {
/* Called from the machine driver */
int wm2000_add_controls(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
if (!wm2000_i2c) {
@ -712,12 +712,12 @@ int wm2000_add_controls(struct snd_soc_codec *codec)
return -ENODEV;
}
ret = snd_soc_dapm_new_controls(codec, wm2000_dapm_widgets,
ret = snd_soc_dapm_new_controls(dapm, wm2000_dapm_widgets,
ARRAY_SIZE(wm2000_dapm_widgets));
if (ret < 0)
return ret;
ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
if (ret < 0)
return ret;

View File

@ -24,9 +24,9 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <trace/events/asoc.h>
#include "wm8350.h"
@ -54,6 +54,7 @@ struct wm8350_output {
struct wm8350_jack_data {
struct snd_soc_jack *jack;
struct delayed_work work;
int report;
int short_report;
};
@ -230,8 +231,9 @@ static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
*/
static void wm8350_pga_work(struct work_struct *work)
{
struct snd_soc_codec *codec =
container_of(work, struct snd_soc_codec, delayed_work.work);
struct snd_soc_dapm_context *dapm =
container_of(work, struct snd_soc_dapm_context, delayed_work.work);
struct snd_soc_codec *codec = dapm->codec;
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
struct wm8350_output *out1 = &wm8350_data->out1,
*out2 = &wm8350_data->out2;
@ -302,8 +304,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
out->ramp = WM8350_RAMP_UP;
out->active = 1;
if (!delayed_work_pending(&codec->delayed_work))
schedule_delayed_work(&codec->delayed_work,
if (!delayed_work_pending(&codec->dapm.delayed_work))
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(1));
break;
@ -311,8 +313,8 @@ static int pga_event(struct snd_soc_dapm_widget *w,
out->ramp = WM8350_RAMP_DOWN;
out->active = 0;
if (!delayed_work_pending(&codec->delayed_work))
schedule_delayed_work(&codec->delayed_work,
if (!delayed_work_pending(&codec->dapm.delayed_work))
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(1));
break;
}
@ -786,9 +788,10 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int wm8350_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
ret = snd_soc_dapm_new_controls(codec,
ret = snd_soc_dapm_new_controls(dapm,
wm8350_dapm_widgets,
ARRAY_SIZE(wm8350_dapm_widgets));
if (ret != 0) {
@ -797,7 +800,7 @@ static int wm8350_add_widgets(struct snd_soc_codec *codec)
}
/* set up audio paths */
ret = snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
ret = snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
if (ret != 0) {
dev_err(codec->dev, "DAPM route register failed\n");
return ret;
@ -1184,7 +1187,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(priv->supplies),
priv->supplies);
if (ret != 0)
@ -1317,7 +1320,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
priv->supplies);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -1334,37 +1337,13 @@ static int wm8350_resume(struct snd_soc_codec *codec)
return 0;
}
static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
static void wm8350_hp_work(struct wm8350_data *priv,
struct wm8350_jack_data *jack,
u16 mask)
{
struct wm8350_data *priv = data;
struct wm8350 *wm8350 = priv->codec.control_data;
u16 reg;
int report;
int mask;
struct wm8350_jack_data *jack = NULL;
switch (irq - wm8350->irq_base) {
case WM8350_IRQ_CODEC_JCK_DET_L:
jack = &priv->hpl;
mask = WM8350_JACK_L_LVL;
break;
case WM8350_IRQ_CODEC_JCK_DET_R:
jack = &priv->hpr;
mask = WM8350_JACK_R_LVL;
break;
default:
BUG();
}
if (!jack->jack) {
dev_warn(wm8350->dev, "Jack interrupt called with no jack\n");
return IRQ_NONE;
}
/* Debounce */
msleep(200);
reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
if (reg & mask)
@ -1374,6 +1353,54 @@ static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
snd_soc_jack_report(jack->jack, report, jack->report);
}
static void wm8350_hpl_work(struct work_struct *work)
{
struct wm8350_data *priv =
container_of(work, struct wm8350_data, hpl.work.work);
wm8350_hp_work(priv, &priv->hpl, WM8350_JACK_L_LVL);
}
static void wm8350_hpr_work(struct work_struct *work)
{
struct wm8350_data *priv =
container_of(work, struct wm8350_data, hpr.work.work);
wm8350_hp_work(priv, &priv->hpr, WM8350_JACK_R_LVL);
}
static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
{
struct wm8350_data *priv = data;
struct wm8350 *wm8350 = priv->codec.control_data;
struct wm8350_jack_data *jack = NULL;
switch (irq - wm8350->irq_base) {
case WM8350_IRQ_CODEC_JCK_DET_L:
#ifndef CONFIG_SND_SOC_WM8350_MODULE
trace_snd_soc_jack_irq("WM8350 HPL");
#endif
jack = &priv->hpl;
break;
case WM8350_IRQ_CODEC_JCK_DET_R:
#ifndef CONFIG_SND_SOC_WM8350_MODULE
trace_snd_soc_jack_irq("WM8350 HPR");
#endif
jack = &priv->hpr;
break;
default:
BUG();
}
if (device_may_wakeup(wm8350->dev))
pm_wakeup_event(wm8350->dev, 250);
schedule_delayed_work(&jack->work, 200);
return IRQ_HANDLED;
}
@ -1436,6 +1463,10 @@ static irqreturn_t wm8350_mic_handler(int irq, void *data)
u16 reg;
int report = 0;
#ifndef CONFIG_SND_SOC_WM8350_MODULE
trace_snd_soc_jack_irq("WM8350 mic");
#endif
reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
if (reg & WM8350_JACK_MICSCD_LVL)
report |= priv->mic.short_report;
@ -1550,7 +1581,9 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
/* Put the codec into reset if it wasn't already */
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
INIT_DELAYED_WORK(&codec->delayed_work, wm8350_pga_work);
INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8350_pga_work);
INIT_DELAYED_WORK(&priv->hpl.work, wm8350_hpl_work);
INIT_DELAYED_WORK(&priv->hpr.work, wm8350_hpr_work);
/* Enable the codec */
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
@ -1640,9 +1673,12 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
priv->hpr.jack = NULL;
priv->mic.jack = NULL;
cancel_delayed_work_sync(&priv->hpl.work);
cancel_delayed_work_sync(&priv->hpr.work);
/* if there was any work waiting then we run it now and
* wait for its completion */
flush_delayed_work_sync(&codec->delayed_work);
flush_delayed_work_sync(&codec->dapm.delayed_work);
wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);

View File

@ -26,7 +26,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -911,10 +910,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int wm8400_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8400_dapm_widgets,
ARRAY_SIZE(wm8400_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, wm8400_dapm_widgets,
ARRAY_SIZE(wm8400_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -1219,7 +1219,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(power),
&power[0]);
if (ret != 0) {
@ -1306,7 +1306,7 @@ static int wm8400_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -24,7 +24,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "wm8510.h"
@ -216,10 +215,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int wm8510_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8510_dapm_widgets,
ARRAY_SIZE(wm8510_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, wm8510_dapm_widgets,
ARRAY_SIZE(wm8510_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -478,7 +478,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY:
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
mdelay(100);
@ -495,7 +495,7 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -24,7 +24,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -109,10 +108,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int wm8523_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8523_dapm_widgets,
ARRAY_SIZE(wm8523_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, wm8523_dapm_widgets,
ARRAY_SIZE(wm8523_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -327,7 +327,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8523->supplies),
wm8523->supplies);
if (ret != 0) {
@ -366,7 +366,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec,
wm8523->supplies);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -31,7 +31,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/initval.h>
#include <asm/div64.h>
@ -191,7 +190,6 @@ static const char *wm8580_supply_names[WM8580_NUM_SUPPLIES] = {
struct wm8580_priv {
enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8580_NUM_SUPPLIES];
u16 reg_cache[WM8580_MAX_REGISTER + 1];
struct pll_state a;
struct pll_state b;
int sysclk[2];
@ -302,10 +300,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int wm8580_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8580_dapm_widgets,
ARRAY_SIZE(wm8580_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, wm8580_dapm_widgets,
ARRAY_SIZE(wm8580_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -507,13 +506,13 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream,
}
/* Look up the SYSCLK ratio; accept only exact matches */
ratio = wm8580->sysclk[dai->id] / params_rate(params);
ratio = wm8580->sysclk[dai->driver->id] / params_rate(params);
for (i = 0; i < ARRAY_SIZE(wm8580_sysclk_ratios); i++)
if (ratio == wm8580_sysclk_ratios[i])
break;
if (i == ARRAY_SIZE(wm8580_sysclk_ratios)) {
dev_err(codec->dev, "Invalid clock ratio %d/%d\n",
wm8580->sysclk[dai->id], params_rate(params));
wm8580->sysclk[dai->driver->id], params_rate(params));
return -EINVAL;
}
paifa |= i;
@ -716,7 +715,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
switch (clk_id) {
case WM8580_CLKSRC_ADCMCLK:
if (dai->id != WM8580_DAI_PAIFTX)
if (dai->driver->id != WM8580_DAI_PAIFTX)
return -EINVAL;
sel = 0 << sel_shift;
break;
@ -735,7 +734,7 @@ static int wm8580_set_sysclk(struct snd_soc_dai *dai, int clk_id,
}
/* We really should validate PLL settings but not yet */
wm8580->sysclk[dai->id] = freq;
wm8580->sysclk[dai->driver->id] = freq;
return snd_soc_update_bits(codec, WM8580_CLKSEL, sel_mask, sel);
}
@ -767,7 +766,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Power up and get individual control of the DACs */
reg = snd_soc_read(codec, WM8580_PWRDN1);
reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD);
@ -785,7 +784,7 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -905,7 +904,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
.set_bias_level = wm8580_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8580_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = &wm8580_reg,
.reg_cache_default = wm8580_reg,
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

View File

@ -25,7 +25,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/initval.h>
@ -34,7 +33,6 @@
/* codec private data */
struct wm8711_priv {
enum snd_soc_control_type bus_type;
u16 reg_cache[WM8711_CACHEREGNUM];
unsigned int sysclk;
};
@ -93,10 +91,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int wm8711_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8711_dapm_widgets,
ARRAY_SIZE(wm8711_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, wm8711_dapm_widgets,
ARRAY_SIZE(wm8711_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -318,7 +317,7 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8711_PWR, 0xffff);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -23,7 +23,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -73,10 +72,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int wm8728_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8728_dapm_widgets,
ARRAY_SIZE(wm8728_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, wm8728_dapm_widgets,
ARRAY_SIZE(wm8728_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -180,7 +180,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE:
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Power everything up... */
reg = snd_soc_read(codec, WM8728_DACCTL);
snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4);
@ -197,7 +197,7 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8728_DACCTL, reg | 0x4);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -26,7 +26,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -44,9 +43,10 @@ static const char *wm8731_supply_names[WM8731_NUM_SUPPLIES] = {
struct wm8731_priv {
enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8731_NUM_SUPPLIES];
u16 reg_cache[WM8731_CACHEREGNUM];
unsigned int sysclk;
int sysclk_type;
int playback_fs;
bool deemph;
};
@ -65,16 +65,79 @@ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = {
#define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0)
static const char *wm8731_input_select[] = {"Line In", "Mic"};
static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"};
static const struct soc_enum wm8731_enum[] = {
SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select),
SOC_ENUM_SINGLE(WM8731_APDIGI, 1, 4, wm8731_deemph),
};
static const struct soc_enum wm8731_insel_enum =
SOC_ENUM_SINGLE(WM8731_APANA, 2, 2, wm8731_input_select);
static int wm8731_deemph[] = { 0, 32000, 44100, 48000 };
static int wm8731_set_deemph(struct snd_soc_codec *codec)
{
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
int val, i, best;
/* If we're using deemphasis select the nearest available sample
* rate.
*/
if (wm8731->deemph) {
best = 1;
for (i = 2; i < ARRAY_SIZE(wm8731_deemph); i++) {
if (abs(wm8731_deemph[i] - wm8731->playback_fs) <
abs(wm8731_deemph[best] - wm8731->playback_fs))
best = i;
}
val = best << 1;
} else {
best = 0;
val = 0;
}
dev_dbg(codec->dev, "Set deemphasis %d (%dHz)\n",
best, wm8731_deemph[best]);
return snd_soc_update_bits(codec, WM8731_APDIGI, 0x6, val);
}
static int wm8731_get_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
ucontrol->value.enumerated.item[0] = wm8731->deemph;
return 0;
}
static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
int deemph = ucontrol->value.enumerated.item[0];
int ret = 0;
if (deemph > 1)
return -EINVAL;
mutex_lock(&codec->mutex);
if (wm8731->deemph != deemph) {
wm8731->deemph = deemph;
wm8731_set_deemph(codec);
ret = 1;
}
mutex_unlock(&codec->mutex);
return ret;
}
static const DECLARE_TLV_DB_SCALE(in_tlv, -3450, 150, 0);
static const DECLARE_TLV_DB_SCALE(sidetone_tlv, -1500, 300, 0);
static const DECLARE_TLV_DB_SCALE(out_tlv, -12100, 100, 1);
static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 2000, 0);
static const struct snd_kcontrol_new wm8731_snd_controls[] = {
@ -87,7 +150,7 @@ SOC_DOUBLE_R_TLV("Capture Volume", WM8731_LINVOL, WM8731_RINVOL, 0, 31, 0,
in_tlv),
SOC_DOUBLE_R("Line Capture Switch", WM8731_LINVOL, WM8731_RINVOL, 7, 1, 1),
SOC_SINGLE("Mic Boost (+20dB)", WM8731_APANA, 0, 1, 0),
SOC_SINGLE_TLV("Mic Boost Volume", WM8731_APANA, 0, 1, 0, mic_tlv),
SOC_SINGLE("Mic Capture Switch", WM8731_APANA, 1, 1, 1),
SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
@ -96,7 +159,8 @@ SOC_SINGLE_TLV("Sidetone Playback Volume", WM8731_APANA, 6, 3, 1,
SOC_SINGLE("ADC High Pass Filter Switch", WM8731_APDIGI, 0, 1, 1),
SOC_SINGLE("Store DC Offset Switch", WM8731_APDIGI, 4, 1, 0),
SOC_ENUM("Playback De-emphasis", wm8731_enum[1]),
SOC_SINGLE_BOOL_EXT("Playback Deemphasis Switch", 0,
wm8731_get_deemph, wm8731_put_deemph),
};
/* Output Mixer */
@ -108,7 +172,7 @@ SOC_DAPM_SINGLE("HiFi Playback Switch", WM8731_APANA, 4, 1, 0),
/* Input mux */
static const struct snd_kcontrol_new wm8731_input_mux_controls =
SOC_DAPM_ENUM("Input Select", wm8731_enum[0]);
SOC_DAPM_ENUM("Input Select", wm8731_insel_enum);
static const struct snd_soc_dapm_widget wm8731_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("OSC", WM8731_PWR, 5, 1, NULL, 0),
@ -165,10 +229,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int wm8731_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8731_dapm_widgets,
ARRAY_SIZE(wm8731_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, wm8731_dapm_widgets,
ARRAY_SIZE(wm8731_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -239,6 +304,8 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
u16 srate = (coeff_div[i].sr << 2) |
(coeff_div[i].bosr << 1) | coeff_div[i].usb;
wm8731->playback_fs = params_rate(params);
snd_soc_write(codec, WM8731_SRATE, srate);
/* bit size */
@ -253,6 +320,8 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream,
break;
}
wm8731_set_deemph(codec);
snd_soc_write(codec, WM8731_IFACE, iface);
return 0;
}
@ -319,7 +388,7 @@ static int wm8731_set_dai_sysclk(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
snd_soc_dapm_sync(codec);
snd_soc_dapm_sync(&codec->dapm);
return 0;
}
@ -399,7 +468,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
wm8731->supplies);
if (ret != 0)
@ -428,7 +497,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
wm8731->supplies);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -542,7 +611,6 @@ err_regulator_enable:
err_regulator_get:
regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
kfree(wm8731);
return ret;
}

754
sound/soc/codecs/wm8737.c Normal file
View File

@ -0,0 +1,754 @@
/*
* wm8737.c -- WM8737 ALSA SoC Audio driver
*
* Copyright 2010 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "wm8737.h"
#define WM8737_NUM_SUPPLIES 4
static const char *wm8737_supply_names[WM8737_NUM_SUPPLIES] = {
"DCVDD",
"DBVDD",
"AVDD",
"MVDD",
};
/* codec private data */
struct wm8737_priv {
enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8737_NUM_SUPPLIES];
unsigned int mclk;
};
static const u16 wm8737_reg[WM8737_REGISTER_COUNT] = {
0x00C3, /* R0 - Left PGA volume */
0x00C3, /* R1 - Right PGA volume */
0x0007, /* R2 - AUDIO path L */
0x0007, /* R3 - AUDIO path R */
0x0000, /* R4 - 3D Enhance */
0x0000, /* R5 - ADC Control */
0x0000, /* R6 - Power Management */
0x000A, /* R7 - Audio Format */
0x0000, /* R8 - Clocking */
0x000F, /* R9 - MIC Preamp Control */
0x0003, /* R10 - Misc Bias Control */
0x0000, /* R11 - Noise Gate */
0x007C, /* R12 - ALC1 */
0x0000, /* R13 - ALC2 */
0x0032, /* R14 - ALC3 */
};
static int wm8737_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, WM8737_RESET, 0);
}
static const unsigned int micboost_tlv[] = {
TLV_DB_RANGE_HEAD(4),
0, 0, TLV_DB_SCALE_ITEM(1300, 0, 0),
1, 1, TLV_DB_SCALE_ITEM(1800, 0, 0),
2, 2, TLV_DB_SCALE_ITEM(2800, 0, 0),
3, 3, TLV_DB_SCALE_ITEM(3300, 0, 0),
};
static const DECLARE_TLV_DB_SCALE(pga_tlv, -9750, 50, 1);
static const DECLARE_TLV_DB_SCALE(adc_tlv, -600, 600, 0);
static const DECLARE_TLV_DB_SCALE(ng_tlv, -7800, 600, 0);
static const DECLARE_TLV_DB_SCALE(alc_max_tlv, -1200, 600, 0);
static const DECLARE_TLV_DB_SCALE(alc_target_tlv, -1800, 100, 0);
static const char *micbias_enum_text[] = {
"25%",
"50%",
"75%",
"100%",
};
static const struct soc_enum micbias_enum =
SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 0, 4, micbias_enum_text);
static const char *low_cutoff_text[] = {
"Low", "High"
};
static const struct soc_enum low_3d =
SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 6, 2, low_cutoff_text);
static const char *high_cutoff_text[] = {
"High", "Low"
};
static const struct soc_enum high_3d =
SOC_ENUM_SINGLE(WM8737_3D_ENHANCE, 5, 2, high_cutoff_text);
static const char *alc_fn_text[] = {
"Disabled", "Right", "Left", "Stereo"
};
static const struct soc_enum alc_fn =
SOC_ENUM_SINGLE(WM8737_ALC1, 7, 4, alc_fn_text);
static const char *alc_hold_text[] = {
"0", "2.67ms", "5.33ms", "10.66ms", "21.32ms", "42.64ms", "85.28ms",
"170.56ms", "341.12ms", "682.24ms", "1.364s", "2.728s", "5.458s",
"10.916s", "21.832s", "43.691s"
};
static const struct soc_enum alc_hold =
SOC_ENUM_SINGLE(WM8737_ALC2, 0, 16, alc_hold_text);
static const char *alc_atk_text[] = {
"8.4ms", "16.8ms", "33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms",
"1.075s", "2.15s", "4.3s", "8.6s"
};
static const struct soc_enum alc_atk =
SOC_ENUM_SINGLE(WM8737_ALC3, 0, 11, alc_atk_text);
static const char *alc_dcy_text[] = {
"33.6ms", "67.2ms", "134.4ms", "268.8ms", "537.6ms", "1.075s", "2.15s",
"4.3s", "8.6s", "17.2s", "34.41s"
};
static const struct soc_enum alc_dcy =
SOC_ENUM_SINGLE(WM8737_ALC3, 4, 11, alc_dcy_text);
static const struct snd_kcontrol_new wm8737_snd_controls[] = {
SOC_DOUBLE_R_TLV("Mic Boost Volume", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
6, 3, 0, micboost_tlv),
SOC_DOUBLE_R("Mic Boost Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
4, 1, 0),
SOC_DOUBLE("Mic ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
3, 1, 0),
SOC_DOUBLE_R_TLV("Capture Volume", WM8737_LEFT_PGA_VOLUME,
WM8737_RIGHT_PGA_VOLUME, 0, 255, 0, pga_tlv),
SOC_DOUBLE("Capture ZC Switch", WM8737_AUDIO_PATH_L, WM8737_AUDIO_PATH_R,
2, 1, 0),
SOC_DOUBLE("INPUT1 DC Bias Switch", WM8737_MISC_BIAS_CONTROL, 0, 1, 1, 0),
SOC_ENUM("Mic PGA Bias", micbias_enum),
SOC_SINGLE("ADC Low Power Switch", WM8737_ADC_CONTROL, 2, 1, 0),
SOC_SINGLE("High Pass Filter Switch", WM8737_ADC_CONTROL, 0, 1, 1),
SOC_DOUBLE("Polarity Invert Switch", WM8737_ADC_CONTROL, 5, 6, 1, 0),
SOC_SINGLE("3D Switch", WM8737_3D_ENHANCE, 0, 1, 0),
SOC_SINGLE("3D Depth", WM8737_3D_ENHANCE, 1, 15, 0),
SOC_ENUM("3D Low Cut-off", low_3d),
SOC_ENUM("3D High Cut-off", low_3d),
SOC_SINGLE_TLV("3D ADC Volume", WM8737_3D_ENHANCE, 7, 1, 1, adc_tlv),
SOC_SINGLE("Noise Gate Switch", WM8737_NOISE_GATE, 0, 1, 0),
SOC_SINGLE_TLV("Noise Gate Threshold Volume", WM8737_NOISE_GATE, 2, 7, 0,
ng_tlv),
SOC_ENUM("ALC", alc_fn),
SOC_SINGLE_TLV("ALC Max Gain Volume", WM8737_ALC1, 4, 7, 0, alc_max_tlv),
SOC_SINGLE_TLV("ALC Target Volume", WM8737_ALC1, 0, 15, 0, alc_target_tlv),
SOC_ENUM("ALC Hold Time", alc_hold),
SOC_SINGLE("ALC ZC Switch", WM8737_ALC2, 4, 1, 0),
SOC_ENUM("ALC Attack Time", alc_atk),
SOC_ENUM("ALC Decay Time", alc_dcy),
};
static const char *linsel_text[] = {
"LINPUT1", "LINPUT2", "LINPUT3", "LINPUT1 DC",
};
static const struct soc_enum linsel_enum =
SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_L, 7, 4, linsel_text);
static const struct snd_kcontrol_new linsel_mux =
SOC_DAPM_ENUM("LINSEL", linsel_enum);
static const char *rinsel_text[] = {
"RINPUT1", "RINPUT2", "RINPUT3", "RINPUT1 DC",
};
static const struct soc_enum rinsel_enum =
SOC_ENUM_SINGLE(WM8737_AUDIO_PATH_R, 7, 4, rinsel_text);
static const struct snd_kcontrol_new rinsel_mux =
SOC_DAPM_ENUM("RINSEL", rinsel_enum);
static const char *bypass_text[] = {
"Direct", "Preamp"
};
static const struct soc_enum lbypass_enum =
SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 2, 2, bypass_text);
static const struct snd_kcontrol_new lbypass_mux =
SOC_DAPM_ENUM("Left Bypass", lbypass_enum);
static const struct soc_enum rbypass_enum =
SOC_ENUM_SINGLE(WM8737_MIC_PREAMP_CONTROL, 3, 2, bypass_text);
static const struct snd_kcontrol_new rbypass_mux =
SOC_DAPM_ENUM("Left Bypass", rbypass_enum);
static const struct snd_soc_dapm_widget wm8737_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("LINPUT1"),
SND_SOC_DAPM_INPUT("LINPUT2"),
SND_SOC_DAPM_INPUT("LINPUT3"),
SND_SOC_DAPM_INPUT("RINPUT1"),
SND_SOC_DAPM_INPUT("RINPUT2"),
SND_SOC_DAPM_INPUT("RINPUT3"),
SND_SOC_DAPM_INPUT("LACIN"),
SND_SOC_DAPM_INPUT("RACIN"),
SND_SOC_DAPM_MUX("LINSEL", SND_SOC_NOPM, 0, 0, &linsel_mux),
SND_SOC_DAPM_MUX("RINSEL", SND_SOC_NOPM, 0, 0, &rinsel_mux),
SND_SOC_DAPM_MUX("Left Preamp Mux", SND_SOC_NOPM, 0, 0, &lbypass_mux),
SND_SOC_DAPM_MUX("Right Preamp Mux", SND_SOC_NOPM, 0, 0, &rbypass_mux),
SND_SOC_DAPM_PGA("PGAL", WM8737_POWER_MANAGEMENT, 5, 0, NULL, 0),
SND_SOC_DAPM_PGA("PGAR", WM8737_POWER_MANAGEMENT, 4, 0, NULL, 0),
SND_SOC_DAPM_DAC("ADCL", NULL, WM8737_POWER_MANAGEMENT, 3, 0),
SND_SOC_DAPM_DAC("ADCR", NULL, WM8737_POWER_MANAGEMENT, 2, 0),
SND_SOC_DAPM_AIF_OUT("AIF", "Capture", 0, WM8737_POWER_MANAGEMENT, 6, 0),
};
static const struct snd_soc_dapm_route intercon[] = {
{ "LINSEL", "LINPUT1", "LINPUT1" },
{ "LINSEL", "LINPUT2", "LINPUT2" },
{ "LINSEL", "LINPUT3", "LINPUT3" },
{ "LINSEL", "LINPUT1 DC", "LINPUT1" },
{ "RINSEL", "RINPUT1", "RINPUT1" },
{ "RINSEL", "RINPUT2", "RINPUT2" },
{ "RINSEL", "RINPUT3", "RINPUT3" },
{ "RINSEL", "RINPUT1 DC", "RINPUT1" },
{ "Left Preamp Mux", "Preamp", "LINSEL" },
{ "Left Preamp Mux", "Direct", "LACIN" },
{ "Right Preamp Mux", "Preamp", "RINSEL" },
{ "Right Preamp Mux", "Direct", "RACIN" },
{ "PGAL", NULL, "Left Preamp Mux" },
{ "PGAR", NULL, "Right Preamp Mux" },
{ "ADCL", NULL, "PGAL" },
{ "ADCR", NULL, "PGAR" },
{ "AIF", NULL, "ADCL" },
{ "AIF", NULL, "ADCR" },
};
static int wm8737_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets,
ARRAY_SIZE(wm8737_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
/* codec mclk clock divider coefficients */
static const struct {
u32 mclk;
u32 rate;
u8 usb;
u8 sr;
} coeff_div[] = {
{ 12288000, 8000, 0, 0x4 },
{ 12288000, 12000, 0, 0x8 },
{ 12288000, 16000, 0, 0xa },
{ 12288000, 24000, 0, 0x1c },
{ 12288000, 32000, 0, 0xc },
{ 12288000, 48000, 0, 0 },
{ 12288000, 96000, 0, 0xe },
{ 11289600, 8000, 0, 0x14 },
{ 11289600, 11025, 0, 0x18 },
{ 11289600, 22050, 0, 0x1a },
{ 11289600, 44100, 0, 0x10 },
{ 11289600, 88200, 0, 0x1e },
{ 18432000, 8000, 0, 0x5 },
{ 18432000, 12000, 0, 0x9 },
{ 18432000, 16000, 0, 0xb },
{ 18432000, 24000, 0, 0x1b },
{ 18432000, 32000, 0, 0xd },
{ 18432000, 48000, 0, 0x1 },
{ 18432000, 96000, 0, 0x1f },
{ 16934400, 8000, 0, 0x15 },
{ 16934400, 11025, 0, 0x19 },
{ 16934400, 22050, 0, 0x1b },
{ 16934400, 44100, 0, 0x11 },
{ 16934400, 88200, 0, 0x1f },
{ 12000000, 8000, 1, 0x4 },
{ 12000000, 11025, 1, 0x19 },
{ 12000000, 12000, 1, 0x8 },
{ 12000000, 16000, 1, 0xa },
{ 12000000, 22050, 1, 0x1b },
{ 12000000, 24000, 1, 0x1c },
{ 12000000, 32000, 1, 0xc },
{ 12000000, 44100, 1, 0x11 },
{ 12000000, 48000, 1, 0x0 },
{ 12000000, 88200, 1, 0x1f },
{ 12000000, 96000, 1, 0xe },
};
static int wm8737_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec;
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
int i;
u16 clocking = 0;
u16 af = 0;
for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
if (coeff_div[i].rate != params_rate(params))
continue;
if (coeff_div[i].mclk == wm8737->mclk)
break;
if (coeff_div[i].mclk == wm8737->mclk * 2) {
clocking |= WM8737_CLKDIV2;
break;
}
}
if (i == ARRAY_SIZE(coeff_div)) {
dev_err(codec->dev, "%dHz MCLK can't support %dHz\n",
wm8737->mclk, params_rate(params));
return -EINVAL;
}
clocking |= coeff_div[i].usb | (coeff_div[i].sr << WM8737_SR_SHIFT);
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
case SNDRV_PCM_FORMAT_S20_3LE:
af |= 0x8;
break;
case SNDRV_PCM_FORMAT_S24_LE:
af |= 0x10;
break;
case SNDRV_PCM_FORMAT_S32_LE:
af |= 0x18;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT, WM8737_WL_MASK, af);
snd_soc_update_bits(codec, WM8737_CLOCKING,
WM8737_USB_MODE | WM8737_CLKDIV2 | WM8737_SR_MASK,
clocking);
return 0;
}
static int wm8737_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 wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
int i;
for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
if (freq == coeff_div[i].mclk ||
freq == coeff_div[i].mclk * 2) {
wm8737->mclk = freq;
return 0;
}
}
dev_err(codec->dev, "MCLK rate %dHz not supported\n", freq);
return -EINVAL;
}
static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
u16 af = 0;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
af |= WM8737_MS;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
af |= 0x2;
break;
case SND_SOC_DAIFMT_RIGHT_J:
break;
case SND_SOC_DAIFMT_LEFT_J:
af |= 0x1;
break;
case SND_SOC_DAIFMT_DSP_A:
af |= 0x3;
break;
case SND_SOC_DAIFMT_DSP_B:
af |= 0x13;
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_NB_IF:
af |= WM8737_LRP;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, WM8737_AUDIO_FORMAT,
WM8737_FORMAT_MASK | WM8737_LRP | WM8737_MS, af);
return 0;
}
static int wm8737_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
int ret;
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
/* VMID at 2*75k */
snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
WM8737_VMIDSEL_MASK, 0);
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
wm8737->supplies);
if (ret != 0) {
dev_err(codec->dev,
"Failed to enable supplies: %d\n",
ret);
return ret;
}
snd_soc_cache_sync(codec);
/* Fast VMID ramp at 2*2.5k */
snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
WM8737_VMIDSEL_MASK, 0x4);
/* Bring VMID up */
snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
WM8737_VMID_MASK |
WM8737_VREF_MASK,
WM8737_VMID_MASK |
WM8737_VREF_MASK);
msleep(500);
}
/* VMID at 2*300k */
snd_soc_update_bits(codec, WM8737_MISC_BIAS_CONTROL,
WM8737_VMIDSEL_MASK, 2);
break;
case SND_SOC_BIAS_OFF:
snd_soc_update_bits(codec, WM8737_POWER_MANAGEMENT,
WM8737_VMID_MASK | WM8737_VREF_MASK, 0);
regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies),
wm8737->supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
#define WM8737_RATES SNDRV_PCM_RATE_8000_96000
#define WM8737_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops wm8737_dai_ops = {
.hw_params = wm8737_hw_params,
.set_sysclk = wm8737_set_dai_sysclk,
.set_fmt = wm8737_set_dai_fmt,
};
static struct snd_soc_dai_driver wm8737_dai = {
.name = "wm8737",
.capture = {
.stream_name = "Capture",
.channels_min = 2, /* Mono modes not yet supported */
.channels_max = 2,
.rates = WM8737_RATES,
.formats = WM8737_FORMATS,
},
.ops = &wm8737_dai_ops,
};
#ifdef CONFIG_PM
static int wm8737_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int wm8737_resume(struct snd_soc_codec *codec)
{
wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
#else
#define wm8737_suspend NULL
#define wm8737_resume NULL
#endif
static int wm8737_probe(struct snd_soc_codec *codec)
{
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
int ret, i;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8737->control_type);
if (ret != 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8737->supplies); i++)
wm8737->supplies[i].supply = wm8737_supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8737->supplies),
wm8737->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8737->supplies),
wm8737->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
goto err_get;
}
ret = wm8737_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset\n");
goto err_enable;
}
snd_soc_update_bits(codec, WM8737_LEFT_PGA_VOLUME, WM8737_LVU,
WM8737_LVU);
snd_soc_update_bits(codec, WM8737_RIGHT_PGA_VOLUME, WM8737_RVU,
WM8737_RVU);
wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
snd_soc_add_controls(codec, wm8737_snd_controls,
ARRAY_SIZE(wm8737_snd_controls));
wm8737_add_widgets(codec);
return 0;
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
err_get:
regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
return ret;
}
static int wm8737_remove(struct snd_soc_codec *codec)
{
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_free(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
.probe = wm8737_probe,
.remove = wm8737_remove,
.suspend = wm8737_suspend,
.resume = wm8737_resume,
.set_bias_level = wm8737_set_bias_level,
.reg_cache_size = WM8737_REGISTER_COUNT - 1, /* Skip reset */
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8737_reg,
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct wm8737_priv *wm8737;
int ret;
wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
if (wm8737 == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c, wm8737);
wm8737->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8737, &wm8737_dai, 1);
if (ret < 0)
kfree(wm8737);
return ret;
}
static __devexit int wm8737_i2c_remove(struct i2c_client *client)
{
snd_soc_unregister_codec(&client->dev);
kfree(i2c_get_clientdata(client));
return 0;
}
static const struct i2c_device_id wm8737_i2c_id[] = {
{ "wm8737", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id);
static struct i2c_driver wm8737_i2c_driver = {
.driver = {
.name = "wm8737",
.owner = THIS_MODULE,
},
.probe = wm8737_i2c_probe,
.remove = __devexit_p(wm8737_i2c_remove),
.id_table = wm8737_i2c_id,
};
#endif
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8737_spi_probe(struct spi_device *spi)
{
struct wm8737_priv *wm8737;
int ret;
wm8737 = kzalloc(sizeof(struct wm8737_priv), GFP_KERNEL);
if (wm8737 == NULL)
return -ENOMEM;
wm8737->control_type = SND_SOC_SPI;
spi_set_drvdata(spi, wm8737);
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_wm8737, &wm8737_dai, 1);
if (ret < 0)
kfree(wm8737);
return ret;
}
static int __devexit wm8737_spi_remove(struct spi_device *spi)
{
snd_soc_unregister_codec(&spi->dev);
kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8737_spi_driver = {
.driver = {
.name = "wm8737",
.owner = THIS_MODULE,
},
.probe = wm8737_spi_probe,
.remove = __devexit_p(wm8737_spi_remove),
};
#endif /* CONFIG_SPI_MASTER */
static int __init wm8737_modinit(void)
{
int ret;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
ret = i2c_add_driver(&wm8737_i2c_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8737 I2C driver: %d\n",
ret);
}
#endif
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8737_spi_driver);
if (ret != 0) {
printk(KERN_ERR "Failed to register WM8737 SPI driver: %d\n",
ret);
}
#endif
return 0;
}
module_init(wm8737_modinit);
static void __exit wm8737_exit(void)
{
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8737_spi_driver);
#endif
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
i2c_del_driver(&wm8737_i2c_driver);
#endif
}
module_exit(wm8737_exit);
MODULE_DESCRIPTION("ASoC WM8737 driver");
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");

322
sound/soc/codecs/wm8737.h Normal file
View File

@ -0,0 +1,322 @@
#ifndef _WM8737_H
#define _WM8737_H
/*
* wm8737.c -- WM8523 ALSA SoC Audio driver
*
* Copyright 2010 Wolfson Microelectronics plc
*
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
*
* 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.
*/
/*
* Register values.
*/
#define WM8737_LEFT_PGA_VOLUME 0x00
#define WM8737_RIGHT_PGA_VOLUME 0x01
#define WM8737_AUDIO_PATH_L 0x02
#define WM8737_AUDIO_PATH_R 0x03
#define WM8737_3D_ENHANCE 0x04
#define WM8737_ADC_CONTROL 0x05
#define WM8737_POWER_MANAGEMENT 0x06
#define WM8737_AUDIO_FORMAT 0x07
#define WM8737_CLOCKING 0x08
#define WM8737_MIC_PREAMP_CONTROL 0x09
#define WM8737_MISC_BIAS_CONTROL 0x0A
#define WM8737_NOISE_GATE 0x0B
#define WM8737_ALC1 0x0C
#define WM8737_ALC2 0x0D
#define WM8737_ALC3 0x0E
#define WM8737_RESET 0x0F
#define WM8737_REGISTER_COUNT 16
#define WM8737_MAX_REGISTER 0x0F
/*
* Field Definitions.
*/
/*
* R0 (0x00) - Left PGA volume
*/
#define WM8737_LVU 0x0100 /* LVU */
#define WM8737_LVU_MASK 0x0100 /* LVU */
#define WM8737_LVU_SHIFT 8 /* LVU */
#define WM8737_LVU_WIDTH 1 /* LVU */
#define WM8737_LINVOL_MASK 0x00FF /* LINVOL - [7:0] */
#define WM8737_LINVOL_SHIFT 0 /* LINVOL - [7:0] */
#define WM8737_LINVOL_WIDTH 8 /* LINVOL - [7:0] */
/*
* R1 (0x01) - Right PGA volume
*/
#define WM8737_RVU 0x0100 /* RVU */
#define WM8737_RVU_MASK 0x0100 /* RVU */
#define WM8737_RVU_SHIFT 8 /* RVU */
#define WM8737_RVU_WIDTH 1 /* RVU */
#define WM8737_RINVOL_MASK 0x00FF /* RINVOL - [7:0] */
#define WM8737_RINVOL_SHIFT 0 /* RINVOL - [7:0] */
#define WM8737_RINVOL_WIDTH 8 /* RINVOL - [7:0] */
/*
* R2 (0x02) - AUDIO path L
*/
#define WM8737_LINSEL_MASK 0x0180 /* LINSEL - [8:7] */
#define WM8737_LINSEL_SHIFT 7 /* LINSEL - [8:7] */
#define WM8737_LINSEL_WIDTH 2 /* LINSEL - [8:7] */
#define WM8737_LMICBOOST_MASK 0x0060 /* LMICBOOST - [6:5] */
#define WM8737_LMICBOOST_SHIFT 5 /* LMICBOOST - [6:5] */
#define WM8737_LMICBOOST_WIDTH 2 /* LMICBOOST - [6:5] */
#define WM8737_LMBE 0x0010 /* LMBE */
#define WM8737_LMBE_MASK 0x0010 /* LMBE */
#define WM8737_LMBE_SHIFT 4 /* LMBE */
#define WM8737_LMBE_WIDTH 1 /* LMBE */
#define WM8737_LMZC 0x0008 /* LMZC */
#define WM8737_LMZC_MASK 0x0008 /* LMZC */
#define WM8737_LMZC_SHIFT 3 /* LMZC */
#define WM8737_LMZC_WIDTH 1 /* LMZC */
#define WM8737_LPZC 0x0004 /* LPZC */
#define WM8737_LPZC_MASK 0x0004 /* LPZC */
#define WM8737_LPZC_SHIFT 2 /* LPZC */
#define WM8737_LPZC_WIDTH 1 /* LPZC */
#define WM8737_LZCTO_MASK 0x0003 /* LZCTO - [1:0] */
#define WM8737_LZCTO_SHIFT 0 /* LZCTO - [1:0] */
#define WM8737_LZCTO_WIDTH 2 /* LZCTO - [1:0] */
/*
* R3 (0x03) - AUDIO path R
*/
#define WM8737_RINSEL_MASK 0x0180 /* RINSEL - [8:7] */
#define WM8737_RINSEL_SHIFT 7 /* RINSEL - [8:7] */
#define WM8737_RINSEL_WIDTH 2 /* RINSEL - [8:7] */
#define WM8737_RMICBOOST_MASK 0x0060 /* RMICBOOST - [6:5] */
#define WM8737_RMICBOOST_SHIFT 5 /* RMICBOOST - [6:5] */
#define WM8737_RMICBOOST_WIDTH 2 /* RMICBOOST - [6:5] */
#define WM8737_RMBE 0x0010 /* RMBE */
#define WM8737_RMBE_MASK 0x0010 /* RMBE */
#define WM8737_RMBE_SHIFT 4 /* RMBE */
#define WM8737_RMBE_WIDTH 1 /* RMBE */
#define WM8737_RMZC 0x0008 /* RMZC */
#define WM8737_RMZC_MASK 0x0008 /* RMZC */
#define WM8737_RMZC_SHIFT 3 /* RMZC */
#define WM8737_RMZC_WIDTH 1 /* RMZC */
#define WM8737_RPZC 0x0004 /* RPZC */
#define WM8737_RPZC_MASK 0x0004 /* RPZC */
#define WM8737_RPZC_SHIFT 2 /* RPZC */
#define WM8737_RPZC_WIDTH 1 /* RPZC */
#define WM8737_RZCTO_MASK 0x0003 /* RZCTO - [1:0] */
#define WM8737_RZCTO_SHIFT 0 /* RZCTO - [1:0] */
#define WM8737_RZCTO_WIDTH 2 /* RZCTO - [1:0] */
/*
* R4 (0x04) - 3D Enhance
*/
#define WM8737_DIV2 0x0080 /* DIV2 */
#define WM8737_DIV2_MASK 0x0080 /* DIV2 */
#define WM8737_DIV2_SHIFT 7 /* DIV2 */
#define WM8737_DIV2_WIDTH 1 /* DIV2 */
#define WM8737_3DLC 0x0040 /* 3DLC */
#define WM8737_3DLC_MASK 0x0040 /* 3DLC */
#define WM8737_3DLC_SHIFT 6 /* 3DLC */
#define WM8737_3DLC_WIDTH 1 /* 3DLC */
#define WM8737_3DUC 0x0020 /* 3DUC */
#define WM8737_3DUC_MASK 0x0020 /* 3DUC */
#define WM8737_3DUC_SHIFT 5 /* 3DUC */
#define WM8737_3DUC_WIDTH 1 /* 3DUC */
#define WM8737_3DDEPTH_MASK 0x001E /* 3DDEPTH - [4:1] */
#define WM8737_3DDEPTH_SHIFT 1 /* 3DDEPTH - [4:1] */
#define WM8737_3DDEPTH_WIDTH 4 /* 3DDEPTH - [4:1] */
#define WM8737_3DE 0x0001 /* 3DE */
#define WM8737_3DE_MASK 0x0001 /* 3DE */
#define WM8737_3DE_SHIFT 0 /* 3DE */
#define WM8737_3DE_WIDTH 1 /* 3DE */
/*
* R5 (0x05) - ADC Control
*/
#define WM8737_MONOMIX_MASK 0x0180 /* MONOMIX - [8:7] */
#define WM8737_MONOMIX_SHIFT 7 /* MONOMIX - [8:7] */
#define WM8737_MONOMIX_WIDTH 2 /* MONOMIX - [8:7] */
#define WM8737_POLARITY_MASK 0x0060 /* POLARITY - [6:5] */
#define WM8737_POLARITY_SHIFT 5 /* POLARITY - [6:5] */
#define WM8737_POLARITY_WIDTH 2 /* POLARITY - [6:5] */
#define WM8737_HPOR 0x0010 /* HPOR */
#define WM8737_HPOR_MASK 0x0010 /* HPOR */
#define WM8737_HPOR_SHIFT 4 /* HPOR */
#define WM8737_HPOR_WIDTH 1 /* HPOR */
#define WM8737_LP 0x0004 /* LP */
#define WM8737_LP_MASK 0x0004 /* LP */
#define WM8737_LP_SHIFT 2 /* LP */
#define WM8737_LP_WIDTH 1 /* LP */
#define WM8737_MONOUT 0x0002 /* MONOUT */
#define WM8737_MONOUT_MASK 0x0002 /* MONOUT */
#define WM8737_MONOUT_SHIFT 1 /* MONOUT */
#define WM8737_MONOUT_WIDTH 1 /* MONOUT */
#define WM8737_ADCHPD 0x0001 /* ADCHPD */
#define WM8737_ADCHPD_MASK 0x0001 /* ADCHPD */
#define WM8737_ADCHPD_SHIFT 0 /* ADCHPD */
#define WM8737_ADCHPD_WIDTH 1 /* ADCHPD */
/*
* R6 (0x06) - Power Management
*/
#define WM8737_VMID 0x0100 /* VMID */
#define WM8737_VMID_MASK 0x0100 /* VMID */
#define WM8737_VMID_SHIFT 8 /* VMID */
#define WM8737_VMID_WIDTH 1 /* VMID */
#define WM8737_VREF 0x0080 /* VREF */
#define WM8737_VREF_MASK 0x0080 /* VREF */
#define WM8737_VREF_SHIFT 7 /* VREF */
#define WM8737_VREF_WIDTH 1 /* VREF */
#define WM8737_AI 0x0040 /* AI */
#define WM8737_AI_MASK 0x0040 /* AI */
#define WM8737_AI_SHIFT 6 /* AI */
#define WM8737_AI_WIDTH 1 /* AI */
#define WM8737_PGL 0x0020 /* PGL */
#define WM8737_PGL_MASK 0x0020 /* PGL */
#define WM8737_PGL_SHIFT 5 /* PGL */
#define WM8737_PGL_WIDTH 1 /* PGL */
#define WM8737_PGR 0x0010 /* PGR */
#define WM8737_PGR_MASK 0x0010 /* PGR */
#define WM8737_PGR_SHIFT 4 /* PGR */
#define WM8737_PGR_WIDTH 1 /* PGR */
#define WM8737_ADL 0x0008 /* ADL */
#define WM8737_ADL_MASK 0x0008 /* ADL */
#define WM8737_ADL_SHIFT 3 /* ADL */
#define WM8737_ADL_WIDTH 1 /* ADL */
#define WM8737_ADR 0x0004 /* ADR */
#define WM8737_ADR_MASK 0x0004 /* ADR */
#define WM8737_ADR_SHIFT 2 /* ADR */
#define WM8737_ADR_WIDTH 1 /* ADR */
#define WM8737_MICBIAS_MASK 0x0003 /* MICBIAS - [1:0] */
#define WM8737_MICBIAS_SHIFT 0 /* MICBIAS - [1:0] */
#define WM8737_MICBIAS_WIDTH 2 /* MICBIAS - [1:0] */
/*
* R7 (0x07) - Audio Format
*/
#define WM8737_SDODIS 0x0080 /* SDODIS */
#define WM8737_SDODIS_MASK 0x0080 /* SDODIS */
#define WM8737_SDODIS_SHIFT 7 /* SDODIS */
#define WM8737_SDODIS_WIDTH 1 /* SDODIS */
#define WM8737_MS 0x0040 /* MS */
#define WM8737_MS_MASK 0x0040 /* MS */
#define WM8737_MS_SHIFT 6 /* MS */
#define WM8737_MS_WIDTH 1 /* MS */
#define WM8737_LRP 0x0010 /* LRP */
#define WM8737_LRP_MASK 0x0010 /* LRP */
#define WM8737_LRP_SHIFT 4 /* LRP */
#define WM8737_LRP_WIDTH 1 /* LRP */
#define WM8737_WL_MASK 0x000C /* WL - [3:2] */
#define WM8737_WL_SHIFT 2 /* WL - [3:2] */
#define WM8737_WL_WIDTH 2 /* WL - [3:2] */
#define WM8737_FORMAT_MASK 0x0003 /* FORMAT - [1:0] */
#define WM8737_FORMAT_SHIFT 0 /* FORMAT - [1:0] */
#define WM8737_FORMAT_WIDTH 2 /* FORMAT - [1:0] */
/*
* R8 (0x08) - Clocking
*/
#define WM8737_AUTODETECT 0x0080 /* AUTODETECT */
#define WM8737_AUTODETECT_MASK 0x0080 /* AUTODETECT */
#define WM8737_AUTODETECT_SHIFT 7 /* AUTODETECT */
#define WM8737_AUTODETECT_WIDTH 1 /* AUTODETECT */
#define WM8737_CLKDIV2 0x0040 /* CLKDIV2 */
#define WM8737_CLKDIV2_MASK 0x0040 /* CLKDIV2 */
#define WM8737_CLKDIV2_SHIFT 6 /* CLKDIV2 */
#define WM8737_CLKDIV2_WIDTH 1 /* CLKDIV2 */
#define WM8737_SR_MASK 0x003E /* SR - [5:1] */
#define WM8737_SR_SHIFT 1 /* SR - [5:1] */
#define WM8737_SR_WIDTH 5 /* SR - [5:1] */
#define WM8737_USB_MODE 0x0001 /* USB MODE */
#define WM8737_USB_MODE_MASK 0x0001 /* USB MODE */
#define WM8737_USB_MODE_SHIFT 0 /* USB MODE */
#define WM8737_USB_MODE_WIDTH 1 /* USB MODE */
/*
* R9 (0x09) - MIC Preamp Control
*/
#define WM8737_RBYPEN 0x0008 /* RBYPEN */
#define WM8737_RBYPEN_MASK 0x0008 /* RBYPEN */
#define WM8737_RBYPEN_SHIFT 3 /* RBYPEN */
#define WM8737_RBYPEN_WIDTH 1 /* RBYPEN */
#define WM8737_LBYPEN 0x0004 /* LBYPEN */
#define WM8737_LBYPEN_MASK 0x0004 /* LBYPEN */
#define WM8737_LBYPEN_SHIFT 2 /* LBYPEN */
#define WM8737_LBYPEN_WIDTH 1 /* LBYPEN */
#define WM8737_MBCTRL_MASK 0x0003 /* MBCTRL - [1:0] */
#define WM8737_MBCTRL_SHIFT 0 /* MBCTRL - [1:0] */
#define WM8737_MBCTRL_WIDTH 2 /* MBCTRL - [1:0] */
/*
* R10 (0x0A) - Misc Bias Control
*/
#define WM8737_VMIDSEL_MASK 0x000C /* VMIDSEL - [3:2] */
#define WM8737_VMIDSEL_SHIFT 2 /* VMIDSEL - [3:2] */
#define WM8737_VMIDSEL_WIDTH 2 /* VMIDSEL - [3:2] */
#define WM8737_LINPUT1_DC_BIAS_ENABLE 0x0002 /* LINPUT1 DC BIAS ENABLE */
#define WM8737_LINPUT1_DC_BIAS_ENABLE_MASK 0x0002 /* LINPUT1 DC BIAS ENABLE */
#define WM8737_LINPUT1_DC_BIAS_ENABLE_SHIFT 1 /* LINPUT1 DC BIAS ENABLE */
#define WM8737_LINPUT1_DC_BIAS_ENABLE_WIDTH 1 /* LINPUT1 DC BIAS ENABLE */
#define WM8737_RINPUT1_DC_BIAS_ENABLE 0x0001 /* RINPUT1 DC BIAS ENABLE */
#define WM8737_RINPUT1_DC_BIAS_ENABLE_MASK 0x0001 /* RINPUT1 DC BIAS ENABLE */
#define WM8737_RINPUT1_DC_BIAS_ENABLE_SHIFT 0 /* RINPUT1 DC BIAS ENABLE */
#define WM8737_RINPUT1_DC_BIAS_ENABLE_WIDTH 1 /* RINPUT1 DC BIAS ENABLE */
/*
* R11 (0x0B) - Noise Gate
*/
#define WM8737_NGTH_MASK 0x001C /* NGTH - [4:2] */
#define WM8737_NGTH_SHIFT 2 /* NGTH - [4:2] */
#define WM8737_NGTH_WIDTH 3 /* NGTH - [4:2] */
#define WM8737_NGAT 0x0001 /* NGAT */
#define WM8737_NGAT_MASK 0x0001 /* NGAT */
#define WM8737_NGAT_SHIFT 0 /* NGAT */
#define WM8737_NGAT_WIDTH 1 /* NGAT */
/*
* R12 (0x0C) - ALC1
*/
#define WM8737_ALCSEL_MASK 0x0180 /* ALCSEL - [8:7] */
#define WM8737_ALCSEL_SHIFT 7 /* ALCSEL - [8:7] */
#define WM8737_ALCSEL_WIDTH 2 /* ALCSEL - [8:7] */
#define WM8737_MAX_GAIN_MASK 0x0070 /* MAX GAIN - [6:4] */
#define WM8737_MAX_GAIN_SHIFT 4 /* MAX GAIN - [6:4] */
#define WM8737_MAX_GAIN_WIDTH 3 /* MAX GAIN - [6:4] */
#define WM8737_ALCL_MASK 0x000F /* ALCL - [3:0] */
#define WM8737_ALCL_SHIFT 0 /* ALCL - [3:0] */
#define WM8737_ALCL_WIDTH 4 /* ALCL - [3:0] */
/*
* R13 (0x0D) - ALC2
*/
#define WM8737_ALCZCE 0x0010 /* ALCZCE */
#define WM8737_ALCZCE_MASK 0x0010 /* ALCZCE */
#define WM8737_ALCZCE_SHIFT 4 /* ALCZCE */
#define WM8737_ALCZCE_WIDTH 1 /* ALCZCE */
#define WM8737_HLD_MASK 0x000F /* HLD - [3:0] */
#define WM8737_HLD_SHIFT 0 /* HLD - [3:0] */
#define WM8737_HLD_WIDTH 4 /* HLD - [3:0] */
/*
* R14 (0x0E) - ALC3
*/
#define WM8737_DCY_MASK 0x00F0 /* DCY - [7:4] */
#define WM8737_DCY_SHIFT 4 /* DCY - [7:4] */
#define WM8737_DCY_WIDTH 4 /* DCY - [7:4] */
#define WM8737_ATK_MASK 0x000F /* ATK - [3:0] */
#define WM8737_ATK_SHIFT 0 /* ATK - [3:0] */
#define WM8737_ATK_WIDTH 4 /* ATK - [3:0] */
/*
* R15 (0x0F) - Reset
*/
#define WM8737_RESET_MASK 0x01FF /* RESET - [8:0] */
#define WM8737_RESET_SHIFT 0 /* RESET - [8:0] */
#define WM8737_RESET_WIDTH 9 /* RESET - [8:0] */
#endif

View File

@ -24,7 +24,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
@ -94,10 +93,11 @@ static const struct snd_soc_dapm_route intercon[] = {
static int wm8741_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8741_dapm_widgets,
ARRAY_SIZE(wm8741_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, intercon, ARRAY_SIZE(intercon));
snd_soc_dapm_new_controls(dapm, wm8741_dapm_widgets,
ARRAY_SIZE(wm8741_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
@ -455,7 +455,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
.resume = wm8741_resume,
.reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
.reg_word_size = sizeof(u16),
.reg_cache_default = &wm8741_reg_defaults,
.reg_cache_default = wm8741_reg_defaults,
};
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

View File

@ -25,7 +25,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include "wm8750.h"
@ -53,7 +52,6 @@ static const u16 wm8750_reg[] = {
struct wm8750_priv {
unsigned int sysclk;
enum snd_soc_control_type control_type;
u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
};
#define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0)
@ -399,10 +397,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int wm8750_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8750_dapm_widgets,
ARRAY_SIZE(wm8750_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, wm8750_dapm_widgets,
ARRAY_SIZE(wm8750_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -615,7 +614,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->bias_level == SND_SOC_BIAS_OFF) {
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Set VMID to 5k */
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
@ -630,7 +629,7 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8750_PWR1, 0x0001);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}

View File

@ -45,7 +45,6 @@
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <asm/div64.h>
@ -623,10 +622,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int wm8753_add_widgets(struct snd_soc_codec *codec)
{
snd_soc_dapm_new_controls(codec, wm8753_dapm_widgets,
ARRAY_SIZE(wm8753_dapm_widgets));
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
snd_soc_dapm_new_controls(dapm, wm8753_dapm_widgets,
ARRAY_SIZE(wm8753_dapm_widgets));
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
@ -1245,7 +1245,7 @@ static int wm8753_set_bias_level(struct snd_soc_codec *codec,
snd_soc_write(codec, WM8753_PWR1, 0x0001);
break;
}
codec->bias_level = level;
codec->dapm.bias_level = level;
return 0;
}
@ -1435,9 +1435,11 @@ static void wm8753_set_dai_mode(struct snd_soc_codec *codec,
static void wm8753_work(struct work_struct *work)
{
struct snd_soc_codec *codec =
container_of(work, struct snd_soc_codec, delayed_work.work);
wm8753_set_bias_level(codec, codec->bias_level);
struct snd_soc_dapm_context *dapm =
container_of(work, struct snd_soc_dapm_context,
delayed_work.work);
struct snd_soc_codec *codec = dapm->codec;
wm8753_set_bias_level(codec, dapm->bias_level);
}
static int wm8753_suspend(struct snd_soc_codec *codec, pm_message_t state)
@ -1466,10 +1468,10 @@ static int wm8753_resume(struct snd_soc_codec *codec)
wm8753_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* charge wm8753 caps */
if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
codec->bias_level = SND_SOC_BIAS_ON;
schedule_delayed_work(&codec->delayed_work,
codec->dapm.bias_level = SND_SOC_BIAS_ON;
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(caps_charge));
}
@ -1481,7 +1483,7 @@ static int wm8753_probe(struct snd_soc_codec *codec)
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
int ret;
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8753_work);
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8753->control_type);
if (ret < 0) {
@ -1500,7 +1502,7 @@ static int wm8753_probe(struct snd_soc_codec *codec)
/* charge output caps */
wm8753_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
schedule_delayed_work(&codec->delayed_work,
schedule_delayed_work(&codec->dapm.delayed_work,
msecs_to_jiffies(caps_charge));
/* set the update bits */
@ -1525,7 +1527,7 @@ static int wm8753_probe(struct snd_soc_codec *codec)
/* power down chip */
static int wm8753_remove(struct snd_soc_codec *codec)
{
flush_delayed_work_sync(&codec->delayed_work);
flush_delayed_work_sync(&codec->dapm.delayed_work);
wm8753_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;

749
sound/soc/codecs/wm8770.c Normal file
View File

@ -0,0 +1,749 @@
/*
* wm8770.c -- WM8770 ALSA SoC Audio driver
*
* Copyright 2010 Wolfson Microelectronics plc
*
* Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include "wm8770.h"
#define WM8770_NUM_SUPPLIES 3
static const char *wm8770_supply_names[WM8770_NUM_SUPPLIES] = {
"AVDD1",
"AVDD2",
"DVDD"
};
static const u16 wm8770_reg_defs[WM8770_CACHEREGNUM] = {
0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0x7f, 0x7f, 0x7f,
0x7f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0, 0x90, 0,
0, 0x22, 0x22, 0x3e,
0xc, 0xc, 0x100, 0x189,
0x189, 0x8770
};
struct wm8770_priv {
enum snd_soc_control_type control_type;
struct regulator_bulk_data supplies[WM8770_NUM_SUPPLIES];
struct notifier_block disable_nb[WM8770_NUM_SUPPLIES];
struct snd_soc_codec *codec;
int sysclk;
};
static int vout12supply_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
static int vout34supply_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event);
/*
* We can't use the same notifier block for more than one supply and
* there's no way I can see to get from a callback to the caller
* except container_of().
*/
#define WM8770_REGULATOR_EVENT(n) \
static int wm8770_regulator_event_##n(struct notifier_block *nb, \
unsigned long event, void *data) \
{ \
struct wm8770_priv *wm8770 = container_of(nb, struct wm8770_priv, \
disable_nb[n]); \
if (event & REGULATOR_EVENT_DISABLE) { \
wm8770->codec->cache_sync = 1; \
} \
return 0; \
}
WM8770_REGULATOR_EVENT(0)
WM8770_REGULATOR_EVENT(1)
WM8770_REGULATOR_EVENT(2)
static const DECLARE_TLV_DB_SCALE(adc_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(dac_dig_tlv, -12750, 50, 1);
static const DECLARE_TLV_DB_SCALE(dac_alg_tlv, -12700, 100, 1);
static const char *dac_phase_text[][2] = {
{ "DAC1 Normal", "DAC1 Inverted" },
{ "DAC2 Normal", "DAC2 Inverted" },
{ "DAC3 Normal", "DAC3 Inverted" },
{ "DAC4 Normal", "DAC4 Inverted" },
};
static const struct soc_enum dac_phase[] = {
SOC_ENUM_DOUBLE(WM8770_DACPHASE, 0, 1, 2, dac_phase_text[0]),
SOC_ENUM_DOUBLE(WM8770_DACPHASE, 2, 3, 2, dac_phase_text[1]),
SOC_ENUM_DOUBLE(WM8770_DACPHASE, 4, 5, 2, dac_phase_text[2]),
SOC_ENUM_DOUBLE(WM8770_DACPHASE, 6, 7, 2, dac_phase_text[3]),
};
static const struct snd_kcontrol_new wm8770_snd_controls[] = {
/* global DAC playback controls */
SOC_SINGLE_TLV("DAC Playback Volume", WM8770_MSDIGVOL, 0, 255, 0,
dac_dig_tlv),
SOC_SINGLE("DAC Playback Switch", WM8770_DACMUTE, 4, 1, 1),
SOC_SINGLE("DAC Playback ZC Switch", WM8770_DACCTRL1, 0, 1, 0),
/* global VOUT playback controls */
SOC_SINGLE_TLV("VOUT Playback Volume", WM8770_MSALGVOL, 0, 127, 0,
dac_alg_tlv),
SOC_SINGLE("VOUT Playback ZC Switch", WM8770_MSALGVOL, 7, 1, 0),
/* VOUT1/2/3/4 specific controls */
SOC_DOUBLE_R_TLV("VOUT1 Playback Volume", WM8770_VOUT1LVOL,
WM8770_VOUT1RVOL, 0, 127, 0, dac_alg_tlv),
SOC_DOUBLE_R("VOUT1 Playback ZC Switch", WM8770_VOUT1LVOL,
WM8770_VOUT1RVOL, 7, 1, 0),
SOC_DOUBLE_R_TLV("VOUT2 Playback Volume", WM8770_VOUT2LVOL,
WM8770_VOUT2RVOL, 0, 127, 0, dac_alg_tlv),
SOC_DOUBLE_R("VOUT2 Playback ZC Switch", WM8770_VOUT2LVOL,
WM8770_VOUT2RVOL, 7, 1, 0),
SOC_DOUBLE_R_TLV("VOUT3 Playback Volume", WM8770_VOUT3LVOL,
WM8770_VOUT3RVOL, 0, 127, 0, dac_alg_tlv),
SOC_DOUBLE_R("VOUT3 Playback ZC Switch", WM8770_VOUT3LVOL,
WM8770_VOUT3RVOL, 7, 1, 0),
SOC_DOUBLE_R_TLV("VOUT4 Playback Volume", WM8770_VOUT4LVOL,
WM8770_VOUT4RVOL, 0, 127, 0, dac_alg_tlv),
SOC_DOUBLE_R("VOUT4 Playback ZC Switch", WM8770_VOUT4LVOL,
WM8770_VOUT4RVOL, 7, 1, 0),
/* DAC1/2/3/4 specific controls */
SOC_DOUBLE_R_TLV("DAC1 Playback Volume", WM8770_DAC1LVOL,
WM8770_DAC1RVOL, 0, 255, 0, dac_dig_tlv),
SOC_SINGLE("DAC1 Deemphasis Switch", WM8770_DACCTRL2, 0, 1, 0),
SOC_ENUM("DAC1 Phase", dac_phase[0]),
SOC_DOUBLE_R_TLV("DAC2 Playback Volume", WM8770_DAC2LVOL,
WM8770_DAC2RVOL, 0, 255, 0, dac_dig_tlv),
SOC_SINGLE("DAC2 Deemphasis Switch", WM8770_DACCTRL2, 1, 1, 0),
SOC_ENUM("DAC2 Phase", dac_phase[1]),
SOC_DOUBLE_R_TLV("DAC3 Playback Volume", WM8770_DAC3LVOL,
WM8770_DAC3RVOL, 0, 255, 0, dac_dig_tlv),
SOC_SINGLE("DAC3 Deemphasis Switch", WM8770_DACCTRL2, 2, 1, 0),
SOC_ENUM("DAC3 Phase", dac_phase[2]),
SOC_DOUBLE_R_TLV("DAC4 Playback Volume", WM8770_DAC4LVOL,
WM8770_DAC4RVOL, 0, 255, 0, dac_dig_tlv),
SOC_SINGLE("DAC4 Deemphasis Switch", WM8770_DACCTRL2, 3, 1, 0),
SOC_ENUM("DAC4 Phase", dac_phase[3]),
/* ADC specific controls */
SOC_DOUBLE_R_TLV("Capture Volume", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
0, 31, 0, adc_tlv),
SOC_DOUBLE_R("Capture Switch", WM8770_ADCLCTRL, WM8770_ADCRCTRL,
5, 1, 1),
/* other controls */
SOC_SINGLE("ADC 128x Oversampling Switch", WM8770_MSTRCTRL, 3, 1, 0),
SOC_SINGLE("ADC Highpass Filter Switch", WM8770_IFACECTRL, 8, 1, 1)
};
static const char *ain_text[] = {
"AIN1", "AIN2", "AIN3", "AIN4",
"AIN5", "AIN6", "AIN7", "AIN8"
};
static const struct soc_enum ain_enum =
SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text);
static const struct snd_kcontrol_new ain_mux =
SOC_DAPM_ENUM("Capture Mux", ain_enum);
static const struct snd_kcontrol_new vout1_mix_controls[] = {
SOC_DAPM_SINGLE("DAC1 Switch", WM8770_OUTMUX1, 0, 1, 0),
SOC_DAPM_SINGLE("AUX1 Switch", WM8770_OUTMUX1, 1, 1, 0),
SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 2, 1, 0)
};
static const struct snd_kcontrol_new vout2_mix_controls[] = {
SOC_DAPM_SINGLE("DAC2 Switch", WM8770_OUTMUX1, 3, 1, 0),
SOC_DAPM_SINGLE("AUX2 Switch", WM8770_OUTMUX1, 4, 1, 0),
SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX1, 5, 1, 0)
};
static const struct snd_kcontrol_new vout3_mix_controls[] = {
SOC_DAPM_SINGLE("DAC3 Switch", WM8770_OUTMUX2, 0, 1, 0),
SOC_DAPM_SINGLE("AUX3 Switch", WM8770_OUTMUX2, 1, 1, 0),
SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 2, 1, 0)
};
static const struct snd_kcontrol_new vout4_mix_controls[] = {
SOC_DAPM_SINGLE("DAC4 Switch", WM8770_OUTMUX2, 3, 1, 0),
SOC_DAPM_SINGLE("Bypass Switch", WM8770_OUTMUX2, 4, 1, 0)
};
static const struct snd_soc_dapm_widget wm8770_dapm_widgets[] = {
SND_SOC_DAPM_INPUT("AUX1"),
SND_SOC_DAPM_INPUT("AUX2"),
SND_SOC_DAPM_INPUT("AUX3"),
SND_SOC_DAPM_INPUT("AIN1"),
SND_SOC_DAPM_INPUT("AIN2"),
SND_SOC_DAPM_INPUT("AIN3"),
SND_SOC_DAPM_INPUT("AIN4"),
SND_SOC_DAPM_INPUT("AIN5"),
SND_SOC_DAPM_INPUT("AIN6"),
SND_SOC_DAPM_INPUT("AIN7"),
SND_SOC_DAPM_INPUT("AIN8"),
SND_SOC_DAPM_MUX("Capture Mux", WM8770_ADCMUX, 8, 1, &ain_mux),
SND_SOC_DAPM_ADC("ADC", "Capture", WM8770_PWDNCTRL, 1, 1),
SND_SOC_DAPM_DAC("DAC1", "Playback", WM8770_PWDNCTRL, 2, 1),
SND_SOC_DAPM_DAC("DAC2", "Playback", WM8770_PWDNCTRL, 3, 1),
SND_SOC_DAPM_DAC("DAC3", "Playback", WM8770_PWDNCTRL, 4, 1),
SND_SOC_DAPM_DAC("DAC4", "Playback", WM8770_PWDNCTRL, 5, 1),
SND_SOC_DAPM_SUPPLY("VOUT12 Supply", SND_SOC_NOPM, 0, 0,
vout12supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_SUPPLY("VOUT34 Supply", SND_SOC_NOPM, 0, 0,
vout34supply_event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
SND_SOC_DAPM_MIXER("VOUT1 Mixer", SND_SOC_NOPM, 0, 0,
vout1_mix_controls, ARRAY_SIZE(vout1_mix_controls)),
SND_SOC_DAPM_MIXER("VOUT2 Mixer", SND_SOC_NOPM, 0, 0,
vout2_mix_controls, ARRAY_SIZE(vout2_mix_controls)),
SND_SOC_DAPM_MIXER("VOUT3 Mixer", SND_SOC_NOPM, 0, 0,
vout3_mix_controls, ARRAY_SIZE(vout3_mix_controls)),
SND_SOC_DAPM_MIXER("VOUT4 Mixer", SND_SOC_NOPM, 0, 0,
vout4_mix_controls, ARRAY_SIZE(vout4_mix_controls)),
SND_SOC_DAPM_OUTPUT("VOUT1"),
SND_SOC_DAPM_OUTPUT("VOUT2"),
SND_SOC_DAPM_OUTPUT("VOUT3"),
SND_SOC_DAPM_OUTPUT("VOUT4")
};
static const struct snd_soc_dapm_route wm8770_intercon[] = {
{ "Capture Mux", "AIN1", "AIN1" },
{ "Capture Mux", "AIN2", "AIN2" },
{ "Capture Mux", "AIN3", "AIN3" },
{ "Capture Mux", "AIN4", "AIN4" },
{ "Capture Mux", "AIN5", "AIN5" },
{ "Capture Mux", "AIN6", "AIN6" },
{ "Capture Mux", "AIN7", "AIN7" },
{ "Capture Mux", "AIN8", "AIN8" },
{ "ADC", NULL, "Capture Mux" },
{ "VOUT1 Mixer", NULL, "VOUT12 Supply" },
{ "VOUT1 Mixer", "DAC1 Switch", "DAC1" },
{ "VOUT1 Mixer", "AUX1 Switch", "AUX1" },
{ "VOUT1 Mixer", "Bypass Switch", "Capture Mux" },
{ "VOUT2 Mixer", NULL, "VOUT12 Supply" },
{ "VOUT2 Mixer", "DAC2 Switch", "DAC2" },
{ "VOUT2 Mixer", "AUX2 Switch", "AUX2" },
{ "VOUT2 Mixer", "Bypass Switch", "Capture Mux" },
{ "VOUT3 Mixer", NULL, "VOUT34 Supply" },
{ "VOUT3 Mixer", "DAC3 Switch", "DAC3" },
{ "VOUT3 Mixer", "AUX3 Switch", "AUX3" },
{ "VOUT3 Mixer", "Bypass Switch", "Capture Mux" },
{ "VOUT4 Mixer", NULL, "VOUT34 Supply" },
{ "VOUT4 Mixer", "DAC4 Switch", "DAC4" },
{ "VOUT4 Mixer", "Bypass Switch", "Capture Mux" },
{ "VOUT1", NULL, "VOUT1 Mixer" },
{ "VOUT2", NULL, "VOUT2 Mixer" },
{ "VOUT3", NULL, "VOUT3 Mixer" },
{ "VOUT4", NULL, "VOUT4 Mixer" }
};
static int vout12supply_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec;
codec = w->codec;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, WM8770_OUTMUX1, 0x180, 0x180);
break;
}
return 0;
}
static int vout34supply_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
struct snd_soc_codec *codec;
codec = w->codec;
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0);
break;
case SND_SOC_DAPM_POST_PMD:
snd_soc_update_bits(codec, WM8770_OUTMUX2, 0x180, 0x180);
break;
}
return 0;
}
static int wm8770_reset(struct snd_soc_codec *codec)
{
return snd_soc_write(codec, WM8770_RESET, 0);
}
static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec;
int iface, master;
codec = dai->codec;
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
master = 0x100;
break;
case SND_SOC_DAIFMT_CBS_CFS:
master = 0;
break;
default:
return -EINVAL;
}
iface = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
iface |= 0x2;
break;
case SND_SOC_DAIFMT_RIGHT_J:
break;
case SND_SOC_DAIFMT_LEFT_J:
iface |= 0x1;
break;
default:
return -EINVAL;
}
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
case SND_SOC_DAIFMT_IB_IF:
iface |= 0xc;
break;
case SND_SOC_DAIFMT_IB_NF:
iface |= 0x8;
break;
case SND_SOC_DAIFMT_NB_IF:
iface |= 0x4;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, WM8770_IFACECTRL, 0xf, iface);
snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x100, master);
return 0;
}
static const int mclk_ratios[] = {
128,
192,
256,
384,
512,
768
};
static int wm8770_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec;
struct wm8770_priv *wm8770;
int i;
int iface;
int shift;
int ratio;
codec = dai->codec;
wm8770 = snd_soc_codec_get_drvdata(codec);
iface = 0;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE:
break;
case SNDRV_PCM_FORMAT_S20_3LE:
iface |= 0x10;
break;
case SNDRV_PCM_FORMAT_S24_LE:
iface |= 0x20;
break;
case SNDRV_PCM_FORMAT_S32_LE:
iface |= 0x30;
break;
}
switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK:
i = 0;
shift = 4;
break;
case SNDRV_PCM_STREAM_CAPTURE:
i = 2;
shift = 0;
break;
default:
return -EINVAL;
}
/* Only need to set MCLK/LRCLK ratio if we're master */
if (snd_soc_read(codec, WM8770_MSTRCTRL) & 0x100) {
for (; i < ARRAY_SIZE(mclk_ratios); ++i) {
ratio = wm8770->sysclk / params_rate(params);
if (ratio == mclk_ratios[i])
break;
}
if (i == ARRAY_SIZE(mclk_ratios)) {
dev_err(codec->dev,
"Unable to configure MCLK ratio %d/%d\n",
wm8770->sysclk, params_rate(params));
return -EINVAL;
}
dev_dbg(codec->dev, "MCLK is %dfs\n", mclk_ratios[i]);
snd_soc_update_bits(codec, WM8770_MSTRCTRL, 0x7 << shift,
i << shift);
}
snd_soc_update_bits(codec, WM8770_IFACECTRL, 0x30, iface);
return 0;
}
static int wm8770_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec;
codec = dai->codec;
return snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10,
!!mute << 4);
}
static int wm8770_set_sysclk(struct snd_soc_dai *dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec;
struct wm8770_priv *wm8770;
codec = dai->codec;
wm8770 = snd_soc_codec_get_drvdata(codec);
wm8770->sysclk = freq;
return 0;
}
static void wm8770_sync_cache(struct snd_soc_codec *codec)
{
int i;
u16 *cache;
if (!codec->cache_sync)
return;
codec->cache_only = 0;
cache = codec->reg_cache;
for (i = 0; i < codec->driver->reg_cache_size; i++) {
if (i == WM8770_RESET || cache[i] == wm8770_reg_defs[i])
continue;
snd_soc_write(codec, i, cache[i]);
}
codec->cache_sync = 0;
}
static int wm8770_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
int ret;
struct wm8770_priv *wm8770;
wm8770 = snd_soc_codec_get_drvdata(codec);
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
wm8770->supplies);
if (ret) {
dev_err(codec->dev,
"Failed to enable supplies: %d\n",
ret);
return ret;
}
wm8770_sync_cache(codec);
/* global powerup */
snd_soc_write(codec, WM8770_PWDNCTRL, 0);
}
break;
case SND_SOC_BIAS_OFF:
/* global powerdown */
snd_soc_write(codec, WM8770_PWDNCTRL, 1);
regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies),
wm8770->supplies);
break;
}
codec->dapm.bias_level = level;
return 0;
}
#define WM8770_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_ops wm8770_dai_ops = {
.digital_mute = wm8770_mute,
.hw_params = wm8770_hw_params,
.set_fmt = wm8770_set_fmt,
.set_sysclk = wm8770_set_sysclk,
};
static struct snd_soc_dai_driver wm8770_dai = {
.name = "wm8770-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_192000,
.formats = WM8770_FORMATS
},
.capture = {
.stream_name = "Capture",
.channels_min = 2,
.channels_max = 2,
.rates = SNDRV_PCM_RATE_8000_96000,
.formats = WM8770_FORMATS
},
.ops = &wm8770_dai_ops,
.symmetric_rates = 1
};
#ifdef CONFIG_PM
static int wm8770_suspend(struct snd_soc_codec *codec, pm_message_t state)
{
wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static int wm8770_resume(struct snd_soc_codec *codec)
{
wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
#else
#define wm8770_suspend NULL
#define wm8770_resume NULL
#endif
static int wm8770_probe(struct snd_soc_codec *codec)
{
struct wm8770_priv *wm8770;
int ret;
int i;
wm8770 = snd_soc_codec_get_drvdata(codec);
wm8770->codec = codec;
codec->dapm.idle_bias_off = 1;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8770->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++)
wm8770->supplies[i].supply = wm8770_supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8770->supplies),
wm8770->supplies);
if (ret) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
return ret;
}
wm8770->disable_nb[0].notifier_call = wm8770_regulator_event_0;
wm8770->disable_nb[1].notifier_call = wm8770_regulator_event_1;
wm8770->disable_nb[2].notifier_call = wm8770_regulator_event_2;
/* This should really be moved into the regulator core */
for (i = 0; i < ARRAY_SIZE(wm8770->supplies); i++) {
ret = regulator_register_notifier(wm8770->supplies[i].consumer,
&wm8770->disable_nb[i]);
if (ret) {
dev_err(codec->dev,
"Failed to register regulator notifier: %d\n",
ret);
}
}
ret = regulator_bulk_enable(ARRAY_SIZE(wm8770->supplies),
wm8770->supplies);
if (ret) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
goto err_reg_get;
}
ret = wm8770_reset(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
goto err_reg_enable;
}
wm8770_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* latch the volume update bits */
snd_soc_update_bits(codec, WM8770_MSDIGVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_MSALGVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_VOUT1RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_VOUT2RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_VOUT3RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_VOUT4RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_DAC1RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_DAC2RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_DAC3RVOL, 0x100, 0x100);
snd_soc_update_bits(codec, WM8770_DAC4RVOL, 0x100, 0x100);
/* mute all DACs */
snd_soc_update_bits(codec, WM8770_DACMUTE, 0x10, 0x10);
snd_soc_add_controls(codec, wm8770_snd_controls,
ARRAY_SIZE(wm8770_snd_controls));
snd_soc_dapm_new_controls(&codec->dapm, wm8770_dapm_widgets,
ARRAY_SIZE(wm8770_dapm_widgets));
snd_soc_dapm_add_routes(&codec->dapm, wm8770_intercon,
ARRAY_SIZE(wm8770_intercon));
return 0;
err_reg_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
err_reg_get:
regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
return ret;
}
static int wm8770_remove(struct snd_soc_codec *codec)
{
struct wm8770_priv *wm8770;
int i;
wm8770 = snd_soc_codec_get_drvdata(codec);
wm8770_set_bias_level(codec, SND_SOC_BIAS_OFF);
for (i = 0; i < ARRAY_SIZE(wm8770->supplies); ++i)
regulator_unregister_notifier(wm8770->supplies[i].consumer,
&wm8770->disable_nb[i]);
regulator_bulk_free(ARRAY_SIZE(wm8770->supplies), wm8770->supplies);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
.probe = wm8770_probe,
.remove = wm8770_remove,
.suspend = wm8770_suspend,
.resume = wm8770_resume,
.set_bias_level = wm8770_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8770_reg_defs),
.reg_word_size = sizeof (u16),
.reg_cache_default = wm8770_reg_defs
};
#if defined(CONFIG_SPI_MASTER)
static int __devinit wm8770_spi_probe(struct spi_device *spi)
{
struct wm8770_priv *wm8770;
int ret;
wm8770 = kzalloc(sizeof(struct wm8770_priv), GFP_KERNEL);
if (!wm8770)
return -ENOMEM;
wm8770->control_type = SND_SOC_SPI;
spi_set_drvdata(spi, wm8770);
ret = snd_soc_register_codec(&spi->dev,
&soc_codec_dev_wm8770, &wm8770_dai, 1);
if (ret < 0)
kfree(wm8770);
return ret;
}
static int __devexit wm8770_spi_remove(struct spi_device *spi)
{
snd_soc_unregister_codec(&spi->dev);
kfree(spi_get_drvdata(spi));
return 0;
}
static struct spi_driver wm8770_spi_driver = {
.driver = {
.name = "wm8770",
.owner = THIS_MODULE,
},
.probe = wm8770_spi_probe,
.remove = __devexit_p(wm8770_spi_remove)
};
#endif
static int __init wm8770_modinit(void)
{
int ret = 0;
#if defined(CONFIG_SPI_MASTER)
ret = spi_register_driver(&wm8770_spi_driver);
if (ret) {
printk(KERN_ERR "Failed to register wm8770 SPI driver: %d\n",
ret);
}
#endif
return ret;
}
module_init(wm8770_modinit);
static void __exit wm8770_exit(void)
{
#if defined(CONFIG_SPI_MASTER)
spi_unregister_driver(&wm8770_spi_driver);
#endif
}
module_exit(wm8770_exit);
MODULE_DESCRIPTION("ASoC WM8770 driver");
MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>");
MODULE_LICENSE("GPL");

51
sound/soc/codecs/wm8770.h Normal file
View File

@ -0,0 +1,51 @@
/*
* wm8770.h -- WM8770 ASoC driver
*
* Copyright 2010 Wolfson Microelectronics plc
*
* Author: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
*
* 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 _WM8770_H
#define _WM8770_H
/* Registers */
#define WM8770_VOUT1LVOL 0
#define WM8770_VOUT1RVOL 0x1
#define WM8770_VOUT2LVOL 0x2
#define WM8770_VOUT2RVOL 0x3
#define WM8770_VOUT3LVOL 0x4
#define WM8770_VOUT3RVOL 0x5
#define WM8770_VOUT4LVOL 0x6
#define WM8770_VOUT4RVOL 0x7
#define WM8770_MSALGVOL 0x8
#define WM8770_DAC1LVOL 0x9
#define WM8770_DAC1RVOL 0xa
#define WM8770_DAC2LVOL 0xb
#define WM8770_DAC2RVOL 0xc
#define WM8770_DAC3LVOL 0xd
#define WM8770_DAC3RVOL 0xe
#define WM8770_DAC4LVOL 0xf
#define WM8770_DAC4RVOL 0x10
#define WM8770_MSDIGVOL 0x11
#define WM8770_DACPHASE 0x12
#define WM8770_DACCTRL1 0x13
#define WM8770_DACMUTE 0x14
#define WM8770_DACCTRL2 0x15
#define WM8770_IFACECTRL 0x16
#define WM8770_MSTRCTRL 0x17
#define WM8770_PWDNCTRL 0x18
#define WM8770_ADCLCTRL 0x19
#define WM8770_ADCRCTRL 0x1a
#define WM8770_ADCMUX 0x1b
#define WM8770_OUTMUX1 0x1c
#define WM8770_OUTMUX2 0x1d
#define WM8770_RESET 0x31
#define WM8770_CACHEREGNUM 0x20
#endif

Some files were not shown because too many files have changed in this diff Show More