Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ASoC: ak4104: add regulator consumer support

The AK4104 has only one power supply, called VDD. Enable it as long as
the codec is in use.

Signed-off-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Mark Brown <broonie@linaro.org>

authored by

Daniel Mack and committed by
Mark Brown
b38d10ed c9eaa447

+55 -7
+55 -7
sound/soc/codecs/ak4104.c
··· 11 11 12 12 #include <linux/module.h> 13 13 #include <linux/slab.h> 14 - #include <sound/core.h> 15 - #include <sound/soc.h> 16 - #include <sound/initval.h> 17 14 #include <linux/spi/spi.h> 18 15 #include <linux/of_device.h> 19 16 #include <linux/of_gpio.h> 17 + #include <linux/regulator/consumer.h> 20 18 #include <sound/asoundef.h> 19 + #include <sound/core.h> 20 + #include <sound/soc.h> 21 + #include <sound/initval.h> 21 22 22 23 /* AK4104 registers addresses */ 23 24 #define AK4104_REG_CONTROL1 0x00 ··· 48 47 49 48 struct ak4104_private { 50 49 struct regmap *regmap; 50 + struct regulator *regulator; 51 51 }; 52 52 53 53 static const struct snd_soc_dapm_widget ak4104_dapm_widgets[] = { ··· 176 174 struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); 177 175 int ret; 178 176 177 + ret = regulator_enable(ak4104->regulator); 178 + if (ret < 0) { 179 + dev_err(codec->dev, "Unable to enable regulator: %d\n", ret); 180 + return ret; 181 + } 182 + 179 183 /* set power-up and non-reset bits */ 180 184 ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, 181 185 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 182 186 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN); 183 187 if (ret < 0) 184 - return ret; 188 + goto exit_disable_regulator; 185 189 186 190 /* enable transmitter */ 187 191 ret = regmap_update_bits(ak4104->regmap, AK4104_REG_TX, 188 192 AK4104_TX_TXE, AK4104_TX_TXE); 189 193 if (ret < 0) 190 - return ret; 194 + goto exit_disable_regulator; 191 195 192 196 return 0; 197 + 198 + exit_disable_regulator: 199 + regulator_disable(ak4104->regulator); 200 + return ret; 193 201 } 194 202 195 203 static int ak4104_remove(struct snd_soc_codec *codec) ··· 208 196 209 197 regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, 210 198 AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, 0); 199 + regulator_disable(ak4104->regulator); 211 200 212 201 return 0; 213 202 } 214 203 204 + #ifdef CONFIG_PM 205 + static int ak4104_soc_suspend(struct snd_soc_codec *codec) 206 + { 207 + struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); 208 + 209 + regulator_disable(priv->regulator); 210 + 211 + return 0; 212 + } 213 + 214 + static int ak4104_soc_resume(struct snd_soc_codec *codec) 215 + { 216 + struct ak4104_private *priv = snd_soc_codec_get_drvdata(codec); 217 + int ret; 218 + 219 + ret = regulator_enable(priv->regulator); 220 + if (ret < 0) 221 + return ret; 222 + 223 + return 0; 224 + } 225 + #else 226 + #define ak4104_soc_suspend NULL 227 + #define ak4104_soc_resume NULL 228 + #endif /* CONFIG_PM */ 229 + 215 230 static struct snd_soc_codec_driver soc_codec_device_ak4104 = { 216 - .probe = ak4104_probe, 217 - .remove = ak4104_remove, 231 + .probe = ak4104_probe, 232 + .remove = ak4104_remove, 233 + .suspend = ak4104_soc_suspend, 234 + .resume = ak4104_soc_resume, 218 235 219 236 .dapm_widgets = ak4104_dapm_widgets, 220 237 .num_dapm_widgets = ARRAY_SIZE(ak4104_dapm_widgets), ··· 279 238 GFP_KERNEL); 280 239 if (ak4104 == NULL) 281 240 return -ENOMEM; 241 + 242 + ak4104->regulator = devm_regulator_get(&spi->dev, "vdd"); 243 + if (IS_ERR(ak4104->regulator)) { 244 + ret = PTR_ERR(ak4104->regulator); 245 + dev_err(&spi->dev, "Unable to get Vdd regulator: %d\n", ret); 246 + return ret; 247 + } 282 248 283 249 ak4104->regmap = devm_regmap_init_spi(spi, &ak4104_regmap); 284 250 if (IS_ERR(ak4104->regmap)) {