Merge branch 'topic/asoc' into for-linus

This commit is contained in:
Takashi Iwai 2011-10-27 10:43:40 +02:00
commit bb14eb0da7
186 changed files with 15231 additions and 3461 deletions

View File

@ -530,6 +530,7 @@ S: Maintained
F: drivers/infiniband/hw/amso1100/ F: drivers/infiniband/hw/amso1100/
ANALOG DEVICES INC ASOC CODEC DRIVERS ANALOG DEVICES INC ASOC CODEC DRIVERS
M: Lars-Peter Clausen <lars@metafoo.de>
L: device-drivers-devel@blackfin.uclinux.org L: device-drivers-devel@blackfin.uclinux.org
L: alsa-devel@alsa-project.org (moderated for non-subscribers) L: alsa-devel@alsa-project.org (moderated for non-subscribers)
W: http://wiki.analog.com/ W: http://wiki.analog.com/
@ -7199,6 +7200,7 @@ T: git git://opensource.wolfsonmicro.com/linux-2.6-audioplus
W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices W: http://opensource.wolfsonmicro.com/content/linux-drivers-wolfson-devices
S: Supported S: Supported
F: Documentation/hwmon/wm83?? F: Documentation/hwmon/wm83??
F: arch/arm/mach-s3c64xx/mach-crag6410*
F: drivers/leds/leds-wm83*.c F: drivers/leds/leds-wm83*.c
F: drivers/input/misc/wm831x-on.c F: drivers/input/misc/wm831x-on.c
F: drivers/input/touchscreen/wm831x-ts.c F: drivers/input/touchscreen/wm831x-ts.c

View File

@ -900,7 +900,6 @@ static struct twl4030_platform_data rx51_twldata __initdata = {
}; };
static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata_or_module = { static struct tpa6130a2_platform_data rx51_tpa6130a2_data __initdata_or_module = {
.id = TPA6130A2,
.power_gpio = 98, .power_gpio = 98,
}; };

View File

@ -330,6 +330,38 @@ static void omap_init_audio(void)
static inline void omap_init_audio(void) {} static inline void omap_init_audio(void) {}
#endif #endif
#if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \
defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE)
static struct omap_device_pm_latency omap_mcpdm_latency[] = {
{
.deactivate_func = omap_device_idle_hwmods,
.activate_func = omap_device_enable_hwmods,
.flags = OMAP_DEVICE_LATENCY_AUTO_ADJUST,
},
};
static void omap_init_mcpdm(void)
{
struct omap_hwmod *oh;
struct omap_device *od;
oh = omap_hwmod_lookup("mcpdm");
if (!oh) {
printk(KERN_ERR "Could not look up mcpdm hw_mod\n");
return;
}
od = omap_device_build("omap-mcpdm", -1, oh, NULL, 0,
omap_mcpdm_latency,
ARRAY_SIZE(omap_mcpdm_latency), 0);
if (IS_ERR(od))
printk(KERN_ERR "Could not build omap_device for omap-mcpdm-dai\n");
}
#else
static inline void omap_init_mcpdm(void) {}
#endif
#if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE) #if defined(CONFIG_SPI_OMAP24XX) || defined(CONFIG_SPI_OMAP24XX_MODULE)
#include <plat/mcspi.h> #include <plat/mcspi.h>
@ -683,6 +715,7 @@ static int __init omap2_init_devices(void)
* in alphabetical order so they're easier to sort through. * in alphabetical order so they're easier to sort through.
*/ */
omap_init_audio(); omap_init_audio();
omap_init_mcpdm();
omap_init_camera(); omap_init_camera();
omap_init_mbox(); omap_init_mbox();
omap_init_mcspi(); omap_init_mcspi();

View File

@ -5430,7 +5430,7 @@ static __initdata struct omap_hwmod *omap44xx_hwmods[] = {
&omap44xx_mcbsp4_hwmod, &omap44xx_mcbsp4_hwmod,
/* mcpdm class */ /* mcpdm class */
/* &omap44xx_mcpdm_hwmod, */ &omap44xx_mcpdm_hwmod,
/* mcspi class */ /* mcspi class */
&omap44xx_mcspi1_hwmod, &omap44xx_mcspi1_hwmod,

View File

@ -74,41 +74,6 @@ void omap_mcbsp_register_board_cfg(struct resource *res, int res_count,
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
#if defined(CONFIG_SND_OMAP_SOC_MCPDM) || \
defined(CONFIG_SND_OMAP_SOC_MCPDM_MODULE)
static struct resource mcpdm_resources[] = {
{
.name = "mcpdm_mem",
.start = OMAP44XX_MCPDM_BASE,
.end = OMAP44XX_MCPDM_BASE + SZ_4K,
.flags = IORESOURCE_MEM,
},
{
.name = "mcpdm_irq",
.start = OMAP44XX_IRQ_MCPDM,
.end = OMAP44XX_IRQ_MCPDM,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device omap_mcpdm_device = {
.name = "omap-mcpdm",
.id = -1,
.num_resources = ARRAY_SIZE(mcpdm_resources),
.resource = mcpdm_resources,
};
static void omap_init_mcpdm(void)
{
(void) platform_device_register(&omap_mcpdm_device);
}
#else
static inline void omap_init_mcpdm(void) {}
#endif
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ #if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \
defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)
@ -291,7 +256,6 @@ static int __init omap_init_devices(void)
* in alphabetical order so they're easier to sort through. * in alphabetical order so they're easier to sort through.
*/ */
omap_init_rng(); omap_init_rng();
omap_init_mcpdm();
omap_init_uwire(); omap_init_uwire();
return 0; return 0;
} }

View File

@ -74,12 +74,12 @@ static irqreturn_t twl6040_vib_irq_handler(int irq, void *data)
if (status & TWL6040_VIBLOCDET) { if (status & TWL6040_VIBLOCDET) {
dev_warn(info->dev, "Left Vibrator overcurrent detected\n"); dev_warn(info->dev, "Left Vibrator overcurrent detected\n");
twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL, twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLL,
TWL6040_VIBENAL); TWL6040_VIBENA);
} }
if (status & TWL6040_VIBROCDET) { if (status & TWL6040_VIBROCDET) {
dev_warn(info->dev, "Right Vibrator overcurrent detected\n"); dev_warn(info->dev, "Right Vibrator overcurrent detected\n");
twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR, twl6040_clear_bits(twl6040, TWL6040_REG_VIBCTLR,
TWL6040_VIBENAR); TWL6040_VIBENA);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
@ -104,16 +104,16 @@ static void twl6040_vibra_enable(struct vibra_info *info)
* overcurrent detection * overcurrent detection
*/ */
twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
TWL6040_VIBENAL | TWL6040_VIBCTRLL); TWL6040_VIBENA | TWL6040_VIBCTRL);
twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
TWL6040_VIBENAR | TWL6040_VIBCTRLR); TWL6040_VIBENA | TWL6040_VIBCTRL);
usleep_range(3000, 3500); usleep_range(3000, 3500);
} }
twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL, twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLL,
TWL6040_VIBENAL); TWL6040_VIBENA);
twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR, twl6040_reg_write(twl6040, TWL6040_REG_VIBCTLR,
TWL6040_VIBENAR); TWL6040_VIBENA);
info->enabled = true; info->enabled = true;
} }
@ -201,6 +201,13 @@ static int vibra_play(struct input_dev *input, void *data,
struct vibra_info *info = input_get_drvdata(input); struct vibra_info *info = input_get_drvdata(input);
int ret; int ret;
/* Do not allow effect, while the routing is set to use audio */
ret = twl6040_get_vibralr_status(info->twl6040);
if (ret & TWL6040_VIBSEL) {
dev_info(&input->dev, "Vibra is configured for audio\n");
return -EBUSY;
}
info->weak_speed = effect->u.rumble.weak_magnitude; info->weak_speed = effect->u.rumble.weak_magnitude;
info->strong_speed = effect->u.rumble.strong_magnitude; info->strong_speed = effect->u.rumble.strong_magnitude;
info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1; info->direction = effect->direction < EFFECT_DIR_180_DEG ? 1 : -1;

View File

@ -34,17 +34,25 @@
#include <linux/mfd/core.h> #include <linux/mfd/core.h>
#include <linux/mfd/twl6040.h> #include <linux/mfd/twl6040.h>
#define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg) int twl6040_reg_read(struct twl6040 *twl6040, unsigned int reg)
{ {
int ret; int ret;
u8 val = 0; u8 val = 0;
mutex_lock(&twl6040->io_mutex); mutex_lock(&twl6040->io_mutex);
/* Vibra control registers from cache */
if (unlikely(reg == TWL6040_REG_VIBCTLL ||
reg == TWL6040_REG_VIBCTLR)) {
val = twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)];
} else {
ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg); ret = twl_i2c_read_u8(TWL_MODULE_AUDIO_VOICE, &val, reg);
if (ret < 0) { if (ret < 0) {
mutex_unlock(&twl6040->io_mutex); mutex_unlock(&twl6040->io_mutex);
return ret; return ret;
} }
}
mutex_unlock(&twl6040->io_mutex); mutex_unlock(&twl6040->io_mutex);
return val; return val;
@ -57,6 +65,9 @@ int twl6040_reg_write(struct twl6040 *twl6040, unsigned int reg, u8 val)
mutex_lock(&twl6040->io_mutex); mutex_lock(&twl6040->io_mutex);
ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg); ret = twl_i2c_write_u8(TWL_MODULE_AUDIO_VOICE, val, reg);
/* Cache the vibra control registers */
if (reg == TWL6040_REG_VIBCTLL || reg == TWL6040_REG_VIBCTLR)
twl6040->vibra_ctrl_cache[VIBRACTRL_MEMBER(reg)] = val;
mutex_unlock(&twl6040->io_mutex); mutex_unlock(&twl6040->io_mutex);
return ret; return ret;
@ -433,6 +444,18 @@ unsigned int twl6040_get_sysclk(struct twl6040 *twl6040)
} }
EXPORT_SYMBOL(twl6040_get_sysclk); EXPORT_SYMBOL(twl6040_get_sysclk);
/* Get the combined status of the vibra control register */
int twl6040_get_vibralr_status(struct twl6040 *twl6040)
{
u8 status;
status = twl6040->vibra_ctrl_cache[0] | twl6040->vibra_ctrl_cache[1];
status &= (TWL6040_VIBENA | TWL6040_VIBSEL);
return status;
}
EXPORT_SYMBOL(twl6040_get_vibralr_status);
static struct resource twl6040_vibra_rsrc[] = { static struct resource twl6040_vibra_rsrc[] = {
{ {
.flags = IORESOURCE_IRQ, .flags = IORESOURCE_IRQ,

View File

@ -243,6 +243,18 @@ static struct mfd_cell wm8994_devs[] = {
* and should be handled via the standard regulator API supply * and should be handled via the standard regulator API supply
* management. * management.
*/ */
static const char *wm1811_main_supplies[] = {
"DBVDD1",
"DBVDD2",
"DBVDD3",
"DCVDD",
"AVDD1",
"AVDD2",
"CPVDD",
"SPKVDD1",
"SPKVDD2",
};
static const char *wm8994_main_supplies[] = { static const char *wm8994_main_supplies[] = {
"DBVDD", "DBVDD",
"DCVDD", "DCVDD",
@ -401,6 +413,9 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
} }
switch (wm8994->type) { switch (wm8994->type) {
case WM1811:
wm8994->num_supplies = ARRAY_SIZE(wm1811_main_supplies);
break;
case WM8994: case WM8994:
wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies); wm8994->num_supplies = ARRAY_SIZE(wm8994_main_supplies);
break; break;
@ -421,6 +436,10 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
} }
switch (wm8994->type) { switch (wm8994->type) {
case WM1811:
for (i = 0; i < ARRAY_SIZE(wm1811_main_supplies); i++)
wm8994->supplies[i].supply = wm1811_main_supplies[i];
break;
case WM8994: case WM8994:
for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++) for (i = 0; i < ARRAY_SIZE(wm8994_main_supplies); i++)
wm8994->supplies[i].supply = wm8994_main_supplies[i]; wm8994->supplies[i].supply = wm8994_main_supplies[i];
@ -454,6 +473,13 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
goto err_enable; goto err_enable;
} }
switch (ret) { switch (ret) {
case 0x1811:
devname = "WM1811";
if (wm8994->type != WM1811)
dev_warn(wm8994->dev, "Device registered as type %d\n",
wm8994->type);
wm8994->type = WM1811;
break;
case 0x8994: case 0x8994:
devname = "WM8994"; devname = "WM8994";
if (wm8994->type != WM8994) if (wm8994->type != WM8994)
@ -651,6 +677,7 @@ static int wm8994_i2c_remove(struct i2c_client *i2c)
} }
static const struct i2c_device_id wm8994_i2c_id[] = { static const struct i2c_device_id wm8994_i2c_id[] = {
{ "wm1811", WM1811 },
{ "wm8994", WM8994 }, { "wm8994", WM8994 },
{ "wm8958", WM8958 }, { "wm8958", WM8958 },
{ } { }

View File

@ -1599,13 +1599,18 @@ static void regulator_disable_work(struct work_struct *work)
int regulator_disable_deferred(struct regulator *regulator, int ms) int regulator_disable_deferred(struct regulator *regulator, int ms)
{ {
struct regulator_dev *rdev = regulator->rdev; struct regulator_dev *rdev = regulator->rdev;
int ret;
mutex_lock(&rdev->mutex); mutex_lock(&rdev->mutex);
rdev->deferred_disables++; rdev->deferred_disables++;
mutex_unlock(&rdev->mutex); mutex_unlock(&rdev->mutex);
return schedule_delayed_work(&rdev->disable_work, ret = schedule_delayed_work(&rdev->disable_work,
msecs_to_jiffies(ms)); msecs_to_jiffies(ms));
if (ret < 0)
return ret;
else
return 0;
} }
EXPORT_SYMBOL_GPL(regulator_disable_deferred); EXPORT_SYMBOL_GPL(regulator_disable_deferred);

View File

@ -140,6 +140,14 @@ static int wm8994_ldo2_list_voltage(struct regulator_dev *rdev,
return (selector * 100000) + 900000; return (selector * 100000) + 900000;
case WM8958: case WM8958:
return (selector * 100000) + 1000000; return (selector * 100000) + 1000000;
case WM1811:
switch (selector) {
case 0:
return -EINVAL;
default:
return (selector * 100000) + 950000;
}
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -170,6 +178,11 @@ static int wm8994_ldo2_set_voltage(struct regulator_dev *rdev,
case WM8958: case WM8958:
selector = (min_uV - 1000000) / 100000; selector = (min_uV - 1000000) / 100000;
break; break;
case WM1811:
selector = (min_uV - 950000) / 100000;
if (selector == 0)
selector = 1;
break;
default: default:
return -EINVAL; return -EINVAL;
} }

View File

@ -68,8 +68,6 @@
#define TWL6040_REG_ACCCTL 0x2D #define TWL6040_REG_ACCCTL 0x2D
#define TWL6040_REG_STATUS 0x2E #define TWL6040_REG_STATUS 0x2E
#define TWL6040_CACHEREGNUM (TWL6040_REG_STATUS + 1)
/* INTID (0x03) fields */ /* INTID (0x03) fields */
#define TWL6040_THINT 0x01 #define TWL6040_THINT 0x01
@ -122,34 +120,24 @@
#define TWL6040_LPLLFIN 0x08 #define TWL6040_LPLLFIN 0x08
#define TWL6040_HPLLSEL 0x10 #define TWL6040_HPLLSEL 0x10
/* HSLCTL (0x10) fields */ /* HSLCTL/R (0x10/0x11) fields */
#define TWL6040_HSDACMODEL 0x02 #define TWL6040_HSDACENA (1 << 0)
#define TWL6040_HSDRVMODEL 0x08 #define TWL6040_HSDACMODE (1 << 1)
#define TWL6040_HSDRVMODE (1 << 3)
/* HSRCTL (0x11) fields */ /* VIBCTLL/R (0x18/0x1A) fields */
#define TWL6040_HSDACMODER 0x02 #define TWL6040_VIBENA (1 << 0)
#define TWL6040_HSDRVMODER 0x08 #define TWL6040_VIBSEL (1 << 1)
#define TWL6040_VIBCTRL (1 << 2)
#define TWL6040_VIBCTRL_P (1 << 3)
#define TWL6040_VIBCTRL_N (1 << 4)
/* VIBCTLL (0x18) fields */ /* VIBDATL/R (0x19/0x1B) fields */
#define TWL6040_VIBENAL 0x01
#define TWL6040_VIBCTRLL 0x04
#define TWL6040_VIBCTRLLP 0x08
#define TWL6040_VIBCTRLLN 0x10
/* VIBDATL (0x19) fields */
#define TWL6040_VIBDAT_MAX 0x64 #define TWL6040_VIBDAT_MAX 0x64
/* VIBCTLR (0x1A) fields */
#define TWL6040_VIBENAR 0x01
#define TWL6040_VIBCTRLR 0x04
#define TWL6040_VIBCTRLRP 0x08
#define TWL6040_VIBCTRLRN 0x10
/* GPOCTL (0x1E) fields */ /* GPOCTL (0x1E) fields */
#define TWL6040_GPO1 0x01 #define TWL6040_GPO1 0x01
@ -197,6 +185,7 @@ struct twl6040 {
int audpwron; int audpwron;
int power_count; int power_count;
int rev; int rev;
u8 vibra_ctrl_cache[2];
int pll; int pll;
unsigned int sysclk; unsigned int sysclk;
@ -221,10 +210,13 @@ int twl6040_get_pll(struct twl6040 *twl6040);
unsigned int twl6040_get_sysclk(struct twl6040 *twl6040); unsigned int twl6040_get_sysclk(struct twl6040 *twl6040);
int twl6040_irq_init(struct twl6040 *twl6040); int twl6040_irq_init(struct twl6040 *twl6040);
void twl6040_irq_exit(struct twl6040 *twl6040); void twl6040_irq_exit(struct twl6040 *twl6040);
/* Get the combined status of the vibra control register */
int twl6040_get_vibralr_status(struct twl6040 *twl6040);
static inline int twl6040_get_revid(struct twl6040 *twl6040) static inline int twl6040_get_revid(struct twl6040 *twl6040)
{ {
return twl6040->rev; return twl6040->rev;
} }
#endif /* End of __TWL6040_CODEC_H__ */ #endif /* End of __TWL6040_CODEC_H__ */

View File

@ -20,6 +20,7 @@
enum wm8994_type { enum wm8994_type {
WM8994 = 0, WM8994 = 0,
WM8958 = 1, WM8958 = 1,
WM1811 = 2,
}; };
struct regulator_dev; struct regulator_dev;

View File

@ -2069,6 +2069,10 @@
/* /*
* R96 (0x60) - Analogue HP (1) * R96 (0x60) - Analogue HP (1)
*/ */
#define WM1811_HPOUT1_ATTN 0x0100 /* HPOUT1_ATTN */
#define WM1811_HPOUT1_ATTN_MASK 0x0100 /* HPOUT1_ATTN */
#define WM1811_HPOUT1_ATTN_SHIFT 8 /* HPOUT1_ATTN */
#define WM1811_HPOUT1_ATTN_WIDTH 1 /* HPOUT1_ATTN */
#define WM8994_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */ #define WM8994_HPOUT1L_RMV_SHORT 0x0080 /* HPOUT1L_RMV_SHORT */
#define WM8994_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */ #define WM8994_HPOUT1L_RMV_SHORT_MASK 0x0080 /* HPOUT1L_RMV_SHORT */
#define WM8994_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */ #define WM8994_HPOUT1L_RMV_SHORT_SHIFT 7 /* HPOUT1L_RMV_SHORT */

View File

@ -24,13 +24,13 @@ struct snd_pcm_substream;
* Describes the physical PCM data formating and clocking. Add new formats * Describes the physical PCM data formating and clocking. Add new formats
* to the end. * to the end.
*/ */
#define SND_SOC_DAIFMT_I2S 0 /* I2S mode */ #define SND_SOC_DAIFMT_I2S 1 /* I2S mode */
#define SND_SOC_DAIFMT_RIGHT_J 1 /* Right Justified mode */ #define SND_SOC_DAIFMT_RIGHT_J 2 /* Right Justified mode */
#define SND_SOC_DAIFMT_LEFT_J 2 /* Left Justified mode */ #define SND_SOC_DAIFMT_LEFT_J 3 /* Left Justified mode */
#define SND_SOC_DAIFMT_DSP_A 3 /* L data MSB after FRM LRC */ #define SND_SOC_DAIFMT_DSP_A 4 /* L data MSB after FRM LRC */
#define SND_SOC_DAIFMT_DSP_B 4 /* L data MSB during FRM LRC */ #define SND_SOC_DAIFMT_DSP_B 5 /* L data MSB during FRM LRC */
#define SND_SOC_DAIFMT_AC97 5 /* AC97 */ #define SND_SOC_DAIFMT_AC97 6 /* AC97 */
#define SND_SOC_DAIFMT_PDM 6 /* Pulse density modulation */ #define SND_SOC_DAIFMT_PDM 7 /* Pulse density modulation */
/* left and right justified also known as MSB and LSB respectively */ /* left and right justified also known as MSB and LSB respectively */
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J #define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
@ -42,8 +42,8 @@ struct snd_pcm_substream;
* DAI bit clocks can be be gated (disabled) when the DAI is not * DAI bit clocks can be be gated (disabled) when the DAI is not
* sending or receiving PCM data in a frame. This can be used to save power. * sending or receiving PCM data in a frame. This can be used to save power.
*/ */
#define SND_SOC_DAIFMT_CONT (0 << 4) /* continuous clock */ #define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */
#define SND_SOC_DAIFMT_GATED (1 << 4) /* clock is gated */ #define SND_SOC_DAIFMT_GATED (2 << 4) /* clock is gated */
/* /*
* DAI hardware signal inversions. * DAI hardware signal inversions.
@ -51,10 +51,10 @@ struct snd_pcm_substream;
* Specifies whether the DAI can also support inverted clocks for the specified * Specifies whether the DAI can also support inverted clocks for the specified
* format. * format.
*/ */
#define SND_SOC_DAIFMT_NB_NF (0 << 8) /* normal bit clock + frame */ #define SND_SOC_DAIFMT_NB_NF (1 << 8) /* normal bit clock + frame */
#define SND_SOC_DAIFMT_NB_IF (1 << 8) /* normal BCLK + inv FRM */ #define SND_SOC_DAIFMT_NB_IF (2 << 8) /* normal BCLK + inv FRM */
#define SND_SOC_DAIFMT_IB_NF (2 << 8) /* invert BCLK + nor FRM */ #define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF (3 << 8) /* invert BCLK + FRM */ #define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */
/* /*
* DAI hardware clock masters. * DAI hardware clock masters.
@ -63,10 +63,10 @@ struct snd_pcm_substream;
* i.e. if the codec is clk and FRM master then the interface is * i.e. if the codec is clk and FRM master then the interface is
* clk and frame slave. * clk and frame slave.
*/ */
#define SND_SOC_DAIFMT_CBM_CFM (0 << 12) /* codec clk & FRM master */ #define SND_SOC_DAIFMT_CBM_CFM (1 << 12) /* codec clk & FRM master */
#define SND_SOC_DAIFMT_CBS_CFM (1 << 12) /* codec clk slave & FRM master */ #define SND_SOC_DAIFMT_CBS_CFM (2 << 12) /* codec clk slave & FRM master */
#define SND_SOC_DAIFMT_CBM_CFS (2 << 12) /* codec clk master & frame slave */ #define SND_SOC_DAIFMT_CBM_CFS (3 << 12) /* codec clk master & frame slave */
#define SND_SOC_DAIFMT_CBS_CFS (3 << 12) /* codec clk & FRM slave */ #define SND_SOC_DAIFMT_CBS_CFS (4 << 12) /* codec clk & FRM slave */
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f #define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0 #define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
@ -242,6 +242,9 @@ struct snd_soc_dai {
void *playback_dma_data; void *playback_dma_data;
void *capture_dma_data; void *capture_dma_data;
/* Symmetry data - only valid if symmetry is being enforced */
unsigned int rate;
/* parent platform/codec */ /* parent platform/codec */
union { union {
struct snd_soc_platform *platform; struct snd_soc_platform *platform;

View File

@ -381,6 +381,9 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm,
int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm, int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
const char *pin); const char *pin);
/* Mostly internal - should not normally be used */
void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason);
/* dapm widget types */ /* dapm widget types */
enum snd_soc_dapm_type { enum snd_soc_dapm_type {
snd_soc_dapm_input = 0, /* input pin */ snd_soc_dapm_input = 0, /* input pin */
@ -473,6 +476,8 @@ struct snd_soc_dapm_widget {
unsigned char ext:1; /* has external widgets */ unsigned char ext:1; /* has external widgets */
unsigned char force:1; /* force state */ unsigned char force:1; /* force state */
unsigned char ignore_suspend:1; /* kept enabled over suspend */ unsigned char ignore_suspend:1; /* kept enabled over suspend */
unsigned char new_power:1; /* power from this run */
unsigned char power_checked:1; /* power checked this run */
int subseq; /* sort within widget type */ int subseq; /* sort within widget type */
int (*power_check)(struct snd_soc_dapm_widget *w); int (*power_check)(struct snd_soc_dapm_widget *w);
@ -492,6 +497,9 @@ struct snd_soc_dapm_widget {
/* used during DAPM updates */ /* used during DAPM updates */
struct list_head power_list; struct list_head power_list;
struct list_head dirty;
int inputs;
int outputs;
}; };
struct snd_soc_dapm_update { struct snd_soc_dapm_update {
@ -537,4 +545,10 @@ struct snd_soc_dapm_widget_list {
struct snd_soc_dapm_widget *widgets[0]; struct snd_soc_dapm_widget *widgets[0];
}; };
struct snd_soc_dapm_stats {
int power_checks;
int path_checks;
int neighbour_checks;
};
#endif #endif

View File

@ -28,13 +28,20 @@
/* /*
* Convenience kcontrol builders * Convenience kcontrol builders
*/ */
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \ #define SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \ ((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \ {.reg = xreg, .rreg = xreg, .shift = shift_left, \
.platform_max = xmax, .invert = xinvert}) .rshift = shift_right, .max = xmax, .platform_max = xmax, \
.invert = xinvert})
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) \
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert)
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \ #define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \ ((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert}) {.reg = xreg, .max = xmax, .platform_max = xmax, .invert = xinvert})
#define SOC_DOUBLE_R_VALUE(xlreg, xrreg, xshift, xmax, xinvert) \
((unsigned long)&(struct soc_mixer_control) \
{.reg = xlreg, .rreg = xrreg, .shift = xshift, .rshift = xshift, \
.max = xmax, .platform_max = xmax, .invert = xinvert})
#define SOC_SINGLE(xname, reg, shift, max, invert) \ #define SOC_SINGLE(xname, reg, shift, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
@ -48,40 +55,36 @@
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) } .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
#define SOC_DOUBLE(xname, xreg, shift_left, shift_right, xmax, xinvert) \ #define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
{.reg = xreg, .shift = shift_left, .rshift = shift_right, \ max, invert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \ #define SOC_DOUBLE_R(xname, reg_left, reg_right, xshift, xmax, xinvert) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.info = snd_soc_info_volsw_2r, \ .info = snd_soc_info_volsw, \
.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \ xmax, xinvert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} } #define SOC_DOUBLE_TLV(xname, reg, shift_left, shift_right, max, invert, tlv_array) \
#define SOC_DOUBLE_TLV(xname, xreg, shift_left, shift_right, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
.put = snd_soc_put_volsw, \ .put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = SOC_DOUBLE_VALUE(reg, shift_left, shift_right, \
{.reg = xreg, .shift = shift_left, .rshift = shift_right,\ max, invert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \ #define SOC_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\ SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_2r, \ .info = snd_soc_info_volsw, \
.get = snd_soc_get_volsw_2r, .put = snd_soc_put_volsw_2r, \ .get = snd_soc_get_volsw, .put = snd_soc_put_volsw, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \ xmax, xinvert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \ #define SOC_DOUBLE_S8_TLV(xname, xreg, xmin, xmax, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
@ -121,14 +124,13 @@
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) } .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert) }
#define SOC_DOUBLE_EXT(xname, xreg, shift_left, shift_right, xmax, xinvert,\ #define SOC_DOUBLE_EXT(xname, reg, shift_left, shift_right, max, invert,\
xhandler_get, xhandler_put) \ xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = \
{.reg = xreg, .shift = shift_left, .rshift = shift_right, \ SOC_DOUBLE_VALUE(reg, shift_left, shift_right, max, invert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\ #define SOC_SINGLE_EXT_TLV(xname, xreg, xshift, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \ xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@ -146,20 +148,18 @@
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = SOC_DOUBLE_VALUE(xreg, shift_left, shift_right, \
{.reg = xreg, .shift = shift_left, .rshift = shift_right, \ xmax, xinvert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\ #define SOC_DOUBLE_R_EXT_TLV(xname, reg_left, reg_right, xshift, xmax, xinvert,\
xhandler_get, xhandler_put, tlv_array) \ xhandler_get, xhandler_put, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \ .tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_2r, \ .info = snd_soc_info_volsw, \
.get = xhandler_get, .put = xhandler_put, \ .get = xhandler_get, .put = xhandler_put, \
.private_value = (unsigned long)&(struct soc_mixer_control) \ .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \ xmax, xinvert) }
.max = xmax, .platform_max = xmax, .invert = xinvert} }
#define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \ #define SOC_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_bool_ext, \ .info = snd_soc_info_bool_ext, \
@ -393,12 +393,8 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol); struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw_2r(struct snd_kcontrol *kcontrol, #define snd_soc_get_volsw_2r snd_soc_get_volsw
struct snd_ctl_elem_info *uinfo); #define snd_soc_put_volsw_2r snd_soc_put_volsw
int snd_soc_get_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_2r(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol, int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo); struct snd_ctl_elem_info *uinfo);
int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol, int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
@ -582,6 +578,7 @@ struct snd_soc_codec {
/* dapm */ /* dapm */
struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context dapm;
unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root; struct dentry *debugfs_codec_root;
@ -713,6 +710,8 @@ struct snd_soc_dai_link {
const char *cpu_dai_name; const char *cpu_dai_name;
const char *codec_dai_name; const char *codec_dai_name;
unsigned int dai_fmt; /* format to set on init */
/* Keep DAI active over suspend */ /* Keep DAI active over suspend */
unsigned int ignore_suspend:1; unsigned int ignore_suspend:1;
@ -825,9 +824,11 @@ struct snd_soc_card {
struct list_head widgets; struct list_head widgets;
struct list_head paths; struct list_head paths;
struct list_head dapm_list; struct list_head dapm_list;
struct list_head dapm_dirty;
/* Generic DAPM context for the card */ /* Generic DAPM context for the card */
struct snd_soc_dapm_context dapm; struct snd_soc_dapm_context dapm;
struct snd_soc_dapm_stats dapm_stats;
#ifdef CONFIG_DEBUG_FS #ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_card_root; struct dentry *debugfs_card_root;
@ -850,8 +851,6 @@ struct snd_soc_pcm_runtime {
unsigned int complete:1; unsigned int complete:1;
unsigned int dev_registered:1; unsigned int dev_registered:1;
/* Symmetry data - only valid if symmetry is being enforced */
unsigned int rate;
long pmdown_time; long pmdown_time;
/* runtime devices */ /* runtime devices */
@ -946,6 +945,18 @@ static inline void snd_soc_initialize_card_lists(struct snd_soc_card *card)
INIT_LIST_HEAD(&card->dapm_list); INIT_LIST_HEAD(&card->dapm_list);
} }
static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc)
{
if (mc->reg == mc->rreg && mc->shift == mc->rshift)
return 0;
/*
* mc->reg == mc->rreg && mc->shift != mc->rshift, or
* mc->reg != mc->rreg means that the control is
* stereo (bits in one register or in two registers)
*/
return 1;
}
int snd_soc_util_init(void); int snd_soc_util_init(void);
void snd_soc_util_exit(void); void snd_soc_util_exit(void);

View File

@ -23,13 +23,7 @@
#ifndef TPA6130A2_PLAT_H #ifndef TPA6130A2_PLAT_H
#define TPA6130A2_PLAT_H #define TPA6130A2_PLAT_H
enum tpa_model {
TPA6130A2,
TPA6140A2,
};
struct tpa6130a2_platform_data { struct tpa6130a2_platform_data {
enum tpa_model id;
int power_gpio; int power_gpio;
}; };

View File

@ -0,0 +1,27 @@
/*
* linux/sound/wm1250-ev1.h - Platform data for WM1250-EV1
*
* Copyright 2011 Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_WM1250_EV1_H
#define __LINUX_SND_WM1250_EV1_H
#define WM1250_EV1_NUM_GPIOS 5
#define WM1250_EV1_GPIO_CLK_ENA 0
#define WM1250_EV1_GPIO_CLK_SEL0 1
#define WM1250_EV1_GPIO_CLK_SEL1 2
#define WM1250_EV1_GPIO_OSR 3
#define WM1250_EV1_GPIO_MASTER 4
struct wm1250_ev1_pdata {
int gpios[WM1250_EV1_NUM_GPIOS];
};
#endif

59
include/sound/wm5100.h Normal file
View File

@ -0,0 +1,59 @@
/*
* linux/sound/wm5100.h -- Platform data for WM5100
*
* Copyright 2011 Wolfson Microelectronics. PLC.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __LINUX_SND_WM5100_H
#define __LINUX_SND_WM5100_H
enum wm5100_in_mode {
WM5100_IN_SE = 0,
WM5100_IN_DIFF = 1,
WM5100_IN_DMIC = 2,
};
enum wm5100_dmic_sup {
WM5100_DMIC_SUP_MICVDD = 0,
WM5100_DMIC_SUP_MICBIAS1 = 1,
WM5100_DMIC_SUP_MICBIAS2 = 2,
WM5100_DMIC_SUP_MICBIAS3 = 3,
};
enum wm5100_micdet_bias {
WM5100_MICDET_MICBIAS1 = 0,
WM5100_MICDET_MICBIAS2 = 1,
WM5100_MICDET_MICBIAS3 = 2,
};
struct wm5100_jack_mode {
enum wm5100_micdet_bias bias;
int hp_pol;
int micd_src;
};
#define WM5100_GPIO_SET 0x10000
struct wm5100_pdata {
int reset; /** GPIO controlling /RESET, if any */
int ldo_ena; /** GPIO controlling LODENA, if any */
int hp_pol; /** GPIO controlling headset polarity, if any */
int irq_flags;
int gpio_base;
struct wm5100_jack_mode jack_modes[2];
/* Input pin mode selection */
enum wm5100_in_mode in_mode[4];
/* DMIC supply selection */
enum wm5100_dmic_sup dmic_sup[4];
int gpio_defaults[6];
};
#endif

View File

@ -216,6 +216,31 @@ DEFINE_EVENT(snd_soc_dapm_widget, snd_soc_dapm_widget_event_done,
); );
TRACE_EVENT(snd_soc_dapm_walk_done,
TP_PROTO(struct snd_soc_card *card),
TP_ARGS(card),
TP_STRUCT__entry(
__string( name, card->name )
__field( int, power_checks )
__field( int, path_checks )
__field( int, neighbour_checks )
),
TP_fast_assign(
__assign_str(name, card->name);
__entry->power_checks = card->dapm_stats.power_checks;
__entry->path_checks = card->dapm_stats.path_checks;
__entry->neighbour_checks = card->dapm_stats.neighbour_checks;
),
TP_printk("%s: checks %d power, %d path, %d neighbour",
__get_str(name), (int)__entry->power_checks,
(int)__entry->path_checks, (int)__entry->neighbour_checks)
);
TRACE_EVENT(snd_soc_jack_irq, TRACE_EVENT(snd_soc_jack_irq,
TP_PROTO(const char *name), TP_PROTO(const char *name),

View File

@ -338,7 +338,6 @@ static int playpaq_wm8510_init(struct snd_soc_pcm_runtime *rtd)
/* always connected pins */ /* always connected pins */
snd_soc_dapm_enable_pin(dapm, "Int Mic"); snd_soc_dapm_enable_pin(dapm, "Int Mic");
snd_soc_dapm_enable_pin(dapm, "Ext Spk"); snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_sync(dapm);

View File

@ -173,8 +173,6 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd)
/* always connected */ /* always connected */
snd_soc_dapm_enable_pin(dapm, "Ext Spk"); snd_soc_dapm_enable_pin(dapm, "Ext Spk");
snd_soc_dapm_sync(dapm);
return 0; return 0;
} }

View File

@ -117,8 +117,6 @@ static int afeb9260_tlv320aic23_init(struct snd_soc_pcm_runtime *rtd)
snd_soc_dapm_enable_pin(dapm, "Line In"); snd_soc_dapm_enable_pin(dapm, "Line In");
snd_soc_dapm_enable_pin(dapm, "Mic Jack"); snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_sync(dapm);
return 0; return 0;
} }

View File

@ -226,7 +226,7 @@ static struct snd_soc_dai_driver au1xac97c_dai_driver = {
static int __devinit au1xac97c_drvprobe(struct platform_device *pdev) static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
{ {
int ret; int ret;
struct resource *r; struct resource *iores, *dmares;
struct au1xpsc_audio_data *ctx; struct au1xpsc_audio_data *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@ -235,29 +235,30 @@ static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
mutex_init(&ctx->lock); mutex_init(&ctx->lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!iores) {
ret = -ENODEV; ret = -ENODEV;
goto out0; goto out0;
} }
ret = -EBUSY; ret = -EBUSY;
if (!request_mem_region(r->start, resource_size(r), pdev->name)) if (!request_mem_region(iores->start, resource_size(iores),
pdev->name))
goto out0; goto out0;
ctx->mmio = ioremap_nocache(r->start, resource_size(r)); ctx->mmio = ioremap_nocache(iores->start, resource_size(iores));
if (!ctx->mmio) if (!ctx->mmio)
goto out1; goto out1;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) if (!dmares)
goto out1; goto out2;
ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) if (!dmares)
goto out1; goto out2;
ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
/* switch it on */ /* switch it on */
WR(ctx, AC97_ENABLE, EN_D | EN_CE); WR(ctx, AC97_ENABLE, EN_D | EN_CE);
@ -270,13 +271,15 @@ static int __devinit au1xac97c_drvprobe(struct platform_device *pdev)
ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver); ret = snd_soc_register_dai(&pdev->dev, &au1xac97c_dai_driver);
if (ret) if (ret)
goto out1; goto out2;
ac97c_workdata = ctx; ac97c_workdata = ctx;
return 0; return 0;
out2:
iounmap(ctx->mmio);
out1: out1:
release_mem_region(r->start, resource_size(r)); release_mem_region(iores->start, resource_size(iores));
out0: out0:
kfree(ctx); kfree(ctx);
return ret; return ret;

