ASoC: wm8962: fix NULL pdata pointer
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / wm8962.c
index e9710280e5e18b882242f8d5b4cb61a2492e8eae..e2de9ecfd6417146dc9976f85017bd34be9aef4b 100644 (file)
@@ -51,6 +51,7 @@ static const char *wm8962_supply_names[WM8962_NUM_SUPPLIES] = {
 
 /* codec private data */
 struct wm8962_priv {
+       struct wm8962_pdata pdata;
        struct regmap *regmap;
        struct snd_soc_codec *codec;
 
@@ -1600,7 +1601,6 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                            struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
-       u16 *reg_cache = codec->reg_cache;
        int ret;
 
        /* Apply the update (if any) */
@@ -1609,16 +1609,19 @@ static int wm8962_put_hp_sw(struct snd_kcontrol *kcontrol,
                return 0;
 
        /* If the left PGA is enabled hit that VU bit... */
-       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTL_PGA_ENA)
-               return snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
-                                    reg_cache[WM8962_HPOUTL_VOLUME]);
+       ret = snd_soc_read(codec, WM8962_PWR_MGMT_2);
+       if (ret & WM8962_HPOUTL_PGA_ENA) {
+               snd_soc_write(codec, WM8962_HPOUTL_VOLUME,
+                             snd_soc_read(codec, WM8962_HPOUTL_VOLUME));
+               return 1;
+       }
 
        /* ...otherwise the right.  The VU is stereo. */
-       if (snd_soc_read(codec, WM8962_PWR_MGMT_2) & WM8962_HPOUTR_PGA_ENA)
-               return snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
-                                    reg_cache[WM8962_HPOUTR_VOLUME]);
+       if (ret & WM8962_HPOUTR_PGA_ENA)
+               snd_soc_write(codec, WM8962_HPOUTR_VOLUME,
+                             snd_soc_read(codec, WM8962_HPOUTR_VOLUME));
 
-       return 0;
+       return 1;
 }
 
 /* The VU bits for the speakers are in a different register to the mute
@@ -2345,12 +2348,13 @@ static const struct snd_soc_dapm_route wm8962_spk_stereo_intercon[] = {
 
 static int wm8962_add_widgets(struct snd_soc_codec *codec)
 {
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        struct snd_soc_dapm_context *dapm = &codec->dapm;
 
        snd_soc_add_codec_controls(codec, wm8962_snd_controls,
                             ARRAY_SIZE(wm8962_snd_controls));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_add_codec_controls(codec, wm8962_spk_mono_controls,
                                     ARRAY_SIZE(wm8962_spk_mono_controls));
        else
@@ -2360,7 +2364,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_new_controls(dapm, wm8962_dapm_widgets,
                                  ARRAY_SIZE(wm8962_dapm_widgets));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_dapm_new_controls(dapm, wm8962_dapm_spk_mono_widgets,
                                          ARRAY_SIZE(wm8962_dapm_spk_mono_widgets));
        else
@@ -2369,7 +2373,7 @@ static int wm8962_add_widgets(struct snd_soc_codec *codec)
 
        snd_soc_dapm_add_routes(dapm, wm8962_intercon,
                                ARRAY_SIZE(wm8962_intercon));
-       if (pdata && pdata->spk_mono)
+       if (pdata->spk_mono)
                snd_soc_dapm_add_routes(dapm, wm8962_spk_mono_intercon,
                                        ARRAY_SIZE(wm8962_spk_mono_intercon));
        else
@@ -3333,14 +3337,14 @@ static struct gpio_chip wm8962_template_chip = {
 static void wm8962_init_gpio(struct snd_soc_codec *codec)
 {
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        int ret;
 
        wm8962->gpio_chip = wm8962_template_chip;
        wm8962->gpio_chip.ngpio = WM8962_MAX_GPIO;
        wm8962->gpio_chip.dev = codec->dev;
 
-       if (pdata && pdata->gpio_base)
+       if (pdata->gpio_base)
                wm8962->gpio_chip.base = pdata->gpio_base;
        else
                wm8962->gpio_chip.base = -1;
@@ -3373,8 +3377,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
 {
        int ret;
        struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec);
-       struct wm8962_pdata *pdata = dev_get_platdata(codec->dev);
-       u16 *reg_cache = codec->reg_cache;
+       struct wm8962_pdata *pdata = &wm8962->pdata;
        int i, trigger, irq_pol;
        bool dmicclk, dmicdat;
 
@@ -3421,30 +3424,29 @@ static int wm8962_probe(struct snd_soc_codec *codec)
                            WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
                            0);
 
-       if (pdata) {
-               /* Apply static configuration for GPIOs */
-               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
-                       if (pdata->gpio_init[i]) {
-                               wm8962_set_gpio_mode(codec, i + 1);
-                               snd_soc_write(codec, 0x200 + i,
-                                             pdata->gpio_init[i] & 0xffff);
-                       }
+       /* Apply static configuration for GPIOs */
+       for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++)
+               if (pdata->gpio_init[i]) {
+                       wm8962_set_gpio_mode(codec, i + 1);
+                       snd_soc_write(codec, 0x200 + i,
+                                       pdata->gpio_init[i] & 0xffff);
+               }
 
-               /* Put the speakers into mono mode? */
-               if (pdata->spk_mono)
-                       reg_cache[WM8962_CLASS_D_CONTROL_2]
-                               |= WM8962_SPK_MONO;
 
