diff options
author | Takashi Iwai <tiwai@suse.de> | 2013-06-28 13:36:22 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2013-06-28 13:36:22 +0200 |
commit | accaf69da1d1e64bd77ac0caad77e4cfc3b654c7 (patch) | |
tree | 0402e4fad9cecd428c8c3c228a08f9e31eb63470 /sound/soc/codecs | |
parent | 975cc02a904ae385721f1bdb65eb1bcf707dfaf1 (diff) | |
parent | 27516080b21cbcb936440d2a3171867860b9a881 (diff) |
Merge tag 'asoc-v3.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: More updates for v3.11
Some more fixes and enhancements, and also a bunch of refectoring for
AC'97 support which enables more than one AC'97 controller driver to be
built in.
Diffstat (limited to 'sound/soc/codecs')
-rw-r--r-- | sound/soc/codecs/88pm860x-codec.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/ac97.c | 7 | ||||
-rw-r--r-- | sound/soc/codecs/ad1980.c | 12 | ||||
-rw-r--r-- | sound/soc/codecs/adau1701.c | 277 | ||||
-rw-r--r-- | sound/soc/codecs/stac9766.c | 26 | ||||
-rw-r--r-- | sound/soc/codecs/tas5086.c | 330 | ||||
-rw-r--r-- | sound/soc/codecs/tlv320aic3x.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/twl6040.c | 109 | ||||
-rw-r--r-- | sound/soc/codecs/wm8400.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8903.c | 6 | ||||
-rw-r--r-- | sound/soc/codecs/wm8904.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8990.c | 11 | ||||
-rw-r--r-- | sound/soc/codecs/wm8991.h | 9 | ||||
-rw-r--r-- | sound/soc/codecs/wm8994.c | 12 | ||||
-rw-r--r-- | sound/soc/codecs/wm8995.h | 7 | ||||
-rw-r--r-- | sound/soc/codecs/wm9705.c | 16 | ||||
-rw-r--r-- | sound/soc/codecs/wm9712.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/wm9713.c | 18 | ||||
-rw-r--r-- | sound/soc/codecs/wm_adsp.h | 10 | ||||
-rw-r--r-- | sound/soc/codecs/wm_hubs.c | 6 |
20 files changed, 726 insertions, 178 deletions
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 1382f3f3f4b..8af04343cc1 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -120,10 +120,8 @@ * before DAC & PGA in DAPM power-off sequence. */ #define PM860X_DAPM_OUTPUT(wname, wevent) \ -{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, \ - .shift = 0, .invert = 0, .kcontrol_news = NULL, \ - .num_kcontrols = 0, .event = wevent, \ - .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD, } + SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, 0, 0, NULL, 0, wevent, \ + SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD) struct pm860x_det { struct snd_soc_jack *hp_jack; diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index ef2ae32ffc6..ec7351803c2 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c @@ -62,13 +62,13 @@ static struct snd_soc_dai_driver ac97_dai = { static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg) { - return soc_ac97_ops.read(codec->ac97, reg); + return soc_ac97_ops->read(codec->ac97, reg); } static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) { - soc_ac97_ops.write(codec->ac97, reg, val); + soc_ac97_ops->write(codec->ac97, reg, val); return 0; } @@ -79,7 +79,8 @@ static int ac97_soc_probe(struct snd_soc_codec *codec) int ret; /* add codec as bus device for standard ac97 */ - ret = snd_ac97_bus(codec->card->snd_card, 0, &soc_ac97_ops, NULL, &ac97_bus); + ret = snd_ac97_bus(codec->card->snd_card, 0, soc_ac97_ops, NULL, + &ac97_bus); if (ret < 0) return ret; diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index f385342947d..89fcf7d6e7b 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -108,7 +108,7 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, case AC97_EXTENDED_STATUS: case AC97_VENDOR_ID1: case AC97_VENDOR_ID2: - return soc_ac97_ops.read(codec->ac97, reg); + return soc_ac97_ops->read(codec->ac97, reg); default: reg = reg >> 1; @@ -124,7 +124,7 @@ static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, { u16 *cache = codec->reg_cache; - soc_ac97_ops.write(codec->ac97, reg, val); + soc_ac97_ops->write(codec->ac97, reg, val); reg = reg >> 1; if (reg < ARRAY_SIZE(ad1980_reg)) cache[reg] = val; @@ -154,13 +154,13 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) u16 retry_cnt = 0; retry: - if (try_warm && soc_ac97_ops.warm_reset) { - soc_ac97_ops.warm_reset(codec->ac97); + if (try_warm && soc_ac97_ops->warm_reset) { + soc_ac97_ops->warm_reset(codec->ac97); if (ac97_read(codec, AC97_RESET) == 0x0090) return 1; } - soc_ac97_ops.reset(codec->ac97); + soc_ac97_ops->reset(codec->ac97); /* Set bit 16slot in register 74h, then every slot will has only 16 * bits. This command is sent out in 20bit mode, in which case the * first nibble of data is eaten by the addr. (Tag is always 16 bit)*/ @@ -186,7 +186,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) printk(KERN_INFO "AD1980 SoC Audio Codec\n"); - ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); if (ret < 0) { printk(KERN_ERR "ad1980: failed to register AC97 codec\n"); return ret; diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index b6b1a773bd3..0e250f118c0 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/of_device.h> +#include <linux/regmap.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -24,16 +25,19 @@ #include "sigmadsp.h" #include "adau1701.h" -#define ADAU1701_DSPCTRL 0x1c -#define ADAU1701_SEROCTL 0x1e -#define ADAU1701_SERICTL 0x1f +#define ADAU1701_DSPCTRL 0x081c +#define ADAU1701_SEROCTL 0x081e +#define ADAU1701_SERICTL 0x081f -#define ADAU1701_AUXNPOW 0x22 +#define ADAU1701_AUXNPOW 0x0822 +#define ADAU1701_PINCONF_0 0x0820 +#define ADAU1701_PINCONF_1 0x0821 +#define ADAU1701_AUXNPOW 0x0822 -#define ADAU1701_OSCIPOW 0x26 -#define ADAU1701_DACSET 0x27 +#define ADAU1701_OSCIPOW 0x0826 +#define ADAU1701_DACSET 0x0827 -#define ADAU1701_NUM_REGS 0x28 +#define ADAU1701_MAX_REGISTER 0x0828 #define ADAU1701_DSPCTRL_CR (1 << 2) #define ADAU1701_DSPCTRL_DAM (1 << 3) @@ -87,11 +91,18 @@ #define ADAU1701_OSCIPOW_OPD 0x04 #define ADAU1701_DACSET_DACINIT 1 +#define ADAU1707_CLKDIV_UNSET (-1UL) + #define ADAU1701_FIRMWARE "adau1701.bin" struct adau1701 { int gpio_nreset; + int gpio_pll_mode[2]; unsigned int dai_fmt; + unsigned int pll_clkdiv; + unsigned int sysclk; + struct regmap *regmap; + u8 pin_config[12]; }; static const struct snd_kcontrol_new adau1701_controls[] = { @@ -123,10 +134,13 @@ static const struct snd_soc_dapm_route adau1701_dapm_routes[] = { { "ADC", NULL, "IN1" }, }; -static unsigned int adau1701_register_size(struct snd_soc_codec *codec, +static unsigned int adau1701_register_size(struct device *dev, unsigned int reg) { switch (reg) { + case ADAU1701_PINCONF_0: + case ADAU1701_PINCONF_1: + return 3; case ADAU1701_DSPCTRL: case ADAU1701_SEROCTL: case ADAU1701_AUXNPOW: @@ -137,33 +151,42 @@ static unsigned int adau1701_register_size(struct snd_soc_codec *codec, return 1; } - dev_err(codec->dev, "Unsupported register address: %d\n", reg); + dev_err(dev, "Unsupported register address: %d\n", reg); return 0; } -static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int value) +static bool adau1701_volatile_reg(struct device *dev, unsigned int reg) { + switch (reg) { + case ADAU1701_DACSET: + return true; + default: + return false; + } +} + +static int adau1701_reg_write(void *context, unsigned int reg, + unsigned int value) +{ + struct i2c_client *client = context; unsigned int i; unsigned int size; - uint8_t buf[4]; + uint8_t buf[5]; int ret; - size = adau1701_register_size(codec, reg); + size = adau1701_register_size(&client->dev, reg); if (size == 0) return -EINVAL; - snd_soc_cache_write(codec, reg, value); - - buf[0] = 0x08; - buf[1] = reg; + buf[0] = reg >> 8; + buf[1] = reg & 0xff; for (i = size + 1; i >= 2; --i) { buf[i] = value; value >>= 8; } - ret = i2c_master_send(to_i2c_client(codec->dev), buf, size + 2); + ret = i2c_master_send(client, buf, size + 2); if (ret == size + 2) return 0; else if (ret < 0) @@ -172,47 +195,105 @@ static int adau1701_write(struct snd_soc_codec *codec, unsigned int reg, return -EIO; } -static unsigned int adau1701_read(struct snd_soc_codec *codec, unsigned int reg) +static int adau1701_reg_read(void *context, unsigned int reg, + unsigned int *value) { - unsigned int value; - unsigned int ret; + int ret; + unsigned int i; + unsigned int size; + uint8_t send_buf[2], recv_buf[3]; + struct i2c_client *client = context; + struct i2c_msg msgs[2]; - ret = snd_soc_cache_read(codec, reg, &value); - if (ret) - return ret; + size = adau1701_register_size(&client->dev, reg); + if (size == 0) + return -EINVAL; - return value; -} + send_buf[0] = reg >> 8; + send_buf[1] = reg & 0xff; -static void adau1701_reset(struct snd_soc_codec *codec) -{ - struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + msgs[0].addr = client->addr; + msgs[0].len = sizeof(send_buf); + msgs[0].buf = send_buf; + msgs[0].flags = 0; - if (!gpio_is_valid(adau1701->gpio_nreset)) - return; + msgs[1].addr = client->addr; + msgs[1].len = size; + msgs[1].buf = recv_buf; + msgs[1].flags = I2C_M_RD; - gpio_set_value(adau1701->gpio_nreset, 0); - /* minimum reset time is 20ns */ - udelay(1); - gpio_set_value(adau1701->gpio_nreset, 1); - /* power-up time may be as long as 85ms */ - mdelay(85); + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + else if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *value = 0; + + for (i = 0; i < size; i++) + *value |= recv_buf[i] << (i * 8); + + return 0; } -static int adau1701_init(struct snd_soc_codec *codec) +static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv) { - int ret; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); struct i2c_client *client = to_i2c_client(codec->dev); + int ret; - adau1701_reset(codec); + if (clkdiv != ADAU1707_CLKDIV_UNSET && + gpio_is_valid(adau1701->gpio_pll_mode[0]) && + gpio_is_valid(adau1701->gpio_pll_mode[1])) { + switch (clkdiv) { + case 64: + gpio_set_value(adau1701->gpio_pll_mode[0], 0); + gpio_set_value(adau1701->gpio_pll_mode[1], 0); + break; + case 256: + gpio_set_value(adau1701->gpio_pll_mode[0], 0); + gpio_set_value(adau1701->gpio_pll_mode[1], 1); + break; + case 384: + gpio_set_value(adau1701->gpio_pll_mode[0], 1); + gpio_set_value(adau1701->gpio_pll_mode[1], 0); + break; + case 0: /* fallback */ + case 512: + gpio_set_value(adau1701->gpio_pll_mode[0], 1); + gpio_set_value(adau1701->gpio_pll_mode[1], 1); + break; + } + } - ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); - if (ret) { - dev_warn(codec->dev, "Failed to load firmware\n"); - return ret; + adau1701->pll_clkdiv = clkdiv; + + if (gpio_is_valid(adau1701->gpio_nreset)) { + gpio_set_value(adau1701->gpio_nreset, 0); + /* minimum reset time is 20ns */ + udelay(1); + gpio_set_value(adau1701->gpio_nreset, 1); + /* power-up time may be as long as 85ms */ + mdelay(85); } - snd_soc_write(codec, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); + /* + * Postpone the firmware download to a point in time when we + * know the correct PLL setup + */ + if (clkdiv != ADAU1707_CLKDIV_UNSET) { + ret = process_sigma_firmware(client, ADAU1701_FIRMWARE); + if (ret) { + dev_warn(codec->dev, "Failed to load firmware\n"); + return ret; + } + } + + regmap_write(adau1701->regmap, ADAU1701_DACSET, ADAU1701_DACSET_DACINIT); + regmap_write(adau1701->regmap, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); + + regcache_mark_dirty(adau1701->regmap); + regcache_sync(adau1701->regmap); return 0; } @@ -291,8 +372,22 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); + unsigned int clkdiv = adau1701->sysclk / params_rate(params); snd_pcm_format_t format; unsigned int val; + int ret; + + /* + * If the mclk/lrclk ratio changes, the chip needs updated PLL + * mode GPIO settings, and a full reset cycle, including a new + * firmware upload. + */ + if (clkdiv != adau1701->pll_clkdiv) { + ret = adau1701_reset(codec, clkdiv); + if (ret < 0) + return ret; + } switch (params_rate(params)) { case 192000: @@ -384,8 +479,8 @@ static int adau1701_set_dai_fmt(struct snd_soc_dai *codec_dai, adau1701->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK; - snd_soc_write(codec, ADAU1701_SERICTL, serictl); - snd_soc_update_bits(codec, ADAU1701_SEROCTL, + regmap_write(adau1701->regmap, ADAU1701_SERICTL, serictl); + regmap_update_bits(adau1701->regmap, ADAU1701_SEROCTL, ~ADAU1701_SEROCTL_WORD_LEN_MASK, seroctl); return 0; @@ -435,6 +530,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir) { unsigned int val; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); switch (clk_id) { case ADAU1701_CLK_SRC_OSC: @@ -448,6 +544,7 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id, } snd_soc_update_bits(codec, ADAU1701_OSCIPOW, ADAU1701_OSCIPOW_OPD, val); + adau1701->sysclk = freq; return 0; } @@ -494,15 +591,37 @@ MODULE_DEVICE_TABLE(of, adau1701_dt_ids); static int adau1701_probe(struct snd_soc_codec *codec) { - int ret; + int i, ret; + unsigned int val; + struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec); codec->control_data = to_i2c_client(codec->dev); - ret = adau1701_init(codec); - if (ret) + /* + * Let the pll_clkdiv variable default to something that won't happen + * at runtime. That way, we can postpone the firmware download from + * adau1701_reset() to a point in time when we know the correct PLL + * mode parameters. + */ + adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET; + + /* initalize with pre-configured pll mode settings */ + ret = adau1701_reset(codec, adau1701->pll_clkdiv); + if (ret < 0) return ret; - snd_soc_write(codec, ADAU1701_DSPCTRL, ADAU1701_DSPCTRL_CR); + /* set up pin config */ + val = 0; + for (i = 0; i < 6; i++) + val |= adau1701->pin_config[i] << (i * 4); + + regmap_write(adau1701->regmap, ADAU1701_PINCONF_0, val); + + val = 0; + for (i = 0; i < 6; i++) + val |= adau1701->pin_config[i + 6] << (i * 4); + + regmap_write(adau1701->regmap, ADAU1701_PINCONF_1, val); return 0; } @@ -512,9 +631,6 @@ static struct snd_soc_codec_driver adau1701_codec_drv = { .set_bias_level = adau1701_set_bias_level, .idle_bias_off = true, - .reg_cache_size = ADAU1701_NUM_REGS, - .reg_word_size = sizeof(u16), - .controls = adau1701_controls, .num_controls = ARRAY_SIZE(adau1701_controls), .dapm_widgets = adau1701_dapm_widgets, @@ -522,28 +638,58 @@ static struct snd_soc_codec_driver adau1701_codec_drv = { .dapm_routes = adau1701_dapm_routes, .num_dapm_routes = ARRAY_SIZE(adau1701_dapm_routes), - .write = adau1701_write, - .read = adau1701_read, - .set_sysclk = adau1701_set_sysclk, }; +static const struct regmap_config adau1701_regmap = { + .reg_bits = 16, + .val_bits = 32, + .max_register = ADAU1701_MAX_REGISTER, + .cache_type = REGCACHE_RBTREE, + .volatile_reg = adau1701_volatile_reg, + .reg_write = adau1701_reg_write, + .reg_read = adau1701_reg_read, +}; + static int adau1701_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct adau1701 *adau1701; struct device *dev = &client->dev; int gpio_nreset = -EINVAL; + int gpio_pll_mode[2] = { -EINVAL, -EINVAL }; int ret; adau1701 = devm_kzalloc(dev, sizeof(*adau1701), GFP_KERNEL); if (!adau1701) return -ENOMEM; + adau1701->regmap = devm_regmap_init(dev, NULL, client, + &adau1701_regmap); + if (IS_ERR(adau1701->regmap)) + return PTR_ERR(adau1701->regmap); + if (dev->of_node) { gpio_nreset = of_get_named_gpio(dev->of_node, "reset-gpio", 0); if (gpio_nreset < 0 && gpio_nreset != -ENOENT) return gpio_nreset; + + gpio_pll_mode[0] = of_get_named_gpio(dev->of_node, + "adi,pll-mode-gpios", 0); + if (gpio_pll_mode[0] < 0 && gpio_pll_mode[0] != -ENOENT) + return gpio_pll_mode[0]; + + gpio_pll_mode[1] = of_get_named_gpio(dev->of_node, + "adi,pll-mode-gpios", 1); + if (gpio_pll_mode[1] < 0 && gpio_pll_mode[1] != -ENOENT) + return gpio_pll_mode[1]; + + of_property_read_u32(dev->of_node, "adi,pll-clkdiv", + &adau1701->pll_clkdiv); + + of_property_read_u8_array(dev->of_node, "adi,pin-config", + adau1701->pin_config, + ARRAY_SIZE(adau1701->pin_config)); } if (gpio_is_valid(gpio_nreset)) { @@ -553,7 +699,24 @@ static int adau1701_i2c_probe(struct i2c_client *client, return ret; } + if (gpio_is_valid(gpio_pll_mode[0]) && + gpio_is_valid(gpio_pll_mode[1])) { + ret = devm_gpio_request_one(dev, gpio_pll_mode[0], + GPIOF_OUT_INIT_LOW, + "ADAU1701 PLL mode 0"); + if (ret < 0) + return ret; + + ret = devm_gpio_request_one(dev, gpio_pll_mode[1], + GPIOF_OUT_INIT_LOW, + "ADAU1701 PLL mode 1"); + if (ret < 0) + return ret; + } + adau1701->gpio_nreset = gpio_nreset; + adau1701->gpio_pll_mode[0] = gpio_pll_mode[0]; + adau1701->gpio_pll_mode[1] = gpio_pll_mode[1]; i2c_set_clientdata(client, adau1701); ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv, diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index 2eda85ba79a..a5455c1aea4 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -28,8 +28,6 @@ #include "stac9766.h" -#define STAC9766_VERSION "0.10" - /* * STAC9766 register cache */ @@ -145,14 +143,14 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg, if (reg > AC97_STAC_PAGE0) { stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - soc_ac97_ops.write(codec->ac97, reg, val); + soc_ac97_ops->write(codec->ac97, reg, val); stac9766_ac97_write(codec, AC97_INT_PAGING, 1); return 0; } if (reg / 2 >= ARRAY_SIZE(stac9766_reg)) return -EIO; - soc_ac97_ops.write(codec->ac97, reg, val); + soc_ac97_ops->write(codec->ac97, reg, val); cache[reg / 2] = val; return 0; } @@ -164,7 +162,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, if (reg > AC97_STAC_PAGE0) { stac9766_ac97_write(codec, AC97_INT_PAGING, 0); - val = soc_ac97_ops.read(codec->ac97, reg - AC97_STAC_PAGE0); + val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0); stac9766_ac97_write(codec, AC97_INT_PAGING, 1); return val; } @@ -175,7 +173,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec, reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2) { - val = soc_ac97_ops.read(codec->ac97, reg); + val = soc_ac97_ops->read(codec->ac97, reg); return val; } return cache[reg / 2]; @@ -242,15 +240,15 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) { - if (try_warm && soc_ac97_ops.warm_reset) { - soc_ac97_ops.warm_reset(codec->ac97); + if (try_warm && soc_ac97_ops->warm_reset) { + soc_ac97_ops->warm_reset(codec->ac97); if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) return 1; } - soc_ac97_ops.reset(codec->ac97); - if (soc_ac97_ops.warm_reset) - soc_ac97_ops.warm_reset(codec->ac97); + soc_ac97_ops->reset(codec->ac97); + if (soc_ac97_ops->warm_reset) + soc_ac97_ops->warm_reset(codec->ac97); if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) return -EIO; return 0; @@ -274,7 +272,7 @@ reset: return -EIO; } codec->ac97->bus->ops->warm_reset(codec->ac97); - id = soc_ac97_ops.read(codec->ac97, AC97_VENDOR_ID2); + id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2); if (id != 0x4c13) { stac9766_reset(codec, 0); reset++; @@ -338,9 +336,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) { int ret = 0; - printk(KERN_INFO "STAC9766 SoC Audio Codec %s\n", STAC9766_VERSION); - - ret = snd_soc_new_ac97_codec(codec, &soc_ac97_ops, 0); + ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0); if (ret < 0) goto codec_err; diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index d447c4aa1d5..6d31d88f720 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -83,6 +83,14 @@ #define TAS5086_SPLIT_CAP_CHARGE 0x1a /* Split cap charge period register */ #define TAS5086_OSC_TRIM 0x1b /* Oscillator trim register */ #define TAS5086_BKNDERR 0x1c +#define TAS5086_INPUT_MUX 0x20 +#define TAS5086_PWM_OUTPUT_MUX 0x25 + +#define TAS5086_MAX_REGISTER TAS5086_PWM_OUTPUT_MUX + +#define TAS5086_PWM_START_MIDZ_FOR_START_1 (1 << 7) +#define TAS5086_PWM_START_MIDZ_FOR_START_2 (1 << 6) +#define TAS5086_PWM_START_CHANNEL_MASK (0x3f) /* * Default TAS5086 power-up configuration @@ -119,9 +127,30 @@ static const struct reg_default tas5086_reg_defaults[] = { { 0x1c, 0x05 }, }; +static int tas5086_register_size(struct device *dev, unsigned int reg) +{ + switch (reg) { + case TAS5086_CLOCK_CONTROL ... TAS5086_BKNDERR: + return 1; + case TAS5086_INPUT_MUX: + case TAS5086_PWM_OUTPUT_MUX: + return 4; + } + + dev_err(dev, "Unsupported register address: %d\n", reg); + return 0; +} + static bool tas5086_accessible_reg(struct device *dev, unsigned int reg) { - return !((reg == 0x0f) || (reg >= 0x11 && reg <= 0x17)); + switch (reg) { + case 0x0f: + case 0x11 ... 0x17: + case 0x1d ... 0x1f: + return false; + default: + return true; + } } static bool tas5086_volatile_reg(struct device *dev, unsigned int reg) @@ -140,6 +169,76 @@ static bool tas5086_writeable_reg(struct device *dev, unsigned int reg) return tas5086_accessible_reg(dev, reg) && (reg != TAS5086_DEV_ID); } +static int tas5086_reg_write(void *context, unsigned int reg, + unsigned int value) +{ + struct i2c_client *client = context; + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas5086_register_size(&client->dev, reg); + if (size == 0) + return -EINVAL; + + buf[0] = reg; + + for (i = size; i >= 1; --i) { + buf[i] = value; + value >>= 8; + } + + ret = i2c_master_send(client, buf, size + 1); + if (ret == size + 1) + return 0; + else if (ret < 0) + return ret; + else + return -EIO; +} + +static int tas5086_reg_read(void *context, unsigned int reg, + unsigned int *value) +{ + struct i2c_client *client = context; + uint8_t send_buf, recv_buf[4]; + struct i2c_msg msgs[2]; + unsigned int size; + unsigned int i; + int ret; + + size = tas5086_register_size(&client->dev, reg); + if (size == 0) + return -EINVAL; + + send_buf = reg; + + msgs[0].addr = client->addr; + msgs[0].len = sizeof(send_buf); + msgs[0].buf = &send_buf; + msgs[0].flags = 0; + + msgs[1].addr = client->addr; + msgs[1].len = size; + msgs[1].buf = recv_buf; + msgs[1].flags = I2C_M_RD; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + return ret; + else if (ret != ARRAY_SIZE(msgs)) + return -EIO; + + *value = 0; + + for (i = 0; i < size; i++) { + *value <<= 8; + *value |= recv_buf[i]; + } + + return 0; +} + struct tas5086_private { struct regmap *regmap; unsigned int mclk, sclk; @@ -376,6 +475,202 @@ static const struct snd_kcontrol_new tas5086_controls[] = { tas5086_get_deemph, tas5086_put_deemph), }; +/* Input mux controls */ +static const char *tas5086_dapm_sdin_texts[] = +{ + "SDIN1-L", "SDIN1-R", "SDIN2-L", "SDIN2-R", + "SDIN3-L", "SDIN3-R", "Ground (0)", "nc" +}; + +static const struct soc_enum tas5086_dapm_input_mux_enum[] = { + SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 20, 8, tas5086_dapm_sdin_texts), + SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 16, 8, tas5086_dapm_sdin_texts), + SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 12, 8, tas5086_dapm_sdin_texts), + SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 8, 8, tas5086_dapm_sdin_texts), + SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 4, 8, tas5086_dapm_sdin_texts), + SOC_ENUM_SINGLE(TAS5086_INPUT_MUX, 0, 8, tas5086_dapm_sdin_texts), +}; + +static const struct snd_kcontrol_new tas5086_dapm_input_mux_controls[] = { + SOC_DAPM_ENUM("Channel 1 input", tas5086_dapm_input_mux_enum[0]), + SOC_DAPM_ENUM("Channel 2 input", tas5086_dapm_input_mux_enum[1]), + SOC_DAPM_ENUM("Channel 3 input", tas5086_dapm_input_mux_enum[2]), + SOC_DAPM_ENUM("Channel 4 input", tas5086_dapm_input_mux_enum[3]), + SOC_DAPM_ENUM("Channel 5 input", tas5086_dapm_input_mux_enum[4]), + SOC_DAPM_ENUM("Channel 6 input", tas5086_dapm_input_mux_enum[5]), +}; + +/* Output mux controls */ +static const char *tas5086_dapm_channel_texts[] = + { "Channel 1 Mux", "Channel 2 Mux", "Channel 3 Mux", + "Channel 4 Mux", "Channel 5 Mux", "Channel 6 Mux" }; + +static const struct soc_enum tas5086_dapm_output_mux_enum[] = { + SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 20, 6, tas5086_dapm_channel_texts), + SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 16, 6, tas5086_dapm_channel_texts), + SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 12, 6, tas5086_dapm_channel_texts), + SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 8, 6, tas5086_dapm_channel_texts), + SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 4, 6, tas5086_dapm_channel_texts), + SOC_ENUM_SINGLE(TAS5086_PWM_OUTPUT_MUX, 0, 6, tas5086_dapm_channel_texts), +}; + +static const struct snd_kcontrol_new tas5086_dapm_output_mux_controls[] = { + SOC_DAPM_ENUM("PWM1 Output", tas5086_dapm_output_mux_enum[0]), + SOC_DAPM_ENUM("PWM2 Output", tas5086_dapm_output_mux_enum[1]), + SOC_DAPM_ENUM("PWM3 Output", tas5086_dapm_output_mux_enum[2]), + SOC_DAPM_ENUM("PWM4 Output", tas5086_dapm_output_mux_enum[3]), + SOC_DAPM_ENUM("PWM5 Output", tas5086_dapm_output_mux_enum[4]), + SOC_DAPM_ENUM("PWM6 Output", tas5086_dapm_output_mux_enum[5]), +}; + +static const struct snd_soc_dapm_widget tas5086_dapm_widgets[] = { + SND_SOC_DAPM_INPUT("SDIN1-L"), + SND_SOC_DAPM_INPUT("SDIN1-R"), + SND_SOC_DAPM_INPUT("SDIN2-L"), + SND_SOC_DAPM_INPUT("SDIN2-R"), + SND_SOC_DAPM_INPUT("SDIN3-L"), + SND_SOC_DAPM_INPUT("SDIN3-R"), + SND_SOC_DAPM_INPUT("SDIN4-L"), + SND_SOC_DAPM_INPUT("SDIN4-R"), + + SND_SOC_DAPM_OUTPUT("PWM1"), + SND_SOC_DAPM_OUTPUT("PWM2"), + SND_SOC_DAPM_OUTPUT("PWM3"), + SND_SOC_DAPM_OUTPUT("PWM4"), + SND_SOC_DAPM_OUTPUT("PWM5"), + SND_SOC_DAPM_OUTPUT("PWM6"), + + SND_SOC_DAPM_MUX("Channel 1 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_input_mux_controls[0]), + SND_SOC_DAPM_MUX("Channel 2 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_input_mux_controls[1]), + SND_SOC_DAPM_MUX("Channel 3 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_input_mux_controls[2]), + SND_SOC_DAPM_MUX("Channel 4 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_input_mux_controls[3]), + SND_SOC_DAPM_MUX("Channel 5 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_input_mux_controls[4]), + SND_SOC_DAPM_MUX("Channel 6 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_input_mux_controls[5]), + + SND_SOC_DAPM_MUX("PWM1 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_output_mux_controls[0]), + SND_SOC_DAPM_MUX("PWM2 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_output_mux_controls[1]), + SND_SOC_DAPM_MUX("PWM3 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_output_mux_controls[2]), + SND_SOC_DAPM_MUX("PWM4 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_output_mux_controls[3]), + SND_SOC_DAPM_MUX("PWM5 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_output_mux_controls[4]), + SND_SOC_DAPM_MUX("PWM6 Mux", SND_SOC_NOPM, 0, 0, + &tas5086_dapm_output_mux_controls[5]), +}; + +static const struct snd_soc_dapm_route tas5086_dapm_routes[] = { + /* SDIN inputs -> channel muxes */ + { "Channel 1 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 1 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 1 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 1 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 1 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 1 Mux", "SDIN3-R", "SDIN3-R" }, + + { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, + + { "Channel 2 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 2 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 2 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 2 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 2 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 2 Mux", "SDIN3-R", "SDIN3-R" }, + + { "Channel 3 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 3 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 3 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 3 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 3 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 3 Mux", "SDIN3-R", "SDIN3-R" }, + + { "Channel 4 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 4 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 4 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 4 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 4 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 4 Mux", "SDIN3-R", "SDIN3-R" }, + + { "Channel 5 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 5 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 5 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 5 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 5 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 5 Mux", "SDIN3-R", "SDIN3-R" }, + + { "Channel 6 Mux", "SDIN1-L", "SDIN1-L" }, + { "Channel 6 Mux", "SDIN1-R", "SDIN1-R" }, + { "Channel 6 Mux", "SDIN2-L", "SDIN2-L" }, + { "Channel 6 Mux", "SDIN2-R", "SDIN2-R" }, + { "Channel 6 Mux", "SDIN3-L", "SDIN3-L" }, + { "Channel 6 Mux", "SDIN3-R", "SDIN3-R" }, + + /* Channel muxes -> PWM muxes */ + { "PWM1 Mux", "Channel 1 Mux", "Channel 1 Mux" }, + { "PWM2 Mux", "Channel 1 Mux", "Channel 1 Mux" }, + { "PWM3 Mux", "Channel 1 Mux", "Channel 1 Mux" }, + { "PWM4 Mux", "Channel 1 Mux", "Channel 1 Mux" }, + { "PWM5 Mux", "Channel 1 Mux", "Channel 1 Mux" }, |