View File

@ -228,47 +228,50 @@ static struct snd_soc_dai_driver au1xi2s_dai_driver = {
static int __devinit au1xi2s_drvprobe(struct platform_device *pdev) static int __devinit au1xi2s_drvprobe(struct platform_device *pdev)
{ {
int ret; int ret;
struct resource *r; struct resource *iores, *dmares;
struct au1xpsc_audio_data *ctx; struct au1xpsc_audio_data *ctx;
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx) if (!ctx)
return -ENOMEM; return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!iores) {
ret = -ENODEV; ret = -ENODEV;
goto out0; goto out0;
} }
ret = -EBUSY; ret = -EBUSY;
if (!request_mem_region(r->start, resource_size(r), pdev->name)) if (!request_mem_region(iores->start, resource_size(iores),
pdev->name))
goto out0; goto out0;
ctx->mmio = ioremap_nocache(r->start, resource_size(r)); ctx->mmio = ioremap_nocache(iores->start, resource_size(iores));
if (!ctx->mmio) if (!ctx->mmio)
goto out1; goto out1;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) if (!dmares)
goto out1; goto out2;
ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; ctx->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) if (!dmares)
goto out1; goto out2;
ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; ctx->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
platform_set_drvdata(pdev, ctx); platform_set_drvdata(pdev, ctx);
ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver); ret = snd_soc_register_dai(&pdev->dev, &au1xi2s_dai_driver);
if (ret) if (ret)
goto out1; goto out2;
return 0; return 0;
out2:
iounmap(ctx->mmio);
out1: out1:
release_mem_region(r->start, resource_size(r)); release_mem_region(iores->start, resource_size(iores));
out0: out0:
kfree(ctx); kfree(ctx);
return ret; return ret;

View File

@ -364,7 +364,7 @@ static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev) static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
{ {
int ret; int ret;
struct resource *r; struct resource *iores, *dmares;
unsigned long sel; unsigned long sel;
struct au1xpsc_audio_data *wd; struct au1xpsc_audio_data *wd;
@ -374,29 +374,30 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
mutex_init(&wd->lock); mutex_init(&wd->lock);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!iores) {
ret = -ENODEV; ret = -ENODEV;
goto out0; goto out0;
} }
ret = -EBUSY; ret = -EBUSY;
if (!request_mem_region(r->start, resource_size(r), pdev->name)) if (!request_mem_region(iores->start, resource_size(iores),
pdev->name))
goto out0; goto out0;
wd->mmio = ioremap(r->start, resource_size(r)); wd->mmio = ioremap(iores->start, resource_size(iores));
if (!wd->mmio) if (!wd->mmio)
goto out1; goto out1;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) if (!dmares)
goto out2; goto out2;
wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) if (!dmares)
goto out2; goto out2;
wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
/* configuration: max dma trigger threshold, enable ac97 */ /* configuration: max dma trigger threshold, enable ac97 */
wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 | wd->cfg = PSC_AC97CFG_RT_FIFO8 | PSC_AC97CFG_TT_FIFO8 |
@ -428,7 +429,7 @@ static int __devinit au1xpsc_ac97_drvprobe(struct platform_device *pdev)
out2: out2:
iounmap(wd->mmio); iounmap(wd->mmio);
out1: out1:
release_mem_region(r->start, resource_size(r)); release_mem_region(iores->start, resource_size(iores));
out0: out0:
kfree(wd); kfree(wd);
return ret; return ret;

View File

@ -290,7 +290,7 @@ static const struct snd_soc_dai_driver au1xpsc_i2s_dai_template = {
static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev) static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
{ {
struct resource *r; struct resource *iores, *dmares;
unsigned long sel; unsigned long sel;
int ret; int ret;
struct au1xpsc_audio_data *wd; struct au1xpsc_audio_data *wd;
@ -299,29 +299,30 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
if (!wd) if (!wd)
return -ENOMEM; return -ENOMEM;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0); iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!r) { if (!iores) {
ret = -ENODEV; ret = -ENODEV;
goto out0; goto out0;
} }
ret = -EBUSY; ret = -EBUSY;
if (!request_mem_region(r->start, resource_size(r), pdev->name)) if (!request_mem_region(iores->start, resource_size(iores),
pdev->name))
goto out0; goto out0;
wd->mmio = ioremap(r->start, resource_size(r)); wd->mmio = ioremap(iores->start, resource_size(iores));
if (!wd->mmio) if (!wd->mmio)
goto out1; goto out1;
r = platform_get_resource(pdev, IORESOURCE_DMA, 0); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0);
if (!r) if (!dmares)
goto out2; goto out2;
wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = r->start; wd->dmaids[SNDRV_PCM_STREAM_PLAYBACK] = dmares->start;
r = platform_get_resource(pdev, IORESOURCE_DMA, 1); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 1);
if (!r) if (!dmares)
goto out2; goto out2;
wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = r->start; wd->dmaids[SNDRV_PCM_STREAM_CAPTURE] = dmares->start;
/* preserve PSC clock source set up by platform (dev.platform_data /* preserve PSC clock source set up by platform (dev.platform_data
* is already occupied by soc layer) * is already occupied by soc layer)
@ -355,7 +356,7 @@ static int __devinit au1xpsc_i2s_drvprobe(struct platform_device *pdev)
out2: out2:
iounmap(wd->mmio); iounmap(wd->mmio);
out1: out1:
release_mem_region(r->start, resource_size(r)); release_mem_region(iores->start, resource_size(iores));
out0: out0:
kfree(wd); kfree(wd);
return ret; return ret;

View File

@ -418,7 +418,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd) static int bf5xx_pcm_ac97_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_card *card = rtd->card->snd_card; struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_soc_dai *dai = rtd->cpu_dai;

View File

@ -257,7 +257,7 @@ static void bf5xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32); static u64 bf5xx_pcm_dmamask = DMA_BIT_MASK(32);
int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd) static int bf5xx_pcm_i2s_new(struct snd_soc_pcm_runtime *rtd)
{ {
struct snd_card *card = rtd->card->snd_card; struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai; struct snd_soc_dai *dai = rtd->cpu_dai;

View File

@ -15,6 +15,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/mfd/88pm860x.h> #include <linux/mfd/88pm860x.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/delay.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
@ -772,11 +773,12 @@ static const struct snd_soc_dapm_widget pm860x_dapm_widgets[] = {
SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0, SND_SOC_DAPM_AIF_IN("I2S DIN", "I2S Playback", 0,
PM860X_DAC_EN_2, 0, 0), SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0, SND_SOC_DAPM_AIF_IN("I2S DIN1", "I2S Playback", 0,
PM860X_DAC_EN_2, 0, 0), SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0, SND_SOC_DAPM_AIF_OUT("I2S DOUT", "I2S Capture", 0,
PM860X_I2S_IFACE_3, 5, 1), PM860X_I2S_IFACE_3, 5, 1),
SND_SOC_DAPM_SUPPLY("I2S CLK", PM860X_DAC_EN_2, 0, 0, NULL, 0),
SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux), SND_SOC_DAPM_MUX("I2S Mic Mux", SND_SOC_NOPM, 0, 0, &i2s_mic_mux),
SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux), SND_SOC_DAPM_MUX("ADC Left Mux", SND_SOC_NOPM, 0, 0, &adcl_mux),
SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux), SND_SOC_DAPM_MUX("ADC Right Mux", SND_SOC_NOPM, 0, 0, &adcr_mux),
@ -868,6 +870,11 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"Left ADC", NULL, "Left ADC MOD"}, {"Left ADC", NULL, "Left ADC MOD"},
{"Right ADC", NULL, "Right ADC MOD"}, {"Right ADC", NULL, "Right ADC MOD"},
/* I2S Clock */
{"I2S DIN", NULL, "I2S CLK"},
{"I2S DIN1", NULL, "I2S CLK"},
{"I2S DOUT", NULL, "I2S CLK"},
/* PCM/AIF1 Inputs */ /* PCM/AIF1 Inputs */
{"PCM SDO", NULL, "ADC Left Mux"}, {"PCM SDO", NULL, "ADC Left Mux"},
{"PCM SDO", NULL, "ADCR EC Mux"}, {"PCM SDO", NULL, "ADCR EC Mux"},
@ -1173,6 +1180,9 @@ static int pm860x_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Enable Audio PLL & Audio section */ /* Enable Audio PLL & Audio section */
data = AUDIO_PLL | AUDIO_SECTION_ON;
pm860x_reg_write(codec->control_data, REG_MISC2, data);
udelay(300);
data = AUDIO_PLL | AUDIO_SECTION_RESET data = AUDIO_PLL | AUDIO_SECTION_RESET
| AUDIO_SECTION_ON; | AUDIO_SECTION_ON;
pm860x_reg_write(codec->control_data, REG_MISC2, data); pm860x_reg_write(codec->control_data, REG_MISC2, data);

View File

@ -40,6 +40,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_MAX9850 if I2C select SND_SOC_MAX9850 if I2C
select SND_SOC_MAX9877 if I2C select SND_SOC_MAX9877 if I2C
select SND_SOC_PCM3008 select SND_SOC_PCM3008
select SND_SOC_RT5631 if I2C
select SND_SOC_SGTL5000 if I2C select SND_SOC_SGTL5000 if I2C
select SND_SOC_SN95031 if INTEL_SCU_IPC select SND_SOC_SN95031 if INTEL_SCU_IPC
select SND_SOC_SPDIF select SND_SOC_SPDIF
@ -48,7 +49,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TLV320AIC23 if I2C select SND_SOC_TLV320AIC23 if I2C
select SND_SOC_TLV320AIC26 if SPI_MASTER select SND_SOC_TLV320AIC26 if SPI_MASTER
select SND_SOC_TVL320AIC32X4 if I2C select SND_SOC_TLV320AIC32X4 if I2C
select SND_SOC_TLV320AIC3X if I2C select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C select SND_SOC_TLV320DAC33 if I2C
@ -59,6 +60,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_WL1273 if MFD_WL1273_CORE select SND_SOC_WL1273 if MFD_WL1273_CORE
select SND_SOC_WM1250_EV1 if I2C select SND_SOC_WM1250_EV1 if I2C
select SND_SOC_WM2000 if I2C select SND_SOC_WM2000 if I2C
select SND_SOC_WM5100 if I2C
select SND_SOC_WM8350 if MFD_WM8350 select SND_SOC_WM8350 if MFD_WM8350
select SND_SOC_WM8400 if MFD_WM8400 select SND_SOC_WM8400 if MFD_WM8400
select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI
@ -218,6 +220,9 @@ config SND_SOC_MAX9850
config SND_SOC_PCM3008 config SND_SOC_PCM3008
tristate tristate
config SND_SOC_RT5631
tristate
#Freescale sgtl5000 codec #Freescale sgtl5000 codec
config SND_SOC_SGTL5000 config SND_SOC_SGTL5000
tristate tristate
@ -244,7 +249,7 @@ config SND_SOC_TLV320AIC26
tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE tristate "TI TLV320AIC26 Codec support" if SND_SOC_OF_SIMPLE
depends on SPI depends on SPI
config SND_SOC_TVL320AIC32X4 config SND_SOC_TLV320AIC32X4
tristate tristate
config SND_SOC_TLV320AIC3X config SND_SOC_TLV320AIC3X
@ -273,6 +278,9 @@ config SND_SOC_WL1273
config SND_SOC_WM1250_EV1 config SND_SOC_WM1250_EV1
tristate tristate
config SND_SOC_WM5100
tristate
config SND_SOC_WM8350 config SND_SOC_WM8350
tristate tristate

View File

@ -26,6 +26,7 @@ snd-soc-max98088-objs := max98088.o
snd-soc-max98095-objs := max98095.o snd-soc-max98095-objs := max98095.o
snd-soc-max9850-objs := max9850.o snd-soc-max9850-objs := max9850.o
snd-soc-pcm3008-objs := pcm3008.o snd-soc-pcm3008-objs := pcm3008.o
snd-soc-rt5631-objs := rt5631.o
snd-soc-sgtl5000-objs := sgtl5000.o snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o snd-soc-alc5623-objs := alc5623.o
snd-soc-sn95031-objs := sn95031.o snd-soc-sn95031-objs := sn95031.o
@ -44,6 +45,7 @@ snd-soc-uda134x-objs := uda134x.o
snd-soc-uda1380-objs := uda1380.o snd-soc-uda1380-objs := uda1380.o
snd-soc-wl1273-objs := wl1273.o snd-soc-wl1273-objs := wl1273.o
snd-soc-wm1250-ev1-objs := wm1250-ev1.o snd-soc-wm1250-ev1-objs := wm1250-ev1.o
snd-soc-wm5100-objs := wm5100.o wm5100-tables.o
snd-soc-wm8350-objs := wm8350.o snd-soc-wm8350-objs := wm8350.o
snd-soc-wm8400-objs := wm8400.o snd-soc-wm8400-objs := wm8400.o
snd-soc-wm8510-objs := wm8510.o snd-soc-wm8510-objs := wm8510.o
@ -125,6 +127,7 @@ obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o
obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o
obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o
obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o
obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif.o
@ -134,7 +137,7 @@ obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TVL320AIC32X4) += snd-soc-tlv320aic32x4.o obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
@ -142,6 +145,7 @@ obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o
obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o
obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o
obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o
obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o
obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o
obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o

View File

@ -103,12 +103,14 @@ static const struct snd_soc_dapm_route audio_paths[] = {
static int ad193x_mute(struct snd_soc_dai *dai, int mute) static int ad193x_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
int reg;
reg = snd_soc_read(codec, AD193X_DAC_CTRL2); if (mute)
reg = (mute > 0) ? reg | AD193X_DAC_MASTER_MUTE : reg & snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
(~AD193X_DAC_MASTER_MUTE); AD193X_DAC_MASTER_MUTE,
snd_soc_write(codec, AD193X_DAC_CTRL2, reg); AD193X_DAC_MASTER_MUTE);
else
snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
AD193X_DAC_MASTER_MUTE, 0);
return 0; return 0;
} }
@ -262,7 +264,7 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
int word_len = 0, reg = 0, master_rate = 0; int word_len = 0, master_rate = 0;
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
@ -297,18 +299,15 @@ static int ad193x_hw_params(struct snd_pcm_substream *substream,
break; break;
} }
reg = snd_soc_read(codec, AD193X_PLL_CLK_CTRL0); snd_soc_update_bits(codec, AD193X_PLL_CLK_CTRL0,
reg = (reg & AD193X_PLL_INPUT_MASK) | master_rate; AD193X_PLL_INPUT_MASK, master_rate);
snd_soc_write(codec, AD193X_PLL_CLK_CTRL0, reg);
reg = snd_soc_read(codec, AD193X_DAC_CTRL2); snd_soc_update_bits(codec, AD193X_DAC_CTRL2,
reg = (reg & (~AD193X_DAC_WORD_LEN_MASK)) AD193X_DAC_WORD_LEN_MASK,
| (word_len << AD193X_DAC_WORD_LEN_SHFT); word_len << AD193X_DAC_WORD_LEN_SHFT);
snd_soc_write(codec, AD193X_DAC_CTRL2, reg);
reg = snd_soc_read(codec, AD193X_ADC_CTRL1); snd_soc_update_bits(codec, AD193X_ADC_CTRL1,
reg = (reg & (~AD193X_ADC_WORD_LEN_MASK)) | word_len; AD193X_ADC_WORD_LEN_MASK, word_len);
snd_soc_write(codec, AD193X_ADC_CTRL1, reg);
return 0; return 0;
} }

View File

@ -11,7 +11,7 @@
#define AD193X_PLL_CLK_CTRL0 0x00 #define AD193X_PLL_CLK_CTRL0 0x00
#define AD193X_PLL_POWERDOWN 0x01 #define AD193X_PLL_POWERDOWN 0x01
#define AD193X_PLL_INPUT_MASK (~0x6) #define AD193X_PLL_INPUT_MASK 0x6
#define AD193X_PLL_INPUT_256 (0 << 1) #define AD193X_PLL_INPUT_256 (0 << 1)
#define AD193X_PLL_INPUT_384 (1 << 1) #define AD193X_PLL_INPUT_384 (1 << 1)
#define AD193X_PLL_INPUT_512 (2 << 1) #define AD193X_PLL_INPUT_512 (2 << 1)

View File

@ -148,7 +148,6 @@ static struct snd_soc_dai_driver ad1980_dai = {
.rates = SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_48000,
.formats = SND_SOC_STD_AC97_FMTS, }, .formats = SND_SOC_STD_AC97_FMTS, },
}; };
EXPORT_SYMBOL_GPL(ad1980_dai);
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{ {

View File

@ -974,7 +974,7 @@ static int adau1373_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
break; break;
case SND_SOC_DAIFMT_CBS_CFS: case SND_SOC_DAIFMT_CBS_CFS:
ctrl = 0; ctrl = 0;
adau1373_dai->master = true; adau1373_dai->master = false;
break; break;
default: default:
return -EINVAL; return -EINVAL;

View File

@ -401,7 +401,7 @@ static int adau1701_digital_mute(struct snd_soc_dai *dai, int mute)
} }
static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
unsigned int freq, int dir) int source, unsigned int freq, int dir)
{ {
unsigned int val; unsigned int val;
@ -458,6 +458,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
int ret; int ret;
codec->dapm.idle_bias_off = 1; codec->dapm.idle_bias_off = 1;
codec->control_data = to_i2c_client(codec->dev);
ret = adau1701_load_firmware(codec); ret = adau1701_load_firmware(codec);
if (ret) if (ret)

View File

@ -1,13 +0,0 @@
/*
* ads117x.h -- Driver for ads1174/8 ADC chips
*
* Copyright 2009 ShotSpotter Inc.
* Author: Graeme Gregory <gg@slimlogic.co.uk>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*/
extern struct snd_soc_dai_driver ads117x_dai;
extern struct snd_soc_codec_driver soc_codec_dev_ads117x;

View File

@ -247,7 +247,7 @@ static struct snd_soc_codec_driver soc_codec_device_ak4104 = {
.probe = ak4104_probe, .probe = ak4104_probe,
.remove = ak4104_remove, .remove = ak4104_remove,
.reg_cache_size = AK4104_NUM_REGS, .reg_cache_size = AK4104_NUM_REGS,
.reg_word_size = sizeof(u16), .reg_word_size = sizeof(u8),
}; };
static int ak4104_spi_probe(struct spi_device *spi) static int ak4104_spi_probe(struct spi_device *spi)

View File

@ -34,74 +34,16 @@
struct ak4535_priv { struct ak4535_priv {
unsigned int sysclk; unsigned int sysclk;
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
}; };
/* /*
* ak4535 register cache * ak4535 register cache
*/ */
static const u16 ak4535_reg[AK4535_CACHEREGNUM] = { static const u8 ak4535_reg[AK4535_CACHEREGNUM] = {
0x0000, 0x0080, 0x0000, 0x0003, 0x00, 0x80, 0x00, 0x03,
0x0002, 0x0000, 0x0011, 0x0001, 0x02, 0x00, 0x11, 0x01,
0x0000, 0x0040, 0x0036, 0x0010, 0x00, 0x40, 0x36, 0x10,
0x0000, 0x0000, 0x0057, 0x0000, 0x00, 0x00, 0x57, 0x00,
};
/*
* read ak4535 register cache
*/
static inline unsigned int ak4535_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= AK4535_CACHEREGNUM)
return -1;
return cache[reg];
}
/*
* write ak4535 register cache
*/
static inline void ak4535_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= AK4535_CACHEREGNUM)
return;
cache[reg] = value;
}
/*
* write to the AK4535 register space
*/
static int ak4535_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D8 AK4535 register offset
* D7...D0 register data
*/
data[0] = reg & 0xff;
data[1] = value & 0xff;
ak4535_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
else
return -EIO;
}
static int ak4535_sync(struct snd_soc_codec *codec)
{
u16 *cache = codec->reg_cache;
int i, r = 0;
for (i = 0; i < AK4535_CACHEREGNUM; i++)
r |= ak4535_write(codec, i, cache[i]);
return r;
}; };
static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"}; static const char *ak4535_mono_gain[] = {"+6dB", "-17dB"};
@ -304,7 +246,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec); struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
u8 mode2 = ak4535_read_reg_cache(codec, AK4535_MODE2) & ~(0x3 << 5); u8 mode2 = snd_soc_read(codec, AK4535_MODE2) & ~(0x3 << 5);
int rate = params_rate(params), fs = 256; int rate = params_rate(params), fs = 256;
if (rate) if (rate)
@ -323,7 +265,7 @@ static int ak4535_hw_params(struct snd_pcm_substream *substream,
} }
/* set rate */ /* set rate */
ak4535_write(codec, AK4535_MODE2, mode2); snd_soc_write(codec, AK4535_MODE2, mode2);
return 0; return 0;
} }
@ -348,44 +290,37 @@ static int ak4535_set_dai_fmt(struct snd_soc_dai *codec_dai,
/* use 32 fs for BCLK to save power */ /* use 32 fs for BCLK to save power */
mode1 |= 0x4; mode1 |= 0x4;
ak4535_write(codec, AK4535_MODE1, mode1); snd_soc_write(codec, AK4535_MODE1, mode1);
return 0; return 0;
} }
static int ak4535_mute(struct snd_soc_dai *dai, int mute) static int ak4535_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC); u16 mute_reg = snd_soc_read(codec, AK4535_DAC);
if (!mute) if (!mute)
ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20); snd_soc_write(codec, AK4535_DAC, mute_reg & ~0x20);
else else
ak4535_write(codec, AK4535_DAC, mute_reg | 0x20); snd_soc_write(codec, AK4535_DAC, mute_reg | 0x20);
return 0; return 0;
} }
static int ak4535_set_bias_level(struct snd_soc_codec *codec, static int ak4535_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 i, mute_reg;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC); snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0);
ak4535_write(codec, AK4535_DAC, mute_reg & ~0x20);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
mute_reg = ak4535_read_reg_cache(codec, AK4535_DAC); snd_soc_update_bits(codec, AK4535_DAC, 0x20, 0x20);
ak4535_write(codec, AK4535_DAC, mute_reg | 0x20);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
i = ak4535_read_reg_cache(codec, AK4535_PM1); snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0x80);
ak4535_write(codec, AK4535_PM1, i | 0x80); snd_soc_update_bits(codec, AK4535_PM2, 0x80, 0);
i = ak4535_read_reg_cache(codec, AK4535_PM2);
ak4535_write(codec, AK4535_PM2, i & (~0x80));
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
i = ak4535_read_reg_cache(codec, AK4535_PM1); snd_soc_update_bits(codec, AK4535_PM1, 0x80, 0);
ak4535_write(codec, AK4535_PM1, i & (~0x80));
break; break;
} }
codec->dapm.bias_level = level; codec->dapm.bias_level = level;
@ -428,7 +363,7 @@ static int ak4535_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int ak4535_resume(struct snd_soc_codec *codec) static int ak4535_resume(struct snd_soc_codec *codec)
{ {
ak4535_sync(codec); snd_soc_cache_sync(codec);
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }
@ -436,11 +371,15 @@ static int ak4535_resume(struct snd_soc_codec *codec)
static int ak4535_probe(struct snd_soc_codec *codec) static int ak4535_probe(struct snd_soc_codec *codec)
{ {
struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec); struct ak4535_priv *ak4535 = snd_soc_codec_get_drvdata(codec);
int ret;
printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION); printk(KERN_INFO "AK4535 Audio Codec %s", AK4535_VERSION);
codec->control_data = ak4535->control_data; ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4535->control_type);
if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
/* power on device */ /* power on device */
ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY); ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@ -461,8 +400,6 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
.remove = ak4535_remove, .remove = ak4535_remove,
.suspend = ak4535_suspend, .suspend = ak4535_suspend,
.resume = ak4535_resume, .resume = ak4535_resume,
.read = ak4535_read_reg_cache,
.write = ak4535_write,
.set_bias_level = ak4535_set_bias_level, .set_bias_level = ak4535_set_bias_level,
.reg_cache_size = ARRAY_SIZE(ak4535_reg), .reg_cache_size = ARRAY_SIZE(ak4535_reg),
.reg_word_size = sizeof(u8), .reg_word_size = sizeof(u8),
@ -485,7 +422,6 @@ static __devinit int ak4535_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(i2c, ak4535); i2c_set_clientdata(i2c, ak4535);
ak4535->control_data = i2c;
ak4535->control_type = SND_SOC_I2C; ak4535->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -31,7 +31,6 @@
/* codec private data */ /* codec private data */
struct ak4641_priv { struct ak4641_priv {
struct snd_soc_codec *codec;
unsigned int sysclk; unsigned int sysclk;
int deemph; int deemph;
int playback_fs; int playback_fs;
@ -226,7 +225,7 @@ static const struct snd_soc_dapm_widget ak4641_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0), SND_SOC_DAPM_PGA("Mono Out 2", AK4641_PM2, 3, 0, NULL, 0),
SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0), SND_SOC_DAPM_ADC("Voice ADC", "Voice Capture", AK4641_BTIF, 0, 0),
SND_SOC_DAPM_ADC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0), SND_SOC_DAPM_DAC("Voice DAC", "Voice Playback", AK4641_BTIF, 1, 0),
SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0), SND_SOC_DAPM_MICBIAS("Mic Int Bias", AK4641_MIC, 3, 0),
SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0), SND_SOC_DAPM_MICBIAS("Mic Ext Bias", AK4641_MIC, 4, 0),

View File

@ -156,81 +156,22 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
struct ak4642_priv { struct ak4642_priv {
unsigned int sysclk; unsigned int sysclk;
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
}; };
/* /*
* ak4642 register cache * ak4642 register cache
*/ */
static const u16 ak4642_reg[AK4642_CACHEREGNUM] = { static const u8 ak4642_reg[AK4642_CACHEREGNUM] = {
0x0000, 0x0000, 0x0001, 0x0000, 0x00, 0x00, 0x01, 0x00,
0x0002, 0x0000, 0x0000, 0x0000, 0x02, 0x00, 0x00, 0x00,
0x00e1, 0x00e1, 0x0018, 0x0000, 0xe1, 0xe1, 0x18, 0x00,
0x00e1, 0x0018, 0x0011, 0x0008, 0xe1, 0x18, 0x11, 0x08,
0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,
0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,
0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,
0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,
0x0000, 0x0000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00,
0x0000, 0x00,
};
/*
* read ak4642 register cache
*/
static inline unsigned int ak4642_read_reg_cache(struct snd_soc_codec *codec,
unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= AK4642_CACHEREGNUM)
return -1;
return cache[reg];
}
/*
* write ak4642 register cache
*/
static inline void ak4642_write_reg_cache(struct snd_soc_codec *codec,
u16 reg, unsigned int value)
{
u16 *cache = codec->reg_cache;
if (reg >= AK4642_CACHEREGNUM)
return;
cache[reg] = value;
}
/*
* write to the AK4642 register space
*/
static int ak4642_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* data is
* D15..D8 AK4642 register offset
* D7...D0 register data
*/
data[0] = reg & 0xff;
data[1] = value & 0xff;
if (codec->hw_write(codec->control_data, data, 2) == 2) {
ak4642_write_reg_cache(codec, reg, value);
return 0;
} else
return -EIO;
}
static int ak4642_sync(struct snd_soc_codec *codec)
{
u16 *cache = codec->reg_cache;
int i, r = 0;
for (i = 0; i < AK4642_CACHEREGNUM; i++)
r |= ak4642_write(codec, i, cache[i]);
return r;
}; };
static int ak4642_dai_startup(struct snd_pcm_substream *substream, static int ak4642_dai_startup(struct snd_pcm_substream *substream,
@ -252,8 +193,8 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
*/ */
snd_soc_update_bits(codec, MD_CTL4, DACH, DACH); snd_soc_update_bits(codec, MD_CTL4, DACH, DACH);
snd_soc_update_bits(codec, MD_CTL3, BST1, BST1); snd_soc_update_bits(codec, MD_CTL3, BST1, BST1);
ak4642_write(codec, L_IVC, 0x91); /* volume */ snd_soc_write(codec, L_IVC, 0x91); /* volume */
ak4642_write(codec, R_IVC, 0x91); /* volume */ snd_soc_write(codec, R_IVC, 0x91); /* volume */
snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC, snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMMIN | PMDAC,
PMVCM | PMMIN | PMDAC); PMVCM | PMMIN | PMDAC);
snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP); snd_soc_update_bits(codec, PW_MGMT2, PMHP_MASK, PMHP);
@ -272,9 +213,9 @@ static int ak4642_dai_startup(struct snd_pcm_substream *substream,
* This operation came from example code of * This operation came from example code of
* "ASAHI KASEI AK4642" (japanese) manual p94. * "ASAHI KASEI AK4642" (japanese) manual p94.
*/ */
ak4642_write(codec, SG_SL1, PMMP | MGAIN0); snd_soc_write(codec, SG_SL1, PMMP | MGAIN0);
ak4642_write(codec, TIMER, ZTM(0x3) | WTM(0x3)); snd_soc_write(codec, TIMER, ZTM(0x3) | WTM(0x3));
ak4642_write(codec, ALC_CTL1, ALC | LMTH0); snd_soc_write(codec, ALC_CTL1, ALC | LMTH0);
snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL, snd_soc_update_bits(codec, PW_MGMT1, PMVCM | PMADL,
PMVCM | PMADL); PMVCM | PMADL);
snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR); snd_soc_update_bits(codec, PW_MGMT3, PMADR, PMADR);
@ -462,7 +403,7 @@ static struct snd_soc_dai_driver ak4642_dai = {
static int ak4642_resume(struct snd_soc_codec *codec) static int ak4642_resume(struct snd_soc_codec *codec)
{ {
ak4642_sync(codec); snd_soc_cache_sync(codec);
return 0; return 0;
} }
@ -470,11 +411,15 @@ static int ak4642_resume(struct snd_soc_codec *codec)
static int ak4642_probe(struct snd_soc_codec *codec) static int ak4642_probe(struct snd_soc_codec *codec)
{ {
struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec); struct ak4642_priv *ak4642 = snd_soc_codec_get_drvdata(codec);
int ret;
dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION); dev_info(codec->dev, "AK4642 Audio Codec %s", AK4642_VERSION);
codec->hw_write = (hw_write_t)i2c_master_send; ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4642->control_type);
codec->control_data = ak4642->control_data; if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
snd_soc_add_controls(codec, ak4642_snd_controls, snd_soc_add_controls(codec, ak4642_snd_controls,
ARRAY_SIZE(ak4642_snd_controls)); ARRAY_SIZE(ak4642_snd_controls));
@ -485,8 +430,6 @@ static int ak4642_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
.probe = ak4642_probe, .probe = ak4642_probe,
.resume = ak4642_resume, .resume = ak4642_resume,
.read = ak4642_read_reg_cache,
.write = ak4642_write,
.reg_cache_size = ARRAY_SIZE(ak4642_reg), .reg_cache_size = ARRAY_SIZE(ak4642_reg),
.reg_word_size = sizeof(u8), .reg_word_size = sizeof(u8),
.reg_cache_default = ak4642_reg, .reg_cache_default = ak4642_reg,
@ -504,7 +447,6 @@ static __devinit int ak4642_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(i2c, ak4642); i2c_set_clientdata(i2c, ak4642);
ak4642->control_data = i2c;
ak4642->control_type = SND_SOC_I2C; ak4642->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -26,7 +26,6 @@
/* codec private data */ /* codec private data */
struct ak4671_priv { struct ak4671_priv {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
}; };
/* ak4671 register cache & default register settings */ /* ak4671 register cache & default register settings */
@ -169,18 +168,15 @@ static int ak4671_out2_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
u8 reg;
switch (event) { switch (event) {
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
reg |= AK4671_MUTEN; AK4671_MUTEN, AK4671_MUTEN);
snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
break; break;
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
reg = snd_soc_read(codec, AK4671_LOUT2_POWER_MANAGERMENT); snd_soc_update_bits(codec, AK4671_LOUT2_POWER_MANAGERMENT,
reg &= ~AK4671_MUTEN; AK4671_MUTEN, 0);
snd_soc_write(codec, AK4671_LOUT2_POWER_MANAGERMENT, reg);
break; break;
} }
@ -576,15 +572,12 @@ static int ak4671_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
static int ak4671_set_bias_level(struct snd_soc_codec *codec, static int ak4671_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u8 reg;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
reg = snd_soc_read(codec, AK4671_AD_DA_POWER_MANAGEMENT); snd_soc_update_bits(codec, AK4671_AD_DA_POWER_MANAGEMENT,
snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, AK4671_PMVCM, AK4671_PMVCM);
reg | AK4671_PMVCM);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00); snd_soc_write(codec, AK4671_AD_DA_POWER_MANAGEMENT, 0x00);
@ -629,8 +622,6 @@ static int ak4671_probe(struct snd_soc_codec *codec)
struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec); struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec);
int ret; int ret;
codec->hw_write = (hw_write_t)i2c_master_send;
ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type); ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@ -675,7 +666,6 @@ static int __devinit ak4671_i2c_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(client, ak4671); i2c_set_clientdata(client, ak4671);
ak4671->control_data = client;
ak4671->control_type = SND_SOC_I2C; ak4671->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&client->dev, ret = snd_soc_register_codec(&client->dev,

View File

@ -40,7 +40,6 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)");
/* codec private data */ /* codec private data */
struct alc5623_priv { struct alc5623_priv {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
u8 id; u8 id;
unsigned int sysclk; unsigned int sysclk;
u16 reg_cache[ALC5623_VENDOR_ID2+2]; u16 reg_cache[ALC5623_VENDOR_ID2+2];
@ -54,8 +53,10 @@ static void alc5623_fill_cache(struct snd_soc_codec *codec)
u16 *cache = codec->reg_cache; u16 *cache = codec->reg_cache;
/* not really efficient ... */ /* not really efficient ... */
codec->cache_bypass = 1;
for (i = 0 ; i < codec->driver->reg_cache_size ; i += step) for (i = 0 ; i < codec->driver->reg_cache_size ; i += step)
cache[i] = codec->hw_read(codec, i); cache[i] = snd_soc_read(codec, i);
codec->cache_bypass = 0;
} }
static inline int alc5623_reset(struct snd_soc_codec *codec) static inline int alc5623_reset(struct snd_soc_codec *codec)
@ -1049,7 +1050,6 @@ static int alc5623_i2c_probe(struct i2c_client *client,
} }
i2c_set_clientdata(client, alc5623); i2c_set_clientdata(client, alc5623);
alc5623->control_data = client;
alc5623->control_type = SND_SOC_I2C; alc5623->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&client->dev, ret = snd_soc_register_codec(&client->dev,

View File

@ -128,7 +128,6 @@ static const char *supply_names[] = {
/* Private data for the CS4270 */ /* Private data for the CS4270 */
struct cs4270_private { struct cs4270_private {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
unsigned int mclk; /* Input frequency of the MCLK pin */ unsigned int mclk; /* Input frequency of the MCLK pin */
unsigned int mode; /* The mode (I2S or left-justified) */ unsigned int mode; /* The mode (I2S or left-justified) */
unsigned int slave_mode; unsigned int slave_mode;
@ -262,7 +261,6 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
/* set DAI format */ /* set DAI format */
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
@ -272,7 +270,7 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
break; break;
default: default:
dev_err(codec->dev, "invalid dai format\n"); dev_err(codec->dev, "invalid dai format\n");
ret = -EINVAL; return -EINVAL;
} }
/* set master/slave audio interface */ /* set master/slave audio interface */
@ -285,10 +283,11 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai,
break; break;
default: default:
/* all other modes are unsupported by the hardware */ /* all other modes are unsupported by the hardware */
ret = -EINVAL; dev_err(codec->dev, "Unknown master/slave configuration\n");
return -EINVAL;
} }
return ret; return 0;
} }
/** /**
@ -490,8 +489,6 @@ static int cs4270_probe(struct snd_soc_codec *codec)
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
int i, ret; int i, ret;
codec->control_data = cs4270->control_data;
/* Tell ASoC what kind of I/O to use to read the registers. ASoC will /* Tell ASoC what kind of I/O to use to read the registers. ASoC will
* then do the I2C transactions itself. * then do the I2C transactions itself.
*/ */
@ -604,7 +601,7 @@ static int cs4270_soc_suspend(struct snd_soc_codec *codec, pm_message_t mesg)
static int cs4270_soc_resume(struct snd_soc_codec *codec) static int cs4270_soc_resume(struct snd_soc_codec *codec)
{ {
struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec); struct cs4270_private *cs4270 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *i2c_client = codec->control_data; struct i2c_client *i2c_client = to_i2c_client(codec->dev);
int reg; int reg;
regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies), regulator_bulk_enable(ARRAY_SIZE(cs4270->supplies),
@ -690,7 +687,6 @@ static int cs4270_i2c_probe(struct i2c_client *i2c_client,
} }
i2c_set_clientdata(i2c_client, cs4270); i2c_set_clientdata(i2c_client, cs4270);
cs4270->control_data = i2c_client;
cs4270->control_type = SND_SOC_I2C; cs4270->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c_client->dev, ret = snd_soc_register_codec(&i2c_client->dev,

View File

@ -156,7 +156,6 @@ static const u8 cs4271_dflt_reg[CS4271_NR_REGS] = {
struct cs4271_private { struct cs4271_private {
/* SND_SOC_I2C or SND_SOC_SPI */ /* SND_SOC_I2C or SND_SOC_SPI */
enum snd_soc_control_type bus_type; enum snd_soc_control_type bus_type;
void *control_data;
unsigned int mclk; unsigned int mclk;
bool master; bool master;
bool deemph; bool deemph;
@ -466,8 +465,6 @@ static int cs4271_probe(struct snd_soc_codec *codec)
int ret; int ret;
int gpio_nreset = -EINVAL; int gpio_nreset = -EINVAL;
codec->control_data = cs4271->control_data;
if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset)) if (cs4271plat && gpio_is_valid(cs4271plat->gpio_nreset))
gpio_nreset = cs4271plat->gpio_nreset; gpio_nreset = cs4271plat->gpio_nreset;
@ -555,7 +552,6 @@ static int __devinit cs4271_spi_probe(struct spi_device *spi)
return -ENOMEM; return -ENOMEM;
spi_set_drvdata(spi, cs4271); spi_set_drvdata(spi, cs4271);
cs4271->control_data = spi;
cs4271->bus_type = SND_SOC_SPI; cs4271->bus_type = SND_SOC_SPI;
return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271, return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
@ -595,7 +591,6 @@ static int __devinit cs4271_i2c_probe(struct i2c_client *client,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(client, cs4271); i2c_set_clientdata(client, cs4271);
cs4271->control_data = client;
cs4271->bus_type = SND_SOC_I2C; cs4271->bus_type = SND_SOC_I2C;
return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271, return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,

View File

@ -42,7 +42,6 @@ enum master_slave_mode {
struct cs42l51_private { struct cs42l51_private {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
unsigned int mclk; unsigned int mclk;
unsigned int audio_mode; /* The mode (I2S or left-justified) */ unsigned int audio_mode; /* The mode (I2S or left-justified) */
enum master_slave_mode func; enum master_slave_mode func;
@ -57,7 +56,7 @@ struct cs42l51_private {
static int cs42l51_fill_cache(struct snd_soc_codec *codec) static int cs42l51_fill_cache(struct snd_soc_codec *codec)
{ {
u8 *cache = codec->reg_cache + 1; u8 *cache = codec->reg_cache + 1;
struct i2c_client *i2c_client = codec->control_data; struct i2c_client *i2c_client = to_i2c_client(codec->dev);
s32 length; s32 length;
length = i2c_smbus_read_i2c_block_data(i2c_client, length = i2c_smbus_read_i2c_block_data(i2c_client,
@ -289,7 +288,6 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
switch (format & SND_SOC_DAIFMT_FORMAT_MASK) { switch (format & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
@ -299,7 +297,7 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
break; break;
default: default:
dev_err(codec->dev, "invalid DAI format\n"); dev_err(codec->dev, "invalid DAI format\n");
ret = -EINVAL; return -EINVAL;
} }
switch (format & SND_SOC_DAIFMT_MASTER_MASK) { switch (format & SND_SOC_DAIFMT_MASTER_MASK) {
@ -310,11 +308,11 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai,
cs42l51->func = MODE_SLAVE_AUTO; cs42l51->func = MODE_SLAVE_AUTO;
break; break;
default: default:
ret = -EINVAL; dev_err(codec->dev, "Unknown master/slave configuration\n");
break; return -EINVAL;
} }
return ret; return 0;
} }
struct cs42l51_ratios { struct cs42l51_ratios {
@ -520,8 +518,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec)
struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret, reg; int ret, reg;
codec->control_data = cs42l51->control_data;
ret = cs42l51_fill_cache(codec); ret = cs42l51_fill_cache(codec);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "failed to fill register cache\n"); dev_err(codec->dev, "failed to fill register cache\n");
@ -593,7 +589,6 @@ static int cs42l51_i2c_probe(struct i2c_client *i2c_client,
} }
i2c_set_clientdata(i2c_client, cs42l51); i2c_set_clientdata(i2c_client, cs42l51);
cs42l51->control_data = i2c_client;
cs42l51->control_type = SND_SOC_I2C; cs42l51->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c_client->dev, ret = snd_soc_register_codec(&i2c_client->dev,

View File

@ -26,23 +26,41 @@
#include <sound/tlv.h> #include <sound/tlv.h>
/* DA7210 register space */ /* DA7210 register space */
#define DA7210_CONTROL 0x01
#define DA7210_STATUS 0x02 #define DA7210_STATUS 0x02
#define DA7210_STARTUP1 0x03 #define DA7210_STARTUP1 0x03
#define DA7210_STARTUP2 0x04
#define DA7210_STARTUP3 0x05
#define DA7210_MIC_L 0x07 #define DA7210_MIC_L 0x07
#define DA7210_MIC_R 0x08 #define DA7210_MIC_R 0x08
#define DA7210_AUX1_L 0x09
#define DA7210_AUX1_R 0x0A
#define DA7210_AUX2 0x0B
#define DA7210_IN_GAIN 0x0C
#define DA7210_INMIX_L 0x0D #define DA7210_INMIX_L 0x0D
#define DA7210_INMIX_R 0x0E #define DA7210_INMIX_R 0x0E
#define DA7210_ADC_HPF 0x0F #define DA7210_ADC_HPF 0x0F
#define DA7210_ADC 0x10 #define DA7210_ADC 0x10
#define DA7210_ADC_EQ1_2 0X11
#define DA7210_ADC_EQ3_4 0x12
#define DA7210_ADC_EQ5 0x13
#define DA7210_DAC_HPF 0x14 #define DA7210_DAC_HPF 0x14
#define DA7210_DAC_L 0x15 #define DA7210_DAC_L 0x15
#define DA7210_DAC_R 0x16 #define DA7210_DAC_R 0x16
#define DA7210_DAC_SEL 0x17 #define DA7210_DAC_SEL 0x17
#define DA7210_SOFTMUTE 0x18
#define DA7210_DAC_EQ1_2 0x19
#define DA7210_DAC_EQ3_4 0x1A
#define DA7210_DAC_EQ5 0x1B
#define DA7210_OUTMIX_L 0x1C #define DA7210_OUTMIX_L 0x1C
#define DA7210_OUTMIX_R 0x1D #define DA7210_OUTMIX_R 0x1D
#define DA7210_OUT1_L 0x1E
#define DA7210_OUT1_R 0x1F
#define DA7210_OUT2 0x20
#define DA7210_HP_L_VOL 0x21 #define DA7210_HP_L_VOL 0x21
#define DA7210_HP_R_VOL 0x22 #define DA7210_HP_R_VOL 0x22
#define DA7210_HP_CFG 0x23 #define DA7210_HP_CFG 0x23
#define DA7210_ZERO_CROSS 0x24
#define DA7210_DAI_SRC_SEL 0x25 #define DA7210_DAI_SRC_SEL 0x25
#define DA7210_DAI_CFG1 0x26 #define DA7210_DAI_CFG1 0x26
#define DA7210_DAI_CFG3 0x28 #define DA7210_DAI_CFG3 0x28
@ -50,6 +68,12 @@
#define DA7210_PLL_DIV2 0x2A #define DA7210_PLL_DIV2 0x2A
#define DA7210_PLL_DIV3 0x2B #define DA7210_PLL_DIV3 0x2B
#define DA7210_PLL 0x2C #define DA7210_PLL 0x2C
#define DA7210_ALC_MAX 0x83
#define DA7210_ALC_MIN 0x84
#define DA7210_ALC_NOIS 0x85
#define DA7210_ALC_ATT 0x86
#define DA7210_ALC_REL 0x87
#define DA7210_ALC_DEL 0x88
#define DA7210_A_HID_UNLOCK 0x8A #define DA7210_A_HID_UNLOCK 0x8A
#define DA7210_A_TEST_UNLOCK 0x8B #define DA7210_A_TEST_UNLOCK 0x8B
#define DA7210_A_PLL1 0x90 #define DA7210_A_PLL1 0x90
@ -72,6 +96,7 @@
#define DA7210_IN_R_EN (1 << 7) #define DA7210_IN_R_EN (1 << 7)
/* ADC bit fields */ /* ADC bit fields */
#define DA7210_ADC_ALC_EN (1 << 0)
#define DA7210_ADC_L_EN (1 << 3) #define DA7210_ADC_L_EN (1 << 3)
#define DA7210_ADC_R_EN (1 << 7) #define DA7210_ADC_R_EN (1 << 7)
@ -105,12 +130,17 @@
/* DAI_CFG1 bit fields */ /* DAI_CFG1 bit fields */
#define DA7210_DAI_WORD_S16_LE (0 << 0) #define DA7210_DAI_WORD_S16_LE (0 << 0)
#define DA7210_DAI_WORD_S20_3LE (1 << 0)
#define DA7210_DAI_WORD_S24_LE (2 << 0) #define DA7210_DAI_WORD_S24_LE (2 << 0)
#define DA7210_DAI_WORD_S32_LE (3 << 0)
#define DA7210_DAI_FLEN_64BIT (1 << 2) #define DA7210_DAI_FLEN_64BIT (1 << 2)
#define DA7210_DAI_MODE_SLAVE (0 << 7)
#define DA7210_DAI_MODE_MASTER (1 << 7) #define DA7210_DAI_MODE_MASTER (1 << 7)
/* DAI_CFG3 bit fields */ /* DAI_CFG3 bit fields */
#define DA7210_DAI_FORMAT_I2SMODE (0 << 0) #define DA7210_DAI_FORMAT_I2SMODE (0 << 0)
#define DA7210_DAI_FORMAT_LEFT_J (1 << 0)
#define DA7210_DAI_FORMAT_RIGHT_J (2 << 0)
#define DA7210_DAI_OE (1 << 3) #define DA7210_DAI_OE (1 << 3)
#define DA7210_DAI_EN (1 << 7) #define DA7210_DAI_EN (1 << 7)
@ -133,6 +163,43 @@
#define DA7210_PLL_FS_96000 (0xF << 0) #define DA7210_PLL_FS_96000 (0xF << 0)
#define DA7210_PLL_EN (0x1 << 7) #define DA7210_PLL_EN (0x1 << 7)
/* SOFTMUTE bit fields */
#define DA7210_RAMP_EN (1 << 6)
/* CONTROL bit fields */
#define DA7210_NOISE_SUP_EN (1 << 3)
/* IN_GAIN bit fields */
#define DA7210_INPGA_L_VOL (0x0F << 0)
#define DA7210_INPGA_R_VOL (0xF0 << 0)
/* ZERO_CROSS bit fields */
#define DA7210_AUX1_L_ZC (1 << 0)
#define DA7210_AUX1_R_ZC (1 << 1)
#define DA7210_HP_L_ZC (1 << 6)
#define DA7210_HP_R_ZC (1 << 7)
/* AUX1_L bit fields */
#define DA7210_AUX1_L_VOL (0x3F << 0)
/* AUX1_R bit fields */
#define DA7210_AUX1_R_VOL (0x3F << 0)
/* Minimum INPGA and AUX1 volume to enable noise suppression */
#define DA7210_INPGA_MIN_VOL_NS 0x0A /* 10.5dB */
#define DA7210_AUX1_MIN_VOL_NS 0x35 /* 6dB */
/* OUT1_L bit fields */
#define DA7210_OUT1_L_EN (1 << 7)
/* OUT1_R bit fields */
#define DA7210_OUT1_R_EN (1 << 7)
/* OUT2 bit fields */
#define DA7210_OUT2_OUTMIX_R (1 << 5)
#define DA7210_OUT2_OUTMIX_L (1 << 6)
#define DA7210_OUT2_EN (1 << 7)
#define DA7210_VERSION "0.0.1" #define DA7210_VERSION "0.0.1"
/* /*
@ -144,24 +211,351 @@
* mute : 0x10 * mute : 0x10
* reserved : 0x00 - 0x0F * reserved : 0x00 - 0x0F
* *
* ** FIXME **
*
* Reserved area are considered as "mute". * Reserved area are considered as "mute".
* -> min = -79.5 dB
*/ */
static const DECLARE_TLV_DB_SCALE(hp_out_tlv, -7950, 150, 1); static const unsigned int hp_out_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -54 dB to +15 dB */
0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0),
};
static const unsigned int lineout_vol_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1),
/* -54dB to 15dB */
0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0)
};
static const unsigned int mono_vol_tlv[] = {
TLV_DB_RANGE_HEAD(2),
0x0, 0x2, TLV_DB_SCALE_ITEM(-1800, 0, 1),
/* -18dB to 6dB */
0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0)
};
static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0);
static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1);
static const DECLARE_TLV_DB_SCALE(dac_gain_tlv, -7725, 75, 0);
/* ADC and DAC high pass filter f0 value */
static const char const *da7210_hpf_cutoff_txt[] = {
"Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi"
};
static const struct soc_enum da7210_dac_hpf_cutoff =
SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt);
static const struct soc_enum da7210_adc_hpf_cutoff =
SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt);
/* ADC and DAC voice (8kHz) high pass cutoff value */
static const char const *da7210_vf_cutoff_txt[] = {
"2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz"
};
static const struct soc_enum da7210_dac_vf_cutoff =
SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt);
static const struct soc_enum da7210_adc_vf_cutoff =
SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt);
static const char *da7210_hp_mode_txt[] = {
"Class H", "Class G"
};
static const struct soc_enum da7210_hp_mode_sel =
SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt);
/* ALC can be enabled only if noise suppression is disabled */
static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
if (ucontrol->value.integer.value[0]) {
/* Check if noise suppression is enabled */
if (snd_soc_read(codec, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) {
dev_dbg(codec->dev,
"Disable noise suppression to enable ALC\n");
return -EINVAL;
}
}
/* If all conditions are met or we are actually disabling ALC */
return snd_soc_put_volsw(kcontrol, ucontrol);
}
/* Noise suppression can be enabled only if following conditions are met
* ALC disabled
* ZC enabled for HP and AUX1 PGA
* INPGA_L_VOL and INPGA_R_VOL >= 10.5 dB
* AUX1_L_VOL and AUX1_R_VOL >= 6 dB
*/
static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
u8 val;
if (ucontrol->value.integer.value[0]) {
/* Check if ALC is enabled */
if (snd_soc_read(codec, DA7210_ADC) & DA7210_ADC_ALC_EN)
goto err;
/* Check ZC for HP and AUX1 PGA */
if ((snd_soc_read(codec, DA7210_ZERO_CROSS) &
(DA7210_AUX1_L_ZC | DA7210_AUX1_R_ZC | DA7210_HP_L_ZC |
DA7210_HP_R_ZC)) != (DA7210_AUX1_L_ZC |
DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | DA7210_HP_R_ZC))
goto err;
/* Check INPGA_L_VOL and INPGA_R_VOL */
val = snd_soc_read(codec, DA7210_IN_GAIN);
if (((val & DA7210_INPGA_L_VOL) < DA7210_INPGA_MIN_VOL_NS) ||
(((val & DA7210_INPGA_R_VOL) >> 4) <
DA7210_INPGA_MIN_VOL_NS))
goto err;
/* Check AUX1_L_VOL and AUX1_R_VOL */
if (((snd_soc_read(codec, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) <
DA7210_AUX1_MIN_VOL_NS) ||
((snd_soc_read(codec, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) <
DA7210_AUX1_MIN_VOL_NS))
goto err;
}
/* If all conditions are met or we are actually disabling Noise sup */
return snd_soc_put_volsw(kcontrol, ucontrol);
err:
return -EINVAL;
}
static const struct snd_kcontrol_new da7210_snd_controls[] = { static const struct snd_kcontrol_new da7210_snd_controls[] = {
SOC_DOUBLE_R_TLV("HeadPhone Playback Volume", SOC_DOUBLE_R_TLV("HeadPhone Playback Volume",
DA7210_HP_L_VOL, DA7210_HP_R_VOL, DA7210_HP_L_VOL, DA7210_HP_R_VOL,
0, 0x3F, 0, hp_out_tlv), 0, 0x3F, 0, hp_out_tlv),
SOC_DOUBLE_R_TLV("Digital Playback Volume",
DA7210_DAC_L, DA7210_DAC_R,
0, 0x77, 1, dac_gain_tlv),
SOC_DOUBLE_R_TLV("Lineout Playback Volume",
DA7210_OUT1_L, DA7210_OUT1_R,
0, 0x3f, 0, lineout_vol_tlv),
SOC_SINGLE_TLV("Mono Playback Volume", DA7210_OUT2, 0, 0x7, 0,
mono_vol_tlv),
/* DAC Equalizer controls */
SOC_SINGLE("DAC EQ Switch", DA7210_DAC_EQ5, 7, 1, 0),
SOC_SINGLE_TLV("DAC EQ1 Volume", DA7210_DAC_EQ1_2, 0, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("DAC EQ2 Volume", DA7210_DAC_EQ1_2, 4, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("DAC EQ3 Volume", DA7210_DAC_EQ3_4, 0, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("DAC EQ4 Volume", DA7210_DAC_EQ3_4, 4, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("DAC EQ5 Volume", DA7210_DAC_EQ5, 0, 0xf, 1,
eq_gain_tlv),
/* ADC Equalizer controls */
SOC_SINGLE("ADC EQ Switch", DA7210_ADC_EQ5, 7, 1, 0),
SOC_SINGLE_TLV("ADC EQ Master Volume", DA7210_ADC_EQ5, 4, 0x3,
1, adc_eq_master_gain_tlv),
SOC_SINGLE_TLV("ADC EQ1 Volume", DA7210_ADC_EQ1_2, 0, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("ADC EQ2 Volume", DA7210_ADC_EQ1_2, 4, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("ADC EQ3 Volume", DA7210_ADC_EQ3_4, 0, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("ADC EQ4 Volume", DA7210_ADC_EQ3_4, 4, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE_TLV("ADC EQ5 Volume", DA7210_ADC_EQ5, 0, 0xf, 1,
eq_gain_tlv),
SOC_SINGLE("DAC HPF Switch", DA7210_DAC_HPF, 3, 1, 0),
SOC_ENUM("DAC HPF Cutoff", da7210_dac_hpf_cutoff),
SOC_SINGLE("DAC Voice Mode Switch", DA7210_DAC_HPF, 7, 1, 0),
SOC_ENUM("DAC Voice Cutoff", da7210_dac_vf_cutoff),
SOC_SINGLE("ADC HPF Switch", DA7210_ADC_HPF, 3, 1, 0),
SOC_ENUM("ADC HPF Cutoff", da7210_adc_hpf_cutoff),
SOC_SINGLE("ADC Voice Mode Switch", DA7210_ADC_HPF, 7, 1, 0),
SOC_ENUM("ADC Voice Cutoff", da7210_adc_vf_cutoff),
/* Mute controls */
SOC_DOUBLE_R("Mic Capture Switch", DA7210_MIC_L, DA7210_MIC_R, 3, 1, 0),
SOC_SINGLE("Aux2 Capture Switch", DA7210_AUX2, 2, 1, 0),
SOC_DOUBLE("ADC Capture Switch", DA7210_ADC, 2, 6, 1, 0),
SOC_SINGLE("Digital Soft Mute Switch", DA7210_SOFTMUTE, 7, 1, 0),
SOC_SINGLE("Digital Soft Mute Rate", DA7210_SOFTMUTE, 0, 0x7, 0),
/* Zero cross controls */
SOC_DOUBLE("Aux1 ZC Switch", DA7210_ZERO_CROSS, 0, 1, 1, 0),
SOC_DOUBLE("In PGA ZC Switch", DA7210_ZERO_CROSS, 2, 3, 1, 0),
SOC_DOUBLE("Lineout ZC Switch", DA7210_ZERO_CROSS, 4, 5, 1, 0),
SOC_DOUBLE("Headphone ZC Switch", DA7210_ZERO_CROSS, 6, 7, 1, 0),
SOC_ENUM("Headphone Class", da7210_hp_mode_sel),
/* ALC controls */
SOC_SINGLE_EXT("ALC Enable Switch", DA7210_ADC, 0, 1, 0,
snd_soc_get_volsw, da7210_put_alc_sw),
SOC_SINGLE("ALC Capture Max Volume", DA7210_ALC_MAX, 0, 0x3F, 0),
SOC_SINGLE("ALC Capture Min Volume", DA7210_ALC_MIN, 0, 0x3F, 0),
SOC_SINGLE("ALC Capture Noise Volume", DA7210_ALC_NOIS, 0, 0x3F, 0),
SOC_SINGLE("ALC Capture Attack Rate", DA7210_ALC_ATT, 0, 0xFF, 0),
SOC_SINGLE("ALC Capture Release Rate", DA7210_ALC_REL, 0, 0xFF, 0),
SOC_SINGLE("ALC Capture Release Delay", DA7210_ALC_DEL, 0, 0xFF, 0),
SOC_SINGLE_EXT("Noise Suppression Enable Switch", DA7210_CONTROL, 3, 1,
0, snd_soc_get_volsw, da7210_put_noise_sup_sw),
};
/*
* DAPM Controls
*
* Current DAPM implementation covers almost all codec components e.g. IOs,
* mixers, PGAs,ADC and DAC.
*/
/* In Mixer Left */
static const struct snd_kcontrol_new da7210_dapm_inmixl_controls[] = {
SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_L, 0, 1, 0),
SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_L, 1, 1, 0),
};
/* In Mixer Right */
static const struct snd_kcontrol_new da7210_dapm_inmixr_controls[] = {
SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_R, 0, 1, 0),
SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_R, 1, 1, 0),
};
/* Out Mixer Left */
static const struct snd_kcontrol_new da7210_dapm_outmixl_controls[] = {
SOC_DAPM_SINGLE("DAC Left Switch", DA7210_OUTMIX_L, 4, 1, 0),
};
/* Out Mixer Right */
static const struct snd_kcontrol_new da7210_dapm_outmixr_controls[] = {
SOC_DAPM_SINGLE("DAC Right Switch", DA7210_OUTMIX_R, 4, 1, 0),
};
/* Mono Mixer */
static const struct snd_kcontrol_new da7210_dapm_monomix_controls[] = {
SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_OUT2, 5, 1, 0),
SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_OUT2, 6, 1, 0),
};
/* DAPM widgets */
static const struct snd_soc_dapm_widget da7210_dapm_widgets[] = {
/* Input Side */
/* Input Lines */
SND_SOC_DAPM_INPUT("MICL"),
SND_SOC_DAPM_INPUT("MICR"),
/* Input PGAs */
SND_SOC_DAPM_PGA("Mic Left", DA7210_STARTUP3, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("Mic Right", DA7210_STARTUP3, 1, 1, NULL, 0),
SND_SOC_DAPM_PGA("INPGA Left", DA7210_INMIX_L, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA("INPGA Right", DA7210_INMIX_R, 7, 0, NULL, 0),
/* Input Mixers */
SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0,
&da7210_dapm_inmixl_controls[0],
ARRAY_SIZE(da7210_dapm_inmixl_controls)),
SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0,
&da7210_dapm_inmixr_controls[0],
ARRAY_SIZE(da7210_dapm_inmixr_controls)),
/* ADCs */
SND_SOC_DAPM_ADC("ADC Left", "Capture", DA7210_STARTUP3, 5, 1),
SND_SOC_DAPM_ADC("ADC Right", "Capture", DA7210_STARTUP3, 6, 1),
/* Output Side */
/* DACs */
SND_SOC_DAPM_DAC("DAC Left", "Playback", DA7210_STARTUP2, 5, 1),
SND_SOC_DAPM_DAC("DAC Right", "Playback", DA7210_STARTUP2, 6, 1),
/* Output Mixers */
SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0,
&da7210_dapm_outmixl_controls[0],
ARRAY_SIZE(da7210_dapm_outmixl_controls)),
SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0,
&da7210_dapm_outmixr_controls[0],
ARRAY_SIZE(da7210_dapm_outmixr_controls)),
SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0,
&da7210_dapm_monomix_controls[0],
ARRAY_SIZE(da7210_dapm_monomix_controls)),
/* Output PGAs */
SND_SOC_DAPM_PGA("OUTPGA Left Enable", DA7210_OUTMIX_L, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA("OUTPGA Right Enable", DA7210_OUTMIX_R, 7, 0, NULL, 0),
SND_SOC_DAPM_PGA("Out1 Left", DA7210_STARTUP2, 0, 1, NULL, 0),
SND_SOC_DAPM_PGA("Out1 Right", DA7210_STARTUP2, 1, 1, NULL, 0),
SND_SOC_DAPM_PGA("Out2 Mono", DA7210_STARTUP2, 2, 1, NULL, 0),
SND_SOC_DAPM_PGA("Headphone Left", DA7210_STARTUP2, 3, 1, NULL, 0),
SND_SOC_DAPM_PGA("Headphone Right", DA7210_STARTUP2, 4, 1, NULL, 0),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("OUT1L"),
SND_SOC_DAPM_OUTPUT("OUT1R"),
SND_SOC_DAPM_OUTPUT("HPL"),
SND_SOC_DAPM_OUTPUT("HPR"),
SND_SOC_DAPM_OUTPUT("OUT2"),
};
/* DAPM audio route definition */
static const struct snd_soc_dapm_route da7210_audio_map[] = {
/* Dest Connecting Widget source */
/* Input path */
{"Mic Left", NULL, "MICL"},
{"Mic Right", NULL, "MICR"},
{"In Mixer Left", "Mic Left Switch", "Mic Left"},
{"In Mixer Left", "Mic Right Switch", "Mic Right"},
{"In Mixer Right", "Mic Right Switch", "Mic Right"},
{"In Mixer Right", "Mic Left Switch", "Mic Left"},
{"INPGA Left", NULL, "In Mixer Left"},
{"ADC Left", NULL, "INPGA Left"},
{"INPGA Right", NULL, "In Mixer Right"},
{"ADC Right", NULL, "INPGA Right"},
/* Output path */
{"Out Mixer Left", "DAC Left Switch", "DAC Left"},
{"Out Mixer Right", "DAC Right Switch", "DAC Right"},
{"Mono Mixer", "Outmix Right Switch", "Out Mixer Right"},
{"Mono Mixer", "Outmix Left Switch", "Out Mixer Left"},
{"OUTPGA Left Enable", NULL, "Out Mixer Left"},
{"OUTPGA Right Enable", NULL, "Out Mixer Right"},
{"Out1 Left", NULL, "OUTPGA Left Enable"},
{"OUT1L", NULL, "Out1 Left"},
{"Out1 Right", NULL, "OUTPGA Right Enable"},
{"OUT1R", NULL, "Out1 Right"},
{"Headphone Left", NULL, "OUTPGA Left Enable"},
{"HPL", NULL, "Headphone Left"},
{"Headphone Right", NULL, "OUTPGA Right Enable"},
{"HPR", NULL, "Headphone Right"},
{"Out2 Mono", NULL, "Mono Mixer"},
{"OUT2", NULL, "Out2 Mono"},
}; };
/* Codec private data */ /* Codec private data */
struct da7210_priv { struct da7210_priv {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
}; };
/* /*
@ -188,72 +582,15 @@ static const u8 da7210_reg[] = {
0x00, /* R88 */ 0x00, /* R88 */
}; };
/* static int da7210_volatile_register(struct snd_soc_codec *codec,
* Read da7210 register cache unsigned int reg)
*/
static inline u32 da7210_read_reg_cache(struct snd_soc_codec *codec, u32 reg)
{ {
u8 *cache = codec->reg_cache; switch (reg) {
BUG_ON(reg >= ARRAY_SIZE(da7210_reg)); case DA7210_STATUS:
return cache[reg]; return 1;
} default:
/*
* Write to the da7210 register space
*/
static int da7210_write(struct snd_soc_codec *codec, u32 reg, u32 value)
{
u8 *cache = codec->reg_cache;
u8 data[2];
BUG_ON(codec->driver->volatile_register);
data[0] = reg & 0xff;
data[1] = value & 0xff;
if (reg >= codec->driver->reg_cache_size)
return -EIO;
if (2 != codec->hw_write(codec->control_data, data, 2))
return -EIO;
cache[reg] = value;
return 0; return 0;
} }
/*
* Read from the da7210 register space.
*/
static inline u32 da7210_read(struct snd_soc_codec *codec, u32 reg)
{
if (DA7210_STATUS == reg)
return i2c_smbus_read_byte_data(codec->control_data, reg);
return da7210_read_reg_cache(codec, reg);
}
static int da7210_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
struct snd_soc_codec *codec = dai->codec;
if (is_play) {
/* Enable Out */
snd_soc_update_bits(codec, DA7210_OUTMIX_L, 0x1F, 0x10);
snd_soc_update_bits(codec, DA7210_OUTMIX_R, 0x1F, 0x10);
} else {
/* Volume 7 */
snd_soc_update_bits(codec, DA7210_MIC_L, 0x7, 0x7);
snd_soc_update_bits(codec, DA7210_MIC_R, 0x7, 0x7);
/* Enable Mic */
snd_soc_update_bits(codec, DA7210_INMIX_L, 0x1F, 0x1);
snd_soc_update_bits(codec, DA7210_INMIX_R, 0x1F, 0x1);
}
return 0;
} }
/* /*
@ -266,93 +603,75 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
u32 dai_cfg1; u32 dai_cfg1;
u32 hpf_reg, hpf_mask, hpf_value;
u32 fs, bypass; u32 fs, bypass;
/* set DAI source to Left and Right ADC */ /* set DAI source to Left and Right ADC */
da7210_write(codec, DA7210_DAI_SRC_SEL, snd_soc_write(codec, DA7210_DAI_SRC_SEL,
DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC); DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC);
/* Enable DAI */ /* Enable DAI */
da7210_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN); snd_soc_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN);
dai_cfg1 = 0xFC & da7210_read(codec, DA7210_DAI_CFG1); dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1);
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
dai_cfg1 |= DA7210_DAI_WORD_S16_LE; dai_cfg1 |= DA7210_DAI_WORD_S16_LE;
break; break;
case SNDRV_PCM_FORMAT_S20_3LE:
dai_cfg1 |= DA7210_DAI_WORD_S20_3LE;
break;
case SNDRV_PCM_FORMAT_S24_LE: case SNDRV_PCM_FORMAT_S24_LE:
dai_cfg1 |= DA7210_DAI_WORD_S24_LE; dai_cfg1 |= DA7210_DAI_WORD_S24_LE;
break; break;
case SNDRV_PCM_FORMAT_S32_LE:
dai_cfg1 |= DA7210_DAI_WORD_S32_LE;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1); snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1);
hpf_reg = (SNDRV_PCM_STREAM_PLAYBACK == substream->stream) ?
DA7210_DAC_HPF : DA7210_ADC_HPF;
switch (params_rate(params)) { switch (params_rate(params)) {
case 8000: case 8000:
fs = DA7210_PLL_FS_8000; fs = DA7210_PLL_FS_8000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP; bypass = DA7210_PLL_BYP;
break; break;
case 11025: case 11025:
fs = DA7210_PLL_FS_11025; fs = DA7210_PLL_FS_11025;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = 0; bypass = 0;
break; break;
case 12000: case 12000:
fs = DA7210_PLL_FS_12000; fs = DA7210_PLL_FS_12000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP; bypass = DA7210_PLL_BYP;
break; break;
case 16000: case 16000:
fs = DA7210_PLL_FS_16000; fs = DA7210_PLL_FS_16000;
hpf_mask = DA7210_VOICE_F0_MASK | DA7210_VOICE_EN;
hpf_value = DA7210_VOICE_F0_25 | DA7210_VOICE_EN;
bypass = DA7210_PLL_BYP; bypass = DA7210_PLL_BYP;
break; break;
case 22050: case 22050:
fs = DA7210_PLL_FS_22050; fs = DA7210_PLL_FS_22050;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = 0; bypass = 0;
break; break;
case 32000: case 32000:
fs = DA7210_PLL_FS_32000; fs = DA7210_PLL_FS_32000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = DA7210_PLL_BYP; bypass = DA7210_PLL_BYP;
break; break;
case 44100: case 44100:
fs = DA7210_PLL_FS_44100; fs = DA7210_PLL_FS_44100;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = 0; bypass = 0;
break; break;
case 48000: case 48000:
fs = DA7210_PLL_FS_48000; fs = DA7210_PLL_FS_48000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = DA7210_PLL_BYP; bypass = DA7210_PLL_BYP;
break; break;
case 88200: case 88200:
fs = DA7210_PLL_FS_88200; fs = DA7210_PLL_FS_88200;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = 0; bypass = 0;
break; break;
case 96000: case 96000:
fs = DA7210_PLL_FS_96000; fs = DA7210_PLL_FS_96000;
hpf_mask = DA7210_VOICE_EN;
hpf_value = 0;
bypass = DA7210_PLL_BYP; bypass = DA7210_PLL_BYP;
break; break;
default: default:
@ -362,7 +681,6 @@ static int da7210_hw_params(struct snd_pcm_substream *substream,
/* Disable active mode */ /* Disable active mode */
snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0); snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0);
snd_soc_update_bits(codec, hpf_reg, hpf_mask, hpf_value);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs); snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs);
snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass); snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, bypass);
@ -382,13 +700,16 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
u32 dai_cfg1; u32 dai_cfg1;
u32 dai_cfg3; u32 dai_cfg3;
dai_cfg1 = 0x7f & da7210_read(codec, DA7210_DAI_CFG1); dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1);
dai_cfg3 = 0xfc & da7210_read(codec, DA7210_DAI_CFG3); dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3);
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM: case SND_SOC_DAIFMT_CBM_CFM:
dai_cfg1 |= DA7210_DAI_MODE_MASTER; dai_cfg1 |= DA7210_DAI_MODE_MASTER;
break; break;
case SND_SOC_DAIFMT_CBS_CFS:
dai_cfg1 |= DA7210_DAI_MODE_SLAVE;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -401,6 +722,12 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
case SND_SOC_DAIFMT_I2S: case SND_SOC_DAIFMT_I2S:
dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE; dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE;
break; break;
case SND_SOC_DAIFMT_LEFT_J:
dai_cfg3 |= DA7210_DAI_FORMAT_LEFT_J;
break;
case SND_SOC_DAIFMT_RIGHT_J:
dai_cfg3 |= DA7210_DAI_FORMAT_RIGHT_J;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -411,19 +738,32 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt)
*/ */
dai_cfg1 |= DA7210_DAI_FLEN_64BIT; dai_cfg1 |= DA7210_DAI_FLEN_64BIT;
da7210_write(codec, DA7210_DAI_CFG1, dai_cfg1); snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1);
da7210_write(codec, DA7210_DAI_CFG3, dai_cfg3); snd_soc_write(codec, DA7210_DAI_CFG3, dai_cfg3);
return 0; return 0;
} }
#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) static int da7210_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
u8 mute_reg = snd_soc_read(codec, DA7210_DAC_HPF) & 0xFB;
if (mute)
snd_soc_write(codec, DA7210_DAC_HPF, mute_reg | 0x4);
else
snd_soc_write(codec, DA7210_DAC_HPF, mute_reg);
return 0;
}
#define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE)
/* DAI operations */ /* DAI operations */
static struct snd_soc_dai_ops da7210_dai_ops = { static struct snd_soc_dai_ops da7210_dai_ops = {
.startup = da7210_startup,
.hw_params = da7210_hw_params, .hw_params = da7210_hw_params,
.set_fmt = da7210_set_dai_fmt, .set_fmt = da7210_set_dai_fmt,
.digital_mute = da7210_mute,
}; };
static struct snd_soc_dai_driver da7210_dai = { static struct snd_soc_dai_driver da7210_dai = {
@ -451,11 +791,15 @@ static struct snd_soc_dai_driver da7210_dai = {
static int da7210_probe(struct snd_soc_codec *codec) static int da7210_probe(struct snd_soc_codec *codec)
{ {
struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec);
int ret;
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
codec->control_data = da7210->control_data; ret = snd_soc_codec_set_cache_io(codec, 8, 8, da7210->control_type);
codec->hw_write = (hw_write_t)i2c_master_send; if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
/* FIXME /* FIXME
* *
@ -472,8 +816,8 @@ static int da7210_probe(struct snd_soc_codec *codec)
/* /*
* make sure that DA7210 use bypass mode before start up * make sure that DA7210 use bypass mode before start up
*/ */
da7210_write(codec, DA7210_STARTUP1, 0); snd_soc_write(codec, DA7210_STARTUP1, 0);
da7210_write(codec, DA7210_PLL_DIV3, snd_soc_write(codec, DA7210_PLL_DIV3,
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP); DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
/* /*
@ -481,36 +825,70 @@ static int da7210_probe(struct snd_soc_codec *codec)
*/ */
/* Enable Left & Right MIC PGA and Mic Bias */ /* Enable Left & Right MIC PGA and Mic Bias */
da7210_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN); snd_soc_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN);
da7210_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN); snd_soc_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN);
/* Enable Left and Right input PGA */ /* Enable Left and Right input PGA */
da7210_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN); snd_soc_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN);
da7210_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN); snd_soc_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN);
/* Enable Left and Right ADC */ /* Enable Left and Right ADC */
da7210_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN); snd_soc_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN);
/* /*
* DAC settings * DAC settings
*/ */
/* Enable Left and Right DAC */ /* Enable Left and Right DAC */
da7210_write(codec, DA7210_DAC_SEL, snd_soc_write(codec, DA7210_DAC_SEL,
DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN | DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN |
DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN); DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN);
/* Enable Left and Right out PGA */ /* Enable Left and Right out PGA */
da7210_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN); snd_soc_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN);
da7210_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN); snd_soc_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN);
/* Enable Left and Right HeadPhone PGA */ /* Enable Left and Right HeadPhone PGA */
da7210_write(codec, DA7210_HP_CFG, snd_soc_write(codec, DA7210_HP_CFG,
DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN | DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN |
DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN); DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN);
/* Enable ramp mode for DAC gain update */
snd_soc_write(codec, DA7210_SOFTMUTE, DA7210_RAMP_EN);
/*
* For DA7210 codec, there are two ways to enable/disable analog IOs
* and ADC/DAC,
* (1) Using "Enable Bit" of register associated with that IO
* (or ADC/DAC)
* e.g. Mic Left can be enabled using bit 7 of MIC_L(0x7) reg
*
* (2) Using "Standby Bit" of STARTUP2 or STARTUP3 register
* e.g. Mic left can be put to STANDBY using bit 0 of STARTUP3(0x5)
*
* Out of these two methods, the one using STANDBY bits is preferred
* way to enable/disable individual blocks. This is because STANDBY
* registers are part of system controller which allows system power
* up/down in a controlled, pop-free manner. Also, as per application
* note of DA7210, STANDBY register bits are only effective if a
* particular IO (or ADC/DAC) is already enabled using enable/disable
* register bits. Keeping these things in mind, current DAPM
* implementation manipulates only STANDBY bits.
*
* Overall implementation can be outlined as below,
*
* - "Enable bit" of an IO or ADC/DAC is used to enable it in probe()
* - "STANDBY bit" is controlled by DAPM
*/
/* Enable Line out amplifiers */
snd_soc_write(codec, DA7210_OUT1_L, DA7210_OUT1_L_EN);
snd_soc_write(codec, DA7210_OUT1_R, DA7210_OUT1_R_EN);
snd_soc_write(codec, DA7210_OUT2, DA7210_OUT2_EN |
DA7210_OUT2_OUTMIX_L | DA7210_OUT2_OUTMIX_R);
/* Diable PLL and bypass it */ /* Diable PLL and bypass it */
da7210_write(codec, DA7210_PLL, DA7210_PLL_FS_48000); snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000);
/* /*
* If 48kHz sound came, it use bypass mode, * If 48kHz sound came, it use bypass mode,
@ -521,25 +899,22 @@ static int da7210_probe(struct snd_soc_codec *codec)
* DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit. * DA7210_PLL_DIV3 :: DA7210_PLL_BYP bit.
* see da7210_hw_params * see da7210_hw_params
*/ */
da7210_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */ snd_soc_write(codec, DA7210_PLL_DIV1, 0xE5); /* MCLK = 12.288MHz */
da7210_write(codec, DA7210_PLL_DIV2, 0x99); snd_soc_write(codec, DA7210_PLL_DIV2, 0x99);
da7210_write(codec, DA7210_PLL_DIV3, 0x0A | snd_soc_write(codec, DA7210_PLL_DIV3, 0x0A |
DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP); DA7210_MCLK_RANGE_10_20_MHZ | DA7210_PLL_BYP);
snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN); snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN);
/* As suggested by Dialog */ /* As suggested by Dialog */
da7210_write(codec, DA7210_A_HID_UNLOCK, 0x8B); /* unlock */ snd_soc_write(codec, DA7210_A_HID_UNLOCK, 0x8B); /* unlock */
da7210_write(codec, DA7210_A_TEST_UNLOCK, 0xB4); snd_soc_write(codec, DA7210_A_TEST_UNLOCK, 0xB4);
da7210_write(codec, DA7210_A_PLL1, 0x01); snd_soc_write(codec, DA7210_A_PLL1, 0x01);
da7210_write(codec, DA7210_A_CP_MODE, 0x7C); snd_soc_write(codec, DA7210_A_CP_MODE, 0x7C);
da7210_write(codec, DA7210_A_HID_UNLOCK, 0x00); /* re-lock */ snd_soc_write(codec, DA7210_A_HID_UNLOCK, 0x00); /* re-lock */
da7210_write(codec, DA7210_A_TEST_UNLOCK, 0x00); snd_soc_write(codec, DA7210_A_TEST_UNLOCK, 0x00);
/* Activate all enabled subsystem */ /* Activate all enabled subsystem */
da7210_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN); snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN);
snd_soc_add_controls(codec, da7210_snd_controls,
ARRAY_SIZE(da7210_snd_controls));
dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION);
@ -548,11 +923,18 @@ static int da7210_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_da7210 = { static struct snd_soc_codec_driver soc_codec_dev_da7210 = {
.probe = da7210_probe, .probe = da7210_probe,
.read = da7210_read,
.write = da7210_write,
.reg_cache_size = ARRAY_SIZE(da7210_reg), .reg_cache_size = ARRAY_SIZE(da7210_reg),
.reg_word_size = sizeof(u8), .reg_word_size = sizeof(u8),
.reg_cache_default = da7210_reg, .reg_cache_default = da7210_reg,
.volatile_register = da7210_volatile_register,
.controls = da7210_snd_controls,
.num_controls = ARRAY_SIZE(da7210_snd_controls),
.dapm_widgets = da7210_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(da7210_dapm_widgets),
.dapm_routes = da7210_audio_map,
.num_dapm_routes = ARRAY_SIZE(da7210_audio_map),
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@ -567,7 +949,6 @@ static int __devinit da7210_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(i2c, da7210); i2c_set_clientdata(i2c, da7210);
da7210->control_data = i2c;
da7210->control_type = SND_SOC_I2C; da7210->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -3,7 +3,7 @@
* *
* Copyright 2007 Wolfson Microelectronics PLC. * Copyright 2007 Wolfson Microelectronics PLC.
* Author: Graeme Gregory * Author: Graeme Gregory
* graeme.gregory@wolfsonmicro.com or linux@wolfsonmicro.com * graeme.gregory@wolfsonmicro.com
* Copyright 2011 Lars-Peter Clausen <lars@metafoo.de> * Copyright 2011 Lars-Peter Clausen <lars@metafoo.de>
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@ -40,7 +40,6 @@ struct max98088_cdata {
struct max98088_priv { struct max98088_priv {
enum max98088_type devtype; enum max98088_type devtype;
void *control_data;
struct max98088_pdata *pdata; struct max98088_pdata *pdata;
unsigned int sysclk; unsigned int sysclk;
struct max98088_cdata dai[2]; struct max98088_cdata dai[2];
@ -1697,12 +1696,18 @@ static struct snd_soc_dai_driver max98088_dai[] = {
} }
}; };
static int max98088_get_channel(const char *name) static const char *eq_mode_name[] = {"EQ1 Mode", "EQ2 Mode"};
static int max98088_get_channel(struct snd_soc_codec *codec, const char *name)
{ {
if (strcmp(name, "EQ1 Mode") == 0) int i;
return 0;
if (strcmp(name, "EQ2 Mode") == 0) for (i = 0; i < ARRAY_SIZE(eq_mode_name); i++)
return 1; if (strcmp(name, eq_mode_name[i]) == 0)
return i;
/* Shouldn't happen */
dev_err(codec->dev, "Bad EQ channel name '%s'\n", name);
return -EINVAL; return -EINVAL;
} }
@ -1807,10 +1812,13 @@ static int max98088_put_eq_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
struct max98088_pdata *pdata = max98088->pdata; struct max98088_pdata *pdata = max98088->pdata;
int channel = max98088_get_channel(kcontrol->id.name); int channel = max98088_get_channel(codec, kcontrol->id.name);
struct max98088_cdata *cdata; struct max98088_cdata *cdata;
int sel = ucontrol->value.integer.value[0]; int sel = ucontrol->value.integer.value[0];
if (channel < 0)
return channel;
cdata = &max98088->dai[channel]; cdata = &max98088->dai[channel];
if (sel >= pdata->eq_cfgcnt) if (sel >= pdata->eq_cfgcnt)
@ -1835,9 +1843,12 @@ static int max98088_get_eq_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec); struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
int channel = max98088_get_channel(kcontrol->id.name); int channel = max98088_get_channel(codec, kcontrol->id.name);
struct max98088_cdata *cdata; struct max98088_cdata *cdata;
if (channel < 0)
return channel;
cdata = &max98088->dai[channel]; cdata = &max98088->dai[channel];
ucontrol->value.enumerated.item[0] = cdata->eq_sel; ucontrol->value.enumerated.item[0] = cdata->eq_sel;
return 0; return 0;
@ -1852,17 +1863,17 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec)
int i, j; int i, j;
const char **t; const char **t;
int ret; int ret;
struct snd_kcontrol_new controls[] = { struct snd_kcontrol_new controls[] = {
SOC_ENUM_EXT("EQ1 Mode", SOC_ENUM_EXT((char *)eq_mode_name[0],
max98088->eq_enum, max98088->eq_enum,
max98088_get_eq_enum, max98088_get_eq_enum,
max98088_put_eq_enum), max98088_put_eq_enum),
SOC_ENUM_EXT("EQ2 Mode", SOC_ENUM_EXT((char *)eq_mode_name[1],
max98088->eq_enum, max98088->eq_enum,
max98088_get_eq_enum, max98088_get_eq_enum,
max98088_put_eq_enum), max98088_put_eq_enum),
}; };
BUILD_BUG_ON(ARRAY_SIZE(controls) != ARRAY_SIZE(eq_mode_name));
cfg = pdata->eq_cfg; cfg = pdata->eq_cfg;
cfgcnt = pdata->eq_cfgcnt; cfgcnt = pdata->eq_cfgcnt;
@ -2066,7 +2077,6 @@ static int max98088_i2c_probe(struct i2c_client *i2c,
max98088->devtype = id->driver_data; max98088->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98088); i2c_set_clientdata(i2c, max98088);
max98088->control_data = i2c;
max98088->pdata = i2c->dev.platform_data; max98088->pdata = i2c->dev.platform_data;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -40,7 +40,6 @@ struct max98095_cdata {
struct max98095_priv { struct max98095_priv {
enum max98095_type devtype; enum max98095_type devtype;
void *control_data;
struct max98095_pdata *pdata; struct max98095_pdata *pdata;
unsigned int sysclk; unsigned int sysclk;
struct max98095_cdata dai[3]; struct max98095_cdata dai[3];
@ -618,14 +617,13 @@ static int max98095_volatile(struct snd_soc_codec *codec, unsigned int reg)
static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg, static int max98095_hw_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value) unsigned int value)
{ {
u8 data[2]; int ret;
data[0] = reg; codec->cache_bypass = 1;
data[1] = value; ret = snd_soc_write(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2) codec->cache_bypass = 0;
return 0;
else return ret ? -EIO : 0;
return -EIO;
} }
/* /*
@ -1992,12 +1990,19 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec)
dev_err(codec->dev, "Failed to add EQ control: %d\n", ret); dev_err(codec->dev, "Failed to add EQ control: %d\n", ret);
} }
static int max98095_get_bq_channel(const char *name) static const char *bq_mode_name[] = {"Biquad1 Mode", "Biquad2 Mode"};
static int max98095_get_bq_channel(struct snd_soc_codec *codec,
const char *name)
{ {
if (strcmp(name, "Biquad1 Mode") == 0) int i;
return 0;
if (strcmp(name, "Biquad2 Mode") == 0) for (i = 0; i < ARRAY_SIZE(bq_mode_name); i++)
return 1; if (strcmp(name, bq_mode_name[i]) == 0)
return i;
/* Shouldn't happen */
dev_err(codec->dev, "Bad biquad channel name '%s'\n", name);
return -EINVAL; return -EINVAL;
} }
@ -2007,14 +2012,15 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct max98095_pdata *pdata = max98095->pdata; struct max98095_pdata *pdata = max98095->pdata;
int channel = max98095_get_bq_channel(kcontrol->id.name); int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata; struct max98095_cdata *cdata;
int sel = ucontrol->value.integer.value[0]; int sel = ucontrol->value.integer.value[0];
struct max98095_biquad_cfg *coef_set; struct max98095_biquad_cfg *coef_set;
int fs, best, best_val, i; int fs, best, best_val, i;
int regmask, regsave; int regmask, regsave;
BUG_ON(channel > 1); if (channel < 0)
return channel;
if (!pdata || !max98095->bq_textcnt) if (!pdata || !max98095->bq_textcnt)
return 0; return 0;
@ -2066,9 +2072,12 @@ static int max98095_get_bq_enum(struct snd_kcontrol *kcontrol,
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec); struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
int channel = max98095_get_bq_channel(kcontrol->id.name); int channel = max98095_get_bq_channel(codec, kcontrol->id.name);
struct max98095_cdata *cdata; struct max98095_cdata *cdata;
if (channel < 0)
return channel;
cdata = &max98095->dai[channel]; cdata = &max98095->dai[channel];
ucontrol->value.enumerated.item[0] = cdata->bq_sel; ucontrol->value.enumerated.item[0] = cdata->bq_sel;
@ -2086,15 +2095,16 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec)
int ret; int ret;
struct snd_kcontrol_new controls[] = { struct snd_kcontrol_new controls[] = {
SOC_ENUM_EXT("Biquad1 Mode", SOC_ENUM_EXT((char *)bq_mode_name[0],
max98095->bq_enum, max98095->bq_enum,
max98095_get_bq_enum, max98095_get_bq_enum,
max98095_put_bq_enum), max98095_put_bq_enum),
SOC_ENUM_EXT("Biquad2 Mode", SOC_ENUM_EXT((char *)bq_mode_name[1],
max98095->bq_enum, max98095->bq_enum,
max98095_get_bq_enum, max98095_get_bq_enum,
max98095_put_bq_enum), max98095_put_bq_enum),
}; };
BUILD_BUG_ON(ARRAY_SIZE(controls) != ARRAY_SIZE(bq_mode_name));
cfg = pdata->bq_cfg; cfg = pdata->bq_cfg;
cfgcnt = pdata->bq_cfgcnt; cfgcnt = pdata->bq_cfgcnt;
@ -2337,7 +2347,6 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
max98095->devtype = id->driver_data; max98095->devtype = id->driver_data;
i2c_set_clientdata(i2c, max98095); i2c_set_clientdata(i2c, max98095);
max98095->control_data = i2c;
max98095->pdata = i2c->dev.platform_data; max98095->pdata = i2c->dev.platform_data;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095, ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_max98095,

1773
sound/soc/codecs/rt5631.c Normal file

File diff suppressed because it is too large Load Diff

701
sound/soc/codecs/rt5631.h Normal file
View File

@ -0,0 +1,701 @@
#ifndef __RTCODEC5631_H__
#define __RTCODEC5631_H__
#define RT5631_RESET 0x00
#define RT5631_SPK_OUT_VOL 0x02
#define RT5631_HP_OUT_VOL 0x04
#define RT5631_MONO_AXO_1_2_VOL 0x06
#define RT5631_AUX_IN_VOL 0x0A
#define RT5631_STEREO_DAC_VOL_1 0x0C
#define RT5631_MIC_CTRL_1 0x0E
#define RT5631_STEREO_DAC_VOL_2 0x10
#define RT5631_ADC_CTRL_1 0x12
#define RT5631_ADC_REC_MIXER 0x14
#define RT5631_ADC_CTRL_2 0x16
#define RT5631_VDAC_DIG_VOL 0x18
#define RT5631_OUTMIXER_L_CTRL 0x1A
#define RT5631_OUTMIXER_R_CTRL 0x1C
#define RT5631_AXO1MIXER_CTRL 0x1E
#define RT5631_AXO2MIXER_CTRL 0x20
#define RT5631_MIC_CTRL_2 0x22
#define RT5631_DIG_MIC_CTRL 0x24
#define RT5631_MONO_INPUT_VOL 0x26
#define RT5631_SPK_MIXER_CTRL 0x28
#define RT5631_SPK_MONO_OUT_CTRL 0x2A
#define RT5631_SPK_MONO_HP_OUT_CTRL 0x2C
#define RT5631_SDP_CTRL 0x34
#define RT5631_MONO_SDP_CTRL 0x36
#define RT5631_STEREO_AD_DA_CLK_CTRL 0x38
#define RT5631_PWR_MANAG_ADD1 0x3A
#define RT5631_PWR_MANAG_ADD2 0x3B
#define RT5631_PWR_MANAG_ADD3 0x3C
#define RT5631_PWR_MANAG_ADD4 0x3E
#define RT5631_GEN_PUR_CTRL_REG 0x40
#define RT5631_GLOBAL_CLK_CTRL 0x42
#define RT5631_PLL_CTRL 0x44
#define RT5631_INT_ST_IRQ_CTRL_1 0x48
#define RT5631_INT_ST_IRQ_CTRL_2 0x4A
#define RT5631_GPIO_CTRL 0x4C
#define RT5631_MISC_CTRL 0x52
#define RT5631_DEPOP_FUN_CTRL_1 0x54
#define RT5631_DEPOP_FUN_CTRL_2 0x56
#define RT5631_JACK_DET_CTRL 0x5A
#define RT5631_SOFT_VOL_CTRL 0x5C
#define RT5631_ALC_CTRL_1 0x64
#define RT5631_ALC_CTRL_2 0x65
#define RT5631_ALC_CTRL_3 0x66
#define RT5631_PSEUDO_SPATL_CTRL 0x68
#define RT5631_INDEX_ADD 0x6A
#define RT5631_INDEX_DATA 0x6C
#define RT5631_EQ_CTRL 0x6E
#define RT5631_VENDOR_ID 0x7A
#define RT5631_VENDOR_ID1 0x7C
#define RT5631_VENDOR_ID2 0x7E
/* Index of Codec Private Register definition */
#define RT5631_EQ_BW_LOP 0x00
#define RT5631_EQ_GAIN_LOP 0x01
#define RT5631_EQ_FC_BP1 0x02
#define RT5631_EQ_BW_BP1 0x03
#define RT5631_EQ_GAIN_BP1 0x04
#define RT5631_EQ_FC_BP2 0x05
#define RT5631_EQ_BW_BP2 0x06
#define RT5631_EQ_GAIN_BP2 0x07
#define RT5631_EQ_FC_BP3 0x08
#define RT5631_EQ_BW_BP3 0x09
#define RT5631_EQ_GAIN_BP3 0x0a
#define RT5631_EQ_BW_HIP 0x0b
#define RT5631_EQ_GAIN_HIP 0x0c
#define RT5631_EQ_HPF_A1 0x0d
#define RT5631_EQ_HPF_A2 0x0e
#define RT5631_EQ_HPF_GAIN 0x0f
#define RT5631_EQ_PRE_VOL_CTRL 0x11
#define RT5631_EQ_POST_VOL_CTRL 0x12
#define RT5631_TEST_MODE_CTRL 0x39
#define RT5631_CP_INTL_REG2 0x45
#define RT5631_ADDA_MIXER_INTL_REG3 0x52
#define RT5631_SPK_INTL_CTRL 0x56
/* global definition */
#define RT5631_L_MUTE (0x1 << 15)
#define RT5631_L_MUTE_SHIFT 15
#define RT5631_L_EN (0x1 << 14)
#define RT5631_L_EN_SHIFT 14
#define RT5631_R_MUTE (0x1 << 7)
#define RT5631_R_MUTE_SHIFT 7
#define RT5631_R_EN (0x1 << 6)
#define RT5631_R_EN_SHIFT 6
#define RT5631_VOL_MASK 0x1f
#define RT5631_L_VOL_SHIFT 8
#define RT5631_R_VOL_SHIFT 0
/* Speaker Output Control(0x02) */
#define RT5631_SPK_L_VOL_SEL_MASK (0x1 << 14)
#define RT5631_SPK_L_VOL_SEL_VMID (0x0 << 14)
#define RT5631_SPK_L_VOL_SEL_SPKMIX_L (0x1 << 14)
#define RT5631_SPK_R_VOL_SEL_MASK (0x1 << 6)
#define RT5631_SPK_R_VOL_SEL_VMID (0x0 << 6)
#define RT5631_SPK_R_VOL_SEL_SPKMIX_R (0x1 << 6)
/* Headphone Output Control(0x04) */
#define RT5631_HP_L_VOL_SEL_MASK (0x1 << 14)
#define RT5631_HP_L_VOL_SEL_VMID (0x0 << 14)
#define RT5631_HP_L_VOL_SEL_OUTMIX_L (0x1 << 14)
#define RT5631_HP_R_VOL_SEL_MASK (0x1 << 6)
#define RT5631_HP_R_VOL_SEL_VMID (0x0 << 6)
#define RT5631_HP_R_VOL_SEL_OUTMIX_R (0x1 << 6)
/* Output Control for AUXOUT/MONO(0x06) */
#define RT5631_AUXOUT_1_VOL_SEL_MASK (0x1 << 14)
#define RT5631_AUXOUT_1_VOL_SEL_VMID (0x0 << 14)
#define RT5631_AUXOUT_1_VOL_SEL_OUTMIX_L (0x1 << 14)
#define RT5631_MUTE_MONO (0x1 << 13)
#define RT5631_MUTE_MONO_SHIFT 13
#define RT5631_AUXOUT_2_VOL_SEL_MASK (0x1 << 6)
#define RT5631_AUXOUT_2_VOL_SEL_VMID (0x0 << 6)
#define RT5631_AUXOUT_2_VOL_SEL_OUTMIX_R (0x1 << 6)
/* Microphone Input Control 1(0x0E) */
#define RT5631_MIC1_DIFF_INPUT_CTRL (0x1 << 15)
#define RT5631_MIC1_DIFF_INPUT_SHIFT 15
#define RT5631_MIC2_DIFF_INPUT_CTRL (0x1 << 7)
#define RT5631_MIC2_DIFF_INPUT_SHIFT 7
/* Stereo DAC Digital Volume2(0x10) */
#define RT5631_DAC_VOL_MASK 0xff
/* ADC Recording Mixer Control(0x14) */
#define RT5631_M_OUTMIXER_L_TO_RECMIXER_L (0x1 << 15)
#define RT5631_M_OUTMIXL_RECMIXL_BIT 15
#define RT5631_M_MIC1_TO_RECMIXER_L (0x1 << 14)
#define RT5631_M_MIC1_RECMIXL_BIT 14
#define RT5631_M_AXIL_TO_RECMIXER_L (0x1 << 13)
#define RT5631_M_AXIL_RECMIXL_BIT 13
#define RT5631_M_MONO_IN_TO_RECMIXER_L (0x1 << 12)
#define RT5631_M_MONO_IN_RECMIXL_BIT 12
#define RT5631_M_OUTMIXER_R_TO_RECMIXER_R (0x1 << 7)
#define RT5631_M_OUTMIXR_RECMIXR_BIT 7
#define RT5631_M_MIC2_TO_RECMIXER_R (0x1 << 6)
#define RT5631_M_MIC2_RECMIXR_BIT 6
#define RT5631_M_AXIR_TO_RECMIXER_R (0x1 << 5)
#define RT5631_M_AXIR_RECMIXR_BIT 5
#define RT5631_M_MONO_IN_TO_RECMIXER_R (0x1 << 4)
#define RT5631_M_MONO_IN_RECMIXR_BIT 4
/* Left Output Mixer Control(0x1A) */
#define RT5631_M_RECMIXER_L_TO_OUTMIXER_L (0x1 << 15)
#define RT5631_M_RECMIXL_OUTMIXL_BIT 15
#define RT5631_M_RECMIXER_R_TO_OUTMIXER_L (0x1 << 14)
#define RT5631_M_RECMIXR_OUTMIXL_BIT 14
#define RT5631_M_DAC_L_TO_OUTMIXER_L (0x1 << 13)
#define RT5631_M_DACL_OUTMIXL_BIT 13
#define RT5631_M_MIC1_TO_OUTMIXER_L (0x1 << 12)
#define RT5631_M_MIC1_OUTMIXL_BIT 12
#define RT5631_M_MIC2_TO_OUTMIXER_L (0x1 << 11)
#define RT5631_M_MIC2_OUTMIXL_BIT 11
#define RT5631_M_MONO_IN_P_TO_OUTMIXER_L (0x1 << 10)
#define RT5631_M_MONO_INP_OUTMIXL_BIT 10
#define RT5631_M_AXIL_TO_OUTMIXER_L (0x1 << 9)
#define RT5631_M_AXIL_OUTMIXL_BIT 9
#define RT5631_M_AXIR_TO_OUTMIXER_L (0x1 << 8)
#define RT5631_M_AXIR_OUTMIXL_BIT 8
#define RT5631_M_VDAC_TO_OUTMIXER_L (0x1 << 7)
#define RT5631_M_VDAC_OUTMIXL_BIT 7
/* Right Output Mixer Control(0x1C) */
#define RT5631_M_RECMIXER_L_TO_OUTMIXER_R (0x1 << 15)
#define RT5631_M_RECMIXL_OUTMIXR_BIT 15
#define RT5631_M_RECMIXER_R_TO_OUTMIXER_R (0x1 << 14)
#define RT5631_M_RECMIXR_OUTMIXR_BIT 14
#define RT5631_M_DAC_R_TO_OUTMIXER_R (0x1 << 13)
#define RT5631_M_DACR_OUTMIXR_BIT 13
#define RT5631_M_MIC1_TO_OUTMIXER_R (0x1 << 12)
#define RT5631_M_MIC1_OUTMIXR_BIT 12
#define RT5631_M_MIC2_TO_OUTMIXER_R (0x1 << 11)
#define RT5631_M_MIC2_OUTMIXR_BIT 11
#define RT5631_M_MONO_IN_N_TO_OUTMIXER_R (0x1 << 10)
#define RT5631_M_MONO_INN_OUTMIXR_BIT 10
#define RT5631_M_AXIL_TO_OUTMIXER_R (0x1 << 9)
#define RT5631_M_AXIL_OUTMIXR_BIT 9
#define RT5631_M_AXIR_TO_OUTMIXER_R (0x1 << 8)
#define RT5631_M_AXIR_OUTMIXR_BIT 8
#define RT5631_M_VDAC_TO_OUTMIXER_R (0x1 << 7)
#define RT5631_M_VDAC_OUTMIXR_BIT 7
/* Lout Mixer Control(0x1E) */
#define RT5631_M_MIC1_TO_AXO1MIXER (0x1 << 15)
#define RT5631_M_MIC1_AXO1MIX_BIT 15
#define RT5631_M_MIC2_TO_AXO1MIXER (0x1 << 11)
#define RT5631_M_MIC2_AXO1MIX_BIT 11
#define RT5631_M_OUTMIXER_L_TO_AXO1MIXER (0x1 << 7)
#define RT5631_M_OUTMIXL_AXO1MIX_BIT 7
#define RT5631_M_OUTMIXER_R_TO_AXO1MIXER (0x1 << 6)
#define RT5631_M_OUTMIXR_AXO1MIX_BIT 6
/* Rout Mixer Control(0x20) */
#define RT5631_M_MIC1_TO_AXO2MIXER (0x1 << 15)
#define RT5631_M_MIC1_AXO2MIX_BIT 15
#define RT5631_M_MIC2_TO_AXO2MIXER (0x1 << 11)
#define RT5631_M_MIC2_AXO2MIX_BIT 11
#define RT5631_M_OUTMIXER_L_TO_AXO2MIXER (0x1 << 7)
#define RT5631_M_OUTMIXL_AXO2MIX_BIT 7
#define RT5631_M_OUTMIXER_R_TO_AXO2MIXER (0x1 << 6)
#define RT5631_M_OUTMIXR_AXO2MIX_BIT 6
/* Micphone Input Control 2(0x22) */
#define RT5631_MIC_BIAS_90_PRECNET_AVDD 1
#define RT5631_MIC_BIAS_75_PRECNET_AVDD 2
#define RT5631_MIC1_BOOST_CTRL_MASK (0xf << 12)
#define RT5631_MIC1_BOOST_CTRL_BYPASS (0x0 << 12)
#define RT5631_MIC1_BOOST_CTRL_20DB (0x1 << 12)
#define RT5631_MIC1_BOOST_CTRL_24DB (0x2 << 12)
#define RT5631_MIC1_BOOST_CTRL_30DB (0x3 << 12)
#define RT5631_MIC1_BOOST_CTRL_35DB (0x4 << 12)
#define RT5631_MIC1_BOOST_CTRL_40DB (0x5 << 12)
#define RT5631_MIC1_BOOST_CTRL_34DB (0x6 << 12)
#define RT5631_MIC1_BOOST_CTRL_50DB (0x7 << 12)
#define RT5631_MIC1_BOOST_CTRL_52DB (0x8 << 12)
#define RT5631_MIC1_BOOST_SHIFT 12
#define RT5631_MIC2_BOOST_CTRL_MASK (0xf << 8)
#define RT5631_MIC2_BOOST_CTRL_BYPASS (0x0 << 8)
#define RT5631_MIC2_BOOST_CTRL_20DB (0x1 << 8)
#define RT5631_MIC2_BOOST_CTRL_24DB (0x2 << 8)
#define RT5631_MIC2_BOOST_CTRL_30DB (0x3 << 8)
#define RT5631_MIC2_BOOST_CTRL_35DB (0x4 << 8)
#define RT5631_MIC2_BOOST_CTRL_40DB (0x5 << 8)
#define RT5631_MIC2_BOOST_CTRL_34DB (0x6 << 8)
#define RT5631_MIC2_BOOST_CTRL_50DB (0x7 << 8)
#define RT5631_MIC2_BOOST_CTRL_52DB (0x8 << 8)
#define RT5631_MIC2_BOOST_SHIFT 8
#define RT5631_MICBIAS1_VOLT_CTRL_MASK (0x1 << 7)
#define RT5631_MICBIAS1_VOLT_CTRL_90P (0x0 << 7)
#define RT5631_MICBIAS1_VOLT_CTRL_75P (0x1 << 7)
#define RT5631_MICBIAS1_S_C_DET_MASK (0x1 << 6)
#define RT5631_MICBIAS1_S_C_DET_DIS (0x0 << 6)
#define RT5631_MICBIAS1_S_C_DET_ENA (0x1 << 6)
#define RT5631_MICBIAS1_SHORT_CURR_DET_MASK (0x3 << 4)
#define RT5631_MICBIAS1_SHORT_CURR_DET_600UA (0x0 << 4)
#define RT5631_MICBIAS1_SHORT_CURR_DET_1500UA (0x1 << 4)
#define RT5631_MICBIAS1_SHORT_CURR_DET_2000UA (0x2 << 4)
#define RT5631_MICBIAS2_VOLT_CTRL_MASK (0x1 << 3)
#define RT5631_MICBIAS2_VOLT_CTRL_90P (0x0 << 3)
#define RT5631_MICBIAS2_VOLT_CTRL_75P (0x1 << 3)
#define RT5631_MICBIAS2_S_C_DET_MASK (0x1 << 2)
#define RT5631_MICBIAS2_S_C_DET_DIS (0x0 << 2)
#define RT5631_MICBIAS2_S_C_DET_ENA (0x1 << 2)
#define RT5631_MICBIAS2_SHORT_CURR_DET_MASK (0x3)
#define RT5631_MICBIAS2_SHORT_CURR_DET_600UA (0x0)
#define RT5631_MICBIAS2_SHORT_CURR_DET_1500UA (0x1)
#define RT5631_MICBIAS2_SHORT_CURR_DET_2000UA (0x2)
/* Digital Microphone Control(0x24) */
#define RT5631_DMIC_ENA_MASK (0x1 << 15)
#define RT5631_DMIC_ENA_SHIFT 15
/* DMIC_ENA: DMIC to ADC Digital filter */
#define RT5631_DMIC_ENA (0x1 << 15)
/* DMIC_DIS: ADC mixer to ADC Digital filter */
#define RT5631_DMIC_DIS (0x0 << 15)
#define RT5631_DMIC_L_CH_MUTE (0x1 << 13)
#define RT5631_DMIC_L_CH_MUTE_SHIFT 13
#define RT5631_DMIC_R_CH_MUTE (0x1 << 12)
#define RT5631_DMIC_R_CH_MUTE_SHIFT 12
#define RT5631_DMIC_L_CH_LATCH_MASK (0x1 << 9)
#define RT5631_DMIC_L_CH_LATCH_RISING (0x1 << 9)
#define RT5631_DMIC_L_CH_LATCH_FALLING (0x0 << 9)
#define RT5631_DMIC_R_CH_LATCH_MASK (0x1 << 8)
#define RT5631_DMIC_R_CH_LATCH_RISING (0x1 << 8)
#define RT5631_DMIC_R_CH_LATCH_FALLING (0x0 << 8)
#define RT5631_DMIC_CLK_CTRL_MASK (0x3 << 4)
#define RT5631_DMIC_CLK_CTRL_TO_128FS (0x0 << 4)
#define RT5631_DMIC_CLK_CTRL_TO_64FS (0x1 << 4)
#define RT5631_DMIC_CLK_CTRL_TO_32FS (0x2 << 4)
/* Microphone Input Volume(0x26) */
#define RT5631_MONO_DIFF_INPUT_SHIFT 15
/* Speaker Mixer Control(0x28) */
#define RT5631_M_RECMIXER_L_TO_SPKMIXER_L (0x1 << 15)
#define RT5631_M_RECMIXL_SPKMIXL_BIT 15
#define RT5631_M_MIC1_P_TO_SPKMIXER_L (0x1 << 14)
#define RT5631_M_MIC1P_SPKMIXL_BIT 14
#define RT5631_M_DAC_L_TO_SPKMIXER_L (0x1 << 13)
#define RT5631_M_DACL_SPKMIXL_BIT 13
#define RT5631_M_OUTMIXER_L_TO_SPKMIXER_L (0x1 << 12)
#define RT5631_M_OUTMIXL_SPKMIXL_BIT 12
#define RT5631_M_RECMIXER_R_TO_SPKMIXER_R (0x1 << 7)
#define RT5631_M_RECMIXR_SPKMIXR_BIT 7
#define RT5631_M_MIC2_P_TO_SPKMIXER_R (0x1 << 6)
#define RT5631_M_MIC2P_SPKMIXR_BIT 6
#define RT5631_M_DAC_R_TO_SPKMIXER_R (0x1 << 5)
#define RT5631_M_DACR_SPKMIXR_BIT 5
#define RT5631_M_OUTMIXER_R_TO_SPKMIXER_R (0x1 << 4)
#define RT5631_M_OUTMIXR_SPKMIXR_BIT 4
/* Speaker/Mono Output Control(0x2A) */
#define RT5631_M_SPKVOL_L_TO_SPOL_MIXER (0x1 << 15)
#define RT5631_M_SPKVOLL_SPOLMIX_BIT 15
#define RT5631_M_SPKVOL_R_TO_SPOL_MIXER (0x1 << 14)
#define RT5631_M_SPKVOLR_SPOLMIX_BIT 14
#define RT5631_M_SPKVOL_L_TO_SPOR_MIXER (0x1 << 13)
#define RT5631_M_SPKVOLL_SPORMIX_BIT 13
#define RT5631_M_SPKVOL_R_TO_SPOR_MIXER (0x1 << 12)
#define RT5631_M_SPKVOLR_SPORMIX_BIT 12
#define RT5631_M_OUTVOL_L_TO_MONOMIXER (0x1 << 11)
#define RT5631_M_OUTVOLL_MONOMIX_BIT 11
#define RT5631_M_OUTVOL_R_TO_MONOMIXER (0x1 << 10)
#define RT5631_M_OUTVOLR_MONOMIX_BIT 10
/* Speaker/Mono/HP Output Control(0x2C) */
#define RT5631_SPK_L_MUX_SEL_MASK (0x3 << 14)
#define RT5631_SPK_L_MUX_SEL_SPKMIXER_L (0x0 << 14)
#define RT5631_SPK_L_MUX_SEL_MONO_IN (0x1 << 14)
#define RT5631_SPK_L_MUX_SEL_DAC_L (0x3 << 14)
#define RT5631_SPK_L_MUX_SEL_SHIFT 14
#define RT5631_SPK_R_MUX_SEL_MASK (0x3 << 10)
#define RT5631_SPK_R_MUX_SEL_SPKMIXER_R (0x0 << 10)
#define RT5631_SPK_R_MUX_SEL_MONO_IN (0x1 << 10)
#define RT5631_SPK_R_MUX_SEL_DAC_R (0x3 << 10)
#define RT5631_SPK_R_MUX_SEL_SHIFT 10
#define RT5631_MONO_MUX_SEL_MASK (0x3 << 6)
#define RT5631_MONO_MUX_SEL_MONOMIXER (0x0 << 6)
#define RT5631_MONO_MUX_SEL_MONO_IN (0x1 << 6)
#define RT5631_MONO_MUX_SEL_SHIFT 6
#define RT5631_HP_L_MUX_SEL_MASK (0x1 << 3)
#define RT5631_HP_L_MUX_SEL_HPVOL_L (0x0 << 3)
#define RT5631_HP_L_MUX_SEL_DAC_L (0x1 << 3)
#define RT5631_HP_L_MUX_SEL_SHIFT 3
#define RT5631_HP_R_MUX_SEL_MASK (0x1 << 2)
#define RT5631_HP_R_MUX_SEL_HPVOL_R (0x0 << 2)
#define RT5631_HP_R_MUX_SEL_DAC_R (0x1 << 2)
#define RT5631_HP_R_MUX_SEL_SHIFT 2
/* Stereo I2S Serial Data Port Control(0x34) */
#define RT5631_SDP_MODE_SEL_MASK (0x1 << 15)
#define RT5631_SDP_MODE_SEL_MASTER (0x0 << 15)
#define RT5631_SDP_MODE_SEL_SLAVE (0x1 << 15)
#define RT5631_SDP_ADC_CPS_SEL_MASK (0x3 << 10)
#define RT5631_SDP_ADC_CPS_SEL_OFF (0x0 << 10)
#define RT5631_SDP_ADC_CPS_SEL_U_LAW (0x1 << 10)
#define RT5631_SDP_ADC_CPS_SEL_A_LAW (0x2 << 10)
#define RT5631_SDP_DAC_CPS_SEL_MASK (0x3 << 8)
#define RT5631_SDP_DAC_CPS_SEL_OFF (0x0 << 8)
#define RT5631_SDP_DAC_CPS_SEL_U_LAW (0x1 << 8)
#define RT5631_SDP_DAC_CPS_SEL_A_LAW (0x2 << 8)
/* 0:Normal 1:Invert */
#define RT5631_SDP_I2S_BCLK_POL_CTRL (0x1 << 7)
/* 0:Normal 1:Invert */
#define RT5631_SDP_DAC_R_INV (0x1 << 6)
/* 0:ADC data appear at left phase of LRCK
* 1:ADC data appear at right phase of LRCK
*/
#define RT5631_SDP_ADC_DATA_L_R_SWAP (0x1 << 5)
/* 0:DAC data appear at left phase of LRCK
* 1:DAC data appear at right phase of LRCK
*/
#define RT5631_SDP_DAC_DATA_L_R_SWAP (0x1 << 4)
/* Data Length Slection */
#define RT5631_SDP_I2S_DL_MASK (0x3 << 2)
#define RT5631_SDP_I2S_DL_16 (0x0 << 2)
#define RT5631_SDP_I2S_DL_20 (0x1 << 2)
#define RT5631_SDP_I2S_DL_24 (0x2 << 2)
#define RT5631_SDP_I2S_DL_8 (0x3 << 2)
/* PCM Data Format Selection */
#define RT5631_SDP_I2S_DF_MASK (0x3)
#define RT5631_SDP_I2S_DF_I2S (0x0)
#define RT5631_SDP_I2S_DF_LEFT (0x1)
#define RT5631_SDP_I2S_DF_PCM_A (0x2)
#define RT5631_SDP_I2S_DF_PCM_B (0x3)
/* Stereo AD/DA Clock Control(0x38h) */
#define RT5631_I2S_PRE_DIV_MASK (0x7 << 13)
#define RT5631_I2S_PRE_DIV_1 (0x0 << 13)
#define RT5631_I2S_PRE_DIV_2 (0x1 << 13)
#define RT5631_I2S_PRE_DIV_4 (0x2 << 13)
#define RT5631_I2S_PRE_DIV_8 (0x3 << 13)
#define RT5631_I2S_PRE_DIV_16 (0x4 << 13)
#define RT5631_I2S_PRE_DIV_32 (0x5 << 13)
/* CLOCK RELATIVE OF BCLK AND LCRK */
#define RT5631_I2S_LRCK_SEL_N_BCLK_MASK (0x1 << 12)
#define RT5631_I2S_LRCK_SEL_64_BCLK (0x0 << 12) /* 64FS */
#define RT5631_I2S_LRCK_SEL_32_BCLK (0x1 << 12) /* 32FS */
#define RT5631_DAC_OSR_SEL_MASK (0x3 << 10)
#define RT5631_DAC_OSR_SEL_128FS (0x3 << 10)
#define RT5631_DAC_OSR_SEL_64FS (0x3 << 10)
#define RT5631_DAC_OSR_SEL_32FS (0x3 << 10)
#define RT5631_DAC_OSR_SEL_16FS (0x3 << 10)
#define RT5631_ADC_OSR_SEL_MASK (0x3 << 8)
#define RT5631_ADC_OSR_SEL_128FS (0x3 << 8)
#define RT5631_ADC_OSR_SEL_64FS (0x3 << 8)
#define RT5631_ADC_OSR_SEL_32FS (0x3 << 8)
#define RT5631_ADC_OSR_SEL_16FS (0x3 << 8)
#define RT5631_ADDA_FILTER_CLK_SEL_256FS (0 << 7) /* 256FS */
#define RT5631_ADDA_FILTER_CLK_SEL_384FS (1 << 7) /* 384FS */
/* Power managment addition 1 (0x3A) */
#define RT5631_PWR_MAIN_I2S_EN (0x1 << 15)
#define RT5631_PWR_MAIN_I2S_BIT 15
#define RT5631_PWR_CLASS_D (0x1 << 12)
#define RT5631_PWR_CLASS_D_BIT 12
#define RT5631_PWR_ADC_L_CLK (0x1 << 11)
#define RT5631_PWR_ADC_L_CLK_BIT 11
#define RT5631_PWR_ADC_R_CLK (0x1 << 10)
#define RT5631_PWR_ADC_R_CLK_BIT 10
#define RT5631_PWR_DAC_L_CLK (0x1 << 9)
#define RT5631_PWR_DAC_L_CLK_BIT 9
#define RT5631_PWR_DAC_R_CLK (0x1 << 8)
#define RT5631_PWR_DAC_R_CLK_BIT 8
#define RT5631_PWR_DAC_REF (0x1 << 7)
#define RT5631_PWR_DAC_REF_BIT 7
#define RT5631_PWR_DAC_L_TO_MIXER (0x1 << 6)
#define RT5631_PWR_DAC_L_TO_MIXER_BIT 6
#define RT5631_PWR_DAC_R_TO_MIXER (0x1 << 5)
#define RT5631_PWR_DAC_R_TO_MIXER_BIT 5
/* Power managment addition 2 (0x3B) */
#define RT5631_PWR_OUTMIXER_L (0x1 << 15)
#define RT5631_PWR_OUTMIXER_L_BIT 15
#define RT5631_PWR_OUTMIXER_R (0x1 << 14)
#define RT5631_PWR_OUTMIXER_R_BIT 14
#define RT5631_PWR_SPKMIXER_L (0x1 << 13)
#define RT5631_PWR_SPKMIXER_L_BIT 13
#define RT5631_PWR_SPKMIXER_R (0x1 << 12)
#define RT5631_PWR_SPKMIXER_R_BIT 12
#define RT5631_PWR_RECMIXER_L (0x1 << 11)
#define RT5631_PWR_RECMIXER_L_BIT 11
#define RT5631_PWR_RECMIXER_R (0x1 << 10)
#define RT5631_PWR_RECMIXER_R_BIT 10
#define RT5631_PWR_MIC1_BOOT_GAIN (0x1 << 5)
#define RT5631_PWR_MIC1_BOOT_GAIN_BIT 5
#define RT5631_PWR_MIC2_BOOT_GAIN (0x1 << 4)
#define RT5631_PWR_MIC2_BOOT_GAIN_BIT 4
#define RT5631_PWR_MICBIAS1_VOL (0x1 << 3)
#define RT5631_PWR_MICBIAS1_VOL_BIT 3
#define RT5631_PWR_MICBIAS2_VOL (0x1 << 2)
#define RT5631_PWR_MICBIAS2_VOL_BIT 2
#define RT5631_PWR_PLL1 (0x1 << 1)
#define RT5631_PWR_PLL1_BIT 1
#define RT5631_PWR_PLL2 (0x1 << 0)
#define RT5631_PWR_PLL2_BIT 0
/* Power managment addition 3(0x3C) */
#define RT5631_PWR_VREF (0x1 << 15)
#define RT5631_PWR_VREF_BIT 15
#define RT5631_PWR_FAST_VREF_CTRL (0x1 << 14)
#define RT5631_PWR_FAST_VREF_CTRL_BIT 14
#define RT5631_PWR_MAIN_BIAS (0x1 << 13)
#define RT5631_PWR_MAIN_BIAS_BIT 13
#define RT5631_PWR_AXO1MIXER (0x1 << 11)
#define RT5631_PWR_AXO1MIXER_BIT 11
#define RT5631_PWR_AXO2MIXER (0x1 << 10)
#define RT5631_PWR_AXO2MIXER_BIT 10
#define RT5631_PWR_MONOMIXER (0x1 << 9)
#define RT5631_PWR_MONOMIXER_BIT 9
#define RT5631_PWR_MONO_DEPOP_DIS (0x1 << 8)
#define RT5631_PWR_MONO_DEPOP_DIS_BIT 8
#define RT5631_PWR_MONO_AMP_EN (0x1 << 7)
#define RT5631_PWR_MONO_AMP_EN_BIT 7
#define RT5631_PWR_CHARGE_PUMP (0x1 << 4)
#define RT5631_PWR_CHARGE_PUMP_BIT 4
#define RT5631_PWR_HP_L_AMP (0x1 << 3)
#define RT5631_PWR_HP_L_AMP_BIT 3
#define RT5631_PWR_HP_R_AMP (0x1 << 2)
#define RT5631_PWR_HP_R_AMP_BIT 2
#define RT5631_PWR_HP_DEPOP_DIS (0x1 << 1)
#define RT5631_PWR_HP_DEPOP_DIS_BIT 1
#define RT5631_PWR_HP_AMP_DRIVING (0x1 << 0)
#define RT5631_PWR_HP_AMP_DRIVING_BIT 0
/* Power managment addition 4(0x3E) */
#define RT5631_PWR_SPK_L_VOL (0x1 << 15)
#define RT5631_PWR_SPK_L_VOL_BIT 15
#define RT5631_PWR_SPK_R_VOL (0x1 << 14)
#define RT5631_PWR_SPK_R_VOL_BIT 14
#define RT5631_PWR_LOUT_VOL (0x1 << 13)
#define RT5631_PWR_LOUT_VOL_BIT 13
#define RT5631_PWR_ROUT_VOL (0x1 << 12)
#define RT5631_PWR_ROUT_VOL_BIT 12
#define RT5631_PWR_HP_L_OUT_VOL (0x1 << 11)
#define RT5631_PWR_HP_L_OUT_VOL_BIT 11
#define RT5631_PWR_HP_R_OUT_VOL (0x1 << 10)
#define RT5631_PWR_HP_R_OUT_VOL_BIT 10
#define RT5631_PWR_AXIL_IN_VOL (0x1 << 9)
#define RT5631_PWR_AXIL_IN_VOL_BIT 9
#define RT5631_PWR_AXIR_IN_VOL (0x1 << 8)
#define RT5631_PWR_AXIR_IN_VOL_BIT 8
#define RT5631_PWR_MONO_IN_P_VOL (0x1 << 7)
#define RT5631_PWR_MONO_IN_P_VOL_BIT 7
#define RT5631_PWR_MONO_IN_N_VOL (0x1 << 6)
#define RT5631_PWR_MONO_IN_N_VOL_BIT 6
/* General Purpose Control Register(0x40) */
#define RT5631_SPK_AMP_AUTO_RATIO_EN (0x1 << 15)
#define RT5631_SPK_AMP_RATIO_CTRL_MASK (0x7 << 12)
#define RT5631_SPK_AMP_RATIO_CTRL_2_34 (0x0 << 12) /* 7.40DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_99 (0x1 << 12) /* 5.99DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_68 (0x2 << 12) /* 4.50DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_56 (0x3 << 12) /* 3.86DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_44 (0x4 << 12) /* 3.16DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_27 (0x5 << 12) /* 2.10DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_09 (0x6 << 12) /* 0.80DB */
#define RT5631_SPK_AMP_RATIO_CTRL_1_00 (0x7 << 12) /* 0.00DB */
#define RT5631_SPK_AMP_RATIO_CTRL_SHIFT 12
#define RT5631_STEREO_DAC_HI_PASS_FILT_EN (0x1 << 11)
#define RT5631_STEREO_ADC_HI_PASS_FILT_EN (0x1 << 10)
/* Select ADC Wind Filter Clock type */
#define RT5631_ADC_WIND_FILT_MASK (0x3 << 4)
#define RT5631_ADC_WIND_FILT_8_16_32K (0x0 << 4) /*8/16/32k*/
#define RT5631_ADC_WIND_FILT_11_22_44K (0x1 << 4) /*11/22/44k*/
#define RT5631_ADC_WIND_FILT_12_24_48K (0x2 << 4) /*12/24/48k*/
#define RT5631_ADC_WIND_FILT_EN (0x1 << 3)
/* SelectADC Wind Filter Corner Frequency */
#define RT5631_ADC_WIND_CNR_FREQ_MASK (0x7 << 0)
#define RT5631_ADC_WIND_CNR_FREQ_82_113_122 (0x0 << 0) /* 82/113/122 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_102_141_153 (0x1 << 0) /* 102/141/153 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_131_180_156 (0x2 << 0) /* 131/180/156 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_163_225_245 (0x3 << 0) /* 163/225/245 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_204_281_306 (0x4 << 0) /* 204/281/306 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_261_360_392 (0x5 << 0) /* 261/360/392 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_327_450_490 (0x6 << 0) /* 327/450/490 Hz */
#define RT5631_ADC_WIND_CNR_FREQ_408_563_612 (0x7 << 0) /* 408/563/612 Hz */
/* Global Clock Control Register(0x42) */
#define RT5631_SYSCLK_SOUR_SEL_MASK (0x3 << 14)
#define RT5631_SYSCLK_SOUR_SEL_MCLK (0x0 << 14)
#define RT5631_SYSCLK_SOUR_SEL_PLL (0x1 << 14)
#define RT5631_SYSCLK_SOUR_SEL_PLL_TCK (0x2 << 14)
#define RT5631_PLLCLK_SOUR_SEL_MASK (0x3 << 12)
#define RT5631_PLLCLK_SOUR_SEL_MCLK (0x0 << 12)
#define RT5631_PLLCLK_SOUR_SEL_BCLK (0x1 << 12)
#define RT5631_PLLCLK_SOUR_SEL_VBCLK (0x2 << 12)
#define RT5631_PLLCLK_PRE_DIV1 (0x0 << 11)
#define RT5631_PLLCLK_PRE_DIV2 (0x1 << 11)
/* PLL Control(0x44) */
#define RT5631_PLL_CTRL_M_VAL(m) ((m)&0xf)
#define RT5631_PLL_CTRL_K_VAL(k) (((k)&0x7) << 4)
#define RT5631_PLL_CTRL_N_VAL(n) (((n)&0xff) << 8)
/* Internal Status and IRQ Control2(0x4A) */
#define RT5631_ADC_DATA_SEL_MASK (0x3 << 14)
#define RT5631_ADC_DATA_SEL_Disable (0x0 << 14)
#define RT5631_ADC_DATA_SEL_MIC1 (0x1 << 14)
#define RT5631_ADC_DATA_SEL_MIC1_SHIFT 14
#define RT5631_ADC_DATA_SEL_MIC2 (0x2 << 14)
#define RT5631_ADC_DATA_SEL_MIC2_SHIFT 15
#define RT5631_ADC_DATA_SEL_STO (0x3 << 14)
#define RT5631_ADC_DATA_SEL_SHIFT 14
/* GPIO Pin Configuration(0x4C) */
#define RT5631_GPIO_PIN_FUN_SEL_MASK (0x1 << 15)
#define RT5631_GPIO_PIN_FUN_SEL_IRQ (0x1 << 15)
#define RT5631_GPIO_PIN_FUN_SEL_GPIO_DIMC (0x0 << 15)
#define RT5631_GPIO_DMIC_FUN_SEL_MASK (0x1 << 3)
#define RT5631_GPIO_DMIC_FUN_SEL_DIMC (0x1 << 3)
#define RT5631_GPIO_DMIC_FUN_SEL_GPIO (0x0 << 3)
#define RT5631_GPIO_PIN_CON_MASK (0x1 << 2)
#define RT5631_GPIO_PIN_SET_INPUT (0x0 << 2)
#define RT5631_GPIO_PIN_SET_OUTPUT (0x1 << 2)
/* De-POP function Control 1(0x54) */
#define RT5631_POW_ON_SOFT_GEN (0x1 << 15)
#define RT5631_EN_MUTE_UNMUTE_DEPOP (0x1 << 14)
#define RT5631_EN_DEPOP2_FOR_HP (0x1 << 7)
/* Power Down HPAMP_L Starts Up Signal */
#define RT5631_PD_HPAMP_L_ST_UP (0x1 << 5)
/* Power Down HPAMP_R Starts Up Signal */
#define RT5631_PD_HPAMP_R_ST_UP (0x1 << 4)
/* Enable left HP mute/unmute depop */
#define RT5631_EN_HP_L_M_UN_MUTE_DEPOP (0x1 << 1)
/* Enable right HP mute/unmute depop */
#define RT5631_EN_HP_R_M_UN_MUTE_DEPOP (0x1 << 0)
/* De-POP Fnction Control(0x56) */
#define RT5631_EN_ONE_BIT_DEPOP (0x1 << 15)
#define RT5631_EN_CAP_FREE_DEPOP (0x1 << 14)
/* Jack Detect Control Register(0x5A) */
#define RT5631_JD_USE_MASK (0x3 << 14)
#define RT5631_JD_USE_JD2 (0x3 << 14)
#define RT5631_JD_USE_JD1 (0x2 << 14)
#define RT5631_JD_USE_GPIO (0x1 << 14)
#define RT5631_JD_OFF (0x0 << 14)
/* JD trigger enable for HP */
#define RT5631_JD_HP_EN (0x1 << 11)
#define RT5631_JD_HP_TRI_MASK (0x1 << 10)
#define RT5631_JD_HP_TRI_HI (0x1 << 10)
#define RT5631_JD_HP_TRI_LO (0x1 << 10)
/* JD trigger enable for speaker LP/LN */
#define RT5631_JD_SPK_L_EN (0x1 << 9)
#define RT5631_JD_SPK_L_TRI_MASK (0x1 << 8)
#define RT5631_JD_SPK_L_TRI_HI (0x1 << 8)
#define RT5631_JD_SPK_L_TRI_LO (0x0 << 8)
/* JD trigger enable for speaker RP/RN */
#define RT5631_JD_SPK_R_EN (0x1 << 7)
#define RT5631_JD_SPK_R_TRI_MASK (0x1 << 6)
#define RT5631_JD_SPK_R_TRI_HI (0x1 << 6)
#define RT5631_JD_SPK_R_TRI_LO (0x0 << 6)
/* JD trigger enable for monoout */
#define RT5631_JD_MONO_EN (0x1 << 5)
#define RT5631_JD_MONO_TRI_MASK (0x1 << 4)
#define RT5631_JD_MONO_TRI_HI (0x1 << 4)
#define RT5631_JD_MONO_TRI_LO (0x0 << 4)
/* JD trigger enable for Lout */
#define RT5631_JD_AUX_1_EN (0x1 << 3)
#define RT5631_JD_AUX_1_MASK (0x1 << 2)
#define RT5631_JD_AUX_1_TRI_HI (0x1 << 2)
#define RT5631_JD_AUX_1_TRI_LO (0x0 << 2)
/* JD trigger enable for Rout */
#define RT5631_JD_AUX_2_EN (0x1 << 1)
#define RT5631_JD_AUX_2_MASK (0x1 << 0)
#define RT5631_JD_AUX_2_TRI_HI (0x1 << 0)
#define RT5631_JD_AUX_2_TRI_LO (0x0 << 0)
/* ALC CONTROL 1(0x64) */
#define RT5631_ALC_ATTACK_RATE_MASK (0x1F << 8)
#define RT5631_ALC_RECOVERY_RATE_MASK (0x1F << 0)
/* ALC CONTROL 2(0x65) */
/* select Compensation gain for Noise gate function */
#define RT5631_ALC_COM_NOISE_GATE_MASK (0xF << 0)
/* ALC CONTROL 3(0x66) */
#define RT5631_ALC_FUN_MASK (0x3 << 14)
#define RT5631_ALC_FUN_DIS (0x0 << 14)
#define RT5631_ALC_ENA_DAC_PATH (0x1 << 14)
#define RT5631_ALC_ENA_ADC_PATH (0x3 << 14)
#define RT5631_ALC_PARA_UPDATE (0x1 << 13)
#define RT5631_ALC_LIMIT_LEVEL_MASK (0x1F << 8)
#define RT5631_ALC_NOISE_GATE_FUN_MASK (0x1 << 7)
#define RT5631_ALC_NOISE_GATE_FUN_DIS (0x0 << 7)
#define RT5631_ALC_NOISE_GATE_FUN_ENA (0x1 << 7)
/* ALC noise gate hold data function */
#define RT5631_ALC_NOISE_GATE_H_D_MASK (0x1 << 6)
#define RT5631_ALC_NOISE_GATE_H_D_DIS (0x0 << 6)
#define RT5631_ALC_NOISE_GATE_H_D_ENA (0x1 << 6)
/* Psedueo Stereo & Spatial Effect Block Control(0x68) */
#define RT5631_SPATIAL_CTRL_EN (0x1 << 15)
#define RT5631_ALL_PASS_FILTER_EN (0x1 << 14)
#define RT5631_PSEUDO_STEREO_EN (0x1 << 13)
#define RT5631_STEREO_EXPENSION_EN (0x1 << 12)
/* 3D gain parameter */
#define RT5631_GAIN_3D_PARA_MASK (0x3 << 6)
#define RT5631_GAIN_3D_PARA_1_00 (0x0 << 6) /* 3D gain 1.0 */
#define RT5631_GAIN_3D_PARA_1_50 (0x1 << 6) /* 3D gain 1.5 */
#define RT5631_GAIN_3D_PARA_2_00 (0x2 << 6) /* 3D gain 2.0 */
/* 3D ratio parameter */
#define RT5631_RATIO_3D_MASK (0x3 << 4)
#define RT5631_RATIO_3D_0_0 (0x0 << 4) /* 3D ratio 0.0 */
#define RT5631_RATIO_3D_0_66 (0x1 << 4) /* 3D ratio 0.66 */
#define RT5631_RATIO_3D_1_0 (0x2 << 4) /* 3D ratio 1.0 */
/* select samplerate for all pass filter */
#define RT5631_APF_FUN_SLE_MASK (0x3 << 0)
#define RT5631_APF_FUN_SEL_48K (0x3 << 0)
#define RT5631_APF_FUN_SEL_44_1K (0x2 << 0)
#define RT5631_APF_FUN_SEL_32K (0x1 << 0)
#define RT5631_APF_FUN_DIS (0x0 << 0)
/* EQ CONTROL 1(0x6E) */
#define RT5631_HW_EQ_PATH_SEL_MASK (0x1 << 15)
#define RT5631_HW_EQ_PATH_SEL_DAC (0x0 << 15)
#define RT5631_HW_EQ_PATH_SEL_ADC (0x1 << 15)
#define RT5631_HW_EQ_UPDATE_CTRL (0x1 << 14)
#define RT5631_EN_HW_EQ_HPF2 (0x1 << 5)
#define RT5631_EN_HW_EQ_HPF1 (0x1 << 4)
#define RT5631_EN_HW_EQ_BP3 (0x1 << 3)
#define RT5631_EN_HW_EQ_BP2 (0x1 << 2)
#define RT5631_EN_HW_EQ_BP1 (0x1 << 1)
#define RT5631_EN_HW_EQ_LPF (0x1 << 0)
#endif /* __RTCODEC5631_H__ */