-               /* Micbias setup, detection enable and detection
-                * threasholds. */
-               if (pdata->mic_cfg)
-                       snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
-                                           WM8962_MICDET_ENA |
-                                           WM8962_MICDET_THR_MASK |
-                                           WM8962_MICSHORT_THR_MASK |
-                                           WM8962_MICBIAS_LVL,
-                                           pdata->mic_cfg);
-       }
+       /* Put the speakers into mono mode? */
+       if (pdata->spk_mono)
+               snd_soc_update_bits(codec, WM8962_CLASS_D_CONTROL_2,
+                               WM8962_SPK_MONO_MASK, WM8962_SPK_MONO);
+
+       /* Micbias setup, detection enable and detection
+        * threasholds. */
+       if (pdata->mic_cfg)
+               snd_soc_update_bits(codec, WM8962_ADDITIONAL_CONTROL_4,
+                                   WM8962_MICDET_ENA |
+                                   WM8962_MICDET_THR_MASK |
+                                   WM8962_MICSHORT_THR_MASK |
+                                   WM8962_MICBIAS_LVL,
+                                   pdata->mic_cfg);
 
        /* Latch volume update bits */
        snd_soc_update_bits(codec, WM8962_LEFT_INPUT_VOLUME,
@@ -3506,7 +3508,7 @@ static int wm8962_probe(struct snd_soc_codec *codec)
        wm8962_init_gpio(codec);
 
        if (wm8962->irq) {
-               if (pdata && pdata->irq_active_low) {
+               if (pdata->irq_active_low) {
                        trigger = IRQF_TRIGGER_LOW;
                        irq_pol = WM8962_IRQ_POL;
                } else {
@@ -3584,6 +3586,34 @@ static const struct regmap_config wm8962_regmap = {
        .cache_type = REGCACHE_RBTREE,
 };
 
+static int wm8962_set_pdata_from_of(struct i2c_client *i2c,
+                                   struct wm8962_pdata *pdata)
+{
+       const struct device_node *np = i2c->dev.of_node;
+       u32 val32;
+       int i;
+
+       if (of_property_read_bool(np, "spk-mono"))
+               pdata->spk_mono = true;
+
+       if (of_property_read_u32(np, "mic-cfg", &val32) >= 0)
+               pdata->mic_cfg = val32;
+
+       if (of_property_read_u32_array(np, "gpio-cfg", pdata->gpio_init,
+                                      ARRAY_SIZE(pdata->gpio_init)) >= 0)
+               for (i = 0; i < ARRAY_SIZE(pdata->gpio_init); i++) {
+                       /*
+                        * The range of GPIO register value is [0x0, 0xffff]
+                        * While the default value of each register is 0x0
+                        * Any other value will be regarded as default value
+                        */
+                       if (pdata->gpio_init[i] > 0xffff)
+                               pdata->gpio_init[i] = 0x0;
+               }
+
+       return 0;
+}
+
 static int wm8962_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
@@ -3603,6 +3633,15 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
        init_completion(&wm8962->fll_lock);
        wm8962->irq = i2c->irq;
 
+       /* If platform data was supplied, update the default data in priv */
+       if (pdata) {
+               memcpy(&wm8962->pdata, pdata, sizeof(struct wm8962_pdata));
+       } else if (i2c->dev.of_node) {
+               ret = wm8962_set_pdata_from_of(i2c, &wm8962->pdata);
+               if (ret != 0)
+                       return ret;
+       }
+
        for (i = 0; i < ARRAY_SIZE(wm8962->supplies); i++)
                wm8962->supplies[i].supply = wm8962_supply_names[i];
 
@@ -3666,7 +3705,7 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
                goto err_enable;
        }
 
-       if (pdata && pdata->in4_dc_measure) {
+       if (wm8962->pdata.in4_dc_measure) {
                ret = regmap_register_patch(wm8962->regmap,
                                            wm8962_dc_measure,
                                            ARRAY_SIZE(wm8962_dc_measure));
@@ -3719,8 +3758,34 @@ static int wm8962_runtime_resume(struct device *dev)
 
        wm8962_reset(wm8962);
 
+       /* SYSCLK defaults to on; make sure it is off so we can safely
+        * write to registers if the device is declocked.
+        */
+       regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+                          WM8962_SYSCLK_ENA, 0);
+
+       /* Ensure we have soft control over all registers */
+       regmap_update_bits(wm8962->regmap, WM8962_CLOCKING2,
+                          WM8962_CLKREG_OVD, WM8962_CLKREG_OVD);
+
+       /* Ensure that the oscillator and PLLs are disabled */
+       regmap_update_bits(wm8962->regmap, WM8962_PLL2,
+                          WM8962_OSC_ENA | WM8962_PLL2_ENA | WM8962_PLL3_ENA,
+                          0);
+
        regcache_sync(wm8962->regmap);
 
+       regmap_update_bits(wm8962->regmap, WM8962_ANTI_POP,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA,
+                          WM8962_STARTUP_BIAS_ENA | WM8962_VMID_BUF_ENA);
+
+       /* Bias enable at 2*5k (fast start-up) */
+       regmap_update_bits(wm8962->regmap, WM8962_PWR_MGMT_1,
+                          WM8962_BIAS_ENA | WM8962_VMID_SEL_MASK,
+                          WM8962_BIAS_ENA | 0x180);
+
+       msleep(5);
+
        return 0;
 }