From de1eff709ddad44daaeb90c1bbe191c55e1c8fd8 Mon Sep 17 00:00:00 2001 From: Daniel Ribeiro Date: Mon, 15 Jun 2009 21:44:31 -0300 Subject: [PATCH] --- yaml --- r: 157634 b: refs/heads/master c: a5479e389e989acfeca9c32eeb0083d086202280 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/arch/arm/plat-omap/include/mach/mcbsp.h | 4 +- trunk/arch/arm/plat-omap/mcbsp.c | 50 +-- trunk/include/linux/tty.h | 2 +- trunk/include/sound/soc-dai.h | 13 +- trunk/include/sound/soc.h | 11 +- trunk/sound/soc/Makefile | 2 +- trunk/sound/soc/codecs/tlv320aic3x.c | 11 +- trunk/sound/soc/codecs/wm8510.c | 174 +++++++--- trunk/sound/soc/codecs/wm8523.c | 98 ++++-- trunk/sound/soc/codecs/wm8580.c | 154 ++++++--- trunk/sound/soc/codecs/wm8728.c | 111 ++++-- trunk/sound/soc/codecs/wm8731.c | 144 ++++++-- trunk/sound/soc/codecs/wm8750.c | 154 ++++++--- trunk/sound/soc/codecs/wm8776.c | 59 +++- trunk/sound/soc/codecs/wm8900.c | 319 +++++++++++------- trunk/sound/soc/codecs/wm8903.c | 244 +++++++++----- trunk/sound/soc/codecs/wm8940.c | 143 +++++--- trunk/sound/soc/codecs/wm8960.c | 200 +++++++---- trunk/sound/soc/codecs/wm8961.c | 231 ++++++++----- trunk/sound/soc/codecs/wm8971.c | 127 ++++--- trunk/sound/soc/codecs/wm8988.c | 138 ++++++-- trunk/sound/soc/codecs/wm8990.c | 194 ++++++----- trunk/sound/soc/codecs/wm9081.c | 234 ++++++++----- trunk/sound/soc/davinci/Kconfig | 11 - trunk/sound/soc/davinci/Makefile | 1 - trunk/sound/soc/davinci/davinci-evm.c | 33 -- trunk/sound/soc/davinci/davinci-i2s.c | 14 +- trunk/sound/soc/davinci/davinci-pcm.c | 5 - trunk/sound/soc/omap/ams-delta.c | 6 +- trunk/sound/soc/omap/omap-mcbsp.c | 10 +- trunk/sound/soc/pxa/magician.c | 2 +- trunk/sound/soc/pxa/pxa-ssp.c | 27 +- trunk/sound/soc/s3c24xx/s3c2443-ac97.c | 10 +- trunk/sound/soc/soc-cache.c | 218 ------------ trunk/sound/soc/soc-core.c | 9 +- 36 files changed, 1914 insertions(+), 1251 deletions(-) delete mode 100644 trunk/sound/soc/soc-cache.c diff --git a/[refs] b/[refs] index 46dace2e07ca..7008f2fe7cd6 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 17244c24f95ba61a12b6afeab5780a1e3f1a4c57 +refs/heads/master: a5479e389e989acfeca9c32eeb0083d086202280 diff --git a/trunk/arch/arm/plat-omap/include/mach/mcbsp.h b/trunk/arch/arm/plat-omap/include/mach/mcbsp.h index 57249bb1e9bc..bb154ea76769 100644 --- a/trunk/arch/arm/plat-omap/include/mach/mcbsp.h +++ b/trunk/arch/arm/plat-omap/include/mach/mcbsp.h @@ -387,8 +387,8 @@ void omap_mcbsp_register_board_cfg(struct omap_mcbsp_platform_data *config, void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config); int omap_mcbsp_request(unsigned int id); void omap_mcbsp_free(unsigned int id); -void omap_mcbsp_start(unsigned int id, int tx, int rx); -void omap_mcbsp_stop(unsigned int id, int tx, int rx); +void omap_mcbsp_start(unsigned int id); +void omap_mcbsp_stop(unsigned int id); void omap_mcbsp_xmit_word(unsigned int id, u32 word); u32 omap_mcbsp_recv_word(unsigned int id); diff --git a/trunk/arch/arm/plat-omap/mcbsp.c b/trunk/arch/arm/plat-omap/mcbsp.c index a3d2313460b3..efa0e0111f38 100644 --- a/trunk/arch/arm/plat-omap/mcbsp.c +++ b/trunk/arch/arm/plat-omap/mcbsp.c @@ -328,15 +328,14 @@ void omap_mcbsp_free(unsigned int id) EXPORT_SYMBOL(omap_mcbsp_free); /* - * Here we start the McBSP, by enabling transmitter, receiver or both. - * If no transmitter or receiver is active prior calling, then sample-rate - * generator and frame sync are started. + * Here we start the McBSP, by enabling the sample + * generator, both transmitter and receivers, + * and the frame sync. */ -void omap_mcbsp_start(unsigned int id, int tx, int rx) +void omap_mcbsp_start(unsigned int id) { struct omap_mcbsp *mcbsp; void __iomem *io_base; - int idle; u16 w; if (!omap_mcbsp_check_valid_id(id)) { @@ -349,40 +348,32 @@ void omap_mcbsp_start(unsigned int id, int tx, int rx) mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7; mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7; - idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | - OMAP_MCBSP_READ(io_base, SPCR1)) & 1); - - if (idle) { - /* Start the sample generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); - } + /* Start the sample generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6)); /* Enable transmitter and receiver */ w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1); w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1); udelay(100); - if (idle) { - /* Start frame sync */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); - } + /* Start frame sync */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7)); /* Dump McBSP Regs */ omap_mcbsp_dump_reg(id); } EXPORT_SYMBOL(omap_mcbsp_start); -void omap_mcbsp_stop(unsigned int id, int tx, int rx) +void omap_mcbsp_stop(unsigned int id) { struct omap_mcbsp *mcbsp; void __iomem *io_base; - int idle; u16 w; if (!omap_mcbsp_check_valid_id(id)) { @@ -395,20 +386,15 @@ void omap_mcbsp_stop(unsigned int id, int tx, int rx) /* Reset transmitter */ w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1)); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1)); /* Reset receiver */ w = OMAP_MCBSP_READ(io_base, SPCR1); - OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1)); - - idle = !((OMAP_MCBSP_READ(io_base, SPCR2) | - OMAP_MCBSP_READ(io_base, SPCR1)) & 1); + OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1)); - if (idle) { - /* Reset the sample rate generator */ - w = OMAP_MCBSP_READ(io_base, SPCR2); - OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); - } + /* Reset the sample rate generator */ + w = OMAP_MCBSP_READ(io_base, SPCR2); + OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6)); } EXPORT_SYMBOL(omap_mcbsp_stop); diff --git a/trunk/include/linux/tty.h b/trunk/include/linux/tty.h index 15bd3b065a9d..26af9816391f 100644 --- a/trunk/include/linux/tty.h +++ b/trunk/include/linux/tty.h @@ -47,7 +47,7 @@ #define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ #define N_PPS 18 /* Pulse per Second */ -#define N_V253 19 /* Codec control over voice modem */ +#define N_AMSDELTA 19 /* codec control over modem, board specific */ /* * This character is the same as _POSIX_VDISABLE: it cannot be used as diff --git a/trunk/include/sound/soc-dai.h b/trunk/include/sound/soc-dai.h index 50c6a0e295b7..2d3fa2950aa1 100644 --- a/trunk/include/sound/soc-dai.h +++ b/trunk/include/sound/soc-dai.h @@ -78,13 +78,7 @@ struct snd_pcm_substream; #define SND_SOC_CLOCK_IN 0 #define SND_SOC_CLOCK_OUT 1 -#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S8 |\ - SNDRV_PCM_FMTBIT_S16_LE |\ - SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_S20_3LE |\ - SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S24_3LE |\ - SNDRV_PCM_FMTBIT_S24_3BE |\ +#define SND_SOC_STD_AC97_FMTS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S32_LE |\ SNDRV_PCM_FMTBIT_S32_BE) @@ -112,7 +106,7 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots); + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width); int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate); @@ -146,7 +140,8 @@ struct snd_soc_dai_ops { */ int (*set_fmt)(struct snd_soc_dai *dai, unsigned int fmt); int (*set_tdm_slot)(struct snd_soc_dai *dai, - unsigned int mask, int slots); + unsigned int tx_mask, unsigned int rx_mask, + int slots, int slot_width); int (*set_tristate)(struct snd_soc_dai *dai, int tristate); /* diff --git a/trunk/include/sound/soc.h b/trunk/include/sound/soc.h index dbb1702688cd..55b330937260 100644 --- a/trunk/include/sound/soc.h +++ b/trunk/include/sound/soc.h @@ -209,20 +209,11 @@ typedef int (*hw_read_t)(void *,char* ,int); extern struct snd_ac97_bus_ops soc_ac97_ops; -enum snd_soc_control_type { - SND_SOC_CUSTOM, - SND_SOC_I2C, - SND_SOC_SPI, -}; - int snd_soc_register_platform(struct snd_soc_platform *platform); void snd_soc_unregister_platform(struct snd_soc_platform *platform); int snd_soc_register_codec(struct snd_soc_codec *codec); void snd_soc_unregister_codec(struct snd_soc_codec *codec); int snd_soc_codec_volatile_register(struct snd_soc_codec *codec, int reg); -int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - int addr_bits, int data_bits, - enum snd_soc_control_type control); #ifdef CONFIG_PM int snd_soc_suspend_device(struct device *dev); @@ -396,7 +387,7 @@ struct snd_soc_codec { int (*volatile_register)(unsigned int); int (*readable_register)(unsigned int); hw_write_t hw_write; - unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int); + hw_read_t hw_read; void *reg_cache; short reg_cache_size; short reg_cache_step; diff --git a/trunk/sound/soc/Makefile b/trunk/sound/soc/Makefile index 4eaf48aab0fa..6f1e28de23cf 100644 --- a/trunk/sound/soc/Makefile +++ b/trunk/sound/soc/Makefile @@ -1,4 +1,4 @@ -snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o +snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o obj-$(CONFIG_SND_SOC) += snd-soc-core.o obj-$(CONFIG_SND_SOC) += codecs/ diff --git a/trunk/sound/soc/codecs/tlv320aic3x.c b/trunk/sound/soc/codecs/tlv320aic3x.c index 126b15b18aeb..cb0d1bf34b57 100644 --- a/trunk/sound/soc/codecs/tlv320aic3x.c +++ b/trunk/sound/soc/codecs/tlv320aic3x.c @@ -145,8 +145,8 @@ static int aic3x_read(struct snd_soc_codec *codec, unsigned int reg, u8 *value) { *value = reg & 0xff; - - value[0] = i2c_smbus_read_byte_data(codec->control_data, value[0]); + if (codec->hw_read(codec->control_data, value, 1) != 1) + return -EIO; aic3x_write_reg_cache(codec, reg, *value); return 0; @@ -1325,6 +1325,12 @@ static struct i2c_driver aic3x_i2c_driver = { .id_table = aic3x_i2c_id, }; +static int aic3x_i2c_read(struct i2c_client *client, u8 *value, int len) +{ + value[0] = i2c_smbus_read_byte_data(client, value[0]); + return (len == 1); +} + static int aic3x_add_i2c_device(struct platform_device *pdev, const struct aic3x_setup_data *setup) { @@ -1397,6 +1403,7 @@ static int aic3x_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { codec->hw_write = (hw_write_t) i2c_master_send; + codec->hw_read = (hw_read_t) aic3x_i2c_read; ret = aic3x_add_i2c_device(pdev, setup); } #else diff --git a/trunk/sound/soc/codecs/wm8510.c b/trunk/sound/soc/codecs/wm8510.c index 060d5d06ba95..261d4cb75964 100644 --- a/trunk/sound/soc/codecs/wm8510.c +++ b/trunk/sound/soc/codecs/wm8510.c @@ -58,7 +58,55 @@ static const u16 wm8510_reg[WM8510_CACHEREGNUM] = { #define WM8510_POWER1_BIASEN 0x08 #define WM8510_POWER1_BUFIOEN 0x10 -#define wm8510_reset(c) snd_soc_write(c, WM8510_RESET, 0) +/* + * read wm8510 register cache + */ +static inline unsigned int wm8510_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8510_RESET) + return 0; + if (reg >= WM8510_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8510 register cache + */ +static inline void wm8510_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8510_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8510 register space + */ +static int wm8510_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8510 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8510_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8510_reset(c) wm8510_write(c, WM8510_RESET, 0) static const char *wm8510_companding[] = { "Off", "NC", "u-law", "A-law" }; static const char *wm8510_deemp[] = { "None", "32kHz", "44.1kHz", "48kHz" }; @@ -279,27 +327,27 @@ static int wm8510_set_dai_pll(struct snd_soc_dai *codec_dai, if (freq_in == 0 || freq_out == 0) { /* Clock CODEC directly from MCLK */ - reg = snd_soc_read(codec, WM8510_CLOCK); - snd_soc_write(codec, WM8510_CLOCK, reg & 0x0ff); + reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); + wm8510_write(codec, WM8510_CLOCK, reg & 0x0ff); /* Turn off PLL */ - reg = snd_soc_read(codec, WM8510_POWER1); - snd_soc_write(codec, WM8510_POWER1, reg & 0x1df); + reg = wm8510_read_reg_cache(codec, WM8510_POWER1); + wm8510_write(codec, WM8510_POWER1, reg & 0x1df); return 0; } pll_factors(freq_out*4, freq_in); - snd_soc_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); - snd_soc_write(codec, WM8510_PLLK1, pll_div.k >> 18); - snd_soc_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); - reg = snd_soc_read(codec, WM8510_POWER1); - snd_soc_write(codec, WM8510_POWER1, reg | 0x020); + wm8510_write(codec, WM8510_PLLN, (pll_div.pre_div << 4) | pll_div.n); + wm8510_write(codec, WM8510_PLLK1, pll_div.k >> 18); + wm8510_write(codec, WM8510_PLLK2, (pll_div.k >> 9) & 0x1ff); + wm8510_write(codec, WM8510_PLLK3, pll_div.k & 0x1ff); + reg = wm8510_read_reg_cache(codec, WM8510_POWER1); + wm8510_write(codec, WM8510_POWER1, reg | 0x020); /* Run CODEC from PLL instead of MCLK */ - reg = snd_soc_read(codec, WM8510_CLOCK); - snd_soc_write(codec, WM8510_CLOCK, reg | 0x100); + reg = wm8510_read_reg_cache(codec, WM8510_CLOCK); + wm8510_write(codec, WM8510_CLOCK, reg | 0x100); return 0; } @@ -315,24 +363,24 @@ static int wm8510_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8510_OPCLKDIV: - reg = snd_soc_read(codec, WM8510_GPIO) & 0x1cf; - snd_soc_write(codec, WM8510_GPIO, reg | div); + reg = wm8510_read_reg_cache(codec, WM8510_GPIO) & 0x1cf; + wm8510_write(codec, WM8510_GPIO, reg | div); break; case WM8510_MCLKDIV: - reg = snd_soc_read(codec, WM8510_CLOCK) & 0x11f; - snd_soc_write(codec, WM8510_CLOCK, reg | div); + reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x11f; + wm8510_write(codec, WM8510_CLOCK, reg | div); break; case WM8510_ADCCLK: - reg = snd_soc_read(codec, WM8510_ADC) & 0x1f7; - snd_soc_write(codec, WM8510_ADC, reg | div); + reg = wm8510_read_reg_cache(codec, WM8510_ADC) & 0x1f7; + wm8510_write(codec, WM8510_ADC, reg | div); break; case WM8510_DACCLK: - reg = snd_soc_read(codec, WM8510_DAC) & 0x1f7; - snd_soc_write(codec, WM8510_DAC, reg | div); + reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0x1f7; + wm8510_write(codec, WM8510_DAC, reg | div); break; case WM8510_BCLKDIV: - reg = snd_soc_read(codec, WM8510_CLOCK) & 0x1e3; - snd_soc_write(codec, WM8510_CLOCK, reg | div); + reg = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1e3; + wm8510_write(codec, WM8510_CLOCK, reg | div); break; default: return -EINVAL; @@ -346,7 +394,7 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, { struct snd_soc_codec *codec = codec_dai->codec; u16 iface = 0; - u16 clk = snd_soc_read(codec, WM8510_CLOCK) & 0x1fe; + u16 clk = wm8510_read_reg_cache(codec, WM8510_CLOCK) & 0x1fe; /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -393,8 +441,8 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8510_IFACE, iface); - snd_soc_write(codec, WM8510_CLOCK, clk); + wm8510_write(codec, WM8510_IFACE, iface); + wm8510_write(codec, WM8510_CLOCK, clk); return 0; } @@ -405,8 +453,8 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = snd_soc_read(codec, WM8510_IFACE) & 0x19f; - u16 adn = snd_soc_read(codec, WM8510_ADD) & 0x1f1; + u16 iface = wm8510_read_reg_cache(codec, WM8510_IFACE) & 0x19f; + u16 adn = wm8510_read_reg_cache(codec, WM8510_ADD) & 0x1f1; /* bit size */ switch (params_format(params)) { @@ -445,20 +493,20 @@ static int wm8510_pcm_hw_params(struct snd_pcm_substream *substream, break; } - snd_soc_write(codec, WM8510_IFACE, iface); - snd_soc_write(codec, WM8510_ADD, adn); + wm8510_write(codec, WM8510_IFACE, iface); + wm8510_write(codec, WM8510_ADD, adn); return 0; } static int wm8510_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8510_DAC) & 0xffbf; + u16 mute_reg = wm8510_read_reg_cache(codec, WM8510_DAC) & 0xffbf; if (mute) - snd_soc_write(codec, WM8510_DAC, mute_reg | 0x40); + wm8510_write(codec, WM8510_DAC, mute_reg | 0x40); else - snd_soc_write(codec, WM8510_DAC, mute_reg); + wm8510_write(codec, WM8510_DAC, mute_reg); return 0; } @@ -466,13 +514,13 @@ static int wm8510_mute(struct snd_soc_dai *dai, int mute) static int wm8510_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 power1 = snd_soc_read(codec, WM8510_POWER1) & ~0x3; + u16 power1 = wm8510_read_reg_cache(codec, WM8510_POWER1) & ~0x3; switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: power1 |= 0x1; /* VMID 50k */ - snd_soc_write(codec, WM8510_POWER1, power1); + wm8510_write(codec, WM8510_POWER1, power1); break; case SND_SOC_BIAS_STANDBY: @@ -480,18 +528,18 @@ static int wm8510_set_bias_level(struct snd_soc_codec *codec, if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Initial cap charge at VMID 5k */ - snd_soc_write(codec, WM8510_POWER1, power1 | 0x3); + wm8510_write(codec, WM8510_POWER1, power1 | 0x3); mdelay(100); } power1 |= 0x2; /* VMID 500k */ - snd_soc_write(codec, WM8510_POWER1, power1); + wm8510_write(codec, WM8510_POWER1, power1); break; case SND_SOC_BIAS_OFF: - snd_soc_write(codec, WM8510_POWER1, 0); - snd_soc_write(codec, WM8510_POWER2, 0); - snd_soc_write(codec, WM8510_POWER3, 0); + wm8510_write(codec, WM8510_POWER1, 0); + wm8510_write(codec, WM8510_POWER2, 0); + wm8510_write(codec, WM8510_POWER3, 0); break; } @@ -565,14 +613,15 @@ static int wm8510_resume(struct platform_device *pdev) * initialise the WM8510 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8510_init(struct snd_soc_device *socdev, - enum snd_soc_control_type control) +static int wm8510_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->card->codec; int ret = 0; codec->name = "WM8510"; codec->owner = THIS_MODULE; + codec->read = wm8510_read_reg_cache; + codec->write = wm8510_write; codec->set_bias_level = wm8510_set_bias_level; codec->dai = &wm8510_dai; codec->num_dai = 1; @@ -582,20 +631,13 @@ static int wm8510_init(struct snd_soc_device *socdev, if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - printk(KERN_ERR "wm8510: failed to set cache I/O: %d\n", - ret); - goto err; - } - wm8510_reset(codec); /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8510: failed to create pcms\n"); - goto err; + goto pcm_err; } /* power on device */ @@ -614,7 +656,7 @@ static int wm8510_init(struct snd_soc_device *socdev, card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -err: +pcm_err: kfree(codec->reg_cache); return ret; } @@ -637,7 +679,7 @@ static int wm8510_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = wm8510_init(socdev, SND_SOC_I2C); + ret = wm8510_init(socdev); if (ret < 0) pr_err("failed to initialise WM8510\n"); @@ -717,7 +759,7 @@ static int __devinit wm8510_spi_probe(struct spi_device *spi) codec->control_data = spi; - ret = wm8510_init(socdev, SND_SOC_SPI); + ret = wm8510_init(socdev); if (ret < 0) dev_err(&spi->dev, "failed to initialise WM8510\n"); @@ -738,6 +780,30 @@ static struct spi_driver wm8510_spi_driver = { .probe = wm8510_spi_probe, .remove = __devexit_p(wm8510_spi_remove), }; + +static int wm8510_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} #endif /* CONFIG_SPI_MASTER */ static int wm8510_probe(struct platform_device *pdev) @@ -762,11 +828,13 @@ static int wm8510_probe(struct platform_device *pdev) wm8510_socdev = socdev; #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8510_add_i2c_device(pdev, setup); } #endif #if defined(CONFIG_SPI_MASTER) if (setup->spi) { + codec->hw_write = (hw_write_t)wm8510_spi_write; ret = spi_register_driver(&wm8510_spi_driver); if (ret != 0) printk(KERN_ERR "can't add spi driver"); diff --git a/trunk/sound/soc/codecs/wm8523.c b/trunk/sound/soc/codecs/wm8523.c index 25870a4652fb..3b499ae7ce6c 100644 --- a/trunk/sound/soc/codecs/wm8523.c +++ b/trunk/sound/soc/codecs/wm8523.c @@ -62,7 +62,7 @@ static const u16 wm8523_reg[WM8523_REGISTER_COUNT] = { 0x0000, /* R8 - ZERO_DETECT */ }; -static int wm8523_volatile_register(unsigned int reg) +static int wm8523_volatile(unsigned int reg) { switch (reg) { case WM8523_DEVICE_ID: @@ -73,9 +73,71 @@ static int wm8523_volatile_register(unsigned int reg) } } +static int wm8523_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + struct wm8523_priv *wm8523 = codec->private_data; + u8 data[3]; + + BUG_ON(reg > WM8523_MAX_REGISTER); + + data[0] = reg; + data[1] = (value >> 8) & 0x00ff; + data[2] = value & 0x00ff; + + if (!wm8523_volatile(reg)) + wm8523->reg_cache[reg] = value; + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + static int wm8523_reset(struct snd_soc_codec *codec) { - return snd_soc_write(codec, WM8523_DEVICE_ID, 0); + return wm8523_write(codec, WM8523_DEVICE_ID, 0); +} + +static unsigned int wm8523_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *i2c = codec->control_data; + + /* Write register */ + xfer[0].addr = i2c->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = i2c->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(i2c->adapter, xfer, 2); + if (ret != 2) { + dev_err(codec->dev, "Failed to read 0x%x: %d\n", reg, ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + + +static unsigned int wm8523_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *reg_cache = codec->reg_cache; + + BUG_ON(reg > WM8523_MAX_REGISTER); + + if (wm8523_volatile(reg)) + return wm8523_read_hw(codec, reg); + else + return reg_cache[reg]; } static const DECLARE_TLV_DB_SCALE(dac_tlv, -10000, 25, 0); @@ -166,8 +228,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; struct wm8523_priv *wm8523 = codec->private_data; int i; - u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); - u16 aifctrl2 = snd_soc_read(codec, WM8523_AIF_CTRL2); + u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); + u16 aifctrl2 = wm8523_read(codec, WM8523_AIF_CTRL2); /* Find a supported LRCLK ratio */ for (i = 0; i < ARRAY_SIZE(lrclk_ratios); i++) { @@ -201,8 +263,8 @@ static int wm8523_hw_params(struct snd_pcm_substream *substream, break; } - snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1); - snd_soc_write(codec, WM8523_AIF_CTRL2, aifctrl2); + wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); + wm8523_write(codec, WM8523_AIF_CTRL2, aifctrl2); return 0; } @@ -260,7 +322,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 aifctrl1 = snd_soc_read(codec, WM8523_AIF_CTRL1); + u16 aifctrl1 = wm8523_read(codec, WM8523_AIF_CTRL1); aifctrl1 &= ~(WM8523_BCLK_INV_MASK | WM8523_LRCLK_INV_MASK | WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); @@ -310,7 +372,7 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8523_AIF_CTRL1, aifctrl1); + wm8523_write(codec, WM8523_AIF_CTRL1, aifctrl1); return 0; } @@ -349,7 +411,7 @@ static int wm8523_set_bias_level(struct snd_soc_codec *codec, /* Sync back default/cached values */ for (i = WM8523_AIF_CTRL1; i < WM8523_MAX_REGISTER; i++) - snd_soc_write(codec, i, wm8523->reg_cache[i]); + wm8523_write(codec, i, wm8523->reg_cache[i]); msleep(100); @@ -481,8 +543,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8523 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8523); -static int wm8523_register(struct wm8523_priv *wm8523, - enum snd_soc_control_type control) +static int wm8523_register(struct wm8523_priv *wm8523) { int ret; struct snd_soc_codec *codec = &wm8523->codec; @@ -500,13 +561,14 @@ static int wm8523_register(struct wm8523_priv *wm8523, codec->private_data = wm8523; codec->name = "WM8523"; codec->owner = THIS_MODULE; + codec->read = wm8523_read; + codec->write = wm8523_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8523_set_bias_level; codec->dai = &wm8523_dai; codec->num_dai = 1; codec->reg_cache_size = WM8523_REGISTER_COUNT; codec->reg_cache = &wm8523->reg_cache; - codec->volatile_register = wm8523_volatile_register; wm8523->rate_constraint.list = &wm8523->rate_constraint_list[0]; wm8523->rate_constraint.count = @@ -514,12 +576,6 @@ static int wm8523_register(struct wm8523_priv *wm8523, memcpy(codec->reg_cache, wm8523_reg, sizeof(wm8523_reg)); - ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - for (i = 0; i < ARRAY_SIZE(wm8523->supplies); i++) wm8523->supplies[i].supply = wm8523_supply_names[i]; @@ -537,7 +593,7 @@ static int wm8523_register(struct wm8523_priv *wm8523, goto err_get; } - ret = snd_soc_read(codec, WM8523_DEVICE_ID); + ret = wm8523_read(codec, WM8523_DEVICE_ID); if (ret < 0) { dev_err(codec->dev, "Failed to read ID register\n"); goto err_enable; @@ -548,7 +604,7 @@ static int wm8523_register(struct wm8523_priv *wm8523, goto err_enable; } - ret = snd_soc_read(codec, WM8523_REVISION); + ret = wm8523_read(codec, WM8523_REVISION); if (ret < 0) { dev_err(codec->dev, "Failed to read revision register\n"); goto err_enable; @@ -628,7 +684,7 @@ static __devinit int wm8523_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm8523_register(wm8523, SND_SOC_I2C); + return wm8523_register(wm8523); } static __devexit int wm8523_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/codecs/wm8580.c b/trunk/sound/soc/codecs/wm8580.c index d5473473a1e3..97b9ed95d289 100644 --- a/trunk/sound/soc/codecs/wm8580.c +++ b/trunk/sound/soc/codecs/wm8580.c @@ -205,6 +205,73 @@ struct wm8580_priv { struct pll_state b; }; +/* + * read wm8580 register cache + */ +static inline unsigned int wm8580_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); + return cache[reg]; +} + +/* + * write wm8580 register cache + */ +static inline void wm8580_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + + cache[reg] = value; +} + +/* + * write to the WM8580 register space + */ +static int wm8580_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + BUG_ON(reg >= ARRAY_SIZE(wm8580_reg)); + + /* Registers are 9 bits wide */ + value &= 0x1ff; + + switch (reg) { + case WM8580_RESET: + /* Uncached */ + break; + default: + if (value == wm8580_read_reg_cache(codec, reg)) + return 0; + } + + /* data is + * D15..D9 WM8580 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8580_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +static inline unsigned int wm8580_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + switch (reg) { + default: + return wm8580_read_reg_cache(codec, reg); + } +} + static const DECLARE_TLV_DB_SCALE(dac_tlv, -12750, 50, 1); static int wm8580_out_vu(struct snd_kcontrol *kcontrol, @@ -213,22 +280,25 @@ static int wm8580_out_vu(struct snd_kcontrol *kcontrol, struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - u16 *reg_cache = codec->reg_cache; unsigned int reg = mc->reg; unsigned int reg2 = mc->rreg; int ret; + u16 val; /* Clear the register cache so we write without VU set */ - reg_cache[reg] = 0; - reg_cache[reg2] = 0; + wm8580_write_reg_cache(codec, reg, 0); + wm8580_write_reg_cache(codec, reg2, 0); ret = snd_soc_put_volsw_2r(kcontrol, ucontrol); if (ret < 0) return ret; /* Now write again with the volume update bit set */ - snd_soc_update_bits(codec, reg, 0x100, 0x100); - snd_soc_update_bits(codec, reg2, 0x100, 0x100); + val = wm8580_read_reg_cache(codec, reg); + wm8580_write(codec, reg, val | 0x0100); + + val = wm8580_read_reg_cache(codec, reg2); + wm8580_write(codec, reg2, val | 0x0100); return 0; } @@ -451,27 +521,27 @@ static int wm8580_set_dai_pll(struct snd_soc_dai *codec_dai, /* Always disable the PLL - it is not safe to leave it running * while reprogramming it. */ - reg = snd_soc_read(codec, WM8580_PWRDN2); - snd_soc_write(codec, WM8580_PWRDN2, reg | pwr_mask); + reg = wm8580_read(codec, WM8580_PWRDN2); + wm8580_write(codec, WM8580_PWRDN2, reg | pwr_mask); if (!freq_in || !freq_out) return 0; - snd_soc_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); - snd_soc_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); - snd_soc_write(codec, WM8580_PLLA3 + offset, + wm8580_write(codec, WM8580_PLLA1 + offset, pll_div.k & 0x1ff); + wm8580_write(codec, WM8580_PLLA2 + offset, (pll_div.k >> 9) & 0xff); + wm8580_write(codec, WM8580_PLLA3 + offset, (pll_div.k >> 18 & 0xf) | (pll_div.n << 4)); - reg = snd_soc_read(codec, WM8580_PLLA4 + offset); + reg = wm8580_read(codec, WM8580_PLLA4 + offset); reg &= ~0x3f; reg |= pll_div.prescale | pll_div.postscale << 1 | pll_div.freqmode << 3; - snd_soc_write(codec, WM8580_PLLA4 + offset, reg); + wm8580_write(codec, WM8580_PLLA4 + offset, reg); /* All done, turn it on */ - reg = snd_soc_read(codec, WM8580_PWRDN2); - snd_soc_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); + reg = wm8580_read(codec, WM8580_PWRDN2); + wm8580_write(codec, WM8580_PWRDN2, reg & ~pwr_mask); return 0; } @@ -486,7 +556,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 paifb = snd_soc_read(codec, WM8580_PAIF3 + dai->id); + u16 paifb = wm8580_read(codec, WM8580_PAIF3 + dai->id); paifb &= ~WM8580_AIF_LENGTH_MASK; /* bit size */ @@ -506,7 +576,7 @@ static int wm8580_paif_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_write(codec, WM8580_PAIF3 + dai->id, paifb); + wm8580_write(codec, WM8580_PAIF3 + dai->id, paifb); return 0; } @@ -518,8 +588,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int aifb; int can_invert_lrclk; - aifa = snd_soc_read(codec, WM8580_PAIF1 + codec_dai->id); - aifb = snd_soc_read(codec, WM8580_PAIF3 + codec_dai->id); + aifa = wm8580_read(codec, WM8580_PAIF1 + codec_dai->id); + aifb = wm8580_read(codec, WM8580_PAIF3 + codec_dai->id); aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); @@ -585,8 +655,8 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); - snd_soc_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); + wm8580_write(codec, WM8580_PAIF1 + codec_dai->id, aifa); + wm8580_write(codec, WM8580_PAIF3 + codec_dai->id, aifb); return 0; } @@ -599,7 +669,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8580_MCLK: - reg = snd_soc_read(codec, WM8580_PLLB4); + reg = wm8580_read(codec, WM8580_PLLB4); reg &= ~WM8580_PLLB4_MCLKOUTSRC_MASK; switch (div) { @@ -621,11 +691,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - snd_soc_write(codec, WM8580_PLLB4, reg); + wm8580_write(codec, WM8580_PLLB4, reg); break; case WM8580_DAC_CLKSEL: - reg = snd_soc_read(codec, WM8580_CLKSEL); + reg = wm8580_read(codec, WM8580_CLKSEL); reg &= ~WM8580_CLKSEL_DAC_CLKSEL_MASK; switch (div) { @@ -643,11 +713,11 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - snd_soc_write(codec, WM8580_CLKSEL, reg); + wm8580_write(codec, WM8580_CLKSEL, reg); break; case WM8580_CLKOUTSRC: - reg = snd_soc_read(codec, WM8580_PLLB4); + reg = wm8580_read(codec, WM8580_PLLB4); reg &= ~WM8580_PLLB4_CLKOUTSRC_MASK; switch (div) { @@ -669,7 +739,7 @@ static int wm8580_set_dai_clkdiv(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - snd_soc_write(codec, WM8580_PLLB4, reg); + wm8580_write(codec, WM8580_PLLB4, reg); break; default: @@ -684,14 +754,14 @@ static int wm8580_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; unsigned int reg; - reg = snd_soc_read(codec, WM8580_DAC_CONTROL5); + reg = wm8580_read(codec, WM8580_DAC_CONTROL5); if (mute) reg |= WM8580_DAC_CONTROL5_MUTEALL; else reg &= ~WM8580_DAC_CONTROL5_MUTEALL; - snd_soc_write(codec, WM8580_DAC_CONTROL5, reg); + wm8580_write(codec, WM8580_DAC_CONTROL5, reg); return 0; } @@ -708,20 +778,20 @@ static int wm8580_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Power up and get individual control of the DACs */ - reg = snd_soc_read(codec, WM8580_PWRDN1); + reg = wm8580_read(codec, WM8580_PWRDN1); reg &= ~(WM8580_PWRDN1_PWDN | WM8580_PWRDN1_ALLDACPD); - snd_soc_write(codec, WM8580_PWRDN1, reg); + wm8580_write(codec, WM8580_PWRDN1, reg); /* Make VMID high impedence */ - reg = snd_soc_read(codec, WM8580_ADC_CONTROL1); + reg = wm8580_read(codec, WM8580_ADC_CONTROL1); reg &= ~0x100; - snd_soc_write(codec, WM8580_ADC_CONTROL1, reg); + wm8580_write(codec, WM8580_ADC_CONTROL1, reg); } break; case SND_SOC_BIAS_OFF: - reg = snd_soc_read(codec, WM8580_PWRDN1); - snd_soc_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); + reg = wm8580_read(codec, WM8580_PWRDN1); + wm8580_write(codec, WM8580_PWRDN1, reg | WM8580_PWRDN1_PWDN); break; } codec->bias_level = level; @@ -832,8 +902,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8580 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8580); -static int wm8580_register(struct wm8580_priv *wm8580, - enum snd_soc_control_type control) +static int wm8580_register(struct wm8580_priv *wm8580) { int ret, i; struct snd_soc_codec *codec = &wm8580->codec; @@ -851,6 +920,8 @@ static int wm8580_register(struct wm8580_priv *wm8580, codec->private_data = wm8580; codec->name = "WM8580"; codec->owner = THIS_MODULE; + codec->read = wm8580_read_reg_cache; + codec->write = wm8580_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8580_set_bias_level; codec->dai = wm8580_dai; @@ -860,12 +931,6 @@ static int wm8580_register(struct wm8580_priv *wm8580, memcpy(codec->reg_cache, wm8580_reg, sizeof(wm8580_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - for (i = 0; i < ARRAY_SIZE(wm8580->supplies); i++) wm8580->supplies[i].supply = wm8580_supply_names[i]; @@ -884,7 +949,7 @@ static int wm8580_register(struct wm8580_priv *wm8580, } /* Get the codec into a known state */ - ret = snd_soc_write(codec, WM8580_RESET, 0); + ret = wm8580_write(codec, WM8580_RESET, 0); if (ret != 0) { dev_err(codec->dev, "Failed to reset codec: %d\n", ret); goto err_regulator_enable; @@ -945,13 +1010,14 @@ static int wm8580_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8580->codec; + codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8580); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8580_register(wm8580, SND_SOC_I2C); + return wm8580_register(wm8580); } static int wm8580_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/codecs/wm8728.c b/trunk/sound/soc/codecs/wm8728.c index 16e969a762c3..e7ff2121ede9 100644 --- a/trunk/sound/soc/codecs/wm8728.c +++ b/trunk/sound/soc/codecs/wm8728.c @@ -43,6 +43,45 @@ static const u16 wm8728_reg_defaults[] = { 0x100, }; +static inline unsigned int wm8728_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); + return cache[reg]; +} + +static inline void wm8728_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg >= ARRAY_SIZE(wm8728_reg_defaults)); + cache[reg] = value; +} + +/* + * write to the WM8728 register space + */ +static int wm8728_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8728 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8728_write_reg_cache(codec, reg, value); + + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + static const DECLARE_TLV_DB_SCALE(wm8728_tlv, -12750, 50, 1); static const struct snd_kcontrol_new wm8728_snd_controls[] = { @@ -82,12 +121,12 @@ static int wm8728_add_widgets(struct snd_soc_codec *codec) static int wm8728_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8728_DACCTL); + u16 mute_reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); if (mute) - snd_soc_write(codec, WM8728_DACCTL, mute_reg | 1); + wm8728_write(codec, WM8728_DACCTL, mute_reg | 1); else - snd_soc_write(codec, WM8728_DACCTL, mute_reg & ~1); + wm8728_write(codec, WM8728_DACCTL, mute_reg & ~1); return 0; } @@ -99,7 +138,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 dac = snd_soc_read(codec, WM8728_DACCTL); + u16 dac = wm8728_read_reg_cache(codec, WM8728_DACCTL); dac &= ~0x18; @@ -116,7 +155,7 @@ static int wm8728_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_write(codec, WM8728_DACCTL, dac); + wm8728_write(codec, WM8728_DACCTL, dac); return 0; } @@ -125,7 +164,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = snd_soc_read(codec, WM8728_IFCTL); + u16 iface = wm8728_read_reg_cache(codec, WM8728_IFCTL); /* Currently only I2S is supported by the driver, though the * hardware is more flexible. @@ -165,7 +204,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8728_IFCTL, iface); + wm8728_write(codec, WM8728_IFCTL, iface); return 0; } @@ -181,19 +220,19 @@ static int wm8728_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Power everything up... */ - reg = snd_soc_read(codec, WM8728_DACCTL); - snd_soc_write(codec, WM8728_DACCTL, reg & ~0x4); + reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + wm8728_write(codec, WM8728_DACCTL, reg & ~0x4); /* ..then sync in the register cache. */ for (i = 0; i < ARRAY_SIZE(wm8728_reg_defaults); i++) - snd_soc_write(codec, i, - snd_soc_read(codec, i)); + wm8728_write(codec, i, + wm8728_read_reg_cache(codec, i)); } break; case SND_SOC_BIAS_OFF: - reg = snd_soc_read(codec, WM8728_DACCTL); - snd_soc_write(codec, WM8728_DACCTL, reg | 0x4); + reg = wm8728_read_reg_cache(codec, WM8728_DACCTL); + wm8728_write(codec, WM8728_DACCTL, reg | 0x4); break; } codec->bias_level = level; @@ -248,14 +287,15 @@ static int wm8728_resume(struct platform_device *pdev) * initialise the WM8728 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8728_init(struct snd_soc_device *socdev, - enum snd_soc_control_type control) +static int wm8728_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->card->codec; int ret = 0; codec->name = "WM8728"; codec->owner = THIS_MODULE; + codec->read = wm8728_read_reg_cache; + codec->write = wm8728_write; codec->set_bias_level = wm8728_set_bias_level; codec->dai = &wm8728_dai; codec->num_dai = 1; @@ -267,18 +307,11 @@ static int wm8728_init(struct snd_soc_device *socdev, if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - printk(KERN_ERR "wm8728: failed to configure cache I/O: %d\n", - ret); - goto err; - } - /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8728: failed to create pcms\n"); - goto err; + goto pcm_err; } /* power on device */ @@ -298,7 +331,7 @@ static int wm8728_init(struct snd_soc_device *socdev, card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -err: +pcm_err: kfree(codec->reg_cache); return ret; } @@ -324,7 +357,7 @@ static int wm8728_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = wm8728_init(socdev, SND_SOC_I2C); + ret = wm8728_init(socdev); if (ret < 0) pr_err("failed to initialise WM8728\n"); @@ -404,7 +437,7 @@ static int __devinit wm8728_spi_probe(struct spi_device *spi) codec->control_data = spi; - ret = wm8728_init(socdev, SND_SOC_SPI); + ret = wm8728_init(socdev); if (ret < 0) dev_err(&spi->dev, "failed to initialise WM8728\n"); @@ -425,6 +458,30 @@ static struct spi_driver wm8728_spi_driver = { .probe = wm8728_spi_probe, .remove = __devexit_p(wm8728_spi_remove), }; + +static int wm8728_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} #endif /* CONFIG_SPI_MASTER */ static int wm8728_probe(struct platform_device *pdev) @@ -449,11 +506,13 @@ static int wm8728_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8728_add_i2c_device(pdev, setup); } #endif #if defined(CONFIG_SPI_MASTER) if (setup->spi) { + codec->hw_write = (hw_write_t)wm8728_spi_write; ret = spi_register_driver(&wm8728_spi_driver); if (ret != 0) printk(KERN_ERR "can't add spi driver"); diff --git a/trunk/sound/soc/codecs/wm8731.c b/trunk/sound/soc/codecs/wm8731.c index d3fd4f28d96e..156002852078 100644 --- a/trunk/sound/soc/codecs/wm8731.c +++ b/trunk/sound/soc/codecs/wm8731.c @@ -40,6 +40,9 @@ struct wm8731_priv { unsigned int sysclk; }; +#ifdef CONFIG_SPI_MASTER +static int wm8731_spi_write(struct spi_device *spi, const char *data, int len); +#endif /* * wm8731 register cache @@ -48,12 +51,60 @@ struct wm8731_priv { * There is no point in caching the reset register */ static const u16 wm8731_reg[WM8731_CACHEREGNUM] = { - 0x0097, 0x0097, 0x0079, 0x0079, - 0x000a, 0x0008, 0x009f, 0x000a, - 0x0000, 0x0000 + 0x0097, 0x0097, 0x0079, 0x0079, + 0x000a, 0x0008, 0x009f, 0x000a, + 0x0000, 0x0000 }; -#define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) +/* + * read wm8731 register cache + */ +static inline unsigned int wm8731_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8731_RESET) + return 0; + if (reg >= WM8731_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8731 register cache + */ +static inline void wm8731_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8731_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8731 register space + */ +static int wm8731_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8731 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8731_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8731_reset(c) wm8731_write(c, WM8731_RESET, 0) static const char *wm8731_input_select[] = {"Line In", "Mic"}; static const char *wm8731_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; @@ -216,12 +267,12 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8731_priv *wm8731 = codec->private_data; - u16 iface = snd_soc_read(codec, WM8731_IFACE) & 0xfff3; + u16 iface = wm8731_read_reg_cache(codec, WM8731_IFACE) & 0xfff3; int i = get_coeff(wm8731->sysclk, params_rate(params)); u16 srate = (coeff_div[i].sr << 2) | (coeff_div[i].bosr << 1) | coeff_div[i].usb; - snd_soc_write(codec, WM8731_SRATE, srate); + wm8731_write(codec, WM8731_SRATE, srate); /* bit size */ switch (params_format(params)) { @@ -235,7 +286,7 @@ static int wm8731_hw_params(struct snd_pcm_substream *substream, break; } - snd_soc_write(codec, WM8731_IFACE, iface); + wm8731_write(codec, WM8731_IFACE, iface); return 0; } @@ -247,7 +298,7 @@ static int wm8731_pcm_prepare(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; /* set active */ - snd_soc_write(codec, WM8731_ACTIVE, 0x0001); + wm8731_write(codec, WM8731_ACTIVE, 0x0001); return 0; } @@ -262,19 +313,19 @@ static void wm8731_shutdown(struct snd_pcm_substream *substream, /* deactivate */ if (!codec->active) { udelay(50); - snd_soc_write(codec, WM8731_ACTIVE, 0x0); + wm8731_write(codec, WM8731_ACTIVE, 0x0); } } static int wm8731_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8731_APDIGI) & 0xfff7; + u16 mute_reg = wm8731_read_reg_cache(codec, WM8731_APDIGI) & 0xfff7; if (mute) - snd_soc_write(codec, WM8731_APDIGI, mute_reg | 0x8); + wm8731_write(codec, WM8731_APDIGI, mute_reg | 0x8); else - snd_soc_write(codec, WM8731_APDIGI, mute_reg); + wm8731_write(codec, WM8731_APDIGI, mute_reg); return 0; } @@ -352,7 +403,7 @@ static int wm8731_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - snd_soc_write(codec, WM8731_IFACE, iface); + wm8731_write(codec, WM8731_IFACE, iface); return 0; } @@ -368,12 +419,12 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, break; case SND_SOC_BIAS_STANDBY: /* Clear PWROFF, gate CLKOUT, everything else as-is */ - reg = snd_soc_read(codec, WM8731_PWR) & 0xff7f; - snd_soc_write(codec, WM8731_PWR, reg | 0x0040); + reg = wm8731_read_reg_cache(codec, WM8731_PWR) & 0xff7f; + wm8731_write(codec, WM8731_PWR, reg | 0x0040); break; case SND_SOC_BIAS_OFF: - snd_soc_write(codec, WM8731_ACTIVE, 0x0); - snd_soc_write(codec, WM8731_PWR, 0xffff); + wm8731_write(codec, WM8731_ACTIVE, 0x0); + wm8731_write(codec, WM8731_PWR, 0xffff); break; } codec->bias_level = level; @@ -423,7 +474,7 @@ static int wm8731_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_codec *codec = socdev->card->codec; - snd_soc_write(codec, WM8731_ACTIVE, 0x0); + wm8731_write(codec, WM8731_ACTIVE, 0x0); wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF); return 0; } @@ -509,11 +560,11 @@ struct snd_soc_codec_device soc_codec_dev_wm8731 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8731); -static int wm8731_register(struct wm8731_priv *wm8731, - enum snd_soc_control_type control) +static int wm8731_register(struct wm8731_priv *wm8731) { int ret; struct snd_soc_codec *codec = &wm8731->codec; + u16 reg; if (wm8731_codec) { dev_err(codec->dev, "Another WM8731 is registered\n"); @@ -528,6 +579,8 @@ static int wm8731_register(struct wm8731_priv *wm8731, codec->private_data = wm8731; codec->name = "WM8731"; codec->owner = THIS_MODULE; + codec->read = wm8731_read_reg_cache; + codec->write = wm8731_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8731_set_bias_level; codec->dai = &wm8731_dai; @@ -537,12 +590,6 @@ static int wm8731_register(struct wm8731_priv *wm8731, memcpy(codec->reg_cache, wm8731_reg, sizeof(wm8731_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - ret = wm8731_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset: %d\n", ret); @@ -554,13 +601,18 @@ static int wm8731_register(struct wm8731_priv *wm8731, wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the update bits */ - snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); - snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0); - snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0); - snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); + reg = wm8731_read_reg_cache(codec, WM8731_LOUT1V); + wm8731_write(codec, WM8731_LOUT1V, reg & ~0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_ROUT1V); + wm8731_write(codec, WM8731_ROUT1V, reg & ~0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_LINVOL); + wm8731_write(codec, WM8731_LINVOL, reg & ~0x0100); + reg = wm8731_read_reg_cache(codec, WM8731_RINVOL); + wm8731_write(codec, WM8731_RINVOL, reg & ~0x0100); /* Disable bypass path by default */ - snd_soc_update_bits(codec, WM8731_APANA, 0x4, 0); + reg = wm8731_read_reg_cache(codec, WM8731_APANA); + wm8731_write(codec, WM8731_APANA, reg & ~0x4); wm8731_codec = codec; @@ -596,6 +648,30 @@ static void wm8731_unregister(struct wm8731_priv *wm8731) } #if defined(CONFIG_SPI_MASTER) +static int wm8731_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} + static int __devinit wm8731_spi_probe(struct spi_device *spi) { struct snd_soc_codec *codec; @@ -607,11 +683,12 @@ static int __devinit wm8731_spi_probe(struct spi_device *spi) codec = &wm8731->codec; codec->control_data = spi; + codec->hw_write = (hw_write_t)wm8731_spi_write; codec->dev = &spi->dev; dev_set_drvdata(&spi->dev, wm8731); - return wm8731_register(wm8731, SND_SOC_SPI); + return wm8731_register(wm8731); } static int __devexit wm8731_spi_remove(struct spi_device *spi) @@ -663,13 +740,14 @@ static __devinit int wm8731_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8731->codec; + codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8731); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8731_register(wm8731, SND_SOC_I2C); + return wm8731_register(wm8731); } static __devexit int wm8731_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/codecs/wm8750.c b/trunk/sound/soc/codecs/wm8750.c index 4ba1e7e93fb4..b64509b01a49 100644 --- a/trunk/sound/soc/codecs/wm8750.c +++ b/trunk/sound/soc/codecs/wm8750.c @@ -55,7 +55,50 @@ static const u16 wm8750_reg[] = { 0x0079, 0x0079, 0x0079, /* 40 */ }; -#define wm8750_reset(c) snd_soc_write(c, WM8750_RESET, 0) +/* + * read wm8750 register cache + */ +static inline unsigned int wm8750_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8750_CACHE_REGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8750 register cache + */ +static inline void wm8750_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8750_CACHE_REGNUM) + return; + cache[reg] = value; +} + +static int wm8750_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8750_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8750_reset(c) wm8750_write(c, WM8750_RESET, 0) /* * WM8750 Controls @@ -551,7 +594,7 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8750_IFACE, iface); + wm8750_write(codec, WM8750_IFACE, iface); return 0; } @@ -563,8 +606,8 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8750_priv *wm8750 = codec->private_data; - u16 iface = snd_soc_read(codec, WM8750_IFACE) & 0x1f3; - u16 srate = snd_soc_read(codec, WM8750_SRATE) & 0x1c0; + u16 iface = wm8750_read_reg_cache(codec, WM8750_IFACE) & 0x1f3; + u16 srate = wm8750_read_reg_cache(codec, WM8750_SRATE) & 0x1c0; int coeff = get_coeff(wm8750->sysclk, params_rate(params)); /* bit size */ @@ -583,9 +626,9 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, } /* set iface & srate */ - snd_soc_write(codec, WM8750_IFACE, iface); + wm8750_write(codec, WM8750_IFACE, iface); if (coeff >= 0) - snd_soc_write(codec, WM8750_SRATE, srate | + wm8750_write(codec, WM8750_SRATE, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; @@ -594,35 +637,35 @@ static int wm8750_pcm_hw_params(struct snd_pcm_substream *substream, static int wm8750_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8750_ADCDAC) & 0xfff7; + u16 mute_reg = wm8750_read_reg_cache(codec, WM8750_ADCDAC) & 0xfff7; if (mute) - snd_soc_write(codec, WM8750_ADCDAC, mute_reg | 0x8); + wm8750_write(codec, WM8750_ADCDAC, mute_reg | 0x8); else - snd_soc_write(codec, WM8750_ADCDAC, mute_reg); + wm8750_write(codec, WM8750_ADCDAC, mute_reg); return 0; } static int wm8750_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = snd_soc_read(codec, WM8750_PWR1) & 0xfe3e; + u16 pwr_reg = wm8750_read_reg_cache(codec, WM8750_PWR1) & 0xfe3e; switch (level) { case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ - snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x00c0); break; case SND_SOC_BIAS_PREPARE: /* set vmid to 5k for quick power up */ - snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x01c1); break; case SND_SOC_BIAS_STANDBY: /* mute dac and set vmid to 500k, enable VREF */ - snd_soc_write(codec, WM8750_PWR1, pwr_reg | 0x0141); + wm8750_write(codec, WM8750_PWR1, pwr_reg | 0x0141); break; case SND_SOC_BIAS_OFF: - snd_soc_write(codec, WM8750_PWR1, 0x0001); + wm8750_write(codec, WM8750_PWR1, 0x0001); break; } codec->bias_level = level; @@ -711,14 +754,15 @@ static int wm8750_resume(struct platform_device *pdev) * initialise the WM8750 driver * register the mixer and dsp interfaces with the kernel */ -static int wm8750_init(struct snd_soc_device *socdev, - enum snd_soc_control_type control) +static int wm8750_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->card->codec; int reg, ret = 0; codec->name = "WM8750"; codec->owner = THIS_MODULE; + codec->read = wm8750_read_reg_cache; + codec->write = wm8750_write; codec->set_bias_level = wm8750_set_bias_level; codec->dai = &wm8750_dai; codec->num_dai = 1; @@ -727,23 +771,13 @@ static int wm8750_init(struct snd_soc_device *socdev, if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - printk(KERN_ERR "wm8750: failed to set cache I/O: %d\n", ret); - goto err; - } - - ret = wm8750_reset(codec); - if (ret < 0) { - printk(KERN_ERR "wm8750: failed to reset: %d\n", ret); - goto err; - } + wm8750_reset(codec); /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8750: failed to create pcms\n"); - goto err; + goto pcm_err; } /* charge output caps */ @@ -752,22 +786,22 @@ static int wm8750_init(struct snd_soc_device *socdev, schedule_delayed_work(&codec->delayed_work, msecs_to_jiffies(1000)); /* set the update bits */ - reg = snd_soc_read(codec, WM8750_LDAC); - snd_soc_write(codec, WM8750_LDAC, reg | 0x0100); - reg = snd_soc_read(codec, WM8750_RDAC); - snd_soc_write(codec, WM8750_RDAC, reg | 0x0100); - reg = snd_soc_read(codec, WM8750_LOUT1V); - snd_soc_write(codec, WM8750_LOUT1V, reg | 0x0100); - reg = snd_soc_read(codec, WM8750_ROUT1V); - snd_soc_write(codec, WM8750_ROUT1V, reg | 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); + reg = wm8750_read_reg_cache(codec, WM8750_LDAC); + wm8750_write(codec, WM8750_LDAC, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_RDAC); + wm8750_write(codec, WM8750_RDAC, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LOUT1V); + wm8750_write(codec, WM8750_LOUT1V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_ROUT1V); + wm8750_write(codec, WM8750_ROUT1V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LOUT2V); + wm8750_write(codec, WM8750_LOUT2V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_ROUT2V); + wm8750_write(codec, WM8750_ROUT2V, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_LINVOL); + wm8750_write(codec, WM8750_LINVOL, reg | 0x0100); + reg = wm8750_read_reg_cache(codec, WM8750_RINVOL); + wm8750_write(codec, WM8750_RINVOL, reg | 0x0100); snd_soc_add_controls(codec, wm8750_snd_controls, ARRAY_SIZE(wm8750_snd_controls)); @@ -782,7 +816,7 @@ static int wm8750_init(struct snd_soc_device *socdev, card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -err: +pcm_err: kfree(codec->reg_cache); return ret; } @@ -810,7 +844,7 @@ static int wm8750_i2c_probe(struct i2c_client *i2c, i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = wm8750_init(socdev, SND_SOC_I2C); + ret = wm8750_init(socdev); if (ret < 0) pr_err("failed to initialise WM8750\n"); @@ -890,7 +924,7 @@ static int __devinit wm8750_spi_probe(struct spi_device *spi) codec->control_data = spi; - ret = wm8750_init(socdev, SND_SOC_SPI); + ret = wm8750_init(socdev); if (ret < 0) dev_err(&spi->dev, "failed to initialise WM8750\n"); @@ -911,6 +945,30 @@ static struct spi_driver wm8750_spi_driver = { .probe = wm8750_spi_probe, .remove = __devexit_p(wm8750_spi_remove), }; + +static int wm8750_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} #endif static int wm8750_probe(struct platform_device *pdev) @@ -944,11 +1002,13 @@ static int wm8750_probe(struct platform_device *pdev) #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8750_add_i2c_device(pdev, setup); } #endif #if defined(CONFIG_SPI_MASTER) if (setup->spi) { + codec->hw_write = (hw_write_t)wm8750_spi_write; ret = spi_register_driver(&wm8750_spi_driver); if (ret != 0) printk(KERN_ERR "can't add spi driver"); diff --git a/trunk/sound/soc/codecs/wm8776.c b/trunk/sound/soc/codecs/wm8776.c index a9829aa26e53..ee12bf824a40 100644 --- a/trunk/sound/soc/codecs/wm8776.c +++ b/trunk/sound/soc/codecs/wm8776.c @@ -52,9 +52,51 @@ static const u16 wm8776_reg[WM8776_CACHEREGNUM] = { 0xa6, 0x01, 0x01 }; +/* + * read wm8776 register cache + */ +static inline unsigned int wm8776_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8776_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8776 register cache + */ +static inline void wm8776_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8776_CACHEREGNUM) + return; + cache[reg] = value; +} + +/* + * write to the WM8776 register space + */ +static int wm8776_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8776_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + static int wm8776_reset(struct snd_soc_codec *codec) { - return snd_soc_write(codec, WM8776_RESET, 0); + return wm8776_write(codec, WM8776_RESET, 0); } static const DECLARE_TLV_DB_SCALE(hp_tlv, -12100, 100, 1); @@ -481,8 +523,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8776 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8776); -static int wm8776_register(struct wm8776_priv *wm8776, - enum snd_soc_control_type control) +static int wm8776_register(struct wm8776_priv *wm8776) { int ret, i; struct snd_soc_codec *codec = &wm8776->codec; @@ -500,6 +541,8 @@ static int wm8776_register(struct wm8776_priv *wm8776, codec->private_data = wm8776; codec->name = "WM8776"; codec->owner = THIS_MODULE; + codec->read = wm8776_read_reg_cache; + codec->write = wm8776_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8776_set_bias_level; codec->dai = wm8776_dai; @@ -509,12 +552,6 @@ static int wm8776_register(struct wm8776_priv *wm8776, memcpy(codec->reg_cache, wm8776_reg, sizeof(wm8776_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - for (i = 0; i < ARRAY_SIZE(wm8776_dai); i++) wm8776_dai[i].dev = codec->dev; @@ -604,7 +641,7 @@ static int __devinit wm8776_spi_probe(struct spi_device *spi) dev_set_drvdata(&spi->dev, wm8776); - return wm8776_register(wm8776, SND_SOC_SPI); + return wm8776_register(wm8776); } static int __devexit wm8776_spi_remove(struct spi_device *spi) @@ -663,7 +700,7 @@ static __devinit int wm8776_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm8776_register(wm8776, SND_SOC_I2C); + return wm8776_register(wm8776); } static __devexit int wm8776_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/codecs/wm8900.c b/trunk/sound/soc/codecs/wm8900.c index 5e9c855c0036..ac308993ac5a 100644 --- a/trunk/sound/soc/codecs/wm8900.c +++ b/trunk/sound/soc/codecs/wm8900.c @@ -183,20 +183,111 @@ static const u16 wm8900_reg_defaults[WM8900_MAXREG] = { /* Remaining registers all zero */ }; -static int wm8900_volatile_register(unsigned int reg) +/* + * read wm8900 register cache + */ +static inline unsigned int wm8900_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + BUG_ON(reg >= WM8900_MAXREG); + + if (reg == WM8900_REG_ID) + return 0; + + return cache[reg]; +} + +/* + * write wm8900 register cache + */ +static inline void wm8900_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + + BUG_ON(reg >= WM8900_MAXREG); + + cache[reg] = value; +} + +/* + * write to the WM8900 register space + */ +static int wm8900_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + + if (value == wm8900_read_reg_cache(codec, reg)) + return 0; + + /* data is + * D15..D9 WM8900 register offset + * D8...D0 register data + */ + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0x00ff; + + wm8900_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + +/* + * Read from the wm8900. + */ +static unsigned int wm8900_chip_read(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + BUG_ON(reg != WM8900_REG_ID && reg != WM8900_REG_POWER1); + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + printk(KERN_CRIT "i2c_transfer returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +/* + * Read from the WM8900 register space. Most registers can't be read + * and are therefore supplied from cache. + */ +static unsigned int wm8900_read(struct snd_soc_codec *codec, unsigned int reg) { switch (reg) { case WM8900_REG_ID: - case WM8900_REG_POWER1: - return 1; + return wm8900_chip_read(codec, reg); default: - return 0; + return wm8900_read_reg_cache(codec, reg); } } static void wm8900_reset(struct snd_soc_codec *codec) { - snd_soc_write(codec, WM8900_REG_RESET, 0); + wm8900_write(codec, WM8900_REG_RESET, 0); memcpy(codec->reg_cache, wm8900_reg_defaults, sizeof(codec->reg_cache)); @@ -206,14 +297,14 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 hpctl1 = snd_soc_read(codec, WM8900_REG_HPCTL1); + u16 hpctl1 = wm8900_read(codec, WM8900_REG_HPCTL1); switch (event) { case SND_SOC_DAPM_PRE_PMU: /* Clamp headphone outputs */ hpctl1 = WM8900_REG_HPCTL1_HP_CLAMP_IP | WM8900_REG_HPCTL1_HP_CLAMP_OP; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); break; case SND_SOC_DAPM_POST_PMU: @@ -222,41 +313,41 @@ static int wm8900_hp_event(struct snd_soc_dapm_widget *w, hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT | WM8900_REG_HPCTL1_HP_SHORT2 | WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); msleep(400); /* Enable the output stage */ hpctl1 &= ~WM8900_REG_HPCTL1_HP_CLAMP_OP; hpctl1 |= WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); /* Remove the shorts */ hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT2; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); hpctl1 &= ~WM8900_REG_HPCTL1_HP_SHORT; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); break; case SND_SOC_DAPM_PRE_PMD: /* Short the output */ hpctl1 |= WM8900_REG_HPCTL1_HP_SHORT; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); /* Disable the output stage */ hpctl1 &= ~WM8900_REG_HPCTL1_HP_OPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); /* Clamp the outputs and power down input */ hpctl1 |= WM8900_REG_HPCTL1_HP_CLAMP_IP | WM8900_REG_HPCTL1_HP_CLAMP_OP; hpctl1 &= ~WM8900_REG_HPCTL1_HP_IPSTAGE_ENA; - snd_soc_write(codec, WM8900_REG_HPCTL1, hpctl1); + wm8900_write(codec, WM8900_REG_HPCTL1, hpctl1); break; case SND_SOC_DAPM_POST_PMD: /* Disable everything */ - snd_soc_write(codec, WM8900_REG_HPCTL1, 0); + wm8900_write(codec, WM8900_REG_HPCTL1, 0); break; default: @@ -632,7 +723,7 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = socdev->card->codec; u16 reg; - reg = snd_soc_read(codec, WM8900_REG_AUDIO1) & ~0x60; + reg = wm8900_read(codec, WM8900_REG_AUDIO1) & ~0x60; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -650,17 +741,17 @@ static int wm8900_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_soc_write(codec, WM8900_REG_AUDIO1, reg); + wm8900_write(codec, WM8900_REG_AUDIO1, reg); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - reg = snd_soc_read(codec, WM8900_REG_DACCTRL); + reg = wm8900_read(codec, WM8900_REG_DACCTRL); if (params_rate(params) <= 24000) reg |= WM8900_REG_DACCTRL_DAC_SB_FILT; else reg &= ~WM8900_REG_DACCTRL_DAC_SB_FILT; - snd_soc_write(codec, WM8900_REG_DACCTRL, reg); + wm8900_write(codec, WM8900_REG_DACCTRL, reg); } return 0; @@ -754,18 +845,18 @@ static int wm8900_set_fll(struct snd_soc_codec *codec, return 0; /* The digital side should be disabled during any change. */ - reg = snd_soc_read(codec, WM8900_REG_POWER1); - snd_soc_write(codec, WM8900_REG_POWER1, + reg = wm8900_read(codec, WM8900_REG_POWER1); + wm8900_write(codec, WM8900_REG_POWER1, reg & (~WM8900_REG_POWER1_FLL_ENA)); /* Disable the FLL? */ if (!freq_in || !freq_out) { - reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); - snd_soc_write(codec, WM8900_REG_CLOCKING1, + reg = wm8900_read(codec, WM8900_REG_CLOCKING1); + wm8900_write(codec, WM8900_REG_CLOCKING1, reg & (~WM8900_REG_CLOCKING1_MCLK_SRC)); - reg = snd_soc_read(codec, WM8900_REG_FLLCTL1); - snd_soc_write(codec, WM8900_REG_FLLCTL1, + reg = wm8900_read(codec, WM8900_REG_FLLCTL1); + wm8900_write(codec, WM8900_REG_FLLCTL1, reg & (~WM8900_REG_FLLCTL1_OSC_ENA)); wm8900->fll_in = freq_in; @@ -782,33 +873,33 @@ static int wm8900_set_fll(struct snd_soc_codec *codec, /* The osclilator *MUST* be enabled before we enable the * digital circuit. */ - snd_soc_write(codec, WM8900_REG_FLLCTL1, + wm8900_write(codec, WM8900_REG_FLLCTL1, fll_div.fll_ratio | WM8900_REG_FLLCTL1_OSC_ENA); - snd_soc_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); - snd_soc_write(codec, WM8900_REG_FLLCTL5, + wm8900_write(codec, WM8900_REG_FLLCTL4, fll_div.n >> 5); + wm8900_write(codec, WM8900_REG_FLLCTL5, (fll_div.fllclk_div << 6) | (fll_div.n & 0x1f)); if (fll_div.k) { - snd_soc_write(codec, WM8900_REG_FLLCTL2, + wm8900_write(codec, WM8900_REG_FLLCTL2, (fll_div.k >> 8) | 0x100); - snd_soc_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); + wm8900_write(codec, WM8900_REG_FLLCTL3, fll_div.k & 0xff); } else - snd_soc_write(codec, WM8900_REG_FLLCTL2, 0); + wm8900_write(codec, WM8900_REG_FLLCTL2, 0); if (fll_div.fll_slow_lock_ref) - snd_soc_write(codec, WM8900_REG_FLLCTL6, + wm8900_write(codec, WM8900_REG_FLLCTL6, WM8900_REG_FLLCTL6_FLL_SLOW_LOCK_REF); else - snd_soc_write(codec, WM8900_REG_FLLCTL6, 0); + wm8900_write(codec, WM8900_REG_FLLCTL6, 0); - reg = snd_soc_read(codec, WM8900_REG_POWER1); - snd_soc_write(codec, WM8900_REG_POWER1, + reg = wm8900_read(codec, WM8900_REG_POWER1); + wm8900_write(codec, WM8900_REG_POWER1, reg | WM8900_REG_POWER1_FLL_ENA); reenable: - reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); - snd_soc_write(codec, WM8900_REG_CLOCKING1, + reg = wm8900_read(codec, WM8900_REG_CLOCKING1); + wm8900_write(codec, WM8900_REG_CLOCKING1, reg | WM8900_REG_CLOCKING1_MCLK_SRC); return 0; @@ -828,38 +919,38 @@ static int wm8900_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8900_BCLK_DIV: - reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); - snd_soc_write(codec, WM8900_REG_CLOCKING1, + reg = wm8900_read(codec, WM8900_REG_CLOCKING1); + wm8900_write(codec, WM8900_REG_CLOCKING1, div | (reg & WM8900_REG_CLOCKING1_BCLK_MASK)); break; case WM8900_OPCLK_DIV: - reg = snd_soc_read(codec, WM8900_REG_CLOCKING1); - snd_soc_write(codec, WM8900_REG_CLOCKING1, + reg = wm8900_read(codec, WM8900_REG_CLOCKING1); + wm8900_write(codec, WM8900_REG_CLOCKING1, div | (reg & WM8900_REG_CLOCKING1_OPCLK_MASK)); break; case WM8900_DAC_LRCLK: - reg = snd_soc_read(codec, WM8900_REG_AUDIO4); - snd_soc_write(codec, WM8900_REG_AUDIO4, + reg = wm8900_read(codec, WM8900_REG_AUDIO4); + wm8900_write(codec, WM8900_REG_AUDIO4, div | (reg & WM8900_LRC_MASK)); break; case WM8900_ADC_LRCLK: - reg = snd_soc_read(codec, WM8900_REG_AUDIO3); - snd_soc_write(codec, WM8900_REG_AUDIO3, + reg = wm8900_read(codec, WM8900_REG_AUDIO3); + wm8900_write(codec, WM8900_REG_AUDIO3, div | (reg & WM8900_LRC_MASK)); break; case WM8900_DAC_CLKDIV: - reg = snd_soc_read(codec, WM8900_REG_CLOCKING2); - snd_soc_write(codec, WM8900_REG_CLOCKING2, + reg = wm8900_read(codec, WM8900_REG_CLOCKING2); + wm8900_write(codec, WM8900_REG_CLOCKING2, div | (reg & WM8900_REG_CLOCKING2_DAC_CLKDIV)); break; case WM8900_ADC_CLKDIV: - reg = snd_soc_read(codec, WM8900_REG_CLOCKING2); - snd_soc_write(codec, WM8900_REG_CLOCKING2, + reg = wm8900_read(codec, WM8900_REG_CLOCKING2); + wm8900_write(codec, WM8900_REG_CLOCKING2, div | (reg & WM8900_REG_CLOCKING2_ADC_CLKDIV)); break; case WM8900_LRCLK_MODE: - reg = snd_soc_read(codec, WM8900_REG_DACCTRL); - snd_soc_write(codec, WM8900_REG_DACCTRL, + reg = wm8900_read(codec, WM8900_REG_DACCTRL); + wm8900_write(codec, WM8900_REG_DACCTRL, div | (reg & WM8900_REG_DACCTRL_AIF_LRCLKRATE)); break; default: @@ -876,10 +967,10 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; unsigned int clocking1, aif1, aif3, aif4; - clocking1 = snd_soc_read(codec, WM8900_REG_CLOCKING1); - aif1 = snd_soc_read(codec, WM8900_REG_AUDIO1); - aif3 = snd_soc_read(codec, WM8900_REG_AUDIO3); - aif4 = snd_soc_read(codec, WM8900_REG_AUDIO4); + clocking1 = wm8900_read(codec, WM8900_REG_CLOCKING1); + aif1 = wm8900_read(codec, WM8900_REG_AUDIO1); + aif3 = wm8900_read(codec, WM8900_REG_AUDIO3); + aif4 = wm8900_read(codec, WM8900_REG_AUDIO4); /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -975,10 +1066,10 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8900_REG_CLOCKING1, clocking1); - snd_soc_write(codec, WM8900_REG_AUDIO1, aif1); - snd_soc_write(codec, WM8900_REG_AUDIO3, aif3); - snd_soc_write(codec, WM8900_REG_AUDIO4, aif4); + wm8900_write(codec, WM8900_REG_CLOCKING1, clocking1); + wm8900_write(codec, WM8900_REG_AUDIO1, aif1); + wm8900_write(codec, WM8900_REG_AUDIO3, aif3); + wm8900_write(codec, WM8900_REG_AUDIO4, aif4); return 0; } @@ -988,14 +1079,14 @@ static int wm8900_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; u16 reg; - reg = snd_soc_read(codec, WM8900_REG_DACCTRL); + reg = wm8900_read(codec, WM8900_REG_DACCTRL); if (mute) reg |= WM8900_REG_DACCTRL_MUTE; else reg &= ~WM8900_REG_DACCTRL_MUTE; - snd_soc_write(codec, WM8900_REG_DACCTRL, reg); + wm8900_write(codec, WM8900_REG_DACCTRL, reg); return 0; } @@ -1044,11 +1135,11 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: /* Enable thermal shutdown */ - reg = snd_soc_read(codec, WM8900_REG_GPIO); - snd_soc_write(codec, WM8900_REG_GPIO, + reg = wm8900_read(codec, WM8900_REG_GPIO); + wm8900_write(codec, WM8900_REG_GPIO, reg | WM8900_REG_GPIO_TEMP_ENA); - reg = snd_soc_read(codec, WM8900_REG_ADDCTL); - snd_soc_write(codec, WM8900_REG_ADDCTL, + reg = wm8900_read(codec, WM8900_REG_ADDCTL); + wm8900_write(codec, WM8900_REG_ADDCTL, reg | WM8900_REG_ADDCTL_TEMP_SD); break; @@ -1059,69 +1150,69 @@ static int wm8900_set_bias_level(struct snd_soc_codec *codec, /* Charge capacitors if initial power up */ if (codec->bias_level == SND_SOC_BIAS_OFF) { /* STARTUP_BIAS_ENA on */ - snd_soc_write(codec, WM8900_REG_POWER1, + wm8900_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA); /* Startup bias mode */ - snd_soc_write(codec, WM8900_REG_ADDCTL, + wm8900_write(codec, WM8900_REG_ADDCTL, WM8900_REG_ADDCTL_BIAS_SRC | WM8900_REG_ADDCTL_VMID_SOFTST); /* VMID 2x50k */ - snd_soc_write(codec, WM8900_REG_POWER1, + wm8900_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA | 0x1); /* Allow capacitors to charge */ schedule_timeout_interruptible(msecs_to_jiffies(400)); /* Enable bias */ - snd_soc_write(codec, WM8900_REG_POWER1, + wm8900_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA | WM8900_REG_POWER1_BIAS_ENA | 0x1); - snd_soc_write(codec, WM8900_REG_ADDCTL, 0); + wm8900_write(codec, WM8900_REG_ADDCTL, 0); - snd_soc_write(codec, WM8900_REG_POWER1, + wm8900_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_BIAS_ENA | 0x1); } - reg = snd_soc_read(codec, WM8900_REG_POWER1); - snd_soc_write(codec, WM8900_REG_POWER1, + reg = wm8900_read(codec, WM8900_REG_POWER1); + wm8900_write(codec, WM8900_REG_POWER1, (reg & WM8900_REG_POWER1_FLL_ENA) | WM8900_REG_POWER1_BIAS_ENA | 0x1); - snd_soc_write(codec, WM8900_REG_POWER2, + wm8900_write(codec, WM8900_REG_POWER2, WM8900_REG_POWER2_SYSCLK_ENA); - snd_soc_write(codec, WM8900_REG_POWER3, 0); + wm8900_write(codec, WM8900_REG_POWER3, 0); break; case SND_SOC_BIAS_OFF: /* Startup bias enable */ - reg = snd_soc_read(codec, WM8900_REG_POWER1); - snd_soc_write(codec, WM8900_REG_POWER1, + reg = wm8900_read(codec, WM8900_REG_POWER1); + wm8900_write(codec, WM8900_REG_POWER1, reg & WM8900_REG_POWER1_STARTUP_BIAS_ENA); - snd_soc_write(codec, WM8900_REG_ADDCTL, + wm8900_write(codec, WM8900_REG_ADDCTL, WM8900_REG_ADDCTL_BIAS_SRC | WM8900_REG_ADDCTL_VMID_SOFTST); /* Discharge caps */ - snd_soc_write(codec, WM8900_REG_POWER1, + wm8900_write(codec, WM8900_REG_POWER1, WM8900_REG_POWER1_STARTUP_BIAS_ENA); schedule_timeout_interruptible(msecs_to_jiffies(500)); /* Remove clamp */ - snd_soc_write(codec, WM8900_REG_HPCTL1, 0); + wm8900_write(codec, WM8900_REG_HPCTL1, 0); /* Power down */ - snd_soc_write(codec, WM8900_REG_ADDCTL, 0); - snd_soc_write(codec, WM8900_REG_POWER1, 0); - snd_soc_write(codec, WM8900_REG_POWER2, 0); - snd_soc_write(codec, WM8900_REG_POWER3, 0); + wm8900_write(codec, WM8900_REG_ADDCTL, 0); + wm8900_write(codec, WM8900_REG_POWER1, 0); + wm8900_write(codec, WM8900_REG_POWER2, 0); + wm8900_write(codec, WM8900_REG_POWER3, 0); /* Need to let things settle before stopping the clock * to ensure that restart works, see "Stopping the * master clock" in the datasheet. */ schedule_timeout_interruptible(msecs_to_jiffies(1)); - snd_soc_write(codec, WM8900_REG_POWER2, + wm8900_write(codec, WM8900_REG_POWER2, WM8900_REG_POWER2_SYSCLK_ENA); break; } @@ -1184,7 +1275,7 @@ static int wm8900_resume(struct platform_device *pdev) if (cache) { for (i = 0; i < WM8900_MAXREG; i++) - snd_soc_write(codec, i, cache[i]); + wm8900_write(codec, i, cache[i]); kfree(cache); } else dev_err(&pdev->dev, "Unable to allocate register cache\n"); @@ -1217,20 +1308,16 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, codec->name = "WM8900"; codec->owner = THIS_MODULE; + codec->read = wm8900_read; + codec->write = wm8900_write; codec->dai = &wm8900_dai; codec->num_dai = 1; + codec->hw_write = (hw_write_t)i2c_master_send; codec->control_data = i2c; codec->set_bias_level = wm8900_set_bias_level; - codec->volatile_register = wm8900_volatile_register; codec->dev = &i2c->dev; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - - reg = snd_soc_read(codec, WM8900_REG_ID); + reg = wm8900_read(codec, WM8900_REG_ID); if (reg != 0x8900) { dev_err(&i2c->dev, "Device is not a WM8900 - ID %x\n", reg); ret = -ENODEV; @@ -1238,7 +1325,7 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, } /* Read back from the chip */ - reg = snd_soc_read(codec, WM8900_REG_POWER1); + reg = wm8900_chip_read(codec, WM8900_REG_POWER1); reg = (reg >> 12) & 0xf; dev_info(&i2c->dev, "WM8900 revision %d\n", reg); @@ -1248,29 +1335,29 @@ static __devinit int wm8900_i2c_probe(struct i2c_client *i2c, wm8900_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the volume update bits */ - snd_soc_write(codec, WM8900_REG_LINVOL, - snd_soc_read(codec, WM8900_REG_LINVOL) | 0x100); - snd_soc_write(codec, WM8900_REG_RINVOL, - snd_soc_read(codec, WM8900_REG_RINVOL) | 0x100); - snd_soc_write(codec, WM8900_REG_LOUT1CTL, - snd_soc_read(codec, WM8900_REG_LOUT1CTL) | 0x100); - snd_soc_write(codec, WM8900_REG_ROUT1CTL, - snd_soc_read(codec, WM8900_REG_ROUT1CTL) | 0x100); - snd_soc_write(codec, WM8900_REG_LOUT2CTL, - snd_soc_read(codec, WM8900_REG_LOUT2CTL) | 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); + wm8900_write(codec, WM8900_REG_LINVOL, + wm8900_read(codec, WM8900_REG_LINVOL) | 0x100); + wm8900_write(codec, WM8900_REG_RINVOL, + wm8900_read(codec, WM8900_REG_RINVOL) | 0x100); + wm8900_write(codec, WM8900_REG_LOUT1CTL, + wm8900_read(codec, WM8900_REG_LOUT1CTL) | 0x100); + wm8900_write(codec, WM8900_REG_ROUT1CTL, + wm8900_read(codec, WM8900_REG_ROUT1CTL) | 0x100); + wm8900_write(codec, WM8900_REG_LOUT2CTL, + wm8900_read(codec, WM8900_REG_LOUT2CTL) | 0x100); + wm8900_write(codec, WM8900_REG_ROUT2CTL, + wm8900_read(codec, WM8900_REG_ROUT2CTL) | 0x100); + wm8900_write(codec, WM8900_REG_LDAC_DV, + wm8900_read(codec, WM8900_REG_LDAC_DV) | 0x100); + wm8900_write(codec, WM8900_REG_RDAC_DV, + wm8900_read(codec, WM8900_REG_RDAC_DV) | 0x100); + wm8900_write(codec, WM8900_REG_LADC_DV, + wm8900_read(codec, WM8900_REG_LADC_DV) | 0x100); + wm8900_write(codec, WM8900_REG_RADC_DV, + wm8900_read(codec, WM8900_REG_RADC_DV) | 0x100); /* Set the DAC and mixer output bias */ - snd_soc_write(codec, WM8900_REG_OUTBIASCTL, 0x81); + wm8900_write(codec, WM8900_REG_OUTBIASCTL, 0x81); wm8900_dai.dev = &i2c->dev; diff --git a/trunk/sound/soc/codecs/wm8903.c b/trunk/sound/soc/codecs/wm8903.c index fe1307b500cf..c9baeae3e275 100644 --- a/trunk/sound/soc/codecs/wm8903.c +++ b/trunk/sound/soc/codecs/wm8903.c @@ -225,20 +225,96 @@ struct wm8903_priv { struct snd_pcm_substream *slave_substream; }; -static int wm8903_volatile_register(unsigned int reg) + +static unsigned int wm8903_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); + + return cache[reg]; +} + +static unsigned int wm8903_hw_read(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + pr_err("i2c_transfer returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +static unsigned int wm8903_read(struct snd_soc_codec *codec, + unsigned int reg) { switch (reg) { case WM8903_SW_RESET_AND_ID: case WM8903_REVISION_NUMBER: case WM8903_INTERRUPT_STATUS_1: case WM8903_WRITE_SEQUENCER_4: - return 1; + return wm8903_hw_read(codec, reg); default: - return 0; + return wm8903_read_reg_cache(codec, reg); } } +static void wm8903_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + + BUG_ON(reg >= ARRAY_SIZE(wm8903_reg_defaults)); + + switch (reg) { + case WM8903_SW_RESET_AND_ID: + case WM8903_REVISION_NUMBER: + break; + + default: + cache[reg] = value; + break; + } +} + +static int wm8903_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + + wm8903_write_reg_cache(codec, reg, value); + + /* Data format is 1 byte of address followed by 2 bytes of data */ + data[0] = reg; + data[1] = (value >> 8) & 0xff; + data[2] = value & 0xff; + + if (codec->hw_write(codec->control_data, data, 3) == 2) + return 0; + else + return -EIO; +} + static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) { u16 reg[5]; @@ -247,13 +323,13 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) BUG_ON(start > 48); /* Enable the sequencer */ - reg[0] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_0); + reg[0] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_0); reg[0] |= WM8903_WSEQ_ENA; - snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); + wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0]); dev_dbg(&i2c->dev, "Starting sequence at %d\n", start); - snd_soc_write(codec, WM8903_WRITE_SEQUENCER_3, + wm8903_write(codec, WM8903_WRITE_SEQUENCER_3, start | WM8903_WSEQ_START); /* Wait for it to complete. If we have the interrupt wired up then @@ -263,13 +339,13 @@ static int wm8903_run_sequence(struct snd_soc_codec *codec, unsigned int start) do { msleep(10); - reg[4] = snd_soc_read(codec, WM8903_WRITE_SEQUENCER_4); + reg[4] = wm8903_read(codec, WM8903_WRITE_SEQUENCER_4); } while (reg[4] & WM8903_WSEQ_BUSY); dev_dbg(&i2c->dev, "Sequence complete\n"); /* Disable the sequencer again */ - snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, + wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, reg[0] & ~WM8903_WSEQ_ENA); return 0; @@ -281,12 +357,12 @@ static void wm8903_sync_reg_cache(struct snd_soc_codec *codec, u16 *cache) /* There really ought to be something better we can do here :/ */ for (i = 0; i < ARRAY_SIZE(wm8903_reg_defaults); i++) - cache[i] = codec->hw_read(codec, i); + cache[i] = wm8903_hw_read(codec, i); } static void wm8903_reset(struct snd_soc_codec *codec) { - snd_soc_write(codec, WM8903_SW_RESET_AND_ID, 0); + wm8903_write(codec, WM8903_SW_RESET_AND_ID, 0); memcpy(codec->reg_cache, wm8903_reg_defaults, sizeof(wm8903_reg_defaults)); } @@ -347,52 +423,52 @@ static int wm8903_output_event(struct snd_soc_dapm_widget *w, } if (event & SND_SOC_DAPM_PRE_PMU) { - val = snd_soc_read(codec, reg); + val = wm8903_read(codec, reg); /* Short the output */ val &= ~(WM8903_OUTPUT_SHORT << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); } if (event & SND_SOC_DAPM_POST_PMU) { - val = snd_soc_read(codec, reg); + val = wm8903_read(codec, reg); val |= (WM8903_OUTPUT_IN << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); val |= (WM8903_OUTPUT_INT << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); /* Turn on the output ENA_OUTP */ val |= (WM8903_OUTPUT_OUT << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); /* Enable the DC servo */ - dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0); + dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); dcs_reg |= dcs_bit; - snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg); + wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); /* Remove the short */ val |= (WM8903_OUTPUT_SHORT << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); } if (event & SND_SOC_DAPM_PRE_PMD) { - val = snd_soc_read(codec, reg); + val = wm8903_read(codec, reg); /* Short the output */ val &= ~(WM8903_OUTPUT_SHORT << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); /* Disable the DC servo */ - dcs_reg = snd_soc_read(codec, WM8903_DC_SERVO_0); + dcs_reg = wm8903_read(codec, WM8903_DC_SERVO_0); dcs_reg &= ~dcs_bit; - snd_soc_write(codec, WM8903_DC_SERVO_0, dcs_reg); + wm8903_write(codec, WM8903_DC_SERVO_0, dcs_reg); /* Then disable the intermediate and output stages */ val &= ~((WM8903_OUTPUT_OUT | WM8903_OUTPUT_INT | WM8903_OUTPUT_IN) << shift); - snd_soc_write(codec, reg, val); + wm8903_write(codec, reg, val); } return 0; @@ -416,13 +492,13 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, u16 reg; int ret; - reg = snd_soc_read(codec, WM8903_CLASS_W_0); + reg = wm8903_read(codec, WM8903_CLASS_W_0); /* Turn it off if we're about to enable bypass */ if (ucontrol->value.integer.value[0]) { if (wm8903->class_w_users == 0) { dev_dbg(&i2c->dev, "Disabling Class W\n"); - snd_soc_write(codec, WM8903_CLASS_W_0, reg & + wm8903_write(codec, WM8903_CLASS_W_0, reg & ~(WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V)); } wm8903->class_w_users++; @@ -435,7 +511,7 @@ static int wm8903_class_w_put(struct snd_kcontrol *kcontrol, if (!ucontrol->value.integer.value[0]) { if (wm8903->class_w_users == 1) { dev_dbg(&i2c->dev, "Enabling Class W\n"); - snd_soc_write(codec, WM8903_CLASS_W_0, reg | + wm8903_write(codec, WM8903_CLASS_W_0, reg | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); } wm8903->class_w_users--; @@ -933,55 +1009,55 @@ static int wm8903_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: case SND_SOC_BIAS_PREPARE: - reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0); + reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); reg &= ~(WM8903_VMID_RES_MASK); reg |= WM8903_VMID_RES_50K; - snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); + wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { - snd_soc_write(codec, WM8903_CLOCK_RATES_2, + wm8903_write(codec, WM8903_CLOCK_RATES_2, WM8903_CLK_SYS_ENA); /* Change DC servo dither level in startup sequence */ - snd_soc_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); - snd_soc_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); - snd_soc_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); + wm8903_write(codec, WM8903_WRITE_SEQUENCER_0, 0x11); + wm8903_write(codec, WM8903_WRITE_SEQUENCER_1, 0x1257); + wm8903_write(codec, WM8903_WRITE_SEQUENCER_2, 0x2); wm8903_run_sequence(codec, 0); wm8903_sync_reg_cache(codec, codec->reg_cache); /* Enable low impedence charge pump output */ - reg = snd_soc_read(codec, + reg = wm8903_read(codec, WM8903_CONTROL_INTERFACE_TEST_1); - snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, + wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, reg | WM8903_TEST_KEY); - reg2 = snd_soc_read(codec, WM8903_CHARGE_PUMP_TEST_1); - snd_soc_write(codec, WM8903_CHARGE_PUMP_TEST_1, + reg2 = wm8903_read(codec, WM8903_CHARGE_PUMP_TEST_1); + wm8903_write(codec, WM8903_CHARGE_PUMP_TEST_1, reg2 | WM8903_CP_SW_KELVIN_MODE_MASK); - snd_soc_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, + wm8903_write(codec, WM8903_CONTROL_INTERFACE_TEST_1, reg); /* By default no bypass paths are enabled so * enable Class W support. */ dev_dbg(&i2c->dev, "Enabling Class W\n"); - snd_soc_write(codec, WM8903_CLASS_W_0, reg | + wm8903_write(codec, WM8903_CLASS_W_0, reg | WM8903_CP_DYN_FREQ | WM8903_CP_DYN_V); } - reg = snd_soc_read(codec, WM8903_VMID_CONTROL_0); + reg = wm8903_read(codec, WM8903_VMID_CONTROL_0); reg &= ~(WM8903_VMID_RES_MASK); reg |= WM8903_VMID_RES_250K; - snd_soc_write(codec, WM8903_VMID_CONTROL_0, reg); + wm8903_write(codec, WM8903_VMID_CONTROL_0, reg); break; case SND_SOC_BIAS_OFF: wm8903_run_sequence(codec, 32); - reg = snd_soc_read(codec, WM8903_CLOCK_RATES_2); + reg = wm8903_read(codec, WM8903_CLOCK_RATES_2); reg &= ~WM8903_CLK_SYS_ENA; - snd_soc_write(codec, WM8903_CLOCK_RATES_2, reg); + wm8903_write(codec, WM8903_CLOCK_RATES_2, reg); break; } @@ -1005,7 +1081,7 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1); + u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); aif1 &= ~(WM8903_LRCLK_DIR | WM8903_BCLK_DIR | WM8903_AIF_FMT_MASK | WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV); @@ -1083,7 +1159,7 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); + wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); return 0; } @@ -1093,14 +1169,14 @@ static int wm8903_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; u16 reg; - reg = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); + reg = wm8903_read(codec, WM8903_DAC_DIGITAL_1); if (mute) reg |= WM8903_DAC_MUTE; else reg &= ~WM8903_DAC_MUTE; - snd_soc_write(codec, WM8903_DAC_DIGITAL_1, reg); + wm8903_write(codec, WM8903_DAC_DIGITAL_1, reg); return 0; } @@ -1290,12 +1366,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, int cur_val; int clk_sys; - u16 aif1 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_1); - u16 aif2 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_2); - u16 aif3 = snd_soc_read(codec, WM8903_AUDIO_INTERFACE_3); - u16 clock0 = snd_soc_read(codec, WM8903_CLOCK_RATES_0); - u16 clock1 = snd_soc_read(codec, WM8903_CLOCK_RATES_1); - u16 dac_digital1 = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); + u16 aif1 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_1); + u16 aif2 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_2); + u16 aif3 = wm8903_read(codec, WM8903_AUDIO_INTERFACE_3); + u16 clock0 = wm8903_read(codec, WM8903_CLOCK_RATES_0); + u16 clock1 = wm8903_read(codec, WM8903_CLOCK_RATES_1); + u16 dac_digital1 = wm8903_read(codec, WM8903_DAC_DIGITAL_1); if (substream == wm8903->slave_substream) { dev_dbg(&i2c->dev, "Ignoring hw_params for slave substream\n"); @@ -1427,12 +1503,12 @@ static int wm8903_hw_params(struct snd_pcm_substream *substream, aif2 |= bclk_divs[bclk_div].div; aif3 |= bclk / fs; - snd_soc_write(codec, WM8903_CLOCK_RATES_0, clock0); - snd_soc_write(codec, WM8903_CLOCK_RATES_1, clock1); - snd_soc_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); - snd_soc_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); - snd_soc_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); - snd_soc_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); + wm8903_write(codec, WM8903_CLOCK_RATES_0, clock0); + wm8903_write(codec, WM8903_CLOCK_RATES_1, clock1); + wm8903_write(codec, WM8903_AUDIO_INTERFACE_1, aif1); + wm8903_write(codec, WM8903_AUDIO_INTERFACE_2, aif2); + wm8903_write(codec, WM8903_AUDIO_INTERFACE_3, aif3); + wm8903_write(codec, WM8903_DAC_DIGITAL_1, dac_digital1); return 0; } @@ -1517,7 +1593,7 @@ static int wm8903_resume(struct platform_device *pdev) if (tmp_cache) { for (i = 2; i < ARRAY_SIZE(wm8903_reg_defaults); i++) if (tmp_cache[i] != reg_cache[i]) - snd_soc_write(codec, i, tmp_cache[i]); + wm8903_write(codec, i, tmp_cache[i]); } else { dev_err(&i2c->dev, "Failed to allocate temporary cache\n"); } @@ -1548,6 +1624,9 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; codec->name = "WM8903"; codec->owner = THIS_MODULE; + codec->read = wm8903_read; + codec->write = wm8903_write; + codec->hw_write = (hw_write_t)i2c_master_send; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8903_set_bias_level; codec->dai = &wm8903_dai; @@ -1555,25 +1634,18 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, codec->reg_cache_size = ARRAY_SIZE(wm8903->reg_cache); codec->reg_cache = &wm8903->reg_cache[0]; codec->private_data = wm8903; - codec->volatile_register = wm8903_volatile_register; i2c_set_clientdata(i2c, codec); codec->control_data = i2c; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); - if (ret != 0) { - dev_err(&i2c->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - - val = snd_soc_read(codec, WM8903_SW_RESET_AND_ID); + val = wm8903_hw_read(codec, WM8903_SW_RESET_AND_ID); if (val != wm8903_reg_defaults[WM8903_SW_RESET_AND_ID]) { dev_err(&i2c->dev, "Device with ID register %x is not a WM8903\n", val); return -ENODEV; } - val = snd_soc_read(codec, WM8903_REVISION_NUMBER); + val = wm8903_read(codec, WM8903_REVISION_NUMBER); dev_info(&i2c->dev, "WM8903 revision %d\n", val & WM8903_CHIP_REV_MASK); @@ -1583,35 +1655,35 @@ static __devinit int wm8903_i2c_probe(struct i2c_client *i2c, wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch volume update bits */ - val = snd_soc_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); + val = wm8903_read(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT); val |= WM8903_ADCVU; - snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); - snd_soc_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); + wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_LEFT, val); + wm8903_write(codec, WM8903_ADC_DIGITAL_VOLUME_RIGHT, val); - val = snd_soc_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); + val = wm8903_read(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT); val |= WM8903_DACVU; - snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); - snd_soc_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); + wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_LEFT, val); + wm8903_write(codec, WM8903_DAC_DIGITAL_VOLUME_RIGHT, val); - val = snd_soc_read(codec, WM8903_ANALOGUE_OUT1_LEFT); + val = wm8903_read(codec, WM8903_ANALOGUE_OUT1_LEFT); val |= WM8903_HPOUTVU; - snd_soc_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); - snd_soc_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); + wm8903_write(codec, WM8903_ANALOGUE_OUT1_LEFT, val); + wm8903_write(codec, WM8903_ANALOGUE_OUT1_RIGHT, val); - val = snd_soc_read(codec, WM8903_ANALOGUE_OUT2_LEFT); + val = wm8903_read(codec, WM8903_ANALOGUE_OUT2_LEFT); val |= WM8903_LINEOUTVU; - snd_soc_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); - snd_soc_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); + wm8903_write(codec, WM8903_ANALOGUE_OUT2_LEFT, val); + wm8903_write(codec, WM8903_ANALOGUE_OUT2_RIGHT, val); - val = snd_soc_read(codec, WM8903_ANALOGUE_OUT3_LEFT); + val = wm8903_read(codec, WM8903_ANALOGUE_OUT3_LEFT); val |= WM8903_SPKVU; - snd_soc_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); - snd_soc_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); + wm8903_write(codec, WM8903_ANALOGUE_OUT3_LEFT, val); + wm8903_write(codec, WM8903_ANALOGUE_OUT3_RIGHT, val); /* Enable DAC soft mute by default */ - val = snd_soc_read(codec, WM8903_DAC_DIGITAL_1); + val = wm8903_read(codec, WM8903_DAC_DIGITAL_1); val |= WM8903_DAC_MUTEMODE; - snd_soc_write(codec, WM8903_DAC_DIGITAL_1, val); + wm8903_write(codec, WM8903_DAC_DIGITAL_1, val); wm8903_dai.dev = &i2c->dev; wm8903_codec = codec; diff --git a/trunk/sound/soc/codecs/wm8940.c b/trunk/sound/soc/codecs/wm8940.c index da97aae475a2..b69210a77423 100644 --- a/trunk/sound/soc/codecs/wm8940.c +++ b/trunk/sound/soc/codecs/wm8940.c @@ -106,6 +106,50 @@ static u16 wm8940_reg_defaults[] = { 0x0000, /* Mono Mixer Control */ }; +static inline unsigned int wm8940_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + + if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) + return -1; + + return cache[reg]; +} + +static inline int wm8940_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + + if (reg >= ARRAY_SIZE(wm8940_reg_defaults)) + return -1; + + cache[reg] = value; + + return 0; +} + +static int wm8940_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + int ret; + u8 data[3] = { reg, + (value & 0xff00) >> 8, + (value & 0x00ff) + }; + + wm8940_write_reg_cache(codec, reg, value); + + ret = codec->hw_write(codec->control_data, data, 3); + + if (ret < 0) + return ret; + else if (ret != 3) + return -EIO; + return 0; +} + static const char *wm8940_companding[] = { "Off", "NC", "u-law", "A-law" }; static const struct soc_enum wm8940_adc_companding_enum = SOC_ENUM_SINGLE(WM8940_COMPANDINGCTL, 1, 4, wm8940_companding); @@ -304,14 +348,14 @@ static int wm8940_add_widgets(struct snd_soc_codec *codec) return ret; } -#define wm8940_reset(c) snd_soc_write(c, WM8940_SOFTRESET, 0); +#define wm8940_reset(c) wm8940_write(c, WM8940_SOFTRESET, 0); static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) { struct snd_soc_codec *codec = codec_dai->codec; - u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFE67; - u16 clk = snd_soc_read(codec, WM8940_CLOCK) & 0x1fe; + u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFE67; + u16 clk = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0x1fe; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { case SND_SOC_DAIFMT_CBM_CFM: @@ -322,7 +366,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, default: return -EINVAL; } - snd_soc_write(codec, WM8940_CLOCK, clk); + wm8940_write(codec, WM8940_CLOCK, clk); switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -355,7 +399,7 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, break; } - snd_soc_write(codec, WM8940_IFACE, iface); + wm8940_write(codec, WM8940_IFACE, iface); return 0; } @@ -367,9 +411,9 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = snd_soc_read(codec, WM8940_IFACE) & 0xFD9F; - u16 addcntrl = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFF1; - u16 companding = snd_soc_read(codec, + u16 iface = wm8940_read_reg_cache(codec, WM8940_IFACE) & 0xFD9F; + u16 addcntrl = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFF1; + u16 companding = wm8940_read_reg_cache(codec, WM8940_COMPANDINGCTL) & 0xFFDF; int ret; @@ -398,7 +442,7 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, case SNDRV_PCM_RATE_48000: break; } - ret = snd_soc_write(codec, WM8940_ADDCNTRL, addcntrl); + ret = wm8940_write(codec, WM8940_ADDCNTRL, addcntrl); if (ret) goto error_ret; @@ -418,10 +462,10 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, iface |= (3 << 5); break; } - ret = snd_soc_write(codec, WM8940_COMPANDINGCTL, companding); + ret = wm8940_write(codec, WM8940_COMPANDINGCTL, companding); if (ret) goto error_ret; - ret = snd_soc_write(codec, WM8940_IFACE, iface); + ret = wm8940_write(codec, WM8940_IFACE, iface); error_ret: return ret; @@ -430,19 +474,19 @@ static int wm8940_i2s_hw_params(struct snd_pcm_substream *substream, static int wm8940_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8940_DAC) & 0xffbf; + u16 mute_reg = wm8940_read_reg_cache(codec, WM8940_DAC) & 0xffbf; if (mute) mute_reg |= 0x40; - return snd_soc_write(codec, WM8940_DAC, mute_reg); + return wm8940_write(codec, WM8940_DAC, mute_reg); } static int wm8940_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { u16 val; - u16 pwr_reg = snd_soc_read(codec, WM8940_POWER1) & 0x1F0; + u16 pwr_reg = wm8940_read_reg_cache(codec, WM8940_POWER1) & 0x1F0; int ret = 0; switch (level) { @@ -450,26 +494,26 @@ static int wm8940_set_bias_level(struct snd_soc_codec *codec, /* ensure bufioen and biasen */ pwr_reg |= (1 << 2) | (1 << 3); /* Enable thermal shutdown */ - val = snd_soc_read(codec, WM8940_OUTPUTCTL); - ret = snd_soc_write(codec, WM8940_OUTPUTCTL, val | 0x2); + val = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); + ret = wm8940_write(codec, WM8940_OUTPUTCTL, val | 0x2); if (ret) break; /* set vmid to 75k */ - ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); break; case SND_SOC_BIAS_PREPARE: /* ensure bufioen and biasen */ pwr_reg |= (1 << 2) | (1 << 3); - ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x1); + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x1); break; case SND_SOC_BIAS_STANDBY: /* ensure bufioen and biasen */ pwr_reg |= (1 << 2) | (1 << 3); /* set vmid to 300k for standby */ - ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg | 0x2); + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg | 0x2); break; case SND_SOC_BIAS_OFF: - ret = snd_soc_write(codec, WM8940_POWER1, pwr_reg); + ret = wm8940_write(codec, WM8940_POWER1, pwr_reg); break; } @@ -543,36 +587,36 @@ static int wm8940_set_dai_pll(struct snd_soc_dai *codec_dai, u16 reg; /* Turn off PLL */ - reg = snd_soc_read(codec, WM8940_POWER1); - snd_soc_write(codec, WM8940_POWER1, reg & 0x1df); + reg = wm8940_read_reg_cache(codec, WM8940_POWER1); + wm8940_write(codec, WM8940_POWER1, reg & 0x1df); if (freq_in == 0 || freq_out == 0) { /* Clock CODEC directly from MCLK */ - reg = snd_soc_read(codec, WM8940_CLOCK); - snd_soc_write(codec, WM8940_CLOCK, reg & 0x0ff); + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); + wm8940_write(codec, WM8940_CLOCK, reg & 0x0ff); /* Pll power down */ - snd_soc_write(codec, WM8940_PLLN, (1 << 7)); + wm8940_write(codec, WM8940_PLLN, (1 << 7)); return 0; } /* Pll is followed by a frequency divide by 4 */ pll_factors(freq_out*4, freq_in); if (pll_div.k) - snd_soc_write(codec, WM8940_PLLN, + wm8940_write(codec, WM8940_PLLN, (pll_div.pre_scale << 4) | pll_div.n | (1 << 6)); else /* No factional component */ - snd_soc_write(codec, WM8940_PLLN, + wm8940_write(codec, WM8940_PLLN, (pll_div.pre_scale << 4) | pll_div.n); - snd_soc_write(codec, WM8940_PLLK1, pll_div.k >> 18); - snd_soc_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); + wm8940_write(codec, WM8940_PLLK1, pll_div.k >> 18); + wm8940_write(codec, WM8940_PLLK2, (pll_div.k >> 9) & 0x1ff); + wm8940_write(codec, WM8940_PLLK3, pll_div.k & 0x1ff); /* Enable the PLL */ - reg = snd_soc_read(codec, WM8940_POWER1); - snd_soc_write(codec, WM8940_POWER1, reg | 0x020); + reg = wm8940_read_reg_cache(codec, WM8940_POWER1); + wm8940_write(codec, WM8940_POWER1, reg | 0x020); /* Run CODEC from PLL instead of MCLK */ - reg = snd_soc_read(codec, WM8940_CLOCK); - snd_soc_write(codec, WM8940_CLOCK, reg | 0x100); + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK); + wm8940_write(codec, WM8940_CLOCK, reg | 0x100); return 0; } @@ -604,16 +648,16 @@ static int wm8940_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8940_BCLKDIV: - reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFFEF3; - ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 2)); + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFFEF3; + ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 2)); break; case WM8940_MCLKDIV: - reg = snd_soc_read(codec, WM8940_CLOCK) & 0xFF1F; - ret = snd_soc_write(codec, WM8940_CLOCK, reg | (div << 5)); + reg = wm8940_read_reg_cache(codec, WM8940_CLOCK) & 0xFF1F; + ret = wm8940_write(codec, WM8940_CLOCK, reg | (div << 5)); break; case WM8940_OPCLKDIV: - reg = snd_soc_read(codec, WM8940_ADDCNTRL) & 0xFFCF; - ret = snd_soc_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); + reg = wm8940_read_reg_cache(codec, WM8940_ADDCNTRL) & 0xFFCF; + ret = wm8940_write(codec, WM8940_ADDCNTRL, reg | (div << 4)); break; } return ret; @@ -764,8 +808,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8940 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8940); -static int wm8940_register(struct wm8940_priv *wm8940, - enum snd_soc_control_type control) +static int wm8940_register(struct wm8940_priv *wm8940) { struct wm8940_setup_data *pdata = wm8940->codec.dev->platform_data; struct snd_soc_codec *codec = &wm8940->codec; @@ -782,6 +825,8 @@ static int wm8940_register(struct wm8940_priv *wm8940, codec->private_data = wm8940; codec->name = "WM8940"; codec->owner = THIS_MODULE; + codec->read = wm8940_read_reg_cache; + codec->write = wm8940_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8940_set_bias_level; codec->dai = &wm8940_dai; @@ -789,12 +834,6 @@ static int wm8940_register(struct wm8940_priv *wm8940, codec->reg_cache_size = ARRAY_SIZE(wm8940_reg_defaults); codec->reg_cache = &wm8940->reg_cache; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); - if (ret == 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - memcpy(codec->reg_cache, wm8940_reg_defaults, sizeof(wm8940_reg_defaults)); @@ -808,15 +847,15 @@ static int wm8940_register(struct wm8940_priv *wm8940, wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - ret = snd_soc_write(codec, WM8940_POWER1, 0x180); + ret = wm8940_write(codec, WM8940_POWER1, 0x180); if (ret < 0) return ret; if (!pdata) dev_warn(codec->dev, "No platform data supplied\n"); else { - reg = snd_soc_read(codec, WM8940_OUTPUTCTL); - ret = snd_soc_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); + reg = wm8940_read_reg_cache(codec, WM8940_OUTPUTCTL); + ret = wm8940_write(codec, WM8940_OUTPUTCTL, reg | pdata->vroi); if (ret < 0) return ret; } @@ -865,7 +904,7 @@ static int wm8940_i2c_probe(struct i2c_client *i2c, codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8940_register(wm8940, SND_SOC_I2C); + return wm8940_register(wm8940); } static int __devexit wm8940_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/codecs/wm8960.c b/trunk/sound/soc/codecs/wm8960.c index f59703be61c8..d1769e6c0c44 100644 --- a/trunk/sound/soc/codecs/wm8960.c +++ b/trunk/sound/soc/codecs/wm8960.c @@ -69,7 +69,61 @@ struct wm8960_priv { struct snd_soc_codec codec; }; -#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0) +/* + * read wm8960 register cache + */ +static inline unsigned int wm8960_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg == WM8960_RESET) + return 0; + if (reg >= WM8960_CACHEREGNUM) + return -1; + return cache[reg]; +} + +/* + * write wm8960 register cache + */ +static inline void wm8960_write_reg_cache(struct snd_soc_codec *codec, + u16 reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg >= WM8960_CACHEREGNUM) + return; + cache[reg] = value; +} + +static inline unsigned int wm8960_read(struct snd_soc_codec *codec, + unsigned int reg) +{ + return wm8960_read_reg_cache(codec, reg); +} + +/* + * write to the WM8960 register space + */ +static int wm8960_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8960 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8960_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8960_reset(c) wm8960_write(c, WM8960_RESET, 0) /* enumerated controls */ static const char *wm8960_deemph[] = {"None", "32Khz", "44.1Khz", "48Khz"}; @@ -366,7 +420,7 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, } /* set iface */ - snd_soc_write(codec, WM8960_IFACE1, iface); + wm8960_write(codec, WM8960_IFACE1, iface); return 0; } @@ -377,7 +431,7 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 iface = snd_soc_read(codec, WM8960_IFACE1) & 0xfff3; + u16 iface = wm8960_read(codec, WM8960_IFACE1) & 0xfff3; /* bit size */ switch (params_format(params)) { @@ -392,19 +446,19 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, } /* set iface */ - snd_soc_write(codec, WM8960_IFACE1, iface); + wm8960_write(codec, WM8960_IFACE1, iface); return 0; } static int wm8960_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8960_DACCTL1) & 0xfff7; + u16 mute_reg = wm8960_read(codec, WM8960_DACCTL1) & 0xfff7; if (mute) - snd_soc_write(codec, WM8960_DACCTL1, mute_reg | 0x8); + wm8960_write(codec, WM8960_DACCTL1, mute_reg | 0x8); else - snd_soc_write(codec, WM8960_DACCTL1, mute_reg); + wm8960_write(codec, WM8960_DACCTL1, mute_reg); return 0; } @@ -420,16 +474,16 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* Set VMID to 2x50k */ - reg = snd_soc_read(codec, WM8960_POWER1); + reg = wm8960_read(codec, WM8960_POWER1); reg &= ~0x180; reg |= 0x80; - snd_soc_write(codec, WM8960_POWER1, reg); + wm8960_write(codec, WM8960_POWER1, reg); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable anti-pop features */ - snd_soc_write(codec, WM8960_APOP1, + wm8960_write(codec, WM8960_APOP1, WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_BUFDCOPEN | WM8960_BUFIOEN); @@ -437,43 +491,43 @@ static int wm8960_set_bias_level(struct snd_soc_codec *codec, reg = WM8960_DISOP; if (pdata) reg |= pdata->dres << 4; - snd_soc_write(codec, WM8960_APOP2, reg); + wm8960_write(codec, WM8960_APOP2, reg); msleep(400); - snd_soc_write(codec, WM8960_APOP2, 0); + wm8960_write(codec, WM8960_APOP2, 0); /* Enable & ramp VMID at 2x50k */ - reg = snd_soc_read(codec, WM8960_POWER1); + reg = wm8960_read(codec, WM8960_POWER1); reg |= 0x80; - snd_soc_write(codec, WM8960_POWER1, reg); + wm8960_write(codec, WM8960_POWER1, reg); msleep(100); /* Enable VREF */ - snd_soc_write(codec, WM8960_POWER1, reg | WM8960_VREF); + wm8960_write(codec, WM8960_POWER1, reg | WM8960_VREF); /* Disable anti-pop features */ - snd_soc_write(codec, WM8960_APOP1, WM8960_BUFIOEN); + wm8960_write(codec, WM8960_APOP1, WM8960_BUFIOEN); } /* Set VMID to 2x250k */ - reg = snd_soc_read(codec, WM8960_POWER1); + reg = wm8960_read(codec, WM8960_POWER1); reg &= ~0x180; reg |= 0x100; - snd_soc_write(codec, WM8960_POWER1, reg); + wm8960_write(codec, WM8960_POWER1, reg); break; case SND_SOC_BIAS_OFF: /* Enable anti-pop features */ - snd_soc_write(codec, WM8960_APOP1, + wm8960_write(codec, WM8960_APOP1, WM8960_POBCTRL | WM8960_SOFT_ST | WM8960_BUFDCOPEN | WM8960_BUFIOEN); /* Disable VMID and VREF, let them discharge */ - snd_soc_write(codec, WM8960_POWER1, 0); + wm8960_write(codec, WM8960_POWER1, 0); msleep(600); - snd_soc_write(codec, WM8960_APOP1, 0); + wm8960_write(codec, WM8960_APOP1, 0); break; } @@ -556,33 +610,33 @@ static int wm8960_set_dai_pll(struct snd_soc_dai *codec_dai, /* Disable the PLL: even if we are changing the frequency the * PLL needs to be disabled while we do so. */ - snd_soc_write(codec, WM8960_CLOCK1, - snd_soc_read(codec, WM8960_CLOCK1) & ~1); - snd_soc_write(codec, WM8960_POWER2, - snd_soc_read(codec, WM8960_POWER2) & ~1); + wm8960_write(codec, WM8960_CLOCK1, + wm8960_read(codec, WM8960_CLOCK1) & ~1); + wm8960_write(codec, WM8960_POWER2, + wm8960_read(codec, WM8960_POWER2) & ~1); if (!freq_in || !freq_out) return 0; - reg = snd_soc_read(codec, WM8960_PLL1) & ~0x3f; + reg = wm8960_read(codec, WM8960_PLL1) & ~0x3f; reg |= pll_div.pre_div << 4; reg |= pll_div.n; if (pll_div.k) { reg |= 0x20; - snd_soc_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); - snd_soc_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); - snd_soc_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); + wm8960_write(codec, WM8960_PLL2, (pll_div.k >> 18) & 0x3f); + wm8960_write(codec, WM8960_PLL3, (pll_div.k >> 9) & 0x1ff); + wm8960_write(codec, WM8960_PLL4, pll_div.k & 0x1ff); } - snd_soc_write(codec, WM8960_PLL1, reg); + wm8960_write(codec, WM8960_PLL1, reg); /* Turn it on */ - snd_soc_write(codec, WM8960_POWER2, - snd_soc_read(codec, WM8960_POWER2) | 1); + wm8960_write(codec, WM8960_POWER2, + wm8960_read(codec, WM8960_POWER2) | 1); msleep(250); - snd_soc_write(codec, WM8960_CLOCK1, - snd_soc_read(codec, WM8960_CLOCK1) | 1); + wm8960_write(codec, WM8960_CLOCK1, + wm8960_read(codec, WM8960_CLOCK1) | 1); return 0; } @@ -595,28 +649,28 @@ static int wm8960_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8960_SYSCLKSEL: - reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1fe; - snd_soc_write(codec, WM8960_CLOCK1, reg | div); + reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1fe; + wm8960_write(codec, WM8960_CLOCK1, reg | div); break; case WM8960_SYSCLKDIV: - reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1f9; - snd_soc_write(codec, WM8960_CLOCK1, reg | div); + reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1f9; + wm8960_write(codec, WM8960_CLOCK1, reg | div); break; case WM8960_DACDIV: - reg = snd_soc_read(codec, WM8960_CLOCK1) & 0x1c7; - snd_soc_write(codec, WM8960_CLOCK1, reg | div); + reg = wm8960_read(codec, WM8960_CLOCK1) & 0x1c7; + wm8960_write(codec, WM8960_CLOCK1, reg | div); break; case WM8960_OPCLKDIV: - reg = snd_soc_read(codec, WM8960_PLL1) & 0x03f; - snd_soc_write(codec, WM8960_PLL1, reg | div); + reg = wm8960_read(codec, WM8960_PLL1) & 0x03f; + wm8960_write(codec, WM8960_PLL1, reg | div); break; case WM8960_DCLKDIV: - reg = snd_soc_read(codec, WM8960_CLOCK2) & 0x03f; - snd_soc_write(codec, WM8960_CLOCK2, reg | div); + reg = wm8960_read(codec, WM8960_CLOCK2) & 0x03f; + wm8960_write(codec, WM8960_CLOCK2, reg | div); break; case WM8960_TOCLKSEL: - reg = snd_soc_read(codec, WM8960_ADDCTL1) & 0x1fd; - snd_soc_write(codec, WM8960_ADDCTL1, reg | div); + reg = wm8960_read(codec, WM8960_ADDCTL1) & 0x1fd; + wm8960_write(codec, WM8960_ADDCTL1, reg | div); break; default: return -EINVAL; @@ -747,8 +801,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8960 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8960); -static int wm8960_register(struct wm8960_priv *wm8960, - enum snd_soc_control_type control) +static int wm8960_register(struct wm8960_priv *wm8960) { struct wm8960_data *pdata = wm8960->codec.dev->platform_data; struct snd_soc_codec *codec = &wm8960->codec; @@ -777,6 +830,8 @@ static int wm8960_register(struct wm8960_priv *wm8960, codec->private_data = wm8960; codec->name = "WM8960"; codec->owner = THIS_MODULE; + codec->read = wm8960_read_reg_cache; + codec->write = wm8960_write; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8960_set_bias_level; codec->dai = &wm8960_dai; @@ -786,12 +841,6 @@ static int wm8960_register(struct wm8960_priv *wm8960, memcpy(codec->reg_cache, wm8960_reg, sizeof(wm8960_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - ret = wm8960_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); @@ -803,26 +852,26 @@ static int wm8960_register(struct wm8960_priv *wm8960, wm8960_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Latch the update bits */ - reg = snd_soc_read(codec, WM8960_LINVOL); - snd_soc_write(codec, WM8960_LINVOL, reg | 0x100); - reg = snd_soc_read(codec, WM8960_RINVOL); - snd_soc_write(codec, WM8960_RINVOL, reg | 0x100); - reg = snd_soc_read(codec, WM8960_LADC); - snd_soc_write(codec, WM8960_LADC, reg | 0x100); - reg = snd_soc_read(codec, WM8960_RADC); - snd_soc_write(codec, WM8960_RADC, reg | 0x100); - reg = snd_soc_read(codec, WM8960_LDAC); - snd_soc_write(codec, WM8960_LDAC, reg | 0x100); - reg = snd_soc_read(codec, WM8960_RDAC); - snd_soc_write(codec, WM8960_RDAC, reg | 0x100); - reg = snd_soc_read(codec, WM8960_LOUT1); - snd_soc_write(codec, WM8960_LOUT1, reg | 0x100); - reg = snd_soc_read(codec, WM8960_ROUT1); - snd_soc_write(codec, WM8960_ROUT1, reg | 0x100); - reg = snd_soc_read(codec, WM8960_LOUT2); - snd_soc_write(codec, WM8960_LOUT2, reg | 0x100); - reg = snd_soc_read(codec, WM8960_ROUT2); - snd_soc_write(codec, WM8960_ROUT2, reg | 0x100); + reg = wm8960_read(codec, WM8960_LINVOL); + wm8960_write(codec, WM8960_LINVOL, reg | 0x100); + reg = wm8960_read(codec, WM8960_RINVOL); + wm8960_write(codec, WM8960_RINVOL, reg | 0x100); + reg = wm8960_read(codec, WM8960_LADC); + wm8960_write(codec, WM8960_LADC, reg | 0x100); + reg = wm8960_read(codec, WM8960_RADC); + wm8960_write(codec, WM8960_RADC, reg | 0x100); + reg = wm8960_read(codec, WM8960_LDAC); + wm8960_write(codec, WM8960_LDAC, reg | 0x100); + reg = wm8960_read(codec, WM8960_RDAC); + wm8960_write(codec, WM8960_RDAC, reg | 0x100); + reg = wm8960_read(codec, WM8960_LOUT1); + wm8960_write(codec, WM8960_LOUT1, reg | 0x100); + reg = wm8960_read(codec, WM8960_ROUT1); + wm8960_write(codec, WM8960_ROUT1, reg | 0x100); + reg = wm8960_read(codec, WM8960_LOUT2); + wm8960_write(codec, WM8960_LOUT2, reg | 0x100); + reg = wm8960_read(codec, WM8960_ROUT2); + wm8960_write(codec, WM8960_ROUT2, reg | 0x100); wm8960_codec = codec; @@ -867,13 +916,14 @@ static __devinit int wm8960_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8960->codec; + codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8960); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8960_register(wm8960, SND_SOC_I2C); + return wm8960_register(wm8960); } static __devexit int wm8960_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/codecs/wm8961.c b/trunk/sound/soc/codecs/wm8961.c index 503032085899..bd1af92a122f 100644 --- a/trunk/sound/soc/codecs/wm8961.c +++ b/trunk/sound/soc/codecs/wm8961.c @@ -292,10 +292,9 @@ struct wm8961_priv { u16 reg_cache[WM8961_MAX_REGISTER]; }; -static int wm8961_volatile_register(unsigned int reg) +static int wm8961_reg_is_volatile(int reg) { switch (reg) { - case WM8961_SOFTWARE_RESET: case WM8961_WRITE_SEQUENCER_7: case WM8961_DC_SERVO_1: return 1; @@ -305,9 +304,76 @@ static int wm8961_volatile_register(unsigned int reg) } } +static unsigned int wm8961_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > WM8961_MAX_REGISTER); + return cache[reg]; +} + +static unsigned int wm8961_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + BUG_ON(reg > WM8961_MAX_REGISTER); + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +static unsigned int wm8961_read(struct snd_soc_codec *codec, unsigned int reg) +{ + if (wm8961_reg_is_volatile(reg)) + return wm8961_read_hw(codec, reg); + else + return wm8961_read_reg_cache(codec, reg); +} + +static int wm8961_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[3]; + + BUG_ON(reg > WM8961_MAX_REGISTER); + + if (!wm8961_reg_is_volatile(reg)) + cache[reg] = value; + + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0x00ff; + + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + static int wm8961_reset(struct snd_soc_codec *codec) { - return snd_soc_write(codec, WM8961_SOFTWARE_RESET, 0); + return wm8961_write(codec, WM8961_SOFTWARE_RESET, 0); } /* @@ -318,33 +384,33 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 hp_reg = snd_soc_read(codec, WM8961_ANALOGUE_HP_0); - u16 cp_reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_1); - u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2); - u16 dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1); + u16 hp_reg = wm8961_read(codec, WM8961_ANALOGUE_HP_0); + u16 cp_reg = wm8961_read(codec, WM8961_CHARGE_PUMP_1); + u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); + u16 dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); int timeout = 500; if (event & SND_SOC_DAPM_POST_PMU) { /* Make sure the output is shorted */ hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Enable the charge pump */ cp_reg |= WM8961_CP_ENA; - snd_soc_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); + wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg); mdelay(5); /* Enable the PGA */ pwr_reg |= WM8961_LOUT1_PGA | WM8961_ROUT1_PGA; - snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); /* Enable the amplifier */ hp_reg |= WM8961_HPR_ENA | WM8961_HPL_ENA; - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Second stage enable */ hp_reg |= WM8961_HPR_ENA_DLY | WM8961_HPL_ENA_DLY; - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Enable the DC servo & trigger startup */ dcs_reg |= @@ -352,10 +418,10 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, WM8961_DCS_ENA_CHAN_HPL | WM8961_DCS_TRIG_STARTUP_HPL; dev_dbg(codec->dev, "Enabling DC servo\n"); - snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg); + wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); do { msleep(1); - dcs_reg = snd_soc_read(codec, WM8961_DC_SERVO_1); + dcs_reg = wm8961_read(codec, WM8961_DC_SERVO_1); } while (--timeout && dcs_reg & (WM8961_DCS_TRIG_STARTUP_HPR | WM8961_DCS_TRIG_STARTUP_HPL)); @@ -367,39 +433,39 @@ static int wm8961_hp_event(struct snd_soc_dapm_widget *w, /* Enable the output stage */ hp_reg |= WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP; - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Remove the short on the output stage */ hp_reg |= WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT; - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); } if (event & SND_SOC_DAPM_PRE_PMD) { /* Short the output */ hp_reg &= ~(WM8961_HPR_RMV_SHORT | WM8961_HPL_RMV_SHORT); - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Disable the output stage */ hp_reg &= ~(WM8961_HPR_ENA_OUTP | WM8961_HPL_ENA_OUTP); - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Disable DC offset cancellation */ dcs_reg &= ~(WM8961_DCS_ENA_CHAN_HPR | WM8961_DCS_ENA_CHAN_HPL); - snd_soc_write(codec, WM8961_DC_SERVO_1, dcs_reg); + wm8961_write(codec, WM8961_DC_SERVO_1, dcs_reg); /* Finish up */ hp_reg &= ~(WM8961_HPR_ENA_DLY | WM8961_HPR_ENA | WM8961_HPL_ENA_DLY | WM8961_HPL_ENA); - snd_soc_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); + wm8961_write(codec, WM8961_ANALOGUE_HP_0, hp_reg); /* Disable the PGA */ pwr_reg &= ~(WM8961_LOUT1_PGA | WM8961_ROUT1_PGA); - snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); /* Disable the charge pump */ dev_dbg(codec->dev, "Disabling charge pump\n"); - snd_soc_write(codec, WM8961_CHARGE_PUMP_1, + wm8961_write(codec, WM8961_CHARGE_PUMP_1, cp_reg & ~WM8961_CP_ENA); } @@ -410,27 +476,27 @@ static int wm8961_spk_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 pwr_reg = snd_soc_read(codec, WM8961_PWR_MGMT_2); - u16 spk_reg = snd_soc_read(codec, WM8961_CLASS_D_CONTROL_1); + u16 pwr_reg = wm8961_read(codec, WM8961_PWR_MGMT_2); + u16 spk_reg = wm8961_read(codec, WM8961_CLASS_D_CONTROL_1); if (event & SND_SOC_DAPM_POST_PMU) { /* Enable the PGA */ pwr_reg |= WM8961_SPKL_PGA | WM8961_SPKR_PGA; - snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); /* Enable the amplifier */ spk_reg |= WM8961_SPKL_ENA | WM8961_SPKR_ENA; - snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); + wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); } if (event & SND_SOC_DAPM_PRE_PMD) { /* Enable the amplifier */ spk_reg &= ~(WM8961_SPKL_ENA | WM8961_SPKR_ENA); - snd_soc_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); + wm8961_write(codec, WM8961_CLASS_D_CONTROL_1, spk_reg); /* Enable the PGA */ pwr_reg &= ~(WM8961_SPKL_PGA | WM8961_SPKR_PGA); - snd_soc_write(codec, WM8961_PWR_MGMT_2, pwr_reg); + wm8961_write(codec, WM8961_PWR_MGMT_2, pwr_reg); } return 0; @@ -648,10 +714,10 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, abs(wm8961_srate[best].rate - fs)) best = i; } - reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_3); + reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_3); reg &= ~WM8961_SAMPLE_RATE_MASK; reg |= wm8961_srate[best].val; - snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); + wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_3, reg); dev_dbg(codec->dev, "Selected SRATE %dHz for %dHz\n", wm8961_srate[best].rate, fs); @@ -681,12 +747,12 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, wm8961_clk_sys_ratio[i].ratio, wm8961->sysclk, fs, wm8961->sysclk / fs); - reg = snd_soc_read(codec, WM8961_CLOCKING_4); + reg = wm8961_read(codec, WM8961_CLOCKING_4); reg &= ~WM8961_CLK_SYS_RATE_MASK; reg |= wm8961_clk_sys_ratio[i].val << WM8961_CLK_SYS_RATE_SHIFT; - snd_soc_write(codec, WM8961_CLOCKING_4, reg); + wm8961_write(codec, WM8961_CLOCKING_4, reg); - reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0); + reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); reg &= ~WM8961_WL_MASK; switch (params_format(params)) { case SNDRV_PCM_FORMAT_S16_LE: @@ -703,15 +769,15 @@ static int wm8961_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, reg); + wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, reg); /* Sloping stop-band filter is recommended for <= 24kHz */ - reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2); + reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); if (fs <= 24000) reg |= WM8961_DACSLOPE; else reg &= WM8961_DACSLOPE; - snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); + wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); return 0; } @@ -722,7 +788,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, { struct snd_soc_codec *codec = dai->codec; struct wm8961_priv *wm8961 = codec->private_data; - u16 reg = snd_soc_read(codec, WM8961_CLOCKING1); + u16 reg = wm8961_read(codec, WM8961_CLOCKING1); if (freq > 33000000) { dev_err(codec->dev, "MCLK must be <33MHz\n"); @@ -738,7 +804,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, reg &= WM8961_MCLKDIV; } - snd_soc_write(codec, WM8961_CLOCKING1, reg); + wm8961_write(codec, WM8961_CLOCKING1, reg); wm8961->sysclk = freq; @@ -748,7 +814,7 @@ static int wm8961_set_sysclk(struct snd_soc_dai *dai, int clk_id, static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { struct snd_soc_codec *codec = dai->codec; - u16 aif = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_0); + u16 aif = wm8961_read(codec, WM8961_AUDIO_INTERFACE_0); aif &= ~(WM8961_BCLKINV | WM8961_LRP | WM8961_MS | WM8961_FORMAT_MASK); @@ -808,26 +874,26 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return -EINVAL; } - return snd_soc_write(codec, WM8961_AUDIO_INTERFACE_0, aif); + return wm8961_write(codec, WM8961_AUDIO_INTERFACE_0, aif); } static int wm8961_set_tristate(struct snd_soc_dai *dai, int tristate) { struct snd_soc_codec *codec = dai->codec; - u16 reg = snd_soc_read(codec, WM8961_ADDITIONAL_CONTROL_2); + u16 reg = wm8961_read(codec, WM8961_ADDITIONAL_CONTROL_2); if (tristate) reg |= WM8961_TRIS; else reg &= ~WM8961_TRIS; - return snd_soc_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); + return wm8961_write(codec, WM8961_ADDITIONAL_CONTROL_2, reg); } static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_1); + u16 reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_1); if (mute) reg |= WM8961_DACMU; @@ -836,7 +902,7 @@ static int wm8961_digital_mute(struct snd_soc_dai *dai, int mute) msleep(17); - return snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); + return wm8961_write(codec, WM8961_ADC_DAC_CONTROL_1, reg); } static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) @@ -846,17 +912,17 @@ static int wm8961_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) switch (div_id) { case WM8961_BCLK: - reg = snd_soc_read(codec, WM8961_CLOCKING2); + reg = wm8961_read(codec, WM8961_CLOCKING2); reg &= ~WM8961_BCLKDIV_MASK; reg |= div; - snd_soc_write(codec, WM8961_CLOCKING2, reg); + wm8961_write(codec, WM8961_CLOCKING2, reg); break; case WM8961_LRCLK: - reg = snd_soc_read(codec, WM8961_AUDIO_INTERFACE_2); + reg = wm8961_read(codec, WM8961_AUDIO_INTERFACE_2); reg &= ~WM8961_LRCLK_RATE_MASK; reg |= div; - snd_soc_write(codec, WM8961_AUDIO_INTERFACE_2, reg); + wm8961_write(codec, WM8961_AUDIO_INTERFACE_2, reg); break; default: @@ -883,34 +949,34 @@ static int wm8961_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: if (codec->bias_level == SND_SOC_BIAS_STANDBY) { /* Enable bias generation */ - reg = snd_soc_read(codec, WM8961_ANTI_POP); + reg = wm8961_read(codec, WM8961_ANTI_POP); reg |= WM8961_BUFIOEN | WM8961_BUFDCOPEN; - snd_soc_write(codec, WM8961_ANTI_POP, reg); + wm8961_write(codec, WM8961_ANTI_POP, reg); /* VMID=2*50k, VREF */ - reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); + reg = wm8961_read(codec, WM8961_PWR_MGMT_1); reg &= ~WM8961_VMIDSEL_MASK; reg |= (1 << WM8961_VMIDSEL_SHIFT) | WM8961_VREF; - snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); + wm8961_write(codec, WM8961_PWR_MGMT_1, reg); } break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_PREPARE) { /* VREF off */ - reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); + reg = wm8961_read(codec, WM8961_PWR_MGMT_1); reg &= ~WM8961_VREF; - snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); + wm8961_write(codec, WM8961_PWR_MGMT_1, reg); /* Bias generation off */ - reg = snd_soc_read(codec, WM8961_ANTI_POP); + reg = wm8961_read(codec, WM8961_ANTI_POP); reg &= ~(WM8961_BUFIOEN | WM8961_BUFDCOPEN); - snd_soc_write(codec, WM8961_ANTI_POP, reg); + wm8961_write(codec, WM8961_ANTI_POP, reg); /* VMID off */ - reg = snd_soc_read(codec, WM8961_PWR_MGMT_1); + reg = wm8961_read(codec, WM8961_PWR_MGMT_1); reg &= ~WM8961_VMIDSEL_MASK; - snd_soc_write(codec, WM8961_PWR_MGMT_1, reg); + wm8961_write(codec, WM8961_PWR_MGMT_1, reg); } break; @@ -1035,7 +1101,7 @@ static int wm8961_resume(struct platform_device *pdev) if (i == WM8961_SOFTWARE_RESET) continue; - snd_soc_write(codec, i, reg_cache[i]); + wm8961_write(codec, i, reg_cache[i]); } wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1074,32 +1140,26 @@ static int wm8961_register(struct wm8961_priv *wm8961) codec->private_data = wm8961; codec->name = "WM8961"; codec->owner = THIS_MODULE; + codec->read = wm8961_read; + codec->write = wm8961_write; codec->dai = &wm8961_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm8961->reg_cache); codec->reg_cache = &wm8961->reg_cache; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm8961_set_bias_level; - codec->volatile_register = wm8961_volatile_register; memcpy(codec->reg_cache, wm8961_reg_defaults, sizeof(wm8961_reg_defaults)); - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - - reg = snd_soc_read(codec, WM8961_SOFTWARE_RESET); + reg = wm8961_read_hw(codec, WM8961_SOFTWARE_RESET); if (reg != 0x1801) { dev_err(codec->dev, "Device is not a WM8961: ID=0x%x\n", reg); ret = -EINVAL; goto err; } - /* This isn't volatile - readback doesn't correspond to write */ - reg = codec->hw_read(codec, WM8961_RIGHT_INPUT_VOLUME); + reg = wm8961_read_hw(codec, WM8961_RIGHT_INPUT_VOLUME); dev_info(codec->dev, "WM8961 family %d revision %c\n", (reg & WM8961_DEVICE_ID_MASK) >> WM8961_DEVICE_ID_SHIFT, ((reg & WM8961_CHIP_REV_MASK) >> WM8961_CHIP_REV_SHIFT) @@ -1112,37 +1172,37 @@ static int wm8961_register(struct wm8961_priv *wm8961) } /* Enable class W */ - reg = snd_soc_read(codec, WM8961_CHARGE_PUMP_B); + reg = wm8961_read(codec, WM8961_CHARGE_PUMP_B); reg |= WM8961_CP_DYN_PWR_MASK; - snd_soc_write(codec, WM8961_CHARGE_PUMP_B, reg); + wm8961_write(codec, WM8961_CHARGE_PUMP_B, reg); /* Latch volume update bits (right channel only, we always * write both out) and default ZC on. */ - reg = snd_soc_read(codec, WM8961_ROUT1_VOLUME); - snd_soc_write(codec, WM8961_ROUT1_VOLUME, + reg = wm8961_read(codec, WM8961_ROUT1_VOLUME); + wm8961_write(codec, WM8961_ROUT1_VOLUME, reg | WM8961_LO1ZC | WM8961_OUT1VU); - snd_soc_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); - reg = snd_soc_read(codec, WM8961_ROUT2_VOLUME); - snd_soc_write(codec, WM8961_ROUT2_VOLUME, + wm8961_write(codec, WM8961_LOUT1_VOLUME, reg | WM8961_LO1ZC); + reg = wm8961_read(codec, WM8961_ROUT2_VOLUME); + wm8961_write(codec, WM8961_ROUT2_VOLUME, reg | WM8961_SPKRZC | WM8961_SPKVU); - snd_soc_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); + wm8961_write(codec, WM8961_LOUT2_VOLUME, reg | WM8961_SPKLZC); - reg = snd_soc_read(codec, WM8961_RIGHT_ADC_VOLUME); - snd_soc_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); - reg = snd_soc_read(codec, WM8961_RIGHT_INPUT_VOLUME); - snd_soc_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); + reg = wm8961_read(codec, WM8961_RIGHT_ADC_VOLUME); + wm8961_write(codec, WM8961_RIGHT_ADC_VOLUME, reg | WM8961_ADCVU); + reg = wm8961_read(codec, WM8961_RIGHT_INPUT_VOLUME); + wm8961_write(codec, WM8961_RIGHT_INPUT_VOLUME, reg | WM8961_IPVU); /* Use soft mute by default */ - reg = snd_soc_read(codec, WM8961_ADC_DAC_CONTROL_2); + reg = wm8961_read(codec, WM8961_ADC_DAC_CONTROL_2); reg |= WM8961_DACSMM; - snd_soc_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); + wm8961_write(codec, WM8961_ADC_DAC_CONTROL_2, reg); /* Use automatic clocking mode by default; for now this is all * we support. */ - reg = snd_soc_read(codec, WM8961_CLOCKING_3); + reg = wm8961_read(codec, WM8961_CLOCKING_3); reg &= ~WM8961_MANUAL_MODE; - snd_soc_write(codec, WM8961_CLOCKING_3, reg); + wm8961_write(codec, WM8961_CLOCKING_3, reg); wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1190,6 +1250,7 @@ static __devinit int wm8961_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8961->codec; + codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8961); codec->control_data = i2c; diff --git a/trunk/sound/soc/codecs/wm8971.c b/trunk/sound/soc/codecs/wm8971.c index d66efb0546ea..032dca22dbd3 100644 --- a/trunk/sound/soc/codecs/wm8971.c +++ b/trunk/sound/soc/codecs/wm8971.c @@ -59,7 +59,44 @@ static const u16 wm8971_reg[] = { 0x0079, 0x0079, 0x0079, /* 40 */ }; -#define wm8971_reset(c) snd_soc_write(c, WM8971_RESET, 0) +static inline unsigned int wm8971_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg < WM8971_REG_COUNT) + return cache[reg]; + + return -1; +} + +static inline void wm8971_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg < WM8971_REG_COUNT) + cache[reg] = value; +} + +static int wm8971_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8971_write_reg_cache (codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8971_reset(c) wm8971_write(c, WM8971_RESET, 0) /* WM8971 Controls */ static const char *wm8971_bass[] = { "Linear Control", "Adaptive Boost" }; @@ -484,7 +521,7 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8971_IFACE, iface); + wm8971_write(codec, WM8971_IFACE, iface); return 0; } @@ -496,8 +533,8 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8971_priv *wm8971 = codec->private_data; - u16 iface = snd_soc_read(codec, WM8971_IFACE) & 0x1f3; - u16 srate = snd_soc_read(codec, WM8971_SRATE) & 0x1c0; + u16 iface = wm8971_read_reg_cache(codec, WM8971_IFACE) & 0x1f3; + u16 srate = wm8971_read_reg_cache(codec, WM8971_SRATE) & 0x1c0; int coeff = get_coeff(wm8971->sysclk, params_rate(params)); /* bit size */ @@ -516,9 +553,9 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, } /* set iface & srate */ - snd_soc_write(codec, WM8971_IFACE, iface); + wm8971_write(codec, WM8971_IFACE, iface); if (coeff >= 0) - snd_soc_write(codec, WM8971_SRATE, srate | + wm8971_write(codec, WM8971_SRATE, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; @@ -527,33 +564,33 @@ static int wm8971_pcm_hw_params(struct snd_pcm_substream *substream, static int wm8971_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8971_ADCDAC) & 0xfff7; + u16 mute_reg = wm8971_read_reg_cache(codec, WM8971_ADCDAC) & 0xfff7; if (mute) - snd_soc_write(codec, WM8971_ADCDAC, mute_reg | 0x8); + wm8971_write(codec, WM8971_ADCDAC, mute_reg | 0x8); else - snd_soc_write(codec, WM8971_ADCDAC, mute_reg); + wm8971_write(codec, WM8971_ADCDAC, mute_reg); return 0; } static int wm8971_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; + u16 pwr_reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; switch (level) { case SND_SOC_BIAS_ON: /* set vmid to 50k and unmute dac */ - snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); + wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x00c1); break; case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: /* mute dac and set vmid to 500k, enable VREF */ - snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); + wm8971_write(codec, WM8971_PWR1, pwr_reg | 0x0140); break; case SND_SOC_BIAS_OFF: - snd_soc_write(codec, WM8971_PWR1, 0x0001); + wm8971_write(codec, WM8971_PWR1, 0x0001); break; } codec->bias_level = level; @@ -630,8 +667,8 @@ static int wm8971_resume(struct platform_device *pdev) /* charge wm8971 caps */ if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { - reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; - snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); + reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; + wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); codec->bias_level = SND_SOC_BIAS_ON; queue_delayed_work(wm8971_workq, &codec->delayed_work, msecs_to_jiffies(1000)); @@ -640,14 +677,15 @@ static int wm8971_resume(struct platform_device *pdev) return 0; } -static int wm8971_init(struct snd_soc_device *socdev, - enum snd_soc_control_type control) +static int wm8971_init(struct snd_soc_device *socdev) { struct snd_soc_codec *codec = socdev->card->codec; int reg, ret = 0; codec->name = "WM8971"; codec->owner = THIS_MODULE; + codec->read = wm8971_read_reg_cache; + codec->write = wm8971_write; codec->set_bias_level = wm8971_set_bias_level; codec->dai = &wm8971_dai; codec->reg_cache_size = ARRAY_SIZE(wm8971_reg); @@ -657,48 +695,42 @@ static int wm8971_init(struct snd_soc_device *socdev, if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); - goto err; - } - wm8971_reset(codec); /* register pcms */ ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { printk(KERN_ERR "wm8971: failed to create pcms\n"); - goto err; + goto pcm_err; } /* charge output caps - set vmid to 5k for quick power up */ - reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; - snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); + reg = wm8971_read_reg_cache(codec, WM8971_PWR1) & 0xfe3e; + wm8971_write(codec, WM8971_PWR1, reg | 0x01c0); codec->bias_level = SND_SOC_BIAS_STANDBY; queue_delayed_work(wm8971_workq, &codec->delayed_work, msecs_to_jiffies(1000)); /* set the update bits */ - reg = snd_soc_read(codec, WM8971_LDAC); - snd_soc_write(codec, WM8971_LDAC, reg | 0x0100); - reg = snd_soc_read(codec, WM8971_RDAC); - snd_soc_write(codec, WM8971_RDAC, reg | 0x0100); - - reg = snd_soc_read(codec, WM8971_LOUT1V); - snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100); - reg = snd_soc_read(codec, WM8971_ROUT1V); - 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); + reg = wm8971_read_reg_cache(codec, WM8971_LDAC); + wm8971_write(codec, WM8971_LDAC, reg | 0x0100); + reg = wm8971_read_reg_cache(codec, WM8971_RDAC); + wm8971_write(codec, WM8971_RDAC, reg | 0x0100); + + reg = wm8971_read_reg_cache(codec, WM8971_LOUT1V); + wm8971_write(codec, WM8971_LOUT1V, reg | 0x0100); + reg = wm8971_read_reg_cache(codec, WM8971_ROUT1V); + wm8971_write(codec, WM8971_ROUT1V, reg | 0x0100); + + reg = wm8971_read_reg_cache(codec, WM8971_LOUT2V); + wm8971_write(codec, WM8971_LOUT2V, reg | 0x0100); + reg = wm8971_read_reg_cache(codec, WM8971_ROUT2V); + wm8971_write(codec, WM8971_ROUT2V, reg | 0x0100); + + reg = wm8971_read_reg_cache(codec, WM8971_LINVOL); + wm8971_write(codec, WM8971_LINVOL, reg | 0x0100); + reg = wm8971_read_reg_cache(codec, WM8971_RINVOL); + wm8971_write(codec, WM8971_RINVOL, reg | 0x0100); snd_soc_add_controls(codec, wm8971_snd_controls, ARRAY_SIZE(wm8971_snd_controls)); @@ -713,7 +745,7 @@ static int wm8971_init(struct snd_soc_device *socdev, card_err: snd_soc_free_pcms(socdev); snd_soc_dapm_free(socdev); -err: +pcm_err: kfree(codec->reg_cache); return ret; } @@ -735,7 +767,7 @@ static int wm8971_i2c_probe(struct i2c_client *i2c, codec->control_data = i2c; - ret = wm8971_init(socdev, SND_SOC_I2C); + ret = wm8971_init(socdev); if (ret < 0) pr_err("failed to initialise WM8971\n"); @@ -845,6 +877,7 @@ static int wm8971_probe(struct platform_device *pdev) #if defined (CONFIG_I2C) || defined (CONFIG_I2C_MODULE) if (setup->i2c_address) { + codec->hw_write = (hw_write_t)i2c_master_send; ret = wm8971_add_i2c_device(pdev, setup); } #endif diff --git a/trunk/sound/soc/codecs/wm8988.c b/trunk/sound/soc/codecs/wm8988.c index 1c8653523c8c..6f15acd10489 100644 --- a/trunk/sound/soc/codecs/wm8988.c +++ b/trunk/sound/soc/codecs/wm8988.c @@ -57,7 +57,50 @@ struct wm8988_priv { }; -#define wm8988_reset(c) snd_soc_write(c, WM8988_RESET, 0) +/* + * read wm8988 register cache + */ +static inline unsigned int wm8988_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8988_NUM_REG) + return -1; + return cache[reg]; +} + +/* + * write wm8988 register cache + */ +static inline void wm8988_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + if (reg > WM8988_NUM_REG) + return; + cache[reg] = value; +} + +static int wm8988_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[2]; + + /* data is + * D15..D9 WM8753 register offset + * D8...D0 register data + */ + data[0] = (reg << 1) | ((value >> 8) & 0x0001); + data[1] = value & 0x00ff; + + wm8988_write_reg_cache(codec, reg, value); + if (codec->hw_write(codec->control_data, data, 2) == 2) + return 0; + else + return -EIO; +} + +#define wm8988_reset(c) wm8988_write(c, WM8988_RESET, 0) /* * WM8988 Controls @@ -183,15 +226,15 @@ static int wm8988_lrc_control(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - u16 adctl2 = snd_soc_read(codec, WM8988_ADCTL2); + u16 adctl2 = wm8988_read_reg_cache(codec, WM8988_ADCTL2); /* Use the DAC to gate LRC if active, otherwise use ADC */ - if (snd_soc_read(codec, WM8988_PWR2) & 0x180) + if (wm8988_read_reg_cache(codec, WM8988_PWR2) & 0x180) adctl2 &= ~0x4; else adctl2 |= 0x4; - return snd_soc_write(codec, WM8988_ADCTL2, adctl2); + return wm8988_write(codec, WM8988_ADCTL2, adctl2); } static const char *wm8988_line_texts[] = { @@ -576,7 +619,7 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8988_IFACE, iface); + wm8988_write(codec, WM8988_IFACE, iface); return 0; } @@ -610,8 +653,8 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; struct wm8988_priv *wm8988 = codec->private_data; - u16 iface = snd_soc_read(codec, WM8988_IFACE) & 0x1f3; - u16 srate = snd_soc_read(codec, WM8988_SRATE) & 0x180; + u16 iface = wm8988_read_reg_cache(codec, WM8988_IFACE) & 0x1f3; + u16 srate = wm8988_read_reg_cache(codec, WM8988_SRATE) & 0x180; int coeff; coeff = get_coeff(wm8988->sysclk, params_rate(params)); @@ -642,9 +685,9 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, } /* set iface & srate */ - snd_soc_write(codec, WM8988_IFACE, iface); + wm8988_write(codec, WM8988_IFACE, iface); if (coeff >= 0) - snd_soc_write(codec, WM8988_SRATE, srate | + wm8988_write(codec, WM8988_SRATE, srate | (coeff_div[coeff].sr << 1) | coeff_div[coeff].usb); return 0; @@ -653,19 +696,19 @@ static int wm8988_pcm_hw_params(struct snd_pcm_substream *substream, static int wm8988_mute(struct snd_soc_dai *dai, int mute) { struct snd_soc_codec *codec = dai->codec; - u16 mute_reg = snd_soc_read(codec, WM8988_ADCDAC) & 0xfff7; + u16 mute_reg = wm8988_read_reg_cache(codec, WM8988_ADCDAC) & 0xfff7; if (mute) - snd_soc_write(codec, WM8988_ADCDAC, mute_reg | 0x8); + wm8988_write(codec, WM8988_ADCDAC, mute_reg | 0x8); else - snd_soc_write(codec, WM8988_ADCDAC, mute_reg); + wm8988_write(codec, WM8988_ADCDAC, mute_reg); return 0; } static int wm8988_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - u16 pwr_reg = snd_soc_read(codec, WM8988_PWR1) & ~0x1c1; + u16 pwr_reg = wm8988_read_reg_cache(codec, WM8988_PWR1) & ~0x1c1; switch (level) { case SND_SOC_BIAS_ON: @@ -673,24 +716,24 @@ static int wm8988_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VREF, VMID=2x50k, digital enabled */ - snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); + wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x00c0); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* VREF, VMID=2x5k */ - snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); + wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x1c1); /* Charge caps */ msleep(100); } /* VREF, VMID=2*500k, digital stopped */ - snd_soc_write(codec, WM8988_PWR1, pwr_reg | 0x0141); + wm8988_write(codec, WM8988_PWR1, pwr_reg | 0x0141); break; case SND_SOC_BIAS_OFF: - snd_soc_write(codec, WM8988_PWR1, 0x0000); + wm8988_write(codec, WM8988_PWR1, 0x0000); break; } codec->bias_level = level; @@ -825,8 +868,7 @@ struct snd_soc_codec_device soc_codec_dev_wm8988 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm8988); -static int wm8988_register(struct wm8988_priv *wm8988, - enum snd_soc_control_type control) +static int wm8988_register(struct wm8988_priv *wm8988) { struct snd_soc_codec *codec = &wm8988->codec; int ret; @@ -845,6 +887,8 @@ static int wm8988_register(struct wm8988_priv *wm8988, codec->private_data = wm8988; codec->name = "WM8988"; codec->owner = THIS_MODULE; + codec->read = wm8988_read_reg_cache; + codec->write = wm8988_write; codec->dai = &wm8988_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm8988->reg_cache); @@ -855,12 +899,6 @@ static int wm8988_register(struct wm8988_priv *wm8988, memcpy(codec->reg_cache, wm8988_reg, sizeof(wm8988_reg)); - ret = snd_soc_codec_set_cache_io(codec, 7, 9, control); - if (ret < 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - goto err; - } - ret = wm8988_reset(codec); if (ret < 0) { dev_err(codec->dev, "Failed to issue reset\n"); @@ -868,16 +906,16 @@ static int wm8988_register(struct wm8988_priv *wm8988, } /* set the update bits (we always update left then right) */ - reg = snd_soc_read(codec, WM8988_RADC); - snd_soc_write(codec, WM8988_RADC, reg | 0x100); - reg = snd_soc_read(codec, WM8988_RDAC); - snd_soc_write(codec, WM8988_RDAC, reg | 0x0100); - reg = snd_soc_read(codec, WM8988_ROUT1V); - 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); + reg = wm8988_read_reg_cache(codec, WM8988_RADC); + wm8988_write(codec, WM8988_RADC, reg | 0x100); + reg = wm8988_read_reg_cache(codec, WM8988_RDAC); + wm8988_write(codec, WM8988_RDAC, reg | 0x0100); + reg = wm8988_read_reg_cache(codec, WM8988_ROUT1V); + wm8988_write(codec, WM8988_ROUT1V, reg | 0x0100); + reg = wm8988_read_reg_cache(codec, WM8988_ROUT2V); + wm8988_write(codec, WM8988_ROUT2V, reg | 0x0100); + reg = wm8988_read_reg_cache(codec, WM8988_RINVOL); + wm8988_write(codec, WM8988_RINVOL, reg | 0x0100); wm8988_set_bias_level(&wm8988->codec, SND_SOC_BIAS_STANDBY); @@ -928,13 +966,14 @@ static int wm8988_i2c_probe(struct i2c_client *i2c, return -ENOMEM; codec = &wm8988->codec; + codec->hw_write = (hw_write_t)i2c_master_send; i2c_set_clientdata(i2c, wm8988); codec->control_data = i2c; codec->dev = &i2c->dev; - return wm8988_register(wm8988, SND_SOC_I2C); + return wm8988_register(wm8988); } static int wm8988_i2c_remove(struct i2c_client *client) @@ -979,6 +1018,30 @@ static struct i2c_driver wm8988_i2c_driver = { #endif #if defined(CONFIG_SPI_MASTER) +static int wm8988_spi_write(struct spi_device *spi, const char *data, int len) +{ + struct spi_transfer t; + struct spi_message m; + u8 msg[2]; + + if (len <= 0) + return 0; + + msg[0] = data[0]; + msg[1] = data[1]; + + spi_message_init(&m); + memset(&t, 0, (sizeof t)); + + t.tx_buf = &msg[0]; + t.len = len; + + spi_message_add_tail(&t, &m); + spi_sync(spi, &m); + + return len; +} + static int __devinit wm8988_spi_probe(struct spi_device *spi) { struct wm8988_priv *wm8988; @@ -989,12 +1052,13 @@ static int __devinit wm8988_spi_probe(struct spi_device *spi) return -ENOMEM; codec = &wm8988->codec; + codec->hw_write = (hw_write_t)wm8988_spi_write; codec->control_data = spi; codec->dev = &spi->dev; spi->dev.driver_data = wm8988; - return wm8988_register(wm8988, SND_SOC_SPI); + return wm8988_register(wm8988); } static int __devexit wm8988_spi_remove(struct spi_device *spi) diff --git a/trunk/sound/soc/codecs/wm8990.c b/trunk/sound/soc/codecs/wm8990.c index 2d702db4131d..d029818350e9 100644 --- a/trunk/sound/soc/codecs/wm8990.c +++ b/trunk/sound/soc/codecs/wm8990.c @@ -108,7 +108,53 @@ static const u16 wm8990_reg[] = { 0x0000, /* R63 - Driver internal */ }; -#define wm8990_reset(c) snd_soc_write(c, WM8990_RESET, 0) +/* + * read wm8990 register cache + */ +static inline unsigned int wm8990_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg >= ARRAY_SIZE(wm8990_reg)); + return cache[reg]; +} + +/* + * write wm8990 register cache + */ +static inline void wm8990_write_reg_cache(struct snd_soc_codec *codec, + unsigned int reg, unsigned int value) +{ + u16 *cache = codec->reg_cache; + + /* Reset register and reserved registers are uncached */ + if (reg == 0 || reg >= ARRAY_SIZE(wm8990_reg)) + return; + + cache[reg] = value; +} + +/* + * write to the wm8990 register space + */ +static int wm8990_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u8 data[3]; + + data[0] = reg & 0xFF; + data[1] = (value >> 8) & 0xFF; + data[2] = value & 0xFF; + + wm8990_write_reg_cache(codec, reg, value); + + if (codec->hw_write(codec->control_data, data, 3) == 2) + return 0; + else + return -EIO; +} + +#define wm8990_reset(c) wm8990_write(c, WM8990_RESET, 0) static const DECLARE_TLV_DB_LINEAR(rec_mix_tlv, -1500, 600); @@ -141,8 +187,8 @@ static int wm899x_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, return ret; /* now hit the volume update bits (always bit 8) */ - val = snd_soc_read(codec, reg); - return snd_soc_write(codec, reg, val | 0x0100); + val = wm8990_read_reg_cache(codec, reg); + return wm8990_write(codec, reg, val | 0x0100); } #define SOC_WM899X_OUTPGA_SINGLE_R_TLV(xname, reg, shift, max, invert,\ @@ -381,8 +427,8 @@ static int inmixer_event(struct snd_soc_dapm_widget *w, { u16 reg, fakepower; - reg = snd_soc_read(w->codec, WM8990_POWER_MANAGEMENT_2); - fakepower = snd_soc_read(w->codec, WM8990_INTDRIVBITS); + reg = wm8990_read_reg_cache(w->codec, WM8990_POWER_MANAGEMENT_2); + fakepower = wm8990_read_reg_cache(w->codec, WM8990_INTDRIVBITS); if (fakepower & ((1 << WM8990_INMIXL_PWR_BIT) | (1 << WM8990_AINLMUX_PWR_BIT))) { @@ -397,7 +443,7 @@ static int inmixer_event(struct snd_soc_dapm_widget *w, } else { reg &= ~WM8990_AINL_ENA; } - snd_soc_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); + wm8990_write(w->codec, WM8990_POWER_MANAGEMENT_2, reg); return 0; } @@ -411,7 +457,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, switch (reg_shift) { case WM8990_SPEAKER_MIXER | (WM8990_LDSPK_BIT << 8) : - reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER1); + reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER1); if (reg & WM8990_LDLO) { printk(KERN_WARNING "Cannot set as Output Mixer 1 LDLO Set\n"); @@ -419,7 +465,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_SPEAKER_MIXER | (WM8990_RDSPK_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_OUTPUT_MIXER2); + reg = wm8990_read_reg_cache(w->codec, WM8990_OUTPUT_MIXER2); if (reg & WM8990_RDRO) { printk(KERN_WARNING "Cannot set as Output Mixer 2 RDRO Set\n"); @@ -427,7 +473,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER1 | (WM8990_LDLO_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); + reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); if (reg & WM8990_LDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer LDSPK Set\n"); @@ -435,7 +481,7 @@ static int outmixer_event(struct snd_soc_dapm_widget *w, } break; case WM8990_OUTPUT_MIXER2 | (WM8990_RDRO_BIT << 8): - reg = snd_soc_read(w->codec, WM8990_SPEAKER_MIXER); + reg = wm8990_read_reg_cache(w->codec, WM8990_SPEAKER_MIXER); if (reg & WM8990_RDSPK) { printk(KERN_WARNING "Cannot set as Speaker Mixer RDSPK Set\n"); @@ -983,24 +1029,24 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, pll_factors(&pll_div, freq_out * 4, freq_in); /* Turn on PLL */ - reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); + reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); reg |= WM8990_PLL_ENA; - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); /* sysclk comes from PLL */ - reg = snd_soc_read(codec, WM8990_CLOCKING_2); - snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); + reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2); + wm8990_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); /* set up N , fractional mode and pre-divisor if neccessary */ - snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | + wm8990_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | (pll_div.div2?WM8990_PRESCALE:0)); - snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); - snd_soc_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); + wm8990_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); + wm8990_write(codec, WM8990_PLL3, (u8)(pll_div.k & 0xFF)); } else { /* Turn on PLL */ - reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); + reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); reg &= ~WM8990_PLL_ENA; - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg); } return 0; } @@ -1027,8 +1073,8 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, struct snd_soc_codec *codec = codec_dai->codec; u16 audio1, audio3; - audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); - audio3 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_3); + audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); + audio3 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_3); /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { @@ -1069,8 +1115,8 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, return -EINVAL; } - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); + wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); + wm8990_write(codec, WM8990_AUDIO_INTERFACE_3, audio3); return 0; } @@ -1082,24 +1128,24 @@ static int wm8990_set_dai_clkdiv(struct snd_soc_dai *codec_dai, switch (div_id) { case WM8990_MCLK_DIV: - reg = snd_soc_read(codec, WM8990_CLOCKING_2) & + reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & ~WM8990_MCLK_DIV_MASK; - snd_soc_write(codec, WM8990_CLOCKING_2, reg | div); + wm8990_write(codec, WM8990_CLOCKING_2, reg | div); break; case WM8990_DACCLK_DIV: - reg = snd_soc_read(codec, WM8990_CLOCKING_2) & + reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & ~WM8990_DAC_CLKDIV_MASK; - snd_soc_write(codec, WM8990_CLOCKING_2, reg | div); + wm8990_write(codec, WM8990_CLOCKING_2, reg | div); break; case WM8990_ADCCLK_DIV: - reg = snd_soc_read(codec, WM8990_CLOCKING_2) & + reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_2) & ~WM8990_ADC_CLKDIV_MASK; - snd_soc_write(codec, WM8990_CLOCKING_2, reg | div); + wm8990_write(codec, WM8990_CLOCKING_2, reg | div); break; case WM8990_BCLK_DIV: - reg = snd_soc_read(codec, WM8990_CLOCKING_1) & + reg = wm8990_read_reg_cache(codec, WM8990_CLOCKING_1) & ~WM8990_BCLK_DIV_MASK; - snd_soc_write(codec, WM8990_CLOCKING_1, reg | div); + wm8990_write(codec, WM8990_CLOCKING_1, reg | div); break; default: return -EINVAL; @@ -1118,7 +1164,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_device *socdev = rtd->socdev; struct snd_soc_codec *codec = socdev->card->codec; - u16 audio1 = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_1); + u16 audio1 = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_1); audio1 &= ~WM8990_AIF_WL_MASK; /* bit size */ @@ -1136,7 +1182,7 @@ static int wm8990_hw_params(struct snd_pcm_substream *substream, break; } - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); + wm8990_write(codec, WM8990_AUDIO_INTERFACE_1, audio1); return 0; } @@ -1145,12 +1191,12 @@ static int wm8990_mute(struct snd_soc_dai *dai, int mute) struct snd_soc_codec *codec = dai->codec; u16 val; - val = snd_soc_read(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; + val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL) & ~WM8990_DAC_MUTE; if (mute) - snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); + wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); else - snd_soc_write(codec, WM8990_DAC_CTRL, val); + wm8990_write(codec, WM8990_DAC_CTRL, val); return 0; } @@ -1166,21 +1212,21 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VMID=2*50k */ - val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) & + val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & ~WM8990_VMID_MODE_MASK; - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x2); break; case SND_SOC_BIAS_STANDBY: if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Enable all output discharge bits */ - snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | + wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_ROUT); /* Enable POBCTRL, SOFT_ST, VMIDTOG and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_VMIDTOG); @@ -1188,83 +1234,83 @@ static int wm8990_set_bias_level(struct snd_soc_codec *codec, msleep(msecs_to_jiffies(300)); /* Disable VMIDTOG */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL); /* disable all output discharge bits */ - snd_soc_write(codec, WM8990_ANTIPOP1, 0); + wm8990_write(codec, WM8990_ANTIPOP1, 0); /* Enable outputs */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1b00); msleep(msecs_to_jiffies(50)); /* Enable VMID at 2x50k */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f02); msleep(msecs_to_jiffies(100)); /* Enable VREF */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); msleep(msecs_to_jiffies(600)); /* Enable BUFIOEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFIOEN); /* Disable outputs */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x3); /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); + wm8990_write(codec, WM8990_ANTIPOP2, WM8990_BUFIOEN); /* Enable workaround for ADC clocking issue. */ - snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); - snd_soc_write(codec, WM8990_EXT_CTL1, 0xa003); - snd_soc_write(codec, WM8990_EXT_ACCESS_ENA, 0); + wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0x2); + wm8990_write(codec, WM8990_EXT_CTL1, 0xa003); + wm8990_write(codec, WM8990_EXT_ACCESS_ENA, 0); } /* VMID=2*250k */ - val = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_1) & + val = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_1) & ~WM8990_VMID_MODE_MASK; - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, val | 0x4); break; case SND_SOC_BIAS_OFF: /* Enable POBCTRL and SOFT_ST */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_POBCTRL | WM8990_BUFIOEN); /* Enable POBCTRL, SOFT_ST and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | + wm8990_write(codec, WM8990_ANTIPOP2, WM8990_SOFTST | WM8990_BUFDCOPEN | WM8990_POBCTRL | WM8990_BUFIOEN); /* mute DAC */ - val = snd_soc_read(codec, WM8990_DAC_CTRL); - snd_soc_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); + val = wm8990_read_reg_cache(codec, WM8990_DAC_CTRL); + wm8990_write(codec, WM8990_DAC_CTRL, val | WM8990_DAC_MUTE); /* Enable any disabled outputs */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f03); /* Disable VMID */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x1f01); msleep(msecs_to_jiffies(300)); /* Enable all output discharge bits */ - snd_soc_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | + wm8990_write(codec, WM8990_ANTIPOP1, WM8990_DIS_LLINE | WM8990_DIS_RLINE | WM8990_DIS_OUT3 | WM8990_DIS_OUT4 | WM8990_DIS_LOUT | WM8990_DIS_ROUT); /* Disable VREF */ - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_1, 0x0); /* disable POBCTRL, SOFT_ST and BUFDCOPEN */ - snd_soc_write(codec, WM8990_ANTIPOP2, 0x0); + wm8990_write(codec, WM8990_ANTIPOP2, 0x0); break; } @@ -1365,6 +1411,8 @@ static int wm8990_init(struct snd_soc_device *socdev) codec->name = "WM8990"; codec->owner = THIS_MODULE; + codec->read = wm8990_read_reg_cache; + codec->write = wm8990_write; codec->set_bias_level = wm8990_set_bias_level; codec->dai = &wm8990_dai; codec->num_dai = 2; @@ -1374,12 +1422,6 @@ static int wm8990_init(struct snd_soc_device *socdev) if (codec->reg_cache == NULL) return -ENOMEM; - ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_I2C); - if (ret < 0) { - printk(KERN_ERR "wm8990: failed to set cache I/O: %d\n", ret); - goto pcm_err; - } - wm8990_reset(codec); /* register pcms */ @@ -1393,18 +1435,18 @@ static int wm8990_init(struct snd_soc_device *socdev) codec->bias_level = SND_SOC_BIAS_OFF; wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY); - reg = snd_soc_read(codec, WM8990_AUDIO_INTERFACE_4); - snd_soc_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); + reg = wm8990_read_reg_cache(codec, WM8990_AUDIO_INTERFACE_4); + wm8990_write(codec, WM8990_AUDIO_INTERFACE_4, reg | WM8990_ALRCGPIO1); - reg = snd_soc_read(codec, WM8990_GPIO1_GPIO2) & + reg = wm8990_read_reg_cache(codec, WM8990_GPIO1_GPIO2) & ~WM8990_GPIO1_SEL_MASK; - snd_soc_write(codec, WM8990_GPIO1_GPIO2, reg | 1); + wm8990_write(codec, WM8990_GPIO1_GPIO2, reg | 1); - reg = snd_soc_read(codec, WM8990_POWER_MANAGEMENT_2); - snd_soc_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); + reg = wm8990_read_reg_cache(codec, WM8990_POWER_MANAGEMENT_2); + wm8990_write(codec, WM8990_POWER_MANAGEMENT_2, reg | WM8990_OPCLK_ENA); - snd_soc_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); - snd_soc_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); + wm8990_write(codec, WM8990_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8)); + wm8990_write(codec, WM8990_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8)); snd_soc_add_controls(codec, wm8990_snd_controls, ARRAY_SIZE(wm8990_snd_controls)); diff --git a/trunk/sound/soc/codecs/wm9081.c b/trunk/sound/soc/codecs/wm9081.c index 1f51dd542a46..c96532351193 100644 --- a/trunk/sound/soc/codecs/wm9081.c +++ b/trunk/sound/soc/codecs/wm9081.c @@ -168,19 +168,84 @@ struct wm9081_priv { struct wm9081_retune_mobile_config *retune; }; -static int wm9081_volatile_register(unsigned int reg) +static int wm9081_reg_is_volatile(int reg) { switch (reg) { - case WM9081_SOFTWARE_RESET: - return 1; default: return 0; } } +static unsigned int wm9081_read_reg_cache(struct snd_soc_codec *codec, + unsigned int reg) +{ + u16 *cache = codec->reg_cache; + BUG_ON(reg > WM9081_MAX_REGISTER); + return cache[reg]; +} + +static unsigned int wm9081_read_hw(struct snd_soc_codec *codec, u8 reg) +{ + struct i2c_msg xfer[2]; + u16 data; + int ret; + struct i2c_client *client = codec->control_data; + + BUG_ON(reg > WM9081_MAX_REGISTER); + + /* Write register */ + xfer[0].addr = client->addr; + xfer[0].flags = 0; + xfer[0].len = 1; + xfer[0].buf = ® + + /* Read data */ + xfer[1].addr = client->addr; + xfer[1].flags = I2C_M_RD; + xfer[1].len = 2; + xfer[1].buf = (u8 *)&data; + + ret = i2c_transfer(client->adapter, xfer, 2); + if (ret != 2) { + dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); + return 0; + } + + return (data >> 8) | ((data & 0xff) << 8); +} + +static unsigned int wm9081_read(struct snd_soc_codec *codec, unsigned int reg) +{ + if (wm9081_reg_is_volatile(reg)) + return wm9081_read_hw(codec, reg); + else + return wm9081_read_reg_cache(codec, reg); +} + +static int wm9081_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int value) +{ + u16 *cache = codec->reg_cache; + u8 data[3]; + + BUG_ON(reg > WM9081_MAX_REGISTER); + + if (!wm9081_reg_is_volatile(reg)) + cache[reg] = value; + + data[0] = reg; + data[1] = value >> 8; + data[2] = value & 0x00ff; + + if (codec->hw_write(codec->control_data, data, 3) == 3) + return 0; + else + return -EIO; +} + static int wm9081_reset(struct snd_soc_codec *codec) { - return snd_soc_write(codec, WM9081_SOFTWARE_RESET, 0); + return wm9081_write(codec, WM9081_SOFTWARE_RESET, 0); } static const DECLARE_TLV_DB_SCALE(drc_in_tlv, -4500, 75, 0); @@ -291,7 +356,7 @@ static int speaker_mode_get(struct snd_kcontrol *kcontrol, struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); unsigned int reg; - reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); + reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); if (reg & WM9081_SPK_MODE) ucontrol->value.integer.value[0] = 1; else @@ -310,8 +375,8 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int reg_pwr = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); - unsigned int reg2 = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_2); + unsigned int reg_pwr = wm9081_read(codec, WM9081_POWER_MANAGEMENT); + unsigned int reg2 = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_2); /* Are we changing anything? */ if (ucontrol->value.integer.value[0] == @@ -332,7 +397,7 @@ static int speaker_mode_put(struct snd_kcontrol *kcontrol, reg2 &= ~WM9081_SPK_MODE; } - snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); + wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_2, reg2); return 0; } @@ -391,7 +456,7 @@ static int speaker_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_codec *codec = w->codec; - unsigned int reg = snd_soc_read(codec, WM9081_POWER_MANAGEMENT); + unsigned int reg = wm9081_read(codec, WM9081_POWER_MANAGEMENT); switch (event) { case SND_SOC_DAPM_POST_PMU: @@ -403,7 +468,7 @@ static int speaker_event(struct snd_soc_dapm_widget *w, break; } - snd_soc_write(codec, WM9081_POWER_MANAGEMENT, reg); + wm9081_write(codec, WM9081_POWER_MANAGEMENT, reg); return 0; } @@ -542,7 +607,7 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id, if (ret != 0) return ret; - reg5 = snd_soc_read(codec, WM9081_FLL_CONTROL_5); + reg5 = wm9081_read(codec, WM9081_FLL_CONTROL_5); reg5 &= ~WM9081_FLL_CLK_SRC_MASK; switch (fll_id) { @@ -556,44 +621,44 @@ static int wm9081_set_fll(struct snd_soc_codec *codec, int fll_id, } /* Disable CLK_SYS while we reconfigure */ - clk_sys_reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3); + clk_sys_reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); if (clk_sys_reg & WM9081_CLK_SYS_ENA) - snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, + wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg & ~WM9081_CLK_SYS_ENA); /* Any FLL configuration change requires that the FLL be * disabled first. */ - reg1 = snd_soc_read(codec, WM9081_FLL_CONTROL_1); + reg1 = wm9081_read(codec, WM9081_FLL_CONTROL_1); reg1 &= ~WM9081_FLL_ENA; - snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1); + wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); /* Apply the configuration */ if (fll_div.k) reg1 |= WM9081_FLL_FRAC_MASK; else reg1 &= ~WM9081_FLL_FRAC_MASK; - snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1); + wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1); - snd_soc_write(codec, WM9081_FLL_CONTROL_2, + wm9081_write(codec, WM9081_FLL_CONTROL_2, (fll_div.fll_outdiv << WM9081_FLL_OUTDIV_SHIFT) | (fll_div.fll_fratio << WM9081_FLL_FRATIO_SHIFT)); - snd_soc_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); + wm9081_write(codec, WM9081_FLL_CONTROL_3, fll_div.k); - reg4 = snd_soc_read(codec, WM9081_FLL_CONTROL_4); + reg4 = wm9081_read(codec, WM9081_FLL_CONTROL_4); reg4 &= ~WM9081_FLL_N_MASK; reg4 |= fll_div.n << WM9081_FLL_N_SHIFT; - snd_soc_write(codec, WM9081_FLL_CONTROL_4, reg4); + wm9081_write(codec, WM9081_FLL_CONTROL_4, reg4); reg5 &= ~WM9081_FLL_CLK_REF_DIV_MASK; reg5 |= fll_div.fll_clk_ref_div << WM9081_FLL_CLK_REF_DIV_SHIFT; - snd_soc_write(codec, WM9081_FLL_CONTROL_5, reg5); + wm9081_write(codec, WM9081_FLL_CONTROL_5, reg5); /* Enable the FLL */ - snd_soc_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); + wm9081_write(codec, WM9081_FLL_CONTROL_1, reg1 | WM9081_FLL_ENA); /* Then bring CLK_SYS up again if it was disabled */ if (clk_sys_reg & WM9081_CLK_SYS_ENA) - snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); + wm9081_write(codec, WM9081_CLOCK_CONTROL_3, clk_sys_reg); dev_dbg(codec->dev, "FLL enabled at %dHz->%dHz\n", Fref, Fout); @@ -677,19 +742,19 @@ static int configure_clock(struct snd_soc_codec *codec) return -EINVAL; } - reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_1); + reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_1); if (mclkdiv) reg |= WM9081_MCLKDIV2; else reg &= ~WM9081_MCLKDIV2; - snd_soc_write(codec, WM9081_CLOCK_CONTROL_1, reg); + wm9081_write(codec, WM9081_CLOCK_CONTROL_1, reg); - reg = snd_soc_read(codec, WM9081_CLOCK_CONTROL_3); + reg = wm9081_read(codec, WM9081_CLOCK_CONTROL_3); if (fll) reg |= WM9081_CLK_SRC_SEL; else reg &= ~WM9081_CLK_SRC_SEL; - snd_soc_write(codec, WM9081_CLOCK_CONTROL_3, reg); + wm9081_write(codec, WM9081_CLOCK_CONTROL_3, reg); dev_dbg(codec->dev, "CLK_SYS is %dHz\n", wm9081->sysclk_rate); @@ -789,76 +854,76 @@ static int wm9081_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: /* VMID=2*40k */ - reg = snd_soc_read(codec, WM9081_VMID_CONTROL); + reg = wm9081_read(codec, WM9081_VMID_CONTROL); reg &= ~WM9081_VMID_SEL_MASK; reg |= 0x2; - snd_soc_write(codec, WM9081_VMID_CONTROL, reg); + wm9081_write(codec, WM9081_VMID_CONTROL, reg); /* Normal bias current */ - reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg &= ~WM9081_STBY_BIAS_ENA; - snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); break; case SND_SOC_BIAS_STANDBY: /* Initial cold start */ if (codec->bias_level == SND_SOC_BIAS_OFF) { /* Disable LINEOUT discharge */ - reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); + reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); reg &= ~WM9081_LINEOUT_DISCH; - snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); + wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); /* Select startup bias source */ - reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg |= WM9081_BIAS_SRC | WM9081_BIAS_ENA; - snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); /* VMID 2*4k; Soft VMID ramp enable */ - reg = snd_soc_read(codec, WM9081_VMID_CONTROL); + reg = wm9081_read(codec, WM9081_VMID_CONTROL); reg |= WM9081_VMID_RAMP | 0x6; - snd_soc_write(codec, WM9081_VMID_CONTROL, reg); + wm9081_write(codec, WM9081_VMID_CONTROL, reg); mdelay(100); /* Normal bias enable & soft start off */ reg |= WM9081_BIAS_ENA; reg &= ~WM9081_VMID_RAMP; - snd_soc_write(codec, WM9081_VMID_CONTROL, reg); + wm9081_write(codec, WM9081_VMID_CONTROL, reg); /* Standard bias source */ - reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg &= ~WM9081_BIAS_SRC; - snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); } /* VMID 2*240k */ - reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg &= ~WM9081_VMID_SEL_MASK; reg |= 0x40; - snd_soc_write(codec, WM9081_VMID_CONTROL, reg); + wm9081_write(codec, WM9081_VMID_CONTROL, reg); /* Standby bias current on */ - reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg |= WM9081_STBY_BIAS_ENA; - snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); break; case SND_SOC_BIAS_OFF: /* Startup bias source */ - reg = snd_soc_read(codec, WM9081_BIAS_CONTROL_1); + reg = wm9081_read(codec, WM9081_BIAS_CONTROL_1); reg |= WM9081_BIAS_SRC; - snd_soc_write(codec, WM9081_BIAS_CONTROL_1, reg); + wm9081_write(codec, WM9081_BIAS_CONTROL_1, reg); /* Disable VMID and biases with soft ramping */ - reg = snd_soc_read(codec, WM9081_VMID_CONTROL); + reg = wm9081_read(codec, WM9081_VMID_CONTROL); reg &= ~(WM9081_VMID_SEL_MASK | WM9081_BIAS_ENA); reg |= WM9081_VMID_RAMP; - snd_soc_write(codec, WM9081_VMID_CONTROL, reg); + wm9081_write(codec, WM9081_VMID_CONTROL, reg); /* Actively discharge LINEOUT */ - reg = snd_soc_read(codec, WM9081_ANTI_POP_CONTROL); + reg = wm9081_read(codec, WM9081_ANTI_POP_CONTROL); reg |= WM9081_LINEOUT_DISCH; - snd_soc_write(codec, WM9081_ANTI_POP_CONTROL, reg); + wm9081_write(codec, WM9081_ANTI_POP_CONTROL, reg); break; } @@ -872,7 +937,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, { struct snd_soc_codec *codec = dai->codec; struct wm9081_priv *wm9081 = codec->private_data; - unsigned int aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2); + unsigned int aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); aif2 &= ~(WM9081_AIF_BCLK_INV | WM9081_AIF_LRCLK_INV | WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK); @@ -953,7 +1018,7 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, return -EINVAL; } - snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); return 0; } @@ -967,18 +1032,18 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream, int ret, i, best, best_val, cur_val; unsigned int clk_ctrl2, aif1, aif2, aif3, aif4; - clk_ctrl2 = snd_soc_read(codec, WM9081_CLOCK_CONTROL_2); + clk_ctrl2 = wm9081_read(codec, WM9081_CLOCK_CONTROL_2); clk_ctrl2 &= ~(WM9081_CLK_SYS_RATE_MASK | WM9081_SAMPLE_RATE_MASK); - aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1); + aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); - aif2 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_2); + aif2 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_2); aif2 &= ~WM9081_AIF_WL_MASK; - aif3 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_3); + aif3 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_3); aif3 &= ~WM9081_BCLK_DIV_MASK; - aif4 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_4); + aif4 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_4); aif4 &= ~WM9081_LRCLK_RATE_MASK; /* What BCLK do we need? */ @@ -1092,22 +1157,22 @@ static int wm9081_hw_params(struct snd_pcm_substream *substream, s->name, s->rate); /* If the EQ is enabled then disable it while we write out */ - eq1 = snd_soc_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; + eq1 = wm9081_read(codec, WM9081_EQ_1) & WM9081_EQ_ENA; if (eq1 & WM9081_EQ_ENA) - snd_soc_write(codec, WM9081_EQ_1, 0); + wm9081_write(codec, WM9081_EQ_1, 0); /* Write out the other values */ for (i = 1; i < ARRAY_SIZE(s->config); i++) - snd_soc_write(codec, WM9081_EQ_1 + i, s->config[i]); + wm9081_write(codec, WM9081_EQ_1 + i, s->config[i]); eq1 |= (s->config[0] & ~WM9081_EQ_ENA); - snd_soc_write(codec, WM9081_EQ_1, eq1); + wm9081_write(codec, WM9081_EQ_1, eq1); } - snd_soc_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); - snd_soc_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); - snd_soc_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); - snd_soc_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); + wm9081_write(codec, WM9081_CLOCK_CONTROL_2, clk_ctrl2); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_2, aif2); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_3, aif3); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_4, aif4); return 0; } @@ -1117,14 +1182,14 @@ static int wm9081_digital_mute(struct snd_soc_dai *codec_dai, int mute) struct snd_soc_codec *codec = codec_dai->codec; unsigned int reg; - reg = snd_soc_read(codec, WM9081_DAC_DIGITAL_2); + reg = wm9081_read(codec, WM9081_DAC_DIGITAL_2); if (mute) reg |= WM9081_DAC_MUTE; else reg &= ~WM9081_DAC_MUTE; - snd_soc_write(codec, WM9081_DAC_DIGITAL_2, reg); + wm9081_write(codec, WM9081_DAC_DIGITAL_2, reg); return 0; } @@ -1149,11 +1214,12 @@ static int wm9081_set_sysclk(struct snd_soc_dai *codec_dai, return 0; } +/* FIXME: Needs to handle slot_width */ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct snd_soc_codec *codec = dai->codec; - unsigned int aif1 = snd_soc_read(codec, WM9081_AUDIO_INTERFACE_1); + unsigned int aif1 = wm9081_read(codec, WM9081_AUDIO_INTERFACE_1); aif1 &= ~(WM9081_AIFDAC_TDM_SLOT_MASK | WM9081_AIFDAC_TDM_MODE_MASK); @@ -1162,7 +1228,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, aif1 |= (slots - 1) << WM9081_AIFDAC_TDM_MODE_SHIFT; - switch (mask) { + switch (rx_mask) { case 1: break; case 2: @@ -1178,7 +1244,7 @@ static int wm9081_set_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; } - snd_soc_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); + wm9081_write(codec, WM9081_AUDIO_INTERFACE_1, aif1); return 0; } @@ -1300,7 +1366,7 @@ static int wm9081_resume(struct platform_device *pdev) if (i == WM9081_SOFTWARE_RESET) continue; - snd_soc_write(codec, i, reg_cache[i]); + wm9081_write(codec, i, reg_cache[i]); } wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); @@ -1320,8 +1386,7 @@ struct snd_soc_codec_device soc_codec_dev_wm9081 = { }; EXPORT_SYMBOL_GPL(soc_codec_dev_wm9081); -static int wm9081_register(struct wm9081_priv *wm9081, - enum snd_soc_control_type control) +static int wm9081_register(struct wm9081_priv *wm9081) { struct snd_soc_codec *codec = &wm9081->codec; int ret; @@ -1340,24 +1405,19 @@ static int wm9081_register(struct wm9081_priv *wm9081, codec->private_data = wm9081; codec->name = "WM9081"; codec->owner = THIS_MODULE; + codec->read = wm9081_read; + codec->write = wm9081_write; codec->dai = &wm9081_dai; codec->num_dai = 1; codec->reg_cache_size = ARRAY_SIZE(wm9081->reg_cache); codec->reg_cache = &wm9081->reg_cache; codec->bias_level = SND_SOC_BIAS_OFF; codec->set_bias_level = wm9081_set_bias_level; - codec->volatile_register = wm9081_volatile_register; memcpy(codec->reg_cache, wm9081_reg_defaults, sizeof(wm9081_reg_defaults)); - ret = snd_soc_codec_set_cache_io(codec, 8, 16, control); - if (ret != 0) { - dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); - return ret; - } - - reg = snd_soc_read(codec, WM9081_SOFTWARE_RESET); + reg = wm9081_read_hw(codec, WM9081_SOFTWARE_RESET); if (reg != 0x9081) { dev_err(codec->dev, "Device is not a WM9081: ID=0x%x\n", reg); ret = -EINVAL; @@ -1373,10 +1433,10 @@ static int wm9081_register(struct wm9081_priv *wm9081, wm9081_set_bias_level(codec, SND_SOC_BIAS_STANDBY); /* Enable zero cross by default */ - reg = snd_soc_read(codec, WM9081_ANALOGUE_LINEOUT); - snd_soc_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); - reg = snd_soc_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); - snd_soc_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, + reg = wm9081_read(codec, WM9081_ANALOGUE_LINEOUT); + wm9081_write(codec, WM9081_ANALOGUE_LINEOUT, reg | WM9081_LINEOUTZC); + reg = wm9081_read(codec, WM9081_ANALOGUE_SPEAKER_PGA); + wm9081_write(codec, WM9081_ANALOGUE_SPEAKER_PGA, reg | WM9081_SPKPGAZC); wm9081_dai.dev = codec->dev; @@ -1431,7 +1491,7 @@ static __devinit int wm9081_i2c_probe(struct i2c_client *i2c, codec->dev = &i2c->dev; - return wm9081_register(wm9081, SND_SOC_I2C); + return wm9081_register(wm9081); } static __devexit int wm9081_i2c_remove(struct i2c_client *client) diff --git a/trunk/sound/soc/davinci/Kconfig b/trunk/sound/soc/davinci/Kconfig index 677a53814878..6802dd5e4731 100644 --- a/trunk/sound/soc/davinci/Kconfig +++ b/trunk/sound/soc/davinci/Kconfig @@ -41,14 +41,3 @@ config SND_DAVINCI_SOC_SFFSDR help Say Y if you want to add support for SoC audio on Lyrtech SFFSDR board. - -config SND_DA830_SOC_EVM - tristate "SoC Audio support for DA830/OMAPL137 EVM" - depends on SND_DAVINCI_SOC && MACH_DAVINCI_DA830_EVM - select SND_DAVINCI_SOC_MCASP - select SND_SOC_TLV320AIC3X - - help - Say Y if you want to add support for SoC audio on TI - DA830/OMAPL137 EVM - diff --git a/trunk/sound/soc/davinci/Makefile b/trunk/sound/soc/davinci/Makefile index 5e2195f80cf1..67be54f3a3a5 100644 --- a/trunk/sound/soc/davinci/Makefile +++ b/trunk/sound/soc/davinci/Makefile @@ -13,5 +13,4 @@ snd-soc-sffsdr-objs := davinci-sffsdr.o obj-$(CONFIG_SND_DAVINCI_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DM6467_SOC_EVM) += snd-soc-evm.o -obj-$(CONFIG_SND_DA830_SOC_EVM) += snd-soc-evm.o obj-$(CONFIG_SND_DAVINCI_SOC_SFFSDR) += snd-soc-sffsdr.o diff --git a/trunk/sound/soc/davinci/davinci-evm.c b/trunk/sound/soc/davinci/davinci-evm.c index a5a92124b6d5..f3bb6f60f205 100644 --- a/trunk/sound/soc/davinci/davinci-evm.c +++ b/trunk/sound/soc/davinci/davinci-evm.c @@ -54,9 +54,6 @@ static int evm_hw_params(struct snd_pcm_substream *substream, else if (machine_is_davinci_evm()) sysclk = 12288000; - else if (machine_is_davinci_da830_evm()) - sysclk = 24576000; - else return -EINVAL; @@ -165,14 +162,6 @@ static struct snd_soc_dai_link dm6467_evm_dai[] = { .ops = &evm_ops, }, }; -static struct snd_soc_dai_link da830_evm_dai = { - .name = "TLV320AIC3X", - .stream_name = "AIC3X", - .cpu_dai = &davinci_mcasp_dai[DAVINCI_MCASP_I2S_DAI], - .codec_dai = &aic3x_dai, - .init = evm_aic3x_init, - .ops = &evm_ops, -}; /* davinci-evm audio machine driver */ static struct snd_soc_card snd_soc_card_evm = { @@ -190,13 +179,6 @@ static struct snd_soc_card dm6467_snd_soc_card_evm = { .num_links = ARRAY_SIZE(dm6467_evm_dai), }; -static struct snd_soc_card da830_snd_soc_card = { - .name = "DA830 EVM", - .dai_link = &da830_evm_dai, - .platform = &davinci_soc_platform, - .num_links = 1, -}; - /* evm audio private data */ static struct aic3x_setup_data evm_aic3x_setup = { .i2c_bus = 1, @@ -209,11 +191,6 @@ static struct aic3x_setup_data dm6467_evm_aic3x_setup = { .i2c_address = 0x18, }; -static struct aic3x_setup_data da830_evm_aic3x_setup = { - .i2c_bus = 1, - .i2c_address = 0x18, -}; - /* evm audio subsystem */ static struct snd_soc_device evm_snd_devdata = { .card = &snd_soc_card_evm, @@ -228,13 +205,6 @@ static struct snd_soc_device dm6467_evm_snd_devdata = { .codec_data = &dm6467_evm_aic3x_setup, }; -/* evm audio subsystem */ -static struct snd_soc_device da830_evm_snd_devdata = { - .card = &da830_snd_soc_card, - .codec_dev = &soc_codec_dev_aic3x, - .codec_data = &da830_evm_aic3x_setup, -}; - static struct platform_device *evm_snd_device; static int __init evm_init(void) @@ -252,9 +222,6 @@ static int __init evm_init(void) } else if (machine_is_davinci_dm6467_evm()) { evm_snd_dev_data = &dm6467_evm_snd_devdata; index = 0; - } else if (machine_is_davinci_da830_evm()) { - evm_snd_dev_data = &da830_evm_snd_devdata; - index = 1; } else return -EINVAL; diff --git a/trunk/sound/soc/davinci/davinci-i2s.c b/trunk/sound/soc/davinci/davinci-i2s.c index 2a56fb78f67a..e5cd97b74c50 100644 --- a/trunk/sound/soc/davinci/davinci-i2s.c +++ b/trunk/sound/soc/davinci/davinci-i2s.c @@ -353,8 +353,9 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct davinci_pcm_dma_params *dma_params = dai->dma_data; - struct davinci_mcbsp_dev *dev = dai->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_pcm_dma_params *dma_params = rtd->dai->cpu_dai->dma_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; struct snd_interval *i = NULL; int mcbsp_word_length; unsigned int rcr, xcr, srgr; @@ -424,7 +425,8 @@ static int davinci_i2s_hw_params(struct snd_pcm_substream *substream, static int davinci_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct davinci_mcbsp_dev *dev = dai->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); davinci_mcbsp_stop(dev, playback); if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) { @@ -437,7 +439,8 @@ static int davinci_i2s_prepare(struct snd_pcm_substream *substream, static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { - struct davinci_mcbsp_dev *dev = dai->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; int ret = 0; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); if ((dev->pcr & DAVINCI_MCBSP_PCR_FSXM) == 0) @@ -463,7 +466,8 @@ static int davinci_i2s_trigger(struct snd_pcm_substream *substream, int cmd, static void davinci_i2s_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct davinci_mcbsp_dev *dev = dai->private_data; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct davinci_mcbsp_dev *dev = rtd->dai->cpu_dai->private_data; int playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); davinci_mcbsp_stop(dev, playback); } diff --git a/trunk/sound/soc/davinci/davinci-pcm.c b/trunk/sound/soc/davinci/davinci-pcm.c index ab43a539c11d..8fd0c3cdc710 100644 --- a/trunk/sound/soc/davinci/davinci-pcm.c +++ b/trunk/sound/soc/davinci/davinci-pcm.c @@ -244,11 +244,6 @@ static int davinci_pcm_open(struct snd_pcm_substream *substream) int ret = 0; snd_soc_set_runtime_hwparams(substream, &davinci_pcm_hardware); - /* ensure that buffer size is a multiple of period size */ - ret = snd_pcm_hw_constraint_integer(runtime, - SNDRV_PCM_HW_PARAM_PERIODS); - if (ret < 0) - return ret; prtd = kzalloc(sizeof(struct davinci_runtime_data), GFP_KERNEL); if (prtd == NULL) diff --git a/trunk/sound/soc/omap/ams-delta.c b/trunk/sound/soc/omap/ams-delta.c index 5a5166ac7279..4f35b1f18cb9 100644 --- a/trunk/sound/soc/omap/ams-delta.c +++ b/trunk/sound/soc/omap/ams-delta.c @@ -500,7 +500,7 @@ static int ams_delta_cx20442_init(struct snd_soc_codec *codec) } /* Register optional line discipline for over the modem control */ - ret = tty_register_ldisc(N_V253, &cx81801_ops); + ret = tty_register_ldisc(N_AMSDELTA, &cx81801_ops); if (ret) { dev_warn(card->dev, "Failed to register line discipline, " @@ -625,9 +625,9 @@ static void __exit ams_delta_module_exit(void) } } - if (tty_unregister_ldisc(N_V253) != 0) + if (tty_unregister_ldisc(N_AMSDELTA) != 0) dev_warn(&ams_delta_audio_platform_device->dev, - "failed to unregister V253 line discipline\n"); + "failed to unregister AMSDELTA line discipline\n"); snd_soc_jack_free_gpios(&ams_delta_hook_switch, ARRAY_SIZE(ams_delta_hook_switch_gpios), diff --git a/trunk/sound/soc/omap/omap-mcbsp.c b/trunk/sound/soc/omap/omap-mcbsp.c index 6a837ffd5d0b..a5d46a7b196a 100644 --- a/trunk/sound/soc/omap/omap-mcbsp.c +++ b/trunk/sound/soc/omap/omap-mcbsp.c @@ -183,21 +183,21 @@ static int omap_mcbsp_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data); - int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); + int err = 0; switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - mcbsp_data->active++; - omap_mcbsp_start(mcbsp_data->bus_id, play, !play); + if (!mcbsp_data->active++) + omap_mcbsp_start(mcbsp_data->bus_id); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - omap_mcbsp_stop(mcbsp_data->bus_id, play, !play); - mcbsp_data->active--; + if (!--mcbsp_data->active) + omap_mcbsp_stop(mcbsp_data->bus_id); break; default: err = -EINVAL; diff --git a/trunk/sound/soc/pxa/magician.c b/trunk/sound/soc/pxa/magician.c index 8889cd371608..9f7c61e23daf 100644 --- a/trunk/sound/soc/pxa/magician.c +++ b/trunk/sound/soc/pxa/magician.c @@ -190,7 +190,7 @@ static int magician_playback_hw_params(struct snd_pcm_substream *substream, if (ret < 0) return ret; - ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 1); + ret = snd_soc_dai_set_tdm_slot(cpu_dai, 1, 0, 1, width); if (ret < 0) return ret; diff --git a/trunk/sound/soc/pxa/pxa-ssp.c b/trunk/sound/soc/pxa/pxa-ssp.c index e22c5cef8fec..5b9ed6464789 100644 --- a/trunk/sound/soc/pxa/pxa-ssp.c +++ b/trunk/sound/soc/pxa/pxa-ssp.c @@ -375,21 +375,34 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, * Set the active slots in TDM/Network mode */ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, - unsigned int mask, int slots) + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct ssp_priv *priv = cpu_dai->private_data; struct ssp_device *ssp = priv->dev.ssp; u32 sscr0; - sscr0 = ssp_read_reg(ssp, SSCR0) & ~SSCR0_SlotsPerFrm(7); + sscr0 = ssp_read_reg(ssp, SSCR0); + sscr0 &= ~(SSCR0_MOD | SSCR0_SlotsPerFrm(8) | SSCR0_EDSS | SSCR0_DSS); + + /* set slot width */ + if (slot_width > 16) + sscr0 |= SSCR0_EDSS | SSCR0_DataSize(slot_width - 16); + else + sscr0 |= SSCR0_DataSize(slot_width); - /* set number of active slots */ - sscr0 |= SSCR0_SlotsPerFrm(slots); + if (slots > 1) { + /* enable network mode */ + sscr0 |= SSCR0_MOD; + + /* set number of active slots */ + sscr0 |= SSCR0_SlotsPerFrm(slots); + + /* set active slot mask */ + ssp_write_reg(ssp, SSTSA, tx_mask); + ssp_write_reg(ssp, SSRSA, rx_mask); + } ssp_write_reg(ssp, SSCR0, sscr0); - /* set active slot mask */ - ssp_write_reg(ssp, SSTSA, mask); - ssp_write_reg(ssp, SSRSA, mask); return 0; } diff --git a/trunk/sound/soc/s3c24xx/s3c2443-ac97.c b/trunk/sound/soc/s3c24xx/s3c2443-ac97.c index bf16f20fcbb3..3f03d5ddfacd 100644 --- a/trunk/sound/soc/s3c24xx/s3c2443-ac97.c +++ b/trunk/sound/soc/s3c24xx/s3c2443-ac97.c @@ -47,7 +47,7 @@ static struct s3c24xx_ac97_info s3c24xx_ac97; static DECLARE_COMPLETION(ac97_completion); static u32 codec_ready; -static DEFINE_MUTEX(ac97_mutex); +static DECLARE_MUTEX(ac97_mutex); static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, unsigned short reg) @@ -56,7 +56,7 @@ static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, u32 ac_codec_cmd; u32 stat, addr, data; - mutex_lock(&ac97_mutex); + down(&ac97_mutex); codec_ready = S3C_AC97_GLBSTAT_CODECREADY; ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); @@ -79,7 +79,7 @@ static unsigned short s3c2443_ac97_read(struct snd_ac97 *ac97, printk(KERN_ERR "s3c24xx-ac97: req addr = %02x," " rep addr = %02x\n", reg, addr); - mutex_unlock(&ac97_mutex); + up(&ac97_mutex); return (unsigned short)data; } @@ -90,7 +90,7 @@ static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, u32 ac_glbctrl; u32 ac_codec_cmd; - mutex_lock(&ac97_mutex); + down(&ac97_mutex); codec_ready = S3C_AC97_GLBSTAT_CODECREADY; ac_codec_cmd = readl(s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); @@ -109,7 +109,7 @@ static void s3c2443_ac97_write(struct snd_ac97 *ac97, unsigned short reg, ac_codec_cmd |= S3C_AC97_CODEC_CMD_READ; writel(ac_codec_cmd, s3c24xx_ac97.regs + S3C_AC97_CODEC_CMD); - mutex_unlock(&ac97_mutex); + up(&ac97_mutex); } diff --git a/trunk/sound/soc/soc-cache.c b/trunk/sound/soc/soc-cache.c deleted file mode 100644 index c8ceddc2a26c..000000000000 --- a/trunk/sound/soc/soc-cache.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * soc-cache.c -- ASoC register cache helpers - * - * Copyright 2009 Wolfson Microelectronics PLC. - * - * Author: Mark Brown - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - */ - -#include -#include -#include - -static unsigned int snd_soc_7_9_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - if (reg >= codec->reg_cache_size) - return -1; - return cache[reg]; -} - -static int snd_soc_7_9_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *cache = codec->reg_cache; - u8 data[2]; - int ret; - - BUG_ON(codec->volatile_register); - - data[0] = (reg << 1) | ((value >> 8) & 0x0001); - data[1] = value & 0x00ff; - - if (reg < codec->reg_cache_size) - cache[reg] = value; - ret = codec->hw_write(codec->control_data, data, 2); - if (ret == 2) - return 0; - if (ret < 0) - return ret; - else - return -EIO; -} - -#if defined(CONFIG_SPI_MASTER) -static int snd_soc_7_9_spi_write(void *control_data, const char *data, - int len) -{ - struct spi_device *spi = control_data; - struct spi_transfer t; - struct spi_message m; - u8 msg[2]; - - if (len <= 0) - return 0; - - msg[0] = data[0]; - msg[1] = data[1]; - - spi_message_init(&m); - memset(&t, 0, (sizeof t)); - - t.tx_buf = &msg[0]; - t.len = len; - - spi_message_add_tail(&t, &m); - spi_sync(spi, &m); - - return len; -} -#else -#define snd_soc_7_9_spi_write NULL -#endif - -static int snd_soc_8_16_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) -{ - u16 *reg_cache = codec->reg_cache; - u8 data[3]; - - data[0] = reg; - data[1] = (value >> 8) & 0xff; - data[2] = value & 0xff; - - if (!snd_soc_codec_volatile_register(codec, reg)) - reg_cache[reg] = value; - - if (codec->hw_write(codec->control_data, data, 3) == 3) - return 0; - else - return -EIO; -} - -static unsigned int snd_soc_8_16_read(struct snd_soc_codec *codec, - unsigned int reg) -{ - u16 *cache = codec->reg_cache; - - if (reg >= codec->reg_cache_size || - snd_soc_codec_volatile_register(codec, reg)) - return codec->hw_read(codec, reg); - else - return cache[reg]; -} - -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) -static unsigned int snd_soc_8_16_read_i2c(struct snd_soc_codec *codec, - unsigned int r) -{ - struct i2c_msg xfer[2]; - u8 reg = r; - u16 data; - int ret; - struct i2c_client *client = codec->control_data; - - /* Write register */ - xfer[0].addr = client->addr; - xfer[0].flags = 0; - xfer[0].len = 1; - xfer[0].buf = ® - - /* Read data */ - xfer[1].addr = client->addr; - xfer[1].flags = I2C_M_RD; - xfer[1].len = 2; - xfer[1].buf = (u8 *)&data; - - ret = i2c_transfer(client->adapter, xfer, 2); - if (ret != 2) { - dev_err(&client->dev, "i2c_transfer() returned %d\n", ret); - return 0; - } - - return (data >> 8) | ((data & 0xff) << 8); -} -#else -#define snd_soc_8_16_read_i2c NULL -#endif - -static struct { - int addr_bits; - int data_bits; - int (*write)(struct snd_soc_codec *codec, unsigned int, unsigned int); - int (*spi_write)(void *, const char *, int); - unsigned int (*read)(struct snd_soc_codec *, unsigned int); - unsigned int (*i2c_read)(struct snd_soc_codec *, unsigned int); -} io_types[] = { - { 7, 9, snd_soc_7_9_write, snd_soc_7_9_spi_write, snd_soc_7_9_read }, - { 8, 16, snd_soc_8_16_write, NULL, snd_soc_8_16_read, - snd_soc_8_16_read_i2c }, -}; - -/** - * snd_soc_codec_set_cache_io: Set up standard I/O functions. - * - * @codec: CODEC to configure. - * @type: Type of cache. - * @addr_bits: Number of bits of register address data. - * @data_bits: Number of bits of data per register. - * @control: Control bus used. - * - * Register formats are frequently shared between many I2C and SPI - * devices. In order to promote code reuse the ASoC core provides - * some standard implementations of CODEC read and write operations - * which can be set up using this function. - * - * The caller is responsible for allocating and initialising the - * actual cache. - * - * Note that at present this code cannot be used by CODECs with - * volatile registers. - */ -int snd_soc_codec_set_cache_io(struct snd_soc_codec *codec, - int addr_bits, int data_bits, - enum snd_soc_control_type control) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(io_types); i++) - if (io_types[i].addr_bits == addr_bits && - io_types[i].data_bits == data_bits) - break; - if (i == ARRAY_SIZE(io_types)) { - printk(KERN_ERR - "No I/O functions for %d bit address %d bit data\n", - addr_bits, data_bits); - return -EINVAL; - } - - codec->write = io_types[i].write; - codec->read = io_types[i].read; - - switch (control) { - case SND_SOC_CUSTOM: - break; - - case SND_SOC_I2C: -#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE)) - codec->hw_write = (hw_write_t)i2c_master_send; -#endif - if (io_types[i].i2c_read) - codec->hw_read = io_types[i].i2c_read; - break; - - case SND_SOC_SPI: - if (io_types[i].spi_write) - codec->hw_write = io_types[i].spi_write; - break; - } - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_codec_set_cache_io); diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index fb8d7a766155..e984a17cd656 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -2223,17 +2223,20 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); /** * snd_soc_dai_set_tdm_slot - configure DAI TDM. * @dai: DAI - * @mask: DAI specific mask representing used slots. + * @tx_mask: bitmask representing active TX slots. + * @rx_mask: bitmask representing active RX slots. * @slots: Number of slots in use. + * @slot_width: Width in bits for each slot. * * Configures a DAI for TDM operation. Both mask and slots are codec and DAI * specific. */ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, - unsigned int mask, int slots) + unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { if (dai->ops && dai->ops->set_tdm_slot) - return dai->ops->set_tdm_slot(dai, mask, slots); + return dai->ops->set_tdm_slot(dai, tx_mask, rx_mask, + slots, slot_width); else return -EINVAL; }