Merge branch 'upstream/wm8974' into for-2.6.33
authorMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 30 Sep 2009 14:48:38 +0000 (15:48 +0100)
committerMark Brown <broonie@opensource.wolfsonmicro.com>
Wed, 30 Sep 2009 14:48:38 +0000 (15:48 +0100)
1  2 
sound/soc/codecs/wm8974.c

@@@ -12,6 -12,7 +12,6 @@@
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
 -#include <linux/version.h>
  #include <linux/kernel.h>
  #include <linux/init.h>
  #include <linux/delay.h>
@@@ -56,7 -57,55 +56,7 @@@ struct wm8974_priv 
  
  static struct snd_soc_codec *wm8974_codec;
  
 -/*
 - * read wm8974 register cache
 - */
 -static inline unsigned int wm8974_read_reg_cache(struct snd_soc_codec *codec,
 -      unsigned int reg)
 -{
 -      u16 *cache = codec->reg_cache;
 -      if (reg == WM8974_RESET)
 -              return 0;
 -      if (reg >= WM8974_CACHEREGNUM)
 -              return -1;
 -      return cache[reg];
 -}
 -
 -/*
 - * write wm8974 register cache
 - */
 -static inline void wm8974_write_reg_cache(struct snd_soc_codec *codec,
 -      u16 reg, unsigned int value)
 -{
 -      u16 *cache = codec->reg_cache;
 -      if (reg >= WM8974_CACHEREGNUM)
 -              return;
 -      cache[reg] = value;
 -}
 -
 -/*
 - * write to the WM8974 register space
 - */
 -static int wm8974_write(struct snd_soc_codec *codec, unsigned int reg,
 -      unsigned int value)
 -{
 -      u8 data[2];
 -
 -      /* data is
 -       *   D15..D9 WM8974 register offset
 -       *   D8...D0 register data
 -       */
 -      data[0] = (reg << 1) | ((value >> 8) & 0x0001);
 -      data[1] = value & 0x00ff;
 -
 -      wm8974_write_reg_cache(codec, reg, value);
 -      if (codec->hw_write(codec->control_data, data, 2) == 2)
 -              return 0;
 -      else
 -              return -EIO;
 -}
 -
 -#define wm8974_reset(c)       wm8974_write(c, WM8974_RESET, 0)
 +#define wm8974_reset(c)       snd_soc_write(c, WM8974_RESET, 0)
  
  static const char *wm8974_companding[] = {"Off", "NC", "u-law", "A-law" };
  static const char *wm8974_deemp[] = {"None", "32kHz", "44.1kHz", "48kHz" };
@@@ -281,36 -330,38 +281,38 @@@ static int wm8974_add_widgets(struct sn
  }
  
  struct pll_ {
-       unsigned int pre_div:4; /* prescale - 1 */
+       unsigned int pre_div:1;
        unsigned int n:4;
        unsigned int k;
  };
  
- static struct pll_ pll_div;
  /* The size in bits of the pll divide multiplied by 10
   * to allow rounding later */
  #define FIXED_PLL_SIZE ((1 << 24) * 10)
  
- static void pll_factors(unsigned int target, unsigned int source)
+ static void pll_factors(struct pll_ *pll_div,
+                       unsigned int target, unsigned int source)
  {
        unsigned long long Kpart;
        unsigned int K, Ndiv, Nmod;
  
+       /* There is a fixed divide by 4 in the output path */
+       target *= 4;
        Ndiv = target / source;
        if (Ndiv < 6) {
-               source >>= 1;
-               pll_div.pre_div = 1;
+               source /= 2;
+               pll_div->pre_div = 1;
                Ndiv = target / source;
        } else
-               pll_div.pre_div = 0;
+               pll_div->pre_div = 0;
  
        if ((Ndiv < 6) || (Ndiv > 12))
                printk(KERN_WARNING
                        "WM8974 N value %u outwith recommended range!\n",
                        Ndiv);
  
-       pll_div.n = Ndiv;
+       pll_div->n = Ndiv;
        Nmod = target % source;
        Kpart = FIXED_PLL_SIZE * (long long)Nmod;
  
        /* Move down to proper range now rounding is done */
        K /= 10;
  
-       pll_div.k = K;
+       pll_div->k = K;
  }
  
 -static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai,
 -              int pll_id, unsigned int freq_in, unsigned int freq_out)
 +static int wm8974_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id,
 +              int source, unsigned int freq_in, unsigned int freq_out)
  {
        struct snd_soc_codec *codec = codec_dai->codec;
+       struct pll_ pll_div;
        u16 reg;
  
        if (freq_in == 0 || freq_out == 0) {
                /* Clock CODEC directly from MCLK */
 -              reg = wm8974_read_reg_cache(codec, WM8974_CLOCK);
 -              wm8974_write(codec, WM8974_CLOCK, reg & 0x0ff);
 +              reg = snd_soc_read(codec, WM8974_CLOCK);
 +              snd_soc_write(codec, WM8974_CLOCK, reg & 0x0ff);
  
                /* Turn off PLL */
 -              reg = wm8974_read_reg_cache(codec, WM8974_POWER1);
 -              wm8974_write(codec, WM8974_POWER1, reg & 0x1df);
 +              reg = snd_soc_read(codec, WM8974_POWER1);
 +              snd_soc_write(codec, WM8974_POWER1, reg & 0x1df);
                return 0;
        }
  
-       pll_factors(freq_out*4, freq_in);
+       pll_factors(&pll_div, freq_out, freq_in);
  
 -      wm8974_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
 -      wm8974_write(codec, WM8974_PLLK1, pll_div.k >> 18);
 -      wm8974_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
 -      wm8974_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff);
 -      reg = wm8974_read_reg_cache(codec, WM8974_POWER1);
 -      wm8974_write(codec, WM8974_POWER1, reg | 0x020);
 +      snd_soc_write(codec, WM8974_PLLN, (pll_div.pre_div << 4) | pll_div.n);
 +      snd_soc_write(codec, WM8974_PLLK1, pll_div.k >> 18);
 +      snd_soc_write(codec, WM8974_PLLK2, (pll_div.k >> 9) & 0x1ff);
 +      snd_soc_write(codec, WM8974_PLLK3, pll_div.k & 0x1ff);
 +      reg = snd_soc_read(codec, WM8974_POWER1);
 +      snd_soc_write(codec, WM8974_POWER1, reg | 0x020);
  
        /* Run CODEC from PLL instead of MCLK */
 -      reg = wm8974_read_reg_cache(codec, WM8974_CLOCK);
 -      wm8974_write(codec, WM8974_CLOCK, reg | 0x100);
 +      reg = snd_soc_read(codec, WM8974_CLOCK);
 +      snd_soc_write(codec, WM8974_CLOCK, reg | 0x100);
  
        return 0;
  }
@@@ -372,24 -424,24 +375,24 @@@ static int wm8974_set_dai_clkdiv(struc
  
        switch (div_id) {
        case WM8974_OPCLKDIV:
 -              reg = wm8974_read_reg_cache(codec, WM8974_GPIO) & 0x1cf;
 -              wm8974_write(codec, WM8974_GPIO, reg | div);
 +              reg = snd_soc_read(codec, WM8974_GPIO) & 0x1cf;
 +              snd_soc_write(codec, WM8974_GPIO, reg | div);
                break;
        case WM8974_MCLKDIV:
 -              reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x11f;
 -              wm8974_write(codec, WM8974_CLOCK, reg | div);
 +              reg = snd_soc_read(codec, WM8974_CLOCK) & 0x11f;
 +              snd_soc_write(codec, WM8974_CLOCK, reg | div);
                break;
        case WM8974_ADCCLK:
 -              reg = wm8974_read_reg_cache(codec, WM8974_ADC) & 0x1f7;
 -              wm8974_write(codec, WM8974_ADC, reg | div);
 +              reg = snd_soc_read(codec, WM8974_ADC) & 0x1f7;
 +              snd_soc_write(codec, WM8974_ADC, reg | div);
                break;
        case WM8974_DACCLK:
 -              reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0x1f7;
 -              wm8974_write(codec, WM8974_DAC, reg | div);
 +              reg = snd_soc_read(codec, WM8974_DAC) & 0x1f7;
 +              snd_soc_write(codec, WM8974_DAC, reg | div);
                break;
        case WM8974_BCLKDIV:
 -              reg = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1e3;
 -              wm8974_write(codec, WM8974_CLOCK, reg | div);
 +              reg = snd_soc_read(codec, WM8974_CLOCK) & 0x1e3;
 +              snd_soc_write(codec, WM8974_CLOCK, reg | div);
                break;
        default:
                return -EINVAL;
@@@ -403,7 -455,7 +406,7 @@@ static int wm8974_set_dai_fmt(struct sn
  {
        struct snd_soc_codec *codec = codec_dai->codec;
        u16 iface = 0;
 -      u16 clk = wm8974_read_reg_cache(codec, WM8974_CLOCK) & 0x1fe;
 +      u16 clk = snd_soc_read(codec, WM8974_CLOCK) & 0x1fe;
  
        /* set master/slave audio interface */
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
                return -EINVAL;
        }
  
 -      wm8974_write(codec, WM8974_IFACE, iface);
 -      wm8974_write(codec, WM8974_CLOCK, clk);
 +      snd_soc_write(codec, WM8974_IFACE, iface);
 +      snd_soc_write(codec, WM8974_CLOCK, clk);
        return 0;
  }
  
@@@ -460,8 -512,8 +463,8 @@@ static int wm8974_pcm_hw_params(struct 
                                struct snd_soc_dai *dai)
  {
        struct snd_soc_codec *codec = dai->codec;
 -      u16 iface = wm8974_read_reg_cache(codec, WM8974_IFACE) & 0x19f;
 -      u16 adn = wm8974_read_reg_cache(codec, WM8974_ADD) & 0x1f1;
 +      u16 iface = snd_soc_read(codec, WM8974_IFACE) & 0x19f;
 +      u16 adn = snd_soc_read(codec, WM8974_ADD) & 0x1f1;
  
        /* bit size */
        switch (params_format(params)) {
                break;
        }
  
 -      wm8974_write(codec, WM8974_IFACE, iface);
 -      wm8974_write(codec, WM8974_ADD, adn);
 +      snd_soc_write(codec, WM8974_IFACE, iface);
 +      snd_soc_write(codec, WM8974_ADD, adn);
        return 0;
  }
  
  static int wm8974_mute(struct snd_soc_dai *dai, int mute)
  {
        struct snd_soc_codec *codec = dai->codec;
 -      u16 mute_reg = wm8974_read_reg_cache(codec, WM8974_DAC) & 0xffbf;
 +      u16 mute_reg = snd_soc_read(codec, WM8974_DAC) & 0xffbf;
  
        if (mute)
 -              wm8974_write(codec, WM8974_DAC, mute_reg | 0x40);
 +              snd_soc_write(codec, WM8974_DAC, mute_reg | 0x40);
        else
 -              wm8974_write(codec, WM8974_DAC, mute_reg);
 +              snd_soc_write(codec, WM8974_DAC, mute_reg);
        return 0;
  }
  
  static int wm8974_set_bias_level(struct snd_soc_codec *codec,
        enum snd_soc_bias_level level)
  {
 -      u16 power1 = wm8974_read_reg_cache(codec, WM8974_POWER1) & ~0x3;
 +      u16 power1 = snd_soc_read(codec, WM8974_POWER1) & ~0x3;
  
        switch (level) {
        case SND_SOC_BIAS_ON:
        case SND_SOC_BIAS_PREPARE:
                power1 |= 0x1;  /* VMID 50k */
 -              wm8974_write(codec, WM8974_POWER1, power1);
 +              snd_soc_write(codec, WM8974_POWER1, power1);
                break;
  
        case SND_SOC_BIAS_STANDBY:
  
                if (codec->bias_level == SND_SOC_BIAS_OFF) {
                        /* Initial cap charge at VMID 5k */
 -                      wm8974_write(codec, WM8974_POWER1, power1 | 0x3);
 +                      snd_soc_write(codec, WM8974_POWER1, power1 | 0x3);
                        mdelay(100);
                }
  
                power1 |= 0x2;  /* VMID 500k */
 -              wm8974_write(codec, WM8974_POWER1, power1);
 +              snd_soc_write(codec, WM8974_POWER1, power1);
                break;
  
        case SND_SOC_BIAS_OFF:
 -              wm8974_write(codec, WM8974_POWER1, 0);
 -              wm8974_write(codec, WM8974_POWER2, 0);
 -              wm8974_write(codec, WM8974_POWER3, 0);
 +              snd_soc_write(codec, WM8974_POWER1, 0);
 +              snd_soc_write(codec, WM8974_POWER2, 0);
 +              snd_soc_write(codec, WM8974_POWER3, 0);
                break;
        }
  
@@@ -689,6 -741,8 +692,6 @@@ static __devinit int wm8974_register(st
        codec->private_data = wm8974;
        codec->name = "WM8974";
        codec->owner = THIS_MODULE;
 -      codec->read = wm8974_read_reg_cache;
 -      codec->write = wm8974_write;
        codec->bias_level = SND_SOC_BIAS_OFF;
        codec->set_bias_level = wm8974_set_bias_level;
        codec->dai = &wm8974_dai;
        codec->reg_cache_size = WM8974_CACHEREGNUM;
        codec->reg_cache = &wm8974->reg_cache;
  
 +      ret = snd_soc_codec_set_cache_io(codec, 7, 9, SND_SOC_I2C);
 +      if (ret < 0) {
 +              dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
 +              goto err;
 +      }
 +
        memcpy(codec->reg_cache, wm8974_reg, sizeof(wm8974_reg));
  
        ret = wm8974_reset(codec);
        if (ret < 0) {
                dev_err(codec->dev, "Failed to issue reset\n");
 -              return ret;
 +              goto err;
        }
  
        wm8974_dai.dev = codec->dev;
        ret = snd_soc_register_codec(codec);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to register codec: %d\n", ret);
 -              return ret;
 +              goto err;
        }
  
        ret = snd_soc_register_dai(&wm8974_dai);
        if (ret != 0) {
                dev_err(codec->dev, "Failed to register DAI: %d\n", ret);
 -              snd_soc_unregister_codec(codec);
 -              return ret;
 +              goto err_codec;
        }
  
        return 0;
 +
 +err_codec:
 +      snd_soc_unregister_codec(codec);
 +err:
 +      kfree(wm8974);
 +      return ret;
  }
  
  static __devexit void wm8974_unregister(struct wm8974_priv *wm8974)