diff options
Diffstat (limited to 'sound/soc/codecs/ad1836.c')
-rw-r--r-- | sound/soc/codecs/ad1836.c | 191 |
1 files changed, 55 insertions, 136 deletions
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index a01006c8c606..d272534c8f84 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -33,15 +33,10 @@ | |||
33 | 33 | ||
34 | /* codec private data */ | 34 | /* codec private data */ |
35 | struct ad1836_priv { | 35 | struct ad1836_priv { |
36 | struct snd_soc_codec codec; | 36 | enum snd_soc_control_type control_type; |
37 | u16 reg_cache[AD1836_NUM_REGS]; | 37 | void *control_data; |
38 | }; | 38 | }; |
39 | 39 | ||
40 | static struct snd_soc_codec *ad1836_codec; | ||
41 | struct snd_soc_codec_device soc_codec_dev_ad1836; | ||
42 | static int ad1836_register(struct ad1836_priv *ad1836); | ||
43 | static void ad1836_unregister(struct ad1836_priv *ad1836); | ||
44 | |||
45 | /* | 40 | /* |
46 | * AD1836 volume/mute/de-emphasis etc. controls | 41 | * AD1836 volume/mute/de-emphasis etc. controls |
47 | */ | 42 | */ |
@@ -146,8 +141,7 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, | |||
146 | int word_len = 0; | 141 | int word_len = 0; |
147 | 142 | ||
148 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 143 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
149 | struct snd_soc_device *socdev = rtd->socdev; | 144 | struct snd_soc_codec *codec = rtd->codec; |
150 | struct snd_soc_codec *codec = socdev->card->codec; | ||
151 | 145 | ||
152 | /* bit size */ | 146 | /* bit size */ |
153 | switch (params_format(params)) { | 147 | switch (params_format(params)) { |
@@ -173,12 +167,9 @@ static int ad1836_hw_params(struct snd_pcm_substream *substream, | |||
173 | } | 167 | } |
174 | 168 | ||
175 | #ifdef CONFIG_PM | 169 | #ifdef CONFIG_PM |
176 | static int ad1836_soc_suspend(struct platform_device *pdev, | 170 | static int ad1836_soc_suspend(struct snd_soc_codec *codec, |
177 | pm_message_t state) | 171 | pm_message_t state) |
178 | { | 172 | { |
179 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
180 | struct snd_soc_codec *codec = socdev->card->codec; | ||
181 | |||
182 | /* reset clock control mode */ | 173 | /* reset clock control mode */ |
183 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); | 174 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); |
184 | adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; | 175 | adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; |
@@ -186,11 +177,8 @@ static int ad1836_soc_suspend(struct platform_device *pdev, | |||
186 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); | 177 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); |
187 | } | 178 | } |
188 | 179 | ||
189 | static int ad1836_soc_resume(struct platform_device *pdev) | 180 | static int ad1836_soc_resume(struct snd_soc_codec *codec) |
190 | { | 181 | { |
191 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
192 | struct snd_soc_codec *codec = socdev->card->codec; | ||
193 | |||
194 | /* restore clock control mode */ | 182 | /* restore clock control mode */ |
195 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); | 183 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); |
196 | adc_ctrl2 |= AD1836_ADC_AUX; | 184 | adc_ctrl2 |= AD1836_ADC_AUX; |
@@ -202,49 +190,14 @@ static int ad1836_soc_resume(struct platform_device *pdev) | |||
202 | #define ad1836_soc_resume NULL | 190 | #define ad1836_soc_resume NULL |
203 | #endif | 191 | #endif |
204 | 192 | ||
205 | static int __devinit ad1836_spi_probe(struct spi_device *spi) | ||
206 | { | ||
207 | struct snd_soc_codec *codec; | ||
208 | struct ad1836_priv *ad1836; | ||
209 | |||
210 | ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL); | ||
211 | if (ad1836 == NULL) | ||
212 | return -ENOMEM; | ||
213 | |||
214 | codec = &ad1836->codec; | ||
215 | codec->control_data = spi; | ||
216 | codec->dev = &spi->dev; | ||
217 | |||
218 | dev_set_drvdata(&spi->dev, ad1836); | ||
219 | |||
220 | return ad1836_register(ad1836); | ||
221 | } | ||
222 | |||
223 | static int __devexit ad1836_spi_remove(struct spi_device *spi) | ||
224 | { | ||
225 | struct ad1836_priv *ad1836 = dev_get_drvdata(&spi->dev); | ||
226 | |||
227 | ad1836_unregister(ad1836); | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static struct spi_driver ad1836_spi_driver = { | ||
232 | .driver = { | ||
233 | .name = "ad1836", | ||
234 | .owner = THIS_MODULE, | ||
235 | }, | ||
236 | .probe = ad1836_spi_probe, | ||
237 | .remove = __devexit_p(ad1836_spi_remove), | ||
238 | }; | ||
239 | |||
240 | static struct snd_soc_dai_ops ad1836_dai_ops = { | 193 | static struct snd_soc_dai_ops ad1836_dai_ops = { |
241 | .hw_params = ad1836_hw_params, | 194 | .hw_params = ad1836_hw_params, |
242 | .set_fmt = ad1836_set_dai_fmt, | 195 | .set_fmt = ad1836_set_dai_fmt, |
243 | }; | 196 | }; |
244 | 197 | ||
245 | /* codec DAI instance */ | 198 | /* codec DAI instance */ |
246 | struct snd_soc_dai ad1836_dai = { | 199 | static struct snd_soc_dai_driver ad1836_dai = { |
247 | .name = "AD1836", | 200 | .name = "ad1836-hifi", |
248 | .playback = { | 201 | .playback = { |
249 | .stream_name = "Playback", | 202 | .stream_name = "Playback", |
250 | .channels_min = 2, | 203 | .channels_min = 2, |
@@ -263,35 +216,13 @@ struct snd_soc_dai ad1836_dai = { | |||
263 | }, | 216 | }, |
264 | .ops = &ad1836_dai_ops, | 217 | .ops = &ad1836_dai_ops, |
265 | }; | 218 | }; |
266 | EXPORT_SYMBOL_GPL(ad1836_dai); | ||
267 | 219 | ||
268 | static int ad1836_register(struct ad1836_priv *ad1836) | 220 | static int ad1836_probe(struct snd_soc_codec *codec) |
269 | { | 221 | { |
270 | int ret; | 222 | struct ad1836_priv *ad1836 = snd_soc_codec_get_drvdata(codec); |
271 | struct snd_soc_codec *codec = &ad1836->codec; | 223 | int ret = 0; |
272 | |||
273 | if (ad1836_codec) { | ||
274 | dev_err(codec->dev, "Another ad1836 is registered\n"); | ||
275 | kfree(ad1836); | ||
276 | return -EINVAL; | ||
277 | } | ||
278 | |||
279 | mutex_init(&codec->mutex); | ||
280 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
281 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
282 | snd_soc_codec_set_drvdata(codec, ad1836); | ||
283 | codec->reg_cache = ad1836->reg_cache; | ||
284 | codec->reg_cache_size = AD1836_NUM_REGS; | ||
285 | codec->name = "AD1836"; | ||
286 | codec->owner = THIS_MODULE; | ||
287 | codec->dai = &ad1836_dai; | ||
288 | codec->num_dai = 1; | ||
289 | INIT_LIST_HEAD(&codec->dapm_widgets); | ||
290 | INIT_LIST_HEAD(&codec->dapm_paths); | ||
291 | |||
292 | ad1836_dai.dev = codec->dev; | ||
293 | ad1836_codec = codec; | ||
294 | 224 | ||
225 | codec->control_data = ad1836->control_data; | ||
295 | ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); | 226 | ret = snd_soc_codec_set_cache_io(codec, 4, 12, SND_SOC_SPI); |
296 | if (ret < 0) { | 227 | if (ret < 0) { |
297 | dev_err(codec->dev, "failed to set cache I/O: %d\n", | 228 | dev_err(codec->dev, "failed to set cache I/O: %d\n", |
@@ -319,81 +250,69 @@ static int ad1836_register(struct ad1836_priv *ad1836) | |||
319 | snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); | 250 | snd_soc_write(codec, AD1836_DAC_L3_VOL, 0x3FF); |
320 | snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); | 251 | snd_soc_write(codec, AD1836_DAC_R3_VOL, 0x3FF); |
321 | 252 | ||
322 | ret = snd_soc_register_codec(codec); | ||
323 | if (ret != 0) { | ||
324 | dev_err(codec->dev, "Failed to register codec: %d\n", ret); | ||
325 | kfree(ad1836); | ||
326 | return ret; | ||
327 | } | ||
328 | |||
329 | ret = snd_soc_register_dai(&ad1836_dai); | ||
330 | if (ret != 0) { | ||
331 | dev_err(codec->dev, "Failed to register DAI: %d\n", ret); | ||
332 | snd_soc_unregister_codec(codec); | ||
333 | kfree(ad1836); | ||
334 | return ret; | ||
335 | } | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static void ad1836_unregister(struct ad1836_priv *ad1836) | ||
341 | { | ||
342 | snd_soc_unregister_dai(&ad1836_dai); | ||
343 | snd_soc_unregister_codec(&ad1836->codec); | ||
344 | kfree(ad1836); | ||
345 | ad1836_codec = NULL; | ||
346 | } | ||
347 | |||
348 | static int ad1836_probe(struct platform_device *pdev) | ||
349 | { | ||
350 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | ||
351 | struct snd_soc_codec *codec; | ||
352 | int ret = 0; | ||
353 | |||
354 | if (ad1836_codec == NULL) { | ||
355 | dev_err(&pdev->dev, "Codec device not registered\n"); | ||
356 | return -ENODEV; | ||
357 | } | ||
358 | |||
359 | socdev->card->codec = ad1836_codec; | ||
360 | codec = ad1836_codec; | ||
361 | |||
362 | /* register pcms */ | ||
363 | ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); | ||
364 | if (ret < 0) { | ||
365 | dev_err(codec->dev, "failed to create pcms: %d\n", ret); | ||
366 | goto pcm_err; | ||
367 | } | ||
368 | |||
369 | snd_soc_add_controls(codec, ad1836_snd_controls, | 253 | snd_soc_add_controls(codec, ad1836_snd_controls, |
370 | ARRAY_SIZE(ad1836_snd_controls)); | 254 | ARRAY_SIZE(ad1836_snd_controls)); |
371 | snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets, | 255 | snd_soc_dapm_new_controls(codec, ad1836_dapm_widgets, |
372 | ARRAY_SIZE(ad1836_dapm_widgets)); | 256 | ARRAY_SIZE(ad1836_dapm_widgets)); |
373 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); | 257 | snd_soc_dapm_add_routes(codec, audio_paths, ARRAY_SIZE(audio_paths)); |
374 | 258 | ||
375 | pcm_err: | ||
376 | return ret; | 259 | return ret; |
377 | } | 260 | } |
378 | 261 | ||
379 | /* power down chip */ | 262 | /* power down chip */ |
380 | static int ad1836_remove(struct platform_device *pdev) | 263 | static int ad1836_remove(struct snd_soc_codec *codec) |
381 | { | 264 | { |
382 | struct snd_soc_device *socdev = platform_get_drvdata(pdev); | 265 | /* reset clock control mode */ |
383 | 266 | u16 adc_ctrl2 = snd_soc_read(codec, AD1836_ADC_CTRL2); | |
384 | snd_soc_free_pcms(socdev); | 267 | adc_ctrl2 &= ~AD1836_ADC_SERFMT_MASK; |
385 | snd_soc_dapm_free(socdev); | ||
386 | 268 | ||
387 | return 0; | 269 | return snd_soc_write(codec, AD1836_ADC_CTRL2, adc_ctrl2); |
388 | } | 270 | } |
389 | 271 | ||
390 | struct snd_soc_codec_device soc_codec_dev_ad1836 = { | 272 | static struct snd_soc_codec_driver soc_codec_dev_ad1836 = { |
391 | .probe = ad1836_probe, | 273 | .probe = ad1836_probe, |
392 | .remove = ad1836_remove, | 274 | .remove = ad1836_remove, |
393 | .suspend = ad1836_soc_suspend, | 275 | .suspend = ad1836_soc_suspend, |
394 | .resume = ad1836_soc_resume, | 276 | .resume = ad1836_soc_resume, |
277 | .reg_cache_size = AD1836_NUM_REGS, | ||
278 | .reg_word_size = sizeof(u16), | ||
279 | }; | ||
280 | |||
281 | static int __devinit ad1836_spi_probe(struct spi_device *spi) | ||
282 | { | ||
283 | struct ad1836_priv *ad1836; | ||
284 | int ret; | ||
285 | |||
286 | ad1836 = kzalloc(sizeof(struct ad1836_priv), GFP_KERNEL); | ||
287 | if (ad1836 == NULL) | ||
288 | return -ENOMEM; | ||
289 | |||
290 | spi_set_drvdata(spi, ad1836); | ||
291 | ad1836->control_data = spi; | ||
292 | ad1836->control_type = SND_SOC_SPI; | ||
293 | |||
294 | ret = snd_soc_register_codec(&spi->dev, | ||
295 | &soc_codec_dev_ad1836, &ad1836_dai, 1); | ||
296 | if (ret < 0) | ||
297 | kfree(ad1836); | ||
298 | return ret; | ||
299 | } | ||
300 | |||
301 | static int __devexit ad1836_spi_remove(struct spi_device *spi) | ||
302 | { | ||
303 | snd_soc_unregister_codec(&spi->dev); | ||
304 | kfree(spi_get_drvdata(spi)); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static struct spi_driver ad1836_spi_driver = { | ||
309 | .driver = { | ||
310 | .name = "ad1836-codec", | ||
311 | .owner = THIS_MODULE, | ||
312 | }, | ||
313 | .probe = ad1836_spi_probe, | ||
314 | .remove = __devexit_p(ad1836_spi_remove), | ||
395 | }; | 315 | }; |
396 | EXPORT_SYMBOL_GPL(soc_codec_dev_ad1836); | ||
397 | 316 | ||
398 | static int __init ad1836_init(void) | 317 | static int __init ad1836_init(void) |
399 | { | 318 | { |