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