View File

@ -131,16 +131,13 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
/* change mic bias resistor to 4Kohm */ /* change mic bias resistor to 4Kohm */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_4k, SGTL5000_BIAS_R_4k); SGTL5000_BIAS_R_MASK,
SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
break; break;
case SND_SOC_DAPM_PRE_PMD: case SND_SOC_DAPM_PRE_PMD:
/*
* SGTL5000_BIAS_R_8k as mask to clean the two bits
* of mic bias and output impedance
*/
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL, snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
SGTL5000_BIAS_R_8k, 0); SGTL5000_BIAS_R_MASK, 0);
break; break;
} }
return 0; return 0;
@ -726,7 +723,9 @@ static int sgtl5000_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL; return -EINVAL;
} }
snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL, i2s_ctl, i2s_ctl); snd_soc_update_bits(codec, SGTL5000_CHIP_I2S_CTRL,
SGTL5000_I2S_DLEN_MASK | SGTL5000_I2S_SCLKFREQ_MASK,
i2s_ctl);
return 0; return 0;
} }
@ -757,7 +756,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
/* set voltage to register */ /* set voltage to register */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
(0x1 << 4) - 1, reg); SGTL5000_LINREG_VDDD_MASK, reg);
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER, snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_LINEREG_D_POWERUP, SGTL5000_LINEREG_D_POWERUP,
@ -783,7 +782,7 @@ static int ldo_regulator_disable(struct regulator_dev *dev)
/* clear voltage info */ /* clear voltage info */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
(0x1 << 4) - 1, 0); SGTL5000_LINREG_VDDD_MASK, 0);
ldo->enabled = 0; ldo->enabled = 0;
@ -809,6 +808,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
int voltage) int voltage)
{ {
struct ldo_regulator *ldo; struct ldo_regulator *ldo;
struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec);
ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL); ldo = kzalloc(sizeof(struct ldo_regulator), GFP_KERNEL);
@ -843,6 +843,7 @@ static int ldo_regulator_register(struct snd_soc_codec *codec,
return ret; return ret;
} }
sgtl5000->ldo = ldo;
return 0; return 0;
} }
@ -1116,7 +1117,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
/* set voltage to register */ /* set voltage to register */
snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL, snd_soc_update_bits(codec, SGTL5000_CHIP_LINREG_CTRL,
(0x1 << 4) - 1, 0x8); SGTL5000_LINREG_VDDD_MASK, 0x8);
/* /*
* if vddd linear reg has been enabled, * if vddd linear reg has been enabled,
@ -1147,8 +1148,7 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP; vag = (vag - SGTL5000_ANA_GND_BASE) / SGTL5000_ANA_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL, snd_soc_update_bits(codec, SGTL5000_CHIP_REF_CTRL,
vag << SGTL5000_ANA_GND_SHIFT, SGTL5000_ANA_GND_MASK, vag << SGTL5000_ANA_GND_SHIFT);
vag << SGTL5000_ANA_GND_SHIFT);
/* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */ /* set line out VAG to vddio / 2, in range (0.8v, 1.675v) */
vag = vddio / 2; vag = vddio / 2;
@ -1162,9 +1162,8 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec)
SGTL5000_LINE_OUT_GND_STP; SGTL5000_LINE_OUT_GND_STP;
snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL, snd_soc_update_bits(codec, SGTL5000_CHIP_LINE_OUT_CTRL,
vag << SGTL5000_LINE_OUT_GND_SHIFT | SGTL5000_LINE_OUT_CURRENT_MASK |
SGTL5000_LINE_OUT_CURRENT_360u << SGTL5000_LINE_OUT_GND_MASK,
SGTL5000_LINE_OUT_CURRENT_SHIFT,
vag << SGTL5000_LINE_OUT_GND_SHIFT | vag << SGTL5000_LINE_OUT_GND_SHIFT |
SGTL5000_LINE_OUT_CURRENT_360u << SGTL5000_LINE_OUT_CURRENT_360u <<
SGTL5000_LINE_OUT_CURRENT_SHIFT); SGTL5000_LINE_OUT_CURRENT_SHIFT);

View File

@ -280,7 +280,7 @@
/* /*
* SGTL5000_CHIP_MIC_CTRL * SGTL5000_CHIP_MIC_CTRL
*/ */
#define SGTL5000_BIAS_R_MASK 0x0200 #define SGTL5000_BIAS_R_MASK 0x0300
#define SGTL5000_BIAS_R_SHIFT 8 #define SGTL5000_BIAS_R_SHIFT 8
#define SGTL5000_BIAS_R_WIDTH 2 #define SGTL5000_BIAS_R_WIDTH 2
#define SGTL5000_BIAS_R_off 0x0 #define SGTL5000_BIAS_R_off 0x0

View File

