Merge branch 'topic/asoc' into for-linus
Conflicts: sound/soc/codecs/ad1938.c
This commit is contained in:
Коммит
d71f4cece4
|
@ -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
|
||||
|
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* 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 @@ err:
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,310 @@
|
|||
/*
|
||||
* 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 {
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* 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
|
|
@ -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 */
|
||||
|
|
|
@ -0,0 +1,249 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
* 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
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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";
|
||||
|
|
|
@ -1,522 +0,0 @@
|
|||
/*
|
||||
* File: sound/soc/codecs/ad1938.c
|
||||
* Author: Barry Song <Barry.Song@analog.com>
|
||||
*
|
||||
* Created: June 04 2009
|
||||
* Description: Driver for AD1938 sound chip
|
||||
*
|
||||
* Modified:
|
||||
* Copyright 2009 Analog Devices Inc.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include "ad1938.h"
|
||||
|
||||
/* codec private data */
|
||||
struct ad1938_priv {
|
||||
struct snd_soc_codec codec;
|
||||
u8 reg_cache[AD1938_NUM_REGS];
|
||||
};
|
||||
|
||||
/* ad1938 register cache & default register settings */
|
||||
static const u8 ad1938_reg[AD1938_NUM_REGS] = {
|
||||
0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *ad1938_codec;
|
||||
struct snd_soc_codec_device soc_codec_dev_ad1938;
|
||||
static int ad1938_register(struct ad1938_priv *ad1938);
|
||||
static void ad1938_unregister(struct ad1938_priv *ad1938);
|
||||
|
||||
/*
|
||||
* AD1938 volume/mute/de-emphasis etc. controls
|
||||
*/
|
||||
static const char *ad1938_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
|
||||
|
||||
static const struct soc_enum ad1938_deemp_enum =
|
||||
SOC_ENUM_SINGLE(AD1938_DAC_CTRL2, 1, 4, ad1938_deemp);
|
||||
|
||||
static const struct snd_kcontrol_new ad1938_snd_controls[] = {
|
||||
/* DAC volume control */
|
||||
SOC_DOUBLE_R("DAC1 Volume", AD1938_DAC_L1_VOL,
|
||||
AD1938_DAC_R1_VOL, 0, 0xFF, 1),
|
||||
SOC_DOUBLE_R("DAC2 Volume", AD1938_DAC_L2_VOL,
|
||||
AD1938_DAC_R2_VOL, 0, 0xFF, 1),
|
||||
SOC_DOUBLE_R("DAC3 Volume", AD1938_DAC_L3_VOL,
|
||||
AD1938_DAC_R3_VOL, 0, 0xFF, 1),
|
||||
SOC_DOUBLE_R("DAC4 Volume", AD1938_DAC_L4_VOL,
|
||||
AD1938_DAC_R4_VOL, 0, 0xFF, 1),
|
||||
|
||||
/* ADC switch control */
|
||||
SOC_DOUBLE("ADC1 Switch", AD1938_ADC_CTRL0, AD1938_ADCL1_MUTE,
|
||||
AD1938_ADCR1_MUTE, 1, 1),
|
||||
SOC_DOUBLE("ADC2 Switch", AD1938_ADC_CTRL0, AD1938_ADCL2_MUTE,
|
||||
AD1938_ADCR2_MUTE, 1, 1),
|
||||
|
||||
/* DAC switch control */
|
||||
SOC_DOUBLE("DAC1 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL1_MUTE,
|
||||
AD1938_DACR1_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC2 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL2_MUTE,
|
||||
AD1938_DACR2_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC3 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL3_MUTE,
|
||||
AD1938_DACR3_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC4 Switch", AD1938_DAC_CHNL_MUTE, AD1938_DACL4_MUTE,
|
||||
AD1938_DACR4_MUTE, 1, 1),
|
||||
|
||||
/* ADC high-pass filter */
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", AD1938_ADC_CTRL0,
|
||||
AD1938_ADC_HIGHPASS_FILTER, 1, 0),
|
||||
|
||||
/* DAC de-emphasis */
|
||||
SOC_ENUM("Playback Deemphasis", ad1938_deemp_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad1938_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", AD1938_DAC_CTRL0, 0, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL_PWR", AD1938_PLL_CLK_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD1938_ADC_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC4OUT"),
|
||||
SND_SOC_DAPM_INPUT("ADC1IN"),
|
||||
SND_SOC_DAPM_INPUT("ADC2IN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_paths[] = {
|
||||
{ "DAC", NULL, "PLL_PWR" },
|
||||
{ "ADC", NULL, "PLL_PWR" },
|
||||
{ "DAC", NULL, "ADC_PWR" },
|
||||
{ "ADC", NULL, "ADC_PWR" },
|
||||
{ "DAC1OUT", "DAC1 Switch", "DAC" },
|
||||
{ "DAC2OUT", "DAC2 Switch", "DAC" },
|
||||
{ "DAC3OUT", "DAC3 Switch", "DAC" },
|
||||
{ "DAC4OUT", "DAC4 Switch", "DAC" },
|
||||
{ "ADC", "ADC1 Switch", "ADC1IN" },
|
||||
{ "ADC", "ADC2 Switch", "ADC2IN" },
|
||||
};
|
||||
|
||||
/*
|
||||
* DAI ops entries
|
||||
*/
|
||||
|
||||
static int ad1938_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int reg;
|
||||
|
||||
reg = snd_soc_read(codec, AD1938_DAC_CTRL2);
|
||||
reg = (mute > 0) ? reg | AD1938_DAC_MASTER_MUTE : reg &
|
||||
(~AD1938_DAC_MASTER_MUTE);
|
||||
snd_soc_write(codec, AD1938_DAC_CTRL2, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad1938_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots, int width)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);
|
||||
int adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);
|
||||
|
||||
dac_reg &= ~AD1938_DAC_CHAN_MASK;
|
||||
adc_reg &= ~AD1938_ADC_CHAN_MASK;
|
||||
|
||||
switch (slots) {
|
||||
case 2:
|
||||
dac_reg |= AD1938_DAC_2_CHANNELS << AD1938_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD1938_ADC_2_CHANNELS << AD1938_ADC_CHAN_SHFT;
|
||||
break;
|
||||
case 4:
|
||||
dac_reg |= AD1938_DAC_4_CHANNELS << AD1938_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD1938_ADC_4_CHANNELS << AD1938_ADC_CHAN_SHFT;
|
||||
break;
|
||||
case 8:
|
||||
dac_reg |= AD1938_DAC_8_CHANNELS << AD1938_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD1938_ADC_8_CHANNELS << AD1938_ADC_CHAN_SHFT;
|
||||
break;
|
||||
case 16:
|
||||
dac_reg |= AD1938_DAC_16_CHANNELS << AD1938_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD1938_ADC_16_CHANNELS << AD1938_ADC_CHAN_SHFT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);
|
||||
snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad1938_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
int adc_reg, dac_reg;
|
||||
|
||||
adc_reg = snd_soc_read(codec, AD1938_ADC_CTRL2);
|
||||
dac_reg = snd_soc_read(codec, AD1938_DAC_CTRL1);
|
||||
|
||||
/* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
|
||||
* with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
|
||||
*/
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
adc_reg &= ~AD1938_ADC_SERFMT_MASK;
|
||||
adc_reg |= AD1938_ADC_SERFMT_TDM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
adc_reg &= ~AD1938_ADC_SERFMT_MASK;
|
||||
adc_reg |= AD1938_ADC_SERFMT_AUX;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
|
||||
adc_reg &= ~AD1938_ADC_LEFT_HIGH;
|
||||
adc_reg &= ~AD1938_ADC_BCLK_INV;
|
||||
dac_reg &= ~AD1938_DAC_LEFT_HIGH;
|
||||
dac_reg &= ~AD1938_DAC_BCLK_INV;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
|
||||
adc_reg |= AD1938_ADC_LEFT_HIGH;
|
||||
adc_reg &= ~AD1938_ADC_BCLK_INV;
|
||||
dac_reg |= AD1938_DAC_LEFT_HIGH;
|
||||
dac_reg &= ~AD1938_DAC_BCLK_INV;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
|
||||
adc_reg &= ~AD1938_ADC_LEFT_HIGH;
|
||||
adc_reg |= AD1938_ADC_BCLK_INV;
|
||||
dac_reg &= ~AD1938_DAC_LEFT_HIGH;
|
||||
dac_reg |= AD1938_DAC_BCLK_INV;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
|
||||
adc_reg |= AD1938_ADC_LEFT_HIGH;
|
||||
adc_reg |= AD1938_ADC_BCLK_INV;
|
||||
dac_reg |= AD1938_DAC_LEFT_HIGH;
|
||||
dac_reg |= AD1938_DAC_BCLK_INV;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
|
||||
adc_reg |= AD1938_ADC_LCR_MASTER;
|
||||
adc_reg |= AD1938_ADC_BCLK_MASTER;
|
||||
dac_reg |= AD1938_DAC_LCR_MASTER;
|
||||
dac_reg |= AD1938_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
|
||||
adc_reg |= AD1938_ADC_LCR_MASTER;
|
||||
adc_reg &= ~AD1938_ADC_BCLK_MASTER;
|
||||
dac_reg |= AD1938_DAC_LCR_MASTER;
|
||||
dac_reg &= ~AD1938_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
|
||||
adc_reg &= ~AD1938_ADC_LCR_MASTER;
|
||||
adc_reg |= AD1938_ADC_BCLK_MASTER;
|
||||
dac_reg &= ~AD1938_DAC_LCR_MASTER;
|
||||
dac_reg |= AD1938_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
|
||||
adc_reg &= ~AD1938_ADC_LCR_MASTER;
|
||||
adc_reg &= ~AD1938_ADC_BCLK_MASTER;
|
||||
dac_reg &= ~AD1938_DAC_LCR_MASTER;
|
||||
dac_reg &= ~AD1938_DAC_BCLK_MASTER;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AD1938_ADC_CTRL2, adc_reg);
|
||||
snd_soc_write(codec, AD1938_DAC_CTRL1, dac_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad1938_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int word_len = 0, reg = 0;
|
||||
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
/* bit size */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
word_len = 3;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
word_len = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
word_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
reg = snd_soc_read(codec, AD1938_DAC_CTRL2);
|
||||
reg = (reg & (~AD1938_DAC_WORD_LEN_MASK)) | word_len;
|
||||
snd_soc_write(codec, AD1938_DAC_CTRL2, reg);
|
||||
|
||||
reg = snd_soc_read(codec, AD1938_ADC_CTRL1);
|
||||
reg = (reg & (~AD1938_ADC_WORD_LEN_MASK)) | word_len;
|
||||
snd_soc_write(codec, AD1938_ADC_CTRL1, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __devinit ad1938_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct ad1938_priv *ad1938;
|
||||
|
||||
ad1938 = kzalloc(sizeof(struct ad1938_priv), GFP_KERNEL);
|
||||
if (ad1938 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &ad1938->codec;
|
||||
codec->control_data = spi;
|
||||
codec->dev = &spi->dev;
|
||||
|
||||
dev_set_drvdata(&spi->dev, ad1938);
|
||||
|
||||
return ad1938_register(ad1938);
|
||||
}
|
||||
|
||||
static int __devexit ad1938_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct ad1938_priv *ad1938 = dev_get_drvdata(&spi->dev);
|
||||
|
||||
ad1938_unregister(ad1938);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver ad1938_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad1938",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad1938_spi_probe,
|
||||
.remove = __devexit_p(ad1938_spi_remove),
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops ad1938_dai_ops = {
|
||||
.hw_params = ad1938_hw_params,
|
||||
.digital_mute = ad1938_mute,
|
||||
.set_tdm_slot = ad1938_set_tdm_slot,
|
||||
.set_fmt = ad1938_set_dai_fmt,
|
||||
};
|
||||
|
||||
/* codec DAI instance */
|
||||
struct snd_soc_dai ad1938_dai = {
|
||||
.name = "AD1938",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &ad1938_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad1938_dai);
|
||||
|
||||
static int ad1938_register(struct ad1938_priv *ad1938)
|
||||
{
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = &ad1938->codec;
|
||||
|
||||
if (ad1938_codec) {
|
||||
dev_err(codec->dev, "Another ad1938 is registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
codec->private_data = ad1938;
|
||||
codec->reg_cache = ad1938->reg_cache;
|
||||
codec->reg_cache_size = AD1938_NUM_REGS;
|
||||
codec->name = "AD1938";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ad1938_dai;
|
||||
codec->num_dai = 1;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ad1938_dai.dev = codec->dev;
|
||||
ad1938_codec = codec;
|
||||
|
||||
memcpy(codec->reg_cache, ad1938_reg, AD1938_NUM_REGS);
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 16, 8, SND_SOC_SPI);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n",
|
||||
ret);
|
||||
kfree(ad1938);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* default setting for ad1938 */
|
||||
|
||||
/* unmute dac channels */
|
||||
snd_soc_write(codec, AD1938_DAC_CHNL_MUTE, 0x0);
|
||||
/* de-emphasis: 48kHz, powedown dac */
|
||||
snd_soc_write(codec, AD1938_DAC_CTRL2, 0x1A);
|
||||
/* powerdown dac, dac in tdm mode */
|
||||
snd_soc_write(codec, AD1938_DAC_CTRL0, 0x41);
|
||||
/* high-pass filter enable */
|
||||
snd_soc_write(codec, AD1938_ADC_CTRL0, 0x3);
|
||||
/* sata delay=1, adc aux mode */
|
||||
snd_soc_write(codec, AD1938_ADC_CTRL1, 0x43);
|
||||
/* pll input: mclki/xi */
|
||||
snd_soc_write(codec, AD1938_PLL_CLK_CTRL0, 0x9D);
|
||||
snd_soc_write(codec, AD1938_PLL_CLK_CTRL1, 0x04);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
kfree(ad1938);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&ad1938_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
kfree(ad1938);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ad1938_unregister(struct ad1938_priv *ad1938)
|
||||
{
|
||||
snd_soc_unregister_dai(&ad1938_dai);
|
||||
snd_soc_unregister_codec(&ad1938->codec);
|
||||
kfree(ad1938);
|
||||
ad1938_codec = NULL;
|
||||
}
|
||||
|
||||
static int ad1938_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
if (ad1938_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = ad1938_codec;
|
||||
codec = ad1938_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, ad1938_snd_controls,
|
||||
ARRAY_SIZE(ad1938_snd_controls));
|
||||
snd_soc_dapm_new_controls(codec, ad1938_dapm_widgets,
|
||||
ARRAY_SIZE(ad1938_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
|
||||
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ad1938_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_ad1938 = {
|
||||
.probe = ad1938_probe,
|
||||
.remove = ad1938_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ad1938);
|
||||
|
||||
static int __init ad1938_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = spi_register_driver(&ad1938_spi_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register ad1938 SPI driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
module_init(ad1938_init);
|
||||
|
||||
static void __exit ad1938_exit(void)
|
||||
{
|
||||
spi_unregister_driver(&ad1938_spi_driver);
|
||||
}
|
||||
module_exit(ad1938_exit);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad1938 driver");
|
||||
MODULE_AUTHOR("Barry Song ");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* 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
|
|
@ -0,0 +1,547 @@
|
|||
/*
|
||||
* AD193X Audio Codec driver supporting AD1936/7/8/9
|
||||
*
|
||||
* Copyright 2010 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include "ad193x.h"
|
||||
|
||||
/* codec private data */
|
||||
struct ad193x_priv {
|
||||
struct snd_soc_codec codec;
|
||||
u8 reg_cache[AD193X_NUM_REGS];
|
||||
};
|
||||
|
||||
/* ad193x register cache & default register settings */
|
||||
static const u8 ad193x_reg[AD193X_NUM_REGS] = {
|
||||
0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 0,
|
||||
};
|
||||
|
||||
static struct snd_soc_codec *ad193x_codec;
|
||||
struct snd_soc_codec_device soc_codec_dev_ad193x;
|
||||
|
||||
/*
|
||||
* AD193X volume/mute/de-emphasis etc. controls
|
||||
*/
|
||||
static const char *ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"};
|
||||
|
||||
static const struct soc_enum ad193x_deemp_enum =
|
||||
SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp);
|
||||
|
||||
static const struct snd_kcontrol_new ad193x_snd_controls[] = {
|
||||
/* DAC volume control */
|
||||
SOC_DOUBLE_R("DAC1 Volume", AD193X_DAC_L1_VOL,
|
||||
AD193X_DAC_R1_VOL, 0, 0xFF, 1),
|
||||
SOC_DOUBLE_R("DAC2 Volume", AD193X_DAC_L2_VOL,
|
||||
AD193X_DAC_R2_VOL, 0, 0xFF, 1),
|
||||
SOC_DOUBLE_R("DAC3 Volume", AD193X_DAC_L3_VOL,
|
||||
AD193X_DAC_R3_VOL, 0, 0xFF, 1),
|
||||
SOC_DOUBLE_R("DAC4 Volume", AD193X_DAC_L4_VOL,
|
||||
AD193X_DAC_R4_VOL, 0, 0xFF, 1),
|
||||
|
||||
/* ADC switch control */
|
||||
SOC_DOUBLE("ADC1 Switch", AD193X_ADC_CTRL0, AD193X_ADCL1_MUTE,
|
||||
AD193X_ADCR1_MUTE, 1, 1),
|
||||
SOC_DOUBLE("ADC2 Switch", AD193X_ADC_CTRL0, AD193X_ADCL2_MUTE,
|
||||
AD193X_ADCR2_MUTE, 1, 1),
|
||||
|
||||
/* DAC switch control */
|
||||
SOC_DOUBLE("DAC1 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL1_MUTE,
|
||||
AD193X_DACR1_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC2 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL2_MUTE,
|
||||
AD193X_DACR2_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC3 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL3_MUTE,
|
||||
AD193X_DACR3_MUTE, 1, 1),
|
||||
SOC_DOUBLE("DAC4 Switch", AD193X_DAC_CHNL_MUTE, AD193X_DACL4_MUTE,
|
||||
AD193X_DACR4_MUTE, 1, 1),
|
||||
|
||||
/* ADC high-pass filter */
|
||||
SOC_SINGLE("ADC High Pass Filter Switch", AD193X_ADC_CTRL0,
|
||||
AD193X_ADC_HIGHPASS_FILTER, 1, 0),
|
||||
|
||||
/* DAC de-emphasis */
|
||||
SOC_ENUM("Playback Deemphasis", ad193x_deemp_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1),
|
||||
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
|
||||
SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
|
||||
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
|
||||
SND_SOC_DAPM_OUTPUT("DAC4OUT"),
|
||||
SND_SOC_DAPM_INPUT("ADC1IN"),
|
||||
SND_SOC_DAPM_INPUT("ADC2IN"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_paths[] = {
|
||||
{ "DAC", NULL, "PLL_PWR" },
|
||||
{ "ADC", NULL, "PLL_PWR" },
|
||||
{ "DAC", NULL, "ADC_PWR" },
|
||||
{ "ADC", NULL, "ADC_PWR" },
|
||||
{ "DAC1OUT", "DAC1 Switch", "DAC" },
|
||||
{ "DAC2OUT", "DAC2 Switch", "DAC" },
|
||||
{ "DAC3OUT", "DAC3 Switch", "DAC" },
|
||||
{ "DAC4OUT", "DAC4 Switch", "DAC" },
|
||||
{ "ADC", "ADC1 Switch", "ADC1IN" },
|
||||
{ "ADC", "ADC2 Switch", "ADC2IN" },
|
||||
};
|
||||
|
||||
/*
|
||||
* DAI ops entries
|
||||
*/
|
||||
|
||||
static int ad193x_mute(struct snd_soc_dai *dai, int mute)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int reg;
|
||||
|
||||
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
|
||||
reg = (mute > 0) ? reg | AD193X_DAC_MASTER_MUTE : reg &
|
||||
(~AD193X_DAC_MASTER_MUTE);
|
||||
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
||||
unsigned int rx_mask, int slots, int width)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
int dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1);
|
||||
int adc_reg = snd_soc_read(codec, AD193X_ADC_CTRL2);
|
||||
|
||||
dac_reg &= ~AD193X_DAC_CHAN_MASK;
|
||||
adc_reg &= ~AD193X_ADC_CHAN_MASK;
|
||||
|
||||
switch (slots) {
|
||||
case 2:
|
||||
dac_reg |= AD193X_DAC_2_CHANNELS << AD193X_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD193X_ADC_2_CHANNELS << AD193X_ADC_CHAN_SHFT;
|
||||
break;
|
||||
case 4:
|
||||
dac_reg |= AD193X_DAC_4_CHANNELS << AD193X_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD193X_ADC_4_CHANNELS << AD193X_ADC_CHAN_SHFT;
|
||||
break;
|
||||
case 8:
|
||||
dac_reg |= AD193X_DAC_8_CHANNELS << AD193X_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD193X_ADC_8_CHANNELS << AD193X_ADC_CHAN_SHFT;
|
||||
break;
|
||||
case 16:
|
||||
dac_reg |= AD193X_DAC_16_CHANNELS << AD193X_DAC_CHAN_SHFT;
|
||||
adc_reg |= AD193X_ADC_16_CHANNELS << AD193X_ADC_CHAN_SHFT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg);
|
||||
snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
||||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
int adc_reg1, adc_reg2, dac_reg;
|
||||
|
||||
adc_reg1 = snd_soc_read(codec, AD193X_ADC_CTRL1);
|
||||
adc_reg2 = snd_soc_read(codec, AD193X_ADC_CTRL2);
|
||||
dac_reg = snd_soc_read(codec, AD193X_DAC_CTRL1);
|
||||
|
||||
/* At present, the driver only support AUX ADC mode(SND_SOC_DAIFMT_I2S
|
||||
* with TDM) and ADC&DAC TDM mode(SND_SOC_DAIFMT_DSP_A)
|
||||
*/
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
adc_reg1 &= ~AD193X_ADC_SERFMT_MASK;
|
||||
adc_reg1 |= AD193X_ADC_SERFMT_TDM;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
adc_reg1 &= ~AD193X_ADC_SERFMT_MASK;
|
||||
adc_reg1 |= AD193X_ADC_SERFMT_AUX;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF: /* normal bit clock + frame */
|
||||
adc_reg2 &= ~AD193X_ADC_LEFT_HIGH;
|
||||
adc_reg2 &= ~AD193X_ADC_BCLK_INV;
|
||||
dac_reg &= ~AD193X_DAC_LEFT_HIGH;
|
||||
dac_reg &= ~AD193X_DAC_BCLK_INV;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF: /* normal bclk + invert frm */
|
||||
adc_reg2 |= AD193X_ADC_LEFT_HIGH;
|
||||
adc_reg2 &= ~AD193X_ADC_BCLK_INV;
|
||||
dac_reg |= AD193X_DAC_LEFT_HIGH;
|
||||
dac_reg &= ~AD193X_DAC_BCLK_INV;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF: /* invert bclk + normal frm */
|
||||
adc_reg2 &= ~AD193X_ADC_LEFT_HIGH;
|
||||
adc_reg2 |= AD193X_ADC_BCLK_INV;
|
||||
dac_reg &= ~AD193X_DAC_LEFT_HIGH;
|
||||
dac_reg |= AD193X_DAC_BCLK_INV;
|
||||
break;
|
||||
|
||||
case SND_SOC_DAIFMT_IB_IF: /* invert bclk + frm */
|
||||
adc_reg2 |= AD193X_ADC_LEFT_HIGH;
|
||||
adc_reg2 |= AD193X_ADC_BCLK_INV;
|
||||
dac_reg |= AD193X_DAC_LEFT_HIGH;
|
||||
dac_reg |= AD193X_DAC_BCLK_INV;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBM_CFM: /* codec clk & frm master */
|
||||
adc_reg2 |= AD193X_ADC_LCR_MASTER;
|
||||
adc_reg2 |= AD193X_ADC_BCLK_MASTER;
|
||||
dac_reg |= AD193X_DAC_LCR_MASTER;
|
||||
dac_reg |= AD193X_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM: /* codec clk slave & frm master */
|
||||
adc_reg2 |= AD193X_ADC_LCR_MASTER;
|
||||
adc_reg2 &= ~AD193X_ADC_BCLK_MASTER;
|
||||
dac_reg |= AD193X_DAC_LCR_MASTER;
|
||||
dac_reg &= ~AD193X_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFS: /* codec clk master & frame slave */
|
||||
adc_reg2 &= ~AD193X_ADC_LCR_MASTER;
|
||||
adc_reg2 |= AD193X_ADC_BCLK_MASTER;
|
||||
dac_reg &= ~AD193X_DAC_LCR_MASTER;
|
||||
dac_reg |= AD193X_DAC_BCLK_MASTER;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFS: /* codec clk & frm slave */
|
||||
adc_reg2 &= ~AD193X_ADC_LCR_MASTER;
|
||||
adc_reg2 &= ~AD193X_ADC_BCLK_MASTER;
|
||||
dac_reg &= ~AD193X_DAC_LCR_MASTER;
|
||||
dac_reg &= ~AD193X_DAC_BCLK_MASTER;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, AD193X_ADC_CTRL1, adc_reg1);
|
||||
snd_soc_write(codec, AD193X_ADC_CTRL2, adc_reg2);
|
||||
snd_soc_write(codec, AD193X_DAC_CTRL1, dac_reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
int word_len = 0, reg = 0;
|
||||
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_device *socdev = rtd->socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
/* bit size */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
word_len = 3;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
word_len = 1;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
word_len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
reg = snd_soc_read(codec, AD193X_DAC_CTRL2);
|
||||
reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) | word_len;
|
||||
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
|
||||
|
||||
reg = snd_soc_read(codec, AD193X_ADC_CTRL1);
|
||||
reg = (reg & (~AD193X_ADC_WORD_LEN_MASK)) | word_len;
|
||||
snd_soc_write(codec, AD193X_ADC_CTRL1, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_bus_probe(struct device *dev, void *ctrl_data, int bus_type)
|
||||
{
|
||||
struct snd_soc_codec *codec;
|
||||
struct ad193x_priv *ad193x;
|
||||
int ret;
|
||||
|
||||
if (ad193x_codec) {
|
||||
dev_err(dev, "Another ad193x is registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ad193x = kzalloc(sizeof(struct ad193x_priv), GFP_KERNEL);
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_set_drvdata(dev, ad193x);
|
||||
|
||||
codec = &ad193x->codec;
|
||||
mutex_init(&codec->mutex);
|
||||
codec->control_data = ctrl_data;
|
||||
codec->dev = dev;
|
||||
snd_soc_codec_set_drvdata(codec, ad193x);
|
||||
codec->reg_cache = ad193x->reg_cache;
|
||||
codec->reg_cache_size = AD193X_NUM_REGS;
|
||||
codec->name = "AD193X";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &ad193x_dai;
|
||||
codec->num_dai = 1;
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
ad193x_dai.dev = codec->dev;
|
||||
ad193x_codec = codec;
|
||||
|
||||
memcpy(codec->reg_cache, ad193x_reg, AD193X_NUM_REGS);
|
||||
|
||||
if (bus_type == SND_SOC_I2C)
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, bus_type);
|
||||
else
|
||||
ret = snd_soc_codec_set_cache_io(codec, 16, 8, bus_type);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n",
|
||||
ret);
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* default setting for ad193x */
|
||||
|
||||
/* unmute dac channels */
|
||||
snd_soc_write(codec, AD193X_DAC_CHNL_MUTE, 0x0);
|
||||
/* de-emphasis: 48kHz, powedown dac */
|
||||
snd_soc_write(codec, AD193X_DAC_CTRL2, 0x1A);
|
||||
/* powerdown dac, dac in tdm mode */
|
||||
snd_soc_write(codec, AD193X_DAC_CTRL0, 0x41);
|
||||
/* high-pass filter enable */
|
||||
snd_soc_write(codec, AD193X_ADC_CTRL0, 0x3);
|
||||
/* sata delay=1, adc aux mode */
|
||||
snd_soc_write(codec, AD193X_ADC_CTRL1, 0x43);
|
||||
/* pll input: mclki/xi */
|
||||
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, 0x99); /* mclk=24.576Mhz: 0x9D; mclk=12.288Mhz: 0x99 */
|
||||
snd_soc_write(codec, AD193X_PLL_CLK_CTRL1, 0x04);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&ad193x_dai);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
|
||||
snd_soc_unregister_codec(codec);
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ad193x_bus_remove(struct device *dev)
|
||||
{
|
||||
struct ad193x_priv *ad193x = dev_get_drvdata(dev);
|
||||
|
||||
snd_soc_unregister_dai(&ad193x_dai);
|
||||
snd_soc_unregister_codec(&ad193x->codec);
|
||||
kfree(ad193x);
|
||||
ad193x_codec = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops ad193x_dai_ops = {
|
||||
.hw_params = ad193x_hw_params,
|
||||
.digital_mute = ad193x_mute,
|
||||
.set_tdm_slot = ad193x_set_tdm_slot,
|
||||
.set_fmt = ad193x_set_dai_fmt,
|
||||
};
|
||||
|
||||
/* codec DAI instance */
|
||||
struct snd_soc_dai ad193x_dai = {
|
||||
.name = "AD193X",
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 8,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.capture = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 4,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE |
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE,
|
||||
},
|
||||
.ops = &ad193x_dai_ops,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(ad193x_dai);
|
||||
|
||||
static int ad193x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
if (ad193x_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = ad193x_codec;
|
||||
codec = ad193x_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, ad193x_snd_controls,
|
||||
ARRAY_SIZE(ad193x_snd_controls));
|
||||
snd_soc_dapm_new_controls(codec, ad193x_dapm_widgets,
|
||||
ARRAY_SIZE(ad193x_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int ad193x_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_ad193x = {
|
||||
.probe = ad193x_probe,
|
||||
.remove = ad193x_remove,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_ad193x);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit ad193x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
return ad193x_bus_probe(&spi->dev, spi, SND_SOC_SPI);
|
||||
}
|
||||
|
||||
static int __devexit ad193x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
return ad193x_bus_remove(&spi->dev);
|
||||
}
|
||||
|
||||
static struct spi_driver ad193x_spi_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = ad193x_spi_probe,
|
||||
.remove = __devexit_p(ad193x_spi_remove),
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static const struct i2c_device_id ad193x_id[] = {
|
||||
{ "ad1936", 0 },
|
||||
{ "ad1937", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ad193x_id);
|
||||
|
||||
static int __devinit ad193x_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
return ad193x_bus_probe(&client->dev, client, SND_SOC_I2C);
|
||||
}
|
||||
|
||||
static int __devexit ad193x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
return ad193x_bus_remove(&client->dev);
|
||||
}
|
||||
|
||||
static struct i2c_driver ad193x_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "ad193x",
|
||||
},
|
||||
.probe = ad193x_i2c_probe,
|
||||
.remove = __devexit_p(ad193x_i2c_remove),
|
||||
.id_table = ad193x_id,
|
||||
};
|
||||
#endif
|
||||
|
||||
static int __init ad193x_modinit(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&ad193x_i2c_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&ad193x_spi_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
module_init(ad193x_modinit);
|
||||
|
||||
static void __exit ad193x_modexit(void)
|
||||
{
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&ad193x_spi_driver);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&ad193x_i2c_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(ad193x_modexit);
|
||||
|
||||
MODULE_DESCRIPTION("ASoC ad193x driver");
|
||||
MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
|
@ -0,0 +1,299 @@
|
|||
/*
|
||||
* 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");
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 @@ reset:
|
|||
}
|
||||
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 @@ reset_err:
|
|||
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)
|
||||
|
|
|
@ -51,6 +51,20 @@
|
|||
|
||||
#define LATENCY_TIME_MS 20
|
||||
|
||||
#define MODE7_LTHR 10
|
||||
#define MODE7_UTHR (DAC33_BUFFER_SIZE_SAMPLES - 10)
|
||||
|
||||
#define BURST_BASEFREQ_HZ 49152000
|
||||
|
||||
#define SAMPLES_TO_US(rate, samples) \
|
||||
(1000000000 / ((rate * 1000) / samples))
|
||||
|
||||
#define US_TO_SAMPLES(rate, us) \
|
||||
(rate / (1000000 / us))
|
||||
|
||||
static void dac33_calculate_times(struct snd_pcm_substream *substream);
|
||||
static int dac33_prepare_chip(struct snd_pcm_substream *substream);
|
||||
|
||||
static struct snd_soc_codec *tlv320dac33_codec;
|
||||
|
||||
enum dac33_state {
|
||||
|
@ -80,6 +94,7 @@ struct tlv320dac33_priv {
|
|||
struct work_struct work;
|
||||
struct snd_soc_codec codec;
|
||||
struct regulator_bulk_data supplies[DAC33_NUM_SUPPLIES];
|
||||
struct snd_pcm_substream *substream;
|
||||
int power_gpio;
|
||||
int chip_power;
|
||||
int irq;
|
||||
|
@ -93,6 +108,17 @@ struct tlv320dac33_priv {
|
|||
enum dac33_fifo_modes fifo_mode;/* FIFO mode selection */
|
||||
unsigned int nsample; /* burst read amount from host */
|
||||
u8 burst_bclkdiv; /* BCLK divider value in burst mode */
|
||||
unsigned int burst_rate; /* Interface speed in Burst modes */
|
||||
|
||||
int keep_bclk; /* Keep the BCLK continuously running
|
||||
* in FIFO modes */
|
||||
spinlock_t lock;
|
||||
unsigned long long t_stamp1; /* Time stamp for FIFO modes to */
|
||||
unsigned long long t_stamp2; /* calculate the FIFO caused delay */
|
||||
|
||||
unsigned int mode1_us_burst; /* Time to burst read n number of
|
||||
* samples */
|
||||
unsigned int mode7_us_to_lthr; /* Time to reach lthr from uthr */
|
||||
|
||||
enum dac33_state state;
|
||||
};
|
||||
|
@ -166,7 +192,7 @@ static inline void dac33_write_reg_cache(struct snd_soc_codec *codec,
|
|||
static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
|
||||
u8 *value)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int val;
|
||||
|
||||
*value = reg & 0xff;
|
||||
|
@ -191,7 +217,7 @@ static int dac33_read(struct snd_soc_codec *codec, unsigned int reg,
|
|||
static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 data[2];
|
||||
int ret = 0;
|
||||
|
||||
|
@ -218,7 +244,7 @@ static int dac33_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&dac33->mutex);
|
||||
|
@ -232,7 +258,7 @@ static int dac33_write_locked(struct snd_soc_codec *codec, unsigned int reg,
|
|||
static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 data[3];
|
||||
int ret = 0;
|
||||
|
||||
|
@ -262,45 +288,47 @@ static int dac33_write16(struct snd_soc_codec *codec, unsigned int reg,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void dac33_restore_regs(struct snd_soc_codec *codec)
|
||||
static void dac33_init_chip(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
u8 *cache = codec->reg_cache;
|
||||
u8 data[2];
|
||||
int i, ret;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (!dac33->chip_power)
|
||||
if (unlikely(!dac33->chip_power))
|
||||
return;
|
||||
|
||||
for (i = DAC33_PWR_CTRL; i <= DAC33_INTP_CTRL_B; i++) {
|
||||
data[0] = i;
|
||||
data[1] = cache[i];
|
||||
/* Skip the read only registers */
|
||||
if ((i >= DAC33_INT_OSC_STATUS &&
|
||||
i <= DAC33_INT_OSC_FREQ_RAT_READ_B) ||
|
||||
(i >= DAC33_FIFO_WPTR_MSB && i <= DAC33_FIFO_IRQ_FLAG) ||
|
||||
i == DAC33_DAC_STATUS_FLAGS ||
|
||||
i == DAC33_SRC_EST_REF_CLK_RATIO_A ||
|
||||
i == DAC33_SRC_EST_REF_CLK_RATIO_B)
|
||||
continue;
|
||||
ret = codec->hw_write(codec->control_data, data, 2);
|
||||
if (ret != 2)
|
||||
dev_err(codec->dev, "Write failed (%d)\n", ret);
|
||||
}
|
||||
for (i = DAC33_LDAC_PWR_CTRL; i <= DAC33_LINEL_TO_LLO_VOL; i++) {
|
||||
data[0] = i;
|
||||
data[1] = cache[i];
|
||||
ret = codec->hw_write(codec->control_data, data, 2);
|
||||
if (ret != 2)
|
||||
dev_err(codec->dev, "Write failed (%d)\n", ret);
|
||||
}
|
||||
for (i = DAC33_LINER_TO_RLO_VOL; i <= DAC33_OSC_TRIM; i++) {
|
||||
data[0] = i;
|
||||
data[1] = cache[i];
|
||||
ret = codec->hw_write(codec->control_data, data, 2);
|
||||
if (ret != 2)
|
||||
dev_err(codec->dev, "Write failed (%d)\n", ret);
|
||||
}
|
||||
/* 44-46: DAC Control Registers */
|
||||
/* A : DAC sample rate Fsref/1.5 */
|
||||
dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
|
||||
/* B : DAC src=normal, not muted */
|
||||
dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
|
||||
DAC33_DACSRCL_LEFT);
|
||||
/* C : (defaults) */
|
||||
dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);
|
||||
|
||||
/* 73 : volume soft stepping control,
|
||||
clock source = internal osc (?) */
|
||||
dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
|
||||
|
||||
dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
|
||||
|
||||
/* Restore only selected registers (gains mostly) */
|
||||
dac33_write(codec, DAC33_LDAC_DIG_VOL_CTRL,
|
||||
dac33_read_reg_cache(codec, DAC33_LDAC_DIG_VOL_CTRL));
|
||||
dac33_write(codec, DAC33_RDAC_DIG_VOL_CTRL,
|
||||
dac33_read_reg_cache(codec, DAC33_RDAC_DIG_VOL_CTRL));
|
||||
|
||||
dac33_write(codec, DAC33_LINEL_TO_LLO_VOL,
|
||||
dac33_read_reg_cache(codec, DAC33_LINEL_TO_LLO_VOL));
|
||||
dac33_write(codec, DAC33_LINER_TO_RLO_VOL,
|
||||
dac33_read_reg_cache(codec, DAC33_LINER_TO_RLO_VOL));
|
||||
}
|
||||
|
||||
static inline void dac33_read_id(struct snd_soc_codec *codec)
|
||||
{
|
||||
u8 reg;
|
||||
|
||||
dac33_read(codec, DAC33_DEVICE_ID_MSB, ®);
|
||||
dac33_read(codec, DAC33_DEVICE_ID_LSB, ®);
|
||||
dac33_read(codec, DAC33_DEVICE_REV_ID, ®);
|
||||
}
|
||||
|
||||
static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
|
||||
|
@ -311,16 +339,25 @@ static inline void dac33_soft_power(struct snd_soc_codec *codec, int power)
|
|||
if (power)
|
||||
reg |= DAC33_PDNALLB;
|
||||
else
|
||||
reg &= ~DAC33_PDNALLB;
|
||||
reg &= ~(DAC33_PDNALLB | DAC33_OSCPDNB |
|
||||
DAC33_DACRPDNB | DAC33_DACLPDNB);
|
||||
dac33_write(codec, DAC33_PWR_CTRL, reg);
|
||||
}
|
||||
|
||||
static int dac33_hard_power(struct snd_soc_codec *codec, int power)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
int ret;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&dac33->mutex);
|
||||
|
||||
/* Safety check */
|
||||
if (unlikely(power == dac33->chip_power)) {
|
||||
dev_dbg(codec->dev, "Trying to set the same power state: %s\n",
|
||||
power ? "ON" : "OFF");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (power) {
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
|
||||
dac33->supplies);
|
||||
|
@ -334,11 +371,6 @@ static int dac33_hard_power(struct snd_soc_codec *codec, int power)
|
|||
gpio_set_value(dac33->power_gpio, 1);
|
||||
|
||||
dac33->chip_power = 1;
|
||||
|
||||
/* Restore registers */
|
||||
dac33_restore_regs(codec);
|
||||
|
||||
dac33_soft_power(codec, 1);
|
||||
} else {
|
||||
dac33_soft_power(codec, 0);
|
||||
if (dac33->power_gpio >= 0)
|
||||
|
@ -360,11 +392,27 @@ exit:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int playback_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
if (likely(dac33->substream)) {
|
||||
dac33_calculate_times(dac33->substream);
|
||||
dac33_prepare_chip(dac33->substream);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_get_nsample(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = dac33->nsample;
|
||||
|
||||
|
@ -375,17 +423,21 @@ static int dac33_set_nsample(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
if (dac33->nsample == ucontrol->value.integer.value[0])
|
||||
return 0;
|
||||
|
||||
if (ucontrol->value.integer.value[0] < dac33->nsample_min ||
|
||||
ucontrol->value.integer.value[0] > dac33->nsample_max)
|
||||
ucontrol->value.integer.value[0] > dac33->nsample_max) {
|
||||
ret = -EINVAL;
|
||||
else
|
||||
} else {
|
||||
dac33->nsample = ucontrol->value.integer.value[0];
|
||||
/* Re calculate the burst time */
|
||||
dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
|
||||
dac33->nsample);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -394,7 +446,7 @@ static int dac33_get_fifo_mode(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.integer.value[0] = dac33->fifo_mode;
|
||||
|
||||
|
@ -405,7 +457,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
if (dac33->fifo_mode == ucontrol->value.integer.value[0])
|
||||
|
@ -485,6 +537,8 @@ static const struct snd_soc_dapm_widget dac33_dapm_widgets[] = {
|
|||
DAC33_OUT_AMP_PWR_CTRL, 6, 3, 3, 0),
|
||||
SND_SOC_DAPM_REG(snd_soc_dapm_mixer, "Output Right Amp Power",
|
||||
DAC33_OUT_AMP_PWR_CTRL, 4, 3, 3, 0),
|
||||
|
||||
SND_SOC_DAPM_PRE("Prepare Playback", playback_event),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map[] = {
|
||||
|
@ -527,18 +581,21 @@ static int dac33_set_bias_level(struct snd_soc_codec *codec,
|
|||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
/* Coming from OFF, switch on the codec */
|
||||
ret = dac33_hard_power(codec, 1);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
dac33_soft_power(codec, 0);
|
||||
dac33_init_chip(codec);
|
||||
}
|
||||
break;
|
||||
case SND_SOC_BIAS_OFF:
|
||||
/* Do not power off, when the codec is already off */
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF)
|
||||
return 0;
|
||||
ret = dac33_hard_power(codec, 0);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
break;
|
||||
}
|
||||
codec->bias_level = level;
|
||||
|
@ -555,13 +612,34 @@ static inline void dac33_prefill_handler(struct tlv320dac33_priv *dac33)
|
|||
switch (dac33->fifo_mode) {
|
||||
case DAC33_FIFO_MODE1:
|
||||
dac33_write16(codec, DAC33_NSAMPLE_MSB,
|
||||
DAC33_THRREG(dac33->nsample));
|
||||
DAC33_THRREG(dac33->nsample + dac33->alarm_threshold));
|
||||
|
||||
/* Take the timestamps */
|
||||
spin_lock_irq(&dac33->lock);
|
||||
dac33->t_stamp2 = ktime_to_us(ktime_get());
|
||||
dac33->t_stamp1 = dac33->t_stamp2;
|
||||
spin_unlock_irq(&dac33->lock);
|
||||
|
||||
dac33_write16(codec, DAC33_PREFILL_MSB,
|
||||
DAC33_THRREG(dac33->alarm_threshold));
|
||||
/* Enable Alarm Threshold IRQ with a delay */
|
||||
udelay(SAMPLES_TO_US(dac33->burst_rate,
|
||||
dac33->alarm_threshold));
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
|
||||
break;
|
||||
case DAC33_FIFO_MODE7:
|
||||
/* Take the timestamp */
|
||||
spin_lock_irq(&dac33->lock);
|
||||
dac33->t_stamp1 = ktime_to_us(ktime_get());
|
||||
/* Move back the timestamp with drain time */
|
||||
dac33->t_stamp1 -= dac33->mode7_us_to_lthr;
|
||||
spin_unlock_irq(&dac33->lock);
|
||||
|
||||
dac33_write16(codec, DAC33_PREFILL_MSB,
|
||||
DAC33_THRREG(10));
|
||||
DAC33_THRREG(MODE7_LTHR));
|
||||
|
||||
/* Enable Upper Threshold IRQ */
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MUT);
|
||||
break;
|
||||
default:
|
||||
dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
|
||||
|
@ -578,6 +656,11 @@ static inline void dac33_playback_handler(struct tlv320dac33_priv *dac33)
|
|||
|
||||
switch (dac33->fifo_mode) {
|
||||
case DAC33_FIFO_MODE1:
|
||||
/* Take the timestamp */
|
||||
spin_lock_irq(&dac33->lock);
|
||||
dac33->t_stamp2 = ktime_to_us(ktime_get());
|
||||
spin_unlock_irq(&dac33->lock);
|
||||
|
||||
dac33_write16(codec, DAC33_NSAMPLE_MSB,
|
||||
DAC33_THRREG(dac33->nsample));
|
||||
break;
|
||||
|
@ -628,33 +711,19 @@ static void dac33_work(struct work_struct *work)
|
|||
static irqreturn_t dac33_interrupt_handler(int irq, void *dev)
|
||||
{
|
||||
struct snd_soc_codec *codec = dev;
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
queue_work(dac33->dac33_wq, &dac33->work);
|
||||
spin_lock(&dac33->lock);
|
||||
dac33->t_stamp1 = ktime_to_us(ktime_get());
|
||||
spin_unlock(&dac33->lock);
|
||||
|
||||
/* Do not schedule the workqueue in Mode7 */
|
||||
if (dac33->fifo_mode != DAC33_FIFO_MODE7)
|
||||
queue_work(dac33->dac33_wq, &dac33->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dac33_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
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 tlv320dac33_priv *dac33 = codec->private_data;
|
||||
unsigned int pwr_ctrl;
|
||||
|
||||
/* Stop pending workqueue */
|
||||
if (dac33->fifo_mode)
|
||||
cancel_work_sync(&dac33->work);
|
||||
|
||||
mutex_lock(&dac33->mutex);
|
||||
pwr_ctrl = dac33_read_reg_cache(codec, DAC33_PWR_CTRL);
|
||||
pwr_ctrl &= ~(DAC33_OSCPDNB | DAC33_DACRPDNB | DAC33_DACLPDNB);
|
||||
dac33_write(codec, DAC33_PWR_CTRL, pwr_ctrl);
|
||||
mutex_unlock(&dac33->mutex);
|
||||
}
|
||||
|
||||
static void dac33_oscwait(struct snd_soc_codec *codec)
|
||||
{
|
||||
int timeout = 20;
|
||||
|
@ -669,6 +738,31 @@ static void dac33_oscwait(struct snd_soc_codec *codec)
|
|||
"internal oscillator calibration failed\n");
|
||||
}
|
||||
|
||||
static int dac33_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
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 tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Stream started, save the substream pointer */
|
||||
dac33->substream = substream;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dac33_shutdown(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
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 tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
dac33->substream = NULL;
|
||||
}
|
||||
|
||||
static int dac33_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
|
@ -715,7 +809,7 @@ static int dac33_prepare_chip(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 tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int oscset, ratioset, pwr_ctrl, reg_tmp;
|
||||
u8 aictrl_a, aictrl_b, fifoctrl_a;
|
||||
|
||||
|
@ -752,6 +846,17 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
|||
}
|
||||
|
||||
mutex_lock(&dac33->mutex);
|
||||
|
||||
if (!dac33->chip_power) {
|
||||
/*
|
||||
* Chip is not powered yet.
|
||||
* Do the init in the dac33_set_bias_level later.
|
||||
*/
|
||||
mutex_unlock(&dac33->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
dac33_soft_power(codec, 0);
|
||||
dac33_soft_power(codec, 1);
|
||||
|
||||
reg_tmp = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
|
||||
|
@ -799,11 +904,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
|||
case DAC33_FIFO_MODE1:
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MODE_B,
|
||||
DAC33_ATM(DAC33_FIFO_IRQ_MODE_LEVEL));
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MASK, DAC33_MAT);
|
||||
break;
|
||||
case DAC33_FIFO_MODE7:
|
||||
/* Disable all interrupts */
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MASK, 0);
|
||||
dac33_write(codec, DAC33_FIFO_IRQ_MODE_A,
|
||||
DAC33_UTM(DAC33_FIFO_IRQ_MODE_LEVEL));
|
||||
break;
|
||||
default:
|
||||
/* in FIFO bypass mode, the interrupts are not used */
|
||||
|
@ -822,7 +926,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
|||
*/
|
||||
fifoctrl_a &= ~DAC33_FBYPAS;
|
||||
fifoctrl_a &= ~DAC33_FAUTO;
|
||||
aictrl_b &= ~DAC33_BCLKON;
|
||||
if (dac33->keep_bclk)
|
||||
aictrl_b |= DAC33_BCLKON;
|
||||
else
|
||||
aictrl_b &= ~DAC33_BCLKON;
|
||||
break;
|
||||
case DAC33_FIFO_MODE7:
|
||||
/*
|
||||
|
@ -833,7 +940,10 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
|||
*/
|
||||
fifoctrl_a &= ~DAC33_FBYPAS;
|
||||
fifoctrl_a |= DAC33_FAUTO;
|
||||
aictrl_b &= ~DAC33_BCLKON;
|
||||
if (dac33->keep_bclk)
|
||||
aictrl_b |= DAC33_BCLKON;
|
||||
else
|
||||
aictrl_b &= ~DAC33_BCLKON;
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
|
@ -875,10 +985,8 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream)
|
|||
* Configure the threshold levels, and leave 10 sample space
|
||||
* at the bottom, and also at the top of the FIFO
|
||||
*/
|
||||
dac33_write16(codec, DAC33_UTHR_MSB,
|
||||
DAC33_THRREG(DAC33_BUFFER_SIZE_SAMPLES - 10));
|
||||
dac33_write16(codec, DAC33_LTHR_MSB,
|
||||
DAC33_THRREG(10));
|
||||
dac33_write16(codec, DAC33_UTHR_MSB, DAC33_THRREG(MODE7_UTHR));
|
||||
dac33_write16(codec, DAC33_LTHR_MSB, DAC33_THRREG(MODE7_LTHR));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -894,9 +1002,13 @@ static void dac33_calculate_times(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 tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int nsample_limit;
|
||||
|
||||
/* In bypass mode we don't need to calculate */
|
||||
if (!dac33->fifo_mode)
|
||||
return;
|
||||
|
||||
/* Number of samples (16bit, stereo) in one period */
|
||||
dac33->nsample_min = snd_pcm_lib_period_bytes(substream) / 4;
|
||||
|
||||
|
@ -930,15 +1042,24 @@ static void dac33_calculate_times(struct snd_pcm_substream *substream)
|
|||
|
||||
if (dac33->nsample > dac33->nsample_max)
|
||||
dac33->nsample = dac33->nsample_max;
|
||||
}
|
||||
|
||||
static int dac33_pcm_prepare(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
dac33_calculate_times(substream);
|
||||
dac33_prepare_chip(substream);
|
||||
switch (dac33->fifo_mode) {
|
||||
case DAC33_FIFO_MODE1:
|
||||
dac33->mode1_us_burst = SAMPLES_TO_US(dac33->burst_rate,
|
||||
dac33->nsample);
|
||||
dac33->t_stamp1 = 0;
|
||||
dac33->t_stamp2 = 0;
|
||||
break;
|
||||
case DAC33_FIFO_MODE7:
|
||||
dac33->mode7_us_to_lthr =
|
||||
SAMPLES_TO_US(substream->runtime->rate,
|
||||
MODE7_UTHR - MODE7_LTHR + 1);
|
||||
dac33->t_stamp1 = 0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
|
@ -947,7 +1068,7 @@ static int dac33_pcm_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 tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
switch (cmd) {
|
||||
|
@ -974,11 +1095,156 @@ static int dac33_pcm_trigger(struct snd_pcm_substream *substream, int cmd,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static snd_pcm_sframes_t dac33_dai_delay(
|
||||
struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
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 tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned long long t0, t1, t_now;
|
||||
unsigned int time_delta;
|
||||
int samples_out, samples_in, samples;
|
||||
snd_pcm_sframes_t delay = 0;
|
||||
|
||||
switch (dac33->fifo_mode) {
|
||||
case DAC33_FIFO_BYPASS:
|
||||
break;
|
||||
case DAC33_FIFO_MODE1:
|
||||
spin_lock(&dac33->lock);
|
||||
t0 = dac33->t_stamp1;
|
||||
t1 = dac33->t_stamp2;
|
||||
spin_unlock(&dac33->lock);
|
||||
t_now = ktime_to_us(ktime_get());
|
||||
|
||||
/* We have not started to fill the FIFO yet, delay is 0 */
|
||||
if (!t1)
|
||||
goto out;
|
||||
|
||||
if (t0 > t1) {
|
||||
/*
|
||||
* Phase 1:
|
||||
* After Alarm threshold, and before nSample write
|
||||
*/
|
||||
time_delta = t_now - t0;
|
||||
samples_out = time_delta ? US_TO_SAMPLES(
|
||||
substream->runtime->rate,
|
||||
time_delta) : 0;
|
||||
|
||||
if (likely(dac33->alarm_threshold > samples_out))
|
||||
delay = dac33->alarm_threshold - samples_out;
|
||||
else
|
||||
delay = 0;
|
||||
} else if ((t_now - t1) <= dac33->mode1_us_burst) {
|
||||
/*
|
||||
* Phase 2:
|
||||
* After nSample write (during burst operation)
|
||||
*/
|
||||
time_delta = t_now - t0;
|
||||
samples_out = time_delta ? US_TO_SAMPLES(
|
||||
substream->runtime->rate,
|
||||
time_delta) : 0;
|
||||
|
||||
time_delta = t_now - t1;
|
||||
samples_in = time_delta ? US_TO_SAMPLES(
|
||||
dac33->burst_rate,
|
||||
time_delta) : 0;
|
||||
|
||||
samples = dac33->alarm_threshold;
|
||||
samples += (samples_in - samples_out);
|
||||
|
||||
if (likely(samples > 0))
|
||||
delay = samples;
|
||||
else
|
||||
delay = 0;
|
||||
} else {
|
||||
/*
|
||||
* Phase 3:
|
||||
* After burst operation, before next alarm threshold
|
||||
*/
|
||||
time_delta = t_now - t0;
|
||||
samples_out = time_delta ? US_TO_SAMPLES(
|
||||
substream->runtime->rate,
|
||||
time_delta) : 0;
|
||||
|
||||
samples_in = dac33->nsample;
|
||||
samples = dac33->alarm_threshold;
|
||||
samples += (samples_in - samples_out);
|
||||
|
||||
if (likely(samples > 0))
|
||||
delay = samples > DAC33_BUFFER_SIZE_SAMPLES ?
|
||||
DAC33_BUFFER_SIZE_SAMPLES : samples;
|
||||
else
|
||||
delay = 0;
|
||||
}
|
||||
break;
|
||||
case DAC33_FIFO_MODE7:
|
||||
spin_lock(&dac33->lock);
|
||||
t0 = dac33->t_stamp1;
|
||||
spin_unlock(&dac33->lock);
|
||||
t_now = ktime_to_us(ktime_get());
|
||||
|
||||
/* We have not started to fill the FIFO yet, delay is 0 */
|
||||
if (!t0)
|
||||
goto out;
|
||||
|
||||
if (t_now <= t0) {
|
||||
/*
|
||||
* Either the timestamps are messed or equal. Report
|
||||
* maximum delay
|
||||
*/
|
||||
delay = MODE7_UTHR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
time_delta = t_now - t0;
|
||||
if (time_delta <= dac33->mode7_us_to_lthr) {
|
||||
/*
|
||||
* Phase 1:
|
||||
* After burst (draining phase)
|
||||
*/
|
||||
samples_out = US_TO_SAMPLES(
|
||||
substream->runtime->rate,
|
||||
time_delta);
|
||||
|
||||
if (likely(MODE7_UTHR > samples_out))
|
||||
delay = MODE7_UTHR - samples_out;
|
||||
else
|
||||
delay = 0;
|
||||
} else {
|
||||
/*
|
||||
* Phase 2:
|
||||
* During burst operation
|
||||
*/
|
||||
time_delta = time_delta - dac33->mode7_us_to_lthr;
|
||||
|
||||
samples_out = US_TO_SAMPLES(
|
||||
substream->runtime->rate,
|
||||
time_delta);
|
||||
samples_in = US_TO_SAMPLES(
|
||||
dac33->burst_rate,
|
||||
time_delta);
|
||||
delay = MODE7_LTHR + samples_in - samples_out;
|
||||
|
||||
if (unlikely(delay > MODE7_UTHR))
|
||||
delay = MODE7_UTHR;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dev_warn(codec->dev, "Unhandled FIFO mode: %d\n",
|
||||
dac33->fifo_mode);
|
||||
break;
|
||||
}
|
||||
out:
|
||||
return delay;
|
||||
}
|
||||
|
||||
static int dac33_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 tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 ioc_reg, asrcb_reg;
|
||||
|
||||
ioc_reg = dac33_read_reg_cache(codec, DAC33_INT_OSC_CTRL);
|
||||
|
@ -1008,7 +1274,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct tlv320dac33_priv *dac33 = codec->private_data;
|
||||
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 aictrl_a, aictrl_b;
|
||||
|
||||
aictrl_a = dac33_read_reg_cache(codec, DAC33_SER_AUDIOIF_CTRL_A);
|
||||
|
@ -1059,35 +1325,6 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dac33_init_chip(struct snd_soc_codec *codec)
|
||||
{
|
||||
/* 44-46: DAC Control Registers */
|
||||
/* A : DAC sample rate Fsref/1.5 */
|
||||
dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0));
|
||||
/* B : DAC src=normal, not muted */
|
||||
dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT |
|
||||
DAC33_DACSRCL_LEFT);
|
||||
/* C : (defaults) */
|
||||
dac33_write(codec, DAC33_DAC_CTRL_C, 0x00);
|
||||
|
||||
/* 64-65 : L&R DAC power control
|
||||
Line In -> OUT 1V/V Gain, DAC -> OUT 4V/V Gain*/
|
||||
dac33_write(codec, DAC33_LDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
|
||||
dac33_write(codec, DAC33_RDAC_PWR_CTRL, DAC33_LROUT_GAIN(2));
|
||||
|
||||
/* 73 : volume soft stepping control,
|
||||
clock source = internal osc (?) */
|
||||
dac33_write(codec, DAC33_ANA_VOL_SOFT_STEP_CTRL, DAC33_VOLCLKEN);
|
||||
|
||||
/* 66 : LOP/LOM Modes */
|
||||
dac33_write(codec, DAC33_OUT_AMP_CM_CTRL, 0xff);
|
||||
|
||||
/* 68 : LOM inverted from LOP */
|
||||
dac33_write(codec, DAC33_OUT_AMP_CTRL, (3<<2));
|
||||
|
||||
dac33_write(codec, DAC33_PWR_CTRL, DAC33_PDNALLB);
|
||||
}
|
||||
|
||||
static int dac33_soc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
@ -1099,12 +1336,7 @@ static int dac33_soc_probe(struct platform_device *pdev)
|
|||
|
||||
codec = tlv320dac33_codec;
|
||||
socdev->card->codec = codec;
|
||||
dac33 = codec->private_data;
|
||||
|
||||
/* Power up the codec */
|
||||
dac33_hard_power(codec, 1);
|
||||
/* Set default configuration */
|
||||
dac33_init_chip(codec);
|
||||
dac33 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
|
@ -1122,12 +1354,6 @@ static int dac33_soc_probe(struct platform_device *pdev)
|
|||
|
||||
dac33_add_widgets(codec);
|
||||
|
||||
/* power on device */
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* Bias level configuration has enabled regulator an extra time */
|
||||
regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
|
||||
|
||||
return 0;
|
||||
|
||||
pcm_err:
|
||||
|
@ -1164,7 +1390,6 @@ static int dac33_soc_resume(struct platform_device *pdev)
|
|||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
dac33_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
dac33_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1182,10 +1407,11 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_tlv320dac33);
|
|||
#define DAC33_FORMATS SNDRV_PCM_FMTBIT_S16_LE
|
||||
|
||||
static struct snd_soc_dai_ops dac33_dai_ops = {
|
||||
.startup = dac33_startup,
|
||||
.shutdown = dac33_shutdown,
|
||||
.hw_params = dac33_hw_params,
|
||||
.prepare = dac33_pcm_prepare,
|
||||
.trigger = dac33_pcm_trigger,
|
||||
.delay = dac33_dai_delay,
|
||||
.set_sysclk = dac33_set_dai_sysclk,
|
||||
.set_fmt = dac33_set_dai_fmt,
|
||||
};
|
||||
|
@ -1221,11 +1447,12 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
return -ENOMEM;
|
||||
|
||||
codec = &dac33->codec;
|
||||
codec->private_data = dac33;
|
||||
snd_soc_codec_set_drvdata(codec, dac33);
|
||||
codec->control_data = client;
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
mutex_init(&dac33->mutex);
|
||||
spin_lock_init(&dac33->lock);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
|
@ -1236,6 +1463,7 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
codec->hw_write = (hw_write_t) i2c_master_send;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = dac33_set_bias_level;
|
||||
codec->idle_bias_off = 1;
|
||||
codec->dai = &dac33_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(dac33_reg);
|
||||
|
@ -1250,8 +1478,12 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
|
||||
dac33->power_gpio = pdata->power_gpio;
|
||||
dac33->burst_bclkdiv = pdata->burst_bclkdiv;
|
||||
/* Pre calculate the burst rate */
|
||||
dac33->burst_rate = BURST_BASEFREQ_HZ / dac33->burst_bclkdiv / 32;
|
||||
dac33->keep_bclk = pdata->keep_bclk;
|
||||
dac33->irq = client->irq;
|
||||
dac33->nsample = NSAMPLE_MAX;
|
||||
dac33->nsample_max = NSAMPLE_MAX;
|
||||
/* Disable FIFO use by default */
|
||||
dac33->fifo_mode = DAC33_FIFO_BYPASS;
|
||||
|
||||
|
@ -1272,8 +1504,6 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
goto error_gpio;
|
||||
}
|
||||
gpio_direction_output(dac33->power_gpio, 0);
|
||||
} else {
|
||||
dac33->chip_power = 1;
|
||||
}
|
||||
|
||||
/* Check if the IRQ number is valid and request it */
|
||||
|
@ -1311,12 +1541,14 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
goto err_get;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(dac33->supplies),
|
||||
dac33->supplies);
|
||||
/* Read the tlv320dac33 ID registers */
|
||||
ret = dac33_hard_power(codec, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
|
||||
goto err_enable;
|
||||
dev_err(codec->dev, "Failed to power up codec: %d\n", ret);
|
||||
goto error_codec;
|
||||
}
|
||||
dac33_read_id(codec);
|
||||
dac33_hard_power(codec, 0);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
|
@ -1331,14 +1563,9 @@ static int __devinit dac33_i2c_probe(struct i2c_client *client,
|
|||
goto error_codec;
|
||||
}
|
||||
|
||||
/* Shut down the codec for now */
|
||||
dac33_hard_power(codec, 0);
|
||||
|
||||
return ret;
|
||||
|
||||
error_codec:
|
||||
regulator_bulk_disable(ARRAY_SIZE(dac33->supplies), dac33->supplies);
|
||||
err_enable:
|
||||
regulator_bulk_free(ARRAY_SIZE(dac33->supplies), dac33->supplies);
|
||||
err_get:
|
||||
if (dac33->irq >= 0) {
|
||||
|
@ -1362,7 +1589,9 @@ static int __devexit dac33_i2c_remove(struct i2c_client *client)
|
|||
struct tlv320dac33_priv *dac33;
|
||||
|
||||
dac33 = i2c_get_clientdata(client);
|
||||
dac33_hard_power(&dac33->codec, 0);
|
||||
|
||||
if (unlikely(dac33->chip_power))
|
||||
dac33_hard_power(&dac33->codec, 0);
|
||||
|
||||
if (dac33->power_gpio >= 0)
|
||||
gpio_free(dac33->power_gpio);
|
||||
|
|
|
@ -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 @@ exit:
|
|||
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) {
|
||||
case TPA6130A2:
|
||||
for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
|
||||
data->supplies[i].supply = tpa6130a2_supply_names[i];
|
||||
break;
|
||||
case TPA6140A2:
|
||||
for (i = 0; i < ARRAY_SIZE(data->supplies); i++)
|
||||
data->supplies[i].supply = tpa6140a2_supply_names[i];;
|
||||
break;
|
||||
switch (data->id) {
|
||||
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];
|
||||
case TPA6130A2:
|
||||
regulator = "Vdd";
|
||||
break;
|
||||
case TPA6140A2:
|
||||
regulator = "AVdd";
|
||||
break;
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
|
@ -124,6 +124,8 @@ struct twl4030_priv {
|
|||
struct snd_soc_codec codec;
|
||||
|
||||
unsigned int codec_powered;
|
||||
|
||||
/* reference counts of AIF/APLL users */
|
||||
unsigned int apll_enabled;
|
||||
|
||||
struct snd_pcm_substream *master_substream;
|
||||
|
@ -136,9 +138,11 @@ struct twl4030_priv {
|
|||
|
||||
unsigned int sysclk;
|
||||
|
||||
/* Headset output state handling */
|
||||
unsigned int hsl_enabled;
|
||||
unsigned int hsr_enabled;
|
||||
/* Output (with associated amp) states */
|
||||
u8 hsl_enabled, hsr_enabled;
|
||||
u8 earpiece_enabled;
|
||||
u8 predrivel_enabled, predriver_enabled;
|
||||
u8 carkitl_enabled, carkitr_enabled;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -174,17 +178,52 @@ static inline void twl4030_write_reg_cache(struct snd_soc_codec *codec,
|
|||
static int twl4030_write(struct snd_soc_codec *codec,
|
||||
unsigned int reg, unsigned int value)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
int write_to_reg = 0;
|
||||
|
||||
twl4030_write_reg_cache(codec, reg, value);
|
||||
if (likely(reg < TWL4030_REG_SW_SHADOW))
|
||||
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value,
|
||||
reg);
|
||||
else
|
||||
return 0;
|
||||
if (likely(reg < TWL4030_REG_SW_SHADOW)) {
|
||||
/* Decide if the given register can be written */
|
||||
switch (reg) {
|
||||
case TWL4030_REG_EAR_CTL:
|
||||
if (twl4030->earpiece_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDL_CTL:
|
||||
if (twl4030->predrivel_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PREDR_CTL:
|
||||
if (twl4030->predriver_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKL_CTL:
|
||||
if (twl4030->carkitl_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_PRECKR_CTL:
|
||||
if (twl4030->carkitr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
case TWL4030_REG_HS_GAIN_SET:
|
||||
if (twl4030->hsl_enabled || twl4030->hsr_enabled)
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
default:
|
||||
/* All other register can be written */
|
||||
write_to_reg = 1;
|
||||
break;
|
||||
}
|
||||
if (write_to_reg)
|
||||
return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
value, reg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void twl4030_codec_enable(struct snd_soc_codec *codec, int enable)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
int mode;
|
||||
|
||||
if (enable == twl4030->codec_powered)
|
||||
|
@ -222,28 +261,28 @@ static void twl4030_init_chip(struct snd_soc_codec *codec)
|
|||
|
||||
static void twl4030_apll_enable(struct snd_soc_codec *codec, int enable)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
int status;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
int status = -1;
|
||||
|
||||
if (enable == twl4030->apll_enabled)
|
||||
return;
|
||||
|
||||
if (enable)
|
||||
/* Enable PLL */
|
||||
status = twl4030_codec_enable_resource(TWL4030_CODEC_RES_APLL);
|
||||
else
|
||||
/* Disable PLL */
|
||||
status = twl4030_codec_disable_resource(TWL4030_CODEC_RES_APLL);
|
||||
if (enable) {
|
||||
twl4030->apll_enabled++;
|
||||
if (twl4030->apll_enabled == 1)
|
||||
status = twl4030_codec_enable_resource(
|
||||
TWL4030_CODEC_RES_APLL);
|
||||
} else {
|
||||
twl4030->apll_enabled--;
|
||||
if (!twl4030->apll_enabled)
|
||||
status = twl4030_codec_disable_resource(
|
||||
TWL4030_CODEC_RES_APLL);
|
||||
}
|
||||
|
||||
if (status >= 0)
|
||||
twl4030_write_reg_cache(codec, TWL4030_REG_APLL_CTL, status);
|
||||
|
||||
twl4030->apll_enabled = enable;
|
||||
}
|
||||
|
||||
static void twl4030_power_up(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 anamicl, regmisc1, byte;
|
||||
int i = 0;
|
||||
|
||||
|
@ -526,26 +565,26 @@ static int micpath_event(struct snd_soc_dapm_widget *w,
|
|||
* Output PGA builder:
|
||||
* Handle the muting and unmuting of the given output (turning off the
|
||||
* amplifier associated with the output pin)
|
||||
* On mute bypass the reg_cache and mute the volume
|
||||
* On unmute: restore the register content
|
||||
* On mute bypass the reg_cache and write 0 to the register
|
||||
* On unmute: restore the register content from the reg_cache
|
||||
* Outputs handled in this way: Earpiece, PreDrivL/R, CarkitL/R
|
||||
*/
|
||||
#define TWL4030_OUTPUT_PGA(pin_name, reg, mask) \
|
||||
static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \
|
||||
struct snd_kcontrol *kcontrol, int event) \
|
||||
{ \
|
||||
u8 reg_val; \
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec); \
|
||||
\
|
||||
switch (event) { \
|
||||
case SND_SOC_DAPM_POST_PMU: \
|
||||
twl4030->pin_name##_enabled = 1; \
|
||||
twl4030_write(w->codec, reg, \
|
||||
twl4030_read_reg_cache(w->codec, reg)); \
|
||||
break; \
|
||||
case SND_SOC_DAPM_POST_PMD: \
|
||||
reg_val = twl4030_read_reg_cache(w->codec, reg); \
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
|
||||
reg_val & (~mask), \
|
||||
reg); \
|
||||
twl4030->pin_name##_enabled = 0; \
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \
|
||||
0, reg); \
|
||||
break; \
|
||||
} \
|
||||
return 0; \
|
||||
|
@ -636,13 +675,38 @@ static int apll_event(struct snd_soc_dapm_widget *w,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int aif_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
u8 audio_if;
|
||||
|
||||
audio_if = twl4030_read_reg_cache(w->codec, TWL4030_REG_AUDIO_IF);
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
/* Enable AIF */
|
||||
/* enable the PLL before we use it to clock the DAI */
|
||||
twl4030_apll_enable(w->codec, 1);
|
||||
|
||||
twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
|
||||
audio_if | TWL4030_AIF_EN);
|
||||
break;
|
||||
case SND_SOC_DAPM_POST_PMD:
|
||||
/* disable the DAI before we stop it's source PLL */
|
||||
twl4030_write(w->codec, TWL4030_REG_AUDIO_IF,
|
||||
audio_if & ~TWL4030_AIF_EN);
|
||||
twl4030_apll_enable(w->codec, 0);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
||||
{
|
||||
struct snd_soc_device *socdev = codec->socdev;
|
||||
struct twl4030_setup_data *setup = socdev->codec_data;
|
||||
|
||||
unsigned char hs_gain, hs_pop;
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
/* Base values for ramp delay calculation: 2^19 - 2^26 */
|
||||
unsigned int ramp_base[] = {524288, 1048576, 2097152, 4194304,
|
||||
8388608, 16777216, 33554432, 67108864};
|
||||
|
@ -665,7 +729,10 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
|||
/* Headset ramp-up according to the TRM */
|
||||
hs_pop |= TWL4030_VMID_EN;
|
||||
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
|
||||
twl4030_write(codec, TWL4030_REG_HS_GAIN_SET, hs_gain);
|
||||
/* Actually write to the register */
|
||||
twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE,
|
||||
hs_gain,
|
||||
TWL4030_REG_HS_GAIN_SET);
|
||||
hs_pop |= TWL4030_RAMP_EN;
|
||||
twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
|
||||
/* Wait ramp delay time + 1, so the VMID can settle */
|
||||
|
@ -702,7 +769,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp)
|
|||
static int headsetlpga_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = w->codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
|
@ -726,7 +793,7 @@ static int headsetlpga_event(struct snd_soc_dapm_widget *w,
|
|||
static int headsetrpga_event(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct twl4030_priv *twl4030 = w->codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(w->codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
|
@ -918,7 +985,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
|
||||
unsigned short val;
|
||||
unsigned short mask, bitmask;
|
||||
|
@ -1036,6 +1103,16 @@ static const struct soc_enum twl4030_vibradir_enum =
|
|||
ARRAY_SIZE(twl4030_vibradir_texts),
|
||||
twl4030_vibradir_texts);
|
||||
|
||||
/* Digimic Left and right swapping */
|
||||
static const char *twl4030_digimicswap_texts[] = {
|
||||
"Not swapped", "Swapped",
|
||||
};
|
||||
|
||||
static const struct soc_enum twl4030_digimicswap_enum =
|
||||
SOC_ENUM_SINGLE(TWL4030_REG_MISC_SET_1, 0,
|
||||
ARRAY_SIZE(twl4030_digimicswap_texts),
|
||||
twl4030_digimicswap_texts);
|
||||
|
||||
static const struct snd_kcontrol_new twl4030_snd_controls[] = {
|
||||
/* Codec operation mode control */
|
||||
SOC_ENUM_EXT("Codec Operation Mode", twl4030_op_modes_enum,
|
||||
|
@ -1112,6 +1189,8 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
|
|||
|
||||
SOC_ENUM("Vibra H-bridge mode", twl4030_vibradirmode_enum),
|
||||
SOC_ENUM("Vibra H-bridge direction", twl4030_vibradir_enum),
|
||||
|
||||
SOC_ENUM("Digimic LR Swap", twl4030_digimicswap_enum),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
||||
|
@ -1128,8 +1207,6 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_INPUT("DIGIMIC1"),
|
||||
|
||||
/* Outputs */
|
||||
SND_SOC_DAPM_OUTPUT("OUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("OUTR"),
|
||||
SND_SOC_DAPM_OUTPUT("EARPIECE"),
|
||||
SND_SOC_DAPM_OUTPUT("PREDRIVEL"),
|
||||
SND_SOC_DAPM_OUTPUT("PREDRIVER"),
|
||||
|
@ -1141,6 +1218,11 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_OUTPUT("HFR"),
|
||||
SND_SOC_DAPM_OUTPUT("VIBRA"),
|
||||
|
||||
/* AIF and APLL clocks for running DAIs (including loopback) */
|
||||
SND_SOC_DAPM_OUTPUT("Virtual HiFi OUT"),
|
||||
SND_SOC_DAPM_INPUT("Virtual HiFi IN"),
|
||||
SND_SOC_DAPM_OUTPUT("Virtual Voice OUT"),
|
||||
|
||||
/* DACs */
|
||||
SND_SOC_DAPM_DAC("DAC Right1", "Right Front HiFi Playback",
|
||||
SND_SOC_NOPM, 0, 0),
|
||||
|
@ -1204,7 +1286,8 @@ static const struct snd_soc_dapm_widget twl4030_dapm_widgets[] = {
|
|||
SND_SOC_DAPM_SUPPLY("APLL Enable", SND_SOC_NOPM, 0, 0, apll_event,
|
||||
SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("AIF Enable", TWL4030_REG_AUDIO_IF, 0, 0, NULL, 0),
|
||||
SND_SOC_DAPM_SUPPLY("AIF Enable", SND_SOC_NOPM, 0, 0, aif_event,
|
||||
SND_SOC_DAPM_PRE_PMU|SND_SOC_DAPM_POST_PMD),
|
||||
|
||||
/* Output MIXER controls */
|
||||
/* Earpiece */
|
||||
|
@ -1334,10 +1417,6 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
{"Digital Voice Playback Mixer", NULL, "DAC Voice"},
|
||||
|
||||
/* Supply for the digital part (APLL) */
|
||||
{"Digital R1 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital L1 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital R2 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital L2 Playback Mixer", NULL, "APLL Enable"},
|
||||
{"Digital Voice Playback Mixer", NULL, "APLL Enable"},
|
||||
|
||||
{"Digital R1 Playback Mixer", NULL, "AIF Enable"},
|
||||
|
@ -1411,8 +1490,14 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
{"Vibra Mux", "AudioR2", "DAC Right2"},
|
||||
|
||||
/* outputs */
|
||||
{"OUTL", NULL, "Analog L2 Playback Mixer"},
|
||||
{"OUTR", NULL, "Analog R2 Playback Mixer"},
|
||||
/* Must be always connected (for AIF and APLL) */
|
||||
{"Virtual HiFi OUT", NULL, "Digital L1 Playback Mixer"},
|
||||
{"Virtual HiFi OUT", NULL, "Digital R1 Playback Mixer"},
|
||||
{"Virtual HiFi OUT", NULL, "Digital L2 Playback Mixer"},
|
||||
{"Virtual HiFi OUT", NULL, "Digital R2 Playback Mixer"},
|
||||
/* Must be always connected (for APLL) */
|
||||
{"Virtual Voice OUT", NULL, "Digital Voice Playback Mixer"},
|
||||
/* Physical outputs */
|
||||
{"EARPIECE", NULL, "Earpiece PGA"},
|
||||
{"PREDRIVEL", NULL, "PredriveL PGA"},
|
||||
{"PREDRIVER", NULL, "PredriveR PGA"},
|
||||
|
@ -1426,6 +1511,12 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
{"VIBRA", NULL, "Vibra Route"},
|
||||
|
||||
/* Capture path */
|
||||
/* Must be always connected (for AIF and APLL) */
|
||||
{"ADC Virtual Left1", NULL, "Virtual HiFi IN"},
|
||||
{"ADC Virtual Right1", NULL, "Virtual HiFi IN"},
|
||||
{"ADC Virtual Left2", NULL, "Virtual HiFi IN"},
|
||||
{"ADC Virtual Right2", NULL, "Virtual HiFi IN"},
|
||||
/* Physical inputs */
|
||||
{"Analog Left", "Main Mic Capture Switch", "MAINMIC"},
|
||||
{"Analog Left", "Headset Mic Capture Switch", "HSMIC"},
|
||||
{"Analog Left", "AUXL Capture Switch", "AUXL"},
|
||||
|
@ -1458,11 +1549,6 @@ static const struct snd_soc_dapm_route intercon[] = {
|
|||
{"ADC Virtual Left2", NULL, "TX2 Capture Route"},
|
||||
{"ADC Virtual Right2", NULL, "TX2 Capture Route"},
|
||||
|
||||
{"ADC Virtual Left1", NULL, "APLL Enable"},
|
||||
{"ADC Virtual Right1", NULL, "APLL Enable"},
|
||||
{"ADC Virtual Left2", NULL, "APLL Enable"},
|
||||
{"ADC Virtual Right2", NULL, "APLL Enable"},
|
||||
|
||||
{"ADC Virtual Left1", NULL, "AIF Enable"},
|
||||
{"ADC Virtual Right1", NULL, "AIF Enable"},
|
||||
{"ADC Virtual Left2", NULL, "AIF Enable"},
|
||||
|
@ -1588,7 +1674,7 @@ static int twl4030_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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (twl4030->master_substream) {
|
||||
twl4030->slave_substream = substream;
|
||||
|
@ -1619,7 +1705,7 @@ static void twl4030_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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (twl4030->master_substream == substream)
|
||||
twl4030->master_substream = twl4030->slave_substream;
|
||||
|
@ -1645,7 +1731,7 @@ static int twl4030_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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode, old_mode, format, old_format;
|
||||
|
||||
/* If the substream has 4 channel, do the necessary setup */
|
||||
|
@ -1765,7 +1851,7 @@ static int twl4030_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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 19200000:
|
||||
|
@ -1880,7 +1966,7 @@ static int twl4030_voice_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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
u8 mode;
|
||||
|
||||
/* If the system master clock is not 26MHz, the voice PCM interface is
|
||||
|
@ -1962,7 +2048,7 @@ static int twl4030_voice_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 twl4030_priv *twl4030 = codec->private_data;
|
||||
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (freq != 26000000) {
|
||||
dev_err(codec->dev, "Unsupported APLL mclk: %u, the Voice"
|
||||
|
@ -2108,7 +2194,6 @@ static int twl4030_soc_resume(struct platform_device *pdev)
|
|||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
twl4030_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
twl4030_set_bias_level(codec, codec->suspend_bias_level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2125,7 +2210,7 @@ static int twl4030_soc_probe(struct platform_device *pdev)
|
|||
BUG_ON(!twl4030_codec);
|
||||
|
||||
codec = twl4030_codec;
|
||||
twl4030 = codec->private_data;
|
||||
twl4030 = snd_soc_codec_get_drvdata(codec);
|
||||
socdev->card->codec = codec;
|
||||
|
||||
/* Configuration for headset ramp delay from setup data */
|
||||
|
@ -2188,7 +2273,7 @@ static int __devinit twl4030_codec_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
codec = &twl4030->codec;
|
||||
codec->private_data = twl4030;
|
||||
snd_soc_codec_set_drvdata(codec, twl4030);
|
||||
codec->dev = &pdev->dev;
|
||||
twl4030_dai[0].dev = &pdev->dev;
|
||||
twl4030_dai[1].dev = &pdev->dev;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,141 @@
|
|||
/*
|
||||
* 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;
|
||||
|
|
|
@ -55,6 +55,7 @@ struct wm8350_output {
|
|||
struct wm8350_jack_data {
|
||||
struct snd_soc_jack *jack;
|
||||
int report;
|
||||
int short_report;
|
||||
};
|
||||
|
||||
struct wm8350_data {
|
||||
|
@ -63,6 +64,7 @@ struct wm8350_data {
|
|||
struct wm8350_output out2;
|
||||
struct wm8350_jack_data hpl;
|
||||
struct wm8350_jack_data hpr;
|
||||
struct wm8350_jack_data mic;
|
||||
struct regulator_bulk_data supplies[ARRAY_SIZE(supply_names)];
|
||||
int fll_freq_out;
|
||||
int fll_freq_in;
|
||||
|
@ -94,7 +96,7 @@ static int wm8350_codec_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
*/
|
||||
static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8350_data *wm8350_data = codec->private_data;
|
||||
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_output *out1 = &wm8350_data->out1;
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
int left_complete = 0, right_complete = 0;
|
||||
|
@ -160,7 +162,7 @@ static inline int wm8350_out1_ramp_step(struct snd_soc_codec *codec)
|
|||
*/
|
||||
static inline int wm8350_out2_ramp_step(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8350_data *wm8350_data = codec->private_data;
|
||||
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_output *out2 = &wm8350_data->out2;
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
int left_complete = 0, right_complete = 0;
|
||||
|
@ -230,7 +232,7 @@ static void wm8350_pga_work(struct work_struct *work)
|
|||
{
|
||||
struct snd_soc_codec *codec =
|
||||
container_of(work, struct snd_soc_codec, delayed_work.work);
|
||||
struct wm8350_data *wm8350_data = codec->private_data;
|
||||
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_output *out1 = &wm8350_data->out1,
|
||||
*out2 = &wm8350_data->out2;
|
||||
int i, out1_complete, out2_complete;
|
||||
|
@ -277,7 +279,7 @@ static int pga_event(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm8350_data *wm8350_data = codec->private_data;
|
||||
struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_output *out;
|
||||
|
||||
switch (w->shift) {
|
||||
|
@ -322,7 +324,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8350_data *wm8350_priv = codec->private_data;
|
||||
struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_output *out = NULL;
|
||||
struct soc_mixer_control *mc =
|
||||
(struct soc_mixer_control *)kcontrol->private_value;
|
||||
|
@ -365,7 +367,7 @@ static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8350_data *wm8350_priv = codec->private_data;
|
||||
struct wm8350_data *wm8350_priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_output *out1 = &wm8350_priv->out1;
|
||||
struct wm8350_output *out2 = &wm8350_priv->out2;
|
||||
struct soc_mixer_control *mc =
|
||||
|
@ -1107,7 +1109,7 @@ static int wm8350_set_fll(struct snd_soc_dai *codec_dai,
|
|||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
struct wm8350_data *priv = codec->private_data;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct _fll_div fll_div;
|
||||
int ret = 0;
|
||||
u16 fll_1, fll_4;
|
||||
|
@ -1159,7 +1161,7 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
|
|||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
struct wm8350_data *priv = codec->private_data;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350_audio_platform_data *platform =
|
||||
wm8350->codec.platform_data;
|
||||
u16 pm1;
|
||||
|
@ -1335,9 +1337,6 @@ static int wm8350_resume(struct platform_device *pdev)
|
|||
|
||||
wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
|
||||
wm8350_set_bias_level(codec, SND_SOC_BIAS_ON);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1392,12 +1391,13 @@ static irqreturn_t wm8350_hp_jack_handler(int irq, void *data)
|
|||
* @jack: jack to report detection events on
|
||||
* @report: value to report
|
||||
*
|
||||
* Enables the headphone jack detection of the WM8350.
|
||||
* Enables the headphone jack detection of the WM8350. If no report
|
||||
* is specified then detection is disabled.
|
||||
*/
|
||||
int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
|
||||
struct snd_soc_jack *jack, int report)
|
||||
{
|
||||
struct wm8350_data *priv = codec->private_data;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
int irq;
|
||||
int ena;
|
||||
|
@ -1421,8 +1421,12 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
|
||||
wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
|
||||
if (report) {
|
||||
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
|
||||
wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena);
|
||||
} else {
|
||||
wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, ena);
|
||||
}
|
||||
|
||||
/* Sync status */
|
||||
wm8350_hp_jack_handler(irq + wm8350->irq_base, priv);
|
||||
|
@ -1431,6 +1435,60 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect);
|
||||
|
||||
static irqreturn_t wm8350_mic_handler(int irq, void *data)
|
||||
{
|
||||
struct wm8350_data *priv = data;
|
||||
struct wm8350 *wm8350 = priv->codec.control_data;
|
||||
u16 reg;
|
||||
int report = 0;
|
||||
|
||||
reg = wm8350_reg_read(wm8350, WM8350_JACK_PIN_STATUS);
|
||||
if (reg & WM8350_JACK_MICSCD_LVL)
|
||||
report |= priv->mic.short_report;
|
||||
if (reg & WM8350_JACK_MICSD_LVL)
|
||||
report |= priv->mic.report;
|
||||
|
||||
snd_soc_jack_report(priv->mic.jack, report,
|
||||
priv->mic.report | priv->mic.short_report);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* wm8350_mic_jack_detect - Enable microphone jack detection.
|
||||
*
|
||||
* @codec: WM8350 codec
|
||||
* @jack: jack to report detection events on
|
||||
* @detect_report: value to report when presence detected
|
||||
* @short_report: value to report when microphone short detected
|
||||
*
|
||||
* Enables the microphone jack detection of the WM8350. If both reports
|
||||
* are specified as zero then detection is disabled.
|
||||
*/
|
||||
int wm8350_mic_jack_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *jack,
|
||||
int detect_report, int short_report)
|
||||
{
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
|
||||
priv->mic.jack = jack;
|
||||
priv->mic.report = detect_report;
|
||||
priv->mic.short_report = short_report;
|
||||
|
||||
if (detect_report || short_report) {
|
||||
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
|
||||
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_1,
|
||||
WM8350_MIC_DET_ENA);
|
||||
} else {
|
||||
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_1,
|
||||
WM8350_MIC_DET_ENA);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm8350_mic_jack_detect);
|
||||
|
||||
static struct snd_soc_codec *wm8350_codec;
|
||||
|
||||
static int wm8350_probe(struct platform_device *pdev)
|
||||
|
@ -1448,7 +1506,7 @@ static int wm8350_probe(struct platform_device *pdev)
|
|||
socdev->card->codec = wm8350_codec;
|
||||
codec = socdev->card->codec;
|
||||
wm8350 = codec->control_data;
|
||||
priv = codec->private_data;
|
||||
priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* Enable the codec */
|
||||
wm8350_set_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
|
||||
|
@ -1494,6 +1552,10 @@ static int wm8350_probe(struct platform_device *pdev)
|
|||
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R,
|
||||
wm8350_hp_jack_handler, 0, "Right jack detect",
|
||||
priv);
|
||||
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICSCD,
|
||||
wm8350_mic_handler, 0, "Microphone short", priv);
|
||||
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
|
||||
wm8350_mic_handler, 0, "Microphone detect", priv);
|
||||
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
|
@ -1515,18 +1577,21 @@ static int wm8350_remove(struct platform_device *pdev)
|
|||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8350 *wm8350 = codec->control_data;
|
||||
struct wm8350_data *priv = codec->private_data;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
wm8350_clear_bits(wm8350, WM8350_JACK_DETECT,
|
||||
WM8350_JDL_ENA | WM8350_JDR_ENA);
|
||||
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA);
|
||||
|
||||
wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICD, priv);
|
||||
wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_MICSCD, priv);
|
||||
wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv);
|
||||
wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv);
|
||||
|
||||
priv->hpl.jack = NULL;
|
||||
priv->hpr.jack = NULL;
|
||||
priv->mic.jack = NULL;
|
||||
|
||||
/* cancel any work waiting to be queued. */
|
||||
ret = cancel_delayed_work(&codec->delayed_work);
|
||||
|
@ -1631,7 +1696,7 @@ static __devinit int wm8350_codec_probe(struct platform_device *pdev)
|
|||
codec->dai = &wm8350_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = WM8350_MAX_REGISTER;
|
||||
codec->private_data = priv;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
codec->control_data = wm8350;
|
||||
|
||||
/* Put the codec into reset if it wasn't already */
|
||||
|
@ -1663,7 +1728,7 @@ static int __devexit wm8350_codec_remove(struct platform_device *pdev)
|
|||
{
|
||||
struct wm8350 *wm8350 = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = wm8350->codec.codec;
|
||||
struct wm8350_data *priv = codec->private_data;
|
||||
struct wm8350_data *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_soc_unregister_dai(&wm8350_dai);
|
||||
snd_soc_unregister_codec(codec);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -77,7 +77,7 @@ struct wm8400_priv {
|
|||
static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
|
||||
unsigned int reg)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = codec->private_data;
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (reg == WM8400_INTDRIVBITS)
|
||||
return wm8400->fake_register;
|
||||
|
@ -91,7 +91,7 @@ static inline unsigned int wm8400_read(struct snd_soc_codec *codec,
|
|||
static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = codec->private_data;
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (reg == WM8400_INTDRIVBITS) {
|
||||
wm8400->fake_register = value;
|
||||
|
@ -102,7 +102,7 @@ static int wm8400_write(struct snd_soc_codec *codec, unsigned int reg,
|
|||
|
||||
static void wm8400_codec_reset(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = codec->private_data;
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
wm8400_reset_codec_reg_cache(wm8400->wm8400);
|
||||
}
|
||||
|
@ -926,7 +926,7 @@ static int wm8400_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 wm8400_priv *wm8400 = codec->private_data;
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
wm8400->sysclk = freq;
|
||||
return 0;
|
||||
|
@ -1015,7 +1015,7 @@ static int wm8400_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
|
|||
unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct wm8400_priv *wm8400 = codec->private_data;
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
struct fll_factors factors;
|
||||
int ret;
|
||||
u16 reg;
|
||||
|
@ -1204,7 +1204,7 @@ static int wm8400_mute(struct snd_soc_dai *dai, int mute)
|
|||
static int wm8400_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8400_priv *wm8400 = codec->private_data;
|
||||
struct wm8400_priv *wm8400 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 val;
|
||||
int ret;
|
||||
|
||||
|
@ -1467,7 +1467,7 @@ static int wm8400_codec_probe(struct platform_device *dev)
|
|||
return -ENOMEM;
|
||||
|
||||
codec = &priv->codec;
|
||||
codec->private_data = priv;
|
||||
snd_soc_codec_set_drvdata(codec, priv);
|
||||
codec->control_data = dev_get_drvdata(&dev->dev);
|
||||
priv->wm8400 = dev_get_drvdata(&dev->dev);
|
||||
|
||||
|
@ -1530,7 +1530,7 @@ err:
|
|||
|
||||
static int __exit wm8400_codec_remove(struct platform_device *dev)
|
||||
{
|
||||
struct wm8400_priv *priv = wm8400_codec->private_data;
|
||||
struct wm8400_priv *priv = snd_soc_codec_get_drvdata(wm8400_codec);
|
||||
u16 reg;
|
||||
|
||||
snd_soc_unregister_dai(&wm8400_dai);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -412,7 +412,7 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
|
|||
{
|
||||
int offset;
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct wm8580_priv *wm8580 = codec->private_data;
|
||||
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
|
||||
struct pll_state *state;
|
||||
struct _pll_div pll_div;
|
||||
unsigned int reg;
|
||||
|
@ -840,7 +840,7 @@ static int wm8580_register(struct wm8580_priv *wm8580,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8580;
|
||||
snd_soc_codec_set_drvdata(codec, wm8580);
|
||||
codec->name = "WM8580";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -163,7 +163,7 @@ static int wm8711_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8711_priv *wm8711 = codec->private_data;
|
||||
struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 iface = snd_soc_read(codec, WM8711_IFACE) & 0xfffc;
|
||||
int i = get_coeff(wm8711->sysclk, params_rate(params));
|
||||
u16 srate = (coeff_div[i].sr << 2) |
|
||||
|
@ -227,7 +227,7 @@ static int wm8711_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 wm8711_priv *wm8711 = codec->private_data;
|
||||
struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -376,7 +376,7 @@ static int wm8711_resume(struct platform_device *pdev)
|
|||
codec->hw_write(codec->control_data, data, 2);
|
||||
}
|
||||
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
wm8711_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,7 @@ static int wm8711_register(struct wm8711_priv *wm8711,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8711;
|
||||
snd_soc_codec_set_drvdata(codec, wm8711);
|
||||
codec->name = "WM8711";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -238,7 +238,7 @@ static int wm8728_resume(struct platform_device *pdev)
|
|||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8728_set_bias_level(codec, codec->suspend_bias_level);
|
||||
wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -225,7 +225,7 @@ static int wm8731_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 wm8731_priv *wm8731 = codec->private_data;
|
||||
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3;
|
||||
int i = get_coeff(wm8731->sysclk, params_rate(params));
|
||||
u16 srate = (coeff_div[i].sr << 2) |
|
||||
|
@ -292,7 +292,7 @@ static int wm8731_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 wm8731_priv *wm8731 = codec->private_data;
|
||||
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -369,6 +369,10 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai,
|
|||
static int wm8731_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
u8 data[2];
|
||||
u16 *cache = codec->reg_cache;
|
||||
u16 reg;
|
||||
|
||||
switch (level) {
|
||||
|
@ -377,6 +381,24 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
|
|||
case SND_SOC_BIAS_PREPARE:
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
|
||||
wm8731->supplies);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
|
||||
if (cache[i] == wm8731_reg[i])
|
||||
continue;
|
||||
|
||||
data[0] = (i << 1) | ((cache[i] >> 8)
|
||||
& 0x0001);
|
||||
data[1] = cache[i] & 0x00ff;
|
||||
codec->hw_write(codec->control_data, data, 2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear PWROFF, gate CLKOUT, everything else as-is */
|
||||
reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f;
|
||||
snd_soc_write(codec, WM8731_PWR, reg | 0x0040);
|
||||
|
@ -384,17 +406,15 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
|
|||
case SND_SOC_BIAS_OFF:
|
||||
snd_soc_write(codec, WM8731_ACTIVE, 0x0);
|
||||
snd_soc_write(codec, WM8731_PWR, 0xffff);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
|
||||
wm8731->supplies);
|
||||
break;
|
||||
}
|
||||
codec->bias_level = level;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WM8731_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
|
||||
SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\
|
||||
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
|
||||
SNDRV_PCM_RATE_96000)
|
||||
#define WM8731_RATES SNDRV_PCM_RATE_8000_96000
|
||||
|
||||
#define WM8731_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
@ -432,12 +452,9 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8731_priv *wm8731 = codec->private_data;
|
||||
|
||||
snd_soc_write(codec, WM8731_ACTIVE, 0x0);
|
||||
wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies),
|
||||
wm8731->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -445,27 +462,8 @@ static int wm8731_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8731_priv *wm8731 = codec->private_data;
|
||||
int i, ret;
|
||||
u8 data[2];
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies),
|
||||
wm8731->supplies);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/* Sync reg_cache with the hardware */
|
||||
for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
|
||||
if (cache[i] == wm8731_reg[i])
|
||||
continue;
|
||||
|
||||
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
|
||||
data[1] = cache[i] & 0x00ff;
|
||||
codec->hw_write(codec->control_data, data, 2);
|
||||
}
|
||||
wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
wm8731_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -540,7 +538,7 @@ static int wm8731_register(struct wm8731_priv *wm8731,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8731;
|
||||
snd_soc_codec_set_drvdata(codec, wm8731);
|
||||
codec->name = "WM8731";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
@ -609,6 +607,9 @@ static int wm8731_register(struct wm8731_priv *wm8731,
|
|||
goto err_codec;
|
||||
}
|
||||
|
||||
/* Regulators will have been enabled by bias management */
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
|
||||
|
||||
return 0;
|
||||
|
||||
err_codec:
|
||||
|
@ -627,7 +628,6 @@ static void wm8731_unregister(struct wm8731_priv *wm8731)
|
|||
wm8731_set_bias_level(&wm8731->codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_unregister_dai(&wm8731_dai);
|
||||
snd_soc_unregister_codec(&wm8731->codec);
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
|
||||
kfree(wm8731);
|
||||
wm8731_codec = NULL;
|
||||
|
@ -708,7 +708,7 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id);
|
|||
|
||||
static struct i2c_driver wm8731_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "WM8731 I2C Codec",
|
||||
.name = "wm8731",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8731_i2c_probe,
|
||||
|
|
|
@ -30,13 +30,6 @@
|
|||
|
||||
#include "wm8750.h"
|
||||
|
||||
#define WM8750_VERSION "0.12"
|
||||
|
||||
/* codec private data */
|
||||
struct wm8750_priv {
|
||||
unsigned int sysclk;
|
||||
};
|
||||
|
||||
/*
|
||||
* wm8750 register cache
|
||||
* We can't read the WM8750 register space when we
|
||||
|
@ -56,6 +49,13 @@ static const u16 wm8750_reg[] = {
|
|||
0x0079, 0x0079, 0x0079, /* 40 */
|
||||
};
|
||||
|
||||
/* codec private data */
|
||||
struct wm8750_priv {
|
||||
unsigned int sysclk;
|
||||
struct snd_soc_codec codec;
|
||||
u16 reg_cache[ARRAY_SIZE(wm8750_reg)];
|
||||
};
|
||||
|
||||
#define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0)
|
||||
|
||||
/*
|
||||
|
@ -483,7 +483,7 @@ static int wm8750_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 wm8750_priv *wm8750 = codec->private_data;
|
||||
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -562,7 +562,7 @@ static int wm8750_pcm_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 wm8750_priv *wm8750 = codec->private_data;
|
||||
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3;
|
||||
u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0;
|
||||
int coeff = get_coeff(wm8750->sysclk, params_rate(params));
|
||||
|
@ -614,10 +614,16 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
|
|||
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0);
|
||||
break;
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/* set vmid to 5k for quick power up */
|
||||
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
|
||||
break;
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
/* Set VMID to 5k */
|
||||
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
|
||||
|
||||
/* ...and ramp */
|
||||
msleep(1000);
|
||||
}
|
||||
|
||||
/* mute dac and set vmid to 500k, enable VREF */
|
||||
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141);
|
||||
break;
|
||||
|
@ -661,13 +667,6 @@ struct snd_soc_dai wm8750_dai = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(wm8750_dai);
|
||||
|
||||
static void wm8750_work(struct work_struct *work)
|
||||
{
|
||||
struct snd_soc_codec *codec =
|
||||
container_of(work, struct snd_soc_codec, delayed_work.work);
|
||||
wm8750_set_bias_level(codec, codec->bias_level);
|
||||
}
|
||||
|
||||
static int wm8750_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
|
@ -696,36 +695,92 @@ static int wm8750_resume(struct platform_device *pdev)
|
|||
|
||||
wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* charge wm8750 caps */
|
||||
if (codec->suspend_bias_level == SND_SOC_BIAS_ON) {
|
||||
wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
|
||||
codec->bias_level = SND_SOC_BIAS_ON;
|
||||
schedule_delayed_work(&codec->delayed_work,
|
||||
msecs_to_jiffies(1000));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec *wm8750_codec;
|
||||
|
||||
static int wm8750_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
if (!wm8750_codec) {
|
||||
dev_err(&pdev->dev, "WM8750 codec not yet registered\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
socdev->card->codec = wm8750_codec;
|
||||
codec = wm8750_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "wm8750: failed to create pcms\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
snd_soc_add_controls(codec, wm8750_snd_controls,
|
||||
ARRAY_SIZE(wm8750_snd_controls));
|
||||
wm8750_add_widgets(codec);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int wm8750_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_wm8750 = {
|
||||
.probe = wm8750_probe,
|
||||
.remove = wm8750_remove,
|
||||
.suspend = wm8750_suspend,
|
||||
.resume = wm8750_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
|
||||
|
||||
/*
|
||||
* initialise the WM8750 driver
|
||||
* register the mixer and dsp interfaces with the kernel
|
||||
*/
|
||||
static int wm8750_init(struct snd_soc_device *socdev,
|
||||
enum snd_soc_control_type control)
|
||||
static int wm8750_register(struct wm8750_priv *wm8750,
|
||||
enum snd_soc_control_type control)
|
||||
{
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct snd_soc_codec *codec = &wm8750->codec;
|
||||
int reg, ret = 0;
|
||||
|
||||
if (wm8750_codec) {
|
||||
dev_err(codec->dev, "Multiple WM8750 devices not supported\n");
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->name = "WM8750";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_STANDBY;
|
||||
codec->set_bias_level = wm8750_set_bias_level;
|
||||
codec->dai = &wm8750_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(wm8750_reg);
|
||||
codec->reg_cache = kmemdup(wm8750_reg, sizeof(wm8750_reg), GFP_KERNEL);
|
||||
if (codec->reg_cache == NULL)
|
||||
return -ENOMEM;
|
||||
codec->reg_cache_size = ARRAY_SIZE(wm8750->reg_cache) + 1;
|
||||
codec->reg_cache = &wm8750->reg_cache;
|
||||
snd_soc_codec_set_drvdata(codec, wm8750);
|
||||
|
||||
memcpy(codec->reg_cache, wm8750_reg, sizeof(wm8750->reg_cache));
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, control);
|
||||
if (ret < 0) {
|
||||
|
@ -739,17 +794,8 @@ static int wm8750_init(struct snd_soc_device *socdev,
|
|||
goto err;
|
||||
}
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
printk(KERN_ERR "wm8750: failed to create pcms\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* charge output caps */
|
||||
wm8750_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
|
||||
codec->bias_level = SND_SOC_BIAS_STANDBY;
|
||||
schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000));
|
||||
wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* set the update bits */
|
||||
reg = snd_soc_read(codec, WM8750_LDAC);
|
||||
|
@ -769,19 +815,37 @@ static int wm8750_init(struct snd_soc_device *socdev,
|
|||
reg = snd_soc_read(codec, WM8750_RINVOL);
|
||||
snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
|
||||
|
||||
snd_soc_add_controls(codec, wm8750_snd_controls,
|
||||
ARRAY_SIZE(wm8750_snd_controls));
|
||||
wm8750_add_widgets(codec);
|
||||
return ret;
|
||||
wm8750_codec = codec;
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dais(&wm8750_dai, 1);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register DAIs: %d\n", ret);
|
||||
goto err_codec;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err:
|
||||
kfree(codec->reg_cache);
|
||||
kfree(wm8750);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If the i2c layer weren't so broken, we could pass this kind of data
|
||||
around */
|
||||
static struct snd_soc_device *wm8750_socdev;
|
||||
static void wm8750_unregister(struct wm8750_priv *wm8750)
|
||||
{
|
||||
wm8750_set_bias_level(&wm8750->codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_unregister_dais(&wm8750_dai, 1);
|
||||
snd_soc_unregister_codec(&wm8750->codec);
|
||||
kfree(wm8750);
|
||||
wm8750_codec = NULL;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
|
@ -795,24 +859,26 @@ static struct snd_soc_device *wm8750_socdev;
|
|||
static int wm8750_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct snd_soc_device *socdev = wm8750_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int ret;
|
||||
struct snd_soc_codec *codec;
|
||||
struct wm8750_priv *wm8750;
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
|
||||
if (wm8750 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &wm8750->codec;
|
||||
codec->control_data = i2c;
|
||||
i2c_set_clientdata(i2c, wm8750);
|
||||
|
||||
ret = wm8750_init(socdev, SND_SOC_I2C);
|
||||
if (ret < 0)
|
||||
pr_err("failed to initialise WM8750\n");
|
||||
codec->dev = &i2c->dev;
|
||||
|
||||
return ret;
|
||||
return wm8750_register(wm8750, SND_SOC_I2C);
|
||||
}
|
||||
|
||||
static int wm8750_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct snd_soc_codec *codec = i2c_get_clientdata(client);
|
||||
kfree(codec->reg_cache);
|
||||
struct wm8750_priv *wm8750 = i2c_get_clientdata(client);
|
||||
wm8750_unregister(wm8750);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -831,66 +897,31 @@ static struct i2c_driver wm8750_i2c_driver = {
|
|||
.remove = wm8750_i2c_remove,
|
||||
.id_table = wm8750_i2c_id,
|
||||
};
|
||||
|
||||
static int wm8750_add_i2c_device(struct platform_device *pdev,
|
||||
const struct wm8750_setup_data *setup)
|
||||
{
|
||||
struct i2c_board_info info;
|
||||
struct i2c_adapter *adapter;
|
||||
struct i2c_client *client;
|
||||
int ret;
|
||||
|
||||
ret = i2c_add_driver(&wm8750_i2c_driver);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev, "can't add i2c driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
memset(&info, 0, sizeof(struct i2c_board_info));
|
||||
info.addr = setup->i2c_address;
|
||||
strlcpy(info.type, "wm8750", I2C_NAME_SIZE);
|
||||
|
||||
adapter = i2c_get_adapter(setup->i2c_bus);
|
||||
if (!adapter) {
|
||||
dev_err(&pdev->dev, "can't get i2c adapter %d\n",
|
||||
setup->i2c_bus);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
client = i2c_new_device(adapter, &info);
|
||||
i2c_put_adapter(adapter);
|
||||
if (!client) {
|
||||
dev_err(&pdev->dev, "can't add i2c device at 0x%x\n",
|
||||
(unsigned int)info.addr);
|
||||
goto err_driver;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_driver:
|
||||
i2c_del_driver(&wm8750_i2c_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8750_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct snd_soc_device *socdev = wm8750_socdev;
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
int ret;
|
||||
struct snd_soc_codec *codec;
|
||||
struct wm8750_priv *wm8750;
|
||||
|
||||
wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
|
||||
if (wm8750 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = &wm8750->codec;
|
||||
codec->control_data = spi;
|
||||
codec->dev = &spi->dev;
|
||||
|
||||
ret = wm8750_init(socdev, SND_SOC_SPI);
|
||||
if (ret < 0)
|
||||
dev_err(&spi->dev, "failed to initialise WM8750\n");
|
||||
dev_set_drvdata(&spi->dev, wm8750);
|
||||
|
||||
return ret;
|
||||
return wm8750_register(wm8750, SND_SOC_SPI);
|
||||
}
|
||||
|
||||
static int __devexit wm8750_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct wm8750_priv *wm8750 = dev_get_drvdata(&spi->dev);
|
||||
wm8750_unregister(wm8750);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -905,115 +936,31 @@ static struct spi_driver wm8750_spi_driver = {
|
|||
};
|
||||
#endif
|
||||
|
||||
static int wm8750_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct wm8750_setup_data *setup = socdev->codec_data;
|
||||
struct snd_soc_codec *codec;
|
||||
struct wm8750_priv *wm8750;
|
||||
int ret;
|
||||
|
||||
pr_info("WM8750 Audio Codec %s", WM8750_VERSION);
|
||||
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
|
||||
if (codec == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
wm8750 = kzalloc(sizeof(struct wm8750_priv), GFP_KERNEL);
|
||||
if (wm8750 == NULL) {
|
||||
kfree(codec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec->private_data = wm8750;
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
wm8750_socdev = socdev;
|
||||
INIT_DELAYED_WORK(&codec->delayed_work, wm8750_work);
|
||||
|
||||
ret = -ENODEV;
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
if (setup->i2c_address) {
|
||||
ret = wm8750_add_i2c_device(pdev, setup);
|
||||
}
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
if (setup->spi) {
|
||||
ret = spi_register_driver(&wm8750_spi_driver);
|
||||
if (ret != 0)
|
||||
printk(KERN_ERR "can't add spi driver");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
kfree(codec->private_data);
|
||||
kfree(codec);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function forces any delayed work to be queued and run.
|
||||
*/
|
||||
static int run_delayed_work(struct delayed_work *dwork)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* cancel any work waiting to be queued. */
|
||||
ret = cancel_delayed_work(dwork);
|
||||
|
||||
/* if there was any work waiting then we run it now and
|
||||
* wait for it's completion */
|
||||
if (ret) {
|
||||
schedule_delayed_work(dwork, 0);
|
||||
flush_scheduled_work();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* power down chip */
|
||||
static int wm8750_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
if (codec->control_data)
|
||||
wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
run_delayed_work(&codec->delayed_work);
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_dapm_free(socdev);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&wm8750_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8750_spi_driver);
|
||||
#endif
|
||||
kfree(codec->private_data);
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_codec_device soc_codec_dev_wm8750 = {
|
||||
.probe = wm8750_probe,
|
||||
.remove = wm8750_remove,
|
||||
.suspend = wm8750_suspend,
|
||||
.resume = wm8750_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8750);
|
||||
|
||||
static int __init wm8750_modinit(void)
|
||||
{
|
||||
return snd_soc_register_dai(&wm8750_dai);
|
||||
int ret;
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
ret = i2c_add_driver(&wm8750_i2c_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register WM8750 I2C driver: %d\n", ret);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&wm8750_spi_driver);
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register WM8750 SPI driver: %d\n", ret);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
module_init(wm8750_modinit);
|
||||
|
||||
static void __exit wm8750_exit(void)
|
||||
{
|
||||
snd_soc_unregister_dai(&wm8750_dai);
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&wm8750_i2c_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8750_spi_driver);
|
||||
#endif
|
||||
}
|
||||
module_exit(wm8750_exit);
|
||||
|
||||
|
|
|
@ -851,7 +851,7 @@ static int wm8753_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 wm8753_priv *wm8753 = codec->private_data;
|
||||
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -914,7 +914,7 @@ static int wm8753_pcm_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 wm8753_priv *wm8753 = codec->private_data;
|
||||
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 voice = wm8753_read_reg_cache(codec, WM8753_PCM) & 0x01f3;
|
||||
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x017f;
|
||||
|
||||
|
@ -1148,7 +1148,7 @@ static int wm8753_i2s_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 wm8753_priv *wm8753 = codec->private_data;
|
||||
struct wm8753_priv *wm8753 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 srate = wm8753_read_reg_cache(codec, WM8753_SRATE1) & 0x01c0;
|
||||
u16 hifi = wm8753_read_reg_cache(codec, WM8753_HIFI) & 0x01f3;
|
||||
int coeff;
|
||||
|
@ -1646,7 +1646,7 @@ static int wm8753_register(struct wm8753_priv *wm8753)
|
|||
codec->num_dai = 2;
|
||||
codec->reg_cache_size = ARRAY_SIZE(wm8753->reg_cache) + 1;
|
||||
codec->reg_cache = &wm8753->reg_cache;
|
||||
codec->private_data = wm8753;
|
||||
snd_soc_codec_set_drvdata(codec, wm8753);
|
||||
|
||||
memcpy(codec->reg_cache, wm8753_reg, sizeof(wm8753->reg_cache));
|
||||
INIT_DELAYED_WORK(&codec->delayed_work, wm8753_work);
|
||||
|
|
|
@ -227,7 +227,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8776_priv *wm8776 = codec->private_data;
|
||||
struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
|
||||
int iface_reg, iface;
|
||||
int ratio_shift, master;
|
||||
int i;
|
||||
|
@ -304,7 +304,7 @@ static int wm8776_set_sysclk(struct snd_soc_dai *dai,
|
|||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8776_priv *wm8776 = codec->private_data;
|
||||
struct wm8776_priv *wm8776 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
BUG_ON(dai->id >= ARRAY_SIZE(wm8776->sysclk));
|
||||
|
||||
|
@ -491,7 +491,7 @@ static int wm8776_register(struct wm8776_priv *wm8776,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8776;
|
||||
snd_soc_codec_set_drvdata(codec, wm8776);
|
||||
codec->name = "WM8776";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -745,7 +745,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
|
|||
static int wm8900_set_fll(struct snd_soc_codec *codec,
|
||||
int fll_id, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct wm8900_priv *wm8900 = codec->private_data;
|
||||
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
|
||||
struct _fll_div fll_div;
|
||||
unsigned int reg;
|
||||
|
||||
|
@ -1132,7 +1132,7 @@ static int wm8900_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8900_priv *wm8900 = codec->private_data;
|
||||
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
|
||||
int fll_out = wm8900->fll_out;
|
||||
int fll_in = wm8900->fll_in;
|
||||
int ret;
|
||||
|
@ -1156,7 +1156,7 @@ static int wm8900_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8900_priv *wm8900 = codec->private_data;
|
||||
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 *cache;
|
||||
int i, ret;
|
||||
|
||||
|
@ -1206,7 +1206,7 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c,
|
|||
return -ENOMEM;
|
||||
|
||||
codec = &wm8900->codec;
|
||||
codec->private_data = wm8900;
|
||||
snd_soc_codec_set_drvdata(codec, wm8900);
|
||||
codec->reg_cache = &wm8900->reg_cache[0];
|
||||
codec->reg_cache_size = WM8900_MAXREG;
|
||||
|
||||
|
@ -1305,7 +1305,7 @@ static __devexit int wm8900_i2c_remove(struct i2c_client *client)
|
|||
wm8900_set_bias_level(wm8900_codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
wm8900_dai.dev = NULL;
|
||||
kfree(wm8900_codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(wm8900_codec));
|
||||
wm8900_codec = NULL;
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -11,26 +11,27 @@
|
|||
*
|
||||
* TODO:
|
||||
* - TDM mode configuration.
|
||||
* - Mic detect.
|
||||
* - Digital microphone support.
|
||||
* - Interrupt support (mic detect and sequencer).
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/wm8903.h>
|
||||
|
||||
#include "wm8903.h"
|
||||
|
||||
|
@ -222,6 +223,14 @@ struct wm8903_priv {
|
|||
int playback_active;
|
||||
int capture_active;
|
||||
|
||||
struct completion wseq;
|
||||
|
||||
struct snd_soc_jack *mic_jack;
|
||||
int mic_det;
|
||||
int mic_short;
|
||||
int mic_last_report;
|
||||
int mic_delay;
|
||||
|
||||
struct snd_pcm_substream *master_substream;
|
||||
struct snd_pcm_substream *slave_substream;
|
||||
};
|
||||
|
@ -244,13 +253,14 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
|
|||
{
|
||||
u16 reg[5];
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
BUG_ON(start > 48);
|
||||
|
||||
/* Enable the sequencer */
|
||||
/* Enable the sequencer if it's not already on */
|
||||
reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0);
|
||||
reg[0] |= WM8903_WSEQ_ENA;
|
||||
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
|
||||
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
|
||||
reg[0] | WM8903_WSEQ_ENA);
|
||||
|
||||
dev_dbg(&i2c->dev, "Starting sequence at %d\n", start);
|
||||
|
||||
|
@ -258,20 +268,19 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start)
|
|||
start | WM8903_WSEQ_START);
|
||||
|
||||
/* Wait for it to complete. If we have the interrupt wired up then
|
||||
* we could block waiting for an interrupt, though polling may still
|
||||
* be desirable for diagnostic purposes.
|
||||
* that will break us out of the poll early.
|
||||
*/
|
||||
do {
|
||||
msleep(10);
|
||||
wait_for_completion_timeout(&wm8903->wseq,
|
||||
msecs_to_jiffies(10));
|
||||
|
||||
reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4);
|
||||
} while (reg[4] & WM8903_WSEQ_BUSY);
|
||||
|
||||
dev_dbg(&i2c->dev, "Sequence complete\n");
|
||||
|
||||
/* Disable the sequencer again */
|
||||
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0,
|
||||
reg[0] & ~WM8903_WSEQ_ENA);
|
||||
/* Disable the sequencer again if we enabled it */
|
||||
snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -412,7 +421,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_codec *codec = widget->codec;
|
||||
struct wm8903_priv *wm8903 = codec->private_data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
u16 reg;
|
||||
int ret;
|
||||
|
@ -993,7 +1002,7 @@ static int wm8903_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 wm8903_priv *wm8903 = codec->private_data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
wm8903->sysclk = freq;
|
||||
|
||||
|
@ -1221,7 +1230,7 @@ static int wm8903_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 wm8903_priv *wm8903 = codec->private_data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
struct snd_pcm_runtime *master_runtime;
|
||||
|
||||
|
@ -1257,7 +1266,7 @@ static void wm8903_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 wm8903_priv *wm8903 = codec->private_data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
wm8903->playback_active--;
|
||||
|
@ -1277,7 +1286,7 @@ static int wm8903_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 wm8903_priv *wm8903 = codec->private_data;
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
int fs = params_rate(params);
|
||||
int bclk;
|
||||
|
@ -1436,6 +1445,116 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* wm8903_mic_detect - Enable microphone detection via the WM8903 IRQ
|
||||
*
|
||||
* @codec: WM8903 codec
|
||||
* @jack: jack to report detection events on
|
||||
* @det: value to report for presence detection
|
||||
* @shrt: value to report for short detection
|
||||
*
|
||||
* Enable microphone detection via IRQ on the WM8903. If GPIOs are
|
||||
* being used to bring out signals to the processor then only platform
|
||||
* data configuration is needed for WM8903 and processor GPIOs should
|
||||
* be configured using snd_soc_jack_add_gpios() instead.
|
||||
*
|
||||
* The current threasholds for detection should be configured using
|
||||
* micdet_cfg in the platform data. Using this function will force on
|
||||
* the microphone bias for the device.
|
||||
*/
|
||||
int wm8903_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
|
||||
int det, int shrt)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
|
||||
int irq_mask = WM8903_MICDET_EINT | WM8903_MICSHRT_EINT;
|
||||
|
||||
dev_dbg(codec->dev, "Enabling microphone detection: %x %x\n",
|
||||
det, shrt);
|
||||
|
||||
/* Store the configuration */
|
||||
wm8903->mic_jack = jack;
|
||||
wm8903->mic_det = det;
|
||||
wm8903->mic_short = shrt;
|
||||
|
||||
/* Enable interrupts we've got a report configured for */
|
||||
if (det)
|
||||
irq_mask &= ~WM8903_MICDET_EINT;
|
||||
if (shrt)
|
||||
irq_mask &= ~WM8903_MICSHRT_EINT;
|
||||
|
||||
snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
|
||||
WM8903_MICDET_EINT | WM8903_MICSHRT_EINT,
|
||||
irq_mask);
|
||||
|
||||
if (det && shrt) {
|
||||
/* Enable mic detection, this may not have been set through
|
||||
* platform data (eg, if the defaults are OK). */
|
||||
snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
|
||||
WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
|
||||
snd_soc_update_bits(codec, WM8903_MIC_BIAS_CONTROL_0,
|
||||
WM8903_MICDET_ENA, WM8903_MICDET_ENA);
|
||||
} else {
|
||||
snd_soc_update_bits(codec, WM8903_MIC_BIAS_CONTROL_0,
|
||||
WM8903_MICDET_ENA, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm8903_mic_detect);
|
||||
|
||||
static irqreturn_t wm8903_irq(int irq, void *data)
|
||||
{
|
||||
struct wm8903_priv *wm8903 = data;
|
||||
struct snd_soc_codec *codec = &wm8903->codec;
|
||||
int mic_report;
|
||||
int int_pol;
|
||||
int int_val = 0;
|
||||
int mask = ~snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1_MASK);
|
||||
|
||||
int_val = snd_soc_read(codec, WM8903_INTERRUPT_STATUS_1) & mask;
|
||||
|
||||
if (int_val & WM8903_WSEQ_BUSY_EINT) {
|
||||
dev_dbg(codec->dev, "Write sequencer done\n");
|
||||
complete(&wm8903->wseq);
|
||||
}
|
||||
|
||||
/*
|
||||
* The rest is microphone jack detection. We need to manually
|
||||
* invert the polarity of the interrupt after each event - to
|
||||
* simplify the code keep track of the last state we reported
|
||||
* and just invert the relevant bits in both the report and
|
||||
* the polarity register.
|
||||
*/
|
||||
mic_report = wm8903->mic_last_report;
|
||||
int_pol = snd_soc_read(codec, WM8903_INTERRUPT_POLARITY_1);
|
||||
|
||||
if (int_val & WM8903_MICSHRT_EINT) {
|
||||
dev_dbg(codec->dev, "Microphone short (pol=%x)\n", int_pol);
|
||||
|
||||
mic_report ^= wm8903->mic_short;
|
||||
int_pol ^= WM8903_MICSHRT_INV;
|
||||
}
|
||||
|
||||
if (int_val & WM8903_MICDET_EINT) {
|
||||
dev_dbg(codec->dev, "Microphone detect (pol=%x)\n", int_pol);
|
||||
|
||||
mic_report ^= wm8903->mic_det;
|
||||
int_pol ^= WM8903_MICDET_INV;
|
||||
|
||||
msleep(wm8903->mic_delay);
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, WM8903_INTERRUPT_POLARITY_1,
|
||||
WM8903_MICSHRT_INV | WM8903_MICDET_INV, int_pol);
|
||||
|
||||
snd_soc_jack_report(wm8903->mic_jack, mic_report,
|
||||
wm8903->mic_short | wm8903->mic_det);
|
||||
|
||||
wm8903->mic_last_report = mic_report;
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
#define WM8903_PLAYBACK_RATES (SNDRV_PCM_RATE_8000 |\
|
||||
SNDRV_PCM_RATE_11025 | \
|
||||
SNDRV_PCM_RATE_16000 | \
|
||||
|
@ -1510,7 +1629,6 @@ static int wm8903_resume(struct platform_device *pdev)
|
|||
|
||||
/* Bring the codec back up to standby first to minimise pop/clicks */
|
||||
wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
wm8903_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
/* Sync back everything else */
|
||||
if (tmp_cache) {
|
||||
|
@ -1530,9 +1648,11 @@ static struct snd_soc_codec *wm8903_codec;
|
|||
static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm8903_platform_data *pdata = dev_get_platdata(&i2c->dev);
|
||||
struct wm8903_priv *wm8903;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
int ret, i;
|
||||
int trigger, irq_pol;
|
||||
u16 val;
|
||||
|
||||
wm8903 = kzalloc(sizeof(struct wm8903_priv), GFP_KERNEL);
|
||||
|
@ -1554,8 +1674,9 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
|||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache);
|
||||
codec->reg_cache = &wm8903->reg_cache[0];
|
||||
codec->private_data = wm8903;
|
||||
snd_soc_codec_set_drvdata(codec, wm8903);
|
||||
codec->volatile_register = wm8903_volatile_register;
|
||||
init_completion(&wm8903->wseq);
|
||||
|
||||
i2c_set_clientdata(i2c, codec);
|
||||
codec->control_data = i2c;
|
||||
|
@ -1579,6 +1700,53 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
wm8903_reset(codec);
|
||||
|
||||
/* Set up GPIOs and microphone detection */
|
||||
if (pdata) {
|
||||
for (i = 0; i < ARRAY_SIZE(pdata->gpio_cfg); i++) {
|
||||
if (!pdata->gpio_cfg[i])
|
||||
continue;
|
||||
|
||||
snd_soc_write(codec, WM8903_GPIO_CONTROL_1 + i,
|
||||
pdata->gpio_cfg[i] & 0xffff);
|
||||
}
|
||||
|
||||
snd_soc_write(codec, WM8903_MIC_BIAS_CONTROL_0,
|
||||
pdata->micdet_cfg);
|
||||
|
||||
/* Microphone detection needs the WSEQ clock */
|
||||
if (pdata->micdet_cfg)
|
||||
snd_soc_update_bits(codec, WM8903_WRITE_SEQUENCER_0,
|
||||
WM8903_WSEQ_ENA, WM8903_WSEQ_ENA);
|
||||
|
||||
wm8903->mic_delay = pdata->micdet_delay;
|
||||
}
|
||||
|
||||
if (i2c->irq) {
|
||||
if (pdata && pdata->irq_active_low) {
|
||||
trigger = IRQF_TRIGGER_LOW;
|
||||
irq_pol = WM8903_IRQ_POL;
|
||||
} else {
|
||||
trigger = IRQF_TRIGGER_HIGH;
|
||||
irq_pol = 0;
|
||||
}
|
||||
|
||||
snd_soc_update_bits(codec, WM8903_INTERRUPT_CONTROL,
|
||||
WM8903_IRQ_POL, irq_pol);
|
||||
|
||||
ret = request_threaded_irq(i2c->irq, NULL, wm8903_irq,
|
||||
trigger | IRQF_ONESHOT,
|
||||
"wm8903", wm8903);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to request IRQ: %d\n",
|
||||
ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Enable write sequencer interrupts */
|
||||
snd_soc_update_bits(codec, WM8903_INTERRUPT_STATUS_1_MASK,
|
||||
WM8903_IM_WSEQ_BUSY_EINT, 0);
|
||||
}
|
||||
|
||||
/* power on device */
|
||||
wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
|
@ -1619,7 +1787,7 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
|||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dai(&wm8903_dai);
|
||||
|
@ -1632,6 +1800,9 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c,
|
|||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err_irq:
|
||||
if (i2c->irq)
|
||||
free_irq(i2c->irq, wm8903);
|
||||
err:
|
||||
wm8903_codec = NULL;
|
||||
kfree(wm8903);
|
||||
|
@ -1641,13 +1812,17 @@ err:
|
|||
static __devexit int wm8903_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct snd_soc_codec *codec = i2c_get_clientdata(client);
|
||||
struct wm8903_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_soc_unregister_dai(&wm8903_dai);
|
||||
snd_soc_unregister_codec(codec);
|
||||
|
||||
wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
kfree(codec->private_data);
|
||||
if (client->irq)
|
||||
free_irq(client->irq, priv);
|
||||
|
||||
kfree(priv);
|
||||
|
||||
wm8903_codec = NULL;
|
||||
wm8903_dai.dev = NULL;
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
extern struct snd_soc_dai wm8903_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_wm8903;
|
||||
|
||||
extern int wm8903_mic_detect(struct snd_soc_codec *codec,
|
||||
struct snd_soc_jack *jack,
|
||||
int det, int shrt);
|
||||
|
||||
#define WM8903_MCLK_DIV_2 1
|
||||
#define WM8903_CLK_SYS 2
|
||||
#define WM8903_BCLK 3
|
||||
|
@ -172,28 +176,6 @@ extern struct snd_soc_codec_device soc_codec_dev_wm8903;
|
|||
#define WM8903_VMID_RES_250K 3
|
||||
#define WM8903_VMID_RES_5K 4
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
|
||||
/*
|
||||
* R8 (0x08) - Analogue DAC 0
|
||||
*/
|
||||
|
@ -1134,201 +1116,6 @@ extern struct snd_soc_codec_device soc_codec_dev_wm8903;
|
|||
#define WM8903_MASK_WRITE_ENA_SHIFT 0 /* MASK_WRITE_ENA */
|
||||
#define WM8903_MASK_WRITE_ENA_WIDTH 1 /* MASK_WRITE_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 */
|
||||
|
||||
/*
|
||||
* R121 (0x79) - Interrupt Status 1
|
||||
*/
|
||||
|
|
|
@ -613,7 +613,7 @@ static int wm8904_reset(struct snd_soc_codec *codec)
|
|||
|
||||
static int wm8904_configure_clocking(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int clock0, clock2, rate;
|
||||
|
||||
/* Gate the clock while we're updating to avoid misclocking */
|
||||
|
@ -669,7 +669,7 @@ static int wm8904_configure_clocking(struct snd_soc_codec *codec)
|
|||
|
||||
static void wm8904_set_drc(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8904_pdata *pdata = wm8904->pdata;
|
||||
int save, i;
|
||||
|
||||
|
@ -689,7 +689,7 @@ static int wm8904_put_drc_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8904_pdata *pdata = wm8904->pdata;
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
|
@ -707,7 +707,7 @@ static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = wm8904->drc_cfg;
|
||||
|
||||
|
@ -716,7 +716,7 @@ static int wm8904_get_drc_enum(struct snd_kcontrol *kcontrol,
|
|||
|
||||
static void wm8904_set_retune_mobile(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8904_pdata *pdata = wm8904->pdata;
|
||||
int best, best_val, save, i, cfg;
|
||||
|
||||
|
@ -760,7 +760,7 @@ static int wm8904_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8904_pdata *pdata = wm8904->pdata;
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
|
@ -778,7 +778,7 @@ static int wm8904_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = wm8904->retune_mobile_cfg;
|
||||
|
||||
|
@ -789,7 +789,7 @@ static int deemph_settings[] = { 0, 32000, 44100, 48000 };
|
|||
|
||||
static int wm8904_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int val, i, best;
|
||||
|
||||
/* If we're using deemphasis select the nearest available sample
|
||||
|
@ -818,7 +818,7 @@ static int wm8904_get_deemph(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
return wm8904->deemph;
|
||||
}
|
||||
|
@ -827,7 +827,7 @@ static int wm8904_put_deemph(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int deemph = ucontrol->value.enumerated.item[0];
|
||||
|
||||
if (deemph > 1)
|
||||
|
@ -943,7 +943,7 @@ static int sysclk_event(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
|
@ -981,7 +981,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg, val;
|
||||
int dcs_mask;
|
||||
int dcs_l, dcs_r;
|
||||
|
@ -1429,7 +1429,7 @@ static const struct snd_soc_dapm_route wm8912_intercon[] = {
|
|||
|
||||
static int wm8904_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
snd_soc_dapm_new_controls(codec, wm8904_core_dapm_widgets,
|
||||
ARRAY_SIZE(wm8904_core_dapm_widgets));
|
||||
|
@ -1543,7 +1543,7 @@ static int wm8904_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, i, best, best_val, cur_val;
|
||||
unsigned int aif1 = 0;
|
||||
unsigned int aif2 = 0;
|
||||
|
@ -1670,7 +1670,7 @@ static int wm8904_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|||
unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8904_priv *priv = codec->private_data;
|
||||
struct wm8904_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case WM8904_CLK_MCLK:
|
||||
|
@ -1786,7 +1786,7 @@ static int wm8904_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
|||
unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int aif1 = 0;
|
||||
|
||||
/* Don't need to validate anything if we're turning off TDM */
|
||||
|
@ -1943,7 +1943,7 @@ static int wm8904_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
|
|||
unsigned int Fref, unsigned int Fout)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
struct _fll_div fll_div;
|
||||
int ret, val;
|
||||
int clock2, fll1;
|
||||
|
@ -2095,7 +2095,7 @@ static int wm8904_digital_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
|
||||
static void wm8904_sync_cache(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
|
||||
if (!codec->cache_sync)
|
||||
|
@ -2122,7 +2122,7 @@ static void wm8904_sync_cache(struct snd_soc_codec *codec)
|
|||
static int wm8904_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8904_priv *wm8904 = codec->private_data;
|
||||
struct wm8904_priv *wm8904 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
|
@ -2395,7 +2395,7 @@ static int wm8904_probe(struct platform_device *pdev)
|
|||
goto pcm_err;
|
||||
}
|
||||
|
||||
wm8904_handle_pdata(codec->private_data);
|
||||
wm8904_handle_pdata(snd_soc_codec_get_drvdata(codec));
|
||||
|
||||
wm8904_add_widgets(codec);
|
||||
|
||||
|
@ -2426,6 +2426,7 @@ EXPORT_SYMBOL_GPL(soc_codec_dev_wm8904);
|
|||
static int wm8904_register(struct wm8904_priv *wm8904,
|
||||
enum snd_soc_control_type control)
|
||||
{
|
||||
struct wm8904_pdata *pdata = wm8904->pdata;
|
||||
int ret;
|
||||
struct snd_soc_codec *codec = &wm8904->codec;
|
||||
int i;
|
||||
|
@ -2439,7 +2440,7 @@ static int wm8904_register(struct wm8904_priv *wm8904,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8904;
|
||||
snd_soc_codec_set_drvdata(codec, wm8904);
|
||||
codec->name = "WM8904";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
@ -2531,6 +2532,22 @@ static int wm8904_register(struct wm8904_priv *wm8904,
|
|||
WM8904_LINEOUTRZC;
|
||||
wm8904->reg_cache[WM8904_CLOCK_RATES_0] &= ~WM8904_SR_MODE;
|
||||
|
||||
/* Apply configuration from the platform data. */
|
||||
if (wm8904->pdata) {
|
||||
for (i = 0; i < WM8904_GPIO_REGS; i++) {
|
||||
if (!pdata->gpio_cfg[i])
|
||||
continue;
|
||||
|
||||
wm8904->reg_cache[WM8904_GPIO_CONTROL_1 + i]
|
||||
= pdata->gpio_cfg[i] & 0xffff;
|
||||
}
|
||||
|
||||
/* Zero is the default value for these anyway */
|
||||
for (i = 0; i < WM8904_MIC_REGS; i++)
|
||||
wm8904->reg_cache[WM8904_MIC_BIAS_CONTROL_0 + i]
|
||||
= pdata->mic_cfg[i];
|
||||
}
|
||||
|
||||
/* Set Class W by default - this will be managed by the Class
|
||||
* G widget at runtime where bypass paths are available.
|
||||
*/
|
||||
|
|
|
@ -185,39 +185,6 @@ extern struct snd_soc_codec_device soc_codec_dev_wm8904;
|
|||
#define WM8904_VMID_ENA_SHIFT 0 /* VMID_ENA */
|
||||
#define WM8904_VMID_ENA_WIDTH 1 /* VMID_ENA */
|
||||
|
||||
/*
|
||||
* 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] */
|
||||
|
||||
/*
|
||||
* R8 (0x08) - Analogue DAC 0
|
||||
*/
|
||||
|
@ -1199,70 +1166,6 @@ extern struct snd_soc_codec_device soc_codec_dev_wm8904;
|
|||
#define WM8904_FLL_CLK_REF_SRC_SHIFT 0 /* FLL_CLK_REF_SRC - [1:0] */
|
||||
#define WM8904_FLL_CLK_REF_SRC_WIDTH 2 /* FLL_CLK_REF_SRC - [1: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] */
|
||||
|
||||
/*
|
||||
* R126 (0x7E) - Digital Pulls
|
||||
*/
|
||||
|
|
|
@ -581,7 +581,7 @@ static int wm8940_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 wm8940_priv *wm8940 = codec->private_data;
|
||||
struct wm8940_priv *wm8940 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -692,7 +692,6 @@ static int wm8940_resume(struct platform_device *pdev)
|
|||
ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
ret = wm8940_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
error_ret:
|
||||
return ret;
|
||||
|
@ -773,7 +772,7 @@ static int wm8940_register(struct wm8940_priv *wm8940,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8940;
|
||||
snd_soc_codec_set_drvdata(codec, wm8940);
|
||||
codec->name = "WM8940";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -235,7 +235,7 @@ static struct {
|
|||
|
||||
static int wm8955_configure_clocking(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8955_priv *wm8955 = codec->private_data;
|
||||
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret, val;
|
||||
int clocking = 0;
|
||||
int srate = 0;
|
||||
|
@ -353,7 +353,7 @@ static int deemph_settings[] = { 0, 32000, 44100, 48000 };
|
|||
|
||||
static int wm8955_set_deemph(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8955_priv *wm8955 = codec->private_data;
|
||||
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
|
||||
int val, i, best;
|
||||
|
||||
/* If we're using deemphasis select the nearest available sample
|
||||
|
@ -382,7 +382,7 @@ static int wm8955_get_deemph(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8955_priv *wm8955 = codec->private_data;
|
||||
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
return wm8955->deemph;
|
||||
}
|
||||
|
@ -391,7 +391,7 @@ static int wm8955_put_deemph(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8955_priv *wm8955 = codec->private_data;
|
||||
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
|
||||
int deemph = ucontrol->value.enumerated.item[0];
|
||||
|
||||
if (deemph > 1)
|
||||
|
@ -598,7 +598,7 @@ static int wm8955_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8955_priv *wm8955 = codec->private_data;
|
||||
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
int wl;
|
||||
|
||||
|
@ -647,7 +647,7 @@ static int wm8955_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|||
unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8955_priv *priv = codec->private_data;
|
||||
struct wm8955_priv *priv = snd_soc_codec_get_drvdata(codec);
|
||||
int div;
|
||||
|
||||
switch (clk_id) {
|
||||
|
@ -770,7 +770,7 @@ static int wm8955_digital_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
static int wm8955_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8955_priv *wm8955 = codec->private_data;
|
||||
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, i;
|
||||
|
||||
switch (level) {
|
||||
|
@ -971,7 +971,7 @@ static int wm8955_register(struct wm8955_priv *wm8955,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8955;
|
||||
snd_soc_codec_set_drvdata(codec, wm8955);
|
||||
codec->name = "WM8955";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <sound/soc-dapm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/wm8960.h>
|
||||
|
||||
#include "wm8960.h"
|
||||
|
||||
|
@ -31,8 +32,14 @@
|
|||
struct snd_soc_codec_device soc_codec_dev_wm8960;
|
||||
|
||||
/* R25 - Power 1 */
|
||||
#define WM8960_VMID_MASK 0x180
|
||||
#define WM8960_VREF 0x40
|
||||
|
||||
/* R26 - Power 2 */
|
||||
#define WM8960_PWR2_LOUT1 0x40
|
||||
#define WM8960_PWR2_ROUT1 0x20
|
||||
#define WM8960_PWR2_OUT3 0x02
|
||||
|
||||
/* R28 - Anti-pop 1 */
|
||||
#define WM8960_POBCTRL 0x80
|
||||
#define WM8960_BUFDCOPEN 0x10
|
||||
|
@ -42,6 +49,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8960;
|
|||
|
||||
/* R29 - Anti-pop 2 */
|
||||
#define WM8960_DISOP 0x40
|
||||
#define WM8960_DRES_MASK 0x30
|
||||
|
||||
/*
|
||||
* wm8960 register cache
|
||||
|
@ -68,6 +76,9 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
|
|||
struct wm8960_priv {
|
||||
u16 reg_cache[WM8960_CACHEREGNUM];
|
||||
struct snd_soc_codec codec;
|
||||
struct snd_soc_dapm_widget *lout1;
|
||||
struct snd_soc_dapm_widget *rout1;
|
||||
struct snd_soc_dapm_widget *out3;
|
||||
};
|
||||
|
||||
#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0)
|
||||
|
@ -226,10 +237,6 @@ SND_SOC_DAPM_MIXER("Right Output Mixer", WM8960_POWER3, 2, 0,
|
|||
&wm8960_routput_mixer[0],
|
||||
ARRAY_SIZE(wm8960_routput_mixer)),
|
||||
|
||||
SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
|
||||
&wm8960_mono_out[0],
|
||||
ARRAY_SIZE(wm8960_mono_out)),
|
||||
|
||||
SND_SOC_DAPM_PGA("LOUT1 PGA", WM8960_POWER2, 6, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("ROUT1 PGA", WM8960_POWER2, 5, 0, NULL, 0),
|
||||
|
||||
|
@ -248,6 +255,17 @@ SND_SOC_DAPM_OUTPUT("SPK_RN"),
|
|||
SND_SOC_DAPM_OUTPUT("OUT3"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget wm8960_dapm_widgets_out3[] = {
|
||||
SND_SOC_DAPM_MIXER("Mono Output Mixer", WM8960_POWER2, 1, 0,
|
||||
&wm8960_mono_out[0],
|
||||
ARRAY_SIZE(wm8960_mono_out)),
|
||||
};
|
||||
|
||||
/* Represent OUT3 as a PGA so that it gets turned on with LOUT1/ROUT1 */
|
||||
static const struct snd_soc_dapm_widget wm8960_dapm_widgets_capless[] = {
|
||||
SND_SOC_DAPM_PGA("OUT3 VMID", WM8960_POWER2, 1, 0, NULL, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_paths[] = {
|
||||
{ "Left Boost Mixer", "LINPUT1 Switch", "LINPUT1" },
|
||||
{ "Left Boost Mixer", "LINPUT2 Switch", "LINPUT2" },
|
||||
|
@ -278,9 +296,6 @@ static const struct snd_soc_dapm_route audio_paths[] = {
|
|||
{ "Right Output Mixer", "Boost Bypass Switch", "Right Boost Mixer" } ,
|
||||
{ "Right Output Mixer", "PCM Playback Switch", "Right DAC" },
|
||||
|
||||
{ "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
|
||||
{ "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
|
||||
|
||||
{ "LOUT1 PGA", NULL, "Left Output Mixer" },
|
||||
{ "ROUT1 PGA", NULL, "Right Output Mixer" },
|
||||
|
||||
|
@ -297,17 +312,65 @@ static const struct snd_soc_dapm_route audio_paths[] = {
|
|||
{ "SPK_LP", NULL, "Left Speaker Output" },
|
||||
{ "SPK_RN", NULL, "Right Speaker Output" },
|
||||
{ "SPK_RP", NULL, "Right Speaker Output" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_paths_out3[] = {
|
||||
{ "Mono Output Mixer", "Left Switch", "Left Output Mixer" },
|
||||
{ "Mono Output Mixer", "Right Switch", "Right Output Mixer" },
|
||||
|
||||
{ "OUT3", NULL, "Mono Output Mixer", }
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_paths_capless[] = {
|
||||
{ "HP_L", NULL, "OUT3 VMID" },
|
||||
{ "HP_R", NULL, "OUT3 VMID" },
|
||||
|
||||
{ "OUT3 VMID", NULL, "Left Output Mixer" },
|
||||
{ "OUT3 VMID", NULL, "Right Output Mixer" },
|
||||
};
|
||||
|
||||
static int wm8960_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8960_data *pdata = codec->dev->platform_data;
|
||||
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
|
||||
struct snd_soc_dapm_widget *w;
|
||||
|
||||
snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets,
|
||||
ARRAY_SIZE(wm8960_dapm_widgets));
|
||||
|
||||
snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths));
|
||||
|
||||
/* In capless mode OUT3 is used to provide VMID for the
|
||||
* headphone outputs, otherwise it is used as a mono mixer.
|
||||
*/
|
||||
if (pdata && pdata->capless) {
|
||||
snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets_capless,
|
||||
ARRAY_SIZE(wm8960_dapm_widgets_capless));
|
||||
|
||||
snd_soc_dapm_add_routes(codec, audio_paths_capless,
|
||||
ARRAY_SIZE(audio_paths_capless));
|
||||
} else {
|
||||
snd_soc_dapm_new_controls(codec, wm8960_dapm_widgets_out3,
|
||||
ARRAY_SIZE(wm8960_dapm_widgets_out3));
|
||||
|
||||
snd_soc_dapm_add_routes(codec, audio_paths_out3,
|
||||
ARRAY_SIZE(audio_paths_out3));
|
||||
}
|
||||
|
||||
/* We need to power up the headphone output stage out of
|
||||
* sequence for capless mode. To save scanning the widget
|
||||
* list each time to find the desired power state do so now
|
||||
* and save the result.
|
||||
*/
|
||||
list_for_each_entry(w, &codec->dapm_widgets, list) {
|
||||
if (strcmp(w->name, "LOUT1 PGA") == 0)
|
||||
wm8960->lout1 = w;
|
||||
if (strcmp(w->name, "ROUT1 PGA") == 0)
|
||||
wm8960->rout1 = w;
|
||||
if (strcmp(w->name, "OUT3 VMID") == 0)
|
||||
wm8960->out3 = w;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -408,10 +471,9 @@ static int wm8960_mute(struct snd_soc_dai *dai, int mute)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wm8960_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8960_data *pdata = codec->dev->platform_data;
|
||||
u16 reg;
|
||||
|
||||
switch (level) {
|
||||
|
@ -430,18 +492,8 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
|
|||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
/* Enable anti-pop features */
|
||||
snd_soc_write(codec, WM8960_APOP1,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN | WM8960_BUFIOEN);
|
||||
|
||||
/* Discharge HP output */
|
||||
reg = WM8960_DISOP;
|
||||
if (pdata)
|
||||
reg |= pdata->dres << 4;
|
||||
snd_soc_write(codec, WM8960_APOP2, reg);
|
||||
|
||||
msleep(400);
|
||||
|
||||
snd_soc_write(codec, WM8960_APOP2, 0);
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN | WM8960_BUFIOEN);
|
||||
|
||||
/* Enable & ramp VMID at 2x50k */
|
||||
reg = snd_soc_read(codec, WM8960_POWER1);
|
||||
|
@ -472,8 +524,101 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec,
|
|||
/* Disable VMID and VREF, let them discharge */
|
||||
snd_soc_write(codec, WM8960_POWER1, 0);
|
||||
msleep(600);
|
||||
break;
|
||||
}
|
||||
|
||||
snd_soc_write(codec, WM8960_APOP1, 0);
|
||||
codec->bias_level = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
switch (codec->bias_level) {
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
/* Enable anti pop mode */
|
||||
snd_soc_update_bits(codec, WM8960_APOP1,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN);
|
||||
|
||||
/* Enable LOUT1, ROUT1 and OUT3 if they're enabled */
|
||||
reg = 0;
|
||||
if (wm8960->lout1 && wm8960->lout1->power)
|
||||
reg |= WM8960_PWR2_LOUT1;
|
||||
if (wm8960->rout1 && wm8960->rout1->power)
|
||||
reg |= WM8960_PWR2_ROUT1;
|
||||
if (wm8960->out3 && wm8960->out3->power)
|
||||
reg |= WM8960_PWR2_OUT3;
|
||||
snd_soc_update_bits(codec, WM8960_POWER2,
|
||||
WM8960_PWR2_LOUT1 |
|
||||
WM8960_PWR2_ROUT1 |
|
||||
WM8960_PWR2_OUT3, reg);
|
||||
|
||||
/* Enable VMID at 2*50k */
|
||||
snd_soc_update_bits(codec, WM8960_POWER1,
|
||||
WM8960_VMID_MASK, 0x80);
|
||||
|
||||
/* Ramp */
|
||||
msleep(100);
|
||||
|
||||
/* Enable VREF */
|
||||
snd_soc_update_bits(codec, WM8960_POWER1,
|
||||
WM8960_VREF, WM8960_VREF);
|
||||
|
||||
msleep(100);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_ON:
|
||||
/* Enable anti-pop mode */
|
||||
snd_soc_update_bits(codec, WM8960_APOP1,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN);
|
||||
|
||||
/* Disable VMID and VREF */
|
||||
snd_soc_update_bits(codec, WM8960_POWER1,
|
||||
WM8960_VREF | WM8960_VMID_MASK, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
switch (codec->bias_level) {
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
/* Disable HP discharge */
|
||||
snd_soc_update_bits(codec, WM8960_APOP2,
|
||||
WM8960_DISOP | WM8960_DRES_MASK,
|
||||
0);
|
||||
|
||||
/* Disable anti-pop features */
|
||||
snd_soc_update_bits(codec, WM8960_APOP1,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN,
|
||||
WM8960_POBCTRL | WM8960_SOFT_ST |
|
||||
WM8960_BUFDCOPEN);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -594,10 +739,6 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
|
|||
u16 reg;
|
||||
|
||||
switch (div_id) {
|
||||
case WM8960_SYSCLKSEL:
|
||||
reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1fe;
|
||||
snd_soc_write(codec, WM8960_CLOCK1, reg | div);
|
||||
break;
|
||||
case WM8960_SYSCLKDIV:
|
||||
reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9;
|
||||
snd_soc_write(codec, WM8960_CLOCK1, reg | div);
|
||||
|
@ -663,7 +804,7 @@ static int wm8960_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm8960_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
codec->set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -682,8 +823,8 @@ static int wm8960_resume(struct platform_device *pdev)
|
|||
codec->hw_write(codec->control_data, data, 2);
|
||||
}
|
||||
|
||||
wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
wm8960_set_bias_level(codec, codec->suspend_bias_level);
|
||||
codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -753,6 +894,8 @@ static int wm8960_register(struct wm8960_priv *wm8960,
|
|||
goto err;
|
||||
}
|
||||
|
||||
codec->set_bias_level = wm8960_set_bias_level_out3;
|
||||
|
||||
if (!pdata) {
|
||||
dev_warn(codec->dev, "No platform data supplied\n");
|
||||
} else {
|
||||
|
@ -760,17 +903,19 @@ static int wm8960_register(struct wm8960_priv *wm8960,
|
|||
dev_err(codec->dev, "Invalid DRES: %d\n", pdata->dres);
|
||||
pdata->dres = 0;
|
||||
}
|
||||
|
||||
if (pdata->capless)
|
||||
codec->set_bias_level = wm8960_set_bias_level_capless;
|
||||
}
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8960;
|
||||
snd_soc_codec_set_drvdata(codec, wm8960);
|
||||
codec->name = "WM8960";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = wm8960_set_bias_level;
|
||||
codec->dai = &wm8960_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->reg_cache_size = WM8960_CACHEREGNUM;
|
||||
|
@ -792,7 +937,7 @@ static int wm8960_register(struct wm8960_priv *wm8960,
|
|||
|
||||
wm8960_dai.dev = codec->dev;
|
||||
|
||||
wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
codec->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
/* Latch the update bits */
|
||||
reg = snd_soc_read(codec, WM8960_LINVOL);
|
||||
|
@ -841,7 +986,7 @@ err:
|
|||
|
||||
static void wm8960_unregister(struct wm8960_priv *wm8960)
|
||||
{
|
||||
wm8960_set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
|
||||
wm8960->codec.set_bias_level(&wm8960->codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_unregister_dai(&wm8960_dai);
|
||||
snd_soc_unregister_codec(&wm8960->codec);
|
||||
kfree(wm8960);
|
||||
|
@ -883,7 +1028,7 @@ MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
|
|||
|
||||
static struct i2c_driver wm8960_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "WM8960 I2C Codec",
|
||||
.name = "wm8960",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm8960_i2c_probe,
|
||||
|
|
|
@ -76,7 +76,6 @@
|
|||
#define WM8960_OPCLKDIV 2
|
||||
#define WM8960_DCLKDIV 3
|
||||
#define WM8960_TOCLKSEL 4
|
||||
#define WM8960_SYSCLKSEL 5
|
||||
|
||||
#define WM8960_SYSCLK_DIV_1 (0 << 1)
|
||||
#define WM8960_SYSCLK_DIV_2 (2 << 1)
|
||||
|
@ -114,14 +113,4 @@
|
|||
extern struct snd_soc_dai wm8960_dai;
|
||||
extern struct snd_soc_codec_device soc_codec_dev_wm8960;
|
||||
|
||||
#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 {
|
||||
int dres;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -631,7 +631,7 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8961_priv *wm8961 = codec->private_data;
|
||||
struct wm8961_priv *wm8961 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, best, target, fs;
|
||||
u16 reg;
|
||||
|
||||
|
@ -722,7 +722,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id,
|
|||
int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8961_priv *wm8961 = codec->private_data;
|
||||
struct wm8961_priv *wm8961 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg = snd_soc_read(codec, WM8961_CLOCKING1);
|
||||
|
||||
if (freq > 33000000) {
|
||||
|
@ -1065,7 +1065,7 @@ static int wm8961_register(struct wm8961_priv *wm8961)
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8961;
|
||||
snd_soc_codec_set_drvdata(codec, wm8961);
|
||||
codec->name = "WM8961";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &wm8961_dai;
|
||||
|
|
|
@ -415,7 +415,7 @@ static int wm8971_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 wm8971_priv *wm8971 = codec->private_data;
|
||||
struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -494,7 +494,7 @@ static int wm8971_pcm_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 wm8971_priv *wm8971 = codec->private_data;
|
||||
struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3;
|
||||
u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0;
|
||||
int coeff = get_coeff(wm8971->sysclk, params_rate(params));
|
||||
|
@ -820,7 +820,7 @@ static int wm8971_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec->private_data = wm8971;
|
||||
snd_soc_codec_set_drvdata(codec, wm8971);
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
|
@ -830,7 +830,7 @@ static int wm8971_probe(struct platform_device *pdev)
|
|||
INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work);
|
||||
wm8971_workq = create_workqueue("wm8971");
|
||||
if (wm8971_workq == NULL) {
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -844,7 +844,7 @@ static int wm8971_probe(struct platform_device *pdev)
|
|||
|
||||
if (ret != 0) {
|
||||
destroy_workqueue(wm8971_workq);
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
}
|
||||
|
||||
|
@ -867,7 +867,7 @@ static int wm8971_remove(struct platform_device *pdev)
|
|||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&wm8971_i2c_driver);
|
||||
#endif
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -181,7 +181,7 @@ SOC_SINGLE("ADC 128x Oversampling Switch", WM8974_ADC, 8, 1, 0),
|
|||
static const struct snd_kcontrol_new wm8974_speaker_mixer_controls[] = {
|
||||
SOC_DAPM_SINGLE("Line Bypass Switch", WM8974_SPKMIX, 1, 1, 0),
|
||||
SOC_DAPM_SINGLE("Aux Playback Switch", WM8974_SPKMIX, 5, 1, 0),
|
||||
SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 1),
|
||||
SOC_DAPM_SINGLE("PCM Playback Switch", WM8974_SPKMIX, 0, 1, 0),
|
||||
};
|
||||
|
||||
/* Mono Output Mixer */
|
||||
|
@ -609,7 +609,7 @@ static int wm8974_resume(struct platform_device *pdev)
|
|||
codec->hw_write(codec->control_data, data, 2);
|
||||
}
|
||||
wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
wm8974_set_bias_level(codec, codec->suspend_bias_level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -677,7 +677,7 @@ static __devinit int wm8974_register(struct wm8974_priv *wm8974)
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8974;
|
||||
snd_soc_codec_set_drvdata(codec, wm8974);
|
||||
codec->name = "WM8974";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -439,7 +439,7 @@ static int wm8978_enum_mclk(unsigned int f_out, unsigned int f_mclk,
|
|||
*/
|
||||
static int wm8978_configure_pll(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8978_priv *wm8978 = codec->private_data;
|
||||
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8978_pll_div pll_div;
|
||||
unsigned int f_opclk = wm8978->f_opclk, f_mclk = wm8978->f_mclk,
|
||||
f_256fs = wm8978->f_256fs;
|
||||
|
@ -535,7 +535,7 @@ static int wm8978_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
|
|||
int div_id, int div)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
struct wm8978_priv *wm8978 = codec->private_data;
|
||||
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
switch (div_id) {
|
||||
|
@ -580,7 +580,7 @@ static int wm8978_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 wm8978_priv *wm8978 = codec->private_data;
|
||||
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
|
||||
dev_dbg(codec->dev, "%s: ID %d, freq %u\n", __func__, clk_id, freq);
|
||||
|
@ -692,7 +692,7 @@ static int wm8978_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 wm8978_priv *wm8978 = codec->private_data;
|
||||
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
|
||||
/* Word length mask = 0x60 */
|
||||
u16 iface_ctl = snd_soc_read(codec, WM8978_AUDIO_INTERFACE) & ~0x60;
|
||||
/* Sampling rate mask = 0xe (for filters) */
|
||||
|
@ -912,7 +912,7 @@ static int wm8978_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8978_priv *wm8978 = codec->private_data;
|
||||
struct wm8978_priv *wm8978 = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
|
@ -1020,7 +1020,7 @@ static __devinit int wm8978_register(struct wm8978_priv *wm8978)
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8978;
|
||||
snd_soc_codec_set_drvdata(codec, wm8978);
|
||||
codec->name = "WM8978";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
|
|
|
@ -495,7 +495,7 @@ static int wm8988_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 wm8988_priv *wm8988 = codec->private_data;
|
||||
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (freq) {
|
||||
case 11289600:
|
||||
|
@ -585,7 +585,7 @@ static int wm8988_pcm_startup(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8988_priv *wm8988 = codec->private_data;
|
||||
struct wm8988_priv *wm8988 = 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.
|
||||
|
@ -610,7 +610,7 @@ static int wm8988_pcm_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 wm8988_priv *wm8988 = codec->private_data;
|
||||
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3;
|
||||
u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180;
|
||||
int coeff;
|
||||
|
@ -833,7 +833,7 @@ static int wm8988_register(struct wm8988_priv *wm8988,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8988;
|
||||
snd_soc_codec_set_drvdata(codec, wm8988);
|
||||
codec->name = "WM8988";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &wm8988_dai;
|
||||
|
|
|
@ -1012,7 +1012,7 @@ static int wm8990_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 wm8990_priv *wm8990 = codec->private_data;
|
||||
struct wm8990_priv *wm8990 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
wm8990->sysclk = freq;
|
||||
return 0;
|
||||
|
@ -1524,7 +1524,7 @@ static int wm8990_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
codec->private_data = wm8990;
|
||||
snd_soc_codec_set_drvdata(codec, wm8990);
|
||||
socdev->card->codec = codec;
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
|
@ -1541,7 +1541,7 @@ static int wm8990_probe(struct platform_device *pdev)
|
|||
#endif
|
||||
|
||||
if (ret != 0) {
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
}
|
||||
return ret;
|
||||
|
@ -1561,7 +1561,7 @@ static int wm8990_remove(struct platform_device *pdev)
|
|||
i2c_unregister_device(codec->control_data);
|
||||
i2c_del_driver(&wm8990_i2c_driver);
|
||||
#endif
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -371,7 +371,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
|
|||
unsigned int Fref, unsigned int Fout)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg1, reg4, reg5;
|
||||
struct _fll_div fll_div;
|
||||
int ret;
|
||||
|
@ -458,7 +458,7 @@ static int wm8993_set_fll(struct snd_soc_dai *dai, int fll_id, int source,
|
|||
|
||||
static int configure_clock(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int reg;
|
||||
|
||||
/* This should be done on init() for bypass paths */
|
||||
|
@ -717,7 +717,7 @@ static int class_w_put(struct snd_kcontrol *kcontrol,
|
|||
{
|
||||
struct snd_soc_dapm_widget *widget = snd_kcontrol_chip(kcontrol);
|
||||
struct snd_soc_codec *codec = widget->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
/* Turn it off if we're using the main output mixer */
|
||||
|
@ -949,7 +949,7 @@ static void wm8993_cache_restore(struct snd_soc_codec *codec)
|
|||
static int wm8993_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
switch (level) {
|
||||
|
@ -1047,7 +1047,7 @@ static int wm8993_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 wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case WM8993_SYSCLK_MCLK:
|
||||
|
@ -1067,7 +1067,7 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai,
|
|||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int aif1 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_1);
|
||||
unsigned int aif4 = snd_soc_read(codec, WM8993_AUDIO_INTERFACE_4);
|
||||
|
||||
|
@ -1163,7 +1163,7 @@ static int wm8993_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, i, best, best_val, cur_val;
|
||||
unsigned int clocking1, clocking3, aif1, aif4;
|
||||
|
||||
|
@ -1328,7 +1328,7 @@ static int wm8993_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
|
|||
unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
int aif1 = 0;
|
||||
int aif2 = 0;
|
||||
|
||||
|
@ -1431,7 +1431,7 @@ static int wm8993_probe(struct platform_device *pdev)
|
|||
|
||||
socdev->card->codec = wm8993_codec;
|
||||
codec = wm8993_codec;
|
||||
wm8993 = codec->private_data;
|
||||
wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
|
@ -1478,7 +1478,7 @@ static int wm8993_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
int fll_fout = wm8993->fll_fout;
|
||||
int fll_fref = wm8993->fll_fref;
|
||||
int ret;
|
||||
|
@ -1502,7 +1502,7 @@ static int wm8993_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8993_priv *wm8993 = codec->private_data;
|
||||
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
@ -1571,7 +1571,7 @@ static int wm8993_i2c_probe(struct i2c_client *i2c,
|
|||
codec->set_bias_level = wm8993_set_bias_level;
|
||||
codec->dai = &wm8993_dai;
|
||||
codec->num_dai = 1;
|
||||
codec->private_data = wm8993;
|
||||
snd_soc_codec_set_drvdata(codec, wm8993);
|
||||
|
||||
wm8993->hubs_data.hp_startup_mode = 1;
|
||||
wm8993->hubs_data.dcs_codes = -2;
|
||||
|
|
|
@ -62,6 +62,12 @@ static int wm8994_retune_mobile_base[] = {
|
|||
|
||||
#define WM8994_REG_CACHE_SIZE 0x621
|
||||
|
||||
struct wm8994_micdet {
|
||||
struct snd_soc_jack *jack;
|
||||
int det;
|
||||
int shrt;
|
||||
};
|
||||
|
||||
/* codec private data */
|
||||
struct wm8994_priv {
|
||||
struct wm_hubs_data hubs;
|
||||
|
@ -87,6 +93,8 @@ struct wm8994_priv {
|
|||
int retune_mobile_cfg[WM8994_NUM_EQ];
|
||||
struct soc_enum retune_mobile_enum;
|
||||
|
||||
struct wm8994_micdet micdet[2];
|
||||
|
||||
struct wm8994_pdata *pdata;
|
||||
};
|
||||
|
||||
|
@ -1696,13 +1704,15 @@ static int wm8994_volatile(unsigned int reg)
|
|||
static int wm8994_write(struct snd_soc_codec *codec, unsigned int reg,
|
||||
unsigned int value)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
BUG_ON(reg > WM8994_MAX_REGISTER);
|
||||
|
||||
if (!wm8994_volatile(reg))
|
||||
wm8994->reg_cache[reg] = value;
|
||||
|
||||
dev_dbg(codec->dev, "0x%x = 0x%x\n", reg, value);
|
||||
|
||||
return wm8994_reg_write(codec->control_data, reg, value);
|
||||
}
|
||||
|
||||
|
@ -1721,7 +1731,7 @@ static unsigned int wm8994_read(struct snd_soc_codec *codec,
|
|||
|
||||
static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int rate;
|
||||
int reg1 = 0;
|
||||
int offset;
|
||||
|
@ -1762,6 +1772,11 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
|
|||
dev_dbg(codec->dev, "Dividing AIF%d clock to %dHz\n",
|
||||
aif + 1, rate);
|
||||
}
|
||||
|
||||
if (rate && rate < 3000000)
|
||||
dev_warn(codec->dev, "AIF%dCLK is %dHz, should be >=3MHz for optimal performance\n",
|
||||
aif + 1, rate);
|
||||
|
||||
wm8994->aifclk[aif] = rate;
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1 + offset,
|
||||
|
@ -1773,7 +1788,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
|
|||
|
||||
static int configure_clock(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int old, new;
|
||||
|
||||
/* Bring up the AIF clocks first */
|
||||
|
@ -1870,7 +1885,7 @@ static int wm8994_put_drc_sw(struct snd_kcontrol *kcontrol,
|
|||
|
||||
static void wm8994_set_drc(struct snd_soc_codec *codec, int drc)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994_pdata *pdata = wm8994->pdata;
|
||||
int base = wm8994_drc_base[drc];
|
||||
int cfg = wm8994->drc_cfg[drc];
|
||||
|
@ -1906,7 +1921,7 @@ static int wm8994_put_drc_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994_pdata *pdata = wm8994->pdata;
|
||||
int drc = wm8994_get_drc(kcontrol->id.name);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
@ -1928,7 +1943,7 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int drc = wm8994_get_drc(kcontrol->id.name);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = wm8994->drc_cfg[drc];
|
||||
|
@ -1938,7 +1953,7 @@ static int wm8994_get_drc_enum(struct snd_kcontrol *kcontrol,
|
|||
|
||||
static void wm8994_set_retune_mobile(struct snd_soc_codec *codec, int block)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994_pdata *pdata = wm8994->pdata;
|
||||
int base = wm8994_retune_mobile_base[block];
|
||||
int iface, best, best_val, save, i, cfg;
|
||||
|
@ -2009,7 +2024,7 @@ static int wm8994_put_retune_mobile_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994_pdata *pdata = wm8994->pdata;
|
||||
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
@ -2031,7 +2046,7 @@ static int wm8994_get_retune_mobile_enum(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int block = wm8994_get_retune_mobile_block(kcontrol->id.name);
|
||||
|
||||
ucontrol->value.enumerated.item[0] = wm8994->retune_mobile_cfg[block];
|
||||
|
@ -2182,13 +2197,13 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
|
|||
/* Only support direct DAC->headphone paths */
|
||||
reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_1);
|
||||
if (!(reg & WM8994_DAC1L_TO_HPOUT1L)) {
|
||||
dev_dbg(codec->dev, "HPL connected to output mixer\n");
|
||||
dev_vdbg(codec->dev, "HPL connected to output mixer\n");
|
||||
enable = 0;
|
||||
}
|
||||
|
||||
reg = snd_soc_read(codec, WM8994_OUTPUT_MIXER_2);
|
||||
if (!(reg & WM8994_DAC1R_TO_HPOUT1R)) {
|
||||
dev_dbg(codec->dev, "HPR connected to output mixer\n");
|
||||
dev_vdbg(codec->dev, "HPR connected to output mixer\n");
|
||||
enable = 0;
|
||||
}
|
||||
|
||||
|
@ -2196,26 +2211,26 @@ static void wm8994_update_class_w(struct snd_soc_codec *codec)
|
|||
reg = snd_soc_read(codec, WM8994_DAC1_LEFT_MIXER_ROUTING);
|
||||
switch (reg) {
|
||||
case WM8994_AIF2DACL_TO_DAC1L:
|
||||
dev_dbg(codec->dev, "Class W source AIF2DAC\n");
|
||||
dev_vdbg(codec->dev, "Class W source AIF2DAC\n");
|
||||
source = 2 << WM8994_CP_DYN_SRC_SEL_SHIFT;
|
||||
break;
|
||||
case WM8994_AIF1DAC2L_TO_DAC1L:
|
||||
dev_dbg(codec->dev, "Class W source AIF1DAC2\n");
|
||||
dev_vdbg(codec->dev, "Class W source AIF1DAC2\n");
|
||||
source = 1 << WM8994_CP_DYN_SRC_SEL_SHIFT;
|
||||
break;
|
||||
case WM8994_AIF1DAC1L_TO_DAC1L:
|
||||
dev_dbg(codec->dev, "Class W source AIF1DAC1\n");
|
||||
dev_vdbg(codec->dev, "Class W source AIF1DAC1\n");
|
||||
source = 0 << WM8994_CP_DYN_SRC_SEL_SHIFT;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(codec->dev, "DAC mixer setting: %x\n", reg);
|
||||
dev_vdbg(codec->dev, "DAC mixer setting: %x\n", reg);
|
||||
enable = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
reg_r = snd_soc_read(codec, WM8994_DAC1_RIGHT_MIXER_ROUTING);
|
||||
if (reg_r != reg) {
|
||||
dev_dbg(codec->dev, "Left and right DAC mixers different\n");
|
||||
dev_vdbg(codec->dev, "Left and right DAC mixers different\n");
|
||||
enable = 0;
|
||||
}
|
||||
|
||||
|
@ -2777,9 +2792,18 @@ static int wm8994_get_fll_config(struct fll_div *fll,
|
|||
|
||||
if (freq_in > 1000000) {
|
||||
fll->fll_fratio = 0;
|
||||
} else {
|
||||
} else if (freq_in > 256000) {
|
||||
fll->fll_fratio = 1;
|
||||
freq_in *= 2;
|
||||
} else if (freq_in > 128000) {
|
||||
fll->fll_fratio = 2;
|
||||
freq_in *= 4;
|
||||
} else if (freq_in > 64000) {
|
||||
fll->fll_fratio = 3;
|
||||
freq_in *= 8;
|
||||
} else {
|
||||
fll->fll_fratio = 4;
|
||||
freq_in *= 16;
|
||||
}
|
||||
pr_debug("FLL_FRATIO=%d, Fref=%dHz\n", fll->fll_fratio, freq_in);
|
||||
|
||||
|
@ -2812,7 +2836,7 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
|
|||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int reg_offset, ret;
|
||||
struct fll_div fll;
|
||||
u16 reg, aif1, aif2;
|
||||
|
@ -2836,6 +2860,21 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (src) {
|
||||
case 0:
|
||||
/* Allow no source specification when stopping */
|
||||
if (freq_out)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case WM8994_FLL_SRC_MCLK1:
|
||||
case WM8994_FLL_SRC_MCLK2:
|
||||
case WM8994_FLL_SRC_LRCLK:
|
||||
case WM8994_FLL_SRC_BCLK:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Are we changing anything? */
|
||||
if (wm8994->fll[id].src == src &&
|
||||
wm8994->fll[id].in == freq_in && wm8994->fll[id].out == freq_out)
|
||||
|
@ -2876,8 +2915,10 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
|
|||
fll.n << WM8994_FLL1_N_SHIFT);
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_FLL1_CONTROL_5 + reg_offset,
|
||||
WM8994_FLL1_REFCLK_DIV_MASK,
|
||||
fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT);
|
||||
WM8994_FLL1_REFCLK_DIV_MASK |
|
||||
WM8994_FLL1_REFCLK_SRC_MASK,
|
||||
(fll.clk_ref_div << WM8994_FLL1_REFCLK_DIV_SHIFT) |
|
||||
(src - 1));
|
||||
|
||||
/* Enable (with fractional mode if required) */
|
||||
if (freq_out) {
|
||||
|
@ -2892,6 +2933,7 @@ static int wm8994_set_fll(struct snd_soc_dai *dai, int id, int src,
|
|||
|
||||
wm8994->fll[id].in = freq_in;
|
||||
wm8994->fll[id].out = freq_out;
|
||||
wm8994->fll[id].src = src;
|
||||
|
||||
/* Enable any gated AIF clocks */
|
||||
snd_soc_update_bits(codec, WM8994_AIF1_CLOCKING_1,
|
||||
|
@ -2908,7 +2950,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
int clk_id, unsigned int freq, int dir)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (dai->id) {
|
||||
case 1:
|
||||
|
@ -3174,7 +3216,7 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int aif1_reg;
|
||||
int bclk_reg;
|
||||
int lrclk_reg;
|
||||
|
@ -3338,6 +3380,36 @@ static int wm8994_aif_mute(struct snd_soc_dai *codec_dai, int mute)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int wm8994_set_tristate(struct snd_soc_dai *codec_dai, int tristate)
|
||||
{
|
||||
struct snd_soc_codec *codec = codec_dai->codec;
|
||||
int reg, val, mask;
|
||||
|
||||
switch (codec_dai->id) {
|
||||
case 1:
|
||||
reg = WM8994_AIF1_MASTER_SLAVE;
|
||||
mask = WM8994_AIF1_TRI;
|
||||
break;
|
||||
case 2:
|
||||
reg = WM8994_AIF2_MASTER_SLAVE;
|
||||
mask = WM8994_AIF2_TRI;
|
||||
break;
|
||||
case 3:
|
||||
reg = WM8994_POWER_MANAGEMENT_6;
|
||||
mask = WM8994_AIF3_TRI;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (tristate)
|
||||
val = mask;
|
||||
else
|
||||
val = 0;
|
||||
|
||||
return snd_soc_update_bits(codec, reg, mask, reg);
|
||||
}
|
||||
|
||||
#define WM8994_RATES SNDRV_PCM_RATE_8000_96000
|
||||
|
||||
#define WM8994_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
|
@ -3349,6 +3421,7 @@ static struct snd_soc_dai_ops wm8994_aif1_dai_ops = {
|
|||
.hw_params = wm8994_hw_params,
|
||||
.digital_mute = wm8994_aif_mute,
|
||||
.set_pll = wm8994_set_fll,
|
||||
.set_tristate = wm8994_set_tristate,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
|
||||
|
@ -3357,6 +3430,11 @@ static struct snd_soc_dai_ops wm8994_aif2_dai_ops = {
|
|||
.hw_params = wm8994_hw_params,
|
||||
.digital_mute = wm8994_aif_mute,
|
||||
.set_pll = wm8994_set_fll,
|
||||
.set_tristate = wm8994_set_tristate,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_ops wm8994_aif3_dai_ops = {
|
||||
.set_tristate = wm8994_set_tristate,
|
||||
};
|
||||
|
||||
struct snd_soc_dai wm8994_dai[] = {
|
||||
|
@ -3400,6 +3478,7 @@ struct snd_soc_dai wm8994_dai[] = {
|
|||
},
|
||||
{
|
||||
.name = "WM8994 AIF3",
|
||||
.id = 3,
|
||||
.playback = {
|
||||
.stream_name = "AIF3 Playback",
|
||||
.channels_min = 2,
|
||||
|
@ -3414,6 +3493,7 @@ struct snd_soc_dai wm8994_dai[] = {
|
|||
.rates = WM8994_RATES,
|
||||
.formats = WM8994_FORMATS,
|
||||
},
|
||||
.ops = &wm8994_aif3_dai_ops,
|
||||
}
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(wm8994_dai);
|
||||
|
@ -3423,7 +3503,7 @@ static int wm8994_suspend(struct platform_device *pdev, pm_message_t state)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
|
||||
|
@ -3444,7 +3524,7 @@ static int wm8994_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm8994_priv *wm8994 = codec->private_data;
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 *reg_cache = codec->reg_cache;
|
||||
int i, ret;
|
||||
|
||||
|
@ -3469,6 +3549,9 @@ static int wm8994_resume(struct platform_device *pdev)
|
|||
wm8994_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8994->fll); i++) {
|
||||
if (!wm8994->fll_suspend[i].out)
|
||||
continue;
|
||||
|
||||
ret = wm8994_set_fll(&codec->dai[0], i + 1,
|
||||
wm8994->fll_suspend[i].src,
|
||||
wm8994->fll_suspend[i].in,
|
||||
|
@ -3639,7 +3722,7 @@ static int wm8994_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
wm8994_handle_pdata(codec->private_data);
|
||||
wm8994_handle_pdata(snd_soc_codec_get_drvdata(codec));
|
||||
|
||||
wm_hubs_add_analogue_controls(codec);
|
||||
snd_soc_add_controls(codec, wm8994_snd_controls,
|
||||
|
@ -3670,6 +3753,96 @@ struct snd_soc_codec_device soc_codec_dev_wm8994 = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm8994);
|
||||
|
||||
/**
|
||||
* wm8994_mic_detect - Enable microphone detection via the WM8994 IRQ
|
||||
*
|
||||
* @codec: WM8994 codec
|
||||
* @jack: jack to report detection events on
|
||||
* @micbias: microphone bias to detect on
|
||||
* @det: value to report for presence detection
|
||||
* @shrt: value to report for short detection
|
||||
*
|
||||
* Enable microphone detection via IRQ on the WM8994. If GPIOs are
|
||||
* being used to bring out signals to the processor then only platform
|
||||
* data configuration is needed for WM8903 and processor GPIOs should
|
||||
* be configured using snd_soc_jack_add_gpios() instead.
|
||||
*
|
||||
* Configuration of detection levels is available via the micbias1_lvl
|
||||
* and micbias2_lvl platform data members.
|
||||
*/
|
||||
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
|
||||
int micbias, int det, int shrt)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
|
||||
struct wm8994_micdet *micdet;
|
||||
int reg;
|
||||
|
||||
switch (micbias) {
|
||||
case 1:
|
||||
micdet = &wm8994->micdet[0];
|
||||
break;
|
||||
case 2:
|
||||
micdet = &wm8994->micdet[1];
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "Configuring microphone detection on %d: %x %x\n",
|
||||
micbias, det, shrt);
|
||||
|
||||
/* Store the configuration */
|
||||
micdet->jack = jack;
|
||||
micdet->det = det;
|
||||
micdet->shrt = shrt;
|
||||
|
||||
/* If either of the jacks is set up then enable detection */
|
||||
if (wm8994->micdet[0].jack || wm8994->micdet[1].jack)
|
||||
reg = WM8994_MICD_ENA;
|
||||
else
|
||||
reg = 0;
|
||||
|
||||
snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, reg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(wm8994_mic_detect);
|
||||
|
||||
static irqreturn_t wm8994_mic_irq(int irq, void *data)
|
||||
{
|
||||
struct wm8994_priv *priv = data;
|
||||
struct snd_soc_codec *codec = &priv->codec;
|
||||
int reg;
|
||||
int report;
|
||||
|
||||
reg = snd_soc_read(codec, WM8994_INTERRUPT_RAW_STATUS_2);
|
||||
if (reg < 0) {
|
||||
dev_err(codec->dev, "Failed to read microphone status: %d\n",
|
||||
reg);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "Microphone status: %x\n", reg);
|
||||
|
||||
report = 0;
|
||||
if (reg & WM8994_MIC1_DET_STS)
|
||||
report |= priv->micdet[0].det;
|
||||
if (reg & WM8994_MIC1_SHRT_STS)
|
||||
report |= priv->micdet[0].shrt;
|
||||
snd_soc_jack_report(priv->micdet[0].jack, report,
|
||||
priv->micdet[0].det | priv->micdet[0].shrt);
|
||||
|
||||
report = 0;
|
||||
if (reg & WM8994_MIC2_DET_STS)
|
||||
report |= priv->micdet[1].det;
|
||||
if (reg & WM8994_MIC2_SHRT_STS)
|
||||
report |= priv->micdet[1].shrt;
|
||||
snd_soc_jack_report(priv->micdet[1].jack, report,
|
||||
priv->micdet[1].det | priv->micdet[1].shrt);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int wm8994_codec_probe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
|
@ -3695,7 +3868,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm8994;
|
||||
snd_soc_codec_set_drvdata(codec, wm8994);
|
||||
codec->control_data = dev_get_drvdata(pdev->dev.parent);
|
||||
codec->name = "WM8994";
|
||||
codec->owner = THIS_MODULE;
|
||||
|
@ -3743,6 +3916,30 @@ static int wm8994_codec_probe(struct platform_device *pdev)
|
|||
break;
|
||||
}
|
||||
|
||||
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_DET,
|
||||
wm8994_mic_irq, "Mic 1 detect", wm8994);
|
||||
if (ret != 0)
|
||||
dev_warn(&pdev->dev,
|
||||
"Failed to request Mic1 detect IRQ: %d\n", ret);
|
||||
|
||||
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT,
|
||||
wm8994_mic_irq, "Mic 1 short", wm8994);
|
||||
if (ret != 0)
|
||||
dev_warn(&pdev->dev,
|
||||
"Failed to request Mic1 short IRQ: %d\n", ret);
|
||||
|
||||
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_DET,
|
||||
wm8994_mic_irq, "Mic 2 detect", wm8994);
|
||||
if (ret != 0)
|
||||
dev_warn(&pdev->dev,
|
||||
"Failed to request Mic2 detect IRQ: %d\n", ret);
|
||||
|
||||
ret = wm8994_request_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT,
|
||||
wm8994_mic_irq, "Mic 2 short", wm8994);
|
||||
if (ret != 0)
|
||||
dev_warn(&pdev->dev,
|
||||
"Failed to request Mic2 short IRQ: %d\n", ret);
|
||||
|
||||
/* Remember if AIFnLRCLK is configured as a GPIO. This should be
|
||||
* configured on init - if a system wants to do this dynamically
|
||||
* at runtime we can deal with that then.
|
||||
|
@ -3750,7 +3947,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
|
|||
ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to read GPIO1 state: %d\n", ret);
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
|
||||
wm8994->lrclk_shared[0] = 1;
|
||||
|
@ -3762,7 +3959,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
|
|||
ret = wm8994_reg_read(codec->control_data, WM8994_GPIO_6);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to read GPIO6 state: %d\n", ret);
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
if ((ret & WM8994_GPN_FN_MASK) != WM8994_GP_FN_PIN_SPECIFIC) {
|
||||
wm8994->lrclk_shared[1] = 1;
|
||||
|
@ -3812,7 +4009,7 @@ static int wm8994_codec_probe(struct platform_device *pdev)
|
|||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to register codec: %d\n", ret);
|
||||
goto err;
|
||||
goto err_irq;
|
||||
}
|
||||
|
||||
ret = snd_soc_register_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
|
||||
|
@ -3827,6 +4024,11 @@ static int wm8994_codec_probe(struct platform_device *pdev)
|
|||
|
||||
err_codec:
|
||||
snd_soc_unregister_codec(codec);
|
||||
err_irq:
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
|
||||
err:
|
||||
kfree(wm8994);
|
||||
return ret;
|
||||
|
@ -3840,6 +4042,10 @@ static int __devexit wm8994_codec_remove(struct platform_device *pdev)
|
|||
wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
snd_soc_unregister_dais(wm8994_dai, ARRAY_SIZE(wm8994_dai));
|
||||
snd_soc_unregister_codec(&wm8994->codec);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_SHRT, wm8994);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC2_DET, wm8994);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_SHRT, wm8994);
|
||||
wm8994_free_irq(codec->control_data, WM8994_IRQ_MIC1_DET, wm8994);
|
||||
kfree(wm8994);
|
||||
wm8994_codec = NULL;
|
||||
|
||||
|
|
|
@ -23,4 +23,12 @@ extern struct snd_soc_dai wm8994_dai[];
|
|||
#define WM8994_FLL1 1
|
||||
#define WM8994_FLL2 2
|
||||
|
||||
#define WM8994_FLL_SRC_MCLK1 1
|
||||
#define WM8994_FLL_SRC_MCLK2 2
|
||||
#define WM8994_FLL_SRC_LRCLK 3
|
||||
#define WM8994_FLL_SRC_BCLK 4
|
||||
|
||||
int wm8994_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
|
||||
int micbias, int det, int shrt);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -521,7 +521,7 @@ static int fll_factors(struct _fll_div *fll_div, unsigned int Fref,
|
|||
static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
|
||||
unsigned int Fref, unsigned int Fout)
|
||||
{
|
||||
struct wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg1, reg4, reg5;
|
||||
struct _fll_div fll_div;
|
||||
int ret;
|
||||
|
@ -607,7 +607,7 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id,
|
|||
|
||||
static int configure_clock(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
int new_sysclk, i, target;
|
||||
unsigned int reg;
|
||||
int ret = 0;
|
||||
|
@ -702,7 +702,7 @@ static int clk_sys_event(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* This should be done on init() for bypass paths */
|
||||
switch (wm9081->sysclk_source) {
|
||||
|
@ -873,7 +873,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai,
|
|||
unsigned int fmt)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2);
|
||||
|
||||
aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV |
|
||||
|
@ -965,7 +965,7 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream,
|
|||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret, i, best, best_val, cur_val;
|
||||
unsigned int clk_ctrl2, aif1, aif2, aif3, aif4;
|
||||
|
||||
|
@ -1139,7 +1139,7 @@ static int wm9081_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 wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (clk_id) {
|
||||
case WM9081_SYSCLK_MCLK:
|
||||
|
@ -1159,7 +1159,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai,
|
|||
unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width)
|
||||
{
|
||||
struct snd_soc_codec *codec = dai->codec;
|
||||
struct wm9081_priv *wm9081 = codec->private_data;
|
||||
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1);
|
||||
|
||||
aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK);
|
||||
|
@ -1242,7 +1242,7 @@ static int wm9081_probe(struct platform_device *pdev)
|
|||
|
||||
socdev->card->codec = wm9081_codec;
|
||||
codec = wm9081_codec;
|
||||
wm9081 = codec->private_data;
|
||||
wm9081 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
|
@ -1339,7 +1339,7 @@ static int wm9081_register(struct wm9081_priv *wm9081,
|
|||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->private_data = wm9081;
|
||||
snd_soc_codec_set_drvdata(codec, wm9081);
|
||||
codec->name = "WM9081";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->dai = &wm9081_dai;
|
||||
|
|
|
@ -0,0 +1,773 @@
|
|||
/*
|
||||
* ALSA SoC WM9090 driver
|
||||
*
|
||||
* Copyright 2009, 2010 Wolfson Microelectronics
|
||||
*
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/soc-dapm.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/wm9090.h>
|
||||
|
||||
#include "wm9090.h"
|
||||
|
||||
static struct snd_soc_codec *wm9090_codec;
|
||||
|
||||
static const u16 wm9090_reg_defaults[] = {
|
||||
0x9093, /* R0 - Software Reset */
|
||||
0x0006, /* R1 - Power Management (1) */
|
||||
0x6000, /* R2 - Power Management (2) */
|
||||
0x0000, /* R3 - Power Management (3) */
|
||||
0x0000, /* R4 */
|
||||
0x0000, /* R5 */
|
||||
0x01C0, /* R6 - Clocking 1 */
|
||||
0x0000, /* R7 */
|
||||
0x0000, /* R8 */
|
||||
0x0000, /* R9 */
|
||||
0x0000, /* R10 */
|
||||
0x0000, /* R11 */
|
||||
0x0000, /* R12 */
|
||||
0x0000, /* R13 */
|
||||
0x0000, /* R14 */
|
||||
0x0000, /* R15 */
|
||||
0x0000, /* R16 */
|
||||
0x0000, /* R17 */
|
||||
0x0000, /* R18 */
|
||||
0x0000, /* R19 */
|
||||
0x0000, /* R20 */
|
||||
0x0000, /* R21 */
|
||||
0x0003, /* R22 - IN1 Line Control */
|
||||
0x0003, /* R23 - IN2 Line Control */
|
||||
0x0083, /* R24 - IN1 Line Input A Volume */
|
||||
0x0083, /* R25 - IN1 Line Input B Volume */
|
||||
0x0083, /* R26 - IN2 Line Input A Volume */
|
||||
0x0083, /* R27 - IN2 Line Input B Volume */
|
||||
0x002D, /* R28 - Left Output Volume */
|
||||
0x002D, /* R29 - Right Output Volume */
|
||||
0x0000, /* R30 */
|
||||
0x0000, /* R31 */
|
||||
0x0000, /* R32 */
|
||||
0x0000, /* R33 */
|
||||
0x0100, /* R34 - SPKMIXL Attenuation */
|
||||
0x0000, /* R35 */
|
||||
0x0010, /* R36 - SPKOUT Mixers */
|
||||
0x0140, /* R37 - ClassD3 */
|
||||
0x0039, /* R38 - Speaker Volume Left */
|
||||
0x0000, /* R39 */
|
||||
0x0000, /* R40 */
|
||||
0x0000, /* R41 */
|
||||
0x0000, /* R42 */
|
||||
0x0000, /* R43 */
|
||||
0x0000, /* R44 */
|
||||
0x0000, /* R45 - Output Mixer1 */
|
||||
0x0000, /* R46 - Output Mixer2 */
|
||||
0x0100, /* R47 - Output Mixer3 */
|
||||
0x0100, /* R48 - Output Mixer4 */
|
||||
0x0000, /* R49 */
|
||||
0x0000, /* R50 */
|
||||
0x0000, /* R51 */
|
||||
0x0000, /* R52 */
|
||||
0x0000, /* R53 */
|
||||
0x0000, /* R54 - Speaker Mixer */
|
||||
0x0000, /* R55 */
|
||||
0x0000, /* R56 */
|
||||
0x000D, /* R57 - AntiPOP2 */
|
||||
0x0000, /* R58 */
|
||||
0x0000, /* R59 */
|
||||
0x0000, /* R60 */
|
||||
0x0000, /* R61 */
|
||||
0x0000, /* R62 */
|
||||
0x0000, /* R63 */
|
||||
0x0000, /* R64 */
|
||||
0x0000, /* R65 */
|
||||
0x0000, /* R66 */
|
||||
0x0000, /* R67 */
|
||||
0x0000, /* R68 */
|
||||
0x0000, /* R69 */
|
||||
0x0000, /* R70 - Write Sequencer 0 */
|
||||
0x0000, /* R71 - Write Sequencer 1 */
|
||||
0x0000, /* R72 - Write Sequencer 2 */
|
||||
0x0000, /* R73 - Write Sequencer 3 */
|
||||
0x0000, /* R74 - Write Sequencer 4 */
|
||||
0x0000, /* R75 - Write Sequencer 5 */
|
||||
0x1F25, /* R76 - Charge Pump 1 */
|
||||
0x0000, /* R77 */
|
||||
0x0000, /* R78 */
|
||||
0x0000, /* R79 */
|
||||
0x0000, /* R80 */
|
||||
0x0000, /* R81 */
|
||||
0x0000, /* R82 */
|
||||
0x0000, /* R83 */
|
||||
0x0000, /* R84 - DC Servo 0 */
|
||||
0x054A, /* R85 - DC Servo 1 */
|
||||
0x0000, /* R86 */
|
||||
0x0000, /* R87 - DC Servo 3 */
|
||||
0x0000, /* R88 - DC Servo Readback 0 */
|
||||
0x0000, /* R89 - DC Servo Readback 1 */
|
||||
0x0000, /* R90 - DC Servo Readback 2 */
|
||||
0x0000, /* R91 */
|
||||
0x0000, /* R92 */
|
||||
0x0000, /* R93 */
|
||||
0x0000, /* R94 */
|
||||
0x0000, /* R95 */
|
||||
0x0100, /* R96 - Analogue HP 0 */
|
||||
0x0000, /* R97 */
|
||||
0x8640, /* R98 - AGC Control 0 */
|
||||
0xC000, /* R99 - AGC Control 1 */
|
||||
0x0200, /* R100 - AGC Control 2 */
|
||||
};
|
||||
|
||||
/* This struct is used to save the context */
|
||||
struct wm9090_priv {
|
||||
/* We're not really registering as a CODEC since ASoC core
|
||||
* does not yet support multiple CODECs but having the CODEC
|
||||
* structure means we can reuse some of the ASoC core
|
||||
* features.
|
||||
*/
|
||||
struct snd_soc_codec codec;
|
||||
struct mutex mutex;
|
||||
u16 reg_cache[WM9090_MAX_REGISTER + 1];
|
||||
struct wm9090_platform_data pdata;
|
||||
};
|
||||
|
||||
static int wm9090_volatile(unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case WM9090_SOFTWARE_RESET:
|
||||
case WM9090_DC_SERVO_0:
|
||||
case WM9090_DC_SERVO_READBACK_0:
|
||||
case WM9090_DC_SERVO_READBACK_1:
|
||||
case WM9090_DC_SERVO_READBACK_2:
|
||||
return 1;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wait_for_dc_servo(struct snd_soc_codec *codec)
|
||||
{
|
||||
unsigned int reg;
|
||||
int count = 0;
|
||||
|
||||
dev_dbg(codec->dev, "Waiting for DC servo...\n");
|
||||
do {
|
||||
count++;
|
||||
msleep(1);
|
||||
reg = snd_soc_read(codec, WM9090_DC_SERVO_READBACK_0);
|
||||
dev_dbg(codec->dev, "DC servo status: %x\n", reg);
|
||||
} while ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
|
||||
!= WM9090_DCS_CAL_COMPLETE_MASK && count < 1000);
|
||||
|
||||
if ((reg & WM9090_DCS_CAL_COMPLETE_MASK)
|
||||
!= WM9090_DCS_CAL_COMPLETE_MASK)
|
||||
dev_err(codec->dev, "Timed out waiting for DC Servo\n");
|
||||
}
|
||||
|
||||
static const unsigned int in_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(6),
|
||||
0, 0, TLV_DB_SCALE_ITEM(-600, 0, 0),
|
||||
1, 3, TLV_DB_SCALE_ITEM(-350, 350, 0),
|
||||
4, 6, TLV_DB_SCALE_ITEM(600, 600, 0),
|
||||
};
|
||||
static const unsigned int mix_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(4),
|
||||
0, 2, TLV_DB_SCALE_ITEM(-1200, 300, 0),
|
||||
3, 3, TLV_DB_SCALE_ITEM(0, 0, 0),
|
||||
};
|
||||
static const DECLARE_TLV_DB_SCALE(out_tlv, -5700, 100, 0);
|
||||
static const unsigned int spkboost_tlv[] = {
|
||||
TLV_DB_RANGE_HEAD(7),
|
||||
0, 6, TLV_DB_SCALE_ITEM(0, 150, 0),
|
||||
7, 7, TLV_DB_SCALE_ITEM(1200, 0, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new wm9090_controls[] = {
|
||||
SOC_SINGLE_TLV("IN1A Volume", WM9090_IN1_LINE_INPUT_A_VOLUME, 0, 6, 0,
|
||||
in_tlv),
|
||||
SOC_SINGLE("IN1A Switch", WM9090_IN1_LINE_INPUT_A_VOLUME, 7, 1, 1),
|
||||
SOC_SINGLE("IN1A ZC Switch", WM9090_IN1_LINE_INPUT_A_VOLUME, 6, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("IN2A Volume", WM9090_IN2_LINE_INPUT_A_VOLUME, 0, 6, 0,
|
||||
in_tlv),
|
||||
SOC_SINGLE("IN2A Switch", WM9090_IN2_LINE_INPUT_A_VOLUME, 7, 1, 1),
|
||||
SOC_SINGLE("IN2A ZC Switch", WM9090_IN2_LINE_INPUT_A_VOLUME, 6, 1, 0),
|
||||
|
||||
SOC_SINGLE("MIXOUTL Switch", WM9090_OUTPUT_MIXER3, 8, 1, 1),
|
||||
SOC_SINGLE_TLV("MIXOUTL IN1A Volume", WM9090_OUTPUT_MIXER3, 6, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("MIXOUTL IN2A Volume", WM9090_OUTPUT_MIXER3, 2, 3, 1,
|
||||
mix_tlv),
|
||||
|
||||
SOC_SINGLE("MIXOUTR Switch", WM9090_OUTPUT_MIXER4, 8, 1, 1),
|
||||
SOC_SINGLE_TLV("MIXOUTR IN1A Volume", WM9090_OUTPUT_MIXER4, 6, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("MIXOUTR IN2A Volume", WM9090_OUTPUT_MIXER4, 2, 3, 1,
|
||||
mix_tlv),
|
||||
|
||||
SOC_SINGLE("SPKMIX Switch", WM9090_SPKMIXL_ATTENUATION, 8, 1, 1),
|
||||
SOC_SINGLE_TLV("SPKMIX IN1A Volume", WM9090_SPKMIXL_ATTENUATION, 6, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("SPKMIX IN2A Volume", WM9090_SPKMIXL_ATTENUATION, 2, 3, 1,
|
||||
mix_tlv),
|
||||
|
||||
SOC_DOUBLE_R_TLV("Headphone Volume", WM9090_LEFT_OUTPUT_VOLUME,
|
||||
WM9090_RIGHT_OUTPUT_VOLUME, 0, 63, 0, out_tlv),
|
||||
SOC_DOUBLE_R("Headphone Switch", WM9090_LEFT_OUTPUT_VOLUME,
|
||||
WM9090_RIGHT_OUTPUT_VOLUME, 6, 1, 1),
|
||||
SOC_DOUBLE_R("Headphone ZC Switch", WM9090_LEFT_OUTPUT_VOLUME,
|
||||
WM9090_RIGHT_OUTPUT_VOLUME, 7, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("Speaker Volume", WM9090_SPEAKER_VOLUME_LEFT, 0, 63, 0,
|
||||
out_tlv),
|
||||
SOC_SINGLE("Speaker Switch", WM9090_SPEAKER_VOLUME_LEFT, 6, 1, 1),
|
||||
SOC_SINGLE("Speaker ZC Switch", WM9090_SPEAKER_VOLUME_LEFT, 7, 1, 0),
|
||||
SOC_SINGLE_TLV("Speaker Boost Volume", WM9090_CLASSD3, 3, 7, 0, spkboost_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new wm9090_in1_se_controls[] = {
|
||||
SOC_SINGLE_TLV("IN1B Volume", WM9090_IN1_LINE_INPUT_B_VOLUME, 0, 6, 0,
|
||||
in_tlv),
|
||||
SOC_SINGLE("IN1B Switch", WM9090_IN1_LINE_INPUT_B_VOLUME, 7, 1, 1),
|
||||
SOC_SINGLE("IN1B ZC Switch", WM9090_IN1_LINE_INPUT_B_VOLUME, 6, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("SPKMIX IN1B Volume", WM9090_SPKMIXL_ATTENUATION, 4, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("MIXOUTL IN1B Volume", WM9090_OUTPUT_MIXER3, 4, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("MIXOUTR IN1B Volume", WM9090_OUTPUT_MIXER4, 4, 3, 1,
|
||||
mix_tlv),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new wm9090_in2_se_controls[] = {
|
||||
SOC_SINGLE_TLV("IN2B Volume", WM9090_IN2_LINE_INPUT_B_VOLUME, 0, 6, 0,
|
||||
in_tlv),
|
||||
SOC_SINGLE("IN2B Switch", WM9090_IN2_LINE_INPUT_B_VOLUME, 7, 1, 1),
|
||||
SOC_SINGLE("IN2B ZC Switch", WM9090_IN2_LINE_INPUT_B_VOLUME, 6, 1, 0),
|
||||
|
||||
SOC_SINGLE_TLV("SPKMIX IN2B Volume", WM9090_SPKMIXL_ATTENUATION, 0, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("MIXOUTL IN2B Volume", WM9090_OUTPUT_MIXER3, 0, 3, 1,
|
||||
mix_tlv),
|
||||
SOC_SINGLE_TLV("MIXOUTR IN2B Volume", WM9090_OUTPUT_MIXER4, 0, 3, 1,
|
||||
mix_tlv),
|
||||
};
|
||||
|
||||
static int hp_ev(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
unsigned int reg = snd_soc_read(codec, WM9090_ANALOGUE_HP_0);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_POST_PMU:
|
||||
snd_soc_update_bits(codec, WM9090_CHARGE_PUMP_1,
|
||||
WM9090_CP_ENA, WM9090_CP_ENA);
|
||||
|
||||
msleep(5);
|
||||
|
||||
snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
|
||||
WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
|
||||
WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA);
|
||||
|
||||
reg |= WM9090_HPOUT1L_DLY | WM9090_HPOUT1R_DLY;
|
||||
snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
|
||||
|
||||
/* Start the DC servo. We don't currently use the
|
||||
* ability to save the state since we don't have full
|
||||
* control of the analogue paths and they can change
|
||||
* DC offsets; see the WM8904 driver for an example of
|
||||
* doing so.
|
||||
*/
|
||||
snd_soc_write(codec, WM9090_DC_SERVO_0,
|
||||
WM9090_DCS_ENA_CHAN_0 |
|
||||
WM9090_DCS_ENA_CHAN_1 |
|
||||
WM9090_DCS_TRIG_STARTUP_1 |
|
||||
WM9090_DCS_TRIG_STARTUP_0);
|
||||
wait_for_dc_servo(codec);
|
||||
|
||||
reg |= WM9090_HPOUT1R_OUTP | WM9090_HPOUT1R_RMV_SHORT |
|
||||
WM9090_HPOUT1L_OUTP | WM9090_HPOUT1L_RMV_SHORT;
|
||||
snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
|
||||
break;
|
||||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
reg &= ~(WM9090_HPOUT1L_RMV_SHORT |
|
||||
WM9090_HPOUT1L_DLY |
|
||||
WM9090_HPOUT1L_OUTP |
|
||||
WM9090_HPOUT1R_RMV_SHORT |
|
||||
WM9090_HPOUT1R_DLY |
|
||||
WM9090_HPOUT1R_OUTP);
|
||||
|
||||
snd_soc_write(codec, WM9090_ANALOGUE_HP_0, reg);
|
||||
|
||||
snd_soc_write(codec, WM9090_DC_SERVO_0, 0);
|
||||
|
||||
snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
|
||||
WM9090_HPOUT1L_ENA | WM9090_HPOUT1R_ENA,
|
||||
0);
|
||||
|
||||
snd_soc_update_bits(codec, WM9090_CHARGE_PUMP_1,
|
||||
WM9090_CP_ENA, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_kcontrol_new spkmix[] = {
|
||||
SOC_DAPM_SINGLE("IN1A Switch", WM9090_SPEAKER_MIXER, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN1B Switch", WM9090_SPEAKER_MIXER, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN2A Switch", WM9090_SPEAKER_MIXER, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN2B Switch", WM9090_SPEAKER_MIXER, 0, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new spkout[] = {
|
||||
SOC_DAPM_SINGLE("Mixer Switch", WM9090_SPKOUT_MIXERS, 4, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new mixoutl[] = {
|
||||
SOC_DAPM_SINGLE("IN1A Switch", WM9090_OUTPUT_MIXER1, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN1B Switch", WM9090_OUTPUT_MIXER1, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN2A Switch", WM9090_OUTPUT_MIXER1, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN2B Switch", WM9090_OUTPUT_MIXER1, 0, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new mixoutr[] = {
|
||||
SOC_DAPM_SINGLE("IN1A Switch", WM9090_OUTPUT_MIXER2, 6, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN1B Switch", WM9090_OUTPUT_MIXER2, 4, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN2A Switch", WM9090_OUTPUT_MIXER2, 2, 1, 0),
|
||||
SOC_DAPM_SINGLE("IN2B Switch", WM9090_OUTPUT_MIXER2, 0, 1, 0),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_widget wm9090_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_INPUT("IN1+"),
|
||||
SND_SOC_DAPM_INPUT("IN1-"),
|
||||
SND_SOC_DAPM_INPUT("IN2+"),
|
||||
SND_SOC_DAPM_INPUT("IN2-"),
|
||||
|
||||
SND_SOC_DAPM_SUPPLY("OSC", WM9090_POWER_MANAGEMENT_1, 3, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_PGA("IN1A PGA", WM9090_POWER_MANAGEMENT_2, 7, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("IN1B PGA", WM9090_POWER_MANAGEMENT_2, 6, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("IN2A PGA", WM9090_POWER_MANAGEMENT_2, 5, 0, NULL, 0),
|
||||
SND_SOC_DAPM_PGA("IN2B PGA", WM9090_POWER_MANAGEMENT_2, 4, 0, NULL, 0),
|
||||
|
||||
SND_SOC_DAPM_MIXER("SPKMIX", WM9090_POWER_MANAGEMENT_3, 3, 0,
|
||||
spkmix, ARRAY_SIZE(spkmix)),
|
||||
SND_SOC_DAPM_MIXER("MIXOUTL", WM9090_POWER_MANAGEMENT_3, 5, 0,
|
||||
mixoutl, ARRAY_SIZE(mixoutl)),
|
||||
SND_SOC_DAPM_MIXER("MIXOUTR", WM9090_POWER_MANAGEMENT_3, 4, 0,
|
||||
mixoutr, ARRAY_SIZE(mixoutr)),
|
||||
|
||||
SND_SOC_DAPM_PGA_E("HP PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
|
||||
hp_ev, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
|
||||
|
||||
SND_SOC_DAPM_PGA("SPKPGA", WM9090_POWER_MANAGEMENT_3, 8, 0, NULL, 0),
|
||||
SND_SOC_DAPM_MIXER("SPKOUT", WM9090_POWER_MANAGEMENT_1, 12, 0,
|
||||
spkout, ARRAY_SIZE(spkout)),
|
||||
|
||||
SND_SOC_DAPM_OUTPUT("HPR"),
|
||||
SND_SOC_DAPM_OUTPUT("HPL"),
|
||||
SND_SOC_DAPM_OUTPUT("Speaker"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map[] = {
|
||||
{ "IN1A PGA", NULL, "IN1+" },
|
||||
{ "IN2A PGA", NULL, "IN2+" },
|
||||
|
||||
{ "SPKMIX", "IN1A Switch", "IN1A PGA" },
|
||||
{ "SPKMIX", "IN2A Switch", "IN2A PGA" },
|
||||
|
||||
{ "MIXOUTL", "IN1A Switch", "IN1A PGA" },
|
||||
{ "MIXOUTL", "IN2A Switch", "IN2A PGA" },
|
||||
|
||||
{ "MIXOUTR", "IN1A Switch", "IN1A PGA" },
|
||||
{ "MIXOUTR", "IN2A Switch", "IN2A PGA" },
|
||||
|
||||
{ "HP PGA", NULL, "OSC" },
|
||||
{ "HP PGA", NULL, "MIXOUTL" },
|
||||
{ "HP PGA", NULL, "MIXOUTR" },
|
||||
|
||||
{ "HPL", NULL, "HP PGA" },
|
||||
{ "HPR", NULL, "HP PGA" },
|
||||
|
||||
{ "SPKPGA", NULL, "OSC" },
|
||||
{ "SPKPGA", NULL, "SPKMIX" },
|
||||
|
||||
{ "SPKOUT", "Mixer Switch", "SPKPGA" },
|
||||
|
||||
{ "Speaker", NULL, "SPKOUT" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map_in1_se[] = {
|
||||
{ "IN1B PGA", NULL, "IN1-" },
|
||||
|
||||
{ "SPKMIX", "IN1B Switch", "IN1B PGA" },
|
||||
{ "MIXOUTL", "IN1B Switch", "IN1B PGA" },
|
||||
{ "MIXOUTR", "IN1B Switch", "IN1B PGA" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map_in1_diff[] = {
|
||||
{ "IN1A PGA", NULL, "IN1-" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map_in2_se[] = {
|
||||
{ "IN2B PGA", NULL, "IN2-" },
|
||||
|
||||
{ "SPKMIX", "IN2B Switch", "IN2B PGA" },
|
||||
{ "MIXOUTL", "IN2B Switch", "IN2B PGA" },
|
||||
{ "MIXOUTR", "IN2B Switch", "IN2B PGA" },
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route audio_map_in2_diff[] = {
|
||||
{ "IN2A PGA", NULL, "IN2-" },
|
||||
};
|
||||
|
||||
static int wm9090_add_controls(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm9090_priv *wm9090 = snd_soc_codec_get_drvdata(codec);
|
||||
int i;
|
||||
|
||||
snd_soc_dapm_new_controls(codec, wm9090_dapm_widgets,
|
||||
ARRAY_SIZE(wm9090_dapm_widgets));
|
||||
|
||||
snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map));
|
||||
|
||||
snd_soc_add_controls(codec, wm9090_controls,
|
||||
ARRAY_SIZE(wm9090_controls));
|
||||
|
||||
if (wm9090->pdata.lin1_diff) {
|
||||
snd_soc_dapm_add_routes(codec, audio_map_in1_diff,
|
||||
ARRAY_SIZE(audio_map_in1_diff));
|
||||
} else {
|
||||
snd_soc_dapm_add_routes(codec, audio_map_in1_se,
|
||||
ARRAY_SIZE(audio_map_in1_se));
|
||||
snd_soc_add_controls(codec, wm9090_in1_se_controls,
|
||||
ARRAY_SIZE(wm9090_in1_se_controls));
|
||||
}
|
||||
|
||||
if (wm9090->pdata.lin2_diff) {
|
||||
snd_soc_dapm_add_routes(codec, audio_map_in2_diff,
|
||||
ARRAY_SIZE(audio_map_in2_diff));
|
||||
} else {
|
||||
snd_soc_dapm_add_routes(codec, audio_map_in2_se,
|
||||
ARRAY_SIZE(audio_map_in2_se));
|
||||
snd_soc_add_controls(codec, wm9090_in2_se_controls,
|
||||
ARRAY_SIZE(wm9090_in2_se_controls));
|
||||
}
|
||||
|
||||
if (wm9090->pdata.agc_ena) {
|
||||
for (i = 0; i < ARRAY_SIZE(wm9090->pdata.agc); i++)
|
||||
snd_soc_write(codec, WM9090_AGC_CONTROL_0 + i,
|
||||
wm9090->pdata.agc[i]);
|
||||
snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_3,
|
||||
WM9090_AGC_ENA, WM9090_AGC_ENA);
|
||||
} else {
|
||||
snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_3,
|
||||
WM9090_AGC_ENA, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The machine driver should call this from their set_bias_level; if there
|
||||
* isn't one then this can just be set as the set_bias_level function.
|
||||
*/
|
||||
static int wm9090_set_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
u16 *reg_cache = codec->reg_cache;
|
||||
int i, ret;
|
||||
|
||||
switch (level) {
|
||||
case SND_SOC_BIAS_ON:
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_PREPARE:
|
||||
snd_soc_update_bits(codec, WM9090_ANTIPOP2, WM9090_VMID_ENA,
|
||||
WM9090_VMID_ENA);
|
||||
snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
|
||||
WM9090_BIAS_ENA |
|
||||
WM9090_VMID_RES_MASK,
|
||||
WM9090_BIAS_ENA |
|
||||
1 << WM9090_VMID_RES_SHIFT);
|
||||
msleep(1); /* Probably an overestimate */
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_STANDBY:
|
||||
if (codec->bias_level == SND_SOC_BIAS_OFF) {
|
||||
/* Restore the register cache */
|
||||
for (i = 1; i < codec->reg_cache_size; i++) {
|
||||
if (reg_cache[i] == wm9090_reg_defaults[i])
|
||||
continue;
|
||||
if (wm9090_volatile(i))
|
||||
continue;
|
||||
|
||||
ret = snd_soc_write(codec, i, reg_cache[i]);
|
||||
if (ret != 0)
|
||||
dev_warn(codec->dev,
|
||||
"Failed to restore register %d: %d\n",
|
||||
i, ret);
|
||||
}
|
||||
}
|
||||
|
||||
/* We keep VMID off during standby since the combination of
|
||||
* ground referenced outputs and class D speaker mean that
|
||||
* latency is not an issue.
|
||||
*/
|
||||
snd_soc_update_bits(codec, WM9090_POWER_MANAGEMENT_1,
|
||||
WM9090_BIAS_ENA | WM9090_VMID_RES_MASK, 0);
|
||||
snd_soc_update_bits(codec, WM9090_ANTIPOP2,
|
||||
WM9090_VMID_ENA, 0);
|
||||
break;
|
||||
|
||||
case SND_SOC_BIAS_OFF:
|
||||
break;
|
||||
}
|
||||
|
||||
codec->bias_level = level;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm9090_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec;
|
||||
int ret = 0;
|
||||
|
||||
if (wm9090_codec == NULL) {
|
||||
dev_err(&pdev->dev, "Codec device not registered\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
socdev->card->codec = wm9090_codec;
|
||||
codec = wm9090_codec;
|
||||
|
||||
/* register pcms */
|
||||
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to create pcms: %d\n", ret);
|
||||
goto pcm_err;
|
||||
}
|
||||
|
||||
wm9090_add_controls(codec);
|
||||
|
||||
return 0;
|
||||
|
||||
pcm_err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int wm9090_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm9090_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
|
||||
wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#define wm9090_suspend NULL
|
||||
#define wm9090_resume NULL
|
||||
#endif
|
||||
|
||||
static int wm9090_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_wm9090 = {
|
||||
.probe = wm9090_probe,
|
||||
.remove = wm9090_remove,
|
||||
.suspend = wm9090_suspend,
|
||||
.resume = wm9090_resume,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_codec_dev_wm9090);
|
||||
|
||||
static int wm9090_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm9090_priv *wm9090;
|
||||
struct snd_soc_codec *codec;
|
||||
int ret;
|
||||
|
||||
wm9090 = kzalloc(sizeof(*wm9090), GFP_KERNEL);
|
||||
if (wm9090 == NULL) {
|
||||
dev_err(&i2c->dev, "Can not allocate memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
codec = &wm9090->codec;
|
||||
|
||||
if (i2c->dev.platform_data)
|
||||
memcpy(&wm9090->pdata, i2c->dev.platform_data,
|
||||
sizeof(wm9090->pdata));
|
||||
|
||||
wm9090_codec = codec;
|
||||
|
||||
i2c_set_clientdata(i2c, wm9090);
|
||||
|
||||
mutex_init(&codec->mutex);
|
||||
INIT_LIST_HEAD(&codec->dapm_widgets);
|
||||
INIT_LIST_HEAD(&codec->dapm_paths);
|
||||
|
||||
codec->control_data = i2c;
|
||||
snd_soc_codec_set_drvdata(codec, wm9090);
|
||||
codec->dev = &i2c->dev;
|
||||
codec->name = "WM9090";
|
||||
codec->owner = THIS_MODULE;
|
||||
codec->bias_level = SND_SOC_BIAS_OFF;
|
||||
codec->set_bias_level = wm9090_set_bias_level,
|
||||
codec->reg_cache_size = WM9090_MAX_REGISTER + 1;
|
||||
codec->reg_cache = &wm9090->reg_cache;
|
||||
codec->volatile_register = wm9090_volatile;
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
memcpy(&wm9090->reg_cache, wm9090_reg_defaults,
|
||||
sizeof(wm9090->reg_cache));
|
||||
|
||||
ret = snd_soc_read(codec, WM9090_SOFTWARE_RESET);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
if (ret != wm9090_reg_defaults[WM9090_SOFTWARE_RESET]) {
|
||||
dev_err(&i2c->dev, "Device is not a WM9090, ID=%x\n", ret);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = snd_soc_write(codec, WM9090_SOFTWARE_RESET, 0);
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
/* Configure some defaults; they will be written out when we
|
||||
* bring the bias up.
|
||||
*/
|
||||
wm9090->reg_cache[WM9090_IN1_LINE_INPUT_A_VOLUME] |= WM9090_IN1_VU
|
||||
| WM9090_IN1A_ZC;
|
||||
wm9090->reg_cache[WM9090_IN1_LINE_INPUT_B_VOLUME] |= WM9090_IN1_VU
|
||||
| WM9090_IN1B_ZC;
|
||||
wm9090->reg_cache[WM9090_IN2_LINE_INPUT_A_VOLUME] |= WM9090_IN2_VU
|
||||
| WM9090_IN2A_ZC;
|
||||
wm9090->reg_cache[WM9090_IN2_LINE_INPUT_B_VOLUME] |= WM9090_IN2_VU
|
||||
| WM9090_IN2B_ZC;
|
||||
wm9090->reg_cache[WM9090_SPEAKER_VOLUME_LEFT] |=
|
||||
WM9090_SPKOUT_VU | WM9090_SPKOUTL_ZC;
|
||||
wm9090->reg_cache[WM9090_LEFT_OUTPUT_VOLUME] |=
|
||||
WM9090_HPOUT1_VU | WM9090_HPOUT1L_ZC;
|
||||
wm9090->reg_cache[WM9090_RIGHT_OUTPUT_VOLUME] |=
|
||||
WM9090_HPOUT1_VU | WM9090_HPOUT1R_ZC;
|
||||
|
||||
wm9090->reg_cache[WM9090_CLOCKING_1] |= WM9090_TOCLK_ENA;
|
||||
|
||||
wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
||||
ret = snd_soc_register_codec(codec);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
|
||||
goto err_bias;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_bias:
|
||||
wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
err:
|
||||
kfree(wm9090);
|
||||
i2c_set_clientdata(i2c, NULL);
|
||||
wm9090_codec = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm9090_i2c_remove(struct i2c_client *i2c)
|
||||
{
|
||||
struct wm9090_priv *wm9090 = i2c_get_clientdata(i2c);
|
||||
struct snd_soc_codec *codec = &wm9090->codec;
|
||||
|
||||
snd_soc_unregister_codec(codec);
|
||||
wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
kfree(wm9090);
|
||||
wm9090_codec = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id wm9090_id[] = {
|
||||
{ "wm9090", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, wm9090_id);
|
||||
|
||||
static struct i2c_driver wm9090_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm9090",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = wm9090_i2c_probe,
|
||||
.remove = __devexit_p(wm9090_i2c_remove),
|
||||
.id_table = wm9090_id,
|
||||
};
|
||||
|
||||
static int __init wm9090_init(void)
|
||||
{
|
||||
return i2c_add_driver(&wm9090_i2c_driver);
|
||||
}
|
||||
module_init(wm9090_init);
|
||||
|
||||
static void __exit wm9090_exit(void)
|
||||
{
|
||||
i2c_del_driver(&wm9090_i2c_driver);
|
||||
}
|
||||
module_exit(wm9090_exit);
|
||||
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
MODULE_DESCRIPTION("WM9090 ASoC driver");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,715 @@
|
|||
/*
|
||||
* ALSA SoC WM9090 driver
|
||||
*
|
||||
* Copyright 2009 Wolfson Microelectronics
|
||||
*
|
||||
* Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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 __WM9090_H
|
||||
#define __WM9090_H
|
||||
|
||||
extern struct snd_soc_codec_device soc_codec_dev_wm9090;
|
||||
|
||||
/*
|
||||
* Register values.
|
||||
*/
|
||||
#define WM9090_SOFTWARE_RESET 0x00
|
||||
#define WM9090_POWER_MANAGEMENT_1 0x01
|
||||
#define WM9090_POWER_MANAGEMENT_2 0x02
|
||||
#define WM9090_POWER_MANAGEMENT_3 0x03
|
||||
#define WM9090_CLOCKING_1 0x06
|
||||
#define WM9090_IN1_LINE_CONTROL 0x16
|
||||
#define WM9090_IN2_LINE_CONTROL 0x17
|
||||
#define WM9090_IN1_LINE_INPUT_A_VOLUME 0x18
|
||||
#define WM9090_IN1_LINE_INPUT_B_VOLUME 0x19
|
||||
#define WM9090_IN2_LINE_INPUT_A_VOLUME 0x1A
|
||||
#define WM9090_IN2_LINE_INPUT_B_VOLUME 0x1B
|
||||
#define WM9090_LEFT_OUTPUT_VOLUME 0x1C
|
||||
#define WM9090_RIGHT_OUTPUT_VOLUME 0x1D
|
||||
#define WM9090_SPKMIXL_ATTENUATION 0x22
|
||||
#define WM9090_SPKOUT_MIXERS 0x24
|
||||
#define WM9090_CLASSD3 0x25
|
||||
#define WM9090_SPEAKER_VOLUME_LEFT 0x26
|
||||
#define WM9090_OUTPUT_MIXER1 0x2D
|
||||
#define WM9090_OUTPUT_MIXER2 0x2E
|
||||
#define WM9090_OUTPUT_MIXER3 0x2F
|
||||
#define WM9090_OUTPUT_MIXER4 0x30
|
||||
#define WM9090_SPEAKER_MIXER 0x36
|
||||
#define WM9090_ANTIPOP2 0x39
|
||||
#define WM9090_WRITE_SEQUENCER_0 0x46
|
||||
#define WM9090_WRITE_SEQUENCER_1 0x47
|
||||
#define WM9090_WRITE_SEQUENCER_2 0x48
|
||||
#define WM9090_WRITE_SEQUENCER_3 0x49
|
||||
#define WM9090_WRITE_SEQUENCER_4 0x4A
|
||||
#define WM9090_WRITE_SEQUENCER_5 0x4B
|
||||
#define WM9090_CHARGE_PUMP_1 0x4C
|
||||
#define WM9090_DC_SERVO_0 0x54
|
||||
#define WM9090_DC_SERVO_1 0x55
|
||||
#define WM9090_DC_SERVO_3 0x57
|
||||
#define WM9090_DC_SERVO_READBACK_0 0x58
|
||||
#define WM9090_DC_SERVO_READBACK_1 0x59
|
||||
#define WM9090_DC_SERVO_READBACK_2 0x5A
|
||||
#define WM9090_ANALOGUE_HP_0 0x60
|
||||
#define WM9090_AGC_CONTROL_0 0x62
|
||||
#define WM9090_AGC_CONTROL_1 0x63
|
||||
#define WM9090_AGC_CONTROL_2 0x64
|
||||
|
||||
#define WM9090_REGISTER_COUNT 40
|
||||
#define WM9090_MAX_REGISTER 0x64
|
||||
|
||||
/*
|
||||
* Field Definitions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* R0 (0x00) - Software Reset
|
||||
*/
|
||||
#define WM9090_SW_RESET_MASK 0xFFFF /* SW_RESET - [15:0] */
|
||||
#define WM9090_SW_RESET_SHIFT 0 /* SW_RESET - [15:0] */
|
||||
#define WM9090_SW_RESET_WIDTH 16 /* SW_RESET - [15:0] */
|
||||
|
||||
/*
|
||||
* R1 (0x01) - Power Management (1)
|
||||
*/
|
||||
#define WM9090_SPKOUTL_ENA 0x1000 /* SPKOUTL_ENA */
|
||||
#define WM9090_SPKOUTL_ENA_MASK 0x1000 /* SPKOUTL_ENA */
|
||||
#define WM9090_SPKOUTL_ENA_SHIFT 12 /* SPKOUTL_ENA */
|
||||
#define WM9090_SPKOUTL_ENA_WIDTH 1 /* SPKOUTL_ENA */
|
||||
#define WM9090_HPOUT1L_ENA 0x0200 /* HPOUT1L_ENA */
|
||||
#define WM9090_HPOUT1L_ENA_MASK 0x0200 /* HPOUT1L_ENA */
|
||||
#define WM9090_HPOUT1L_ENA_SHIFT 9 /* HPOUT1L_ENA */
|
||||
#define WM9090_HPOUT1L_ENA_WIDTH 1 /* HPOUT1L_ENA */
|
||||
#define WM9090_HPOUT1R_ENA 0x0100 /* HPOUT1R_ENA */
|
||||
#define WM9090_HPOUT1R_ENA_MASK 0x0100 /* HPOUT1R_ENA */
|
||||
#define WM9090_HPOUT1R_ENA_SHIFT 8 /* HPOUT1R_ENA */
|
||||
#define WM9090_HPOUT1R_ENA_WIDTH 1 /* HPOUT1R_ENA */
|
||||
#define WM9090_OSC_ENA 0x0008 /* OSC_ENA */
|
||||
#define WM9090_OSC_ENA_MASK 0x0008 /* OSC_ENA */
|
||||
#define WM9090_OSC_ENA_SHIFT 3 /* OSC_ENA */
|
||||
#define WM9090_OSC_ENA_WIDTH 1 /* OSC_ENA */
|
||||
#define WM9090_VMID_RES_MASK 0x0006 /* VMID_RES - [2:1] */
|
||||
#define WM9090_VMID_RES_SHIFT 1 /* VMID_RES - [2:1] */
|
||||
#define WM9090_VMID_RES_WIDTH 2 /* VMID_RES - [2:1] */
|
||||
#define WM9090_BIAS_ENA 0x0001 /* BIAS_ENA */
|
||||
#define WM9090_BIAS_ENA_MASK 0x0001 /* BIAS_ENA */
|
||||
#define WM9090_BIAS_ENA_SHIFT 0 /* BIAS_ENA */
|
||||
#define WM9090_BIAS_ENA_WIDTH 1 /* BIAS_ENA */
|
||||
|
||||
/*
|
||||
* R2 (0x02) - Power Management (2)
|
||||
*/
|
||||
#define WM9090_TSHUT 0x8000 /* TSHUT */
|
||||
#define WM9090_TSHUT_MASK 0x8000 /* TSHUT */
|
||||
#define WM9090_TSHUT_SHIFT 15 /* TSHUT */
|
||||
#define WM9090_TSHUT_WIDTH 1 /* TSHUT */
|
||||
#define WM9090_TSHUT_ENA 0x4000 /* TSHUT_ENA */
|
||||
#define WM9090_TSHUT_ENA_MASK 0x4000 /* TSHUT_ENA */
|
||||
#define WM9090_TSHUT_ENA_SHIFT 14 /* TSHUT_ENA */
|
||||
#define WM9090_TSHUT_ENA_WIDTH 1 /* TSHUT_ENA */
|
||||
#define WM9090_TSHUT_OPDIS 0x2000 /* TSHUT_OPDIS */
|
||||
#define WM9090_TSHUT_OPDIS_MASK 0x2000 /* TSHUT_OPDIS */
|
||||
#define WM9090_TSHUT_OPDIS_SHIFT 13 /* TSHUT_OPDIS */
|
||||
#define WM9090_TSHUT_OPDIS_WIDTH 1 /* TSHUT_OPDIS */
|
||||
#define WM9090_IN1A_ENA 0x0080 /* IN1A_ENA */
|
||||
#define WM9090_IN1A_ENA_MASK 0x0080 /* IN1A_ENA */
|
||||
#define WM9090_IN1A_ENA_SHIFT 7 /* IN1A_ENA */
|
||||
#define WM9090_IN1A_ENA_WIDTH 1 /* IN1A_ENA */
|
||||
#define WM9090_IN1B_ENA 0x0040 /* IN1B_ENA */
|
||||
#define WM9090_IN1B_ENA_MASK 0x0040 /* IN1B_ENA */
|
||||
#define WM9090_IN1B_ENA_SHIFT 6 /* IN1B_ENA */
|
||||
#define WM9090_IN1B_ENA_WIDTH 1 /* IN1B_ENA */
|
||||
#define WM9090_IN2A_ENA 0x0020 /* IN2A_ENA */
|
||||
#define WM9090_IN2A_ENA_MASK 0x0020 /* IN2A_ENA */
|
||||
#define WM9090_IN2A_ENA_SHIFT 5 /* IN2A_ENA */
|
||||
#define WM9090_IN2A_ENA_WIDTH 1 /* IN2A_ENA */
|
||||
#define WM9090_IN2B_ENA 0x0010 /* IN2B_ENA */
|
||||
#define WM9090_IN2B_ENA_MASK 0x0010 /* IN2B_ENA */
|
||||
#define WM9090_IN2B_ENA_SHIFT 4 /* IN2B_ENA */
|
||||
#define WM9090_IN2B_ENA_WIDTH 1 /* IN2B_ENA */
|
||||
|
||||
/*
|
||||
* R3 (0x03) - Power Management (3)
|
||||
*/
|
||||
#define WM9090_AGC_ENA 0x4000 /* AGC_ENA */
|
||||
#define WM9090_AGC_ENA_MASK 0x4000 /* AGC_ENA */
|
||||
#define WM9090_AGC_ENA_SHIFT 14 /* AGC_ENA */
|
||||
#define WM9090_AGC_ENA_WIDTH 1 /* AGC_ENA */
|
||||
#define WM9090_SPKLVOL_ENA 0x0100 /* SPKLVOL_ENA */
|
||||
#define WM9090_SPKLVOL_ENA_MASK 0x0100 /* SPKLVOL_ENA */
|
||||
#define WM9090_SPKLVOL_ENA_SHIFT 8 /* SPKLVOL_ENA */
|
||||
#define WM9090_SPKLVOL_ENA_WIDTH 1 /* SPKLVOL_ENA */
|
||||
#define WM9090_MIXOUTL_ENA 0x0020 /* MIXOUTL_ENA */
|
||||
#define WM9090_MIXOUTL_ENA_MASK 0x0020 /* MIXOUTL_ENA */
|
||||
#define WM9090_MIXOUTL_ENA_SHIFT 5 /* MIXOUTL_ENA */
|
||||
#define WM9090_MIXOUTL_ENA_WIDTH 1 /* MIXOUTL_ENA */
|
||||
#define WM9090_MIXOUTR_ENA 0x0010 /* MIXOUTR_ENA */
|
||||
#define WM9090_MIXOUTR_ENA_MASK 0x0010 /* MIXOUTR_ENA */
|
||||
#define WM9090_MIXOUTR_ENA_SHIFT 4 /* MIXOUTR_ENA */
|
||||
#define WM9090_MIXOUTR_ENA_WIDTH 1 /* MIXOUTR_ENA */
|
||||
#define WM9090_SPKMIX_ENA 0x0008 /* SPKMIX_ENA */
|
||||
#define WM9090_SPKMIX_ENA_MASK 0x0008 /* SPKMIX_ENA */
|
||||
#define WM9090_SPKMIX_ENA_SHIFT 3 /* SPKMIX_ENA */
|
||||
#define WM9090_SPKMIX_ENA_WIDTH 1 /* SPKMIX_ENA */
|
||||
|
||||
/*
|
||||
* R6 (0x06) - Clocking 1
|
||||
*/
|
||||
#define WM9090_TOCLK_RATE 0x8000 /* TOCLK_RATE */
|
||||
#define WM9090_TOCLK_RATE_MASK 0x8000 /* TOCLK_RATE */
|
||||
#define WM9090_TOCLK_RATE_SHIFT 15 /* TOCLK_RATE */
|
||||
#define WM9090_TOCLK_RATE_WIDTH 1 /* TOCLK_RATE */
|
||||
#define WM9090_TOCLK_ENA 0x4000 /* TOCLK_ENA */
|
||||
#define WM9090_TOCLK_ENA_MASK 0x4000 /* TOCLK_ENA */
|
||||
#define WM9090_TOCLK_ENA_SHIFT 14 /* TOCLK_ENA */
|
||||
#define WM9090_TOCLK_ENA_WIDTH 1 /* TOCLK_ENA */
|
||||
|
||||
/*
|
||||
* R22 (0x16) - IN1 Line Control
|
||||
*/
|
||||
#define WM9090_IN1_DIFF 0x0002 /* IN1_DIFF */
|
||||
#define WM9090_IN1_DIFF_MASK 0x0002 /* IN1_DIFF */
|
||||
#define WM9090_IN1_DIFF_SHIFT 1 /* IN1_DIFF */
|
||||
#define WM9090_IN1_DIFF_WIDTH 1 /* IN1_DIFF */
|
||||
#define WM9090_IN1_CLAMP 0x0001 /* IN1_CLAMP */
|
||||
#define WM9090_IN1_CLAMP_MASK 0x0001 /* IN1_CLAMP */
|
||||
#define WM9090_IN1_CLAMP_SHIFT 0 /* IN1_CLAMP */
|
||||
#define WM9090_IN1_CLAMP_WIDTH 1 /* IN1_CLAMP */
|
||||
|
||||
/*
|
||||
* R23 (0x17) - IN2 Line Control
|
||||
*/
|
||||
#define WM9090_IN2_DIFF 0x0002 /* IN2_DIFF */
|
||||
#define WM9090_IN2_DIFF_MASK 0x0002 /* IN2_DIFF */
|
||||
#define WM9090_IN2_DIFF_SHIFT 1 /* IN2_DIFF */
|
||||
#define WM9090_IN2_DIFF_WIDTH 1 /* IN2_DIFF */
|
||||
#define WM9090_IN2_CLAMP 0x0001 /* IN2_CLAMP */
|
||||
#define WM9090_IN2_CLAMP_MASK 0x0001 /* IN2_CLAMP */
|
||||
#define WM9090_IN2_CLAMP_SHIFT 0 /* IN2_CLAMP */
|
||||
#define WM9090_IN2_CLAMP_WIDTH 1 /* IN2_CLAMP */
|
||||
|
||||
/*
|
||||
* R24 (0x18) - IN1 Line Input A Volume
|
||||
*/
|
||||
#define WM9090_IN1_VU 0x0100 /* IN1_VU */
|
||||
#define WM9090_IN1_VU_MASK 0x0100 /* IN1_VU */
|
||||
#define WM9090_IN1_VU_SHIFT 8 /* IN1_VU */
|
||||
#define WM9090_IN1_VU_WIDTH 1 /* IN1_VU */
|
||||
#define WM9090_IN1A_MUTE 0x0080 /* IN1A_MUTE */
|
||||
#define WM9090_IN1A_MUTE_MASK 0x0080 /* IN1A_MUTE */
|
||||
#define WM9090_IN1A_MUTE_SHIFT 7 /* IN1A_MUTE */
|
||||
#define WM9090_IN1A_MUTE_WIDTH 1 /* IN1A_MUTE */
|
||||
#define WM9090_IN1A_ZC 0x0040 /* IN1A_ZC */
|
||||
#define WM9090_IN1A_ZC_MASK 0x0040 /* IN1A_ZC */
|
||||
#define WM9090_IN1A_ZC_SHIFT 6 /* IN1A_ZC */
|
||||
#define WM9090_IN1A_ZC_WIDTH 1 /* IN1A_ZC */
|
||||
#define WM9090_IN1A_VOL_MASK 0x0007 /* IN1A_VOL - [2:0] */
|
||||
#define WM9090_IN1A_VOL_SHIFT 0 /* IN1A_VOL - [2:0] */
|
||||
#define WM9090_IN1A_VOL_WIDTH 3 /* IN1A_VOL - [2:0] */
|
||||
|
||||
/*
|
||||
* R25 (0x19) - IN1 Line Input B Volume
|
||||
*/
|
||||
#define WM9090_IN1_VU 0x0100 /* IN1_VU */
|
||||
#define WM9090_IN1_VU_MASK 0x0100 /* IN1_VU */
|
||||
#define WM9090_IN1_VU_SHIFT 8 /* IN1_VU */
|
||||
#define WM9090_IN1_VU_WIDTH 1 /* IN1_VU */
|
||||
#define WM9090_IN1B_MUTE 0x0080 /* IN1B_MUTE */
|
||||
#define WM9090_IN1B_MUTE_MASK 0x0080 /* IN1B_MUTE */
|
||||
#define WM9090_IN1B_MUTE_SHIFT 7 /* IN1B_MUTE */
|
||||
#define WM9090_IN1B_MUTE_WIDTH 1 /* IN1B_MUTE */
|
||||
#define WM9090_IN1B_ZC 0x0040 /* IN1B_ZC */
|
||||
#define WM9090_IN1B_ZC_MASK 0x0040 /* IN1B_ZC */
|
||||
#define WM9090_IN1B_ZC_SHIFT 6 /* IN1B_ZC */
|
||||
#define WM9090_IN1B_ZC_WIDTH 1 /* IN1B_ZC */
|
||||
#define WM9090_IN1B_VOL_MASK 0x0007 /* IN1B_VOL - [2:0] */
|
||||
#define WM9090_IN1B_VOL_SHIFT 0 /* IN1B_VOL - [2:0] */
|
||||
#define WM9090_IN1B_VOL_WIDTH 3 /* IN1B_VOL - [2:0] */
|
||||
|
||||
/*
|
||||
* R26 (0x1A) - IN2 Line Input A Volume
|
||||
*/
|
||||
#define WM9090_IN2_VU 0x0100 /* IN2_VU */
|
||||
#define WM9090_IN2_VU_MASK 0x0100 /* IN2_VU */
|
||||
#define WM9090_IN2_VU_SHIFT 8 /* IN2_VU */
|
||||
#define WM9090_IN2_VU_WIDTH 1 /* IN2_VU */
|
||||
#define WM9090_IN2A_MUTE 0x0080 /* IN2A_MUTE */
|
||||
#define WM9090_IN2A_MUTE_MASK 0x0080 /* IN2A_MUTE */
|
||||
#define WM9090_IN2A_MUTE_SHIFT 7 /* IN2A_MUTE */
|
||||
#define WM9090_IN2A_MUTE_WIDTH 1 /* IN2A_MUTE */
|
||||
#define WM9090_IN2A_ZC 0x0040 /* IN2A_ZC */
|
||||
#define WM9090_IN2A_ZC_MASK 0x0040 /* IN2A_ZC */
|
||||
#define WM9090_IN2A_ZC_SHIFT 6 /* IN2A_ZC */
|
||||
#define WM9090_IN2A_ZC_WIDTH 1 /* IN2A_ZC */
|
||||
#define WM9090_IN2A_VOL_MASK 0x0007 /* IN2A_VOL - [2:0] */
|
||||
#define WM9090_IN2A_VOL_SHIFT 0 /* IN2A_VOL - [2:0] */
|
||||
#define WM9090_IN2A_VOL_WIDTH 3 /* IN2A_VOL - [2:0] */
|
||||
|
||||
/*
|
||||
* R27 (0x1B) - IN2 Line Input B Volume
|
||||
*/
|
||||
#define WM9090_IN2_VU 0x0100 /* IN2_VU */
|
||||
#define WM9090_IN2_VU_MASK 0x0100 /* IN2_VU */
|
||||
#define WM9090_IN2_VU_SHIFT 8 /* IN2_VU */
|
||||
#define WM9090_IN2_VU_WIDTH 1 /* IN2_VU */
|
||||
#define WM9090_IN2B_MUTE 0x0080 /* IN2B_MUTE */
|
||||
#define WM9090_IN2B_MUTE_MASK 0x0080 /* IN2B_MUTE */
|
||||
#define WM9090_IN2B_MUTE_SHIFT 7 /* IN2B_MUTE */
|
||||
#define WM9090_IN2B_MUTE_WIDTH 1 /* IN2B_MUTE */
|
||||
#define WM9090_IN2B_ZC 0x0040 /* IN2B_ZC */
|
||||
#define WM9090_IN2B_ZC_MASK 0x0040 /* IN2B_ZC */
|
||||
#define WM9090_IN2B_ZC_SHIFT 6 /* IN2B_ZC */
|
||||
#define WM9090_IN2B_ZC_WIDTH 1 /* IN2B_ZC */
|
||||
#define WM9090_IN2B_VOL_MASK 0x0007 /* IN2B_VOL - [2:0] */
|
||||
#define WM9090_IN2B_VOL_SHIFT 0 /* IN2B_VOL - [2:0] */
|
||||
#define WM9090_IN2B_VOL_WIDTH 3 /* IN2B_VOL - [2:0] */
|
||||
|
||||
/*
|
||||
* R28 (0x1C) - Left Output Volume
|
||||
*/
|
||||
#define WM9090_HPOUT1_VU 0x0100 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1L_ZC 0x0080 /* HPOUT1L_ZC */
|
||||
#define WM9090_HPOUT1L_ZC_MASK 0x0080 /* HPOUT1L_ZC */
|
||||
#define WM9090_HPOUT1L_ZC_SHIFT 7 /* HPOUT1L_ZC */
|
||||
#define WM9090_HPOUT1L_ZC_WIDTH 1 /* HPOUT1L_ZC */
|
||||
#define WM9090_HPOUT1L_MUTE 0x0040 /* HPOUT1L_MUTE */
|
||||
#define WM9090_HPOUT1L_MUTE_MASK 0x0040 /* HPOUT1L_MUTE */
|
||||
#define WM9090_HPOUT1L_MUTE_SHIFT 6 /* HPOUT1L_MUTE */
|
||||
#define WM9090_HPOUT1L_MUTE_WIDTH 1 /* HPOUT1L_MUTE */
|
||||
#define WM9090_HPOUT1L_VOL_MASK 0x003F /* HPOUT1L_VOL - [5:0] */
|
||||
#define WM9090_HPOUT1L_VOL_SHIFT 0 /* HPOUT1L_VOL - [5:0] */
|
||||
#define WM9090_HPOUT1L_VOL_WIDTH 6 /* HPOUT1L_VOL - [5:0] */
|
||||
|
||||
/*
|
||||
* R29 (0x1D) - Right Output Volume
|
||||
*/
|
||||
#define WM9090_HPOUT1_VU 0x0100 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1_VU_MASK 0x0100 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1_VU_SHIFT 8 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1_VU_WIDTH 1 /* HPOUT1_VU */
|
||||
#define WM9090_HPOUT1R_ZC 0x0080 /* HPOUT1R_ZC */
|
||||
#define WM9090_HPOUT1R_ZC_MASK 0x0080 /* HPOUT1R_ZC */
|
||||
#define WM9090_HPOUT1R_ZC_SHIFT 7 /* HPOUT1R_ZC */
|
||||
#define WM9090_HPOUT1R_ZC_WIDTH 1 /* HPOUT1R_ZC */
|
||||
#define WM9090_HPOUT1R_MUTE 0x0040 /* HPOUT1R_MUTE */
|
||||
#define WM9090_HPOUT1R_MUTE_MASK 0x0040 /* HPOUT1R_MUTE */
|
||||
#define WM9090_HPOUT1R_MUTE_SHIFT 6 /* HPOUT1R_MUTE */
|
||||
#define WM9090_HPOUT1R_MUTE_WIDTH 1 /* HPOUT1R_MUTE */
|
||||
#define WM9090_HPOUT1R_VOL_MASK 0x003F /* HPOUT1R_VOL - [5:0] */
|
||||
#define WM9090_HPOUT1R_VOL_SHIFT 0 /* HPOUT1R_VOL - [5:0] */
|
||||
#define WM9090_HPOUT1R_VOL_WIDTH 6 /* HPOUT1R_VOL - [5:0] */
|
||||
|
||||
/*
|
||||
* R34 (0x22) - SPKMIXL Attenuation
|
||||
*/
|
||||
#define WM9090_SPKMIX_MUTE 0x0100 /* SPKMIX_MUTE */
|
||||
#define WM9090_SPKMIX_MUTE_MASK 0x0100 /* SPKMIX_MUTE */
|
||||
#define WM9090_SPKMIX_MUTE_SHIFT 8 /* SPKMIX_MUTE */
|
||||
#define WM9090_SPKMIX_MUTE_WIDTH 1 /* SPKMIX_MUTE */
|
||||
#define WM9090_IN1A_SPKMIX_VOL_MASK 0x00C0 /* IN1A_SPKMIX_VOL - [7:6] */
|
||||
#define WM9090_IN1A_SPKMIX_VOL_SHIFT 6 /* IN1A_SPKMIX_VOL - [7:6] */
|
||||
#define WM9090_IN1A_SPKMIX_VOL_WIDTH 2 /* IN1A_SPKMIX_VOL - [7:6] */
|
||||
#define WM9090_IN1B_SPKMIX_VOL_MASK 0x0030 /* IN1B_SPKMIX_VOL - [5:4] */
|
||||
#define WM9090_IN1B_SPKMIX_VOL_SHIFT 4 /* IN1B_SPKMIX_VOL - [5:4] */
|
||||
#define WM9090_IN1B_SPKMIX_VOL_WIDTH 2 /* IN1B_SPKMIX_VOL - [5:4] */
|
||||
#define WM9090_IN2A_SPKMIX_VOL_MASK 0x000C /* IN2A_SPKMIX_VOL - [3:2] */
|
||||
#define WM9090_IN2A_SPKMIX_VOL_SHIFT 2 /* IN2A_SPKMIX_VOL - [3:2] */
|
||||
#define WM9090_IN2A_SPKMIX_VOL_WIDTH 2 /* IN2A_SPKMIX_VOL - [3:2] */
|
||||
#define WM9090_IN2B_SPKMIX_VOL_MASK 0x0003 /* IN2B_SPKMIX_VOL - [1:0] */
|
||||
#define WM9090_IN2B_SPKMIX_VOL_SHIFT 0 /* IN2B_SPKMIX_VOL - [1:0] */
|
||||
#define WM9090_IN2B_SPKMIX_VOL_WIDTH 2 /* IN2B_SPKMIX_VOL - [1:0] */
|
||||
|
||||
/*
|
||||
* R36 (0x24) - SPKOUT Mixers
|
||||
*/
|
||||
#define WM9090_SPKMIXL_TO_SPKOUTL 0x0010 /* SPKMIXL_TO_SPKOUTL */
|
||||
#define WM9090_SPKMIXL_TO_SPKOUTL_MASK 0x0010 /* SPKMIXL_TO_SPKOUTL */
|
||||
#define WM9090_SPKMIXL_TO_SPKOUTL_SHIFT 4 /* SPKMIXL_TO_SPKOUTL */
|
||||
#define WM9090_SPKMIXL_TO_SPKOUTL_WIDTH 1 /* SPKMIXL_TO_SPKOUTL */
|
||||
|
||||
/*
|
||||
* R37 (0x25) - ClassD3
|
||||
*/
|
||||
#define WM9090_SPKOUTL_BOOST_MASK 0x0038 /* SPKOUTL_BOOST - [5:3] */
|
||||
#define WM9090_SPKOUTL_BOOST_SHIFT 3 /* SPKOUTL_BOOST - [5:3] */
|
||||
#define WM9090_SPKOUTL_BOOST_WIDTH 3 /* SPKOUTL_BOOST - [5:3] */
|
||||
|
||||
/*
|
||||
* R38 (0x26) - Speaker Volume Left
|
||||
*/
|
||||
#define WM9090_SPKOUT_VU 0x0100 /* SPKOUT_VU */
|
||||
#define WM9090_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
|
||||
#define WM9090_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
|
||||
#define WM9090_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
|
||||
#define WM9090_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */
|
||||
#define WM9090_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */
|
||||
#define WM9090_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */
|
||||
#define WM9090_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */
|
||||
#define WM9090_SPKOUTL_MUTE 0x0040 /* SPKOUTL_MUTE */
|
||||
#define WM9090_SPKOUTL_MUTE_MASK 0x0040 /* SPKOUTL_MUTE */
|
||||
#define WM9090_SPKOUTL_MUTE_SHIFT 6 /* SPKOUTL_MUTE */
|
||||
#define WM9090_SPKOUTL_MUTE_WIDTH 1 /* SPKOUTL_MUTE */
|
||||
#define WM9090_SPKOUTL_VOL_MASK 0x003F /* SPKOUTL_VOL - [5:0] */
|
||||
#define WM9090_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [5:0] */
|
||||
#define WM9090_SPKOUTL_VOL_WIDTH 6 /* SPKOUTL_VOL - [5:0] */
|
||||
|
||||
/*
|
||||
* R45 (0x2D) - Output Mixer1
|
||||
*/
|
||||
#define WM9090_IN1A_TO_MIXOUTL 0x0040 /* IN1A_TO_MIXOUTL */
|
||||
#define WM9090_IN1A_TO_MIXOUTL_MASK 0x0040 /* IN1A_TO_MIXOUTL */
|
||||
#define WM9090_IN1A_TO_MIXOUTL_SHIFT 6 /* IN1A_TO_MIXOUTL */
|
||||
#define WM9090_IN1A_TO_MIXOUTL_WIDTH 1 /* IN1A_TO_MIXOUTL */
|
||||
#define WM9090_IN2A_TO_MIXOUTL 0x0004 /* IN2A_TO_MIXOUTL */
|
||||
#define WM9090_IN2A_TO_MIXOUTL_MASK 0x0004 /* IN2A_TO_MIXOUTL */
|
||||
#define WM9090_IN2A_TO_MIXOUTL_SHIFT 2 /* IN2A_TO_MIXOUTL */
|
||||
#define WM9090_IN2A_TO_MIXOUTL_WIDTH 1 /* IN2A_TO_MIXOUTL */
|
||||
|
||||
/*
|
||||
* R46 (0x2E) - Output Mixer2
|
||||
*/
|
||||
#define WM9090_IN1A_TO_MIXOUTR 0x0040 /* IN1A_TO_MIXOUTR */
|
||||
#define WM9090_IN1A_TO_MIXOUTR_MASK 0x0040 /* IN1A_TO_MIXOUTR */
|
||||
#define WM9090_IN1A_TO_MIXOUTR_SHIFT 6 /* IN1A_TO_MIXOUTR */
|
||||
#define WM9090_IN1A_TO_MIXOUTR_WIDTH 1 /* IN1A_TO_MIXOUTR */
|
||||
#define WM9090_IN1B_TO_MIXOUTR 0x0010 /* IN1B_TO_MIXOUTR */
|
||||
#define WM9090_IN1B_TO_MIXOUTR_MASK 0x0010 /* IN1B_TO_MIXOUTR */
|
||||
#define WM9090_IN1B_TO_MIXOUTR_SHIFT 4 /* IN1B_TO_MIXOUTR */
|
||||
#define WM9090_IN1B_TO_MIXOUTR_WIDTH 1 /* IN1B_TO_MIXOUTR */
|
||||
#define WM9090_IN2A_TO_MIXOUTR 0x0004 /* IN2A_TO_MIXOUTR */
|
||||
#define WM9090_IN2A_TO_MIXOUTR_MASK 0x0004 /* IN2A_TO_MIXOUTR */
|
||||
#define WM9090_IN2A_TO_MIXOUTR_SHIFT 2 /* IN2A_TO_MIXOUTR */
|
||||
#define WM9090_IN2A_TO_MIXOUTR_WIDTH 1 /* IN2A_TO_MIXOUTR */
|
||||
#define WM9090_IN2B_TO_MIXOUTR 0x0001 /* IN2B_TO_MIXOUTR */
|
||||
#define WM9090_IN2B_TO_MIXOUTR_MASK 0x0001 /* IN2B_TO_MIXOUTR */
|
||||
#define WM9090_IN2B_TO_MIXOUTR_SHIFT 0 /* IN2B_TO_MIXOUTR */
|
||||
#define WM9090_IN2B_TO_MIXOUTR_WIDTH 1 /* IN2B_TO_MIXOUTR */
|
||||
|
||||
/*
|
||||
* R47 (0x2F) - Output Mixer3
|
||||
*/
|
||||
#define WM9090_MIXOUTL_MUTE 0x0100 /* MIXOUTL_MUTE */
|
||||
#define WM9090_MIXOUTL_MUTE_MASK 0x0100 /* MIXOUTL_MUTE */
|
||||
#define WM9090_MIXOUTL_MUTE_SHIFT 8 /* MIXOUTL_MUTE */
|
||||
#define WM9090_MIXOUTL_MUTE_WIDTH 1 /* MIXOUTL_MUTE */
|
||||
#define WM9090_IN1A_MIXOUTL_VOL_MASK 0x00C0 /* IN1A_MIXOUTL_VOL - [7:6] */
|
||||
#define WM9090_IN1A_MIXOUTL_VOL_SHIFT 6 /* IN1A_MIXOUTL_VOL - [7:6] */
|
||||
#define WM9090_IN1A_MIXOUTL_VOL_WIDTH 2 /* IN1A_MIXOUTL_VOL - [7:6] */
|
||||
#define WM9090_IN2A_MIXOUTL_VOL_MASK 0x000C /* IN2A_MIXOUTL_VOL - [3:2] */
|
||||
#define WM9090_IN2A_MIXOUTL_VOL_SHIFT 2 /* IN2A_MIXOUTL_VOL - [3:2] */
|
||||
#define WM9090_IN2A_MIXOUTL_VOL_WIDTH 2 /* IN2A_MIXOUTL_VOL - [3:2] */
|
||||
|
||||
/*
|
||||
* R48 (0x30) - Output Mixer4
|
||||
*/
|
||||
#define WM9090_MIXOUTR_MUTE 0x0100 /* MIXOUTR_MUTE */
|
||||
#define WM9090_MIXOUTR_MUTE_MASK 0x0100 /* MIXOUTR_MUTE */
|
||||
#define WM9090_MIXOUTR_MUTE_SHIFT 8 /* MIXOUTR_MUTE */
|
||||
#define WM9090_MIXOUTR_MUTE_WIDTH 1 /* MIXOUTR_MUTE */
|
||||
#define WM9090_IN1A_MIXOUTR_VOL_MASK 0x00C0 /* IN1A_MIXOUTR_VOL - [7:6] */
|
||||
#define WM9090_IN1A_MIXOUTR_VOL_SHIFT 6 /* IN1A_MIXOUTR_VOL - [7:6] */
|
||||
#define WM9090_IN1A_MIXOUTR_VOL_WIDTH 2 /* IN1A_MIXOUTR_VOL - [7:6] */
|
||||
#define WM9090_IN1B_MIXOUTR_VOL_MASK 0x0030 /* IN1B_MIXOUTR_VOL - [5:4] */
|
||||
#define WM9090_IN1B_MIXOUTR_VOL_SHIFT 4 /* IN1B_MIXOUTR_VOL - [5:4] */
|
||||
#define WM9090_IN1B_MIXOUTR_VOL_WIDTH 2 /* IN1B_MIXOUTR_VOL - [5:4] */
|
||||
#define WM9090_IN2A_MIXOUTR_VOL_MASK 0x000C /* IN2A_MIXOUTR_VOL - [3:2] */
|
||||
#define WM9090_IN2A_MIXOUTR_VOL_SHIFT 2 /* IN2A_MIXOUTR_VOL - [3:2] */
|
||||
#define WM9090_IN2A_MIXOUTR_VOL_WIDTH 2 /* IN2A_MIXOUTR_VOL - [3:2] */
|
||||
#define WM9090_IN2B_MIXOUTR_VOL_MASK 0x0003 /* IN2B_MIXOUTR_VOL - [1:0] */
|
||||
#define WM9090_IN2B_MIXOUTR_VOL_SHIFT 0 /* IN2B_MIXOUTR_VOL - [1:0] */
|
||||
#define WM9090_IN2B_MIXOUTR_VOL_WIDTH 2 /* IN2B_MIXOUTR_VOL - [1:0] */
|
||||
|
||||
/*
|
||||
* R54 (0x36) - Speaker Mixer
|
||||
*/
|
||||
#define WM9090_IN1A_TO_SPKMIX 0x0040 /* IN1A_TO_SPKMIX */
|
||||
#define WM9090_IN1A_TO_SPKMIX_MASK 0x0040 /* IN1A_TO_SPKMIX */
|
||||
#define WM9090_IN1A_TO_SPKMIX_SHIFT 6 /* IN1A_TO_SPKMIX */
|
||||
#define WM9090_IN1A_TO_SPKMIX_WIDTH 1 /* IN1A_TO_SPKMIX */
|
||||
#define WM9090_IN1B_TO_SPKMIX 0x0010 /* IN1B_TO_SPKMIX */
|
||||
#define WM9090_IN1B_TO_SPKMIX_MASK 0x0010 /* IN1B_TO_SPKMIX */
|
||||
#define WM9090_IN1B_TO_SPKMIX_SHIFT 4 /* IN1B_TO_SPKMIX */
|
||||
#define WM9090_IN1B_TO_SPKMIX_WIDTH 1 /* IN1B_TO_SPKMIX */
|
||||
#define WM9090_IN2A_TO_SPKMIX 0x0004 /* IN2A_TO_SPKMIX */
|
||||
#define WM9090_IN2A_TO_SPKMIX_MASK 0x0004 /* IN2A_TO_SPKMIX */
|
||||
#define WM9090_IN2A_TO_SPKMIX_SHIFT 2 /* IN2A_TO_SPKMIX */
|
||||
#define WM9090_IN2A_TO_SPKMIX_WIDTH 1 /* IN2A_TO_SPKMIX */
|
||||
#define WM9090_IN2B_TO_SPKMIX 0x0001 /* IN2B_TO_SPKMIX */
|
||||
#define WM9090_IN2B_TO_SPKMIX_MASK 0x0001 /* IN2B_TO_SPKMIX */
|
||||
#define WM9090_IN2B_TO_SPKMIX_SHIFT 0 /* IN2B_TO_SPKMIX */
|
||||
#define WM9090_IN2B_TO_SPKMIX_WIDTH 1 /* IN2B_TO_SPKMIX */
|
||||
|
||||
/*
|
||||
* R57 (0x39) - AntiPOP2
|
||||
*/
|
||||
#define WM9090_VMID_BUF_ENA 0x0008 /* VMID_BUF_ENA */
|
||||
#define WM9090_VMID_BUF_ENA_MASK 0x0008 /* VMID_BUF_ENA */
|
||||
#define WM9090_VMID_BUF_ENA_SHIFT 3 /* VMID_BUF_ENA */
|
||||
#define WM9090_VMID_BUF_ENA_WIDTH 1 /* VMID_BUF_ENA */
|
||||
#define WM9090_VMID_ENA 0x0001 /* VMID_ENA */
|
||||
#define WM9090_VMID_ENA_MASK 0x0001 /* VMID_ENA */
|
||||
#define WM9090_VMID_ENA_SHIFT 0 /* VMID_ENA */
|
||||
#define WM9090_VMID_ENA_WIDTH 1 /* VMID_ENA */
|
||||
|
||||
/*
|
||||
* R70 (0x46) - Write Sequencer 0
|
||||
*/
|
||||
#define WM9090_WSEQ_ENA 0x0100 /* WSEQ_ENA */
|
||||
#define WM9090_WSEQ_ENA_MASK 0x0100 /* WSEQ_ENA */
|
||||
#define WM9090_WSEQ_ENA_SHIFT 8 /* WSEQ_ENA */
|
||||
#define WM9090_WSEQ_ENA_WIDTH 1 /* WSEQ_ENA */
|
||||
#define WM9090_WSEQ_WRITE_INDEX_MASK 0x000F /* WSEQ_WRITE_INDEX - [3:0] */
|
||||
#define WM9090_WSEQ_WRITE_INDEX_SHIFT 0 /* WSEQ_WRITE_INDEX - [3:0] */
|
||||
#define WM9090_WSEQ_WRITE_INDEX_WIDTH 4 /* WSEQ_WRITE_INDEX - [3:0] */
|
||||
|
||||
/*
|
||||
* R71 (0x47) - Write Sequencer 1
|
||||
*/
|
||||
#define WM9090_WSEQ_DATA_WIDTH_MASK 0x7000 /* WSEQ_DATA_WIDTH - [14:12] */
|
||||
#define WM9090_WSEQ_DATA_WIDTH_SHIFT 12 /* WSEQ_DATA_WIDTH - [14:12] */
|
||||
#define WM9090_WSEQ_DATA_WIDTH_WIDTH 3 /* WSEQ_DATA_WIDTH - [14:12] */
|
||||
#define WM9090_WSEQ_DATA_START_MASK 0x0F00 /* WSEQ_DATA_START - [11:8] */
|
||||
#define WM9090_WSEQ_DATA_START_SHIFT 8 /* WSEQ_DATA_START - [11:8] */
|
||||
#define WM9090_WSEQ_DATA_START_WIDTH 4 /* WSEQ_DATA_START - [11:8] */
|
||||
#define WM9090_WSEQ_ADDR_MASK 0x00FF /* WSEQ_ADDR - [7:0] */
|
||||
#define WM9090_WSEQ_ADDR_SHIFT 0 /* WSEQ_ADDR - [7:0] */
|
||||
#define WM9090_WSEQ_ADDR_WIDTH 8 /* WSEQ_ADDR - [7:0] */
|
||||
|
||||
/*
|
||||
* R72 (0x48) - Write Sequencer 2
|
||||
*/
|
||||
#define WM9090_WSEQ_EOS 0x4000 /* WSEQ_EOS */
|
||||
#define WM9090_WSEQ_EOS_MASK 0x4000 /* WSEQ_EOS */
|
||||
#define WM9090_WSEQ_EOS_SHIFT 14 /* WSEQ_EOS */
|
||||
#define WM9090_WSEQ_EOS_WIDTH 1 /* WSEQ_EOS */
|
||||
#define WM9090_WSEQ_DELAY_MASK 0x0F00 /* WSEQ_DELAY - [11:8] */
|
||||
#define WM9090_WSEQ_DELAY_SHIFT 8 /* WSEQ_DELAY - [11:8] */
|
||||
#define WM9090_WSEQ_DELAY_WIDTH 4 /* WSEQ_DELAY - [11:8] */
|
||||
#define WM9090_WSEQ_DATA_MASK 0x00FF /* WSEQ_DATA - [7:0] */
|
||||
#define WM9090_WSEQ_DATA_SHIFT 0 /* WSEQ_DATA - [7:0] */
|
||||
#define WM9090_WSEQ_DATA_WIDTH 8 /* WSEQ_DATA - [7:0] */
|
||||
|
||||
/*
|
||||
* R73 (0x49) - Write Sequencer 3
|
||||
*/
|
||||
#define WM9090_WSEQ_ABORT 0x0200 /* WSEQ_ABORT */
|
||||
#define WM9090_WSEQ_ABORT_MASK 0x0200 /* WSEQ_ABORT */
|
||||
#define WM9090_WSEQ_ABORT_SHIFT 9 /* WSEQ_ABORT */
|
||||
#define WM9090_WSEQ_ABORT_WIDTH 1 /* WSEQ_ABORT */
|
||||
#define WM9090_WSEQ_START 0x0100 /* WSEQ_START */
|
||||
#define WM9090_WSEQ_START_MASK 0x0100 /* WSEQ_START */
|
||||
#define WM9090_WSEQ_START_SHIFT 8 /* WSEQ_START */
|
||||
#define WM9090_WSEQ_START_WIDTH 1 /* WSEQ_START */
|
||||
#define WM9090_WSEQ_START_INDEX_MASK 0x003F /* WSEQ_START_INDEX - [5:0] */
|
||||
#define WM9090_WSEQ_START_INDEX_SHIFT 0 /* WSEQ_START_INDEX - [5:0] */
|
||||
#define WM9090_WSEQ_START_INDEX_WIDTH 6 /* WSEQ_START_INDEX - [5:0] */
|
||||
|
||||
/*
|
||||
* R74 (0x4A) - Write Sequencer 4
|
||||
*/
|
||||
#define WM9090_WSEQ_BUSY 0x0001 /* WSEQ_BUSY */
|
||||
#define WM9090_WSEQ_BUSY_MASK 0x0001 /* WSEQ_BUSY */
|
||||
#define WM9090_WSEQ_BUSY_SHIFT 0 /* WSEQ_BUSY */
|
||||
#define WM9090_WSEQ_BUSY_WIDTH 1 /* WSEQ_BUSY */
|
||||
|
||||
/*
|
||||
* R75 (0x4B) - Write Sequencer 5
|
||||
*/
|
||||
#define WM9090_WSEQ_CURRENT_INDEX_MASK 0x003F /* WSEQ_CURRENT_INDEX - [5:0] */
|
||||
#define WM9090_WSEQ_CURRENT_INDEX_SHIFT 0 /* WSEQ_CURRENT_INDEX - [5:0] */
|
||||
#define WM9090_WSEQ_CURRENT_INDEX_WIDTH 6 /* WSEQ_CURRENT_INDEX - [5:0] */
|
||||
|
||||
/*
|
||||
* R76 (0x4C) - Charge Pump 1
|
||||
*/
|
||||
#define WM9090_CP_ENA 0x8000 /* CP_ENA */
|
||||
#define WM9090_CP_ENA_MASK 0x8000 /* CP_ENA */
|
||||
#define WM9090_CP_ENA_SHIFT 15 /* CP_ENA */
|
||||
#define WM9090_CP_ENA_WIDTH 1 /* CP_ENA */
|
||||
|
||||
/*
|
||||
* R84 (0x54) - DC Servo 0
|
||||
*/
|
||||
#define WM9090_DCS_TRIG_SINGLE_1 0x2000 /* DCS_TRIG_SINGLE_1 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_1_MASK 0x2000 /* DCS_TRIG_SINGLE_1 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_1_SHIFT 13 /* DCS_TRIG_SINGLE_1 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_1_WIDTH 1 /* DCS_TRIG_SINGLE_1 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_0 0x1000 /* DCS_TRIG_SINGLE_0 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_0_MASK 0x1000 /* DCS_TRIG_SINGLE_0 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_0_SHIFT 12 /* DCS_TRIG_SINGLE_0 */
|
||||
#define WM9090_DCS_TRIG_SINGLE_0_WIDTH 1 /* DCS_TRIG_SINGLE_0 */
|
||||
#define WM9090_DCS_TRIG_SERIES_1 0x0200 /* DCS_TRIG_SERIES_1 */
|
||||
#define WM9090_DCS_TRIG_SERIES_1_MASK 0x0200 /* DCS_TRIG_SERIES_1 */
|
||||
#define WM9090_DCS_TRIG_SERIES_1_SHIFT 9 /* DCS_TRIG_SERIES_1 */
|
||||
#define WM9090_DCS_TRIG_SERIES_1_WIDTH 1 /* DCS_TRIG_SERIES_1 */
|
||||
#define WM9090_DCS_TRIG_SERIES_0 0x0100 /* DCS_TRIG_SERIES_0 */
|
||||
#define WM9090_DCS_TRIG_SERIES_0_MASK 0x0100 /* DCS_TRIG_SERIES_0 */
|
||||
#define WM9090_DCS_TRIG_SERIES_0_SHIFT 8 /* DCS_TRIG_SERIES_0 */
|
||||
#define WM9090_DCS_TRIG_SERIES_0_WIDTH 1 /* DCS_TRIG_SERIES_0 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_1 0x0020 /* DCS_TRIG_STARTUP_1 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_1_MASK 0x0020 /* DCS_TRIG_STARTUP_1 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_1_SHIFT 5 /* DCS_TRIG_STARTUP_1 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_1_WIDTH 1 /* DCS_TRIG_STARTUP_1 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_0 0x0010 /* DCS_TRIG_STARTUP_0 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_0_MASK 0x0010 /* DCS_TRIG_STARTUP_0 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_0_SHIFT 4 /* DCS_TRIG_STARTUP_0 */
|
||||
#define WM9090_DCS_TRIG_STARTUP_0_WIDTH 1 /* DCS_TRIG_STARTUP_0 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_1 0x0008 /* DCS_TRIG_DAC_WR_1 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_1_MASK 0x0008 /* DCS_TRIG_DAC_WR_1 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_1_SHIFT 3 /* DCS_TRIG_DAC_WR_1 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_1_WIDTH 1 /* DCS_TRIG_DAC_WR_1 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_0 0x0004 /* DCS_TRIG_DAC_WR_0 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_0_MASK 0x0004 /* DCS_TRIG_DAC_WR_0 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_0_SHIFT 2 /* DCS_TRIG_DAC_WR_0 */
|
||||
#define WM9090_DCS_TRIG_DAC_WR_0_WIDTH 1 /* DCS_TRIG_DAC_WR_0 */
|
||||
#define WM9090_DCS_ENA_CHAN_1 0x0002 /* DCS_ENA_CHAN_1 */
|
||||
#define WM9090_DCS_ENA_CHAN_1_MASK 0x0002 /* DCS_ENA_CHAN_1 */
|
||||
#define WM9090_DCS_ENA_CHAN_1_SHIFT 1 /* DCS_ENA_CHAN_1 */
|
||||
#define WM9090_DCS_ENA_CHAN_1_WIDTH 1 /* DCS_ENA_CHAN_1 */
|
||||
#define WM9090_DCS_ENA_CHAN_0 0x0001 /* DCS_ENA_CHAN_0 */
|
||||
#define WM9090_DCS_ENA_CHAN_0_MASK 0x0001 /* DCS_ENA_CHAN_0 */
|
||||
#define WM9090_DCS_ENA_CHAN_0_SHIFT 0 /* DCS_ENA_CHAN_0 */
|
||||
#define WM9090_DCS_ENA_CHAN_0_WIDTH 1 /* DCS_ENA_CHAN_0 */
|
||||
|
||||
/*
|
||||
* R85 (0x55) - DC Servo 1
|
||||
*/
|
||||
#define WM9090_DCS_SERIES_NO_01_MASK 0x0FE0 /* DCS_SERIES_NO_01 - [11:5] */
|
||||
#define WM9090_DCS_SERIES_NO_01_SHIFT 5 /* DCS_SERIES_NO_01 - [11:5] */
|
||||
#define WM9090_DCS_SERIES_NO_01_WIDTH 7 /* DCS_SERIES_NO_01 - [11:5] */
|
||||
#define WM9090_DCS_TIMER_PERIOD_01_MASK 0x000F /* DCS_TIMER_PERIOD_01 - [3:0] */
|
||||
#define WM9090_DCS_TIMER_PERIOD_01_SHIFT 0 /* DCS_TIMER_PERIOD_01 - [3:0] */
|
||||
#define WM9090_DCS_TIMER_PERIOD_01_WIDTH 4 /* DCS_TIMER_PERIOD_01 - [3:0] */
|
||||
|
||||
/*
|
||||
* R87 (0x57) - DC Servo 3
|
||||
*/
|
||||
#define WM9090_DCS_DAC_WR_VAL_1_MASK 0xFF00 /* DCS_DAC_WR_VAL_1 - [15:8] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_1_SHIFT 8 /* DCS_DAC_WR_VAL_1 - [15:8] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_1_WIDTH 8 /* DCS_DAC_WR_VAL_1 - [15:8] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_0_MASK 0x00FF /* DCS_DAC_WR_VAL_0 - [7:0] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_0_SHIFT 0 /* DCS_DAC_WR_VAL_0 - [7:0] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_0_WIDTH 8 /* DCS_DAC_WR_VAL_0 - [7:0] */
|
||||
|
||||
/*
|
||||
* R88 (0x58) - DC Servo Readback 0
|
||||
*/
|
||||
#define WM9090_DCS_CAL_COMPLETE_MASK 0x0300 /* DCS_CAL_COMPLETE - [9:8] */
|
||||
#define WM9090_DCS_CAL_COMPLETE_SHIFT 8 /* DCS_CAL_COMPLETE - [9:8] */
|
||||
#define WM9090_DCS_CAL_COMPLETE_WIDTH 2 /* DCS_CAL_COMPLETE - [9:8] */
|
||||
#define WM9090_DCS_DAC_WR_COMPLETE_MASK 0x0030 /* DCS_DAC_WR_COMPLETE - [5:4] */
|
||||
#define WM9090_DCS_DAC_WR_COMPLETE_SHIFT 4 /* DCS_DAC_WR_COMPLETE - [5:4] */
|
||||
#define WM9090_DCS_DAC_WR_COMPLETE_WIDTH 2 /* DCS_DAC_WR_COMPLETE - [5:4] */
|
||||
#define WM9090_DCS_STARTUP_COMPLETE_MASK 0x0003 /* DCS_STARTUP_COMPLETE - [1:0] */
|
||||
#define WM9090_DCS_STARTUP_COMPLETE_SHIFT 0 /* DCS_STARTUP_COMPLETE - [1:0] */
|
||||
#define WM9090_DCS_STARTUP_COMPLETE_WIDTH 2 /* DCS_STARTUP_COMPLETE - [1:0] */
|
||||
|
||||
/*
|
||||
* R89 (0x59) - DC Servo Readback 1
|
||||
*/
|
||||
#define WM9090_DCS_DAC_WR_VAL_1_RD_MASK 0x00FF /* DCS_DAC_WR_VAL_1_RD - [7:0] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_1_RD_SHIFT 0 /* DCS_DAC_WR_VAL_1_RD - [7:0] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_1_RD_WIDTH 8 /* DCS_DAC_WR_VAL_1_RD - [7:0] */
|
||||
|
||||
/*
|
||||
* R90 (0x5A) - DC Servo Readback 2
|
||||
*/
|
||||
#define WM9090_DCS_DAC_WR_VAL_0_RD_MASK 0x00FF /* DCS_DAC_WR_VAL_0_RD - [7:0] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_0_RD_SHIFT 0 /* DCS_DAC_WR_VAL_0_RD - [7:0] */
|
||||
#define WM9090_DCS_DAC_WR_VAL_0_RD_WIDTH 8 /* DCS_DAC_WR_VAL_0_RD - [7:0] */
|
||||
|
||||
/*
|
||||
* R96 (0x60) - Analogue HP 0
|
||||
*/
|
||||
#define WM9090_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */
|
||||
#define WM9090_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */
|
||||
#define WM9090_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */
|
||||
#define WM9090_HPOUT1L_RMV_SHORT_WIDTH 1 /* HPOUT1L_RMV_SHORT */
|
||||
#define WM9090_HPOUT1L_OUTP 0x0040 /* HPOUT1L_OUTP */
|
||||
#define WM9090_HPOUT1L_OUTP_MASK 0x0040 /* HPOUT1L_OUTP */
|
||||
#define WM9090_HPOUT1L_OUTP_SHIFT 6 /* HPOUT1L_OUTP */
|
||||
#define WM9090_HPOUT1L_OUTP_WIDTH 1 /* HPOUT1L_OUTP */
|
||||
#define WM9090_HPOUT1L_DLY 0x0020 /* HPOUT1L_DLY */
|
||||
#define WM9090_HPOUT1L_DLY_MASK 0x0020 /* HPOUT1L_DLY */
|
||||
#define WM9090_HPOUT1L_DLY_SHIFT 5 /* HPOUT1L_DLY */
|
||||
#define WM9090_HPOUT1L_DLY_WIDTH 1 /* HPOUT1L_DLY */
|
||||
#define WM9090_HPOUT1R_RMV_SHORT 0x0008 /* HPOUT1R_RMV_SHORT */
|
||||
#define WM9090_HPOUT1R_RMV_SHORT_MASK 0x0008 /* HPOUT1R_RMV_SHORT */
|
||||
#define WM9090_HPOUT1R_RMV_SHORT_SHIFT 3 /* HPOUT1R_RMV_SHORT */
|
||||
#define WM9090_HPOUT1R_RMV_SHORT_WIDTH 1 /* HPOUT1R_RMV_SHORT */
|
||||
#define WM9090_HPOUT1R_OUTP 0x0004 /* HPOUT1R_OUTP */
|
||||
#define WM9090_HPOUT1R_OUTP_MASK 0x0004 /* HPOUT1R_OUTP */
|
||||
#define WM9090_HPOUT1R_OUTP_SHIFT 2 /* HPOUT1R_OUTP */
|
||||
#define WM9090_HPOUT1R_OUTP_WIDTH 1 /* HPOUT1R_OUTP */
|
||||
#define WM9090_HPOUT1R_DLY 0x0002 /* HPOUT1R_DLY */
|
||||
#define WM9090_HPOUT1R_DLY_MASK 0x0002 /* HPOUT1R_DLY */
|
||||
#define WM9090_HPOUT1R_DLY_SHIFT 1 /* HPOUT1R_DLY */
|
||||
#define WM9090_HPOUT1R_DLY_WIDTH 1 /* HPOUT1R_DLY */
|
||||
|
||||
/*
|
||||
* R98 (0x62) - AGC Control 0
|
||||
*/
|
||||
#define WM9090_AGC_CLIP_ENA 0x8000 /* AGC_CLIP_ENA */
|
||||
#define WM9090_AGC_CLIP_ENA_MASK 0x8000 /* AGC_CLIP_ENA */
|
||||
#define WM9090_AGC_CLIP_ENA_SHIFT 15 /* AGC_CLIP_ENA */
|
||||
#define WM9090_AGC_CLIP_ENA_WIDTH 1 /* AGC_CLIP_ENA */
|
||||
#define WM9090_AGC_CLIP_THR_MASK 0x0F00 /* AGC_CLIP_THR - [11:8] */
|
||||
#define WM9090_AGC_CLIP_THR_SHIFT 8 /* AGC_CLIP_THR - [11:8] */
|
||||
#define WM9090_AGC_CLIP_THR_WIDTH 4 /* AGC_CLIP_THR - [11:8] */
|
||||
#define WM9090_AGC_CLIP_ATK_MASK 0x0070 /* AGC_CLIP_ATK - [6:4] */
|
||||
#define WM9090_AGC_CLIP_ATK_SHIFT 4 /* AGC_CLIP_ATK - [6:4] */
|
||||
#define WM9090_AGC_CLIP_ATK_WIDTH 3 /* AGC_CLIP_ATK - [6:4] */
|
||||
#define WM9090_AGC_CLIP_DCY_MASK 0x0007 /* AGC_CLIP_DCY - [2:0] */
|
||||
#define WM9090_AGC_CLIP_DCY_SHIFT 0 /* AGC_CLIP_DCY - [2:0] */
|
||||
#define WM9090_AGC_CLIP_DCY_WIDTH 3 /* AGC_CLIP_DCY - [2:0] */
|
||||
|
||||
/*
|
||||
* R99 (0x63) - AGC Control 1
|
||||
*/
|
||||
#define WM9090_AGC_PWR_ENA 0x8000 /* AGC_PWR_ENA */
|
||||
#define WM9090_AGC_PWR_ENA_MASK 0x8000 /* AGC_PWR_ENA */
|
||||
#define WM9090_AGC_PWR_ENA_SHIFT 15 /* AGC_PWR_ENA */
|
||||
#define WM9090_AGC_PWR_ENA_WIDTH 1 /* AGC_PWR_ENA */
|
||||
#define WM9090_AGC_PWR_AVG 0x1000 /* AGC_PWR_AVG */
|
||||
#define WM9090_AGC_PWR_AVG_MASK 0x1000 /* AGC_PWR_AVG */
|
||||
#define WM9090_AGC_PWR_AVG_SHIFT 12 /* AGC_PWR_AVG */
|
||||
#define WM9090_AGC_PWR_AVG_WIDTH 1 /* AGC_PWR_AVG */
|
||||
#define WM9090_AGC_PWR_THR_MASK 0x0F00 /* AGC_PWR_THR - [11:8] */
|
||||
#define WM9090_AGC_PWR_THR_SHIFT 8 /* AGC_PWR_THR - [11:8] */
|
||||
#define WM9090_AGC_PWR_THR_WIDTH 4 /* AGC_PWR_THR - [11:8] */
|
||||
#define WM9090_AGC_PWR_ATK_MASK 0x0070 /* AGC_PWR_ATK - [6:4] */
|
||||
#define WM9090_AGC_PWR_ATK_SHIFT 4 /* AGC_PWR_ATK - [6:4] */
|
||||
#define WM9090_AGC_PWR_ATK_WIDTH 3 /* AGC_PWR_ATK - [6:4] */
|
||||
#define WM9090_AGC_PWR_DCY_MASK 0x0007 /* AGC_PWR_DCY - [2:0] */
|
||||
#define WM9090_AGC_PWR_DCY_SHIFT 0 /* AGC_PWR_DCY - [2:0] */
|
||||
#define WM9090_AGC_PWR_DCY_WIDTH 3 /* AGC_PWR_DCY - [2:0] */
|
||||
|
||||
/*
|
||||
* R100 (0x64) - AGC Control 2
|
||||
*/
|
||||
#define WM9090_AGC_RAMP 0x0100 /* AGC_RAMP */
|
||||
#define WM9090_AGC_RAMP_MASK 0x0100 /* AGC_RAMP */
|
||||
#define WM9090_AGC_RAMP_SHIFT 8 /* AGC_RAMP */
|
||||
#define WM9090_AGC_RAMP_WIDTH 1 /* AGC_RAMP */
|
||||
#define WM9090_AGC_MINGAIN_MASK 0x003F /* AGC_MINGAIN - [5:0] */
|
||||
#define WM9090_AGC_MINGAIN_SHIFT 0 /* AGC_MINGAIN - [5:0] */
|
||||
#define WM9090_AGC_MINGAIN_WIDTH 6 /* AGC_MINGAIN - [5:0] */
|
||||
|
||||
#endif
|
|
@ -632,9 +632,6 @@ static int wm9712_soc_resume(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
|
||||
wm9712_set_bias_level(codec, SND_SOC_BIAS_ON);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -764,7 +764,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source)
|
|||
static int wm9713_set_pll(struct snd_soc_codec *codec,
|
||||
int pll_id, unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
struct wm9713_priv *wm9713 = codec->private_data;
|
||||
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg, reg2;
|
||||
struct _pll_div pll_div;
|
||||
|
||||
|
@ -1175,7 +1175,7 @@ static int wm9713_soc_resume(struct platform_device *pdev)
|
|||
{
|
||||
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
|
||||
struct snd_soc_codec *codec = socdev->card->codec;
|
||||
struct wm9713_priv *wm9713 = codec->private_data;
|
||||
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
|
||||
int i, ret;
|
||||
u16 *cache = codec->reg_cache;
|
||||
|
||||
|
@ -1201,9 +1201,6 @@ static int wm9713_soc_resume(struct platform_device *pdev)
|
|||
}
|
||||
}
|
||||
|
||||
if (codec->suspend_bias_level == SND_SOC_BIAS_ON)
|
||||
wm9713_set_bias_level(codec, SND_SOC_BIAS_ON);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1228,8 +1225,9 @@ static int wm9713_soc_probe(struct platform_device *pdev)
|
|||
codec->reg_cache_size = sizeof(wm9713_reg);
|
||||
codec->reg_cache_step = 2;
|
||||
|
||||
codec->private_data = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
|
||||
if (codec->private_data == NULL) {
|
||||
snd_soc_codec_set_drvdata(codec, kzalloc(sizeof(struct wm9713_priv),
|
||||
GFP_KERNEL));
|
||||
if (snd_soc_codec_get_drvdata(codec) == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto priv_err;
|
||||
}
|
||||
|
@ -1280,7 +1278,7 @@ pcm_err:
|
|||
snd_soc_free_ac97_codec(codec);
|
||||
|
||||
codec_err:
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
|
||||
priv_err:
|
||||
kfree(codec->reg_cache);
|
||||
|
@ -1302,7 +1300,7 @@ static int wm9713_soc_remove(struct platform_device *pdev)
|
|||
snd_soc_dapm_free(socdev);
|
||||
snd_soc_free_pcms(socdev);
|
||||
snd_soc_free_ac97_codec(codec);
|
||||
kfree(codec->private_data);
|
||||
kfree(snd_soc_codec_get_drvdata(codec));
|
||||
kfree(codec->reg_cache);
|
||||
kfree(codec);
|
||||
return 0;
|
||||
|
|
|
@ -91,7 +91,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec, unsigned int op)
|
|||
*/
|
||||
static void calibrate_dc_servo(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm_hubs_data *hubs = codec->private_data;
|
||||
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
|
||||
u16 reg, reg_l, reg_r, dcs_cfg;
|
||||
|
||||
/* Set for 32 series updates */
|
||||
|
@ -127,6 +127,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
|
|||
break;
|
||||
}
|
||||
|
||||
dev_dbg(codec->dev, "DCS input: %x %x\n", reg_l, reg_r);
|
||||
|
||||
/* HPOUT1L */
|
||||
if (reg_l + hubs->dcs_codes > 0 &&
|
||||
reg_l + hubs->dcs_codes < 0xff)
|
||||
|
@ -139,6 +141,8 @@ static void calibrate_dc_servo(struct snd_soc_codec *codec)
|
|||
reg_r += hubs->dcs_codes;
|
||||
dcs_cfg |= reg_r;
|
||||
|
||||
dev_dbg(codec->dev, "DCS result: %x\n", dcs_cfg);
|
||||
|
||||
/* Do it */
|
||||
snd_soc_write(codec, WM8993_DC_SERVO_3, dcs_cfg);
|
||||
wait_for_dc_servo(codec,
|
||||
|
@ -154,7 +158,7 @@ static int wm8993_put_dc_servo(struct snd_kcontrol *kcontrol,
|
|||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
|
||||
struct wm_hubs_data *hubs = codec->private_data;
|
||||
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_put_volsw_2r(kcontrol, ucontrol);
|
||||
|
@ -327,7 +331,7 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w,
|
|||
struct snd_kcontrol *kcontrol, int event)
|
||||
{
|
||||
struct snd_soc_codec *codec = w->codec;
|
||||
struct wm_hubs_data *hubs = codec->private_data;
|
||||
struct wm_hubs_data *hubs = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
switch (event) {
|
||||
case SND_SOC_DAPM_PRE_PMU:
|
||||
|
@ -397,14 +401,14 @@ static int hp_event(struct snd_soc_dapm_widget *w,
|
|||
|
||||
case SND_SOC_DAPM_PRE_PMD:
|
||||
snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
|
||||
WM8993_HPOUT1L_DLY |
|
||||
WM8993_HPOUT1R_DLY |
|
||||
WM8993_HPOUT1L_OUTP |
|
||||
WM8993_HPOUT1R_OUTP |
|
||||
WM8993_HPOUT1L_RMV_SHORT |
|
||||
WM8993_HPOUT1R_RMV_SHORT, 0);
|
||||
|
||||
snd_soc_update_bits(codec, WM8993_ANALOGUE_HP_0,
|
||||
WM8993_HPOUT1L_OUTP |
|
||||
WM8993_HPOUT1R_OUTP, 0);
|
||||
WM8993_HPOUT1L_DLY |
|
||||
WM8993_HPOUT1R_DLY, 0);
|
||||
|
||||
snd_soc_update_bits(codec, WM8993_POWER_MANAGEMENT_1,
|
||||
WM8993_HPOUT1L_ENA | WM8993_HPOUT1R_ENA,
|
||||
|
|
|
@ -12,15 +12,38 @@ config SND_DAVINCI_SOC_I2S
|
|||
config SND_DAVINCI_SOC_MCASP
|
||||
tristate
|
||||
|
||||
config SND_DAVINCI_SOC_VCIF
|
||||
tristate
|
||||
|
||||
config SND_DAVINCI_SOC_EVM
|
||||
tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM"
|
||||
depends on SND_DAVINCI_SOC
|
||||
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
|
||||
depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM
|
||||
select SND_DAVINCI_SOC_I2S
|
||||
select SND_SOC_TLV320AIC3X
|
||||
help
|
||||
Say Y if you want to add support for SoC audio on TI
|
||||
DaVinci DM6446 or DM355 EVM platforms.
|
||||
DaVinci DM6446, DM355 or DM365 EVM platforms.
|
||||
|
||||
choice
|
||||
prompt "DM365 codec select"
|
||||
depends on SND_DAVINCI_SOC_EVM
|
||||
depends on MACH_DAVINCI_DM365_EVM
|
||||
default SND_DM365_EXTERNAL_CODEC
|
||||
|
||||
config SND_DM365_AIC3X_CODEC
|
||||
bool "Audio Codec - AIC3101"
|
||||
help
|
||||
Say Y if you want to add support for AIC3101 audio codec
|
||||
|
||||
config SND_DM365_VOICE_CODEC
|
||||
bool "Voice Codec - CQ93VC"
|
||||
select MFD_DAVINCI_VOICECODEC
|
||||
select SND_DAVINCI_SOC_VCIF
|
||||
select SND_SOC_CQ0093VC
|
||||
help
|
||||
Say Y if you want to add support for SoC On-chip voice codec
|
||||
endchoice
|
||||
|
||||
config SND_DM6467_SOC_EVM
|
||||
tristate "SoC Audio support for DaVinci DM6467 EVM"
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
snd-soc-davinci-objs := davinci-pcm.o
|
||||
snd-soc-davinci-i2s-objs := davinci-i2s.o
|
||||
snd-soc-davinci-mcasp-objs:= davinci-mcasp.o
|
||||
snd-soc-davinci-vcif-objs:= davinci-vcif.o
|
||||
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC) += snd-soc-davinci.o
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC_I2S) += snd-soc-davinci-i2s.o
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC_MCASP) += snd-soc-davinci-mcasp.o
|
||||
obj-$(CONFIG_SND_DAVINCI_SOC_VCIF) += snd-soc-davinci-vcif.o
|
||||
|
||||
# DAVINCI Machine Support
|
||||
snd-soc-evm-objs := davinci-evm.o
|
||||
|
|
|
@ -28,10 +28,12 @@
|
|||
#include <mach/mux.h>
|
||||
|
||||
#include "../codecs/tlv320aic3x.h"
|
||||
#include "../codecs/cq93vc.h"
|
||||
#include "../codecs/spdif_transciever.h"
|
||||
#include "davinci-pcm.h"
|
||||
#include "davinci-i2s.h"
|
||||
#include "davinci-mcasp.h"
|
||||
#include "davinci-vcif.h"
|
||||
|
||||
#define AUDIO_FORMAT (SND_SOC_DAIFMT_DSP_B | \
|
||||
SND_SOC_DAIFMT_CBM_CFM | SND_SOC_DAIFMT_IB_NF)
|
||||
|
@ -81,10 +83,24 @@ static int evm_hw_params(struct snd_pcm_substream *substream,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int evm_spdif_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
|
||||
|
||||
/* set cpu DAI configuration */
|
||||
return snd_soc_dai_set_fmt(cpu_dai, AUDIO_FORMAT);
|
||||
}
|
||||
|
||||
static struct snd_soc_ops evm_ops = {
|
||||
.hw_params = evm_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_ops evm_spdif_ops = {
|
||||
.hw_params = evm_spdif_hw_params,
|
||||
};
|
||||
|
||||
/* davinci-evm machine dapm widgets */
|
||||
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_HP("Headphone Jack", NULL),
|
||||
|
@ -151,6 +167,22 @@ static struct snd_soc_dai_link evm_dai = {
|
|||
.ops = &evm_ops,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link dm365_evm_dai = {
|
||||
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
|
||||
.name = "TLV320AIC3X",
|
||||
.stream_name = "AIC3X",
|
||||
.cpu_dai = &davinci_i2s_dai,
|
||||
.codec_dai = &aic3x_dai,
|
||||
.init = evm_aic3x_init,
|
||||
.ops = &evm_ops,
|
||||
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
|
||||
.name = "Voice Codec - CQ93VC",
|
||||
.stream_name = "CQ93",
|
||||
.cpu_dai = &davinci_vcif_dai,
|
||||
.codec_dai = &cq93vc_dai,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link dm6467_evm_dai[] = {
|
||||
{
|
||||
.name = "TLV320AIC3X",
|
||||
|
@ -165,7 +197,7 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = {
|
|||
.stream_name = "spdif",
|
||||
.cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_DIT_DAI],
|
||||
.codec_dai = &dit_stub_dai,
|
||||
.ops = &evm_ops,
|
||||
.ops = &evm_spdif_ops,
|
||||
},
|
||||
};
|
||||
static struct snd_soc_dai_link da8xx_evm_dai = {
|
||||
|
@ -177,7 +209,7 @@ static struct snd_soc_dai_link da8xx_evm_dai = {
|
|||
.ops = &evm_ops,
|
||||
};
|
||||
|
||||
/* davinci dm6446, dm355 or dm365 evm audio machine driver */
|
||||
/* davinci dm6446, dm355 evm audio machine driver */
|
||||
static struct snd_soc_card snd_soc_card_evm = {
|
||||
.name = "DaVinci EVM",
|
||||
.platform = &davinci_soc_platform,
|
||||
|
@ -185,6 +217,15 @@ static struct snd_soc_card snd_soc_card_evm = {
|
|||
.num_links = 1,
|
||||
};
|
||||
|
||||
/* davinci dm365 evm audio machine driver */
|
||||
static struct snd_soc_card dm365_snd_soc_card_evm = {
|
||||
.name = "DaVinci DM365 EVM",
|
||||
.platform = &davinci_soc_platform,
|
||||
.dai_link = &dm365_evm_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
|
||||
/* davinci dm6467 evm audio machine driver */
|
||||
static struct snd_soc_card dm6467_snd_soc_card_evm = {
|
||||
.name = "DaVinci DM6467 EVM",
|
||||
|
@ -216,6 +257,17 @@ static struct snd_soc_device evm_snd_devdata = {
|
|||
.codec_data = &aic3x_setup,
|
||||
};
|
||||
|
||||
/* evm audio subsystem */
|
||||
static struct snd_soc_device dm365_evm_snd_devdata = {
|
||||
.card = &dm365_snd_soc_card_evm,
|
||||
#ifdef CONFIG_SND_DM365_AIC3X_CODEC
|
||||
.codec_dev = &soc_codec_dev_aic3x,
|
||||
.codec_data = &aic3x_setup,
|
||||
#elif defined(CONFIG_SND_DM365_VOICE_CODEC)
|
||||
.codec_dev = &soc_codec_dev_cq93vc,
|
||||
#endif
|
||||
};
|
||||
|
||||
/* evm audio subsystem */
|
||||
static struct snd_soc_device dm6467_evm_snd_devdata = {
|
||||
.card = &dm6467_snd_soc_card_evm,
|
||||
|
@ -244,12 +296,15 @@ static int __init evm_init(void)
|
|||
int index;
|
||||
int ret;
|
||||
|
||||
if (machine_is_davinci_evm() || machine_is_davinci_dm365_evm()) {
|
||||
if (machine_is_davinci_evm()) {
|
||||
evm_snd_dev_data = &evm_snd_devdata;
|
||||
index = 0;
|
||||
} else if (machine_is_davinci_dm355_evm()) {
|
||||
evm_snd_dev_data = &evm_snd_devdata;
|
||||
index = 1;
|
||||
} else if (machine_is_davinci_dm365_evm()) {
|
||||
evm_snd_dev_data = &dm365_evm_snd_devdata;
|
||||
index = 0;
|
||||
} else if (machine_is_davinci_dm6467_evm()) {
|
||||
evm_snd_dev_data = &dm6467_evm_snd_devdata;
|
||||
index = 0;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче