diff options
Diffstat (limited to 'sound/soc/codecs/wm8962.c')
| -rw-r--r-- | sound/soc/codecs/wm8962.c | 145 | 
1 files changed, 105 insertions, 40 deletions
| diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index e9710280e5e1..e2de9ecfd641 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -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;  } |