@ -102,7 +102,7 @@ static int sn95031_initialize_adc(struct snd_soc_codec *sn95031_codec)
{ {
int base_addr, chnl_addr; int base_addr, chnl_addr;
int value; int value;
static int channel_index; int channel_index;
/* Index of the first channel in which the stop bit is set */ /* Index of the first channel in which the stop bit is set */
channel_index = find_free_channel(sn95031_codec); channel_index = find_free_channel(sn95031_codec);
@ -161,7 +161,6 @@ static unsigned int sn95031_get_mic_bias(struct snd_soc_codec *codec)
pr_debug("mic bias = %dmV\n", mic_bias); pr_debug("mic bias = %dmV\n", mic_bias);
return mic_bias; return mic_bias;
} }
EXPORT_SYMBOL_GPL(sn95031_get_mic_bias);
/*end - adc helper functions */ /*end - adc helper functions */
static inline unsigned int sn95031_read(struct snd_soc_codec *codec, static inline unsigned int sn95031_read(struct snd_soc_codec *codec,
@ -716,7 +715,7 @@ static struct snd_soc_dai_ops sn95031_vib2_dai_ops = {
.hw_params = sn95031_pcm_hw_params, .hw_params = sn95031_pcm_hw_params,
}; };
struct snd_soc_dai_driver sn95031_dais[] = { static struct snd_soc_dai_driver sn95031_dais[] = {
{ {
.name = "SN95031 Headset", .name = "SN95031 Headset",
.playback = { .playback = {
@ -827,7 +826,6 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
{ {
pr_debug("codec_probe called\n"); pr_debug("codec_probe called\n");
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.idle_bias_off = 1; codec->dapm.idle_bias_off = 1;
/* PCM interface config /* PCM interface config

View File

@ -59,6 +59,7 @@ struct ssm2602_priv {
struct snd_pcm_substream *slave_substream; struct snd_pcm_substream *slave_substream;
enum ssm2602_type type; enum ssm2602_type type;
unsigned int clk_out_pwr;
}; };
/* /*
@ -342,12 +343,14 @@ static void ssm2602_shutdown(struct snd_pcm_substream *substream,
static int ssm2602_mute(struct snd_soc_dai *dai, int mute) static int ssm2602_mute(struct snd_soc_dai *dai, int mute)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 mute_reg = snd_soc_read(codec, SSM2602_APDIGI) & ~APDIGI_ENABLE_DAC_MUTE;
if (mute) if (mute)
snd_soc_write(codec, SSM2602_APDIGI, snd_soc_update_bits(codec, SSM2602_APDIGI,
mute_reg | APDIGI_ENABLE_DAC_MUTE); APDIGI_ENABLE_DAC_MUTE,
APDIGI_ENABLE_DAC_MUTE);
else else
snd_soc_write(codec, SSM2602_APDIGI, mute_reg); snd_soc_update_bits(codec, SSM2602_APDIGI,
APDIGI_ENABLE_DAC_MUTE, 0);
return 0; return 0;
} }
@ -356,6 +359,11 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
if (dir == SND_SOC_CLOCK_IN) {
if (clk_id != SSM2602_SYSCLK)
return -EINVAL;
switch (freq) { switch (freq) {
case 11289600: case 11289600:
case 12000000: case 12000000:
@ -363,10 +371,35 @@ static int ssm2602_set_dai_sysclk(struct snd_soc_dai *codec_dai,
case 16934400: case 16934400:
case 18432000: case 18432000:
ssm2602->sysclk = freq; ssm2602->sysclk = freq;
return 0; break;
} default:
return -EINVAL; return -EINVAL;
} }
} else {
unsigned int mask;
switch (clk_id) {
case SSM2602_CLK_CLKOUT:
mask = PWR_CLK_OUT_PDN;
break;
case SSM2602_CLK_XTO:
mask = PWR_OSC_PDN;
break;
default:
return -EINVAL;
}
if (freq == 0)
ssm2602->clk_out_pwr |= mask;
else
ssm2602->clk_out_pwr &= ~mask;
snd_soc_update_bits(codec, SSM2602_PWR,
PWR_CLK_OUT_PDN | PWR_OSC_PDN, ssm2602->clk_out_pwr);
}
return 0;
}
static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai, static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt) unsigned int fmt)
@ -430,23 +463,27 @@ static int ssm2602_set_dai_fmt(struct snd_soc_dai *codec_dai,
static int ssm2602_set_bias_level(struct snd_soc_codec *codec, static int ssm2602_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 reg = snd_soc_read(codec, SSM2602_PWR); struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
reg &= ~(PWR_POWER_OFF | PWR_OSC_PDN);
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/* vref/mid, osc on, dac unmute */ /* vref/mid on, osc and clkout on if enabled */
snd_soc_write(codec, SSM2602_PWR, reg); snd_soc_update_bits(codec, SSM2602_PWR,
PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
ssm2602->clk_out_pwr);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */ /* everything off except vref/vmid, */
snd_soc_write(codec, SSM2602_PWR, reg | PWR_CLK_OUT_PDN); snd_soc_update_bits(codec, SSM2602_PWR,
PWR_POWER_OFF | PWR_CLK_OUT_PDN | PWR_OSC_PDN,
PWR_CLK_OUT_PDN | PWR_OSC_PDN);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* everything off, dac mute, inactive */ /* everything off */
snd_soc_write(codec, SSM2602_PWR, 0xffff); snd_soc_update_bits(codec, SSM2602_PWR,
PWR_POWER_OFF, PWR_POWER_OFF);
break; break;
} }
@ -505,12 +542,12 @@ static int ssm2602_resume(struct snd_soc_codec *codec)
static int ssm2602_probe(struct snd_soc_codec *codec) static int ssm2602_probe(struct snd_soc_codec *codec)
{ {
struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret, reg; int ret;
reg = snd_soc_read(codec, SSM2602_LOUT1V); snd_soc_update_bits(codec, SSM2602_LOUT1V,
snd_soc_write(codec, SSM2602_LOUT1V, reg | LOUT1V_LRHP_BOTH); LOUT1V_LRHP_BOTH, LOUT1V_LRHP_BOTH);
reg = snd_soc_read(codec, SSM2602_ROUT1V); snd_soc_update_bits(codec, SSM2602_ROUT1V,
snd_soc_write(codec, SSM2602_ROUT1V, reg | ROUT1V_RLHP_BOTH); ROUT1V_RLHP_BOTH, ROUT1V_RLHP_BOTH);
ret = snd_soc_add_controls(codec, ssm2602_snd_controls, ret = snd_soc_add_controls(codec, ssm2602_snd_controls,
ARRAY_SIZE(ssm2602_snd_controls)); ARRAY_SIZE(ssm2602_snd_controls));
@ -543,7 +580,7 @@ static int ssm2604_probe(struct snd_soc_codec *codec)
static int ssm260x_probe(struct snd_soc_codec *codec) static int ssm260x_probe(struct snd_soc_codec *codec)
{ {
struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec);
int ret, reg; int ret;
pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION); pr_info("ssm2602 Audio Codec %s", SSM2602_VERSION);
@ -560,10 +597,10 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
} }
/* set the update bits */ /* set the update bits */
reg = snd_soc_read(codec, SSM2602_LINVOL); snd_soc_update_bits(codec, SSM2602_LINVOL,
snd_soc_write(codec, SSM2602_LINVOL, reg | LINVOL_LRIN_BOTH); LINVOL_LRIN_BOTH, LINVOL_LRIN_BOTH);
reg = snd_soc_read(codec, SSM2602_RINVOL); snd_soc_update_bits(codec, SSM2602_RINVOL,
snd_soc_write(codec, SSM2602_RINVOL, reg | RINVOL_RLIN_BOTH); RINVOL_RLIN_BOTH, RINVOL_RLIN_BOTH);
/*select Line in as default input*/ /*select Line in as default input*/
snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC | snd_soc_write(codec, SSM2602_APANA, APANA_SELECT_DAC |
APANA_ENABLE_MIC_BOOST); APANA_ENABLE_MIC_BOOST);
@ -577,7 +614,12 @@ static int ssm260x_probe(struct snd_soc_codec *codec)
break; break;
} }
if (ret)
return ret; return ret;
ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
} }
/* remove everything here */ /* remove everything here */

View File

@ -116,6 +116,10 @@
#define SSM2602_CACHEREGNUM 10 #define SSM2602_CACHEREGNUM 10
#define SSM2602_SYSCLK 0 enum ssm2602_clk {
SSM2602_SYSCLK,
SSM2602_CLK_CLKOUT,
SSM2602_CLK_XTO
};
#endif #endif

View File

@ -756,25 +756,19 @@ static int sta32x_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
/* read reg reset values into cache */ /* Chip documentation explicitly requires that the reset values
for (i = 0; i < STA32X_REGISTER_COUNT; i++) * of reserved register bits are left untouched.
snd_soc_cache_write(codec, i, sta32x_regs[i]); * Write the register default value to cache for reserved registers,
* so the write to the these registers are suppressed by the cache
/* preserve reset values of reserved register bits */ * restore code when it skips writes of default registers.
snd_soc_cache_write(codec, STA32X_CONFC, */
codec->hw_read(codec, STA32X_CONFC)); snd_soc_cache_write(codec, STA32X_CONFC, 0xc2);
snd_soc_cache_write(codec, STA32X_CONFE, snd_soc_cache_write(codec, STA32X_CONFE, 0xc2);
codec->hw_read(codec, STA32X_CONFE)); snd_soc_cache_write(codec, STA32X_CONFF, 0x5c);
snd_soc_cache_write(codec, STA32X_CONFF, snd_soc_cache_write(codec, STA32X_MMUTE, 0x10);
codec->hw_read(codec, STA32X_CONFF)); snd_soc_cache_write(codec, STA32X_AUTO1, 0x60);
snd_soc_cache_write(codec, STA32X_MMUTE, snd_soc_cache_write(codec, STA32X_AUTO3, 0x00);
codec->hw_read(codec, STA32X_MMUTE)); snd_soc_cache_write(codec, STA32X_C3CFG, 0x40);
snd_soc_cache_write(codec, STA32X_AUTO1,
codec->hw_read(codec, STA32X_AUTO1));
snd_soc_cache_write(codec, STA32X_AUTO3,
codec->hw_read(codec, STA32X_AUTO3));
snd_soc_cache_write(codec, STA32X_C3CFG,
codec->hw_read(codec, STA32X_C3CFG));
/* FIXME enable thermal warning adjustment and recovery */ /* FIXME enable thermal warning adjustment and recovery */
snd_soc_update_bits(codec, STA32X_CONFA, snd_soc_update_bits(codec, STA32X_CONFA,
@ -837,6 +831,7 @@ static const struct snd_soc_codec_driver sta32x_codec = {
.resume = sta32x_resume, .resume = sta32x_resume,
.reg_cache_size = STA32X_REGISTER_COUNT, .reg_cache_size = STA32X_REGISTER_COUNT,
.reg_word_size = sizeof(u8), .reg_word_size = sizeof(u8),
.reg_cache_default = sta32x_regs,
.volatile_register = sta32x_reg_is_volatile, .volatile_register = sta32x_reg_is_volatile,
.set_bias_level = sta32x_set_bias_level, .set_bias_level = sta32x_set_bias_level,
.controls = sta32x_snd_controls, .controls = sta32x_snd_controls,

View File

@ -47,63 +47,6 @@ static const u16 tlv320aic23_reg[] = {
0x0000, 0x0000, 0x0000, 0x0000, /* 12 */ 0x0000, 0x0000, 0x0000, 0x0000, /* 12 */
}; };
/*
* read tlv320aic23 register cache
*/
static inline unsigned int tlv320aic23_read_reg_cache(struct snd_soc_codec
*codec, unsigned int reg)
{
u16 *cache = codec->reg_cache;
if (reg >= ARRAY_SIZE(tlv320aic23_reg))
return -1;
return cache[reg];
}
/*
* write tlv320aic23 register cache
*/
static inline void tlv320aic23_write_reg_cache(struct snd_soc_codec *codec,
u8 reg, u16 value)
{
u16 *cache = codec->reg_cache;
if (reg >= ARRAY_SIZE(tlv320aic23_reg))
return;
cache[reg] = value;
}
/*
* write to the tlv320aic23 register space
*/
static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int value)
{
u8 data[2];
/* TLV320AIC23 has 7 bit address and 9 bits of data
* so we need to switch one data bit into reg and rest
* of data into val
*/
if (reg > 9 && reg != 15) {
printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg);
return -1;
}
data[0] = (reg << 1) | (value >> 8 & 0x01);
data[1] = value & 0xff;
tlv320aic23_write_reg_cache(codec, reg, value);
if (codec->hw_write(codec->control_data, data, 2) == 2)
return 0;
printk(KERN_ERR "%s cannot write %03x to register R%u\n", __func__,
value, reg);
return -EIO;
}
static const char *rec_src_text[] = { "Line", "Mic" }; static const char *rec_src_text[] = { "Line", "Mic" };
static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"};
@ -139,8 +82,8 @@ static int snd_soc_tlv320aic23_put_volsw(struct snd_kcontrol *kcontrol,
*/ */
val = (val >= 4) ? 4 : (3 - val); val = (val >= 4) ? 4 : (3 - val);
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (~0x1C0); reg = snd_soc_read(codec, TLV320AIC23_ANLG) & (~0x1C0);
tlv320aic23_write(codec, TLV320AIC23_ANLG, reg | (val << 6)); snd_soc_write(codec, TLV320AIC23_ANLG, reg | (val << 6));
return 0; return 0;
} }
@ -151,7 +94,7 @@ static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
u16 val; u16 val;
val = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG) & (0x1C0); val = snd_soc_read(codec, TLV320AIC23_ANLG) & (0x1C0);
val = val >> 6; val = val >> 6;
val = (val >= 4) ? 4 : (3 - val); val = (val >= 4) ? 4 : (3 - val);
ucontrol->value.integer.value[0] = val; ucontrol->value.integer.value[0] = val;
@ -159,15 +102,6 @@ static int snd_soc_tlv320aic23_get_volsw(struct snd_kcontrol *kcontrol,
} }
#define SOC_TLV320AIC23_SINGLE_TLV(xname, reg, shift, max, invert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, .get = snd_soc_tlv320aic23_get_volsw,\
.put = snd_soc_tlv320aic23_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = { static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL, SOC_DOUBLE_R_TLV("Digital Playback Volume", TLV320AIC23_LCHNVOL,
TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv), TLV320AIC23_RCHNVOL, 0, 127, 0, out_gain_tlv),
@ -178,8 +112,9 @@ static const struct snd_kcontrol_new tlv320aic23_snd_controls[] = {
TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv), TLV320AIC23_RINVOL, 0, 31, 0, input_gain_tlv),
SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1), SOC_SINGLE("Mic Input Switch", TLV320AIC23_ANLG, 1, 1, 1),
SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0), SOC_SINGLE("Mic Booster Switch", TLV320AIC23_ANLG, 0, 1, 0),
SOC_TLV320AIC23_SINGLE_TLV("Sidetone Volume", TLV320AIC23_ANLG, SOC_SINGLE_EXT_TLV("Sidetone Volume", TLV320AIC23_ANLG, 6, 4, 0,
6, 4, 0, sidetone_vol_tlv), snd_soc_tlv320aic23_get_volsw,
snd_soc_tlv320aic23_put_volsw, sidetone_vol_tlv),
SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph), SOC_ENUM("Playback De-emphasis", tlv320aic23_deemph),
}; };
@ -240,7 +175,6 @@ static const struct snd_soc_dapm_route tlv320aic23_intercon[] = {
/* AIC23 driver data */ /* AIC23 driver data */
struct aic23 { struct aic23 {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
int mclk; int mclk;
int requested_adc; int requested_adc;
int requested_dac; int requested_dac;
@ -352,7 +286,7 @@ static int find_rate(int mclk, u32 need_adc, u32 need_dac)
static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk, static void get_current_sample_rates(struct snd_soc_codec *codec, int mclk,
u32 *sample_rate_adc, u32 *sample_rate_dac) u32 *sample_rate_adc, u32 *sample_rate_dac)
{ {
int src = tlv320aic23_read_reg_cache(codec, TLV320AIC23_SRATE); int src = snd_soc_read(codec, TLV320AIC23_SRATE);
int sr = (src >> 2) & 0x0f; int sr = (src >> 2) & 0x0f;
int val = (mclk / bosr_usb_divisor_table[src & 3]); int val = (mclk / bosr_usb_divisor_table[src & 3]);
int adc = (val * sr_adc_mult_table[sr]) / SR_MULT; int adc = (val * sr_adc_mult_table[sr]) / SR_MULT;
@ -376,7 +310,7 @@ static int set_sample_rate_control(struct snd_soc_codec *codec, int mclk,
__func__, sample_rate_adc, sample_rate_dac); __func__, sample_rate_adc, sample_rate_dac);
return -EINVAL; return -EINVAL;
} }
tlv320aic23_write(codec, TLV320AIC23_SRATE, data); snd_soc_write(codec, TLV320AIC23_SRATE, data);
#ifdef DEBUG #ifdef DEBUG
{ {
u32 adc, dac; u32 adc, dac;
@ -415,9 +349,8 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
if (ret < 0) if (ret < 0)
return ret; return ret;
iface_reg = iface_reg = snd_soc_read(codec, TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
tlv320aic23_read_reg_cache(codec,
TLV320AIC23_DIGT_FMT) & ~(0x03 << 2);
switch (params_format(params)) { switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S16_LE: case SNDRV_PCM_FORMAT_S16_LE:
break; break;
@ -431,7 +364,7 @@ static int tlv320aic23_hw_params(struct snd_pcm_substream *substream,
iface_reg |= (0x03 << 2); iface_reg |= (0x03 << 2);
break; break;
} }
tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg); snd_soc_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
return 0; return 0;
} }
@ -443,7 +376,7 @@ static int tlv320aic23_pcm_prepare(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = rtd->codec; struct snd_soc_codec *codec = rtd->codec;
/* set active */ /* set active */
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0001); snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0001);
return 0; return 0;
} }
@ -458,7 +391,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream,
/* deactivate */ /* deactivate */
if (!codec->active) { if (!codec->active) {
udelay(50); udelay(50);
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
} }
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
aic23->requested_dac = 0; aic23->requested_dac = 0;
@ -471,14 +404,14 @@ static int tlv320aic23_mute(struct snd_soc_dai *dai, int mute)
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
u16 reg; u16 reg;
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT); reg = snd_soc_read(codec, TLV320AIC23_DIGT);
if (mute) if (mute)
reg |= TLV320AIC23_DACM_MUTE; reg |= TLV320AIC23_DACM_MUTE;
else else
reg &= ~TLV320AIC23_DACM_MUTE; reg &= ~TLV320AIC23_DACM_MUTE;
tlv320aic23_write(codec, TLV320AIC23_DIGT, reg); snd_soc_write(codec, TLV320AIC23_DIGT, reg);
return 0; return 0;
} }
@ -489,8 +422,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 iface_reg; u16 iface_reg;
iface_reg = iface_reg = snd_soc_read(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
tlv320aic23_read_reg_cache(codec, TLV320AIC23_DIGT_FMT) & (~0x03);
/* set master/slave audio interface */ /* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@ -524,7 +456,7 @@ static int tlv320aic23_set_dai_fmt(struct snd_soc_dai *codec_dai,
} }
tlv320aic23_write(codec, TLV320AIC23_DIGT_FMT, iface_reg); snd_soc_write(codec, TLV320AIC23_DIGT_FMT, iface_reg);
return 0; return 0;
} }
@ -540,26 +472,26 @@ static int tlv320aic23_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec, static int tlv320aic23_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_PWR) & 0xff7f; u16 reg = snd_soc_read(codec, TLV320AIC23_PWR) & 0xff7f;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/* vref/mid, osc on, dac unmute */ /* vref/mid, osc on, dac unmute */
reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \ reg &= ~(TLV320AIC23_DEVICE_PWR_OFF | TLV320AIC23_OSC_OFF | \
TLV320AIC23_DAC_OFF); TLV320AIC23_DAC_OFF);
tlv320aic23_write(codec, TLV320AIC23_PWR, reg); snd_soc_write(codec, TLV320AIC23_PWR, reg);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
/* everything off except vref/vmid, */ /* everything off except vref/vmid, */
tlv320aic23_write(codec, TLV320AIC23_PWR, reg | \ snd_soc_write(codec, TLV320AIC23_PWR,
TLV320AIC23_CLK_OFF); reg | TLV320AIC23_CLK_OFF);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
/* everything off, dac mute, inactive */ /* everything off, dac mute, inactive */
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x0); snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0);
tlv320aic23_write(codec, TLV320AIC23_PWR, 0xffff); snd_soc_write(codec, TLV320AIC23_PWR, 0xffff);
break; break;
} }
codec->dapm.bias_level = level; codec->dapm.bias_level = level;
@ -606,13 +538,7 @@ static int tlv320aic23_suspend(struct snd_soc_codec *codec,
static int tlv320aic23_resume(struct snd_soc_codec *codec) static int tlv320aic23_resume(struct snd_soc_codec *codec)
{ {
u16 reg; snd_soc_cache_sync(codec);
/* Sync reg_cache with the hardware */
for (reg = 0; reg <= TLV320AIC23_ACTIVE; reg++) {
u16 val = tlv320aic23_read_reg_cache(codec, reg);
tlv320aic23_write(codec, reg, val);
}
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
@ -621,46 +547,52 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec)
static int tlv320aic23_probe(struct snd_soc_codec *codec) static int tlv320aic23_probe(struct snd_soc_codec *codec)
{ {
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
int reg; int ret;
printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION); printk(KERN_INFO "AIC23 Audio Codec %s\n", AIC23_VERSION);
codec->control_data = aic23->control_data;
codec->hw_write = (hw_write_t)i2c_master_send; ret = snd_soc_codec_set_cache_io(codec, 7, 9, aic23->control_type);
codec->hw_read = NULL; if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
return ret;
}
/* Reset codec */ /* Reset codec */
tlv320aic23_write(codec, TLV320AIC23_RESET, 0); snd_soc_write(codec, TLV320AIC23_RESET, 0);
/* Write the register default value to cache for reserved registers,
* so the write to the these registers are suppressed by the cache
* restore code when it skips writes of default registers.
*/
snd_soc_cache_write(codec, 0x0A, 0);
snd_soc_cache_write(codec, 0x0B, 0);
snd_soc_cache_write(codec, 0x0C, 0);
snd_soc_cache_write(codec, 0x0D, 0);
snd_soc_cache_write(codec, 0x0E, 0);
/* power on device */ /* power on device */
tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY); tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
tlv320aic23_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K); snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
/* Unmute input */ /* Unmute input */
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_LINVOL); snd_soc_update_bits(codec, TLV320AIC23_LINVOL,
tlv320aic23_write(codec, TLV320AIC23_LINVOL, TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
(reg & (~TLV320AIC23_LIM_MUTED)) |
(TLV320AIC23_LRS_ENABLED));
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_RINVOL); snd_soc_update_bits(codec, TLV320AIC23_RINVOL,
tlv320aic23_write(codec, TLV320AIC23_RINVOL, TLV320AIC23_LIM_MUTED, TLV320AIC23_LRS_ENABLED);
(reg & (~TLV320AIC23_LIM_MUTED)) |
TLV320AIC23_LRS_ENABLED);
reg = tlv320aic23_read_reg_cache(codec, TLV320AIC23_ANLG); snd_soc_update_bits(codec, TLV320AIC23_ANLG,
tlv320aic23_write(codec, TLV320AIC23_ANLG, TLV320AIC23_BYPASS_ON | TLV320AIC23_MICM_MUTED,
(reg) & (~TLV320AIC23_BYPASS_ON) & 0);
(~TLV320AIC23_MICM_MUTED));
/* Default output volume */ /* Default output volume */
tlv320aic23_write(codec, TLV320AIC23_LCHNVOL, snd_soc_write(codec, TLV320AIC23_LCHNVOL,
TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
TLV320AIC23_OUT_VOL_MASK); snd_soc_write(codec, TLV320AIC23_RCHNVOL,
tlv320aic23_write(codec, TLV320AIC23_RCHNVOL, TLV320AIC23_DEFAULT_OUT_VOL & TLV320AIC23_OUT_VOL_MASK);
TLV320AIC23_DEFAULT_OUT_VOL &
TLV320AIC23_OUT_VOL_MASK);
tlv320aic23_write(codec, TLV320AIC23_ACTIVE, 0x1); snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x1);
snd_soc_add_controls(codec, tlv320aic23_snd_controls, snd_soc_add_controls(codec, tlv320aic23_snd_controls,
ARRAY_SIZE(tlv320aic23_snd_controls)); ARRAY_SIZE(tlv320aic23_snd_controls));
@ -682,8 +614,6 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
.remove = tlv320aic23_remove, .remove = tlv320aic23_remove,
.suspend = tlv320aic23_suspend, .suspend = tlv320aic23_suspend,
.resume = tlv320aic23_resume, .resume = tlv320aic23_resume,
.read = tlv320aic23_read_reg_cache,
.write = tlv320aic23_write,
.set_bias_level = tlv320aic23_set_bias_level, .set_bias_level = tlv320aic23_set_bias_level,
.dapm_widgets = tlv320aic23_dapm_widgets, .dapm_widgets = tlv320aic23_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
@ -710,7 +640,6 @@ static int tlv320aic23_codec_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(i2c, aic23); i2c_set_clientdata(i2c, aic23);
aic23->control_data = i2c;
aic23->control_type = SND_SOC_I2C; aic23->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -528,40 +528,33 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
u8 value;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
if (aic32x4->master) { if (aic32x4->master) {
/* Switch on PLL */ /* Switch on PLL */
value = snd_soc_read(codec, AIC32X4_PLLPR); snd_soc_update_bits(codec, AIC32X4_PLLPR,
snd_soc_write(codec, AIC32X4_PLLPR, AIC32X4_PLLEN, AIC32X4_PLLEN);
(value | AIC32X4_PLLEN));
/* Switch on NDAC Divider */ /* Switch on NDAC Divider */
value = snd_soc_read(codec, AIC32X4_NDAC); snd_soc_update_bits(codec, AIC32X4_NDAC,
snd_soc_write(codec, AIC32X4_NDAC, AIC32X4_NDACEN, AIC32X4_NDACEN);
value | AIC32X4_NDACEN);
/* Switch on MDAC Divider */ /* Switch on MDAC Divider */
value = snd_soc_read(codec, AIC32X4_MDAC); snd_soc_update_bits(codec, AIC32X4_MDAC,
snd_soc_write(codec, AIC32X4_MDAC, AIC32X4_MDACEN, AIC32X4_MDACEN);
value | AIC32X4_MDACEN);
/* Switch on NADC Divider */ /* Switch on NADC Divider */
value = snd_soc_read(codec, AIC32X4_NADC); snd_soc_update_bits(codec, AIC32X4_NADC,
snd_soc_write(codec, AIC32X4_NADC, AIC32X4_NADCEN, AIC32X4_NADCEN);
value | AIC32X4_MDACEN);
/* Switch on MADC Divider */ /* Switch on MADC Divider */
value = snd_soc_read(codec, AIC32X4_MADC); snd_soc_update_bits(codec, AIC32X4_MADC,
snd_soc_write(codec, AIC32X4_MADC, AIC32X4_MADCEN, AIC32X4_MADCEN);
value | AIC32X4_MDACEN);
/* Switch on BCLK_N Divider */ /* Switch on BCLK_N Divider */
value = snd_soc_read(codec, AIC32X4_BCLKN); snd_soc_update_bits(codec, AIC32X4_BCLKN,
snd_soc_write(codec, AIC32X4_BCLKN, AIC32X4_BCLKEN, AIC32X4_BCLKEN);
value | AIC32X4_BCLKEN);
} }
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
@ -569,34 +562,28 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (aic32x4->master) { if (aic32x4->master) {
/* Switch off PLL */ /* Switch off PLL */
value = snd_soc_read(codec, AIC32X4_PLLPR); snd_soc_update_bits(codec, AIC32X4_PLLPR,
snd_soc_write(codec, AIC32X4_PLLPR, AIC32X4_PLLEN, 0);
(value & ~AIC32X4_PLLEN));
/* Switch off NDAC Divider */ /* Switch off NDAC Divider */
value = snd_soc_read(codec, AIC32X4_NDAC); snd_soc_update_bits(codec, AIC32X4_NDAC,
snd_soc_write(codec, AIC32X4_NDAC, AIC32X4_NDACEN, 0);
value & ~AIC32X4_NDACEN);
/* Switch off MDAC Divider */ /* Switch off MDAC Divider */
value = snd_soc_read(codec, AIC32X4_MDAC); snd_soc_update_bits(codec, AIC32X4_MDAC,
snd_soc_write(codec, AIC32X4_MDAC, AIC32X4_MDACEN, 0);
value & ~AIC32X4_MDACEN);
/* Switch off NADC Divider */ /* Switch off NADC Divider */
value = snd_soc_read(codec, AIC32X4_NADC); snd_soc_update_bits(codec, AIC32X4_NADC,
snd_soc_write(codec, AIC32X4_NADC, AIC32X4_NADCEN, 0);
value & ~AIC32X4_NDACEN);
/* Switch off MADC Divider */ /* Switch off MADC Divider */
value = snd_soc_read(codec, AIC32X4_MADC); snd_soc_update_bits(codec, AIC32X4_MADC,
snd_soc_write(codec, AIC32X4_MADC, AIC32X4_MADCEN, 0);
value & ~AIC32X4_MDACEN);
value = snd_soc_read(codec, AIC32X4_BCLKN);
/* Switch off BCLK_N Divider */ /* Switch off BCLK_N Divider */
snd_soc_write(codec, AIC32X4_BCLKN, snd_soc_update_bits(codec, AIC32X4_BCLKN,
value & ~AIC32X4_BCLKEN); AIC32X4_BCLKEN, 0);
} }
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
@ -685,10 +672,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
} }
/* Mic PGA routing */ /* Mic PGA routing */
if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) { if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) {
snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K); snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K);
} }
if (aic32x4->micpga_routing | AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) { if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) {
snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K); snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K);
} }

View File

@ -76,7 +76,6 @@ struct aic3x_priv {
struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES]; struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
struct aic3x_setup_data *setup; struct aic3x_setup_data *setup;
void *control_data;
unsigned int sysclk; unsigned int sysclk;
struct list_head list; struct list_head list;
int master; int master;
@ -138,7 +137,10 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg,
if (reg >= AIC3X_CACHEREGNUM) if (reg >= AIC3X_CACHEREGNUM)
return -1; return -1;
*value = codec->hw_read(codec, reg); codec->cache_bypass = 1;
*value = snd_soc_read(codec, reg);
codec->cache_bypass = 0;
cache[reg] = *value; cache[reg] = *value;
return 0; return 0;
@ -198,6 +200,10 @@ static int snd_soc_dapm_put_volsw_aic3x(struct snd_kcontrol *kcontrol,
else else
/* old connection must be powered down */ /* old connection must be powered down */
path->connect = invert ? 1 : 0; path->connect = invert ? 1 : 0;
dapm_mark_dirty(path->source, "tlv320aic3x source");
dapm_mark_dirty(path->sink, "tlv320aic3x sink");
break; break;
} }
@ -1383,7 +1389,6 @@ static int aic3x_probe(struct snd_soc_codec *codec)
int ret, i; int ret, i;
INIT_LIST_HEAD(&aic3x->list); INIT_LIST_HEAD(&aic3x->list);
codec->control_data = aic3x->control_data;
aic3x->codec = codec; aic3x->codec = codec;
codec->dapm.idle_bias_off = 1; codec->dapm.idle_bias_off = 1;
@ -1495,9 +1500,9 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = {
*/ */
static const struct i2c_device_id aic3x_i2c_id[] = { static const struct i2c_device_id aic3x_i2c_id[] = {
[AIC3X_MODEL_3X] = { "tlv320aic3x", 0 }, { "tlv320aic3x", AIC3X_MODEL_3X },
[AIC3X_MODEL_33] = { "tlv320aic33", 0 }, { "tlv320aic33", AIC3X_MODEL_33 },
[AIC3X_MODEL_3007] = { "tlv320aic3007", 0 }, { "tlv320aic3007", AIC3X_MODEL_3007 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id);
@ -1512,7 +1517,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
struct aic3x_pdata *pdata = i2c->dev.platform_data; struct aic3x_pdata *pdata = i2c->dev.platform_data;
struct aic3x_priv *aic3x; struct aic3x_priv *aic3x;
int ret; int ret;
const struct i2c_device_id *tbl;
aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL); aic3x = kzalloc(sizeof(struct aic3x_priv), GFP_KERNEL);
if (aic3x == NULL) { if (aic3x == NULL) {
@ -1520,7 +1524,6 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
} }
aic3x->control_data = i2c;
aic3x->control_type = SND_SOC_I2C; aic3x->control_type = SND_SOC_I2C;
i2c_set_clientdata(i2c, aic3x); i2c_set_clientdata(i2c, aic3x);
@ -1531,11 +1534,7 @@ static int aic3x_i2c_probe(struct i2c_client *i2c,
aic3x->gpio_reset = -1; aic3x->gpio_reset = -1;
} }
for (tbl = aic3x_i2c_id; tbl->name[0]; tbl++) { aic3x->model = id->driver_data;
if (!strcmp(tbl->name, id->name))
break;
}
aic3x->model = tbl - aic3x_i2c_id;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_aic3x, &aic3x_dai, 1); &soc_codec_dev_aic3x, &aic3x_dai, 1);

View File

@ -55,13 +55,13 @@
#define BURST_BASEFREQ_HZ 49152000 #define BURST_BASEFREQ_HZ 49152000
#define SAMPLES_TO_US(rate, samples) \ #define SAMPLES_TO_US(rate, samples) \
(1000000000 / ((rate * 1000) / samples)) (1000000000 / (((rate) * 1000) / (samples)))
#define US_TO_SAMPLES(rate, us) \ #define US_TO_SAMPLES(rate, us) \
(rate / (1000000 / (us < 1000000 ? us : 1000000))) ((rate) / (1000000 / ((us) < 1000000 ? (us) : 1000000)))
#define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \ #define UTHR_FROM_PERIOD_SIZE(samples, playrate, burstrate) \
((samples * 5000) / ((burstrate * 5000) / (burstrate - playrate))) (((samples)*5000) / (((burstrate)*5000) / ((burstrate) - (playrate))))
static void dac33_calculate_times(struct snd_pcm_substream *substream); static void dac33_calculate_times(struct snd_pcm_substream *substream);
static int dac33_prepare_chip(struct snd_pcm_substream *substream); static int dac33_prepare_chip(struct snd_pcm_substream *substream);
@ -627,18 +627,6 @@ static const struct snd_soc_dapm_route audio_map[] = {
{"RIGHT_LO", NULL, "Codec Power"}, {"RIGHT_LO", NULL, "Codec Power"},
}; };
static int dac33_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, dac33_dapm_widgets,
ARRAY_SIZE(dac33_dapm_widgets));
/* set up audio path interconnects */
snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map));
return 0;
}
static int dac33_set_bias_level(struct snd_soc_codec *codec, static int dac33_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
@ -1451,15 +1439,11 @@ static int dac33_soc_probe(struct snd_soc_codec *codec)
} }
} }
snd_soc_add_controls(codec, dac33_snd_controls,
ARRAY_SIZE(dac33_snd_controls));
/* Only add the FIFO controls, if we have valid IRQ number */ /* Only add the FIFO controls, if we have valid IRQ number */
if (dac33->irq >= 0) if (dac33->irq >= 0)
snd_soc_add_controls(codec, dac33_mode_snd_controls, snd_soc_add_controls(codec, dac33_mode_snd_controls,
ARRAY_SIZE(dac33_mode_snd_controls)); ARRAY_SIZE(dac33_mode_snd_controls));
dac33_add_widgets(codec);
err_power: err_power:
return ret; return ret;
} }
@ -1502,6 +1486,13 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320dac33 = {
.remove = dac33_soc_remove, .remove = dac33_soc_remove,
.suspend = dac33_soc_suspend, .suspend = dac33_soc_suspend,
.resume = dac33_soc_resume, .resume = dac33_soc_resume,
.controls = dac33_snd_controls,
.num_controls = ARRAY_SIZE(dac33_snd_controls),
.dapm_widgets = dac33_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(dac33_dapm_widgets),
.dapm_routes = audio_map,
.num_dapm_routes = ARRAY_SIZE(audio_map),
}; };
#define DAC33_RATES (SNDRV_PCM_RATE_44100 | \ #define DAC33_RATES (SNDRV_PCM_RATE_44100 | \

View File

@ -33,6 +33,11 @@
#include "tpa6130a2.h" #include "tpa6130a2.h"
enum tpa_model {
TPA6130A2,
TPA6140A2,
};
static struct i2c_client *tpa6130a2_client; static struct i2c_client *tpa6130a2_client;
/* This struct is used to save the context */ /* This struct is used to save the context */
@ -383,7 +388,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
pdata = client->dev.platform_data; pdata = client->dev.platform_data;
data->power_gpio = pdata->power_gpio; data->power_gpio = pdata->power_gpio;
data->id = pdata->id; data->id = id->driver_data;
mutex_init(&data->mutex); mutex_init(&data->mutex);
@ -405,7 +410,7 @@ static int __devinit tpa6130a2_probe(struct i2c_client *client,
switch (data->id) { switch (data->id) {
default: default:
dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n", dev_warn(dev, "Unknown TPA model (%d). Assuming 6130A2\n",
pdata->id); data->id);
case TPA6130A2: case TPA6130A2:
regulator = "Vdd"; regulator = "Vdd";
break; break;
@ -469,7 +474,8 @@ static int __devexit tpa6130a2_remove(struct i2c_client *client)
} }
static const struct i2c_device_id tpa6130a2_id[] = { static const struct i2c_device_id tpa6130a2_id[] = {
{ "tpa6130a2", 0 }, { "tpa6130a2", TPA6130A2 },
{ "tpa6140a2", TPA6140A2 },
{ } { }
}; };
MODULE_DEVICE_TABLE(i2c, tpa6130a2_id); MODULE_DEVICE_TABLE(i2c, tpa6130a2_id);

View File

@ -863,34 +863,6 @@ static int digimic_event(struct snd_soc_dapm_widget *w,
* Inverting not going to help with these. * Inverting not going to help with these.
* Custom volsw and volsw_2r get/put functions to handle these gain bits. * Custom volsw and volsw_2r get/put functions to handle these gain bits.
*/ */
#define SOC_DOUBLE_TLV_TWL4030(xname, xreg, shift_left, shift_right, xmax,\
xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw, \
.get = snd_soc_get_volsw_twl4030, \
.put = snd_soc_put_volsw_twl4030, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = shift_left, .rshift = shift_right,\
.max = xmax, .invert = xinvert} }
#define SOC_DOUBLE_R_TLV_TWL4030(xname, reg_left, reg_right, xshift, xmax,\
xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE,\
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_2r, \
.get = snd_soc_get_volsw_r2_twl4030,\
.put = snd_soc_put_volsw_r2_twl4030, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
.rshift = xshift, .max = xmax, .invert = xinvert} }
#define SOC_SINGLE_TLV_TWL4030(xname, xreg, xshift, xmax, xinvert, tlv_array) \
SOC_DOUBLE_TLV_TWL4030(xname, xreg, xshift, xshift, xmax, \
xinvert, tlv_array)
static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol, static int snd_soc_get_volsw_twl4030(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
@ -1197,19 +1169,23 @@ static const struct snd_kcontrol_new twl4030_snd_controls[] = {
TWL4030_REG_VDL_APGA_CTL, 1, 1, 0), TWL4030_REG_VDL_APGA_CTL, 1, 1, 0),
/* Separate output gain controls */ /* Separate output gain controls */
SOC_DOUBLE_R_TLV_TWL4030("PreDriv Playback Volume", SOC_DOUBLE_R_EXT_TLV("PreDriv Playback Volume",
TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL, TWL4030_REG_PREDL_CTL, TWL4030_REG_PREDR_CTL,
4, 3, 0, output_tvl), 4, 3, 0, snd_soc_get_volsw_r2_twl4030,
snd_soc_put_volsw_r2_twl4030, output_tvl),
SOC_DOUBLE_TLV_TWL4030("Headset Playback Volume", SOC_DOUBLE_EXT_TLV("Headset Playback Volume",
TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, output_tvl), TWL4030_REG_HS_GAIN_SET, 0, 2, 3, 0, snd_soc_get_volsw_twl4030,
snd_soc_put_volsw_twl4030, output_tvl),
SOC_DOUBLE_R_TLV_TWL4030("Carkit Playback Volume", SOC_DOUBLE_R_EXT_TLV("Carkit Playback Volume",
TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL, TWL4030_REG_PRECKL_CTL, TWL4030_REG_PRECKR_CTL,
4, 3, 0, output_tvl), 4, 3, 0, snd_soc_get_volsw_r2_twl4030,
snd_soc_put_volsw_r2_twl4030, output_tvl),
SOC_SINGLE_TLV_TWL4030("Earpiece Playback Volume", SOC_SINGLE_EXT_TLV("Earpiece Playback Volume",
TWL4030_REG_EAR_CTL, 4, 3, 0, output_ear_tvl), TWL4030_REG_EAR_CTL, 4, 3, 0, snd_soc_get_volsw_twl4030,
snd_soc_put_volsw_twl4030, output_ear_tvl),
/* Common capture gain controls */ /* Common capture gain controls */
SOC_DOUBLE_R_TLV("TX1 Digital Capture Volume", SOC_DOUBLE_R_TLV("TX1 Digital Capture Volume",
@ -1633,17 +1609,6 @@ static const struct snd_soc_dapm_route intercon[] = {
}; };
static int twl4030_add_widgets(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = &codec->dapm;
snd_soc_dapm_new_controls(dapm, twl4030_dapm_widgets,
ARRAY_SIZE(twl4030_dapm_widgets));
snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
return 0;
}
static int twl4030_set_bias_level(struct snd_soc_codec *codec, static int twl4030_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
@ -2265,9 +2230,6 @@ static int twl4030_soc_probe(struct snd_soc_codec *codec)
twl4030_init_chip(codec); twl4030_init_chip(codec);
snd_soc_add_controls(codec, twl4030_snd_controls,
ARRAY_SIZE(twl4030_snd_controls));
twl4030_add_widgets(codec);
return 0; return 0;
} }
@ -2293,6 +2255,13 @@ static struct snd_soc_codec_driver soc_codec_dev_twl4030 = {
.reg_cache_size = sizeof(twl4030_reg), .reg_cache_size = sizeof(twl4030_reg),
.reg_word_size = sizeof(u8), .reg_word_size = sizeof(u8),
.reg_cache_default = twl4030_reg, .reg_cache_default = twl4030_reg,
.controls = twl4030_snd_controls,
.num_controls = ARRAY_SIZE(twl4030_snd_controls),
.dapm_widgets = twl4030_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(twl4030_dapm_widgets),
.dapm_routes = intercon,
.num_dapm_routes = ARRAY_SIZE(intercon),
}; };
static int __devinit twl4030_codec_probe(struct platform_device *pdev) static int __devinit twl4030_codec_probe(struct platform_device *pdev)

File diff suppressed because it is too large Load Diff

View File

@ -22,8 +22,21 @@
#ifndef __TWL6040_H__ #ifndef __TWL6040_H__
#define __TWL6040_H__ #define __TWL6040_H__
enum twl6040_trim {
TWL6040_TRIM_TRIM1 = 0,
TWL6040_TRIM_TRIM2,
TWL6040_TRIM_TRIM3,
TWL6040_TRIM_HSOTRIM,
TWL6040_TRIM_HFOTRIM,
TWL6040_TRIM_INVAL,
};
#define TWL6040_HSF_TRIM_LEFT(x) (x & 0x0f)
#define TWL6040_HSF_TRIM_RIGHT(x) ((x >> 4) & 0x0f)
void twl6040_hs_jack_detect(struct snd_soc_codec *codec, void twl6040_hs_jack_detect(struct snd_soc_codec *codec,
struct snd_soc_jack *jack, int report); struct snd_soc_jack *jack, int report);
int twl6040_get_clk_id(struct snd_soc_codec *codec); int twl6040_get_clk_id(struct snd_soc_codec *codec);
int twl6040_get_trim_value(struct snd_soc_codec *codec, enum twl6040_trim trim);
#endif /* End of __TWL6040_H__ */ #endif /* End of __TWL6040_H__ */

View File

@ -462,7 +462,6 @@ static int wl1273_probe(struct snd_soc_codec *codec)
wl1273->core = *core; wl1273->core = *core;
snd_soc_codec_set_drvdata(codec, wl1273); snd_soc_codec_set_drvdata(codec, wl1273);
mutex_init(&codec->mutex);
r = snd_soc_add_controls(codec, wl1273_controls, r = snd_soc_add_controls(codec, wl1273_controls,
ARRAY_SIZE(wl1273_controls)); ARRAY_SIZE(wl1273_controls));

View File

