forked from Minki/linux
Merge branch 'topic/remove-irqf_disable' into for-linus
This commit is contained in:
commit
9430148d80
@ -0,0 +1,11 @@
|
||||
* Freescale SGTL5000 Stereo Codec
|
||||
|
||||
Required properties:
|
||||
- compatible : "fsl,sgtl5000".
|
||||
|
||||
Example:
|
||||
|
||||
codec: sgtl5000@0a {
|
||||
compatible = "fsl,sgtl5000";
|
||||
reg = <0x0a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8510.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8510.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8510 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8510"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8510@1a {
|
||||
compatible = "wlf,wm8510";
|
||||
reg = <0x1a>;
|
||||
};
|
16
Documentation/devicetree/bindings/sound/wm8523.txt
Normal file
16
Documentation/devicetree/bindings/sound/wm8523.txt
Normal file
@ -0,0 +1,16 @@
|
||||
WM8523 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8523"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8523@1a {
|
||||
compatible = "wlf,wm8523";
|
||||
reg = <0x1a>;
|
||||
};
|
16
Documentation/devicetree/bindings/sound/wm8580.txt
Normal file
16
Documentation/devicetree/bindings/sound/wm8580.txt
Normal file
@ -0,0 +1,16 @@
|
||||
WM8580 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8580"
|
||||
|
||||
- reg : the I2C address of the device.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8580@1a {
|
||||
compatible = "wlf,wm8580";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8711.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8711.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8711 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8711"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8711@1a {
|
||||
compatible = "wlf,wm8711";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8728.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8728.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8728 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8728"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8728@1a {
|
||||
compatible = "wlf,wm8728";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8731.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8731.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8731 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8731"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8731@1a {
|
||||
compatible = "wlf,wm8731";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8737.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8737.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8737 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8737"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8737@1a {
|
||||
compatible = "wlf,wm8737";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8741.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8741.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8741 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8741"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8741@1a {
|
||||
compatible = "wlf,wm8741";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8750.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8750.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8750 and WM8987 audio CODECs
|
||||
|
||||
These devices support both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8750" or "wlf,wm8987"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8750@1a {
|
||||
compatible = "wlf,wm8750";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8753.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8753.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8753 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8753"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8737@1a {
|
||||
compatible = "wlf,wm8753";
|
||||
reg = <0x1a>;
|
||||
};
|
16
Documentation/devicetree/bindings/sound/wm8770.txt
Normal file
16
Documentation/devicetree/bindings/sound/wm8770.txt
Normal file
@ -0,0 +1,16 @@
|
||||
WM8770 audio CODEC
|
||||
|
||||
This device supports SPI.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8770"
|
||||
|
||||
- reg : the chip select number.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8770@1 {
|
||||
compatible = "wlf,wm8770";
|
||||
reg = <1>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8776.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8776.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8776 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8776"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8776@1a {
|
||||
compatible = "wlf,wm8776";
|
||||
reg = <0x1a>;
|
||||
};
|
18
Documentation/devicetree/bindings/sound/wm8804.txt
Normal file
18
Documentation/devicetree/bindings/sound/wm8804.txt
Normal file
@ -0,0 +1,18 @@
|
||||
WM8804 audio CODEC
|
||||
|
||||
This device supports both I2C and SPI (configured with pin strapping
|
||||
on the board).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "wlf,wm8804"
|
||||
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8804@1a {
|
||||
compatible = "wlf,wm8804";
|
||||
reg = <0x1a>;
|
||||
};
|
@ -159,6 +159,11 @@ static void __init edb93xx_register_spi(void)
|
||||
/*************************************************************************
|
||||
* EDB93xx I2S
|
||||
*************************************************************************/
|
||||
static struct platform_device edb93xx_audio_device = {
|
||||
.name = "edb93xx-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static int __init edb93xx_has_audio(void)
|
||||
{
|
||||
return (machine_is_edb9301() || machine_is_edb9302() ||
|
||||
@ -170,6 +175,7 @@ static void __init edb93xx_register_i2s(void)
|
||||
{
|
||||
if (edb93xx_has_audio()) {
|
||||
ep93xx_register_i2s();
|
||||
platform_device_register(&edb93xx_audio_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,17 @@ static struct i2c_board_info __initdata simone_i2c_board_info[] = {
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device simone_audio_device = {
|
||||
.name = "simone-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void __init simone_register_audio(void)
|
||||
{
|
||||
ep93xx_register_ac97();
|
||||
platform_device_register(&simone_audio_device);
|
||||
}
|
||||
|
||||
static void __init simone_init_machine(void)
|
||||
{
|
||||
ep93xx_init_devices();
|
||||
@ -61,7 +72,7 @@ static void __init simone_init_machine(void)
|
||||
ep93xx_register_fb(&simone_fb_info);
|
||||
ep93xx_register_i2c(&simone_i2c_gpio_data, simone_i2c_board_info,
|
||||
ARRAY_SIZE(simone_i2c_board_info));
|
||||
ep93xx_register_ac97();
|
||||
simone_register_audio();
|
||||
}
|
||||
|
||||
MACHINE_START(SIM_ONE, "Simplemachines Sim.One Board")
|
||||
|
@ -150,6 +150,17 @@ static struct ep93xxfb_mach_info __initdata snappercl15_fb_info = {
|
||||
.bpp = 16,
|
||||
};
|
||||
|
||||
static struct platform_device snappercl15_audio_device = {
|
||||
.name = "snappercl15-audio",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static void __init snappercl15_register_audio(void)
|
||||
{
|
||||
ep93xx_register_i2s();
|
||||
platform_device_register(&snappercl15_audio_device);
|
||||
}
|
||||
|
||||
static void __init snappercl15_init_machine(void)
|
||||
{
|
||||
ep93xx_init_devices();
|
||||
@ -157,7 +168,7 @@ static void __init snappercl15_init_machine(void)
|
||||
ep93xx_register_i2c(&snappercl15_i2c_gpio_data, snappercl15_i2c_data,
|
||||
ARRAY_SIZE(snappercl15_i2c_data));
|
||||
ep93xx_register_fb(&snappercl15_fb_info);
|
||||
ep93xx_register_i2s();
|
||||
snappercl15_register_audio();
|
||||
platform_device_register(&snappercl15_nand_device);
|
||||
}
|
||||
|
||||
|
@ -422,6 +422,7 @@ static struct resource au1200_psc1_res[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/* AC97 or I2S device */
|
||||
static struct platform_device db1200_audio_dev = {
|
||||
/* name assigned later based on switch setting */
|
||||
.id = 1, /* PSC ID */
|
||||
@ -429,19 +430,32 @@ static struct platform_device db1200_audio_dev = {
|
||||
.resource = au1200_psc1_res,
|
||||
};
|
||||
|
||||
/* DB1200 ASoC card device */
|
||||
static struct platform_device db1200_sound_dev = {
|
||||
/* name assigned later based on switch setting */
|
||||
.id = 1, /* PSC ID */
|
||||
};
|
||||
|
||||
static struct platform_device db1200_stac_dev = {
|
||||
.name = "ac97-codec",
|
||||
.id = 1, /* on PSC1 */
|
||||
};
|
||||
|
||||
static struct platform_device db1200_audiodma_dev = {
|
||||
.name = "au1xpsc-pcm",
|
||||
.id = 1, /* PSC ID */
|
||||
};
|
||||
|
||||
static struct platform_device *db1200_devs[] __initdata = {
|
||||
NULL, /* PSC0, selected by S6.8 */
|
||||
&db1200_ide_dev,
|
||||
&db1200_eth_dev,
|
||||
&db1200_rtc_dev,
|
||||
&db1200_nand_dev,
|
||||
&db1200_audiodma_dev,
|
||||
&db1200_audio_dev,
|
||||
&db1200_stac_dev,
|
||||
&db1200_sound_dev,
|
||||
};
|
||||
|
||||
static int __init db1200_dev_init(void)
|
||||
@ -501,10 +515,12 @@ static int __init db1200_dev_init(void)
|
||||
if (sw == BCSR_SWITCHES_DIP_8) {
|
||||
bcsr_mod(BCSR_RESETS, 0, BCSR_RESETS_PSC1MUX);
|
||||
db1200_audio_dev.name = "au1xpsc_i2s";
|
||||
db1200_sound_dev.name = "db1200-i2s";
|
||||
printk(KERN_INFO " S6.7 ON : PSC1 mode I2S\n");
|
||||
} else {
|
||||
bcsr_mod(BCSR_RESETS, BCSR_RESETS_PSC1MUX, 0);
|
||||
db1200_audio_dev.name = "au1xpsc_ac97";
|
||||
db1200_sound_dev.name = "db1200-ac97";
|
||||
printk(KERN_INFO " S6.7 OFF: PSC1 mode AC97\n");
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,11 @@
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/au1000_dma.h>
|
||||
#include <asm/mach-au1x00/au1xxx.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
#include "../platform.h"
|
||||
@ -85,6 +88,45 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static struct resource alchemy_ac97c_res[] = {
|
||||
[0] = {
|
||||
.start = AU1000_AC97_PHYS_ADDR,
|
||||
.end = AU1000_AC97_PHYS_ADDR + 0xfff,
|
||||
.flags = IORESOURCE_MEM,
|
||||
},
|
||||
[1] = {
|
||||
.start = DMA_ID_AC97C_TX,
|
||||
.end = DMA_ID_AC97C_TX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
[2] = {
|
||||
.start = DMA_ID_AC97C_RX,
|
||||
.end = DMA_ID_AC97C_RX,
|
||||
.flags = IORESOURCE_DMA,
|
||||
},
|
||||
};
|
||||
|
||||
static struct platform_device alchemy_ac97c_dev = {
|
||||
.name = "alchemy-ac97c",
|
||||
.id = -1,
|
||||
.resource = alchemy_ac97c_res,
|
||||
.num_resources = ARRAY_SIZE(alchemy_ac97c_res),
|
||||
};
|
||||
|
||||
static struct platform_device alchemy_ac97c_dma_dev = {
|
||||
.name = "alchemy-pcm-dma",
|
||||
.id = 0,
|
||||
};
|
||||
|
||||
static struct platform_device db1x00_codec_dev = {
|
||||
.name = "ac97-codec",
|
||||
.id = -1,
|
||||
};
|
||||
|
||||
static struct platform_device db1x00_audio_dev = {
|
||||
.name = "db1000-audio",
|
||||
};
|
||||
|
||||
static int __init db1xxx_dev_init(void)
|
||||
{
|
||||
#ifdef DB1XXX_HAS_PCMCIA
|
||||
@ -113,6 +155,12 @@ static int __init db1xxx_dev_init(void)
|
||||
1);
|
||||
#endif
|
||||
db1x_register_norflash(BOARD_FLASH_SIZE, BOARD_FLASH_WIDTH, F_SWAPPED);
|
||||
|
||||
platform_device_register(&db1x00_codec_dev);
|
||||
platform_device_register(&alchemy_ac97c_dma_dev);
|
||||
platform_device_register(&alchemy_ac97c_dev);
|
||||
platform_device_register(&db1x00_audio_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
device_initcall(db1xxx_dev_init);
|
||||
|
@ -37,6 +37,11 @@ struct regmap {
|
||||
void *work_buf; /* Scratch buffer used to format I/O */
|
||||
struct regmap_format format; /* Buffer format */
|
||||
const struct regmap_bus *bus;
|
||||
|
||||
unsigned int max_register;
|
||||
bool (*writeable_reg)(struct device *dev, unsigned int reg);
|
||||
bool (*readable_reg)(struct device *dev, unsigned int reg);
|
||||
bool (*volatile_reg)(struct device *dev, unsigned int reg);
|
||||
};
|
||||
|
||||
static void regmap_format_4_12_write(struct regmap *map,
|
||||
@ -116,6 +121,10 @@ struct regmap *regmap_init(struct device *dev,
|
||||
map->format.val_bytes = config->val_bits / 8;
|
||||
map->dev = dev;
|
||||
map->bus = bus;
|
||||
map->max_register = config->max_register;
|
||||
map->writeable_reg = config->writeable_reg;
|
||||
map->readable_reg = config->readable_reg;
|
||||
map->volatile_reg = config->volatile_reg;
|
||||
|
||||
switch (config->reg_bits) {
|
||||
case 4:
|
||||
|
@ -97,7 +97,7 @@ static void twl6040_vibra_enable(struct vibra_info *info)
|
||||
}
|
||||
|
||||
twl6040_power(info->twl6040, 1);
|
||||
if (twl6040->rev <= TWL6040_REV_ES1_1) {
|
||||
if (twl6040_get_revid(twl6040) <= TWL6040_REV_ES1_1) {
|
||||
/*
|
||||
* ERRATA: Disable overcurrent protection for at least
|
||||
* 3ms when enabling vibrator drivers to avoid false
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include <linux/mfd/core.h>
|
||||
#include <linux/mfd/twl6040.h>
|
||||
|
||||
static struct platform_device *twl6040_dev;
|
||||
|
||||
int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
|
||||
{
|
||||
int ret;
|
||||
@ -203,11 +201,11 @@ static irqreturn_t twl6040_naudint_handler(int irq, void *data)
|
||||
if (intid & TWL6040_THINT) {
|
||||
status = twl6040_reg_read(twl6040, TWL6040_REG_STATUS);
|
||||
if (status & TWL6040_TSHUTDET) {
|
||||
dev_warn(&twl6040_dev->dev,
|
||||
dev_warn(twl6040->dev,
|
||||
"Thermal shutdown, powering-off");
|
||||
twl6040_power(twl6040, 0);
|
||||
} else {
|
||||
dev_warn(&twl6040_dev->dev,
|
||||
dev_warn(twl6040->dev,
|
||||
"Leaving thermal shutdown, powering-on");
|
||||
twl6040_power(twl6040, 1);
|
||||
}
|
||||
@ -227,7 +225,7 @@ static int twl6040_power_up_completion(struct twl6040 *twl6040,
|
||||
if (!time_left) {
|
||||
intid = twl6040_reg_read(twl6040, TWL6040_REG_INTID);
|
||||
if (!(intid & TWL6040_READYINT)) {
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"timeout waiting for READYINT\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
@ -255,7 +253,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
|
||||
/* wait for power-up completion */
|
||||
ret = twl6040_power_up_completion(twl6040, naudint);
|
||||
if (ret) {
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"automatic power-down failed\n");
|
||||
twl6040->power_count = 0;
|
||||
goto out;
|
||||
@ -264,7 +262,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
|
||||
/* use manual power-up sequence */
|
||||
ret = twl6040_power_up(twl6040);
|
||||
if (ret) {
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"manual power-up failed\n");
|
||||
twl6040->power_count = 0;
|
||||
goto out;
|
||||
@ -276,7 +274,7 @@ int twl6040_power(struct twl6040 *twl6040, int on)
|
||||
} else {
|
||||
/* already powered-down */
|
||||
if (!twl6040->power_count) {
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"device is already powered-off\n");
|
||||
ret = -EPERM;
|
||||
goto out;
|
||||
@ -326,7 +324,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
lppllctl &= ~TWL6040_LPLLFIN;
|
||||
break;
|
||||
default:
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"freq_out %d not supported\n", freq_out);
|
||||
ret = -EINVAL;
|
||||
goto pll_out;
|
||||
@ -347,7 +345,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
hppllctl);
|
||||
break;
|
||||
default:
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"freq_in %d not supported\n", freq_in);
|
||||
ret = -EINVAL;
|
||||
goto pll_out;
|
||||
@ -356,7 +354,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
case TWL6040_SYSCLK_SEL_HPPLL:
|
||||
/* high-performance PLL can provide only 19.2 MHz */
|
||||
if (freq_out != 19200000) {
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"freq_out %d not supported\n", freq_out);
|
||||
ret = -EINVAL;
|
||||
goto pll_out;
|
||||
@ -389,7 +387,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
TWL6040_HPLLENA;
|
||||
break;
|
||||
default:
|
||||
dev_err(&twl6040_dev->dev,
|
||||
dev_err(twl6040->dev,
|
||||
"freq_in %d not supported\n", freq_in);
|
||||
ret = -EINVAL;
|
||||
goto pll_out;
|
||||
@ -406,7 +404,7 @@ int twl6040_set_pll(struct twl6040 *twl6040, int pll_id,
|
||||
twl6040_reg_write(twl6040, TWL6040_REG_LPPLLCTL, lppllctl);
|
||||
break;
|
||||
default:
|
||||
dev_err(&twl6040_dev->dev, "unknown pll id %d\n", pll_id);
|
||||
dev_err(twl6040->dev, "unknown pll id %d\n", pll_id);
|
||||
ret = -EINVAL;
|
||||
goto pll_out;
|
||||
}
|
||||
@ -471,9 +469,7 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, twl6040);
|
||||
|
||||
twl6040_dev = pdev;
|
||||
twl6040->dev = &pdev->dev;
|
||||
twl6040->audpwron = pdata->audpwron_gpio;
|
||||
twl6040->irq = pdata->naudint_irq;
|
||||
twl6040->irq_base = pdata->irq_base;
|
||||
|
||||
@ -483,6 +479,12 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
|
||||
|
||||
twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
|
||||
|
||||
/* ERRATA: Automatic power-up is not possible in ES1.0 */
|
||||
if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
|
||||
twl6040->audpwron = pdata->audpwron_gpio;
|
||||
else
|
||||
twl6040->audpwron = -EINVAL;
|
||||
|
||||
if (gpio_is_valid(twl6040->audpwron)) {
|
||||
ret = gpio_request(twl6040->audpwron, "audpwron");
|
||||
if (ret)
|
||||
@ -493,10 +495,6 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
|
||||
goto gpio2_err;
|
||||
}
|
||||
|
||||
/* ERRATA: Automatic power-up is not possible in ES1.0 */
|
||||
if (twl6040->rev == TWL6040_REV_ES1_0)
|
||||
twl6040->audpwron = -EINVAL;
|
||||
|
||||
/* codec interrupt */
|
||||
ret = twl6040_irq_init(twl6040);
|
||||
if (ret)
|
||||
@ -566,7 +564,6 @@ gpio2_err:
|
||||
gpio1_err:
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(twl6040);
|
||||
twl6040_dev = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -586,7 +583,6 @@ static int __devexit twl6040_remove(struct platform_device *pdev)
|
||||
mfd_remove_devices(&pdev->dev);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
kfree(twl6040);
|
||||
twl6040_dev = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1552,6 +1552,63 @@ int regulator_force_disable(struct regulator *regulator)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_force_disable);
|
||||
|
||||
static void regulator_disable_work(struct work_struct *work)
|
||||
{
|
||||
struct regulator_dev *rdev = container_of(work, struct regulator_dev,
|
||||
disable_work.work);
|
||||
int count, i, ret;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
|
||||
BUG_ON(!rdev->deferred_disables);
|
||||
|
||||
count = rdev->deferred_disables;
|
||||
rdev->deferred_disables = 0;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = _regulator_disable(rdev);
|
||||
if (ret != 0)
|
||||
rdev_err(rdev, "Deferred disable failed: %d\n", ret);
|
||||
}
|
||||
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
if (rdev->supply) {
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = regulator_disable(rdev->supply);
|
||||
if (ret != 0) {
|
||||
rdev_err(rdev,
|
||||
"Supply disable failed: %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* regulator_disable_deferred - disable regulator output with delay
|
||||
* @regulator: regulator source
|
||||
* @ms: miliseconds until the regulator is disabled
|
||||
*
|
||||
* Execute regulator_disable() on the regulator after a delay. This
|
||||
* is intended for use with devices that require some time to quiesce.
|
||||
*
|
||||
* NOTE: this will only disable the regulator output if no other consumer
|
||||
* devices have it enabled, the regulator device supports disabling and
|
||||
* machine constraints permit this operation.
|
||||
*/
|
||||
int regulator_disable_deferred(struct regulator *regulator, int ms)
|
||||
{
|
||||
struct regulator_dev *rdev = regulator->rdev;
|
||||
|
||||
mutex_lock(&rdev->mutex);
|
||||
rdev->deferred_disables++;
|
||||
mutex_unlock(&rdev->mutex);
|
||||
|
||||
return schedule_delayed_work(&rdev->disable_work,
|
||||
msecs_to_jiffies(ms));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regulator_disable_deferred);
|
||||
|
||||
static int _regulator_is_enabled(struct regulator_dev *rdev)
|
||||
{
|
||||
/* If we don't know then assume that the regulator is always on */
|
||||
@ -2622,6 +2679,7 @@ struct regulator_dev *regulator_register(struct regulator_desc *regulator_desc,
|
||||
INIT_LIST_HEAD(&rdev->consumer_list);
|
||||
INIT_LIST_HEAD(&rdev->list);
|
||||
BLOCKING_INIT_NOTIFIER_HEAD(&rdev->notifier);
|
||||
INIT_DELAYED_WORK(&rdev->disable_work, regulator_disable_work);
|
||||
|
||||
/* preform any regulator specific init */
|
||||
if (init_data->regulator_init) {
|
||||
@ -2729,6 +2787,7 @@ void regulator_unregister(struct regulator_dev *rdev)
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
debugfs_remove_recursive(rdev->debugfs);
|
||||
#endif
|
||||
flush_work_sync(&rdev->disable_work.work);
|
||||
WARN_ON(rdev->open_count);
|
||||
unset_regulator_supplies(rdev);
|
||||
list_del(&rdev->list);
|
||||
|
@ -70,9 +70,6 @@
|
||||
|
||||
#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
|
||||
|
||||
#define TWL6040_VIOREGNUM 18
|
||||
#define TWL6040_VDDREGNUM 21
|
||||
|
||||
/* INTID (0x03) fields */
|
||||
|
||||
#define TWL6040_THINT 0x01
|
||||
@ -225,4 +222,9 @@ unsigned int twl6040_get_sysclk(struct twl6040 *twl6040);
|
||||
int twl6040_irq_init(struct twl6040 *twl6040);
|
||||
void twl6040_irq_exit(struct twl6040 *twl6040);
|
||||
|
||||
static inline int twl6040_get_revid(struct twl6040 *twl6040)
|
||||
{
|
||||
return twl6040->rev;
|
||||
}
|
||||
|
||||
#endif /* End of __TWL6040_CODEC_H__ */
|
||||
|
@ -72,6 +72,7 @@
|
||||
#define WM8994_DC_SERVO_2 0x55
|
||||
#define WM8994_DC_SERVO_4 0x57
|
||||
#define WM8994_DC_SERVO_READBACK 0x58
|
||||
#define WM8994_DC_SERVO_4E 0x59
|
||||
#define WM8994_ANALOGUE_HP_1 0x60
|
||||
#define WM8958_MIC_DETECT_1 0xD0
|
||||
#define WM8958_MIC_DETECT_2 0xD1
|
||||
@ -133,6 +134,8 @@
|
||||
#define WM8994_AIF1_DAC1_FILTERS_2 0x421
|
||||
#define WM8994_AIF1_DAC2_FILTERS_1 0x422
|
||||
#define WM8994_AIF1_DAC2_FILTERS_2 0x423
|
||||
#define WM8958_AIF1_DAC1_NOISE_GATE 0x430
|
||||
#define WM8958_AIF1_DAC2_NOISE_GATE 0x431
|
||||
#define WM8994_AIF1_DRC1_1 0x440
|
||||
#define WM8994_AIF1_DRC1_2 0x441
|
||||
#define WM8994_AIF1_DRC1_3 0x442
|
||||
@ -190,6 +193,7 @@
|
||||
#define WM8994_AIF2_ADC_FILTERS 0x510
|
||||
#define WM8994_AIF2_DAC_FILTERS_1 0x520
|
||||
#define WM8994_AIF2_DAC_FILTERS_2 0x521
|
||||
#define WM8958_AIF2_DAC_NOISE_GATE 0x530
|
||||
#define WM8994_AIF2_DRC_1 0x540
|
||||
#define WM8994_AIF2_DRC_2 0x541
|
||||
#define WM8994_AIF2_DRC_3 0x542
|
||||
@ -1920,6 +1924,44 @@
|
||||
#define WM8994_LDO2_DISCH_SHIFT 0 /* LDO2_DISCH */
|
||||
#define WM8994_LDO2_DISCH_WIDTH 1 /* LDO2_DISCH */
|
||||
|
||||
/*
|
||||
* R61 (0x3D) - MICBIAS1
|
||||
*/
|
||||
#define WM8958_MICB1_RATE 0x0020 /* MICB1_RATE */
|
||||
#define WM8958_MICB1_RATE_MASK 0x0020 /* MICB1_RATE */
|
||||
#define WM8958_MICB1_RATE_SHIFT 5 /* MICB1_RATE */
|
||||
#define WM8958_MICB1_RATE_WIDTH 1 /* MICB1_RATE */
|
||||
#define WM8958_MICB1_MODE 0x0010 /* MICB1_MODE */
|
||||
#define WM8958_MICB1_MODE_MASK 0x0010 /* MICB1_MODE */
|
||||
#define WM8958_MICB1_MODE_SHIFT 4 /* MICB1_MODE */
|
||||
#define WM8958_MICB1_MODE_WIDTH 1 /* MICB1_MODE */
|
||||
#define WM8958_MICB1_LVL_MASK 0x000E /* MICB1_LVL - [3:1] */
|
||||
#define WM8958_MICB1_LVL_SHIFT 1 /* MICB1_LVL - [3:1] */
|
||||
#define WM8958_MICB1_LVL_WIDTH 3 /* MICB1_LVL - [3:1] */
|
||||
#define WM8958_MICB1_DISCH 0x0001 /* MICB1_DISCH */
|
||||
#define WM8958_MICB1_DISCH_MASK 0x0001 /* MICB1_DISCH */
|
||||
#define WM8958_MICB1_DISCH_SHIFT 0 /* MICB1_DISCH */
|
||||
#define WM8958_MICB1_DISCH_WIDTH 1 /* MICB1_DISCH */
|
||||
|
||||
/*
|
||||
* R62 (0x3E) - MICBIAS2
|
||||
*/
|
||||
#define WM8958_MICB2_RATE 0x0020 /* MICB2_RATE */
|
||||
#define WM8958_MICB2_RATE_MASK 0x0020 /* MICB2_RATE */
|
||||
#define WM8958_MICB2_RATE_SHIFT 5 /* MICB2_RATE */
|
||||
#define WM8958_MICB2_RATE_WIDTH 1 /* MICB2_RATE */
|
||||
#define WM8958_MICB2_MODE 0x0010 /* MICB2_MODE */
|
||||
#define WM8958_MICB2_MODE_MASK 0x0010 /* MICB2_MODE */
|
||||
#define WM8958_MICB2_MODE_SHIFT 4 /* MICB2_MODE */
|
||||
#define WM8958_MICB2_MODE_WIDTH 1 /* MICB2_MODE */
|
||||
#define WM8958_MICB2_LVL_MASK 0x000E /* MICB2_LVL - [3:1] */
|
||||
#define WM8958_MICB2_LVL_SHIFT 1 /* MICB2_LVL - [3:1] */
|
||||
#define WM8958_MICB2_LVL_WIDTH 3 /* MICB2_LVL - [3:1] */
|
||||
#define WM8958_MICB2_DISCH 0x0001 /* MICB2_DISCH */
|
||||
#define WM8958_MICB2_DISCH_MASK 0x0001 /* MICB2_DISCH */
|
||||
#define WM8958_MICB2_DISCH_SHIFT 0 /* MICB2_DISCH */
|
||||
#define WM8958_MICB2_DISCH_WIDTH 1 /* MICB2_DISCH */
|
||||
|
||||
/*
|
||||
* R76 (0x4C) - Charge Pump (1)
|
||||
*/
|
||||
@ -2948,6 +2990,34 @@
|
||||
#define WM8994_AIF1DAC2_3D_ENA_SHIFT 8 /* AIF1DAC2_3D_ENA */
|
||||
#define WM8994_AIF1DAC2_3D_ENA_WIDTH 1 /* AIF1DAC2_3D_ENA */
|
||||
|
||||
/*
|
||||
* R1072 (0x430) - AIF1 DAC1 Noise Gate
|
||||
*/
|
||||
#define WM8958_AIF1DAC1_NG_HLD_MASK 0x0060 /* AIF1DAC1_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF1DAC1_NG_HLD_SHIFT 5 /* AIF1DAC1_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF1DAC1_NG_HLD_WIDTH 2 /* AIF1DAC1_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF1DAC1_NG_THR_MASK 0x000E /* AIF1DAC1_NG_THR - [3:1] */
|
||||
#define WM8958_AIF1DAC1_NG_THR_SHIFT 1 /* AIF1DAC1_NG_THR - [3:1] */
|
||||
#define WM8958_AIF1DAC1_NG_THR_WIDTH 3 /* AIF1DAC1_NG_THR - [3:1] */
|
||||
#define WM8958_AIF1DAC1_NG_ENA 0x0001 /* AIF1DAC1_NG_ENA */
|
||||
#define WM8958_AIF1DAC1_NG_ENA_MASK 0x0001 /* AIF1DAC1_NG_ENA */
|
||||
#define WM8958_AIF1DAC1_NG_ENA_SHIFT 0 /* AIF1DAC1_NG_ENA */
|
||||
#define WM8958_AIF1DAC1_NG_ENA_WIDTH 1 /* AIF1DAC1_NG_ENA */
|
||||
|
||||
/*
|
||||
* R1073 (0x431) - AIF1 DAC2 Noise Gate
|
||||
*/
|
||||
#define WM8958_AIF1DAC2_NG_HLD_MASK 0x0060 /* AIF1DAC2_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF1DAC2_NG_HLD_SHIFT 5 /* AIF1DAC2_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF1DAC2_NG_HLD_WIDTH 2 /* AIF1DAC2_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF1DAC2_NG_THR_MASK 0x000E /* AIF1DAC2_NG_THR - [3:1] */
|
||||
#define WM8958_AIF1DAC2_NG_THR_SHIFT 1 /* AIF1DAC2_NG_THR - [3:1] */
|
||||
#define WM8958_AIF1DAC2_NG_THR_WIDTH 3 /* AIF1DAC2_NG_THR - [3:1] */
|
||||
#define WM8958_AIF1DAC2_NG_ENA 0x0001 /* AIF1DAC2_NG_ENA */
|
||||
#define WM8958_AIF1DAC2_NG_ENA_MASK 0x0001 /* AIF1DAC2_NG_ENA */
|
||||
#define WM8958_AIF1DAC2_NG_ENA_SHIFT 0 /* AIF1DAC2_NG_ENA */
|
||||
#define WM8958_AIF1DAC2_NG_ENA_WIDTH 1 /* AIF1DAC2_NG_ENA */
|
||||
|
||||
/*
|
||||
* R1088 (0x440) - AIF1 DRC1 (1)
|
||||
*/
|
||||
@ -3559,6 +3629,20 @@
|
||||
#define WM8994_AIF2DAC_3D_ENA_SHIFT 8 /* AIF2DAC_3D_ENA */
|
||||
#define WM8994_AIF2DAC_3D_ENA_WIDTH 1 /* AIF2DAC_3D_ENA */
|
||||
|
||||
/*
|
||||
* R1328 (0x530) - AIF2 DAC Noise Gate
|
||||
*/
|
||||
#define WM8958_AIF2DAC_NG_HLD_MASK 0x0060 /* AIF2DAC_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF2DAC_NG_HLD_SHIFT 5 /* AIF2DAC_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF2DAC_NG_HLD_WIDTH 2 /* AIF2DAC_NG_HLD - [6:5] */
|
||||
#define WM8958_AIF2DAC_NG_THR_MASK 0x000E /* AIF2DAC_NG_THR - [3:1] */
|
||||
#define WM8958_AIF2DAC_NG_THR_SHIFT 1 /* AIF2DAC_NG_THR - [3:1] */
|
||||
#define WM8958_AIF2DAC_NG_THR_WIDTH 3 /* AIF2DAC_NG_THR - [3:1] */
|
||||
#define WM8958_AIF2DAC_NG_ENA 0x0001 /* AIF2DAC_NG_ENA */
|
||||
#define WM8958_AIF2DAC_NG_ENA_MASK 0x0001 /* AIF2DAC_NG_ENA */
|
||||
#define WM8958_AIF2DAC_NG_ENA_SHIFT 0 /* AIF2DAC_NG_ENA */
|
||||
#define WM8958_AIF2DAC_NG_ENA_WIDTH 1 /* AIF2DAC_NG_ENA */
|
||||
|
||||
/*
|
||||
* R1344 (0x540) - AIF2 DRC (1)
|
||||
*/
|
||||
|
@ -20,9 +20,61 @@
|
||||
struct i2c_client;
|
||||
struct spi_device;
|
||||
|
||||
/**
|
||||
* Default value for a register. We use an array of structs rather
|
||||
* than a simple array as many modern devices have very sparse
|
||||
* register maps.
|
||||
*
|
||||
* @reg: Register address.
|
||||
* @def: Register default value.
|
||||
*/
|
||||
struct reg_default {
|
||||
unsigned int reg;
|
||||
unsigned int def;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration for the register map of a device.
|
||||
*
|
||||
* @reg_bits: Number of bits in a register address, mandatory.
|
||||
* @val_bits: Number of bits in a register value, mandatory.
|
||||
*
|
||||
* @writeable_reg: Optional callback returning true if the register
|
||||
* can be written to.
|
||||
* @readable_reg: Optional callback returning true if the register
|
||||
* can be read from.
|
||||
* @volatile_reg: Optional callback returning true if the register
|
||||
* value can't be cached.
|
||||
* @precious_reg: Optional callback returning true if the rgister
|
||||
* should not be read outside of a call from the driver
|
||||
* (eg, a clear on read interrupt status register).
|
||||
*
|
||||
* @max_register: Optional, specifies the maximum valid register index.
|
||||
* @reg_defaults: Power on reset values for registers (for use with
|
||||
* register cache support).
|
||||
* @num_reg_defaults: Number of elements in reg_defaults.
|
||||
*
|
||||
* @read_flag_mask: Mask to be set in the top byte of the register when doing
|
||||
* a read.
|
||||
* @write_flag_mask: Mask to be set in the top byte of the register when doing
|
||||
* a write. If both read_flag_mask and write_flag_mask are
|
||||
* empty the regmap_bus default masks are used.
|
||||
*/
|
||||
struct regmap_config {
|
||||
int reg_bits;
|
||||
int val_bits;
|
||||
|
||||
bool (*writeable_reg)(struct device *dev, unsigned int reg);
|
||||
bool (*readable_reg)(struct device *dev, unsigned int reg);
|
||||
bool (*volatile_reg)(struct device *dev, unsigned int reg);
|
||||
bool (*precious_reg)(struct device *dev, unsigned int reg);
|
||||
|
||||
unsigned int max_register;
|
||||
struct reg_default *reg_defaults;
|
||||
int num_reg_defaults;
|
||||
|
||||
u8 read_flag_mask;
|
||||
u8 write_flag_mask;
|
||||
};
|
||||
|
||||
typedef int (*regmap_hw_write)(struct device *dev, const void *data,
|
||||
|
@ -141,6 +141,7 @@ int regulator_enable(struct regulator *regulator);
|
||||
int regulator_disable(struct regulator *regulator);
|
||||
int regulator_force_disable(struct regulator *regulator);
|
||||
int regulator_is_enabled(struct regulator *regulator);
|
||||
int regulator_disable_deferred(struct regulator *regulator, int ms);
|
||||
|
||||
int regulator_bulk_get(struct device *dev, int num_consumers,
|
||||
struct regulator_bulk_data *consumers);
|
||||
@ -211,6 +212,12 @@ static inline int regulator_disable(struct regulator *regulator)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int regulator_disable_deferred(struct regulator *regulator,
|
||||
int ms)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int regulator_is_enabled(struct regulator *regulator)
|
||||
{
|
||||
return 1;
|
||||
|
@ -199,6 +199,9 @@ struct regulator_dev {
|
||||
struct regulation_constraints *constraints;
|
||||
struct regulator *supply; /* for tree */
|
||||
|
||||
struct delayed_work disable_work;
|
||||
int deferred_disables;
|
||||
|
||||
void *reg_data; /* regulator_dev data */
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
34
include/sound/adau1373.h
Normal file
34
include/sound/adau1373.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Analog Devices ADAU1373 Audio Codec drive
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_ADAU1373_H__
|
||||
#define __SOUND_ADAU1373_H__
|
||||
|
||||
enum adau1373_micbias_voltage {
|
||||
ADAU1373_MICBIAS_2_9V = 0,
|
||||
ADAU1373_MICBIAS_2_2V = 1,
|
||||
ADAU1373_MICBIAS_2_6V = 2,
|
||||
ADAU1373_MICBIAS_1_8V = 3,
|
||||
};
|
||||
|
||||
#define ADAU1373_DRC_SIZE 13
|
||||
|
||||
struct adau1373_platform_data {
|
||||
bool input_differential[4];
|
||||
bool lineout_differential;
|
||||
bool lineout_ground_sense;
|
||||
|
||||
unsigned int num_drc;
|
||||
uint8_t drc_setting[3][ADAU1373_DRC_SIZE];
|
||||
|
||||
enum adau1373_micbias_voltage micbias1;
|
||||
enum adau1373_micbias_voltage micbias2;
|
||||
};
|
||||
|
||||
#endif
|
@ -62,7 +62,7 @@ static int snd_legacy_find_free_irq(int *irq_table)
|
||||
{
|
||||
while (*irq_table != -1) {
|
||||
if (!request_irq(*irq_table, snd_legacy_empty_irq_handler,
|
||||
IRQF_DISABLED | IRQF_PROBE_SHARED, "ALSA Test IRQ",
|
||||
IRQF_PROBE_SHARED, "ALSA Test IRQ",
|
||||
(void *) irq_table)) {
|
||||
free_irq(*irq_table, (void *) irq_table);
|
||||
return *irq_table;
|
||||
|
16
include/sound/saif.h
Normal file
16
include/sound/saif.h
Normal file
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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 __SOUND_SAIF_H__
|
||||
#define __SOUND_SAIF_H__
|
||||
|
||||
struct mxs_saif_platform_data {
|
||||
int (*init) (void);
|
||||
int (*get_master_id) (unsigned int saif_id);
|
||||
};
|
||||
#endif
|
@ -524,6 +524,8 @@ struct snd_soc_dapm_context {
|
||||
enum snd_soc_bias_level target_bias_level;
|
||||
struct list_head list;
|
||||
|
||||
int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_dapm;
|
||||
#endif
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/control.h>
|
||||
@ -260,6 +261,7 @@ extern struct snd_ac97_bus_ops soc_ac97_ops;
|
||||
enum snd_soc_control_type {
|
||||
SND_SOC_I2C = 1,
|
||||
SND_SOC_SPI,
|
||||
SND_SOC_REGMAP,
|
||||
};
|
||||
|
||||
enum snd_soc_compress_type {
|
||||
@ -274,7 +276,7 @@ enum snd_soc_pcm_subclass {
|
||||
};
|
||||
|
||||
int snd_soc_codec_set_sysclk(struct snd_soc_codec *codec, int clk_id,
|
||||
unsigned int freq, int dir);
|
||||
int source, unsigned int freq, int dir);
|
||||
int snd_soc_codec_set_pll(struct snd_soc_codec *codec, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out);
|
||||
|
||||
@ -576,6 +578,7 @@ struct snd_soc_codec {
|
||||
const void *reg_def_copy;
|
||||
const struct snd_soc_cache_ops *cache_ops;
|
||||
struct mutex cache_rw_mutex;
|
||||
int val_bytes;
|
||||
|
||||
/* dapm */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
@ -607,7 +610,7 @@ struct snd_soc_codec_driver {
|
||||
|
||||
/* codec wide operations */
|
||||
int (*set_sysclk)(struct snd_soc_codec *codec,
|
||||
int clk_id, unsigned int freq, int dir);
|
||||
int clk_id, int source, unsigned int freq, int dir);
|
||||
int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,
|
||||
unsigned int freq_in, unsigned int freq_out);
|
||||
|
||||
@ -619,7 +622,7 @@ struct snd_soc_codec_driver {
|
||||
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
|
||||
int (*readable_register)(struct snd_soc_codec *, unsigned int);
|
||||
int (*writable_register)(struct snd_soc_codec *, unsigned int);
|
||||
short reg_cache_size;
|
||||
unsigned int reg_cache_size;
|
||||
short reg_cache_step;
|
||||
short reg_word_size;
|
||||
const void *reg_cache_default;
|
||||
@ -630,10 +633,14 @@ struct snd_soc_codec_driver {
|
||||
/* codec bias level */
|
||||
int (*set_bias_level)(struct snd_soc_codec *,
|
||||
enum snd_soc_bias_level level);
|
||||
bool idle_bias_off;
|
||||
|
||||
void (*seq_notifier)(struct snd_soc_dapm_context *,
|
||||
enum snd_soc_dapm_type, int);
|
||||
|
||||
/* codec stream completion event */
|
||||
int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
@ -669,6 +676,9 @@ struct snd_soc_platform_driver {
|
||||
/* platform stream ops */
|
||||
struct snd_pcm_ops *ops;
|
||||
|
||||
/* platform stream completion event */
|
||||
int (*stream_event)(struct snd_soc_dapm_context *dapm, int event);
|
||||
|
||||
/* probe ordering - for components with runtime dependencies */
|
||||
int probe_order;
|
||||
int remove_order;
|
||||
|
@ -443,7 +443,7 @@ static int aaci_pcm_open(struct snd_pcm_substream *substream)
|
||||
mutex_lock(&aaci->irq_lock);
|
||||
if (!aaci->users++) {
|
||||
ret = request_irq(aaci->dev->irq[0], aaci_irq,
|
||||
IRQF_SHARED | IRQF_DISABLED, DRIVER_NAME, aaci);
|
||||
IRQF_SHARED, DRIVER_NAME, aaci);
|
||||
if (ret != 0)
|
||||
aaci->users--;
|
||||
}
|
||||
|
@ -359,7 +359,7 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev)
|
||||
if (ret)
|
||||
goto err_clk2;
|
||||
|
||||
ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
|
||||
ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
|
||||
if (ret < 0)
|
||||
goto err_irq;
|
||||
|
||||
|
@ -1153,7 +1153,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
|
||||
"0x%x done\n", (unsigned int)ml403_ac97cr->port);
|
||||
/* get irq */
|
||||
irq = platform_get_irq(pfdev, 0);
|
||||
if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED,
|
||||
if (request_irq(irq, snd_ml403_ac97cr_irq, 0,
|
||||
dev_name(&pfdev->dev), (void *)ml403_ac97cr)) {
|
||||
snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
|
||||
"unable to grab IRQ %d\n",
|
||||
@ -1166,7 +1166,7 @@ snd_ml403_ac97cr_create(struct snd_card *card, struct platform_device *pfdev,
|
||||
"request (playback) irq %d done\n",
|
||||
ml403_ac97cr->irq);
|
||||
irq = platform_get_irq(pfdev, 1);
|
||||
if (request_irq(irq, snd_ml403_ac97cr_irq, IRQF_DISABLED,
|
||||
if (request_irq(irq, snd_ml403_ac97cr_irq, 0,
|
||||
dev_name(&pfdev->dev), (void *)ml403_ac97cr)) {
|
||||
snd_printk(KERN_ERR SND_ML403_AC97CR_DRIVER ": "
|
||||
"unable to grab IRQ %d\n",
|
||||
|
@ -577,7 +577,7 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
|
||||
else
|
||||
mpu->cport = port + 1;
|
||||
if (irq >= 0) {
|
||||
if (request_irq(irq, snd_mpu401_uart_interrupt, IRQF_DISABLED,
|
||||
if (request_irq(irq, snd_mpu401_uart_interrupt, 0,
|
||||
"MPU401 UART", (void *) mpu)) {
|
||||
snd_printk(KERN_ERR "mpu401_uart: "
|
||||
"unable to grab IRQ %d\n", irq);
|
||||
|
@ -589,7 +589,7 @@ static int __devinit snd_mtpav_get_ISA(struct mtpav * mcard)
|
||||
return -EBUSY;
|
||||
}
|
||||
mcard->port = port;
|
||||
if (request_irq(irq, snd_mtpav_irqh, IRQF_DISABLED, "MOTU MTPAV", mcard)) {
|
||||
if (request_irq(irq, snd_mtpav_irqh, 0, "MOTU MTPAV", mcard)) {
|
||||
snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -816,7 +816,7 @@ static int __devinit snd_uart16550_create(struct snd_card *card,
|
||||
|
||||
if (irq >= 0 && irq != SNDRV_AUTO_IRQ) {
|
||||
if (request_irq(irq, snd_uart16550_interrupt,
|
||||
IRQF_DISABLED, "Serial MIDI", uart)) {
|
||||
0, "Serial MIDI", uart)) {
|
||||
snd_printk(KERN_WARNING
|
||||
"irq %d busy. Using Polling.\n", irq);
|
||||
} else {
|
||||
|
@ -595,7 +595,7 @@ int __devinit snd_ad1816a_create(struct snd_card *card,
|
||||
snd_ad1816a_free(chip);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (request_irq(irq, snd_ad1816a_interrupt, IRQF_DISABLED, "AD1816A", (void *) chip)) {
|
||||
if (request_irq(irq, snd_ad1816a_interrupt, 0, "AD1816A", (void *) chip)) {
|
||||
snd_printk(KERN_ERR "ad1816a: can't grab IRQ %d\n", irq);
|
||||
snd_ad1816a_free(chip);
|
||||
return -EBUSY;
|
||||
|
@ -661,7 +661,7 @@ int snd_es1688_create(struct snd_card *card,
|
||||
snd_printk(KERN_ERR "es1688: can't grab port 0x%lx\n", port + 4);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (request_irq(irq, snd_es1688_interrupt, IRQF_DISABLED, "ES1688", (void *) chip)) {
|
||||
if (request_irq(irq, snd_es1688_interrupt, 0, "ES1688", (void *) chip)) {
|
||||
snd_printk(KERN_ERR "es1688: can't grab IRQ %d\n", irq);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -1805,7 +1805,7 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card,
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx",
|
||||
if (request_irq(irq, snd_es18xx_interrupt, 0, "ES18xx",
|
||||
(void *) card)) {
|
||||
snd_es18xx_free(card);
|
||||
snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq);
|
||||
|
@ -180,7 +180,7 @@ int snd_gus_create(struct snd_card *card,
|
||||
snd_gus_free(gus);
|
||||
return -EBUSY;
|
||||
}
|
||||
if (irq >= 0 && request_irq(irq, snd_gus_interrupt, IRQF_DISABLED, "GUS GF1", (void *) gus)) {
|
||||
if (irq >= 0 && request_irq(irq, snd_gus_interrupt, 0, "GUS GF1", (void *) gus)) {
|
||||
snd_printk(KERN_ERR "gus: can't grab irq %d\n", irq);
|
||||
snd_gus_free(gus);
|
||||
return -EBUSY;
|
||||
|
@ -291,7 +291,7 @@ static int __devinit snd_gusmax_probe(struct device *pdev, unsigned int dev)
|
||||
goto _err;
|
||||
}
|
||||
|
||||
if (request_irq(xirq, snd_gusmax_interrupt, IRQF_DISABLED, "GUS MAX", (void *)maxcard)) {
|
||||
if (request_irq(xirq, snd_gusmax_interrupt, 0, "GUS MAX", (void *)maxcard)) {
|
||||
snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
|
||||
err = -EBUSY;
|
||||
goto _err;
|
||||
|
@ -684,7 +684,7 @@ static int __devinit snd_interwave_probe(struct snd_card *card, int dev)
|
||||
if ((err = snd_gus_initialize(gus)) < 0)
|
||||
return err;
|
||||
|
||||
if (request_irq(xirq, snd_interwave_interrupt, IRQF_DISABLED,
|
||||
if (request_irq(xirq, snd_interwave_interrupt, 0,
|
||||
"InterWave", iwcard)) {
|
||||
snd_printk(KERN_ERR PFX "unable to grab IRQ %d\n", xirq);
|
||||
return -EBUSY;
|
||||
|
@ -667,7 +667,7 @@ static int __devinit snd_opl3sa2_probe(struct snd_card *card, int dev)
|
||||
err = snd_opl3sa2_detect(card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = request_irq(xirq, snd_opl3sa2_interrupt, IRQF_DISABLED,
|
||||
err = request_irq(xirq, snd_opl3sa2_interrupt, 0,
|
||||
"OPL3-SA2", card);
|
||||
if (err) {
|
||||
snd_printk(KERN_ERR PFX "can't grab IRQ %d\n", xirq);
|
||||
|
@ -892,7 +892,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
|
||||
#endif
|
||||
#ifdef OPTi93X
|
||||
error = request_irq(irq, snd_opti93x_interrupt,
|
||||
IRQF_DISABLED, DEV_NAME" - WSS", chip);
|
||||
0, DEV_NAME" - WSS", chip);
|
||||
if (error < 0) {
|
||||
snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq);
|
||||
return error;
|
||||
|
@ -240,7 +240,7 @@ int snd_sbdsp_create(struct snd_card *card,
|
||||
if (request_irq(irq, irq_handler,
|
||||
(hardware == SB_HW_ALS4000 ||
|
||||
hardware == SB_HW_CS5530) ?
|
||||
IRQF_SHARED : IRQF_DISABLED,
|
||||
IRQF_SHARED : 0,
|
||||
"SoundBlaster", (void *) chip)) {
|
||||
snd_printk(KERN_ERR "sb: can't grab irq %d\n", irq);
|
||||
snd_sbdsp_free(chip);
|
||||
|
@ -418,7 +418,7 @@ snd_wavefront_probe (struct snd_card *card, int dev)
|
||||
return -EBUSY;
|
||||
}
|
||||
if (request_irq(ics2115_irq[dev], snd_wavefront_ics2115_interrupt,
|
||||
IRQF_DISABLED, "ICS2115", acard)) {
|
||||
0, "ICS2115", acard)) {
|
||||
snd_printk(KERN_ERR "unable to use ICS2115 IRQ %d\n", ics2115_irq[dev]);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
@ -1833,7 +1833,7 @@ int snd_wss_create(struct snd_card *card,
|
||||
}
|
||||
chip->cport = cport;
|
||||
if (!(hwshare & WSS_HWSHARE_IRQ))
|
||||
if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED,
|
||||
if (request_irq(irq, snd_wss_interrupt, 0,
|
||||
"WSS", (void *) chip)) {
|
||||
snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq);
|
||||
snd_wss_free(chip);
|
||||
|
@ -23,12 +23,15 @@ config SND_SGI_HAL2
|
||||
|
||||
|
||||
config SND_AU1X00
|
||||
tristate "Au1x00 AC97 Port Driver"
|
||||
tristate "Au1x00 AC97 Port Driver (DEPRECATED)"
|
||||
depends on SOC_AU1000 || SOC_AU1100 || SOC_AU1500
|
||||
select SND_PCM
|
||||
select SND_AC97_CODEC
|
||||
help
|
||||
ALSA Sound driver for the Au1x00's AC97 port.
|
||||
|
||||
Newer drivers for ASoC are available, please do not use
|
||||
this driver as it will be removed in the future.
|
||||
|
||||
endif # SND_MIPS
|
||||
|
||||
|
@ -465,13 +465,13 @@ snd_au1000_pcm_new(struct snd_au1000 *au1000)
|
||||
|
||||
flags = claim_dma_lock();
|
||||
if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX,
|
||||
"AC97 TX", au1000_dma_interrupt, IRQF_DISABLED,
|
||||
"AC97 TX", au1000_dma_interrupt, 0,
|
||||
au1000->stream[PLAYBACK])) < 0) {
|
||||
release_dma_lock(flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX,
|
||||
"AC97 RX", au1000_dma_interrupt, IRQF_DISABLED,
|
||||
"AC97 RX", au1000_dma_interrupt, 0,
|
||||
au1000->stream[CAPTURE])) < 0){
|
||||
release_dma_lock(flags);
|
||||
return -EBUSY;
|
||||
|
@ -1234,7 +1234,7 @@ static int sis_resume(struct pci_dev *pci)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
||||
if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, sis)) {
|
||||
printk(KERN_ERR "sis7019: unable to regain IRQ %d\n", pci->irq);
|
||||
goto error;
|
||||
@ -1340,7 +1340,7 @@ static int __devinit sis_chip_create(struct snd_card *card,
|
||||
if (rc)
|
||||
goto error_out_cleanup;
|
||||
|
||||
if (request_irq(pci->irq, sis_interrupt, IRQF_DISABLED|IRQF_SHARED,
|
||||
if (request_irq(pci->irq, sis_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, sis)) {
|
||||
printk(KERN_ERR "unable to allocate irq %d\n", sis->irq);
|
||||
goto error_out_cleanup;
|
||||
|
@ -845,7 +845,7 @@ static int __devinit snd_ps3_allocate_irq(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = request_irq(the_card.irq_no, snd_ps3_interrupt, IRQF_DISABLED,
|
||||
ret = request_irq(the_card.irq_no, snd_ps3_interrupt, 0,
|
||||
SND_PS3_DRIVER_NAME, &the_card);
|
||||
if (ret) {
|
||||
pr_info("%s: request_irq failed (%d)\n", __func__, ret);
|
||||
|
@ -7,6 +7,8 @@ menuconfig SND_SOC
|
||||
select SND_PCM
|
||||
select AC97_BUS if SND_SOC_AC97_BUS
|
||||
select SND_JACK if INPUT=y || INPUT=SND
|
||||
select REGMAP_I2C if I2C
|
||||
select REGMAP_SPI if SPI_MASTER
|
||||
---help---
|
||||
|
||||
If you want ASoC support, you should say Y here and also to the
|
||||
@ -51,6 +53,7 @@ source "sound/soc/nuc900/Kconfig"
|
||||
source "sound/soc/omap/Kconfig"
|
||||
source "sound/soc/kirkwood/Kconfig"
|
||||
source "sound/soc/mid-x86/Kconfig"
|
||||
source "sound/soc/mxs/Kconfig"
|
||||
source "sound/soc/pxa/Kconfig"
|
||||
source "sound/soc/samsung/Kconfig"
|
||||
source "sound/soc/s6000/Kconfig"
|
||||
|
@ -12,6 +12,7 @@ obj-$(CONFIG_SND_SOC) += fsl/
|
||||
obj-$(CONFIG_SND_SOC) += imx/
|
||||
obj-$(CONFIG_SND_SOC) += jz4740/
|
||||
obj-$(CONFIG_SND_SOC) += mid-x86/
|
||||
obj-$(CONFIG_SND_SOC) += mxs/
|
||||
obj-$(CONFIG_SND_SOC) += nuc900/
|
||||
obj-$(CONFIG_SND_SOC) += omap/
|
||||
obj-$(CONFIG_SND_SOC) += kirkwood/
|
||||
|
@ -383,14 +383,17 @@ static int __init playpaq_asoc_init(void)
|
||||
_gclk0 = clk_get(NULL, "gclk0");
|
||||
if (IS_ERR(_gclk0)) {
|
||||
_gclk0 = NULL;
|
||||
ret = PTR_ERR(_gclk0);
|
||||
goto err_gclk0;
|
||||
}
|
||||
_pll0 = clk_get(NULL, "pll0");
|
||||
if (IS_ERR(_pll0)) {
|
||||
_pll0 = NULL;
|
||||
ret = PTR_ERR(_pll0);
|
||||
goto err_pll0;
|
||||
}
|
||||
if (clk_set_parent(_gclk0, _pll0)) {
|
||||
ret = clk_set_parent(_gclk0, _pll0);
|
||||
if (ret) {
|
||||
pr_warning("snd-soc-playpaq: "
|
||||
"Failed to set PLL0 as parent for DAC clock\n");
|
||||
goto err_set_clk;
|
||||
|
@ -18,10 +18,38 @@ config SND_SOC_AU1XPSC_AC97
|
||||
select SND_AC97_CODEC
|
||||
select SND_SOC_AC97_BUS
|
||||
|
||||
##
|
||||
## Au1000/1500/1100 DMA + AC97C/I2SC
|
||||
##
|
||||
config SND_SOC_AU1XAUDIO
|
||||
tristate "SoC Audio for Au1000/Au1500/Au1100"
|
||||
depends on MIPS_ALCHEMY
|
||||
help
|
||||
This is a driver set for the AC97 unit and the
|
||||
old DMA controller as found on the Au1000/Au1500/Au1100 chips.
|
||||
|
||||
config SND_SOC_AU1XAC97C
|
||||
tristate
|
||||
select AC97_BUS
|
||||
select SND_AC97_CODEC
|
||||
select SND_SOC_AC97_BUS
|
||||
|
||||
config SND_SOC_AU1XI2SC
|
||||
tristate
|
||||
|
||||
|
||||
##
|
||||
## Boards
|
||||
##
|
||||
config SND_SOC_DB1000
|
||||
tristate "DB1000 Audio support"
|
||||
depends on SND_SOC_AU1XAUDIO
|
||||
select SND_SOC_AU1XAC97C
|
||||
select SND_SOC_AC97_CODEC
|
||||
help
|
||||
Select this option to enable AC97 audio on the early DB1x00 series
|
||||
of boards (DB1000/DB1500/DB1100).
|
||||
|
||||
config SND_SOC_DB1200
|
||||
tristate "DB1200 AC97+I2S audio support"
|
||||
depends on SND_SOC_AU1XPSC
|
||||
|
@ -3,11 +3,21 @@ snd-soc-au1xpsc-dbdma-objs := dbdma2.o
|
||||
snd-soc-au1xpsc-i2s-objs := psc-i2s.o
|
||||
snd-soc-au1xpsc-ac97-objs := psc-ac97.o
|
||||
|
||||
# Au1000/1500/1100 Audio units
|
||||
snd-soc-au1x-dma-objs := dma.o
|
||||
snd-soc-au1x-ac97c-objs := ac97c.o
|
||||
snd-soc-au1x-i2sc-objs := i2sc.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_AU1XPSC) += snd-soc-au1xpsc-dbdma.o
|
||||
obj-$(CONFIG_SND_SOC_AU1XPSC_I2S) += snd-soc-au1xpsc-i2s.o
|
||||
obj-$(CONFIG_SND_SOC_AU1XPSC_AC97) += snd-soc-au1xpsc-ac97.o
|
||||
obj-$(CONFIG_SND_SOC_AU1XAUDIO) += snd-soc-au1x-dma.o
|
||||
obj-$(CONFIG_SND_SOC_AU1XAC97C) += snd-soc-au1x-ac97c.o
|
||||
obj-$(CONFIG_SND_SOC_AU1XI2SC) += snd-soc-au1x-i2sc.o
|
||||
|
||||
# Boards
|
||||
snd-soc-db1000-objs := db1000.o
|
||||
snd-soc-db1200-objs := db1200.o
|
||||
|
||||
obj-$(CONFIG_SND_SOC_DB1000) += snd-soc-db1000.o
|
||||
obj-$(CONFIG_SND_SOC_DB1200) += snd-soc-db1200.o
|
||||
|
363
sound/soc/au1x/ac97c.c
Normal file
363
sound/soc/au1x/ac97c.c
Normal file
@ -0,0 +1,363 @@
|
||||
/*
|
||||
* Au1000/Au1500/Au1100 AC97C controller driver for ASoC
|
||||
*
|
||||
* (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*
|
||||
* based on the old ALSA driver originally written by
|
||||
* Charles Eidsness <charles@cooper-street.com>
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
/* register offsets and bits */
|
||||
#define AC97_CONFIG 0x00
|
||||
#define AC97_STATUS 0x04
|
||||
#define AC97_DATA 0x08
|
||||
#define AC97_CMDRESP 0x0c
|
||||
#define AC97_ENABLE 0x10
|
||||
|
||||
#define CFG_RC(x) (((x) & 0x3ff) << 13) /* valid rx slots mask */
|
||||
#define CFG_XS(x) (((x) & 0x3ff) << 3) /* valid tx slots mask */
|
||||
#define CFG_SG (1 << 2) /* sync gate */
|
||||
#define CFG_SN (1 << 1) /* sync control */
|
||||
#define CFG_RS (1 << 0) /* acrst# control */
|
||||
#define STAT_XU (1 << 11) /* tx underflow */
|
||||
#define STAT_XO (1 << 10) /* tx overflow */
|
||||
#define STAT_RU (1 << 9) /* rx underflow */
|
||||
#define STAT_RO (1 << 8) /* rx overflow */
|
||||
#define STAT_RD (1 << 7) /* codec ready */
|
||||
#define STAT_CP (1 << 6) /* command pending */
|
||||
#define STAT_TE (1 << 4) /* tx fifo empty */
|
||||
#define STAT_TF (1 << 3) /* tx fifo full */
|
||||
#define STAT_RE (1 << 1) /* rx fifo empty */
|
||||
#define STAT_RF (1 << 0) /* rx fifo full */
|
||||
#define CMD_SET_DATA(x) (((x) & 0xffff) << 16)
|
||||
#define CMD_GET_DATA(x) ((x) & 0xffff)
|
||||
#define CMD_READ (1 << 7)
|
||||
#define CMD_WRITE (0 << 7)
|
||||
#define CMD_IDX(x) ((x) & 0x7f)
|
||||
#define EN_D (1 << 1) /* DISable bit */
|
||||
#define EN_CE (1 << 0) /* clock enable bit */
|
||||
|
||||
/* how often to retry failed codec register reads/writes */
|
||||
#define AC97_RW_RETRIES 5
|
||||
|
||||
#define AC97_RATES \
|
||||
SNDRV_PCM_RATE_CONTINUOUS
|
||||
|
||||
#define AC97_FMTS \
|
||||
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE)
|
||||
|
||||
/* instance data. There can be only one, MacLeod!!!!, fortunately there IS only
|
||||
* once AC97C on early Alchemy chips. The newer ones aren't so lucky.
|
||||
*/
|
||||
static struct au1xpsc_audio_data *ac97c_workdata;
|
||||
#define ac97_to_ctx(x) ac97c_workdata
|
||||
|
||||
static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
|
||||
{
|
||||
return __raw_readl(ctx->mmio + reg);
|
||||
}
|
||||
|
||||
static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
|
||||
{
|
||||
__raw_writel(v, ctx->mmio + reg);
|
||||
wmb();
|
||||
}
|
||||
|
||||
static unsigned short au1xac97c_ac97_read(struct snd_ac97 *ac97,
|
||||
unsigned short r)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
|
||||
unsigned int tmo, retry;
|
||||
unsigned long data;
|
||||
|
||||
data = ~0;
|
||||
retry = AC97_RW_RETRIES;
|
||||
do {
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
tmo = 5;
|
||||
while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
|
||||
udelay(21); /* wait an ac97 frame time */
|
||||
if (!tmo) {
|
||||
pr_debug("ac97rd timeout #1\n");
|
||||
goto next;
|
||||
}
|
||||
|
||||
WR(ctx, AC97_CMDRESP, CMD_IDX(r) | CMD_READ);
|
||||
|
||||
/* stupid errata: data is only valid for 21us, so
|
||||
* poll, Forrest, poll...
|
||||
*/
|
||||
tmo = 0x10000;
|
||||
while ((RD(ctx, AC97_STATUS) & STAT_CP) && tmo--)
|
||||
asm volatile ("nop");
|
||||
data = RD(ctx, AC97_CMDRESP);
|
||||
|
||||
if (!tmo)
|
||||
pr_debug("ac97rd timeout #2\n");
|
||||
|
||||
next:
|
||||
mutex_unlock(&ctx->lock);
|
||||
} while (--retry && !tmo);
|
||||
|
||||
pr_debug("AC97RD %04x %04lx %d\n", r, data, retry);
|
||||
|
||||
return retry ? data & 0xffff : 0xffff;
|
||||
}
|
||||
|
||||
static void au1xac97c_ac97_write(struct snd_ac97 *ac97, unsigned short r,
|
||||
unsigned short v)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
|
||||
unsigned int tmo, retry;
|
||||
|
||||
retry = AC97_RW_RETRIES;
|
||||
do {
|
||||
mutex_lock(&ctx->lock);
|
||||
|
||||
for (tmo = 5; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
|
||||
udelay(21);
|
||||
if (!tmo) {
|
||||
pr_debug("ac97wr timeout #1\n");
|
||||
goto next;
|
||||
}
|
||||
|
||||
WR(ctx, AC97_CMDRESP, CMD_WRITE | CMD_IDX(r) | CMD_SET_DATA(v));
|
||||
|
||||
for (tmo = 10; (RD(ctx, AC97_STATUS) & STAT_CP) && tmo; tmo--)
|
||||
udelay(21);
|
||||
if (!tmo)
|
||||
pr_debug("ac97wr timeout #2\n");
|
||||
next:
|
||||
mutex_unlock(&ctx->lock);
|
||||
} while (--retry && !tmo);
|
||||
|
||||
pr_debug("AC97WR %04x %04x %d\n", r, v, retry);
|
||||
}
|
||||
|
||||
static void au1xac97c_ac97_warm_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
|
||||
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG | CFG_SN);
|
||||
msleep(20);
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg | CFG_SG);
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg);
|
||||
}
|
||||
|
||||
static void au1xac97c_ac97_cold_reset(struct snd_ac97 *ac97)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = ac97_to_ctx(ac97);
|
||||
int i;
|
||||
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg | CFG_RS);
|
||||
msleep(500);
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg);
|
||||
|
||||
/* wait for codec ready */
|
||||
i = 50;
|
||||
while (((RD(ctx, AC97_STATUS) & STAT_RD) == 0) && --i)
|
||||
msleep(20);
|
||||
if (!i)
|
||||
printk(KERN_ERR "ac97c: codec not ready after cold reset\n");
|
||||
}
|
||||
|
||||
/* AC97 controller operations */
|
||||
struct snd_ac97_bus_ops soc_ac97_ops = {
|
||||
.read = au1xac97c_ac97_read,
|
||||
.write = au1xac97c_ac97_write,
|
||||
.reset = au1xac97c_ac97_cold_reset,
|
||||
.warm_reset = au1xac97c_ac97_warm_reset,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(soc_ac97_ops); /* globals be gone! */
|
||||
|
||||
static int alchemy_ac97c_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
|
||||
snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops alchemy_ac97c_ops = {
|
||||
.startup = alchemy_ac97c_startup,
|
||||
};
|
||||
|
||||
static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
return ac97c_workdata ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_driver au1xac97c_dai_driver = {
|
||||
.name = "alchemy-ac97c",
|
||||
.ac97_control = 1,
|
||||
.probe = au1xac97c_dai_probe,
|
||||
.playback = {
|
||||
.rates = AC97_RATES,
|
||||
.formats = AC97_FMTS,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.rates = AC97_RATES,
|
||||
.formats = AC97_FMTS,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &alchemy_ac97c_ops,
|
||||
};
|
||||
|
||||
static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *r;
|
||||
struct au1xpsc_audio_data *ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&ctx->lock);
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out0;
|
||||
}
|
||||
|
||||
ret = -EBUSY;
|
||||
if (!request_mem_region(r->start, resource_size(r), pdev->name))
|
||||
goto out0;
|
||||
|
||||
ctx->mmio = ioremap_nocache(r->start, resource_size(r));
|
||||
if (!ctx->mmio)
|
||||
goto out1;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r)
|
||||
goto out1;
|
||||
ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r)
|
||||
goto out1;
|
||||
ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
|
||||
|
||||
/* switch it on */
|
||||
WR(ctx, AC97_ENABLE, EN_D | EN_CE);
|
||||
WR(ctx, AC97_ENABLE, EN_CE);
|
||||
|
||||
ctx->cfg = CFG_RC(3) | CFG_XS(3);
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg);
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
ac97c_workdata = ctx;
|
||||
return 0;
|
||||
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
kfree(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit au1xac97c_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
|
||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
|
||||
|
||||
iounmap(ctx->mmio);
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
kfree(ctx);
|
||||
|
||||
ac97c_workdata = NULL; /* MDEV */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int au1xac97c_drvsuspend(struct device *dev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
|
||||
|
||||
WR(ctx, AC97_ENABLE, EN_D); /* clock off, disable */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xac97c_drvresume(struct device *dev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
|
||||
|
||||
WR(ctx, AC97_ENABLE, EN_D | EN_CE);
|
||||
WR(ctx, AC97_ENABLE, EN_CE);
|
||||
WR(ctx, AC97_CONFIG, ctx->cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops au1xpscac97_pmops = {
|
||||
.suspend = au1xac97c_drvsuspend,
|
||||
.resume = au1xac97c_drvresume,
|
||||
};
|
||||
|
||||
#define AU1XPSCAC97_PMOPS (&au1xpscac97_pmops)
|
||||
|
||||
#else
|
||||
|
||||
#define AU1XPSCAC97_PMOPS NULL
|
||||
|
||||
#endif
|
||||
|
||||
static struct platform_driver au1xac97c_driver = {
|
||||
.driver = {
|
||||
.name = "alchemy-ac97c",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = AU1XPSCAC97_PMOPS,
|
||||
},
|
||||
.probe = au1xac97c_drvprobe,
|
||||
.remove = __devexit_p(au1xac97c_drvremove),
|
||||
};
|
||||
|
||||
static int __init au1xac97c_load(void)
|
||||
{
|
||||
ac97c_workdata = NULL;
|
||||
return platform_driver_register(&au1xac97c_driver);
|
||||
}
|
||||
|
||||
static void __exit au1xac97c_unload(void)
|
||||
{
|
||||
platform_driver_unregister(&au1xac97c_driver);
|
||||
}
|
||||
|
||||
module_init(au1xac97c_load);
|
||||
module_exit(au1xac97c_unload);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Au1000/1500/1100 AC97C ASoC driver");
|
||||
MODULE_AUTHOR("Manuel Lauss");
|
75
sound/soc/au1x/db1000.c
Normal file
75
sound/soc/au1x/db1000.c
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* DB1000/DB1500/DB1100 ASoC audio fabric support code.
|
||||
*
|
||||
* (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-db1x00/bcsr.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
static struct snd_soc_dai_link db1000_ac97_dai = {
|
||||
.name = "AC97",
|
||||
.stream_name = "AC97 HiFi",
|
||||
.codec_dai_name = "ac97-hifi",
|
||||
.cpu_dai_name = "alchemy-ac97c",
|
||||
.platform_name = "alchemy-pcm-dma.0",
|
||||
.codec_name = "ac97-codec",
|
||||
};
|
||||
|
||||
static struct snd_soc_card db1000_ac97 = {
|
||||
.name = "DB1000_AC97",
|
||||
.dai_link = &db1000_ac97_dai,
|
||||
.num_links = 1,
|
||||
};
|
||||
|
||||
static int __devinit db1000_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &db1000_ac97;
|
||||
card->dev = &pdev->dev;
|
||||
return snd_soc_register_card(card);
|
||||
}
|
||||
|
||||
static int __devexit db1000_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
snd_soc_unregister_card(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver db1000_audio_driver = {
|
||||
.driver = {
|
||||
.name = "db1000-audio",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = db1000_audio_probe,
|
||||
.remove = __devexit_p(db1000_audio_remove),
|
||||
};
|
||||
|
||||
static int __init db1000_audio_load(void)
|
||||
{
|
||||
return platform_driver_register(&db1000_audio_driver);
|
||||
}
|
||||
|
||||
static void __exit db1000_audio_unload(void)
|
||||
{
|
||||
platform_driver_unregister(&db1000_audio_driver);
|
||||
}
|
||||
|
||||
module_init(db1000_audio_load);
|
||||
module_exit(db1000_audio_unload);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("DB1000/DB1500/DB1100 ASoC audio");
|
||||
MODULE_AUTHOR("Manuel Lauss");
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* DB1200 ASoC audio fabric support code.
|
||||
*
|
||||
* (c) 2008-9 Manuel Lauss <manuel.lauss@gmail.com>
|
||||
* (c) 2008-2011 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*
|
||||
*/
|
||||
|
||||
@ -21,6 +21,17 @@
|
||||
#include "../codecs/wm8731.h"
|
||||
#include "psc.h"
|
||||
|
||||
static struct platform_device_id db1200_pids[] = {
|
||||
{
|
||||
.name = "db1200-ac97",
|
||||
.driver_data = 0,
|
||||
}, {
|
||||
.name = "db1200-i2s",
|
||||
.driver_data = 1,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
/*------------------------- AC97 PART ---------------------------*/
|
||||
|
||||
static struct snd_soc_dai_link db1200_ac97_dai = {
|
||||
@ -89,36 +100,47 @@ static struct snd_soc_card db1200_i2s_machine = {
|
||||
|
||||
/*------------------------- COMMON PART ---------------------------*/
|
||||
|
||||
static struct platform_device *db1200_asoc_dev;
|
||||
static struct snd_soc_card *db1200_cards[] __devinitdata = {
|
||||
&db1200_ac97_machine,
|
||||
&db1200_i2s_machine,
|
||||
};
|
||||
|
||||
static int __devinit db1200_audio_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct platform_device_id *pid = platform_get_device_id(pdev);
|
||||
struct snd_soc_card *card;
|
||||
|
||||
card = db1200_cards[pid->driver_data];
|
||||
card->dev = &pdev->dev;
|
||||
return snd_soc_register_card(card);
|
||||
}
|
||||
|
||||
static int __devexit db1200_audio_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
snd_soc_unregister_card(card);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver db1200_audio_driver = {
|
||||
.driver = {
|
||||
.name = "db1200-ac97",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.id_table = db1200_pids,
|
||||
.probe = db1200_audio_probe,
|
||||
.remove = __devexit_p(db1200_audio_remove),
|
||||
};
|
||||
|
||||
static int __init db1200_audio_load(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = -ENOMEM;
|
||||
db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
|
||||
if (!db1200_asoc_dev)
|
||||
goto out;
|
||||
|
||||
/* DB1200 board setup set PSC1MUX to preferred audio device */
|
||||
if (bcsr_read(BCSR_RESETS) & BCSR_RESETS_PSC1MUX)
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_i2s_machine);
|
||||
else
|
||||
platform_set_drvdata(db1200_asoc_dev, &db1200_ac97_machine);
|
||||
|
||||
ret = platform_device_add(db1200_asoc_dev);
|
||||
|
||||
if (ret) {
|
||||
platform_device_put(db1200_asoc_dev);
|
||||
db1200_asoc_dev = NULL;
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
return platform_driver_register(&db1200_audio_driver);
|
||||
}
|
||||
|
||||
static void __exit db1200_audio_unload(void)
|
||||
{
|
||||
platform_device_unregister(db1200_asoc_dev);
|
||||
platform_driver_unregister(&db1200_audio_driver);
|
||||
}
|
||||
|
||||
module_init(db1200_audio_load);
|
||||
|
@ -169,7 +169,7 @@ static int au1x_pcm_dbdma_realloc(struct au1xpsc_audio_dmadata *pcd,
|
||||
|
||||
au1x_pcm_dbdma_free(pcd);
|
||||
|
||||
if (stype == PCM_RX)
|
||||
if (stype == SNDRV_PCM_STREAM_CAPTURE)
|
||||
pcd->ddma_chan = au1xxx_dbdma_chan_alloc(pcd->ddma_id,
|
||||
DSCR_CMD0_ALWAYS,
|
||||
au1x_pcm_dmarx_cb, (void *)pcd);
|
||||
@ -198,7 +198,7 @@ static inline struct au1xpsc_audio_dmadata *to_dmadata(struct snd_pcm_substream
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
struct au1xpsc_audio_dmadata *pcd =
|
||||
snd_soc_platform_get_drvdata(rtd->platform);
|
||||
return &pcd[SUBSTREAM_TYPE(ss)];
|
||||
return &pcd[ss->stream];
|
||||
}
|
||||
|
||||
static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
@ -212,7 +212,7 @@ static int au1xpsc_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
stype = SUBSTREAM_TYPE(substream);
|
||||
stype = substream->stream;
|
||||
pcd = to_dmadata(substream);
|
||||
|
||||
DBG("runtime->dma_area = 0x%08lx dma_addr_t = 0x%08lx dma_size = %d "
|
||||
@ -255,7 +255,7 @@ static int au1xpsc_pcm_prepare(struct snd_pcm_substream *substream)
|
||||
|
||||
au1xxx_dbdma_reset(pcd->ddma_chan);
|
||||
|
||||
if (SUBSTREAM_TYPE(substream) == PCM_RX) {
|
||||
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
||||
au1x_pcm_queue_rx(pcd);
|
||||
au1x_pcm_queue_rx(pcd);
|
||||
} else {
|
||||
@ -293,6 +293,16 @@ au1xpsc_pcm_pointer(struct snd_pcm_substream *substream)
|
||||
|
||||
static int au1xpsc_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *pcd = to_dmadata(substream);
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
int stype = substream->stream, *dmaids;
|
||||
|
||||
dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
if (!dmaids)
|
||||
return -ENODEV; /* whoa, has ordering changed? */
|
||||
|
||||
pcd->ddma_id = dmaids[stype];
|
||||
|
||||
snd_soc_set_runtime_hwparams(substream, &au1xpsc_pcm_hardware);
|
||||
return 0;
|
||||
}
|
||||
@ -340,36 +350,18 @@ struct snd_soc_platform_driver au1xpsc_soc_platform = {
|
||||
static int __devinit au1xpsc_pcm_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_dmadata *dmadata;
|
||||
struct resource *r;
|
||||
int ret;
|
||||
|
||||
dmadata = kzalloc(2 * sizeof(struct au1xpsc_audio_dmadata), GFP_KERNEL);
|
||||
if (!dmadata)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out1;
|
||||
}
|
||||
dmadata[PCM_TX].ddma_id = r->start;
|
||||
|
||||
/* RX DMA */
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out1;
|
||||
}
|
||||
dmadata[PCM_RX].ddma_id = r->start;
|
||||
|
||||
platform_set_drvdata(pdev, dmadata);
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform);
|
||||
if (!ret)
|
||||
return ret;
|
||||
if (ret)
|
||||
kfree(dmadata);
|
||||
|
||||
out1:
|
||||
kfree(dmadata);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -405,57 +397,6 @@ static void __exit au1xpsc_audio_dbdma_unload(void)
|
||||
module_init(au1xpsc_audio_dbdma_load);
|
||||
module_exit(au1xpsc_audio_dbdma_unload);
|
||||
|
||||
|
||||
struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res, *r;
|
||||
struct platform_device *pd;
|
||||
int id[2];
|
||||
int ret;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r)
|
||||
return NULL;
|
||||
id[0] = r->start;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r)
|
||||
return NULL;
|
||||
id[1] = r->start;
|
||||
|
||||
res = kzalloc(sizeof(struct resource) * 2, GFP_KERNEL);
|
||||
if (!res)
|
||||
return NULL;
|
||||
|
||||
res[0].start = res[0].end = id[0];
|
||||
res[1].start = res[1].end = id[1];
|
||||
res[0].flags = res[1].flags = IORESOURCE_DMA;
|
||||
|
||||
pd = platform_device_alloc("au1xpsc-pcm", pdev->id);
|
||||
if (!pd)
|
||||
goto out;
|
||||
|
||||
pd->resource = res;
|
||||
pd->num_resources = 2;
|
||||
|
||||
ret = platform_device_add(pd);
|
||||
if (!ret)
|
||||
return pd;
|
||||
|
||||
platform_device_put(pd);
|
||||
out:
|
||||
kfree(res);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(au1xpsc_pcm_add);
|
||||
|
||||
void au1xpsc_pcm_destroy(struct platform_device *dmapd)
|
||||
{
|
||||
if (dmapd)
|
||||
platform_device_unregister(dmapd);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(au1xpsc_pcm_destroy);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Au12x0/Au1550 PSC Audio DMA driver");
|
||||
MODULE_AUTHOR("Manuel Lauss");
|
||||
|
377
sound/soc/au1x/dma.c
Normal file
377
sound/soc/au1x/dma.c
Normal file
@ -0,0 +1,377 @@
|
||||
/*
|
||||
* Au1000/Au1500/Au1100 Audio DMA support.
|
||||
*
|
||||
* (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*
|
||||
* copied almost verbatim from the old ALSA driver, written by
|
||||
* Charles Eidsness <charles@cooper-street.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
#include <asm/mach-au1x00/au1000_dma.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
#define ALCHEMY_PCM_FMTS \
|
||||
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
|
||||
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
|
||||
SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | \
|
||||
SNDRV_PCM_FMTBIT_U32_LE | SNDRV_PCM_FMTBIT_U32_BE | \
|
||||
0)
|
||||
|
||||
struct pcm_period {
|
||||
u32 start;
|
||||
u32 relative_end; /* relative to start of buffer */
|
||||
struct pcm_period *next;
|
||||
};
|
||||
|
||||
struct audio_stream {
|
||||
struct snd_pcm_substream *substream;
|
||||
int dma;
|
||||
struct pcm_period *buffer;
|
||||
unsigned int period_size;
|
||||
unsigned int periods;
|
||||
};
|
||||
|
||||
struct alchemy_pcm_ctx {
|
||||
struct audio_stream stream[2]; /* playback & capture */
|
||||
};
|
||||
|
||||
static void au1000_release_dma_link(struct audio_stream *stream)
|
||||
{
|
||||
struct pcm_period *pointer;
|
||||
struct pcm_period *pointer_next;
|
||||
|
||||
stream->period_size = 0;
|
||||
stream->periods = 0;
|
||||
pointer = stream->buffer;
|
||||
if (!pointer)
|
||||
return;
|
||||
do {
|
||||
pointer_next = pointer->next;
|
||||
kfree(pointer);
|
||||
pointer = pointer_next;
|
||||
} while (pointer != stream->buffer);
|
||||
stream->buffer = NULL;
|
||||
}
|
||||
|
||||
static int au1000_setup_dma_link(struct audio_stream *stream,
|
||||
unsigned int period_bytes,
|
||||
unsigned int periods)
|
||||
{
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
struct pcm_period *pointer;
|
||||
unsigned long dma_start;
|
||||
int i;
|
||||
|
||||
dma_start = virt_to_phys(runtime->dma_area);
|
||||
|
||||
if (stream->period_size == period_bytes &&
|
||||
stream->periods == periods)
|
||||
return 0; /* not changed */
|
||||
|
||||
au1000_release_dma_link(stream);
|
||||
|
||||
stream->period_size = period_bytes;
|
||||
stream->periods = periods;
|
||||
|
||||
stream->buffer = kmalloc(sizeof(struct pcm_period), GFP_KERNEL);
|
||||
if (!stream->buffer)
|
||||
return -ENOMEM;
|
||||
pointer = stream->buffer;
|
||||
for (i = 0; i < periods; i++) {
|
||||
pointer->start = (u32)(dma_start + (i * period_bytes));
|
||||
pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
|
||||
if (i < periods - 1) {
|
||||
pointer->next = kmalloc(sizeof(struct pcm_period),
|
||||
GFP_KERNEL);
|
||||
if (!pointer->next) {
|
||||
au1000_release_dma_link(stream);
|
||||
return -ENOMEM;
|
||||
}
|
||||
pointer = pointer->next;
|
||||
}
|
||||
}
|
||||
pointer->next = stream->buffer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void au1000_dma_stop(struct audio_stream *stream)
|
||||
{
|
||||
if (stream->buffer)
|
||||
disable_dma(stream->dma);
|
||||
}
|
||||
|
||||
static void au1000_dma_start(struct audio_stream *stream)
|
||||
{
|
||||
if (!stream->buffer)
|
||||
return;
|
||||
|
||||
init_dma(stream->dma);
|
||||
if (get_dma_active_buffer(stream->dma) == 0) {
|
||||
clear_dma_done0(stream->dma);
|
||||
set_dma_addr0(stream->dma, stream->buffer->start);
|
||||
set_dma_count0(stream->dma, stream->period_size >> 1);
|
||||
set_dma_addr1(stream->dma, stream->buffer->next->start);
|
||||
set_dma_count1(stream->dma, stream->period_size >> 1);
|
||||
} else {
|
||||
clear_dma_done1(stream->dma);
|
||||
set_dma_addr1(stream->dma, stream->buffer->start);
|
||||
set_dma_count1(stream->dma, stream->period_size >> 1);
|
||||
set_dma_addr0(stream->dma, stream->buffer->next->start);
|
||||
set_dma_count0(stream->dma, stream->period_size >> 1);
|
||||
}
|
||||
enable_dma_buffers(stream->dma);
|
||||
start_dma(stream->dma);
|
||||
}
|
||||
|
||||
static irqreturn_t au1000_dma_interrupt(int irq, void *ptr)
|
||||
{
|
||||
struct audio_stream *stream = (struct audio_stream *)ptr;
|
||||
struct snd_pcm_substream *substream = stream->substream;
|
||||
|
||||
switch (get_dma_buffer_done(stream->dma)) {
|
||||
case DMA_D0:
|
||||
stream->buffer = stream->buffer->next;
|
||||
clear_dma_done0(stream->dma);
|
||||
set_dma_addr0(stream->dma, stream->buffer->next->start);
|
||||
set_dma_count0(stream->dma, stream->period_size >> 1);
|
||||
enable_dma_buffer0(stream->dma);
|
||||
break;
|
||||
case DMA_D1:
|
||||
stream->buffer = stream->buffer->next;
|
||||
clear_dma_done1(stream->dma);
|
||||
set_dma_addr1(stream->dma, stream->buffer->next->start);
|
||||
set_dma_count1(stream->dma, stream->period_size >> 1);
|
||||
enable_dma_buffer1(stream->dma);
|
||||
break;
|
||||
case (DMA_D0 | DMA_D1):
|
||||
pr_debug("DMA %d missed interrupt.\n", stream->dma);
|
||||
au1000_dma_stop(stream);
|
||||
au1000_dma_start(stream);
|
||||
break;
|
||||
case (~DMA_D0 & ~DMA_D1):
|
||||
pr_debug("DMA %d empty irq.\n", stream->dma);
|
||||
}
|
||||
snd_pcm_period_elapsed(substream);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static const struct snd_pcm_hardware alchemy_pcm_hardware = {
|
||||
.info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BATCH,
|
||||
.formats = ALCHEMY_PCM_FMTS,
|
||||
.rates = SNDRV_PCM_RATE_8000_192000,
|
||||
.rate_min = SNDRV_PCM_RATE_8000,
|
||||
.rate_max = SNDRV_PCM_RATE_192000,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.period_bytes_min = 1024,
|
||||
.period_bytes_max = 16 * 1024 - 1,
|
||||
.periods_min = 4,
|
||||
.periods_max = 255,
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
.fifo_size = 16,
|
||||
};
|
||||
|
||||
static inline struct alchemy_pcm_ctx *ss_to_ctx(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct snd_soc_pcm_runtime *rtd = ss->private_data;
|
||||
return snd_soc_platform_get_drvdata(rtd->platform);
|
||||
}
|
||||
|
||||
static inline struct audio_stream *ss_to_as(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(ss);
|
||||
return &(ctx->stream[ss->stream]);
|
||||
}
|
||||
|
||||
static int alchemy_pcm_open(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
int *dmaids, s = substream->stream;
|
||||
char *name;
|
||||
|
||||
dmaids = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
|
||||
if (!dmaids)
|
||||
return -ENODEV; /* whoa, has ordering changed? */
|
||||
|
||||
/* DMA setup */
|
||||
name = (s == SNDRV_PCM_STREAM_PLAYBACK) ? "audio-tx" : "audio-rx";
|
||||
ctx->stream[s].dma = request_au1000_dma(dmaids[s], name,
|
||||
au1000_dma_interrupt, 0,
|
||||
&ctx->stream[s]);
|
||||
set_dma_mode(ctx->stream[s].dma,
|
||||
get_dma_mode(ctx->stream[s].dma) & ~DMA_NC);
|
||||
|
||||
ctx->stream[s].substream = substream;
|
||||
ctx->stream[s].buffer = NULL;
|
||||
snd_soc_set_runtime_hwparams(substream, &alchemy_pcm_hardware);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alchemy_pcm_close(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = ss_to_ctx(substream);
|
||||
int stype = substream->stream;
|
||||
|
||||
ctx->stream[stype].substream = NULL;
|
||||
free_au1000_dma(ctx->stream[stype].dma);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alchemy_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(substream);
|
||||
int err;
|
||||
|
||||
err = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = au1000_setup_dma_link(stream,
|
||||
params_period_bytes(hw_params),
|
||||
params_periods(hw_params));
|
||||
if (err)
|
||||
snd_pcm_lib_free_pages(substream);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int alchemy_pcm_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(substream);
|
||||
au1000_release_dma_link(stream);
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
static int alchemy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(substream);
|
||||
int err = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
au1000_dma_start(stream);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
au1000_dma_stop(stream);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t alchemy_pcm_pointer(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct audio_stream *stream = ss_to_as(ss);
|
||||
long location;
|
||||
|
||||
location = get_dma_residue(stream->dma);
|
||||
location = stream->buffer->relative_end - location;
|
||||
if (location == -1)
|
||||
location = 0;
|
||||
return bytes_to_frames(ss->runtime, location);
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops alchemy_pcm_ops = {
|
||||
.open = alchemy_pcm_open,
|
||||
.close = alchemy_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = alchemy_pcm_hw_params,
|
||||
.hw_free = alchemy_pcm_hw_free,
|
||||
.trigger = alchemy_pcm_trigger,
|
||||
.pointer = alchemy_pcm_pointer,
|
||||
};
|
||||
|
||||
static void alchemy_pcm_free_dma_buffers(struct snd_pcm *pcm)
|
||||
{
|
||||
snd_pcm_lib_preallocate_free_for_all(pcm);
|
||||
}
|
||||
|
||||
static int alchemy_pcm_new(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_pcm *pcm = rtd->pcm;
|
||||
|
||||
snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
|
||||
snd_dma_continuous_data(GFP_KERNEL), 65536, (4096 * 1024) - 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct snd_soc_platform_driver alchemy_pcm_soc_platform = {
|
||||
.ops = &alchemy_pcm_ops,
|
||||
.pcm_new = alchemy_pcm_new,
|
||||
.pcm_free = alchemy_pcm_free_dma_buffers,
|
||||
};
|
||||
|
||||
static int __devinit alchemy_pcm_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform);
|
||||
if (ret)
|
||||
kfree(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit alchemy_pcm_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct alchemy_pcm_ctx *ctx = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_platform(&pdev->dev);
|
||||
kfree(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver alchemy_pcmdma_driver = {
|
||||
.driver = {
|
||||
.name = "alchemy-pcm-dma",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = alchemy_pcm_drvprobe,
|
||||
.remove = __devexit_p(alchemy_pcm_drvremove),
|
||||
};
|
||||
|
||||
static int __init alchemy_pcmdma_load(void)
|
||||
{
|
||||
return platform_driver_register(&alchemy_pcmdma_driver);
|
||||
}
|
||||
|
||||
static void __exit alchemy_pcmdma_unload(void)
|
||||
{
|
||||
platform_driver_unregister(&alchemy_pcmdma_driver);
|
||||
}
|
||||
|
||||
module_init(alchemy_pcmdma_load);
|
||||
module_exit(alchemy_pcmdma_unload);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Au1000/Au1500/Au1100 Audio DMA driver");
|
||||
MODULE_AUTHOR("Manuel Lauss");
|
346
sound/soc/au1x/i2sc.c
Normal file
346
sound/soc/au1x/i2sc.c
Normal file
@ -0,0 +1,346 @@
|
||||
/*
|
||||
* Au1000/Au1500/Au1100 I2S controller driver for ASoC
|
||||
*
|
||||
* (c) 2011 Manuel Lauss <manuel.lauss@googlemail.com>
|
||||
*
|
||||
* Note: clock supplied to the I2S controller must be 256x samplerate.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/soc.h>
|
||||
#include <asm/mach-au1x00/au1000.h>
|
||||
|
||||
#include "psc.h"
|
||||
|
||||
#define I2S_RXTX 0x00
|
||||
#define I2S_CFG 0x04
|
||||
#define I2S_ENABLE 0x08
|
||||
|
||||
#define CFG_XU (1 << 25) /* tx underflow */
|
||||
#define CFG_XO (1 << 24)
|
||||
#define CFG_RU (1 << 23)
|
||||
#define CFG_RO (1 << 22)
|
||||
#define CFG_TR (1 << 21)
|
||||
#define CFG_TE (1 << 20)
|
||||
#define CFG_TF (1 << 19)
|
||||
#define CFG_RR (1 << 18)
|
||||
#define CFG_RF (1 << 17)
|
||||
#define CFG_ICK (1 << 12) /* clock invert */
|
||||
#define CFG_PD (1 << 11) /* set to make I2SDIO INPUT */
|
||||
#define CFG_LB (1 << 10) /* loopback */
|
||||
#define CFG_IC (1 << 9) /* word select invert */
|
||||
#define CFG_FM_I2S (0 << 7) /* I2S format */
|
||||
#define CFG_FM_LJ (1 << 7) /* left-justified */
|
||||
#define CFG_FM_RJ (2 << 7) /* right-justified */
|
||||
#define CFG_FM_MASK (3 << 7)
|
||||
#define CFG_TN (1 << 6) /* tx fifo en */
|
||||
#define CFG_RN (1 << 5) /* rx fifo en */
|
||||
#define CFG_SZ_8 (0x08)
|
||||
#define CFG_SZ_16 (0x10)
|
||||
#define CFG_SZ_18 (0x12)
|
||||
#define CFG_SZ_20 (0x14)
|
||||
#define CFG_SZ_24 (0x18)
|
||||
#define CFG_SZ_MASK (0x1f)
|
||||
#define EN_D (1 << 1) /* DISable */
|
||||
#define EN_CE (1 << 0) /* clock enable */
|
||||
|
||||
/* only limited by clock generator and board design */
|
||||
#define AU1XI2SC_RATES \
|
||||
SNDRV_PCM_RATE_CONTINUOUS
|
||||
|
||||
#define AU1XI2SC_FMTS \
|
||||
(SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | \
|
||||
SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \
|
||||
SNDRV_PCM_FMTBIT_U16_LE | SNDRV_PCM_FMTBIT_U16_BE | \
|
||||
SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_U18_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S18_3BE | SNDRV_PCM_FMTBIT_U18_3BE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \
|
||||
SNDRV_PCM_FMTBIT_S20_3BE | SNDRV_PCM_FMTBIT_U20_3BE | \
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \
|
||||
SNDRV_PCM_FMTBIT_U24_LE | SNDRV_PCM_FMTBIT_U24_BE | \
|
||||
0)
|
||||
|
||||
static inline unsigned long RD(struct au1xpsc_audio_data *ctx, int reg)
|
||||
{
|
||||
return __raw_readl(ctx->mmio + reg);
|
||||
}
|
||||
|
||||
static inline void WR(struct au1xpsc_audio_data *ctx, int reg, unsigned long v)
|
||||
{
|
||||
__raw_writel(v, ctx->mmio + reg);
|
||||
wmb();
|
||||
}
|
||||
|
||||
static int au1xi2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(cpu_dai);
|
||||
unsigned long c;
|
||||
int ret;
|
||||
|
||||
ret = -EINVAL;
|
||||
c = ctx->cfg;
|
||||
|
||||
c &= ~CFG_FM_MASK;
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
c |= CFG_FM_I2S;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_MSB:
|
||||
c |= CFG_FM_RJ;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LSB:
|
||||
c |= CFG_FM_LJ;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
c &= ~(CFG_IC | CFG_ICK); /* IB-IF */
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
c |= CFG_IC | CFG_ICK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
c |= CFG_IC;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
c |= CFG_ICK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* I2S controller only supports master */
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS: /* CODEC slave */
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
ctx->cfg = c;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au1xi2s_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
|
||||
int stype = SUBSTREAM_TYPE(substream);
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
/* power up */
|
||||
WR(ctx, I2S_ENABLE, EN_D | EN_CE);
|
||||
WR(ctx, I2S_ENABLE, EN_CE);
|
||||
ctx->cfg |= (stype == PCM_TX) ? CFG_TN : CFG_RN;
|
||||
WR(ctx, I2S_CFG, ctx->cfg);
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
ctx->cfg &= ~((stype == PCM_TX) ? CFG_TN : CFG_RN);
|
||||
WR(ctx, I2S_CFG, ctx->cfg);
|
||||
WR(ctx, I2S_ENABLE, EN_D); /* power off */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long msbits_to_reg(int msbits)
|
||||
{
|
||||
switch (msbits) {
|
||||
case 8:
|
||||
return CFG_SZ_8;
|
||||
case 16:
|
||||
return CFG_SZ_16;
|
||||
case 18:
|
||||
return CFG_SZ_18;
|
||||
case 20:
|
||||
return CFG_SZ_20;
|
||||
case 24:
|
||||
return CFG_SZ_24;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xi2s_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long v;
|
||||
|
||||
v = msbits_to_reg(params->msbits);
|
||||
if (!v)
|
||||
return -EINVAL;
|
||||
|
||||
ctx->cfg &= ~CFG_SZ_MASK;
|
||||
ctx->cfg |= v;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xi2s_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = snd_soc_dai_get_drvdata(dai);
|
||||
snd_soc_dai_set_dma_data(dai, substream, &ctx->dmaids[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct snd_soc_dai_ops au1xi2s_dai_ops = {
|
||||
.startup = au1xi2s_startup,
|
||||
.trigger = au1xi2s_trigger,
|
||||
.hw_params = au1xi2s_hw_params,
|
||||
.set_fmt = au1xi2s_set_fmt,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_driver au1xi2s_dai_driver = {
|
||||
.symmetric_rates = 1,
|
||||
.playback = {
|
||||
.rates = AU1XI2SC_RATES,
|
||||
.formats = AU1XI2SC_FMTS,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.capture = {
|
||||
.rates = AU1XI2SC_RATES,
|
||||
.formats = AU1XI2SC_FMTS,
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
},
|
||||
.ops = &au1xi2s_dai_ops,
|
||||
};
|
||||
|
||||
static int __devinit au1xi2s_drvprobe(struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct resource *r;
|
||||
struct au1xpsc_audio_data *ctx;
|
||||
|
||||
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!r) {
|
||||
ret = -ENODEV;
|
||||
goto out0;
|
||||
}
|
||||
|
||||
ret = -EBUSY;
|
||||
if (!request_mem_region(r->start, resource_size(r), pdev->name))
|
||||
goto out0;
|
||||
|
||||
ctx->mmio = ioremap_nocache(r->start, resource_size(r));
|
||||
if (!ctx->mmio)
|
||||
goto out1;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r)
|
||||
goto out1;
|
||||
ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r)
|
||||
goto out1;
|
||||
ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
|
||||
|
||||
platform_set_drvdata(pdev, ctx);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
return 0;
|
||||
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
kfree(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit au1xi2s_drvremove(struct platform_device *pdev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = platform_get_drvdata(pdev);
|
||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
|
||||
|
||||
iounmap(ctx->mmio);
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
kfree(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int au1xi2s_drvsuspend(struct device *dev)
|
||||
{
|
||||
struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev);
|
||||
|
||||
WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xi2s_drvresume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops au1xi2sc_pmops = {
|
||||
.suspend = au1xi2s_drvsuspend,
|
||||
.resume = au1xi2s_drvresume,
|
||||
};
|
||||
|
||||
#define AU1XI2SC_PMOPS (&au1xi2sc_pmops)
|
||||
|
||||
#else
|
||||
|
||||
#define AU1XI2SC_PMOPS NULL
|
||||
|
||||
#endif
|
||||
|
||||
static struct platform_driver au1xi2s_driver = {
|
||||
.driver = {
|
||||
.name = "alchemy-i2sc",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = AU1XI2SC_PMOPS,
|
||||
},
|
||||
.probe = au1xi2s_drvprobe,
|
||||
.remove = __devexit_p(au1xi2s_drvremove),
|
||||
};
|
||||
|
||||
static int __init au1xi2s_load(void)
|
||||
{
|
||||
return platform_driver_register(&au1xi2s_driver);
|
||||
}
|
||||
|
||||
static void __exit au1xi2s_unload(void)
|
||||
{
|
||||
platform_driver_unregister(&au1xi2s_driver);
|
||||
}
|
||||
|
||||
module_init(au1xi2s_load);
|
||||
module_exit(au1xi2s_unload);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("Au1000/1500/1100 I2S ASoC driver");
|
||||
MODULE_AUTHOR("Manuel Lauss");
|
@ -41,14 +41,14 @@
|
||||
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3BE)
|
||||
|
||||
#define AC97PCR_START(stype) \
|
||||
((stype) == PCM_TX ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TS : PSC_AC97PCR_RS)
|
||||
#define AC97PCR_STOP(stype) \
|
||||
((stype) == PCM_TX ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TP : PSC_AC97PCR_RP)
|
||||
#define AC97PCR_CLRFIFO(stype) \
|
||||
((stype) == PCM_TX ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97PCR_TC : PSC_AC97PCR_RC)
|
||||
|
||||
#define AC97STAT_BUSY(stype) \
|
||||
((stype) == PCM_TX ? PSC_AC97STAT_TB : PSC_AC97STAT_RB)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_AC97STAT_TB : PSC_AC97STAT_RB)
|
||||
|
||||
/* instance data. There can be only one, MacLeod!!!! */
|
||||
static struct au1xpsc_audio_data *au1xpsc_ac97_workdata;
|
||||
@ -215,7 +215,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
unsigned long r, ro, stat;
|
||||
int chans, t, stype = SUBSTREAM_TYPE(substream);
|
||||
int chans, t, stype = substream->stream;
|
||||
|
||||
chans = params_channels(params);
|
||||
|
||||
@ -235,7 +235,7 @@ static int au1xpsc_ac97_hw_params(struct snd_pcm_substream *substream,
|
||||
r |= PSC_AC97CFG_SET_LEN(params->msbits);
|
||||
|
||||
/* channels: enable slots for front L/R channel */
|
||||
if (stype == PCM_TX) {
|
||||
if (stype == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
r &= ~PSC_AC97CFG_TXSLOT_MASK;
|
||||
r |= PSC_AC97CFG_TXSLOT_ENA(3);
|
||||
r |= PSC_AC97CFG_TXSLOT_ENA(4);
|
||||
@ -294,7 +294,7 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
|
||||
int cmd, struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, stype = SUBSTREAM_TYPE(substream);
|
||||
int ret, stype = substream->stream;
|
||||
|
||||
ret = 0;
|
||||
|
||||
@ -324,12 +324,21 @@ static int au1xpsc_ac97_trigger(struct snd_pcm_substream *substream,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_ac97_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int au1xpsc_ac97_probe(struct snd_soc_dai *dai)
|
||||
{
|
||||
return au1xpsc_ac97_workdata ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
|
||||
.startup = au1xpsc_ac97_startup,
|
||||
.trigger = au1xpsc_ac97_trigger,
|
||||
.hw_params = au1xpsc_ac97_hw_params,
|
||||
};
|
||||
@ -379,6 +388,16 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
if (!wd->mmio)
|
||||
goto out1;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r)
|
||||
goto out2;
|
||||
wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r)
|
||||
goto out2;
|
||||
wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
|
||||
|
||||
/* configuration: max dma trigger threshold, enable ac97 */
|
||||
wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
|
||||
PSC_AC97CFG_DE_ENABLE;
|
||||
@ -401,15 +420,13 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
if (ret)
|
||||
goto out1;
|
||||
goto out2;
|
||||
|
||||
wd->dmapd = au1xpsc_pcm_add(pdev);
|
||||
if (wd->dmapd) {
|
||||
au1xpsc_ac97_workdata = wd;
|
||||
return 0;
|
||||
}
|
||||
au1xpsc_ac97_workdata = wd;
|
||||
return 0;
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
out2:
|
||||
iounmap(wd->mmio);
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
@ -422,9 +439,6 @@ static int __devexit au1xpsc_ac97_drvremove(struct platform_device *pdev)
|
||||
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
|
||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
if (wd->dmapd)
|
||||
au1xpsc_pcm_destroy(wd->dmapd);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
/* disable PSC completely */
|
||||
|
@ -42,13 +42,13 @@
|
||||
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE)
|
||||
|
||||
#define I2SSTAT_BUSY(stype) \
|
||||
((stype) == PCM_TX ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SSTAT_TB : PSC_I2SSTAT_RB)
|
||||
#define I2SPCR_START(stype) \
|
||||
((stype) == PCM_TX ? PSC_I2SPCR_TS : PSC_I2SPCR_RS)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TS : PSC_I2SPCR_RS)
|
||||
#define I2SPCR_STOP(stype) \
|
||||
((stype) == PCM_TX ? PSC_I2SPCR_TP : PSC_I2SPCR_RP)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TP : PSC_I2SPCR_RP)
|
||||
#define I2SPCR_CLRFIFO(stype) \
|
||||
((stype) == PCM_TX ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
|
||||
((stype) == SNDRV_PCM_STREAM_PLAYBACK ? PSC_I2SPCR_TC : PSC_I2SPCR_RC)
|
||||
|
||||
|
||||
static int au1xpsc_i2s_set_fmt(struct snd_soc_dai *cpu_dai,
|
||||
@ -240,7 +240,7 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
int ret, stype = SUBSTREAM_TYPE(substream);
|
||||
int ret, stype = substream->stream;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
@ -257,7 +257,16 @@ static int au1xpsc_i2s_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int au1xpsc_i2s_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_dai *dai)
|
||||
{
|
||||
struct au1xpsc_audio_data *pscdata = snd_soc_dai_get_drvdata(dai);
|
||||
snd_soc_dai_set_dma_data(dai, substream, &pscdata->dmaids[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_dai_ops au1xpsc_i2s_dai_ops = {
|
||||
.startup = au1xpsc_i2s_startup,
|
||||
.trigger = au1xpsc_i2s_trigger,
|
||||
.hw_params = au1xpsc_i2s_hw_params,
|
||||
.set_fmt = au1xpsc_i2s_set_fmt,
|
||||
@ -304,6 +313,16 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
if (!wd->mmio)
|
||||
goto out1;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
|
||||
if (!r)
|
||||
goto out2;
|
||||
wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
|
||||
if (!r)
|
||||
goto out2;
|
||||
wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start;
|
||||
|
||||
/* preserve PSC clock source set up by platform (dev.platform_data
|
||||
* is already occupied by soc layer)
|
||||
*/
|
||||
@ -330,15 +349,11 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, wd);
|
||||
|
||||
ret = snd_soc_register_dai(&pdev->dev, &wd->dai_drv);
|
||||
if (ret)
|
||||
goto out1;
|
||||
|
||||
/* finally add the DMA device for this PSC */
|
||||
wd->dmapd = au1xpsc_pcm_add(pdev);
|
||||
if (wd->dmapd)
|
||||
if (!ret)
|
||||
return 0;
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
out2:
|
||||
iounmap(wd->mmio);
|
||||
out1:
|
||||
release_mem_region(r->start, resource_size(r));
|
||||
out0:
|
||||
@ -351,9 +366,6 @@ static int __devexit au1xpsc_i2s_drvremove(struct platform_device *pdev)
|
||||
struct au1xpsc_audio_data *wd = platform_get_drvdata(pdev);
|
||||
struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
|
||||
if (wd->dmapd)
|
||||
au1xpsc_pcm_destroy(wd->dmapd);
|
||||
|
||||
snd_soc_unregister_dai(&pdev->dev);
|
||||
|
||||
au_writel(0, I2S_CFG(wd));
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Au12x0/Au1550 PSC ALSA ASoC audio support.
|
||||
* Alchemy ALSA ASoC audio support.
|
||||
*
|
||||
* (c) 2007-2008 MSC Vertriebsges.m.b.H.,
|
||||
* (c) 2007-2011 MSC Vertriebsges.m.b.H.,
|
||||
* Manuel Lauss <manuel.lauss@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@ -13,10 +13,6 @@
|
||||
#ifndef _AU1X_PCM_H
|
||||
#define _AU1X_PCM_H
|
||||
|
||||
/* DBDMA helpers */
|
||||
extern struct platform_device *au1xpsc_pcm_add(struct platform_device *pdev);
|
||||
extern void au1xpsc_pcm_destroy(struct platform_device *dmapd);
|
||||
|
||||
struct au1xpsc_audio_data {
|
||||
void __iomem *mmio;
|
||||
|
||||
@ -27,15 +23,9 @@ struct au1xpsc_audio_data {
|
||||
|
||||
unsigned long pm[2];
|
||||
struct mutex lock;
|
||||
struct platform_device *dmapd;
|
||||
int dmaids[2];
|
||||
};
|
||||
|
||||
#define PCM_TX 0
|
||||
#define PCM_RX 1
|
||||
|
||||
#define SUBSTREAM_TYPE(substream) \
|
||||
((substream)->stream == SNDRV_PCM_STREAM_PLAYBACK ? PCM_TX : PCM_RX)
|
||||
|
||||
/* easy access macros */
|
||||
#define PSC_CTRL(x) ((unsigned long)((x)->mmio) + PSC_CTRL_OFFSET)
|
||||
#define PSC_SEL(x) ((unsigned long)((x)->mmio) + PSC_SEL_OFFSET)
|
||||
|
@ -27,6 +27,19 @@ config SND_SOC_BFIN_EVAL_ADAU1701
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAU1373
|
||||
tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && I2C
|
||||
select SND_BF5XX_SOC_I2S
|
||||
select SND_SOC_ADAU1373
|
||||
help
|
||||
Say Y if you want to add support for the Analog Devices EVAL-ADAU1373
|
||||
board connected to one of the Blackfin evaluation boards like the
|
||||
BF5XX-STAMP or BF5XX-EZKIT.
|
||||
|
||||
Note: This driver assumes that first ADAU1373 DAI is connected to the
|
||||
first SPORT port on the BF5XX board.
|
||||
|
||||
config SND_SOC_BFIN_EVAL_ADAV80X
|
||||
tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards"
|
||||
depends on SND_BF5XX_I2S && (SPI_MASTER || I2C)
|
||||
|
@ -21,6 +21,7 @@ snd-ad1980-objs := bf5xx-ad1980.o
|
||||
snd-ssm2602-objs := bf5xx-ssm2602.o
|
||||
snd-ad73311-objs := bf5xx-ad73311.o
|
||||
snd-ad193x-objs := bf5xx-ad193x.o
|
||||
snd-soc-bfin-eval-adau1373-objs := bfin-eval-adau1373.o
|
||||
snd-soc-bfin-eval-adau1701-objs := bfin-eval-adau1701.o
|
||||
snd-soc-bfin-eval-adav80x-objs := bfin-eval-adav80x.o
|
||||
|
||||
@ -29,5 +30,6 @@ 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_AD193X) += snd-ad193x.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1373) += snd-soc-bfin-eval-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAU1701) += snd-soc-bfin-eval-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_BFIN_EVAL_ADAV80X) += snd-soc-bfin-eval-adav80x.o
|
||||
|
202
sound/soc/blackfin/bfin-eval-adau1373.c
Normal file
202
sound/soc/blackfin/bfin-eval-adau1373.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Machine driver for EVAL-ADAU1373 on Analog Devices bfin
|
||||
* evaluation boards.
|
||||
*
|
||||
* Copyright 2011 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/soc.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "../codecs/adau1373.h"
|
||||
|
||||
static const struct snd_soc_dapm_widget bfin_eval_adau1373_dapm_widgets[] = {
|
||||
SND_SOC_DAPM_LINE("Line In1", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In2", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In3", NULL),
|
||||
SND_SOC_DAPM_LINE("Line In4", NULL),
|
||||
|
||||
SND_SOC_DAPM_LINE("Line Out1", NULL),
|
||||
SND_SOC_DAPM_LINE("Line Out2", NULL),
|
||||
SND_SOC_DAPM_LINE("Stereo Out", NULL),
|
||||
SND_SOC_DAPM_HP("Headphone", NULL),
|
||||
SND_SOC_DAPM_HP("Earpiece", NULL),
|
||||
SND_SOC_DAPM_SPK("Speaker", NULL),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route bfin_eval_adau1373_dapm_routes[] = {
|
||||
{ "AIN1L", NULL, "Line In1" },
|
||||
{ "AIN1R", NULL, "Line In1" },
|
||||
{ "AIN2L", NULL, "Line In2" },
|
||||
{ "AIN2R", NULL, "Line In2" },
|
||||
{ "AIN3L", NULL, "Line In3" },
|
||||
{ "AIN3R", NULL, "Line In3" },
|
||||
{ "AIN4L", NULL, "Line In4" },
|
||||
{ "AIN4R", NULL, "Line In4" },
|
||||
|
||||
/* MICBIAS can be connected via a jumper to the line-in jack, since w
|
||||
don't know which one is going to be used, just power both. */
|
||||
{ "Line In1", NULL, "MICBIAS1" },
|
||||
{ "Line In2", NULL, "MICBIAS1" },
|
||||
{ "Line In3", NULL, "MICBIAS1" },
|
||||
{ "Line In4", NULL, "MICBIAS1" },
|
||||
{ "Line In1", NULL, "MICBIAS2" },
|
||||
{ "Line In2", NULL, "MICBIAS2" },
|
||||
{ "Line In3", NULL, "MICBIAS2" },
|
||||
{ "Line In4", NULL, "MICBIAS2" },
|
||||
|
||||
{ "Line Out1", NULL, "LOUT1L" },
|
||||
{ "Line Out1", NULL, "LOUT1R" },
|
||||
{ "Line Out2", NULL, "LOUT2L" },
|
||||
{ "Line Out2", NULL, "LOUT2R" },
|
||||
{ "Headphone", NULL, "HPL" },
|
||||
{ "Headphone", NULL, "HPR" },
|
||||
{ "Earpiece", NULL, "EP" },
|
||||
{ "Speaker", NULL, "SPKL" },
|
||||
{ "Stereo Out", NULL, "SPKR" },
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1373_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->cpu_dai;
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
int ret;
|
||||
int pll_rate;
|
||||
|
||||
ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_fmt(codec_dai, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBM_CFM);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (params_rate(params)) {
|
||||
case 48000:
|
||||
case 8000:
|
||||
case 12000:
|
||||
case 16000:
|
||||
case 24000:
|
||||
case 32000:
|
||||
pll_rate = 48000 * 1024;
|
||||
break;
|
||||
case 44100:
|
||||
case 7350:
|
||||
case 11025:
|
||||
case 14700:
|
||||
case 22050:
|
||||
case 29400:
|
||||
pll_rate = 44100 * 1024;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
|
||||
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int bfin_eval_adau1373_codec_init(struct snd_soc_pcm_runtime *rtd)
|
||||
{
|
||||
struct snd_soc_dai *codec_dai = rtd->codec_dai;
|
||||
unsigned int pll_rate = 48000 * 1024;
|
||||
int ret;
|
||||
|
||||
ret = snd_soc_dai_set_pll(codec_dai, ADAU1373_PLL1,
|
||||
ADAU1373_PLL_SRC_MCLK1, 12288000, pll_rate);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = snd_soc_dai_set_sysclk(codec_dai, ADAU1373_CLK_SRC_PLL1, pll_rate,
|
||||
SND_SOC_CLOCK_IN);
|
||||
|
||||
return ret;
|
||||
}
|
||||
static struct snd_soc_ops bfin_eval_adau1373_ops = {
|
||||
.hw_params = bfin_eval_adau1373_hw_params,
|
||||
};
|
||||
|
||||
static struct snd_soc_dai_link bfin_eval_adau1373_dai = {
|
||||
.name = "adau1373",
|
||||
.stream_name = "adau1373",
|
||||
.cpu_dai_name = "bfin-i2s.0",
|
||||
.codec_dai_name = "adau1373-aif1",
|
||||
.platform_name = "bfin-i2s-pcm-audio",
|
||||
.codec_name = "adau1373.0-001a",
|
||||
.ops = &bfin_eval_adau1373_ops,
|
||||
.init = bfin_eval_adau1373_codec_init,
|
||||
};
|
||||
|
||||
static struct snd_soc_card bfin_eval_adau1373 = {
|
||||
.name = "bfin-eval-adau1373",
|
||||
.dai_link = &bfin_eval_adau1373_dai,
|
||||
.num_links = 1,
|
||||
|
||||
.dapm_widgets = bfin_eval_adau1373_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(bfin_eval_adau1373_dapm_widgets),
|
||||
.dapm_routes = bfin_eval_adau1373_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(bfin_eval_adau1373_dapm_routes),
|
||||
};
|
||||
|
||||
static int bfin_eval_adau1373_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = &bfin_eval_adau1373;
|
||||
|
||||
card->dev = &pdev->dev;
|
||||
|
||||
return snd_soc_register_card(&bfin_eval_adau1373);
|
||||
}
|
||||
|
||||
static int __devexit bfin_eval_adau1373_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct snd_soc_card *card = platform_get_drvdata(pdev);
|
||||
|
||||
snd_soc_unregister_card(card);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bfin_eval_adau1373_driver = {
|
||||
.driver = {
|
||||
.name = "bfin-eval-adau1373",
|
||||
.owner = THIS_MODULE,
|
||||
.pm = &snd_soc_pm_ops,
|
||||
},
|
||||
.probe = bfin_eval_adau1373_probe,
|
||||
.remove = __devexit_p(bfin_eval_adau1373_remove),
|
||||
};
|
||||
|
||||
static int __init bfin_eval_adau1373_init(void)
|
||||
{
|
||||
return platform_driver_register(&bfin_eval_adau1373_driver);
|
||||
}
|
||||
module_init(bfin_eval_adau1373_init);
|
||||
|
||||
static void __exit bfin_eval_adau1373_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&bfin_eval_adau1373_driver);
|
||||
}
|
||||
module_exit(bfin_eval_adau1373_exit);
|
||||
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("ALSA SoC bfin adau1373 driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS("platform:bfin-eval-adau1373");
|
@ -17,6 +17,7 @@ config SND_SOC_ALL_CODECS
|
||||
select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI
|
||||
select SND_SOC_AD1980 if SND_SOC_AC97_BUS
|
||||
select SND_SOC_AD73311
|
||||
select SND_SOC_ADAU1373 if I2C
|
||||
select SND_SOC_ADAV80X
|
||||
select SND_SOC_ADS117X
|
||||
select SND_SOC_AK4104 if SPI_MASTER
|
||||
@ -139,6 +140,9 @@ config SND_SOC_ADAU1701
|
||||
select SIGMA
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAU1373
|
||||
tristate
|
||||
|
||||
config SND_SOC_ADAV80X
|
||||
tristate
|
||||
|
||||
|
@ -5,6 +5,7 @@ snd-soc-ad193x-objs := ad193x.o
|
||||
snd-soc-ad1980-objs := ad1980.o
|
||||
snd-soc-ad73311-objs := ad73311.o
|
||||
snd-soc-adau1701-objs := adau1701.o
|
||||
snd-soc-adau1373-objs := adau1373.o
|
||||
snd-soc-adav80x-objs := adav80x.o
|
||||
snd-soc-ads117x-objs := ads117x.o
|
||||
snd-soc-ak4104-objs := ak4104.o
|
||||
@ -100,6 +101,7 @@ obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.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_ADAU1373) += snd-soc-adau1373.o
|
||||
obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o
|
||||
obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o
|
||||
obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/* codec private data */
|
||||
struct ad193x_priv {
|
||||
enum snd_soc_control_type control_type;
|
||||
struct regmap *regmap;
|
||||
int sysclk;
|
||||
};
|
||||
|
||||
@ -349,10 +349,8 @@ static int ad193x_probe(struct snd_soc_codec *codec)
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
int ret;
|
||||
|
||||
if (ad193x->control_type == SND_SOC_I2C)
|
||||
ret = snd_soc_codec_set_cache_io(codec, 8, 8, ad193x->control_type);
|
||||
else
|
||||
ret = snd_soc_codec_set_cache_io(codec, 16, 8, ad193x->control_type);
|
||||
codec->control_data = ad193x->regmap;
|
||||
ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
@ -388,6 +386,14 @@ static struct snd_soc_codec_driver soc_codec_dev_ad193x = {
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
|
||||
static const struct regmap_config ad193x_spi_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 16,
|
||||
.read_flag_mask = 0x09,
|
||||
.write_flag_mask = 0x08,
|
||||
};
|
||||
|
||||
static int __devinit ad193x_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad193x_priv *ad193x;
|
||||
@ -397,20 +403,36 @@ static int __devinit ad193x_spi_probe(struct spi_device *spi)
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ad193x->regmap = regmap_init_spi(spi, &ad193x_spi_regmap_config);
|
||||
if (IS_ERR(ad193x->regmap)) {
|
||||
ret = PTR_ERR(ad193x->regmap);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
spi_set_drvdata(spi, ad193x);
|
||||
ad193x->control_type = SND_SOC_SPI;
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_ad193x, &ad193x_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ad193x);
|
||||
goto err_regmap_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_regmap_exit:
|
||||
regmap_exit(ad193x->regmap);
|
||||
err_free:
|
||||
kfree(ad193x);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ad193x_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct ad193x_priv *ad193x = spi_get_drvdata(spi);
|
||||
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
kfree(spi_get_drvdata(spi));
|
||||
regmap_exit(ad193x->regmap);
|
||||
kfree(ad193x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -425,6 +447,12 @@ static struct spi_driver ad193x_spi_driver = {
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
|
||||
static const struct regmap_config ad193x_i2c_regmap_config = {
|
||||
.val_bits = 8,
|
||||
.reg_bits = 8,
|
||||
};
|
||||
|
||||
static const struct i2c_device_id ad193x_id[] = {
|
||||
{ "ad1936", 0 },
|
||||
{ "ad1937", 0 },
|
||||
@ -442,20 +470,35 @@ static int __devinit ad193x_i2c_probe(struct i2c_client *client,
|
||||
if (ad193x == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
ad193x->regmap = regmap_init_i2c(client, &ad193x_i2c_regmap_config);
|
||||
if (IS_ERR(ad193x->regmap)) {
|
||||
ret = PTR_ERR(ad193x->regmap);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, ad193x);
|
||||
ad193x->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&client->dev,
|
||||
&soc_codec_dev_ad193x, &ad193x_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(ad193x);
|
||||
goto err_regmap_exit;
|
||||
|
||||
return 0;
|
||||
|
||||
err_regmap_exit:
|
||||
regmap_exit(ad193x->regmap);
|
||||
err_free:
|
||||
kfree(ad193x);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit ad193x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct ad193x_priv *ad193x = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
regmap_exit(ad193x->regmap);
|
||||
kfree(ad193x);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -9,20 +9,20 @@
|
||||
#ifndef __AD193X_H__
|
||||
#define __AD193X_H__
|
||||
|
||||
#define AD193X_PLL_CLK_CTRL0 0x800
|
||||
#define AD193X_PLL_CLK_CTRL0 0x00
|
||||
#define AD193X_PLL_POWERDOWN 0x01
|
||||
#define AD193X_PLL_INPUT_MASK (~0x6)
|
||||
#define AD193X_PLL_INPUT_256 (0 << 1)
|
||||
#define AD193X_PLL_INPUT_384 (1 << 1)
|
||||
#define AD193X_PLL_INPUT_512 (2 << 1)
|
||||
#define AD193X_PLL_INPUT_768 (3 << 1)
|
||||
#define AD193X_PLL_CLK_CTRL1 0x801
|
||||
#define AD193X_DAC_CTRL0 0x802
|
||||
#define AD193X_PLL_CLK_CTRL1 0x01
|
||||
#define AD193X_DAC_CTRL0 0x02
|
||||
#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_CTRL1 0x03
|
||||
#define AD193X_DAC_2_CHANNELS 0
|
||||
#define AD193X_DAC_4_CHANNELS 1
|
||||
#define AD193X_DAC_8_CHANNELS 2
|
||||
@ -33,11 +33,11 @@
|
||||
#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_CTRL2 0x04
|
||||
#define AD193X_DAC_WORD_LEN_SHFT 3
|
||||
#define AD193X_DAC_WORD_LEN_MASK 0x18
|
||||
#define AD193X_DAC_MASTER_MUTE 1
|
||||
#define AD193X_DAC_CHNL_MUTE 0x805
|
||||
#define AD193X_DAC_CHNL_MUTE 0x05
|
||||
#define AD193X_DACL1_MUTE 0
|
||||
#define AD193X_DACR1_MUTE 1
|
||||
#define AD193X_DACL2_MUTE 2
|
||||
@ -46,28 +46,28 @@
|
||||
#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_DAC_L1_VOL 0x06
|
||||
#define AD193X_DAC_R1_VOL 0x07
|
||||
#define AD193X_DAC_L2_VOL 0x08
|
||||
#define AD193X_DAC_R2_VOL 0x09
|
||||
#define AD193X_DAC_L3_VOL 0x0a
|
||||
#define AD193X_DAC_R3_VOL 0x0b
|
||||
#define AD193X_DAC_L4_VOL 0x0c
|
||||
#define AD193X_DAC_R4_VOL 0x0d
|
||||
#define AD193X_ADC_CTRL0 0x0e
|
||||
#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_CTRL1 0x0f
|
||||
#define AD193X_ADC_SERFMT_MASK 0x60
|
||||
#define AD193X_ADC_SERFMT_STEREO (0 << 5)
|
||||
#define AD193X_ADC_SERFMT_TDM (1 << 5)
|
||||
#define AD193X_ADC_SERFMT_AUX (2 << 5)
|
||||
#define AD193X_ADC_WORD_LEN_MASK 0x3
|
||||
#define AD193X_ADC_CTRL2 0x810
|
||||
#define AD193X_ADC_CTRL2 0x10
|
||||
#define AD193X_ADC_2_CHANNELS 0
|
||||
#define AD193X_ADC_4_CHANNELS 1
|
||||
#define AD193X_ADC_8_CHANNELS 2
|
||||
|
@ -200,18 +200,22 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec)
|
||||
}
|
||||
|
||||
/* Read out vendor ID to make sure it is ad1980 */
|
||||
if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144)
|
||||
if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
|
||||
ret = -ENODEV;
|
||||
goto reset_err;
|
||||
}
|
||||
|
||||
vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
|
||||
|
||||
if (vendor_id2 != 0x5370) {
|
||||
if (vendor_id2 != 0x5374)
|
||||
if (vendor_id2 != 0x5374) {
|
||||
ret = -ENODEV;
|
||||
goto reset_err;
|
||||
else
|
||||
} else {
|
||||
printk(KERN_WARNING "ad1980: "
|
||||
"Found AD1981 - only 2/2 IN/OUT Channels "
|
||||
"supported\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* unmute captures and playbacks volume */
|
||||
|
1414
sound/soc/codecs/adau1373.c
Normal file
1414
sound/soc/codecs/adau1373.c
Normal file
File diff suppressed because it is too large
Load Diff
29
sound/soc/codecs/adau1373.h
Normal file
29
sound/soc/codecs/adau1373.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef __ADAU1373_H__
|
||||
#define __ADAU1373_H__
|
||||
|
||||
enum adau1373_pll_src {
|
||||
ADAU1373_PLL_SRC_MCLK1 = 0,
|
||||
ADAU1373_PLL_SRC_BCLK1 = 1,
|
||||
ADAU1373_PLL_SRC_BCLK2 = 2,
|
||||
ADAU1373_PLL_SRC_BCLK3 = 3,
|
||||
ADAU1373_PLL_SRC_LRCLK1 = 4,
|
||||
ADAU1373_PLL_SRC_LRCLK2 = 5,
|
||||
ADAU1373_PLL_SRC_LRCLK3 = 6,
|
||||
ADAU1373_PLL_SRC_GPIO1 = 7,
|
||||
ADAU1373_PLL_SRC_GPIO2 = 8,
|
||||
ADAU1373_PLL_SRC_GPIO3 = 9,
|
||||
ADAU1373_PLL_SRC_GPIO4 = 10,
|
||||
ADAU1373_PLL_SRC_MCLK2 = 11,
|
||||
};
|
||||
|
||||
enum adau1373_pll {
|
||||
ADAU1373_PLL1 = 0,
|
||||
ADAU1373_PLL2 = 1,
|
||||
};
|
||||
|
||||
enum adau1373_clk_src {
|
||||
ADAU1373_CLK_SRC_PLL1 = 0,
|
||||
ADAU1373_CLK_SRC_PLL2 = 1,
|
||||
};
|
||||
|
||||
#endif
|
@ -523,7 +523,8 @@ static int adav80x_hw_params(struct snd_pcm_substream *substream,
|
||||
}
|
||||
|
||||
static int adav80x_set_sysclk(struct snd_soc_codec *codec,
|
||||
int clk_id, unsigned int freq, int dir)
|
||||
int clk_id, int source,
|
||||
unsigned int freq, int dir)
|
||||
{
|
||||
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
|
@ -41,7 +41,6 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
|
||||
struct alc5623_priv {
|
||||
enum snd_soc_control_type control_type;
|
||||
void *control_data;
|
||||
struct mutex mutex;
|
||||
u8 id;
|
||||
unsigned int sysclk;
|
||||
u16 reg_cache[ALC5623_VENDOR_ID2+2];
|
||||
@ -1052,7 +1051,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
|
||||
i2c_set_clientdata(client, alc5623);
|
||||
alc5623->control_data = client;
|
||||
alc5623->control_type = SND_SOC_I2C;
|
||||
mutex_init(&alc5623->mutex);
|
||||
|
||||
ret = snd_soc_register_codec(&client->dev,
|
||||
&soc_codec_device_alc5623, &alc5623_dai, 1);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/regulator/driver.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/pcm.h>
|
||||
@ -1436,10 +1437,17 @@ static const struct i2c_device_id sgtl5000_id[] = {
|
||||
|
||||
MODULE_DEVICE_TABLE(i2c, sgtl5000_id);
|
||||
|
||||
static const struct of_device_id sgtl5000_dt_ids[] = {
|
||||
{ .compatible = "fsl,sgtl5000", },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids);
|
||||
|
||||
static struct i2c_driver sgtl5000_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "sgtl5000",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = sgtl5000_dt_ids,
|
||||
},
|
||||
.probe = sgtl5000_i2c_probe,
|
||||
.remove = __devexit_p(sgtl5000_i2c_remove),
|
||||
|
@ -79,7 +79,7 @@ static void configure_adc(struct snd_soc_codec *sn95031_codec, int val)
|
||||
*/
|
||||
static int find_free_channel(struct snd_soc_codec *sn95031_codec)
|
||||
{
|
||||
int ret = 0, i, value;
|
||||
int i, value;
|
||||
|
||||
/* check whether ADC is enabled */
|
||||
value = snd_soc_read(sn95031_codec, SN95031_ADC1CNTL1);
|
||||
@ -91,12 +91,10 @@ static int find_free_channel(struct snd_soc_codec *sn95031_codec)
|
||||
for (i = 0; i < SN95031_ADC_CHANLS_MAX; i++) {
|
||||
value = snd_soc_read(sn95031_codec,
|
||||
SN95031_ADC_CHNL_START_ADDR + i);
|
||||
if (value & SN95031_STOPBIT_MASK) {
|
||||
ret = i;
|
||||
if (value & SN95031_STOPBIT_MASK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ret > SN95031_ADC_LOOP_MAX) ? (-EINVAL) : ret;
|
||||
return (i == SN95031_ADC_CHANLS_MAX) ? (-EINVAL) : i;
|
||||
}
|
||||
|
||||
/* Initialize the ADC for reading micbias values. Can sleep. */
|
||||
@ -660,7 +658,7 @@ static int sn95031_pcm_spkr_mute(struct snd_soc_dai *dai, int mute)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
static int sn95031_pcm_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
|
||||
{
|
||||
unsigned int format, rate;
|
||||
|
@ -294,7 +294,6 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
|
||||
struct snd_soc_pcm_runtime *rtd = substream->private_data;
|
||||
struct snd_soc_codec *codec = rtd->codec;
|
||||
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
|
||||
struct i2c_client *i2c = codec->control_data;
|
||||
struct snd_pcm_runtime *master_runtime;
|
||||
|
||||
/* The DAI has shared clocks so if we already have a playback or
|
||||
@ -303,7 +302,7 @@ static int ssm2602_startup(struct snd_pcm_substream *substream,
|
||||
*/
|
||||
if (ssm2602->master_substream) {
|
||||
master_runtime = ssm2602->master_substream->runtime;
|
||||
dev_dbg(&i2c->dev, "Constraining to %d bits at %dHz\n",
|
||||
dev_dbg(codec->dev, "Constraining to %d bits at %dHz\n",
|
||||
master_runtime->sample_bits,
|
||||
master_runtime->rate);
|
||||
|
||||
|
@ -524,13 +524,17 @@ static int sta32x_hw_params(struct snd_pcm_substream *substream,
|
||||
rate = params_rate(params);
|
||||
pr_debug("rate: %u\n", rate);
|
||||
for (i = 0; i < ARRAY_SIZE(interpolation_ratios); i++)
|
||||
if (interpolation_ratios[i].fs == rate)
|
||||
if (interpolation_ratios[i].fs == rate) {
|
||||
ir = interpolation_ratios[i].ir;
|
||||
break;
|
||||
}
|
||||
if (ir < 0)
|
||||
return -EINVAL;
|
||||
for (i = 0; mclk_ratios[ir][i].ratio; i++)
|
||||
if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk)
|
||||
if (mclk_ratios[ir][i].ratio * rate == sta32x->mclk) {
|
||||
mcs = mclk_ratios[ir][i].mcs;
|
||||
break;
|
||||
}
|
||||
if (mcs < 0)
|
||||
return -EINVAL;
|
||||
|
||||
@ -808,6 +812,7 @@ static int sta32x_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
|
||||
regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
|
||||
|
||||
@ -867,18 +872,8 @@ static __devinit int sta32x_i2c_probe(struct i2c_client *i2c,
|
||||
static __devexit int sta32x_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct sta32x_priv *sta32x = i2c_get_clientdata(client);
|
||||
struct snd_soc_codec *codec = sta32x->codec;
|
||||
|
||||
if (codec)
|
||||
sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
|
||||
|
||||
regulator_bulk_free(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
|
||||
|
||||
if (codec) {
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
snd_soc_codec_set_drvdata(codec, NULL);
|
||||
}
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
kfree(sta32x);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1431,7 +1431,7 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
|
||||
/* Check if the IRQ number is valid and request it */
|
||||
if (dac33->irq >= 0) {
|
||||
ret = request_irq(dac33->irq, dac33_interrupt_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_DISABLED,
|
||||
IRQF_TRIGGER_RISING,
|
||||
codec->name, codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Could not request IRQ%d (%d)\n",
|
||||
|
@ -446,7 +446,6 @@ err_regulator:
|
||||
gpio_free(data->power_gpio);
|
||||
err_gpio:
|
||||
kfree(data);
|
||||
i2c_set_clientdata(tpa6130a2_client, NULL);
|
||||
tpa6130a2_client = NULL;
|
||||
|
||||
return ret;
|
||||
|
@ -118,8 +118,8 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
|
||||
0x4A, /* TWL6040_LPPLLDIV 0x09 */
|
||||
0x00, /* TWL6040_AMICBCTL 0x0A */
|
||||
0x00, /* TWL6040_DMICBCTL 0x0B */
|
||||
0x18, /* TWL6040_MICLCTL 0x0C - No input selected on Left Mic */
|
||||
0x18, /* TWL6040_MICRCTL 0x0D - No input selected on Right Mic */
|
||||
0x00, /* TWL6040_MICLCTL 0x0C */
|
||||
0x00, /* TWL6040_MICRCTL 0x0D */
|
||||
0x00, /* TWL6040_MICGAIN 0x0E */
|
||||
0x1B, /* TWL6040_LINEGAIN 0x0F */
|
||||
0x00, /* TWL6040_HSLCTL 0x10 */
|
||||
@ -155,41 +155,8 @@ static const u8 twl6040_reg[TWL6040_CACHEREGNUM] = {
|
||||
0x00, /* TWL6040_STATUS (ro) 0x2E */
|
||||
};
|
||||
|
||||
/*
|
||||
* twl6040 vio/gnd registers:
|
||||
* registers under vio/gnd supply can be accessed
|
||||
* before the power-up sequence, after NRESPWRON goes high
|
||||
*/
|
||||
static const int twl6040_vio_reg[TWL6040_VIOREGNUM] = {
|
||||
TWL6040_REG_ASICID,
|
||||
TWL6040_REG_ASICREV,
|
||||
TWL6040_REG_INTID,
|
||||
TWL6040_REG_INTMR,
|
||||
TWL6040_REG_NCPCTL,
|
||||
TWL6040_REG_LDOCTL,
|
||||
TWL6040_REG_AMICBCTL,
|
||||
TWL6040_REG_DMICBCTL,
|
||||
TWL6040_REG_HKCTL1,
|
||||
TWL6040_REG_HKCTL2,
|
||||
TWL6040_REG_GPOCTL,
|
||||
TWL6040_REG_TRIM1,
|
||||
TWL6040_REG_TRIM2,
|
||||
TWL6040_REG_TRIM3,
|
||||
TWL6040_REG_HSOTRIM,
|
||||
TWL6040_REG_HFOTRIM,
|
||||
TWL6040_REG_ACCCTL,
|
||||
TWL6040_REG_STATUS,
|
||||
};
|
||||
|
||||
/*
|
||||
* twl6040 vdd/vss registers:
|
||||
* registers under vdd/vss supplies can only be accessed
|
||||
* after the power-up sequence
|
||||
*/
|
||||
static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
|
||||
TWL6040_REG_HPPLLCTL,
|
||||
TWL6040_REG_LPPLLCTL,
|
||||
TWL6040_REG_LPPLLDIV,
|
||||
/* List of registers to be restored after power up */
|
||||
static const int twl6040_restore_list[] = {
|
||||
TWL6040_REG_MICLCTL,
|
||||
TWL6040_REG_MICRCTL,
|
||||
TWL6040_REG_MICGAIN,
|
||||
@ -202,12 +169,6 @@ static const int twl6040_vdd_reg[TWL6040_VDDREGNUM] = {
|
||||
TWL6040_REG_HFLGAIN,
|
||||
TWL6040_REG_HFRCTL,
|
||||
TWL6040_REG_HFRGAIN,
|
||||
TWL6040_REG_VIBCTLL,
|
||||
TWL6040_REG_VIBDATL,
|
||||
TWL6040_REG_VIBCTLR,
|
||||
TWL6040_REG_VIBDATR,
|
||||
TWL6040_REG_ALB,
|
||||
TWL6040_REG_DLB,
|
||||
};
|
||||
|
||||
/* set of rates for each pll: low-power and high-performance */
|
||||
@ -296,56 +257,27 @@ static int twl6040_write(struct snd_soc_codec *codec,
|
||||
return twl6040_reg_write(twl6040, reg, value);
|
||||
}
|
||||
|
||||
static void twl6040_init_vio_regs(struct snd_soc_codec *codec)
|
||||
static void twl6040_init_chip(struct snd_soc_codec *codec)
|
||||
{
|
||||
u8 *cache = codec->reg_cache;
|
||||
int reg, i;
|
||||
struct twl6040 *twl6040 = codec->control_data;
|
||||
u8 val;
|
||||
|
||||
for (i = 0; i < TWL6040_VIOREGNUM; i++) {
|
||||
reg = twl6040_vio_reg[i];
|
||||
/*
|
||||
* skip read-only registers (ASICID, ASICREV, STATUS)
|
||||
* and registers shared among MFD children
|
||||
*/
|
||||
switch (reg) {
|
||||
case TWL6040_REG_ASICID:
|
||||
case TWL6040_REG_ASICREV:
|
||||
case TWL6040_REG_INTID:
|
||||
case TWL6040_REG_INTMR:
|
||||
case TWL6040_REG_NCPCTL:
|
||||
case TWL6040_REG_LDOCTL:
|
||||
case TWL6040_REG_GPOCTL:
|
||||
case TWL6040_REG_ACCCTL:
|
||||
case TWL6040_REG_STATUS:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
twl6040_write(codec, reg, cache[reg]);
|
||||
}
|
||||
val = twl6040_get_revid(twl6040);
|
||||
twl6040_write_reg_cache(codec, TWL6040_REG_ASICREV, val);
|
||||
|
||||
/* Change chip defaults */
|
||||
/* No imput selected for microphone amplifiers */
|
||||
twl6040_write_reg_cache(codec, TWL6040_REG_MICLCTL, 0x18);
|
||||
twl6040_write_reg_cache(codec, TWL6040_REG_MICRCTL, 0x18);
|
||||
}
|
||||
|
||||
static void twl6040_init_vdd_regs(struct snd_soc_codec *codec)
|
||||
static void twl6040_restore_regs(struct snd_soc_codec *codec)
|
||||
{
|
||||
u8 *cache = codec->reg_cache;
|
||||
int reg, i;
|
||||
|
||||
for (i = 0; i < TWL6040_VDDREGNUM; i++) {
|
||||
reg = twl6040_vdd_reg[i];
|
||||
/* skip vibra and PLL registers */
|
||||
switch (reg) {
|
||||
case TWL6040_REG_VIBCTLL:
|
||||
case TWL6040_REG_VIBDATL:
|
||||
case TWL6040_REG_VIBCTLR:
|
||||
case TWL6040_REG_VIBDATR:
|
||||
case TWL6040_REG_HPPLLCTL:
|
||||
case TWL6040_REG_LPPLLCTL:
|
||||
case TWL6040_REG_LPPLLDIV:
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(twl6040_restore_list); i++) {
|
||||
reg = twl6040_restore_list[i];
|
||||
twl6040_write(codec, reg, cache[reg]);
|
||||
}
|
||||
}
|
||||
@ -1325,8 +1257,7 @@ static int twl6040_set_bias_level(struct snd_soc_codec *codec,
|
||||
|
||||
priv->codec_powered = 1;
|
||||
|
||||
/* initialize vdd/vss registers with reg_cache */
|
||||
twl6040_init_vdd_regs(codec);
|
||||
twl6040_restore_regs(codec);
|
||||
|
||||
/* Set external boost GPO */
|
||||
twl6040_write(codec, TWL6040_REG_GPOCTL, 0x02);
|
||||
@ -1468,7 +1399,7 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
|
||||
.playback = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 1,
|
||||
.channels_max = 2,
|
||||
.channels_max = 5,
|
||||
.rates = TWL6040_RATES,
|
||||
.formats = TWL6040_FORMATS,
|
||||
},
|
||||
@ -1518,8 +1449,8 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
|
||||
.name = "twl6040-vib",
|
||||
.playback = {
|
||||
.stream_name = "Vibra Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.formats = TWL6040_FORMATS,
|
||||
},
|
||||
@ -1620,8 +1551,7 @@ static int twl6040_probe(struct snd_soc_codec *codec)
|
||||
goto plugirq_err;
|
||||
}
|
||||
|
||||
/* init vio registers */
|
||||
twl6040_init_vio_regs(codec);
|
||||
twl6040_init_chip(codec);
|
||||
|
||||
/* power on device */
|
||||
ret = twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
|
||||
|
@ -56,8 +56,26 @@ static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
|
||||
};
|
||||
|
||||
static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
const struct i2c_device_id *i2c_id)
|
||||
{
|
||||
int id, board, rev;
|
||||
|
||||
board = i2c_smbus_read_byte_data(i2c, 0);
|
||||
if (board < 0) {
|
||||
dev_err(&i2c->dev, "Failed to read ID: %d\n", board);
|
||||
return board;
|
||||
}
|
||||
|
||||
id = (board & 0xfe) >> 2;
|
||||
rev = board & 0x3;
|
||||
|
||||
if (id != 1) {
|
||||
dev_err(&i2c->dev, "Unknown board ID %d\n", id);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
dev_info(&i2c->dev, "revision %d\n", rev + 1);
|
||||
|
||||
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
|
||||
&wm1250_ev1_dai, 1);
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -598,6 +599,11 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
|
||||
.reg_cache_default =wm8510_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8510_of_match[] = {
|
||||
{ .compatible = "wlf,wm8510" },
|
||||
{ },
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8510_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -628,6 +634,7 @@ static struct spi_driver wm8510_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8510",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8510_of_match,
|
||||
},
|
||||
.probe = wm8510_spi_probe,
|
||||
.remove = __devexit_p(wm8510_spi_remove),
|
||||
@ -671,6 +678,7 @@ static struct i2c_driver wm8510_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8510-codec",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8510_of_match,
|
||||
},
|
||||
.probe = wm8510_i2c_probe,
|
||||
.remove = __devexit_p(wm8510_i2c_remove),
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -84,7 +85,7 @@ static const char *wm8523_zd_count_text[] = {
|
||||
static const struct soc_enum wm8523_zc_count =
|
||||
SOC_ENUM_SINGLE(WM8523_ZERO_DETECT, 0, 2, wm8523_zd_count_text);
|
||||
|
||||
static const struct snd_kcontrol_new wm8523_snd_controls[] = {
|
||||
static const struct snd_kcontrol_new wm8523_controls[] = {
|
||||
SOC_DOUBLE_R_TLV("Playback Volume", WM8523_DAC_GAINL, WM8523_DAC_GAINR,
|
||||
0, 448, 0, dac_tlv),
|
||||
SOC_SINGLE("ZC Switch", WM8523_DAC_CTRL3, 4, 1, 0),
|
||||
@ -101,22 +102,11 @@ SND_SOC_DAPM_OUTPUT("LINEVOUTL"),
|
||||
SND_SOC_DAPM_OUTPUT("LINEVOUTR"),
|
||||
};
|
||||
|
||||
static const struct snd_soc_dapm_route intercon[] = {
|
||||
static const struct snd_soc_dapm_route wm8523_dapm_routes[] = {
|
||||
{ "LINEVOUTL", NULL, "DAC" },
|
||||
{ "LINEVOUTR", NULL, "DAC" },
|
||||
};
|
||||
|
||||
static int wm8523_add_widgets(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct snd_soc_dapm_context *dapm = &codec->dapm;
|
||||
|
||||
snd_soc_dapm_new_controls(dapm, wm8523_dapm_widgets,
|
||||
ARRAY_SIZE(wm8523_dapm_widgets));
|
||||
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct {
|
||||
int value;
|
||||
int ratio;
|
||||
@ -479,10 +469,6 @@ static int wm8523_probe(struct snd_soc_codec *codec)
|
||||
/* Bias level configuration will have done an extra enable */
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8523->supplies), wm8523->supplies);
|
||||
|
||||
snd_soc_add_controls(codec, wm8523_snd_controls,
|
||||
ARRAY_SIZE(wm8523_snd_controls));
|
||||
wm8523_add_widgets(codec);
|
||||
|
||||
return 0;
|
||||
|
||||
err_enable:
|
||||
@ -512,6 +498,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = wm8523_reg,
|
||||
.volatile_register = wm8523_volatile_register,
|
||||
|
||||
.controls = wm8523_controls,
|
||||
.num_controls = ARRAY_SIZE(wm8523_controls),
|
||||
.dapm_widgets = wm8523_dapm_widgets,
|
||||
.num_dapm_widgets = ARRAY_SIZE(wm8523_dapm_widgets),
|
||||
.dapm_routes = wm8523_dapm_routes,
|
||||
.num_dapm_routes = ARRAY_SIZE(wm8523_dapm_routes),
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8523_of_match[] = {
|
||||
{ .compatible = "wlf,wm8523" },
|
||||
{ },
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
@ -551,8 +549,9 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8523_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8523-codec",
|
||||
.name = "wm8523",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8523_of_match,
|
||||
},
|
||||
.probe = wm8523_i2c_probe,
|
||||
.remove = __devexit_p(wm8523_i2c_remove),
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
@ -907,6 +908,11 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8580 = {
|
||||
.reg_cache_default = wm8580_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8580_of_match[] = {
|
||||
{ .compatible = "wlf,wm8580" },
|
||||
{ },
|
||||
};
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static int wm8580_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
@ -943,8 +949,9 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8580_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8580-codec",
|
||||
.name = "wm8580",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8580_of_match,
|
||||
},
|
||||
.probe = wm8580_i2c_probe,
|
||||
.remove = wm8580_i2c_remove,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -414,6 +415,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
|
||||
.num_dapm_routes = ARRAY_SIZE(wm8711_intercon),
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8711_of_match[] = {
|
||||
{ .compatible = "wlf,wm8711", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8711_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8711_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -443,8 +450,9 @@ static int __devexit wm8711_spi_remove(struct spi_device *spi)
|
||||
|
||||
static struct spi_driver wm8711_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8711-codec",
|
||||
.name = "wm8711",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8711_of_match,
|
||||
},
|
||||
.probe = wm8711_spi_probe,
|
||||
.remove = __devexit_p(wm8711_spi_remove),
|
||||
@ -487,8 +495,9 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8711_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8711-codec",
|
||||
.name = "wm8711",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8711_of_match,
|
||||
},
|
||||
.probe = wm8711_i2c_probe,
|
||||
.remove = __devexit_p(wm8711_i2c_remove),
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -269,6 +270,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
|
||||
.num_dapm_routes = ARRAY_SIZE(wm8728_intercon),
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8728_of_match[] = {
|
||||
{ .compatible = "wlf,wm8728", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8728_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8728_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -298,8 +305,9 @@ static int __devexit wm8728_spi_remove(struct spi_device *spi)
|
||||
|
||||
static struct spi_driver wm8728_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8728-codec",
|
||||
.name = "wm8728",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8728_of_match,
|
||||
},
|
||||
.probe = wm8728_spi_probe,
|
||||
.remove = __devexit_p(wm8728_spi_remove),
|
||||
@ -342,8 +350,9 @@ MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8728_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8728-codec",
|
||||
.name = "wm8728",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8728_of_match,
|
||||
},
|
||||
.probe = wm8728_i2c_probe,
|
||||
.remove = __devexit_p(wm8728_i2c_remove),
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -607,6 +608,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
|
||||
.num_dapm_routes = ARRAY_SIZE(wm8731_intercon),
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8731_of_match[] = {
|
||||
{ .compatible = "wlf,wm8731", },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, wm8731_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8731_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -638,6 +646,7 @@ static struct spi_driver wm8731_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8731",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8731_of_match,
|
||||
},
|
||||
.probe = wm8731_spi_probe,
|
||||
.remove = __devexit_p(wm8731_spi_remove),
|
||||
@ -682,6 +691,7 @@ static struct i2c_driver wm8731_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8731",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8731_of_match,
|
||||
},
|
||||
.probe = wm8731_i2c_probe,
|
||||
.remove = __devexit_p(wm8731_i2c_remove),
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -634,6 +635,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
|
||||
.reg_cache_default = wm8737_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8737_of_match[] = {
|
||||
{ .compatible = "wlf,wm8737", },
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, wm8737_of_match);
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static __devinit int wm8737_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
@ -673,6 +681,7 @@ static struct i2c_driver wm8737_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8737",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8737_of_match,
|
||||
},
|
||||
.probe = wm8737_i2c_probe,
|
||||
.remove = __devexit_p(wm8737_i2c_remove),
|
||||
@ -711,6 +720,7 @@ static struct spi_driver wm8737_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8737",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8737_of_match,
|
||||
},
|
||||
.probe = wm8737_spi_probe,
|
||||
.remove = __devexit_p(wm8737_spi_remove),
|
||||
|
@ -17,9 +17,11 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -422,17 +424,35 @@ static int wm8741_probe(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
|
||||
wm8741->supplies[i].supply = wm8741_supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8741->supplies),
|
||||
wm8741->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to request supplies: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
|
||||
wm8741->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to enable supplies: %d\n", ret);
|
||||
goto err_get;
|
||||
}
|
||||
|
||||
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8741->control_type);
|
||||
if (ret != 0) {
|
||||
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
|
||||
return ret;
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
ret = wm8741_reset(codec);
|
||||
if (ret < 0) {
|
||||
dev_err(codec->dev, "Failed to issue reset\n");
|
||||
return ret;
|
||||
goto err_enable;
|
||||
}
|
||||
|
||||
/* Change some default settings - latch VU */
|
||||
@ -451,58 +471,61 @@ static int wm8741_probe(struct snd_soc_codec *codec)
|
||||
|
||||
dev_dbg(codec->dev, "Successful registration\n");
|
||||
return ret;
|
||||
|
||||
err_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
err_get:
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8741_remove(struct snd_soc_codec *codec)
|
||||
{
|
||||
struct wm8741_priv *wm8741 = snd_soc_codec_get_drvdata(codec);
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct snd_soc_codec_driver soc_codec_dev_wm8741 = {
|
||||
.probe = wm8741_probe,
|
||||
.remove = wm8741_remove,
|
||||
.resume = wm8741_resume,
|
||||
.reg_cache_size = ARRAY_SIZE(wm8741_reg_defaults),
|
||||
.reg_word_size = sizeof(u16),
|
||||
.reg_cache_default = wm8741_reg_defaults,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8741_of_match[] = {
|
||||
{ .compatible = "wlf,wm8741", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8741_of_match);
|
||||
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
static int wm8741_i2c_probe(struct i2c_client *i2c,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct wm8741_priv *wm8741;
|
||||
int ret, i;
|
||||
int ret;
|
||||
|
||||
wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
|
||||
if (wm8741 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(wm8741->supplies); i++)
|
||||
wm8741->supplies[i].supply = wm8741_supply_names[i];
|
||||
|
||||
ret = regulator_bulk_get(&i2c->dev, ARRAY_SIZE(wm8741->supplies),
|
||||
wm8741->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = regulator_bulk_enable(ARRAY_SIZE(wm8741->supplies),
|
||||
wm8741->supplies);
|
||||
if (ret != 0) {
|
||||
dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret);
|
||||
goto err_get;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(i2c, wm8741);
|
||||
wm8741->control_type = SND_SOC_I2C;
|
||||
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_wm8741, &wm8741_dai, 1);
|
||||
if (ret < 0)
|
||||
goto err_enable;
|
||||
ret = snd_soc_register_codec(&i2c->dev,
|
||||
&soc_codec_dev_wm8741, &wm8741_dai, 1);
|
||||
if (ret != 0)
|
||||
goto err;
|
||||
|
||||
return ret;
|
||||
|
||||
err_enable:
|
||||
regulator_bulk_disable(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
|
||||
err_get:
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
err:
|
||||
kfree(wm8741);
|
||||
return ret;
|
||||
@ -510,10 +533,7 @@ err:
|
||||
|
||||
static int wm8741_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct wm8741_priv *wm8741 = i2c_get_clientdata(client);
|
||||
|
||||
snd_soc_unregister_codec(&client->dev);
|
||||
regulator_bulk_free(ARRAY_SIZE(wm8741->supplies), wm8741->supplies);
|
||||
kfree(i2c_get_clientdata(client));
|
||||
return 0;
|
||||
}
|
||||
@ -526,8 +546,9 @@ MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8741_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8741-codec",
|
||||
.name = "wm8741",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8741_of_match,
|
||||
},
|
||||
.probe = wm8741_i2c_probe,
|
||||
.remove = wm8741_i2c_remove,
|
||||
@ -535,6 +556,44 @@ static struct i2c_driver wm8741_i2c_driver = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8741_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct wm8741_priv *wm8741;
|
||||
int ret;
|
||||
|
||||
wm8741 = kzalloc(sizeof(struct wm8741_priv), GFP_KERNEL);
|
||||
if (wm8741 == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
wm8741->control_type = SND_SOC_SPI;
|
||||
spi_set_drvdata(spi, wm8741);
|
||||
|
||||
ret = snd_soc_register_codec(&spi->dev,
|
||||
&soc_codec_dev_wm8741, &wm8741_dai, 1);
|
||||
if (ret < 0)
|
||||
kfree(wm8741);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __devexit wm8741_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
snd_soc_unregister_codec(&spi->dev);
|
||||
kfree(spi_get_drvdata(spi));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver wm8741_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8741",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8741_of_match,
|
||||
},
|
||||
.probe = wm8741_spi_probe,
|
||||
.remove = __devexit_p(wm8741_spi_remove),
|
||||
};
|
||||
#endif /* CONFIG_SPI_MASTER */
|
||||
|
||||
static int __init wm8741_modinit(void)
|
||||
{
|
||||
int ret = 0;
|
||||
@ -544,6 +603,13 @@ static int __init wm8741_modinit(void)
|
||||
if (ret != 0)
|
||||
pr_err("Failed to register WM8741 I2C driver: %d\n", ret);
|
||||
#endif
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
ret = spi_register_driver(&wm8741_spi_driver);
|
||||
if (ret != 0) {
|
||||
printk(KERN_ERR "Failed to register wm8741 SPI driver: %d\n",
|
||||
ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -551,6 +617,9 @@ module_init(wm8741_modinit);
|
||||
|
||||
static void __exit wm8741_exit(void)
|
||||
{
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
spi_unregister_driver(&wm8741_spi_driver);
|
||||
#endif
|
||||
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
|
||||
i2c_del_driver(&wm8741_i2c_driver);
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
@ -751,6 +752,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
|
||||
.reg_cache_default = wm8750_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8750_of_match[] = {
|
||||
{ .compatible = "wlf,wm8750", },
|
||||
{ .compatible = "wlf,wm8987", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8750_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8750_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -787,8 +795,9 @@ MODULE_DEVICE_TABLE(spi, wm8750_spi_ids);
|
||||
|
||||
static struct spi_driver wm8750_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8750-codec",
|
||||
.name = "wm8750",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8750_of_match,
|
||||
},
|
||||
.id_table = wm8750_spi_ids,
|
||||
.probe = wm8750_spi_probe,
|
||||
@ -833,8 +842,9 @@ MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8750_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8750-codec",
|
||||
.name = "wm8750",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8750_of_match,
|
||||
},
|
||||
.probe = wm8750_i2c_probe,
|
||||
.remove = __devexit_p(wm8750_i2c_remove),
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
@ -1490,6 +1491,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8753 = {
|
||||
.reg_cache_default = wm8753_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8753_of_match[] = {
|
||||
{ .compatible = "wlf,wm8753", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8753_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8753_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -1519,8 +1526,9 @@ static int __devexit wm8753_spi_remove(struct spi_device *spi)
|
||||
|
||||
static struct spi_driver wm8753_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8753-codec",
|
||||
.name = "wm8753",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8753_of_match,
|
||||
},
|
||||
.probe = wm8753_spi_probe,
|
||||
.remove = __devexit_p(wm8753_spi_remove),
|
||||
@ -1563,8 +1571,9 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8753_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8753-codec",
|
||||
.name = "wm8753",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8753_of_match,
|
||||
},
|
||||
.probe = wm8753_i2c_probe,
|
||||
.remove = __devexit_p(wm8753_i2c_remove),
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
@ -684,6 +685,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8770 = {
|
||||
.reg_cache_default = wm8770_reg_defs
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8770_of_match[] = {
|
||||
{ .compatible = "wlf,wm8770", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8770_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8770_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -715,6 +722,7 @@ static struct spi_driver wm8770_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8770",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8770_of_match,
|
||||
},
|
||||
.probe = wm8770_spi_probe,
|
||||
.remove = __devexit_p(wm8770_spi_remove)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/slab.h>
|
||||
@ -215,8 +216,6 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
|
||||
int ratio_shift, master;
|
||||
int i;
|
||||
|
||||
iface = 0;
|
||||
|
||||
switch (dai->driver->id) {
|
||||
case WM8776_DAI_DAC:
|
||||
iface_reg = WM8776_DACIFCTRL;
|
||||
@ -232,20 +231,23 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
/* Set word length */
|
||||
switch (params_format(params)) {
|
||||
case SNDRV_PCM_FORMAT_S16_LE:
|
||||
switch (snd_pcm_format_width(params_format(params))) {
|
||||
case 16:
|
||||
iface = 0;
|
||||
case 20:
|
||||
iface = 0x10;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S20_3LE:
|
||||
iface |= 0x10;
|
||||
case 24:
|
||||
iface = 0x20;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S24_LE:
|
||||
iface |= 0x20;
|
||||
break;
|
||||
case SNDRV_PCM_FORMAT_S32_LE:
|
||||
iface |= 0x30;
|
||||
case 32:
|
||||
iface = 0x30;
|
||||
break;
|
||||
default:
|
||||
dev_err(codec->dev, "Unsupported sample size: %i\n",
|
||||
snd_pcm_format_width(params_format(params)));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Only need to set MCLK/LRCLK ratio if we're master */
|
||||
@ -320,11 +322,6 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WM8776_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\
|
||||
SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\
|
||||
SNDRV_PCM_RATE_96000)
|
||||
|
||||
|
||||
#define WM8776_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
|
||||
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
|
||||
|
||||
@ -349,7 +346,9 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
|
||||
.stream_name = "Playback",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = WM8776_RATES,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 32000,
|
||||
.rate_max = 192000,
|
||||
.formats = WM8776_FORMATS,
|
||||
},
|
||||
.ops = &wm8776_dac_ops,
|
||||
@ -361,7 +360,9 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
|
||||
.stream_name = "Capture",
|
||||
.channels_min = 2,
|
||||
.channels_max = 2,
|
||||
.rates = WM8776_RATES,
|
||||
.rates = SNDRV_PCM_RATE_CONTINUOUS,
|
||||
.rate_min = 32000,
|
||||
.rate_max = 96000,
|
||||
.formats = WM8776_FORMATS,
|
||||
},
|
||||
.ops = &wm8776_adc_ops,
|
||||
@ -452,6 +453,12 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
|
||||
.reg_cache_default = wm8776_reg,
|
||||
};
|
||||
|
||||
static const struct of_device_id wm8776_of_match[] = {
|
||||
{ .compatible = "wlf,wm8776", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, wm8776_of_match);
|
||||
|
||||
#if defined(CONFIG_SPI_MASTER)
|
||||
static int __devinit wm8776_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
@ -481,8 +488,9 @@ static int __devexit wm8776_spi_remove(struct spi_device *spi)
|
||||
|
||||
static struct spi_driver wm8776_spi_driver = {
|
||||
.driver = {
|
||||
.name = "wm8776-codec",
|
||||
.name = "wm8776",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8776_of_match,
|
||||
},
|
||||
.probe = wm8776_spi_probe,
|
||||
.remove = __devexit_p(wm8776_spi_remove),
|
||||
@ -525,8 +533,9 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id);
|
||||
|
||||
static struct i2c_driver wm8776_i2c_driver = {
|
||||
.driver = {
|
||||
.name = "wm8776-codec",
|
||||
.name = "wm8776",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = wm8776_of_match,
|
||||
},
|
||||
.probe = wm8776_i2c_probe,
|
||||
.remove = __devexit_p(wm8776_i2c_remove),
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user