| OLD | NEW |
| 1 /* | 1 /* |
| 2 * wm8971.c -- WM8971 ALSA SoC Audio driver | 2 * wm8971.c -- WM8971 ALSA SoC Audio driver |
| 3 * | 3 * |
| 4 * Copyright 2005 Lab126, Inc. | 4 * Copyright 2005 Lab126, Inc. |
| 5 * | 5 * |
| 6 * Author: Kenneth Kiraly <kiraly@lab126.com> | 6 * Author: Kenneth Kiraly <kiraly@lab126.com> |
| 7 * | 7 * |
| 8 * Based on wm8753.c by Liam Girdwood | 8 * Based on wm8753.c by Liam Girdwood |
| 9 * | 9 * |
| 10 * This program is free software; you can redistribute it and/or modify it | 10 * This program is free software; you can redistribute it and/or modify it |
| 11 * under the terms of the GNU General Public License as published by the | 11 * under the terms of the GNU General Public License as published by the |
| 12 * Free Software Foundation; either version 2 of the License, or (at your | 12 * Free Software Foundation; either version 2 of the License, or (at your |
| 13 * option) any later version. | 13 * option) any later version. |
| 14 */ | 14 */ |
| 15 | 15 |
| 16 #include <linux/module.h> | 16 #include <linux/module.h> |
| 17 #include <linux/moduleparam.h> | 17 #include <linux/moduleparam.h> |
| 18 #include <linux/init.h> | 18 #include <linux/init.h> |
| 19 #include <linux/delay.h> | 19 #include <linux/delay.h> |
| 20 #include <linux/pm.h> | 20 #include <linux/pm.h> |
| 21 #include <linux/i2c.h> | 21 #include <linux/i2c.h> |
| 22 #include <linux/platform_device.h> | 22 #include <linux/platform_device.h> |
| 23 #include <linux/slab.h> | 23 #include <linux/slab.h> |
| 24 #include <sound/core.h> | 24 #include <sound/core.h> |
| 25 #include <sound/pcm.h> | 25 #include <sound/pcm.h> |
| 26 #include <sound/pcm_params.h> | 26 #include <sound/pcm_params.h> |
| 27 #include <sound/soc.h> | 27 #include <sound/soc.h> |
| 28 #include <sound/soc-dapm.h> | |
| 29 #include <sound/initval.h> | 28 #include <sound/initval.h> |
| 30 | 29 |
| 31 #include "wm8971.h" | 30 #include "wm8971.h" |
| 32 | 31 |
| 33 #define WM8971_REG_COUNT 43 | 32 #define WM8971_REG_COUNT 43 |
| 34 | 33 |
| 35 static struct workqueue_struct *wm8971_workq = NULL; | 34 static struct workqueue_struct *wm8971_workq = NULL; |
| 36 | 35 |
| 37 /* codec private data */ | 36 /* codec private data */ |
| 38 struct wm8971_priv { | 37 struct wm8971_priv { |
| (...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, | 325 {"Right ADC Mux", "Mono (Right)", "Right PGA Mux"}, |
| 327 {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, | 326 {"Right ADC Mux", "Digital Mono", "Right PGA Mux"}, |
| 328 | 327 |
| 329 /* ADC */ | 328 /* ADC */ |
| 330 {"Left ADC", NULL, "Left ADC Mux"}, | 329 {"Left ADC", NULL, "Left ADC Mux"}, |
| 331 {"Right ADC", NULL, "Right ADC Mux"}, | 330 {"Right ADC", NULL, "Right ADC Mux"}, |
| 332 }; | 331 }; |
| 333 | 332 |
| 334 static int wm8971_add_widgets(struct snd_soc_codec *codec) | 333 static int wm8971_add_widgets(struct snd_soc_codec *codec) |
| 335 { | 334 { |
| 336 » snd_soc_dapm_new_controls(codec, wm8971_dapm_widgets, | 335 » struct snd_soc_dapm_context *dapm = &codec->dapm; |
| 336 |
| 337 » snd_soc_dapm_new_controls(dapm, wm8971_dapm_widgets, |
| 337 ARRAY_SIZE(wm8971_dapm_widgets)); | 338 ARRAY_SIZE(wm8971_dapm_widgets)); |
| 338 | 339 » snd_soc_dapm_add_routes(dapm, audio_map, ARRAY_SIZE(audio_map)); |
| 339 » snd_soc_dapm_add_routes(codec, audio_map, ARRAY_SIZE(audio_map)); | |
| 340 | 340 |
| 341 return 0; | 341 return 0; |
| 342 } | 342 } |
| 343 | 343 |
| 344 struct _coeff_div { | 344 struct _coeff_div { |
| 345 u32 mclk; | 345 u32 mclk; |
| 346 u32 rate; | 346 u32 rate; |
| 347 u16 fs; | 347 u16 fs; |
| 348 u8 sr:5; | 348 u8 sr:5; |
| 349 u8 usb:1; | 349 u8 usb:1; |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 case SND_SOC_BIAS_PREPARE: | 546 case SND_SOC_BIAS_PREPARE: |
| 547 break; | 547 break; |
| 548 case SND_SOC_BIAS_STANDBY: | 548 case SND_SOC_BIAS_STANDBY: |
| 549 /* mute dac and set vmid to 500k, enable VREF */ | 549 /* mute dac and set vmid to 500k, enable VREF */ |
| 550 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); | 550 snd_soc_write(codec, WM8971_PWR1, pwr_reg | 0x0140); |
| 551 break; | 551 break; |
| 552 case SND_SOC_BIAS_OFF: | 552 case SND_SOC_BIAS_OFF: |
| 553 snd_soc_write(codec, WM8971_PWR1, 0x0001); | 553 snd_soc_write(codec, WM8971_PWR1, 0x0001); |
| 554 break; | 554 break; |
| 555 } | 555 } |
| 556 » codec->bias_level = level; | 556 » codec->dapm.bias_level = level; |
| 557 return 0; | 557 return 0; |
| 558 } | 558 } |
| 559 | 559 |
| 560 #define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ | 560 #define WM8971_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
| 561 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_441
00 | \ | 561 SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_441
00 | \ |
| 562 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_960
00) | 562 SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_960
00) |
| 563 | 563 |
| 564 #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 564 #define WM8971_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
| 565 SNDRV_PCM_FMTBIT_S24_LE) | 565 SNDRV_PCM_FMTBIT_S24_LE) |
| 566 | 566 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 583 .stream_name = "Capture", | 583 .stream_name = "Capture", |
| 584 .channels_min = 1, | 584 .channels_min = 1, |
| 585 .channels_max = 2, | 585 .channels_max = 2, |
| 586 .rates = WM8971_RATES, | 586 .rates = WM8971_RATES, |
| 587 .formats = WM8971_FORMATS,}, | 587 .formats = WM8971_FORMATS,}, |
| 588 .ops = &wm8971_dai_ops, | 588 .ops = &wm8971_dai_ops, |
| 589 }; | 589 }; |
| 590 | 590 |
| 591 static void wm8971_work(struct work_struct *work) | 591 static void wm8971_work(struct work_struct *work) |
| 592 { | 592 { |
| 593 » struct snd_soc_codec *codec = | 593 » struct snd_soc_dapm_context *dapm = |
| 594 » » container_of(work, struct snd_soc_codec, delayed_work.work); | 594 » » container_of(work, struct snd_soc_dapm_context, |
| 595 » wm8971_set_bias_level(codec, codec->bias_level); | 595 » » » delayed_work.work); |
| 596 » struct snd_soc_codec *codec = dapm->codec; |
| 597 » wm8971_set_bias_level(codec, codec->dapm.bias_level); |
| 596 } | 598 } |
| 597 | 599 |
| 598 static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state) | 600 static int wm8971_suspend(struct snd_soc_codec *codec, pm_message_t state) |
| 599 { | 601 { |
| 600 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); | 602 wm8971_set_bias_level(codec, SND_SOC_BIAS_OFF); |
| 601 return 0; | 603 return 0; |
| 602 } | 604 } |
| 603 | 605 |
| 604 static int wm8971_resume(struct snd_soc_codec *codec) | 606 static int wm8971_resume(struct snd_soc_codec *codec) |
| 605 { | 607 { |
| 606 int i; | 608 int i; |
| 607 u8 data[2]; | 609 u8 data[2]; |
| 608 u16 *cache = codec->reg_cache; | 610 u16 *cache = codec->reg_cache; |
| 609 u16 reg; | 611 u16 reg; |
| 610 | 612 |
| 611 /* Sync reg_cache with the hardware */ | 613 /* Sync reg_cache with the hardware */ |
| 612 for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) { | 614 for (i = 0; i < ARRAY_SIZE(wm8971_reg); i++) { |
| 613 if (i + 1 == WM8971_RESET) | 615 if (i + 1 == WM8971_RESET) |
| 614 continue; | 616 continue; |
| 615 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); | 617 data[0] = (i << 1) | ((cache[i] >> 8) & 0x0001); |
| 616 data[1] = cache[i] & 0x00ff; | 618 data[1] = cache[i] & 0x00ff; |
| 617 codec->hw_write(codec->control_data, data, 2); | 619 codec->hw_write(codec->control_data, data, 2); |
| 618 } | 620 } |
| 619 | 621 |
| 620 wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 622 wm8971_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
| 621 | 623 |
| 622 /* charge wm8971 caps */ | 624 /* charge wm8971 caps */ |
| 623 » if (codec->suspend_bias_level == SND_SOC_BIAS_ON) { | 625 » if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) { |
| 624 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; | 626 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; |
| 625 snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); | 627 snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); |
| 626 » » codec->bias_level = SND_SOC_BIAS_ON; | 628 » » codec->dapm.bias_level = SND_SOC_BIAS_ON; |
| 627 » » queue_delayed_work(wm8971_workq, &codec->delayed_work, | 629 » » queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, |
| 628 msecs_to_jiffies(1000)); | 630 msecs_to_jiffies(1000)); |
| 629 } | 631 } |
| 630 | 632 |
| 631 return 0; | 633 return 0; |
| 632 } | 634 } |
| 633 | 635 |
| 634 static int wm8971_probe(struct snd_soc_codec *codec) | 636 static int wm8971_probe(struct snd_soc_codec *codec) |
| 635 { | 637 { |
| 636 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); | 638 struct wm8971_priv *wm8971 = snd_soc_codec_get_drvdata(codec); |
| 637 int ret = 0; | 639 int ret = 0; |
| 638 u16 reg; | 640 u16 reg; |
| 639 | 641 |
| 640 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type); | 642 ret = snd_soc_codec_set_cache_io(codec, 7, 9, wm8971->control_type); |
| 641 if (ret < 0) { | 643 if (ret < 0) { |
| 642 printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); | 644 printk(KERN_ERR "wm8971: failed to set cache I/O: %d\n", ret); |
| 643 return ret; | 645 return ret; |
| 644 } | 646 } |
| 645 | 647 |
| 646 » INIT_DELAYED_WORK(&codec->delayed_work, wm8971_work); | 648 » INIT_DELAYED_WORK(&codec->dapm.delayed_work, wm8971_work); |
| 647 wm8971_workq = create_workqueue("wm8971"); | 649 wm8971_workq = create_workqueue("wm8971"); |
| 648 if (wm8971_workq == NULL) | 650 if (wm8971_workq == NULL) |
| 649 return -ENOMEM; | 651 return -ENOMEM; |
| 650 | 652 |
| 651 wm8971_reset(codec); | 653 wm8971_reset(codec); |
| 652 | 654 |
| 653 /* charge output caps - set vmid to 5k for quick power up */ | 655 /* charge output caps - set vmid to 5k for quick power up */ |
| 654 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; | 656 reg = snd_soc_read(codec, WM8971_PWR1) & 0xfe3e; |
| 655 snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); | 657 snd_soc_write(codec, WM8971_PWR1, reg | 0x01c0); |
| 656 » codec->bias_level = SND_SOC_BIAS_STANDBY; | 658 » codec->dapm.bias_level = SND_SOC_BIAS_STANDBY; |
| 657 » queue_delayed_work(wm8971_workq, &codec->delayed_work, | 659 » queue_delayed_work(wm8971_workq, &codec->dapm.delayed_work, |
| 658 msecs_to_jiffies(1000)); | 660 msecs_to_jiffies(1000)); |
| 659 | 661 |
| 660 /* set the update bits */ | 662 /* set the update bits */ |
| 661 reg = snd_soc_read(codec, WM8971_LDAC); | 663 reg = snd_soc_read(codec, WM8971_LDAC); |
| 662 snd_soc_write(codec, WM8971_LDAC, reg | 0x0100); | 664 snd_soc_write(codec, WM8971_LDAC, reg | 0x0100); |
| 663 reg = snd_soc_read(codec, WM8971_RDAC); | 665 reg = snd_soc_read(codec, WM8971_RDAC); |
| 664 snd_soc_write(codec, WM8971_RDAC, reg | 0x0100); | 666 snd_soc_write(codec, WM8971_RDAC, reg | 0x0100); |
| 665 | 667 |
| 666 reg = snd_soc_read(codec, WM8971_LOUT1V); | 668 reg = snd_soc_read(codec, WM8971_LOUT1V); |
| 667 snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100); | 669 snd_soc_write(codec, WM8971_LOUT1V, reg | 0x0100); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 770 { | 772 { |
| 771 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) | 773 #if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE) |
| 772 i2c_del_driver(&wm8971_i2c_driver); | 774 i2c_del_driver(&wm8971_i2c_driver); |
| 773 #endif | 775 #endif |
| 774 } | 776 } |
| 775 module_exit(wm8971_exit); | 777 module_exit(wm8971_exit); |
| 776 | 778 |
| 777 MODULE_DESCRIPTION("ASoC WM8971 driver"); | 779 MODULE_DESCRIPTION("ASoC WM8971 driver"); |
| 778 MODULE_AUTHOR("Lab126"); | 780 MODULE_AUTHOR("Lab126"); |
| 779 MODULE_LICENSE("GPL"); | 781 MODULE_LICENSE("GPL"); |
| OLD | NEW |