提交 d71f4cec 编写于 作者: T Takashi Iwai

Merge branch 'topic/asoc' into for-linus

Conflicts:
	sound/soc/codecs/ad1938.c
......@@ -605,7 +605,11 @@ static __init void dm365_evm_init(void)
/* maybe setup mmc1/etc ... _after_ mmc0 */
evm_init_cpld();
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
dm365_init_asp(&dm365_evm_snd_data);
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
dm365_init_vc(&dm365_evm_snd_data);
#endif
dm365_init_rtc();
dm365_init_ks(&dm365evm_ks_data);
......
......@@ -187,32 +187,28 @@ static struct omap_mcbsp_platform_data omap44xx_mcbsp_pdata[] = {
.phys_base = OMAP44XX_MCBSP1_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP1_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP1_TX,
.rx_irq = INT_24XX_MCBSP1_IRQ_RX,
.tx_irq = INT_24XX_MCBSP1_IRQ_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP1,
.ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP44XX_MCBSP2_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP2_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP2_TX,
.rx_irq = INT_24XX_MCBSP2_IRQ_RX,
.tx_irq = INT_24XX_MCBSP2_IRQ_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP2,
.ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP44XX_MCBSP3_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP3_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP3_TX,
.rx_irq = INT_24XX_MCBSP3_IRQ_RX,
.tx_irq = INT_24XX_MCBSP3_IRQ_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP3,
.ops = &omap2_mcbsp_ops,
},
{
.phys_base = OMAP44XX_MCBSP4_BASE,
.dma_rx_sync = OMAP44XX_DMA_MCBSP4_RX,
.dma_tx_sync = OMAP44XX_DMA_MCBSP4_TX,
.rx_irq = INT_24XX_MCBSP4_IRQ_RX,
.tx_irq = INT_24XX_MCBSP4_IRQ_TX,
.tx_irq = OMAP44XX_IRQ_MCBSP4,
.ops = &omap2_mcbsp_ops,
},
};
......
......@@ -30,7 +30,6 @@
#include <mach/regs-mem.h>
#include <mach/regs-lcd.h>
#include <mach/regs-sdi.h>
#include <plat/regs-s3c2412-iis.h>
#include <plat/regs-iis.h>
#include <plat/regs-spi.h>
......@@ -119,13 +118,11 @@ static struct s3c24xx_dma_map __initdata s3c2412_dma_mappings[] = {
.name = "i2s-sdi",
.channels = MAP(S3C2412_DMAREQSEL_I2SRX),
.channels_rx = MAP(S3C2412_DMAREQSEL_I2SRX),
.hw_addr.from = S3C2410_PA_IIS + S3C2412_IISRXD,
},
[DMACH_I2S_OUT] = {
.name = "i2s-sdo",
.channels = MAP(S3C2412_DMAREQSEL_I2STX),
.channels_rx = MAP(S3C2412_DMAREQSEL_I2STX),
.hw_addr.to = S3C2410_PA_IIS + S3C2412_IISTXD,
},
[DMACH_USB_EP1] = {
.name = "usb-ep1",
......
......@@ -149,6 +149,8 @@
#define OMAP_MCBSP_REG_WAKEUPEN 0xA8
#define OMAP_MCBSP_REG_XCCR 0xAC
#define OMAP_MCBSP_REG_RCCR 0xB0
#define OMAP_MCBSP_REG_XBUFFSTAT 0xB4
#define OMAP_MCBSP_REG_RBUFFSTAT 0xB8
#define OMAP_MCBSP_REG_SSELCR 0xBC
#define OMAP_ST_REG_REV 0x00
......@@ -471,6 +473,8 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold);
u16 omap_mcbsp_get_max_tx_threshold(unsigned int id);
u16 omap_mcbsp_get_max_rx_threshold(unsigned int id);
u16 omap_mcbsp_get_tx_delay(unsigned int id);
u16 omap_mcbsp_get_rx_delay(unsigned int id);
int omap_mcbsp_get_dma_op_mode(unsigned int id);
#else
static inline void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
......@@ -479,6 +483,8 @@ static inline void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
{ }
static inline u16 omap_mcbsp_get_max_tx_threshold(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_max_rx_threshold(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_tx_delay(unsigned int id) { return 0; }
static inline u16 omap_mcbsp_get_rx_delay(unsigned int id) { return 0; }
static inline int omap_mcbsp_get_dma_op_mode(unsigned int id) { return 0; }
#endif
int omap_mcbsp_request(unsigned int id);
......
......@@ -489,7 +489,7 @@ void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
{
struct omap_mcbsp *mcbsp;
if (!cpu_is_omap34xx())
if (!cpu_is_omap34xx() && !cpu_is_omap44xx())
return;
if (!omap_mcbsp_check_valid_id(id)) {
......@@ -511,7 +511,7 @@ void omap_mcbsp_set_rx_threshold(unsigned int id, u16 threshold)
{
struct omap_mcbsp *mcbsp;
if (!cpu_is_omap34xx())
if (!cpu_is_omap34xx() && !cpu_is_omap44xx())
return;
if (!omap_mcbsp_check_valid_id(id)) {
......@@ -560,6 +560,61 @@ u16 omap_mcbsp_get_max_rx_threshold(unsigned int id)
}
EXPORT_SYMBOL(omap_mcbsp_get_max_rx_threshold);
#define MCBSP2_FIFO_SIZE 0x500 /* 1024 + 256 locations */
#define MCBSP1345_FIFO_SIZE 0x80 /* 128 locations */
/*
* omap_mcbsp_get_tx_delay returns the number of used slots in the McBSP FIFO
*/
u16 omap_mcbsp_get_tx_delay(unsigned int id)
{
struct omap_mcbsp *mcbsp;
u16 buffstat;
if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
}
mcbsp = id_to_mcbsp_ptr(id);
/* Returns the number of free locations in the buffer */
buffstat = MCBSP_READ(mcbsp, XBUFFSTAT);
/* Number of slots are different in McBSP ports */
if (mcbsp->id == 2)
return MCBSP2_FIFO_SIZE - buffstat;
else
return MCBSP1345_FIFO_SIZE - buffstat;
}
EXPORT_SYMBOL(omap_mcbsp_get_tx_delay);
/*
* omap_mcbsp_get_rx_delay returns the number of free slots in the McBSP FIFO
* to reach the threshold value (when the DMA will be triggered to read it)
*/
u16 omap_mcbsp_get_rx_delay(unsigned int id)
{
struct omap_mcbsp *mcbsp;
u16 buffstat, threshold;
if (!omap_mcbsp_check_valid_id(id)) {
printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
return -ENODEV;
}
mcbsp = id_to_mcbsp_ptr(id);
/* Returns the number of used locations in the buffer */
buffstat = MCBSP_READ(mcbsp, RBUFFSTAT);
/* RX threshold */
threshold = MCBSP_READ(mcbsp, THRSH1);
/* Return the number of location till we reach the threshold limit */
if (threshold <= buffstat)
return 0;
else
return threshold - buffstat;
}
EXPORT_SYMBOL(omap_mcbsp_get_rx_delay);
/*
* omap_mcbsp_get_dma_op_mode just return the current configured
* operating mode for the mcbsp channel
......@@ -587,7 +642,7 @@ static inline void omap34xx_mcbsp_request(struct omap_mcbsp *mcbsp)
* Enable wakup behavior, smart idle and all wakeups
* REVISIT: some wakeups may be unnecessary
*/
if (cpu_is_omap34xx()) {
if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
u16 syscon;
syscon = MCBSP_READ(mcbsp, SYSCON);
......@@ -610,7 +665,7 @@ static inline void omap34xx_mcbsp_free(struct omap_mcbsp *mcbsp)
/*
* Disable wakup behavior, smart idle and all wakeups
*/
if (cpu_is_omap34xx()) {
if (cpu_is_omap34xx() || cpu_is_omap44xx()) {
u16 syscon;
syscon = MCBSP_READ(mcbsp, SYSCON);
......@@ -724,14 +779,17 @@ int omap_mcbsp_request(unsigned int id)
goto err_clk_disable;
}
init_completion(&mcbsp->rx_irq_completion);
err = request_irq(mcbsp->rx_irq, omap_mcbsp_rx_irq_handler,
if (mcbsp->rx_irq) {
init_completion(&mcbsp->rx_irq_completion);
err = request_irq(mcbsp->rx_irq,
omap_mcbsp_rx_irq_handler,
0, "McBSP", (void *)mcbsp);
if (err != 0) {
dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
"for McBSP%d\n", mcbsp->rx_irq,
mcbsp->id);
goto err_free_irq;
if (err != 0) {
dev_err(mcbsp->dev, "Unable to request RX IRQ %d "
"for McBSP%d\n", mcbsp->rx_irq,
mcbsp->id);
goto err_free_irq;
}
}
}
......@@ -781,7 +839,8 @@ void omap_mcbsp_free(unsigned int id)
if (mcbsp->io_type == OMAP_MCBSP_IRQ_IO) {
/* Free IRQs */
free_irq(mcbsp->rx_irq, (void *)mcbsp);
if (mcbsp->rx_irq)
free_irq(mcbsp->rx_irq, (void *)mcbsp);
free_irq(mcbsp->tx_irq, (void *)mcbsp);
}
......@@ -855,7 +914,7 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx)
MCBSP_WRITE(mcbsp, SPCR2, w | (1 << 7));
}
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
/* Release the transmitter and receiver */
w = MCBSP_READ_CACHE(mcbsp, XCCR);
w &= ~(tx ? XDISABLE : 0);
......@@ -885,7 +944,7 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
/* Reset transmitter */
tx &= 1;
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
w = MCBSP_READ_CACHE(mcbsp, XCCR);
w |= (tx ? XDISABLE : 0);
MCBSP_WRITE(mcbsp, XCCR, w);
......@@ -895,7 +954,7 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx)
/* Reset receiver */
rx &= 1;
if (cpu_is_omap2430() || cpu_is_omap34xx()) {
if (cpu_is_omap2430() || cpu_is_omap34xx() || cpu_is_omap44xx()) {
w = MCBSP_READ_CACHE(mcbsp, RCCR);
w |= (rx ? RDISABLE : 0);
MCBSP_WRITE(mcbsp, RCCR, w);
......
......@@ -81,6 +81,18 @@ static void wm8994_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
wm8994_set_bits(wm8994, WM8994_GPIO_1 + offset, WM8994_GPN_LVL, value);
}
static int wm8994_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct wm8994_gpio *wm8994_gpio = to_wm8994_gpio(chip);
struct wm8994 *wm8994 = wm8994_gpio->wm8994;
if (!wm8994->irq_base)
return -EINVAL;
return wm8994->irq_base + offset;
}
#ifdef CONFIG_DEBUG_FS
static void wm8994_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
......
......@@ -53,6 +53,10 @@ config MFD_SH_MOBILE_SDHI
This driver supports the SDHI hardware block found in many
SuperH Mobile SoCs.
config MFD_DAVINCI_VOICECODEC
tristate
select MFD_CORE
config MFD_DM355EVM_MSP
bool "DaVinci DM355 EVM microcontroller"
depends on I2C && MACH_DAVINCI_DM355_EVM
......@@ -297,9 +301,9 @@ config MFD_WM8350_I2C
selected to enable support for the functionality of the chip.
config MFD_WM8994
tristate "Support Wolfson Microelectronics WM8994"
bool "Support Wolfson Microelectronics WM8994"
select MFD_CORE
depends on I2C
depends on I2C=y && GENERIC_HARDIRQS
help
The WM8994 is a highly integrated hi-fi CODEC designed for
smartphone applicatiosn. As well as audio functionality it
......
......@@ -12,6 +12,7 @@ obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o
obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
......@@ -25,7 +26,7 @@ wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o
wm8350-objs += wm8350-irq.o
obj-$(CONFIG_MFD_WM8350) += wm8350.o
obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o
obj-$(CONFIG_MFD_WM8994) += wm8994-core.o wm8994-irq.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_MENELAUS) += menelaus.o
......
/*
* DaVinci Voice Codec Core Interface for TI platforms
*
* Copyright (C) 2010 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <sound/pcm.h>
#include <linux/mfd/davinci_voicecodec.h>
u32 davinci_vc_read(struct davinci_vc *davinci_vc, int reg)
{
return __raw_readl(davinci_vc->base + reg);
}
void davinci_vc_write(struct davinci_vc *davinci_vc,
int reg, u32 val)
{
__raw_writel(val, davinci_vc->base + reg);
}
static int __init davinci_vc_probe(struct platform_device *pdev)
{
struct davinci_vc *davinci_vc;
struct resource *res, *mem;
struct mfd_cell *cell = NULL;
int ret;
davinci_vc = kzalloc(sizeof(struct davinci_vc), GFP_KERNEL);
if (!davinci_vc) {
dev_dbg(&pdev->dev,
"could not allocate memory for private data\n");
return -ENOMEM;
}
davinci_vc->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(davinci_vc->clk)) {
dev_dbg(&pdev->dev,
"could not get the clock for voice codec\n");
ret = -ENODEV;
goto fail1;
}
clk_enable(davinci_vc->clk);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "no mem resource\n");
ret = -ENODEV;
goto fail2;
}
davinci_vc->pbase = res->start;
davinci_vc->base_size = resource_size(res);
mem = request_mem_region(davinci_vc->pbase, davinci_vc->base_size,
pdev->name);
if (!mem) {
dev_err(&pdev->dev, "VCIF region already claimed\n");
ret = -EBUSY;
goto fail2;
}
davinci_vc->base = ioremap(davinci_vc->pbase, davinci_vc->base_size);
if (!davinci_vc->base) {
dev_err(&pdev->dev, "can't ioremap mem resource.\n");
ret = -ENOMEM;
goto fail3;
}
res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
return -ENXIO;
}
davinci_vc->davinci_vcif.dma_tx_channel = res->start;
davinci_vc->davinci_vcif.dma_tx_addr =
(dma_addr_t)(io_v2p(davinci_vc->base) + DAVINCI_VC_WFIFO);
res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!res) {
dev_err(&pdev->dev, "no DMA resource\n");
return -ENXIO;
}
davinci_vc->davinci_vcif.dma_rx_channel = res->start;
davinci_vc->davinci_vcif.dma_rx_addr =
(dma_addr_t)(io_v2p(davinci_vc->base) + DAVINCI_VC_RFIFO);
davinci_vc->dev = &pdev->dev;
davinci_vc->pdev = pdev;
/* Voice codec interface client */
cell = &davinci_vc->cells[DAVINCI_VC_VCIF_CELL];
cell->name = "davinci_vcif";
cell->driver_data = davinci_vc;
/* Voice codec CQ93VC client */
cell = &davinci_vc->cells[DAVINCI_VC_CQ93VC_CELL];
cell->name = "cq93vc";
cell->driver_data = davinci_vc;
ret = mfd_add_devices(&pdev->dev, pdev->id, davinci_vc->cells,
DAVINCI_VC_CELLS, NULL, 0);
if (ret != 0) {
dev_err(&pdev->dev, "fail to register client devices\n");
goto fail4;
}
return 0;
fail4:
iounmap(davinci_vc->base);
fail3:
release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
fail2:
clk_disable(davinci_vc->clk);
clk_put(davinci_vc->clk);
davinci_vc->clk = NULL;
fail1:
kfree(davinci_vc);
return ret;
}
static int __devexit davinci_vc_remove(struct platform_device *pdev)
{
struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
mfd_remove_devices(&pdev->dev);
iounmap(davinci_vc->base);
release_mem_region(davinci_vc->pbase, davinci_vc->base_size);
clk_disable(davinci_vc->clk);
clk_put(davinci_vc->clk);
davinci_vc->clk = NULL;
kfree(davinci_vc);
return 0;
}
static struct platform_driver davinci_vc_driver = {
.driver = {
.name = "davinci_voicecodec",
.owner = THIS_MODULE,
},
.remove = __devexit_p(davinci_vc_remove),
};
static int __init davinci_vc_init(void)
{
return platform_driver_probe(&davinci_vc_driver, davinci_vc_probe);
}
module_init(davinci_vc_init);
static void __exit davinci_vc_exit(void)
{
platform_driver_unregister(&davinci_vc_driver);
}
module_exit(davinci_vc_exit);
MODULE_AUTHOR("Miguel Aguilar");
MODULE_DESCRIPTION("Texas Instruments DaVinci Voice Codec Core Interface");
MODULE_LICENSE("GPL");
......@@ -109,7 +109,7 @@
#endif
#if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
defined(CONFIG_SND_SOC_TWL6030) || defined(CONFIG_SND_SOC_TWL6030_MODULE)
defined(CONFIG_SND_SOC_TWL6040) || defined(CONFIG_SND_SOC_TWL6040_MODULE)
#define twl_has_codec() true
#else
#define twl_has_codec() false
......@@ -708,7 +708,7 @@ add_children(struct twl4030_platform_data *pdata, unsigned long features)
/* Phoenix*/
if (twl_has_codec() && pdata->codec && twl_class_is_6030()) {
sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
child = add_child(sub_chip_id, "twl6030_codec",
child = add_child(sub_chip_id, "twl6040_codec",
pdata->codec, sizeof(*pdata->codec),
false, 0, 0);
if (IS_ERR(child))
......
......@@ -21,6 +21,7 @@
#include <linux/mfd/wm831x/core.h>
#include <linux/mfd/wm831x/pdata.h>
#include <linux/mfd/wm831x/gpio.h>
#include <linux/mfd/wm831x/irq.h>
#include <linux/delay.h>
......@@ -388,12 +389,41 @@ static void wm831x_irq_mask(unsigned int irq)
wm831x->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static int wm831x_irq_set_type(unsigned int irq, unsigned int type)
{
struct wm831x *wm831x = get_irq_chip_data(irq);
int val;
irq = irq - wm831x->irq_base;
if (irq < WM831X_IRQ_GPIO_1 || irq > WM831X_IRQ_GPIO_11)
return -EINVAL;
switch (type) {
case IRQ_TYPE_EDGE_BOTH:
val = WM831X_GPN_INT_MODE;
break;
case IRQ_TYPE_EDGE_RISING:
val = WM831X_GPN_POL;
break;
case IRQ_TYPE_EDGE_FALLING:
val = 0;
break;
default:
return -EINVAL;
}
return wm831x_set_bits(wm831x, WM831X_GPIO1_CONTROL + irq,
WM831X_GPN_INT_MODE | WM831X_GPN_POL, val);
}
static struct irq_chip wm831x_irq_chip = {
.name = "wm831x",
.bus_lock = wm831x_irq_lock,
.bus_sync_unlock = wm831x_irq_sync_unlock,
.mask = wm831x_irq_mask,
.unmask = wm831x_irq_unmask,
.set_type = wm831x_irq_set_type,
};
/* The processing of the primary interrupt occurs in a thread so that
......
......@@ -173,9 +173,34 @@ static struct mfd_cell wm8994_regulator_devs[] = {
{ .name = "wm8994-ldo", .id = 2 },
};
static struct resource wm8994_codec_resources[] = {
{
.start = WM8994_IRQ_TEMP_SHUT,
.end = WM8994_IRQ_TEMP_WARN,
.flags = IORESOURCE_IRQ,
},
};
static struct resource wm8994_gpio_resources[] = {
{
.start = WM8994_IRQ_GPIO(1),
.end = WM8994_IRQ_GPIO(11),
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell wm8994_devs[] = {
{ .name = "wm8994-codec" },
{ .name = "wm8994-gpio" },
{
.name = "wm8994-codec",
.num_resources = ARRAY_SIZE(wm8994_codec_resources),
.resources = wm8994_codec_resources,
},
{
.name = "wm8994-gpio",
.num_resources = ARRAY_SIZE(wm8994_gpio_resources),
.resources = wm8994_gpio_resources,
},
};
/*
......@@ -236,6 +261,11 @@ static int wm8994_device_resume(struct device *dev)
return ret;
}
ret = wm8994_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK,
WM8994_NUM_IRQ_REGS * 2, &wm8994->irq_masks_cur);
if (ret < 0)
dev_err(dev, "Failed to restore interrupt masks: %d\n", ret);
ret = wm8994_write(wm8994, WM8994_LDO_1, WM8994_NUM_LDO_REGS * 2,
&wm8994->ldo_regs);
if (ret < 0)
......@@ -348,6 +378,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
if (pdata) {
wm8994->irq_base = pdata->irq_base;
wm8994->gpio_base = pdata->gpio_base;
/* GPIO configuration is only applied if it's non-zero */
......@@ -375,16 +406,20 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
WM8994_LDO1_DISCH, 0);
}
wm8994_irq_init(wm8994);
ret = mfd_add_devices(wm8994->dev, -1,
wm8994_devs, ARRAY_SIZE(wm8994_devs),
NULL, 0);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to add children: %d\n", ret);
goto err_enable;
goto err_irq;
}
return 0;
err_irq:
wm8994_irq_exit(wm8994);
err_enable:
regulator_bulk_disable(ARRAY_SIZE(wm8994_main_supplies),
wm8994->supplies);
......@@ -401,6 +436,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, unsigned long id, int irq)
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),
wm8994->supplies);
regulator_bulk_free(ARRAY_SIZE(wm8994_main_supplies), wm8994->supplies);
......@@ -469,6 +505,7 @@ static int wm8994_i2c_probe(struct i2c_client *i2c,
wm8994->control_data = i2c;
wm8994->read_dev = wm8994_i2c_read_device;
wm8994->write_dev = wm8994_i2c_write_device;
wm8994->irq = i2c->irq;
return wm8994_device_init(wm8994, id->driver_data, i2c->irq);
}
......
/*
* wm8994-irq.c -- Interrupt controller support for Wolfson WM8994
*
* 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 as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <linux/interrupt.h>
#include <linux/mfd/wm8994/core.h>
#include <linux/mfd/wm8994/registers.h>
#include <linux/delay.h>
struct wm8994_irq_data {
int reg;
int mask;
};
static struct wm8994_irq_data wm8994_irqs[] = {
[WM8994_IRQ_TEMP_SHUT] = {
.reg = 2,
.mask = WM8994_TEMP_SHUT_EINT,
},
[WM8994_IRQ_MIC1_DET] = {
.reg = 2,
.mask = WM8994_MIC1_DET_EINT,
},
[WM8994_IRQ_MIC1_SHRT] = {
.reg = 2,
.mask = WM8994_MIC1_SHRT_EINT,
},
[WM8994_IRQ_MIC2_DET] = {
.reg = 2,
.mask = WM8994_MIC2_DET_EINT,
},
[WM8994_IRQ_MIC2_SHRT] = {
.reg = 2,
.mask = WM8994_MIC2_SHRT_EINT,
},
[WM8994_IRQ_FLL1_LOCK] = {
.reg = 2,
.mask = WM8994_FLL1_LOCK_EINT,
},
[WM8994_IRQ_FLL2_LOCK] = {
.reg = 2,
.mask = WM8994_FLL2_LOCK_EINT,
},
[WM8994_IRQ_SRC1_LOCK] = {
.reg = 2,
.mask = WM8994_SRC1_LOCK_EINT,
},
[WM8994_IRQ_SRC2_LOCK] = {
.reg = 2,
.mask = WM8994_SRC2_LOCK_EINT,
},
[WM8994_IRQ_AIF1DRC1_SIG_DET] = {
.reg = 2,
.mask = WM8994_AIF1DRC1_SIG_DET,
},
[WM8994_IRQ_AIF1DRC2_SIG_DET] = {
.reg = 2,
.mask = WM8994_AIF1DRC2_SIG_DET_EINT,
},
[WM8994_IRQ_AIF2DRC_SIG_DET] = {
.reg = 2,
.mask = WM8994_AIF2DRC_SIG_DET_EINT,
},
[WM8994_IRQ_FIFOS_ERR] = {
.reg = 2,
.mask = WM8994_FIFOS_ERR_EINT,
},
[WM8994_IRQ_WSEQ_DONE] = {
.reg = 2,
.mask = WM8994_WSEQ_DONE_EINT,
},
[WM8994_IRQ_DCS_DONE] = {
.reg = 2,
.mask = WM8994_DCS_DONE_EINT,
},
[WM8994_IRQ_TEMP_WARN] = {
.reg = 2,
.mask = WM8994_TEMP_WARN_EINT,
},
[WM8994_IRQ_GPIO(1)] = {
.reg = 1,
.mask = WM8994_GP1_EINT,
},
[WM8994_IRQ_GPIO(2)] = {
.reg = 1,
.mask = WM8994_GP2_EINT,
},
[WM8994_IRQ_GPIO(3)] = {
.reg = 1,
.mask = WM8994_GP3_EINT,
},
[WM8994_IRQ_GPIO(4)] = {
.reg = 1,
.mask = WM8994_GP4_EINT,
},
[WM8994_IRQ_GPIO(5)] = {
.reg = 1,
.mask = WM8994_GP5_EINT,
},
[WM8994_IRQ_GPIO(6)] = {
.reg = 1,
.mask = WM8994_GP6_EINT,
},
[WM8994_IRQ_GPIO(7)] = {
.reg = 1,
.mask = WM8994_GP7_EINT,
},
[WM8994_IRQ_GPIO(8)] = {
.reg = 1,
.mask = WM8994_GP8_EINT,
},
[WM8994_IRQ_GPIO(9)] = {
.reg = 1,
.mask = WM8994_GP8_EINT,
},
[WM8994_IRQ_GPIO(10)] = {
.reg = 1,
.mask = WM8994_GP10_EINT,
},
[WM8994_IRQ_GPIO(11)] = {
.reg = 1,
.mask = WM8994_GP11_EINT,
},
};
static inline int irq_data_to_status_reg(struct wm8994_irq_data *irq_data)
{
return WM8994_INTERRUPT_STATUS_1 - 1 + irq_data->reg;
}
static inline int irq_data_to_mask_reg(struct wm8994_irq_data *irq_data)
{
return WM8994_INTERRUPT_STATUS_1_MASK - 1 + irq_data->reg;
}
static inline struct wm8994_irq_data *irq_to_wm8994_irq(struct wm8994 *wm8994,
int irq)
{
return &wm8994_irqs[irq - wm8994->irq_base];
}
static void wm8994_irq_lock(unsigned int irq)
{
struct wm8994 *wm8994 = get_irq_chip_data(irq);
mutex_lock(&wm8994->irq_lock);
}
static void wm8994_irq_sync_unlock(unsigned int irq)
{
struct wm8994 *wm8994 = get_irq_chip_data(irq);
int i;
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
/* If there's been a change in the mask write it back
* to the hardware. */
if (wm8994->irq_masks_cur[i] != wm8994->irq_masks_cache[i]) {
wm8994->irq_masks_cache[i] = wm8994->irq_masks_cur[i];
wm8994_reg_write(wm8994,
WM8994_INTERRUPT_STATUS_1_MASK + i,
wm8994->irq_masks_cur[i]);
}
}
mutex_unlock(&wm8994->irq_lock);
}
static void wm8994_irq_unmask(unsigned int irq)
{
struct wm8994 *wm8994 = get_irq_chip_data(irq);
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
wm8994->irq_masks_cur[irq_data->reg - 1] &= ~irq_data->mask;
}
static void wm8994_irq_mask(unsigned int irq)
{
struct wm8994 *wm8994 = get_irq_chip_data(irq);
struct wm8994_irq_data *irq_data = irq_to_wm8994_irq(wm8994, irq);
wm8994->irq_masks_cur[irq_data->reg - 1] |= irq_data->mask;
}
static struct irq_chip wm8994_irq_chip = {
.name = "wm8994",
.bus_lock = wm8994_irq_lock,
.bus_sync_unlock = wm8994_irq_sync_unlock,
.mask = wm8994_irq_mask,
.unmask = wm8994_irq_unmask,
};
/* The processing of the primary interrupt occurs in a thread so that
* we can interact with the device over I2C or SPI. */
static irqreturn_t wm8994_irq_thread(int irq, void *data)
{
struct wm8994 *wm8994 = data;
unsigned int i;
u16 status[WM8994_NUM_IRQ_REGS];
int ret;
ret = wm8994_bulk_read(wm8994, WM8994_INTERRUPT_STATUS_1,
WM8994_NUM_IRQ_REGS, status);
if (ret < 0) {
dev_err(wm8994->dev, "Failed to read interrupt status: %d\n",
ret);
return IRQ_NONE;
}
/* Apply masking */
for (i = 0; i < WM8994_NUM_IRQ_REGS; i++)
status[i] &= ~wm8994->irq_masks_cur[i];
/* Report */
for (i = 0; i < ARRAY_SIZE(wm8994_irqs); i++) {
if (status[wm8994_irqs[i].reg - 1] & wm8994_irqs[i].mask)
handle_nested_irq(wm8994->irq_base + i);
}
/* Ack any unmasked IRQs */
for (i = 0; i < ARRAY_SIZE(status); i++) {
if (status[i])
wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1 + i,
status[i]);
}
return IRQ_HANDLED;
}
int wm8994_irq_init(struct wm8994 *wm8994)
{
int i, cur_irq, ret;
mutex_init(&wm8994->irq_lock);
/* Mask the individual interrupt sources */
for (i = 0; i < ARRAY_SIZE(wm8994->irq_masks_cur); i++) {
wm8994->irq_masks_cur[i] = 0xffff;
wm8994->irq_masks_cache[i] = 0xffff;
wm8994_reg_write(wm8994, WM8994_INTERRUPT_STATUS_1_MASK + i,
0xffff);
}
if (!wm8994->irq) {
dev_warn(wm8994->dev,
"No interrupt specified, no interrupts\n");
wm8994->irq_base = 0;
return 0;
}
if (!wm8994->irq_base) {
dev_err(wm8994->dev,
"No interrupt base specified, no interrupts\n");
return 0;
}
/* Register them with genirq */
for (cur_irq = wm8994->irq_base;
cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base;
cur_irq++) {
set_irq_chip_data(cur_irq, wm8994);
set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip,
handle_edge_irq);
set_irq_nested_thread(cur_irq, 1);
/* ARM needs us to explicitly flag the IRQ as valid
* and will set them noprobe when we do so. */
#ifdef CONFIG_ARM
set_irq_flags(cur_irq, IRQF_VALID);
#else
set_irq_noprobe(cur_irq);
#endif
}
ret = request_threaded_irq(wm8994->irq, NULL, wm8994_irq_thread,
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"wm8994", wm8994);
if (ret != 0) {
dev_err(wm8994->dev, "Failed to request IRQ %d: %d\n",
wm8994->irq, ret);
return ret;
}
/* Enable top level interrupt if it was masked */
wm8994_reg_write(wm8994, WM8994_INTERRUPT_CONTROL, 0);
return 0;
}
void wm8994_irq_exit(struct wm8994 *wm8994)
{
if (wm8994->irq)
free_irq(wm8994->irq, wm8994);
}
......@@ -569,9 +569,9 @@ struct twl4030_codec_data {
struct twl4030_codec_audio_data *audio;
struct twl4030_codec_vibra_data *vibra;
/* twl6030 */
int audpwron_gpio; /* audio power-on gpio */
int naudint_irq; /* audio interrupt */
/* twl6040 */
int audpwron_gpio; /* audio power-on gpio */
int naudint_irq; /* audio interrupt */
};
struct twl4030_platform_data {
......
/*
* DaVinci Voice Codec Core Interface for TI platforms
*
* Copyright (C) 2010 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __LINUX_MFD_DAVINCI_VOICECODEC_H_
#define __LINUX_MFD_DAVINIC_VOICECODEC_H_
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/mfd/core.h>
#include <mach/edma.h>
/*
* Register values.
*/
#define DAVINCI_VC_PID 0x00
#define DAVINCI_VC_CTRL 0x04
#define DAVINCI_VC_INTEN 0x08
#define DAVINCI_VC_INTSTATUS 0x0c
#define DAVINCI_VC_INTCLR 0x10
#define DAVINCI_VC_EMUL_CTRL 0x14
#define DAVINCI_VC_RFIFO 0x20
#define DAVINCI_VC_WFIFO 0x24
#define DAVINCI_VC_FIFOSTAT 0x28
#define DAVINCI_VC_TST_CTRL 0x2C
#define DAVINCI_VC_REG05 0x94
#define DAVINCI_VC_REG09 0xA4
#define DAVINCI_VC_REG12 0xB0
/* DAVINCI_VC_CTRL bit fields */
#define DAVINCI_VC_CTRL_MASK 0x5500
#define DAVINCI_VC_CTRL_RSTADC BIT(0)
#define DAVINCI_VC_CTRL_RSTDAC BIT(1)
#define DAVINCI_VC_CTRL_RD_BITS_8 BIT(4)
#define DAVINCI_VC_CTRL_RD_UNSIGNED BIT(5)
#define DAVINCI_VC_CTRL_WD_BITS_8 BIT(6)
#define DAVINCI_VC_CTRL_WD_UNSIGNED BIT(7)
#define DAVINCI_VC_CTRL_RFIFOEN BIT(8)
#define DAVINCI_VC_CTRL_RFIFOCL BIT(9)
#define DAVINCI_VC_CTRL_RFIFOMD_WORD_1 BIT(10)
#define DAVINCI_VC_CTRL_WFIFOEN BIT(12)
#define DAVINCI_VC_CTRL_WFIFOCL BIT(13)
#define DAVINCI_VC_CTRL_WFIFOMD_WORD_1 BIT(14)
/* DAVINCI_VC_INT bit fields */
#define DAVINCI_VC_INT_MASK 0x3F
#define DAVINCI_VC_INT_RDRDY_MASK BIT(0)
#define DAVINCI_VC_INT_RERROVF_MASK BIT(1)
#define DAVINCI_VC_INT_RERRUDR_MASK BIT(2)
#define DAVINCI_VC_INT_WDREQ_MASK BIT(3)
#define DAVINCI_VC_INT_WERROVF_MASKBIT BIT(4)
#define DAVINCI_VC_INT_WERRUDR_MASK BIT(5)
/* DAVINCI_VC_REG05 bit fields */
#define DAVINCI_VC_REG05_PGA_GAIN 0x07
/* DAVINCI_VC_REG09 bit fields */
#define DAVINCI_VC_REG09_MUTE 0x40
#define DAVINCI_VC_REG09_DIG_ATTEN 0x3F
/* DAVINCI_VC_REG12 bit fields */
#define DAVINCI_VC_REG12_POWER_ALL_ON 0xFD
#define DAVINCI_VC_REG12_POWER_ALL_OFF 0x00
#define DAVINCI_VC_CELLS 2
enum davinci_vc_cells {
DAVINCI_VC_VCIF_CELL,
DAVINCI_VC_CQ93VC_CELL,
};
struct davinci_vcif {
struct platform_device *pdev;
u32 dma_tx_channel;
u32 dma_rx_channel;
dma_addr_t dma_tx_addr;
dma_addr_t dma_rx_addr;
};
struct cq93vc {
struct platform_device *pdev;
struct snd_soc_codec *codec;
u32 sysclk;
};
struct davinci_vc;
struct davinci_vc {
/* Device data */
struct device *dev;
struct platform_device *pdev;
struct clk *clk;
/* Memory resources */
void __iomem *base;
resource_size_t pbase;
size_t base_size;
/* MFD cells */
struct mfd_cell cells[DAVINCI_VC_CELLS];
/* Client devices */
struct davinci_vcif davinci_vcif;
struct cq93vc cq93vc;
};
#endif
......@@ -492,6 +492,8 @@
*/
#define WM8350_JACK_L_LVL 0x0800
#define WM8350_JACK_R_LVL 0x0400
#define WM8350_JACK_MICSCD_LVL 0x0200
#define WM8350_JACK_MICSD_LVL 0x0100
/*
* WM8350 Platform setup
......
......@@ -15,14 +15,38 @@
#ifndef __MFD_WM8994_CORE_H__
#define __MFD_WM8994_CORE_H__
#include <linux/interrupt.h>
struct regulator_dev;
struct regulator_bulk_data;
#define WM8994_NUM_GPIO_REGS 11
#define WM8994_NUM_LDO_REGS 2
#define WM8994_NUM_LDO_REGS 2
#define WM8994_NUM_IRQ_REGS 2
#define WM8994_IRQ_TEMP_SHUT 0
#define WM8994_IRQ_MIC1_DET 1
#define WM8994_IRQ_MIC1_SHRT 2
#define WM8994_IRQ_MIC2_DET 3
#define WM8994_IRQ_MIC2_SHRT 4
#define WM8994_IRQ_FLL1_LOCK 5
#define WM8994_IRQ_FLL2_LOCK 6
#define WM8994_IRQ_SRC1_LOCK 7
#define WM8994_IRQ_SRC2_LOCK 8
#define WM8994_IRQ_AIF1DRC1_SIG_DET 9
#define WM8994_IRQ_AIF1DRC2_SIG_DET 10
#define WM8994_IRQ_AIF2DRC_SIG_DET 11
#define WM8994_IRQ_FIFOS_ERR 12
#define WM8994_IRQ_WSEQ_DONE 13
#define WM8994_IRQ_DCS_DONE 14
#define WM8994_IRQ_TEMP_WARN 15
/* GPIOs in the chip are numbered from 1-11 */
#define WM8994_IRQ_GPIO(x) (x + WM8994_IRQ_TEMP_WARN)
struct wm8994 {
struct mutex io_lock;
struct mutex irq_lock;
struct device *dev;
int (*read_dev)(struct wm8994 *wm8994, unsigned short reg,
......@@ -33,6 +57,11 @@ struct wm8994 {
void *control_data;
int gpio_base;
int irq_base;
int irq;
u16 irq_masks_cur[WM8994_NUM_IRQ_REGS];
u16 irq_masks_cache[WM8994_NUM_IRQ_REGS];
/* Used over suspend/resume */
u16 ldo_regs[WM8994_NUM_LDO_REGS];
......@@ -51,4 +80,26 @@ int wm8994_set_bits(struct wm8994 *wm8994, unsigned short reg,
int wm8994_bulk_read(struct wm8994 *wm8994, unsigned short reg,
int count, u16 *buf);
/* Helper to save on boilerplate */
static inline int wm8994_request_irq(struct wm8994 *wm8994, int irq,
irq_handler_t handler, const char *name,
void *data)
{
if (!wm8994->irq_base)
return -EINVAL;
return request_threaded_irq(wm8994->irq_base + irq, NULL, handler,
IRQF_TRIGGER_RISING, name,
data);
}
static inline void wm8994_free_irq(struct wm8994 *wm8994, int irq, void *data)
{
if (!wm8994->irq_base)
return;
free_irq(wm8994->irq_base + irq, data);
}
int wm8994_irq_init(struct wm8994 *wm8994);
void wm8994_irq_exit(struct wm8994 *wm8994);
#endif
......@@ -70,6 +70,7 @@ struct wm8994_pdata {
struct wm8994_ldo_pdata ldo[WM8994_NUM_LDO];
int irq_base; /** Base IRQ number for WM8994, required for IRQs */
int num_drc_cfgs;
struct wm8994_drc_cfg *drc_cfgs;
......
......@@ -182,6 +182,12 @@ struct snd_soc_dai_ops {
struct snd_soc_dai *);
int (*trigger)(struct snd_pcm_substream *, int,
struct snd_soc_dai *);
/*
* For hardware based FIFO caused delay reporting.
* Optional.
*/
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
struct snd_soc_dai *);
};
/*
......@@ -215,7 +221,6 @@ struct snd_soc_dai {
unsigned int symmetric_rates:1;
/* DAI runtime info */
struct snd_pcm_runtime *runtime;
struct snd_soc_codec *codec;
unsigned int active;
unsigned char pop_wait:1;
......
......@@ -339,6 +339,9 @@ 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,
const char *pin);
int snd_soc_dapm_ignore_suspend(struct snd_soc_codec *codec, const char *pin);
/* dapm widget types */
enum snd_soc_dapm_type {
......@@ -425,9 +428,8 @@ struct snd_soc_dapm_widget {
unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */
unsigned char ext:1; /* has external widgets */
unsigned char muted:1; /* muted for pop reduction */
unsigned char suspend:1; /* was active before suspend */
unsigned char pmdown:1; /* waiting for timeout */
unsigned char force:1; /* force state */
unsigned char ignore_suspend:1; /* kept enabled over suspend */
int (*power_check)(struct snd_soc_dapm_widget *w);
......
......@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/types.h>
#include <linux/notifier.h>
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
......@@ -29,10 +30,10 @@
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
.invert = xinvert})
.platform_max = xmax, .invert = xinvert})
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .max = xmax, .invert = xinvert})
{.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
#define SOC_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
......@@ -52,14 +53,14 @@
.put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw_2r, \
.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
......@@ -69,7 +70,7 @@
.put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = shift_left, .rshift = shift_right,\
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
......@@ -79,7 +80,7 @@
.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
......@@ -88,7 +89,8 @@
.info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
.put = snd_soc_put_volsw_s8, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .min = xmin, .max = xmax} }
{.reg = xreg, .min = xmin, .max = xmax, \
.platform_max = xmax} }
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmax, xtexts) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.max = xmax, .texts = xtexts }
......@@ -125,7 +127,7 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
......@@ -145,7 +147,7 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = shift_left, .rshift = shift_right, \
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
......@@ -156,7 +158,7 @@
.get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
.max = xmax, .invert = xinvert} }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_bool_ext, \
......@@ -212,6 +214,7 @@ struct snd_soc_dai_mode;
struct snd_soc_pcm_runtime;
struct snd_soc_dai;
struct snd_soc_platform;
struct snd_soc_dai_link;
struct snd_soc_codec;
struct soc_enum;
struct snd_soc_ac97_ops;
......@@ -260,6 +263,10 @@ int snd_soc_jack_new(struct snd_soc_card *card, const char *id, int type,
void snd_soc_jack_report(struct snd_soc_jack *jack, int status, int mask);
int snd_soc_jack_add_pins(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_pin *pins);
void snd_soc_jack_notifier_register(struct snd_soc_jack *jack,
struct notifier_block *nb);
void snd_soc_jack_notifier_unregister(struct snd_soc_jack *jack,
struct notifier_block *nb);
#ifdef CONFIG_GPIOLIB
int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
struct snd_soc_jack_gpio *gpios);
......@@ -320,6 +327,8 @@ int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_limit_volume(struct snd_soc_codec *codec,
const char *name, int max);
/**
* struct snd_soc_jack_pin - Describes a pin to update based on jack detection
......@@ -363,6 +372,7 @@ struct snd_soc_jack {
struct snd_soc_card *card;
struct list_head pins;
int status;
struct blocking_notifier_head notifier;
};
/* SoC PCM stream information */
......@@ -374,7 +384,7 @@ struct snd_soc_pcm_stream {
unsigned int rate_max; /* max rate */
unsigned int channels_min; /* min channels */
unsigned int channels_max; /* max channels */
unsigned int active:1; /* stream is in use */
unsigned int active; /* stream is in use */
void *dma_data; /* used by platform code */
};
......@@ -407,7 +417,7 @@ struct snd_soc_codec {
struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int active;
unsigned int pcm_devs;
void *private_data;
void *drvdata;
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
......@@ -462,14 +472,21 @@ struct snd_soc_platform {
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
int (*suspend)(struct snd_soc_dai *dai);
int (*resume)(struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_dai_link *dai_link);
int (*resume)(struct snd_soc_dai_link *dai_link);
/* pcm creation and destruction */
int (*pcm_new)(struct snd_card *, struct snd_soc_dai *,
struct snd_pcm *);
void (*pcm_free)(struct snd_pcm *);
/*
* For platform caused delay reporting.
* Optional.
*/
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
struct snd_soc_dai *);
/* platform stream ops */
struct snd_pcm_ops *pcm_ops;
};
......@@ -489,6 +506,9 @@ struct snd_soc_dai_link {
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_codec *codec);
/* Keep DAI active over suspend */
unsigned int ignore_suspend:1;
/* Symmetry requirements */
unsigned int symmetric_rates:1;
......@@ -553,7 +573,7 @@ struct snd_soc_pcm_runtime {
/* mixer control */
struct soc_mixer_control {
int min, max;
int min, max, platform_max;
unsigned int reg, rreg, shift, rshift, invert;
};
......@@ -583,6 +603,17 @@ static inline unsigned int snd_soc_write(struct snd_soc_codec *codec,
return codec->write(codec, reg, val);
}
static inline void snd_soc_codec_set_drvdata(struct snd_soc_codec *codec,
void *data)
{
codec->drvdata = data;
}
static inline void *snd_soc_codec_get_drvdata(struct snd_soc_codec *codec)
{
return codec->drvdata;
}
#include <sound/soc-dai.h>
#endif
/*
* Platform data for Texas Instruments TLV320AIC3x codec
*
* Author: Jarkko Nikula <jhnikula@gmail.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 __TLV320AIC3x_H__
#define __TLV320AIC3x_H__
struct aic3x_pdata {
int gpio_reset; /* < 0 if not used */
};
#endif
\ No newline at end of file
......@@ -15,6 +15,7 @@
struct tlv320dac33_platform_data {
int power_gpio;
int keep_bclk; /* Keep the BCLK running in FIFO modes */
u8 burst_bclkdiv;
};
......
......@@ -21,6 +21,7 @@ struct uda134x_platform_data {
#define UDA134X_UDA1340 1
#define UDA134X_UDA1341 2
#define UDA134X_UDA1344 3
#define UDA134X_UDA1345 4
};
#endif /* _UDA134X_H */
/*
* linux/sound/wm8903.h -- Platform data for WM8903
*
* Copyright 2010 Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_WM8903_H
#define __LINUX_SND_WM8903_H
/* Used to enable configuration of a GPIO to all zeros */
#define WM8903_GPIO_NO_CONFIG 0x8000
/*
* R6 (0x06) - Mic Bias Control 0
*/
#define WM8903_MICDET_HYST_ENA 0x0080 /* MICDET_HYST_ENA */
#define WM8903_MICDET_HYST_ENA_MASK 0x0080 /* MICDET_HYST_ENA */
#define WM8903_MICDET_HYST_ENA_SHIFT 7 /* MICDET_HYST_ENA */
#define WM8903_MICDET_HYST_ENA_WIDTH 1 /* MICDET_HYST_ENA */
#define WM8903_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */
#define WM8903_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */
#define WM8903_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */
#define WM8903_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */
#define WM8903_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */
#define WM8903_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */
#define WM8903_MICDET_ENA 0x0002 /* MICDET_ENA */
#define WM8903_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */
#define WM8903_MICDET_ENA_SHIFT 1 /* MICDET_ENA */
#define WM8903_MICDET_ENA_WIDTH 1 /* MICDET_ENA */
#define WM8903_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */
#define WM8903_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */
#define WM8903_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */
#define WM8903_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */
/*
* R116 (0x74) - GPIO Control 1
*/
#define WM8903_GP1_FN_MASK 0x1F00 /* GP1_FN - [12:8] */
#define WM8903_GP1_FN_SHIFT 8 /* GP1_FN - [12:8] */
#define WM8903_GP1_FN_WIDTH 5 /* GP1_FN - [12:8] */
#define WM8903_GP1_DIR 0x0080 /* GP1_DIR */
#define WM8903_GP1_DIR_MASK 0x0080 /* GP1_DIR */
#define WM8903_GP1_DIR_SHIFT 7 /* GP1_DIR */
#define WM8903_GP1_DIR_WIDTH 1 /* GP1_DIR */
#define WM8903_GP1_OP_CFG 0x0040 /* GP1_OP_CFG */
#define WM8903_GP1_OP_CFG_MASK 0x0040 /* GP1_OP_CFG */
#define WM8903_GP1_OP_CFG_SHIFT 6 /* GP1_OP_CFG */
#define WM8903_GP1_OP_CFG_WIDTH 1 /* GP1_OP_CFG */
#define WM8903_GP1_IP_CFG 0x0020 /* GP1_IP_CFG */
#define WM8903_GP1_IP_CFG_MASK 0x0020 /* GP1_IP_CFG */
#define WM8903_GP1_IP_CFG_SHIFT 5 /* GP1_IP_CFG */
#define WM8903_GP1_IP_CFG_WIDTH 1 /* GP1_IP_CFG */
#define WM8903_GP1_LVL 0x0010 /* GP1_LVL */
#define WM8903_GP1_LVL_MASK 0x0010 /* GP1_LVL */
#define WM8903_GP1_LVL_SHIFT 4 /* GP1_LVL */
#define WM8903_GP1_LVL_WIDTH 1 /* GP1_LVL */
#define WM8903_GP1_PD 0x0008 /* GP1_PD */
#define WM8903_GP1_PD_MASK 0x0008 /* GP1_PD */
#define WM8903_GP1_PD_SHIFT 3 /* GP1_PD */
#define WM8903_GP1_PD_WIDTH 1 /* GP1_PD */
#define WM8903_GP1_PU 0x0004 /* GP1_PU */
#define WM8903_GP1_PU_MASK 0x0004 /* GP1_PU */
#define WM8903_GP1_PU_SHIFT 2 /* GP1_PU */
#define WM8903_GP1_PU_WIDTH 1 /* GP1_PU */
#define WM8903_GP1_INTMODE 0x0002 /* GP1_INTMODE */
#define WM8903_GP1_INTMODE_MASK 0x0002 /* GP1_INTMODE */
#define WM8903_GP1_INTMODE_SHIFT 1 /* GP1_INTMODE */
#define WM8903_GP1_INTMODE_WIDTH 1 /* GP1_INTMODE */
#define WM8903_GP1_DB 0x0001 /* GP1_DB */
#define WM8903_GP1_DB_MASK 0x0001 /* GP1_DB */
#define WM8903_GP1_DB_SHIFT 0 /* GP1_DB */
#define WM8903_GP1_DB_WIDTH 1 /* GP1_DB */
/*
* R117 (0x75) - GPIO Control 2
*/
#define WM8903_GP2_FN_MASK 0x1F00 /* GP2_FN - [12:8] */
#define WM8903_GP2_FN_SHIFT 8 /* GP2_FN - [12:8] */
#define WM8903_GP2_FN_WIDTH 5 /* GP2_FN - [12:8] */
#define WM8903_GP2_DIR 0x0080 /* GP2_DIR */
#define WM8903_GP2_DIR_MASK 0x0080 /* GP2_DIR */
#define WM8903_GP2_DIR_SHIFT 7 /* GP2_DIR */
#define WM8903_GP2_DIR_WIDTH 1 /* GP2_DIR */
#define WM8903_GP2_OP_CFG 0x0040 /* GP2_OP_CFG */
#define WM8903_GP2_OP_CFG_MASK 0x0040 /* GP2_OP_CFG */
#define WM8903_GP2_OP_CFG_SHIFT 6 /* GP2_OP_CFG */
#define WM8903_GP2_OP_CFG_WIDTH 1 /* GP2_OP_CFG */
#define WM8903_GP2_IP_CFG 0x0020 /* GP2_IP_CFG */
#define WM8903_GP2_IP_CFG_MASK 0x0020 /* GP2_IP_CFG */
#define WM8903_GP2_IP_CFG_SHIFT 5 /* GP2_IP_CFG */
#define WM8903_GP2_IP_CFG_WIDTH 1 /* GP2_IP_CFG */
#define WM8903_GP2_LVL 0x0010 /* GP2_LVL */
#define WM8903_GP2_LVL_MASK 0x0010 /* GP2_LVL */
#define WM8903_GP2_LVL_SHIFT 4 /* GP2_LVL */
#define WM8903_GP2_LVL_WIDTH 1 /* GP2_LVL */
#define WM8903_GP2_PD 0x0008 /* GP2_PD */
#define WM8903_GP2_PD_MASK 0x0008 /* GP2_PD */
#define WM8903_GP2_PD_SHIFT 3 /* GP2_PD */
#define WM8903_GP2_PD_WIDTH 1 /* GP2_PD */
#define WM8903_GP2_PU 0x0004 /* GP2_PU */
#define WM8903_GP2_PU_MASK 0x0004 /* GP2_PU */
#define WM8903_GP2_PU_SHIFT 2 /* GP2_PU */
#define WM8903_GP2_PU_WIDTH 1 /* GP2_PU */
#define WM8903_GP2_INTMODE 0x0002 /* GP2_INTMODE */
#define WM8903_GP2_INTMODE_MASK 0x0002 /* GP2_INTMODE */
#define WM8903_GP2_INTMODE_SHIFT 1 /* GP2_INTMODE */
#define WM8903_GP2_INTMODE_WIDTH 1 /* GP2_INTMODE */
#define WM8903_GP2_DB 0x0001 /* GP2_DB */
#define WM8903_GP2_DB_MASK 0x0001 /* GP2_DB */
#define WM8903_GP2_DB_SHIFT 0 /* GP2_DB */
#define WM8903_GP2_DB_WIDTH 1 /* GP2_DB */
/*
* R118 (0x76) - GPIO Control 3
*/
#define WM8903_GP3_FN_MASK 0x1F00 /* GP3_FN - [12:8] */
#define WM8903_GP3_FN_SHIFT 8 /* GP3_FN - [12:8] */
#define WM8903_GP3_FN_WIDTH 5 /* GP3_FN - [12:8] */
#define WM8903_GP3_DIR 0x0080 /* GP3_DIR */
#define WM8903_GP3_DIR_MASK 0x0080 /* GP3_DIR */
#define WM8903_GP3_DIR_SHIFT 7 /* GP3_DIR */
#define WM8903_GP3_DIR_WIDTH 1 /* GP3_DIR */
#define WM8903_GP3_OP_CFG 0x0040 /* GP3_OP_CFG */
#define WM8903_GP3_OP_CFG_MASK 0x0040 /* GP3_OP_CFG */
#define WM8903_GP3_OP_CFG_SHIFT 6 /* GP3_OP_CFG */
#define WM8903_GP3_OP_CFG_WIDTH 1 /* GP3_OP_CFG */
#define WM8903_GP3_IP_CFG 0x0020 /* GP3_IP_CFG */
#define WM8903_GP3_IP_CFG_MASK 0x0020 /* GP3_IP_CFG */
#define WM8903_GP3_IP_CFG_SHIFT 5 /* GP3_IP_CFG */
#define WM8903_GP3_IP_CFG_WIDTH 1 /* GP3_IP_CFG */
#define WM8903_GP3_LVL 0x0010 /* GP3_LVL */
#define WM8903_GP3_LVL_MASK 0x0010 /* GP3_LVL */
#define WM8903_GP3_LVL_SHIFT 4 /* GP3_LVL */
#define WM8903_GP3_LVL_WIDTH 1 /* GP3_LVL */
#define WM8903_GP3_PD 0x0008 /* GP3_PD */
#define WM8903_GP3_PD_MASK 0x0008 /* GP3_PD */
#define WM8903_GP3_PD_SHIFT 3 /* GP3_PD */
#define WM8903_GP3_PD_WIDTH 1 /* GP3_PD */
#define WM8903_GP3_PU 0x0004 /* GP3_PU */
#define WM8903_GP3_PU_MASK 0x0004 /* GP3_PU */
#define WM8903_GP3_PU_SHIFT 2 /* GP3_PU */
#define WM8903_GP3_PU_WIDTH 1 /* GP3_PU */
#define WM8903_GP3_INTMODE 0x0002 /* GP3_INTMODE */
#define WM8903_GP3_INTMODE_MASK 0x0002 /* GP3_INTMODE */
#define WM8903_GP3_INTMODE_SHIFT 1 /* GP3_INTMODE */
#define WM8903_GP3_INTMODE_WIDTH 1 /* GP3_INTMODE */
#define WM8903_GP3_DB 0x0001 /* GP3_DB */
#define WM8903_GP3_DB_MASK 0x0001 /* GP3_DB */
#define WM8903_GP3_DB_SHIFT 0 /* GP3_DB */
#define WM8903_GP3_DB_WIDTH 1 /* GP3_DB */
/*
* R119 (0x77) - GPIO Control 4
*/
#define WM8903_GP4_FN_MASK 0x1F00 /* GP4_FN - [12:8] */
#define WM8903_GP4_FN_SHIFT 8 /* GP4_FN - [12:8] */
#define WM8903_GP4_FN_WIDTH 5 /* GP4_FN - [12:8] */
#define WM8903_GP4_DIR 0x0080 /* GP4_DIR */
#define WM8903_GP4_DIR_MASK 0x0080 /* GP4_DIR */
#define WM8903_GP4_DIR_SHIFT 7 /* GP4_DIR */
#define WM8903_GP4_DIR_WIDTH 1 /* GP4_DIR */
#define WM8903_GP4_OP_CFG 0x0040 /* GP4_OP_CFG */
#define WM8903_GP4_OP_CFG_MASK 0x0040 /* GP4_OP_CFG */
#define WM8903_GP4_OP_CFG_SHIFT 6 /* GP4_OP_CFG */
#define WM8903_GP4_OP_CFG_WIDTH 1 /* GP4_OP_CFG */
#define WM8903_GP4_IP_CFG 0x0020 /* GP4_IP_CFG */
#define WM8903_GP4_IP_CFG_MASK 0x0020 /* GP4_IP_CFG */
#define WM8903_GP4_IP_CFG_SHIFT 5 /* GP4_IP_CFG */
#define WM8903_GP4_IP_CFG_WIDTH 1 /* GP4_IP_CFG */
#define WM8903_GP4_LVL 0x0010 /* GP4_LVL */
#define WM8903_GP4_LVL_MASK 0x0010 /* GP4_LVL */
#define WM8903_GP4_LVL_SHIFT 4 /* GP4_LVL */
#define WM8903_GP4_LVL_WIDTH 1 /* GP4_LVL */
#define WM8903_GP4_PD 0x0008 /* GP4_PD */
#define WM8903_GP4_PD_MASK 0x0008 /* GP4_PD */
#define WM8903_GP4_PD_SHIFT 3 /* GP4_PD */
#define WM8903_GP4_PD_WIDTH 1 /* GP4_PD */
#define WM8903_GP4_PU 0x0004 /* GP4_PU */
#define WM8903_GP4_PU_MASK 0x0004 /* GP4_PU */
#define WM8903_GP4_PU_SHIFT 2 /* GP4_PU */
#define WM8903_GP4_PU_WIDTH 1 /* GP4_PU */
#define WM8903_GP4_INTMODE 0x0002 /* GP4_INTMODE */
#define WM8903_GP4_INTMODE_MASK 0x0002 /* GP4_INTMODE */
#define WM8903_GP4_INTMODE_SHIFT 1 /* GP4_INTMODE */
#define WM8903_GP4_INTMODE_WIDTH 1 /* GP4_INTMODE */
#define WM8903_GP4_DB 0x0001 /* GP4_DB */
#define WM8903_GP4_DB_MASK 0x0001 /* GP4_DB */
#define WM8903_GP4_DB_SHIFT 0 /* GP4_DB */
#define WM8903_GP4_DB_WIDTH 1 /* GP4_DB */
/*
* R120 (0x78) - GPIO Control 5
*/
#define WM8903_GP5_FN_MASK 0x1F00 /* GP5_FN - [12:8] */
#define WM8903_GP5_FN_SHIFT 8 /* GP5_FN - [12:8] */
#define WM8903_GP5_FN_WIDTH 5 /* GP5_FN - [12:8] */
#define WM8903_GP5_DIR 0x0080 /* GP5_DIR */
#define WM8903_GP5_DIR_MASK 0x0080 /* GP5_DIR */
#define WM8903_GP5_DIR_SHIFT 7 /* GP5_DIR */
#define WM8903_GP5_DIR_WIDTH 1 /* GP5_DIR */
#define WM8903_GP5_OP_CFG 0x0040 /* GP5_OP_CFG */
#define WM8903_GP5_OP_CFG_MASK 0x0040 /* GP5_OP_CFG */
#define WM8903_GP5_OP_CFG_SHIFT 6 /* GP5_OP_CFG */
#define WM8903_GP5_OP_CFG_WIDTH 1 /* GP5_OP_CFG */
#define WM8903_GP5_IP_CFG 0x0020 /* GP5_IP_CFG */
#define WM8903_GP5_IP_CFG_MASK 0x0020 /* GP5_IP_CFG */
#define WM8903_GP5_IP_CFG_SHIFT 5 /* GP5_IP_CFG */
#define WM8903_GP5_IP_CFG_WIDTH 1 /* GP5_IP_CFG */
#define WM8903_GP5_LVL 0x0010 /* GP5_LVL */
#define WM8903_GP5_LVL_MASK 0x0010 /* GP5_LVL */
#define WM8903_GP5_LVL_SHIFT 4 /* GP5_LVL */
#define WM8903_GP5_LVL_WIDTH 1 /* GP5_LVL */
#define WM8903_GP5_PD 0x0008 /* GP5_PD */
#define WM8903_GP5_PD_MASK 0x0008 /* GP5_PD */
#define WM8903_GP5_PD_SHIFT 3 /* GP5_PD */
#define WM8903_GP5_PD_WIDTH 1 /* GP5_PD */
#define WM8903_GP5_PU 0x0004 /* GP5_PU */
#define WM8903_GP5_PU_MASK 0x0004 /* GP5_PU */
#define WM8903_GP5_PU_SHIFT 2 /* GP5_PU */
#define WM8903_GP5_PU_WIDTH 1 /* GP5_PU */
#define WM8903_GP5_INTMODE 0x0002 /* GP5_INTMODE */
#define WM8903_GP5_INTMODE_MASK 0x0002 /* GP5_INTMODE */
#define WM8903_GP5_INTMODE_SHIFT 1 /* GP5_INTMODE */
#define WM8903_GP5_INTMODE_WIDTH 1 /* GP5_INTMODE */
#define WM8903_GP5_DB 0x0001 /* GP5_DB */
#define WM8903_GP5_DB_MASK 0x0001 /* GP5_DB */
#define WM8903_GP5_DB_SHIFT 0 /* GP5_DB */
#define WM8903_GP5_DB_WIDTH 1 /* GP5_DB */
struct wm8903_platform_data {
bool irq_active_low; /* Set if IRQ active low, default high */
/* Default register value for R6 (Mic bias), used to configure
* microphone detection. In conjunction with gpio_cfg this
* can be used to route the microphone status signals out onto
* the GPIOs for use with snd_soc_jack_add_gpios().
*/
u16 micdet_cfg;
int micdet_delay; /* Delay after microphone detection (ms) */
u32 gpio_cfg[5]; /* Default register values for GPIO pin mux */
};
#endif
......@@ -15,8 +15,111 @@
#ifndef __MFD_WM8994_PDATA_H__
#define __MFD_WM8994_PDATA_H__
#define WM8904_DRC_REGS 4
#define WM8904_EQ_REGS 25
/* Used to enable configuration of a GPIO to all zeros */
#define WM8904_GPIO_NO_CONFIG 0x8000
/*
* R6 (0x06) - Mic Bias Control 0
*/
#define WM8904_MICDET_THR_MASK 0x0070 /* MICDET_THR - [6:4] */
#define WM8904_MICDET_THR_SHIFT 4 /* MICDET_THR - [6:4] */
#define WM8904_MICDET_THR_WIDTH 3 /* MICDET_THR - [6:4] */
#define WM8904_MICSHORT_THR_MASK 0x000C /* MICSHORT_THR - [3:2] */
#define WM8904_MICSHORT_THR_SHIFT 2 /* MICSHORT_THR - [3:2] */
#define WM8904_MICSHORT_THR_WIDTH 2 /* MICSHORT_THR - [3:2] */
#define WM8904_MICDET_ENA 0x0002 /* MICDET_ENA */
#define WM8904_MICDET_ENA_MASK 0x0002 /* MICDET_ENA */
#define WM8904_MICDET_ENA_SHIFT 1 /* MICDET_ENA */
#define WM8904_MICDET_ENA_WIDTH 1 /* MICDET_ENA */
#define WM8904_MICBIAS_ENA 0x0001 /* MICBIAS_ENA */
#define WM8904_MICBIAS_ENA_MASK 0x0001 /* MICBIAS_ENA */
#define WM8904_MICBIAS_ENA_SHIFT 0 /* MICBIAS_ENA */
#define WM8904_MICBIAS_ENA_WIDTH 1 /* MICBIAS_ENA */
/*
* R7 (0x07) - Mic Bias Control 1
*/
#define WM8904_MIC_DET_FILTER_ENA 0x8000 /* MIC_DET_FILTER_ENA */
#define WM8904_MIC_DET_FILTER_ENA_MASK 0x8000 /* MIC_DET_FILTER_ENA */
#define WM8904_MIC_DET_FILTER_ENA_SHIFT 15 /* MIC_DET_FILTER_ENA */
#define WM8904_MIC_DET_FILTER_ENA_WIDTH 1 /* MIC_DET_FILTER_ENA */
#define WM8904_MIC_SHORT_FILTER_ENA 0x4000 /* MIC_SHORT_FILTER_ENA */
#define WM8904_MIC_SHORT_FILTER_ENA_MASK 0x4000 /* MIC_SHORT_FILTER_ENA */
#define WM8904_MIC_SHORT_FILTER_ENA_SHIFT 14 /* MIC_SHORT_FILTER_ENA */
#define WM8904_MIC_SHORT_FILTER_ENA_WIDTH 1 /* MIC_SHORT_FILTER_ENA */
#define WM8904_MICBIAS_SEL_MASK 0x0007 /* MICBIAS_SEL - [2:0] */
#define WM8904_MICBIAS_SEL_SHIFT 0 /* MICBIAS_SEL - [2:0] */
#define WM8904_MICBIAS_SEL_WIDTH 3 /* MICBIAS_SEL - [2:0] */
/*
* R121 (0x79) - GPIO Control 1
*/
#define WM8904_GPIO1_PU 0x0020 /* GPIO1_PU */
#define WM8904_GPIO1_PU_MASK 0x0020 /* GPIO1_PU */
#define WM8904_GPIO1_PU_SHIFT 5 /* GPIO1_PU */
#define WM8904_GPIO1_PU_WIDTH 1 /* GPIO1_PU */
#define WM8904_GPIO1_PD 0x0010 /* GPIO1_PD */
#define WM8904_GPIO1_PD_MASK 0x0010 /* GPIO1_PD */
#define WM8904_GPIO1_PD_SHIFT 4 /* GPIO1_PD */
#define WM8904_GPIO1_PD_WIDTH 1 /* GPIO1_PD */
#define WM8904_GPIO1_SEL_MASK 0x000F /* GPIO1_SEL - [3:0] */
#define WM8904_GPIO1_SEL_SHIFT 0 /* GPIO1_SEL - [3:0] */
#define WM8904_GPIO1_SEL_WIDTH 4 /* GPIO1_SEL - [3:0] */
/*
* R122 (0x7A) - GPIO Control 2
*/
#define WM8904_GPIO2_PU 0x0020 /* GPIO2_PU */
#define WM8904_GPIO2_PU_MASK 0x0020 /* GPIO2_PU */
#define WM8904_GPIO2_PU_SHIFT 5 /* GPIO2_PU */
#define WM8904_GPIO2_PU_WIDTH 1 /* GPIO2_PU */
#define WM8904_GPIO2_PD 0x0010 /* GPIO2_PD */
#define WM8904_GPIO2_PD_MASK 0x0010 /* GPIO2_PD */
#define WM8904_GPIO2_PD_SHIFT 4 /* GPIO2_PD */
#define WM8904_GPIO2_PD_WIDTH 1 /* GPIO2_PD */
#define WM8904_GPIO2_SEL_MASK 0x000F /* GPIO2_SEL - [3:0] */
#define WM8904_GPIO2_SEL_SHIFT 0 /* GPIO2_SEL - [3:0] */
#define WM8904_GPIO2_SEL_WIDTH 4 /* GPIO2_SEL - [3:0] */
/*
* R123 (0x7B) - GPIO Control 3
*/
#define WM8904_GPIO3_PU 0x0020 /* GPIO3_PU */
#define WM8904_GPIO3_PU_MASK 0x0020 /* GPIO3_PU */
#define WM8904_GPIO3_PU_SHIFT 5 /* GPIO3_PU */
#define WM8904_GPIO3_PU_WIDTH 1 /* GPIO3_PU */
#define WM8904_GPIO3_PD 0x0010 /* GPIO3_PD */
#define WM8904_GPIO3_PD_MASK 0x0010 /* GPIO3_PD */
#define WM8904_GPIO3_PD_SHIFT 4 /* GPIO3_PD */
#define WM8904_GPIO3_PD_WIDTH 1 /* GPIO3_PD */
#define WM8904_GPIO3_SEL_MASK 0x000F /* GPIO3_SEL - [3:0] */
#define WM8904_GPIO3_SEL_SHIFT 0 /* GPIO3_SEL - [3:0] */
#define WM8904_GPIO3_SEL_WIDTH 4 /* GPIO3_SEL - [3:0] */
/*
* R124 (0x7C) - GPIO Control 4
*/
#define WM8904_GPI7_ENA 0x0200 /* GPI7_ENA */
#define WM8904_GPI7_ENA_MASK 0x0200 /* GPI7_ENA */
#define WM8904_GPI7_ENA_SHIFT 9 /* GPI7_ENA */
#define WM8904_GPI7_ENA_WIDTH 1 /* GPI7_ENA */
#define WM8904_GPI8_ENA 0x0100 /* GPI8_ENA */
#define WM8904_GPI8_ENA_MASK 0x0100 /* GPI8_ENA */
#define WM8904_GPI8_ENA_SHIFT 8 /* GPI8_ENA */
#define WM8904_GPI8_ENA_WIDTH 1 /* GPI8_ENA */
#define WM8904_GPIO_BCLK_MODE_ENA 0x0080 /* GPIO_BCLK_MODE_ENA */
#define WM8904_GPIO_BCLK_MODE_ENA_MASK 0x0080 /* GPIO_BCLK_MODE_ENA */
#define WM8904_GPIO_BCLK_MODE_ENA_SHIFT 7 /* GPIO_BCLK_MODE_ENA */
#define WM8904_GPIO_BCLK_MODE_ENA_WIDTH 1 /* GPIO_BCLK_MODE_ENA */
#define WM8904_GPIO_BCLK_SEL_MASK 0x000F /* GPIO_BCLK_SEL - [3:0] */
#define WM8904_GPIO_BCLK_SEL_SHIFT 0 /* GPIO_BCLK_SEL - [3:0] */
#define WM8904_GPIO_BCLK_SEL_WIDTH 4 /* GPIO_BCLK_SEL - [3:0] */
#define WM8904_MIC_REGS 2
#define WM8904_GPIO_REGS 4
#define WM8904_DRC_REGS 4
#define WM8904_EQ_REGS 25
/**
* DRC configurations are specified with a label and a set of register
......@@ -52,6 +155,9 @@ struct wm8904_pdata {
int num_retune_mobile_cfgs;
struct wm8904_retune_mobile_cfg *retune_mobile_cfgs;
u32 gpio_cfg[WM8904_GPIO_REGS];
u32 mic_cfg[WM8904_MIC_REGS];
};
#endif
/*
* wm8960.h -- WM8960 Soc Audio driver platform data
*
* 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 _WM8960_PDATA_H
#define _WM8960_PDATA_H
#define WM8960_DRES_400R 0
#define WM8960_DRES_200R 1
#define WM8960_DRES_600R 2
#define WM8960_DRES_150R 3
#define WM8960_DRES_MAX 3
struct wm8960_data {
bool capless; /* Headphone outputs configured in capless mode */
int dres; /* Discharge resistance for headphone outputs */
};
#endif
/*
* linux/sound/wm9090.h -- Platform data for WM9090
*
* Copyright 2009, 2010 Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_WM9090_H
#define __LINUX_SND_WM9090_H
struct wm9090_platform_data {
/* Line inputs 1 & 2 can optionally be differential */
unsigned int lin1_diff:1;
unsigned int lin2_diff:1;
/* AGC configuration. This is intended to protect the speaker
* against overdriving and will therefore depend on the
* hardware setup with incorrect runtime configuration
* potentially causing hardware damage.
*/
unsigned int agc_ena:1;
u16 agc[3];
};
#endif
......@@ -415,9 +415,12 @@ static void atmel_pcm_free_dma_buffers(struct snd_pcm *pcm)
}
#ifdef CONFIG_PM
static int atmel_pcm_suspend(struct snd_soc_dai *dai)
static int atmel_pcm_suspend(struct snd_soc_dai_link *dai_link)
{
struct snd_pcm_runtime *runtime = dai->runtime;
struct snd_pcm *pcm = dai_link->pcm;
struct snd_pcm_str *stream = &pcm->streams[0];
struct snd_pcm_substream *substream = stream->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct atmel_runtime_data *prtd;
struct atmel_pcm_dma_params *params;
......@@ -439,9 +442,12 @@ static int atmel_pcm_suspend(struct snd_soc_dai *dai)
return 0;
}
static int atmel_pcm_resume(struct snd_soc_dai *dai)
static int atmel_pcm_resume(struct snd_soc_dai_link *dai_link)
{
struct snd_pcm_runtime *runtime = dai->runtime;
struct snd_pcm *pcm = dai_link->pcm;
struct snd_pcm_str *stream = &pcm->streams[0];
struct snd_pcm_substream *substream = stream->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
struct atmel_runtime_data *prtd;
struct atmel_pcm_dma_params *params;
......
......@@ -49,13 +49,14 @@ config SND_BF5XX_SOC_AD1836
help
Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT.
config SND_BF5XX_SOC_AD1938
tristate "SoC AD1938 Audio support for Blackfin"
config SND_BF5XX_SOC_AD193X
tristate "SoC AD193X Audio support for Blackfin"
depends on SND_BF5XX_TDM
select SND_BF5XX_SOC_TDM
select SND_SOC_AD1938
select SND_SOC_AD193X
help
Say Y if you want to add support for AD1938 codec on Blackfin.
Say Y if you want to add support for AD193X codec on Blackfin.
This driver supports AD1936, AD1937, AD1938 and AD1939.
config SND_BF5XX_AC97
tristate "SoC AC97 Audio for the ADI BF5xx chip"
......
......@@ -20,10 +20,10 @@ snd-ad1836-objs := bf5xx-ad1836.o
snd-ad1980-objs := bf5xx-ad1980.o
snd-ssm2602-objs := bf5xx-ssm2602.o
snd-ad73311-objs := bf5xx-ad73311.o
snd-ad1938-objs := bf5xx-ad1938.o
snd-ad193x-objs := bf5xx-ad193x.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1836) += snd-ad1836.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1980) += snd-ad1980.o
obj-$(CONFIG_SND_BF5XX_SOC_SSM2602) += snd-ssm2602.o
obj-$(CONFIG_SND_BF5XX_SOC_AD73311) += snd-ad73311.o
obj-$(CONFIG_SND_BF5XX_SOC_AD1938) += snd-ad1938.o
obj-$(CONFIG_SND_BF5XX_SOC_AD193X) += snd-ad193x.o
/*
* File: sound/soc/blackfin/bf5xx-ad1938.c
* File: sound/soc/blackfin/bf5xx-ad193x.c
* Author: Barry Song <Barry.Song@analog.com>
*
* Created: Thur June 4 2009
* Description: Board driver for ad1938 sound chip
* Description: Board driver for ad193x sound chip
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
......@@ -38,15 +38,15 @@
#include <asm/dma.h>
#include <asm/portmux.h>
#include "../codecs/ad1938.h"
#include "../codecs/ad193x.h"
#include "bf5xx-sport.h"
#include "bf5xx-tdm-pcm.h"
#include "bf5xx-tdm.h"
static struct snd_soc_card bf5xx_ad1938;
static struct snd_soc_card bf5xx_ad193x;
static int bf5xx_ad1938_startup(struct snd_pcm_substream *substream)
static int bf5xx_ad193x_startup(struct snd_pcm_substream *substream)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
......@@ -55,7 +55,7 @@ static int bf5xx_ad1938_startup(struct snd_pcm_substream *substream)
return 0;
}
static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream,
static int bf5xx_ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
......@@ -89,61 +89,61 @@ static int bf5xx_ad1938_hw_params(struct snd_pcm_substream *substream,
return 0;
}
static struct snd_soc_ops bf5xx_ad1938_ops = {
.startup = bf5xx_ad1938_startup,
.hw_params = bf5xx_ad1938_hw_params,
static struct snd_soc_ops bf5xx_ad193x_ops = {
.startup = bf5xx_ad193x_startup,
.hw_params = bf5xx_ad193x_hw_params,
};
static struct snd_soc_dai_link bf5xx_ad1938_dai = {
.name = "ad1938",
.stream_name = "AD1938",
static struct snd_soc_dai_link bf5xx_ad193x_dai = {
.name = "ad193x",
.stream_name = "AD193X",
.cpu_dai = &bf5xx_tdm_dai,
.codec_dai = &ad1938_dai,
.ops = &bf5xx_ad1938_ops,
.codec_dai = &ad193x_dai,
.ops = &bf5xx_ad193x_ops,
};
static struct snd_soc_card bf5xx_ad1938 = {
.name = "bf5xx_ad1938",
static struct snd_soc_card bf5xx_ad193x = {
.name = "bf5xx_ad193x",
.platform = &bf5xx_tdm_soc_platform,
.dai_link = &bf5xx_ad1938_dai,
.dai_link = &bf5xx_ad193x_dai,
.num_links = 1,
};
static struct snd_soc_device bf5xx_ad1938_snd_devdata = {
.card = &bf5xx_ad1938,
.codec_dev = &soc_codec_dev_ad1938,
static struct snd_soc_device bf5xx_ad193x_snd_devdata = {
.card = &bf5xx_ad193x,
.codec_dev = &soc_codec_dev_ad193x,
};
static struct platform_device *bfxx_ad1938_snd_device;
static struct platform_device *bfxx_ad193x_snd_device;
static int __init bf5xx_ad1938_init(void)
static int __init bf5xx_ad193x_init(void)
{
int ret;
bfxx_ad1938_snd_device = platform_device_alloc("soc-audio", -1);
if (!bfxx_ad1938_snd_device)
bfxx_ad193x_snd_device = platform_device_alloc("soc-audio", -1);
if (!bfxx_ad193x_snd_device)
return -ENOMEM;
platform_set_drvdata(bfxx_ad1938_snd_device, &bf5xx_ad1938_snd_devdata);
bf5xx_ad1938_snd_devdata.dev = &bfxx_ad1938_snd_device->dev;
ret = platform_device_add(bfxx_ad1938_snd_device);
platform_set_drvdata(bfxx_ad193x_snd_device, &bf5xx_ad193x_snd_devdata);
bf5xx_ad193x_snd_devdata.dev = &bfxx_ad193x_snd_device->dev;
ret = platform_device_add(bfxx_ad193x_snd_device);
if (ret)
platform_device_put(bfxx_ad1938_snd_device);
platform_device_put(bfxx_ad193x_snd_device);
return ret;
}
static void __exit bf5xx_ad1938_exit(void)
static void __exit bf5xx_ad193x_exit(void)
{
platform_device_unregister(bfxx_ad1938_snd_device);
platform_device_unregister(bfxx_ad193x_snd_device);
}
module_init(bf5xx_ad1938_init);
module_exit(bf5xx_ad1938_exit);
module_init(bf5xx_ad193x_init);
module_exit(bf5xx_ad193x_exit);
/* Module information */
MODULE_AUTHOR("Barry Song");
MODULE_DESCRIPTION("ALSA SoC AD1938 board driver");
MODULE_DESCRIPTION("ALSA SoC AD193X board driver");
MODULE_LICENSE("GPL");
......@@ -34,33 +34,7 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <asm/dma.h>
struct sport_register {
u16 tcr1; u16 reserved0;
u16 tcr2; u16 reserved1;
u16 tclkdiv; u16 reserved2;
u16 tfsdiv; u16 reserved3;
u32 tx;
u32 reserved_l0;
u32 rx;
u32 reserved_l1;
u16 rcr1; u16 reserved4;
u16 rcr2; u16 reserved5;
u16 rclkdiv; u16 reserved6;
u16 rfsdiv; u16 reserved7;
u16 stat; u16 reserved8;
u16 chnl; u16 reserved9;
u16 mcmc1; u16 reserved10;
u16 mcmc2; u16 reserved11;
u32 mtcs0;
u32 mtcs1;
u32 mtcs2;
u32 mtcs3;
u32 mrcs0;
u32 mrcs1;
u32 mrcs2;
u32 mrcs3;
};
#include <asm/bfin_sport.h>
#define DESC_ELEMENT_COUNT 9
......
......@@ -13,7 +13,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_L3
select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS
select SND_SOC_AD1836 if SPI_MASTER
select SND_SOC_AD1938 if SPI_MASTER
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
select SND_SOC_ADS117X
select SND_SOC_AD73311 if I2C
......@@ -21,6 +21,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_CQ0093VC if MFD_DAVINCI_VOICECODEC
select SND_SOC_CS4270 if I2C
select SND_SOC_MAX9877 if I2C
select SND_SOC_DA7210 if I2C
......@@ -34,6 +35,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
select SND_SOC_TWL6040 if TWL4030_CORE
select SND_SOC_UDA134X
select SND_SOC_UDA1380 if I2C
select SND_SOC_WM2000 if I2C
......@@ -64,6 +66,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WM8993 if I2C
select SND_SOC_WM8994 if MFD_WM8994
select SND_SOC_WM9081 if I2C
select SND_SOC_WM9090 if I2C
select SND_SOC_WM9705 if SND_SOC_AC97_BUS
select SND_SOC_WM9712 if SND_SOC_AC97_BUS
select SND_SOC_WM9713 if SND_SOC_AC97_BUS
......@@ -90,7 +93,7 @@ config SND_SOC_AC97_CODEC
config SND_SOC_AD1836
tristate
config SND_SOC_AD1938
config SND_SOC_AD193X
tristate
config SND_SOC_AD1980
......@@ -114,6 +117,9 @@ config SND_SOC_AK4642
config SND_SOC_AK4671
tristate
config SND_SOC_CQ0093VC
tristate
# Cirrus Logic CS4270 Codec
config SND_SOC_CS4270
tristate
......@@ -164,6 +170,9 @@ config SND_SOC_TWL4030
select TWL4030_CODEC
tristate
config SND_SOC_TWL6040
tristate
config SND_SOC_UDA134X
tristate
......@@ -269,3 +278,6 @@ config SND_SOC_TPA6130A2
config SND_SOC_WM2000
tristate
config SND_SOC_WM9090
tristate
snd-soc-ac97-objs := ac97.o
snd-soc-ad1836-objs := ad1836.o
snd-soc-ad1938-objs := ad1938.o
snd-soc-ad193x-objs := ad193x.o
snd-soc-ad1980-objs := ad1980.o
snd-soc-ad73311-objs := ad73311.o
snd-soc-ads117x-objs := ads117x.o
......@@ -8,6 +8,7 @@ snd-soc-ak4104-objs := ak4104.o
snd-soc-ak4535-objs := ak4535.o
snd-soc-ak4642-objs := ak4642.o
snd-soc-ak4671-objs := ak4671.o
snd-soc-cq93vc-objs := cq93vc.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cx20442-objs := cx20442.o
snd-soc-da7210-objs := da7210.o
......@@ -21,6 +22,7 @@ snd-soc-tlv320aic26-objs := tlv320aic26.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o
snd-soc-wm8350-objs := wm8350.o
......@@ -59,10 +61,11 @@ snd-soc-wm-hubs-objs := wm_hubs.o
snd-soc-max9877-objs := max9877.o
snd-soc-tpa6130a2-objs := tpa6130a2.o
snd-soc-wm2000-objs := wm2000.o
snd-soc-wm9090-objs := wm9090.o
obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o
obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o
obj-$(CONFIG_SND_SOC_AD1938) += snd-soc-ad1938.o
obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o
obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o
obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
......@@ -70,6 +73,7 @@ obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o
obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o
obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o
obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o
obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o
......@@ -83,6 +87,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
......@@ -121,3 +126,4 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o
......@@ -278,7 +278,7 @@ static int ad1836_register(struct ad1836_priv *ad1836)
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = ad1836;
snd_soc_codec_set_drvdata(codec, ad1836);
codec->reg_cache = ad1836->reg_cache;
codec->reg_cache_size = AD1836_NUM_REGS;
codec->name = "AD1836";
......
/*
* File: sound/soc/codecs/ad1836.h
* Based on:
* Author: Barry Song <Barry.Song@analog.com>
*
* Created: May 25, 2009
* Description: definitions for AD1938 registers
*
* Modified:
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
* 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, see the file COPYING, or write
* to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __AD1938_H__
#define __AD1938_H__
#define AD1938_PLL_CLK_CTRL0 0
#define AD1938_PLL_POWERDOWN 0x01
#define AD1938_PLL_CLK_CTRL1 1
#define AD1938_DAC_CTRL0 2
#define AD1938_DAC_POWERDOWN 0x01
#define AD1938_DAC_SERFMT_MASK 0xC0
#define AD1938_DAC_SERFMT_STEREO (0 << 6)
#define AD1938_DAC_SERFMT_TDM (1 << 6)
#define AD1938_DAC_CTRL1 3
#define AD1938_DAC_2_CHANNELS 0
#define AD1938_DAC_4_CHANNELS 1
#define AD1938_DAC_8_CHANNELS 2
#define AD1938_DAC_16_CHANNELS 3
#define AD1938_DAC_CHAN_SHFT 1
#define AD1938_DAC_CHAN_MASK (3 << AD1938_DAC_CHAN_SHFT)
#define AD1938_DAC_LCR_MASTER (1 << 4)
#define AD1938_DAC_BCLK_MASTER (1 << 5)
#define AD1938_DAC_LEFT_HIGH (1 << 3)
#define AD1938_DAC_BCLK_INV (1 << 7)
#define AD1938_DAC_CTRL2 4
#define AD1938_DAC_WORD_LEN_MASK 0xC
#define AD1938_DAC_MASTER_MUTE 1
#define AD1938_DAC_CHNL_MUTE 5
#define AD1938_DACL1_MUTE 0
#define AD1938_DACR1_MUTE 1
#define AD1938_DACL2_MUTE 2
#define AD1938_DACR2_MUTE 3
#define AD1938_DACL3_MUTE 4
#define AD1938_DACR3_MUTE 5
#define AD1938_DACL4_MUTE 6
#define AD1938_DACR4_MUTE 7
#define AD1938_DAC_L1_VOL 6
#define AD1938_DAC_R1_VOL 7
#define AD1938_DAC_L2_VOL 8
#define AD1938_DAC_R2_VOL 9
#define AD1938_DAC_L3_VOL 10
#define AD1938_DAC_R3_VOL 11
#define AD1938_DAC_L4_VOL 12
#define AD1938_DAC_R4_VOL 13
#define AD1938_ADC_CTRL0 14
#define AD1938_ADC_POWERDOWN 0x01
#define AD1938_ADC_HIGHPASS_FILTER 1
#define AD1938_ADCL1_MUTE 2
#define AD1938_ADCR1_MUTE 3
#define AD1938_ADCL2_MUTE 4
#define AD1938_ADCR2_MUTE 5
#define AD1938_ADC_CTRL1 15
#define AD1938_ADC_SERFMT_MASK 0x60
#define AD1938_ADC_SERFMT_STEREO (0 << 5)
#define AD1938_ADC_SERFMT_TDM (1 << 2)
#define AD1938_ADC_SERFMT_AUX (2 << 5)
#define AD1938_ADC_WORD_LEN_MASK 0x3
#define AD1938_ADC_CTRL2 16
#define AD1938_ADC_2_CHANNELS 0
#define AD1938_ADC_4_CHANNELS 1
#define AD1938_ADC_8_CHANNELS 2
#define AD1938_ADC_16_CHANNELS 3
#define AD1938_ADC_CHAN_SHFT 4
#define AD1938_ADC_CHAN_MASK (3 << AD1938_ADC_CHAN_SHFT)
#define AD1938_ADC_LCR_MASTER (1 << 3)
#define AD1938_ADC_BCLK_MASTER (1 << 6)
#define AD1938_ADC_LEFT_HIGH (1 << 2)
#define AD1938_ADC_BCLK_INV (1 << 1)
#define AD1938_NUM_REGS 17
extern struct snd_soc_dai ad1938_dai;
extern struct snd_soc_codec_device soc_codec_dev_ad1938;
#endif
/*
* AD193X Audio Codec driver
*
* Copyright 2010 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#ifndef __AD193X_H__
#define __AD193X_H__
#define AD193X_PLL_CLK_CTRL0 0x800
#define AD193X_PLL_POWERDOWN 0x01
#define AD193X_PLL_CLK_CTRL1 0x801
#define AD193X_DAC_CTRL0 0x802
#define AD193X_DAC_POWERDOWN 0x01
#define AD193X_DAC_SERFMT_MASK 0xC0
#define AD193X_DAC_SERFMT_STEREO (0 << 6)
#define AD193X_DAC_SERFMT_TDM (1 << 6)
#define AD193X_DAC_CTRL1 0x803
#define AD193X_DAC_2_CHANNELS 0
#define AD193X_DAC_4_CHANNELS 1
#define AD193X_DAC_8_CHANNELS 2
#define AD193X_DAC_16_CHANNELS 3
#define AD193X_DAC_CHAN_SHFT 1
#define AD193X_DAC_CHAN_MASK (3 << AD193X_DAC_CHAN_SHFT)
#define AD193X_DAC_LCR_MASTER (1 << 4)
#define AD193X_DAC_BCLK_MASTER (1 << 5)
#define AD193X_DAC_LEFT_HIGH (1 << 3)
#define AD193X_DAC_BCLK_INV (1 << 7)
#define AD193X_DAC_CTRL2 0x804
#define AD193X_DAC_WORD_LEN_MASK 0xC
#define AD193X_DAC_MASTER_MUTE 1
#define AD193X_DAC_CHNL_MUTE 0x805
#define AD193X_DACL1_MUTE 0
#define AD193X_DACR1_MUTE 1
#define AD193X_DACL2_MUTE 2
#define AD193X_DACR2_MUTE 3
#define AD193X_DACL3_MUTE 4
#define AD193X_DACR3_MUTE 5
#define AD193X_DACL4_MUTE 6
#define AD193X_DACR4_MUTE 7
#define AD193X_DAC_L1_VOL 0x806
#define AD193X_DAC_R1_VOL 0x807
#define AD193X_DAC_L2_VOL 0x808
#define AD193X_DAC_R2_VOL 0x809
#define AD193X_DAC_L3_VOL 0x80a
#define AD193X_DAC_R3_VOL 0x80b
#define AD193X_DAC_L4_VOL 0x80c
#define AD193X_DAC_R4_VOL 0x80d
#define AD193X_ADC_CTRL0 0x80e
#define AD193X_ADC_POWERDOWN 0x01
#define AD193X_ADC_HIGHPASS_FILTER 1
#define AD193X_ADCL1_MUTE 2
#define AD193X_ADCR1_MUTE 3
#define AD193X_ADCL2_MUTE 4
#define AD193X_ADCR2_MUTE 5
#define AD193X_ADC_CTRL1 0x80f
#define AD193X_ADC_SERFMT_MASK 0x60
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
#define AD193X_ADC_SERFMT_TDM (1 << 2)
#define AD193X_ADC_SERFMT_AUX (2 << 5)
#define AD193X_ADC_WORD_LEN_MASK 0x3
#define AD193X_ADC_CTRL2 0x810
#define AD193X_ADC_2_CHANNELS 0
#define AD193X_ADC_4_CHANNELS 1
#define AD193X_ADC_8_CHANNELS 2
#define AD193X_ADC_16_CHANNELS 3
#define AD193X_ADC_CHAN_SHFT 4
#define AD193X_ADC_CHAN_MASK (3 << AD193X_ADC_CHAN_SHFT)
#define AD193X_ADC_LCR_MASTER (1 << 3)
#define AD193X_ADC_BCLK_MASTER (1 << 6)
#define AD193X_ADC_LEFT_HIGH (1 << 2)
#define AD193X_ADC_BCLK_INV (1 << 1)
#define AD193X_NUM_REGS 17
extern struct snd_soc_dai ad193x_dai;
extern struct snd_soc_codec_device soc_codec_dev_ad193x;
#endif
......@@ -222,7 +222,7 @@ static int ak4104_spi_probe(struct spi_device *spi)
codec->owner = THIS_MODULE;
codec->dai = &ak4104_dai;
codec->num_dai = 1;
codec->private_data = ak4104;
snd_soc_codec_set_drvdata(codec, ak4104);
codec->control_data = spi;
codec->reg_cache = ak4104->reg_cache;
codec->reg_cache_size = AK4104_NUM_REGS;
......
......@@ -302,7 +302,7 @@ static int ak4535_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 ak4535_priv *ak4535 = codec->private_data;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
ak4535->sysclk = freq;
return 0;
......@@ -315,7 +315,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct ak4535_priv *ak4535 = codec->private_data;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256;
......@@ -446,7 +446,6 @@ static int ak4535_resume(struct platform_device *pdev)
struct snd_soc_codec *codec = socdev->card->codec;
ak4535_sync(codec);
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ak4535_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
......@@ -600,7 +599,7 @@ static int ak4535_probe(struct platform_device *pdev)
return -ENOMEM;
}
codec->private_data = ak4535;
snd_soc_codec_set_drvdata(codec, ak4535);
socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
......@@ -617,7 +616,7 @@ static int ak4535_probe(struct platform_device *pdev)
#endif
if (ret != 0) {
kfree(codec->private_data);
kfree(snd_soc_codec_get_drvdata(codec));
kfree(codec);
}
return ret;
......@@ -639,7 +638,7 @@ static int ak4535_remove(struct platform_device *pdev)
i2c_unregister_device(codec->control_data);
i2c_del_driver(&ak4535_i2c_driver);
#endif
kfree(codec->private_data);
kfree(snd_soc_codec_get_drvdata(codec));
kfree(codec);
return 0;
......
......@@ -81,12 +81,39 @@
#define AK4642_CACHEREGNUM 0x25
/* PW_MGMT2 */
#define HPMTN (1 << 6)
#define PMHPL (1 << 5)
#define PMHPR (1 << 4)
#define MS (1 << 3) /* master/slave select */
#define MCKO (1 << 1)
#define PMPLL (1 << 0)
#define PMHP_MASK (PMHPL | PMHPR)
#define PMHP PMHP_MASK
/* MD_CTL1 */
#define PLL3 (1 << 7)
#define PLL2 (1 << 6)
#define PLL1 (1 << 5)
#define PLL0 (1 << 4)
#define PLL_MASK (PLL3 | PLL2 | PLL1 | PLL0)
#define BCKO_MASK (1 << 3)
#define BCKO_64 BCKO_MASK
/* MD_CTL2 */
#define FS0 (1 << 0)
#define FS1 (1 << 1)
#define FS2 (1 << 2)
#define FS3 (1 << 5)
#define FS_MASK (FS0 | FS1 | FS2 | FS3)
struct snd_soc_codec_device soc_codec_dev_ak4642;
/* codec private data */
struct ak4642_priv {
struct snd_soc_codec codec;
unsigned int sysclk;
};
static struct snd_soc_codec *ak4642_codec;
......@@ -177,17 +204,12 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
*
* PLL, Master Mode
* Audio I/F Format :MSB justified (ADC & DAC)
* Sampling Frequency: 44.1kHz
* Digital Volume: −8dB
* Digital Volume: -8dB
* Bass Boost Level : Middle
*
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p97.
*
* Example code use 0x39, 0x79 value for 0x01 address,
* But we need MCKO (0x02) bit now
*/
ak4642_write(codec, 0x05, 0x27);
ak4642_write(codec, 0x0f, 0x09);
ak4642_write(codec, 0x0e, 0x19);
ak4642_write(codec, 0x09, 0x91);
......@@ -195,15 +217,14 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
ak4642_write(codec, 0x0a, 0x28);
ak4642_write(codec, 0x0d, 0x28);
ak4642_write(codec, 0x00, 0x64);
ak4642_write(codec, 0x01, 0x3b); /* + MCKO bit */
ak4642_write(codec, 0x01, 0x7b); /* + MCKO bit */
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, HPMTN);
} else {
/*
* start stereo input
*
* PLL Master Mode
* Audio I/F Format:MSB justified (ADC & DAC)
* Sampling Frequency:44.1kHz
* Pre MIC AMP:+20dB
* MIC Power On
* ALC setting:Refer to Table 35
......@@ -212,7 +233,6 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94.
*/
ak4642_write(codec, 0x05, 0x27);
ak4642_write(codec, 0x02, 0x05);
ak4642_write(codec, 0x06, 0x3c);
ak4642_write(codec, 0x08, 0xe1);
......@@ -233,8 +253,8 @@ static void ak4642_dai_shutdown(struct snd_pcm_substream *substream,
if (is_play) {
/* stop headphone output */
ak4642_write(codec, 0x01, 0x3b);
ak4642_write(codec, 0x01, 0x0b);
snd_soc_update_bits(codec, PW_MGMT2, HPMTN, 0);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, 0);
ak4642_write(codec, 0x00, 0x40);
ak4642_write(codec, 0x0e, 0x11);
ak4642_write(codec, 0x0f, 0x08);
......@@ -250,9 +270,111 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct ak4642_priv *ak4642 = codec->private_data;
u8 pll;
switch (freq) {
case 11289600:
pll = PLL2;
break;
case 12288000:
pll = PLL2 | PLL0;
break;
case 12000000:
pll = PLL2 | PLL1;
break;
case 24000000:
pll = PLL2 | PLL1 | PLL0;
break;
case 13500000:
pll = PLL3 | PLL2;
break;
case 27000000:
pll = PLL3 | PLL2 | PLL0;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
return 0;
}
static int ak4642_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
{
struct snd_soc_codec *codec = dai->codec;
u8 data;
u8 bcko;
data = MCKO | PMPLL; /* use MCKO */
bcko = 0;
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
data |= MS;
bcko = BCKO_64;
break;
case SND_SOC_DAIFMT_CBS_CFS:
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, PW_MGMT2, MS, data);
snd_soc_update_bits(codec, MD_CTL1, BCKO_MASK, bcko);
return 0;
}
static int ak4642_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
u8 rate;
switch (params_rate(params)) {
case 7350:
rate = FS2;
break;
case 8000:
rate = 0;
break;
case 11025:
rate = FS2 | FS0;
break;
case 12000:
rate = FS0;
break;
case 14700:
rate = FS2 | FS1;
break;
case 16000:
rate = FS1;
break;
case 22050:
rate = FS2 | FS1 | FS0;
break;
case 24000:
rate = FS1 | FS0;
break;
case 29400:
rate = FS3 | FS2 | FS1;
break;
case 32000:
rate = FS3 | FS1;
break;
case 44100:
rate = FS3 | FS2 | FS1 | FS0;
break;
case 48000:
rate = FS3 | FS1 | FS0;
break;
default:
return -EINVAL;
break;
}
snd_soc_update_bits(codec, MD_CTL2, FS_MASK, rate);
ak4642->sysclk = freq;
return 0;
}
......@@ -260,6 +382,8 @@ static struct snd_soc_dai_ops ak4642_dai_ops = {
.startup = ak4642_dai_startup,
.shutdown = ak4642_dai_shutdown,
.set_sysclk = ak4642_dai_set_sysclk,
.set_fmt = ak4642_dai_set_fmt,
.hw_params = ak4642_dai_hw_params,
};
struct snd_soc_dai ak4642_dai = {
......@@ -277,6 +401,7 @@ struct snd_soc_dai ak4642_dai = {
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE },
.ops = &ak4642_dai_ops,
.symmetric_rates = 1,
};
EXPORT_SYMBOL_GPL(ak4642_dai);
......@@ -307,7 +432,7 @@ static int ak4642_init(struct ak4642_priv *ak4642)
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = ak4642;
snd_soc_codec_set_drvdata(codec, ak4642);
codec->name = "AK4642";
codec->owner = THIS_MODULE;
codec->read = ak4642_read_reg_cache;
......@@ -338,26 +463,6 @@ static int ak4642_init(struct ak4642_priv *ak4642)
goto reg_cache_err;
}
/*
* clock setting
*
* Audio I/F Format: MSB justified (ADC & DAC)
* BICK frequency at Master Mode: 64fs
* Input Master Clock Select at PLL Mode: 11.2896MHz
* MCKO: Enable
* Sampling Frequency: 44.1kHz
*
* This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p89.
*
* please fix-me
*/
ak4642_write(codec, 0x01, 0x08);
ak4642_write(codec, 0x04, 0x4a);
ak4642_write(codec, 0x05, 0x27);
ak4642_write(codec, 0x00, 0x40);
ak4642_write(codec, 0x01, 0x0b);
return ret;
reg_cache_err:
......
......@@ -702,7 +702,7 @@ static int ak4671_register(struct ak4671_priv *ak4671,
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = ak4671;
snd_soc_codec_set_drvdata(codec, ak4671);
codec->name = "AK4671";
codec->owner = THIS_MODULE;
codec->bias_level = SND_SOC_BIAS_OFF;
......
/*
* ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
*
* Copyright (C) 2010 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/clk.h>
#include <linux/mfd/davinci_voicecodec.h>
#include <sound/core.h>
#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>
#include "cq93vc.h"
static inline unsigned int cq93vc_read(struct snd_soc_codec *codec,
unsigned int reg)
{
struct davinci_vc *davinci_vc = codec->control_data;
return readl(davinci_vc->base + reg);
}
static inline int cq93vc_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
struct davinci_vc *davinci_vc = codec->control_data;
writel(value, davinci_vc->base + reg);
return 0;
}
static const struct snd_kcontrol_new cq93vc_snd_controls[] = {
SOC_SINGLE("PGA Capture Volume", DAVINCI_VC_REG05, 0, 0x03, 0),
SOC_SINGLE("Mono DAC Playback Volume", DAVINCI_VC_REG09, 0, 0x3f, 0),
};
static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u8 reg = cq93vc_read(codec, DAVINCI_VC_REG09) & ~DAVINCI_VC_REG09_MUTE;
if (mute)
cq93vc_write(codec, DAVINCI_VC_REG09,
reg | DAVINCI_VC_REG09_MUTE);
else
cq93vc_write(codec, DAVINCI_VC_REG09, reg);
return 0;
}
static int cq93vc_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 davinci_vc *davinci_vc = codec->control_data;
switch (freq) {
case 22579200:
case 27000000:
case 33868800:
davinci_vc->cq93vc.sysclk = freq;
return 0;
}
return -EINVAL;
}
static int cq93vc_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
switch (level) {
case SND_SOC_BIAS_ON:
cq93vc_write(codec, DAVINCI_VC_REG12,
DAVINCI_VC_REG12_POWER_ALL_ON);
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
cq93vc_write(codec, DAVINCI_VC_REG12,
DAVINCI_VC_REG12_POWER_ALL_OFF);
break;
case SND_SOC_BIAS_OFF:
/* force all power off */
cq93vc_write(codec, DAVINCI_VC_REG12,
DAVINCI_VC_REG12_POWER_ALL_OFF);
break;
}
codec->bias_level = level;
return 0;
}
#define CQ93VC_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000)
#define CQ93VC_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
static struct snd_soc_dai_ops cq93vc_dai_ops = {
.digital_mute = cq93vc_mute,
.set_sysclk = cq93vc_set_dai_sysclk,
};
struct snd_soc_dai cq93vc_dai = {
.name = "CQ93VC",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = CQ93VC_RATES,
.formats = CQ93VC_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = CQ93VC_RATES,
.formats = CQ93VC_FORMATS,},
.ops = &cq93vc_dai_ops,
};
EXPORT_SYMBOL_GPL(cq93vc_dai);
static int cq93vc_resume(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static struct snd_soc_codec *cq93vc_codec;
static int cq93vc_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
struct snd_soc_codec *codec;
int ret;
socdev->card->codec = cq93vc_codec;
codec = socdev->card->codec;
/* Register pcms */
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
if (ret < 0) {
dev_err(dev, "%s: failed to create pcms\n", pdev->name);
return ret;
}
/* Set controls */
snd_soc_add_controls(codec, cq93vc_snd_controls,
ARRAY_SIZE(cq93vc_snd_controls));
/* Off, with power on */
cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
static int cq93vc_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
return 0;
}
struct snd_soc_codec_device soc_codec_dev_cq93vc = {
.probe = cq93vc_probe,
.remove = cq93vc_remove,
.resume = cq93vc_resume,
};
EXPORT_SYMBOL_GPL(soc_codec_dev_cq93vc);
static __init int cq93vc_codec_probe(struct platform_device *pdev)
{
struct davinci_vc *davinci_vc = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
int ret;
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL) {
dev_dbg(davinci_vc->dev,
"could not allocate memory for codec data\n");
return -ENOMEM;
}
davinci_vc->cq93vc.codec = codec;
cq93vc_dai.dev = &pdev->dev;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->dev = &pdev->dev;
codec->name = "CQ93VC";
codec->owner = THIS_MODULE;
codec->read = cq93vc_read;
codec->write = cq93vc_write;
codec->set_bias_level = cq93vc_set_bias_level;
codec->dai = &cq93vc_dai;
codec->num_dai = 1;
codec->control_data = davinci_vc;
cq93vc_codec = codec;
ret = snd_soc_register_codec(codec);
if (ret) {
dev_err(davinci_vc->dev, "failed to register codec\n");
goto fail1;
}
ret = snd_soc_register_dai(&cq93vc_dai);
if (ret) {
dev_err(davinci_vc->dev, "could register dai\n");
goto fail2;
}
return 0;
fail2:
snd_soc_unregister_codec(codec);
fail1:
kfree(codec);
cq93vc_codec = NULL;
return ret;
}
static int __devexit cq93vc_codec_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = socdev->card->codec;
snd_soc_unregister_dai(&cq93vc_dai);
snd_soc_unregister_codec(&codec);
kfree(codec);
cq93vc_codec = NULL;
return 0;
}
static struct platform_driver cq93vc_codec_driver = {
.driver = {
.name = "cq93vc",
.owner = THIS_MODULE,
},
.probe = cq93vc_codec_probe,
.remove = __devexit_p(cq93vc_codec_remove),
};
static __init int cq93vc_init(void)
{
return platform_driver_probe(&cq93vc_codec_driver, cq93vc_codec_probe);
}
module_init(cq93vc_init);
static __exit void cq93vc_exit(void)
{
platform_driver_unregister(&cq93vc_codec_driver);
}
module_exit(cq93vc_exit);
MODULE_DESCRIPTION("Texas Instruments DaVinci ASoC CQ0093 Voice Codec Driver");
MODULE_AUTHOR("Miguel Aguilar");
MODULE_LICENSE("GPL");
/*
* ALSA SoC CQ0093 Voice Codec Driver for DaVinci platforms
*
* Copyright (C) 2010 Texas Instruments, Inc
*
* Author: Miguel Aguilar <miguel.aguilar@ridgerun.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _CQ93VC_H
#define _CQ93VC_H
extern struct snd_soc_dai cq93vc_dai;
extern struct snd_soc_codec_device soc_codec_dev_cq93vc;
#endif
......@@ -211,7 +211,7 @@ static int cs4270_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 cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
unsigned int rates = 0;
unsigned int rate_min = -1;
unsigned int rate_max = 0;
......@@ -270,7 +270,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int format)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
/* set DAI format */
......@@ -412,7 +412,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret;
unsigned int i;
unsigned int rate;
......@@ -491,7 +491,7 @@ static int cs4270_hw_params(struct snd_pcm_substream *substream,
static int cs4270_dai_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int reg6;
reg6 = snd_soc_read(codec, CS4270_MUTE);
......@@ -524,7 +524,7 @@ static int cs4270_soc_put_mute(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int left = !ucontrol->value.integer.value[0];
int right = !ucontrol->value.integer.value[1];
......@@ -600,7 +600,7 @@ static int cs4270_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int i, ret;
/* Connect the codec to the socdev. snd_soc_new_pcms() needs this. */
......@@ -657,7 +657,7 @@ static int cs4270_remove(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
snd_soc_free_pcms(socdev);
regulator_bulk_disable(ARRAY_SIZE(cs4270->supplies), cs4270->supplies);
......@@ -730,7 +730,7 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
codec->owner = THIS_MODULE;
codec->dai = &cs4270_dai;
codec->num_dai = 1;
codec->private_data = cs4270;
snd_soc_codec_set_drvdata(codec, cs4270);
codec->control_data = i2c_client;
codec->read = cs4270_read_reg_cache;
codec->write = cs4270_i2c_write;
......@@ -843,7 +843,7 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id);
static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
{
struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int reg, ret;
reg = snd_soc_read(codec, CS4270_PWRCTL) | CS4270_PWRCTL_PDN_ALL;
......@@ -863,7 +863,7 @@ static int cs4270_soc_suspend(struct platform_device *pdev, pm_message_t mesg)
static int cs4270_soc_resume(struct platform_device *pdev)
{
struct snd_soc_codec *codec = cs4270_codec;
struct cs4270_private *cs4270 = codec->private_data;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c_client = codec->control_data;
int reg;
......
......@@ -387,7 +387,7 @@ static int cx20442_register(struct cx20442_priv *cx20442)
codec->name = "CX20442";
codec->owner = THIS_MODULE;
codec->private_data = cx20442;
snd_soc_codec_set_drvdata(codec, cx20442);
codec->dai = &cx20442_dai;
codec->num_dai = 1;
......
......@@ -56,8 +56,14 @@
#define DA7210_DAI_SRC_SEL 0x25
#define DA7210_DAI_CFG1 0x26
#define DA7210_DAI_CFG3 0x28
#define DA7210_PLL_DIV1 0x29
#define DA7210_PLL_DIV2 0x2A
#define DA7210_PLL_DIV3 0x2B
#define DA7210_PLL 0x2C
#define DA7210_A_HID_UNLOCK 0x8A
#define DA7210_A_TEST_UNLOCK 0x8B
#define DA7210_A_PLL1 0x90
#define DA7210_A_CP_MODE 0xA7
/* STARTUP1 bit fields */
#define DA7210_SC_MST_EN (1 << 0)
......@@ -75,15 +81,14 @@
/* INMIX_R bit fields */
#define DA7210_IN_R_EN (1 << 7)
/* ADC_HPF bit fields */
#define DA7210_ADC_VOICE_EN (1 << 7)
/* ADC bit fields */
#define DA7210_ADC_L_EN (1 << 3)
#define DA7210_ADC_R_EN (1 << 7)
/* DAC_HPF fields */
#define DA7210_DAC_VOICE_EN (1 << 7)
/* DAC/ADC HPF fields */
#define DA7210_VOICE_F0_MASK (0x7 << 4)
#define DA7210_VOICE_F0_25 (1 << 4)
#define DA7210_VOICE_EN (1 << 7)
/* DAC_SEL bit fields */
#define DA7210_DAC_L_SRC_DAI_L (4 << 0)
......@@ -124,7 +129,19 @@
#define DA7210_PLL_BYP (1 << 6)
/* PLL bit fields */
#define DA7210_PLL_FS_48000 (11 << 0)
#define DA7210_PLL_FS_MASK (0xF << 0)
#define DA7210_PLL_FS_8000 (0x1 << 0)
#define DA7210_PLL_FS_11025 (0x2 << 0)
#define DA7210_PLL_FS_12000 (0x3 << 0)
#define DA7210_PLL_FS_16000 (0x5 << 0)
#define DA7210_PLL_FS_22050 (0x6 << 0)
#define DA7210_PLL_FS_24000 (0x7 << 0)
#define DA7210_PLL_FS_32000 (0x9 << 0)
#define DA7210_PLL_FS_44100 (0xA << 0)
#define DA7210_PLL_FS_48000 (0xB << 0)
#define DA7210_PLL_FS_88200 (0xE << 0)
#define DA7210_PLL_FS_96000 (0xF << 0)
#define DA7210_PLL_EN (0x1 << 7)
#define DA7210_VERSION "0.0.1"
......@@ -165,7 +182,7 @@ static const u8 da7210_reg[] = {
static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg)
{
u8 *cache = codec->reg_cache;
BUG_ON(reg > ARRAY_SIZE(da7210_reg));
BUG_ON(reg >= ARRAY_SIZE(da7210_reg));
return cache[reg];
}
......@@ -242,7 +259,8 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
u32 dai_cfg1;
u32 reg, mask;
u32 hpf_reg, hpf_mask, hpf_value;
u32 fs, bypass;
/* set DAI source to Left and Right ADC */
da7210_write(codec, DA7210_DAI_SRC_SEL,
......@@ -266,25 +284,84 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1);
/* FIXME
*
* It support 48K only now
*/
hpf_reg = (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) ?
DA7210_DAC_HPF : DA7210_ADC_HPF;
switch (params_rate(params)) {
case 8000:
fs = DA7210_PLL_FS_8000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP;
break;
case 11025:
fs = DA7210_PLL_FS_11025;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = 0;
break;
case 12000:
fs = DA7210_PLL_FS_12000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP;
break;
case 16000:
fs = DA7210_PLL_FS_16000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP;
break;
case 22050:
fs = DA7210_PLL_FS_22050;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = 0;
break;
case 32000:
fs = DA7210_PLL_FS_32000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = DA7210_PLL_BYP;
break;
case 44100:
fs = DA7210_PLL_FS_44100;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = 0;
break;
case 48000:
if (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) {
reg = DA7210_DAC_HPF;
mask = DA7210_DAC_VOICE_EN;
} else {
reg = DA7210_ADC_HPF;
mask = DA7210_ADC_VOICE_EN;
}
fs = DA7210_PLL_FS_48000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = DA7210_PLL_BYP;
break;
case 88200:
fs = DA7210_PLL_FS_88200;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = 0;
break;
case 96000:
fs = DA7210_PLL_FS_96000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = DA7210_PLL_BYP;
break;
default:
return -EINVAL;
}
snd_soc_update_bits(codec, reg, mask, 0);
/* Disable active mode */
snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
snd_soc_update_bits(codec, hpf_reg, hpf_mask, hpf_value);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
/* Enable active mode */
snd_soc_update_bits(codec, DA7210_STARTUP1,
DA7210_SC_MST_EN, DA7210_SC_MST_EN);
return 0;
}
......@@ -362,6 +439,7 @@ struct snd_soc_dai da7210_dai = {
.formats = DA7210_FORMATS,
},
.ops = &da7210_dai_ops,
.symmetric_rates = 1,
};
EXPORT_SYMBOL_GPL(da7210_dai);
......@@ -383,7 +461,7 @@ static int da7210_init(struct da7210_priv *da7210)
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = da7210;
snd_soc_codec_set_drvdata(codec, da7210);
codec->name = "DA7210";
codec->owner = THIS_MODULE;
codec->read = da7210_read;
......@@ -416,8 +494,22 @@ static int da7210_init(struct da7210_priv *da7210)
/* FIXME
*
* This driver use fixed value here
* And below settings expects MCLK = 12.288MHz
*
* When you select different MCLK, please check...
* DA7210_PLL_DIV1 val
* DA7210_PLL_DIV2 val
* DA7210_PLL_DIV3 val
* DA7210_PLL_DIV3 :: DA7210_MCLK_RANGExxx
*/
/*
* make sure that DA7210 use bypass mode before start up
*/
da7210_write(codec, DA7210_STARTUP1, 0);
da7210_write(codec, DA7210_PLL_DIV3,
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
/*
* ADC settings
*/
......@@ -454,9 +546,28 @@ static int da7210_init(struct da7210_priv *da7210)
/* Diable PLL and bypass it */
da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
/* Bypass PLL and set MCLK freq rang to 10-20MHz */
da7210_write(codec, DA7210_PLL_DIV3,
/*
* If 48kHz sound came, it use bypass mode,
* and when it is 44.1kHz, it use PLL.
*
* This time, this driver sets PLL always ON
* and controls bypass/PLL mode by switching
* DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
* see da7210_hw_params
*/
da7210_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
da7210_write(codec, DA7210_PLL_DIV2, 0x99);
da7210_write(codec, DA7210_PLL_DIV3, 0x0A |
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
/* As suggested by Dialog */
da7210_write(codec, DA7210_A_HID_UNLOCK, 0x8B); /* unlock */
da7210_write(codec, DA7210_A_TEST_UNLOCK, 0xB4);
da7210_write(codec, DA7210_A_PLL1, 0x01);
da7210_write(codec, DA7210_A_CP_MODE, 0x7C);
da7210_write(codec, DA7210_A_HID_UNLOCK, 0x00); /* re-lock */
da7210_write(codec, DA7210_A_TEST_UNLOCK, 0x00);
/* Activate all enabled subsystem */
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
......
......@@ -140,6 +140,7 @@ SOC_DOUBLE_R("Capture Volume", SSM2602_LINVOL, SSM2602_RINVOL, 0, 31, 0),
SOC_DOUBLE_R("Capture Switch", SSM2602_LINVOL, SSM2602_RINVOL, 7, 1, 1),
SOC_SINGLE("Mic Boost (+20dB)", SSM2602_APANA, 0, 1, 0),
SOC_SINGLE("Mic Boost2 (+20dB)", SSM2602_APANA, 7, 1, 0),
SOC_SINGLE("Mic Switch", SSM2602_APANA, 1, 1, 1),
SOC_SINGLE("Sidetone Playback Volume", SSM2602_APANA, 6, 3, 1),
......@@ -277,7 +278,7 @@ static int ssm2602_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct ssm2602_priv *ssm2602 = codec->private_data;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = codec->control_data;
u16 iface = ssm2602_read_reg_cache(codec, SSM2602_IFACE) & 0xfff3;
int i = get_coeff(ssm2602->sysclk, params_rate(params));
......@@ -322,7 +323,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct ssm2602_priv *ssm2602 = codec->private_data;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c = codec->control_data;
struct snd_pcm_runtime *master_runtime;
......@@ -373,7 +374,7 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct ssm2602_priv *ssm2602 = codec->private_data;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
/* deactivate */
if (!codec->active)
......@@ -401,7 +402,7 @@ static int ssm2602_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 ssm2602_priv *ssm2602 = codec->private_data;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
switch (freq) {
case 11289600:
case 12000000:
......@@ -559,7 +560,6 @@ static int ssm2602_resume(struct platform_device *pdev)
codec->hw_write(codec->control_data, data, 2);
}
ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
ssm2602_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
......@@ -605,8 +605,7 @@ static int ssm2602_init(struct snd_soc_device *socdev)
reg = ssm2602_read_reg_cache(codec, SSM2602_ROUT1V);
ssm2602_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH);
/*select Line in as default input*/
ssm2602_write(codec, SSM2602_APANA,
APANA_ENABLE_MIC_BOOST2 | APANA_SELECT_DAC |
ssm2602_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
APANA_ENABLE_MIC_BOOST);
ssm2602_write(codec, SSM2602_PWR, 0);
......@@ -727,7 +726,7 @@ static int ssm2602_probe(struct platform_device *pdev)
return -ENOMEM;
}
codec->private_data = ssm2602;
snd_soc_codec_set_drvdata(codec, ssm2602);
socdev->card->codec = codec;
mutex_init(&codec->mutex);
INIT_LIST_HEAD(&codec->dapm_widgets);
......@@ -760,7 +759,7 @@ static int ssm2602_remove(struct platform_device *pdev)
i2c_unregister_device(codec->control_data);
i2c_del_driver(&ssm2602_i2c_driver);
#endif
kfree(codec->private_data);
kfree(snd_soc_codec_get_drvdata(codec));
kfree(codec);
return 0;
......
......@@ -289,9 +289,6 @@ static int stac9766_codec_resume(struct platform_device *pdev)
}
stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
stac9766_set_bias_level(codec, SND_SOC_BIAS_ON);
return 0;
}
......@@ -410,7 +407,7 @@ static int stac9766_codec_probe(struct platform_device *pdev)
pcm_err:
snd_soc_free_ac97_codec(codec);
codec_err:
kfree(codec->private_data);
kfree(snd_soc_codec_get_drvdata(codec));
cache_err:
kfree(socdev->card->codec);
socdev->card->codec = NULL;
......
......@@ -634,7 +634,6 @@ static int tlv320aic23_resume(struct platform_device *pdev)
}
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
tlv320aic23_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
......
......@@ -49,7 +49,7 @@ struct aic26 {
static unsigned int aic26_reg_read(struct snd_soc_codec *codec,
unsigned int reg)
{
struct aic26 *aic26 = codec->private_data;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
u16 cmd, value;
u8 buffer[2];
......@@ -93,7 +93,7 @@ static unsigned int aic26_reg_read_cache(struct snd_soc_codec *codec,
static int aic26_reg_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
struct aic26 *aic26 = codec->private_data;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
u16 cmd;
u8 buffer[4];
......@@ -132,7 +132,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct aic26 *aic26 = codec->private_data;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
int fsref, divisor, wlen, pval, jval, dval, qval;
u16 reg;
......@@ -199,7 +199,7 @@ static int aic26_hw_params(struct snd_pcm_substream *substream,
static int aic26_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct aic26 *aic26 = codec->private_data;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
u16 reg = aic26_reg_read_cache(codec, AIC26_REG_DAC_GAIN);
dev_dbg(&aic26->spi->dev, "aic26_mute(dai=%p, mute=%i)\n",
......@@ -218,7 +218,7 @@ static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct aic26 *aic26 = codec->private_data;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
dev_dbg(&aic26->spi->dev, "aic26_set_sysclk(dai=%p, clk_id==%i,"
" freq=%i, dir=%i)\n",
......@@ -235,7 +235,7 @@ static int aic26_set_sysclk(struct snd_soc_dai *codec_dai,
static int aic26_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct aic26 *aic26 = codec->private_data;
struct aic26 *aic26 = snd_soc_codec_get_drvdata(codec);
dev_dbg(&aic26->spi->dev, "aic26_set_fmt(dai=%p, fmt==%i)\n",
codec_dai, fmt);
......@@ -431,7 +431,7 @@ static int aic26_spi_probe(struct spi_device *spi)
/* Setup what we can in the codec structure so that the register
* access functions will work as expected. More will be filled
* out when it is probed by the SoC CODEC part of this driver */
aic26->codec.private_data = aic26;
snd_soc_codec_set_drvdata(&aic26->codec, aic26);
aic26->codec.name = "aic26";
aic26->codec.owner = THIS_MODULE;
aic26->codec.dai = &aic26_dai;
......
......@@ -38,6 +38,8 @@
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <sound/core.h>
......@@ -47,16 +49,25 @@
#include <sound/soc-dapm.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/tlv320aic3x.h>
#include "tlv320aic3x.h"
#define AIC3X_VERSION "0.2"
#define AIC3X_NUM_SUPPLIES 4
static const char *aic3x_supply_names[AIC3X_NUM_SUPPLIES] = {
"IOVDD", /* I/O Voltage */
"DVDD", /* Digital Core Voltage */
"AVDD", /* Analog DAC Voltage */
"DRVDD", /* ADC Analog and Output Driver Voltage */
};
/* codec private data */
struct aic3x_priv {
struct snd_soc_codec codec;
struct regulator_bulk_data supplies[AIC3X_NUM_SUPPLIES];
unsigned int sysclk;
int master;
int gpio_reset;
};
/*
......@@ -764,7 +775,7 @@ static int aic3x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct aic3x_priv *aic3x = codec->private_data;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int codec_clk = 0, bypass_pll = 0, fsref, last_clk = 0;
u8 data, j, r, p, pll_q, pll_p = 1, pll_r = 1, pll_j = 1;
u16 d, pll_d = 1;
......@@ -931,7 +942,7 @@ static int aic3x_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 aic3x_priv *aic3x = codec->private_data;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
aic3x->sysclk = freq;
return 0;
......@@ -941,7 +952,7 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct aic3x_priv *aic3x = codec->private_data;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
u8 iface_areg, iface_breg;
int delay = 0;
......@@ -995,12 +1006,13 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int aic3x_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct aic3x_priv *aic3x = codec->private_data;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
u8 reg;
switch (level) {
case SND_SOC_BIAS_ON:
/* all power is driven by DAPM system */
break;
case SND_SOC_BIAS_PREPARE:
if (aic3x->master) {
/* enable pll */
reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
......@@ -1008,48 +1020,9 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
reg | PLL_ENABLE);
}
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
/*
* all power is driven by DAPM system,
* so output power is safe if bypass was set
*/
if (aic3x->master) {
/* disable pll */
reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
aic3x_write(codec, AIC3X_PLL_PROGA_REG,
reg & ~PLL_ENABLE);
}
break;
/* fall through and disable pll */
case SND_SOC_BIAS_OFF:
/* force all power off */
reg = aic3x_read_reg_cache(codec, LINE1L_2_LADC_CTRL);
aic3x_write(codec, LINE1L_2_LADC_CTRL, reg & ~LADC_PWR_ON);
reg = aic3x_read_reg_cache(codec, LINE1R_2_RADC_CTRL);
aic3x_write(codec, LINE1R_2_RADC_CTRL, reg & ~RADC_PWR_ON);
reg = aic3x_read_reg_cache(codec, DAC_PWR);
aic3x_write(codec, DAC_PWR, reg & ~(LDAC_PWR_ON | RDAC_PWR_ON));
reg = aic3x_read_reg_cache(codec, HPLOUT_CTRL);
aic3x_write(codec, HPLOUT_CTRL, reg & ~HPLOUT_PWR_ON);
reg = aic3x_read_reg_cache(codec, HPROUT_CTRL);
aic3x_write(codec, HPROUT_CTRL, reg & ~HPROUT_PWR_ON);
reg = aic3x_read_reg_cache(codec, HPLCOM_CTRL);
aic3x_write(codec, HPLCOM_CTRL, reg & ~HPLCOM_PWR_ON);
reg = aic3x_read_reg_cache(codec, HPRCOM_CTRL);
aic3x_write(codec, HPRCOM_CTRL, reg & ~HPRCOM_PWR_ON);
reg = aic3x_read_reg_cache(codec, MONOLOPM_CTRL);
aic3x_write(codec, MONOLOPM_CTRL, reg & ~MONOLOPM_PWR_ON);
reg = aic3x_read_reg_cache(codec, LLOPM_CTRL);
aic3x_write(codec, LLOPM_CTRL, reg & ~LLOPM_PWR_ON);
reg = aic3x_read_reg_cache(codec, RLOPM_CTRL);
aic3x_write(codec, RLOPM_CTRL, reg & ~RLOPM_PWR_ON);
if (aic3x->master) {
/* disable pll */
reg = aic3x_read_reg_cache(codec, AIC3X_PLL_PROGA_REG);
......@@ -1171,7 +1144,7 @@ static int aic3x_resume(struct platform_device *pdev)
codec->hw_write(codec->control_data, data, 2);
}
aic3x_set_bias_level(codec, codec->suspend_bias_level);
aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
......@@ -1309,6 +1282,13 @@ static int aic3x_unregister(struct aic3x_priv *aic3x)
snd_soc_unregister_dai(&aic3x_dai);
snd_soc_unregister_codec(&aic3x->codec);
if (aic3x->gpio_reset >= 0) {
gpio_set_value(aic3x->gpio_reset, 0);
gpio_free(aic3x->gpio_reset);
}
regulator_bulk_disable(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
kfree(aic3x);
aic3x_codec = NULL;
......@@ -1330,6 +1310,8 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
{
struct snd_soc_codec *codec;
struct aic3x_priv *aic3x;
struct aic3x_pdata *pdata = i2c->dev.platform_data;
int ret, i;
aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) {
......@@ -1339,13 +1321,53 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
codec = &aic3x->codec;
codec->dev = &i2c->dev;
codec->private_data = aic3x;
snd_soc_codec_set_drvdata(codec, aic3x);
codec->control_data = i2c;
codec->hw_write = (hw_write_t) i2c_master_send;
i2c_set_clientdata(i2c, aic3x);
aic3x->gpio_reset = -1;
if (pdata && pdata->gpio_reset >= 0) {
ret = gpio_request(pdata->gpio_reset, "tlv320aic3x reset");
if (ret != 0)
goto err_gpio;
aic3x->gpio_reset = pdata->gpio_reset;
gpio_direction_output(aic3x->gpio_reset, 0);
}
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
aic3x->supplies[i].supply = aic3x_supply_names[i];
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
goto err_get;
}
ret = regulator_bulk_enable(ARRAY_SIZE(aic3x->supplies),
aic3x->supplies);
if (ret != 0) {
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
goto err_enable;
}
if (aic3x->gpio_reset >= 0) {
udelay(1);
gpio_set_value(aic3x->gpio_reset, 1);
}
return aic3x_register(codec);
err_enable:
regulator_bulk_free(ARRAY_SIZE(aic3x->supplies), aic3x->supplies);
err_get:
if (aic3x->gpio_reset >= 0)
gpio_free(aic3x->gpio_reset);
err_gpio:
kfree(aic3x);
return ret;
}
static int aic3x_i2c_remove(struct i2c_client *client)
......
此差异已折叠。
......@@ -36,24 +36,14 @@
static struct i2c_client *tpa6130a2_client;
#define TPA6130A2_NUM_SUPPLIES 2
static const char *tpa6130a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
"CPVSS",
"Vdd",
};
static const char *tpa6140a2_supply_names[TPA6130A2_NUM_SUPPLIES] = {
"HPVdd",
"AVdd",
};
/* This struct is used to save the context */
struct tpa6130a2_data {
struct mutex mutex;
unsigned char regs[TPA6130A2_CACHEREGNUM];
struct regulator_bulk_data supplies[TPA6130A2_NUM_SUPPLIES];
struct regulator *supply;
int power_gpio;
unsigned char power_state;
enum tpa_model id;
};
static int tpa6130a2_i2c_read(int reg)
......@@ -135,11 +125,10 @@ static int tpa6130a2_power(int power)
if (data->power_gpio >= 0)
gpio_set_value(data->power_gpio, 1);
ret = regulator_bulk_enable(ARRAY_SIZE(data->supplies),
data->supplies);
ret = regulator_enable(data->supply);
if (ret != 0) {
dev_err(&tpa6130a2_client->dev,
"Failed to enable supplies: %d\n", ret);
"Failed to enable supply: %d\n", ret);
goto exit;
}
......@@ -160,11 +149,10 @@ static int tpa6130a2_power(int power)
if (data->power_gpio >= 0)
gpio_set_value(data->power_gpio, 0);
ret = regulator_bulk_disable(ARRAY_SIZE(data->supplies),
data->supplies);
ret = regulator_disable(data->supply);
if (ret != 0) {
dev_err(&tpa6130a2_client->dev,
"Failed to disable supplies: %d\n", ret);
"Failed to disable supply: %d\n", ret);
goto exit;
}
......@@ -176,7 +164,7 @@ static int tpa6130a2_power(int power)
return ret;
}
static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
static int tpa6130a2_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
......@@ -184,7 +172,8 @@ static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
struct tpa6130a2_data *data;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int mask = mc->max;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
BUG_ON(tpa6130a2_client == NULL);
......@@ -197,13 +186,13 @@ static int tpa6130a2_get_reg(struct snd_kcontrol *kcontrol,
if (invert)
ucontrol->value.integer.value[0] =
mask - ucontrol->value.integer.value[0];
max - ucontrol->value.integer.value[0];
mutex_unlock(&data->mutex);
return 0;
}
static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
static int tpa6130a2_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct soc_mixer_control *mc =
......@@ -211,7 +200,8 @@ static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
struct tpa6130a2_data *data;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int mask = mc->max;
int max = mc->max;
unsigned int mask = (1 << fls(max)) - 1;
unsigned int invert = mc->invert;
unsigned int val = (ucontrol->value.integer.value[0] & mask);
unsigned int val_reg;
......@@ -220,7 +210,7 @@ static int tpa6130a2_set_reg(struct snd_kcontrol *kcontrol,
data = i2c_get_clientdata(tpa6130a2_client);
if (invert)
val = mask - val;
val = max - val;
mutex_lock(&data->mutex);
......@@ -260,10 +250,24 @@ static const unsigned int tpa6130_tlv[] = {
static const struct snd_kcontrol_new tpa6130a2_controls[] = {
SOC_SINGLE_EXT_TLV("TPA6130A2 Headphone Playback Volume",
TPA6130A2_REG_VOL_MUTE, 0, 0x3f, 0,
tpa6130a2_get_reg, tpa6130a2_set_reg,
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
tpa6130_tlv),
};
static const unsigned int tpa6140_tlv[] = {
TLV_DB_RANGE_HEAD(3),
0, 8, TLV_DB_SCALE_ITEM(-5900, 400, 0),
9, 16, TLV_DB_SCALE_ITEM(-2500, 200, 0),
17, 31, TLV_DB_SCALE_ITEM(-1000, 100, 0),
};
static const struct snd_kcontrol_new tpa6140a2_controls[] = {
SOC_SINGLE_EXT_TLV("TPA6140A2 Headphone Playback Volume",
TPA6130A2_REG_VOL_MUTE, 1, 0x1f, 0,
tpa6130a2_get_volsw, tpa6130a2_put_volsw,
tpa6140_tlv),
};
/*
* Enable or disable channel (left or right)
* The bit number for mute and amplifier are the same per channel:
......@@ -355,8 +359,8 @@ static const struct snd_soc_dapm_widget tpa6130a2_dapm_widgets[] = {
0, 0, tpa6130a2_supply_event,
SND_SOC_DAPM_POST_PMU|SND_SOC_DAPM_POST_PMD),
/* Outputs */
SND_SOC_DAPM_HP("TPA6130A2 Headphone Left", NULL),
SND_SOC_DAPM_HP("TPA6130A2 Headphone Right", NULL),
SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Left"),
SND_SOC_DAPM_OUTPUT("TPA6130A2 Headphone Right"),
};
static const struct snd_soc_dapm_route audio_map[] = {
......@@ -369,13 +373,22 @@ static const struct snd_soc_dapm_route audio_map[] = {
int tpa6130a2_add_controls(struct snd_soc_codec *codec)
{
struct tpa6130a2_data *data;
BUG_ON(tpa6130a2_client == NULL);
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));
return snd_soc_add_controls(codec, tpa6130a2_controls,
ARRAY_SIZE(tpa6130a2_controls));
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);
......@@ -386,7 +399,8 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
struct device *dev;
struct tpa6130a2_data *data;
struct tpa6130a2_platform_data *pdata;
int i, ret;
const char *regulator;
int ret;
dev = &client->dev;
......@@ -408,6 +422,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
pdata = client->dev.platform_data;
data->power_gpio = pdata->power_gpio;
data->id = pdata->id;
mutex_init(&data->mutex);
......@@ -426,26 +441,22 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
gpio_direction_output(data->power_gpio, 0);
}
switch (pdata->id) {
switch (data->id) {
default:
dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
pdata->id);
case TPA6130A2:
for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
data->supplies[i].supply = tpa6130a2_supply_names[i];
regulator = "Vdd";
break;
case TPA6140A2:
for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
data->supplies[i].supply = tpa6140a2_supply_names[i];;
regulator = "AVdd";
break;
default:
dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
pdata->id);
for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
data->supplies[i].supply = tpa6130a2_supply_names[i];
}
ret = regulator_bulk_get(dev, ARRAY_SIZE(data->supplies),
data->supplies);
if (ret != 0) {
dev_err(dev, "Failed to request supplies: %d\n", ret);
data->supply = regulator_get(dev, regulator);
if (IS_ERR(data->supply)) {
ret = PTR_ERR(data->supply);
dev_err(dev, "Failed to request supply: %d\n", ret);
goto err_regulator;
}
......@@ -468,7 +479,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
return 0;
err_power:
regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies);
regulator_put(data->supply);
err_regulator:
if (data->power_gpio >= 0)
gpio_free(data->power_gpio);
......@@ -489,7 +500,7 @@ static int __devexit tpa6130a2_remove(struct i2c_client *client)
if (data->power_gpio >= 0)
gpio_free(data->power_gpio);
regulator_bulk_free(ARRAY_SIZE(data->supplies), data->supplies);
regulator_put(data->supply);
kfree(data);
tpa6130a2_client = NULL;
......
此差异已折叠。
此差异已折叠。
/*
* ALSA SoC TWL6040 codec driver
*
* Author: Misael Lopez Cruz <x0052729@ti.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.
*
* 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
*
*/
#ifndef __TWL6040_H__
#define __TWL6040_H__
#define TWL6040_REG_ASICID 0x01
#define TWL6040_REG_ASICREV 0x02
#define TWL6040_REG_INTID 0x03
#define TWL6040_REG_INTMR 0x04
#define TWL6040_REG_NCPCTL 0x05
#define TWL6040_REG_LDOCTL 0x06
#define TWL6040_REG_HPPLLCTL 0x07
#define TWL6040_REG_LPPLLCTL 0x08
#define TWL6040_REG_LPPLLDIV 0x09
#define TWL6040_REG_AMICBCTL 0x0A
#define TWL6040_REG_DMICBCTL 0x0B
#define TWL6040_REG_MICLCTL 0x0C
#define TWL6040_REG_MICRCTL 0x0D
#define TWL6040_REG_MICGAIN 0x0E
#define TWL6040_REG_LINEGAIN 0x0F
#define TWL6040_REG_HSLCTL 0x10
#define TWL6040_REG_HSRCTL 0x11
#define TWL6040_REG_HSGAIN 0x12
#define TWL6040_REG_EARCTL 0x13
#define TWL6040_REG_HFLCTL 0x14
#define TWL6040_REG_HFLGAIN 0x15
#define TWL6040_REG_HFRCTL 0x16
#define TWL6040_REG_HFRGAIN 0x17
#define TWL6040_REG_VIBCTLL 0x18
#define TWL6040_REG_VIBDATL 0x19
#define TWL6040_REG_VIBCTLR 0x1A
#define TWL6040_REG_VIBDATR 0x1B
#define TWL6040_REG_HKCTL1 0x1C
#define TWL6040_REG_HKCTL2 0x1D
#define TWL6040_REG_GPOCTL 0x1E
#define TWL6040_REG_ALB 0x1F
#define TWL6040_REG_DLB 0x20
#define TWL6040_REG_TRIM1 0x28
#define TWL6040_REG_TRIM2 0x29
#define TWL6040_REG_TRIM3 0x2A
#define TWL6040_REG_HSOTRIM 0x2B
#define TWL6040_REG_HFOTRIM 0x2C
#define TWL6040_REG_ACCCTL 0x2D
#define TWL6040_REG_STATUS 0x2E
#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
#define TWL6040_VIOREGNUM 18
#define TWL6040_VDDREGNUM 21
/* INTID (0x03) fields */
#define TWL6040_THINT 0x01
#define TWL6040_PLUGINT 0x02
#define TWL6040_UNPLUGINT 0x04
#define TWL6040_HOOKINT 0x08
#define TWL6040_HFINT 0x10
#define TWL6040_VIBINT 0x20
#define TWL6040_READYINT 0x40
/* INTMR (0x04) fields */
#define TWL6040_READYMSK 0x40
#define TWL6040_ALLINT_MSK 0x7B
/* NCPCTL (0x05) fields */
#define TWL6040_NCPENA 0x01
#define TWL6040_NCPOPEN 0x40
/* LDOCTL (0x06) fields */
#define TWL6040_LSLDOENA 0x01
#define TWL6040_HSLDOENA 0x04
#define TWL6040_REFENA 0x40
#define TWL6040_OSCENA 0x80
/* HPPLLCTL (0x07) fields */
#define TWL6040_HPLLENA 0x01
#define TWL6040_HPLLRST 0x02
#define TWL6040_HPLLBP 0x04
#define TWL6040_HPLLSQRENA 0x08
#define TWL6040_HPLLSQRBP 0x10
#define TWL6040_MCLK_12000KHZ (0 << 5)
#define TWL6040_MCLK_19200KHZ (1 << 5)
#define TWL6040_MCLK_26000KHZ (2 << 5)
#define TWL6040_MCLK_38400KHZ (3 << 5)
#define TWL6040_MCLK_MSK 0x60
/* LPPLLCTL (0x08) fields */
#define TWL6040_LPLLENA 0x01
#define TWL6040_LPLLRST 0x02
#define TWL6040_LPLLSEL 0x04
#define TWL6040_LPLLFIN 0x08
#define TWL6040_HPLLSEL 0x10
/* HSLCTL (0x10) fields */
#define TWL6040_HSDACMODEL 0x02
#define TWL6040_HSDRVMODEL 0x08
/* HSRCTL (0x11) fields */
#define TWL6040_HSDACMODER 0x02
#define TWL6040_HSDRVMODER 0x08
/* ACCCTL (0x2D) fields */
#define TWL6040_RESETSPLIT 0x04
#define TWL6040_SYSCLK_SEL_LPPLL 1
#define TWL6040_SYSCLK_SEL_HPPLL 2
#define TWL6040_HPPLL_ID 1
#define TWL6040_LPPLL_ID 2
extern struct snd_soc_dai twl6040_dai;
extern struct snd_soc_codec_device soc_codec_dev_twl6040;
#endif /* End of __TWL6040_H__ */
......@@ -175,7 +175,7 @@ static int uda134x_startup(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct uda134x_priv *uda134x = codec->private_data;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
struct snd_pcm_runtime *master_runtime;
if (uda134x->master_substream) {
......@@ -208,7 +208,7 @@ static void uda134x_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct uda134x_priv *uda134x = codec->private_data;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
if (uda134x->master_substream == substream)
uda134x->master_substream = uda134x->slave_substream;
......@@ -223,7 +223,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct uda134x_priv *uda134x = codec->private_data;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
u8 hw_params;
if (substream == uda134x->slave_substream) {
......@@ -295,7 +295,7 @@ static int uda134x_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 uda134x_priv *uda134x = codec->private_data;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
pr_debug("%s clk_id: %d, freq: %u, dir: %d\n", __func__,
clk_id, freq, dir);
......@@ -317,7 +317,7 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
struct snd_soc_codec *codec = codec_dai->codec;
struct uda134x_priv *uda134x = codec->private_data;
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
pr_debug("%s fmt: %08X\n", __func__, fmt);
......@@ -432,6 +432,14 @@ SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
};
static const struct snd_kcontrol_new uda1345_snd_controls[] = {
SOC_SINGLE("Master Playback Volume", UDA134X_DATA000, 0, 0x3F, 1),
SOC_ENUM("PCM Playback De-emphasis", uda134x_mixer_enum[1]),
SOC_SINGLE("DC Filter Enable Switch", UDA134X_STATUS0, 0, 1, 0),
};
static struct snd_soc_dai_ops uda134x_dai_ops = {
.startup = uda134x_startup,
.shutdown = uda134x_shutdown,
......@@ -487,6 +495,7 @@ static int uda134x_soc_probe(struct platform_device *pdev)
case UDA134X_UDA1340:
case UDA134X_UDA1341:
case UDA134X_UDA1344:
case UDA134X_UDA1345:
break;
default:
printk(KERN_ERR "UDA134X SoC codec: "
......@@ -504,7 +513,7 @@ static int uda134x_soc_probe(struct platform_device *pdev)
uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL);
if (uda134x == NULL)
goto priv_err;
codec->private_data = uda134x;
snd_soc_codec_set_drvdata(codec, uda134x);
codec->reg_cache = kmemdup(uda134x_reg, sizeof(uda134x_reg),
GFP_KERNEL);
......@@ -552,6 +561,10 @@ static int uda134x_soc_probe(struct platform_device *pdev)
ret = snd_soc_add_controls(codec, uda1341_snd_controls,
ARRAY_SIZE(uda1341_snd_controls));
break;
case UDA134X_UDA1345:
ret = snd_soc_add_controls(codec, uda1345_snd_controls,
ARRAY_SIZE(uda1345_snd_controls));
break;
default:
printk(KERN_ERR "%s unknown codec type: %d",
__func__, pd->model);
......@@ -568,7 +581,7 @@ static int uda134x_soc_probe(struct platform_device *pdev)
pcm_err:
kfree(codec->reg_cache);
reg_err:
kfree(codec->private_data);
kfree(snd_soc_codec_get_drvdata(codec));
priv_err:
kfree(codec);
return ret;
......@@ -586,7 +599,7 @@ static int uda134x_soc_remove(struct platform_device *pdev)
snd_soc_free_pcms(socdev);
snd_soc_dapm_free(socdev);
kfree(codec->private_data);
kfree(snd_soc_codec_get_drvdata(codec));
kfree(codec->reg_cache);
kfree(codec);
......
......@@ -476,7 +476,7 @@ static int uda1380_trigger(struct snd_pcm_substream *substream, int cmd,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct uda1380_priv *uda1380 = codec->private_data;
struct uda1380_priv *uda1380 = snd_soc_codec_get_drvdata(codec);
int mixer = uda1380_read_reg_cache(codec, UDA1380_MIXER);
switch (cmd) {
......@@ -670,7 +670,6 @@ static int uda1380_resume(struct platform_device *pdev)
codec->hw_write(codec->control_data, data, 2);
}
uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
uda1380_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
......@@ -774,7 +773,7 @@ static int uda1380_register(struct uda1380_priv *uda1380)
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = uda1380;
snd_soc_codec_set_drvdata(codec, uda1380);
codec->name = "UDA1380";
codec->owner = THIS_MODULE;
codec->read = uda1380_read_reg_cache;
......
此差异已折叠。
......@@ -25,5 +25,8 @@ enum wm8350_jack {
int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
struct snd_soc_jack *jack, int report);
int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack,
int detect_report, int short_report);
#endif
此差异已折叠。
......@@ -557,7 +557,7 @@ static int wm8510_resume(struct platform_device *pdev)
codec->hw_write(codec->control_data, data, 2);
}
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
wm8510_set_bias_level(codec, codec->suspend_bias_level);
return 0;
}
......
......@@ -138,7 +138,7 @@ static int wm8523_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
struct wm8523_priv *wm8523 = codec->private_data;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
/* The set of sample rates that can be supported depends on the
* MCLK supplied to the CODEC - enforce this.
......@@ -164,7 +164,7 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_device *socdev = rtd->socdev;
struct snd_soc_codec *codec = socdev->card->codec;
struct wm8523_priv *wm8523 = codec->private_data;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int i;
u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1);
u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2);
......@@ -211,7 +211,7 @@ static int wm8523_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 wm8523_priv *wm8523 = codec->private_data;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
unsigned int val;
int i;
......@@ -318,7 +318,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int wm8523_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm8523_priv *wm8523 = codec->private_data;
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int ret, i;
switch (level) {
......@@ -489,7 +489,7 @@ static int wm8523_register(struct wm8523_priv *wm8523,
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
codec->private_data = wm8523;
snd_soc_codec_set_drvdata(codec, wm8523);
codec->name = "WM8523";
codec->owner = THIS_MODULE;
codec->bias_level = SND_SOC_BIAS_OFF;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册