diff options
Diffstat (limited to 'sound/soc/codecs/ak4104.c')
| -rw-r--r-- | sound/soc/codecs/ak4104.c | 73 | 
1 files changed, 62 insertions, 11 deletions
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index 71059c07ae7..1fd7f72b2a6 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -11,13 +11,14 @@  #include <linux/module.h>  #include <linux/slab.h> -#include <sound/core.h> -#include <sound/soc.h> -#include <sound/initval.h>  #include <linux/spi/spi.h>  #include <linux/of_device.h>  #include <linux/of_gpio.h> +#include <linux/regulator/consumer.h>  #include <sound/asoundef.h> +#include <sound/core.h> +#include <sound/soc.h> +#include <sound/initval.h>  /* AK4104 registers addresses */  #define AK4104_REG_CONTROL1		0x00 @@ -45,10 +46,9 @@  #define AK4104_TX_TXE			(1 << 0)  #define AK4104_TX_V			(1 << 1) -#define DRV_NAME "ak4104-codec" -  struct ak4104_private {  	struct regmap *regmap; +	struct regulator *regulator;  };  static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { @@ -176,22 +176,30 @@ static int ak4104_probe(struct snd_soc_codec *codec)  	struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec);  	int ret; -	codec->control_data = ak4104->regmap; +	ret = regulator_enable(ak4104->regulator); +	if (ret < 0) { +		dev_err(codec->dev, "Unable to enable regulator: %d\n", ret); +		return ret; +	}  	/* set power-up and non-reset bits */  	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,  				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN,  				 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN);  	if (ret < 0) -		return ret; +		goto exit_disable_regulator;  	/* enable transmitter */  	ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX,  				 AK4104_TX_TXE, AK4104_TX_TXE);  	if (ret < 0) -		return ret; +		goto exit_disable_regulator;  	return 0; + +exit_disable_regulator: +	regulator_disable(ak4104->regulator); +	return ret;  }  static int ak4104_remove(struct snd_soc_codec *codec) @@ -200,13 +208,42 @@ static int ak4104_remove(struct snd_soc_codec *codec)  	regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1,  			   AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); +	regulator_disable(ak4104->regulator); + +	return 0; +} + +#ifdef CONFIG_PM +static int ak4104_soc_suspend(struct snd_soc_codec *codec) +{ +	struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); + +	regulator_disable(priv->regulator);  	return 0;  } +static int ak4104_soc_resume(struct snd_soc_codec *codec) +{ +	struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); +	int ret; + +	ret = regulator_enable(priv->regulator); +	if (ret < 0) +		return ret; + +	return 0; +} +#else +#define ak4104_soc_suspend	NULL +#define ak4104_soc_resume	NULL +#endif /* CONFIG_PM */ +  static struct snd_soc_codec_driver soc_codec_device_ak4104 = { -	.probe =	ak4104_probe, -	.remove =	ak4104_remove, +	.probe = ak4104_probe, +	.remove = ak4104_remove, +	.suspend = ak4104_soc_suspend, +	.resume = ak4104_soc_resume,  	.dapm_widgets = ak4104_dapm_widgets,  	.num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), @@ -243,6 +280,13 @@ static int ak4104_spi_probe(struct spi_device *spi)  	if (ak4104 == NULL)  		return -ENOMEM; +	ak4104->regulator = devm_regulator_get(&spi->dev, "vdd"); +	if (IS_ERR(ak4104->regulator)) { +		ret = PTR_ERR(ak4104->regulator); +		dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret); +		return ret; +	} +  	ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap);  	if (IS_ERR(ak4104->regmap)) {  		ret = PTR_ERR(ak4104->regmap); @@ -291,12 +335,19 @@ static const struct of_device_id ak4104_of_match[] = {  };  MODULE_DEVICE_TABLE(of, ak4104_of_match); +static const struct spi_device_id ak4104_id_table[] = { +	{ "ak4104", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, ak4104_id_table); +  static struct spi_driver ak4104_spi_driver = {  	.driver  = { -		.name   = DRV_NAME, +		.name   = "ak4104",  		.owner  = THIS_MODULE,  		.of_match_table = ak4104_of_match,  	}, +	.id_table = ak4104_id_table,  	.probe  = ak4104_spi_probe,  	.remove = ak4104_spi_remove,  };  | 