@ -12,10 +12,59 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/gpio.h>
#include <sound/soc.h> #include <sound/soc.h>
#include <sound/soc-dapm.h> #include <sound/soc-dapm.h>
#include <sound/wm1250-ev1.h>
static const char *wm1250_gpio_names[WM1250_EV1_NUM_GPIOS] = {
"WM1250 CLK_ENA",
"WM1250 CLK_SEL0",
"WM1250 CLK_SEL1",
"WM1250 OSR",
"WM1250 MASTER",
};
struct wm1250_priv {
struct gpio gpios[WM1250_EV1_NUM_GPIOS];
};
static int wm1250_ev1_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
struct wm1250_priv *wm1250 = dev_get_drvdata(codec->dev);
int ena;
if (wm1250)
ena = wm1250->gpios[WM1250_EV1_GPIO_CLK_ENA].gpio;
else
ena = -1;
switch (level) {
case SND_SOC_BIAS_ON:
break;
case SND_SOC_BIAS_PREPARE:
break;
case SND_SOC_BIAS_STANDBY:
if (ena >= 0)
gpio_set_value_cansleep(ena, 1);
break;
case SND_SOC_BIAS_OFF:
if (ena >= 0)
gpio_set_value_cansleep(ena, 0);
break;
}
codec->dapm.bias_level = level;
return 0;
}
static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = { static const struct snd_soc_dapm_widget wm1250_ev1_dapm_widgets[] = {
SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_ADC("ADC", "wm1250-ev1 Capture", SND_SOC_NOPM, 0, 0),
@ -53,12 +102,67 @@ static struct snd_soc_codec_driver soc_codec_dev_wm1250_ev1 = {
.num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets), .num_dapm_widgets = ARRAY_SIZE(wm1250_ev1_dapm_widgets),
.dapm_routes = wm1250_ev1_dapm_routes, .dapm_routes = wm1250_ev1_dapm_routes,
.num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes), .num_dapm_routes = ARRAY_SIZE(wm1250_ev1_dapm_routes),
.set_bias_level = wm1250_ev1_set_bias_level,
.idle_bias_off = true,
}; };
static int __devinit wm1250_ev1_pdata(struct i2c_client *i2c)
{
struct wm1250_ev1_pdata *pdata = dev_get_platdata(&i2c->dev);
struct wm1250_priv *wm1250;
int i, ret;
if (!pdata)
return 0;
wm1250 = kzalloc(sizeof(*wm1250), GFP_KERNEL);
if (!wm1250) {
dev_err(&i2c->dev, "Unable to allocate private data\n");
ret = -ENOMEM;
goto err;
}
for (i = 0; i < ARRAY_SIZE(wm1250->gpios); i++) {
wm1250->gpios[i].gpio = pdata->gpios[i];
wm1250->gpios[i].label = wm1250_gpio_names[i];
wm1250->gpios[i].flags = GPIOF_OUT_INIT_LOW;
}
wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL0].flags = GPIOF_OUT_INIT_HIGH;
wm1250->gpios[WM1250_EV1_GPIO_CLK_SEL1].flags = GPIOF_OUT_INIT_HIGH;
ret = gpio_request_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
if (ret != 0) {
dev_err(&i2c->dev, "Failed to get GPIOs: %d\n", ret);
goto err_alloc;
}
dev_set_drvdata(&i2c->dev, wm1250);
return ret;
err_alloc:
kfree(wm1250);
err:
return ret;
}
static void wm1250_ev1_free(struct i2c_client *i2c)
{
struct wm1250_priv *wm1250 = dev_get_drvdata(&i2c->dev);
if (wm1250) {
gpio_free_array(wm1250->gpios, ARRAY_SIZE(wm1250->gpios));
kfree(wm1250);
}
}
static int __devinit wm1250_ev1_probe(struct i2c_client *i2c, static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
const struct i2c_device_id *i2c_id) const struct i2c_device_id *i2c_id)
{ {
int id, board, rev; int id, board, rev, ret;
dev_set_drvdata(&i2c->dev, NULL);
board = i2c_smbus_read_byte_data(i2c, 0); board = i2c_smbus_read_byte_data(i2c, 0);
if (board < 0) { if (board < 0) {
@ -76,13 +180,25 @@ static int __devinit wm1250_ev1_probe(struct i2c_client *i2c,
dev_info(&i2c->dev, "revision %d\n", rev + 1); dev_info(&i2c->dev, "revision %d\n", rev + 1);
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1, ret = wm1250_ev1_pdata(i2c);
if (ret != 0)
return ret;
ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm1250_ev1,
&wm1250_ev1_dai, 1); &wm1250_ev1_dai, 1);
if (ret != 0) {
dev_err(&i2c->dev, "Failed to register CODEC: %d\n", ret);
wm1250_ev1_free(i2c);
return ret;
}
return 0;
} }
static int __devexit wm1250_ev1_remove(struct i2c_client *i2c) static int __devexit wm1250_ev1_remove(struct i2c_client *i2c)
{ {
snd_soc_unregister_codec(&i2c->dev); snd_soc_unregister_codec(&i2c->dev);
wm1250_ev1_free(i2c);
return 0; return 0;
} }

File diff suppressed because it is too large Load Diff

2809
sound/soc/codecs/wm5100.c Normal file

File diff suppressed because it is too large Load Diff

5155
sound/soc/codecs/wm5100.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -355,7 +355,7 @@ static int wm8350_put_volsw_2r_vu(struct snd_kcontrol *kcontrol,
return 1; return 1;
} }
ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -392,23 +392,9 @@ static int wm8350_get_volsw_2r(struct snd_kcontrol *kcontrol,
break; break;
} }
return snd_soc_get_volsw_2r(kcontrol, ucontrol); return snd_soc_get_volsw(kcontrol, ucontrol);
} }
/* double control with volume update */
#define SOC_WM8350_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \
xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE | \
SNDRV_CTL_ELEM_ACCESS_VOLATILE, \
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_2r, \
.get = wm8350_get_volsw_2r, .put = wm8350_put_volsw_2r_vu, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
.rshift = xshift, .max = xmax, .invert = xinvert}, }
static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; static const char *wm8350_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" };
static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" }; static const char *wm8350_pol[] = { "Normal", "Inv R", "Inv L", "Inv L & R" };
static const char *wm8350_dacmutem[] = { "Normal", "Soft" }; static const char *wm8350_dacmutem[] = { "Normal", "Soft" };
@ -443,26 +429,29 @@ static const unsigned int capture_sd_tlv[] = {
static const struct snd_kcontrol_new wm8350_snd_controls[] = { static const struct snd_kcontrol_new wm8350_snd_controls[] = {
SOC_ENUM("Playback Deemphasis", wm8350_enum[0]), SOC_ENUM("Playback Deemphasis", wm8350_enum[0]),
SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]), SOC_ENUM("Playback DAC Inversion", wm8350_enum[1]),
SOC_WM8350_DOUBLE_R_TLV("Playback PCM Volume", SOC_DOUBLE_R_EXT_TLV("Playback PCM Volume",
WM8350_DAC_DIGITAL_VOLUME_L, WM8350_DAC_DIGITAL_VOLUME_L,
WM8350_DAC_DIGITAL_VOLUME_R, WM8350_DAC_DIGITAL_VOLUME_R,
0, 255, 0, dac_pcm_tlv), 0, 255, 0, wm8350_get_volsw_2r,
wm8350_put_volsw_2r_vu, dac_pcm_tlv),
SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]), SOC_ENUM("Playback PCM Mute Function", wm8350_enum[2]),
SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]), SOC_ENUM("Playback PCM Mute Speed", wm8350_enum[3]),
SOC_ENUM("Capture PCM Filter", wm8350_enum[4]), SOC_ENUM("Capture PCM Filter", wm8350_enum[4]),
SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]), SOC_ENUM("Capture PCM HP Filter", wm8350_enum[5]),
SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]), SOC_ENUM("Capture ADC Inversion", wm8350_enum[6]),
SOC_WM8350_DOUBLE_R_TLV("Capture PCM Volume", SOC_DOUBLE_R_EXT_TLV("Capture PCM Volume",
WM8350_ADC_DIGITAL_VOLUME_L, WM8350_ADC_DIGITAL_VOLUME_L,
WM8350_ADC_DIGITAL_VOLUME_R, WM8350_ADC_DIGITAL_VOLUME_R,
0, 255, 0, adc_pcm_tlv), 0, 255, 0, wm8350_get_volsw_2r,
wm8350_put_volsw_2r_vu, adc_pcm_tlv),
SOC_DOUBLE_TLV("Capture Sidetone Volume", SOC_DOUBLE_TLV("Capture Sidetone Volume",
WM8350_ADC_DIVIDER, WM8350_ADC_DIVIDER,
8, 4, 15, 1, capture_sd_tlv), 8, 4, 15, 1, capture_sd_tlv),
SOC_WM8350_DOUBLE_R_TLV("Capture Volume", SOC_DOUBLE_R_EXT_TLV("Capture Volume",
WM8350_LEFT_INPUT_VOLUME, WM8350_LEFT_INPUT_VOLUME,
WM8350_RIGHT_INPUT_VOLUME, WM8350_RIGHT_INPUT_VOLUME,
2, 63, 0, pre_amp_tlv), 2, 63, 0, wm8350_get_volsw_2r,
wm8350_put_volsw_2r_vu, pre_amp_tlv),
SOC_DOUBLE_R("Capture ZC Switch", SOC_DOUBLE_R("Capture ZC Switch",
WM8350_LEFT_INPUT_VOLUME, WM8350_LEFT_INPUT_VOLUME,
WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0), WM8350_RIGHT_INPUT_VOLUME, 13, 1, 0),
@ -490,17 +479,19 @@ static const struct snd_kcontrol_new wm8350_snd_controls[] = {
SOC_SINGLE_TLV("Out4 Capture Volume", SOC_SINGLE_TLV("Out4 Capture Volume",
WM8350_INPUT_MIXER_VOLUME, WM8350_INPUT_MIXER_VOLUME,
1, 7, 0, out_mix_tlv), 1, 7, 0, out_mix_tlv),
SOC_WM8350_DOUBLE_R_TLV("Out1 Playback Volume", SOC_DOUBLE_R_EXT_TLV("Out1 Playback Volume",
WM8350_LOUT1_VOLUME, WM8350_LOUT1_VOLUME,
WM8350_ROUT1_VOLUME, WM8350_ROUT1_VOLUME,
2, 63, 0, out_pga_tlv), 2, 63, 0, wm8350_get_volsw_2r,
wm8350_put_volsw_2r_vu, out_pga_tlv),
SOC_DOUBLE_R("Out1 Playback ZC Switch", SOC_DOUBLE_R("Out1 Playback ZC Switch",
WM8350_LOUT1_VOLUME, WM8350_LOUT1_VOLUME,
WM8350_ROUT1_VOLUME, 13, 1, 0), WM8350_ROUT1_VOLUME, 13, 1, 0),
SOC_WM8350_DOUBLE_R_TLV("Out2 Playback Volume", SOC_DOUBLE_R_EXT_TLV("Out2 Playback Volume",
WM8350_LOUT2_VOLUME, WM8350_LOUT2_VOLUME,
WM8350_ROUT2_VOLUME, WM8350_ROUT2_VOLUME,
2, 63, 0, out_pga_tlv), 2, 63, 0, wm8350_get_volsw_2r,
wm8350_put_volsw_2r_vu, out_pga_tlv),
SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME, SOC_DOUBLE_R("Out2 Playback ZC Switch", WM8350_LOUT2_VOLUME,
WM8350_ROUT2_VOLUME, 13, 1, 0), WM8350_ROUT2_VOLUME, 13, 1, 0),
SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0), SOC_SINGLE("Out2 Right Invert Switch", WM8350_ROUT2_VOLUME, 10, 1, 0),

View File

@ -383,7 +383,7 @@ static int inmixer_event (struct snd_soc_dapm_widget *w,
(1 << WM8400_AINRMUX_PWR))) { (1 << WM8400_AINRMUX_PWR))) {
reg |= WM8400_AINR_ENA; reg |= WM8400_AINR_ENA;
} else { } else {
reg &= ~WM8400_AINL_ENA; reg &= ~WM8400_AINR_ENA;
} }
wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg); wm8400_write(w->codec, WM8400_POWER_MANAGEMENT_2, reg);

View File

@ -480,6 +480,8 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec,
power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN; power1 |= WM8510_POWER1_BIASEN | WM8510_POWER1_BUFIOEN;
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec);
/* Initial cap charge at VMID 5k */ /* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8510_POWER1, power1 | 0x3); snd_soc_write(codec, WM8510_POWER1, power1 | 0x3);
mdelay(100); mdelay(100);
@ -541,18 +543,7 @@ static int wm8510_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8510_resume(struct snd_soc_codec *codec) static int wm8510_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8510_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }

View File

@ -406,7 +406,6 @@ static int wm8523_probe(struct snd_soc_codec *codec)
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec); struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
int ret, i; int ret, i;
codec->hw_write = (hw_write_t)i2c_master_send;
wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0];
wm8523->rate_constraint.count = wm8523->rate_constraint.count =
ARRAY_SIZE(wm8523->rate_constraint_list); ARRAY_SIZE(wm8523->rate_constraint_list);

View File

@ -213,7 +213,7 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
reg_cache[reg] = 0; reg_cache[reg] = 0;
reg_cache[reg2] = 0; reg_cache[reg2] = 0;
ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); ret = snd_soc_put_volsw(kcontrol, ucontrol);
if (ret < 0) if (ret < 0)
return ret; return ret;
@ -224,31 +224,19 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol,
return 0; return 0;
} }
#define SOC_WM8580_OUT_DOUBLE_R_TLV(xname, reg_left, reg_right, xshift, xmax, \
xinvert, tlv_array) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
.info = snd_soc_info_volsw_2r, \
.get = snd_soc_get_volsw_2r, .put = wm8580_out_vu, \
.private_value = (unsigned long)&(struct soc_mixer_control) \
{.reg = reg_left, .rreg = reg_right, .shift = xshift, \
.max = xmax, .invert = xinvert} }
static const struct snd_kcontrol_new wm8580_snd_controls[] = { static const struct snd_kcontrol_new wm8580_snd_controls[] = {
SOC_WM8580_OUT_DOUBLE_R_TLV("DAC1 Playback Volume", SOC_DOUBLE_R_EXT_TLV("DAC1 Playback Volume",
WM8580_DIGITAL_ATTENUATION_DACL1, WM8580_DIGITAL_ATTENUATION_DACL1,
WM8580_DIGITAL_ATTENUATION_DACR1, WM8580_DIGITAL_ATTENUATION_DACR1,
0, 0xff, 0, dac_tlv), 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
SOC_WM8580_OUT_DOUBLE_R_TLV("DAC2 Playback Volume", SOC_DOUBLE_R_EXT_TLV("DAC2 Playback Volume",
WM8580_DIGITAL_ATTENUATION_DACL2, WM8580_DIGITAL_ATTENUATION_DACL2,
WM8580_DIGITAL_ATTENUATION_DACR2, WM8580_DIGITAL_ATTENUATION_DACR2,
0, 0xff, 0, dac_tlv), 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
SOC_WM8580_OUT_DOUBLE_R_TLV("DAC3 Playback Volume", SOC_DOUBLE_R_EXT_TLV("DAC3 Playback Volume",
WM8580_DIGITAL_ATTENUATION_DACL3, WM8580_DIGITAL_ATTENUATION_DACL3,
WM8580_DIGITAL_ATTENUATION_DACR3, WM8580_DIGITAL_ATTENUATION_DACR3,
0, 0xff, 0, dac_tlv), 0, 0xff, 0, snd_soc_get_volsw, wm8580_out_vu, dac_tlv),
SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0), SOC_SINGLE("DAC1 Deemphasis Switch", WM8580_DAC_CONTROL3, 0, 1, 0),
SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0), SOC_SINGLE("DAC2 Deemphasis Switch", WM8580_DAC_CONTROL3, 1, 1, 0),
@ -442,8 +430,7 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
/* Always disable the PLL - it is not safe to leave it running /* Always disable the PLL - it is not safe to leave it running
* while reprogramming it. * while reprogramming it.
*/ */
reg = snd_soc_read(codec, WM8580_PWRDN2); snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, pwr_mask);
snd_soc_write(codec, WM8580_PWRDN2, reg | pwr_mask);
if (!freq_in || !freq_out) if (!freq_in || !freq_out)
return 0; return 0;
@ -461,8 +448,7 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
snd_soc_write(codec, WM8580_PLLA4 + offset, reg); snd_soc_write(codec, WM8580_PLLA4 + offset, reg);
/* All done, turn it on */ /* All done, turn it on */
reg = snd_soc_read(codec, WM8580_PWRDN2); snd_soc_update_bits(codec, WM8580_PWRDN2, pwr_mask, 0);
snd_soc_write(codec, WM8580_PWRDN2, reg & ~pwr_mask);
return 0; return 0;
} }
@ -760,7 +746,6 @@ static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute)
static int wm8580_set_bias_level(struct snd_soc_codec *codec, static int wm8580_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 reg;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
@ -769,20 +754,19 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
/* Power up and get individual control of the DACs */ /* Power up and get individual control of the DACs */
reg = snd_soc_read(codec, WM8580_PWRDN1); snd_soc_update_bits(codec, WM8580_PWRDN1,
reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); WM8580_PWRDN1_PWDN |
snd_soc_write(codec, WM8580_PWRDN1, reg); WM8580_PWRDN1_ALLDACPD, 0);
/* Make VMID high impedance */ /* Make VMID high impedance */
reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); snd_soc_update_bits(codec, WM8580_ADC_CONTROL1,
reg &= ~0x100; 0x100, 0);
snd_soc_write(codec, WM8580_ADC_CONTROL1, reg);
} }
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
reg = snd_soc_read(codec, WM8580_PWRDN1); snd_soc_update_bits(codec, WM8580_PWRDN1,
snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); WM8580_PWRDN1_PWDN, WM8580_PWRDN1_PWDN);
break; break;
} }
codec->dapm.bias_level = level; codec->dapm.bias_level = level;

View File

@ -3,7 +3,7 @@
* *
* Copyright 2006 Wolfson Microelectronics * Copyright 2006 Wolfson Microelectronics
* *
* Author: Mike Arthur <linux@wolfsonmicro.com> * Author: Mike Arthur <Mike.Arthur@wolfsonmicro.com>
* *
* Based on wm8731.c by Richard Purdie * Based on wm8731.c by Richard Purdie
* *
@ -287,7 +287,6 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai,
return 0; return 0;
} }
static int wm8711_set_bias_level(struct snd_soc_codec *codec, static int wm8711_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
@ -300,6 +299,9 @@ static int wm8711_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
snd_soc_cache_sync(codec);
snd_soc_write(codec, WM8711_PWR, reg | 0x0040); snd_soc_write(codec, WM8711_PWR, reg | 0x0040);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
@ -346,25 +348,14 @@ static int wm8711_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8711_resume(struct snd_soc_codec *codec) static int wm8711_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8711_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }
static int wm8711_probe(struct snd_soc_codec *codec) static int wm8711_probe(struct snd_soc_codec *codec)
{ {
struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec); struct wm8711_priv *wm8711 = snd_soc_codec_get_drvdata(codec);
int ret, reg; int ret;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type); ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8711->bus_type);
if (ret < 0) { if (ret < 0) {
@ -381,10 +372,8 @@ static int wm8711_probe(struct snd_soc_codec *codec)
wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the update bits */ /* Latch the update bits */
reg = snd_soc_read(codec, WM8711_LOUT1V); snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100);
snd_soc_write(codec, WM8711_LOUT1V, reg | 0x0100); snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8711_ROUT1V);
snd_soc_write(codec, WM8711_ROUT1V, reg | 0x0100);
snd_soc_add_controls(codec, wm8711_snd_controls, snd_soc_add_controls(codec, wm8711_snd_controls,
ARRAY_SIZE(wm8711_snd_controls)); ARRAY_SIZE(wm8711_snd_controls));

View File

@ -427,9 +427,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
int i, ret; int ret;
u8 data[2];
u16 *cache = codec->reg_cache;
u16 reg; u16 reg;
switch (level) { switch (level) {
@ -444,16 +442,7 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec,
if (ret != 0) if (ret != 0)
return ret; return ret;
/* Sync reg_cache with the hardware */ snd_soc_cache_sync(codec);
for (i = 0; i < ARRAY_SIZE(wm8731_reg); i++) {
if (cache[i] == wm8731_reg[i])
continue;
data[0] = (i << 1) | ((cache[i] >> 8)
& 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
} }
/* Clear PWROFF, gate CLKOUT, everything else as-is */ /* Clear PWROFF, gate CLKOUT, everything else as-is */

View File

@ -339,10 +339,10 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai,
iface |= 0x0004; iface |= 0x0004;
break; break;
case SND_SOC_DAIFMT_DSP_A: case SND_SOC_DAIFMT_DSP_A:
iface |= 0x0003; iface |= 0x000C;
break; break;
case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_DSP_B:
iface |= 0x0013; iface |= 0x001C;
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -404,15 +404,7 @@ static struct snd_soc_dai_driver wm8741_dai = {
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int wm8741_resume(struct snd_soc_codec *codec) static int wm8741_resume(struct snd_soc_codec *codec)
{ {
u16 *cache = codec->reg_cache; snd_soc_cache_sync(codec);
int i;
/* RESTORE REG Cache */
for (i = 0; i < WM8741_REGISTER_COUNT; i++) {
if (cache[i] == wm8741_reg_defaults[i] || WM8741_RESET == i)
continue;
snd_soc_write(codec, i, cache[i]);
}
return 0; return 0;
} }
#else #else
@ -462,7 +454,7 @@ static int wm8741_probe(struct snd_soc_codec *codec)
WM8741_UPDATELM, WM8741_UPDATELM); WM8741_UPDATELM, WM8741_UPDATELM);
snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION,
WM8741_UPDATERL, WM8741_UPDATERL); WM8741_UPDATERL, WM8741_UPDATERL);
snd_soc_update_bits(codec, WM8741_DACRLSB_ATTENUATION, snd_soc_update_bits(codec, WM8741_DACRMSB_ATTENUATION,
WM8741_UPDATERM, WM8741_UPDATERM); WM8741_UPDATERM, WM8741_UPDATERM);
snd_soc_add_controls(codec, wm8741_snd_controls, snd_soc_add_controls(codec, wm8741_snd_controls,

View File

@ -616,6 +616,8 @@ static int wm8750_set_bias_level(struct snd_soc_codec *codec,
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec);
/* Set VMID to 5k */ /* Set VMID to 5k */
snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1);
@ -673,28 +675,14 @@ static int wm8750_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8750_resume(struct snd_soc_codec *codec) static int wm8750_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8750_reg); i++) {
if (i == WM8750_RESET)
continue;
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }
static int wm8750_probe(struct snd_soc_codec *codec) static int wm8750_probe(struct snd_soc_codec *codec)
{ {
struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec); struct wm8750_priv *wm8750 = snd_soc_codec_get_drvdata(codec);
int reg, ret; int ret;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type); ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8750->control_type);
if (ret < 0) { if (ret < 0) {
@ -712,22 +700,14 @@ static int wm8750_probe(struct snd_soc_codec *codec)
wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set the update bits */ /* set the update bits */
reg = snd_soc_read(codec, WM8750_LDAC); snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100);
snd_soc_write(codec, WM8750_LDAC, reg | 0x0100); snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8750_RDAC); snd_soc_update_bits(codec, WM8750_LOUT1V, 0x0100, 0x0100);
snd_soc_write(codec, WM8750_RDAC, reg | 0x0100); snd_soc_update_bits(codec, WM8750_ROUT1V, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8750_LOUT1V); snd_soc_update_bits(codec, WM8750_LOUT2V, 0x0100, 0x0100);
snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100); snd_soc_update_bits(codec, WM8750_ROUT2V, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8750_ROUT1V); snd_soc_update_bits(codec, WM8750_LINVOL, 0x0100, 0x0100);
snd_soc_write(codec, WM8750_ROUT1V, reg | 0x0100); snd_soc_update_bits(codec, WM8750_RINVOL, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8750_LOUT2V);
snd_soc_write(codec, WM8750_LOUT2V, reg | 0x0100);
reg = snd_soc_read(codec, WM8750_ROUT2V);
snd_soc_write(codec, WM8750_ROUT2V, reg | 0x0100);
reg = snd_soc_read(codec, WM8750_LINVOL);
snd_soc_write(codec, WM8750_LINVOL, reg | 0x0100);
reg = snd_soc_read(codec, WM8750_RINVOL);
snd_soc_write(codec, WM8750_RINVOL, reg | 0x0100);
snd_soc_add_controls(codec, wm8750_snd_controls, snd_soc_add_controls(codec, wm8750_snd_controls,
ARRAY_SIZE(wm8750_snd_controls)); ARRAY_SIZE(wm8750_snd_controls));

View File

@ -1455,8 +1455,8 @@ static int wm8753_probe(struct snd_soc_codec *codec)
/* set the update bits */ /* set the update bits */
snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_LADC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_RDAC, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_RADC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_LOUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_ROUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100); snd_soc_update_bits(codec, WM8753_LOUT2V, 0x0100, 0x0100);

View File

@ -308,6 +308,8 @@ static int wm8776_set_bias_level(struct snd_soc_codec *codec,
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec);
/* Disable the global powerdown; DAPM does the rest */ /* Disable the global powerdown; DAPM does the rest */
snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0); snd_soc_update_bits(codec, WM8776_PWRDOWN, 1, 0);
} }
@ -379,21 +381,7 @@ static int wm8776_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8776_resume(struct snd_soc_codec *codec) static int wm8776_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8776_reg); i++) {
if (cache[i] == wm8776_reg[i])
continue;
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }
#else #else

View File

@ -60,7 +60,7 @@ static struct platform_driver wm8782_codec_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
}, },
.probe = wm8782_probe, .probe = wm8782_probe,
.remove = wm8782_remove, .remove = __devexit_p(wm8782_remove),
}; };
static int __init wm8782_init(void) static int __init wm8782_init(void)

View File

@ -110,8 +110,8 @@
#define WM8900_REG_CLOCKING1_BCLK_DIR 0x1 #define WM8900_REG_CLOCKING1_BCLK_DIR 0x1
#define WM8900_REG_CLOCKING1_MCLK_SRC 0x100 #define WM8900_REG_CLOCKING1_MCLK_SRC 0x100
#define WM8900_REG_CLOCKING1_BCLK_MASK (~0x01e) #define WM8900_REG_CLOCKING1_BCLK_MASK 0x01e
#define WM8900_REG_CLOCKING1_OPCLK_MASK (~0x7000) #define WM8900_REG_CLOCKING1_OPCLK_MASK 0x7000
#define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0 #define WM8900_REG_CLOCKING2_ADC_CLKDIV 0xe0
#define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c #define WM8900_REG_CLOCKING2_DAC_CLKDIV 0x1c
@ -135,7 +135,7 @@
#define WM8900_REG_HPCTL1_HP_SHORT 0x08 #define WM8900_REG_HPCTL1_HP_SHORT 0x08
#define WM8900_REG_HPCTL1_HP_SHORT2 0x04 #define WM8900_REG_HPCTL1_HP_SHORT2 0x04
#define WM8900_LRC_MASK 0xfc00 #define WM8900_LRC_MASK 0x03ff
struct wm8900_priv { struct wm8900_priv {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
@ -742,26 +742,20 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
{ {
struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec); struct wm8900_priv *wm8900 = snd_soc_codec_get_drvdata(codec);
struct _fll_div fll_div; struct _fll_div fll_div;
unsigned int reg;
if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out) if (wm8900->fll_in == freq_in && wm8900->fll_out == freq_out)
return 0; return 0;
/* The digital side should be disabled during any change. */ /* The digital side should be disabled during any change. */
reg = snd_soc_read(codec, WM8900_REG_POWER1); snd_soc_update_bits(codec, WM8900_REG_POWER1,
snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_FLL_ENA, 0);
reg & (~WM8900_REG_POWER1_FLL_ENA));
/* Disable the FLL? */ /* Disable the FLL? */
if (!freq_in || !freq_out) { if (!freq_in || !freq_out) {
reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
snd_soc_write(codec, WM8900_REG_CLOCKING1, WM8900_REG_CLOCKING1_MCLK_SRC, 0);
reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); snd_soc_update_bits(codec, WM8900_REG_FLLCTL1,
WM8900_REG_FLLCTL1_OSC_ENA, 0);
reg = snd_soc_read(codec, WM8900_REG_FLLCTL1);
snd_soc_write(codec, WM8900_REG_FLLCTL1,
reg & (~WM8900_REG_FLLCTL1_OSC_ENA));
wm8900->fll_in = freq_in; wm8900->fll_in = freq_in;
wm8900->fll_out = freq_out; wm8900->fll_out = freq_out;
@ -796,15 +790,14 @@ static int wm8900_set_fll(struct snd_soc_codec *codec,
else else
snd_soc_write(codec, WM8900_REG_FLLCTL6, 0); snd_soc_write(codec, WM8900_REG_FLLCTL6, 0);
reg = snd_soc_read(codec, WM8900_REG_POWER1); snd_soc_update_bits(codec, WM8900_REG_POWER1,
snd_soc_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_FLL_ENA,
reg | WM8900_REG_POWER1_FLL_ENA); WM8900_REG_POWER1_FLL_ENA);
reenable: reenable:
reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
snd_soc_write(codec, WM8900_REG_CLOCKING1, WM8900_REG_CLOCKING1_MCLK_SRC,
reg | WM8900_REG_CLOCKING1_MCLK_SRC); WM8900_REG_CLOCKING1_MCLK_SRC);
return 0; return 0;
} }
@ -818,43 +811,35 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div) int div_id, int div)
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
unsigned int reg;
switch (div_id) { switch (div_id) {
case WM8900_BCLK_DIV: case WM8900_BCLK_DIV:
reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
snd_soc_write(codec, WM8900_REG_CLOCKING1, WM8900_REG_CLOCKING1_BCLK_MASK, div);
div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK));
break; break;
case WM8900_OPCLK_DIV: case WM8900_OPCLK_DIV:
reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); snd_soc_update_bits(codec, WM8900_REG_CLOCKING1,
snd_soc_write(codec, WM8900_REG_CLOCKING1, WM8900_REG_CLOCKING1_OPCLK_MASK, div);
div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK));
break; break;
case WM8900_DAC_LRCLK: case WM8900_DAC_LRCLK:
reg = snd_soc_read(codec, WM8900_REG_AUDIO4); snd_soc_update_bits(codec, WM8900_REG_AUDIO4,
snd_soc_write(codec, WM8900_REG_AUDIO4, WM8900_LRC_MASK, div);
div | (reg & WM8900_LRC_MASK));
break; break;
case WM8900_ADC_LRCLK: case WM8900_ADC_LRCLK:
reg = snd_soc_read(codec, WM8900_REG_AUDIO3); snd_soc_update_bits(codec, WM8900_REG_AUDIO3,
snd_soc_write(codec, WM8900_REG_AUDIO3, WM8900_LRC_MASK, div);
div | (reg & WM8900_LRC_MASK));
break; break;
case WM8900_DAC_CLKDIV: case WM8900_DAC_CLKDIV:
reg = snd_soc_read(codec, WM8900_REG_CLOCKING2); snd_soc_update_bits(codec, WM8900_REG_CLOCKING2,
snd_soc_write(codec, WM8900_REG_CLOCKING2, WM8900_REG_CLOCKING2_DAC_CLKDIV, div);
div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV));
break; break;
case WM8900_ADC_CLKDIV: case WM8900_ADC_CLKDIV:
reg = snd_soc_read(codec, WM8900_REG_CLOCKING2); snd_soc_update_bits(codec, WM8900_REG_CLOCKING2,
snd_soc_write(codec, WM8900_REG_CLOCKING2, WM8900_REG_CLOCKING2_ADC_CLKDIV, div);
div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV));
break; break;
case WM8900_LRCLK_MODE: case WM8900_LRCLK_MODE:
reg = snd_soc_read(codec, WM8900_REG_DACCTRL); snd_soc_update_bits(codec, WM8900_REG_DACCTRL,
snd_soc_write(codec, WM8900_REG_DACCTRL, WM8900_REG_DACCTRL_AIF_LRCLKRATE, div);
div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE));
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -1037,12 +1022,12 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec,
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
/* Enable thermal shutdown */ /* Enable thermal shutdown */
reg = snd_soc_read(codec, WM8900_REG_GPIO); snd_soc_update_bits(codec, WM8900_REG_GPIO,
snd_soc_write(codec, WM8900_REG_GPIO, WM8900_REG_GPIO_TEMP_ENA,
reg | WM8900_REG_GPIO_TEMP_ENA); WM8900_REG_GPIO_TEMP_ENA);
reg = snd_soc_read(codec, WM8900_REG_ADDCTL); snd_soc_update_bits(codec, WM8900_REG_ADDCTL,
snd_soc_write(codec, WM8900_REG_ADDCTL, WM8900_REG_ADDCTL_TEMP_SD,
reg | WM8900_REG_ADDCTL_TEMP_SD); WM8900_REG_ADDCTL_TEMP_SD);
break; break;
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
@ -1205,26 +1190,16 @@ static int wm8900_probe(struct snd_soc_codec *codec)
wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* Latch the volume update bits */ /* Latch the volume update bits */
snd_soc_write(codec, WM8900_REG_LINVOL, snd_soc_update_bits(codec, WM8900_REG_LINVOL, 0x100, 0x100);
snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100); snd_soc_update_bits(codec, WM8900_REG_RINVOL, 0x100, 0x100);
snd_soc_write(codec, WM8900_REG_RINVOL, snd_soc_update_bits(codec, WM8900_REG_LOUT1CTL, 0x100, 0x100);
snd_soc_read(codec, WM8900_REG_RINVOL) | 0x100); snd_soc_update_bits(codec, WM8900_REG_ROUT1CTL, 0x100, 0x100);
snd_soc_write(codec, WM8900_REG_LOUT1CTL, snd_soc_update_bits(codec, WM8900_REG_LOUT2CTL, 0x100, 0x100);
snd_soc_read(codec, WM8900_REG_LOUT1CTL) | 0x100); snd_soc_update_bits(codec, WM8900_REG_ROUT2CTL, 0x100, 0x100);
snd_soc_write(codec, WM8900_REG_ROUT1CTL, snd_soc_update_bits(codec, WM8900_REG_LDAC_DV, 0x100, 0x100);
snd_soc_read(codec, WM8900_REG_ROUT1CTL) | 0x100); snd_soc_update_bits(codec, WM8900_REG_RDAC_DV, 0x100, 0x100);
snd_soc_write(codec, WM8900_REG_LOUT2CTL, snd_soc_update_bits(codec, WM8900_REG_LADC_DV, 0x100, 0x100);
snd_soc_read(codec, WM8900_REG_LOUT2CTL) | 0x100); snd_soc_update_bits(codec, WM8900_REG_RADC_DV, 0x100, 0x100);
snd_soc_write(codec, WM8900_REG_ROUT2CTL,
snd_soc_read(codec, WM8900_REG_ROUT2CTL) | 0x100);
snd_soc_write(codec, WM8900_REG_LDAC_DV,
snd_soc_read(codec, WM8900_REG_LDAC_DV) | 0x100);
snd_soc_write(codec, WM8900_REG_RDAC_DV,
snd_soc_read(codec, WM8900_REG_RDAC_DV) | 0x100);
snd_soc_write(codec, WM8900_REG_LADC_DV,
snd_soc_read(codec, WM8900_REG_LADC_DV) | 0x100);
snd_soc_write(codec, WM8900_REG_RADC_DV,
snd_soc_read(codec, WM8900_REG_RADC_DV) | 0x100);
/* Set the DAC and mixer output bias */ /* Set the DAC and mixer output bias */
snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81); snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81);

View File

@ -50,7 +50,6 @@ static const char *wm8904_supply_names[WM8904_NUM_SUPPLIES] = {
struct wm8904_priv { struct wm8904_priv {
enum wm8904_type devtype; enum wm8904_type devtype;
void *control_data;
struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES]; struct regulator_bulk_data supplies[WM8904_NUM_SUPPLIES];
@ -2540,7 +2539,6 @@ static __devinit int wm8904_i2c_probe(struct i2c_client *i2c,
wm8904->devtype = id->driver_data; wm8904->devtype = id->driver_data;
i2c_set_clientdata(i2c, wm8904); i2c_set_clientdata(i2c, wm8904);
wm8904->control_data = i2c;
wm8904->pdata = i2c->dev.platform_data; wm8904->pdata = i2c->dev.platform_data;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -43,9 +43,19 @@
struct wm8940_priv { struct wm8940_priv {
unsigned int sysclk; unsigned int sysclk;
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
}; };
static int wm8940_volatile_register(struct snd_soc_codec *codec,
unsigned int reg)
{
switch (reg) {
case WM8940_SOFTRESET:
return 1;
default:
return 0;
}
}
static u16 wm8940_reg_defaults[] = { static u16 wm8940_reg_defaults[] = {
0x8940, /* Soft Reset */ 0x8940, /* Soft Reset */
0x0000, /* Power 1 */ 0x0000, /* Power 1 */
@ -460,6 +470,14 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = snd_soc_cache_sync(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
return ret;
}
}
/* ensure bufioen and biasen */ /* ensure bufioen and biasen */
pwr_reg |= (1 << 2) | (1 << 3); pwr_reg |= (1 << 2) | (1 << 3);
/* set vmid to 300k for standby */ /* set vmid to 300k for standby */
@ -470,6 +488,8 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec,
break; break;
} }
codec->dapm.bias_level = level;
return ret; return ret;
} }
@ -660,30 +680,8 @@ static int wm8940_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8940_resume(struct snd_soc_codec *codec) static int wm8940_resume(struct snd_soc_codec *codec)
{ {
int i; wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
int ret; return 0;
u8 data[3];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware
* Could use auto incremented writes to speed this up
*/
for (i = 0; i < ARRAY_SIZE(wm8940_reg_defaults); i++) {
data[0] = i;
data[1] = (cache[i] & 0xFF00) >> 8;
data[2] = cache[i] & 0x00FF;
ret = codec->hw_write(codec->control_data, data, 3);
if (ret < 0)
goto error_ret;
else if (ret != 3) {
ret = -EIO;
goto error_ret;
}
}
ret = wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
error_ret:
return ret;
} }
static int wm8940_probe(struct snd_soc_codec *codec) static int wm8940_probe(struct snd_soc_codec *codec)
@ -693,7 +691,6 @@ static int wm8940_probe(struct snd_soc_codec *codec)
int ret; int ret;
u16 reg; u16 reg;
codec->control_data = wm8940->control_data;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type); ret = snd_soc_codec_set_cache_io(codec, 8, 16, wm8940->control_type);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@ -744,6 +741,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
.reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults), .reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults),
.reg_word_size = sizeof(u16), .reg_word_size = sizeof(u16),
.reg_cache_default = wm8940_reg_defaults, .reg_cache_default = wm8940_reg_defaults,
.volatile_register = wm8940_volatile_register,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
@ -758,7 +756,6 @@ static __devinit int wm8940_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(i2c, wm8940); i2c_set_clientdata(i2c, wm8940);
wm8940->control_data = i2c;
wm8940->control_type = SND_SOC_I2C; wm8940->control_type = SND_SOC_I2C;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,

View File

