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

Merge branch 'topic/asoc' into topic/remove-irqf_disable

* Freescale SGTL5000 Stereo Codec
Required properties:
- compatible : "fsl,sgtl5000".
Example:
codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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>;
};
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 @@ static int __devinit twl6040_probe(struct platform_device *pdev)
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
......
/*
* 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
/*
* 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;
......
......@@ -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
......@@ -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
/*
* 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");
/*
* 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");
/*
* 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 __init db1200_audio_load(void)
static int __devinit db1200_audio_probe(struct platform_device *pdev)
{
int ret;
const struct platform_device_id *pid = platform_get_device_id(pdev);
struct snd_soc_card *card;
ret = -ENOMEM;
db1200_asoc_dev = platform_device_alloc("soc-audio", 1); /* PSC1 */
if (!db1200_asoc_dev)
goto out;
card = db1200_cards[pid->driver_data];
card->dev = &pdev->dev;
return snd_soc_register_card(card);
}
/* 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);
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;
}
ret = platform_device_add(db1200_asoc_dev);
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),
};
if (ret) {
platform_device_put(db1200_asoc_dev);
db1200_asoc_dev = NULL;
}
out:
return ret;
static int __init db1200_audio_load(void)
{
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");
/*
* 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, IRQF_DISABLED,
&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");
/*
* 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));
......
/*
* 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
......@@ -128,7 +128,7 @@ static int snd_ad73311_configure(void)
return 0;
}
static int bf5xx_probe(struct platform_device *pdev)
static int bf5xx_probe(struct snd_soc_card *card)
{
int err;
if (gpio_request(GPIO_SE, "AD73311_SE")) {
......
/*
* 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 */
......
此差异已折叠。
#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;
}
......
......@@ -446,7 +446,6 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
gpio_free(data->power_gpio);
err_gpio:
kfree(data);
i2c_set_clientdata(tpa6130a2_client, NULL);
tpa6130a2_client = NULL;
return ret;
......
此差异已折叠。
......@@ -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),
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -83,6 +83,8 @@ struct wm8994_priv {
struct completion fll_locked[2];
bool fll_locked_irq;
int vmid_refcount;
int dac_rates[2];
int lrclk_shared[2];
......
此差异已折叠。
此差异已折叠。
......@@ -1120,8 +1120,8 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute)
return 0;
}
static int wm9081_set_sysclk(struct snd_soc_codec *codec,
int clk_id, unsigned int freq, int dir)
static int wm9081_set_sysclk(struct snd_soc_codec *codec, int clk_id,
int source, unsigned int freq, int dir)
{
struct wm9081_priv *wm9081 = snd_soc_codec_get_drvdata(codec);
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册