@ -72,7 +72,6 @@ static const u16 wm8960_reg[WM8960_CACHEREGNUM] = {
struct wm8960_priv { struct wm8960_priv {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
int (*set_bias_level)(struct snd_soc_codec *, int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level); enum snd_soc_bias_level level);
struct snd_soc_dapm_widget *lout1; struct snd_soc_dapm_widget *lout1;
@ -575,6 +574,8 @@ static int wm8960_set_bias_level_out3(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec);
/* Enable anti-pop features */ /* Enable anti-pop features */
snd_soc_write(codec, WM8960_APOP1, snd_soc_write(codec, WM8960_APOP1,
WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_POBCTRL | WM8960_SOFT_ST |
@ -677,6 +678,9 @@ static int wm8960_set_bias_level_capless(struct snd_soc_codec *codec,
WM8960_VREF | WM8960_VMID_MASK, 0); WM8960_VREF | WM8960_VMID_MASK, 0);
break; break;
case SND_SOC_BIAS_OFF:
snd_soc_cache_sync(codec);
break;
default: default:
break; break;
} }
@ -902,16 +906,6 @@ static int wm8960_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8960_resume(struct snd_soc_codec *codec) static int wm8960_resume(struct snd_soc_codec *codec)
{ {
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec); struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8960_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
@ -925,7 +919,6 @@ static int wm8960_probe(struct snd_soc_codec *codec)
u16 reg; u16 reg;
wm8960->set_bias_level = wm8960_set_bias_level_out3; wm8960->set_bias_level = wm8960_set_bias_level_out3;
codec->control_data = wm8960->control_data;
if (!pdata) { if (!pdata) {
dev_warn(codec->dev, "No platform data supplied\n"); dev_warn(codec->dev, "No platform data supplied\n");
@ -1015,7 +1008,6 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, wm8960); i2c_set_clientdata(i2c, wm8960);
wm8960->control_type = SND_SOC_I2C; wm8960->control_type = SND_SOC_I2C;
wm8960->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8960, &wm8960_dai, 1); &soc_codec_dev_wm8960, &wm8960_dai, 1);

View File

@ -974,7 +974,9 @@ static int wm8961_probe(struct snd_soc_codec *codec)
} }
/* This isn't volatile - readback doesn't correspond to write */ /* This isn't volatile - readback doesn't correspond to write */
reg = codec->hw_read(codec, WM8961_RIGHT_INPUT_VOLUME); codec->cache_bypass = 1;
reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME);
codec->cache_bypass = 0;
dev_info(codec->dev, "WM8961 family %d revision %c\n", dev_info(codec->dev, "WM8961 family %d revision %c\n",
(reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT,
((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT)

View File

@ -2139,7 +2139,6 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol) struct snd_ctl_elem_value *ucontrol)
{ {
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
u16 *reg_cache = codec->reg_cache;
int ret; int ret;
/* Apply the update (if any) */ /* Apply the update (if any) */
@ -2148,16 +2147,19 @@ static int wm8962_put_spk_sw(struct snd_kcontrol *kcontrol,
return 0; return 0;
/* If the left PGA is enabled hit that VU bit... */ /* If the left PGA is enabled hit that VU bit... */
if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTL_PGA_ENA) ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
return snd_soc_write(codec, WM8962_SPKOUTL_VOLUME, if (ret & WM8962_SPKOUTL_PGA_ENA) {
reg_cache[WM8962_SPKOUTL_VOLUME]); snd_soc_write(codec, WM8962_SPKOUTL_VOLUME,
snd_soc_read(codec, WM8962_SPKOUTL_VOLUME));
return 1;
}
/* ...otherwise the right. The VU is stereo. */ /* ...otherwise the right. The VU is stereo. */
if (reg_cache[WM8962_PWR_MGMT_2] & WM8962_SPKOUTR_PGA_ENA) if (ret & WM8962_SPKOUTR_PGA_ENA)
return snd_soc_write(codec, WM8962_SPKOUTR_VOLUME, snd_soc_write(codec, WM8962_SPKOUTR_VOLUME,
reg_cache[WM8962_SPKOUTR_VOLUME]); snd_soc_read(codec, WM8962_SPKOUTR_VOLUME));
return 0; return 1;
} }
static const char *cap_hpf_mode_text[] = { static const char *cap_hpf_mode_text[] = {
@ -2498,7 +2500,6 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
struct snd_soc_codec *codec = w->codec; struct snd_soc_codec *codec = w->codec;
u16 *reg_cache = codec->reg_cache;
int reg; int reg;
switch (w->shift) { switch (w->shift) {
@ -2521,7 +2522,7 @@ static int out_pga_event(struct snd_soc_dapm_widget *w,
switch (event) { switch (event) {
case SND_SOC_DAPM_POST_PMU: case SND_SOC_DAPM_POST_PMU:
return snd_soc_write(codec, reg, reg_cache[reg]); return snd_soc_write(codec, reg, snd_soc_read(codec, reg));
default: default:
BUG(); BUG();
return -EINVAL; return -EINVAL;
@ -2667,7 +2668,7 @@ SND_SOC_DAPM_INPUT("IN4R"),
SND_SOC_DAPM_INPUT("Beep"), SND_SOC_DAPM_INPUT("Beep"),
SND_SOC_DAPM_INPUT("DMICDAT"), SND_SOC_DAPM_INPUT("DMICDAT"),
SND_SOC_DAPM_MICBIAS("MICBIAS", WM8962_PWR_MGMT_1, 1, 0), SND_SOC_DAPM_SUPPLY("MICBIAS", WM8962_PWR_MGMT_1, 1, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0), SND_SOC_DAPM_SUPPLY("Class G", WM8962_CHARGE_PUMP_B, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event, SND_SOC_DAPM_SUPPLY("SYSCLK", WM8962_CLOCKING2, 5, 0, sysclk_event,
@ -2688,7 +2689,7 @@ SND_SOC_DAPM_MIXER("MIXINL", WM8962_PWR_MGMT_1, 5, 0,
SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0, SND_SOC_DAPM_MIXER("MIXINR", WM8962_PWR_MGMT_1, 4, 0,
mixinr, ARRAY_SIZE(mixinr)), mixinr, ARRAY_SIZE(mixinr)),
SND_SOC_DAPM_AIF_IN("DMIC", NULL, 0, WM8962_PWR_MGMT_1, 10, 0), SND_SOC_DAPM_AIF_IN("DMIC_ENA", NULL, 0, WM8962_PWR_MGMT_1, 10, 0),
SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0), SND_SOC_DAPM_ADC("ADCL", "Capture", WM8962_PWR_MGMT_1, 3, 0),
SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0), SND_SOC_DAPM_ADC("ADCR", "Capture", WM8962_PWR_MGMT_1, 2, 0),
@ -2767,18 +2768,18 @@ static const struct snd_soc_dapm_route wm8962_intercon[] = {
{ "MICBIAS", NULL, "SYSCLK" }, { "MICBIAS", NULL, "SYSCLK" },
{ "DMIC", NULL, "DMICDAT" }, { "DMIC_ENA", NULL, "DMICDAT" },
{ "ADCL", NULL, "SYSCLK" }, { "ADCL", NULL, "SYSCLK" },
{ "ADCL", NULL, "TOCLK" }, { "ADCL", NULL, "TOCLK" },
{ "ADCL", NULL, "MIXINL" }, { "ADCL", NULL, "MIXINL" },
{ "ADCL", NULL, "DMIC" }, { "ADCL", NULL, "DMIC_ENA" },
{ "ADCL", NULL, "DSP2" }, { "ADCL", NULL, "DSP2" },
{ "ADCR", NULL, "SYSCLK" }, { "ADCR", NULL, "SYSCLK" },
{ "ADCR", NULL, "TOCLK" }, { "ADCR", NULL, "TOCLK" },
{ "ADCR", NULL, "MIXINR" }, { "ADCR", NULL, "MIXINR" },
{ "ADCR", NULL, "DMIC" }, { "ADCR", NULL, "DMIC_ENA" },
{ "ADCR", NULL, "DSP2" }, { "ADCR", NULL, "DSP2" },
{ "STL", "Left", "ADCL" }, { "STL", "Left", "ADCL" },
@ -3223,9 +3224,9 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
int aif0 = 0; int aif0 = 0;
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
aif0 |= WM8962_LRCLK_INV;
case SND_SOC_DAIFMT_DSP_B: case SND_SOC_DAIFMT_DSP_B:
aif0 |= WM8962_LRCLK_INV | 3;
case SND_SOC_DAIFMT_DSP_A:
aif0 |= 3; aif0 |= 3;
switch (fmt & SND_SOC_DAIFMT_INV_MASK) { switch (fmt & SND_SOC_DAIFMT_INV_MASK) {

View File

@ -546,6 +546,9 @@ static int wm8971_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
snd_soc_cache_sync(codec);
/* mute dac and set vmid to 500k, enable VREF */ /* mute dac and set vmid to 500k, enable VREF */
snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140);
break; break;
@ -605,20 +608,8 @@ static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8971_resume(struct snd_soc_codec *codec) static int wm8971_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
u16 reg; u16 reg;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) {
if (i + 1 == WM8971_RESET)
continue;
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* charge wm8971 caps */ /* charge wm8971 caps */
@ -660,25 +651,14 @@ static int wm8971_probe(struct snd_soc_codec *codec)
msecs_to_jiffies(1000)); msecs_to_jiffies(1000));
/* set the update bits */ /* set the update bits */
reg = snd_soc_read(codec, WM8971_LDAC); snd_soc_update_bits(codec, WM8971_LDAC, 0x0100, 0x0100);
snd_soc_write(codec, WM8971_LDAC, reg | 0x0100); snd_soc_update_bits(codec, WM8971_RDAC, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8971_RDAC); snd_soc_update_bits(codec, WM8971_LOUT1V, 0x0100, 0x0100);
snd_soc_write(codec, WM8971_RDAC, reg | 0x0100); snd_soc_update_bits(codec, WM8971_ROUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8971_LOUT2V, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8971_LOUT1V); snd_soc_update_bits(codec, WM8971_ROUT2V, 0x0100, 0x0100);
snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100); snd_soc_update_bits(codec, WM8971_LINVOL, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8971_ROUT1V); snd_soc_update_bits(codec, WM8971_RINVOL, 0x0100, 0x0100);
snd_soc_write(codec, WM8971_ROUT1V, reg | 0x0100);
reg = snd_soc_read(codec, WM8971_LOUT2V);
snd_soc_write(codec, WM8971_LOUT2V, reg | 0x0100);
reg = snd_soc_read(codec, WM8971_ROUT2V);
snd_soc_write(codec, WM8971_ROUT2V, reg | 0x0100);
reg = snd_soc_read(codec, WM8971_LINVOL);
snd_soc_write(codec, WM8971_LINVOL, reg | 0x0100);
reg = snd_soc_read(codec, WM8971_RINVOL);
snd_soc_write(codec, WM8971_RINVOL, reg | 0x0100);
snd_soc_add_controls(codec, wm8971_snd_controls, snd_soc_add_controls(codec, wm8971_snd_controls,
ARRAY_SIZE(wm8971_snd_controls)); ARRAY_SIZE(wm8971_snd_controls));

View File

@ -3,7 +3,7 @@
* *
* Copyright 2006-2009 Wolfson Microelectronics PLC. * Copyright 2006-2009 Wolfson Microelectronics PLC.
* *
* Author: Liam Girdwood <linux@wolfsonmicro.com> * Author: Liam Girdwood <Liam.Girdwood@wolfsonmicro.com>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License version 2 as
@ -530,6 +530,8 @@ static int wm8974_set_bias_level(struct snd_soc_codec *codec,
power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN; power1 |= WM8974_POWER1_BIASEN | WM8974_POWER1_BUFIOEN;
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec);
/* Initial cap charge at VMID 5k */ /* Initial cap charge at VMID 5k */
snd_soc_write(codec, WM8974_POWER1, power1 | 0x3); snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
mdelay(100); mdelay(100);
@ -589,18 +591,7 @@ static int wm8974_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8974_resume(struct snd_soc_codec *codec) static int wm8974_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8974_reg); i++) {
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }

View File

@ -52,7 +52,6 @@ static const u16 wm8978_reg[WM8978_CACHEREGNUM] = {
/* codec private data */ /* codec private data */
struct wm8978_priv { struct wm8978_priv {
enum snd_soc_control_type control_type; enum snd_soc_control_type control_type;
void *control_data;
unsigned int f_pllout; unsigned int f_pllout;
unsigned int f_mclk; unsigned int f_mclk;
unsigned int f_256fs; unsigned int f_256fs;
@ -955,7 +954,6 @@ static int wm8978_probe(struct snd_soc_codec *codec)
* default hardware setting * default hardware setting
*/ */
wm8978->sysclk = WM8978_PLL; wm8978->sysclk = WM8978_PLL;
codec->control_data = wm8978->control_data;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
@ -1016,7 +1014,6 @@ static __devinit int wm8978_i2c_probe(struct i2c_client *i2c,
return -ENOMEM; return -ENOMEM;
i2c_set_clientdata(i2c, wm8978); i2c_set_clientdata(i2c, wm8978);
wm8978->control_data = i2c;
ret = snd_soc_register_codec(&i2c->dev, ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8978, &wm8978_dai, 1); &soc_codec_dev_wm8978, &wm8978_dai, 1);

View File

@ -1007,7 +1007,7 @@ static int wm8983_probe(struct snd_soc_codec *codec)
return ret; return ret;
} }
ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0x8983); ret = snd_soc_write(codec, WM8983_SOFTWARE_RESET, 0);
if (ret < 0) { if (ret < 0) {
dev_err(codec->dev, "Failed to issue reset: %d\n", ret); dev_err(codec->dev, "Failed to issue reset: %d\n", ret);
return ret; return ret;

View File

@ -55,7 +55,6 @@ struct wm8988_priv {
struct snd_pcm_hw_constraint_list *sysclk_constraints; struct snd_pcm_hw_constraint_list *sysclk_constraints;
}; };
#define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0) #define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0)
/* /*
@ -676,6 +675,8 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
snd_soc_cache_sync(codec);
/* VREF, VMID=2x5k */ /* VREF, VMID=2x5k */
snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1);
@ -736,21 +737,7 @@ static int wm8988_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8988_resume(struct snd_soc_codec *codec) static int wm8988_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < WM8988_NUM_REG; i++) {
if (i == WM8988_RESET)
continue;
data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }
@ -759,7 +746,6 @@ static int wm8988_probe(struct snd_soc_codec *codec)
struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec); struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm; struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret = 0; int ret = 0;
u16 reg;
ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type); ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8988->control_type);
if (ret < 0) { if (ret < 0) {
@ -774,16 +760,11 @@ static int wm8988_probe(struct snd_soc_codec *codec)
} }
/* set the update bits (we always update left then right) */ /* set the update bits (we always update left then right) */
reg = snd_soc_read(codec, WM8988_RADC); snd_soc_update_bits(codec, WM8988_RADC, 0x0100, 0x0100);
snd_soc_write(codec, WM8988_RADC, reg | 0x100); snd_soc_update_bits(codec, WM8988_RDAC, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8988_RDAC); snd_soc_update_bits(codec, WM8988_ROUT1V, 0x0100, 0x0100);
snd_soc_write(codec, WM8988_RDAC, reg | 0x0100); snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100);
reg = snd_soc_read(codec, WM8988_ROUT1V); snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100);
snd_soc_write(codec, WM8988_ROUT1V, reg | 0x0100);
reg = snd_soc_read(codec, WM8988_ROUT2V);
snd_soc_write(codec, WM8988_ROUT2V, reg | 0x0100);
reg = snd_soc_read(codec, WM8988_RINVOL);
snd_soc_write(codec, WM8988_RINVOL, reg | 0x0100);
wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);

View File

@ -36,10 +36,17 @@ struct wm8990_priv {
unsigned int pcmclk; unsigned int pcmclk;
}; };
/* static int wm8990_volatile_register(struct snd_soc_codec *codec,
* wm8990 register cache. Note that register 0 is not included in the unsigned int reg)
* cache. {
*/ switch (reg) {
case WM8990_RESET:
return 1;
default:
return 0;
}
}
static const u16 wm8990_reg[] = { static const u16 wm8990_reg[] = {
0x8990, /* R0 - Reset */ 0x8990, /* R0 - Reset */
0x0000, /* R1 - Power Management (1) */ 0x0000, /* R1 - Power Management (1) */
@ -394,7 +401,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
(1 << WM8990_AINRMUX_PWR_BIT))) { (1 << WM8990_AINRMUX_PWR_BIT))) {
reg |= WM8990_AINR_ENA; reg |= WM8990_AINR_ENA;
} else { } else {
reg &= ~WM8990_AINL_ENA; reg &= ~WM8990_AINR_ENA;
} }
snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg);
@ -974,7 +981,6 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int target,
static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
int source, unsigned int freq_in, unsigned int freq_out) int source, unsigned int freq_in, unsigned int freq_out)
{ {
u16 reg;
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
struct _pll_div pll_div; struct _pll_div pll_div;
@ -982,13 +988,12 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
pll_factors(&pll_div, freq_out * 4, freq_in); pll_factors(&pll_div, freq_out * 4, freq_in);
/* Turn on PLL */ /* Turn on PLL */
reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
reg |= WM8990_PLL_ENA; WM8990_PLL_ENA, WM8990_PLL_ENA);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
/* sysclk comes from PLL */ /* sysclk comes from PLL */
reg = snd_soc_read(codec, WM8990_CLOCKING_2); snd_soc_update_bits(codec, WM8990_CLOCKING_2,
snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); WM8990_SYSCLK_SRC, WM8990_SYSCLK_SRC);
/* set up N , fractional mode and pre-divisor if necessary */ /* set up N , fractional mode and pre-divisor if necessary */
snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM |
@ -996,10 +1001,9 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8));
snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF));
} else { } else {
/* Turn on PLL */ /* Turn off PLL */
reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
reg &= ~WM8990_PLL_ENA; WM8990_PLL_ENA, 0);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg);
} }
return 0; return 0;
} }
@ -1077,28 +1081,23 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai,
int div_id, int div) int div_id, int div)
{ {
struct snd_soc_codec *codec = codec_dai->codec; struct snd_soc_codec *codec = codec_dai->codec;
u16 reg;
switch (div_id) { switch (div_id) {
case WM8990_MCLK_DIV: case WM8990_MCLK_DIV:
reg = snd_soc_read(codec, WM8990_CLOCKING_2) & snd_soc_update_bits(codec, WM8990_CLOCKING_2,
~WM8990_MCLK_DIV_MASK; WM8990_MCLK_DIV_MASK, div);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break; break;
case WM8990_DACCLK_DIV: case WM8990_DACCLK_DIV:
reg = snd_soc_read(codec, WM8990_CLOCKING_2) & snd_soc_update_bits(codec, WM8990_CLOCKING_2,
~WM8990_DAC_CLKDIV_MASK; WM8990_DAC_CLKDIV_MASK, div);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break; break;
case WM8990_ADCCLK_DIV: case WM8990_ADCCLK_DIV:
reg = snd_soc_read(codec, WM8990_CLOCKING_2) & snd_soc_update_bits(codec, WM8990_CLOCKING_2,
~WM8990_ADC_CLKDIV_MASK; WM8990_ADC_CLKDIV_MASK, div);
snd_soc_write(codec, WM8990_CLOCKING_2, reg | div);
break; break;
case WM8990_BCLK_DIV: case WM8990_BCLK_DIV:
reg = snd_soc_read(codec, WM8990_CLOCKING_1) & snd_soc_update_bits(codec, WM8990_CLOCKING_1,
~WM8990_BCLK_DIV_MASK; WM8990_BCLK_DIV_MASK, div);
snd_soc_write(codec, WM8990_CLOCKING_1, reg | div);
break; break;
default: default:
return -EINVAL; return -EINVAL;
@ -1156,7 +1155,7 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute)
static int wm8990_set_bias_level(struct snd_soc_codec *codec, static int wm8990_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level) enum snd_soc_bias_level level)
{ {
u16 val; int ret;
switch (level) { switch (level) {
case SND_SOC_BIAS_ON: case SND_SOC_BIAS_ON:
@ -1164,13 +1163,18 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE: case SND_SOC_BIAS_PREPARE:
/* VMID=2*50k */ /* VMID=2*50k */
val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) & snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1,
~WM8990_VMID_MODE_MASK; WM8990_VMID_MODE_MASK, 0x2);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2);
break; break;
case SND_SOC_BIAS_STANDBY: case SND_SOC_BIAS_STANDBY:
if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) {
ret = snd_soc_cache_sync(codec);
if (ret < 0) {
dev_err(codec->dev, "Failed to sync cache: %d\n", ret);
return ret;
}
/* Enable all output discharge bits */ /* Enable all output discharge bits */
snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE |
WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_RLINE | WM8990_DIS_OUT3 |
@ -1225,9 +1229,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
} }
/* VMID=2*250k */ /* VMID=2*250k */
val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) & snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_1,
~WM8990_VMID_MODE_MASK; WM8990_VMID_MODE_MASK, 0x4);
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4);
break; break;
case SND_SOC_BIAS_OFF: case SND_SOC_BIAS_OFF:
@ -1241,8 +1244,8 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec,
WM8990_BUFIOEN); WM8990_BUFIOEN);
/* mute DAC */ /* mute DAC */
val = snd_soc_read(codec, WM8990_DAC_CTRL); snd_soc_update_bits(codec, WM8990_DAC_CTRL,
snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); WM8990_DAC_MUTE, WM8990_DAC_MUTE);
/* Enable any disabled outputs */ /* Enable any disabled outputs */
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03);
@ -1319,19 +1322,6 @@ static int wm8990_suspend(struct snd_soc_codec *codec, pm_message_t state)
static int wm8990_resume(struct snd_soc_codec *codec) static int wm8990_resume(struct snd_soc_codec *codec)
{ {
int i;
u8 data[2];
u16 *cache = codec->reg_cache;
/* Sync reg_cache with the hardware */
for (i = 0; i < ARRAY_SIZE(wm8990_reg); i++) {
if (i + 1 == WM8990_RESET)
continue;
data[0] = ((i + 1) << 1) | ((cache[i] >> 8) & 0x0001);
data[1] = cache[i] & 0x00ff;
codec->hw_write(codec->control_data, data, 2);
}
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; return 0;
} }
@ -1343,7 +1333,6 @@ static int wm8990_resume(struct snd_soc_codec *codec)
static int wm8990_probe(struct snd_soc_codec *codec) static int wm8990_probe(struct snd_soc_codec *codec)
{ {
int ret; int ret;
u16 reg;
ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C);
if (ret < 0) { if (ret < 0) {
@ -1356,15 +1345,14 @@ static int wm8990_probe(struct snd_soc_codec *codec)
/* charge output caps */ /* charge output caps */
wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4); snd_soc_update_bits(codec, WM8990_AUDIO_INTERFACE_4,
snd_soc_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); WM8990_ALRCGPIO1, WM8990_ALRCGPIO1);
reg = snd_soc_read(codec, WM8990_GPIO1_GPIO2) & snd_soc_update_bits(codec, WM8990_GPIO1_GPIO2,
~WM8990_GPIO1_SEL_MASK; WM8990_GPIO1_SEL_MASK, 1);
snd_soc_write(codec, WM8990_GPIO1_GPIO2, reg | 1);
reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); snd_soc_update_bits(codec, WM8990_POWER_MANAGEMENT_2,
snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); WM8990_OPCLK_ENA, WM8990_OPCLK_ENA);
snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
@ -1392,6 +1380,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
.reg_cache_size = ARRAY_SIZE(wm8990_reg), .reg_cache_size = ARRAY_SIZE(wm8990_reg),
.reg_word_size = sizeof(u16), .reg_word_size = sizeof(u16),
.reg_cache_default = wm8990_reg, .reg_cache_default = wm8990_reg,
.volatile_register = wm8990_volatile_register,
}; };
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)

View File

@ -3,7 +3,7 @@
* *
* Copyright 2007-2010 Wolfson Microelectronics PLC. * Copyright 2007-2010 Wolfson Microelectronics PLC.
* Author: Graeme Gregory * Author: Graeme Gregory
* linux@wolfsonmicro.com * Graeme.Gregory@wolfsonmicro.com
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the * under the terms of the GNU General Public License as published by the
@ -393,7 +393,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w,
(1 << WM8991_AINRMUX_PWR_BIT))) (1 << WM8991_AINRMUX_PWR_BIT)))
reg |= WM8991_AINR_ENA; reg |= WM8991_AINR_ENA;
else else
reg &= ~WM8991_AINL_ENA; reg &= ~WM8991_AINR_ENA;
snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg); snd_soc_write(w->codec, WM8991_POWER_MANAGEMENT_2, reg);
return 0; return 0;
@ -1264,7 +1264,6 @@ static int wm8991_probe(struct snd_soc_codec *codec)
{ {
struct wm8991_priv *wm8991; struct wm8991_priv *wm8991;
int ret; int ret;
unsigned int reg;
wm8991 = snd_soc_codec_get_drvdata(codec); wm8991 = snd_soc_codec_get_drvdata(codec);
@ -1282,19 +1281,18 @@ static int wm8991_probe(struct snd_soc_codec *codec)
wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY); wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
reg = snd_soc_read(codec, WM8991_AUDIO_INTERFACE_4); snd_soc_update_bits(codec, WM8991_AUDIO_INTERFACE_4,
snd_soc_write(codec, WM8991_AUDIO_INTERFACE_4, reg | WM8991_ALRCGPIO1); WM8991_ALRCGPIO1, WM8991_ALRCGPIO1);
reg = snd_soc_read(codec, WM8991_GPIO1_GPIO2) & snd_soc_update_bits(codec, WM8991_GPIO1_GPIO2,
~WM8991_GPIO1_SEL_MASK; WM8991_GPIO1_SEL_MASK, 1);
snd_soc_write(codec, WM8991_GPIO1_GPIO2, reg | 1);
reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_1); snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_1,
snd_soc_write(codec, WM8991_POWER_MANAGEMENT_1, reg | WM8991_VREF_ENA| WM8991_VREF_ENA | WM8991_VMID_MODE_MASK,
WM8991_VMID_MODE_MASK); WM8991_VREF_ENA | WM8991_VMID_MODE_MASK);
reg = snd_soc_read(codec, WM8991_POWER_MANAGEMENT_2); snd_soc_update_bits(codec, WM8991_POWER_MANAGEMENT_2,
snd_soc_write(codec, WM8991_POWER_MANAGEMENT_2, reg | WM8991_OPCLK_ENA); WM8991_OPCLK_ENA, WM8991_OPCLK_ENA);
snd_soc_write(codec, WM8991_DAC_CTRL, 0); snd_soc_write(codec, WM8991_DAC_CTRL, 0);
snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_write(codec, WM8991_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));

View File

@ -208,7 +208,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
static int configure_clock(struct snd_soc_codec *codec) static int configure_clock(struct snd_soc_codec *codec)
{ {
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int old, new; int change, new;
/* Bring up the AIF clocks first */ /* Bring up the AIF clocks first */
configure_aif_clock(codec, 0); configure_aif_clock(codec, 0);
@ -229,14 +229,11 @@ static int configure_clock(struct snd_soc_codec *codec)
else else
new = 0; new = 0;
old = snd_soc_read(codec, WM8994_CLOCKING_1) & WM8994_SYSCLK_SRC; change = snd_soc_update_bits(codec, WM8994_CLOCKING_1,
WM8994_SYSCLK_SRC, new);
/* If there's no change then we're done. */ if (!change)
if (old == new)
return 0; return 0;
snd_soc_update_bits(codec, WM8994_CLOCKING_1, WM8994_SYSCLK_SRC, new);
snd_soc_dapm_sync(&codec->dapm); snd_soc_dapm_sync(&codec->dapm);
return 0; return 0;
@ -283,6 +280,7 @@ static const DECLARE_TLV_DB_SCALE(st_tlv, -3600, 300, 0);
static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0); static const DECLARE_TLV_DB_SCALE(wm8994_3d_tlv, -1600, 183, 0);
static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0);
static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0); static const DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
static const DECLARE_TLV_DB_SCALE(mixin_boost_tlv, 0, 900, 0);
#define WM8994_DRC_SWITCH(xname, reg, shift) \ #define WM8994_DRC_SWITCH(xname, reg, shift) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
@ -703,6 +701,13 @@ SOC_SINGLE_TLV("AIF2DAC Noise Gate Threshold Volume",
7, 1, ng_tlv), 7, 1, ng_tlv),
}; };
static const struct snd_kcontrol_new wm1811_snd_controls[] = {
SOC_SINGLE_TLV("MIXINL IN1LP Boost Volume", WM8994_INPUT_MIXER_1, 7, 1, 0,
mixin_boost_tlv),
SOC_SINGLE_TLV("MIXINL IN1RP Boost Volume", WM8994_INPUT_MIXER_1, 8, 1, 0,
mixin_boost_tlv),
};
static int clk_sys_event(struct snd_soc_dapm_widget *w, static int clk_sys_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event) struct snd_kcontrol *kcontrol, int event)
{ {
@ -1414,7 +1419,7 @@ SND_SOC_DAPM_MUX("AIF2DAC Mux", SND_SOC_NOPM, 0, 0, &aif2dac_mux),
SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux), SND_SOC_DAPM_MUX("AIF2ADC Mux", SND_SOC_NOPM, 0, 0, &aif2adc_mux),
SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("AIF3DACDAT", "AIF3 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_IN("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("AIF3ADCDAT", "AIF3 Capture", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0), SND_SOC_DAPM_SUPPLY("TOCLK", WM8994_CLOCKING_1, 4, 0, NULL, 0),
@ -2053,6 +2058,15 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec,
WM8958_CP_DISCH); WM8958_CP_DISCH);
} }
break; break;
case WM1811:
if (wm8994->revision < 2) {
snd_soc_write(codec, 0x102, 0x3);
snd_soc_write(codec, 0x5d, 0x7e);
snd_soc_write(codec, 0x5e, 0x0);
snd_soc_write(codec, 0x102, 0x0);
}
break;
} }
/* Discharge LINEOUT1 & 2 */ /* Discharge LINEOUT1 & 2 */
@ -2168,10 +2182,18 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
/* The AIF2 format configuration needs to be mirrored to AIF3 /* The AIF2 format configuration needs to be mirrored to AIF3
* on WM8958 if it's in use so just do it all the time. */ * on WM8958 if it's in use so just do it all the time. */
if (control->type == WM8958 && dai->id == 2) switch (control->type) {
case WM1811:
case WM8958:
if (dai->id == 2)
snd_soc_update_bits(codec, WM8958_AIF3_CONTROL_1, snd_soc_update_bits(codec, WM8958_AIF3_CONTROL_1,
WM8994_AIF1_LRCLK_INV | WM8994_AIF1_LRCLK_INV |
WM8958_AIF3_FMT_MASK, aif1); WM8958_AIF3_FMT_MASK, aif1);
break;
default:
break;
}
snd_soc_update_bits(codec, aif1_reg, snd_soc_update_bits(codec, aif1_reg,
WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV | WM8994_AIF1_BCLK_INV | WM8994_AIF1_LRCLK_INV |
@ -2213,7 +2235,6 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai) struct snd_soc_dai *dai)
{ {
struct snd_soc_codec *codec = dai->codec; struct snd_soc_codec *codec = dai->codec;
struct wm8994 *control = codec->control_data;
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
int aif1_reg; int aif1_reg;
int aif2_reg; int aif2_reg;
@ -2256,14 +2277,6 @@ static int wm8994_hw_params(struct snd_pcm_substream *substream,
dev_dbg(codec->dev, "AIF2 using split LRCLK\n"); dev_dbg(codec->dev, "AIF2 using split LRCLK\n");
} }
break; break;
case 3:
switch (control->type) {
case WM8958:
aif1_reg = WM8958_AIF3_CONTROL_1;
break;
default:
return 0;
}
default: default:
return -EINVAL; return -EINVAL;
} }
@ -2384,6 +2397,7 @@ static int wm8994_aif3_hw_params(struct snd_pcm_substream *substream,
switch (dai->id) { switch (dai->id) {
case 3: case 3:
switch (control->type) { switch (control->type) {
case WM1811:
case WM8958: case WM8958:
aif1_reg = WM8958_AIF3_CONTROL_1; aif1_reg = WM8958_AIF3_CONTROL_1;
break; break;
@ -2424,7 +2438,7 @@ static void wm8994_aif_shutdown(struct snd_pcm_substream *substream,
rate_reg = WM8994_AIF1_RATE; rate_reg = WM8994_AIF1_RATE;
break; break;
case 2: case 2:
rate_reg = WM8994_AIF1_RATE; rate_reg = WM8994_AIF2_RATE;
break; break;
default: default:
break; break;
@ -2614,6 +2628,7 @@ static int wm8994_suspend(struct snd_soc_codec *codec, pm_message_t state)
case WM8994: case WM8994:
snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0); snd_soc_update_bits(codec, WM8994_MICBIAS, WM8994_MICD_ENA, 0);
break; break;
case WM1811:
case WM8958: case WM8958:
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
WM8958_MICD_ENA, 0); WM8958_MICD_ENA, 0);
@ -2682,6 +2697,7 @@ static int wm8994_resume(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8994_MICBIAS, snd_soc_update_bits(codec, WM8994_MICBIAS,
WM8994_MICD_ENA, WM8994_MICD_ENA); WM8994_MICD_ENA, WM8994_MICD_ENA);
break; break;
case WM1811:
case WM8958: case WM8958:
if (wm8994->jack_cb) if (wm8994->jack_cb)
snd_soc_update_bits(codec, WM8958_MIC_DETECT_1, snd_soc_update_bits(codec, WM8958_MIC_DETECT_1,
@ -2980,8 +2996,13 @@ int wm8958_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack,
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
struct wm8994 *control = codec->control_data; struct wm8994 *control = codec->control_data;
if (control->type != WM8958) switch (control->type) {
case WM1811:
case WM8958:
break;
default:
return -EINVAL; return -EINVAL;
}
if (jack) { if (jack) {
if (!cb) { if (!cb) {
@ -3135,6 +3156,24 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8994->hubs.dcs_readback_mode = 1; wm8994->hubs.dcs_readback_mode = 1;
break; break;
case WM1811:
wm8994->hubs.dcs_readback_mode = 2;
wm8994->hubs.no_series_update = 1;
switch (wm8994->revision) {
case 0:
case 1:
wm8994->hubs.dcs_codes_l = -9;
wm8994->hubs.dcs_codes_r = -5;
break;
default:
break;
}
snd_soc_update_bits(codec, WM8994_ANALOGUE_HP_1,
WM1811_HPOUT1_ATTN, WM1811_HPOUT1_ATTN);
break;
default: default:
break; break;
} }
@ -3195,6 +3234,7 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
break; break;
case WM8958: case WM8958:
case WM1811:
if (wm8994->micdet_irq) { if (wm8994->micdet_irq) {
ret = request_threaded_irq(wm8994->micdet_irq, NULL, ret = request_threaded_irq(wm8994->micdet_irq, NULL,
wm8958_mic_irq, wm8958_mic_irq,
@ -3357,6 +3397,19 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(wm8994_dac_widgets)); ARRAY_SIZE(wm8994_dac_widgets));
} }
break; break;
case WM1811:
snd_soc_add_controls(codec, wm8958_snd_controls,
ARRAY_SIZE(wm8958_snd_controls));
snd_soc_dapm_new_controls(dapm, wm8958_dapm_widgets,
ARRAY_SIZE(wm8958_dapm_widgets));
snd_soc_dapm_new_controls(dapm, wm8994_lateclk_widgets,
ARRAY_SIZE(wm8994_lateclk_widgets));
snd_soc_dapm_new_controls(dapm, wm8994_adc_widgets,
ARRAY_SIZE(wm8994_adc_widgets));
snd_soc_dapm_new_controls(dapm, wm8994_dac_widgets,
ARRAY_SIZE(wm8994_dac_widgets));
break;
} }
@ -3393,6 +3446,12 @@ static int wm8994_codec_probe(struct snd_soc_codec *codec)
wm8958_dsp2_init(codec); wm8958_dsp2_init(codec);
break; break;
case WM1811:
snd_soc_dapm_add_routes(dapm, wm8994_lateclk_intercon,
ARRAY_SIZE(wm8994_lateclk_intercon));
snd_soc_dapm_add_routes(dapm, wm8958_intercon,
ARRAY_SIZE(wm8958_intercon));
break;
} }
return 0; return 0;
@ -3448,6 +3507,7 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
wm8994); wm8994);
break; break;
case WM1811:
case WM8958: case WM8958:
if (wm8994->micdet_irq) if (wm8994->micdet_irq)
free_irq(wm8994->micdet_irq, wm8994); free_irq(wm8994->micdet_irq, wm8994);

View File

@ -485,7 +485,7 @@ static int configure_aif_clock(struct snd_soc_codec *codec, int aif)
static int configure_clock(struct snd_soc_codec *codec) static int configure_clock(struct snd_soc_codec *codec)
{ {
struct wm8995_priv *wm8995; struct wm8995_priv *wm8995;
int old, new; int change, new;
wm8995 = snd_soc_codec_get_drvdata(codec); wm8995 = snd_soc_codec_get_drvdata(codec);
@ -509,14 +509,10 @@ static int configure_clock(struct snd_soc_codec *codec)
else else
new = 0; new = 0;
old = snd_soc_read(codec, WM8995_CLOCKING_1) & WM8995_SYSCLK_SRC; change = snd_soc_update_bits(codec, WM8995_CLOCKING_1,
/* If there's no change then we're done. */
if (old == new)
return 0;
snd_soc_update_bits(codec, WM8995_CLOCKING_1,
WM8995_SYSCLK_SRC_MASK, new); WM8995_SYSCLK_SRC_MASK, new);
if (!change)
return 0;
snd_soc_dapm_sync(&codec->dapm); snd_soc_dapm_sync(&codec->dapm);
@ -1573,9 +1569,16 @@ static int wm8995_resume(struct snd_soc_codec *codec)
static int wm8995_remove(struct snd_soc_codec *codec) static int wm8995_remove(struct snd_soc_codec *codec)
{ {
struct wm8995_priv *wm8995; struct wm8995_priv *wm8995;
int i;
wm8995 = snd_soc_codec_get_drvdata(codec); wm8995 = snd_soc_codec_get_drvdata(codec);
wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i)
regulator_unregister_notifier(wm8995->supplies[i].consumer,
&wm8995->disable_nb[i]);
regulator_bulk_free(ARRAY_SIZE(wm8995->supplies), wm8995->supplies);
return 0; return 0;
} }

View File

@ -641,6 +641,14 @@ SOC_DOUBLE_R("Speaker ZC Switch", WM8996_LEFT_PDM_SPEAKER,
SOC_SINGLE("DSP1 EQ Switch", WM8996_DSP1_RX_EQ_GAINS_1, 0, 1, 0), SOC_SINGLE("DSP1 EQ Switch", WM8996_DSP1_RX_EQ_GAINS_1, 0, 1, 0),
SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0), SOC_SINGLE("DSP2 EQ Switch", WM8996_DSP2_RX_EQ_GAINS_1, 0, 1, 0),
SOC_SINGLE("DSP1 DRC TXL Switch", WM8996_DSP1_DRC_1, 0, 1, 0),
SOC_SINGLE("DSP1 DRC TXR Switch", WM8996_DSP1_DRC_1, 1, 1, 0),
SOC_SINGLE("DSP1 DRC RX Switch", WM8996_DSP1_DRC_1, 2, 1, 0),
SOC_SINGLE("DSP2 DRC TXL Switch", WM8996_DSP2_DRC_1, 0, 1, 0),
SOC_SINGLE("DSP2 DRC TXR Switch", WM8996_DSP2_DRC_1, 1, 1, 0),
SOC_SINGLE("DSP2 DRC RX Switch", WM8996_DSP2_DRC_1, 2, 1, 0),
}; };
static const struct snd_kcontrol_new wm8996_eq_controls[] = { static const struct snd_kcontrol_new wm8996_eq_controls[] = {
@ -1105,9 +1113,9 @@ SND_SOC_DAPM_AIF_IN("AIF2RX1", "AIF2 Playback", 0,
SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 1, SND_SOC_DAPM_AIF_IN("AIF2RX0", "AIF2 Playback", 1,
WM8996_POWER_MANAGEMENT_4, 8, 0), WM8996_POWER_MANAGEMENT_4, 8, 0),
SND_SOC_DAPM_AIF_IN("AIF2TX1", "AIF2 Capture", 0, SND_SOC_DAPM_AIF_OUT("AIF2TX1", "AIF2 Capture", 0,
WM8996_POWER_MANAGEMENT_6, 9, 0), WM8996_POWER_MANAGEMENT_6, 9, 0),
SND_SOC_DAPM_AIF_IN("AIF2TX0", "AIF2 Capture", 1, SND_SOC_DAPM_AIF_OUT("AIF2TX0", "AIF2 Capture", 1,
WM8996_POWER_MANAGEMENT_6, 8, 0), WM8996_POWER_MANAGEMENT_6, 8, 0),
SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5, SND_SOC_DAPM_AIF_IN("AIF1RX5", "AIF1 Playback", 5,
@ -1912,7 +1920,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK, snd_soc_update_bits(codec, lrclk_reg, WM8996_AIF1RX_RATE_MASK,
lrclk); lrclk);
snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2, snd_soc_update_bits(codec, WM8996_AIF_CLOCKING_2,
WM8996_DSP1_DIV_SHIFT << dsp_shift, dsp); WM8996_DSP1_DIV_MASK << dsp_shift, dsp);
return 0; return 0;
} }
@ -2698,7 +2706,6 @@ static int wm8996_probe(struct snd_soc_codec *codec)
init_completion(&wm8996->fll_lock); init_completion(&wm8996->fll_lock);
dapm->idle_bias_off = true; dapm->idle_bias_off = true;
dapm->bias_level = SND_SOC_BIAS_OFF;
ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C); ret = snd_soc_codec_set_cache_io(codec, 16, 16, SND_SOC_I2C);
if (ret != 0) { if (ret != 0) {

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