diff options
Diffstat (limited to 'sound')
124 files changed, 5965 insertions, 1423 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index 051d55b05521..9f404e965ea2 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -684,7 +684,7 @@ int snd_info_card_free(struct snd_card *card) | |||
684 | * snd_info_get_line - read one line from the procfs buffer | 684 | * snd_info_get_line - read one line from the procfs buffer |
685 | * @buffer: the procfs buffer | 685 | * @buffer: the procfs buffer |
686 | * @line: the buffer to store | 686 | * @line: the buffer to store |
687 | * @len: the max. buffer size - 1 | 687 | * @len: the max. buffer size |
688 | * | 688 | * |
689 | * Reads one line from the buffer and stores the string. | 689 | * Reads one line from the buffer and stores the string. |
690 | * | 690 | * |
@@ -704,7 +704,7 @@ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) | |||
704 | buffer->stop = 1; | 704 | buffer->stop = 1; |
705 | if (c == '\n') | 705 | if (c == '\n') |
706 | break; | 706 | break; |
707 | if (len) { | 707 | if (len > 1) { |
708 | len--; | 708 | len--; |
709 | *line++ = c; | 709 | *line++ = c; |
710 | } | 710 | } |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 9acc77eae487..0032278567ad 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -1782,14 +1782,16 @@ static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream, | |||
1782 | { | 1782 | { |
1783 | struct snd_pcm_hw_params *params = arg; | 1783 | struct snd_pcm_hw_params *params = arg; |
1784 | snd_pcm_format_t format; | 1784 | snd_pcm_format_t format; |
1785 | int channels, width; | 1785 | int channels; |
1786 | ssize_t frame_size; | ||
1786 | 1787 | ||
1787 | params->fifo_size = substream->runtime->hw.fifo_size; | 1788 | params->fifo_size = substream->runtime->hw.fifo_size; |
1788 | if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { | 1789 | if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) { |
1789 | format = params_format(params); | 1790 | format = params_format(params); |
1790 | channels = params_channels(params); | 1791 | channels = params_channels(params); |
1791 | width = snd_pcm_format_physical_width(format); | 1792 | frame_size = snd_pcm_format_size(format, channels); |
1792 | params->fifo_size /= width * channels; | 1793 | if (frame_size > 0) |
1794 | params->fifo_size /= (unsigned)frame_size; | ||
1793 | } | 1795 | } |
1794 | return 0; | 1796 | return 0; |
1795 | } | 1797 | } |
diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 4560ca0e5651..2c6fd80e0bd1 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c | |||
@@ -142,11 +142,11 @@ static struct pcm_format_data pcm_formats[(INT)SNDRV_PCM_FORMAT_LAST+1] = { | |||
142 | }, | 142 | }, |
143 | [SNDRV_PCM_FORMAT_DSD_U8] = { | 143 | [SNDRV_PCM_FORMAT_DSD_U8] = { |
144 | .width = 8, .phys = 8, .le = 1, .signd = 0, | 144 | .width = 8, .phys = 8, .le = 1, .signd = 0, |
145 | .silence = {}, | 145 | .silence = { 0x69 }, |
146 | }, | 146 | }, |
147 | [SNDRV_PCM_FORMAT_DSD_U16_LE] = { | 147 | [SNDRV_PCM_FORMAT_DSD_U16_LE] = { |
148 | .width = 16, .phys = 16, .le = 1, .signd = 0, | 148 | .width = 16, .phys = 16, .le = 1, .signd = 0, |
149 | .silence = {}, | 149 | .silence = { 0x69, 0x69 }, |
150 | }, | 150 | }, |
151 | /* FIXME: the following three formats are not defined properly yet */ | 151 | /* FIXME: the following three formats are not defined properly yet */ |
152 | [SNDRV_PCM_FORMAT_MPEG] = { | 152 | [SNDRV_PCM_FORMAT_MPEG] = { |
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c index f96bf4c7c232..95fc2eaf11dc 100644 --- a/sound/firewire/amdtp.c +++ b/sound/firewire/amdtp.c | |||
@@ -507,7 +507,16 @@ static void amdtp_pull_midi(struct amdtp_stream *s, | |||
507 | static void update_pcm_pointers(struct amdtp_stream *s, | 507 | static void update_pcm_pointers(struct amdtp_stream *s, |
508 | struct snd_pcm_substream *pcm, | 508 | struct snd_pcm_substream *pcm, |
509 | unsigned int frames) | 509 | unsigned int frames) |
510 | { unsigned int ptr; | 510 | { |
511 | unsigned int ptr; | ||
512 | |||
513 | /* | ||
514 | * In IEC 61883-6, one data block represents one event. In ALSA, one | ||
515 | * event equals to one PCM frame. But Dice has a quirk to transfer | ||
516 | * two PCM frames in one data block. | ||
517 | */ | ||
518 | if (s->double_pcm_frames) | ||
519 | frames *= 2; | ||
511 | 520 | ||
512 | ptr = s->pcm_buffer_pointer + frames; | 521 | ptr = s->pcm_buffer_pointer + frames; |
513 | if (ptr >= pcm->runtime->buffer_size) | 522 | if (ptr >= pcm->runtime->buffer_size) |
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h index d8ee7b0e9386..4823c08196ac 100644 --- a/sound/firewire/amdtp.h +++ b/sound/firewire/amdtp.h | |||
@@ -125,6 +125,7 @@ struct amdtp_stream { | |||
125 | unsigned int pcm_buffer_pointer; | 125 | unsigned int pcm_buffer_pointer; |
126 | unsigned int pcm_period_pointer; | 126 | unsigned int pcm_period_pointer; |
127 | bool pointer_flush; | 127 | bool pointer_flush; |
128 | bool double_pcm_frames; | ||
128 | 129 | ||
129 | struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; | 130 | struct snd_rawmidi_substream *midi[AMDTP_MAX_CHANNELS_FOR_MIDI * 8]; |
130 | 131 | ||
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c index a9a30c0161f1..e3a04d69c853 100644 --- a/sound/firewire/dice.c +++ b/sound/firewire/dice.c | |||
@@ -567,10 +567,14 @@ static int dice_hw_params(struct snd_pcm_substream *substream, | |||
567 | return err; | 567 | return err; |
568 | 568 | ||
569 | /* | 569 | /* |
570 | * At rates above 96 kHz, pretend that the stream runs at half the | 570 | * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in |
571 | * actual sample rate with twice the number of channels; two samples | 571 | * one data block of AMDTP packet. Thus sampling transfer frequency is |
572 | * of a channel are stored consecutively in the packet. Requires | 572 | * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are |
573 | * blocking mode and PCM buffer size should be aligned to SYT_INTERVAL. | 573 | * transferred on AMDTP packets at 96 kHz. Two successive samples of a |
574 | * channel are stored consecutively in the packet. This quirk is called | ||
575 | * as 'Dual Wire'. | ||
576 | * For this quirk, blocking mode is required and PCM buffer size should | ||
577 | * be aligned to SYT_INTERVAL. | ||
574 | */ | 578 | */ |
575 | channels = params_channels(hw_params); | 579 | channels = params_channels(hw_params); |
576 | if (rate_index > 4) { | 580 | if (rate_index > 4) { |
@@ -579,18 +583,25 @@ static int dice_hw_params(struct snd_pcm_substream *substream, | |||
579 | return err; | 583 | return err; |
580 | } | 584 | } |
581 | 585 | ||
582 | for (i = 0; i < channels; i++) { | ||
583 | dice->stream.pcm_positions[i * 2] = i; | ||
584 | dice->stream.pcm_positions[i * 2 + 1] = i + channels; | ||
585 | } | ||
586 | |||
587 | rate /= 2; | 586 | rate /= 2; |
588 | channels *= 2; | 587 | channels *= 2; |
588 | dice->stream.double_pcm_frames = true; | ||
589 | } else { | ||
590 | dice->stream.double_pcm_frames = false; | ||
589 | } | 591 | } |
590 | 592 | ||
591 | mode = rate_index_to_mode(rate_index); | 593 | mode = rate_index_to_mode(rate_index); |
592 | amdtp_stream_set_parameters(&dice->stream, rate, channels, | 594 | amdtp_stream_set_parameters(&dice->stream, rate, channels, |
593 | dice->rx_midi_ports[mode]); | 595 | dice->rx_midi_ports[mode]); |
596 | if (rate_index > 4) { | ||
597 | channels /= 2; | ||
598 | |||
599 | for (i = 0; i < channels; i++) { | ||
600 | dice->stream.pcm_positions[i] = i * 2; | ||
601 | dice->stream.pcm_positions[i + channels] = i * 2 + 1; | ||
602 | } | ||
603 | } | ||
604 | |||
594 | amdtp_stream_set_pcm_format(&dice->stream, | 605 | amdtp_stream_set_pcm_format(&dice->stream, |
595 | params_format(hw_params)); | 606 | params_format(hw_params)); |
596 | 607 | ||
diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h index f2e34e3f27ee..5851249f11d9 100644 --- a/sound/pci/ctxfi/ct20k1reg.h +++ b/sound/pci/ctxfi/ct20k1reg.h | |||
@@ -7,7 +7,7 @@ | |||
7 | */ | 7 | */ |
8 | 8 | ||
9 | #ifndef CT20K1REG_H | 9 | #ifndef CT20K1REG_H |
10 | #define CT20k1REG_H | 10 | #define CT20K1REG_H |
11 | 11 | ||
12 | /* 20k1 registers */ | 12 | /* 20k1 registers */ |
13 | #define DSPXRAM_START 0x000000 | 13 | #define DSPXRAM_START 0x000000 |
@@ -632,5 +632,3 @@ | |||
632 | #define I2SD_R 0x19L | 632 | #define I2SD_R 0x19L |
633 | 633 | ||
634 | #endif /* CT20K1REG_H */ | 634 | #endif /* CT20K1REG_H */ |
635 | |||
636 | |||
diff --git a/sound/pci/hda/ca0132_regs.h b/sound/pci/hda/ca0132_regs.h index 07e760937d3c..8371274aa811 100644 --- a/sound/pci/hda/ca0132_regs.h +++ b/sound/pci/hda/ca0132_regs.h | |||
@@ -20,7 +20,7 @@ | |||
20 | */ | 20 | */ |
21 | 21 | ||
22 | #ifndef __CA0132_REGS_H | 22 | #ifndef __CA0132_REGS_H |
23 | #define __CA0312_REGS_H | 23 | #define __CA0132_REGS_H |
24 | 24 | ||
25 | #define DSP_CHIP_OFFSET 0x100000 | 25 | #define DSP_CHIP_OFFSET 0x100000 |
26 | #define DSP_DBGCNTL_MODULE_OFFSET 0xE30 | 26 | #define DSP_DBGCNTL_MODULE_OFFSET 0xE30 |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6f2fa838b635..47ccb8f44adb 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -217,6 +217,7 @@ enum { | |||
217 | CXT_FIXUP_HEADPHONE_MIC_PIN, | 217 | CXT_FIXUP_HEADPHONE_MIC_PIN, |
218 | CXT_FIXUP_HEADPHONE_MIC, | 218 | CXT_FIXUP_HEADPHONE_MIC, |
219 | CXT_FIXUP_GPIO1, | 219 | CXT_FIXUP_GPIO1, |
220 | CXT_FIXUP_ASPIRE_DMIC, | ||
220 | CXT_FIXUP_THINKPAD_ACPI, | 221 | CXT_FIXUP_THINKPAD_ACPI, |
221 | CXT_FIXUP_OLPC_XO, | 222 | CXT_FIXUP_OLPC_XO, |
222 | CXT_FIXUP_CAP_MIX_AMP, | 223 | CXT_FIXUP_CAP_MIX_AMP, |
@@ -664,6 +665,12 @@ static const struct hda_fixup cxt_fixups[] = { | |||
664 | { } | 665 | { } |
665 | }, | 666 | }, |
666 | }, | 667 | }, |
668 | [CXT_FIXUP_ASPIRE_DMIC] = { | ||
669 | .type = HDA_FIXUP_FUNC, | ||
670 | .v.func = cxt_fixup_stereo_dmic, | ||
671 | .chained = true, | ||
672 | .chain_id = CXT_FIXUP_GPIO1, | ||
673 | }, | ||
667 | [CXT_FIXUP_THINKPAD_ACPI] = { | 674 | [CXT_FIXUP_THINKPAD_ACPI] = { |
668 | .type = HDA_FIXUP_FUNC, | 675 | .type = HDA_FIXUP_FUNC, |
669 | .v.func = hda_fixup_thinkpad_acpi, | 676 | .v.func = hda_fixup_thinkpad_acpi, |
@@ -744,7 +751,7 @@ static const struct hda_model_fixup cxt5051_fixup_models[] = { | |||
744 | 751 | ||
745 | static const struct snd_pci_quirk cxt5066_fixups[] = { | 752 | static const struct snd_pci_quirk cxt5066_fixups[] = { |
746 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), | 753 | SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), |
747 | SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1), | 754 | SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC), |
748 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), | 755 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), |
749 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), | 756 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), |
750 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), | 757 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), |
@@ -770,6 +777,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { | |||
770 | { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, | 777 | { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, |
771 | { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, | 778 | { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, |
772 | { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, | 779 | { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, |
780 | { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" }, | ||
773 | { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, | 781 | { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, |
774 | {} | 782 | {} |
775 | }; | 783 | }; |
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 36badba2dcec..99d7d7fecaad 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -50,6 +50,8 @@ MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); | |||
50 | #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec)) | 50 | #define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec)) |
51 | 51 | ||
52 | #define is_valleyview(codec) ((codec)->vendor_id == 0x80862882) | 52 | #define is_valleyview(codec) ((codec)->vendor_id == 0x80862882) |
53 | #define is_cherryview(codec) ((codec)->vendor_id == 0x80862883) | ||
54 | #define is_valleyview_plus(codec) (is_valleyview(codec) || is_cherryview(codec)) | ||
53 | 55 | ||
54 | struct hdmi_spec_per_cvt { | 56 | struct hdmi_spec_per_cvt { |
55 | hda_nid_t cvt_nid; | 57 | hda_nid_t cvt_nid; |
@@ -1459,7 +1461,7 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, | |||
1459 | mux_idx); | 1461 | mux_idx); |
1460 | 1462 | ||
1461 | /* configure unused pins to choose other converters */ | 1463 | /* configure unused pins to choose other converters */ |
1462 | if (is_haswell_plus(codec) || is_valleyview(codec)) | 1464 | if (is_haswell_plus(codec) || is_valleyview_plus(codec)) |
1463 | intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx); | 1465 | intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx); |
1464 | 1466 | ||
1465 | snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); | 1467 | snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); |
@@ -1598,7 +1600,8 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) | |||
1598 | * and this can make HW reset converter selection on a pin. | 1600 | * and this can make HW reset converter selection on a pin. |
1599 | */ | 1601 | */ |
1600 | if (eld->eld_valid && !old_eld_valid && per_pin->setup) { | 1602 | if (eld->eld_valid && !old_eld_valid && per_pin->setup) { |
1601 | if (is_haswell_plus(codec) || is_valleyview(codec)) { | 1603 | if (is_haswell_plus(codec) || |
1604 | is_valleyview_plus(codec)) { | ||
1602 | intel_verify_pin_cvt_connect(codec, per_pin); | 1605 | intel_verify_pin_cvt_connect(codec, per_pin); |
1603 | intel_not_share_assigned_cvt(codec, pin_nid, | 1606 | intel_not_share_assigned_cvt(codec, pin_nid, |
1604 | per_pin->mux_idx); | 1607 | per_pin->mux_idx); |
@@ -1779,7 +1782,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
1779 | bool non_pcm; | 1782 | bool non_pcm; |
1780 | int pinctl; | 1783 | int pinctl; |
1781 | 1784 | ||
1782 | if (is_haswell_plus(codec) || is_valleyview(codec)) { | 1785 | if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { |
1783 | /* Verify pin:cvt selections to avoid silent audio after S3. | 1786 | /* Verify pin:cvt selections to avoid silent audio after S3. |
1784 | * After S3, the audio driver restores pin:cvt selections | 1787 | * After S3, the audio driver restores pin:cvt selections |
1785 | * but this can happen before gfx is ready and such selection | 1788 | * but this can happen before gfx is ready and such selection |
@@ -2330,9 +2333,8 @@ static int patch_generic_hdmi(struct hda_codec *codec) | |||
2330 | intel_haswell_fixup_enable_dp12(codec); | 2333 | intel_haswell_fixup_enable_dp12(codec); |
2331 | } | 2334 | } |
2332 | 2335 | ||
2333 | if (is_haswell(codec) || is_valleyview(codec)) { | 2336 | if (is_haswell_plus(codec) || is_valleyview_plus(codec)) |
2334 | codec->depop_delay = 0; | 2337 | codec->depop_delay = 0; |
2335 | } | ||
2336 | 2338 | ||
2337 | if (hdmi_parse_codec(codec) < 0) { | 2339 | if (hdmi_parse_codec(codec) < 0) { |
2338 | codec->spec = NULL; | 2340 | codec->spec = NULL; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 6b38ec3c6e57..1ba22fb527c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -181,6 +181,8 @@ static void alc_fix_pll(struct hda_codec *codec) | |||
181 | spec->pll_coef_idx); | 181 | spec->pll_coef_idx); |
182 | val = snd_hda_codec_read(codec, spec->pll_nid, 0, | 182 | val = snd_hda_codec_read(codec, spec->pll_nid, 0, |
183 | AC_VERB_GET_PROC_COEF, 0); | 183 | AC_VERB_GET_PROC_COEF, 0); |
184 | if (val == -1) | ||
185 | return; | ||
184 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, | 186 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX, |
185 | spec->pll_coef_idx); | 187 | spec->pll_coef_idx); |
186 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, | 188 | snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF, |
@@ -326,6 +328,7 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) | |||
326 | case 0x10ec0885: | 328 | case 0x10ec0885: |
327 | case 0x10ec0887: | 329 | case 0x10ec0887: |
328 | /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ | 330 | /*case 0x10ec0889:*/ /* this causes an SPDIF problem */ |
331 | case 0x10ec0900: | ||
329 | alc889_coef_init(codec); | 332 | alc889_coef_init(codec); |
330 | break; | 333 | break; |
331 | case 0x10ec0888: | 334 | case 0x10ec0888: |
@@ -2348,6 +2351,7 @@ static int patch_alc882(struct hda_codec *codec) | |||
2348 | switch (codec->vendor_id) { | 2351 | switch (codec->vendor_id) { |
2349 | case 0x10ec0882: | 2352 | case 0x10ec0882: |
2350 | case 0x10ec0885: | 2353 | case 0x10ec0885: |
2354 | case 0x10ec0900: | ||
2351 | break; | 2355 | break; |
2352 | default: | 2356 | default: |
2353 | /* ALC883 and variants */ | 2357 | /* ALC883 and variants */ |
@@ -2806,6 +2810,8 @@ static void alc286_shutup(struct hda_codec *codec) | |||
2806 | static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) | 2810 | static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) |
2807 | { | 2811 | { |
2808 | int val = alc_read_coef_idx(codec, 0x04); | 2812 | int val = alc_read_coef_idx(codec, 0x04); |
2813 | if (val == -1) | ||
2814 | return; | ||
2809 | if (power_up) | 2815 | if (power_up) |
2810 | val |= 1 << 11; | 2816 | val |= 1 << 11; |
2811 | else | 2817 | else |
@@ -3264,6 +3270,15 @@ static int alc269_resume(struct hda_codec *codec) | |||
3264 | snd_hda_codec_resume_cache(codec); | 3270 | snd_hda_codec_resume_cache(codec); |
3265 | alc_inv_dmic_sync(codec, true); | 3271 | alc_inv_dmic_sync(codec, true); |
3266 | hda_call_check_power_status(codec, 0x01); | 3272 | hda_call_check_power_status(codec, 0x01); |
3273 | |||
3274 | /* on some machine, the BIOS will clear the codec gpio data when enter | ||
3275 | * suspend, and won't restore the data after resume, so we restore it | ||
3276 | * in the driver. | ||
3277 | */ | ||
3278 | if (spec->gpio_led) | ||
3279 | snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_SET_GPIO_DATA, | ||
3280 | spec->gpio_led); | ||
3281 | |||
3267 | if (spec->has_alc5505_dsp) | 3282 | if (spec->has_alc5505_dsp) |
3268 | alc5505_dsp_resume(codec); | 3283 | alc5505_dsp_resume(codec); |
3269 | 3284 | ||
@@ -4395,6 +4410,7 @@ enum { | |||
4395 | ALC292_FIXUP_TPT440_DOCK, | 4410 | ALC292_FIXUP_TPT440_DOCK, |
4396 | ALC283_FIXUP_BXBT2807_MIC, | 4411 | ALC283_FIXUP_BXBT2807_MIC, |
4397 | ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, | 4412 | ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED, |
4413 | ALC282_FIXUP_ASPIRE_V5_PINS, | ||
4398 | }; | 4414 | }; |
4399 | 4415 | ||
4400 | static const struct hda_fixup alc269_fixups[] = { | 4416 | static const struct hda_fixup alc269_fixups[] = { |
@@ -4842,6 +4858,22 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4842 | .chained_before = true, | 4858 | .chained_before = true, |
4843 | .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE | 4859 | .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE |
4844 | }, | 4860 | }, |
4861 | [ALC282_FIXUP_ASPIRE_V5_PINS] = { | ||
4862 | .type = HDA_FIXUP_PINS, | ||
4863 | .v.pins = (const struct hda_pintbl[]) { | ||
4864 | { 0x12, 0x90a60130 }, | ||
4865 | { 0x14, 0x90170110 }, | ||
4866 | { 0x17, 0x40000008 }, | ||
4867 | { 0x18, 0x411111f0 }, | ||
4868 | { 0x19, 0x411111f0 }, | ||
4869 | { 0x1a, 0x411111f0 }, | ||
4870 | { 0x1b, 0x411111f0 }, | ||
4871 | { 0x1d, 0x40f89b2d }, | ||
4872 | { 0x1e, 0x411111f0 }, | ||
4873 | { 0x21, 0x0321101f }, | ||
4874 | { }, | ||
4875 | }, | ||
4876 | }, | ||
4845 | 4877 | ||
4846 | }; | 4878 | }; |
4847 | 4879 | ||
@@ -4853,6 +4885,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4853 | SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), | 4885 | SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), |
4854 | SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), | 4886 | SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), |
4855 | SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), | 4887 | SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), |
4888 | SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS), | ||
4856 | SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), | 4889 | SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), |
4857 | SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 4890 | SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
4858 | SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 4891 | SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
@@ -5311,27 +5344,30 @@ static void alc269_fill_coef(struct hda_codec *codec) | |||
5311 | if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { | 5344 | if ((alc_get_coef0(codec) & 0x00ff) == 0x017) { |
5312 | val = alc_read_coef_idx(codec, 0x04); | 5345 | val = alc_read_coef_idx(codec, 0x04); |
5313 | /* Power up output pin */ | 5346 | /* Power up output pin */ |
5314 | alc_write_coef_idx(codec, 0x04, val | (1<<11)); | 5347 | if (val != -1) |
5348 | alc_write_coef_idx(codec, 0x04, val | (1<<11)); | ||
5315 | } | 5349 | } |
5316 | 5350 | ||
5317 | if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { | 5351 | if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { |
5318 | val = alc_read_coef_idx(codec, 0xd); | 5352 | val = alc_read_coef_idx(codec, 0xd); |
5319 | if ((val & 0x0c00) >> 10 != 0x1) { | 5353 | if (val != -1 && (val & 0x0c00) >> 10 != 0x1) { |
5320 | /* Capless ramp up clock control */ | 5354 | /* Capless ramp up clock control */ |
5321 | alc_write_coef_idx(codec, 0xd, val | (1<<10)); | 5355 | alc_write_coef_idx(codec, 0xd, val | (1<<10)); |
5322 | } | 5356 | } |
5323 | val = alc_read_coef_idx(codec, 0x17); | 5357 | val = alc_read_coef_idx(codec, 0x17); |
5324 | if ((val & 0x01c0) >> 6 != 0x4) { | 5358 | if (val != -1 && (val & 0x01c0) >> 6 != 0x4) { |
5325 | /* Class D power on reset */ | 5359 | /* Class D power on reset */ |
5326 | alc_write_coef_idx(codec, 0x17, val | (1<<7)); | 5360 | alc_write_coef_idx(codec, 0x17, val | (1<<7)); |
5327 | } | 5361 | } |
5328 | } | 5362 | } |
5329 | 5363 | ||
5330 | val = alc_read_coef_idx(codec, 0xd); /* Class D */ | 5364 | val = alc_read_coef_idx(codec, 0xd); /* Class D */ |
5331 | alc_write_coef_idx(codec, 0xd, val | (1<<14)); | 5365 | if (val != -1) |
5366 | alc_write_coef_idx(codec, 0xd, val | (1<<14)); | ||
5332 | 5367 | ||
5333 | val = alc_read_coef_idx(codec, 0x4); /* HP */ | 5368 | val = alc_read_coef_idx(codec, 0x4); /* HP */ |
5334 | alc_write_coef_idx(codec, 0x4, val | (1<<11)); | 5369 | if (val != -1) |
5370 | alc_write_coef_idx(codec, 0x4, val | (1<<11)); | ||
5335 | } | 5371 | } |
5336 | 5372 | ||
5337 | /* | 5373 | /* |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index ea823e1100da..98cd1908c039 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -566,8 +566,8 @@ static void stac_init_power_map(struct hda_codec *codec) | |||
566 | if (snd_hda_jack_tbl_get(codec, nid)) | 566 | if (snd_hda_jack_tbl_get(codec, nid)) |
567 | continue; | 567 | continue; |
568 | if (def_conf == AC_JACK_PORT_COMPLEX && | 568 | if (def_conf == AC_JACK_PORT_COMPLEX && |
569 | !(spec->vref_mute_led_nid == nid || | 569 | spec->vref_mute_led_nid != nid && |
570 | is_jack_detectable(codec, nid))) { | 570 | is_jack_detectable(codec, nid)) { |
571 | snd_hda_jack_detect_enable_callback(codec, nid, | 571 | snd_hda_jack_detect_enable_callback(codec, nid, |
572 | STAC_PWR_EVENT, | 572 | STAC_PWR_EVENT, |
573 | jack_update_power); | 573 | jack_update_power); |
@@ -4276,11 +4276,18 @@ static int stac_parse_auto_config(struct hda_codec *codec) | |||
4276 | return err; | 4276 | return err; |
4277 | } | 4277 | } |
4278 | 4278 | ||
4279 | stac_init_power_map(codec); | ||
4280 | |||
4281 | return 0; | 4279 | return 0; |
4282 | } | 4280 | } |
4283 | 4281 | ||
4282 | static int stac_build_controls(struct hda_codec *codec) | ||
4283 | { | ||
4284 | int err = snd_hda_gen_build_controls(codec); | ||
4285 | |||
4286 | if (err < 0) | ||
4287 | return err; | ||
4288 | stac_init_power_map(codec); | ||
4289 | return 0; | ||
4290 | } | ||
4284 | 4291 | ||
4285 | static int stac_init(struct hda_codec *codec) | 4292 | static int stac_init(struct hda_codec *codec) |
4286 | { | 4293 | { |
@@ -4392,7 +4399,7 @@ static int stac_suspend(struct hda_codec *codec) | |||
4392 | #endif /* CONFIG_PM */ | 4399 | #endif /* CONFIG_PM */ |
4393 | 4400 | ||
4394 | static const struct hda_codec_ops stac_patch_ops = { | 4401 | static const struct hda_codec_ops stac_patch_ops = { |
4395 | .build_controls = snd_hda_gen_build_controls, | 4402 | .build_controls = stac_build_controls, |
4396 | .build_pcms = snd_hda_gen_build_pcms, | 4403 | .build_pcms = snd_hda_gen_build_pcms, |
4397 | .init = stac_init, | 4404 | .init = stac_init, |
4398 | .free = stac_free, | 4405 | .free = stac_free, |
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 922006dd0583..4c3b0af39fd8 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c | |||
@@ -1337,8 +1337,6 @@ static int pm860x_probe(struct snd_soc_codec *codec) | |||
1337 | } | 1337 | } |
1338 | } | 1338 | } |
1339 | 1339 | ||
1340 | pm860x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1341 | |||
1342 | return 0; | 1340 | return 0; |
1343 | 1341 | ||
1344 | out: | 1342 | out: |
@@ -1354,7 +1352,6 @@ static int pm860x_remove(struct snd_soc_codec *codec) | |||
1354 | 1352 | ||
1355 | for (i = 3; i >= 0; i--) | 1353 | for (i = 3; i >= 0; i--) |
1356 | free_irq(pm860x->irq[i], pm860x); | 1354 | free_irq(pm860x->irq[i], pm860x); |
1357 | pm860x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1358 | return 0; | 1355 | return 0; |
1359 | } | 1356 | } |
1360 | 1357 | ||
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 8838838e25ed..5b47c550bb89 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -43,6 +43,7 @@ config SND_SOC_ALL_CODECS | |||
43 | select SND_SOC_ALC5623 if I2C | 43 | select SND_SOC_ALC5623 if I2C |
44 | select SND_SOC_ALC5632 if I2C | 44 | select SND_SOC_ALC5632 if I2C |
45 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC | 45 | select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC |
46 | select SND_SOC_CS35L32 if I2C | ||
46 | select SND_SOC_CS42L51_I2C if I2C | 47 | select SND_SOC_CS42L51_I2C if I2C |
47 | select SND_SOC_CS42L52 if I2C && INPUT | 48 | select SND_SOC_CS42L52 if I2C && INPUT |
48 | select SND_SOC_CS42L56 if I2C && INPUT | 49 | select SND_SOC_CS42L56 if I2C && INPUT |
@@ -56,7 +57,10 @@ config SND_SOC_ALL_CODECS | |||
56 | select SND_SOC_DA7213 if I2C | 57 | select SND_SOC_DA7213 if I2C |
57 | select SND_SOC_DA732X if I2C | 58 | select SND_SOC_DA732X if I2C |
58 | select SND_SOC_DA9055 if I2C | 59 | select SND_SOC_DA9055 if I2C |
60 | select SND_SOC_DMIC | ||
59 | select SND_SOC_BT_SCO | 61 | select SND_SOC_BT_SCO |
62 | select SND_SOC_ES8328_SPI if SPI_MASTER | ||
63 | select SND_SOC_ES8328_I2C if I2C | ||
60 | select SND_SOC_ISABELLE if I2C | 64 | select SND_SOC_ISABELLE if I2C |
61 | select SND_SOC_JZ4740_CODEC | 65 | select SND_SOC_JZ4740_CODEC |
62 | select SND_SOC_LM4857 if I2C | 66 | select SND_SOC_LM4857 if I2C |
@@ -90,6 +94,7 @@ config SND_SOC_ALL_CODECS | |||
90 | select SND_SOC_SSM2518 if I2C | 94 | select SND_SOC_SSM2518 if I2C |
91 | select SND_SOC_SSM2602_SPI if SPI_MASTER | 95 | select SND_SOC_SSM2602_SPI if SPI_MASTER |
92 | select SND_SOC_SSM2602_I2C if I2C | 96 | select SND_SOC_SSM2602_I2C if I2C |
97 | select SND_SOC_SSM4567 if I2C | ||
93 | select SND_SOC_STA32X if I2C | 98 | select SND_SOC_STA32X if I2C |
94 | select SND_SOC_STA350 if I2C | 99 | select SND_SOC_STA350 if I2C |
95 | select SND_SOC_STA529 if I2C | 100 | select SND_SOC_STA529 if I2C |
@@ -323,6 +328,10 @@ config SND_SOC_ALC5632 | |||
323 | config SND_SOC_CQ0093VC | 328 | config SND_SOC_CQ0093VC |
324 | tristate | 329 | tristate |
325 | 330 | ||
331 | config SND_SOC_CS35L32 | ||
332 | tristate "Cirrus Logic CS35L32 CODEC" | ||
333 | depends on I2C | ||
334 | |||
326 | config SND_SOC_CS42L51 | 335 | config SND_SOC_CS42L51 |
327 | tristate | 336 | tristate |
328 | 337 | ||
@@ -405,6 +414,17 @@ config SND_SOC_DMIC | |||
405 | config SND_SOC_HDMI_CODEC | 414 | config SND_SOC_HDMI_CODEC |
406 | tristate "HDMI stub CODEC" | 415 | tristate "HDMI stub CODEC" |
407 | 416 | ||
417 | config SND_SOC_ES8328 | ||
418 | tristate "Everest Semi ES8328 CODEC" | ||
419 | |||
420 | config SND_SOC_ES8328_I2C | ||
421 | tristate | ||
422 | select SND_SOC_ES8328 | ||
423 | |||
424 | config SND_SOC_ES8328_SPI | ||
425 | tristate | ||
426 | select SND_SOC_ES8328 | ||
427 | |||
408 | config SND_SOC_ISABELLE | 428 | config SND_SOC_ISABELLE |
409 | tristate | 429 | tristate |
410 | 430 | ||
@@ -464,6 +484,7 @@ config SND_SOC_RL6231 | |||
464 | 484 | ||
465 | config SND_SOC_RT286 | 485 | config SND_SOC_RT286 |
466 | tristate | 486 | tristate |
487 | depends on I2C | ||
467 | 488 | ||
468 | config SND_SOC_RT5631 | 489 | config SND_SOC_RT5631 |
469 | tristate | 490 | tristate |
@@ -520,12 +541,20 @@ config SND_SOC_SSM2602 | |||
520 | tristate | 541 | tristate |
521 | 542 | ||
522 | config SND_SOC_SSM2602_SPI | 543 | config SND_SOC_SSM2602_SPI |
544 | tristate "Analog Devices SSM2602 CODEC - SPI" | ||
545 | depends on SPI_MASTER | ||
523 | select SND_SOC_SSM2602 | 546 | select SND_SOC_SSM2602 |
524 | tristate | 547 | select REGMAP_SPI |
525 | 548 | ||
526 | config SND_SOC_SSM2602_I2C | 549 | config SND_SOC_SSM2602_I2C |
550 | tristate "Analog Devices SSM2602 CODEC - I2C" | ||
551 | depends on I2C | ||
527 | select SND_SOC_SSM2602 | 552 | select SND_SOC_SSM2602 |
528 | tristate | 553 | select REGMAP_I2C |
554 | |||
555 | config SND_SOC_SSM4567 | ||
556 | tristate "Analog Devices ssm4567 amplifier driver support" | ||
557 | depends on I2C | ||
529 | 558 | ||
530 | config SND_SOC_STA32X | 559 | config SND_SOC_STA32X |
531 | tristate | 560 | tristate |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 20afe0f0c5be..5dce451661e4 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -32,6 +32,7 @@ snd-soc-ak4671-objs := ak4671.o | |||
32 | snd-soc-ak5386-objs := ak5386.o | 32 | snd-soc-ak5386-objs := ak5386.o |
33 | snd-soc-arizona-objs := arizona.o | 33 | snd-soc-arizona-objs := arizona.o |
34 | snd-soc-cq93vc-objs := cq93vc.o | 34 | snd-soc-cq93vc-objs := cq93vc.o |
35 | snd-soc-cs35l32-objs := cs35l32.o | ||
35 | snd-soc-cs42l51-objs := cs42l51.o | 36 | snd-soc-cs42l51-objs := cs42l51.o |
36 | snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o | 37 | snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o |
37 | snd-soc-cs42l52-objs := cs42l52.o | 38 | snd-soc-cs42l52-objs := cs42l52.o |
@@ -49,6 +50,9 @@ snd-soc-da732x-objs := da732x.o | |||
49 | snd-soc-da9055-objs := da9055.o | 50 | snd-soc-da9055-objs := da9055.o |
50 | snd-soc-bt-sco-objs := bt-sco.o | 51 | snd-soc-bt-sco-objs := bt-sco.o |
51 | snd-soc-dmic-objs := dmic.o | 52 | snd-soc-dmic-objs := dmic.o |
53 | snd-soc-es8328-objs := es8328.o | ||
54 | snd-soc-es8328-i2c-objs := es8328-i2c.o | ||
55 | snd-soc-es8328-spi-objs := es8328-spi.o | ||
52 | snd-soc-isabelle-objs := isabelle.o | 56 | snd-soc-isabelle-objs := isabelle.o |
53 | snd-soc-jz4740-codec-objs := jz4740.o | 57 | snd-soc-jz4740-codec-objs := jz4740.o |
54 | snd-soc-l3-objs := l3.o | 58 | snd-soc-l3-objs := l3.o |
@@ -91,6 +95,7 @@ snd-soc-ssm2518-objs := ssm2518.o | |||
91 | snd-soc-ssm2602-objs := ssm2602.o | 95 | snd-soc-ssm2602-objs := ssm2602.o |
92 | snd-soc-ssm2602-spi-objs := ssm2602-spi.o | 96 | snd-soc-ssm2602-spi-objs := ssm2602-spi.o |
93 | snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o | 97 | snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o |
98 | snd-soc-ssm4567-objs := ssm4567.o | ||
94 | snd-soc-sta32x-objs := sta32x.o | 99 | snd-soc-sta32x-objs := sta32x.o |
95 | snd-soc-sta350-objs := sta350.o | 100 | snd-soc-sta350-objs := sta350.o |
96 | snd-soc-sta529-objs := sta529.o | 101 | snd-soc-sta529-objs := sta529.o |
@@ -203,6 +208,7 @@ obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o | |||
203 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o | 208 | obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o |
204 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o | 209 | obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o |
205 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o | 210 | obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o |
211 | obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o | ||
206 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o | 212 | obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o |
207 | obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o | 213 | obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o |
208 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o | 214 | obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o |
@@ -220,6 +226,9 @@ obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o | |||
220 | obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o | 226 | obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o |
221 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o | 227 | obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o |
222 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o | 228 | obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o |
229 | obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o | ||
230 | obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o | ||
231 | obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o | ||
223 | obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o | 232 | obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o |
224 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | 233 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o |
225 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 234 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
@@ -258,6 +267,7 @@ obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o | |||
258 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o | 267 | obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o |
259 | obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o | 268 | obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o |
260 | obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o | 269 | obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o |
270 | obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o | ||
261 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o | 271 | obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o |
262 | obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o | 272 | obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o |
263 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | 273 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o |
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c index 1fb4402bf72d..fd43827bb856 100644 --- a/sound/soc/codecs/ab8500-codec.c +++ b/sound/soc/codecs/ab8500-codec.c | |||
@@ -56,8 +56,7 @@ | |||
56 | #define GPIO31_DIR_OUTPUT 0x40 | 56 | #define GPIO31_DIR_OUTPUT 0x40 |
57 | 57 | ||
58 | /* Macrocell register definitions */ | 58 | /* Macrocell register definitions */ |
59 | #define AB8500_CTRL3_REG 0x0200 | 59 | #define AB8500_GPIO_DIR4_REG 0x13 /* Bank AB8500_MISC */ |
60 | #define AB8500_GPIO_DIR4_REG 0x1013 | ||
61 | 60 | ||
62 | /* Nr of FIR/IIR-coeff banks in ANC-block */ | 61 | /* Nr of FIR/IIR-coeff banks in ANC-block */ |
63 | #define AB8500_NR_OF_ANC_COEFF_BANKS 2 | 62 | #define AB8500_NR_OF_ANC_COEFF_BANKS 2 |
@@ -126,6 +125,8 @@ struct ab8500_codec_drvdata_dbg { | |||
126 | 125 | ||
127 | /* Private data for AB8500 device-driver */ | 126 | /* Private data for AB8500 device-driver */ |
128 | struct ab8500_codec_drvdata { | 127 | struct ab8500_codec_drvdata { |
128 | struct regmap *regmap; | ||
129 | |||
129 | /* Sidetone */ | 130 | /* Sidetone */ |
130 | long *sid_fir_values; | 131 | long *sid_fir_values; |
131 | enum sid_state sid_status; | 132 | enum sid_state sid_status; |
@@ -166,49 +167,35 @@ static inline const char *amic_type_str(enum amic_type type) | |||
166 | */ | 167 | */ |
167 | 168 | ||
168 | /* Read a register from the audio-bank of AB8500 */ | 169 | /* Read a register from the audio-bank of AB8500 */ |
169 | static unsigned int ab8500_codec_read_reg(struct snd_soc_codec *codec, | 170 | static int ab8500_codec_read_reg(void *context, unsigned int reg, |
170 | unsigned int reg) | 171 | unsigned int *value) |
171 | { | 172 | { |
173 | struct device *dev = context; | ||
172 | int status; | 174 | int status; |
173 | unsigned int value = 0; | ||
174 | 175 | ||
175 | u8 value8; | 176 | u8 value8; |
176 | status = abx500_get_register_interruptible(codec->dev, AB8500_AUDIO, | 177 | status = abx500_get_register_interruptible(dev, AB8500_AUDIO, |
177 | reg, &value8); | 178 | reg, &value8); |
178 | if (status < 0) { | 179 | *value = (unsigned int)value8; |
179 | dev_err(codec->dev, | ||
180 | "%s: ERROR: Register (0x%02x:0x%02x) read failed (%d).\n", | ||
181 | __func__, (u8)AB8500_AUDIO, (u8)reg, status); | ||
182 | } else { | ||
183 | dev_dbg(codec->dev, | ||
184 | "%s: Read 0x%02x from register 0x%02x:0x%02x\n", | ||
185 | __func__, value8, (u8)AB8500_AUDIO, (u8)reg); | ||
186 | value = (unsigned int)value8; | ||
187 | } | ||
188 | 180 | ||
189 | return value; | 181 | return status; |
190 | } | 182 | } |
191 | 183 | ||
192 | /* Write to a register in the audio-bank of AB8500 */ | 184 | /* Write to a register in the audio-bank of AB8500 */ |
193 | static int ab8500_codec_write_reg(struct snd_soc_codec *codec, | 185 | static int ab8500_codec_write_reg(void *context, unsigned int reg, |
194 | unsigned int reg, unsigned int value) | 186 | unsigned int value) |
195 | { | 187 | { |
196 | int status; | 188 | struct device *dev = context; |
197 | |||
198 | status = abx500_set_register_interruptible(codec->dev, AB8500_AUDIO, | ||
199 | reg, value); | ||
200 | if (status < 0) | ||
201 | dev_err(codec->dev, | ||
202 | "%s: ERROR: Register (%02x:%02x) write failed (%d).\n", | ||
203 | __func__, (u8)AB8500_AUDIO, (u8)reg, status); | ||
204 | else | ||
205 | dev_dbg(codec->dev, | ||
206 | "%s: Wrote 0x%02x into register %02x:%02x\n", | ||
207 | __func__, (u8)value, (u8)AB8500_AUDIO, (u8)reg); | ||
208 | 189 | ||
209 | return status; | 190 | return abx500_set_register_interruptible(dev, AB8500_AUDIO, |
191 | reg, value); | ||
210 | } | 192 | } |
211 | 193 | ||
194 | static const struct regmap_config ab8500_codec_regmap = { | ||
195 | .reg_read = ab8500_codec_read_reg, | ||
196 | .reg_write = ab8500_codec_write_reg, | ||
197 | }; | ||
198 | |||
212 | /* | 199 | /* |
213 | * Controls - DAPM | 200 | * Controls - DAPM |
214 | */ | 201 | */ |
@@ -1968,16 +1955,16 @@ static int ab8500_audio_setup_mics(struct snd_soc_codec *codec, | |||
1968 | dev_dbg(codec->dev, "%s: Enter.\n", __func__); | 1955 | dev_dbg(codec->dev, "%s: Enter.\n", __func__); |
1969 | 1956 | ||
1970 | /* Set DMic-clocks to outputs */ | 1957 | /* Set DMic-clocks to outputs */ |
1971 | status = abx500_get_register_interruptible(codec->dev, (u8)AB8500_MISC, | 1958 | status = abx500_get_register_interruptible(codec->dev, AB8500_MISC, |
1972 | (u8)AB8500_GPIO_DIR4_REG, | 1959 | AB8500_GPIO_DIR4_REG, |
1973 | &value8); | 1960 | &value8); |
1974 | if (status < 0) | 1961 | if (status < 0) |
1975 | return status; | 1962 | return status; |
1976 | value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | | 1963 | value = value8 | GPIO27_DIR_OUTPUT | GPIO29_DIR_OUTPUT | |
1977 | GPIO31_DIR_OUTPUT; | 1964 | GPIO31_DIR_OUTPUT; |
1978 | status = abx500_set_register_interruptible(codec->dev, | 1965 | status = abx500_set_register_interruptible(codec->dev, |
1979 | (u8)AB8500_MISC, | 1966 | AB8500_MISC, |
1980 | (u8)AB8500_GPIO_DIR4_REG, | 1967 | AB8500_GPIO_DIR4_REG, |
1981 | value); | 1968 | value); |
1982 | if (status < 0) | 1969 | if (status < 0) |
1983 | return status; | 1970 | return status; |
@@ -2565,9 +2552,6 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec) | |||
2565 | 2552 | ||
2566 | static struct snd_soc_codec_driver ab8500_codec_driver = { | 2553 | static struct snd_soc_codec_driver ab8500_codec_driver = { |
2567 | .probe = ab8500_codec_probe, | 2554 | .probe = ab8500_codec_probe, |
2568 | .read = ab8500_codec_read_reg, | ||
2569 | .write = ab8500_codec_write_reg, | ||
2570 | .reg_word_size = sizeof(u8), | ||
2571 | .controls = ab8500_ctrls, | 2555 | .controls = ab8500_ctrls, |
2572 | .num_controls = ARRAY_SIZE(ab8500_ctrls), | 2556 | .num_controls = ARRAY_SIZE(ab8500_ctrls), |
2573 | .dapm_widgets = ab8500_dapm_widgets, | 2557 | .dapm_widgets = ab8500_dapm_widgets, |
@@ -2592,6 +2576,15 @@ static int ab8500_codec_driver_probe(struct platform_device *pdev) | |||
2592 | drvdata->anc_status = ANC_UNCONFIGURED; | 2576 | drvdata->anc_status = ANC_UNCONFIGURED; |
2593 | dev_set_drvdata(&pdev->dev, drvdata); | 2577 | dev_set_drvdata(&pdev->dev, drvdata); |
2594 | 2578 | ||
2579 | drvdata->regmap = devm_regmap_init(&pdev->dev, NULL, &pdev->dev, | ||
2580 | &ab8500_codec_regmap); | ||
2581 | if (IS_ERR(drvdata->regmap)) { | ||
2582 | status = PTR_ERR(drvdata->regmap); | ||
2583 | dev_err(&pdev->dev, "%s: Failed to allocate regmap: %d\n", | ||
2584 | __func__, status); | ||
2585 | return status; | ||
2586 | } | ||
2587 | |||
2595 | dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); | 2588 | dev_dbg(&pdev->dev, "%s: Register codec.\n", __func__); |
2596 | status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, | 2589 | status = snd_soc_register_codec(&pdev->dev, &ab8500_codec_driver, |
2597 | ab8500_codec_dai, | 2590 | ab8500_codec_dai, |
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c index e889e1b84192..bd9b1839c8b0 100644 --- a/sound/soc/codecs/ac97.c +++ b/sound/soc/codecs/ac97.c | |||
@@ -69,19 +69,6 @@ static struct snd_soc_dai_driver ac97_dai = { | |||
69 | .ops = &ac97_dai_ops, | 69 | .ops = &ac97_dai_ops, |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static unsigned int ac97_read(struct snd_soc_codec *codec, | ||
73 | unsigned int reg) | ||
74 | { | ||
75 | return soc_ac97_ops->read(codec->ac97, reg); | ||
76 | } | ||
77 | |||
78 | static int ac97_write(struct snd_soc_codec *codec, unsigned int reg, | ||
79 | unsigned int val) | ||
80 | { | ||
81 | soc_ac97_ops->write(codec->ac97, reg, val); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int ac97_soc_probe(struct snd_soc_codec *codec) | 72 | static int ac97_soc_probe(struct snd_soc_codec *codec) |
86 | { | 73 | { |
87 | struct snd_ac97_bus *ac97_bus; | 74 | struct snd_ac97_bus *ac97_bus; |
@@ -122,8 +109,6 @@ static int ac97_soc_resume(struct snd_soc_codec *codec) | |||
122 | #endif | 109 | #endif |
123 | 110 | ||
124 | static struct snd_soc_codec_driver soc_codec_dev_ac97 = { | 111 | static struct snd_soc_codec_driver soc_codec_dev_ac97 = { |
125 | .write = ac97_write, | ||
126 | .read = ac97_read, | ||
127 | .probe = ac97_soc_probe, | 112 | .probe = ac97_soc_probe, |
128 | .suspend = ac97_soc_suspend, | 113 | .suspend = ac97_soc_suspend, |
129 | .resume = ac97_soc_resume, | 114 | .resume = ac97_soc_resume, |
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index 1ff7d4d027e9..7c784ad3e8b2 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -1448,29 +1448,10 @@ static int adau1373_set_bias_level(struct snd_soc_codec *codec, | |||
1448 | return 0; | 1448 | return 0; |
1449 | } | 1449 | } |
1450 | 1450 | ||
1451 | static int adau1373_remove(struct snd_soc_codec *codec) | ||
1452 | { | ||
1453 | adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1454 | return 0; | ||
1455 | } | ||
1456 | |||
1457 | static int adau1373_suspend(struct snd_soc_codec *codec) | ||
1458 | { | ||
1459 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | ||
1460 | int ret; | ||
1461 | |||
1462 | ret = adau1373_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1463 | regcache_cache_only(adau1373->regmap, true); | ||
1464 | |||
1465 | return ret; | ||
1466 | } | ||
1467 | |||
1468 | static int adau1373_resume(struct snd_soc_codec *codec) | 1451 | static int adau1373_resume(struct snd_soc_codec *codec) |
1469 | { | 1452 | { |
1470 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); | 1453 | struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec); |
1471 | 1454 | ||
1472 | regcache_cache_only(adau1373->regmap, false); | ||
1473 | adau1373_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1474 | regcache_sync(adau1373->regmap); | 1455 | regcache_sync(adau1373->regmap); |
1475 | 1456 | ||
1476 | return 0; | 1457 | return 0; |
@@ -1501,8 +1482,6 @@ static const struct regmap_config adau1373_regmap_config = { | |||
1501 | 1482 | ||
1502 | static struct snd_soc_codec_driver adau1373_codec_driver = { | 1483 | static struct snd_soc_codec_driver adau1373_codec_driver = { |
1503 | .probe = adau1373_probe, | 1484 | .probe = adau1373_probe, |
1504 | .remove = adau1373_remove, | ||
1505 | .suspend = adau1373_suspend, | ||
1506 | .resume = adau1373_resume, | 1485 | .resume = adau1373_resume, |
1507 | .set_bias_level = adau1373_set_bias_level, | 1486 | .set_bias_level = adau1373_set_bias_level, |
1508 | .idle_bias_off = true, | 1487 | .idle_bias_off = true, |
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c index 848cab839553..5518ebd6947c 100644 --- a/sound/soc/codecs/adau1761.c +++ b/sound/soc/codecs/adau1761.c | |||
@@ -714,9 +714,9 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec) | |||
714 | 714 | ||
715 | static const struct snd_soc_codec_driver adau1761_codec_driver = { | 715 | static const struct snd_soc_codec_driver adau1761_codec_driver = { |
716 | .probe = adau1761_codec_probe, | 716 | .probe = adau1761_codec_probe, |
717 | .suspend = adau17x1_suspend, | ||
718 | .resume = adau17x1_resume, | 717 | .resume = adau17x1_resume, |
719 | .set_bias_level = adau1761_set_bias_level, | 718 | .set_bias_level = adau1761_set_bias_level, |
719 | .suspend_bias_off = true, | ||
720 | 720 | ||
721 | .controls = adau1761_controls, | 721 | .controls = adau1761_controls, |
722 | .num_controls = ARRAY_SIZE(adau1761_controls), | 722 | .num_controls = ARRAY_SIZE(adau1761_controls), |
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c index 045a61413840..e9fc00fb13dd 100644 --- a/sound/soc/codecs/adau1781.c +++ b/sound/soc/codecs/adau1781.c | |||
@@ -446,9 +446,9 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec) | |||
446 | 446 | ||
447 | static const struct snd_soc_codec_driver adau1781_codec_driver = { | 447 | static const struct snd_soc_codec_driver adau1781_codec_driver = { |
448 | .probe = adau1781_codec_probe, | 448 | .probe = adau1781_codec_probe, |
449 | .suspend = adau17x1_suspend, | ||
450 | .resume = adau17x1_resume, | 449 | .resume = adau17x1_resume, |
451 | .set_bias_level = adau1781_set_bias_level, | 450 | .set_bias_level = adau1781_set_bias_level, |
451 | .suspend_bias_off = true, | ||
452 | 452 | ||
453 | .controls = adau1781_controls, | 453 | .controls = adau1781_controls, |
454 | .num_controls = ARRAY_SIZE(adau1781_controls), | 454 | .num_controls = ARRAY_SIZE(adau1781_controls), |
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 0b659704e60c..3e16c1c64115 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c | |||
@@ -815,13 +815,6 @@ int adau17x1_add_routes(struct snd_soc_codec *codec) | |||
815 | } | 815 | } |
816 | EXPORT_SYMBOL_GPL(adau17x1_add_routes); | 816 | EXPORT_SYMBOL_GPL(adau17x1_add_routes); |
817 | 817 | ||
818 | int adau17x1_suspend(struct snd_soc_codec *codec) | ||
819 | { | ||
820 | codec->driver->set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
821 | return 0; | ||
822 | } | ||
823 | EXPORT_SYMBOL_GPL(adau17x1_suspend); | ||
824 | |||
825 | int adau17x1_resume(struct snd_soc_codec *codec) | 818 | int adau17x1_resume(struct snd_soc_codec *codec) |
826 | { | 819 | { |
827 | struct adau *adau = snd_soc_codec_get_drvdata(codec); | 820 | struct adau *adau = snd_soc_codec_get_drvdata(codec); |
@@ -829,7 +822,6 @@ int adau17x1_resume(struct snd_soc_codec *codec) | |||
829 | if (adau->switch_mode) | 822 | if (adau->switch_mode) |
830 | adau->switch_mode(codec->dev); | 823 | adau->switch_mode(codec->dev); |
831 | 824 | ||
832 | codec->driver->set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
833 | regcache_sync(adau->regmap); | 825 | regcache_sync(adau->regmap); |
834 | 826 | ||
835 | return 0; | 827 | return 0; |
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h index 3ffabaf4c7a8..e4a557fd7155 100644 --- a/sound/soc/codecs/adau17x1.h +++ b/sound/soc/codecs/adau17x1.h | |||
@@ -52,7 +52,6 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec, | |||
52 | enum adau17x1_micbias_voltage micbias); | 52 | enum adau17x1_micbias_voltage micbias); |
53 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); | 53 | bool adau17x1_readable_register(struct device *dev, unsigned int reg); |
54 | bool adau17x1_volatile_register(struct device *dev, unsigned int reg); | 54 | bool adau17x1_volatile_register(struct device *dev, unsigned int reg); |
55 | int adau17x1_suspend(struct snd_soc_codec *codec); | ||
56 | int adau17x1_resume(struct snd_soc_codec *codec); | 55 | int adau17x1_resume(struct snd_soc_codec *codec); |
57 | 56 | ||
58 | extern const struct snd_soc_dai_ops adau17x1_dai_ops; | 57 | extern const struct snd_soc_dai_ops adau17x1_dai_ops; |
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index c43b93fdf0df..ce3cdca9fc62 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
@@ -812,42 +812,23 @@ static int adav80x_probe(struct snd_soc_codec *codec) | |||
812 | /* Disable DAC zero flag */ | 812 | /* Disable DAC zero flag */ |
813 | regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); | 813 | regmap_write(adav80x->regmap, ADAV80X_DAC_CTRL3, 0x6); |
814 | 814 | ||
815 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 815 | return 0; |
816 | } | ||
817 | |||
818 | static int adav80x_suspend(struct snd_soc_codec *codec) | ||
819 | { | ||
820 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | ||
821 | int ret; | ||
822 | |||
823 | ret = adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
824 | regcache_cache_only(adav80x->regmap, true); | ||
825 | |||
826 | return ret; | ||
827 | } | 816 | } |
828 | 817 | ||
829 | static int adav80x_resume(struct snd_soc_codec *codec) | 818 | static int adav80x_resume(struct snd_soc_codec *codec) |
830 | { | 819 | { |
831 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 820 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
832 | 821 | ||
833 | regcache_cache_only(adav80x->regmap, false); | ||
834 | adav80x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
835 | regcache_sync(adav80x->regmap); | 822 | regcache_sync(adav80x->regmap); |
836 | 823 | ||
837 | return 0; | 824 | return 0; |
838 | } | 825 | } |
839 | 826 | ||
840 | static int adav80x_remove(struct snd_soc_codec *codec) | ||
841 | { | ||
842 | return adav80x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
843 | } | ||
844 | |||
845 | static struct snd_soc_codec_driver adav80x_codec_driver = { | 827 | static struct snd_soc_codec_driver adav80x_codec_driver = { |
846 | .probe = adav80x_probe, | 828 | .probe = adav80x_probe, |
847 | .remove = adav80x_remove, | ||
848 | .suspend = adav80x_suspend, | ||
849 | .resume = adav80x_resume, | 829 | .resume = adav80x_resume, |
850 | .set_bias_level = adav80x_set_bias_level, | 830 | .set_bias_level = adav80x_set_bias_level, |
831 | .suspend_bias_off = true, | ||
851 | 832 | ||
852 | .set_pll = adav80x_set_pll, | 833 | .set_pll = adav80x_set_pll, |
853 | .set_sysclk = adav80x_set_sysclk, | 834 | .set_sysclk = adav80x_set_sysclk, |
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index bd41ee4da078..2c71f16bd661 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -1278,6 +1278,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1278 | else | 1278 | else |
1279 | rates = &arizona_48k_bclk_rates[0]; | 1279 | rates = &arizona_48k_bclk_rates[0]; |
1280 | 1280 | ||
1281 | wl = snd_pcm_format_width(params_format(params)); | ||
1282 | |||
1281 | if (tdm_slots) { | 1283 | if (tdm_slots) { |
1282 | arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", | 1284 | arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", |
1283 | tdm_slots, tdm_width); | 1285 | tdm_slots, tdm_width); |
@@ -1285,6 +1287,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1285 | channels = tdm_slots; | 1287 | channels = tdm_slots; |
1286 | } else { | 1288 | } else { |
1287 | bclk_target = snd_soc_params_to_bclk(params); | 1289 | bclk_target = snd_soc_params_to_bclk(params); |
1290 | tdm_width = wl; | ||
1288 | } | 1291 | } |
1289 | 1292 | ||
1290 | if (chan_limit && chan_limit < channels) { | 1293 | if (chan_limit && chan_limit < channels) { |
@@ -1319,8 +1322,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, | |||
1319 | arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", | 1322 | arizona_aif_dbg(dai, "BCLK %dHz LRCLK %dHz\n", |
1320 | rates[bclk], rates[bclk] / lrclk); | 1323 | rates[bclk], rates[bclk] / lrclk); |
1321 | 1324 | ||
1322 | wl = snd_pcm_format_width(params_format(params)); | 1325 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | tdm_width; |
1323 | frame = wl << ARIZONA_AIF1TX_WL_SHIFT | wl; | ||
1324 | 1326 | ||
1325 | reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame); | 1327 | reconfig = arizona_aif_cfg_changed(codec, base, bclk, lrclk, frame); |
1326 | 1328 | ||
diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c new file mode 100644 index 000000000000..c125925da92e --- /dev/null +++ b/sound/soc/codecs/cs35l32.c | |||
@@ -0,0 +1,631 @@ | |||
1 | /* | ||
2 | * cs35l32.c -- CS35L32 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2014 CirrusLogic, Inc. | ||
5 | * | ||
6 | * Author: Brian Austin <brian.austin@cirrus.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/moduleparam.h> | ||
16 | #include <linux/version.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/i2c.h> | ||
21 | #include <linux/gpio.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/platform_device.h> | ||
25 | #include <linux/regulator/consumer.h> | ||
26 | #include <linux/gpio/consumer.h> | ||
27 | #include <linux/of_device.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/pcm.h> | ||
30 | #include <sound/pcm_params.h> | ||
31 | #include <sound/soc.h> | ||
32 | #include <sound/soc-dapm.h> | ||
33 | #include <sound/initval.h> | ||
34 | #include <sound/tlv.h> | ||
35 | #include <dt-bindings/sound/cs35l32.h> | ||
36 | |||
37 | #include "cs35l32.h" | ||
38 | |||
39 | #define CS35L32_NUM_SUPPLIES 2 | ||
40 | static const char *const cs35l32_supply_names[CS35L32_NUM_SUPPLIES] = { | ||
41 | "VA", | ||
42 | "VP", | ||
43 | }; | ||
44 | |||
45 | struct cs35l32_private { | ||
46 | struct regmap *regmap; | ||
47 | struct snd_soc_codec *codec; | ||
48 | struct regulator_bulk_data supplies[CS35L32_NUM_SUPPLIES]; | ||
49 | struct cs35l32_platform_data pdata; | ||
50 | struct gpio_desc *reset_gpio; | ||
51 | }; | ||
52 | |||
53 | static const struct reg_default cs35l32_reg_defaults[] = { | ||
54 | |||
55 | { 0x06, 0x04 }, /* Power Ctl 1 */ | ||
56 | { 0x07, 0xE8 }, /* Power Ctl 2 */ | ||
57 | { 0x08, 0x40 }, /* Clock Ctl */ | ||
58 | { 0x09, 0x20 }, /* Low Battery Threshold */ | ||
59 | { 0x0A, 0x00 }, /* Voltage Monitor [RO] */ | ||
60 | { 0x0B, 0x40 }, /* Conv Peak Curr Protection CTL */ | ||
61 | { 0x0C, 0x07 }, /* IMON Scaling */ | ||
62 | { 0x0D, 0x03 }, /* Audio/LED Pwr Manager */ | ||
63 | { 0x0F, 0x20 }, /* Serial Port Control */ | ||
64 | { 0x10, 0x14 }, /* Class D Amp CTL */ | ||
65 | { 0x11, 0x00 }, /* Protection Release CTL */ | ||
66 | { 0x12, 0xFF }, /* Interrupt Mask 1 */ | ||
67 | { 0x13, 0xFF }, /* Interrupt Mask 2 */ | ||
68 | { 0x14, 0xFF }, /* Interrupt Mask 3 */ | ||
69 | { 0x19, 0x00 }, /* LED Flash Mode Current */ | ||
70 | { 0x1A, 0x00 }, /* LED Movie Mode Current */ | ||
71 | { 0x1B, 0x20 }, /* LED Flash Timer */ | ||
72 | { 0x1C, 0x00 }, /* LED Flash Inhibit Current */ | ||
73 | }; | ||
74 | |||
75 | static bool cs35l32_readable_register(struct device *dev, unsigned int reg) | ||
76 | { | ||
77 | switch (reg) { | ||
78 | case CS35L32_DEVID_AB: | ||
79 | case CS35L32_DEVID_CD: | ||
80 | case CS35L32_DEVID_E: | ||
81 | case CS35L32_FAB_ID: | ||
82 | case CS35L32_REV_ID: | ||
83 | case CS35L32_PWRCTL1: | ||
84 | case CS35L32_PWRCTL2: | ||
85 | case CS35L32_CLK_CTL: | ||
86 | case CS35L32_BATT_THRESHOLD: | ||
87 | case CS35L32_VMON: | ||
88 | case CS35L32_BST_CPCP_CTL: | ||
89 | case CS35L32_IMON_SCALING: | ||
90 | case CS35L32_AUDIO_LED_MNGR: | ||
91 | case CS35L32_ADSP_CTL: | ||
92 | case CS35L32_CLASSD_CTL: | ||
93 | case CS35L32_PROTECT_CTL: | ||
94 | case CS35L32_INT_MASK_1: | ||
95 | case CS35L32_INT_MASK_2: | ||
96 | case CS35L32_INT_MASK_3: | ||
97 | case CS35L32_INT_STATUS_1: | ||
98 | case CS35L32_INT_STATUS_2: | ||
99 | case CS35L32_INT_STATUS_3: | ||
100 | case CS35L32_LED_STATUS: | ||
101 | case CS35L32_FLASH_MODE: | ||
102 | case CS35L32_MOVIE_MODE: | ||
103 | case CS35L32_FLASH_TIMER: | ||
104 | case CS35L32_FLASH_INHIBIT: | ||
105 | return true; | ||
106 | default: | ||
107 | return false; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | static bool cs35l32_volatile_register(struct device *dev, unsigned int reg) | ||
112 | { | ||
113 | switch (reg) { | ||
114 | case CS35L32_DEVID_AB: | ||
115 | case CS35L32_DEVID_CD: | ||
116 | case CS35L32_DEVID_E: | ||
117 | case CS35L32_FAB_ID: | ||
118 | case CS35L32_REV_ID: | ||
119 | case CS35L32_INT_STATUS_1: | ||
120 | case CS35L32_INT_STATUS_2: | ||
121 | case CS35L32_INT_STATUS_3: | ||
122 | case CS35L32_LED_STATUS: | ||
123 | return true; | ||
124 | default: | ||
125 | return false; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static bool cs35l32_precious_register(struct device *dev, unsigned int reg) | ||
130 | { | ||
131 | switch (reg) { | ||
132 | case CS35L32_INT_STATUS_1: | ||
133 | case CS35L32_INT_STATUS_2: | ||
134 | case CS35L32_INT_STATUS_3: | ||
135 | case CS35L32_LED_STATUS: | ||
136 | return true; | ||
137 | default: | ||
138 | return false; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static DECLARE_TLV_DB_SCALE(classd_ctl_tlv, 900, 300, 0); | ||
143 | |||
144 | static const struct snd_kcontrol_new imon_ctl = | ||
145 | SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 6, 1, 1); | ||
146 | |||
147 | static const struct snd_kcontrol_new vmon_ctl = | ||
148 | SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 7, 1, 1); | ||
149 | |||
150 | static const struct snd_kcontrol_new vpmon_ctl = | ||
151 | SOC_DAPM_SINGLE("Switch", CS35L32_PWRCTL2, 5, 1, 1); | ||
152 | |||
153 | static const struct snd_kcontrol_new cs35l32_snd_controls[] = { | ||
154 | SOC_SINGLE_TLV("Speaker Volume", CS35L32_CLASSD_CTL, | ||
155 | 3, 0x04, 1, classd_ctl_tlv), | ||
156 | SOC_SINGLE("Zero Cross Switch", CS35L32_CLASSD_CTL, 2, 1, 0), | ||
157 | SOC_SINGLE("Gain Manager Switch", CS35L32_AUDIO_LED_MNGR, 3, 1, 0), | ||
158 | }; | ||
159 | |||
160 | static const struct snd_soc_dapm_widget cs35l32_dapm_widgets[] = { | ||
161 | |||
162 | SND_SOC_DAPM_SUPPLY("BOOST", CS35L32_PWRCTL1, 2, 1, NULL, 0), | ||
163 | SND_SOC_DAPM_OUT_DRV("Speaker", CS35L32_PWRCTL1, 7, 1, NULL, 0), | ||
164 | |||
165 | SND_SOC_DAPM_AIF_OUT("SDOUT", NULL, 0, CS35L32_PWRCTL2, 3, 1), | ||
166 | |||
167 | SND_SOC_DAPM_INPUT("VP"), | ||
168 | SND_SOC_DAPM_INPUT("ISENSE"), | ||
169 | SND_SOC_DAPM_INPUT("VSENSE"), | ||
170 | |||
171 | SND_SOC_DAPM_SWITCH("VMON ADC", CS35L32_PWRCTL2, 7, 1, &vmon_ctl), | ||
172 | SND_SOC_DAPM_SWITCH("IMON ADC", CS35L32_PWRCTL2, 6, 1, &imon_ctl), | ||
173 | SND_SOC_DAPM_SWITCH("VPMON ADC", CS35L32_PWRCTL2, 5, 1, &vpmon_ctl), | ||
174 | }; | ||
175 | |||
176 | static const struct snd_soc_dapm_route cs35l32_audio_map[] = { | ||
177 | |||
178 | {"Speaker", NULL, "BOOST"}, | ||
179 | |||
180 | {"VMON ADC", NULL, "VSENSE"}, | ||
181 | {"IMON ADC", NULL, "ISENSE"}, | ||
182 | {"VPMON ADC", NULL, "VP"}, | ||
183 | |||
184 | {"SDOUT", "Switch", "VMON ADC"}, | ||
185 | {"SDOUT", "Switch", "IMON ADC"}, | ||
186 | {"SDOUT", "Switch", "VPMON ADC"}, | ||
187 | |||
188 | {"Capture", NULL, "SDOUT"}, | ||
189 | }; | ||
190 | |||
191 | static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | ||
192 | { | ||
193 | struct snd_soc_codec *codec = codec_dai->codec; | ||
194 | |||
195 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
196 | case SND_SOC_DAIFMT_CBM_CFM: | ||
197 | snd_soc_update_bits(codec, CS35L32_ADSP_CTL, | ||
198 | CS35L32_ADSP_MASTER_MASK, | ||
199 | CS35L32_ADSP_MASTER_MASK); | ||
200 | break; | ||
201 | case SND_SOC_DAIFMT_CBS_CFS: | ||
202 | snd_soc_update_bits(codec, CS35L32_ADSP_CTL, | ||
203 | CS35L32_ADSP_MASTER_MASK, 0); | ||
204 | break; | ||
205 | default: | ||
206 | return -EINVAL; | ||
207 | } | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int cs35l32_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
213 | { | ||
214 | struct snd_soc_codec *codec = dai->codec; | ||
215 | |||
216 | return snd_soc_update_bits(codec, CS35L32_PWRCTL2, | ||
217 | CS35L32_SDOUT_3ST, tristate << 3); | ||
218 | } | ||
219 | |||
220 | static const struct snd_soc_dai_ops cs35l32_ops = { | ||
221 | .set_fmt = cs35l32_set_dai_fmt, | ||
222 | .set_tristate = cs35l32_set_tristate, | ||
223 | }; | ||
224 | |||
225 | static struct snd_soc_dai_driver cs35l32_dai[] = { | ||
226 | { | ||
227 | .name = "cs35l32-monitor", | ||
228 | .id = 0, | ||
229 | .capture = { | ||
230 | .stream_name = "Capture", | ||
231 | .channels_min = 2, | ||
232 | .channels_max = 2, | ||
233 | .rates = CS35L32_RATES, | ||
234 | .formats = CS35L32_FORMATS, | ||
235 | }, | ||
236 | .ops = &cs35l32_ops, | ||
237 | .symmetric_rates = 1, | ||
238 | } | ||
239 | }; | ||
240 | |||
241 | static int cs35l32_codec_set_sysclk(struct snd_soc_codec *codec, | ||
242 | int clk_id, int source, unsigned int freq, int dir) | ||
243 | { | ||
244 | unsigned int val; | ||
245 | |||
246 | switch (freq) { | ||
247 | case 6000000: | ||
248 | val = CS35L32_MCLK_RATIO; | ||
249 | break; | ||
250 | case 12000000: | ||
251 | val = CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO; | ||
252 | break; | ||
253 | case 6144000: | ||
254 | val = 0; | ||
255 | break; | ||
256 | case 12288000: | ||
257 | val = CS35L32_MCLK_DIV2_MASK; | ||
258 | break; | ||
259 | default: | ||
260 | return -EINVAL; | ||
261 | } | ||
262 | |||
263 | return snd_soc_update_bits(codec, CS35L32_CLK_CTL, | ||
264 | CS35L32_MCLK_DIV2_MASK | CS35L32_MCLK_RATIO_MASK, val); | ||
265 | } | ||
266 | |||
267 | static struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { | ||
268 | .set_sysclk = cs35l32_codec_set_sysclk, | ||
269 | |||
270 | .dapm_widgets = cs35l32_dapm_widgets, | ||
271 | .num_dapm_widgets = ARRAY_SIZE(cs35l32_dapm_widgets), | ||
272 | .dapm_routes = cs35l32_audio_map, | ||
273 | .num_dapm_routes = ARRAY_SIZE(cs35l32_audio_map), | ||
274 | |||
275 | .controls = cs35l32_snd_controls, | ||
276 | .num_controls = ARRAY_SIZE(cs35l32_snd_controls), | ||
277 | }; | ||
278 | |||
279 | /* Current and threshold powerup sequence Pg37 in datasheet */ | ||
280 | static const struct reg_default cs35l32_monitor_patch[] = { | ||
281 | |||
282 | { 0x00, 0x99 }, | ||
283 | { 0x48, 0x17 }, | ||
284 | { 0x49, 0x56 }, | ||
285 | { 0x43, 0x01 }, | ||
286 | { 0x3B, 0x62 }, | ||
287 | { 0x3C, 0x80 }, | ||
288 | { 0x00, 0x00 }, | ||
289 | }; | ||
290 | |||
291 | static struct regmap_config cs35l32_regmap = { | ||
292 | .reg_bits = 8, | ||
293 | .val_bits = 8, | ||
294 | |||
295 | .max_register = CS35L32_MAX_REGISTER, | ||
296 | .reg_defaults = cs35l32_reg_defaults, | ||
297 | .num_reg_defaults = ARRAY_SIZE(cs35l32_reg_defaults), | ||
298 | .volatile_reg = cs35l32_volatile_register, | ||
299 | .readable_reg = cs35l32_readable_register, | ||
300 | .precious_reg = cs35l32_precious_register, | ||
301 | .cache_type = REGCACHE_RBTREE, | ||
302 | }; | ||
303 | |||
304 | static int cs35l32_handle_of_data(struct i2c_client *i2c_client, | ||
305 | struct cs35l32_platform_data *pdata) | ||
306 | { | ||
307 | struct device_node *np = i2c_client->dev.of_node; | ||
308 | unsigned int val; | ||
309 | |||
310 | if (of_property_read_u32(np, "cirrus,sdout-share", &val) >= 0) | ||
311 | pdata->sdout_share = val; | ||
312 | |||
313 | of_property_read_u32(np, "cirrus,boost-manager", &val); | ||
314 | switch (val) { | ||
315 | case CS35L32_BOOST_MGR_AUTO: | ||
316 | case CS35L32_BOOST_MGR_AUTO_AUDIO: | ||
317 | case CS35L32_BOOST_MGR_BYPASS: | ||
318 | case CS35L32_BOOST_MGR_FIXED: | ||
319 | pdata->boost_mng = val; | ||
320 | break; | ||
321 | default: | ||
322 | dev_err(&i2c_client->dev, | ||
323 | "Wrong cirrus,boost-manager DT value %d\n", val); | ||
324 | pdata->boost_mng = CS35L32_BOOST_MGR_BYPASS; | ||
325 | } | ||
326 | |||
327 | of_property_read_u32(np, "cirrus,sdout-datacfg", &val); | ||
328 | switch (val) { | ||
329 | case CS35L32_DATA_CFG_LR_VP: | ||
330 | case CS35L32_DATA_CFG_LR_STAT: | ||
331 | case CS35L32_DATA_CFG_LR: | ||
332 | case CS35L32_DATA_CFG_LR_VPSTAT: | ||
333 | pdata->sdout_datacfg = val; | ||
334 | break; | ||
335 | default: | ||
336 | dev_err(&i2c_client->dev, | ||
337 | "Wrong cirrus,sdout-datacfg DT value %d\n", val); | ||
338 | pdata->sdout_datacfg = CS35L32_DATA_CFG_LR; | ||
339 | } | ||
340 | |||
341 | of_property_read_u32(np, "cirrus,battery-threshold", &val); | ||
342 | switch (val) { | ||
343 | case CS35L32_BATT_THRESH_3_1V: | ||
344 | case CS35L32_BATT_THRESH_3_2V: | ||
345 | case CS35L32_BATT_THRESH_3_3V: | ||
346 | case CS35L32_BATT_THRESH_3_4V: | ||
347 | pdata->batt_thresh = val; | ||
348 | break; | ||
349 | default: | ||
350 | dev_err(&i2c_client->dev, | ||
351 | "Wrong cirrus,battery-threshold DT value %d\n", val); | ||
352 | pdata->batt_thresh = CS35L32_BATT_THRESH_3_3V; | ||
353 | } | ||
354 | |||
355 | of_property_read_u32(np, "cirrus,battery-recovery", &val); | ||
356 | switch (val) { | ||
357 | case CS35L32_BATT_RECOV_3_1V: | ||
358 | case CS35L32_BATT_RECOV_3_2V: | ||
359 | case CS35L32_BATT_RECOV_3_3V: | ||
360 | case CS35L32_BATT_RECOV_3_4V: | ||
361 | case CS35L32_BATT_RECOV_3_5V: | ||
362 | case CS35L32_BATT_RECOV_3_6V: | ||
363 | pdata->batt_recov = val; | ||
364 | break; | ||
365 | default: | ||
366 | dev_err(&i2c_client->dev, | ||
367 | "Wrong cirrus,battery-recovery DT value %d\n", val); | ||
368 | pdata->batt_recov = CS35L32_BATT_RECOV_3_4V; | ||
369 | } | ||
370 | |||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int cs35l32_i2c_probe(struct i2c_client *i2c_client, | ||
375 | const struct i2c_device_id *id) | ||
376 | { | ||
377 | struct cs35l32_private *cs35l32; | ||
378 | struct cs35l32_platform_data *pdata = | ||
379 | dev_get_platdata(&i2c_client->dev); | ||
380 | int ret, i; | ||
381 | unsigned int devid = 0; | ||
382 | unsigned int reg; | ||
383 | |||
384 | |||
385 | cs35l32 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs35l32_private), | ||
386 | GFP_KERNEL); | ||
387 | if (!cs35l32) { | ||
388 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
389 | return -ENOMEM; | ||
390 | } | ||
391 | |||
392 | i2c_set_clientdata(i2c_client, cs35l32); | ||
393 | |||
394 | cs35l32->regmap = devm_regmap_init_i2c(i2c_client, &cs35l32_regmap); | ||
395 | if (IS_ERR(cs35l32->regmap)) { | ||
396 | ret = PTR_ERR(cs35l32->regmap); | ||
397 | dev_err(&i2c_client->dev, "regmap_init() failed: %d\n", ret); | ||
398 | return ret; | ||
399 | } | ||
400 | |||
401 | if (pdata) { | ||
402 | cs35l32->pdata = *pdata; | ||
403 | } else { | ||
404 | pdata = devm_kzalloc(&i2c_client->dev, | ||
405 | sizeof(struct cs35l32_platform_data), | ||
406 | GFP_KERNEL); | ||
407 | if (!pdata) { | ||
408 | dev_err(&i2c_client->dev, "could not allocate pdata\n"); | ||
409 | return -ENOMEM; | ||
410 | } | ||
411 | if (i2c_client->dev.of_node) { | ||
412 | ret = cs35l32_handle_of_data(i2c_client, | ||
413 | &cs35l32->pdata); | ||
414 | if (ret != 0) | ||
415 | return ret; | ||
416 | } | ||
417 | } | ||
418 | |||
419 | for (i = 0; i < ARRAY_SIZE(cs35l32->supplies); i++) | ||
420 | cs35l32->supplies[i].supply = cs35l32_supply_names[i]; | ||
421 | |||
422 | ret = devm_regulator_bulk_get(&i2c_client->dev, | ||
423 | ARRAY_SIZE(cs35l32->supplies), | ||
424 | cs35l32->supplies); | ||
425 | if (ret != 0) { | ||
426 | dev_err(&i2c_client->dev, | ||
427 | "Failed to request supplies: %d\n", ret); | ||
428 | return ret; | ||
429 | } | ||
430 | |||
431 | ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), | ||
432 | cs35l32->supplies); | ||
433 | if (ret != 0) { | ||
434 | dev_err(&i2c_client->dev, | ||
435 | "Failed to enable supplies: %d\n", ret); | ||
436 | return ret; | ||
437 | } | ||
438 | |||
439 | /* Reset the Device */ | ||
440 | cs35l32->reset_gpio = devm_gpiod_get(&i2c_client->dev, | ||
441 | "reset-gpios"); | ||
442 | if (IS_ERR(cs35l32->reset_gpio)) { | ||
443 | ret = PTR_ERR(cs35l32->reset_gpio); | ||
444 | if (ret != -ENOENT && ret != -ENOSYS) | ||
445 | return ret; | ||
446 | |||
447 | cs35l32->reset_gpio = NULL; | ||
448 | } else { | ||
449 | ret = gpiod_direction_output(cs35l32->reset_gpio, 0); | ||
450 | if (ret) | ||
451 | return ret; | ||
452 | gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); | ||
453 | } | ||
454 | |||
455 | /* initialize codec */ | ||
456 | ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); | ||
457 | devid = (reg & 0xFF) << 12; | ||
458 | |||
459 | ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_CD, ®); | ||
460 | devid |= (reg & 0xFF) << 4; | ||
461 | |||
462 | ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_E, ®); | ||
463 | devid |= (reg & 0xF0) >> 4; | ||
464 | |||
465 | if (devid != CS35L32_CHIP_ID) { | ||
466 | ret = -ENODEV; | ||
467 | dev_err(&i2c_client->dev, | ||
468 | "CS35L32 Device ID (%X). Expected %X\n", | ||
469 | devid, CS35L32_CHIP_ID); | ||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | ret = regmap_read(cs35l32->regmap, CS35L32_REV_ID, ®); | ||
474 | if (ret < 0) { | ||
475 | dev_err(&i2c_client->dev, "Get Revision ID failed\n"); | ||
476 | return ret; | ||
477 | } | ||
478 | |||
479 | ret = regmap_register_patch(cs35l32->regmap, cs35l32_monitor_patch, | ||
480 | ARRAY_SIZE(cs35l32_monitor_patch)); | ||
481 | if (ret < 0) { | ||
482 | dev_err(&i2c_client->dev, "Failed to apply errata patch\n"); | ||
483 | return ret; | ||
484 | } | ||
485 | |||
486 | dev_info(&i2c_client->dev, | ||
487 | "Cirrus Logic CS35L32, Revision: %02X\n", reg & 0xFF); | ||
488 | |||
489 | /* Setup VBOOST Management */ | ||
490 | if (cs35l32->pdata.boost_mng) | ||
491 | regmap_update_bits(cs35l32->regmap, CS35L32_AUDIO_LED_MNGR, | ||
492 | CS35L32_BOOST_MASK, | ||
493 | cs35l32->pdata.boost_mng); | ||
494 | |||
495 | /* Setup ADSP Format Config */ | ||
496 | if (cs35l32->pdata.sdout_share) | ||
497 | regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, | ||
498 | CS35L32_ADSP_SHARE_MASK, | ||
499 | cs35l32->pdata.sdout_share << 3); | ||
500 | |||
501 | /* Setup ADSP Data Configuration */ | ||
502 | if (cs35l32->pdata.sdout_datacfg) | ||
503 | regmap_update_bits(cs35l32->regmap, CS35L32_ADSP_CTL, | ||
504 | CS35L32_ADSP_DATACFG_MASK, | ||
505 | cs35l32->pdata.sdout_datacfg << 4); | ||
506 | |||
507 | /* Setup Low Battery Recovery */ | ||
508 | if (cs35l32->pdata.batt_recov) | ||
509 | regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, | ||
510 | CS35L32_BATT_REC_MASK, | ||
511 | cs35l32->pdata.batt_recov << 1); | ||
512 | |||
513 | /* Setup Low Battery Threshold */ | ||
514 | if (cs35l32->pdata.batt_thresh) | ||
515 | regmap_update_bits(cs35l32->regmap, CS35L32_BATT_THRESHOLD, | ||
516 | CS35L32_BATT_THRESH_MASK, | ||
517 | cs35l32->pdata.batt_thresh << 4); | ||
518 | |||
519 | /* Power down the AMP */ | ||
520 | regmap_update_bits(cs35l32->regmap, CS35L32_PWRCTL1, CS35L32_PDN_AMP, | ||
521 | CS35L32_PDN_AMP); | ||
522 | |||
523 | /* Clear MCLK Error Bit since we don't have the clock yet */ | ||
524 | ret = regmap_read(cs35l32->regmap, CS35L32_INT_STATUS_1, ®); | ||
525 | |||
526 | ret = snd_soc_register_codec(&i2c_client->dev, | ||
527 | &soc_codec_dev_cs35l32, cs35l32_dai, | ||
528 | ARRAY_SIZE(cs35l32_dai)); | ||
529 | if (ret < 0) | ||
530 | goto err_disable; | ||
531 | |||
532 | return 0; | ||
533 | |||
534 | err_disable: | ||
535 | regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), | ||
536 | cs35l32->supplies); | ||
537 | return ret; | ||
538 | } | ||
539 | |||
540 | static int cs35l32_i2c_remove(struct i2c_client *i2c_client) | ||
541 | { | ||
542 | struct cs35l32_private *cs35l32 = i2c_get_clientdata(i2c_client); | ||
543 | |||
544 | snd_soc_unregister_codec(&i2c_client->dev); | ||
545 | |||
546 | /* Hold down reset */ | ||
547 | if (cs35l32->reset_gpio) | ||
548 | gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); | ||
549 | |||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | #ifdef CONFIG_PM_RUNTIME | ||
554 | static int cs35l32_runtime_suspend(struct device *dev) | ||
555 | { | ||
556 | struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); | ||
557 | |||
558 | regcache_cache_only(cs35l32->regmap, true); | ||
559 | regcache_mark_dirty(cs35l32->regmap); | ||
560 | |||
561 | /* Hold down reset */ | ||
562 | if (cs35l32->reset_gpio) | ||
563 | gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); | ||
564 | |||
565 | /* remove power */ | ||
566 | regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), | ||
567 | cs35l32->supplies); | ||
568 | |||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int cs35l32_runtime_resume(struct device *dev) | ||
573 | { | ||
574 | struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); | ||
575 | int ret; | ||
576 | |||
577 | /* Enable power */ | ||
578 | ret = regulator_bulk_enable(ARRAY_SIZE(cs35l32->supplies), | ||
579 | cs35l32->supplies); | ||
580 | if (ret != 0) { | ||
581 | dev_err(dev, "Failed to enable supplies: %d\n", | ||
582 | ret); | ||
583 | return ret; | ||
584 | } | ||
585 | |||
586 | if (cs35l32->reset_gpio) | ||
587 | gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); | ||
588 | |||
589 | regcache_cache_only(cs35l32->regmap, false); | ||
590 | regcache_sync(cs35l32->regmap); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | #endif | ||
595 | |||
596 | static const struct dev_pm_ops cs35l32_runtime_pm = { | ||
597 | SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, | ||
598 | NULL) | ||
599 | }; | ||
600 | |||
601 | static const struct of_device_id cs35l32_of_match[] = { | ||
602 | { .compatible = "cirrus,cs35l32", }, | ||
603 | {}, | ||
604 | }; | ||
605 | MODULE_DEVICE_TABLE(of, cs35l32_of_match); | ||
606 | |||
607 | |||
608 | static const struct i2c_device_id cs35l32_id[] = { | ||
609 | {"cs35l32", 0}, | ||
610 | {} | ||
611 | }; | ||
612 | |||
613 | MODULE_DEVICE_TABLE(i2c, cs35l32_id); | ||
614 | |||
615 | static struct i2c_driver cs35l32_i2c_driver = { | ||
616 | .driver = { | ||
617 | .name = "cs35l32", | ||
618 | .owner = THIS_MODULE, | ||
619 | .pm = &cs35l32_runtime_pm, | ||
620 | .of_match_table = cs35l32_of_match, | ||
621 | }, | ||
622 | .id_table = cs35l32_id, | ||
623 | .probe = cs35l32_i2c_probe, | ||
624 | .remove = cs35l32_i2c_remove, | ||
625 | }; | ||
626 | |||
627 | module_i2c_driver(cs35l32_i2c_driver); | ||
628 | |||
629 | MODULE_DESCRIPTION("ASoC CS35L32 driver"); | ||
630 | MODULE_AUTHOR("Brian Austin, Cirrus Logic Inc, <brian.austin@cirrus.com>"); | ||
631 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h new file mode 100644 index 000000000000..31ab804a22bc --- /dev/null +++ b/sound/soc/codecs/cs35l32.h | |||
@@ -0,0 +1,93 @@ | |||
1 | /* | ||
2 | * cs35l32.h -- CS35L32 ALSA SoC audio driver | ||
3 | * | ||
4 | * Copyright 2014 CirrusLogic, Inc. | ||
5 | * | ||
6 | * Author: Brian Austin <brian.austin@cirrus.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #ifndef __CS35L32_H__ | ||
15 | #define __CS35L32_H__ | ||
16 | |||
17 | struct cs35l32_platform_data { | ||
18 | /* Low Battery Threshold */ | ||
19 | unsigned int batt_thresh; | ||
20 | /* Low Battery Recovery */ | ||
21 | unsigned int batt_recov; | ||
22 | /* LED Current Management*/ | ||
23 | unsigned int led_mng; | ||
24 | /* Audio Gain w/ LED */ | ||
25 | unsigned int audiogain_mng; | ||
26 | /* Boost Management */ | ||
27 | unsigned int boost_mng; | ||
28 | /* Data CFG for DUAL device */ | ||
29 | unsigned int sdout_datacfg; | ||
30 | /* SDOUT Sharing */ | ||
31 | unsigned int sdout_share; | ||
32 | }; | ||
33 | |||
34 | #define CS35L32_CHIP_ID 0x00035A32 | ||
35 | #define CS35L32_DEVID_AB 0x01 /* Device ID A & B [RO] */ | ||
36 | #define CS35L32_DEVID_CD 0x02 /* Device ID C & D [RO] */ | ||
37 | #define CS35L32_DEVID_E 0x03 /* Device ID E [RO] */ | ||
38 | #define CS35L32_FAB_ID 0x04 /* Fab ID [RO] */ | ||
39 | #define CS35L32_REV_ID 0x05 /* Revision ID [RO] */ | ||
40 | #define CS35L32_PWRCTL1 0x06 /* Power Ctl 1 */ | ||
41 | #define CS35L32_PWRCTL2 0x07 /* Power Ctl 2 */ | ||
42 | #define CS35L32_CLK_CTL 0x08 /* Clock Ctl */ | ||
43 | #define CS35L32_BATT_THRESHOLD 0x09 /* Low Battery Threshold */ | ||
44 | #define CS35L32_VMON 0x0A /* Voltage Monitor [RO] */ | ||
45 | #define CS35L32_BST_CPCP_CTL 0x0B /* Conv Peak Curr Protection CTL */ | ||
46 | #define CS35L32_IMON_SCALING 0x0C /* IMON Scaling */ | ||
47 | #define CS35L32_AUDIO_LED_MNGR 0x0D /* Audio/LED Pwr Manager */ | ||
48 | #define CS35L32_ADSP_CTL 0x0F /* Serial Port Control */ | ||
49 | #define CS35L32_CLASSD_CTL 0x10 /* Class D Amp CTL */ | ||
50 | #define CS35L32_PROTECT_CTL 0x11 /* Protection Release CTL */ | ||
51 | #define CS35L32_INT_MASK_1 0x12 /* Interrupt Mask 1 */ | ||
52 | #define CS35L32_INT_MASK_2 0x13 /* Interrupt Mask 2 */ | ||
53 | #define CS35L32_INT_MASK_3 0x14 /* Interrupt Mask 3 */ | ||
54 | #define CS35L32_INT_STATUS_1 0x15 /* Interrupt Status 1 [RO] */ | ||
55 | #define CS35L32_INT_STATUS_2 0x16 /* Interrupt Status 2 [RO] */ | ||
56 | #define CS35L32_INT_STATUS_3 0x17 /* Interrupt Status 3 [RO] */ | ||
57 | #define CS35L32_LED_STATUS 0x18 /* LED Lighting Status [RO] */ | ||
58 | #define CS35L32_FLASH_MODE 0x19 /* LED Flash Mode Current */ | ||
59 | #define CS35L32_MOVIE_MODE 0x1A /* LED Movie Mode Current */ | ||
60 | #define CS35L32_FLASH_TIMER 0x1B /* LED Flash Timer */ | ||
61 | #define CS35L32_FLASH_INHIBIT 0x1C /* LED Flash Inhibit Current */ | ||
62 | #define CS35L32_MAX_REGISTER 0x1C | ||
63 | |||
64 | #define CS35L32_MCLK_DIV2 0x01 | ||
65 | #define CS35L32_MCLK_RATIO 0x01 | ||
66 | #define CS35L32_MCLKDIS 0x80 | ||
67 | #define CS35L32_PDN_ALL 0x01 | ||
68 | #define CS35L32_PDN_AMP 0x80 | ||
69 | #define CS35L32_PDN_BOOST 0x04 | ||
70 | #define CS35L32_PDN_IMON 0x40 | ||
71 | #define CS35L32_PDN_VMON 0x80 | ||
72 | #define CS35L32_PDN_VPMON 0x20 | ||
73 | #define CS35L32_PDN_ADSP 0x08 | ||
74 | |||
75 | #define CS35L32_MCLK_DIV2_MASK 0x40 | ||
76 | #define CS35L32_MCLK_RATIO_MASK 0x01 | ||
77 | #define CS35L32_MCLK_MASK 0x41 | ||
78 | #define CS35L32_ADSP_MASTER_MASK 0x40 | ||
79 | #define CS35L32_BOOST_MASK 0x03 | ||
80 | #define CS35L32_GAIN_MGR_MASK 0x08 | ||
81 | #define CS35L32_ADSP_SHARE_MASK 0x08 | ||
82 | #define CS35L32_ADSP_DATACFG_MASK 0x30 | ||
83 | #define CS35L32_SDOUT_3ST 0x80 | ||
84 | #define CS35L32_BATT_REC_MASK 0x0E | ||
85 | #define CS35L32_BATT_THRESH_MASK 0x30 | ||
86 | |||
87 | #define CS35L32_RATES (SNDRV_PCM_RATE_48000) | ||
88 | #define CS35L32_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
89 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
90 | SNDRV_PCM_FMTBIT_S32_LE) | ||
91 | |||
92 | |||
93 | #endif | ||
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index a20b30ca52c0..4fdd47d700e3 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c | |||
@@ -77,6 +77,7 @@ static bool cs4265_readable_register(struct device *dev, unsigned int reg) | |||
77 | case CS4265_INT_MASK: | 77 | case CS4265_INT_MASK: |
78 | case CS4265_STATUS_MODE_MSB: | 78 | case CS4265_STATUS_MODE_MSB: |
79 | case CS4265_STATUS_MODE_LSB: | 79 | case CS4265_STATUS_MODE_LSB: |
80 | case CS4265_CHIP_ID: | ||
80 | return true; | 81 | return true; |
81 | default: | 82 | default: |
82 | return false; | 83 | return false; |
@@ -282,10 +283,10 @@ static const struct cs4265_clk_para clk_map_table[] = { | |||
282 | 283 | ||
283 | /*64k*/ | 284 | /*64k*/ |
284 | {8192000, 64000, 1, 0}, | 285 | {8192000, 64000, 1, 0}, |
285 | {1228800, 64000, 1, 1}, | 286 | {12288000, 64000, 1, 1}, |
286 | {1693440, 64000, 1, 2}, | 287 | {16934400, 64000, 1, 2}, |
287 | {2457600, 64000, 1, 3}, | 288 | {24576000, 64000, 1, 3}, |
288 | {3276800, 64000, 1, 4}, | 289 | {32768000, 64000, 1, 4}, |
289 | 290 | ||
290 | /* 88.2k */ | 291 | /* 88.2k */ |
291 | {11289600, 88200, 1, 0}, | 292 | {11289600, 88200, 1, 0}, |
@@ -435,10 +436,10 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, | |||
435 | index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); | 436 | index = cs4265_get_clk_index(cs4265->sysclk, params_rate(params)); |
436 | if (index >= 0) { | 437 | if (index >= 0) { |
437 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | 438 | snd_soc_update_bits(codec, CS4265_ADC_CTL, |
438 | CS4265_ADC_FM, clk_map_table[index].fm_mode); | 439 | CS4265_ADC_FM, clk_map_table[index].fm_mode << 6); |
439 | snd_soc_update_bits(codec, CS4265_MCLK_FREQ, | 440 | snd_soc_update_bits(codec, CS4265_MCLK_FREQ, |
440 | CS4265_MCLK_FREQ_MASK, | 441 | CS4265_MCLK_FREQ_MASK, |
441 | clk_map_table[index].mclkdiv); | 442 | clk_map_table[index].mclkdiv << 4); |
442 | 443 | ||
443 | } else { | 444 | } else { |
444 | dev_err(codec->dev, "can't get correct mclk\n"); | 445 | dev_err(codec->dev, "can't get correct mclk\n"); |
@@ -458,12 +459,12 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, | |||
458 | if (params_width(params) == 16) { | 459 | if (params_width(params) == 16) { |
459 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | 460 | snd_soc_update_bits(codec, CS4265_DAC_CTL, |
460 | CS4265_DAC_CTL_DIF, (1 << 5)); | 461 | CS4265_DAC_CTL_DIF, (1 << 5)); |
461 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | 462 | snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, |
462 | CS4265_SPDIF_CTL2_DIF, (1 << 7)); | 463 | CS4265_SPDIF_CTL2_DIF, (1 << 7)); |
463 | } else { | 464 | } else { |
464 | snd_soc_update_bits(codec, CS4265_DAC_CTL, | 465 | snd_soc_update_bits(codec, CS4265_DAC_CTL, |
465 | CS4265_DAC_CTL_DIF, (3 << 5)); | 466 | CS4265_DAC_CTL_DIF, (3 << 5)); |
466 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | 467 | snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, |
467 | CS4265_SPDIF_CTL2_DIF, (1 << 7)); | 468 | CS4265_SPDIF_CTL2_DIF, (1 << 7)); |
468 | } | 469 | } |
469 | break; | 470 | break; |
@@ -472,7 +473,7 @@ static int cs4265_pcm_hw_params(struct snd_pcm_substream *substream, | |||
472 | CS4265_DAC_CTL_DIF, 0); | 473 | CS4265_DAC_CTL_DIF, 0); |
473 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | 474 | snd_soc_update_bits(codec, CS4265_ADC_CTL, |
474 | CS4265_ADC_DIF, 0); | 475 | CS4265_ADC_DIF, 0); |
475 | snd_soc_update_bits(codec, CS4265_ADC_CTL, | 476 | snd_soc_update_bits(codec, CS4265_SPDIF_CTL2, |
476 | CS4265_SPDIF_CTL2_DIF, (1 << 6)); | 477 | CS4265_SPDIF_CTL2_DIF, (1 << 6)); |
477 | 478 | ||
478 | break; | 479 | break; |
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 969167d8b71e..35fbef743fbe 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
@@ -176,9 +176,9 @@ static bool cs42l52_volatile_register(struct device *dev, unsigned int reg) | |||
176 | case CS42L52_BATT_LEVEL: | 176 | case CS42L52_BATT_LEVEL: |
177 | case CS42L52_SPK_STATUS: | 177 | case CS42L52_SPK_STATUS: |
178 | case CS42L52_CHARGE_PUMP: | 178 | case CS42L52_CHARGE_PUMP: |
179 | return 1; | 179 | return true; |
180 | default: | 180 | default: |
181 | return 0; | 181 | return false; |
182 | } | 182 | } |
183 | } | 183 | } |
184 | 184 | ||
@@ -946,20 +946,6 @@ static struct snd_soc_dai_driver cs42l52_dai = { | |||
946 | .ops = &cs42l52_ops, | 946 | .ops = &cs42l52_ops, |
947 | }; | 947 | }; |
948 | 948 | ||
949 | static int cs42l52_suspend(struct snd_soc_codec *codec) | ||
950 | { | ||
951 | cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
952 | |||
953 | return 0; | ||
954 | } | ||
955 | |||
956 | static int cs42l52_resume(struct snd_soc_codec *codec) | ||
957 | { | ||
958 | cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
959 | |||
960 | return 0; | ||
961 | } | ||
962 | |||
963 | static int beep_rates[] = { | 949 | static int beep_rates[] = { |
964 | 261, 522, 585, 667, 706, 774, 889, 1000, | 950 | 261, 522, 585, 667, 706, 774, 889, 1000, |
965 | 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 | 951 | 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 |
@@ -1104,8 +1090,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec) | |||
1104 | 1090 | ||
1105 | cs42l52_init_beep(codec); | 1091 | cs42l52_init_beep(codec); |
1106 | 1092 | ||
1107 | cs42l52_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1108 | |||
1109 | cs42l52->sysclk = CS42L52_DEFAULT_CLK; | 1093 | cs42l52->sysclk = CS42L52_DEFAULT_CLK; |
1110 | cs42l52->config.format = CS42L52_DEFAULT_FORMAT; | 1094 | cs42l52->config.format = CS42L52_DEFAULT_FORMAT; |
1111 | 1095 | ||
@@ -1115,7 +1099,6 @@ static int cs42l52_probe(struct snd_soc_codec *codec) | |||
1115 | static int cs42l52_remove(struct snd_soc_codec *codec) | 1099 | static int cs42l52_remove(struct snd_soc_codec *codec) |
1116 | { | 1100 | { |
1117 | cs42l52_free_beep(codec); | 1101 | cs42l52_free_beep(codec); |
1118 | cs42l52_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1119 | 1102 | ||
1120 | return 0; | 1103 | return 0; |
1121 | } | 1104 | } |
@@ -1123,9 +1106,8 @@ static int cs42l52_remove(struct snd_soc_codec *codec) | |||
1123 | static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { | 1106 | static struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { |
1124 | .probe = cs42l52_probe, | 1107 | .probe = cs42l52_probe, |
1125 | .remove = cs42l52_remove, | 1108 | .remove = cs42l52_remove, |
1126 | .suspend = cs42l52_suspend, | ||
1127 | .resume = cs42l52_resume, | ||
1128 | .set_bias_level = cs42l52_set_bias_level, | 1109 | .set_bias_level = cs42l52_set_bias_level, |
1110 | .suspend_bias_off = true, | ||
1129 | 1111 | ||
1130 | .dapm_widgets = cs42l52_dapm_widgets, | 1112 | .dapm_widgets = cs42l52_dapm_widgets, |
1131 | .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets), | 1113 | .num_dapm_widgets = ARRAY_SIZE(cs42l52_dapm_widgets), |
diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index c766a5a9ce80..2ddc7ac10ad7 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c | |||
@@ -171,9 +171,9 @@ static bool cs42l56_volatile_register(struct device *dev, unsigned int reg) | |||
171 | { | 171 | { |
172 | switch (reg) { | 172 | switch (reg) { |
173 | case CS42L56_INT_STATUS: | 173 | case CS42L56_INT_STATUS: |
174 | return 1; | 174 | return true; |
175 | default: | 175 | default: |
176 | return 0; | 176 | return false; |
177 | } | 177 | } |
178 | } | 178 | } |
179 | 179 | ||
@@ -1016,20 +1016,6 @@ static struct snd_soc_dai_driver cs42l56_dai = { | |||
1016 | .ops = &cs42l56_ops, | 1016 | .ops = &cs42l56_ops, |
1017 | }; | 1017 | }; |
1018 | 1018 | ||
1019 | static int cs42l56_suspend(struct snd_soc_codec *codec) | ||
1020 | { | ||
1021 | cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1022 | |||
1023 | return 0; | ||
1024 | } | ||
1025 | |||
1026 | static int cs42l56_resume(struct snd_soc_codec *codec) | ||
1027 | { | ||
1028 | cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1029 | |||
1030 | return 0; | ||
1031 | } | ||
1032 | |||
1033 | static int beep_freq[] = { | 1019 | static int beep_freq[] = { |
1034 | 261, 522, 585, 667, 706, 774, 889, 1000, | 1020 | 261, 522, 585, 667, 706, 774, 889, 1000, |
1035 | 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 | 1021 | 1043, 1200, 1333, 1412, 1600, 1714, 2000, 2182 |
@@ -1168,18 +1154,12 @@ static int cs42l56_probe(struct snd_soc_codec *codec) | |||
1168 | { | 1154 | { |
1169 | cs42l56_init_beep(codec); | 1155 | cs42l56_init_beep(codec); |
1170 | 1156 | ||
1171 | cs42l56_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1172 | |||
1173 | return 0; | 1157 | return 0; |
1174 | } | 1158 | } |
1175 | 1159 | ||
1176 | static int cs42l56_remove(struct snd_soc_codec *codec) | 1160 | static int cs42l56_remove(struct snd_soc_codec *codec) |
1177 | { | 1161 | { |
1178 | struct cs42l56_private *cs42l56 = snd_soc_codec_get_drvdata(codec); | ||
1179 | |||
1180 | cs42l56_free_beep(codec); | 1162 | cs42l56_free_beep(codec); |
1181 | cs42l56_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1182 | regulator_bulk_free(ARRAY_SIZE(cs42l56->supplies), cs42l56->supplies); | ||
1183 | 1163 | ||
1184 | return 0; | 1164 | return 0; |
1185 | } | 1165 | } |
@@ -1187,9 +1167,8 @@ static int cs42l56_remove(struct snd_soc_codec *codec) | |||
1187 | static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { | 1167 | static struct snd_soc_codec_driver soc_codec_dev_cs42l56 = { |
1188 | .probe = cs42l56_probe, | 1168 | .probe = cs42l56_probe, |
1189 | .remove = cs42l56_remove, | 1169 | .remove = cs42l56_remove, |
1190 | .suspend = cs42l56_suspend, | ||
1191 | .resume = cs42l56_resume, | ||
1192 | .set_bias_level = cs42l56_set_bias_level, | 1170 | .set_bias_level = cs42l56_set_bias_level, |
1171 | .suspend_bias_off = true, | ||
1193 | 1172 | ||
1194 | .dapm_widgets = cs42l56_dapm_widgets, | 1173 | .dapm_widgets = cs42l56_dapm_widgets, |
1195 | .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), | 1174 | .num_dapm_widgets = ARRAY_SIZE(cs42l56_dapm_widgets), |
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 0e7b9eb2ba61..2f8b94683e83 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -1330,25 +1330,10 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
1330 | } | 1330 | } |
1331 | }; | 1331 | }; |
1332 | 1332 | ||
1333 | static int cs42l73_suspend(struct snd_soc_codec *codec) | ||
1334 | { | ||
1335 | cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1336 | |||
1337 | return 0; | ||
1338 | } | ||
1339 | |||
1340 | static int cs42l73_resume(struct snd_soc_codec *codec) | ||
1341 | { | ||
1342 | cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | static int cs42l73_probe(struct snd_soc_codec *codec) | 1333 | static int cs42l73_probe(struct snd_soc_codec *codec) |
1347 | { | 1334 | { |
1348 | struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec); | 1335 | struct cs42l73_private *cs42l73 = snd_soc_codec_get_drvdata(codec); |
1349 | 1336 | ||
1350 | cs42l73_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1351 | |||
1352 | /* Set Charge Pump Frequency */ | 1337 | /* Set Charge Pump Frequency */ |
1353 | if (cs42l73->pdata.chgfreq) | 1338 | if (cs42l73->pdata.chgfreq) |
1354 | snd_soc_update_bits(codec, CS42L73_CPFCHC, | 1339 | snd_soc_update_bits(codec, CS42L73_CPFCHC, |
@@ -1362,18 +1347,10 @@ static int cs42l73_probe(struct snd_soc_codec *codec) | |||
1362 | return 0; | 1347 | return 0; |
1363 | } | 1348 | } |
1364 | 1349 | ||
1365 | static int cs42l73_remove(struct snd_soc_codec *codec) | ||
1366 | { | ||
1367 | cs42l73_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1368 | return 0; | ||
1369 | } | ||
1370 | |||
1371 | static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { | 1350 | static struct snd_soc_codec_driver soc_codec_dev_cs42l73 = { |
1372 | .probe = cs42l73_probe, | 1351 | .probe = cs42l73_probe, |
1373 | .remove = cs42l73_remove, | ||
1374 | .suspend = cs42l73_suspend, | ||
1375 | .resume = cs42l73_resume, | ||
1376 | .set_bias_level = cs42l73_set_bias_level, | 1352 | .set_bias_level = cs42l73_set_bias_level, |
1353 | .suspend_bias_off = true, | ||
1377 | 1354 | ||
1378 | .dapm_widgets = cs42l73_dapm_widgets, | 1355 | .dapm_widgets = cs42l73_dapm_widgets, |
1379 | .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets), | 1356 | .num_dapm_widgets = ARRAY_SIZE(cs42l73_dapm_widgets), |
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 2fae31cb0067..61b2f9a2eef1 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c | |||
@@ -35,7 +35,6 @@ | |||
35 | 35 | ||
36 | struct da732x_priv { | 36 | struct da732x_priv { |
37 | struct regmap *regmap; | 37 | struct regmap *regmap; |
38 | struct snd_soc_codec *codec; | ||
39 | 38 | ||
40 | unsigned int sysclk; | 39 | unsigned int sysclk; |
41 | bool pll_en; | 40 | bool pll_en; |
@@ -217,7 +216,7 @@ static void da732x_set_charge_pump(struct snd_soc_codec *codec, int state) | |||
217 | snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS); | 216 | snd_soc_write(codec, DA732X_REG_CP_CTRL1, DA723X_CP_DIS); |
218 | break; | 217 | break; |
219 | default: | 218 | default: |
220 | pr_err(KERN_ERR "Wrong charge pump state\n"); | 219 | pr_err("Wrong charge pump state\n"); |
221 | break; | 220 | break; |
222 | } | 221 | } |
223 | } | 222 | } |
@@ -1508,31 +1507,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
1508 | return 0; | 1507 | return 0; |
1509 | } | 1508 | } |
1510 | 1509 | ||
1511 | static int da732x_probe(struct snd_soc_codec *codec) | ||
1512 | { | ||
1513 | struct da732x_priv *da732x = snd_soc_codec_get_drvdata(codec); | ||
1514 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
1515 | |||
1516 | da732x->codec = codec; | ||
1517 | |||
1518 | dapm->idle_bias_off = false; | ||
1519 | |||
1520 | da732x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1521 | |||
1522 | return 0; | ||
1523 | } | ||
1524 | |||
1525 | static int da732x_remove(struct snd_soc_codec *codec) | ||
1526 | { | ||
1527 | |||
1528 | da732x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1529 | |||
1530 | return 0; | ||
1531 | } | ||
1532 | |||
1533 | static struct snd_soc_codec_driver soc_codec_dev_da732x = { | 1510 | static struct snd_soc_codec_driver soc_codec_dev_da732x = { |
1534 | .probe = da732x_probe, | ||
1535 | .remove = da732x_remove, | ||
1536 | .set_bias_level = da732x_set_bias_level, | 1511 | .set_bias_level = da732x_set_bias_level, |
1537 | .controls = da732x_snd_controls, | 1512 | .controls = da732x_snd_controls, |
1538 | .num_controls = ARRAY_SIZE(da732x_snd_controls), | 1513 | .num_controls = ARRAY_SIZE(da732x_snd_controls), |
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index 1dceafeec415..f586cbd30b77 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h | |||
@@ -11,7 +11,7 @@ | |||
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifndef __DA732X_H_ | 13 | #ifndef __DA732X_H_ |
14 | #define __DA732X_H | 14 | #define __DA732X_H_ |
15 | 15 | ||
16 | #include <sound/soc.h> | 16 | #include <sound/soc.h> |
17 | 17 | ||
diff --git a/sound/soc/codecs/es8328-i2c.c b/sound/soc/codecs/es8328-i2c.c new file mode 100644 index 000000000000..aae410d122ee --- /dev/null +++ b/sound/soc/codecs/es8328-i2c.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * es8328-i2c.c -- ES8328 ALSA SoC I2C Audio driver | ||
3 | * | ||
4 | * Copyright 2014 Sutajio Ko-Usagi PTE LTD | ||
5 | * | ||
6 | * Author: Sean Cross <xobs@kosagi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/regmap.h> | ||
16 | |||
17 | #include <sound/soc.h> | ||
18 | |||
19 | #include "es8328.h" | ||
20 | |||
21 | static const struct i2c_device_id es8328_id[] = { | ||
22 | { "everest,es8328", 0 }, | ||
23 | { } | ||
24 | }; | ||
25 | MODULE_DEVICE_TABLE(i2c, es8328_id); | ||
26 | |||
27 | static const struct of_device_id es8328_of_match[] = { | ||
28 | { .compatible = "everest,es8328", }, | ||
29 | { } | ||
30 | }; | ||
31 | MODULE_DEVICE_TABLE(of, es8328_of_match); | ||
32 | |||
33 | static int es8328_i2c_probe(struct i2c_client *i2c, | ||
34 | const struct i2c_device_id *id) | ||
35 | { | ||
36 | return es8328_probe(&i2c->dev, | ||
37 | devm_regmap_init_i2c(i2c, &es8328_regmap_config)); | ||
38 | } | ||
39 | |||
40 | static int es8328_i2c_remove(struct i2c_client *i2c) | ||
41 | { | ||
42 | snd_soc_unregister_codec(&i2c->dev); | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static struct i2c_driver es8328_i2c_driver = { | ||
47 | .driver = { | ||
48 | .name = "es8328", | ||
49 | .of_match_table = es8328_of_match, | ||
50 | }, | ||
51 | .probe = es8328_i2c_probe, | ||
52 | .remove = es8328_i2c_remove, | ||
53 | .id_table = es8328_id, | ||
54 | }; | ||
55 | |||
56 | module_i2c_driver(es8328_i2c_driver); | ||
57 | |||
58 | MODULE_DESCRIPTION("ASoC ES8328 audio CODEC I2C driver"); | ||
59 | MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); | ||
60 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/es8328-spi.c b/sound/soc/codecs/es8328-spi.c new file mode 100644 index 000000000000..8fbd935e1c76 --- /dev/null +++ b/sound/soc/codecs/es8328-spi.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * es8328.c -- ES8328 ALSA SoC SPI Audio driver | ||
3 | * | ||
4 | * Copyright 2014 Sutajio Ko-Usagi PTE LTD | ||
5 | * | ||
6 | * Author: Sean Cross <xobs@kosagi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/regmap.h> | ||
15 | #include <linux/spi/spi.h> | ||
16 | #include <sound/soc.h> | ||
17 | #include "es8328.h" | ||
18 | |||
19 | static const struct of_device_id es8328_of_match[] = { | ||
20 | { .compatible = "everest,es8328", }, | ||
21 | { } | ||
22 | }; | ||
23 | MODULE_DEVICE_TABLE(of, es8328_of_match); | ||
24 | |||
25 | static int es8328_spi_probe(struct spi_device *spi) | ||
26 | { | ||
27 | return es8328_probe(&spi->dev, | ||
28 | devm_regmap_init_spi(spi, &es8328_regmap_config)); | ||
29 | } | ||
30 | |||
31 | static int es8328_spi_remove(struct spi_device *spi) | ||
32 | { | ||
33 | snd_soc_unregister_codec(&spi->dev); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static struct spi_driver es8328_spi_driver = { | ||
38 | .driver = { | ||
39 | .name = "es8328", | ||
40 | .of_match_table = es8328_of_match, | ||
41 | }, | ||
42 | .probe = es8328_spi_probe, | ||
43 | .remove = es8328_spi_remove, | ||
44 | }; | ||
45 | |||
46 | module_spi_driver(es8328_spi_driver); | ||
47 | MODULE_DESCRIPTION("ASoC ES8328 audio CODEC SPI driver"); | ||
48 | MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); | ||
49 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/es8328.c b/sound/soc/codecs/es8328.c new file mode 100644 index 000000000000..f27325155ace --- /dev/null +++ b/sound/soc/codecs/es8328.c | |||
@@ -0,0 +1,756 @@ | |||
1 | /* | ||
2 | * es8328.c -- ES8328 ALSA SoC Audio driver | ||
3 | * | ||
4 | * Copyright 2014 Sutajio Ko-Usagi PTE LTD | ||
5 | * | ||
6 | * Author: Sean Cross <xobs@kosagi.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/delay.h> | ||
15 | #include <linux/of_device.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/pm.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/regulator/consumer.h> | ||
21 | #include <sound/core.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/pcm.h> | ||
24 | #include <sound/pcm_params.h> | ||
25 | #include <sound/soc.h> | ||
26 | #include <sound/tlv.h> | ||
27 | #include "es8328.h" | ||
28 | |||
29 | #define ES8328_SYSCLK_RATE_1X 11289600 | ||
30 | #define ES8328_SYSCLK_RATE_2X 22579200 | ||
31 | |||
32 | /* Run the codec at 22.5792 or 11.2896 MHz to support these rates */ | ||
33 | static struct { | ||
34 | int rate; | ||
35 | u8 ratio; | ||
36 | } mclk_ratios[] = { | ||
37 | { 8000, 9 }, | ||
38 | {11025, 7 }, | ||
39 | {22050, 4 }, | ||
40 | {44100, 2 }, | ||
41 | }; | ||
42 | |||
43 | /* regulator supplies for sgtl5000, VDDD is an optional external supply */ | ||
44 | enum sgtl5000_regulator_supplies { | ||
45 | DVDD, | ||
46 | AVDD, | ||
47 | PVDD, | ||
48 | HPVDD, | ||
49 | ES8328_SUPPLY_NUM | ||
50 | }; | ||
51 | |||
52 | /* vddd is optional supply */ | ||
53 | static const char * const supply_names[ES8328_SUPPLY_NUM] = { | ||
54 | "DVDD", | ||
55 | "AVDD", | ||
56 | "PVDD", | ||
57 | "HPVDD", | ||
58 | }; | ||
59 | |||
60 | #define ES8328_RATES (SNDRV_PCM_RATE_44100 | \ | ||
61 | SNDRV_PCM_RATE_22050 | \ | ||
62 | SNDRV_PCM_RATE_11025) | ||
63 | #define ES8328_FORMATS (SNDRV_PCM_FMTBIT_S16_LE) | ||
64 | |||
65 | struct es8328_priv { | ||
66 | struct regmap *regmap; | ||
67 | struct clk *clk; | ||
68 | int playback_fs; | ||
69 | bool deemph; | ||
70 | struct regulator_bulk_data supplies[ES8328_SUPPLY_NUM]; | ||
71 | }; | ||
72 | |||
73 | /* | ||
74 | * ES8328 Controls | ||
75 | */ | ||
76 | |||
77 | static const char * const adcpol_txt[] = {"Normal", "L Invert", "R Invert", | ||
78 | "L + R Invert"}; | ||
79 | static SOC_ENUM_SINGLE_DECL(adcpol, | ||
80 | ES8328_ADCCONTROL6, 6, adcpol_txt); | ||
81 | |||
82 | static const DECLARE_TLV_DB_SCALE(play_tlv, -3000, 100, 0); | ||
83 | static const DECLARE_TLV_DB_SCALE(dac_adc_tlv, -9600, 50, 0); | ||
84 | static const DECLARE_TLV_DB_SCALE(pga_tlv, 0, 300, 0); | ||
85 | static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | ||
86 | static const DECLARE_TLV_DB_SCALE(mic_tlv, 0, 300, 0); | ||
87 | |||
88 | static const int deemph_settings[] = { 0, 32000, 44100, 48000 }; | ||
89 | |||
90 | static int es8328_set_deemph(struct snd_soc_codec *codec) | ||
91 | { | ||
92 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
93 | int val, i, best; | ||
94 | |||
95 | /* | ||
96 | * If we're using deemphasis select the nearest available sample | ||
97 | * rate. | ||
98 | */ | ||
99 | if (es8328->deemph) { | ||
100 | best = 1; | ||
101 | for (i = 2; i < ARRAY_SIZE(deemph_settings); i++) { | ||
102 | if (abs(deemph_settings[i] - es8328->playback_fs) < | ||
103 | abs(deemph_settings[best] - es8328->playback_fs)) | ||
104 | best = i; | ||
105 | } | ||
106 | |||
107 | val = best << 1; | ||
108 | } else { | ||
109 | val = 0; | ||
110 | } | ||
111 | |||
112 | dev_dbg(codec->dev, "Set deemphasis %d\n", val); | ||
113 | |||
114 | return snd_soc_update_bits(codec, ES8328_DACCONTROL6, 0x6, val); | ||
115 | } | ||
116 | |||
117 | static int es8328_get_deemph(struct snd_kcontrol *kcontrol, | ||
118 | struct snd_ctl_elem_value *ucontrol) | ||
119 | { | ||
120 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
121 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
122 | |||
123 | ucontrol->value.enumerated.item[0] = es8328->deemph; | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | static int es8328_put_deemph(struct snd_kcontrol *kcontrol, | ||
128 | struct snd_ctl_elem_value *ucontrol) | ||
129 | { | ||
130 | struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); | ||
131 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
132 | int deemph = ucontrol->value.enumerated.item[0]; | ||
133 | int ret; | ||
134 | |||
135 | if (deemph > 1) | ||
136 | return -EINVAL; | ||
137 | |||
138 | ret = es8328_set_deemph(codec); | ||
139 | if (ret < 0) | ||
140 | return ret; | ||
141 | |||
142 | es8328->deemph = deemph; | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | |||
148 | |||
149 | static const struct snd_kcontrol_new es8328_snd_controls[] = { | ||
150 | SOC_DOUBLE_R_TLV("Capture Digital Volume", | ||
151 | ES8328_ADCCONTROL8, ES8328_ADCCONTROL9, | ||
152 | 0, 0xc0, 1, dac_adc_tlv), | ||
153 | SOC_SINGLE("Capture ZC Switch", ES8328_ADCCONTROL7, 6, 1, 0), | ||
154 | |||
155 | SOC_SINGLE_BOOL_EXT("DAC Deemphasis Switch", 0, | ||
156 | es8328_get_deemph, es8328_put_deemph), | ||
157 | |||
158 | SOC_ENUM("Capture Polarity", adcpol), | ||
159 | |||
160 | SOC_SINGLE_TLV("Left Mixer Left Bypass Volume", | ||
161 | ES8328_DACCONTROL17, 3, 7, 1, bypass_tlv), | ||
162 | SOC_SINGLE_TLV("Left Mixer Right Bypass Volume", | ||
163 | ES8328_DACCONTROL19, 3, 7, 1, bypass_tlv), | ||
164 | SOC_SINGLE_TLV("Right Mixer Left Bypass Volume", | ||
165 | ES8328_DACCONTROL18, 3, 7, 1, bypass_tlv), | ||
166 | SOC_SINGLE_TLV("Right Mixer Right Bypass Volume", | ||
167 | ES8328_DACCONTROL20, 3, 7, 1, bypass_tlv), | ||
168 | |||
169 | SOC_DOUBLE_R_TLV("PCM Volume", | ||
170 | ES8328_LDACVOL, ES8328_RDACVOL, | ||
171 | 0, ES8328_DACVOL_MAX, 1, dac_adc_tlv), | ||
172 | |||
173 | SOC_DOUBLE_R_TLV("Output 1 Playback Volume", | ||
174 | ES8328_LOUT1VOL, ES8328_ROUT1VOL, | ||
175 | 0, ES8328_OUT1VOL_MAX, 0, play_tlv), | ||
176 | |||
177 | SOC_DOUBLE_R_TLV("Output 2 Playback Volume", | ||
178 | ES8328_LOUT2VOL, ES8328_ROUT2VOL, | ||
179 | 0, ES8328_OUT2VOL_MAX, 0, play_tlv), | ||
180 | |||
181 | SOC_DOUBLE_TLV("Mic PGA Volume", ES8328_ADCCONTROL1, | ||
182 | 4, 0, 8, 0, mic_tlv), | ||
183 | }; | ||
184 | |||
185 | /* | ||
186 | * DAPM Controls | ||
187 | */ | ||
188 | |||
189 | static const char * const es8328_line_texts[] = { | ||
190 | "Line 1", "Line 2", "PGA", "Differential"}; | ||
191 | |||
192 | static const struct soc_enum es8328_lline_enum = | ||
193 | SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 3, | ||
194 | ARRAY_SIZE(es8328_line_texts), | ||
195 | es8328_line_texts); | ||
196 | static const struct snd_kcontrol_new es8328_left_line_controls = | ||
197 | SOC_DAPM_ENUM("Route", es8328_lline_enum); | ||
198 | |||
199 | static const struct soc_enum es8328_rline_enum = | ||
200 | SOC_ENUM_SINGLE(ES8328_DACCONTROL16, 0, | ||
201 | ARRAY_SIZE(es8328_line_texts), | ||
202 | es8328_line_texts); | ||
203 | static const struct snd_kcontrol_new es8328_right_line_controls = | ||
204 | SOC_DAPM_ENUM("Route", es8328_lline_enum); | ||
205 | |||
206 | /* Left Mixer */ | ||
207 | static const struct snd_kcontrol_new es8328_left_mixer_controls[] = { | ||
208 | SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL17, 8, 1, 0), | ||
209 | SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL17, 7, 1, 0), | ||
210 | SOC_DAPM_SINGLE("Right Playback Switch", ES8328_DACCONTROL18, 8, 1, 0), | ||
211 | SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL18, 7, 1, 0), | ||
212 | }; | ||
213 | |||
214 | /* Right Mixer */ | ||
215 | static const struct snd_kcontrol_new es8328_right_mixer_controls[] = { | ||
216 | SOC_DAPM_SINGLE("Left Playback Switch", ES8328_DACCONTROL19, 8, 1, 0), | ||
217 | SOC_DAPM_SINGLE("Left Bypass Switch", ES8328_DACCONTROL19, 7, 1, 0), | ||
218 | SOC_DAPM_SINGLE("Playback Switch", ES8328_DACCONTROL20, 8, 1, 0), | ||
219 | SOC_DAPM_SINGLE("Right Bypass Switch", ES8328_DACCONTROL20, 7, 1, 0), | ||
220 | }; | ||
221 | |||
222 | static const char * const es8328_pga_sel[] = { | ||
223 | "Line 1", "Line 2", "Line 3", "Differential"}; | ||
224 | |||
225 | /* Left PGA Mux */ | ||
226 | static const struct soc_enum es8328_lpga_enum = | ||
227 | SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 6, | ||
228 | ARRAY_SIZE(es8328_pga_sel), | ||
229 | es8328_pga_sel); | ||
230 | static const struct snd_kcontrol_new es8328_left_pga_controls = | ||
231 | SOC_DAPM_ENUM("Route", es8328_lpga_enum); | ||
232 | |||
233 | /* Right PGA Mux */ | ||
234 | static const struct soc_enum es8328_rpga_enum = | ||
235 | SOC_ENUM_SINGLE(ES8328_ADCCONTROL2, 4, | ||
236 | ARRAY_SIZE(es8328_pga_sel), | ||
237 | es8328_pga_sel); | ||
238 | static const struct snd_kcontrol_new es8328_right_pga_controls = | ||
239 | SOC_DAPM_ENUM("Route", es8328_rpga_enum); | ||
240 | |||
241 | /* Differential Mux */ | ||
242 | static const char * const es8328_diff_sel[] = {"Line 1", "Line 2"}; | ||
243 | static SOC_ENUM_SINGLE_DECL(diffmux, | ||
244 | ES8328_ADCCONTROL3, 7, es8328_diff_sel); | ||
245 | static const struct snd_kcontrol_new es8328_diffmux_controls = | ||
246 | SOC_DAPM_ENUM("Route", diffmux); | ||
247 | |||
248 | /* Mono ADC Mux */ | ||
249 | static const char * const es8328_mono_mux[] = {"Stereo", "Mono (Left)", | ||
250 | "Mono (Right)", "Digital Mono"}; | ||
251 | static SOC_ENUM_SINGLE_DECL(monomux, | ||
252 | ES8328_ADCCONTROL3, 3, es8328_mono_mux); | ||
253 | static const struct snd_kcontrol_new es8328_monomux_controls = | ||
254 | SOC_DAPM_ENUM("Route", monomux); | ||
255 | |||
256 | static const struct snd_soc_dapm_widget es8328_dapm_widgets[] = { | ||
257 | SND_SOC_DAPM_MUX("Differential Mux", SND_SOC_NOPM, 0, 0, | ||
258 | &es8328_diffmux_controls), | ||
259 | SND_SOC_DAPM_MUX("Left ADC Mux", SND_SOC_NOPM, 0, 0, | ||
260 | &es8328_monomux_controls), | ||
261 | SND_SOC_DAPM_MUX("Right ADC Mux", SND_SOC_NOPM, 0, 0, | ||
262 | &es8328_monomux_controls), | ||
263 | |||
264 | SND_SOC_DAPM_MUX("Left PGA Mux", ES8328_ADCPOWER, | ||
265 | ES8328_ADCPOWER_AINL_OFF, 1, | ||
266 | &es8328_left_pga_controls), | ||
267 | SND_SOC_DAPM_MUX("Right PGA Mux", ES8328_ADCPOWER, | ||
268 | ES8328_ADCPOWER_AINR_OFF, 1, | ||
269 | &es8328_right_pga_controls), | ||
270 | |||
271 | SND_SOC_DAPM_MUX("Left Line Mux", SND_SOC_NOPM, 0, 0, | ||
272 | &es8328_left_line_controls), | ||
273 | SND_SOC_DAPM_MUX("Right Line Mux", SND_SOC_NOPM, 0, 0, | ||
274 | &es8328_right_line_controls), | ||
275 | |||
276 | SND_SOC_DAPM_ADC("Right ADC", "Right Capture", ES8328_ADCPOWER, | ||
277 | ES8328_ADCPOWER_ADCR_OFF, 1), | ||
278 | SND_SOC_DAPM_ADC("Left ADC", "Left Capture", ES8328_ADCPOWER, | ||
279 | ES8328_ADCPOWER_ADCL_OFF, 1), | ||
280 | |||
281 | SND_SOC_DAPM_SUPPLY("Mic Bias", ES8328_ADCPOWER, | ||
282 | ES8328_ADCPOWER_MIC_BIAS_OFF, 1, NULL, 0), | ||
283 | SND_SOC_DAPM_SUPPLY("Mic Bias Gen", ES8328_ADCPOWER, | ||
284 | ES8328_ADCPOWER_ADC_BIAS_GEN_OFF, 1, NULL, 0), | ||
285 | |||
286 | SND_SOC_DAPM_SUPPLY("DAC STM", ES8328_CHIPPOWER, | ||
287 | ES8328_CHIPPOWER_DACSTM_RESET, 1, NULL, 0), | ||
288 | SND_SOC_DAPM_SUPPLY("ADC STM", ES8328_CHIPPOWER, | ||
289 | ES8328_CHIPPOWER_ADCSTM_RESET, 1, NULL, 0), | ||
290 | |||
291 | SND_SOC_DAPM_SUPPLY("DAC DIG", ES8328_CHIPPOWER, | ||
292 | ES8328_CHIPPOWER_DACDIG_OFF, 1, NULL, 0), | ||
293 | SND_SOC_DAPM_SUPPLY("ADC DIG", ES8328_CHIPPOWER, | ||
294 | ES8328_CHIPPOWER_ADCDIG_OFF, 1, NULL, 0), | ||
295 | |||
296 | SND_SOC_DAPM_SUPPLY("DAC DLL", ES8328_CHIPPOWER, | ||
297 | ES8328_CHIPPOWER_DACDLL_OFF, 1, NULL, 0), | ||
298 | SND_SOC_DAPM_SUPPLY("ADC DLL", ES8328_CHIPPOWER, | ||
299 | ES8328_CHIPPOWER_ADCDLL_OFF, 1, NULL, 0), | ||
300 | |||
301 | SND_SOC_DAPM_SUPPLY("ADC Vref", ES8328_CHIPPOWER, | ||
302 | ES8328_CHIPPOWER_ADCVREF_OFF, 1, NULL, 0), | ||
303 | SND_SOC_DAPM_SUPPLY("DAC Vref", ES8328_CHIPPOWER, | ||
304 | ES8328_CHIPPOWER_DACVREF_OFF, 1, NULL, 0), | ||
305 | |||
306 | SND_SOC_DAPM_DAC("Right DAC", "Right Playback", ES8328_DACPOWER, | ||
307 | ES8328_DACPOWER_RDAC_OFF, 1), | ||
308 | SND_SOC_DAPM_DAC("Left DAC", "Left Playback", ES8328_DACPOWER, | ||
309 | ES8328_DACPOWER_LDAC_OFF, 1), | ||
310 | |||
311 | SND_SOC_DAPM_MIXER("Left Mixer", SND_SOC_NOPM, 0, 0, | ||
312 | &es8328_left_mixer_controls[0], | ||
313 | ARRAY_SIZE(es8328_left_mixer_controls)), | ||
314 | SND_SOC_DAPM_MIXER("Right Mixer", SND_SOC_NOPM, 0, 0, | ||
315 | &es8328_right_mixer_controls[0], | ||
316 | ARRAY_SIZE(es8328_right_mixer_controls)), | ||
317 | |||
318 | SND_SOC_DAPM_PGA("Right Out 2", ES8328_DACPOWER, | ||
319 | ES8328_DACPOWER_ROUT2_ON, 0, NULL, 0), | ||
320 | SND_SOC_DAPM_PGA("Left Out 2", ES8328_DACPOWER, | ||
321 | ES8328_DACPOWER_LOUT2_ON, 0, NULL, 0), | ||
322 | SND_SOC_DAPM_PGA("Right Out 1", ES8328_DACPOWER, | ||
323 | ES8328_DACPOWER_ROUT1_ON, 0, NULL, 0), | ||
324 | SND_SOC_DAPM_PGA("Left Out 1", ES8328_DACPOWER, | ||
325 | ES8328_DACPOWER_LOUT1_ON, 0, NULL, 0), | ||
326 | |||
327 | SND_SOC_DAPM_OUTPUT("LOUT1"), | ||
328 | SND_SOC_DAPM_OUTPUT("ROUT1"), | ||
329 | SND_SOC_DAPM_OUTPUT("LOUT2"), | ||
330 | SND_SOC_DAPM_OUTPUT("ROUT2"), | ||
331 | |||
332 | SND_SOC_DAPM_INPUT("LINPUT1"), | ||
333 | SND_SOC_DAPM_INPUT("LINPUT2"), | ||
334 | SND_SOC_DAPM_INPUT("RINPUT1"), | ||
335 | SND_SOC_DAPM_INPUT("RINPUT2"), | ||
336 | }; | ||
337 | |||
338 | static const struct snd_soc_dapm_route es8328_dapm_routes[] = { | ||
339 | |||
340 | { "Left Line Mux", "Line 1", "LINPUT1" }, | ||
341 | { "Left Line Mux", "Line 2", "LINPUT2" }, | ||
342 | { "Left Line Mux", "PGA", "Left PGA Mux" }, | ||
343 | { "Left Line Mux", "Differential", "Differential Mux" }, | ||
344 | |||
345 | { "Right Line Mux", "Line 1", "RINPUT1" }, | ||
346 | { "Right Line Mux", "Line 2", "RINPUT2" }, | ||
347 | { "Right Line Mux", "PGA", "Right PGA Mux" }, | ||
348 | { "Right Line Mux", "Differential", "Differential Mux" }, | ||
349 | |||
350 | { "Left PGA Mux", "Line 1", "LINPUT1" }, | ||
351 | { "Left PGA Mux", "Line 2", "LINPUT2" }, | ||
352 | { "Left PGA Mux", "Differential", "Differential Mux" }, | ||
353 | |||
354 | { "Right PGA Mux", "Line 1", "RINPUT1" }, | ||
355 | { "Right PGA Mux", "Line 2", "RINPUT2" }, | ||
356 | { "Right PGA Mux", "Differential", "Differential Mux" }, | ||
357 | |||
358 | { "Differential Mux", "Line 1", "LINPUT1" }, | ||
359 | { "Differential Mux", "Line 1", "RINPUT1" }, | ||
360 | { "Differential Mux", "Line 2", "LINPUT2" }, | ||
361 | { "Differential Mux", "Line 2", "RINPUT2" }, | ||
362 | |||
363 | { "Left ADC Mux", "Stereo", "Left PGA Mux" }, | ||
364 | { "Left ADC Mux", "Mono (Left)", "Left PGA Mux" }, | ||
365 | { "Left ADC Mux", "Digital Mono", "Left PGA Mux" }, | ||
366 | |||
367 | { "Right ADC Mux", "Stereo", "Right PGA Mux" }, | ||
368 | { "Right ADC Mux", "Mono (Right)", "Right PGA Mux" }, | ||
369 | { "Right ADC Mux", "Digital Mono", "Right PGA Mux" }, | ||
370 | |||
371 | { "Left ADC", NULL, "Left ADC Mux" }, | ||
372 | { "Right ADC", NULL, "Right ADC Mux" }, | ||
373 | |||
374 | { "ADC DIG", NULL, "ADC STM" }, | ||
375 | { "ADC DIG", NULL, "ADC Vref" }, | ||
376 | { "ADC DIG", NULL, "ADC DLL" }, | ||
377 | |||
378 | { "Left ADC", NULL, "ADC DIG" }, | ||
379 | { "Right ADC", NULL, "ADC DIG" }, | ||
380 | |||
381 | { "Mic Bias", NULL, "Mic Bias Gen" }, | ||
382 | |||
383 | { "Left Line Mux", "Line 1", "LINPUT1" }, | ||
384 | { "Left Line Mux", "Line 2", "LINPUT2" }, | ||
385 | { "Left Line Mux", "PGA", "Left PGA Mux" }, | ||
386 | { "Left Line Mux", "Differential", "Differential Mux" }, | ||
387 | |||
388 | { "Right Line Mux", "Line 1", "RINPUT1" }, | ||
389 | { "Right Line Mux", "Line 2", "RINPUT2" }, | ||
390 | { "Right Line Mux", "PGA", "Right PGA Mux" }, | ||
391 | { "Right Line Mux", "Differential", "Differential Mux" }, | ||
392 | |||
393 | { "Left Out 1", NULL, "Left DAC" }, | ||
394 | { "Right Out 1", NULL, "Right DAC" }, | ||
395 | { "Left Out 2", NULL, "Left DAC" }, | ||
396 | { "Right Out 2", NULL, "Right DAC" }, | ||
397 | |||
398 | { "Left Mixer", "Playback Switch", "Left DAC" }, | ||
399 | { "Left Mixer", "Left Bypass Switch", "Left Line Mux" }, | ||
400 | { "Left Mixer", "Right Playback Switch", "Right DAC" }, | ||
401 | { "Left Mixer", "Right Bypass Switch", "Right Line Mux" }, | ||
402 | |||
403 | { "Right Mixer", "Left Playback Switch", "Left DAC" }, | ||
404 | { "Right Mixer", "Left Bypass Switch", "Left Line Mux" }, | ||
405 | { "Right Mixer", "Playback Switch", "Right DAC" }, | ||
406 | { "Right Mixer", "Right Bypass Switch", "Right Line Mux" }, | ||
407 | |||
408 | { "DAC DIG", NULL, "DAC STM" }, | ||
409 | { "DAC DIG", NULL, "DAC Vref" }, | ||
410 | { "DAC DIG", NULL, "DAC DLL" }, | ||
411 | |||
412 | { "Left DAC", NULL, "DAC DIG" }, | ||
413 | { "Right DAC", NULL, "DAC DIG" }, | ||
414 | |||
415 | { "Left Out 1", NULL, "Left Mixer" }, | ||
416 | { "LOUT1", NULL, "Left Out 1" }, | ||
417 | { "Right Out 1", NULL, "Right Mixer" }, | ||
418 | { "ROUT1", NULL, "Right Out 1" }, | ||
419 | |||
420 | { "Left Out 2", NULL, "Left Mixer" }, | ||
421 | { "LOUT2", NULL, "Left Out 2" }, | ||
422 | { "Right Out 2", NULL, "Right Mixer" }, | ||
423 | { "ROUT2", NULL, "Right Out 2" }, | ||
424 | }; | ||
425 | |||
426 | static int es8328_mute(struct snd_soc_dai *dai, int mute) | ||
427 | { | ||
428 | return snd_soc_update_bits(dai->codec, ES8328_DACCONTROL3, | ||
429 | ES8328_DACCONTROL3_DACMUTE, | ||
430 | mute ? ES8328_DACCONTROL3_DACMUTE : 0); | ||
431 | } | ||
432 | |||
433 | static int es8328_hw_params(struct snd_pcm_substream *substream, | ||
434 | struct snd_pcm_hw_params *params, | ||
435 | struct snd_soc_dai *dai) | ||
436 | { | ||
437 | struct snd_soc_codec *codec = dai->codec; | ||
438 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
439 | int clk_rate; | ||
440 | int i; | ||
441 | int reg; | ||
442 | u8 ratio; | ||
443 | |||
444 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
445 | reg = ES8328_DACCONTROL2; | ||
446 | else | ||
447 | reg = ES8328_ADCCONTROL5; | ||
448 | |||
449 | clk_rate = clk_get_rate(es8328->clk); | ||
450 | |||
451 | if ((clk_rate != ES8328_SYSCLK_RATE_1X) && | ||
452 | (clk_rate != ES8328_SYSCLK_RATE_2X)) { | ||
453 | dev_err(codec->dev, | ||
454 | "%s: clock is running at %d Hz, not %d or %d Hz\n", | ||
455 | __func__, clk_rate, | ||
456 | ES8328_SYSCLK_RATE_1X, ES8328_SYSCLK_RATE_2X); | ||
457 | return -EINVAL; | ||
458 | } | ||
459 | |||
460 | /* find master mode MCLK to sampling frequency ratio */ | ||
461 | ratio = mclk_ratios[0].rate; | ||
462 | for (i = 1; i < ARRAY_SIZE(mclk_ratios); i++) | ||
463 | if (params_rate(params) <= mclk_ratios[i].rate) | ||
464 | ratio = mclk_ratios[i].ratio; | ||
465 | |||
466 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
467 | es8328->playback_fs = params_rate(params); | ||
468 | es8328_set_deemph(codec); | ||
469 | } | ||
470 | |||
471 | return snd_soc_update_bits(codec, reg, ES8328_RATEMASK, ratio); | ||
472 | } | ||
473 | |||
474 | static int es8328_set_dai_fmt(struct snd_soc_dai *codec_dai, | ||
475 | unsigned int fmt) | ||
476 | { | ||
477 | struct snd_soc_codec *codec = codec_dai->codec; | ||
478 | struct es8328_priv *es8328 = snd_soc_codec_get_drvdata(codec); | ||
479 | int clk_rate; | ||
480 | u8 mode = ES8328_DACCONTROL1_DACWL_16; | ||
481 | |||
482 | /* set master/slave audio interface */ | ||
483 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBM_CFM) | ||
484 | return -EINVAL; | ||
485 | |||
486 | /* interface format */ | ||
487 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
488 | case SND_SOC_DAIFMT_I2S: | ||
489 | mode |= ES8328_DACCONTROL1_DACFORMAT_I2S; | ||
490 | break; | ||
491 | case SND_SOC_DAIFMT_RIGHT_J: | ||
492 | mode |= ES8328_DACCONTROL1_DACFORMAT_RJUST; | ||
493 | break; | ||
494 | case SND_SOC_DAIFMT_LEFT_J: | ||
495 | mode |= ES8328_DACCONTROL1_DACFORMAT_LJUST; | ||
496 | break; | ||
497 | default: | ||
498 | return -EINVAL; | ||
499 | } | ||
500 | |||
501 | /* clock inversion */ | ||
502 | if ((fmt & SND_SOC_DAIFMT_INV_MASK) != SND_SOC_DAIFMT_NB_NF) | ||
503 | return -EINVAL; | ||
504 | |||
505 | snd_soc_write(codec, ES8328_DACCONTROL1, mode); | ||
506 | snd_soc_write(codec, ES8328_ADCCONTROL4, mode); | ||
507 | |||
508 | /* Master serial port mode, with BCLK generated automatically */ | ||
509 | clk_rate = clk_get_rate(es8328->clk); | ||
510 | if (clk_rate == ES8328_SYSCLK_RATE_1X) | ||
511 | snd_soc_write(codec, ES8328_MASTERMODE, | ||
512 | ES8328_MASTERMODE_MSC); | ||
513 | else | ||
514 | snd_soc_write(codec, ES8328_MASTERMODE, | ||
515 | ES8328_MASTERMODE_MCLKDIV2 | | ||
516 | ES8328_MASTERMODE_MSC); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int es8328_set_bias_level(struct snd_soc_codec *codec, | ||
522 | enum snd_soc_bias_level level) | ||
523 | { | ||
524 | switch (level) { | ||
525 | case SND_SOC_BIAS_ON: | ||
526 | break; | ||
527 | |||
528 | case SND_SOC_BIAS_PREPARE: | ||
529 | /* VREF, VMID=2x50k, digital enabled */ | ||
530 | snd_soc_write(codec, ES8328_CHIPPOWER, 0); | ||
531 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
532 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
533 | ES8328_CONTROL1_ENREF, | ||
534 | ES8328_CONTROL1_VMIDSEL_50k | | ||
535 | ES8328_CONTROL1_ENREF); | ||
536 | break; | ||
537 | |||
538 | case SND_SOC_BIAS_STANDBY: | ||
539 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
540 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
541 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
542 | ES8328_CONTROL1_ENREF, | ||
543 | ES8328_CONTROL1_VMIDSEL_5k | | ||
544 | ES8328_CONTROL1_ENREF); | ||
545 | |||
546 | /* Charge caps */ | ||
547 | msleep(100); | ||
548 | } | ||
549 | |||
550 | snd_soc_write(codec, ES8328_CONTROL2, | ||
551 | ES8328_CONTROL2_OVERCURRENT_ON | | ||
552 | ES8328_CONTROL2_THERMAL_SHUTDOWN_ON); | ||
553 | |||
554 | /* VREF, VMID=2*500k, digital stopped */ | ||
555 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
556 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
557 | ES8328_CONTROL1_ENREF, | ||
558 | ES8328_CONTROL1_VMIDSEL_500k | | ||
559 | ES8328_CONTROL1_ENREF); | ||
560 | break; | ||
561 | |||
562 | case SND_SOC_BIAS_OFF: | ||
563 | snd_soc_update_bits(codec, ES8328_CONTROL1, | ||
564 | ES8328_CONTROL1_VMIDSEL_MASK | | ||
565 | ES8328_CONTROL1_ENREF, | ||
566 | 0); | ||
567 | break; | ||
568 | } | ||
569 | codec->dapm.bias_level = level; | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static const struct snd_soc_dai_ops es8328_dai_ops = { | ||
574 | .hw_params = es8328_hw_params, | ||
575 | .digital_mute = es8328_mute, | ||
576 | .set_fmt = es8328_set_dai_fmt, | ||
577 | }; | ||
578 | |||
579 | static struct snd_soc_dai_driver es8328_dai = { | ||
580 | .name = "es8328-hifi-analog", | ||
581 | .playback = { | ||
582 | .stream_name = "Playback", | ||
583 | .channels_min = 2, | ||
584 | .channels_max = 2, | ||
585 | .rates = ES8328_RATES, | ||
586 | .formats = ES8328_FORMATS, | ||
587 | }, | ||
588 | .capture = { | ||
589 | .stream_name = "Capture", | ||
590 | .channels_min = 2, | ||
591 | .channels_max = 2, | ||
592 | .rates = ES8328_RATES, | ||
593 | .formats = ES8328_FORMATS, | ||
594 | }, | ||
595 | .ops = &es8328_dai_ops, | ||
596 | }; | ||
597 | |||
598 | static int es8328_suspend(struct snd_soc_codec *codec) | ||
599 | { | ||
600 | struct es8328_priv *es8328; | ||
601 | int ret; | ||
602 | |||
603 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
604 | |||
605 | clk_disable_unprepare(es8328->clk); | ||
606 | |||
607 | ret = regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), | ||
608 | es8328->supplies); | ||
609 | if (ret) { | ||
610 | dev_err(codec->dev, "unable to disable regulators\n"); | ||
611 | return ret; | ||
612 | } | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int es8328_resume(struct snd_soc_codec *codec) | ||
617 | { | ||
618 | struct regmap *regmap = dev_get_regmap(codec->dev, NULL); | ||
619 | struct es8328_priv *es8328; | ||
620 | int ret; | ||
621 | |||
622 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
623 | |||
624 | ret = clk_prepare_enable(es8328->clk); | ||
625 | if (ret) { | ||
626 | dev_err(codec->dev, "unable to enable clock\n"); | ||
627 | return ret; | ||
628 | } | ||
629 | |||
630 | ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), | ||
631 | es8328->supplies); | ||
632 | if (ret) { | ||
633 | dev_err(codec->dev, "unable to enable regulators\n"); | ||
634 | return ret; | ||
635 | } | ||
636 | |||
637 | regcache_mark_dirty(regmap); | ||
638 | ret = regcache_sync(regmap); | ||
639 | if (ret) { | ||
640 | dev_err(codec->dev, "unable to sync regcache\n"); | ||
641 | return ret; | ||
642 | } | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int es8328_codec_probe(struct snd_soc_codec *codec) | ||
648 | { | ||
649 | struct es8328_priv *es8328; | ||
650 | int ret; | ||
651 | |||
652 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
653 | |||
654 | ret = regulator_bulk_enable(ARRAY_SIZE(es8328->supplies), | ||
655 | es8328->supplies); | ||
656 | if (ret) { | ||
657 | dev_err(codec->dev, "unable to enable regulators\n"); | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | /* Setup clocks */ | ||
662 | es8328->clk = devm_clk_get(codec->dev, NULL); | ||
663 | if (IS_ERR(es8328->clk)) { | ||
664 | dev_err(codec->dev, "codec clock missing or invalid\n"); | ||
665 | ret = PTR_ERR(es8328->clk); | ||
666 | goto clk_fail; | ||
667 | } | ||
668 | |||
669 | ret = clk_prepare_enable(es8328->clk); | ||
670 | if (ret) { | ||
671 | dev_err(codec->dev, "unable to prepare codec clk\n"); | ||
672 | goto clk_fail; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | |||
677 | clk_fail: | ||
678 | regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), | ||
679 | es8328->supplies); | ||
680 | return ret; | ||
681 | } | ||
682 | |||
683 | static int es8328_remove(struct snd_soc_codec *codec) | ||
684 | { | ||
685 | struct es8328_priv *es8328; | ||
686 | |||
687 | es8328 = snd_soc_codec_get_drvdata(codec); | ||
688 | |||
689 | if (es8328->clk) | ||
690 | clk_disable_unprepare(es8328->clk); | ||
691 | |||
692 | regulator_bulk_disable(ARRAY_SIZE(es8328->supplies), | ||
693 | es8328->supplies); | ||
694 | |||
695 | return 0; | ||
696 | } | ||
697 | |||
698 | const struct regmap_config es8328_regmap_config = { | ||
699 | .reg_bits = 8, | ||
700 | .val_bits = 8, | ||
701 | .max_register = ES8328_REG_MAX, | ||
702 | .cache_type = REGCACHE_RBTREE, | ||
703 | }; | ||
704 | EXPORT_SYMBOL_GPL(es8328_regmap_config); | ||
705 | |||
706 | static struct snd_soc_codec_driver es8328_codec_driver = { | ||
707 | .probe = es8328_codec_probe, | ||
708 | .suspend = es8328_suspend, | ||
709 | .resume = es8328_resume, | ||
710 | .remove = es8328_remove, | ||
711 | .set_bias_level = es8328_set_bias_level, | ||
712 | .suspend_bias_off = true, | ||
713 | |||
714 | .controls = es8328_snd_controls, | ||
715 | .num_controls = ARRAY_SIZE(es8328_snd_controls), | ||
716 | .dapm_widgets = es8328_dapm_widgets, | ||
717 | .num_dapm_widgets = ARRAY_SIZE(es8328_dapm_widgets), | ||
718 | .dapm_routes = es8328_dapm_routes, | ||
719 | .num_dapm_routes = ARRAY_SIZE(es8328_dapm_routes), | ||
720 | }; | ||
721 | |||
722 | int es8328_probe(struct device *dev, struct regmap *regmap) | ||
723 | { | ||
724 | struct es8328_priv *es8328; | ||
725 | int ret; | ||
726 | int i; | ||
727 | |||
728 | if (IS_ERR(regmap)) | ||
729 | return PTR_ERR(regmap); | ||
730 | |||
731 | es8328 = devm_kzalloc(dev, sizeof(*es8328), GFP_KERNEL); | ||
732 | if (es8328 == NULL) | ||
733 | return -ENOMEM; | ||
734 | |||
735 | es8328->regmap = regmap; | ||
736 | |||
737 | for (i = 0; i < ARRAY_SIZE(es8328->supplies); i++) | ||
738 | es8328->supplies[i].supply = supply_names[i]; | ||
739 | |||
740 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(es8328->supplies), | ||
741 | es8328->supplies); | ||
742 | if (ret) { | ||
743 | dev_err(dev, "unable to get regulators\n"); | ||
744 | return ret; | ||
745 | } | ||
746 | |||
747 | dev_set_drvdata(dev, es8328); | ||
748 | |||
749 | return snd_soc_register_codec(dev, | ||
750 | &es8328_codec_driver, &es8328_dai, 1); | ||
751 | } | ||
752 | EXPORT_SYMBOL_GPL(es8328_probe); | ||
753 | |||
754 | MODULE_DESCRIPTION("ASoC ES8328 driver"); | ||
755 | MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); | ||
756 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/es8328.h b/sound/soc/codecs/es8328.h new file mode 100644 index 000000000000..cb36afe10c0e --- /dev/null +++ b/sound/soc/codecs/es8328.h | |||
@@ -0,0 +1,314 @@ | |||
1 | /* | ||
2 | * es8328.h -- ES8328 ALSA SoC Audio driver | ||
3 | */ | ||
4 | |||
5 | #ifndef _ES8328_H | ||
6 | #define _ES8328_H | ||
7 | |||
8 | #include <linux/regmap.h> | ||
9 | |||
10 | struct device; | ||
11 | |||
12 | extern const struct regmap_config es8328_regmap_config; | ||
13 | int es8328_probe(struct device *dev, struct regmap *regmap); | ||
14 | |||
15 | #define ES8328_DACLVOL 46 | ||
16 | #define ES8328_DACRVOL 47 | ||
17 | #define ES8328_DACCTL 28 | ||
18 | #define ES8328_RATEMASK (0x1f << 0) | ||
19 | |||
20 | #define ES8328_CONTROL1 0x00 | ||
21 | #define ES8328_CONTROL1_VMIDSEL_OFF (0 << 0) | ||
22 | #define ES8328_CONTROL1_VMIDSEL_50k (1 << 0) | ||
23 | #define ES8328_CONTROL1_VMIDSEL_500k (2 << 0) | ||
24 | #define ES8328_CONTROL1_VMIDSEL_5k (3 << 0) | ||
25 | #define ES8328_CONTROL1_VMIDSEL_MASK (7 << 0) | ||
26 | #define ES8328_CONTROL1_ENREF (1 << 2) | ||
27 | #define ES8328_CONTROL1_SEQEN (1 << 3) | ||
28 | #define ES8328_CONTROL1_SAMEFS (1 << 4) | ||
29 | #define ES8328_CONTROL1_DACMCLK_ADC (0 << 5) | ||
30 | #define ES8328_CONTROL1_DACMCLK_DAC (1 << 5) | ||
31 | #define ES8328_CONTROL1_LRCM (1 << 6) | ||
32 | #define ES8328_CONTROL1_SCP_RESET (1 << 7) | ||
33 | |||
34 | #define ES8328_CONTROL2 0x01 | ||
35 | #define ES8328_CONTROL2_VREF_BUF_OFF (1 << 0) | ||
36 | #define ES8328_CONTROL2_VREF_LOWPOWER (1 << 1) | ||
37 | #define ES8328_CONTROL2_IBIASGEN_OFF (1 << 2) | ||
38 | #define ES8328_CONTROL2_ANALOG_OFF (1 << 3) | ||
39 | #define ES8328_CONTROL2_VREF_BUF_LOWPOWER (1 << 4) | ||
40 | #define ES8328_CONTROL2_VCM_MOD_LOWPOWER (1 << 5) | ||
41 | #define ES8328_CONTROL2_OVERCURRENT_ON (1 << 6) | ||
42 | #define ES8328_CONTROL2_THERMAL_SHUTDOWN_ON (1 << 7) | ||
43 | |||
44 | #define ES8328_CHIPPOWER 0x02 | ||
45 | #define ES8328_CHIPPOWER_DACVREF_OFF 0 | ||
46 | #define ES8328_CHIPPOWER_ADCVREF_OFF 1 | ||
47 | #define ES8328_CHIPPOWER_DACDLL_OFF 2 | ||
48 | #define ES8328_CHIPPOWER_ADCDLL_OFF 3 | ||
49 | #define ES8328_CHIPPOWER_DACSTM_RESET 4 | ||
50 | #define ES8328_CHIPPOWER_ADCSTM_RESET 5 | ||
51 | #define ES8328_CHIPPOWER_DACDIG_OFF 6 | ||
52 | #define ES8328_CHIPPOWER_ADCDIG_OFF 7 | ||
53 | |||
54 | #define ES8328_ADCPOWER 0x03 | ||
55 | #define ES8328_ADCPOWER_INT1_LOWPOWER 0 | ||
56 | #define ES8328_ADCPOWER_FLASH_ADC_LOWPOWER 1 | ||
57 | #define ES8328_ADCPOWER_ADC_BIAS_GEN_OFF 2 | ||
58 | #define ES8328_ADCPOWER_MIC_BIAS_OFF 3 | ||
59 | #define ES8328_ADCPOWER_ADCR_OFF 4 | ||
60 | #define ES8328_ADCPOWER_ADCL_OFF 5 | ||
61 | #define ES8328_ADCPOWER_AINR_OFF 6 | ||
62 | #define ES8328_ADCPOWER_AINL_OFF 7 | ||
63 | |||
64 | #define ES8328_DACPOWER 0x04 | ||
65 | #define ES8328_DACPOWER_OUT3_ON 0 | ||
66 | #define ES8328_DACPOWER_MONO_ON 1 | ||
67 | #define ES8328_DACPOWER_ROUT2_ON 2 | ||
68 | #define ES8328_DACPOWER_LOUT2_ON 3 | ||
69 | #define ES8328_DACPOWER_ROUT1_ON 4 | ||
70 | #define ES8328_DACPOWER_LOUT1_ON 5 | ||
71 | #define ES8328_DACPOWER_RDAC_OFF 6 | ||
72 | #define ES8328_DACPOWER_LDAC_OFF 7 | ||
73 | |||
74 | #define ES8328_CHIPLOPOW1 0x05 | ||
75 | #define ES8328_CHIPLOPOW2 0x06 | ||
76 | #define ES8328_ANAVOLMANAG 0x07 | ||
77 | |||
78 | #define ES8328_MASTERMODE 0x08 | ||
79 | #define ES8328_MASTERMODE_BCLKDIV (0 << 0) | ||
80 | #define ES8328_MASTERMODE_BCLK_INV (1 << 5) | ||
81 | #define ES8328_MASTERMODE_MCLKDIV2 (1 << 6) | ||
82 | #define ES8328_MASTERMODE_MSC (1 << 7) | ||
83 | |||
84 | #define ES8328_ADCCONTROL1 0x09 | ||
85 | #define ES8328_ADCCONTROL2 0x0a | ||
86 | #define ES8328_ADCCONTROL3 0x0b | ||
87 | #define ES8328_ADCCONTROL4 0x0c | ||
88 | #define ES8328_ADCCONTROL5 0x0d | ||
89 | #define ES8328_ADCCONTROL5_RATEMASK (0x1f << 0) | ||
90 | |||
91 | #define ES8328_ADCCONTROL6 0x0e | ||
92 | |||
93 | #define ES8328_ADCCONTROL7 0x0f | ||
94 | #define ES8328_ADCCONTROL7_ADC_MUTE (1 << 2) | ||
95 | #define ES8328_ADCCONTROL7_ADC_LER (1 << 3) | ||
96 | #define ES8328_ADCCONTROL7_ADC_ZERO_CROSS (1 << 4) | ||
97 | #define ES8328_ADCCONTROL7_ADC_SOFT_RAMP (1 << 5) | ||
98 | #define ES8328_ADCCONTROL7_ADC_RAMP_RATE_4 (0 << 6) | ||
99 | #define ES8328_ADCCONTROL7_ADC_RAMP_RATE_8 (1 << 6) | ||
100 | #define ES8328_ADCCONTROL7_ADC_RAMP_RATE_16 (2 << 6) | ||
101 | #define ES8328_ADCCONTROL7_ADC_RAMP_RATE_32 (3 << 6) | ||
102 | |||
103 | #define ES8328_ADCCONTROL8 0x10 | ||
104 | #define ES8328_ADCCONTROL9 0x11 | ||
105 | #define ES8328_ADCCONTROL10 0x12 | ||
106 | #define ES8328_ADCCONTROL11 0x13 | ||
107 | #define ES8328_ADCCONTROL12 0x14 | ||
108 | #define ES8328_ADCCONTROL13 0x15 | ||
109 | #define ES8328_ADCCONTROL14 0x16 | ||
110 | |||
111 | #define ES8328_DACCONTROL1 0x17 | ||
112 | #define ES8328_DACCONTROL1_DACFORMAT_I2S (0 << 1) | ||
113 | #define ES8328_DACCONTROL1_DACFORMAT_LJUST (1 << 1) | ||
114 | #define ES8328_DACCONTROL1_DACFORMAT_RJUST (2 << 1) | ||
115 | #define ES8328_DACCONTROL1_DACFORMAT_PCM (3 << 1) | ||
116 | #define ES8328_DACCONTROL1_DACWL_24 (0 << 3) | ||
117 | #define ES8328_DACCONTROL1_DACWL_20 (1 << 3) | ||
118 | #define ES8328_DACCONTROL1_DACWL_18 (2 << 3) | ||
119 | #define ES8328_DACCONTROL1_DACWL_16 (3 << 3) | ||
120 | #define ES8328_DACCONTROL1_DACWL_32 (4 << 3) | ||
121 | #define ES8328_DACCONTROL1_DACLRP_I2S_POL_NORMAL (0 << 6) | ||
122 | #define ES8328_DACCONTROL1_DACLRP_I2S_POL_INV (1 << 6) | ||
123 | #define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK2 (0 << 6) | ||
124 | #define ES8328_DACCONTROL1_DACLRP_PCM_MSB_CLK1 (1 << 6) | ||
125 | #define ES8328_DACCONTROL1_LRSWAP (1 << 7) | ||
126 | |||
127 | #define ES8328_DACCONTROL2 0x18 | ||
128 | #define ES8328_DACCONTROL2_RATEMASK (0x1f << 0) | ||
129 | #define ES8328_DACCONTROL2_DOUBLESPEED (1 << 5) | ||
130 | |||
131 | #define ES8328_DACCONTROL3 0x19 | ||
132 | #define ES8328_DACCONTROL3_AUTOMUTE (1 << 2) | ||
133 | #define ES8328_DACCONTROL3_DACMUTE (1 << 2) | ||
134 | #define ES8328_DACCONTROL3_LEFTGAINVOL (1 << 3) | ||
135 | #define ES8328_DACCONTROL3_DACZEROCROSS (1 << 4) | ||
136 | #define ES8328_DACCONTROL3_DACSOFTRAMP (1 << 5) | ||
137 | #define ES8328_DACCONTROL3_DACRAMPRATE (3 << 6) | ||
138 | |||
139 | #define ES8328_LDACVOL 0x1a | ||
140 | #define ES8328_LDACVOL_MASK (0 << 0) | ||
141 | #define ES8328_LDACVOL_MAX (0xc0) | ||
142 | |||
143 | #define ES8328_RDACVOL 0x1b | ||
144 | #define ES8328_RDACVOL_MASK (0 << 0) | ||
145 | #define ES8328_RDACVOL_MAX (0xc0) | ||
146 | |||
147 | #define ES8328_DACVOL_MAX (0xc0) | ||
148 | |||
149 | #define ES8328_DACCONTROL4 0x1a | ||
150 | #define ES8328_DACCONTROL5 0x1b | ||
151 | |||
152 | #define ES8328_DACCONTROL6 0x1c | ||
153 | #define ES8328_DACCONTROL6_CLICKFREE (1 << 3) | ||
154 | #define ES8328_DACCONTROL6_DAC_INVR (1 << 4) | ||
155 | #define ES8328_DACCONTROL6_DAC_INVL (1 << 5) | ||
156 | #define ES8328_DACCONTROL6_DEEMPH_OFF (0 << 6) | ||
157 | #define ES8328_DACCONTROL6_DEEMPH_32k (1 << 6) | ||
158 | #define ES8328_DACCONTROL6_DEEMPH_44_1k (2 << 6) | ||
159 | #define ES8328_DACCONTROL6_DEEMPH_48k (3 << 6) | ||
160 | |||
161 | #define ES8328_DACCONTROL7 0x1d | ||
162 | #define ES8328_DACCONTROL7_VPP_SCALE_3p5 (0 << 0) | ||
163 | #define ES8328_DACCONTROL7_VPP_SCALE_4p0 (1 << 0) | ||
164 | #define ES8328_DACCONTROL7_VPP_SCALE_3p0 (2 << 0) | ||
165 | #define ES8328_DACCONTROL7_VPP_SCALE_2p5 (3 << 0) | ||
166 | #define ES8328_DACCONTROL7_SHELVING_STRENGTH (1 << 2) /* In eights */ | ||
167 | #define ES8328_DACCONTROL7_MONO (1 << 5) | ||
168 | #define ES8328_DACCONTROL7_ZEROR (1 << 6) | ||
169 | #define ES8328_DACCONTROL7_ZEROL (1 << 7) | ||
170 | |||
171 | /* Shelving filter */ | ||
172 | #define ES8328_DACCONTROL8 0x1e | ||
173 | #define ES8328_DACCONTROL9 0x1f | ||
174 | #define ES8328_DACCONTROL10 0x20 | ||
175 | #define ES8328_DACCONTROL11 0x21 | ||
176 | #define ES8328_DACCONTROL12 0x22 | ||
177 | #define ES8328_DACCONTROL13 0x23 | ||
178 | #define ES8328_DACCONTROL14 0x24 | ||
179 | #define ES8328_DACCONTROL15 0x25 | ||
180 | |||
181 | #define ES8328_DACCONTROL16 0x26 | ||
182 | #define ES8328_DACCONTROL16_RMIXSEL_RIN1 (0 << 0) | ||
183 | #define ES8328_DACCONTROL16_RMIXSEL_RIN2 (1 << 0) | ||
184 | #define ES8328_DACCONTROL16_RMIXSEL_RIN3 (2 << 0) | ||
185 | #define ES8328_DACCONTROL16_RMIXSEL_RADC (3 << 0) | ||
186 | #define ES8328_DACCONTROL16_LMIXSEL_LIN1 (0 << 3) | ||
187 | #define ES8328_DACCONTROL16_LMIXSEL_LIN2 (1 << 3) | ||
188 | #define ES8328_DACCONTROL16_LMIXSEL_LIN3 (2 << 3) | ||
189 | #define ES8328_DACCONTROL16_LMIXSEL_LADC (3 << 3) | ||
190 | |||
191 | #define ES8328_DACCONTROL17 0x27 | ||
192 | #define ES8328_DACCONTROL17_LI2LOVOL (7 << 3) | ||
193 | #define ES8328_DACCONTROL17_LI2LO (1 << 6) | ||
194 | #define ES8328_DACCONTROL17_LD2LO (1 << 7) | ||
195 | |||
196 | #define ES8328_DACCONTROL18 0x28 | ||
197 | #define ES8328_DACCONTROL18_RI2LOVOL (7 << 3) | ||
198 | #define ES8328_DACCONTROL18_RI2LO (1 << 6) | ||
199 | #define ES8328_DACCONTROL18_RD2LO (1 << 7) | ||
200 | |||
201 | #define ES8328_DACCONTROL19 0x29 | ||
202 | #define ES8328_DACCONTROL19_LI2ROVOL (7 << 3) | ||
203 | #define ES8328_DACCONTROL19_LI2RO (1 << 6) | ||
204 | #define ES8328_DACCONTROL19_LD2RO (1 << 7) | ||
205 | |||
206 | #define ES8328_DACCONTROL20 0x2a | ||
207 | #define ES8328_DACCONTROL20_RI2ROVOL (7 << 3) | ||
208 | #define ES8328_DACCONTROL20_RI2RO (1 << 6) | ||
209 | #define ES8328_DACCONTROL20_RD2RO (1 << 7) | ||
210 | |||
211 | #define ES8328_DACCONTROL21 0x2b | ||
212 | #define ES8328_DACCONTROL21_LI2MOVOL (7 << 3) | ||
213 | #define ES8328_DACCONTROL21_LI2MO (1 << 6) | ||
214 | #define ES8328_DACCONTROL21_LD2MO (1 << 7) | ||
215 | |||
216 | #define ES8328_DACCONTROL22 0x2c | ||
217 | #define ES8328_DACCONTROL22_RI2MOVOL (7 << 3) | ||
218 | #define ES8328_DACCONTROL22_RI2MO (1 << 6) | ||
219 | #define ES8328_DACCONTROL22_RD2MO (1 << 7) | ||
220 | |||
221 | #define ES8328_DACCONTROL23 0x2d | ||
222 | #define ES8328_DACCONTROL23_MOUTINV (1 << 1) | ||
223 | #define ES8328_DACCONTROL23_HPSWPOL (1 << 2) | ||
224 | #define ES8328_DACCONTROL23_HPSWEN (1 << 3) | ||
225 | #define ES8328_DACCONTROL23_VROI_1p5k (0 << 4) | ||
226 | #define ES8328_DACCONTROL23_VROI_40k (1 << 4) | ||
227 | #define ES8328_DACCONTROL23_OUT3_VREF (0 << 5) | ||
228 | #define ES8328_DACCONTROL23_OUT3_ROUT1 (1 << 5) | ||
229 | #define ES8328_DACCONTROL23_OUT3_MONOOUT (2 << 5) | ||
230 | #define ES8328_DACCONTROL23_OUT3_RIGHT_MIXER (3 << 5) | ||
231 | #define ES8328_DACCONTROL23_ROUT2INV (1 << 7) | ||
232 | |||
233 | /* LOUT1 Amplifier */ | ||
234 | #define ES8328_LOUT1VOL 0x2e | ||
235 | #define ES8328_LOUT1VOL_MASK (0 << 5) | ||
236 | #define ES8328_LOUT1VOL_MAX (0x24) | ||
237 | |||
238 | /* ROUT1 Amplifier */ | ||
239 | #define ES8328_ROUT1VOL 0x2f | ||
240 | #define ES8328_ROUT1VOL_MASK (0 << 5) | ||
241 | #define ES8328_ROUT1VOL_MAX (0x24) | ||
242 | |||
243 | #define ES8328_OUT1VOL_MAX (0x24) | ||
244 | |||
245 | /* LOUT2 Amplifier */ | ||
246 | #define ES8328_LOUT2VOL 0x30 | ||
247 | #define ES8328_LOUT2VOL_MASK (0 << 5) | ||
248 | #define ES8328_LOUT2VOL_MAX (0x24) | ||
249 | |||
250 | /* ROUT2 Amplifier */ | ||
251 | #define ES8328_ROUT2VOL 0x31 | ||
252 | #define ES8328_ROUT2VOL_MASK (0 << 5) | ||
253 | #define ES8328_ROUT2VOL_MAX (0x24) | ||
254 | |||
255 | #define ES8328_OUT2VOL_MAX (0x24) | ||
256 | |||
257 | /* Mono Out Amplifier */ | ||
258 | #define ES8328_MONOOUTVOL 0x32 | ||
259 | #define ES8328_MONOOUTVOL_MASK (0 << 5) | ||
260 | #define ES8328_MONOOUTVOL_MAX (0x24) | ||
261 | |||
262 | #define ES8328_DACCONTROL29 0x33 | ||
263 | #define ES8328_DACCONTROL30 0x34 | ||
264 | |||
265 | #define ES8328_SYSCLK 0 | ||
266 | |||
267 | #define ES8328_REG_MAX 0x35 | ||
268 | |||
269 | #define ES8328_PLL1 0 | ||
270 | #define ES8328_PLL2 1 | ||
271 | |||
272 | /* clock inputs */ | ||
273 | #define ES8328_MCLK 0 | ||
274 | #define ES8328_PCMCLK 1 | ||
275 | |||
276 | /* clock divider id's */ | ||
277 | #define ES8328_PCMDIV 0 | ||
278 | #define ES8328_BCLKDIV 1 | ||
279 | #define ES8328_VXCLKDIV 2 | ||
280 | |||
281 | /* PCM clock dividers */ | ||
282 | #define ES8328_PCM_DIV_1 (0 << 6) | ||
283 | #define ES8328_PCM_DIV_3 (2 << 6) | ||
284 | #define ES8328_PCM_DIV_5_5 (3 << 6) | ||
285 | #define ES8328_PCM_DIV_2 (4 << 6) | ||
286 | #define ES8328_PCM_DIV_4 (5 << 6) | ||
287 | #define ES8328_PCM_DIV_6 (6 << 6) | ||
288 | #define ES8328_PCM_DIV_8 (7 << 6) | ||
289 | |||
290 | /* BCLK clock dividers */ | ||
291 | #define ES8328_BCLK_DIV_1 (0 << 7) | ||
292 | #define ES8328_BCLK_DIV_2 (1 << 7) | ||
293 | #define ES8328_BCLK_DIV_4 (2 << 7) | ||
294 | #define ES8328_BCLK_DIV_8 (3 << 7) | ||
295 | |||
296 | /* VXCLK clock dividers */ | ||
297 | #define ES8328_VXCLK_DIV_1 (0 << 6) | ||
298 | #define ES8328_VXCLK_DIV_2 (1 << 6) | ||
299 | #define ES8328_VXCLK_DIV_4 (2 << 6) | ||
300 | #define ES8328_VXCLK_DIV_8 (3 << 6) | ||
301 | #define ES8328_VXCLK_DIV_16 (4 << 6) | ||
302 | |||
303 | #define ES8328_DAI_HIFI 0 | ||
304 | #define ES8328_DAI_VOICE 1 | ||
305 | |||
306 | #define ES8328_1536FS 1536 | ||
307 | #define ES8328_1024FS 1024 | ||
308 | #define ES8328_768FS 768 | ||
309 | #define ES8328_512FS 512 | ||
310 | #define ES8328_384FS 384 | ||
311 | #define ES8328_256FS 256 | ||
312 | #define ES8328_128FS 128 | ||
313 | |||
314 | #endif | ||
diff --git a/sound/soc/codecs/jz4740.c b/sound/soc/codecs/jz4740.c index bcebd1a9ce31..df7c01cf7072 100644 --- a/sound/soc/codecs/jz4740.c +++ b/sound/soc/codecs/jz4740.c | |||
@@ -293,41 +293,13 @@ static int jz4740_codec_dev_probe(struct snd_soc_codec *codec) | |||
293 | regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1, | 293 | regmap_update_bits(jz4740_codec->regmap, JZ4740_REG_CODEC_1, |
294 | JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); | 294 | JZ4740_CODEC_1_SW2_ENABLE, JZ4740_CODEC_1_SW2_ENABLE); |
295 | 295 | ||
296 | jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
297 | |||
298 | return 0; | 296 | return 0; |
299 | } | 297 | } |
300 | 298 | ||
301 | static int jz4740_codec_dev_remove(struct snd_soc_codec *codec) | ||
302 | { | ||
303 | jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | #ifdef CONFIG_PM_SLEEP | ||
309 | |||
310 | static int jz4740_codec_suspend(struct snd_soc_codec *codec) | ||
311 | { | ||
312 | return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
313 | } | ||
314 | |||
315 | static int jz4740_codec_resume(struct snd_soc_codec *codec) | ||
316 | { | ||
317 | return jz4740_codec_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
318 | } | ||
319 | |||
320 | #else | ||
321 | #define jz4740_codec_suspend NULL | ||
322 | #define jz4740_codec_resume NULL | ||
323 | #endif | ||
324 | |||
325 | static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { | 299 | static struct snd_soc_codec_driver soc_codec_dev_jz4740_codec = { |
326 | .probe = jz4740_codec_dev_probe, | 300 | .probe = jz4740_codec_dev_probe, |
327 | .remove = jz4740_codec_dev_remove, | ||
328 | .suspend = jz4740_codec_suspend, | ||
329 | .resume = jz4740_codec_resume, | ||
330 | .set_bias_level = jz4740_codec_set_bias_level, | 301 | .set_bias_level = jz4740_codec_set_bias_level, |
302 | .suspend_bias_off = true, | ||
331 | 303 | ||
332 | .controls = jz4740_codec_controls, | 304 | .controls = jz4740_codec_controls, |
333 | .num_controls = ARRAY_SIZE(jz4740_codec_controls), | 305 | .num_controls = ARRAY_SIZE(jz4740_codec_controls), |
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 275b3f72f3f4..c1ae5764983f 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -1395,18 +1395,6 @@ static struct snd_soc_dai_driver lm49453_dai[] = { | |||
1395 | }, | 1395 | }, |
1396 | }; | 1396 | }; |
1397 | 1397 | ||
1398 | static int lm49453_suspend(struct snd_soc_codec *codec) | ||
1399 | { | ||
1400 | lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1401 | return 0; | ||
1402 | } | ||
1403 | |||
1404 | static int lm49453_resume(struct snd_soc_codec *codec) | ||
1405 | { | ||
1406 | lm49453_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1407 | return 0; | ||
1408 | } | ||
1409 | |||
1410 | /* power down chip */ | 1398 | /* power down chip */ |
1411 | static int lm49453_remove(struct snd_soc_codec *codec) | 1399 | static int lm49453_remove(struct snd_soc_codec *codec) |
1412 | { | 1400 | { |
@@ -1416,8 +1404,6 @@ static int lm49453_remove(struct snd_soc_codec *codec) | |||
1416 | 1404 | ||
1417 | static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { | 1405 | static struct snd_soc_codec_driver soc_codec_dev_lm49453 = { |
1418 | .remove = lm49453_remove, | 1406 | .remove = lm49453_remove, |
1419 | .suspend = lm49453_suspend, | ||
1420 | .resume = lm49453_resume, | ||
1421 | .set_bias_level = lm49453_set_bias_level, | 1407 | .set_bias_level = lm49453_set_bias_level, |
1422 | .controls = lm49453_snd_controls, | 1408 | .controls = lm49453_snd_controls, |
1423 | .num_controls = ARRAY_SIZE(lm49453_snd_controls), | 1409 | .num_controls = ARRAY_SIZE(lm49453_snd_controls), |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 4a063fa88526..d519294f57c7 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -1311,8 +1311,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1311 | {"MIC1 Input", NULL, "MIC1"}, | 1311 | {"MIC1 Input", NULL, "MIC1"}, |
1312 | {"MIC2 Input", NULL, "MIC2"}, | 1312 | {"MIC2 Input", NULL, "MIC2"}, |
1313 | 1313 | ||
1314 | {"DMICL", NULL, "DMICL_ENA"}, | ||
1315 | {"DMICR", NULL, "DMICR_ENA"}, | ||
1316 | {"DMICL", NULL, "AHPF"}, | 1314 | {"DMICL", NULL, "AHPF"}, |
1317 | {"DMICR", NULL, "AHPF"}, | 1315 | {"DMICR", NULL, "AHPF"}, |
1318 | 1316 | ||
@@ -1370,6 +1368,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = { | |||
1370 | {"DMIC Mux", "ADC", "ADCR"}, | 1368 | {"DMIC Mux", "ADC", "ADCR"}, |
1371 | {"DMIC Mux", "DMIC", "DMICL"}, | 1369 | {"DMIC Mux", "DMIC", "DMICL"}, |
1372 | {"DMIC Mux", "DMIC", "DMICR"}, | 1370 | {"DMIC Mux", "DMIC", "DMICR"}, |
1371 | {"DMIC Mux", "DMIC", "DMICL_ENA"}, | ||
1372 | {"DMIC Mux", "DMIC", "DMICR_ENA"}, | ||
1373 | 1373 | ||
1374 | {"LBENL Mux", "Normal", "DMIC Mux"}, | 1374 | {"LBENL Mux", "Normal", "DMIC Mux"}, |
1375 | {"LBENL Mux", "Loopback", "LTENL Mux"}, | 1375 | {"LBENL Mux", "Loopback", "LTENL Mux"}, |
@@ -1972,6 +1972,102 @@ static int max98090_dai_digital_mute(struct snd_soc_dai *codec_dai, int mute) | |||
1972 | return 0; | 1972 | return 0; |
1973 | } | 1973 | } |
1974 | 1974 | ||
1975 | static int max98090_dai_trigger(struct snd_pcm_substream *substream, int cmd, | ||
1976 | struct snd_soc_dai *dai) | ||
1977 | { | ||
1978 | struct snd_soc_codec *codec = dai->codec; | ||
1979 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | ||
1980 | |||
1981 | switch (cmd) { | ||
1982 | case SNDRV_PCM_TRIGGER_START: | ||
1983 | case SNDRV_PCM_TRIGGER_RESUME: | ||
1984 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
1985 | if (!max98090->master && dai->active == 1) | ||
1986 | queue_delayed_work(system_power_efficient_wq, | ||
1987 | &max98090->pll_det_enable_work, | ||
1988 | msecs_to_jiffies(10)); | ||
1989 | break; | ||
1990 | case SNDRV_PCM_TRIGGER_STOP: | ||
1991 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
1992 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
1993 | if (!max98090->master && dai->active == 1) | ||
1994 | schedule_work(&max98090->pll_det_disable_work); | ||
1995 | break; | ||
1996 | default: | ||
1997 | break; | ||
1998 | } | ||
1999 | |||
2000 | return 0; | ||
2001 | } | ||
2002 | |||
2003 | static void max98090_pll_det_enable_work(struct work_struct *work) | ||
2004 | { | ||
2005 | struct max98090_priv *max98090 = | ||
2006 | container_of(work, struct max98090_priv, | ||
2007 | pll_det_enable_work.work); | ||
2008 | struct snd_soc_codec *codec = max98090->codec; | ||
2009 | unsigned int status, mask; | ||
2010 | |||
2011 | /* | ||
2012 | * Clear status register in order to clear possibly already occurred | ||
2013 | * PLL unlock. If PLL hasn't still locked, the status will be set | ||
2014 | * again and PLL unlock interrupt will occur. | ||
2015 | * Note this will clear all status bits | ||
2016 | */ | ||
2017 | regmap_read(max98090->regmap, M98090_REG_DEVICE_STATUS, &status); | ||
2018 | |||
2019 | /* | ||
2020 | * Queue jack work in case jack state has just changed but handler | ||
2021 | * hasn't run yet | ||
2022 | */ | ||
2023 | regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); | ||
2024 | status &= mask; | ||
2025 | if (status & M98090_JDET_MASK) | ||
2026 | queue_delayed_work(system_power_efficient_wq, | ||
2027 | &max98090->jack_work, | ||
2028 | msecs_to_jiffies(100)); | ||
2029 | |||
2030 | /* Enable PLL unlock interrupt */ | ||
2031 | snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, | ||
2032 | M98090_IULK_MASK, | ||
2033 | 1 << M98090_IULK_SHIFT); | ||
2034 | } | ||
2035 | |||
2036 | static void max98090_pll_det_disable_work(struct work_struct *work) | ||
2037 | { | ||
2038 | struct max98090_priv *max98090 = | ||
2039 | container_of(work, struct max98090_priv, pll_det_disable_work); | ||
2040 | struct snd_soc_codec *codec = max98090->codec; | ||
2041 | |||
2042 | cancel_delayed_work_sync(&max98090->pll_det_enable_work); | ||
2043 | |||
2044 | /* Disable PLL unlock interrupt */ | ||
2045 | snd_soc_update_bits(codec, M98090_REG_INTERRUPT_S, | ||
2046 | M98090_IULK_MASK, 0); | ||
2047 | } | ||
2048 | |||
2049 | static void max98090_pll_work(struct work_struct *work) | ||
2050 | { | ||
2051 | struct max98090_priv *max98090 = | ||
2052 | container_of(work, struct max98090_priv, pll_work); | ||
2053 | struct snd_soc_codec *codec = max98090->codec; | ||
2054 | |||
2055 | if (!snd_soc_codec_is_active(codec)) | ||
2056 | return; | ||
2057 | |||
2058 | dev_info(codec->dev, "PLL unlocked\n"); | ||
2059 | |||
2060 | /* Toggle shutdown OFF then ON */ | ||
2061 | snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, | ||
2062 | M98090_SHDNN_MASK, 0); | ||
2063 | msleep(10); | ||
2064 | snd_soc_update_bits(codec, M98090_REG_DEVICE_SHUTDOWN, | ||
2065 | M98090_SHDNN_MASK, M98090_SHDNN_MASK); | ||
2066 | |||
2067 | /* Give PLL time to lock */ | ||
2068 | msleep(10); | ||
2069 | } | ||
2070 | |||
1975 | static void max98090_jack_work(struct work_struct *work) | 2071 | static void max98090_jack_work(struct work_struct *work) |
1976 | { | 2072 | { |
1977 | struct max98090_priv *max98090 = container_of(work, | 2073 | struct max98090_priv *max98090 = container_of(work, |
@@ -2063,12 +2159,16 @@ static void max98090_jack_work(struct work_struct *work) | |||
2063 | 2159 | ||
2064 | static irqreturn_t max98090_interrupt(int irq, void *data) | 2160 | static irqreturn_t max98090_interrupt(int irq, void *data) |
2065 | { | 2161 | { |
2066 | struct snd_soc_codec *codec = data; | 2162 | struct max98090_priv *max98090 = data; |
2067 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 2163 | struct snd_soc_codec *codec = max98090->codec; |
2068 | int ret; | 2164 | int ret; |
2069 | unsigned int mask; | 2165 | unsigned int mask; |
2070 | unsigned int active; | 2166 | unsigned int active; |
2071 | 2167 | ||
2168 | /* Treat interrupt before codec is initialized as spurious */ | ||
2169 | if (codec == NULL) | ||
2170 | return IRQ_NONE; | ||
2171 | |||
2072 | dev_dbg(codec->dev, "***** max98090_interrupt *****\n"); | 2172 | dev_dbg(codec->dev, "***** max98090_interrupt *****\n"); |
2073 | 2173 | ||
2074 | ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); | 2174 | ret = regmap_read(max98090->regmap, M98090_REG_INTERRUPT_S, &mask); |
@@ -2103,8 +2203,10 @@ static irqreturn_t max98090_interrupt(int irq, void *data) | |||
2103 | if (active & M98090_SLD_MASK) | 2203 | if (active & M98090_SLD_MASK) |
2104 | dev_dbg(codec->dev, "M98090_SLD_MASK\n"); | 2204 | dev_dbg(codec->dev, "M98090_SLD_MASK\n"); |
2105 | 2205 | ||
2106 | if (active & M98090_ULK_MASK) | 2206 | if (active & M98090_ULK_MASK) { |
2107 | dev_err(codec->dev, "M98090_ULK_MASK\n"); | 2207 | dev_dbg(codec->dev, "M98090_ULK_MASK\n"); |
2208 | schedule_work(&max98090->pll_work); | ||
2209 | } | ||
2108 | 2210 | ||
2109 | if (active & M98090_JDET_MASK) { | 2211 | if (active & M98090_JDET_MASK) { |
2110 | dev_dbg(codec->dev, "M98090_JDET_MASK\n"); | 2212 | dev_dbg(codec->dev, "M98090_JDET_MASK\n"); |
@@ -2177,6 +2279,7 @@ static struct snd_soc_dai_ops max98090_dai_ops = { | |||
2177 | .set_tdm_slot = max98090_set_tdm_slot, | 2279 | .set_tdm_slot = max98090_set_tdm_slot, |
2178 | .hw_params = max98090_dai_hw_params, | 2280 | .hw_params = max98090_dai_hw_params, |
2179 | .digital_mute = max98090_dai_digital_mute, | 2281 | .digital_mute = max98090_dai_digital_mute, |
2282 | .trigger = max98090_dai_trigger, | ||
2180 | }; | 2283 | }; |
2181 | 2284 | ||
2182 | static struct snd_soc_dai_driver max98090_dai[] = { | 2285 | static struct snd_soc_dai_driver max98090_dai[] = { |
@@ -2230,7 +2333,6 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2230 | max98090->lin_state = 0; | 2333 | max98090->lin_state = 0; |
2231 | max98090->pa1en = 0; | 2334 | max98090->pa1en = 0; |
2232 | max98090->pa2en = 0; | 2335 | max98090->pa2en = 0; |
2233 | max98090->extmic_mux = 0; | ||
2234 | 2336 | ||
2235 | ret = snd_soc_read(codec, M98090_REG_REVISION_ID); | 2337 | ret = snd_soc_read(codec, M98090_REG_REVISION_ID); |
2236 | if (ret < 0) { | 2338 | if (ret < 0) { |
@@ -2258,22 +2360,16 @@ static int max98090_probe(struct snd_soc_codec *codec) | |||
2258 | max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; | 2360 | max98090->jack_state = M98090_JACK_STATE_NO_HEADSET; |
2259 | 2361 | ||
2260 | INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); | 2362 | INIT_DELAYED_WORK(&max98090->jack_work, max98090_jack_work); |
2363 | INIT_DELAYED_WORK(&max98090->pll_det_enable_work, | ||
2364 | max98090_pll_det_enable_work); | ||
2365 | INIT_WORK(&max98090->pll_det_disable_work, | ||
2366 | max98090_pll_det_disable_work); | ||
2367 | INIT_WORK(&max98090->pll_work, max98090_pll_work); | ||
2261 | 2368 | ||
2262 | /* Enable jack detection */ | 2369 | /* Enable jack detection */ |
2263 | snd_soc_write(codec, M98090_REG_JACK_DETECT, | 2370 | snd_soc_write(codec, M98090_REG_JACK_DETECT, |
2264 | M98090_JDETEN_MASK | M98090_JDEB_25MS); | 2371 | M98090_JDETEN_MASK | M98090_JDEB_25MS); |
2265 | 2372 | ||
2266 | /* Register for interrupts */ | ||
2267 | dev_dbg(codec->dev, "irq = %d\n", max98090->irq); | ||
2268 | |||
2269 | ret = devm_request_threaded_irq(codec->dev, max98090->irq, NULL, | ||
2270 | max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
2271 | "max98090_interrupt", codec); | ||
2272 | if (ret < 0) { | ||
2273 | dev_err(codec->dev, "request_irq failed: %d\n", | ||
2274 | ret); | ||
2275 | } | ||
2276 | |||
2277 | /* | 2373 | /* |
2278 | * Clear any old interrupts. | 2374 | * Clear any old interrupts. |
2279 | * An old interrupt ocurring prior to installing the ISR | 2375 | * An old interrupt ocurring prior to installing the ISR |
@@ -2310,6 +2406,10 @@ static int max98090_remove(struct snd_soc_codec *codec) | |||
2310 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); | 2406 | struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec); |
2311 | 2407 | ||
2312 | cancel_delayed_work_sync(&max98090->jack_work); | 2408 | cancel_delayed_work_sync(&max98090->jack_work); |
2409 | cancel_delayed_work_sync(&max98090->pll_det_enable_work); | ||
2410 | cancel_work_sync(&max98090->pll_det_disable_work); | ||
2411 | cancel_work_sync(&max98090->pll_work); | ||
2412 | max98090->codec = NULL; | ||
2313 | 2413 | ||
2314 | return 0; | 2414 | return 0; |
2315 | } | 2415 | } |
@@ -2362,7 +2462,6 @@ static int max98090_i2c_probe(struct i2c_client *i2c, | |||
2362 | max98090->devtype = driver_data; | 2462 | max98090->devtype = driver_data; |
2363 | i2c_set_clientdata(i2c, max98090); | 2463 | i2c_set_clientdata(i2c, max98090); |
2364 | max98090->pdata = i2c->dev.platform_data; | 2464 | max98090->pdata = i2c->dev.platform_data; |
2365 | max98090->irq = i2c->irq; | ||
2366 | 2465 | ||
2367 | max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); | 2466 | max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap); |
2368 | if (IS_ERR(max98090->regmap)) { | 2467 | if (IS_ERR(max98090->regmap)) { |
@@ -2371,6 +2470,15 @@ static int max98090_i2c_probe(struct i2c_client *i2c, | |||
2371 | goto err_enable; | 2470 | goto err_enable; |
2372 | } | 2471 | } |
2373 | 2472 | ||
2473 | ret = devm_request_threaded_irq(&i2c->dev, i2c->irq, NULL, | ||
2474 | max98090_interrupt, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
2475 | "max98090_interrupt", max98090); | ||
2476 | if (ret < 0) { | ||
2477 | dev_err(&i2c->dev, "request_irq failed: %d\n", | ||
2478 | ret); | ||
2479 | return ret; | ||
2480 | } | ||
2481 | |||
2374 | ret = snd_soc_register_codec(&i2c->dev, | 2482 | ret = snd_soc_register_codec(&i2c->dev, |
2375 | &soc_codec_dev_max98090, max98090_dai, | 2483 | &soc_codec_dev_max98090, max98090_dai, |
2376 | ARRAY_SIZE(max98090_dai)); | 2484 | ARRAY_SIZE(max98090_dai)); |
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h index cf1b6062ba8c..a5f6bada06da 100644 --- a/sound/soc/codecs/max98090.h +++ b/sound/soc/codecs/max98090.h | |||
@@ -11,11 +11,6 @@ | |||
11 | #ifndef _MAX98090_H | 11 | #ifndef _MAX98090_H |
12 | #define _MAX98090_H | 12 | #define _MAX98090_H |
13 | 13 | ||
14 | #include <linux/version.h> | ||
15 | |||
16 | /* One can override the Linux version here with an explicit version number */ | ||
17 | #define M98090_LINUX_VERSION LINUX_VERSION_CODE | ||
18 | |||
19 | /* | 14 | /* |
20 | * MAX98090 Register Definitions | 15 | * MAX98090 Register Definitions |
21 | */ | 16 | */ |
@@ -1502,9 +1497,6 @@ | |||
1502 | #define M98090_REVID_WIDTH 8 | 1497 | #define M98090_REVID_WIDTH 8 |
1503 | #define M98090_REVID_NUM (1<<M98090_REVID_WIDTH) | 1498 | #define M98090_REVID_NUM (1<<M98090_REVID_WIDTH) |
1504 | 1499 | ||
1505 | #define M98090_BYTE1(w) ((w >> 8) & 0xff) | ||
1506 | #define M98090_BYTE0(w) (w & 0xff) | ||
1507 | |||
1508 | /* Silicon revision number */ | 1500 | /* Silicon revision number */ |
1509 | #define M98090_REVA 0x40 | 1501 | #define M98090_REVA 0x40 |
1510 | #define M98091_REVA 0x50 | 1502 | #define M98091_REVA 0x50 |
@@ -1529,9 +1521,11 @@ struct max98090_priv { | |||
1529 | unsigned int bclk; | 1521 | unsigned int bclk; |
1530 | unsigned int lrclk; | 1522 | unsigned int lrclk; |
1531 | struct max98090_cdata dai[1]; | 1523 | struct max98090_cdata dai[1]; |
1532 | int irq; | ||
1533 | int jack_state; | 1524 | int jack_state; |
1534 | struct delayed_work jack_work; | 1525 | struct delayed_work jack_work; |
1526 | struct delayed_work pll_det_enable_work; | ||
1527 | struct work_struct pll_det_disable_work; | ||
1528 | struct work_struct pll_work; | ||
1535 | struct snd_soc_jack *jack; | 1529 | struct snd_soc_jack *jack; |
1536 | unsigned int dai_fmt; | 1530 | unsigned int dai_fmt; |
1537 | int tdm_slots; | 1531 | int tdm_slots; |
@@ -1539,7 +1533,6 @@ struct max98090_priv { | |||
1539 | u8 lin_state; | 1533 | u8 lin_state; |
1540 | unsigned int pa1en; | 1534 | unsigned int pa1en; |
1541 | unsigned int pa2en; | 1535 | unsigned int pa2en; |
1542 | unsigned int extmic_mux; | ||
1543 | unsigned int sidetone; | 1536 | unsigned int sidetone; |
1544 | bool master; | 1537 | bool master; |
1545 | }; | 1538 | }; |
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index e661e8420e3d..711f55039522 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c | |||
@@ -565,41 +565,19 @@ static struct snd_soc_dai_driver ml26124_dai = { | |||
565 | .symmetric_rates = 1, | 565 | .symmetric_rates = 1, |
566 | }; | 566 | }; |
567 | 567 | ||
568 | #ifdef CONFIG_PM | ||
569 | static int ml26124_suspend(struct snd_soc_codec *codec) | ||
570 | { | ||
571 | ml26124_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | static int ml26124_resume(struct snd_soc_codec *codec) | ||
577 | { | ||
578 | ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | #else | ||
583 | #define ml26124_suspend NULL | ||
584 | #define ml26124_resume NULL | ||
585 | #endif | ||
586 | |||
587 | static int ml26124_probe(struct snd_soc_codec *codec) | 568 | static int ml26124_probe(struct snd_soc_codec *codec) |
588 | { | 569 | { |
589 | /* Software Reset */ | 570 | /* Software Reset */ |
590 | snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1); | 571 | snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 1); |
591 | snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0); | 572 | snd_soc_update_bits(codec, ML26124_SW_RST, 0x01, 0); |
592 | 573 | ||
593 | ml26124_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
594 | |||
595 | return 0; | 574 | return 0; |
596 | } | 575 | } |
597 | 576 | ||
598 | static struct snd_soc_codec_driver soc_codec_dev_ml26124 = { | 577 | static struct snd_soc_codec_driver soc_codec_dev_ml26124 = { |
599 | .probe = ml26124_probe, | 578 | .probe = ml26124_probe, |
600 | .suspend = ml26124_suspend, | ||
601 | .resume = ml26124_resume, | ||
602 | .set_bias_level = ml26124_set_bias_level, | 579 | .set_bias_level = ml26124_set_bias_level, |
580 | .suspend_bias_off = true, | ||
603 | .dapm_widgets = ml26124_dapm_widgets, | 581 | .dapm_widgets = ml26124_dapm_widgets, |
604 | .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets), | 582 | .num_dapm_widgets = ARRAY_SIZE(ml26124_dapm_widgets), |
605 | .dapm_routes = ml26124_intercon, | 583 | .dapm_routes = ml26124_intercon, |
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index 163ec3855fd4..0c8aefab404c 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -259,13 +259,13 @@ static const struct soc_enum pcm512x_veds = | |||
259 | pcm512x_ramp_step_text); | 259 | pcm512x_ramp_step_text); |
260 | 260 | ||
261 | static const struct snd_kcontrol_new pcm512x_controls[] = { | 261 | static const struct snd_kcontrol_new pcm512x_controls[] = { |
262 | SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, | 262 | SOC_DOUBLE_R_TLV("Digital Playback Volume", PCM512x_DIGITAL_VOLUME_2, |
263 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), | 263 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), |
264 | SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, | 264 | SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, |
265 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), | 265 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), |
266 | SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, | 266 | SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, |
267 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), | 267 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), |
268 | SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, | 268 | SOC_DOUBLE("Digital Playback Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, |
269 | PCM512x_RQMR_SHIFT, 1, 1), | 269 | PCM512x_RQMR_SHIFT, 1, 1), |
270 | 270 | ||
271 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), | 271 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), |
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index e4f6102efc1a..4aa555cbcca8 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c | |||
@@ -51,7 +51,7 @@ static struct reg_default rt286_index_def[] = { | |||
51 | { 0x04, 0xaf01 }, | 51 | { 0x04, 0xaf01 }, |
52 | { 0x08, 0x000d }, | 52 | { 0x08, 0x000d }, |
53 | { 0x09, 0xd810 }, | 53 | { 0x09, 0xd810 }, |
54 | { 0x0a, 0x0060 }, | 54 | { 0x0a, 0x0120 }, |
55 | { 0x0b, 0x0000 }, | 55 | { 0x0b, 0x0000 }, |
56 | { 0x0d, 0x2800 }, | 56 | { 0x0d, 0x2800 }, |
57 | { 0x0f, 0x0000 }, | 57 | { 0x0f, 0x0000 }, |
@@ -60,7 +60,7 @@ static struct reg_default rt286_index_def[] = { | |||
60 | { 0x33, 0x0208 }, | 60 | { 0x33, 0x0208 }, |
61 | { 0x49, 0x0004 }, | 61 | { 0x49, 0x0004 }, |
62 | { 0x4f, 0x50e9 }, | 62 | { 0x4f, 0x50e9 }, |
63 | { 0x50, 0x2c00 }, | 63 | { 0x50, 0x2000 }, |
64 | { 0x63, 0x2902 }, | 64 | { 0x63, 0x2902 }, |
65 | { 0x67, 0x1111 }, | 65 | { 0x67, 0x1111 }, |
66 | { 0x68, 0x1016 }, | 66 | { 0x68, 0x1016 }, |
@@ -104,7 +104,6 @@ static const struct reg_default rt286_reg[] = { | |||
104 | { 0x02170700, 0x00000000 }, | 104 | { 0x02170700, 0x00000000 }, |
105 | { 0x02270100, 0x00000000 }, | 105 | { 0x02270100, 0x00000000 }, |
106 | { 0x02370100, 0x00000000 }, | 106 | { 0x02370100, 0x00000000 }, |
107 | { 0x02040000, 0x00004002 }, | ||
108 | { 0x01870700, 0x00000020 }, | 107 | { 0x01870700, 0x00000020 }, |
109 | { 0x00830000, 0x000000c3 }, | 108 | { 0x00830000, 0x000000c3 }, |
110 | { 0x00930000, 0x000000c3 }, | 109 | { 0x00930000, 0x000000c3 }, |
@@ -192,7 +191,6 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | |||
192 | /*handle index registers*/ | 191 | /*handle index registers*/ |
193 | if (reg <= 0xff) { | 192 | if (reg <= 0xff) { |
194 | rt286_hw_write(client, RT286_COEF_INDEX, reg); | 193 | rt286_hw_write(client, RT286_COEF_INDEX, reg); |
195 | reg = RT286_PROC_COEF; | ||
196 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { | 194 | for (i = 0; i < INDEX_CACHE_SIZE; i++) { |
197 | if (reg == rt286->index_cache[i].reg) { | 195 | if (reg == rt286->index_cache[i].reg) { |
198 | rt286->index_cache[i].def = value; | 196 | rt286->index_cache[i].def = value; |
@@ -200,6 +198,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value) | |||
200 | } | 198 | } |
201 | 199 | ||
202 | } | 200 | } |
201 | reg = RT286_PROC_COEF; | ||
203 | } | 202 | } |
204 | 203 | ||
205 | data[0] = (reg >> 24) & 0xff; | 204 | data[0] = (reg >> 24) & 0xff; |
@@ -270,6 +269,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value) | |||
270 | return 0; | 269 | return 0; |
271 | } | 270 | } |
272 | 271 | ||
272 | #ifdef CONFIG_PM | ||
273 | static void rt286_index_sync(struct snd_soc_codec *codec) | 273 | static void rt286_index_sync(struct snd_soc_codec *codec) |
274 | { | 274 | { |
275 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | 275 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); |
@@ -280,6 +280,7 @@ static void rt286_index_sync(struct snd_soc_codec *codec) | |||
280 | rt286->index_cache[i].def); | 280 | rt286->index_cache[i].def); |
281 | } | 281 | } |
282 | } | 282 | } |
283 | #endif | ||
283 | 284 | ||
284 | static int rt286_support_power_controls[] = { | 285 | static int rt286_support_power_controls[] = { |
285 | RT286_DAC_OUT1, | 286 | RT286_DAC_OUT1, |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 6bc6efdec550..c3f2decd643c 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -1906,6 +1906,32 @@ static int rt5640_set_bias_level(struct snd_soc_codec *codec, | |||
1906 | return 0; | 1906 | return 0; |
1907 | } | 1907 | } |
1908 | 1908 | ||
1909 | int rt5640_dmic_enable(struct snd_soc_codec *codec, | ||
1910 | bool dmic1_data_pin, bool dmic2_data_pin) | ||
1911 | { | ||
1912 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | ||
1913 | |||
1914 | regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, | ||
1915 | RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); | ||
1916 | |||
1917 | if (dmic1_data_pin) { | ||
1918 | regmap_update_bits(rt5640->regmap, RT5640_DMIC, | ||
1919 | RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); | ||
1920 | regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, | ||
1921 | RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); | ||
1922 | } | ||
1923 | |||
1924 | if (dmic2_data_pin) { | ||
1925 | regmap_update_bits(rt5640->regmap, RT5640_DMIC, | ||
1926 | RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); | ||
1927 | regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, | ||
1928 | RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); | ||
1929 | } | ||
1930 | |||
1931 | return 0; | ||
1932 | } | ||
1933 | EXPORT_SYMBOL_GPL(rt5640_dmic_enable); | ||
1934 | |||
1909 | static int rt5640_probe(struct snd_soc_codec *codec) | 1935 | static int rt5640_probe(struct snd_soc_codec *codec) |
1910 | { | 1936 | { |
1911 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); | 1937 | struct rt5640_priv *rt5640 = snd_soc_codec_get_drvdata(codec); |
@@ -1945,6 +1971,10 @@ static int rt5640_probe(struct snd_soc_codec *codec) | |||
1945 | return -ENODEV; | 1971 | return -ENODEV; |
1946 | } | 1972 | } |
1947 | 1973 | ||
1974 | if (rt5640->pdata.dmic_en) | ||
1975 | rt5640_dmic_enable(codec, rt5640->pdata.dmic1_data_pin, | ||
1976 | rt5640->pdata.dmic2_data_pin); | ||
1977 | |||
1948 | return 0; | 1978 | return 0; |
1949 | } | 1979 | } |
1950 | 1980 | ||
@@ -2059,6 +2089,7 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5640 = { | |||
2059 | static const struct regmap_config rt5640_regmap = { | 2089 | static const struct regmap_config rt5640_regmap = { |
2060 | .reg_bits = 8, | 2090 | .reg_bits = 8, |
2061 | .val_bits = 16, | 2091 | .val_bits = 16, |
2092 | .use_single_rw = true, | ||
2062 | 2093 | ||
2063 | .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) * | 2094 | .max_register = RT5640_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5640_ranges) * |
2064 | RT5640_PR_SPACING), | 2095 | RT5640_PR_SPACING), |
@@ -2194,25 +2225,6 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, | |||
2194 | regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, | 2225 | regmap_update_bits(rt5640->regmap, RT5640_IN3_IN4, |
2195 | RT5640_IN_DF2, RT5640_IN_DF2); | 2226 | RT5640_IN_DF2, RT5640_IN_DF2); |
2196 | 2227 | ||
2197 | if (rt5640->pdata.dmic_en) { | ||
2198 | regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, | ||
2199 | RT5640_GP2_PIN_MASK, RT5640_GP2_PIN_DMIC1_SCL); | ||
2200 | |||
2201 | if (rt5640->pdata.dmic1_data_pin) { | ||
2202 | regmap_update_bits(rt5640->regmap, RT5640_DMIC, | ||
2203 | RT5640_DMIC_1_DP_MASK, RT5640_DMIC_1_DP_GPIO3); | ||
2204 | regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, | ||
2205 | RT5640_GP3_PIN_MASK, RT5640_GP3_PIN_DMIC1_SDA); | ||
2206 | } | ||
2207 | |||
2208 | if (rt5640->pdata.dmic2_data_pin) { | ||
2209 | regmap_update_bits(rt5640->regmap, RT5640_DMIC, | ||
2210 | RT5640_DMIC_2_DP_MASK, RT5640_DMIC_2_DP_GPIO4); | ||
2211 | regmap_update_bits(rt5640->regmap, RT5640_GPIO_CTRL1, | ||
2212 | RT5640_GP4_PIN_MASK, RT5640_GP4_PIN_DMIC2_SDA); | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | rt5640->hp_mute = 1; | 2228 | rt5640->hp_mute = 1; |
2217 | 2229 | ||
2218 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, | 2230 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, |
diff --git a/sound/soc/codecs/rt5640.h b/sound/soc/codecs/rt5640.h index 58ebe96b86da..3deb8babeabb 100644 --- a/sound/soc/codecs/rt5640.h +++ b/sound/soc/codecs/rt5640.h | |||
@@ -2097,4 +2097,7 @@ struct rt5640_priv { | |||
2097 | bool hp_mute; | 2097 | bool hp_mute; |
2098 | }; | 2098 | }; |
2099 | 2099 | ||
2100 | int rt5640_dmic_enable(struct snd_soc_codec *codec, | ||
2101 | bool dmic1_data_pin, bool dmic2_data_pin); | ||
2102 | |||
2100 | #endif | 2103 | #endif |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a7762d0a623e..3fb83bf09768 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/i2c.h> | 17 | #include <linux/i2c.h> |
18 | #include <linux/platform_device.h> | 18 | #include <linux/platform_device.h> |
19 | #include <linux/spi/spi.h> | 19 | #include <linux/spi/spi.h> |
20 | #include <linux/gpio.h> | ||
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
@@ -2103,6 +2104,77 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, | |||
2103 | return 0; | 2104 | return 0; |
2104 | } | 2105 | } |
2105 | 2106 | ||
2107 | static int rt5645_jack_detect(struct snd_soc_codec *codec, | ||
2108 | struct snd_soc_jack *jack) | ||
2109 | { | ||
2110 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2111 | int gpio_state, jack_type = 0; | ||
2112 | unsigned int val; | ||
2113 | |||
2114 | gpio_state = gpio_get_value(rt5645->pdata.hp_det_gpio); | ||
2115 | |||
2116 | dev_dbg(codec->dev, "gpio = %d(%d)\n", rt5645->pdata.hp_det_gpio, | ||
2117 | gpio_state); | ||
2118 | |||
2119 | if ((rt5645->pdata.gpio_hp_det_active_high && gpio_state) || | ||
2120 | (!rt5645->pdata.gpio_hp_det_active_high && !gpio_state)) { | ||
2121 | snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias1"); | ||
2122 | snd_soc_dapm_force_enable_pin(&codec->dapm, "micbias2"); | ||
2123 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | ||
2124 | snd_soc_dapm_force_enable_pin(&codec->dapm, "Mic Det Power"); | ||
2125 | snd_soc_dapm_sync(&codec->dapm); | ||
2126 | |||
2127 | snd_soc_write(codec, RT5645_IN1_CTRL1, 0x0006); | ||
2128 | snd_soc_write(codec, RT5645_JD_CTRL3, 0x00b0); | ||
2129 | |||
2130 | snd_soc_update_bits(codec, RT5645_IN1_CTRL2, | ||
2131 | RT5645_CBJ_MN_JD, 0); | ||
2132 | snd_soc_update_bits(codec, RT5645_IN1_CTRL2, | ||
2133 | RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); | ||
2134 | |||
2135 | msleep(400); | ||
2136 | val = snd_soc_read(codec, RT5645_IN1_CTRL3) & 0x7; | ||
2137 | dev_dbg(codec->dev, "val = %d\n", val); | ||
2138 | |||
2139 | if (val == 1 || val == 2) | ||
2140 | jack_type = SND_JACK_HEADSET; | ||
2141 | else | ||
2142 | jack_type = SND_JACK_HEADPHONE; | ||
2143 | |||
2144 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias1"); | ||
2145 | snd_soc_dapm_disable_pin(&codec->dapm, "micbias2"); | ||
2146 | snd_soc_dapm_disable_pin(&codec->dapm, "LDO2"); | ||
2147 | snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power"); | ||
2148 | snd_soc_dapm_sync(&codec->dapm); | ||
2149 | } | ||
2150 | |||
2151 | snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET); | ||
2152 | |||
2153 | return 0; | ||
2154 | } | ||
2155 | |||
2156 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | ||
2157 | struct snd_soc_jack *jack) | ||
2158 | { | ||
2159 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | ||
2160 | |||
2161 | rt5645->jack = jack; | ||
2162 | |||
2163 | rt5645_jack_detect(codec, rt5645->jack); | ||
2164 | |||
2165 | return 0; | ||
2166 | } | ||
2167 | EXPORT_SYMBOL_GPL(rt5645_set_jack_detect); | ||
2168 | |||
2169 | static irqreturn_t rt5645_irq(int irq, void *data) | ||
2170 | { | ||
2171 | struct rt5645_priv *rt5645 = data; | ||
2172 | |||
2173 | rt5645_jack_detect(rt5645->codec, rt5645->jack); | ||
2174 | |||
2175 | return IRQ_HANDLED; | ||
2176 | } | ||
2177 | |||
2106 | static int rt5645_probe(struct snd_soc_codec *codec) | 2178 | static int rt5645_probe(struct snd_soc_codec *codec) |
2107 | { | 2179 | { |
2108 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); | 2180 | struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); |
@@ -2250,6 +2322,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2250 | if (rt5645 == NULL) | 2322 | if (rt5645 == NULL) |
2251 | return -ENOMEM; | 2323 | return -ENOMEM; |
2252 | 2324 | ||
2325 | rt5645->i2c = i2c; | ||
2253 | i2c_set_clientdata(i2c, rt5645); | 2326 | i2c_set_clientdata(i2c, rt5645); |
2254 | 2327 | ||
2255 | if (pdata) | 2328 | if (pdata) |
@@ -2345,12 +2418,38 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
2345 | 2418 | ||
2346 | } | 2419 | } |
2347 | 2420 | ||
2421 | if (rt5645->i2c->irq) { | ||
2422 | ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, | ||
2423 | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | ||
2424 | | IRQF_ONESHOT, "rt5645", rt5645); | ||
2425 | if (ret) | ||
2426 | dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); | ||
2427 | } | ||
2428 | |||
2429 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) { | ||
2430 | ret = gpio_request(rt5645->pdata.hp_det_gpio, "rt5645"); | ||
2431 | if (ret) | ||
2432 | dev_err(&i2c->dev, "Fail gpio_request hp_det_gpio\n"); | ||
2433 | |||
2434 | ret = gpio_direction_input(rt5645->pdata.hp_det_gpio); | ||
2435 | if (ret) | ||
2436 | dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n"); | ||
2437 | } | ||
2438 | |||
2348 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, | 2439 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, |
2349 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); | 2440 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); |
2350 | } | 2441 | } |
2351 | 2442 | ||
2352 | static int rt5645_i2c_remove(struct i2c_client *i2c) | 2443 | static int rt5645_i2c_remove(struct i2c_client *i2c) |
2353 | { | 2444 | { |
2445 | struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c); | ||
2446 | |||
2447 | if (i2c->irq) | ||
2448 | free_irq(i2c->irq, rt5645); | ||
2449 | |||
2450 | if (gpio_is_valid(rt5645->pdata.hp_det_gpio)) | ||
2451 | gpio_free(rt5645->pdata.hp_det_gpio); | ||
2452 | |||
2354 | snd_soc_unregister_codec(&i2c->dev); | 2453 | snd_soc_unregister_codec(&i2c->dev); |
2355 | 2454 | ||
2356 | return 0; | 2455 | return 0; |
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 355b7e9eefab..50c62c5668ea 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h | |||
@@ -2166,6 +2166,8 @@ struct rt5645_priv { | |||
2166 | struct snd_soc_codec *codec; | 2166 | struct snd_soc_codec *codec; |
2167 | struct rt5645_platform_data pdata; | 2167 | struct rt5645_platform_data pdata; |
2168 | struct regmap *regmap; | 2168 | struct regmap *regmap; |
2169 | struct i2c_client *i2c; | ||
2170 | struct snd_soc_jack *jack; | ||
2169 | 2171 | ||
2170 | int sysclk; | 2172 | int sysclk; |
2171 | int sysclk_src; | 2173 | int sysclk_src; |
@@ -2178,4 +2180,7 @@ struct rt5645_priv { | |||
2178 | int pll_out; | 2180 | int pll_out; |
2179 | }; | 2181 | }; |
2180 | 2182 | ||
2183 | int rt5645_set_jack_detect(struct snd_soc_codec *codec, | ||
2184 | struct snd_soc_jack *jack); | ||
2185 | |||
2181 | #endif /* __RT5645_H__ */ | 2186 | #endif /* __RT5645_H__ */ |
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 67f14556462f..16aa4d99a713 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c | |||
@@ -15,10 +15,12 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/delay.h> | 16 | #include <linux/delay.h> |
17 | #include <linux/pm.h> | 17 | #include <linux/pm.h> |
18 | #include <linux/of_gpio.h> | ||
18 | #include <linux/regmap.h> | 19 | #include <linux/regmap.h> |
19 | #include <linux/i2c.h> | 20 | #include <linux/i2c.h> |
20 | #include <linux/platform_device.h> | 21 | #include <linux/platform_device.h> |
21 | #include <linux/spi/spi.h> | 22 | #include <linux/spi/spi.h> |
23 | #include <linux/gpio.h> | ||
22 | #include <sound/core.h> | 24 | #include <sound/core.h> |
23 | #include <sound/pcm.h> | 25 | #include <sound/pcm.h> |
24 | #include <sound/pcm_params.h> | 26 | #include <sound/pcm_params.h> |
@@ -540,6 +542,7 @@ static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0); | |||
540 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); | 542 | static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0); |
541 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); | 543 | static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0); |
542 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); | 544 | static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0); |
545 | static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0); | ||
543 | 546 | ||
544 | /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ | 547 | /* {0, +20, +24, +30, +35, +40, +44, +50, +52} dB */ |
545 | static unsigned int bst_tlv[] = { | 548 | static unsigned int bst_tlv[] = { |
@@ -604,6 +607,10 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = { | |||
604 | RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, | 607 | RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0, |
605 | adc_vol_tlv), | 608 | adc_vol_tlv), |
606 | 609 | ||
610 | /* Sidetone Control */ | ||
611 | SOC_SINGLE_TLV("Sidetone Volume", RT5677_SIDETONE_CTRL, | ||
612 | RT5677_ST_VOL_SFT, 31, 0, st_vol_tlv), | ||
613 | |||
607 | /* ADC Boost Volume Control */ | 614 | /* ADC Boost Volume Control */ |
608 | SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST, | 615 | SOC_DOUBLE_TLV("STO1 ADC Boost Volume", RT5677_STO1_2_ADC_BST, |
609 | RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0, | 616 | RT5677_STO1_ADC_L_BST_SFT, RT5677_STO1_ADC_R_BST_SFT, 3, 0, |
@@ -1700,14 +1707,19 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1700 | 1707 | ||
1701 | SND_SOC_DAPM_INPUT("Haptic Generator"), | 1708 | SND_SOC_DAPM_INPUT("Haptic Generator"), |
1702 | 1709 | ||
1703 | SND_SOC_DAPM_PGA("DMIC1", RT5677_DMIC_CTRL1, RT5677_DMIC_1_EN_SFT, 0, | 1710 | SND_SOC_DAPM_PGA("DMIC1", SND_SOC_NOPM, 0, 0, NULL, 0), |
1704 | NULL, 0), | 1711 | SND_SOC_DAPM_PGA("DMIC2", SND_SOC_NOPM, 0, 0, NULL, 0), |
1705 | SND_SOC_DAPM_PGA("DMIC2", RT5677_DMIC_CTRL1, RT5677_DMIC_2_EN_SFT, 0, | 1712 | SND_SOC_DAPM_PGA("DMIC3", SND_SOC_NOPM, 0, 0, NULL, 0), |
1706 | NULL, 0), | 1713 | SND_SOC_DAPM_PGA("DMIC4", SND_SOC_NOPM, 0, 0, NULL, 0), |
1707 | SND_SOC_DAPM_PGA("DMIC3", RT5677_DMIC_CTRL1, RT5677_DMIC_3_EN_SFT, 0, | 1714 | |
1708 | NULL, 0), | 1715 | SND_SOC_DAPM_SUPPLY("DMIC1 power", RT5677_DMIC_CTRL1, |
1709 | SND_SOC_DAPM_PGA("DMIC4", RT5677_DMIC_CTRL2, RT5677_DMIC_4_EN_SFT, 0, | 1716 | RT5677_DMIC_1_EN_SFT, 0, NULL, 0), |
1710 | NULL, 0), | 1717 | SND_SOC_DAPM_SUPPLY("DMIC2 power", RT5677_DMIC_CTRL1, |
1718 | RT5677_DMIC_2_EN_SFT, 0, NULL, 0), | ||
1719 | SND_SOC_DAPM_SUPPLY("DMIC3 power", RT5677_DMIC_CTRL1, | ||
1720 | RT5677_DMIC_3_EN_SFT, 0, NULL, 0), | ||
1721 | SND_SOC_DAPM_SUPPLY("DMIC4 power", RT5677_DMIC_CTRL2, | ||
1722 | RT5677_DMIC_4_EN_SFT, 0, NULL, 0), | ||
1711 | 1723 | ||
1712 | SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, | 1724 | SND_SOC_DAPM_SUPPLY("DMIC CLK", SND_SOC_NOPM, 0, 0, |
1713 | set_dmic_clk, SND_SOC_DAPM_PRE_PMU), | 1725 | set_dmic_clk, SND_SOC_DAPM_PRE_PMU), |
@@ -1987,6 +1999,9 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = { | |||
1987 | /* Sidetone Mux */ | 1999 | /* Sidetone Mux */ |
1988 | SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, | 2000 | SND_SOC_DAPM_MUX("Sidetone Mux", SND_SOC_NOPM, 0, 0, |
1989 | &rt5677_sidetone_mux), | 2001 | &rt5677_sidetone_mux), |
2002 | SND_SOC_DAPM_SUPPLY("Sidetone Power", RT5677_SIDETONE_CTRL, | ||
2003 | RT5677_ST_EN_SFT, 0, NULL, 0), | ||
2004 | |||
1990 | /* VAD Mux*/ | 2005 | /* VAD Mux*/ |
1991 | SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0, | 2006 | SND_SOC_DAPM_MUX("VAD ADC Mux", SND_SOC_NOPM, 0, 0, |
1992 | &rt5677_vad_src_mux), | 2007 | &rt5677_vad_src_mux), |
@@ -2130,15 +2145,22 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2130 | { "DMIC L4", NULL, "DMIC CLK" }, | 2145 | { "DMIC L4", NULL, "DMIC CLK" }, |
2131 | { "DMIC R4", NULL, "DMIC CLK" }, | 2146 | { "DMIC R4", NULL, "DMIC CLK" }, |
2132 | 2147 | ||
2148 | { "DMIC L1", NULL, "DMIC1 power" }, | ||
2149 | { "DMIC R1", NULL, "DMIC1 power" }, | ||
2150 | { "DMIC L3", NULL, "DMIC3 power" }, | ||
2151 | { "DMIC R3", NULL, "DMIC3 power" }, | ||
2152 | { "DMIC L4", NULL, "DMIC4 power" }, | ||
2153 | { "DMIC R4", NULL, "DMIC4 power" }, | ||
2154 | |||
2133 | { "BST1", NULL, "IN1P" }, | 2155 | { "BST1", NULL, "IN1P" }, |
2134 | { "BST1", NULL, "IN1N" }, | 2156 | { "BST1", NULL, "IN1N" }, |
2135 | { "BST2", NULL, "IN2P" }, | 2157 | { "BST2", NULL, "IN2P" }, |
2136 | { "BST2", NULL, "IN2N" }, | 2158 | { "BST2", NULL, "IN2N" }, |
2137 | 2159 | ||
2138 | { "IN1P", NULL, "micbias1" }, | 2160 | { "IN1P", NULL, "MICBIAS1" }, |
2139 | { "IN1N", NULL, "micbias1" }, | 2161 | { "IN1N", NULL, "MICBIAS1" }, |
2140 | { "IN2P", NULL, "micbias1" }, | 2162 | { "IN2P", NULL, "MICBIAS1" }, |
2141 | { "IN2N", NULL, "micbias1" }, | 2163 | { "IN2N", NULL, "MICBIAS1" }, |
2142 | 2164 | ||
2143 | { "ADC 1", NULL, "BST1" }, | 2165 | { "ADC 1", NULL, "BST1" }, |
2144 | { "ADC 1", NULL, "ADC 1 power" }, | 2166 | { "ADC 1", NULL, "ADC 1 power" }, |
@@ -2691,6 +2713,7 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2691 | { "Sidetone Mux", "DMIC4 L", "DMIC L4" }, | 2713 | { "Sidetone Mux", "DMIC4 L", "DMIC L4" }, |
2692 | { "Sidetone Mux", "ADC1", "ADC 1" }, | 2714 | { "Sidetone Mux", "ADC1", "ADC 1" }, |
2693 | { "Sidetone Mux", "ADC2", "ADC 2" }, | 2715 | { "Sidetone Mux", "ADC2", "ADC 2" }, |
2716 | { "Sidetone Mux", NULL, "Sidetone Power" }, | ||
2694 | 2717 | ||
2695 | { "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" }, | 2718 | { "Stereo DAC MIXL", "ST L Switch", "Sidetone Mux" }, |
2696 | { "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, | 2719 | { "Stereo DAC MIXL", "DAC1 L Switch", "DAC1 MIXL" }, |
@@ -2793,6 +2816,16 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = { | |||
2793 | { "PDM2R", NULL, "PDM2 R Mux" }, | 2816 | { "PDM2R", NULL, "PDM2 R Mux" }, |
2794 | }; | 2817 | }; |
2795 | 2818 | ||
2819 | static const struct snd_soc_dapm_route rt5677_dmic2_clk_1[] = { | ||
2820 | { "DMIC L2", NULL, "DMIC1 power" }, | ||
2821 | { "DMIC R2", NULL, "DMIC1 power" }, | ||
2822 | }; | ||
2823 | |||
2824 | static const struct snd_soc_dapm_route rt5677_dmic2_clk_2[] = { | ||
2825 | { "DMIC L2", NULL, "DMIC2 power" }, | ||
2826 | { "DMIC R2", NULL, "DMIC2 power" }, | ||
2827 | }; | ||
2828 | |||
2796 | static int rt5677_hw_params(struct snd_pcm_substream *substream, | 2829 | static int rt5677_hw_params(struct snd_pcm_substream *substream, |
2797 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | 2830 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) |
2798 | { | 2831 | { |
@@ -3084,6 +3117,59 @@ static int rt5677_set_dai_pll(struct snd_soc_dai *dai, int pll_id, int source, | |||
3084 | return 0; | 3117 | return 0; |
3085 | } | 3118 | } |
3086 | 3119 | ||
3120 | static int rt5677_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
3121 | unsigned int rx_mask, int slots, int slot_width) | ||
3122 | { | ||
3123 | struct snd_soc_codec *codec = dai->codec; | ||
3124 | unsigned int val = 0; | ||
3125 | |||
3126 | if (rx_mask || tx_mask) | ||
3127 | val |= (1 << 12); | ||
3128 | |||
3129 | switch (slots) { | ||
3130 | case 4: | ||
3131 | val |= (1 << 10); | ||
3132 | break; | ||
3133 | case 6: | ||
3134 | val |= (2 << 10); | ||
3135 | break; | ||
3136 | case 8: | ||
3137 | val |= (3 << 10); | ||
3138 | break; | ||
3139 | case 2: | ||
3140 | default: | ||
3141 | break; | ||
3142 | } | ||
3143 | |||
3144 | switch (slot_width) { | ||
3145 | case 20: | ||
3146 | val |= (1 << 8); | ||
3147 | break; | ||
3148 | case 24: | ||
3149 | val |= (2 << 8); | ||
3150 | break; | ||
3151 | case 32: | ||
3152 | val |= (3 << 8); | ||
3153 | break; | ||
3154 | case 16: | ||
3155 | default: | ||
3156 | break; | ||
3157 | } | ||
3158 | |||
3159 | switch (dai->id) { | ||
3160 | case RT5677_AIF1: | ||
3161 | snd_soc_update_bits(codec, RT5677_TDM1_CTRL1, 0x1f00, val); | ||
3162 | break; | ||
3163 | case RT5677_AIF2: | ||
3164 | snd_soc_update_bits(codec, RT5677_TDM2_CTRL1, 0x1f00, val); | ||
3165 | break; | ||
3166 | default: | ||
3167 | break; | ||
3168 | } | ||
3169 | |||
3170 | return 0; | ||
3171 | } | ||
3172 | |||
3087 | static int rt5677_set_bias_level(struct snd_soc_codec *codec, | 3173 | static int rt5677_set_bias_level(struct snd_soc_codec *codec, |
3088 | enum snd_soc_bias_level level) | 3174 | enum snd_soc_bias_level level) |
3089 | { | 3175 | { |
@@ -3138,12 +3224,148 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec, | |||
3138 | return 0; | 3224 | return 0; |
3139 | } | 3225 | } |
3140 | 3226 | ||
3227 | #ifdef CONFIG_GPIOLIB | ||
3228 | static inline struct rt5677_priv *gpio_to_rt5677(struct gpio_chip *chip) | ||
3229 | { | ||
3230 | return container_of(chip, struct rt5677_priv, gpio_chip); | ||
3231 | } | ||
3232 | |||
3233 | static void rt5677_gpio_set(struct gpio_chip *chip, unsigned offset, int value) | ||
3234 | { | ||
3235 | struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); | ||
3236 | |||
3237 | switch (offset) { | ||
3238 | case RT5677_GPIO1 ... RT5677_GPIO5: | ||
3239 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, | ||
3240 | 0x1 << (offset * 3 + 1), !!value << (offset * 3 + 1)); | ||
3241 | break; | ||
3242 | |||
3243 | case RT5677_GPIO6: | ||
3244 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, | ||
3245 | RT5677_GPIO6_OUT_MASK, !!value << RT5677_GPIO6_OUT_SFT); | ||
3246 | break; | ||
3247 | |||
3248 | default: | ||
3249 | break; | ||
3250 | } | ||
3251 | } | ||
3252 | |||
3253 | static int rt5677_gpio_direction_out(struct gpio_chip *chip, | ||
3254 | unsigned offset, int value) | ||
3255 | { | ||
3256 | struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); | ||
3257 | |||
3258 | switch (offset) { | ||
3259 | case RT5677_GPIO1 ... RT5677_GPIO5: | ||
3260 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, | ||
3261 | 0x3 << (offset * 3 + 1), | ||
3262 | (0x2 | !!value) << (offset * 3 + 1)); | ||
3263 | break; | ||
3264 | |||
3265 | case RT5677_GPIO6: | ||
3266 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, | ||
3267 | RT5677_GPIO6_DIR_MASK | RT5677_GPIO6_OUT_MASK, | ||
3268 | RT5677_GPIO6_DIR_OUT | !!value << RT5677_GPIO6_OUT_SFT); | ||
3269 | break; | ||
3270 | |||
3271 | default: | ||
3272 | break; | ||
3273 | } | ||
3274 | |||
3275 | return 0; | ||
3276 | } | ||
3277 | |||
3278 | static int rt5677_gpio_get(struct gpio_chip *chip, unsigned offset) | ||
3279 | { | ||
3280 | struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); | ||
3281 | int value, ret; | ||
3282 | |||
3283 | ret = regmap_read(rt5677->regmap, RT5677_GPIO_ST, &value); | ||
3284 | if (ret < 0) | ||
3285 | return ret; | ||
3286 | |||
3287 | return (value & (0x1 << offset)) >> offset; | ||
3288 | } | ||
3289 | |||
3290 | static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset) | ||
3291 | { | ||
3292 | struct rt5677_priv *rt5677 = gpio_to_rt5677(chip); | ||
3293 | |||
3294 | switch (offset) { | ||
3295 | case RT5677_GPIO1 ... RT5677_GPIO5: | ||
3296 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, | ||
3297 | 0x1 << (offset * 3 + 2), 0x0); | ||
3298 | break; | ||
3299 | |||
3300 | case RT5677_GPIO6: | ||
3301 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL3, | ||
3302 | RT5677_GPIO6_DIR_MASK, RT5677_GPIO6_DIR_IN); | ||
3303 | break; | ||
3304 | |||
3305 | default: | ||
3306 | break; | ||
3307 | } | ||
3308 | |||
3309 | return 0; | ||
3310 | } | ||
3311 | |||
3312 | static struct gpio_chip rt5677_template_chip = { | ||
3313 | .label = "rt5677", | ||
3314 | .owner = THIS_MODULE, | ||
3315 | .direction_output = rt5677_gpio_direction_out, | ||
3316 | .set = rt5677_gpio_set, | ||
3317 | .direction_input = rt5677_gpio_direction_in, | ||
3318 | .get = rt5677_gpio_get, | ||
3319 | .can_sleep = 1, | ||
3320 | }; | ||
3321 | |||
3322 | static void rt5677_init_gpio(struct i2c_client *i2c) | ||
3323 | { | ||
3324 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
3325 | int ret; | ||
3326 | |||
3327 | rt5677->gpio_chip = rt5677_template_chip; | ||
3328 | rt5677->gpio_chip.ngpio = RT5677_GPIO_NUM; | ||
3329 | rt5677->gpio_chip.dev = &i2c->dev; | ||
3330 | rt5677->gpio_chip.base = -1; | ||
3331 | |||
3332 | ret = gpiochip_add(&rt5677->gpio_chip); | ||
3333 | if (ret != 0) | ||
3334 | dev_err(&i2c->dev, "Failed to add GPIOs: %d\n", ret); | ||
3335 | } | ||
3336 | |||
3337 | static void rt5677_free_gpio(struct i2c_client *i2c) | ||
3338 | { | ||
3339 | struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c); | ||
3340 | |||
3341 | gpiochip_remove(&rt5677->gpio_chip); | ||
3342 | } | ||
3343 | #else | ||
3344 | static void rt5677_init_gpio(struct i2c_client *i2c) | ||
3345 | { | ||
3346 | } | ||
3347 | |||
3348 | static void rt5677_free_gpio(struct i2c_client *i2c) | ||
3349 | { | ||
3350 | } | ||
3351 | #endif | ||
3352 | |||
3141 | static int rt5677_probe(struct snd_soc_codec *codec) | 3353 | static int rt5677_probe(struct snd_soc_codec *codec) |
3142 | { | 3354 | { |
3143 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 3355 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
3144 | 3356 | ||
3145 | rt5677->codec = codec; | 3357 | rt5677->codec = codec; |
3146 | 3358 | ||
3359 | if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { | ||
3360 | snd_soc_dapm_add_routes(&codec->dapm, | ||
3361 | rt5677_dmic2_clk_2, | ||
3362 | ARRAY_SIZE(rt5677_dmic2_clk_2)); | ||
3363 | } else { /*use dmic1 clock by default*/ | ||
3364 | snd_soc_dapm_add_routes(&codec->dapm, | ||
3365 | rt5677_dmic2_clk_1, | ||
3366 | ARRAY_SIZE(rt5677_dmic2_clk_1)); | ||
3367 | } | ||
3368 | |||
3147 | rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); | 3369 | rt5677_set_bias_level(codec, SND_SOC_BIAS_OFF); |
3148 | 3370 | ||
3149 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); | 3371 | regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020); |
@@ -3157,6 +3379,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) | |||
3157 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 3379 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
3158 | 3380 | ||
3159 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); | 3381 | regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); |
3382 | if (gpio_is_valid(rt5677->pow_ldo2)) | ||
3383 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | ||
3160 | 3384 | ||
3161 | return 0; | 3385 | return 0; |
3162 | } | 3386 | } |
@@ -3168,6 +3392,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) | |||
3168 | 3392 | ||
3169 | regcache_cache_only(rt5677->regmap, true); | 3393 | regcache_cache_only(rt5677->regmap, true); |
3170 | regcache_mark_dirty(rt5677->regmap); | 3394 | regcache_mark_dirty(rt5677->regmap); |
3395 | if (gpio_is_valid(rt5677->pow_ldo2)) | ||
3396 | gpio_set_value_cansleep(rt5677->pow_ldo2, 0); | ||
3171 | 3397 | ||
3172 | return 0; | 3398 | return 0; |
3173 | } | 3399 | } |
@@ -3176,6 +3402,10 @@ static int rt5677_resume(struct snd_soc_codec *codec) | |||
3176 | { | 3402 | { |
3177 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); | 3403 | struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); |
3178 | 3404 | ||
3405 | if (gpio_is_valid(rt5677->pow_ldo2)) { | ||
3406 | gpio_set_value_cansleep(rt5677->pow_ldo2, 1); | ||
3407 | msleep(10); | ||
3408 | } | ||
3179 | regcache_cache_only(rt5677->regmap, false); | 3409 | regcache_cache_only(rt5677->regmap, false); |
3180 | regcache_sync(rt5677->regmap); | 3410 | regcache_sync(rt5677->regmap); |
3181 | 3411 | ||
@@ -3195,6 +3425,7 @@ static struct snd_soc_dai_ops rt5677_aif_dai_ops = { | |||
3195 | .set_fmt = rt5677_set_dai_fmt, | 3425 | .set_fmt = rt5677_set_dai_fmt, |
3196 | .set_sysclk = rt5677_set_dai_sysclk, | 3426 | .set_sysclk = rt5677_set_dai_sysclk, |
3197 | .set_pll = rt5677_set_dai_pll, | 3427 | .set_pll = rt5677_set_dai_pll, |
3428 | .set_tdm_slot = rt5677_set_tdm_slot, | ||
3198 | }; | 3429 | }; |
3199 | 3430 | ||
3200 | static struct snd_soc_dai_driver rt5677_dai[] = { | 3431 | static struct snd_soc_dai_driver rt5677_dai[] = { |
@@ -3333,6 +3564,35 @@ static const struct i2c_device_id rt5677_i2c_id[] = { | |||
3333 | }; | 3564 | }; |
3334 | MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); | 3565 | MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); |
3335 | 3566 | ||
3567 | static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) | ||
3568 | { | ||
3569 | rt5677->pdata.in1_diff = of_property_read_bool(np, | ||
3570 | "realtek,in1-differential"); | ||
3571 | rt5677->pdata.in2_diff = of_property_read_bool(np, | ||
3572 | "realtek,in2-differential"); | ||
3573 | rt5677->pdata.lout1_diff = of_property_read_bool(np, | ||
3574 | "realtek,lout1-differential"); | ||
3575 | rt5677->pdata.lout2_diff = of_property_read_bool(np, | ||
3576 | "realtek,lout2-differential"); | ||
3577 | rt5677->pdata.lout3_diff = of_property_read_bool(np, | ||
3578 | "realtek,lout3-differential"); | ||
3579 | |||
3580 | rt5677->pow_ldo2 = of_get_named_gpio(np, | ||
3581 | "realtek,pow-ldo2-gpio", 0); | ||
3582 | |||
3583 | /* | ||
3584 | * POW_LDO2 is optional (it may be statically tied on the board). | ||
3585 | * -ENOENT means that the property doesn't exist, i.e. there is no | ||
3586 | * GPIO, so is not an error. Any other error code means the property | ||
3587 | * exists, but could not be parsed. | ||
3588 | */ | ||
3589 | if (!gpio_is_valid(rt5677->pow_ldo2) && | ||
3590 | (rt5677->pow_ldo2 != -ENOENT)) | ||
3591 | return rt5677->pow_ldo2; | ||
3592 | |||
3593 | return 0; | ||
3594 | } | ||
3595 | |||
3336 | static int rt5677_i2c_probe(struct i2c_client *i2c, | 3596 | static int rt5677_i2c_probe(struct i2c_client *i2c, |
3337 | const struct i2c_device_id *id) | 3597 | const struct i2c_device_id *id) |
3338 | { | 3598 | { |
@@ -3351,6 +3611,33 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3351 | if (pdata) | 3611 | if (pdata) |
3352 | rt5677->pdata = *pdata; | 3612 | rt5677->pdata = *pdata; |
3353 | 3613 | ||
3614 | if (i2c->dev.of_node) { | ||
3615 | ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); | ||
3616 | if (ret) { | ||
3617 | dev_err(&i2c->dev, "Failed to parse device tree: %d\n", | ||
3618 | ret); | ||
3619 | return ret; | ||
3620 | } | ||
3621 | } else { | ||
3622 | rt5677->pow_ldo2 = -EINVAL; | ||
3623 | } | ||
3624 | |||
3625 | if (gpio_is_valid(rt5677->pow_ldo2)) { | ||
3626 | ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, | ||
3627 | GPIOF_OUT_INIT_HIGH, | ||
3628 | "RT5677 POW_LDO2"); | ||
3629 | if (ret < 0) { | ||
3630 | dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", | ||
3631 | rt5677->pow_ldo2, ret); | ||
3632 | return ret; | ||
3633 | } | ||
3634 | /* Wait a while until I2C bus becomes available. The datasheet | ||
3635 | * does not specify the exact we should wait but startup | ||
3636 | * sequence mentiones at least a few milliseconds. | ||
3637 | */ | ||
3638 | msleep(10); | ||
3639 | } | ||
3640 | |||
3354 | rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); | 3641 | rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap); |
3355 | if (IS_ERR(rt5677->regmap)) { | 3642 | if (IS_ERR(rt5677->regmap)) { |
3356 | ret = PTR_ERR(rt5677->regmap); | 3643 | ret = PTR_ERR(rt5677->regmap); |
@@ -3381,6 +3668,29 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3381 | regmap_update_bits(rt5677->regmap, RT5677_IN1, | 3668 | regmap_update_bits(rt5677->regmap, RT5677_IN1, |
3382 | RT5677_IN_DF2, RT5677_IN_DF2); | 3669 | RT5677_IN_DF2, RT5677_IN_DF2); |
3383 | 3670 | ||
3671 | if (rt5677->pdata.lout1_diff) | ||
3672 | regmap_update_bits(rt5677->regmap, RT5677_LOUT1, | ||
3673 | RT5677_LOUT1_L_DF, RT5677_LOUT1_L_DF); | ||
3674 | |||
3675 | if (rt5677->pdata.lout2_diff) | ||
3676 | regmap_update_bits(rt5677->regmap, RT5677_LOUT1, | ||
3677 | RT5677_LOUT2_L_DF, RT5677_LOUT2_L_DF); | ||
3678 | |||
3679 | if (rt5677->pdata.lout3_diff) | ||
3680 | regmap_update_bits(rt5677->regmap, RT5677_LOUT1, | ||
3681 | RT5677_LOUT3_L_DF, RT5677_LOUT3_L_DF); | ||
3682 | |||
3683 | if (rt5677->pdata.dmic2_clk_pin == RT5677_DMIC_CLK2) { | ||
3684 | regmap_update_bits(rt5677->regmap, RT5677_GEN_CTRL2, | ||
3685 | RT5677_GPIO5_FUNC_MASK, | ||
3686 | RT5677_GPIO5_FUNC_DMIC); | ||
3687 | regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL2, | ||
3688 | RT5677_GPIO5_DIR_MASK, | ||
3689 | RT5677_GPIO5_DIR_OUT); | ||
3690 | } | ||
3691 | |||
3692 | rt5677_init_gpio(i2c); | ||
3693 | |||
3384 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, | 3694 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677, |
3385 | rt5677_dai, ARRAY_SIZE(rt5677_dai)); | 3695 | rt5677_dai, ARRAY_SIZE(rt5677_dai)); |
3386 | } | 3696 | } |
@@ -3388,6 +3698,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, | |||
3388 | static int rt5677_i2c_remove(struct i2c_client *i2c) | 3698 | static int rt5677_i2c_remove(struct i2c_client *i2c) |
3389 | { | 3699 | { |
3390 | snd_soc_unregister_codec(&i2c->dev); | 3700 | snd_soc_unregister_codec(&i2c->dev); |
3701 | rt5677_free_gpio(i2c); | ||
3391 | 3702 | ||
3392 | return 0; | 3703 | return 0; |
3393 | } | 3704 | } |
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 863393e62096..d4eb6d5e6746 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h | |||
@@ -382,6 +382,10 @@ | |||
382 | #define RT5677_ST_SEL_SFT 9 | 382 | #define RT5677_ST_SEL_SFT 9 |
383 | #define RT5677_ST_EN (0x1 << 6) | 383 | #define RT5677_ST_EN (0x1 << 6) |
384 | #define RT5677_ST_EN_SFT 6 | 384 | #define RT5677_ST_EN_SFT 6 |
385 | #define RT5677_ST_GAIN (0x1 << 5) | ||
386 | #define RT5677_ST_GAIN_SFT 5 | ||
387 | #define RT5677_ST_VOL_MASK (0x1f << 0) | ||
388 | #define RT5677_ST_VOL_SFT 0 | ||
385 | 389 | ||
386 | /* Analog DAC1/2/3 Source Control (0x15) */ | 390 | /* Analog DAC1/2/3 Source Control (0x15) */ |
387 | #define RT5677_ANA_DAC3_SRC_SEL_MASK (0x3 << 4) | 391 | #define RT5677_ANA_DAC3_SRC_SEL_MASK (0x3 << 4) |
@@ -1287,16 +1291,16 @@ | |||
1287 | #define RT5677_PLL1_PD_SFT 8 | 1291 | #define RT5677_PLL1_PD_SFT 8 |
1288 | #define RT5677_PLL1_PD_1 (0x0 << 8) | 1292 | #define RT5677_PLL1_PD_1 (0x0 << 8) |
1289 | #define RT5677_PLL1_PD_2 (0x1 << 8) | 1293 | #define RT5677_PLL1_PD_2 (0x1 << 8) |
1290 | #define RT5671_DAC_OSR_MASK (0x3 << 6) | 1294 | #define RT5677_DAC_OSR_MASK (0x3 << 6) |
1291 | #define RT5671_DAC_OSR_SFT 6 | 1295 | #define RT5677_DAC_OSR_SFT 6 |
1292 | #define RT5671_DAC_OSR_128 (0x0 << 6) | 1296 | #define RT5677_DAC_OSR_128 (0x0 << 6) |
1293 | #define RT5671_DAC_OSR_64 (0x1 << 6) | 1297 | #define RT5677_DAC_OSR_64 (0x1 << 6) |
1294 | #define RT5671_DAC_OSR_32 (0x2 << 6) | 1298 | #define RT5677_DAC_OSR_32 (0x2 << 6) |
1295 | #define RT5671_ADC_OSR_MASK (0x3 << 4) | 1299 | #define RT5677_ADC_OSR_MASK (0x3 << 4) |
1296 | #define RT5671_ADC_OSR_SFT 4 | 1300 | #define RT5677_ADC_OSR_SFT 4 |
1297 | #define RT5671_ADC_OSR_128 (0x0 << 4) | 1301 | #define RT5677_ADC_OSR_128 (0x0 << 4) |
1298 | #define RT5671_ADC_OSR_64 (0x1 << 4) | 1302 | #define RT5677_ADC_OSR_64 (0x1 << 4) |
1299 | #define RT5671_ADC_OSR_32 (0x2 << 4) | 1303 | #define RT5677_ADC_OSR_32 (0x2 << 4) |
1300 | 1304 | ||
1301 | /* Global Clock Control 2 (0x81) */ | 1305 | /* Global Clock Control 2 (0x81) */ |
1302 | #define RT5677_PLL2_PR_SRC_MASK (0x1 << 15) | 1306 | #define RT5677_PLL2_PR_SRC_MASK (0x1 << 15) |
@@ -1312,18 +1316,18 @@ | |||
1312 | #define RT5677_PLL2_SRC_BCLK4 (0x4 << 12) | 1316 | #define RT5677_PLL2_SRC_BCLK4 (0x4 << 12) |
1313 | #define RT5677_PLL2_SRC_RCCLK (0x5 << 12) | 1317 | #define RT5677_PLL2_SRC_RCCLK (0x5 << 12) |
1314 | #define RT5677_PLL2_SRC_SLIM (0x6 << 12) | 1318 | #define RT5677_PLL2_SRC_SLIM (0x6 << 12) |
1315 | #define RT5671_DSP_ASRC_O_SRC (0x3 << 10) | 1319 | #define RT5677_DSP_ASRC_O_SRC (0x3 << 10) |
1316 | #define RT5671_DSP_ASRC_O_SRC_SFT 10 | 1320 | #define RT5677_DSP_ASRC_O_SRC_SFT 10 |
1317 | #define RT5671_DSP_ASRC_O_MCLK (0x0 << 10) | 1321 | #define RT5677_DSP_ASRC_O_MCLK (0x0 << 10) |
1318 | #define RT5671_DSP_ASRC_O_PLL1 (0x1 << 10) | 1322 | #define RT5677_DSP_ASRC_O_PLL1 (0x1 << 10) |
1319 | #define RT5671_DSP_ASRC_O_SLIM (0x2 << 10) | 1323 | #define RT5677_DSP_ASRC_O_SLIM (0x2 << 10) |
1320 | #define RT5671_DSP_ASRC_O_RCCLK (0x3 << 10) | 1324 | #define RT5677_DSP_ASRC_O_RCCLK (0x3 << 10) |
1321 | #define RT5671_DSP_ASRC_I_SRC (0x3 << 8) | 1325 | #define RT5677_DSP_ASRC_I_SRC (0x3 << 8) |
1322 | #define RT5671_DSP_ASRC_I_SRC_SFT 8 | 1326 | #define RT5677_DSP_ASRC_I_SRC_SFT 8 |
1323 | #define RT5671_DSP_ASRC_I_MCLK (0x0 << 8) | 1327 | #define RT5677_DSP_ASRC_I_MCLK (0x0 << 8) |
1324 | #define RT5671_DSP_ASRC_I_PLL1 (0x1 << 8) | 1328 | #define RT5677_DSP_ASRC_I_PLL1 (0x1 << 8) |
1325 | #define RT5671_DSP_ASRC_I_SLIM (0x2 << 8) | 1329 | #define RT5677_DSP_ASRC_I_SLIM (0x2 << 8) |
1326 | #define RT5671_DSP_ASRC_I_RCCLK (0x3 << 8) | 1330 | #define RT5677_DSP_ASRC_I_RCCLK (0x3 << 8) |
1327 | #define RT5677_DSP_CLK_SRC_MASK (0x1 << 7) | 1331 | #define RT5677_DSP_CLK_SRC_MASK (0x1 << 7) |
1328 | #define RT5677_DSP_CLK_SRC_SFT 7 | 1332 | #define RT5677_DSP_CLK_SRC_SFT 7 |
1329 | #define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7) | 1333 | #define RT5677_DSP_CLK_SRC_PLL2 (0x0 << 7) |
@@ -1363,6 +1367,110 @@ | |||
1363 | #define RT5677_SEL_SRC_IB01 (0x1 << 0) | 1367 | #define RT5677_SEL_SRC_IB01 (0x1 << 0) |
1364 | #define RT5677_SEL_SRC_IB01_SFT 0 | 1368 | #define RT5677_SEL_SRC_IB01_SFT 0 |
1365 | 1369 | ||
1370 | /* GPIO status (0xbf) */ | ||
1371 | #define RT5677_GPIO6_STATUS_MASK (0x1 << 5) | ||
1372 | #define RT5677_GPIO6_STATUS_SFT 5 | ||
1373 | #define RT5677_GPIO5_STATUS_MASK (0x1 << 4) | ||
1374 | #define RT5677_GPIO5_STATUS_SFT 4 | ||
1375 | #define RT5677_GPIO4_STATUS_MASK (0x1 << 3) | ||
1376 | #define RT5677_GPIO4_STATUS_SFT 3 | ||
1377 | #define RT5677_GPIO3_STATUS_MASK (0x1 << 2) | ||
1378 | #define RT5677_GPIO3_STATUS_SFT 2 | ||
1379 | #define RT5677_GPIO2_STATUS_MASK (0x1 << 1) | ||
1380 | #define RT5677_GPIO2_STATUS_SFT 1 | ||
1381 | #define RT5677_GPIO1_STATUS_MASK (0x1 << 0) | ||
1382 | #define RT5677_GPIO1_STATUS_SFT 0 | ||
1383 | |||
1384 | /* GPIO Control 1 (0xc0) */ | ||
1385 | #define RT5677_GPIO1_PIN_MASK (0x1 << 15) | ||
1386 | #define RT5677_GPIO1_PIN_SFT 15 | ||
1387 | #define RT5677_GPIO1_PIN_GPIO1 (0x0 << 15) | ||
1388 | #define RT5677_GPIO1_PIN_IRQ (0x1 << 15) | ||
1389 | #define RT5677_IPTV_MODE_MASK (0x1 << 14) | ||
1390 | #define RT5677_IPTV_MODE_SFT 14 | ||
1391 | #define RT5677_IPTV_MODE_GPIO (0x0 << 14) | ||
1392 | #define RT5677_IPTV_MODE_IPTV (0x1 << 14) | ||
1393 | #define RT5677_FUNC_MODE_MASK (0x1 << 13) | ||
1394 | #define RT5677_FUNC_MODE_SFT 13 | ||
1395 | #define RT5677_FUNC_MODE_DMIC_GPIO (0x0 << 13) | ||
1396 | #define RT5677_FUNC_MODE_JTAG (0x1 << 13) | ||
1397 | |||
1398 | /* GPIO Control 2 (0xc1) */ | ||
1399 | #define RT5677_GPIO5_DIR_MASK (0x1 << 14) | ||
1400 | #define RT5677_GPIO5_DIR_SFT 14 | ||
1401 | #define RT5677_GPIO5_DIR_IN (0x0 << 14) | ||
1402 | #define RT5677_GPIO5_DIR_OUT (0x1 << 14) | ||
1403 | #define RT5677_GPIO5_OUT_MASK (0x1 << 13) | ||
1404 | #define RT5677_GPIO5_OUT_SFT 13 | ||
1405 | #define RT5677_GPIO5_OUT_LO (0x0 << 13) | ||
1406 | #define RT5677_GPIO5_OUT_HI (0x1 << 13) | ||
1407 | #define RT5677_GPIO5_P_MASK (0x1 << 12) | ||
1408 | #define RT5677_GPIO5_P_SFT 12 | ||
1409 | #define RT5677_GPIO5_P_NOR (0x0 << 12) | ||
1410 | #define RT5677_GPIO5_P_INV (0x1 << 12) | ||
1411 | #define RT5677_GPIO4_DIR_MASK (0x1 << 11) | ||
1412 | #define RT5677_GPIO4_DIR_SFT 11 | ||
1413 | #define RT5677_GPIO4_DIR_IN (0x0 << 11) | ||
1414 | #define RT5677_GPIO4_DIR_OUT (0x1 << 11) | ||
1415 | #define RT5677_GPIO4_OUT_MASK (0x1 << 10) | ||
1416 | #define RT5677_GPIO4_OUT_SFT 10 | ||
1417 | #define RT5677_GPIO4_OUT_LO (0x0 << 10) | ||
1418 | #define RT5677_GPIO4_OUT_HI (0x1 << 10) | ||
1419 | #define RT5677_GPIO4_P_MASK (0x1 << 9) | ||
1420 | #define RT5677_GPIO4_P_SFT 9 | ||
1421 | #define RT5677_GPIO4_P_NOR (0x0 << 9) | ||
1422 | #define RT5677_GPIO4_P_INV (0x1 << 9) | ||
1423 | #define RT5677_GPIO3_DIR_MASK (0x1 << 8) | ||
1424 | #define RT5677_GPIO3_DIR_SFT 8 | ||
1425 | #define RT5677_GPIO3_DIR_IN (0x0 << 8) | ||
1426 | #define RT5677_GPIO3_DIR_OUT (0x1 << 8) | ||
1427 | #define RT5677_GPIO3_OUT_MASK (0x1 << 7) | ||
1428 | #define RT5677_GPIO3_OUT_SFT 7 | ||
1429 | #define RT5677_GPIO3_OUT_LO (0x0 << 7) | ||
1430 | #define RT5677_GPIO3_OUT_HI (0x1 << 7) | ||
1431 | #define RT5677_GPIO3_P_MASK (0x1 << 6) | ||
1432 | #define RT5677_GPIO3_P_SFT 6 | ||
1433 | #define RT5677_GPIO3_P_NOR (0x0 << 6) | ||
1434 | #define RT5677_GPIO3_P_INV (0x1 << 6) | ||
1435 | #define RT5677_GPIO2_DIR_MASK (0x1 << 5) | ||
1436 | #define RT5677_GPIO2_DIR_SFT 5 | ||
1437 | #define RT5677_GPIO2_DIR_IN (0x0 << 5) | ||
1438 | #define RT5677_GPIO2_DIR_OUT (0x1 << 5) | ||
1439 | #define RT5677_GPIO2_OUT_MASK (0x1 << 4) | ||
1440 | #define RT5677_GPIO2_OUT_SFT 4 | ||
1441 | #define RT5677_GPIO2_OUT_LO (0x0 << 4) | ||
1442 | #define RT5677_GPIO2_OUT_HI (0x1 << 4) | ||
1443 | #define RT5677_GPIO2_P_MASK (0x1 << 3) | ||
1444 | #define RT5677_GPIO2_P_SFT 3 | ||
1445 | #define RT5677_GPIO2_P_NOR (0x0 << 3) | ||
1446 | #define RT5677_GPIO2_P_INV (0x1 << 3) | ||
1447 | #define RT5677_GPIO1_DIR_MASK (0x1 << 2) | ||
1448 | #define RT5677_GPIO1_DIR_SFT 2 | ||
1449 | #define RT5677_GPIO1_DIR_IN (0x0 << 2) | ||
1450 | #define RT5677_GPIO1_DIR_OUT (0x1 << 2) | ||
1451 | #define RT5677_GPIO1_OUT_MASK (0x1 << 1) | ||
1452 | #define RT5677_GPIO1_OUT_SFT 1 | ||
1453 | #define RT5677_GPIO1_OUT_LO (0x0 << 1) | ||
1454 | #define RT5677_GPIO1_OUT_HI (0x1 << 1) | ||
1455 | #define RT5677_GPIO1_P_MASK (0x1 << 0) | ||
1456 | #define RT5677_GPIO1_P_SFT 0 | ||
1457 | #define RT5677_GPIO1_P_NOR (0x0 << 0) | ||
1458 | #define RT5677_GPIO1_P_INV (0x1 << 0) | ||
1459 | |||
1460 | /* GPIO Control 3 (0xc2) */ | ||
1461 | #define RT5677_GPIO6_DIR_MASK (0x1 << 2) | ||
1462 | #define RT5677_GPIO6_DIR_SFT 2 | ||
1463 | #define RT5677_GPIO6_DIR_IN (0x0 << 2) | ||
1464 | #define RT5677_GPIO6_DIR_OUT (0x1 << 2) | ||
1465 | #define RT5677_GPIO6_OUT_MASK (0x1 << 1) | ||
1466 | #define RT5677_GPIO6_OUT_SFT 1 | ||
1467 | #define RT5677_GPIO6_OUT_LO (0x0 << 1) | ||
1468 | #define RT5677_GPIO6_OUT_HI (0x1 << 1) | ||
1469 | #define RT5677_GPIO6_P_MASK (0x1 << 0) | ||
1470 | #define RT5677_GPIO6_P_SFT 0 | ||
1471 | #define RT5677_GPIO6_P_NOR (0x0 << 0) | ||
1472 | #define RT5677_GPIO6_P_INV (0x1 << 0) | ||
1473 | |||
1366 | /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ | 1474 | /* Virtual DSP Mixer Control (0xf7 0xf8 0xf9) */ |
1367 | #define RT5677_DSP_IB_01_H (0x1 << 15) | 1475 | #define RT5677_DSP_IB_01_H (0x1 << 15) |
1368 | #define RT5677_DSP_IB_01_H_SFT 15 | 1476 | #define RT5677_DSP_IB_01_H_SFT 15 |
@@ -1393,6 +1501,11 @@ | |||
1393 | #define RT5677_DSP_IB_9_L (0x1 << 1) | 1501 | #define RT5677_DSP_IB_9_L (0x1 << 1) |
1394 | #define RT5677_DSP_IB_9_L_SFT 1 | 1502 | #define RT5677_DSP_IB_9_L_SFT 1 |
1395 | 1503 | ||
1504 | /* General Control2 (0xfc)*/ | ||
1505 | #define RT5677_GPIO5_FUNC_MASK (0x1 << 9) | ||
1506 | #define RT5677_GPIO5_FUNC_GPIO (0x0 << 9) | ||
1507 | #define RT5677_GPIO5_FUNC_DMIC (0x1 << 9) | ||
1508 | |||
1396 | /* System Clock Source */ | 1509 | /* System Clock Source */ |
1397 | enum { | 1510 | enum { |
1398 | RT5677_SCLK_S_MCLK, | 1511 | RT5677_SCLK_S_MCLK, |
@@ -1418,6 +1531,16 @@ enum { | |||
1418 | RT5677_AIFS, | 1531 | RT5677_AIFS, |
1419 | }; | 1532 | }; |
1420 | 1533 | ||
1534 | enum { | ||
1535 | RT5677_GPIO1, | ||
1536 | RT5677_GPIO2, | ||
1537 | RT5677_GPIO3, | ||
1538 | RT5677_GPIO4, | ||
1539 | RT5677_GPIO5, | ||
1540 | RT5677_GPIO6, | ||
1541 | RT5677_GPIO_NUM, | ||
1542 | }; | ||
1543 | |||
1421 | struct rt5677_priv { | 1544 | struct rt5677_priv { |
1422 | struct snd_soc_codec *codec; | 1545 | struct snd_soc_codec *codec; |
1423 | struct rt5677_platform_data pdata; | 1546 | struct rt5677_platform_data pdata; |
@@ -1431,6 +1554,10 @@ struct rt5677_priv { | |||
1431 | int pll_src; | 1554 | int pll_src; |
1432 | int pll_in; | 1555 | int pll_in; |
1433 | int pll_out; | 1556 | int pll_out; |
1557 | int pow_ldo2; /* POW_LDO2 pin */ | ||
1558 | #ifdef CONFIG_GPIOLIB | ||
1559 | struct gpio_chip gpio_chip; | ||
1560 | #endif | ||
1434 | }; | 1561 | }; |
1435 | 1562 | ||
1436 | #endif /* __RT5677_H__ */ | 1563 | #endif /* __RT5677_H__ */ |
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e997d271728d..6bb77d76561b 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c | |||
@@ -626,6 +626,9 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate) | |||
626 | } else { | 626 | } else { |
627 | dev_err(codec->dev, | 627 | dev_err(codec->dev, |
628 | "PLL not supported in slave mode\n"); | 628 | "PLL not supported in slave mode\n"); |
629 | dev_err(codec->dev, "%d ratio is not supported. " | ||
630 | "SYS_MCLK needs to be 256, 384 or 512 * fs\n", | ||
631 | sgtl5000->sysclk / sys_fs); | ||
629 | return -EINVAL; | 632 | return -EINVAL; |
630 | } | 633 | } |
631 | } | 634 | } |
@@ -1073,26 +1076,6 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg) | |||
1073 | } | 1076 | } |
1074 | } | 1077 | } |
1075 | 1078 | ||
1076 | #ifdef CONFIG_SUSPEND | ||
1077 | static int sgtl5000_suspend(struct snd_soc_codec *codec) | ||
1078 | { | ||
1079 | sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1080 | |||
1081 | return 0; | ||
1082 | } | ||
1083 | |||
1084 | static int sgtl5000_resume(struct snd_soc_codec *codec) | ||
1085 | { | ||
1086 | /* Bring the codec back up to standby to enable regulators */ | ||
1087 | sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1088 | |||
1089 | return 0; | ||
1090 | } | ||
1091 | #else | ||
1092 | #define sgtl5000_suspend NULL | ||
1093 | #define sgtl5000_resume NULL | ||
1094 | #endif /* CONFIG_SUSPEND */ | ||
1095 | |||
1096 | /* | 1079 | /* |
1097 | * sgtl5000 has 3 internal power supplies: | 1080 | * sgtl5000 has 3 internal power supplies: |
1098 | * 1. VAG, normally set to vdda/2 | 1081 | * 1. VAG, normally set to vdda/2 |
@@ -1352,11 +1335,6 @@ static int sgtl5000_probe(struct snd_soc_codec *codec) | |||
1352 | */ | 1335 | */ |
1353 | snd_soc_write(codec, SGTL5000_DAP_CTRL, 0); | 1336 | snd_soc_write(codec, SGTL5000_DAP_CTRL, 0); |
1354 | 1337 | ||
1355 | /* leading to standby state */ | ||
1356 | ret = sgtl5000_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1357 | if (ret) | ||
1358 | goto err; | ||
1359 | |||
1360 | return 0; | 1338 | return 0; |
1361 | 1339 | ||
1362 | err: | 1340 | err: |
@@ -1373,8 +1351,6 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) | |||
1373 | { | 1351 | { |
1374 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); | 1352 | struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); |
1375 | 1353 | ||
1376 | sgtl5000_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1377 | |||
1378 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), | 1354 | regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), |
1379 | sgtl5000->supplies); | 1355 | sgtl5000->supplies); |
1380 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), | 1356 | regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), |
@@ -1387,9 +1363,8 @@ static int sgtl5000_remove(struct snd_soc_codec *codec) | |||
1387 | static struct snd_soc_codec_driver sgtl5000_driver = { | 1363 | static struct snd_soc_codec_driver sgtl5000_driver = { |
1388 | .probe = sgtl5000_probe, | 1364 | .probe = sgtl5000_probe, |
1389 | .remove = sgtl5000_remove, | 1365 | .remove = sgtl5000_remove, |
1390 | .suspend = sgtl5000_suspend, | ||
1391 | .resume = sgtl5000_resume, | ||
1392 | .set_bias_level = sgtl5000_set_bias_level, | 1366 | .set_bias_level = sgtl5000_set_bias_level, |
1367 | .suspend_bias_off = true, | ||
1393 | .controls = sgtl5000_snd_controls, | 1368 | .controls = sgtl5000_snd_controls, |
1394 | .num_controls = ARRAY_SIZE(sgtl5000_snd_controls), | 1369 | .num_controls = ARRAY_SIZE(sgtl5000_snd_controls), |
1395 | .dapm_widgets = sgtl5000_dapm_widgets, | 1370 | .dapm_widgets = sgtl5000_dapm_widgets, |
@@ -1442,6 +1417,7 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1442 | { | 1417 | { |
1443 | struct sgtl5000_priv *sgtl5000; | 1418 | struct sgtl5000_priv *sgtl5000; |
1444 | int ret, reg, rev; | 1419 | int ret, reg, rev; |
1420 | unsigned int mclk; | ||
1445 | 1421 | ||
1446 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), | 1422 | sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv), |
1447 | GFP_KERNEL); | 1423 | GFP_KERNEL); |
@@ -1465,6 +1441,14 @@ static int sgtl5000_i2c_probe(struct i2c_client *client, | |||
1465 | return ret; | 1441 | return ret; |
1466 | } | 1442 | } |
1467 | 1443 | ||
1444 | /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */ | ||
1445 | mclk = clk_get_rate(sgtl5000->mclk); | ||
1446 | if (mclk < 8000000 || mclk > 27000000) { | ||
1447 | dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n", | ||
1448 | mclk / 1000000, mclk / 1000 % 1000); | ||
1449 | return -EINVAL; | ||
1450 | } | ||
1451 | |||
1468 | ret = clk_prepare_enable(sgtl5000->mclk); | 1452 | ret = clk_prepare_enable(sgtl5000->mclk); |
1469 | if (ret) | 1453 | if (ret) |
1470 | return ret; | 1454 | return ret; |
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index e8680bea5f86..67ea55adb307 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c | |||
@@ -646,17 +646,6 @@ static struct snd_soc_dai_driver ssm2518_dai = { | |||
646 | .ops = &ssm2518_dai_ops, | 646 | .ops = &ssm2518_dai_ops, |
647 | }; | 647 | }; |
648 | 648 | ||
649 | static int ssm2518_probe(struct snd_soc_codec *codec) | ||
650 | { | ||
651 | return ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
652 | } | ||
653 | |||
654 | static int ssm2518_remove(struct snd_soc_codec *codec) | ||
655 | { | ||
656 | ssm2518_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, | 649 | static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, |
661 | int source, unsigned int freq, int dir) | 650 | int source, unsigned int freq, int dir) |
662 | { | 651 | { |
@@ -727,8 +716,6 @@ static int ssm2518_set_sysclk(struct snd_soc_codec *codec, int clk_id, | |||
727 | } | 716 | } |
728 | 717 | ||
729 | static struct snd_soc_codec_driver ssm2518_codec_driver = { | 718 | static struct snd_soc_codec_driver ssm2518_codec_driver = { |
730 | .probe = ssm2518_probe, | ||
731 | .remove = ssm2518_remove, | ||
732 | .set_bias_level = ssm2518_set_bias_level, | 719 | .set_bias_level = ssm2518_set_bias_level, |
733 | .set_sysclk = ssm2518_set_sysclk, | 720 | .set_sysclk = ssm2518_set_sysclk, |
734 | .idle_bias_off = true, | 721 | .idle_bias_off = true, |
diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index abd63d537173..0d9779d6bfda 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c | |||
@@ -41,10 +41,19 @@ static const struct i2c_device_id ssm2602_i2c_id[] = { | |||
41 | }; | 41 | }; |
42 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); | 42 | MODULE_DEVICE_TABLE(i2c, ssm2602_i2c_id); |
43 | 43 | ||
44 | static const struct of_device_id ssm2602_of_match[] = { | ||
45 | { .compatible = "adi,ssm2602", }, | ||
46 | { .compatible = "adi,ssm2603", }, | ||
47 | { .compatible = "adi,ssm2604", }, | ||
48 | { } | ||
49 | }; | ||
50 | MODULE_DEVICE_TABLE(of, ssm2602_of_match); | ||
51 | |||
44 | static struct i2c_driver ssm2602_i2c_driver = { | 52 | static struct i2c_driver ssm2602_i2c_driver = { |
45 | .driver = { | 53 | .driver = { |
46 | .name = "ssm2602", | 54 | .name = "ssm2602", |
47 | .owner = THIS_MODULE, | 55 | .owner = THIS_MODULE, |
56 | .of_match_table = ssm2602_of_match, | ||
48 | }, | 57 | }, |
49 | .probe = ssm2602_i2c_probe, | 58 | .probe = ssm2602_i2c_probe, |
50 | .remove = ssm2602_i2c_remove, | 59 | .remove = ssm2602_i2c_remove, |
diff --git a/sound/soc/codecs/ssm2602-spi.c b/sound/soc/codecs/ssm2602-spi.c index 2bf55e24a7bb..b5df14fbe3ad 100644 --- a/sound/soc/codecs/ssm2602-spi.c +++ b/sound/soc/codecs/ssm2602-spi.c | |||
@@ -26,10 +26,17 @@ static int ssm2602_spi_remove(struct spi_device *spi) | |||
26 | return 0; | 26 | return 0; |
27 | } | 27 | } |
28 | 28 | ||
29 | static const struct of_device_id ssm2602_of_match[] = { | ||
30 | { .compatible = "adi,ssm2602", }, | ||
31 | { } | ||
32 | }; | ||
33 | MODULE_DEVICE_TABLE(of, ssm2602_of_match); | ||
34 | |||
29 | static struct spi_driver ssm2602_spi_driver = { | 35 | static struct spi_driver ssm2602_spi_driver = { |
30 | .driver = { | 36 | .driver = { |
31 | .name = "ssm2602", | 37 | .name = "ssm2602", |
32 | .owner = THIS_MODULE, | 38 | .owner = THIS_MODULE, |
39 | .of_match_table = ssm2602_of_match, | ||
33 | }, | 40 | }, |
34 | .probe = ssm2602_spi_probe, | 41 | .probe = ssm2602_spi_probe, |
35 | .remove = ssm2602_spi_remove, | 42 | .remove = ssm2602_spi_remove, |
diff --git a/sound/soc/codecs/ssm2602.c b/sound/soc/codecs/ssm2602.c index 484b3bbe8624..314eaece1b7d 100644 --- a/sound/soc/codecs/ssm2602.c +++ b/sound/soc/codecs/ssm2602.c | |||
@@ -192,7 +192,7 @@ static const struct snd_pcm_hw_constraint_list ssm2602_constraints_12288000 = { | |||
192 | }; | 192 | }; |
193 | 193 | ||
194 | static const unsigned int ssm2602_rates_11289600[] = { | 194 | static const unsigned int ssm2602_rates_11289600[] = { |
195 | 8000, 44100, 88200, | 195 | 8000, 11025, 22050, 44100, 88200, |
196 | }; | 196 | }; |
197 | 197 | ||
198 | static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { | 198 | static const struct snd_pcm_hw_constraint_list ssm2602_constraints_11289600 = { |
@@ -237,6 +237,16 @@ static const struct ssm2602_coeff ssm2602_coeff_table[] = { | |||
237 | {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)}, | 237 | {18432000, 96000, SSM2602_COEFF_SRATE(0x7, 0x1, 0x0)}, |
238 | {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)}, | 238 | {12000000, 96000, SSM2602_COEFF_SRATE(0x7, 0x0, 0x1)}, |
239 | 239 | ||
240 | /* 11.025k */ | ||
241 | {11289600, 11025, SSM2602_COEFF_SRATE(0xc, 0x0, 0x0)}, | ||
242 | {16934400, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x0)}, | ||
243 | {12000000, 11025, SSM2602_COEFF_SRATE(0xc, 0x1, 0x1)}, | ||
244 | |||
245 | /* 22.05k */ | ||
246 | {11289600, 22050, SSM2602_COEFF_SRATE(0xd, 0x0, 0x0)}, | ||
247 | {16934400, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x0)}, | ||
248 | {12000000, 22050, SSM2602_COEFF_SRATE(0xd, 0x1, 0x1)}, | ||
249 | |||
240 | /* 44.1k */ | 250 | /* 44.1k */ |
241 | {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)}, | 251 | {11289600, 44100, SSM2602_COEFF_SRATE(0x8, 0x0, 0x0)}, |
242 | {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)}, | 252 | {16934400, 44100, SSM2602_COEFF_SRATE(0x8, 0x1, 0x0)}, |
@@ -467,7 +477,8 @@ static int ssm2602_set_bias_level(struct snd_soc_codec *codec, | |||
467 | return 0; | 477 | return 0; |
468 | } | 478 | } |
469 | 479 | ||
470 | #define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ | 480 | #define SSM2602_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ |
481 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050 |\ | ||
471 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ | 482 | SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ |
472 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ | 483 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ |
473 | SNDRV_PCM_RATE_96000) | 484 | SNDRV_PCM_RATE_96000) |
@@ -502,18 +513,11 @@ static struct snd_soc_dai_driver ssm2602_dai = { | |||
502 | .symmetric_samplebits = 1, | 513 | .symmetric_samplebits = 1, |
503 | }; | 514 | }; |
504 | 515 | ||
505 | static int ssm2602_suspend(struct snd_soc_codec *codec) | ||
506 | { | ||
507 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
508 | return 0; | ||
509 | } | ||
510 | |||
511 | static int ssm2602_resume(struct snd_soc_codec *codec) | 516 | static int ssm2602_resume(struct snd_soc_codec *codec) |
512 | { | 517 | { |
513 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); | 518 | struct ssm2602_priv *ssm2602 = snd_soc_codec_get_drvdata(codec); |
514 | 519 | ||
515 | regcache_sync(ssm2602->regmap); | 520 | regcache_sync(ssm2602->regmap); |
516 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
517 | 521 | ||
518 | return 0; | 522 | return 0; |
519 | } | 523 | } |
@@ -586,27 +590,14 @@ static int ssm260x_codec_probe(struct snd_soc_codec *codec) | |||
586 | break; | 590 | break; |
587 | } | 591 | } |
588 | 592 | ||
589 | if (ret) | 593 | return ret; |
590 | return ret; | ||
591 | |||
592 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
593 | |||
594 | return 0; | ||
595 | } | ||
596 | |||
597 | /* remove everything here */ | ||
598 | static int ssm2602_remove(struct snd_soc_codec *codec) | ||
599 | { | ||
600 | ssm2602_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
601 | return 0; | ||
602 | } | 594 | } |
603 | 595 | ||
604 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { | 596 | static struct snd_soc_codec_driver soc_codec_dev_ssm2602 = { |
605 | .probe = ssm260x_codec_probe, | 597 | .probe = ssm260x_codec_probe, |
606 | .remove = ssm2602_remove, | ||
607 | .suspend = ssm2602_suspend, | ||
608 | .resume = ssm2602_resume, | 598 | .resume = ssm2602_resume, |
609 | .set_bias_level = ssm2602_set_bias_level, | 599 | .set_bias_level = ssm2602_set_bias_level, |
600 | .suspend_bias_off = true, | ||
610 | 601 | ||
611 | .controls = ssm260x_snd_controls, | 602 | .controls = ssm260x_snd_controls, |
612 | .num_controls = ARRAY_SIZE(ssm260x_snd_controls), | 603 | .num_controls = ARRAY_SIZE(ssm260x_snd_controls), |
@@ -647,7 +638,7 @@ int ssm2602_probe(struct device *dev, enum ssm2602_type type, | |||
647 | return -ENOMEM; | 638 | return -ENOMEM; |
648 | 639 | ||
649 | dev_set_drvdata(dev, ssm2602); | 640 | dev_set_drvdata(dev, ssm2602); |
650 | ssm2602->type = SSM2602; | 641 | ssm2602->type = type; |
651 | ssm2602->regmap = regmap; | 642 | ssm2602->regmap = regmap; |
652 | 643 | ||
653 | return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, | 644 | return snd_soc_register_codec(dev, &soc_codec_dev_ssm2602, |
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c new file mode 100644 index 000000000000..4b5c17f8507e --- /dev/null +++ b/sound/soc/codecs/ssm4567.c | |||
@@ -0,0 +1,343 @@ | |||
1 | /* | ||
2 | * SSM4567 amplifier audio driver | ||
3 | * | ||
4 | * Copyright 2014 Google Chromium project. | ||
5 | * Author: Anatol Pomozov <anatol@chromium.org> | ||
6 | * | ||
7 | * Based on code copyright/by: | ||
8 | * Copyright 2013 Analog Devices Inc. | ||
9 | * | ||
10 | * Licensed under the GPL-2. | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/i2c.h> | ||
16 | #include <linux/regmap.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <sound/core.h> | ||
19 | #include <sound/pcm.h> | ||
20 | #include <sound/pcm_params.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/initval.h> | ||
23 | #include <sound/tlv.h> | ||
24 | |||
25 | #define SSM4567_REG_POWER_CTRL 0x00 | ||
26 | #define SSM4567_REG_AMP_SNS_CTRL 0x01 | ||
27 | #define SSM4567_REG_DAC_CTRL 0x02 | ||
28 | #define SSM4567_REG_DAC_VOLUME 0x03 | ||
29 | #define SSM4567_REG_SAI_CTRL_1 0x04 | ||
30 | #define SSM4567_REG_SAI_CTRL_2 0x05 | ||
31 | #define SSM4567_REG_SAI_PLACEMENT_1 0x06 | ||
32 | #define SSM4567_REG_SAI_PLACEMENT_2 0x07 | ||
33 | #define SSM4567_REG_SAI_PLACEMENT_3 0x08 | ||
34 | #define SSM4567_REG_SAI_PLACEMENT_4 0x09 | ||
35 | #define SSM4567_REG_SAI_PLACEMENT_5 0x0a | ||
36 | #define SSM4567_REG_SAI_PLACEMENT_6 0x0b | ||
37 | #define SSM4567_REG_BATTERY_V_OUT 0x0c | ||
38 | #define SSM4567_REG_LIMITER_CTRL_1 0x0d | ||
39 | #define SSM4567_REG_LIMITER_CTRL_2 0x0e | ||
40 | #define SSM4567_REG_LIMITER_CTRL_3 0x0f | ||
41 | #define SSM4567_REG_STATUS_1 0x10 | ||
42 | #define SSM4567_REG_STATUS_2 0x11 | ||
43 | #define SSM4567_REG_FAULT_CTRL 0x12 | ||
44 | #define SSM4567_REG_PDM_CTRL 0x13 | ||
45 | #define SSM4567_REG_MCLK_RATIO 0x14 | ||
46 | #define SSM4567_REG_BOOST_CTRL_1 0x15 | ||
47 | #define SSM4567_REG_BOOST_CTRL_2 0x16 | ||
48 | #define SSM4567_REG_SOFT_RESET 0xff | ||
49 | |||
50 | /* POWER_CTRL */ | ||
51 | #define SSM4567_POWER_APWDN_EN BIT(7) | ||
52 | #define SSM4567_POWER_BSNS_PWDN BIT(6) | ||
53 | #define SSM4567_POWER_VSNS_PWDN BIT(5) | ||
54 | #define SSM4567_POWER_ISNS_PWDN BIT(4) | ||
55 | #define SSM4567_POWER_BOOST_PWDN BIT(3) | ||
56 | #define SSM4567_POWER_AMP_PWDN BIT(2) | ||
57 | #define SSM4567_POWER_VBAT_ONLY BIT(1) | ||
58 | #define SSM4567_POWER_SPWDN BIT(0) | ||
59 | |||
60 | /* DAC_CTRL */ | ||
61 | #define SSM4567_DAC_HV BIT(7) | ||
62 | #define SSM4567_DAC_MUTE BIT(6) | ||
63 | #define SSM4567_DAC_HPF BIT(5) | ||
64 | #define SSM4567_DAC_LPM BIT(4) | ||
65 | #define SSM4567_DAC_FS_MASK 0x7 | ||
66 | #define SSM4567_DAC_FS_8000_12000 0x0 | ||
67 | #define SSM4567_DAC_FS_16000_24000 0x1 | ||
68 | #define SSM4567_DAC_FS_32000_48000 0x2 | ||
69 | #define SSM4567_DAC_FS_64000_96000 0x3 | ||
70 | #define SSM4567_DAC_FS_128000_192000 0x4 | ||
71 | |||
72 | struct ssm4567 { | ||
73 | struct regmap *regmap; | ||
74 | }; | ||
75 | |||
76 | static const struct reg_default ssm4567_reg_defaults[] = { | ||
77 | { SSM4567_REG_POWER_CTRL, 0x81 }, | ||
78 | { SSM4567_REG_AMP_SNS_CTRL, 0x09 }, | ||
79 | { SSM4567_REG_DAC_CTRL, 0x32 }, | ||
80 | { SSM4567_REG_DAC_VOLUME, 0x40 }, | ||
81 | { SSM4567_REG_SAI_CTRL_1, 0x00 }, | ||
82 | { SSM4567_REG_SAI_CTRL_2, 0x08 }, | ||
83 | { SSM4567_REG_SAI_PLACEMENT_1, 0x01 }, | ||
84 | { SSM4567_REG_SAI_PLACEMENT_2, 0x20 }, | ||
85 | { SSM4567_REG_SAI_PLACEMENT_3, 0x32 }, | ||
86 | { SSM4567_REG_SAI_PLACEMENT_4, 0x07 }, | ||
87 | { SSM4567_REG_SAI_PLACEMENT_5, 0x07 }, | ||
88 | { SSM4567_REG_SAI_PLACEMENT_6, 0x07 }, | ||
89 | { SSM4567_REG_BATTERY_V_OUT, 0x00 }, | ||
90 | { SSM4567_REG_LIMITER_CTRL_1, 0xa4 }, | ||
91 | { SSM4567_REG_LIMITER_CTRL_2, 0x73 }, | ||
92 | { SSM4567_REG_LIMITER_CTRL_3, 0x00 }, | ||
93 | { SSM4567_REG_STATUS_1, 0x00 }, | ||
94 | { SSM4567_REG_STATUS_2, 0x00 }, | ||
95 | { SSM4567_REG_FAULT_CTRL, 0x30 }, | ||
96 | { SSM4567_REG_PDM_CTRL, 0x40 }, | ||
97 | { SSM4567_REG_MCLK_RATIO, 0x11 }, | ||
98 | { SSM4567_REG_BOOST_CTRL_1, 0x03 }, | ||
99 | { SSM4567_REG_BOOST_CTRL_2, 0x00 }, | ||
100 | { SSM4567_REG_SOFT_RESET, 0x00 }, | ||
101 | }; | ||
102 | |||
103 | |||
104 | static bool ssm4567_readable_reg(struct device *dev, unsigned int reg) | ||
105 | { | ||
106 | switch (reg) { | ||
107 | case SSM4567_REG_POWER_CTRL ... SSM4567_REG_BOOST_CTRL_2: | ||
108 | return true; | ||
109 | default: | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | } | ||
114 | |||
115 | static bool ssm4567_writeable_reg(struct device *dev, unsigned int reg) | ||
116 | { | ||
117 | switch (reg) { | ||
118 | case SSM4567_REG_POWER_CTRL ... SSM4567_REG_SAI_PLACEMENT_6: | ||
119 | case SSM4567_REG_LIMITER_CTRL_1 ... SSM4567_REG_LIMITER_CTRL_3: | ||
120 | case SSM4567_REG_FAULT_CTRL ... SSM4567_REG_BOOST_CTRL_2: | ||
121 | /* The datasheet states that soft reset register is read-only, | ||
122 | * but logically it is write-only. */ | ||
123 | case SSM4567_REG_SOFT_RESET: | ||
124 | return true; | ||
125 | default: | ||
126 | return false; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static bool ssm4567_volatile_reg(struct device *dev, unsigned int reg) | ||
131 | { | ||
132 | switch (reg) { | ||
133 | case SSM4567_REG_BATTERY_V_OUT: | ||
134 | case SSM4567_REG_STATUS_1 ... SSM4567_REG_STATUS_2: | ||
135 | case SSM4567_REG_SOFT_RESET: | ||
136 | return true; | ||
137 | default: | ||
138 | return false; | ||
139 | } | ||
140 | } | ||
141 | |||
142 | static const DECLARE_TLV_DB_MINMAX_MUTE(ssm4567_vol_tlv, -7125, 2400); | ||
143 | |||
144 | static const struct snd_kcontrol_new ssm4567_snd_controls[] = { | ||
145 | SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0, | ||
146 | 0xff, 1, ssm4567_vol_tlv), | ||
147 | SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0), | ||
148 | }; | ||
149 | |||
150 | static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = { | ||
151 | SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1), | ||
152 | |||
153 | SND_SOC_DAPM_OUTPUT("OUT"), | ||
154 | }; | ||
155 | |||
156 | static const struct snd_soc_dapm_route ssm4567_routes[] = { | ||
157 | { "OUT", NULL, "DAC" }, | ||
158 | }; | ||
159 | |||
160 | static int ssm4567_hw_params(struct snd_pcm_substream *substream, | ||
161 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
162 | { | ||
163 | struct snd_soc_codec *codec = dai->codec; | ||
164 | struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec); | ||
165 | unsigned int rate = params_rate(params); | ||
166 | unsigned int dacfs; | ||
167 | |||
168 | if (rate >= 8000 && rate <= 12000) | ||
169 | dacfs = SSM4567_DAC_FS_8000_12000; | ||
170 | else if (rate >= 16000 && rate <= 24000) | ||
171 | dacfs = SSM4567_DAC_FS_16000_24000; | ||
172 | else if (rate >= 32000 && rate <= 48000) | ||
173 | dacfs = SSM4567_DAC_FS_32000_48000; | ||
174 | else if (rate >= 64000 && rate <= 96000) | ||
175 | dacfs = SSM4567_DAC_FS_64000_96000; | ||
176 | else if (rate >= 128000 && rate <= 192000) | ||
177 | dacfs = SSM4567_DAC_FS_128000_192000; | ||
178 | else | ||
179 | return -EINVAL; | ||
180 | |||
181 | return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL, | ||
182 | SSM4567_DAC_FS_MASK, dacfs); | ||
183 | } | ||
184 | |||
185 | static int ssm4567_mute(struct snd_soc_dai *dai, int mute) | ||
186 | { | ||
187 | struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(dai->codec); | ||
188 | unsigned int val; | ||
189 | |||
190 | val = mute ? SSM4567_DAC_MUTE : 0; | ||
191 | return regmap_update_bits(ssm4567->regmap, SSM4567_REG_DAC_CTRL, | ||
192 | SSM4567_DAC_MUTE, val); | ||
193 | } | ||
194 | |||
195 | static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable) | ||
196 | { | ||
197 | int ret = 0; | ||
198 | |||
199 | if (!enable) { | ||
200 | ret = regmap_update_bits(ssm4567->regmap, | ||
201 | SSM4567_REG_POWER_CTRL, | ||
202 | SSM4567_POWER_SPWDN, SSM4567_POWER_SPWDN); | ||
203 | regcache_mark_dirty(ssm4567->regmap); | ||
204 | } | ||
205 | |||
206 | regcache_cache_only(ssm4567->regmap, !enable); | ||
207 | |||
208 | if (enable) { | ||
209 | ret = regmap_update_bits(ssm4567->regmap, | ||
210 | SSM4567_REG_POWER_CTRL, | ||
211 | SSM4567_POWER_SPWDN, 0x00); | ||
212 | regcache_sync(ssm4567->regmap); | ||
213 | } | ||
214 | |||
215 | return ret; | ||
216 | } | ||
217 | |||
218 | static int ssm4567_set_bias_level(struct snd_soc_codec *codec, | ||
219 | enum snd_soc_bias_level level) | ||
220 | { | ||
221 | struct ssm4567 *ssm4567 = snd_soc_codec_get_drvdata(codec); | ||
222 | int ret = 0; | ||
223 | |||
224 | switch (level) { | ||
225 | case SND_SOC_BIAS_ON: | ||
226 | break; | ||
227 | case SND_SOC_BIAS_PREPARE: | ||
228 | break; | ||
229 | case SND_SOC_BIAS_STANDBY: | ||
230 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
231 | ret = ssm4567_set_power(ssm4567, true); | ||
232 | break; | ||
233 | case SND_SOC_BIAS_OFF: | ||
234 | ret = ssm4567_set_power(ssm4567, false); | ||
235 | break; | ||
236 | } | ||
237 | |||
238 | if (ret) | ||
239 | return ret; | ||
240 | |||
241 | codec->dapm.bias_level = level; | ||
242 | |||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | static const struct snd_soc_dai_ops ssm4567_dai_ops = { | ||
247 | .hw_params = ssm4567_hw_params, | ||
248 | .digital_mute = ssm4567_mute, | ||
249 | }; | ||
250 | |||
251 | static struct snd_soc_dai_driver ssm4567_dai = { | ||
252 | .name = "ssm4567-hifi", | ||
253 | .playback = { | ||
254 | .stream_name = "Playback", | ||
255 | .channels_min = 1, | ||
256 | .channels_max = 1, | ||
257 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
258 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | ||
259 | SNDRV_PCM_FMTBIT_S32, | ||
260 | }, | ||
261 | .ops = &ssm4567_dai_ops, | ||
262 | }; | ||
263 | |||
264 | static struct snd_soc_codec_driver ssm4567_codec_driver = { | ||
265 | .set_bias_level = ssm4567_set_bias_level, | ||
266 | .idle_bias_off = true, | ||
267 | |||
268 | .controls = ssm4567_snd_controls, | ||
269 | .num_controls = ARRAY_SIZE(ssm4567_snd_controls), | ||
270 | .dapm_widgets = ssm4567_dapm_widgets, | ||
271 | .num_dapm_widgets = ARRAY_SIZE(ssm4567_dapm_widgets), | ||
272 | .dapm_routes = ssm4567_routes, | ||
273 | .num_dapm_routes = ARRAY_SIZE(ssm4567_routes), | ||
274 | }; | ||
275 | |||
276 | static const struct regmap_config ssm4567_regmap_config = { | ||
277 | .val_bits = 8, | ||
278 | .reg_bits = 8, | ||
279 | |||
280 | .max_register = SSM4567_REG_SOFT_RESET, | ||
281 | .readable_reg = ssm4567_readable_reg, | ||
282 | .writeable_reg = ssm4567_writeable_reg, | ||
283 | .volatile_reg = ssm4567_volatile_reg, | ||
284 | |||
285 | .cache_type = REGCACHE_RBTREE, | ||
286 | .reg_defaults = ssm4567_reg_defaults, | ||
287 | .num_reg_defaults = ARRAY_SIZE(ssm4567_reg_defaults), | ||
288 | }; | ||
289 | |||
290 | static int ssm4567_i2c_probe(struct i2c_client *i2c, | ||
291 | const struct i2c_device_id *id) | ||
292 | { | ||
293 | struct ssm4567 *ssm4567; | ||
294 | int ret; | ||
295 | |||
296 | ssm4567 = devm_kzalloc(&i2c->dev, sizeof(*ssm4567), GFP_KERNEL); | ||
297 | if (ssm4567 == NULL) | ||
298 | return -ENOMEM; | ||
299 | |||
300 | i2c_set_clientdata(i2c, ssm4567); | ||
301 | |||
302 | ssm4567->regmap = devm_regmap_init_i2c(i2c, &ssm4567_regmap_config); | ||
303 | if (IS_ERR(ssm4567->regmap)) | ||
304 | return PTR_ERR(ssm4567->regmap); | ||
305 | |||
306 | ret = regmap_write(ssm4567->regmap, SSM4567_REG_SOFT_RESET, 0x00); | ||
307 | if (ret) | ||
308 | return ret; | ||
309 | |||
310 | ret = ssm4567_set_power(ssm4567, false); | ||
311 | if (ret) | ||
312 | return ret; | ||
313 | |||
314 | return snd_soc_register_codec(&i2c->dev, &ssm4567_codec_driver, | ||
315 | &ssm4567_dai, 1); | ||
316 | } | ||
317 | |||
318 | static int ssm4567_i2c_remove(struct i2c_client *client) | ||
319 | { | ||
320 | snd_soc_unregister_codec(&client->dev); | ||
321 | return 0; | ||
322 | } | ||
323 | |||
324 | static const struct i2c_device_id ssm4567_i2c_ids[] = { | ||
325 | { "ssm4567", 0 }, | ||
326 | { } | ||
327 | }; | ||
328 | MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); | ||
329 | |||
330 | static struct i2c_driver ssm4567_driver = { | ||
331 | .driver = { | ||
332 | .name = "ssm4567", | ||
333 | .owner = THIS_MODULE, | ||
334 | }, | ||
335 | .probe = ssm4567_i2c_probe, | ||
336 | .remove = ssm4567_i2c_remove, | ||
337 | .id_table = ssm4567_i2c_ids, | ||
338 | }; | ||
339 | module_i2c_driver(ssm4567_driver); | ||
340 | |||
341 | MODULE_DESCRIPTION("ASoC SSM4567 driver"); | ||
342 | MODULE_AUTHOR("Anatol Pomozov <anatol@chromium.org>"); | ||
343 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 9aa1323fb2ab..89c748dd3d6e 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver | 4 | * sound/soc/codecs/sta529.c -- spear ALSA Soc codec driver |
5 | * | 5 | * |
6 | * Copyright (C) 2012 ST Microelectronics | 6 | * Copyright (C) 2012 ST Microelectronics |
7 | * Rajeev Kumar <rajeev-dlh.kumar@st.com> | 7 | * Rajeev Kumar <rajeevkumar.linux@gmail.com> |
8 | * | 8 | * |
9 | * This file is licensed under the terms of the GNU General Public | 9 | * This file is licensed under the terms of the GNU General Public |
10 | * License version 2. This program is licensed "as is" without any | 10 | * License version 2. This program is licensed "as is" without any |
@@ -426,5 +426,5 @@ static struct i2c_driver sta529_i2c_driver = { | |||
426 | module_i2c_driver(sta529_i2c_driver); | 426 | module_i2c_driver(sta529_i2c_driver); |
427 | 427 | ||
428 | MODULE_DESCRIPTION("ASoC STA529 codec driver"); | 428 | MODULE_DESCRIPTION("ASoC STA529 codec driver"); |
429 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | 429 | MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); |
430 | MODULE_LICENSE("GPL"); | 430 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 23b32960ff1d..f039dc825971 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c | |||
@@ -78,6 +78,44 @@ struct tas2552_data { | |||
78 | unsigned int mclk; | 78 | unsigned int mclk; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | /* Input mux controls */ | ||
82 | static const char *tas2552_input_texts[] = { | ||
83 | "Digital", "Analog" | ||
84 | }; | ||
85 | |||
86 | static SOC_ENUM_SINGLE_DECL(tas2552_input_mux_enum, TAS2552_CFG_3, 7, | ||
87 | tas2552_input_texts); | ||
88 | |||
89 | static const struct snd_kcontrol_new tas2552_input_mux_control[] = { | ||
90 | SOC_DAPM_ENUM("Input selection", tas2552_input_mux_enum) | ||
91 | }; | ||
92 | |||
93 | static const struct snd_soc_dapm_widget tas2552_dapm_widgets[] = | ||
94 | { | ||
95 | SND_SOC_DAPM_INPUT("IN"), | ||
96 | |||
97 | /* MUX Controls */ | ||
98 | SND_SOC_DAPM_MUX("Input selection", SND_SOC_NOPM, 0, 0, | ||
99 | tas2552_input_mux_control), | ||
100 | |||
101 | SND_SOC_DAPM_AIF_IN("DAC IN", "DAC Playback", 0, SND_SOC_NOPM, 0, 0), | ||
102 | SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), | ||
103 | SND_SOC_DAPM_OUT_DRV("ClassD", TAS2552_CFG_2, 7, 0, NULL, 0), | ||
104 | SND_SOC_DAPM_SUPPLY("PLL", TAS2552_CFG_2, 3, 0, NULL, 0), | ||
105 | |||
106 | SND_SOC_DAPM_OUTPUT("OUT") | ||
107 | }; | ||
108 | |||
109 | static const struct snd_soc_dapm_route tas2552_audio_map[] = { | ||
110 | {"DAC", NULL, "DAC IN"}, | ||
111 | {"Input selection", "Digital", "DAC"}, | ||
112 | {"Input selection", "Analog", "IN"}, | ||
113 | {"ClassD", NULL, "Input selection"}, | ||
114 | {"OUT", NULL, "ClassD"}, | ||
115 | {"ClassD", NULL, "PLL"}, | ||
116 | }; | ||
117 | |||
118 | #ifdef CONFIG_PM_RUNTIME | ||
81 | static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) | 119 | static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) |
82 | { | 120 | { |
83 | u8 cfg1_reg; | 121 | u8 cfg1_reg; |
@@ -90,6 +128,7 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) | |||
90 | snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, | 128 | snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, |
91 | TAS2552_SWS_MASK, cfg1_reg); | 129 | TAS2552_SWS_MASK, cfg1_reg); |
92 | } | 130 | } |
131 | #endif | ||
93 | 132 | ||
94 | static int tas2552_hw_params(struct snd_pcm_substream *substream, | 133 | static int tas2552_hw_params(struct snd_pcm_substream *substream, |
95 | struct snd_pcm_hw_params *params, | 134 | struct snd_pcm_hw_params *params, |
@@ -101,10 +140,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, | |||
101 | int d; | 140 | int d; |
102 | u8 p, j; | 141 | u8 p, j; |
103 | 142 | ||
104 | /* Turn on Class D amplifier */ | ||
105 | snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK, | ||
106 | TAS2552_CLASSD_EN); | ||
107 | |||
108 | if (!tas2552->mclk) | 143 | if (!tas2552->mclk) |
109 | return -EINVAL; | 144 | return -EINVAL; |
110 | 145 | ||
@@ -147,9 +182,6 @@ static int tas2552_hw_params(struct snd_pcm_substream *substream, | |||
147 | 182 | ||
148 | } | 183 | } |
149 | 184 | ||
150 | snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, | ||
151 | TAS2552_PLL_ENABLE); | ||
152 | |||
153 | return 0; | 185 | return 0; |
154 | } | 186 | } |
155 | 187 | ||
@@ -269,19 +301,10 @@ static const struct dev_pm_ops tas2552_pm = { | |||
269 | NULL) | 301 | NULL) |
270 | }; | 302 | }; |
271 | 303 | ||
272 | static void tas2552_shutdown(struct snd_pcm_substream *substream, | ||
273 | struct snd_soc_dai *dai) | ||
274 | { | ||
275 | struct snd_soc_codec *codec = dai->codec; | ||
276 | |||
277 | snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); | ||
278 | } | ||
279 | |||
280 | static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { | 304 | static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { |
281 | .hw_params = tas2552_hw_params, | 305 | .hw_params = tas2552_hw_params, |
282 | .set_sysclk = tas2552_set_dai_sysclk, | 306 | .set_sysclk = tas2552_set_dai_sysclk, |
283 | .set_fmt = tas2552_set_dai_fmt, | 307 | .set_fmt = tas2552_set_dai_fmt, |
284 | .shutdown = tas2552_shutdown, | ||
285 | .digital_mute = tas2552_mute, | 308 | .digital_mute = tas2552_mute, |
286 | }; | 309 | }; |
287 | 310 | ||
@@ -294,7 +317,7 @@ static struct snd_soc_dai_driver tas2552_dai[] = { | |||
294 | { | 317 | { |
295 | .name = "tas2552-amplifier", | 318 | .name = "tas2552-amplifier", |
296 | .playback = { | 319 | .playback = { |
297 | .stream_name = "Speaker", | 320 | .stream_name = "Playback", |
298 | .channels_min = 2, | 321 | .channels_min = 2, |
299 | .channels_max = 2, | 322 | .channels_max = 2, |
300 | .rates = SNDRV_PCM_RATE_8000_192000, | 323 | .rates = SNDRV_PCM_RATE_8000_192000, |
@@ -312,6 +335,7 @@ static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24); | |||
312 | static const struct snd_kcontrol_new tas2552_snd_controls[] = { | 335 | static const struct snd_kcontrol_new tas2552_snd_controls[] = { |
313 | SOC_SINGLE_TLV("Speaker Driver Playback Volume", | 336 | SOC_SINGLE_TLV("Speaker Driver Playback Volume", |
314 | TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv), | 337 | TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv), |
338 | SOC_DAPM_SINGLE("Playback AMP", SND_SOC_NOPM, 0, 1, 0), | ||
315 | }; | 339 | }; |
316 | 340 | ||
317 | static const struct reg_default tas2552_init_regs[] = { | 341 | static const struct reg_default tas2552_init_regs[] = { |
@@ -321,6 +345,7 @@ static const struct reg_default tas2552_init_regs[] = { | |||
321 | static int tas2552_codec_probe(struct snd_soc_codec *codec) | 345 | static int tas2552_codec_probe(struct snd_soc_codec *codec) |
322 | { | 346 | { |
323 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); | 347 | struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); |
348 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
324 | int ret; | 349 | int ret; |
325 | 350 | ||
326 | tas2552->codec = codec; | 351 | tas2552->codec = codec; |
@@ -362,9 +387,14 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec) | |||
362 | goto patch_fail; | 387 | goto patch_fail; |
363 | } | 388 | } |
364 | 389 | ||
365 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN | | 390 | snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN | |
366 | TAS2552_BOOST_EN | TAS2552_APT_EN | | 391 | TAS2552_APT_EN | TAS2552_LIM_EN); |
367 | TAS2552_LIM_EN); | 392 | |
393 | snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets, | ||
394 | ARRAY_SIZE(tas2552_dapm_widgets)); | ||
395 | snd_soc_dapm_add_routes(dapm, tas2552_audio_map, | ||
396 | ARRAY_SIZE(tas2552_audio_map)); | ||
397 | |||
368 | return 0; | 398 | return 0; |
369 | 399 | ||
370 | patch_fail: | 400 | patch_fail: |
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 0f64c7890eed..145fe5b253d4 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c | |||
@@ -167,13 +167,13 @@ struct aic31xx_priv { | |||
167 | struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; | 167 | struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; |
168 | struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; | 168 | struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; |
169 | unsigned int sysclk; | 169 | unsigned int sysclk; |
170 | u8 p_div; | ||
170 | int rate_div_line; | 171 | int rate_div_line; |
171 | }; | 172 | }; |
172 | 173 | ||
173 | struct aic31xx_rate_divs { | 174 | struct aic31xx_rate_divs { |
174 | u32 mclk; | 175 | u32 mclk_p; |
175 | u32 rate; | 176 | u32 rate; |
176 | u8 p_val; | ||
177 | u8 pll_j; | 177 | u8 pll_j; |
178 | u16 pll_d; | 178 | u16 pll_d; |
179 | u16 dosr; | 179 | u16 dosr; |
@@ -186,51 +186,51 @@ struct aic31xx_rate_divs { | |||
186 | 186 | ||
187 | /* ADC dividers can be disabled by cofiguring them to 0 */ | 187 | /* ADC dividers can be disabled by cofiguring them to 0 */ |
188 | static const struct aic31xx_rate_divs aic31xx_divs[] = { | 188 | static const struct aic31xx_rate_divs aic31xx_divs[] = { |
189 | /* mclk rate pll: p j d dosr ndac mdac aors nadc madc */ | 189 | /* mclk/p rate pll: j d dosr ndac mdac aors nadc madc */ |
190 | /* 8k rate */ | 190 | /* 8k rate */ |
191 | {12000000, 8000, 1, 8, 1920, 128, 48, 2, 128, 48, 2}, | 191 | {12000000, 8000, 8, 1920, 128, 48, 2, 128, 48, 2}, |
192 | {24000000, 8000, 2, 8, 1920, 128, 48, 2, 128, 48, 2}, | 192 | {12000000, 8000, 8, 1920, 128, 32, 3, 128, 32, 3}, |
193 | {25000000, 8000, 2, 7, 8643, 128, 48, 2, 128, 48, 2}, | 193 | {12500000, 8000, 7, 8643, 128, 48, 2, 128, 48, 2}, |
194 | /* 11.025k rate */ | 194 | /* 11.025k rate */ |
195 | {12000000, 11025, 1, 7, 5264, 128, 32, 2, 128, 32, 2}, | 195 | {12000000, 11025, 7, 5264, 128, 32, 2, 128, 32, 2}, |
196 | {24000000, 11025, 2, 7, 5264, 128, 32, 2, 128, 32, 2}, | 196 | {12000000, 11025, 8, 4672, 128, 24, 3, 128, 24, 3}, |
197 | {25000000, 11025, 2, 7, 2253, 128, 32, 2, 128, 32, 2}, | 197 | {12500000, 11025, 7, 2253, 128, 32, 2, 128, 32, 2}, |
198 | /* 16k rate */ | 198 | /* 16k rate */ |
199 | {12000000, 16000, 1, 8, 1920, 128, 24, 2, 128, 24, 2}, | 199 | {12000000, 16000, 8, 1920, 128, 24, 2, 128, 24, 2}, |
200 | {24000000, 16000, 2, 8, 1920, 128, 24, 2, 128, 24, 2}, | 200 | {12000000, 16000, 8, 1920, 128, 16, 3, 128, 16, 3}, |
201 | {25000000, 16000, 2, 7, 8643, 128, 24, 2, 128, 24, 2}, | 201 | {12500000, 16000, 7, 8643, 128, 24, 2, 128, 24, 2}, |
202 | /* 22.05k rate */ | 202 | /* 22.05k rate */ |
203 | {12000000, 22050, 1, 7, 5264, 128, 16, 2, 128, 16, 2}, | 203 | {12000000, 22050, 7, 5264, 128, 16, 2, 128, 16, 2}, |
204 | {24000000, 22050, 2, 7, 5264, 128, 16, 2, 128, 16, 2}, | 204 | {12000000, 22050, 8, 4672, 128, 12, 3, 128, 12, 3}, |
205 | {25000000, 22050, 2, 7, 2253, 128, 16, 2, 128, 16, 2}, | 205 | {12500000, 22050, 7, 2253, 128, 16, 2, 128, 16, 2}, |
206 | /* 32k rate */ | 206 | /* 32k rate */ |
207 | {12000000, 32000, 1, 8, 1920, 128, 12, 2, 128, 12, 2}, | 207 | {12000000, 32000, 8, 1920, 128, 12, 2, 128, 12, 2}, |
208 | {24000000, 32000, 2, 8, 1920, 128, 12, 2, 128, 12, 2}, | 208 | {12000000, 32000, 8, 1920, 128, 8, 3, 128, 8, 3}, |
209 | {25000000, 32000, 2, 7, 8643, 128, 12, 2, 128, 12, 2}, | 209 | {12500000, 32000, 7, 8643, 128, 12, 2, 128, 12, 2}, |
210 | /* 44.1k rate */ | 210 | /* 44.1k rate */ |
211 | {12000000, 44100, 1, 7, 5264, 128, 8, 2, 128, 8, 2}, | 211 | {12000000, 44100, 7, 5264, 128, 8, 2, 128, 8, 2}, |
212 | {24000000, 44100, 2, 7, 5264, 128, 8, 2, 128, 8, 2}, | 212 | {12000000, 44100, 8, 4672, 128, 6, 3, 128, 6, 3}, |
213 | {25000000, 44100, 2, 7, 2253, 128, 8, 2, 128, 8, 2}, | 213 | {12500000, 44100, 7, 2253, 128, 8, 2, 128, 8, 2}, |
214 | /* 48k rate */ | 214 | /* 48k rate */ |
215 | {12000000, 48000, 1, 8, 1920, 128, 8, 2, 128, 8, 2}, | 215 | {12000000, 48000, 8, 1920, 128, 8, 2, 128, 8, 2}, |
216 | {24000000, 48000, 2, 8, 1920, 128, 8, 2, 128, 8, 2}, | 216 | {12000000, 48000, 7, 6800, 96, 5, 4, 96, 5, 4}, |
217 | {25000000, 48000, 2, 7, 8643, 128, 8, 2, 128, 8, 2}, | 217 | {12500000, 48000, 7, 8643, 128, 8, 2, 128, 8, 2}, |
218 | /* 88.2k rate */ | 218 | /* 88.2k rate */ |
219 | {12000000, 88200, 1, 7, 5264, 64, 8, 2, 64, 8, 2}, | 219 | {12000000, 88200, 7, 5264, 64, 8, 2, 64, 8, 2}, |
220 | {24000000, 88200, 2, 7, 5264, 64, 8, 2, 64, 8, 2}, | 220 | {12000000, 88200, 8, 4672, 64, 6, 3, 64, 6, 3}, |
221 | {25000000, 88200, 2, 7, 2253, 64, 8, 2, 64, 8, 2}, | 221 | {12500000, 88200, 7, 2253, 64, 8, 2, 64, 8, 2}, |
222 | /* 96k rate */ | 222 | /* 96k rate */ |
223 | {12000000, 96000, 1, 8, 1920, 64, 8, 2, 64, 8, 2}, | 223 | {12000000, 96000, 8, 1920, 64, 8, 2, 64, 8, 2}, |
224 | {24000000, 96000, 2, 8, 1920, 64, 8, 2, 64, 8, 2}, | 224 | {12000000, 96000, 7, 6800, 48, 5, 4, 48, 5, 4}, |
225 | {25000000, 96000, 2, 7, 8643, 64, 8, 2, 64, 8, 2}, | 225 | {12500000, 96000, 7, 8643, 64, 8, 2, 64, 8, 2}, |
226 | /* 176.4k rate */ | 226 | /* 176.4k rate */ |
227 | {12000000, 176400, 1, 7, 5264, 32, 8, 2, 32, 8, 2}, | 227 | {12000000, 176400, 7, 5264, 32, 8, 2, 32, 8, 2}, |
228 | {24000000, 176400, 2, 7, 5264, 32, 8, 2, 32, 8, 2}, | 228 | {12000000, 176400, 8, 4672, 32, 6, 3, 32, 6, 3}, |
229 | {25000000, 176400, 2, 7, 2253, 32, 8, 2, 32, 8, 2}, | 229 | {12500000, 176400, 7, 2253, 32, 8, 2, 32, 8, 2}, |
230 | /* 192k rate */ | 230 | /* 192k rate */ |
231 | {12000000, 192000, 1, 8, 1920, 32, 8, 2, 32, 8, 2}, | 231 | {12000000, 192000, 8, 1920, 32, 8, 2, 32, 8, 2}, |
232 | {24000000, 192000, 2, 8, 1920, 32, 8, 2, 32, 8, 2}, | 232 | {12000000, 192000, 7, 6800, 24, 5, 4, 24, 5, 4}, |
233 | {25000000, 192000, 2, 7, 8643, 32, 8, 2, 32, 8, 2}, | 233 | {12500000, 192000, 7, 8643, 32, 8, 2, 32, 8, 2}, |
234 | }; | 234 | }; |
235 | 235 | ||
236 | static const char * const ldac_in_text[] = { | 236 | static const char * const ldac_in_text[] = { |
@@ -680,7 +680,10 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, | |||
680 | struct snd_pcm_hw_params *params) | 680 | struct snd_pcm_hw_params *params) |
681 | { | 681 | { |
682 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); | 682 | struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); |
683 | int bclk_score = snd_soc_params_to_frame_size(params); | ||
684 | int mclk_p = aic31xx->sysclk / aic31xx->p_div; | ||
683 | int bclk_n = 0; | 685 | int bclk_n = 0; |
686 | int match = -1; | ||
684 | int i; | 687 | int i; |
685 | 688 | ||
686 | /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ | 689 | /* Use PLL as CODEC_CLKIN and DAC_CLK as BDIV_CLKIN */ |
@@ -691,19 +694,41 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, | |||
691 | 694 | ||
692 | for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) { | 695 | for (i = 0; i < ARRAY_SIZE(aic31xx_divs); i++) { |
693 | if (aic31xx_divs[i].rate == params_rate(params) && | 696 | if (aic31xx_divs[i].rate == params_rate(params) && |
694 | aic31xx_divs[i].mclk == aic31xx->sysclk) | 697 | aic31xx_divs[i].mclk_p == mclk_p) { |
695 | break; | 698 | int s = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) % |
699 | snd_soc_params_to_frame_size(params); | ||
700 | int bn = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) / | ||
701 | snd_soc_params_to_frame_size(params); | ||
702 | if (s < bclk_score && bn > 0) { | ||
703 | match = i; | ||
704 | bclk_n = bn; | ||
705 | bclk_score = s; | ||
706 | } | ||
707 | } | ||
696 | } | 708 | } |
697 | 709 | ||
698 | if (i == ARRAY_SIZE(aic31xx_divs)) { | 710 | if (match == -1) { |
699 | dev_err(codec->dev, "%s: Sampling rate %u not supported\n", | 711 | dev_err(codec->dev, |
712 | "%s: Sample rate (%u) and format not supported\n", | ||
700 | __func__, params_rate(params)); | 713 | __func__, params_rate(params)); |
714 | /* See bellow for details how fix this. */ | ||
701 | return -EINVAL; | 715 | return -EINVAL; |
702 | } | 716 | } |
717 | if (bclk_score != 0) { | ||
718 | dev_warn(codec->dev, "Can not produce exact bitclock"); | ||
719 | /* This is fine if using dsp format, but if using i2s | ||
720 | there may be trouble. To fix the issue edit the | ||
721 | aic31xx_divs table for your mclk and sample | ||
722 | rate. Details can be found from: | ||
723 | http://www.ti.com/lit/ds/symlink/tlv320aic3100.pdf | ||
724 | Section: 5.6 CLOCK Generation and PLL | ||
725 | */ | ||
726 | } | ||
727 | i = match; | ||
703 | 728 | ||
704 | /* PLL configuration */ | 729 | /* PLL configuration */ |
705 | snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK, | 730 | snd_soc_update_bits(codec, AIC31XX_PLLPR, AIC31XX_PLL_MASK, |
706 | (aic31xx_divs[i].p_val << 4) | 0x01); | 731 | (aic31xx->p_div << 4) | 0x01); |
707 | snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j); | 732 | snd_soc_write(codec, AIC31XX_PLLJ, aic31xx_divs[i].pll_j); |
708 | 733 | ||
709 | snd_soc_write(codec, AIC31XX_PLLDMSB, | 734 | snd_soc_write(codec, AIC31XX_PLLDMSB, |
@@ -729,14 +754,6 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, | |||
729 | snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr); | 754 | snd_soc_write(codec, AIC31XX_AOSR, aic31xx_divs[i].aosr); |
730 | 755 | ||
731 | /* Bit clock divider configuration. */ | 756 | /* Bit clock divider configuration. */ |
732 | bclk_n = (aic31xx_divs[i].dosr * aic31xx_divs[i].mdac) | ||
733 | / snd_soc_params_to_frame_size(params); | ||
734 | if (bclk_n == 0) { | ||
735 | dev_err(codec->dev, "%s: Not enough BLCK bandwidth\n", | ||
736 | __func__); | ||
737 | return -EINVAL; | ||
738 | } | ||
739 | |||
740 | snd_soc_update_bits(codec, AIC31XX_BCLKN, | 757 | snd_soc_update_bits(codec, AIC31XX_BCLKN, |
741 | AIC31XX_PLL_MASK, bclk_n); | 758 | AIC31XX_PLL_MASK, bclk_n); |
742 | 759 | ||
@@ -745,7 +762,7 @@ static int aic31xx_setup_pll(struct snd_soc_codec *codec, | |||
745 | dev_dbg(codec->dev, | 762 | dev_dbg(codec->dev, |
746 | "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n", | 763 | "pll %d.%04d/%d dosr %d n %d m %d aosr %d n %d m %d bclk_n %d\n", |
747 | aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d, | 764 | aic31xx_divs[i].pll_j, aic31xx_divs[i].pll_d, |
748 | aic31xx_divs[i].p_val, aic31xx_divs[i].dosr, | 765 | aic31xx->p_div, aic31xx_divs[i].dosr, |
749 | aic31xx_divs[i].ndac, aic31xx_divs[i].mdac, | 766 | aic31xx_divs[i].ndac, aic31xx_divs[i].mdac, |
750 | aic31xx_divs[i].aosr, aic31xx_divs[i].nadc, | 767 | aic31xx_divs[i].aosr, aic31xx_divs[i].nadc, |
751 | aic31xx_divs[i].madc, bclk_n); | 768 | aic31xx_divs[i].madc, bclk_n); |
@@ -813,7 +830,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
813 | { | 830 | { |
814 | struct snd_soc_codec *codec = codec_dai->codec; | 831 | struct snd_soc_codec *codec = codec_dai->codec; |
815 | u8 iface_reg1 = 0; | 832 | u8 iface_reg1 = 0; |
816 | u8 iface_reg3 = 0; | 833 | u8 iface_reg2 = 0; |
817 | u8 dsp_a_val = 0; | 834 | u8 dsp_a_val = 0; |
818 | 835 | ||
819 | dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt); | 836 | dev_dbg(codec->dev, "## %s: fmt = 0x%x\n", __func__, fmt); |
@@ -838,7 +855,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
838 | /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */ | 855 | /* NOTE: BCLKINV bit value 1 equas NB and 0 equals IB */ |
839 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 856 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
840 | case SND_SOC_DAIFMT_NB_NF: | 857 | case SND_SOC_DAIFMT_NB_NF: |
841 | iface_reg3 |= AIC31XX_BCLKINV_MASK; | 858 | iface_reg2 |= AIC31XX_BCLKINV_MASK; |
842 | break; | 859 | break; |
843 | case SND_SOC_DAIFMT_IB_NF: | 860 | case SND_SOC_DAIFMT_IB_NF: |
844 | break; | 861 | break; |
@@ -870,7 +887,7 @@ static int aic31xx_set_dai_fmt(struct snd_soc_dai *codec_dai, | |||
870 | dsp_a_val); | 887 | dsp_a_val); |
871 | snd_soc_update_bits(codec, AIC31XX_IFACE2, | 888 | snd_soc_update_bits(codec, AIC31XX_IFACE2, |
872 | AIC31XX_BCLKINV_MASK, | 889 | AIC31XX_BCLKINV_MASK, |
873 | iface_reg3); | 890 | iface_reg2); |
874 | 891 | ||
875 | return 0; | 892 | return 0; |
876 | } | 893 | } |
@@ -885,7 +902,16 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, | |||
885 | dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n", | 902 | dev_dbg(codec->dev, "## %s: clk_id = %d, freq = %d, dir = %d\n", |
886 | __func__, clk_id, freq, dir); | 903 | __func__, clk_id, freq, dir); |
887 | 904 | ||
888 | for (i = 0; aic31xx_divs[i].mclk != freq; i++) { | 905 | for (i = 1; freq/i > 20000000 && i < 8; i++) |
906 | ; | ||
907 | if (freq/i > 20000000) { | ||
908 | dev_err(aic31xx->dev, "%s: Too high mclk frequency %u\n", | ||
909 | __func__, freq); | ||
910 | return -EINVAL; | ||
911 | } | ||
912 | aic31xx->p_div = i; | ||
913 | |||
914 | for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) { | ||
889 | if (i == ARRAY_SIZE(aic31xx_divs)) { | 915 | if (i == ARRAY_SIZE(aic31xx_divs)) { |
890 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", | 916 | dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n", |
891 | __func__, freq); | 917 | __func__, freq); |
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 52ed57c69dfa..fe16c34607bb 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h | |||
@@ -18,7 +18,8 @@ | |||
18 | #define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000 | 18 | #define AIC31XX_RATES SNDRV_PCM_RATE_8000_192000 |
19 | 19 | ||
20 | #define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ | 20 | #define AIC31XX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE \ |
21 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) | 21 | | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE \ |
22 | | SNDRV_PCM_FMTBIT_S32_LE) | ||
22 | 23 | ||
23 | 24 | ||
24 | #define AIC31XX_STEREO_CLASS_D_BIT 0x1 | 25 | #define AIC31XX_STEREO_CLASS_D_BIT 0x1 |
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index 5e8626ae612b..f7c2a575a892 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c | |||
@@ -1235,20 +1235,6 @@ static struct snd_soc_dai_driver aic3x_dai = { | |||
1235 | .symmetric_rates = 1, | 1235 | .symmetric_rates = 1, |
1236 | }; | 1236 | }; |
1237 | 1237 | ||
1238 | static int aic3x_suspend(struct snd_soc_codec *codec) | ||
1239 | { | ||
1240 | aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
1241 | |||
1242 | return 0; | ||
1243 | } | ||
1244 | |||
1245 | static int aic3x_resume(struct snd_soc_codec *codec) | ||
1246 | { | ||
1247 | aic3x_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
1248 | |||
1249 | return 0; | ||
1250 | } | ||
1251 | |||
1252 | static void aic3x_mono_init(struct snd_soc_codec *codec) | 1238 | static void aic3x_mono_init(struct snd_soc_codec *codec) |
1253 | { | 1239 | { |
1254 | /* DAC to Mono Line Out default volume and route to Output mixer */ | 1240 | /* DAC to Mono Line Out default volume and route to Output mixer */ |
@@ -1442,8 +1428,6 @@ static struct snd_soc_codec_driver soc_codec_dev_aic3x = { | |||
1442 | .idle_bias_off = true, | 1428 | .idle_bias_off = true, |
1443 | .probe = aic3x_probe, | 1429 | .probe = aic3x_probe, |
1444 | .remove = aic3x_remove, | 1430 | .remove = aic3x_remove, |
1445 | .suspend = aic3x_suspend, | ||
1446 | .resume = aic3x_resume, | ||
1447 | .controls = aic3x_snd_controls, | 1431 | .controls = aic3x_snd_controls, |
1448 | .num_controls = ARRAY_SIZE(aic3x_snd_controls), | 1432 | .num_controls = ARRAY_SIZE(aic3x_snd_controls), |
1449 | .dapm_widgets = aic3x_dapm_widgets, | 1433 | .dapm_widgets = aic3x_dapm_widgets, |
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 7bb0d36d4c54..a01ad629ed61 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -2319,11 +2319,8 @@ static void wm5100_init_gpio(struct i2c_client *i2c) | |||
2319 | static void wm5100_free_gpio(struct i2c_client *i2c) | 2319 | static void wm5100_free_gpio(struct i2c_client *i2c) |
2320 | { | 2320 | { |
2321 | struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); | 2321 | struct wm5100_priv *wm5100 = i2c_get_clientdata(i2c); |
2322 | int ret; | ||
2323 | 2322 | ||
2324 | ret = gpiochip_remove(&wm5100->gpio_chip); | 2323 | gpiochip_remove(&wm5100->gpio_chip); |
2325 | if (ret != 0) | ||
2326 | dev_err(&i2c->dev, "Failed to remove GPIOs: %d\n", ret); | ||
2327 | } | 2324 | } |
2328 | #else | 2325 | #else |
2329 | static void wm5100_init_gpio(struct i2c_client *i2c) | 2326 | static void wm5100_init_gpio(struct i2c_client *i2c) |
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 3dfdcc4197fa..628ec774cf22 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c | |||
@@ -212,7 +212,7 @@ static void wm8350_pga_work(struct work_struct *work) | |||
212 | { | 212 | { |
213 | struct snd_soc_dapm_context *dapm = | 213 | struct snd_soc_dapm_context *dapm = |
214 | container_of(work, struct snd_soc_dapm_context, delayed_work.work); | 214 | container_of(work, struct snd_soc_dapm_context, delayed_work.work); |
215 | struct snd_soc_codec *codec = dapm->codec; | 215 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); |
216 | struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); | 216 | struct wm8350_data *wm8350_data = snd_soc_codec_get_drvdata(codec); |
217 | struct wm8350_output *out1 = &wm8350_data->out1, | 217 | struct wm8350_output *out1 = &wm8350_data->out1, |
218 | *out2 = &wm8350_data->out2; | 218 | *out2 = &wm8350_data->out2; |
diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index a237f1627f61..31bb4801a005 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c | |||
@@ -413,7 +413,6 @@ static int wm8741_resume(struct snd_soc_codec *codec) | |||
413 | return 0; | 413 | return 0; |
414 | } | 414 | } |
415 | #else | 415 | #else |
416 | #define wm8741_suspend NULL | ||
417 | #define wm8741_resume NULL | 416 | #define wm8741_resume NULL |
418 | #endif | 417 | #endif |
419 | 418 | ||
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index e54e097f4fcb..21ca3a94fc96 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -1433,7 +1433,7 @@ static void wm8753_work(struct work_struct *work) | |||
1433 | struct snd_soc_dapm_context *dapm = | 1433 | struct snd_soc_dapm_context *dapm = |
1434 | container_of(work, struct snd_soc_dapm_context, | 1434 | container_of(work, struct snd_soc_dapm_context, |
1435 | delayed_work.work); | 1435 | delayed_work.work); |
1436 | struct snd_soc_codec *codec = dapm->codec; | 1436 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); |
1437 | wm8753_set_bias_level(codec, dapm->bias_level); | 1437 | wm8753_set_bias_level(codec, dapm->bias_level); |
1438 | } | 1438 | } |
1439 | 1439 | ||
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 0ea01dfcb6e1..3addc5fe5cb2 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -518,23 +518,6 @@ static int wm8804_set_bias_level(struct snd_soc_codec *codec, | |||
518 | return 0; | 518 | return 0; |
519 | } | 519 | } |
520 | 520 | ||
521 | #ifdef CONFIG_PM | ||
522 | static int wm8804_suspend(struct snd_soc_codec *codec) | ||
523 | { | ||
524 | wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int wm8804_resume(struct snd_soc_codec *codec) | ||
529 | { | ||
530 | wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
531 | return 0; | ||
532 | } | ||
533 | #else | ||
534 | #define wm8804_suspend NULL | ||
535 | #define wm8804_resume NULL | ||
536 | #endif | ||
537 | |||
538 | static int wm8804_remove(struct snd_soc_codec *codec) | 521 | static int wm8804_remove(struct snd_soc_codec *codec) |
539 | { | 522 | { |
540 | struct wm8804_priv *wm8804; | 523 | struct wm8804_priv *wm8804; |
@@ -671,8 +654,6 @@ static struct snd_soc_dai_driver wm8804_dai = { | |||
671 | static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { | 654 | static struct snd_soc_codec_driver soc_codec_dev_wm8804 = { |
672 | .probe = wm8804_probe, | 655 | .probe = wm8804_probe, |
673 | .remove = wm8804_remove, | 656 | .remove = wm8804_remove, |
674 | .suspend = wm8804_suspend, | ||
675 | .resume = wm8804_resume, | ||
676 | .set_bias_level = wm8804_set_bias_level, | 657 | .set_bias_level = wm8804_set_bias_level, |
677 | .idle_bias_off = true, | 658 | .idle_bias_off = true, |
678 | 659 | ||
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index aa0984864e76..c038b3e04398 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c | |||
@@ -1877,11 +1877,7 @@ static void wm8903_init_gpio(struct wm8903_priv *wm8903) | |||
1877 | 1877 | ||
1878 | static void wm8903_free_gpio(struct wm8903_priv *wm8903) | 1878 | static void wm8903_free_gpio(struct wm8903_priv *wm8903) |
1879 | { | 1879 | { |
1880 | int ret; | 1880 | gpiochip_remove(&wm8903->gpio_chip); |
1881 | |||
1882 | ret = gpiochip_remove(&wm8903->gpio_chip); | ||
1883 | if (ret != 0) | ||
1884 | dev_err(wm8903->dev, "Failed to remove GPIOs: %d\n", ret); | ||
1885 | } | 1881 | } |
1886 | #else | 1882 | #else |
1887 | static void wm8903_init_gpio(struct wm8903_priv *wm8903) | 1883 | static void wm8903_init_gpio(struct wm8903_priv *wm8903) |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 1098ae32f1f9..9077411e62ce 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -3398,11 +3398,8 @@ static void wm8962_init_gpio(struct snd_soc_codec *codec) | |||
3398 | static void wm8962_free_gpio(struct snd_soc_codec *codec) | 3398 | static void wm8962_free_gpio(struct snd_soc_codec *codec) |
3399 | { | 3399 | { |
3400 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3400 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
3401 | int ret; | ||
3402 | 3401 | ||
3403 | ret = gpiochip_remove(&wm8962->gpio_chip); | 3402 | gpiochip_remove(&wm8962->gpio_chip); |
3404 | if (ret != 0) | ||
3405 | dev_err(codec->dev, "Failed to remove GPIOs: %d\n", ret); | ||
3406 | } | 3403 | } |
3407 | #else | 3404 | #else |
3408 | static void wm8962_init_gpio(struct snd_soc_codec *codec) | 3405 | static void wm8962_init_gpio(struct snd_soc_codec *codec) |
diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index 0499cd4cfb71..39ddb9b8834c 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c | |||
@@ -615,7 +615,7 @@ static void wm8971_work(struct work_struct *work) | |||
615 | struct snd_soc_dapm_context *dapm = | 615 | struct snd_soc_dapm_context *dapm = |
616 | container_of(work, struct snd_soc_dapm_context, | 616 | container_of(work, struct snd_soc_dapm_context, |
617 | delayed_work.work); | 617 | delayed_work.work); |
618 | struct snd_soc_codec *codec = dapm->codec; | 618 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm); |
619 | wm8971_set_bias_level(codec, codec->dapm.bias_level); | 619 | wm8971_set_bias_level(codec, codec->dapm.bias_level); |
620 | } | 620 | } |
621 | 621 | ||
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index cae4ac5a5730..1288edeb8c7d 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -1998,23 +1998,6 @@ static int wm8995_set_bias_level(struct snd_soc_codec *codec, | |||
1998 | return 0; | 1998 | return 0; |
1999 | } | 1999 | } |
2000 | 2000 | ||
2001 | #ifdef CONFIG_PM | ||
2002 | static int wm8995_suspend(struct snd_soc_codec *codec) | ||
2003 | { | ||
2004 | wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF); | ||
2005 | return 0; | ||
2006 | } | ||
2007 | |||
2008 | static int wm8995_resume(struct snd_soc_codec *codec) | ||
2009 | { | ||
2010 | wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | ||
2011 | return 0; | ||
2012 | } | ||
2013 | #else | ||
2014 | #define wm8995_suspend NULL | ||
2015 | #define wm8995_resume NULL | ||
2016 | #endif | ||
2017 | |||
2018 | static int wm8995_remove(struct snd_soc_codec *codec) | 2001 | static int wm8995_remove(struct snd_soc_codec *codec) |
2019 | { | 2002 | { |
2020 | struct wm8995_priv *wm8995; | 2003 | struct wm8995_priv *wm8995; |
@@ -2220,8 +2203,6 @@ static struct snd_soc_dai_driver wm8995_dai[] = { | |||
2220 | static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { | 2203 | static struct snd_soc_codec_driver soc_codec_dev_wm8995 = { |
2221 | .probe = wm8995_probe, | 2204 | .probe = wm8995_probe, |
2222 | .remove = wm8995_remove, | 2205 | .remove = wm8995_remove, |
2223 | .suspend = wm8995_suspend, | ||
2224 | .resume = wm8995_resume, | ||
2225 | .set_bias_level = wm8995_set_bias_level, | 2206 | .set_bias_level = wm8995_set_bias_level, |
2226 | .idle_bias_off = true, | 2207 | .idle_bias_off = true, |
2227 | }; | 2208 | }; |
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index f16ff4f56923..b1dcc11c1b23 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c | |||
@@ -2216,11 +2216,7 @@ static void wm8996_init_gpio(struct wm8996_priv *wm8996) | |||
2216 | 2216 | ||
2217 | static void wm8996_free_gpio(struct wm8996_priv *wm8996) | 2217 | static void wm8996_free_gpio(struct wm8996_priv *wm8996) |
2218 | { | 2218 | { |
2219 | int ret; | 2219 | gpiochip_remove(&wm8996->gpio_chip); |
2220 | |||
2221 | ret = gpiochip_remove(&wm8996->gpio_chip); | ||
2222 | if (ret != 0) | ||
2223 | dev_err(wm8996->dev, "Failed to remove GPIOs: %d\n", ret); | ||
2224 | } | 2220 | } |
2225 | #else | 2221 | #else |
2226 | static void wm8996_init_gpio(struct wm8996_priv *wm8996) | 2222 | static void wm8996_init_gpio(struct wm8996_priv *wm8996) |
diff --git a/sound/soc/davinci/Kconfig b/sound/soc/davinci/Kconfig index d69510c53239..8e948c63f3d9 100644 --- a/sound/soc/davinci/Kconfig +++ b/sound/soc/davinci/Kconfig | |||
@@ -63,7 +63,8 @@ config SND_DM365_AIC3X_CODEC | |||
63 | Say Y if you want to add support for AIC3101 audio codec | 63 | Say Y if you want to add support for AIC3101 audio codec |
64 | 64 | ||
65 | config SND_DM365_VOICE_CODEC | 65 | config SND_DM365_VOICE_CODEC |
66 | bool "Voice Codec - CQ93VC" | 66 | tristate "Voice Codec - CQ93VC" |
67 | depends on SND_DAVINCI_SOC | ||
67 | select MFD_DAVINCI_VOICECODEC | 68 | select MFD_DAVINCI_VOICECODEC |
68 | select SND_DAVINCI_SOC_VCIF | 69 | select SND_DAVINCI_SOC_VCIF |
69 | select SND_SOC_CQ0093VC | 70 | select SND_SOC_CQ0093VC |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index c28508da34cf..0eed9b1b24e1 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -42,14 +42,26 @@ | |||
42 | 42 | ||
43 | #define MCASP_MAX_AFIFO_DEPTH 64 | 43 | #define MCASP_MAX_AFIFO_DEPTH 64 |
44 | 44 | ||
45 | static u32 context_regs[] = { | ||
46 | DAVINCI_MCASP_TXFMCTL_REG, | ||
47 | DAVINCI_MCASP_RXFMCTL_REG, | ||
48 | DAVINCI_MCASP_TXFMT_REG, | ||
49 | DAVINCI_MCASP_RXFMT_REG, | ||
50 | DAVINCI_MCASP_ACLKXCTL_REG, | ||
51 | DAVINCI_MCASP_ACLKRCTL_REG, | ||
52 | DAVINCI_MCASP_AHCLKXCTL_REG, | ||
53 | DAVINCI_MCASP_AHCLKRCTL_REG, | ||
54 | DAVINCI_MCASP_PDIR_REG, | ||
55 | DAVINCI_MCASP_RXMASK_REG, | ||
56 | DAVINCI_MCASP_TXMASK_REG, | ||
57 | DAVINCI_MCASP_RXTDM_REG, | ||
58 | DAVINCI_MCASP_TXTDM_REG, | ||
59 | }; | ||
60 | |||
45 | struct davinci_mcasp_context { | 61 | struct davinci_mcasp_context { |
46 | u32 txfmtctl; | 62 | u32 config_regs[ARRAY_SIZE(context_regs)]; |
47 | u32 rxfmtctl; | 63 | u32 afifo_regs[2]; /* for read/write fifo control registers */ |
48 | u32 txfmt; | 64 | u32 *xrsr_regs; /* for serializer configuration */ |
49 | u32 rxfmt; | ||
50 | u32 aclkxctl; | ||
51 | u32 aclkrctl; | ||
52 | u32 pdir; | ||
53 | }; | 65 | }; |
54 | 66 | ||
55 | struct davinci_mcasp { | 67 | struct davinci_mcasp { |
@@ -403,7 +415,8 @@ out: | |||
403 | return ret; | 415 | return ret; |
404 | } | 416 | } |
405 | 417 | ||
406 | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) | 418 | static int __davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, |
419 | int div, bool explicit) | ||
407 | { | 420 | { |
408 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 421 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); |
409 | 422 | ||
@@ -420,7 +433,8 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div | |||
420 | ACLKXDIV(div - 1), ACLKXDIV_MASK); | 433 | ACLKXDIV(div - 1), ACLKXDIV_MASK); |
421 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, | 434 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, |
422 | ACLKRDIV(div - 1), ACLKRDIV_MASK); | 435 | ACLKRDIV(div - 1), ACLKRDIV_MASK); |
423 | mcasp->bclk_div = div; | 436 | if (explicit) |
437 | mcasp->bclk_div = div; | ||
424 | break; | 438 | break; |
425 | 439 | ||
426 | case 2: /* BCLK/LRCLK ratio */ | 440 | case 2: /* BCLK/LRCLK ratio */ |
@@ -434,6 +448,12 @@ static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div | |||
434 | return 0; | 448 | return 0; |
435 | } | 449 | } |
436 | 450 | ||
451 | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, | ||
452 | int div) | ||
453 | { | ||
454 | return __davinci_mcasp_set_clkdiv(dai, div_id, div, 1); | ||
455 | } | ||
456 | |||
437 | static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | 457 | static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, |
438 | unsigned int freq, int dir) | 458 | unsigned int freq, int dir) |
439 | { | 459 | { |
@@ -459,8 +479,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | |||
459 | { | 479 | { |
460 | u32 fmt; | 480 | u32 fmt; |
461 | u32 tx_rotate = (word_length / 4) & 0x7; | 481 | u32 tx_rotate = (word_length / 4) & 0x7; |
462 | u32 rx_rotate = (32 - word_length) / 4; | ||
463 | u32 mask = (1ULL << word_length) - 1; | 482 | u32 mask = (1ULL << word_length) - 1; |
483 | /* | ||
484 | * For captured data we should not rotate, inversion and masking is | ||
485 | * enoguh to get the data to the right position: | ||
486 | * Format data from bus after reverse (XRBUF) | ||
487 | * S16_LE: |LSB|MSB|xxx|xxx| |xxx|xxx|MSB|LSB| | ||
488 | * S24_3LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| | ||
489 | * S24_LE: |LSB|DAT|MSB|xxx| |xxx|MSB|DAT|LSB| | ||
490 | * S32_LE: |LSB|DAT|DAT|MSB| |MSB|DAT|DAT|LSB| | ||
491 | */ | ||
492 | u32 rx_rotate = 0; | ||
464 | 493 | ||
465 | /* | 494 | /* |
466 | * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() | 495 | * if s BCLK-to-LRCLK ratio has been configured via the set_clkdiv() |
@@ -738,7 +767,7 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
738 | "Inaccurate BCLK: %u Hz / %u != %u Hz\n", | 767 | "Inaccurate BCLK: %u Hz / %u != %u Hz\n", |
739 | mcasp->sysclk_freq, div, bclk_freq); | 768 | mcasp->sysclk_freq, div, bclk_freq); |
740 | } | 769 | } |
741 | davinci_mcasp_set_clkdiv(cpu_dai, 1, div); | 770 | __davinci_mcasp_set_clkdiv(cpu_dai, 1, div, 0); |
742 | } | 771 | } |
743 | 772 | ||
744 | ret = mcasp_common_hw_param(mcasp, substream->stream, | 773 | ret = mcasp_common_hw_param(mcasp, substream->stream, |
@@ -857,14 +886,24 @@ static int davinci_mcasp_suspend(struct snd_soc_dai *dai) | |||
857 | { | 886 | { |
858 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 887 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); |
859 | struct davinci_mcasp_context *context = &mcasp->context; | 888 | struct davinci_mcasp_context *context = &mcasp->context; |
889 | u32 reg; | ||
890 | int i; | ||
860 | 891 | ||
861 | context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); | 892 | for (i = 0; i < ARRAY_SIZE(context_regs); i++) |
862 | context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | 893 | context->config_regs[i] = mcasp_get_reg(mcasp, context_regs[i]); |
863 | context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); | 894 | |
864 | context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); | 895 | if (mcasp->txnumevt) { |
865 | context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | 896 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; |
866 | context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); | 897 | context->afifo_regs[0] = mcasp_get_reg(mcasp, reg); |
867 | context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); | 898 | } |
899 | if (mcasp->rxnumevt) { | ||
900 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
901 | context->afifo_regs[1] = mcasp_get_reg(mcasp, reg); | ||
902 | } | ||
903 | |||
904 | for (i = 0; i < mcasp->num_serializer; i++) | ||
905 | context->xrsr_regs[i] = mcasp_get_reg(mcasp, | ||
906 | DAVINCI_MCASP_XRSRCTL_REG(i)); | ||
868 | 907 | ||
869 | return 0; | 908 | return 0; |
870 | } | 909 | } |
@@ -873,14 +912,24 @@ static int davinci_mcasp_resume(struct snd_soc_dai *dai) | |||
873 | { | 912 | { |
874 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | 913 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); |
875 | struct davinci_mcasp_context *context = &mcasp->context; | 914 | struct davinci_mcasp_context *context = &mcasp->context; |
915 | u32 reg; | ||
916 | int i; | ||
917 | |||
918 | for (i = 0; i < ARRAY_SIZE(context_regs); i++) | ||
919 | mcasp_set_reg(mcasp, context_regs[i], context->config_regs[i]); | ||
920 | |||
921 | if (mcasp->txnumevt) { | ||
922 | reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET; | ||
923 | mcasp_set_reg(mcasp, reg, context->afifo_regs[0]); | ||
924 | } | ||
925 | if (mcasp->rxnumevt) { | ||
926 | reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET; | ||
927 | mcasp_set_reg(mcasp, reg, context->afifo_regs[1]); | ||
928 | } | ||
876 | 929 | ||
877 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); | 930 | for (i = 0; i < mcasp->num_serializer; i++) |
878 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); | 931 | mcasp_set_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(i), |
879 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); | 932 | context->xrsr_regs[i]); |
880 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); | ||
881 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); | ||
882 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); | ||
883 | mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); | ||
884 | 933 | ||
885 | return 0; | 934 | return 0; |
886 | } | 935 | } |
@@ -1199,6 +1248,11 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1199 | mcasp->op_mode = pdata->op_mode; | 1248 | mcasp->op_mode = pdata->op_mode; |
1200 | mcasp->tdm_slots = pdata->tdm_slots; | 1249 | mcasp->tdm_slots = pdata->tdm_slots; |
1201 | mcasp->num_serializer = pdata->num_serializer; | 1250 | mcasp->num_serializer = pdata->num_serializer; |
1251 | #ifdef CONFIG_PM_SLEEP | ||
1252 | mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev, | ||
1253 | sizeof(u32) * mcasp->num_serializer, | ||
1254 | GFP_KERNEL); | ||
1255 | #endif | ||
1202 | mcasp->serial_dir = pdata->serial_dir; | 1256 | mcasp->serial_dir = pdata->serial_dir; |
1203 | mcasp->version = pdata->version; | 1257 | mcasp->version = pdata->version; |
1204 | mcasp->txnumevt = pdata->txnumevt; | 1258 | mcasp->txnumevt = pdata->txnumevt; |
diff --git a/sound/soc/davinci/edma-pcm.c b/sound/soc/davinci/edma-pcm.c index 605e643133db..59e588abe54b 100644 --- a/sound/soc/davinci/edma-pcm.c +++ b/sound/soc/davinci/edma-pcm.c | |||
@@ -25,6 +25,8 @@ | |||
25 | #include <sound/dmaengine_pcm.h> | 25 | #include <sound/dmaengine_pcm.h> |
26 | #include <linux/edma.h> | 26 | #include <linux/edma.h> |
27 | 27 | ||
28 | #include "edma-pcm.h" | ||
29 | |||
28 | static const struct snd_pcm_hardware edma_pcm_hardware = { | 30 | static const struct snd_pcm_hardware edma_pcm_hardware = { |
29 | .info = SNDRV_PCM_INFO_MMAP | | 31 | .info = SNDRV_PCM_INFO_MMAP | |
30 | SNDRV_PCM_INFO_MMAP_VALID | | 32 | SNDRV_PCM_INFO_MMAP_VALID | |
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c index 25c31f1655f6..e961388e6e9c 100644 --- a/sound/soc/dwc/designware_i2s.c +++ b/sound/soc/dwc/designware_i2s.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * sound/soc/dwc/designware_i2s.c | 4 | * sound/soc/dwc/designware_i2s.c |
5 | * | 5 | * |
6 | * Copyright (C) 2010 ST Microelectronics | 6 | * Copyright (C) 2010 ST Microelectronics |
7 | * Rajeev Kumar <rajeev-dlh.kumar@st.com> | 7 | * Rajeev Kumar <rajeevkumar.linux@gmail.com> |
8 | * | 8 | * |
9 | * This file is licensed under the terms of the GNU General Public | 9 | * This file is licensed under the terms of the GNU General Public |
10 | * License version 2. This program is licensed "as is" without any | 10 | * License version 2. This program is licensed "as is" without any |
@@ -455,7 +455,7 @@ static struct platform_driver dw_i2s_driver = { | |||
455 | 455 | ||
456 | module_platform_driver(dw_i2s_driver); | 456 | module_platform_driver(dw_i2s_driver); |
457 | 457 | ||
458 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | 458 | MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); |
459 | MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface"); | 459 | MODULE_DESCRIPTION("DESIGNWARE I2S SoC Interface"); |
460 | MODULE_LICENSE("GPL"); | 460 | MODULE_LICENSE("GPL"); |
461 | MODULE_ALIAS("platform:designware_i2s"); | 461 | MODULE_ALIAS("platform:designware_i2s"); |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index f54a8fc99291..081e406b3713 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -49,7 +49,6 @@ config SND_SOC_FSL_ESAI | |||
49 | tristate "Enhanced Serial Audio Interface (ESAI) module support" | 49 | tristate "Enhanced Serial Audio Interface (ESAI) module support" |
50 | select REGMAP_MMIO | 50 | select REGMAP_MMIO |
51 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n | 51 | select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n |
52 | select SND_SOC_FSL_UTILS | ||
53 | help | 52 | help |
54 | Say Y if you want to add Enhanced Synchronous Audio Interface | 53 | Say Y if you want to add Enhanced Synchronous Audio Interface |
55 | (ESAI) support for the Freescale CPUs. | 54 | (ESAI) support for the Freescale CPUs. |
@@ -241,6 +240,18 @@ config SND_SOC_IMX_WM8962 | |||
241 | Say Y if you want to add support for SoC audio on an i.MX board with | 240 | Say Y if you want to add support for SoC audio on an i.MX board with |
242 | a wm8962 codec. | 241 | a wm8962 codec. |
243 | 242 | ||
243 | config SND_SOC_IMX_ES8328 | ||
244 | tristate "SoC Audio support for i.MX boards with the ES8328 codec" | ||
245 | depends on OF && (I2C || SPI) | ||
246 | select SND_SOC_ES8328_I2C if I2C | ||
247 | select SND_SOC_ES8328_SPI if SPI_MASTER | ||
248 | select SND_SOC_IMX_PCM_DMA | ||
249 | select SND_SOC_IMX_AUDMUX | ||
250 | select SND_SOC_FSL_SSI | ||
251 | help | ||
252 | Say Y if you want to add support for the ES8328 audio codec connected | ||
253 | via SSI/I2S over either SPI or I2C. | ||
254 | |||
244 | config SND_SOC_IMX_SGTL5000 | 255 | config SND_SOC_IMX_SGTL5000 |
245 | tristate "SoC Audio support for i.MX boards with sgtl5000" | 256 | tristate "SoC Audio support for i.MX boards with sgtl5000" |
246 | depends on OF && I2C | 257 | depends on OF && I2C |
@@ -269,6 +280,20 @@ config SND_SOC_IMX_MC13783 | |||
269 | select SND_SOC_MC13783 | 280 | select SND_SOC_MC13783 |
270 | select SND_SOC_IMX_PCM_DMA | 281 | select SND_SOC_IMX_PCM_DMA |
271 | 282 | ||
283 | config SND_SOC_FSL_ASOC_CARD | ||
284 | tristate "Generic ASoC Sound Card with ASRC support" | ||
285 | depends on OF && I2C | ||
286 | select SND_SOC_IMX_AUDMUX | ||
287 | select SND_SOC_IMX_PCM_DMA | ||
288 | select SND_SOC_FSL_ESAI | ||
289 | select SND_SOC_FSL_SAI | ||
290 | select SND_SOC_FSL_SSI | ||
291 | help | ||
292 | ALSA SoC Audio support with ASRC feature for Freescale SoCs that have | ||
293 | ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888 | ||
294 | and SGTL5000. | ||
295 | Say Y if you want to add support for Freescale Generic ASoC Sound Card. | ||
296 | |||
272 | endif # SND_IMX_SOC | 297 | endif # SND_IMX_SOC |
273 | 298 | ||
274 | endmenu | 299 | endmenu |
diff --git a/sound/soc/fsl/Makefile b/sound/soc/fsl/Makefile index 9ff59267eac9..d28dc25c9375 100644 --- a/sound/soc/fsl/Makefile +++ b/sound/soc/fsl/Makefile | |||
@@ -11,6 +11,7 @@ snd-soc-p1022-rdk-objs := p1022_rdk.o | |||
11 | obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o | 11 | obj-$(CONFIG_SND_SOC_P1022_RDK) += snd-soc-p1022-rdk.o |
12 | 12 | ||
13 | # Freescale SSI/DMA/SAI/SPDIF Support | 13 | # Freescale SSI/DMA/SAI/SPDIF Support |
14 | snd-soc-fsl-asoc-card-objs := fsl-asoc-card.o | ||
14 | snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o | 15 | snd-soc-fsl-asrc-objs := fsl_asrc.o fsl_asrc_dma.o |
15 | snd-soc-fsl-sai-objs := fsl_sai.o | 16 | snd-soc-fsl-sai-objs := fsl_sai.o |
16 | snd-soc-fsl-ssi-y := fsl_ssi.o | 17 | snd-soc-fsl-ssi-y := fsl_ssi.o |
@@ -19,6 +20,7 @@ snd-soc-fsl-spdif-objs := fsl_spdif.o | |||
19 | snd-soc-fsl-esai-objs := fsl_esai.o | 20 | snd-soc-fsl-esai-objs := fsl_esai.o |
20 | snd-soc-fsl-utils-objs := fsl_utils.o | 21 | snd-soc-fsl-utils-objs := fsl_utils.o |
21 | snd-soc-fsl-dma-objs := fsl_dma.o | 22 | snd-soc-fsl-dma-objs := fsl_dma.o |
23 | obj-$(CONFIG_SND_SOC_FSL_ASOC_CARD) += snd-soc-fsl-asoc-card.o | ||
22 | obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o | 24 | obj-$(CONFIG_SND_SOC_FSL_ASRC) += snd-soc-fsl-asrc.o |
23 | obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o | 25 | obj-$(CONFIG_SND_SOC_FSL_SAI) += snd-soc-fsl-sai.o |
24 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o | 26 | obj-$(CONFIG_SND_SOC_FSL_SSI) += snd-soc-fsl-ssi.o |
@@ -50,6 +52,7 @@ snd-soc-eukrea-tlv320-objs := eukrea-tlv320.o | |||
50 | snd-soc-phycore-ac97-objs := phycore-ac97.o | 52 | snd-soc-phycore-ac97-objs := phycore-ac97.o |
51 | snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o | 53 | snd-soc-mx27vis-aic32x4-objs := mx27vis-aic32x4.o |
52 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o | 54 | snd-soc-wm1133-ev1-objs := wm1133-ev1.o |
55 | snd-soc-imx-es8328-objs := imx-es8328.o | ||
53 | snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o | 56 | snd-soc-imx-sgtl5000-objs := imx-sgtl5000.o |
54 | snd-soc-imx-wm8962-objs := imx-wm8962.o | 57 | snd-soc-imx-wm8962-objs := imx-wm8962.o |
55 | snd-soc-imx-spdif-objs := imx-spdif.o | 58 | snd-soc-imx-spdif-objs := imx-spdif.o |
@@ -59,6 +62,7 @@ obj-$(CONFIG_SND_SOC_EUKREA_TLV320) += snd-soc-eukrea-tlv320.o | |||
59 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o | 62 | obj-$(CONFIG_SND_SOC_PHYCORE_AC97) += snd-soc-phycore-ac97.o |
60 | obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o | 63 | obj-$(CONFIG_SND_SOC_MX27VIS_AIC32X4) += snd-soc-mx27vis-aic32x4.o |
61 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o | 64 | obj-$(CONFIG_SND_MXC_SOC_WM1133_EV1) += snd-soc-wm1133-ev1.o |
65 | obj-$(CONFIG_SND_SOC_IMX_ES8328) += snd-soc-imx-es8328.o | ||
62 | obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o | 66 | obj-$(CONFIG_SND_SOC_IMX_SGTL5000) += snd-soc-imx-sgtl5000.o |
63 | obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o | 67 | obj-$(CONFIG_SND_SOC_IMX_WM8962) += snd-soc-imx-wm8962.o |
64 | obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o | 68 | obj-$(CONFIG_SND_SOC_IMX_SPDIF) += snd-soc-imx-spdif.o |
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c new file mode 100644 index 000000000000..007c772f3cef --- /dev/null +++ b/sound/soc/fsl/fsl-asoc-card.c | |||
@@ -0,0 +1,574 @@ | |||
1 | /* | ||
2 | * Freescale Generic ASoC Sound Card driver with ASRC | ||
3 | * | ||
4 | * Copyright (C) 2014 Freescale Semiconductor, Inc. | ||
5 | * | ||
6 | * Author: Nicolin Chen <nicoleotsuka@gmail.com> | ||
7 | * | ||
8 | * This file is licensed under the terms of the GNU General Public License | ||
9 | * version 2. This program is licensed "as is" without any warranty of any | ||
10 | * kind, whether express or implied. | ||
11 | */ | ||
12 | |||
13 | #include <linux/clk.h> | ||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | #include <sound/pcm_params.h> | ||
18 | #include <sound/soc.h> | ||
19 | |||
20 | #include "fsl_esai.h" | ||
21 | #include "fsl_sai.h" | ||
22 | #include "imx-audmux.h" | ||
23 | |||
24 | #include "../codecs/sgtl5000.h" | ||
25 | #include "../codecs/wm8962.h" | ||
26 | |||
27 | #define RX 0 | ||
28 | #define TX 1 | ||
29 | |||
30 | /* Default DAI format without Master and Slave flag */ | ||
31 | #define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF) | ||
32 | |||
33 | /** | ||
34 | * CODEC private data | ||
35 | * | ||
36 | * @mclk_freq: Clock rate of MCLK | ||
37 | * @mclk_id: MCLK (or main clock) id for set_sysclk() | ||
38 | * @fll_id: FLL (or secordary clock) id for set_sysclk() | ||
39 | * @pll_id: PLL id for set_pll() | ||
40 | */ | ||
41 | struct codec_priv { | ||
42 | unsigned long mclk_freq; | ||
43 | u32 mclk_id; | ||
44 | u32 fll_id; | ||
45 | u32 pll_id; | ||
46 | }; | ||
47 | |||
48 | /** | ||
49 | * CPU private data | ||
50 | * | ||
51 | * @sysclk_freq[2]: SYSCLK rates for set_sysclk() | ||
52 | * @sysclk_dir[2]: SYSCLK directions for set_sysclk() | ||
53 | * @sysclk_id[2]: SYSCLK ids for set_sysclk() | ||
54 | * | ||
55 | * Note: [1] for tx and [0] for rx | ||
56 | */ | ||
57 | struct cpu_priv { | ||
58 | unsigned long sysclk_freq[2]; | ||
59 | u32 sysclk_dir[2]; | ||
60 | u32 sysclk_id[2]; | ||
61 | }; | ||
62 | |||
63 | /** | ||
64 | * Freescale Generic ASOC card private data | ||
65 | * | ||
66 | * @dai_link[3]: DAI link structure including normal one and DPCM link | ||
67 | * @pdev: platform device pointer | ||
68 | * @codec_priv: CODEC private data | ||
69 | * @cpu_priv: CPU private data | ||
70 | * @card: ASoC card structure | ||
71 | * @sample_rate: Current sample rate | ||
72 | * @sample_format: Current sample format | ||
73 | * @asrc_rate: ASRC sample rate used by Back-Ends | ||
74 | * @asrc_format: ASRC sample format used by Back-Ends | ||
75 | * @dai_fmt: DAI format between CPU and CODEC | ||
76 | * @name: Card name | ||
77 | */ | ||
78 | |||
79 | struct fsl_asoc_card_priv { | ||
80 | struct snd_soc_dai_link dai_link[3]; | ||
81 | struct platform_device *pdev; | ||
82 | struct codec_priv codec_priv; | ||
83 | struct cpu_priv cpu_priv; | ||
84 | struct snd_soc_card card; | ||
85 | u32 sample_rate; | ||
86 | u32 sample_format; | ||
87 | u32 asrc_rate; | ||
88 | u32 asrc_format; | ||
89 | u32 dai_fmt; | ||
90 | char name[32]; | ||
91 | }; | ||
92 | |||
93 | /** | ||
94 | * This dapm route map exsits for DPCM link only. | ||
95 | * The other routes shall go through Device Tree. | ||
96 | */ | ||
97 | static const struct snd_soc_dapm_route audio_map[] = { | ||
98 | {"CPU-Playback", NULL, "ASRC-Playback"}, | ||
99 | {"Playback", NULL, "CPU-Playback"}, | ||
100 | {"ASRC-Capture", NULL, "CPU-Capture"}, | ||
101 | {"CPU-Capture", NULL, "Capture"}, | ||
102 | }; | ||
103 | |||
104 | /* Add all possible widgets into here without being redundant */ | ||
105 | static const struct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = { | ||
106 | SND_SOC_DAPM_LINE("Line Out Jack", NULL), | ||
107 | SND_SOC_DAPM_LINE("Line In Jack", NULL), | ||
108 | SND_SOC_DAPM_HP("Headphone Jack", NULL), | ||
109 | SND_SOC_DAPM_SPK("Ext Spk", NULL), | ||
110 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
111 | SND_SOC_DAPM_MIC("AMIC", NULL), | ||
112 | SND_SOC_DAPM_MIC("DMIC", NULL), | ||
113 | }; | ||
114 | |||
115 | static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream, | ||
116 | struct snd_pcm_hw_params *params) | ||
117 | { | ||
118 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
119 | struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
120 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | ||
121 | struct cpu_priv *cpu_priv = &priv->cpu_priv; | ||
122 | struct device *dev = rtd->card->dev; | ||
123 | int ret; | ||
124 | |||
125 | priv->sample_rate = params_rate(params); | ||
126 | priv->sample_format = params_format(params); | ||
127 | |||
128 | if (priv->card.set_bias_level) | ||
129 | return 0; | ||
130 | |||
131 | /* Specific configurations of DAIs starts from here */ | ||
132 | ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, cpu_priv->sysclk_id[tx], | ||
133 | cpu_priv->sysclk_freq[tx], | ||
134 | cpu_priv->sysclk_dir[tx]); | ||
135 | if (ret) { | ||
136 | dev_err(dev, "failed to set sysclk for cpu dai\n"); | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | static struct snd_soc_ops fsl_asoc_card_ops = { | ||
144 | .hw_params = fsl_asoc_card_hw_params, | ||
145 | }; | ||
146 | |||
147 | static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | ||
148 | struct snd_pcm_hw_params *params) | ||
149 | { | ||
150 | struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(rtd->card); | ||
151 | struct snd_interval *rate; | ||
152 | struct snd_mask *mask; | ||
153 | |||
154 | rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
155 | rate->max = rate->min = priv->asrc_rate; | ||
156 | |||
157 | mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
158 | snd_mask_none(mask); | ||
159 | snd_mask_set(mask, priv->asrc_format); | ||
160 | |||
161 | return 0; | ||
162 | } | ||
163 | |||
164 | static struct snd_soc_dai_link fsl_asoc_card_dai[] = { | ||
165 | /* Default ASoC DAI Link*/ | ||
166 | { | ||
167 | .name = "HiFi", | ||
168 | .stream_name = "HiFi", | ||
169 | .ops = &fsl_asoc_card_ops, | ||
170 | }, | ||
171 | /* DPCM Link between Front-End and Back-End (Optional) */ | ||
172 | { | ||
173 | .name = "HiFi-ASRC-FE", | ||
174 | .stream_name = "HiFi-ASRC-FE", | ||
175 | .codec_name = "snd-soc-dummy", | ||
176 | .codec_dai_name = "snd-soc-dummy-dai", | ||
177 | .dpcm_playback = 1, | ||
178 | .dpcm_capture = 1, | ||
179 | .dynamic = 1, | ||
180 | }, | ||
181 | { | ||
182 | .name = "HiFi-ASRC-BE", | ||
183 | .stream_name = "HiFi-ASRC-BE", | ||
184 | .platform_name = "snd-soc-dummy", | ||
185 | .be_hw_params_fixup = be_hw_params_fixup, | ||
186 | .ops = &fsl_asoc_card_ops, | ||
187 | .dpcm_playback = 1, | ||
188 | .dpcm_capture = 1, | ||
189 | .no_pcm = 1, | ||
190 | }, | ||
191 | }; | ||
192 | |||
193 | static int fsl_asoc_card_set_bias_level(struct snd_soc_card *card, | ||
194 | struct snd_soc_dapm_context *dapm, | ||
195 | enum snd_soc_bias_level level) | ||
196 | { | ||
197 | struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); | ||
198 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | ||
199 | struct codec_priv *codec_priv = &priv->codec_priv; | ||
200 | struct device *dev = card->dev; | ||
201 | unsigned int pll_out; | ||
202 | int ret; | ||
203 | |||
204 | if (dapm->dev != codec_dai->dev) | ||
205 | return 0; | ||
206 | |||
207 | switch (level) { | ||
208 | case SND_SOC_BIAS_PREPARE: | ||
209 | if (dapm->bias_level != SND_SOC_BIAS_STANDBY) | ||
210 | break; | ||
211 | |||
212 | if (priv->sample_format == SNDRV_PCM_FORMAT_S24_LE) | ||
213 | pll_out = priv->sample_rate * 384; | ||
214 | else | ||
215 | pll_out = priv->sample_rate * 256; | ||
216 | |||
217 | ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, | ||
218 | codec_priv->mclk_id, | ||
219 | codec_priv->mclk_freq, pll_out); | ||
220 | if (ret) { | ||
221 | dev_err(dev, "failed to start FLL: %d\n", ret); | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->fll_id, | ||
226 | pll_out, SND_SOC_CLOCK_IN); | ||
227 | if (ret) { | ||
228 | dev_err(dev, "failed to set SYSCLK: %d\n", ret); | ||
229 | return ret; | ||
230 | } | ||
231 | break; | ||
232 | |||
233 | case SND_SOC_BIAS_STANDBY: | ||
234 | if (dapm->bias_level != SND_SOC_BIAS_PREPARE) | ||
235 | break; | ||
236 | |||
237 | ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, | ||
238 | codec_priv->mclk_freq, | ||
239 | SND_SOC_CLOCK_IN); | ||
240 | if (ret) { | ||
241 | dev_err(dev, "failed to switch away from FLL: %d\n", ret); | ||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | ret = snd_soc_dai_set_pll(codec_dai, codec_priv->pll_id, 0, 0, 0); | ||
246 | if (ret) { | ||
247 | dev_err(dev, "failed to stop FLL: %d\n", ret); | ||
248 | return ret; | ||
249 | } | ||
250 | break; | ||
251 | |||
252 | default: | ||
253 | break; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int fsl_asoc_card_audmux_init(struct device_node *np, | ||
260 | struct fsl_asoc_card_priv *priv) | ||
261 | { | ||
262 | struct device *dev = &priv->pdev->dev; | ||
263 | u32 int_ptcr = 0, ext_ptcr = 0; | ||
264 | int int_port, ext_port; | ||
265 | int ret; | ||
266 | |||
267 | ret = of_property_read_u32(np, "mux-int-port", &int_port); | ||
268 | if (ret) { | ||
269 | dev_err(dev, "mux-int-port missing or invalid\n"); | ||
270 | return ret; | ||
271 | } | ||
272 | ret = of_property_read_u32(np, "mux-ext-port", &ext_port); | ||
273 | if (ret) { | ||
274 | dev_err(dev, "mux-ext-port missing or invalid\n"); | ||
275 | return ret; | ||
276 | } | ||
277 | |||
278 | /* | ||
279 | * The port numbering in the hardware manual starts at 1, while | ||
280 | * the AUDMUX API expects it starts at 0. | ||
281 | */ | ||
282 | int_port--; | ||
283 | ext_port--; | ||
284 | |||
285 | /* | ||
286 | * Use asynchronous mode (6 wires) for all cases. | ||
287 | * If only 4 wires are needed, just set SSI into | ||
288 | * synchronous mode and enable 4 PADs in IOMUX. | ||
289 | */ | ||
290 | switch (priv->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
291 | case SND_SOC_DAIFMT_CBM_CFM: | ||
292 | int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | | ||
293 | IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | | ||
294 | IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | | ||
295 | IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | | ||
296 | IMX_AUDMUX_V2_PTCR_RFSDIR | | ||
297 | IMX_AUDMUX_V2_PTCR_RCLKDIR | | ||
298 | IMX_AUDMUX_V2_PTCR_TFSDIR | | ||
299 | IMX_AUDMUX_V2_PTCR_TCLKDIR; | ||
300 | break; | ||
301 | case SND_SOC_DAIFMT_CBM_CFS: | ||
302 | int_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | ext_port) | | ||
303 | IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | | ||
304 | IMX_AUDMUX_V2_PTCR_RCLKDIR | | ||
305 | IMX_AUDMUX_V2_PTCR_TCLKDIR; | ||
306 | ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | | ||
307 | IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | | ||
308 | IMX_AUDMUX_V2_PTCR_RFSDIR | | ||
309 | IMX_AUDMUX_V2_PTCR_TFSDIR; | ||
310 | break; | ||
311 | case SND_SOC_DAIFMT_CBS_CFM: | ||
312 | int_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | ext_port) | | ||
313 | IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | | ||
314 | IMX_AUDMUX_V2_PTCR_RFSDIR | | ||
315 | IMX_AUDMUX_V2_PTCR_TFSDIR; | ||
316 | ext_ptcr = IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | | ||
317 | IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | | ||
318 | IMX_AUDMUX_V2_PTCR_RCLKDIR | | ||
319 | IMX_AUDMUX_V2_PTCR_TCLKDIR; | ||
320 | break; | ||
321 | case SND_SOC_DAIFMT_CBS_CFS: | ||
322 | ext_ptcr = IMX_AUDMUX_V2_PTCR_RFSEL(8 | int_port) | | ||
323 | IMX_AUDMUX_V2_PTCR_RCSEL(8 | int_port) | | ||
324 | IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | | ||
325 | IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | | ||
326 | IMX_AUDMUX_V2_PTCR_RFSDIR | | ||
327 | IMX_AUDMUX_V2_PTCR_RCLKDIR | | ||
328 | IMX_AUDMUX_V2_PTCR_TFSDIR | | ||
329 | IMX_AUDMUX_V2_PTCR_TCLKDIR; | ||
330 | break; | ||
331 | default: | ||
332 | return -EINVAL; | ||
333 | } | ||
334 | |||
335 | /* Asynchronous mode can not be set along with RCLKDIR */ | ||
336 | ret = imx_audmux_v2_configure_port(int_port, 0, | ||
337 | IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); | ||
338 | if (ret) { | ||
339 | dev_err(dev, "audmux internal port setup failed\n"); | ||
340 | return ret; | ||
341 | } | ||
342 | |||
343 | ret = imx_audmux_v2_configure_port(int_port, int_ptcr, | ||
344 | IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); | ||
345 | if (ret) { | ||
346 | dev_err(dev, "audmux internal port setup failed\n"); | ||
347 | return ret; | ||
348 | } | ||
349 | |||
350 | ret = imx_audmux_v2_configure_port(ext_port, 0, | ||
351 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); | ||
352 | if (ret) { | ||
353 | dev_err(dev, "audmux external port setup failed\n"); | ||
354 | return ret; | ||
355 | } | ||
356 | |||
357 | ret = imx_audmux_v2_configure_port(ext_port, ext_ptcr, | ||
358 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); | ||
359 | if (ret) { | ||
360 | dev_err(dev, "audmux external port setup failed\n"); | ||
361 | return ret; | ||
362 | } | ||
363 | |||
364 | return 0; | ||
365 | } | ||
366 | |||
367 | static int fsl_asoc_card_late_probe(struct snd_soc_card *card) | ||
368 | { | ||
369 | struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card); | ||
370 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | ||
371 | struct codec_priv *codec_priv = &priv->codec_priv; | ||
372 | struct device *dev = card->dev; | ||
373 | int ret; | ||
374 | |||
375 | ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id, | ||
376 | codec_priv->mclk_freq, SND_SOC_CLOCK_IN); | ||
377 | if (ret) { | ||
378 | dev_err(dev, "failed to set sysclk in %s\n", __func__); | ||
379 | return ret; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int fsl_asoc_card_probe(struct platform_device *pdev) | ||
386 | { | ||
387 | struct device_node *cpu_np, *codec_np, *asrc_np; | ||
388 | struct device_node *np = pdev->dev.of_node; | ||
389 | struct platform_device *asrc_pdev = NULL; | ||
390 | struct platform_device *cpu_pdev; | ||
391 | struct fsl_asoc_card_priv *priv; | ||
392 | struct i2c_client *codec_dev; | ||
393 | struct clk *codec_clk; | ||
394 | u32 width; | ||
395 | int ret; | ||
396 | |||
397 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
398 | if (!priv) | ||
399 | return -ENOMEM; | ||
400 | |||
401 | cpu_np = of_parse_phandle(np, "audio-cpu", 0); | ||
402 | /* Give a chance to old DT binding */ | ||
403 | if (!cpu_np) | ||
404 | cpu_np = of_parse_phandle(np, "ssi-controller", 0); | ||
405 | codec_np = of_parse_phandle(np, "audio-codec", 0); | ||
406 | if (!cpu_np || !codec_np) { | ||
407 | dev_err(&pdev->dev, "phandle missing or invalid\n"); | ||
408 | ret = -EINVAL; | ||
409 | goto fail; | ||
410 | } | ||
411 | |||
412 | cpu_pdev = of_find_device_by_node(cpu_np); | ||
413 | if (!cpu_pdev) { | ||
414 | dev_err(&pdev->dev, "failed to find CPU DAI device\n"); | ||
415 | ret = -EINVAL; | ||
416 | goto fail; | ||
417 | } | ||
418 | |||
419 | codec_dev = of_find_i2c_device_by_node(codec_np); | ||
420 | if (!codec_dev) { | ||
421 | dev_err(&pdev->dev, "failed to find codec platform device\n"); | ||
422 | ret = -EINVAL; | ||
423 | goto fail; | ||
424 | } | ||
425 | |||
426 | asrc_np = of_parse_phandle(np, "audio-asrc", 0); | ||
427 | if (asrc_np) | ||
428 | asrc_pdev = of_find_device_by_node(asrc_np); | ||
429 | |||
430 | /* Get the MCLK rate only, and leave it controlled by CODEC drivers */ | ||
431 | codec_clk = clk_get(&codec_dev->dev, NULL); | ||
432 | if (!IS_ERR(codec_clk)) { | ||
433 | priv->codec_priv.mclk_freq = clk_get_rate(codec_clk); | ||
434 | clk_put(codec_clk); | ||
435 | } | ||
436 | |||
437 | /* Default sample rate and format, will be updated in hw_params() */ | ||
438 | priv->sample_rate = 44100; | ||
439 | priv->sample_format = SNDRV_PCM_FORMAT_S16_LE; | ||
440 | |||
441 | /* Assign a default DAI format, and allow each card to overwrite it */ | ||
442 | priv->dai_fmt = DAI_FMT_BASE; | ||
443 | |||
444 | /* Diversify the card configurations */ | ||
445 | if (of_device_is_compatible(np, "fsl,imx-audio-cs42888")) { | ||
446 | priv->card.set_bias_level = NULL; | ||
447 | priv->cpu_priv.sysclk_freq[TX] = priv->codec_priv.mclk_freq; | ||
448 | priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq; | ||
449 | priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; | ||
450 | priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT; | ||
451 | priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; | ||
452 | } else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) { | ||
453 | priv->codec_priv.mclk_id = SGTL5000_SYSCLK; | ||
454 | priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
455 | } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8962")) { | ||
456 | priv->card.set_bias_level = fsl_asoc_card_set_bias_level; | ||
457 | priv->codec_priv.mclk_id = WM8962_SYSCLK_MCLK; | ||
458 | priv->codec_priv.fll_id = WM8962_SYSCLK_FLL; | ||
459 | priv->codec_priv.pll_id = WM8962_FLL; | ||
460 | priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; | ||
461 | } else { | ||
462 | dev_err(&pdev->dev, "unknown Device Tree compatible\n"); | ||
463 | return -EINVAL; | ||
464 | } | ||
465 | |||
466 | /* Common settings for corresponding Freescale CPU DAI driver */ | ||
467 | if (strstr(cpu_np->name, "ssi")) { | ||
468 | /* Only SSI needs to configure AUDMUX */ | ||
469 | ret = fsl_asoc_card_audmux_init(np, priv); | ||
470 | if (ret) { | ||
471 | dev_err(&pdev->dev, "failed to init audmux\n"); | ||
472 | goto asrc_fail; | ||
473 | } | ||
474 | } else if (strstr(cpu_np->name, "esai")) { | ||
475 | priv->cpu_priv.sysclk_id[1] = ESAI_HCKT_EXTAL; | ||
476 | priv->cpu_priv.sysclk_id[0] = ESAI_HCKR_EXTAL; | ||
477 | } else if (strstr(cpu_np->name, "sai")) { | ||
478 | priv->cpu_priv.sysclk_id[1] = FSL_SAI_CLK_MAST1; | ||
479 | priv->cpu_priv.sysclk_id[0] = FSL_SAI_CLK_MAST1; | ||
480 | } | ||
481 | |||
482 | sprintf(priv->name, "%s-audio", codec_dev->name); | ||
483 | |||
484 | /* Initialize sound card */ | ||
485 | priv->pdev = pdev; | ||
486 | priv->card.dev = &pdev->dev; | ||
487 | priv->card.name = priv->name; | ||
488 | priv->card.dai_link = priv->dai_link; | ||
489 | priv->card.dapm_routes = audio_map; | ||
490 | priv->card.late_probe = fsl_asoc_card_late_probe; | ||
491 | priv->card.num_dapm_routes = ARRAY_SIZE(audio_map); | ||
492 | priv->card.dapm_widgets = fsl_asoc_card_dapm_widgets; | ||
493 | priv->card.num_dapm_widgets = ARRAY_SIZE(fsl_asoc_card_dapm_widgets); | ||
494 | |||
495 | memcpy(priv->dai_link, fsl_asoc_card_dai, | ||
496 | sizeof(struct snd_soc_dai_link) * ARRAY_SIZE(priv->dai_link)); | ||
497 | |||
498 | /* Normal DAI Link */ | ||
499 | priv->dai_link[0].cpu_of_node = cpu_np; | ||
500 | priv->dai_link[0].codec_of_node = codec_np; | ||
501 | priv->dai_link[0].codec_dai_name = codec_dev->name; | ||
502 | priv->dai_link[0].platform_of_node = cpu_np; | ||
503 | priv->dai_link[0].dai_fmt = priv->dai_fmt; | ||
504 | priv->card.num_links = 1; | ||
505 | |||
506 | if (asrc_pdev) { | ||
507 | /* DPCM DAI Links only if ASRC exsits */ | ||
508 | priv->dai_link[1].cpu_of_node = asrc_np; | ||
509 | priv->dai_link[1].platform_of_node = asrc_np; | ||
510 | priv->dai_link[2].codec_dai_name = codec_dev->name; | ||
511 | priv->dai_link[2].codec_of_node = codec_np; | ||
512 | priv->dai_link[2].cpu_of_node = cpu_np; | ||
513 | priv->dai_link[2].dai_fmt = priv->dai_fmt; | ||
514 | priv->card.num_links = 3; | ||
515 | |||
516 | ret = of_property_read_u32(asrc_np, "fsl,asrc-rate", | ||
517 | &priv->asrc_rate); | ||
518 | if (ret) { | ||
519 | dev_err(&pdev->dev, "failed to get output rate\n"); | ||
520 | ret = -EINVAL; | ||
521 | goto asrc_fail; | ||
522 | } | ||
523 | |||
524 | ret = of_property_read_u32(asrc_np, "fsl,asrc-width", &width); | ||
525 | if (ret) { | ||
526 | dev_err(&pdev->dev, "failed to get output rate\n"); | ||
527 | ret = -EINVAL; | ||
528 | goto asrc_fail; | ||
529 | } | ||
530 | |||
531 | if (width == 24) | ||
532 | priv->asrc_format = SNDRV_PCM_FORMAT_S24_LE; | ||
533 | else | ||
534 | priv->asrc_format = SNDRV_PCM_FORMAT_S16_LE; | ||
535 | } | ||
536 | |||
537 | /* Finish card registering */ | ||
538 | platform_set_drvdata(pdev, priv); | ||
539 | snd_soc_card_set_drvdata(&priv->card, priv); | ||
540 | |||
541 | ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); | ||
542 | if (ret) | ||
543 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | ||
544 | |||
545 | asrc_fail: | ||
546 | of_node_put(asrc_np); | ||
547 | fail: | ||
548 | of_node_put(codec_np); | ||
549 | of_node_put(cpu_np); | ||
550 | |||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | static const struct of_device_id fsl_asoc_card_dt_ids[] = { | ||
555 | { .compatible = "fsl,imx-audio-cs42888", }, | ||
556 | { .compatible = "fsl,imx-audio-sgtl5000", }, | ||
557 | { .compatible = "fsl,imx-audio-wm8962", }, | ||
558 | {} | ||
559 | }; | ||
560 | |||
561 | static struct platform_driver fsl_asoc_card_driver = { | ||
562 | .probe = fsl_asoc_card_probe, | ||
563 | .driver = { | ||
564 | .name = "fsl-asoc-card", | ||
565 | .pm = &snd_soc_pm_ops, | ||
566 | .of_match_table = fsl_asoc_card_dt_ids, | ||
567 | }, | ||
568 | }; | ||
569 | module_platform_driver(fsl_asoc_card_driver); | ||
570 | |||
571 | MODULE_DESCRIPTION("Freescale Generic ASoC Sound Card driver with ASRC"); | ||
572 | MODULE_AUTHOR("Nicolin Chen <nicoleotsuka@gmail.com>"); | ||
573 | MODULE_ALIAS("platform:fsl-asoc-card"); | ||
574 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 822110420b71..3b145313f93e 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c | |||
@@ -684,7 +684,7 @@ static bool fsl_asrc_writeable_reg(struct device *dev, unsigned int reg) | |||
684 | } | 684 | } |
685 | } | 685 | } |
686 | 686 | ||
687 | static struct regmap_config fsl_asrc_regmap_config = { | 687 | static const struct regmap_config fsl_asrc_regmap_config = { |
688 | .reg_bits = 32, | 688 | .reg_bits = 32, |
689 | .reg_stride = 4, | 689 | .reg_stride = 4, |
690 | .val_bits = 32, | 690 | .val_bits = 32, |
@@ -802,10 +802,6 @@ static int fsl_asrc_probe(struct platform_device *pdev) | |||
802 | 802 | ||
803 | asrc_priv->paddr = res->start; | 803 | asrc_priv->paddr = res->start; |
804 | 804 | ||
805 | /* Register regmap and let it prepare core clock */ | ||
806 | if (of_property_read_bool(np, "big-endian")) | ||
807 | fsl_asrc_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
808 | |||
809 | asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, | 805 | asrc_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "mem", regs, |
810 | &fsl_asrc_regmap_config); | 806 | &fsl_asrc_regmap_config); |
811 | if (IS_ERR(asrc_priv->regmap)) { | 807 | if (IS_ERR(asrc_priv->regmap)) { |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 72d154e7dd03..8bcdfda09d7a 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
@@ -18,7 +18,6 @@ | |||
18 | 18 | ||
19 | #include "fsl_esai.h" | 19 | #include "fsl_esai.h" |
20 | #include "imx-pcm.h" | 20 | #include "imx-pcm.h" |
21 | #include "fsl_utils.h" | ||
22 | 21 | ||
23 | #define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000 | 22 | #define FSL_ESAI_RATES SNDRV_PCM_RATE_8000_192000 |
24 | #define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ | 23 | #define FSL_ESAI_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ |
@@ -38,6 +37,7 @@ | |||
38 | * @fsysclk: system clock source to derive HCK, SCK and FS | 37 | * @fsysclk: system clock source to derive HCK, SCK and FS |
39 | * @fifo_depth: depth of tx/rx FIFO | 38 | * @fifo_depth: depth of tx/rx FIFO |
40 | * @slot_width: width of each DAI slot | 39 | * @slot_width: width of each DAI slot |
40 | * @slots: number of slots | ||
41 | * @hck_rate: clock rate of desired HCKx clock | 41 | * @hck_rate: clock rate of desired HCKx clock |
42 | * @sck_rate: clock rate of desired SCKx clock | 42 | * @sck_rate: clock rate of desired SCKx clock |
43 | * @hck_dir: the direction of HCKx pads | 43 | * @hck_dir: the direction of HCKx pads |
@@ -56,6 +56,7 @@ struct fsl_esai { | |||
56 | struct clk *fsysclk; | 56 | struct clk *fsysclk; |
57 | u32 fifo_depth; | 57 | u32 fifo_depth; |
58 | u32 slot_width; | 58 | u32 slot_width; |
59 | u32 slots; | ||
59 | u32 hck_rate[2]; | 60 | u32 hck_rate[2]; |
60 | u32 sck_rate[2]; | 61 | u32 sck_rate[2]; |
61 | bool hck_dir[2]; | 62 | bool hck_dir[2]; |
@@ -363,6 +364,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, | |||
363 | ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); | 364 | ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); |
364 | 365 | ||
365 | esai_priv->slot_width = slot_width; | 366 | esai_priv->slot_width = slot_width; |
367 | esai_priv->slots = slots; | ||
366 | 368 | ||
367 | return 0; | 369 | return 0; |
368 | } | 370 | } |
@@ -510,10 +512,11 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
510 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 512 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
511 | u32 width = snd_pcm_format_width(params_format(params)); | 513 | u32 width = snd_pcm_format_width(params_format(params)); |
512 | u32 channels = params_channels(params); | 514 | u32 channels = params_channels(params); |
515 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); | ||
513 | u32 bclk, mask, val; | 516 | u32 bclk, mask, val; |
514 | int ret; | 517 | int ret; |
515 | 518 | ||
516 | bclk = params_rate(params) * esai_priv->slot_width * 2; | 519 | bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots; |
517 | 520 | ||
518 | ret = fsl_esai_set_bclk(dai, tx, bclk); | 521 | ret = fsl_esai_set_bclk(dai, tx, bclk); |
519 | if (ret) | 522 | if (ret) |
@@ -530,7 +533,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | |||
530 | mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | | 533 | mask = ESAI_xFCR_xFR_MASK | ESAI_xFCR_xWA_MASK | ESAI_xFCR_xFWM_MASK | |
531 | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); | 534 | (tx ? ESAI_xFCR_TE_MASK | ESAI_xFCR_TIEN : ESAI_xFCR_RE_MASK); |
532 | val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | | 535 | val = ESAI_xFCR_xWA(width) | ESAI_xFCR_xFWM(esai_priv->fifo_depth) | |
533 | (tx ? ESAI_xFCR_TE(channels) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(channels)); | 536 | (tx ? ESAI_xFCR_TE(pins) | ESAI_xFCR_TIEN : ESAI_xFCR_RE(pins)); |
534 | 537 | ||
535 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); | 538 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val); |
536 | 539 | ||
@@ -565,6 +568,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
565 | struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); | 568 | struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); |
566 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; | 569 | bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
567 | u8 i, channels = substream->runtime->channels; | 570 | u8 i, channels = substream->runtime->channels; |
571 | u32 pins = DIV_ROUND_UP(channels, esai_priv->slots); | ||
568 | 572 | ||
569 | switch (cmd) { | 573 | switch (cmd) { |
570 | case SNDRV_PCM_TRIGGER_START: | 574 | case SNDRV_PCM_TRIGGER_START: |
@@ -579,7 +583,7 @@ static int fsl_esai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
579 | 583 | ||
580 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), | 584 | regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), |
581 | tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, | 585 | tx ? ESAI_xCR_TE_MASK : ESAI_xCR_RE_MASK, |
582 | tx ? ESAI_xCR_TE(channels) : ESAI_xCR_RE(channels)); | 586 | tx ? ESAI_xCR_TE(pins) : ESAI_xCR_RE(pins)); |
583 | break; | 587 | break; |
584 | case SNDRV_PCM_TRIGGER_SUSPEND: | 588 | case SNDRV_PCM_TRIGGER_SUSPEND: |
585 | case SNDRV_PCM_TRIGGER_STOP: | 589 | case SNDRV_PCM_TRIGGER_STOP: |
@@ -607,7 +611,6 @@ static struct snd_soc_dai_ops fsl_esai_dai_ops = { | |||
607 | .hw_params = fsl_esai_hw_params, | 611 | .hw_params = fsl_esai_hw_params, |
608 | .set_sysclk = fsl_esai_set_dai_sysclk, | 612 | .set_sysclk = fsl_esai_set_dai_sysclk, |
609 | .set_fmt = fsl_esai_set_dai_fmt, | 613 | .set_fmt = fsl_esai_set_dai_fmt, |
610 | .xlate_tdm_slot_mask = fsl_asoc_xlate_tdm_slot_mask, | ||
611 | .set_tdm_slot = fsl_esai_set_dai_tdm_slot, | 614 | .set_tdm_slot = fsl_esai_set_dai_tdm_slot, |
612 | }; | 615 | }; |
613 | 616 | ||
@@ -707,7 +710,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) | |||
707 | } | 710 | } |
708 | } | 711 | } |
709 | 712 | ||
710 | static struct regmap_config fsl_esai_regmap_config = { | 713 | static const struct regmap_config fsl_esai_regmap_config = { |
711 | .reg_bits = 32, | 714 | .reg_bits = 32, |
712 | .reg_stride = 4, | 715 | .reg_stride = 4, |
713 | .val_bits = 32, | 716 | .val_bits = 32, |
@@ -733,9 +736,6 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
733 | esai_priv->pdev = pdev; | 736 | esai_priv->pdev = pdev; |
734 | strcpy(esai_priv->name, np->name); | 737 | strcpy(esai_priv->name, np->name); |
735 | 738 | ||
736 | if (of_property_read_bool(np, "big-endian")) | ||
737 | fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
738 | |||
739 | /* Get the addresses and IRQ */ | 739 | /* Get the addresses and IRQ */ |
740 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 740 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
741 | regs = devm_ioremap_resource(&pdev->dev, res); | 741 | regs = devm_ioremap_resource(&pdev->dev, res); |
@@ -783,6 +783,9 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
783 | /* Set a default slot size */ | 783 | /* Set a default slot size */ |
784 | esai_priv->slot_width = 32; | 784 | esai_priv->slot_width = 32; |
785 | 785 | ||
786 | /* Set a default slot number */ | ||
787 | esai_priv->slots = 2; | ||
788 | |||
786 | /* Set a default master/slave state */ | 789 | /* Set a default master/slave state */ |
787 | esai_priv->slave_mode = true; | 790 | esai_priv->slave_mode = true; |
788 | 791 | ||
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 75e14033e8d8..91a550f4a10d 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h | |||
@@ -130,8 +130,8 @@ | |||
130 | #define ESAI_xFCR_RE_WIDTH 4 | 130 | #define ESAI_xFCR_RE_WIDTH 4 |
131 | #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) | 131 | #define ESAI_xFCR_TE_MASK (((1 << ESAI_xFCR_TE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) |
132 | #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) | 132 | #define ESAI_xFCR_RE_MASK (((1 << ESAI_xFCR_RE_WIDTH) - 1) << ESAI_xFCR_xE_SHIFT) |
133 | #define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_TE_MASK) | 133 | #define ESAI_xFCR_TE(x) ((ESAI_xFCR_TE_MASK >> (ESAI_xFCR_TE_WIDTH - x)) & ESAI_xFCR_TE_MASK) |
134 | #define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xFCR_RE_MASK) | 134 | #define ESAI_xFCR_RE(x) ((ESAI_xFCR_RE_MASK >> (ESAI_xFCR_RE_WIDTH - x)) & ESAI_xFCR_RE_MASK) |
135 | #define ESAI_xFCR_xFR_SHIFT 1 | 135 | #define ESAI_xFCR_xFR_SHIFT 1 |
136 | #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) | 136 | #define ESAI_xFCR_xFR_MASK (1 << ESAI_xFCR_xFR_SHIFT) |
137 | #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) | 137 | #define ESAI_xFCR_xFR (1 << ESAI_xFCR_xFR_SHIFT) |
@@ -272,8 +272,8 @@ | |||
272 | #define ESAI_xCR_RE_WIDTH 4 | 272 | #define ESAI_xCR_RE_WIDTH 4 |
273 | #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) | 273 | #define ESAI_xCR_TE_MASK (((1 << ESAI_xCR_TE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) |
274 | #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) | 274 | #define ESAI_xCR_RE_MASK (((1 << ESAI_xCR_RE_WIDTH) - 1) << ESAI_xCR_xE_SHIFT) |
275 | #define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_TE_MASK) | 275 | #define ESAI_xCR_TE(x) ((ESAI_xCR_TE_MASK >> (ESAI_xCR_TE_WIDTH - x)) & ESAI_xCR_TE_MASK) |
276 | #define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - ((x + 1) >> 1))) & ESAI_xCR_RE_MASK) | 276 | #define ESAI_xCR_RE(x) ((ESAI_xCR_RE_MASK >> (ESAI_xCR_RE_WIDTH - x)) & ESAI_xCR_RE_MASK) |
277 | 277 | ||
278 | /* | 278 | /* |
279 | * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 | 279 | * Transmit Clock Control Register -- REG_ESAI_TCCR 0xD8 |
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index faa049797897..7eeb1dd8ce27 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
@@ -175,7 +175,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, | |||
175 | bool tx = fsl_dir == FSL_FMT_TRANSMITTER; | 175 | bool tx = fsl_dir == FSL_FMT_TRANSMITTER; |
176 | u32 val_cr2 = 0, val_cr4 = 0; | 176 | u32 val_cr2 = 0, val_cr4 = 0; |
177 | 177 | ||
178 | if (!sai->big_endian_data) | 178 | if (!sai->is_lsb_first) |
179 | val_cr4 |= FSL_SAI_CR4_MF; | 179 | val_cr4 |= FSL_SAI_CR4_MF; |
180 | 180 | ||
181 | /* DAI mode */ | 181 | /* DAI mode */ |
@@ -304,7 +304,7 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
304 | val_cr5 |= FSL_SAI_CR5_WNW(word_width); | 304 | val_cr5 |= FSL_SAI_CR5_WNW(word_width); |
305 | val_cr5 |= FSL_SAI_CR5_W0W(word_width); | 305 | val_cr5 |= FSL_SAI_CR5_W0W(word_width); |
306 | 306 | ||
307 | if (sai->big_endian_data) | 307 | if (sai->is_lsb_first) |
308 | val_cr5 |= FSL_SAI_CR5_FBT(0); | 308 | val_cr5 |= FSL_SAI_CR5_FBT(0); |
309 | else | 309 | else |
310 | val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); | 310 | val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); |
@@ -330,13 +330,13 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
330 | u32 xcsr, count = 100; | 330 | u32 xcsr, count = 100; |
331 | 331 | ||
332 | /* | 332 | /* |
333 | * The transmitter bit clock and frame sync are to be | 333 | * Asynchronous mode: Clear SYNC for both Tx and Rx. |
334 | * used by both the transmitter and receiver. | 334 | * Rx sync with Tx clocks: Clear SYNC for Tx, set it for Rx. |
335 | * Tx sync with Rx clocks: Clear SYNC for Rx, set it for Tx. | ||
335 | */ | 336 | */ |
336 | regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, | 337 | regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, 0); |
337 | ~FSL_SAI_CR2_SYNC); | ||
338 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, | 338 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, |
339 | FSL_SAI_CR2_SYNC); | 339 | sai->synchronous[RX] ? FSL_SAI_CR2_SYNC : 0); |
340 | 340 | ||
341 | /* | 341 | /* |
342 | * It is recommended that the transmitter is the last enabled | 342 | * It is recommended that the transmitter is the last enabled |
@@ -437,8 +437,13 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) | |||
437 | { | 437 | { |
438 | struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); | 438 | struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); |
439 | 439 | ||
440 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); | 440 | /* Software Reset for both Tx and Rx */ |
441 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); | 441 | regmap_write(sai->regmap, FSL_SAI_TCSR, FSL_SAI_CSR_SR); |
442 | regmap_write(sai->regmap, FSL_SAI_RCSR, FSL_SAI_CSR_SR); | ||
443 | /* Clear SR bit to finish the reset */ | ||
444 | regmap_write(sai->regmap, FSL_SAI_TCSR, 0); | ||
445 | regmap_write(sai->regmap, FSL_SAI_RCSR, 0); | ||
446 | |||
442 | regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, | 447 | regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, |
443 | FSL_SAI_MAXBURST_TX * 2); | 448 | FSL_SAI_MAXBURST_TX * 2); |
444 | regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, | 449 | regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, |
@@ -539,7 +544,7 @@ static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) | |||
539 | } | 544 | } |
540 | } | 545 | } |
541 | 546 | ||
542 | static struct regmap_config fsl_sai_regmap_config = { | 547 | static const struct regmap_config fsl_sai_regmap_config = { |
543 | .reg_bits = 32, | 548 | .reg_bits = 32, |
544 | .reg_stride = 4, | 549 | .reg_stride = 4, |
545 | .val_bits = 32, | 550 | .val_bits = 32, |
@@ -568,11 +573,7 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
568 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) | 573 | if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx6sx-sai")) |
569 | sai->sai_on_imx = true; | 574 | sai->sai_on_imx = true; |
570 | 575 | ||
571 | sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); | 576 | sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); |
572 | if (sai->big_endian_regs) | ||
573 | fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
574 | |||
575 | sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); | ||
576 | 577 | ||
577 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 578 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
578 | base = devm_ioremap_resource(&pdev->dev, res); | 579 | base = devm_ioremap_resource(&pdev->dev, res); |
@@ -621,6 +622,33 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
621 | return ret; | 622 | return ret; |
622 | } | 623 | } |
623 | 624 | ||
625 | /* Sync Tx with Rx as default by following old DT binding */ | ||
626 | sai->synchronous[RX] = true; | ||
627 | sai->synchronous[TX] = false; | ||
628 | fsl_sai_dai.symmetric_rates = 1; | ||
629 | fsl_sai_dai.symmetric_channels = 1; | ||
630 | fsl_sai_dai.symmetric_samplebits = 1; | ||
631 | |||
632 | if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && | ||
633 | of_find_property(np, "fsl,sai-asynchronous", NULL)) { | ||
634 | /* error out if both synchronous and asynchronous are present */ | ||
635 | dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); | ||
636 | return -EINVAL; | ||
637 | } | ||
638 | |||
639 | if (of_find_property(np, "fsl,sai-synchronous-rx", NULL)) { | ||
640 | /* Sync Rx with Tx */ | ||
641 | sai->synchronous[RX] = false; | ||
642 | sai->synchronous[TX] = true; | ||
643 | } else if (of_find_property(np, "fsl,sai-asynchronous", NULL)) { | ||
644 | /* Discard all settings for asynchronous mode */ | ||
645 | sai->synchronous[RX] = false; | ||
646 | sai->synchronous[TX] = false; | ||
647 | fsl_sai_dai.symmetric_rates = 0; | ||
648 | fsl_sai_dai.symmetric_channels = 0; | ||
649 | fsl_sai_dai.symmetric_samplebits = 0; | ||
650 | } | ||
651 | |||
624 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; | 652 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; |
625 | sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; | 653 | sai->dma_params_tx.addr = res->start + FSL_SAI_TDR; |
626 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; | 654 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; |
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 0e6c9f595d75..34667209b607 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h | |||
@@ -48,6 +48,7 @@ | |||
48 | /* SAI Transmit/Recieve Control Register */ | 48 | /* SAI Transmit/Recieve Control Register */ |
49 | #define FSL_SAI_CSR_TERE BIT(31) | 49 | #define FSL_SAI_CSR_TERE BIT(31) |
50 | #define FSL_SAI_CSR_FR BIT(25) | 50 | #define FSL_SAI_CSR_FR BIT(25) |
51 | #define FSL_SAI_CSR_SR BIT(24) | ||
51 | #define FSL_SAI_CSR_xF_SHIFT 16 | 52 | #define FSL_SAI_CSR_xF_SHIFT 16 |
52 | #define FSL_SAI_CSR_xF_W_SHIFT 18 | 53 | #define FSL_SAI_CSR_xF_W_SHIFT 18 |
53 | #define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT) | 54 | #define FSL_SAI_CSR_xF_MASK (0x1f << FSL_SAI_CSR_xF_SHIFT) |
@@ -131,13 +132,16 @@ struct fsl_sai { | |||
131 | struct clk *bus_clk; | 132 | struct clk *bus_clk; |
132 | struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; | 133 | struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; |
133 | 134 | ||
134 | bool big_endian_regs; | 135 | bool is_lsb_first; |
135 | bool big_endian_data; | ||
136 | bool is_dsp_mode; | 136 | bool is_dsp_mode; |
137 | bool sai_on_imx; | 137 | bool sai_on_imx; |
138 | bool synchronous[2]; | ||
138 | 139 | ||
139 | struct snd_dmaengine_dai_dma_data dma_params_rx; | 140 | struct snd_dmaengine_dai_dma_data dma_params_rx; |
140 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 141 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
141 | }; | 142 | }; |
142 | 143 | ||
144 | #define TX 1 | ||
145 | #define RX 0 | ||
146 | |||
143 | #endif /* __FSL_SAI_H */ | 147 | #endif /* __FSL_SAI_H */ |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 70acfe4a9bd5..9b791621294c 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -15,7 +15,6 @@ | |||
15 | 15 | ||
16 | #include <linux/bitrev.h> | 16 | #include <linux/bitrev.h> |
17 | #include <linux/clk.h> | 17 | #include <linux/clk.h> |
18 | #include <linux/clk-private.h> | ||
19 | #include <linux/module.h> | 18 | #include <linux/module.h> |
20 | #include <linux/of_address.h> | 19 | #include <linux/of_address.h> |
21 | #include <linux/of_device.h> | 20 | #include <linux/of_device.h> |
@@ -1040,7 +1039,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) | |||
1040 | } | 1039 | } |
1041 | } | 1040 | } |
1042 | 1041 | ||
1043 | static struct regmap_config fsl_spdif_regmap_config = { | 1042 | static const struct regmap_config fsl_spdif_regmap_config = { |
1044 | .reg_bits = 32, | 1043 | .reg_bits = 32, |
1045 | .reg_stride = 4, | 1044 | .reg_stride = 4, |
1046 | .val_bits = 32, | 1045 | .val_bits = 32, |
@@ -1184,9 +1183,6 @@ static int fsl_spdif_probe(struct platform_device *pdev) | |||
1184 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | 1183 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); |
1185 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; | 1184 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; |
1186 | 1185 | ||
1187 | if (of_property_read_bool(np, "big-endian")) | ||
1188 | fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
1189 | |||
1190 | /* Get the addresses and IRQ */ | 1186 | /* Get the addresses and IRQ */ |
1191 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1187 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1192 | regs = devm_ioremap_resource(&pdev->dev, res); | 1188 | regs = devm_ioremap_resource(&pdev->dev, res); |
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 87eb5776a39b..e6955170dc42 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c | |||
@@ -169,6 +169,7 @@ struct fsl_ssi_private { | |||
169 | u8 i2s_mode; | 169 | u8 i2s_mode; |
170 | bool use_dma; | 170 | bool use_dma; |
171 | bool use_dual_fifo; | 171 | bool use_dual_fifo; |
172 | bool has_ipg_clk_name; | ||
172 | unsigned int fifo_depth; | 173 | unsigned int fifo_depth; |
173 | struct fsl_ssi_rxtx_reg_val rxtx_reg_val; | 174 | struct fsl_ssi_rxtx_reg_val rxtx_reg_val; |
174 | 175 | ||
@@ -259,6 +260,11 @@ static bool fsl_ssi_is_i2s_master(struct fsl_ssi_private *ssi_private) | |||
259 | SND_SOC_DAIFMT_CBS_CFS; | 260 | SND_SOC_DAIFMT_CBS_CFS; |
260 | } | 261 | } |
261 | 262 | ||
263 | static bool fsl_ssi_is_i2s_cbm_cfs(struct fsl_ssi_private *ssi_private) | ||
264 | { | ||
265 | return (ssi_private->dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == | ||
266 | SND_SOC_DAIFMT_CBM_CFS; | ||
267 | } | ||
262 | /** | 268 | /** |
263 | * fsl_ssi_isr: SSI interrupt handler | 269 | * fsl_ssi_isr: SSI interrupt handler |
264 | * | 270 | * |
@@ -525,6 +531,11 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
525 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 531 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
526 | struct fsl_ssi_private *ssi_private = | 532 | struct fsl_ssi_private *ssi_private = |
527 | snd_soc_dai_get_drvdata(rtd->cpu_dai); | 533 | snd_soc_dai_get_drvdata(rtd->cpu_dai); |
534 | int ret; | ||
535 | |||
536 | ret = clk_prepare_enable(ssi_private->clk); | ||
537 | if (ret) | ||
538 | return ret; | ||
528 | 539 | ||
529 | /* When using dual fifo mode, it is safer to ensure an even period | 540 | /* When using dual fifo mode, it is safer to ensure an even period |
530 | * size. If appearing to an odd number while DMA always starts its | 541 | * size. If appearing to an odd number while DMA always starts its |
@@ -539,6 +550,21 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream, | |||
539 | } | 550 | } |
540 | 551 | ||
541 | /** | 552 | /** |
553 | * fsl_ssi_shutdown: shutdown the SSI | ||
554 | * | ||
555 | */ | ||
556 | static void fsl_ssi_shutdown(struct snd_pcm_substream *substream, | ||
557 | struct snd_soc_dai *dai) | ||
558 | { | ||
559 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
560 | struct fsl_ssi_private *ssi_private = | ||
561 | snd_soc_dai_get_drvdata(rtd->cpu_dai); | ||
562 | |||
563 | clk_disable_unprepare(ssi_private->clk); | ||
564 | |||
565 | } | ||
566 | |||
567 | /** | ||
542 | * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock | 568 | * fsl_ssi_set_bclk - configure Digital Audio Interface bit clock |
543 | * | 569 | * |
544 | * Note: This function can be only called when using SSI as DAI master | 570 | * Note: This function can be only called when using SSI as DAI master |
@@ -705,6 +731,23 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, | |||
705 | } | 731 | } |
706 | } | 732 | } |
707 | 733 | ||
734 | if (!fsl_ssi_is_ac97(ssi_private)) { | ||
735 | u8 i2smode; | ||
736 | /* | ||
737 | * Switch to normal net mode in order to have a frame sync | ||
738 | * signal every 32 bits instead of 16 bits | ||
739 | */ | ||
740 | if (fsl_ssi_is_i2s_cbm_cfs(ssi_private) && sample_size == 16) | ||
741 | i2smode = CCSR_SSI_SCR_I2S_MODE_NORMAL | | ||
742 | CCSR_SSI_SCR_NET; | ||
743 | else | ||
744 | i2smode = ssi_private->i2s_mode; | ||
745 | |||
746 | regmap_update_bits(regs, CCSR_SSI_SCR, | ||
747 | CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, | ||
748 | channels == 1 ? 0 : i2smode); | ||
749 | } | ||
750 | |||
708 | /* | 751 | /* |
709 | * FIXME: The documentation says that SxCCR[WL] should not be | 752 | * FIXME: The documentation says that SxCCR[WL] should not be |
710 | * modified while the SSI is enabled. The only time this can | 753 | * modified while the SSI is enabled. The only time this can |
@@ -724,11 +767,6 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, | |||
724 | regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK, | 767 | regmap_update_bits(regs, CCSR_SSI_SRCCR, CCSR_SSI_SxCCR_WL_MASK, |
725 | wl); | 768 | wl); |
726 | 769 | ||
727 | if (!fsl_ssi_is_ac97(ssi_private)) | ||
728 | regmap_update_bits(regs, CCSR_SSI_SCR, | ||
729 | CCSR_SSI_SCR_NET | CCSR_SSI_SCR_I2S_MODE_MASK, | ||
730 | channels == 1 ? 0 : ssi_private->i2s_mode); | ||
731 | |||
732 | return 0; | 770 | return 0; |
733 | } | 771 | } |
734 | 772 | ||
@@ -748,8 +786,9 @@ static int fsl_ssi_hw_free(struct snd_pcm_substream *substream, | |||
748 | return 0; | 786 | return 0; |
749 | } | 787 | } |
750 | 788 | ||
751 | static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, | 789 | static int _fsl_ssi_set_dai_fmt(struct device *dev, |
752 | unsigned int fmt) | 790 | struct fsl_ssi_private *ssi_private, |
791 | unsigned int fmt) | ||
753 | { | 792 | { |
754 | struct regmap *regs = ssi_private->regs; | 793 | struct regmap *regs = ssi_private->regs; |
755 | u32 strcr = 0, stcr, srcr, scr, mask; | 794 | u32 strcr = 0, stcr, srcr, scr, mask; |
@@ -758,7 +797,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, | |||
758 | ssi_private->dai_fmt = fmt; | 797 | ssi_private->dai_fmt = fmt; |
759 | 798 | ||
760 | if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) { | 799 | if (fsl_ssi_is_i2s_master(ssi_private) && IS_ERR(ssi_private->baudclk)) { |
761 | dev_err(&ssi_private->pdev->dev, "baudclk is missing which is necessary for master mode\n"); | 800 | dev_err(dev, "baudclk is missing which is necessary for master mode\n"); |
762 | return -EINVAL; | 801 | return -EINVAL; |
763 | } | 802 | } |
764 | 803 | ||
@@ -780,6 +819,7 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, | |||
780 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 819 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
781 | case SND_SOC_DAIFMT_I2S: | 820 | case SND_SOC_DAIFMT_I2S: |
782 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 821 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
822 | case SND_SOC_DAIFMT_CBM_CFS: | ||
783 | case SND_SOC_DAIFMT_CBS_CFS: | 823 | case SND_SOC_DAIFMT_CBS_CFS: |
784 | ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; | 824 | ssi_private->i2s_mode |= CCSR_SSI_SCR_I2S_MODE_MASTER; |
785 | regmap_update_bits(regs, CCSR_SSI_STCCR, | 825 | regmap_update_bits(regs, CCSR_SSI_STCCR, |
@@ -853,6 +893,11 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi_private *ssi_private, | |||
853 | case SND_SOC_DAIFMT_CBM_CFM: | 893 | case SND_SOC_DAIFMT_CBM_CFM: |
854 | scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; | 894 | scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; |
855 | break; | 895 | break; |
896 | case SND_SOC_DAIFMT_CBM_CFS: | ||
897 | strcr &= ~CCSR_SSI_STCR_TXDIR; | ||
898 | strcr |= CCSR_SSI_STCR_TFDIR; | ||
899 | scr &= ~CCSR_SSI_SCR_SYS_CLK_EN; | ||
900 | break; | ||
856 | default: | 901 | default: |
857 | return -EINVAL; | 902 | return -EINVAL; |
858 | } | 903 | } |
@@ -913,7 +958,7 @@ static int fsl_ssi_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | |||
913 | { | 958 | { |
914 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); | 959 | struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(cpu_dai); |
915 | 960 | ||
916 | return _fsl_ssi_set_dai_fmt(ssi_private, fmt); | 961 | return _fsl_ssi_set_dai_fmt(cpu_dai->dev, ssi_private, fmt); |
917 | } | 962 | } |
918 | 963 | ||
919 | /** | 964 | /** |
@@ -1020,6 +1065,7 @@ static int fsl_ssi_dai_probe(struct snd_soc_dai *dai) | |||
1020 | 1065 | ||
1021 | static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { | 1066 | static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { |
1022 | .startup = fsl_ssi_startup, | 1067 | .startup = fsl_ssi_startup, |
1068 | .shutdown = fsl_ssi_shutdown, | ||
1023 | .hw_params = fsl_ssi_hw_params, | 1069 | .hw_params = fsl_ssi_hw_params, |
1024 | .hw_free = fsl_ssi_hw_free, | 1070 | .hw_free = fsl_ssi_hw_free, |
1025 | .set_fmt = fsl_ssi_set_dai_fmt, | 1071 | .set_fmt = fsl_ssi_set_dai_fmt, |
@@ -1145,17 +1191,22 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, | |||
1145 | u32 dmas[4]; | 1191 | u32 dmas[4]; |
1146 | int ret; | 1192 | int ret; |
1147 | 1193 | ||
1148 | ssi_private->clk = devm_clk_get(&pdev->dev, NULL); | 1194 | if (ssi_private->has_ipg_clk_name) |
1195 | ssi_private->clk = devm_clk_get(&pdev->dev, "ipg"); | ||
1196 | else | ||
1197 | ssi_private->clk = devm_clk_get(&pdev->dev, NULL); | ||
1149 | if (IS_ERR(ssi_private->clk)) { | 1198 | if (IS_ERR(ssi_private->clk)) { |
1150 | ret = PTR_ERR(ssi_private->clk); | 1199 | ret = PTR_ERR(ssi_private->clk); |
1151 | dev_err(&pdev->dev, "could not get clock: %d\n", ret); | 1200 | dev_err(&pdev->dev, "could not get clock: %d\n", ret); |
1152 | return ret; | 1201 | return ret; |
1153 | } | 1202 | } |
1154 | 1203 | ||
1155 | ret = clk_prepare_enable(ssi_private->clk); | 1204 | if (!ssi_private->has_ipg_clk_name) { |
1156 | if (ret) { | 1205 | ret = clk_prepare_enable(ssi_private->clk); |
1157 | dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); | 1206 | if (ret) { |
1158 | return ret; | 1207 | dev_err(&pdev->dev, "clk_prepare_enable failed: %d\n", ret); |
1208 | return ret; | ||
1209 | } | ||
1159 | } | 1210 | } |
1160 | 1211 | ||
1161 | /* For those SLAVE implementations, we ingore non-baudclk cases | 1212 | /* For those SLAVE implementations, we ingore non-baudclk cases |
@@ -1213,8 +1264,9 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, | |||
1213 | return 0; | 1264 | return 0; |
1214 | 1265 | ||
1215 | error_pcm: | 1266 | error_pcm: |
1216 | clk_disable_unprepare(ssi_private->clk); | ||
1217 | 1267 | ||
1268 | if (!ssi_private->has_ipg_clk_name) | ||
1269 | clk_disable_unprepare(ssi_private->clk); | ||
1218 | return ret; | 1270 | return ret; |
1219 | } | 1271 | } |
1220 | 1272 | ||
@@ -1223,7 +1275,8 @@ static void fsl_ssi_imx_clean(struct platform_device *pdev, | |||
1223 | { | 1275 | { |
1224 | if (!ssi_private->use_dma) | 1276 | if (!ssi_private->use_dma) |
1225 | imx_pcm_fiq_exit(pdev); | 1277 | imx_pcm_fiq_exit(pdev); |
1226 | clk_disable_unprepare(ssi_private->clk); | 1278 | if (!ssi_private->has_ipg_clk_name) |
1279 | clk_disable_unprepare(ssi_private->clk); | ||
1227 | } | 1280 | } |
1228 | 1281 | ||
1229 | static int fsl_ssi_probe(struct platform_device *pdev) | 1282 | static int fsl_ssi_probe(struct platform_device *pdev) |
@@ -1262,9 +1315,6 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1262 | if (sprop) { | 1315 | if (sprop) { |
1263 | if (!strcmp(sprop, "ac97-slave")) | 1316 | if (!strcmp(sprop, "ac97-slave")) |
1264 | ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97; | 1317 | ssi_private->dai_fmt = SND_SOC_DAIFMT_AC97; |
1265 | else if (!strcmp(sprop, "i2s-slave")) | ||
1266 | ssi_private->dai_fmt = SND_SOC_DAIFMT_I2S | | ||
1267 | SND_SOC_DAIFMT_CBM_CFM; | ||
1268 | } | 1318 | } |
1269 | 1319 | ||
1270 | ssi_private->use_dma = !of_property_read_bool(np, | 1320 | ssi_private->use_dma = !of_property_read_bool(np, |
@@ -1298,8 +1348,16 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1298 | return -ENOMEM; | 1348 | return -ENOMEM; |
1299 | } | 1349 | } |
1300 | 1350 | ||
1301 | ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, | 1351 | ret = of_property_match_string(np, "clock-names", "ipg"); |
1352 | if (ret < 0) { | ||
1353 | ssi_private->has_ipg_clk_name = false; | ||
1354 | ssi_private->regs = devm_regmap_init_mmio(&pdev->dev, iomem, | ||
1302 | &fsl_ssi_regconfig); | 1355 | &fsl_ssi_regconfig); |
1356 | } else { | ||
1357 | ssi_private->has_ipg_clk_name = true; | ||
1358 | ssi_private->regs = devm_regmap_init_mmio_clk(&pdev->dev, | ||
1359 | "ipg", iomem, &fsl_ssi_regconfig); | ||
1360 | } | ||
1303 | if (IS_ERR(ssi_private->regs)) { | 1361 | if (IS_ERR(ssi_private->regs)) { |
1304 | dev_err(&pdev->dev, "Failed to init register map\n"); | 1362 | dev_err(&pdev->dev, "Failed to init register map\n"); |
1305 | return PTR_ERR(ssi_private->regs); | 1363 | return PTR_ERR(ssi_private->regs); |
@@ -1387,7 +1445,8 @@ static int fsl_ssi_probe(struct platform_device *pdev) | |||
1387 | 1445 | ||
1388 | done: | 1446 | done: |
1389 | if (ssi_private->dai_fmt) | 1447 | if (ssi_private->dai_fmt) |
1390 | _fsl_ssi_set_dai_fmt(ssi_private, ssi_private->dai_fmt); | 1448 | _fsl_ssi_set_dai_fmt(&pdev->dev, ssi_private, |
1449 | ssi_private->dai_fmt); | ||
1391 | 1450 | ||
1392 | return 0; | 1451 | return 0; |
1393 | 1452 | ||
diff --git a/sound/soc/fsl/imx-es8328.c b/sound/soc/fsl/imx-es8328.c new file mode 100644 index 000000000000..653e66d150c8 --- /dev/null +++ b/sound/soc/fsl/imx-es8328.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Freescale Semiconductor, Inc. | ||
3 | * Copyright 2012 Linaro Ltd. | ||
4 | * | ||
5 | * The code contained herein is licensed under the GNU General Public | ||
6 | * License. You may obtain a copy of the GNU General Public License | ||
7 | * Version 2 or later at the following locations: | ||
8 | * | ||
9 | * http://www.opensource.org/licenses/gpl-license.html | ||
10 | * http://www.gnu.org/copyleft/gpl.html | ||
11 | */ | ||
12 | |||
13 | #include <linux/gpio.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/of.h> | ||
16 | #include <linux/of_platform.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/of_gpio.h> | ||
19 | #include <sound/soc.h> | ||
20 | #include <sound/jack.h> | ||
21 | |||
22 | #include "imx-audmux.h" | ||
23 | |||
24 | #define DAI_NAME_SIZE 32 | ||
25 | #define MUX_PORT_MAX 7 | ||
26 | |||
27 | struct imx_es8328_data { | ||
28 | struct device *dev; | ||
29 | struct snd_soc_dai_link dai; | ||
30 | struct snd_soc_card card; | ||
31 | char codec_dai_name[DAI_NAME_SIZE]; | ||
32 | char platform_name[DAI_NAME_SIZE]; | ||
33 | int jack_gpio; | ||
34 | }; | ||
35 | |||
36 | static struct snd_soc_jack_gpio headset_jack_gpios[] = { | ||
37 | { | ||
38 | .gpio = -1, | ||
39 | .name = "headset-gpio", | ||
40 | .report = SND_JACK_HEADSET, | ||
41 | .invert = 0, | ||
42 | .debounce_time = 200, | ||
43 | }, | ||
44 | }; | ||
45 | |||
46 | static struct snd_soc_jack headset_jack; | ||
47 | |||
48 | static int imx_es8328_dai_init(struct snd_soc_pcm_runtime *rtd) | ||
49 | { | ||
50 | struct imx_es8328_data *data = container_of(rtd->card, | ||
51 | struct imx_es8328_data, card); | ||
52 | int ret = 0; | ||
53 | |||
54 | /* Headphone jack detection */ | ||
55 | if (gpio_is_valid(data->jack_gpio)) { | ||
56 | ret = snd_soc_jack_new(rtd->codec, "Headphone", | ||
57 | SND_JACK_HEADPHONE | SND_JACK_BTN_0, | ||
58 | &headset_jack); | ||
59 | if (ret) | ||
60 | return ret; | ||
61 | |||
62 | headset_jack_gpios[0].gpio = data->jack_gpio; | ||
63 | ret = snd_soc_jack_add_gpios(&headset_jack, | ||
64 | ARRAY_SIZE(headset_jack_gpios), | ||
65 | headset_jack_gpios); | ||
66 | } | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | static const struct snd_soc_dapm_widget imx_es8328_dapm_widgets[] = { | ||
72 | SND_SOC_DAPM_MIC("Mic Jack", NULL), | ||
73 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
74 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
75 | SND_SOC_DAPM_REGULATOR_SUPPLY("audio-amp", 1, 0), | ||
76 | }; | ||
77 | |||
78 | static int imx_es8328_probe(struct platform_device *pdev) | ||
79 | { | ||
80 | struct device_node *np = pdev->dev.of_node; | ||
81 | struct device_node *ssi_np, *codec_np; | ||
82 | struct platform_device *ssi_pdev; | ||
83 | struct imx_es8328_data *data; | ||
84 | u32 int_port, ext_port; | ||
85 | int ret; | ||
86 | struct device *dev = &pdev->dev; | ||
87 | |||
88 | ret = of_property_read_u32(np, "mux-int-port", &int_port); | ||
89 | if (ret) { | ||
90 | dev_err(dev, "mux-int-port missing or invalid\n"); | ||
91 | goto fail; | ||
92 | } | ||
93 | if (int_port > MUX_PORT_MAX || int_port == 0) { | ||
94 | dev_err(dev, "mux-int-port: hardware only has %d mux ports\n", | ||
95 | MUX_PORT_MAX); | ||
96 | goto fail; | ||
97 | } | ||
98 | |||
99 | ret = of_property_read_u32(np, "mux-ext-port", &ext_port); | ||
100 | if (ret) { | ||
101 | dev_err(dev, "mux-ext-port missing or invalid\n"); | ||
102 | goto fail; | ||
103 | } | ||
104 | if (ext_port > MUX_PORT_MAX || ext_port == 0) { | ||
105 | dev_err(dev, "mux-ext-port: hardware only has %d mux ports\n", | ||
106 | MUX_PORT_MAX); | ||
107 | goto fail; | ||
108 | } | ||
109 | |||
110 | /* | ||
111 | * The port numbering in the hardware manual starts at 1, while | ||
112 | * the audmux API expects it starts at 0. | ||
113 | */ | ||
114 | int_port--; | ||
115 | ext_port--; | ||
116 | ret = imx_audmux_v2_configure_port(int_port, | ||
117 | IMX_AUDMUX_V2_PTCR_SYN | | ||
118 | IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | | ||
119 | IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | | ||
120 | IMX_AUDMUX_V2_PTCR_TFSDIR | | ||
121 | IMX_AUDMUX_V2_PTCR_TCLKDIR, | ||
122 | IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); | ||
123 | if (ret) { | ||
124 | dev_err(dev, "audmux internal port setup failed\n"); | ||
125 | return ret; | ||
126 | } | ||
127 | ret = imx_audmux_v2_configure_port(ext_port, | ||
128 | IMX_AUDMUX_V2_PTCR_SYN, | ||
129 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); | ||
130 | if (ret) { | ||
131 | dev_err(dev, "audmux external port setup failed\n"); | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | ssi_np = of_parse_phandle(pdev->dev.of_node, "ssi-controller", 0); | ||
136 | codec_np = of_parse_phandle(pdev->dev.of_node, "audio-codec", 0); | ||
137 | if (!ssi_np || !codec_np) { | ||
138 | dev_err(dev, "phandle missing or invalid\n"); | ||
139 | ret = -EINVAL; | ||
140 | goto fail; | ||
141 | } | ||
142 | |||
143 | ssi_pdev = of_find_device_by_node(ssi_np); | ||
144 | if (!ssi_pdev) { | ||
145 | dev_err(dev, "failed to find SSI platform device\n"); | ||
146 | ret = -EINVAL; | ||
147 | goto fail; | ||
148 | } | ||
149 | |||
150 | data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); | ||
151 | if (!data) { | ||
152 | ret = -ENOMEM; | ||
153 | goto fail; | ||
154 | } | ||
155 | |||
156 | data->dev = dev; | ||
157 | |||
158 | data->jack_gpio = of_get_named_gpio(pdev->dev.of_node, "jack-gpio", 0); | ||
159 | |||
160 | data->dai.name = "hifi"; | ||
161 | data->dai.stream_name = "hifi"; | ||
162 | data->dai.codec_dai_name = "es8328-hifi-analog"; | ||
163 | data->dai.codec_of_node = codec_np; | ||
164 | data->dai.cpu_of_node = ssi_np; | ||
165 | data->dai.platform_of_node = ssi_np; | ||
166 | data->dai.init = &imx_es8328_dai_init; | ||
167 | data->dai.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
168 | SND_SOC_DAIFMT_CBM_CFM; | ||
169 | |||
170 | data->card.dev = dev; | ||
171 | data->card.dapm_widgets = imx_es8328_dapm_widgets; | ||
172 | data->card.num_dapm_widgets = ARRAY_SIZE(imx_es8328_dapm_widgets); | ||
173 | ret = snd_soc_of_parse_card_name(&data->card, "model"); | ||
174 | if (ret) { | ||
175 | dev_err(dev, "Unable to parse card name\n"); | ||
176 | goto fail; | ||
177 | } | ||
178 | ret = snd_soc_of_parse_audio_routing(&data->card, "audio-routing"); | ||
179 | if (ret) { | ||
180 | dev_err(dev, "Unable to parse routing: %d\n", ret); | ||
181 | goto fail; | ||
182 | } | ||
183 | data->card.num_links = 1; | ||
184 | data->card.owner = THIS_MODULE; | ||
185 | data->card.dai_link = &data->dai; | ||
186 | |||
187 | ret = snd_soc_register_card(&data->card); | ||
188 | if (ret) { | ||
189 | dev_err(dev, "Unable to register: %d\n", ret); | ||
190 | goto fail; | ||
191 | } | ||
192 | |||
193 | platform_set_drvdata(pdev, data); | ||
194 | fail: | ||
195 | of_node_put(ssi_np); | ||
196 | of_node_put(codec_np); | ||
197 | |||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | static int imx_es8328_remove(struct platform_device *pdev) | ||
202 | { | ||
203 | struct imx_es8328_data *data = platform_get_drvdata(pdev); | ||
204 | |||
205 | snd_soc_jack_free_gpios(&headset_jack, ARRAY_SIZE(headset_jack_gpios), | ||
206 | headset_jack_gpios); | ||
207 | |||
208 | snd_soc_unregister_card(&data->card); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static const struct of_device_id imx_es8328_dt_ids[] = { | ||
214 | { .compatible = "fsl,imx-audio-es8328", }, | ||
215 | { /* sentinel */ } | ||
216 | }; | ||
217 | MODULE_DEVICE_TABLE(of, imx_es8328_dt_ids); | ||
218 | |||
219 | static struct platform_driver imx_es8328_driver = { | ||
220 | .driver = { | ||
221 | .name = "imx-es8328", | ||
222 | .of_match_table = imx_es8328_dt_ids, | ||
223 | }, | ||
224 | .probe = imx_es8328_probe, | ||
225 | .remove = imx_es8328_remove, | ||
226 | }; | ||
227 | module_platform_driver(imx_es8328_driver); | ||
228 | |||
229 | MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>"); | ||
230 | MODULE_DESCRIPTION("Kosagi i.MX6 ES8328 ASoC machine driver"); | ||
231 | MODULE_LICENSE("GPL v2"); | ||
232 | MODULE_ALIAS("platform:imx-audio-es8328"); | ||
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index 159e517fa09a..fcb431fe20b4 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c | |||
@@ -10,10 +10,13 @@ | |||
10 | */ | 10 | */ |
11 | #include <linux/clk.h> | 11 | #include <linux/clk.h> |
12 | #include <linux/device.h> | 12 | #include <linux/device.h> |
13 | #include <linux/gpio.h> | ||
13 | #include <linux/module.h> | 14 | #include <linux/module.h> |
14 | #include <linux/of.h> | 15 | #include <linux/of.h> |
16 | #include <linux/of_gpio.h> | ||
15 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
16 | #include <linux/string.h> | 18 | #include <linux/string.h> |
19 | #include <sound/jack.h> | ||
17 | #include <sound/simple_card.h> | 20 | #include <sound/simple_card.h> |
18 | #include <sound/soc-dai.h> | 21 | #include <sound/soc-dai.h> |
19 | #include <sound/soc.h> | 22 | #include <sound/soc.h> |
@@ -25,9 +28,15 @@ struct simple_card_data { | |||
25 | struct asoc_simple_dai codec_dai; | 28 | struct asoc_simple_dai codec_dai; |
26 | } *dai_props; | 29 | } *dai_props; |
27 | unsigned int mclk_fs; | 30 | unsigned int mclk_fs; |
31 | int gpio_hp_det; | ||
32 | int gpio_mic_det; | ||
28 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ | 33 | struct snd_soc_dai_link dai_link[]; /* dynamically allocated */ |
29 | }; | 34 | }; |
30 | 35 | ||
36 | #define simple_priv_to_dev(priv) ((priv)->snd_card.dev) | ||
37 | #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i) | ||
38 | #define simple_priv_to_props(priv, i) ((priv)->dai_props + i) | ||
39 | |||
31 | static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, | 40 | static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, |
32 | struct snd_pcm_hw_params *params) | 41 | struct snd_pcm_hw_params *params) |
33 | { | 42 | { |
@@ -50,6 +59,32 @@ static struct snd_soc_ops asoc_simple_card_ops = { | |||
50 | .hw_params = asoc_simple_card_hw_params, | 59 | .hw_params = asoc_simple_card_hw_params, |
51 | }; | 60 | }; |
52 | 61 | ||
62 | static struct snd_soc_jack simple_card_hp_jack; | ||
63 | static struct snd_soc_jack_pin simple_card_hp_jack_pins[] = { | ||
64 | { | ||
65 | .pin = "Headphones", | ||
66 | .mask = SND_JACK_HEADPHONE, | ||
67 | }, | ||
68 | }; | ||
69 | static struct snd_soc_jack_gpio simple_card_hp_jack_gpio = { | ||
70 | .name = "Headphone detection", | ||
71 | .report = SND_JACK_HEADPHONE, | ||
72 | .debounce_time = 150, | ||
73 | }; | ||
74 | |||
75 | static struct snd_soc_jack simple_card_mic_jack; | ||
76 | static struct snd_soc_jack_pin simple_card_mic_jack_pins[] = { | ||
77 | { | ||
78 | .pin = "Mic Jack", | ||
79 | .mask = SND_JACK_MICROPHONE, | ||
80 | }, | ||
81 | }; | ||
82 | static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = { | ||
83 | .name = "Mic detection", | ||
84 | .report = SND_JACK_MICROPHONE, | ||
85 | .debounce_time = 150, | ||
86 | }; | ||
87 | |||
53 | static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, | 88 | static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai, |
54 | struct asoc_simple_dai *set) | 89 | struct asoc_simple_dai *set) |
55 | { | 90 | { |
@@ -105,42 +140,70 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
105 | if (ret < 0) | 140 | if (ret < 0) |
106 | return ret; | 141 | return ret; |
107 | 142 | ||
143 | if (gpio_is_valid(priv->gpio_hp_det)) { | ||
144 | snd_soc_jack_new(codec->codec, "Headphones", SND_JACK_HEADPHONE, | ||
145 | &simple_card_hp_jack); | ||
146 | snd_soc_jack_add_pins(&simple_card_hp_jack, | ||
147 | ARRAY_SIZE(simple_card_hp_jack_pins), | ||
148 | simple_card_hp_jack_pins); | ||
149 | |||
150 | simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det; | ||
151 | snd_soc_jack_add_gpios(&simple_card_hp_jack, 1, | ||
152 | &simple_card_hp_jack_gpio); | ||
153 | } | ||
154 | |||
155 | if (gpio_is_valid(priv->gpio_mic_det)) { | ||
156 | snd_soc_jack_new(codec->codec, "Mic Jack", SND_JACK_MICROPHONE, | ||
157 | &simple_card_mic_jack); | ||
158 | snd_soc_jack_add_pins(&simple_card_mic_jack, | ||
159 | ARRAY_SIZE(simple_card_mic_jack_pins), | ||
160 | simple_card_mic_jack_pins); | ||
161 | simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det; | ||
162 | snd_soc_jack_add_gpios(&simple_card_mic_jack, 1, | ||
163 | &simple_card_mic_jack_gpio); | ||
164 | } | ||
108 | return 0; | 165 | return 0; |
109 | } | 166 | } |
110 | 167 | ||
111 | static int | 168 | static int |
112 | asoc_simple_card_sub_parse_of(struct device_node *np, | 169 | asoc_simple_card_sub_parse_of(struct device_node *np, |
113 | struct asoc_simple_dai *dai, | 170 | struct asoc_simple_dai *dai, |
114 | const struct device_node **p_node, | 171 | struct device_node **p_node, |
115 | const char **name) | 172 | const char **name, |
173 | int *args_count) | ||
116 | { | 174 | { |
117 | struct device_node *node; | 175 | struct of_phandle_args args; |
118 | struct clk *clk; | 176 | struct clk *clk; |
119 | u32 val; | 177 | u32 val; |
120 | int ret; | 178 | int ret; |
121 | 179 | ||
122 | /* | 180 | /* |
123 | * get node via "sound-dai = <&phandle port>" | 181 | * Get node via "sound-dai = <&phandle port>" |
124 | * it will be used as xxx_of_node on soc_bind_dai_link() | 182 | * it will be used as xxx_of_node on soc_bind_dai_link() |
125 | */ | 183 | */ |
126 | node = of_parse_phandle(np, "sound-dai", 0); | 184 | ret = of_parse_phandle_with_args(np, "sound-dai", |
127 | if (!node) | 185 | "#sound-dai-cells", 0, &args); |
128 | return -ENODEV; | 186 | if (ret) |
129 | *p_node = node; | 187 | return ret; |
188 | |||
189 | *p_node = args.np; | ||
190 | |||
191 | if (args_count) | ||
192 | *args_count = args.args_count; | ||
130 | 193 | ||
131 | /* get dai->name */ | 194 | /* Get dai->name */ |
132 | ret = snd_soc_of_get_dai_name(np, name); | 195 | ret = snd_soc_of_get_dai_name(np, name); |
133 | if (ret < 0) | 196 | if (ret < 0) |
134 | return ret; | 197 | return ret; |
135 | 198 | ||
136 | /* parse TDM slot */ | 199 | /* Parse TDM slot */ |
137 | ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); | 200 | ret = snd_soc_of_parse_tdm_slot(np, &dai->slots, &dai->slot_width); |
138 | if (ret) | 201 | if (ret) |
139 | return ret; | 202 | return ret; |
140 | 203 | ||
141 | /* | 204 | /* |
142 | * dai->sysclk come from | 205 | * Parse dai->sysclk come from "clocks = <&xxx>" |
143 | * "clocks = <&xxx>" (if system has common clock) | 206 | * (if system has common clock) |
144 | * or "system-clock-frequency = <xxx>" | 207 | * or "system-clock-frequency = <xxx>" |
145 | * or device's module clock. | 208 | * or device's module clock. |
146 | */ | 209 | */ |
@@ -155,7 +218,7 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
155 | } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { | 218 | } else if (!of_property_read_u32(np, "system-clock-frequency", &val)) { |
156 | dai->sysclk = val; | 219 | dai->sysclk = val; |
157 | } else { | 220 | } else { |
158 | clk = of_clk_get(node, 0); | 221 | clk = of_clk_get(args.np, 0); |
159 | if (!IS_ERR(clk)) | 222 | if (!IS_ERR(clk)) |
160 | dai->sysclk = clk_get_rate(clk); | 223 | dai->sysclk = clk_get_rate(clk); |
161 | } | 224 | } |
@@ -163,12 +226,14 @@ asoc_simple_card_sub_parse_of(struct device_node *np, | |||
163 | return 0; | 226 | return 0; |
164 | } | 227 | } |
165 | 228 | ||
166 | static int simple_card_dai_link_of(struct device_node *node, | 229 | static int asoc_simple_card_dai_link_of(struct device_node *node, |
167 | struct device *dev, | 230 | struct simple_card_data *priv, |
168 | struct snd_soc_dai_link *dai_link, | 231 | int idx, |
169 | struct simple_dai_props *dai_props, | 232 | bool is_top_level_node) |
170 | bool is_top_level_node) | ||
171 | { | 233 | { |
234 | struct device *dev = simple_priv_to_dev(priv); | ||
235 | struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx); | ||
236 | struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx); | ||
172 | struct device_node *np = NULL; | 237 | struct device_node *np = NULL; |
173 | struct device_node *bitclkmaster = NULL; | 238 | struct device_node *bitclkmaster = NULL; |
174 | struct device_node *framemaster = NULL; | 239 | struct device_node *framemaster = NULL; |
@@ -176,8 +241,9 @@ static int simple_card_dai_link_of(struct device_node *node, | |||
176 | char *name; | 241 | char *name; |
177 | char prop[128]; | 242 | char prop[128]; |
178 | char *prefix = ""; | 243 | char *prefix = ""; |
179 | int ret; | 244 | int ret, cpu_args; |
180 | 245 | ||
246 | /* For single DAI link & old style of DT node */ | ||
181 | if (is_top_level_node) | 247 | if (is_top_level_node) |
182 | prefix = "simple-audio-card,"; | 248 | prefix = "simple-audio-card,"; |
183 | 249 | ||
@@ -195,7 +261,8 @@ static int simple_card_dai_link_of(struct device_node *node, | |||
195 | 261 | ||
196 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, | 262 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai, |
197 | &dai_link->cpu_of_node, | 263 | &dai_link->cpu_of_node, |
198 | &dai_link->cpu_dai_name); | 264 | &dai_link->cpu_dai_name, |
265 | &cpu_args); | ||
199 | if (ret < 0) | 266 | if (ret < 0) |
200 | goto dai_link_of_err; | 267 | goto dai_link_of_err; |
201 | 268 | ||
@@ -226,14 +293,16 @@ static int simple_card_dai_link_of(struct device_node *node, | |||
226 | 293 | ||
227 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, | 294 | ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai, |
228 | &dai_link->codec_of_node, | 295 | &dai_link->codec_of_node, |
229 | &dai_link->codec_dai_name); | 296 | &dai_link->codec_dai_name, NULL); |
230 | if (ret < 0) | 297 | if (ret < 0) |
231 | goto dai_link_of_err; | 298 | goto dai_link_of_err; |
232 | 299 | ||
233 | if (strlen(prefix) && !bitclkmaster && !framemaster) { | 300 | if (strlen(prefix) && !bitclkmaster && !framemaster) { |
234 | /* No dai-link level and master setting was not found from | 301 | /* |
235 | sound node level, revert back to legacy DT parsing and | 302 | * No DAI link level and master setting was found |
236 | take the settings from codec node. */ | 303 | * from sound node level, revert back to legacy DT |
304 | * parsing and take the settings from codec node. | ||
305 | */ | ||
237 | dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", | 306 | dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n", |
238 | __func__); | 307 | __func__); |
239 | dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = | 308 | dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt = |
@@ -262,10 +331,10 @@ static int simple_card_dai_link_of(struct device_node *node, | |||
262 | goto dai_link_of_err; | 331 | goto dai_link_of_err; |
263 | } | 332 | } |
264 | 333 | ||
265 | /* simple-card assumes platform == cpu */ | 334 | /* Simple Card assumes platform == cpu */ |
266 | dai_link->platform_of_node = dai_link->cpu_of_node; | 335 | dai_link->platform_of_node = dai_link->cpu_of_node; |
267 | 336 | ||
268 | /* Link name is created from CPU/CODEC dai name */ | 337 | /* DAI link name is created from CPU/CODEC dai name */ |
269 | name = devm_kzalloc(dev, | 338 | name = devm_kzalloc(dev, |
270 | strlen(dai_link->cpu_dai_name) + | 339 | strlen(dai_link->cpu_dai_name) + |
271 | strlen(dai_link->codec_dai_name) + 2, | 340 | strlen(dai_link->codec_dai_name) + 2, |
@@ -274,6 +343,7 @@ static int simple_card_dai_link_of(struct device_node *node, | |||
274 | dai_link->codec_dai_name); | 343 | dai_link->codec_dai_name); |
275 | dai_link->name = dai_link->stream_name = name; | 344 | dai_link->name = dai_link->stream_name = name; |
276 | dai_link->ops = &asoc_simple_card_ops; | 345 | dai_link->ops = &asoc_simple_card_ops; |
346 | dai_link->init = asoc_simple_card_dai_init; | ||
277 | 347 | ||
278 | dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); | 348 | dev_dbg(dev, "\tname : %s\n", dai_link->stream_name); |
279 | dev_dbg(dev, "\tcpu : %s / %04x / %d\n", | 349 | dev_dbg(dev, "\tcpu : %s / %04x / %d\n", |
@@ -285,6 +355,18 @@ static int simple_card_dai_link_of(struct device_node *node, | |||
285 | dai_props->codec_dai.fmt, | 355 | dai_props->codec_dai.fmt, |
286 | dai_props->codec_dai.sysclk); | 356 | dai_props->codec_dai.sysclk); |
287 | 357 | ||
358 | /* | ||
359 | * In soc_bind_dai_link() will check cpu name after | ||
360 | * of_node matching if dai_link has cpu_dai_name. | ||
361 | * but, it will never match if name was created by | ||
362 | * fmt_single_name() remove cpu_dai_name if cpu_args | ||
363 | * was 0. See: | ||
364 | * fmt_single_name() | ||
365 | * fmt_multiple_name() | ||
366 | */ | ||
367 | if (!cpu_args) | ||
368 | dai_link->cpu_dai_name = NULL; | ||
369 | |||
288 | dai_link_of_err: | 370 | dai_link_of_err: |
289 | if (np) | 371 | if (np) |
290 | of_node_put(np); | 372 | of_node_put(np); |
@@ -296,19 +378,19 @@ dai_link_of_err: | |||
296 | } | 378 | } |
297 | 379 | ||
298 | static int asoc_simple_card_parse_of(struct device_node *node, | 380 | static int asoc_simple_card_parse_of(struct device_node *node, |
299 | struct simple_card_data *priv, | 381 | struct simple_card_data *priv) |
300 | struct device *dev, | ||
301 | int multi) | ||
302 | { | 382 | { |
303 | struct snd_soc_dai_link *dai_link = priv->snd_card.dai_link; | 383 | struct device *dev = simple_priv_to_dev(priv); |
304 | struct simple_dai_props *dai_props = priv->dai_props; | ||
305 | u32 val; | 384 | u32 val; |
306 | int ret; | 385 | int ret; |
307 | 386 | ||
308 | /* parsing the card name from DT */ | 387 | if (!node) |
388 | return -EINVAL; | ||
389 | |||
390 | /* Parse the card name from DT */ | ||
309 | snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); | 391 | snd_soc_of_parse_card_name(&priv->snd_card, "simple-audio-card,name"); |
310 | 392 | ||
311 | /* off-codec widgets */ | 393 | /* The off-codec widgets */ |
312 | if (of_property_read_bool(node, "simple-audio-card,widgets")) { | 394 | if (of_property_read_bool(node, "simple-audio-card,widgets")) { |
313 | ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, | 395 | ret = snd_soc_of_parse_audio_simple_widgets(&priv->snd_card, |
314 | "simple-audio-card,widgets"); | 396 | "simple-audio-card,widgets"); |
@@ -332,32 +414,45 @@ static int asoc_simple_card_parse_of(struct device_node *node, | |||
332 | dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? | 414 | dev_dbg(dev, "New simple-card: %s\n", priv->snd_card.name ? |
333 | priv->snd_card.name : ""); | 415 | priv->snd_card.name : ""); |
334 | 416 | ||
335 | if (multi) { | 417 | /* Single/Muti DAI link(s) & New style of DT node */ |
418 | if (of_get_child_by_name(node, "simple-audio-card,dai-link")) { | ||
336 | struct device_node *np = NULL; | 419 | struct device_node *np = NULL; |
337 | int i; | 420 | int i = 0; |
338 | for (i = 0; (np = of_get_next_child(node, np)); i++) { | 421 | |
422 | for_each_child_of_node(node, np) { | ||
339 | dev_dbg(dev, "\tlink %d:\n", i); | 423 | dev_dbg(dev, "\tlink %d:\n", i); |
340 | ret = simple_card_dai_link_of(np, dev, dai_link + i, | 424 | ret = asoc_simple_card_dai_link_of(np, priv, |
341 | dai_props + i, false); | 425 | i, false); |
342 | if (ret < 0) { | 426 | if (ret < 0) { |
343 | of_node_put(np); | 427 | of_node_put(np); |
344 | return ret; | 428 | return ret; |
345 | } | 429 | } |
430 | i++; | ||
346 | } | 431 | } |
347 | } else { | 432 | } else { |
348 | ret = simple_card_dai_link_of(node, dev, dai_link, dai_props, | 433 | /* For single DAI link & old style of DT node */ |
349 | true); | 434 | ret = asoc_simple_card_dai_link_of(node, priv, 0, true); |
350 | if (ret < 0) | 435 | if (ret < 0) |
351 | return ret; | 436 | return ret; |
352 | } | 437 | } |
353 | 438 | ||
439 | priv->gpio_hp_det = of_get_named_gpio(node, | ||
440 | "simple-audio-card,hp-det-gpio", 0); | ||
441 | if (priv->gpio_hp_det == -EPROBE_DEFER) | ||
442 | return -EPROBE_DEFER; | ||
443 | |||
444 | priv->gpio_mic_det = of_get_named_gpio(node, | ||
445 | "simple-audio-card,mic-det-gpio", 0); | ||
446 | if (priv->gpio_mic_det == -EPROBE_DEFER) | ||
447 | return -EPROBE_DEFER; | ||
448 | |||
354 | if (!priv->snd_card.name) | 449 | if (!priv->snd_card.name) |
355 | priv->snd_card.name = priv->snd_card.dai_link->name; | 450 | priv->snd_card.name = priv->snd_card.dai_link->name; |
356 | 451 | ||
357 | return 0; | 452 | return 0; |
358 | } | 453 | } |
359 | 454 | ||
360 | /* update the reference count of the devices nodes at end of probe */ | 455 | /* Decrease the reference count of the device nodes */ |
361 | static int asoc_simple_card_unref(struct platform_device *pdev) | 456 | static int asoc_simple_card_unref(struct platform_device *pdev) |
362 | { | 457 | { |
363 | struct snd_soc_card *card = platform_get_drvdata(pdev); | 458 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
@@ -384,34 +479,29 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
384 | struct snd_soc_dai_link *dai_link; | 479 | struct snd_soc_dai_link *dai_link; |
385 | struct device_node *np = pdev->dev.of_node; | 480 | struct device_node *np = pdev->dev.of_node; |
386 | struct device *dev = &pdev->dev; | 481 | struct device *dev = &pdev->dev; |
387 | int num_links, multi, ret; | 482 | int num_links, ret; |
388 | 483 | ||
389 | /* get the number of DAI links */ | 484 | /* Get the number of DAI links */ |
390 | if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) { | 485 | if (np && of_get_child_by_name(np, "simple-audio-card,dai-link")) |
391 | num_links = of_get_child_count(np); | 486 | num_links = of_get_child_count(np); |
392 | multi = 1; | 487 | else |
393 | } else { | ||
394 | num_links = 1; | 488 | num_links = 1; |
395 | multi = 0; | ||
396 | } | ||
397 | 489 | ||
398 | /* allocate the private data and the DAI link array */ | 490 | /* Allocate the private data and the DAI link array */ |
399 | priv = devm_kzalloc(dev, | 491 | priv = devm_kzalloc(dev, |
400 | sizeof(*priv) + sizeof(*dai_link) * num_links, | 492 | sizeof(*priv) + sizeof(*dai_link) * num_links, |
401 | GFP_KERNEL); | 493 | GFP_KERNEL); |
402 | if (!priv) | 494 | if (!priv) |
403 | return -ENOMEM; | 495 | return -ENOMEM; |
404 | 496 | ||
405 | /* | 497 | /* Init snd_soc_card */ |
406 | * init snd_soc_card | ||
407 | */ | ||
408 | priv->snd_card.owner = THIS_MODULE; | 498 | priv->snd_card.owner = THIS_MODULE; |
409 | priv->snd_card.dev = dev; | 499 | priv->snd_card.dev = dev; |
410 | dai_link = priv->dai_link; | 500 | dai_link = priv->dai_link; |
411 | priv->snd_card.dai_link = dai_link; | 501 | priv->snd_card.dai_link = dai_link; |
412 | priv->snd_card.num_links = num_links; | 502 | priv->snd_card.num_links = num_links; |
413 | 503 | ||
414 | /* get room for the other properties */ | 504 | /* Get room for the other properties */ |
415 | priv->dai_props = devm_kzalloc(dev, | 505 | priv->dai_props = devm_kzalloc(dev, |
416 | sizeof(*priv->dai_props) * num_links, | 506 | sizeof(*priv->dai_props) * num_links, |
417 | GFP_KERNEL); | 507 | GFP_KERNEL); |
@@ -420,25 +510,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
420 | 510 | ||
421 | if (np && of_device_is_available(np)) { | 511 | if (np && of_device_is_available(np)) { |
422 | 512 | ||
423 | ret = asoc_simple_card_parse_of(np, priv, dev, multi); | 513 | ret = asoc_simple_card_parse_of(np, priv); |
424 | if (ret < 0) { | 514 | if (ret < 0) { |
425 | if (ret != -EPROBE_DEFER) | 515 | if (ret != -EPROBE_DEFER) |
426 | dev_err(dev, "parse error %d\n", ret); | 516 | dev_err(dev, "parse error %d\n", ret); |
427 | goto err; | 517 | goto err; |
428 | } | 518 | } |
429 | 519 | ||
430 | /* | ||
431 | * soc_bind_dai_link() will check cpu name | ||
432 | * after of_node matching if dai_link has cpu_dai_name. | ||
433 | * but, it will never match if name was created by fmt_single_name() | ||
434 | * remove cpu_dai_name to escape name matching. | ||
435 | * see | ||
436 | * fmt_single_name() | ||
437 | * fmt_multiple_name() | ||
438 | */ | ||
439 | if (num_links == 1) | ||
440 | dai_link->cpu_dai_name = NULL; | ||
441 | |||
442 | } else { | 520 | } else { |
443 | struct asoc_simple_card_info *cinfo; | 521 | struct asoc_simple_card_info *cinfo; |
444 | 522 | ||
@@ -464,6 +542,7 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
464 | dai_link->codec_name = cinfo->codec; | 542 | dai_link->codec_name = cinfo->codec; |
465 | dai_link->cpu_dai_name = cinfo->cpu_dai.name; | 543 | dai_link->cpu_dai_name = cinfo->cpu_dai.name; |
466 | dai_link->codec_dai_name = cinfo->codec_dai.name; | 544 | dai_link->codec_dai_name = cinfo->codec_dai.name; |
545 | dai_link->init = asoc_simple_card_dai_init; | ||
467 | memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, | 546 | memcpy(&priv->dai_props->cpu_dai, &cinfo->cpu_dai, |
468 | sizeof(priv->dai_props->cpu_dai)); | 547 | sizeof(priv->dai_props->cpu_dai)); |
469 | memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, | 548 | memcpy(&priv->dai_props->codec_dai, &cinfo->codec_dai, |
@@ -473,20 +552,32 @@ static int asoc_simple_card_probe(struct platform_device *pdev) | |||
473 | priv->dai_props->codec_dai.fmt |= cinfo->daifmt; | 552 | priv->dai_props->codec_dai.fmt |= cinfo->daifmt; |
474 | } | 553 | } |
475 | 554 | ||
476 | /* | ||
477 | * init snd_soc_dai_link | ||
478 | */ | ||
479 | dai_link->init = asoc_simple_card_dai_init; | ||
480 | |||
481 | snd_soc_card_set_drvdata(&priv->snd_card, priv); | 555 | snd_soc_card_set_drvdata(&priv->snd_card, priv); |
482 | 556 | ||
483 | ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); | 557 | ret = devm_snd_soc_register_card(&pdev->dev, &priv->snd_card); |
558 | if (ret >= 0) | ||
559 | return ret; | ||
484 | 560 | ||
485 | err: | 561 | err: |
486 | asoc_simple_card_unref(pdev); | 562 | asoc_simple_card_unref(pdev); |
487 | return ret; | 563 | return ret; |
488 | } | 564 | } |
489 | 565 | ||
566 | static int asoc_simple_card_remove(struct platform_device *pdev) | ||
567 | { | ||
568 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
569 | struct simple_card_data *priv = snd_soc_card_get_drvdata(card); | ||
570 | |||
571 | if (gpio_is_valid(priv->gpio_hp_det)) | ||
572 | snd_soc_jack_free_gpios(&simple_card_hp_jack, 1, | ||
573 | &simple_card_hp_jack_gpio); | ||
574 | if (gpio_is_valid(priv->gpio_mic_det)) | ||
575 | snd_soc_jack_free_gpios(&simple_card_mic_jack, 1, | ||
576 | &simple_card_mic_jack_gpio); | ||
577 | |||
578 | return asoc_simple_card_unref(pdev); | ||
579 | } | ||
580 | |||
490 | static const struct of_device_id asoc_simple_of_match[] = { | 581 | static const struct of_device_id asoc_simple_of_match[] = { |
491 | { .compatible = "simple-audio-card", }, | 582 | { .compatible = "simple-audio-card", }, |
492 | {}, | 583 | {}, |
@@ -500,6 +591,7 @@ static struct platform_driver asoc_simple_card = { | |||
500 | .of_match_table = asoc_simple_of_match, | 591 | .of_match_table = asoc_simple_of_match, |
501 | }, | 592 | }, |
502 | .probe = asoc_simple_card_probe, | 593 | .probe = asoc_simple_card_probe, |
594 | .remove = asoc_simple_card_remove, | ||
503 | }; | 595 | }; |
504 | 596 | ||
505 | module_platform_driver(asoc_simple_card); | 597 | module_platform_driver(asoc_simple_card); |
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 7acbfc43a0c6..f841786dad15 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -2,7 +2,8 @@ | |||
2 | snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o | 2 | snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o |
3 | snd-soc-sst-acpi-objs := sst-acpi.o | 3 | snd-soc-sst-acpi-objs := sst-acpi.o |
4 | 4 | ||
5 | snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o sst-mfld-platform-compress.o | 5 | snd-soc-sst-mfld-platform-objs := sst-mfld-platform-pcm.o \ |
6 | sst-mfld-platform-compress.o sst-atom-controls.o | ||
6 | snd-soc-mfld-machine-objs := mfld_machine.o | 7 | snd-soc-mfld-machine-objs := mfld_machine.o |
7 | 8 | ||
8 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o | 9 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o |
diff --git a/sound/soc/intel/byt-max98090.c b/sound/soc/intel/byt-max98090.c index b8b8af571ef1..d52681e7225e 100644 --- a/sound/soc/intel/byt-max98090.c +++ b/sound/soc/intel/byt-max98090.c | |||
@@ -139,6 +139,7 @@ static struct snd_soc_card byt_max98090_card = { | |||
139 | .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), | 139 | .num_dapm_routes = ARRAY_SIZE(byt_max98090_audio_map), |
140 | .controls = byt_max98090_controls, | 140 | .controls = byt_max98090_controls, |
141 | .num_controls = ARRAY_SIZE(byt_max98090_controls), | 141 | .num_controls = ARRAY_SIZE(byt_max98090_controls), |
142 | .fully_routed = true, | ||
142 | }; | 143 | }; |
143 | 144 | ||
144 | static int byt_max98090_probe(struct platform_device *pdev) | 145 | static int byt_max98090_probe(struct platform_device *pdev) |
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c index 234a58de3c53..e03abdf21c1b 100644 --- a/sound/soc/intel/byt-rt5640.c +++ b/sound/soc/intel/byt-rt5640.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/acpi.h> | 18 | #include <linux/acpi.h> |
19 | #include <linux/device.h> | 19 | #include <linux/device.h> |
20 | #include <linux/dmi.h> | ||
20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 23 | #include <sound/pcm_params.h> |
@@ -36,8 +37,6 @@ static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | |||
36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | 37 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { |
37 | {"Headset Mic", NULL, "MICBIAS1"}, | 38 | {"Headset Mic", NULL, "MICBIAS1"}, |
38 | {"IN2P", NULL, "Headset Mic"}, | 39 | {"IN2P", NULL, "Headset Mic"}, |
39 | {"IN2N", NULL, "Headset Mic"}, | ||
40 | {"DMIC1", NULL, "Internal Mic"}, | ||
41 | {"Headphone", NULL, "HPOL"}, | 40 | {"Headphone", NULL, "HPOL"}, |
42 | {"Headphone", NULL, "HPOR"}, | 41 | {"Headphone", NULL, "HPOR"}, |
43 | {"Speaker", NULL, "SPOLP"}, | 42 | {"Speaker", NULL, "SPOLP"}, |
@@ -46,6 +45,31 @@ static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | |||
46 | {"Speaker", NULL, "SPORN"}, | 45 | {"Speaker", NULL, "SPORN"}, |
47 | }; | 46 | }; |
48 | 47 | ||
48 | static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic1_map[] = { | ||
49 | {"DMIC1", NULL, "Internal Mic"}, | ||
50 | }; | ||
51 | |||
52 | static const struct snd_soc_dapm_route byt_rt5640_intmic_dmic2_map[] = { | ||
53 | {"DMIC2", NULL, "Internal Mic"}, | ||
54 | }; | ||
55 | |||
56 | static const struct snd_soc_dapm_route byt_rt5640_intmic_in1_map[] = { | ||
57 | {"Internal Mic", NULL, "MICBIAS1"}, | ||
58 | {"IN1P", NULL, "Internal Mic"}, | ||
59 | }; | ||
60 | |||
61 | enum { | ||
62 | BYT_RT5640_DMIC1_MAP, | ||
63 | BYT_RT5640_DMIC2_MAP, | ||
64 | BYT_RT5640_IN1_MAP, | ||
65 | }; | ||
66 | |||
67 | #define BYT_RT5640_MAP(quirk) ((quirk) & 0xff) | ||
68 | #define BYT_RT5640_DMIC_EN BIT(16) | ||
69 | |||
70 | static unsigned long byt_rt5640_quirk = BYT_RT5640_DMIC1_MAP | | ||
71 | BYT_RT5640_DMIC_EN; | ||
72 | |||
49 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { | 73 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { |
50 | SOC_DAPM_PIN_SWITCH("Headphone"), | 74 | SOC_DAPM_PIN_SWITCH("Headphone"), |
51 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | 75 | SOC_DAPM_PIN_SWITCH("Headset Mic"), |
@@ -77,12 +101,41 @@ static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, | |||
77 | return 0; | 101 | return 0; |
78 | } | 102 | } |
79 | 103 | ||
104 | static int byt_rt5640_quirk_cb(const struct dmi_system_id *id) | ||
105 | { | ||
106 | byt_rt5640_quirk = (unsigned long)id->driver_data; | ||
107 | return 1; | ||
108 | } | ||
109 | |||
110 | static const struct dmi_system_id byt_rt5640_quirk_table[] = { | ||
111 | { | ||
112 | .callback = byt_rt5640_quirk_cb, | ||
113 | .matches = { | ||
114 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | ||
115 | DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"), | ||
116 | }, | ||
117 | .driver_data = (unsigned long *)BYT_RT5640_IN1_MAP, | ||
118 | }, | ||
119 | { | ||
120 | .callback = byt_rt5640_quirk_cb, | ||
121 | .matches = { | ||
122 | DMI_MATCH(DMI_SYS_VENDOR, "DellInc."), | ||
123 | DMI_MATCH(DMI_PRODUCT_NAME, "Venue 8 Pro 5830"), | ||
124 | }, | ||
125 | .driver_data = (unsigned long *)(BYT_RT5640_DMIC2_MAP | | ||
126 | BYT_RT5640_DMIC_EN), | ||
127 | }, | ||
128 | {} | ||
129 | }; | ||
130 | |||
80 | static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | 131 | static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) |
81 | { | 132 | { |
82 | int ret; | 133 | int ret; |
83 | struct snd_soc_codec *codec = runtime->codec; | 134 | struct snd_soc_codec *codec = runtime->codec; |
84 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 135 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
85 | struct snd_soc_card *card = runtime->card; | 136 | struct snd_soc_card *card = runtime->card; |
137 | const struct snd_soc_dapm_route *custom_map; | ||
138 | int num_routes; | ||
86 | 139 | ||
87 | card->dapm.idle_bias_off = true; | 140 | card->dapm.idle_bias_off = true; |
88 | 141 | ||
@@ -93,6 +146,31 @@ static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | |||
93 | return ret; | 146 | return ret; |
94 | } | 147 | } |
95 | 148 | ||
149 | dmi_check_system(byt_rt5640_quirk_table); | ||
150 | switch (BYT_RT5640_MAP(byt_rt5640_quirk)) { | ||
151 | case BYT_RT5640_IN1_MAP: | ||
152 | custom_map = byt_rt5640_intmic_in1_map; | ||
153 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_in1_map); | ||
154 | break; | ||
155 | case BYT_RT5640_DMIC2_MAP: | ||
156 | custom_map = byt_rt5640_intmic_dmic2_map; | ||
157 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic2_map); | ||
158 | break; | ||
159 | default: | ||
160 | custom_map = byt_rt5640_intmic_dmic1_map; | ||
161 | num_routes = ARRAY_SIZE(byt_rt5640_intmic_dmic1_map); | ||
162 | } | ||
163 | |||
164 | ret = snd_soc_dapm_add_routes(dapm, custom_map, num_routes); | ||
165 | if (ret) | ||
166 | return ret; | ||
167 | |||
168 | if (byt_rt5640_quirk & BYT_RT5640_DMIC_EN) { | ||
169 | ret = rt5640_dmic_enable(codec, 0, 0); | ||
170 | if (ret) | ||
171 | return ret; | ||
172 | } | ||
173 | |||
96 | snd_soc_dapm_ignore_suspend(dapm, "HPOL"); | 174 | snd_soc_dapm_ignore_suspend(dapm, "HPOL"); |
97 | snd_soc_dapm_ignore_suspend(dapm, "HPOR"); | 175 | snd_soc_dapm_ignore_suspend(dapm, "HPOR"); |
98 | 176 | ||
@@ -131,6 +209,7 @@ static struct snd_soc_card byt_rt5640_card = { | |||
131 | .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), | 209 | .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), |
132 | .dapm_routes = byt_rt5640_audio_map, | 210 | .dapm_routes = byt_rt5640_audio_map, |
133 | .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), | 211 | .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), |
212 | .fully_routed = true, | ||
134 | }; | 213 | }; |
135 | 214 | ||
136 | static int byt_rt5640_probe(struct platform_device *pdev) | 215 | static int byt_rt5640_probe(struct platform_device *pdev) |
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c index 42edc6f4fc4a..03d0a166b635 100644 --- a/sound/soc/intel/sst-acpi.c +++ b/sound/soc/intel/sst-acpi.c | |||
@@ -246,8 +246,8 @@ static struct sst_acpi_desc sst_acpi_broadwell_desc = { | |||
246 | }; | 246 | }; |
247 | 247 | ||
248 | static struct sst_acpi_mach baytrail_machines[] = { | 248 | static struct sst_acpi_mach baytrail_machines[] = { |
249 | { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" }, | 249 | { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, |
250 | { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-i2s_master" }, | 250 | { "193C9890", "byt-max98090", "intel/fw_sst_0f28.bin-48kHz_i2s_master" }, |
251 | {} | 251 | {} |
252 | }; | 252 | }; |
253 | 253 | ||
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c new file mode 100644 index 000000000000..7104a34181a9 --- /dev/null +++ b/sound/soc/intel/sst-atom-controls.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* | ||
2 | * sst-atom-controls.c - Intel MID Platform driver DPCM ALSA controls for Mrfld | ||
3 | * | ||
4 | * Copyright (C) 2013-14 Intel Corp | ||
5 | * Author: Omair Mohammed Abdullah <omair.m.abdullah@intel.com> | ||
6 | * Vinod Koul <vinod.koul@intel.com> | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; version 2 of the License. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
19 | */ | ||
20 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
21 | |||
22 | #include <linux/slab.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/tlv.h> | ||
25 | #include "sst-mfld-platform.h" | ||
26 | #include "sst-atom-controls.h" | ||
27 | |||
28 | static int sst_fill_byte_control(struct sst_data *drv, | ||
29 | u8 ipc_msg, u8 block, | ||
30 | u8 task_id, u8 pipe_id, | ||
31 | u16 len, void *cmd_data) | ||
32 | { | ||
33 | struct snd_sst_bytes_v2 *byte_data = drv->byte_stream; | ||
34 | |||
35 | byte_data->type = SST_CMD_BYTES_SET; | ||
36 | byte_data->ipc_msg = ipc_msg; | ||
37 | byte_data->block = block; | ||
38 | byte_data->task_id = task_id; | ||
39 | byte_data->pipe_id = pipe_id; | ||
40 | |||
41 | if (len > SST_MAX_BIN_BYTES - sizeof(*byte_data)) { | ||
42 | dev_err(&drv->pdev->dev, "command length too big (%u)", len); | ||
43 | return -EINVAL; | ||
44 | } | ||
45 | byte_data->len = len; | ||
46 | memcpy(byte_data->bytes, cmd_data, len); | ||
47 | print_hex_dump_bytes("writing to lpe: ", DUMP_PREFIX_OFFSET, | ||
48 | byte_data, len + sizeof(*byte_data)); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | static int sst_fill_and_send_cmd_unlocked(struct sst_data *drv, | ||
53 | u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, | ||
54 | void *cmd_data, u16 len) | ||
55 | { | ||
56 | int ret = 0; | ||
57 | |||
58 | ret = sst_fill_byte_control(drv, ipc_msg, | ||
59 | block, task_id, pipe_id, len, cmd_data); | ||
60 | if (ret < 0) | ||
61 | return ret; | ||
62 | return sst->ops->send_byte_stream(sst->dev, drv->byte_stream); | ||
63 | } | ||
64 | |||
65 | /** | ||
66 | * sst_fill_and_send_cmd - generate the IPC message and send it to the FW | ||
67 | * @ipc_msg: type of IPC (CMD, SET_PARAMS, GET_PARAMS) | ||
68 | * @cmd_data: the IPC payload | ||
69 | */ | ||
70 | static int sst_fill_and_send_cmd(struct sst_data *drv, | ||
71 | u8 ipc_msg, u8 block, u8 task_id, u8 pipe_id, | ||
72 | void *cmd_data, u16 len) | ||
73 | { | ||
74 | int ret; | ||
75 | |||
76 | mutex_lock(&drv->lock); | ||
77 | ret = sst_fill_and_send_cmd_unlocked(drv, ipc_msg, block, | ||
78 | task_id, pipe_id, cmd_data, len); | ||
79 | mutex_unlock(&drv->lock); | ||
80 | |||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | static int sst_send_algo_cmd(struct sst_data *drv, | ||
85 | struct sst_algo_control *bc) | ||
86 | { | ||
87 | int len, ret = 0; | ||
88 | struct sst_cmd_set_params *cmd; | ||
89 | |||
90 | /*bc->max includes sizeof algos + length field*/ | ||
91 | len = sizeof(cmd->dst) + sizeof(cmd->command_id) + bc->max; | ||
92 | |||
93 | cmd = kzalloc(len, GFP_KERNEL); | ||
94 | if (cmd == NULL) | ||
95 | return -ENOMEM; | ||
96 | |||
97 | SST_FILL_DESTINATION(2, cmd->dst, bc->pipe_id, bc->module_id); | ||
98 | cmd->command_id = bc->cmd_id; | ||
99 | memcpy(cmd->params, bc->params, bc->max); | ||
100 | |||
101 | ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS, | ||
102 | SST_FLAG_BLOCKED, bc->task_id, 0, cmd, len); | ||
103 | kfree(cmd); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol, | ||
108 | struct snd_ctl_elem_info *uinfo) | ||
109 | { | ||
110 | struct sst_algo_control *bc = (void *)kcontrol->private_value; | ||
111 | |||
112 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; | ||
113 | uinfo->count = bc->max; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int sst_algo_control_get(struct snd_kcontrol *kcontrol, | ||
119 | struct snd_ctl_elem_value *ucontrol) | ||
120 | { | ||
121 | struct sst_algo_control *bc = (void *)kcontrol->private_value; | ||
122 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
123 | |||
124 | switch (bc->type) { | ||
125 | case SST_ALGO_PARAMS: | ||
126 | memcpy(ucontrol->value.bytes.data, bc->params, bc->max); | ||
127 | break; | ||
128 | default: | ||
129 | dev_err(component->dev, "Invalid Input- algo type:%d\n", | ||
130 | bc->type); | ||
131 | return -EINVAL; | ||
132 | |||
133 | } | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int sst_algo_control_set(struct snd_kcontrol *kcontrol, | ||
138 | struct snd_ctl_elem_value *ucontrol) | ||
139 | { | ||
140 | int ret = 0; | ||
141 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); | ||
142 | struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt); | ||
143 | struct sst_algo_control *bc = (void *)kcontrol->private_value; | ||
144 | |||
145 | dev_dbg(cmpnt->dev, "control_name=%s\n", kcontrol->id.name); | ||
146 | mutex_lock(&drv->lock); | ||
147 | switch (bc->type) { | ||
148 | case SST_ALGO_PARAMS: | ||
149 | memcpy(bc->params, ucontrol->value.bytes.data, bc->max); | ||
150 | break; | ||
151 | default: | ||
152 | mutex_unlock(&drv->lock); | ||
153 | dev_err(cmpnt->dev, "Invalid Input- algo type:%d\n", | ||
154 | bc->type); | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | /*if pipe is enabled, need to send the algo params from here*/ | ||
158 | if (bc->w && bc->w->power) | ||
159 | ret = sst_send_algo_cmd(drv, bc); | ||
160 | mutex_unlock(&drv->lock); | ||
161 | |||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static const struct snd_kcontrol_new sst_algo_controls[] = { | ||
166 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24, | ||
167 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), | ||
168 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "iir", 300, SST_MODULE_ID_IIR_24, | ||
169 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), | ||
170 | SST_ALGO_KCONTROL_BYTES("media_loop1_out", "mdrp", 286, SST_MODULE_ID_MDRP, | ||
171 | SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), | ||
172 | SST_ALGO_KCONTROL_BYTES("media_loop2_out", "fir", 272, SST_MODULE_ID_FIR_24, | ||
173 | SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR), | ||
174 | SST_ALGO_KCONTROL_BYTES("media_loop2_out", "iir", 300, SST_MODULE_ID_IIR_24, | ||
175 | SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_VB_SET_IIR), | ||
176 | SST_ALGO_KCONTROL_BYTES("media_loop2_out", "mdrp", 286, SST_MODULE_ID_MDRP, | ||
177 | SST_PATH_INDEX_MEDIA_LOOP2_OUT, 0, SST_TASK_SBA, SBA_SET_MDRP), | ||
178 | SST_ALGO_KCONTROL_BYTES("sprot_loop_out", "lpro", 192, SST_MODULE_ID_SPROT, | ||
179 | SST_PATH_INDEX_SPROT_LOOP_OUT, 0, SST_TASK_SBA, SBA_VB_LPRO), | ||
180 | SST_ALGO_KCONTROL_BYTES("codec_in0", "dcr", 52, SST_MODULE_ID_FILT_DCR, | ||
181 | SST_PATH_INDEX_CODEC_IN0, 0, SST_TASK_SBA, SBA_VB_SET_IIR), | ||
182 | SST_ALGO_KCONTROL_BYTES("codec_in1", "dcr", 52, SST_MODULE_ID_FILT_DCR, | ||
183 | SST_PATH_INDEX_CODEC_IN1, 0, SST_TASK_SBA, SBA_VB_SET_IIR), | ||
184 | |||
185 | }; | ||
186 | |||
187 | static int sst_algo_control_init(struct device *dev) | ||
188 | { | ||
189 | int i = 0; | ||
190 | struct sst_algo_control *bc; | ||
191 | /*allocate space to cache the algo parameters in the driver*/ | ||
192 | for (i = 0; i < ARRAY_SIZE(sst_algo_controls); i++) { | ||
193 | bc = (struct sst_algo_control *)sst_algo_controls[i].private_value; | ||
194 | bc->params = devm_kzalloc(dev, bc->max, GFP_KERNEL); | ||
195 | if (bc->params == NULL) | ||
196 | return -ENOMEM; | ||
197 | } | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform) | ||
202 | { | ||
203 | int ret = 0; | ||
204 | struct sst_data *drv = snd_soc_platform_get_drvdata(platform); | ||
205 | |||
206 | drv->byte_stream = devm_kzalloc(platform->dev, | ||
207 | SST_MAX_BIN_BYTES, GFP_KERNEL); | ||
208 | if (!drv->byte_stream) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | /*Initialize algo control params*/ | ||
212 | ret = sst_algo_control_init(platform->dev); | ||
213 | if (ret) | ||
214 | return ret; | ||
215 | ret = snd_soc_add_platform_controls(platform, sst_algo_controls, | ||
216 | ARRAY_SIZE(sst_algo_controls)); | ||
217 | return ret; | ||
218 | } | ||
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h index 14063ab8c7c5..a73e894b175c 100644 --- a/sound/soc/intel/sst-atom-controls.h +++ b/sound/soc/intel/sst-atom-controls.h | |||
@@ -1,4 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * sst-atom-controls.h - Intel MID Platform driver header file | ||
3 | * | ||
2 | * Copyright (C) 2013-14 Intel Corp | 4 | * Copyright (C) 2013-14 Intel Corp |
3 | * Author: Ramesh Babu <ramesh.babu.koul@intel.com> | 5 | * Author: Ramesh Babu <ramesh.babu.koul@intel.com> |
4 | * Omair M Abdullah <omair.m.abdullah@intel.com> | 6 | * Omair M Abdullah <omair.m.abdullah@intel.com> |
@@ -18,13 +20,423 @@ | |||
18 | * | 20 | * |
19 | */ | 21 | */ |
20 | 22 | ||
21 | #ifndef __SST_CONTROLS_V2_H__ | 23 | #ifndef __SST_ATOM_CONTROLS_H__ |
22 | #define __SST_CONTROLS_V2_H__ | 24 | #define __SST_ATOM_CONTROLS_H__ |
23 | 25 | ||
24 | enum { | 26 | enum { |
25 | MERR_DPCM_AUDIO = 0, | 27 | MERR_DPCM_AUDIO = 0, |
26 | MERR_DPCM_COMPR, | 28 | MERR_DPCM_COMPR, |
27 | }; | 29 | }; |
28 | 30 | ||
31 | /* define a bit for each mixer input */ | ||
32 | #define SST_MIX_IP(x) (x) | ||
33 | |||
34 | #define SST_IP_CODEC0 SST_MIX_IP(2) | ||
35 | #define SST_IP_CODEC1 SST_MIX_IP(3) | ||
36 | #define SST_IP_LOOP0 SST_MIX_IP(4) | ||
37 | #define SST_IP_LOOP1 SST_MIX_IP(5) | ||
38 | #define SST_IP_LOOP2 SST_MIX_IP(6) | ||
39 | #define SST_IP_PROBE SST_MIX_IP(7) | ||
40 | #define SST_IP_VOIP SST_MIX_IP(12) | ||
41 | #define SST_IP_PCM0 SST_MIX_IP(13) | ||
42 | #define SST_IP_PCM1 SST_MIX_IP(14) | ||
43 | #define SST_IP_MEDIA0 SST_MIX_IP(17) | ||
44 | #define SST_IP_MEDIA1 SST_MIX_IP(18) | ||
45 | #define SST_IP_MEDIA2 SST_MIX_IP(19) | ||
46 | #define SST_IP_MEDIA3 SST_MIX_IP(20) | ||
47 | |||
48 | #define SST_IP_LAST SST_IP_MEDIA3 | ||
49 | |||
50 | #define SST_SWM_INPUT_COUNT (SST_IP_LAST + 1) | ||
51 | #define SST_CMD_SWM_MAX_INPUTS 6 | ||
52 | |||
53 | #define SST_PATH_ID_SHIFT 8 | ||
54 | #define SST_DEFAULT_LOCATION_ID 0xFFFF | ||
55 | #define SST_DEFAULT_CELL_NBR 0xFF | ||
56 | #define SST_DEFAULT_MODULE_ID 0xFFFF | ||
57 | |||
58 | /* | ||
59 | * Audio DSP Path Ids. Specified by the audio DSP FW | ||
60 | */ | ||
61 | enum sst_path_index { | ||
62 | SST_PATH_INDEX_CODEC_OUT0 = (0x02 << SST_PATH_ID_SHIFT), | ||
63 | SST_PATH_INDEX_CODEC_OUT1 = (0x03 << SST_PATH_ID_SHIFT), | ||
64 | |||
65 | SST_PATH_INDEX_SPROT_LOOP_OUT = (0x04 << SST_PATH_ID_SHIFT), | ||
66 | SST_PATH_INDEX_MEDIA_LOOP1_OUT = (0x05 << SST_PATH_ID_SHIFT), | ||
67 | SST_PATH_INDEX_MEDIA_LOOP2_OUT = (0x06 << SST_PATH_ID_SHIFT), | ||
68 | |||
69 | SST_PATH_INDEX_VOIP_OUT = (0x0C << SST_PATH_ID_SHIFT), | ||
70 | SST_PATH_INDEX_PCM0_OUT = (0x0D << SST_PATH_ID_SHIFT), | ||
71 | SST_PATH_INDEX_PCM1_OUT = (0x0E << SST_PATH_ID_SHIFT), | ||
72 | SST_PATH_INDEX_PCM2_OUT = (0x0F << SST_PATH_ID_SHIFT), | ||
73 | |||
74 | SST_PATH_INDEX_MEDIA0_OUT = (0x12 << SST_PATH_ID_SHIFT), | ||
75 | SST_PATH_INDEX_MEDIA1_OUT = (0x13 << SST_PATH_ID_SHIFT), | ||
76 | |||
77 | |||
78 | /* Start of input paths */ | ||
79 | SST_PATH_INDEX_CODEC_IN0 = (0x82 << SST_PATH_ID_SHIFT), | ||
80 | SST_PATH_INDEX_CODEC_IN1 = (0x83 << SST_PATH_ID_SHIFT), | ||
81 | |||
82 | SST_PATH_INDEX_SPROT_LOOP_IN = (0x84 << SST_PATH_ID_SHIFT), | ||
83 | SST_PATH_INDEX_MEDIA_LOOP1_IN = (0x85 << SST_PATH_ID_SHIFT), | ||
84 | SST_PATH_INDEX_MEDIA_LOOP2_IN = (0x86 << SST_PATH_ID_SHIFT), | ||
85 | |||
86 | SST_PATH_INDEX_VOIP_IN = (0x8C << SST_PATH_ID_SHIFT), | ||
87 | |||
88 | SST_PATH_INDEX_PCM0_IN = (0x8D << SST_PATH_ID_SHIFT), | ||
89 | SST_PATH_INDEX_PCM1_IN = (0x8E << SST_PATH_ID_SHIFT), | ||
90 | |||
91 | SST_PATH_INDEX_MEDIA0_IN = (0x8F << SST_PATH_ID_SHIFT), | ||
92 | SST_PATH_INDEX_MEDIA1_IN = (0x90 << SST_PATH_ID_SHIFT), | ||
93 | SST_PATH_INDEX_MEDIA2_IN = (0x91 << SST_PATH_ID_SHIFT), | ||
94 | |||
95 | SST_PATH_INDEX_MEDIA3_IN = (0x9C << SST_PATH_ID_SHIFT), | ||
96 | |||
97 | SST_PATH_INDEX_RESERVED = (0xFF << SST_PATH_ID_SHIFT), | ||
98 | }; | ||
99 | |||
100 | /* | ||
101 | * path IDs | ||
102 | */ | ||
103 | enum sst_swm_inputs { | ||
104 | SST_SWM_IN_CODEC0 = (SST_PATH_INDEX_CODEC_IN0 | SST_DEFAULT_CELL_NBR), | ||
105 | SST_SWM_IN_CODEC1 = (SST_PATH_INDEX_CODEC_IN1 | SST_DEFAULT_CELL_NBR), | ||
106 | SST_SWM_IN_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_IN | SST_DEFAULT_CELL_NBR), | ||
107 | SST_SWM_IN_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_IN | SST_DEFAULT_CELL_NBR), | ||
108 | SST_SWM_IN_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_IN | SST_DEFAULT_CELL_NBR), | ||
109 | SST_SWM_IN_VOIP = (SST_PATH_INDEX_VOIP_IN | SST_DEFAULT_CELL_NBR), | ||
110 | SST_SWM_IN_PCM0 = (SST_PATH_INDEX_PCM0_IN | SST_DEFAULT_CELL_NBR), | ||
111 | SST_SWM_IN_PCM1 = (SST_PATH_INDEX_PCM1_IN | SST_DEFAULT_CELL_NBR), | ||
112 | SST_SWM_IN_MEDIA0 = (SST_PATH_INDEX_MEDIA0_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ | ||
113 | SST_SWM_IN_MEDIA1 = (SST_PATH_INDEX_MEDIA1_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ | ||
114 | SST_SWM_IN_MEDIA2 = (SST_PATH_INDEX_MEDIA2_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ | ||
115 | SST_SWM_IN_MEDIA3 = (SST_PATH_INDEX_MEDIA3_IN | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ | ||
116 | SST_SWM_IN_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR) | ||
117 | }; | ||
118 | |||
119 | /* | ||
120 | * path IDs | ||
121 | */ | ||
122 | enum sst_swm_outputs { | ||
123 | SST_SWM_OUT_CODEC0 = (SST_PATH_INDEX_CODEC_OUT0 | SST_DEFAULT_CELL_NBR), | ||
124 | SST_SWM_OUT_CODEC1 = (SST_PATH_INDEX_CODEC_OUT1 | SST_DEFAULT_CELL_NBR), | ||
125 | SST_SWM_OUT_SPROT_LOOP = (SST_PATH_INDEX_SPROT_LOOP_OUT | SST_DEFAULT_CELL_NBR), | ||
126 | SST_SWM_OUT_MEDIA_LOOP1 = (SST_PATH_INDEX_MEDIA_LOOP1_OUT | SST_DEFAULT_CELL_NBR), | ||
127 | SST_SWM_OUT_MEDIA_LOOP2 = (SST_PATH_INDEX_MEDIA_LOOP2_OUT | SST_DEFAULT_CELL_NBR), | ||
128 | SST_SWM_OUT_VOIP = (SST_PATH_INDEX_VOIP_OUT | SST_DEFAULT_CELL_NBR), | ||
129 | SST_SWM_OUT_PCM0 = (SST_PATH_INDEX_PCM0_OUT | SST_DEFAULT_CELL_NBR), | ||
130 | SST_SWM_OUT_PCM1 = (SST_PATH_INDEX_PCM1_OUT | SST_DEFAULT_CELL_NBR), | ||
131 | SST_SWM_OUT_PCM2 = (SST_PATH_INDEX_PCM2_OUT | SST_DEFAULT_CELL_NBR), | ||
132 | SST_SWM_OUT_MEDIA0 = (SST_PATH_INDEX_MEDIA0_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ | ||
133 | SST_SWM_OUT_MEDIA1 = (SST_PATH_INDEX_MEDIA1_OUT | SST_DEFAULT_CELL_NBR), /* Part of Media Mixer */ | ||
134 | SST_SWM_OUT_END = (SST_PATH_INDEX_RESERVED | SST_DEFAULT_CELL_NBR), | ||
135 | }; | ||
136 | |||
137 | enum sst_ipc_msg { | ||
138 | SST_IPC_IA_CMD = 1, | ||
139 | SST_IPC_IA_SET_PARAMS, | ||
140 | SST_IPC_IA_GET_PARAMS, | ||
141 | }; | ||
142 | |||
143 | enum sst_cmd_type { | ||
144 | SST_CMD_BYTES_SET = 1, | ||
145 | SST_CMD_BYTES_GET = 2, | ||
146 | }; | ||
147 | |||
148 | enum sst_task { | ||
149 | SST_TASK_SBA = 1, | ||
150 | SST_TASK_MMX, | ||
151 | }; | ||
152 | |||
153 | enum sst_type { | ||
154 | SST_TYPE_CMD = 1, | ||
155 | SST_TYPE_PARAMS, | ||
156 | }; | ||
157 | |||
158 | enum sst_flag { | ||
159 | SST_FLAG_BLOCKED = 1, | ||
160 | SST_FLAG_NONBLOCK, | ||
161 | }; | ||
162 | |||
163 | /* | ||
164 | * Enumeration for indexing the gain cells in VB_SET_GAIN DSP command | ||
165 | */ | ||
166 | enum sst_gain_index { | ||
167 | /* GAIN IDs for SB task start here */ | ||
168 | SST_GAIN_INDEX_CODEC_OUT0, | ||
169 | SST_GAIN_INDEX_CODEC_OUT1, | ||
170 | SST_GAIN_INDEX_CODEC_IN0, | ||
171 | SST_GAIN_INDEX_CODEC_IN1, | ||
172 | |||
173 | SST_GAIN_INDEX_SPROT_LOOP_OUT, | ||
174 | SST_GAIN_INDEX_MEDIA_LOOP1_OUT, | ||
175 | SST_GAIN_INDEX_MEDIA_LOOP2_OUT, | ||
176 | |||
177 | SST_GAIN_INDEX_PCM0_IN_LEFT, | ||
178 | SST_GAIN_INDEX_PCM0_IN_RIGHT, | ||
179 | |||
180 | SST_GAIN_INDEX_PCM1_OUT_LEFT, | ||
181 | SST_GAIN_INDEX_PCM1_OUT_RIGHT, | ||
182 | SST_GAIN_INDEX_PCM1_IN_LEFT, | ||
183 | SST_GAIN_INDEX_PCM1_IN_RIGHT, | ||
184 | SST_GAIN_INDEX_PCM2_OUT_LEFT, | ||
185 | |||
186 | SST_GAIN_INDEX_PCM2_OUT_RIGHT, | ||
187 | SST_GAIN_INDEX_VOIP_OUT, | ||
188 | SST_GAIN_INDEX_VOIP_IN, | ||
189 | |||
190 | /* Gain IDs for MMX task start here */ | ||
191 | SST_GAIN_INDEX_MEDIA0_IN_LEFT, | ||
192 | SST_GAIN_INDEX_MEDIA0_IN_RIGHT, | ||
193 | SST_GAIN_INDEX_MEDIA1_IN_LEFT, | ||
194 | SST_GAIN_INDEX_MEDIA1_IN_RIGHT, | ||
195 | |||
196 | SST_GAIN_INDEX_MEDIA2_IN_LEFT, | ||
197 | SST_GAIN_INDEX_MEDIA2_IN_RIGHT, | ||
198 | |||
199 | SST_GAIN_INDEX_GAIN_END | ||
200 | }; | ||
201 | |||
202 | /* | ||
203 | * Audio DSP module IDs specified by FW spec | ||
204 | * TODO: Update with all modules | ||
205 | */ | ||
206 | enum sst_module_id { | ||
207 | SST_MODULE_ID_PCM = 0x0001, | ||
208 | SST_MODULE_ID_MP3 = 0x0002, | ||
209 | SST_MODULE_ID_MP24 = 0x0003, | ||
210 | SST_MODULE_ID_AAC = 0x0004, | ||
211 | SST_MODULE_ID_AACP = 0x0005, | ||
212 | SST_MODULE_ID_EAACP = 0x0006, | ||
213 | SST_MODULE_ID_WMA9 = 0x0007, | ||
214 | SST_MODULE_ID_WMA10 = 0x0008, | ||
215 | SST_MODULE_ID_WMA10P = 0x0009, | ||
216 | SST_MODULE_ID_RA = 0x000A, | ||
217 | SST_MODULE_ID_DDAC3 = 0x000B, | ||
218 | SST_MODULE_ID_TRUE_HD = 0x000C, | ||
219 | SST_MODULE_ID_HD_PLUS = 0x000D, | ||
220 | |||
221 | SST_MODULE_ID_SRC = 0x0064, | ||
222 | SST_MODULE_ID_DOWNMIX = 0x0066, | ||
223 | SST_MODULE_ID_GAIN_CELL = 0x0067, | ||
224 | SST_MODULE_ID_SPROT = 0x006D, | ||
225 | SST_MODULE_ID_BASS_BOOST = 0x006E, | ||
226 | SST_MODULE_ID_STEREO_WDNG = 0x006F, | ||
227 | SST_MODULE_ID_AV_REMOVAL = 0x0070, | ||
228 | SST_MODULE_ID_MIC_EQ = 0x0071, | ||
229 | SST_MODULE_ID_SPL = 0x0072, | ||
230 | SST_MODULE_ID_ALGO_VTSV = 0x0073, | ||
231 | SST_MODULE_ID_NR = 0x0076, | ||
232 | SST_MODULE_ID_BWX = 0x0077, | ||
233 | SST_MODULE_ID_DRP = 0x0078, | ||
234 | SST_MODULE_ID_MDRP = 0x0079, | ||
235 | |||
236 | SST_MODULE_ID_ANA = 0x007A, | ||
237 | SST_MODULE_ID_AEC = 0x007B, | ||
238 | SST_MODULE_ID_NR_SNS = 0x007C, | ||
239 | SST_MODULE_ID_SER = 0x007D, | ||
240 | SST_MODULE_ID_AGC = 0x007E, | ||
241 | |||
242 | SST_MODULE_ID_CNI = 0x007F, | ||
243 | SST_MODULE_ID_CONTEXT_ALGO_AWARE = 0x0080, | ||
244 | SST_MODULE_ID_FIR_24 = 0x0081, | ||
245 | SST_MODULE_ID_IIR_24 = 0x0082, | ||
246 | |||
247 | SST_MODULE_ID_ASRC = 0x0083, | ||
248 | SST_MODULE_ID_TONE_GEN = 0x0084, | ||
249 | SST_MODULE_ID_BMF = 0x0086, | ||
250 | SST_MODULE_ID_EDL = 0x0087, | ||
251 | SST_MODULE_ID_GLC = 0x0088, | ||
252 | |||
253 | SST_MODULE_ID_FIR_16 = 0x0089, | ||
254 | SST_MODULE_ID_IIR_16 = 0x008A, | ||
255 | SST_MODULE_ID_DNR = 0x008B, | ||
256 | |||
257 | SST_MODULE_ID_VIRTUALIZER = 0x008C, | ||
258 | SST_MODULE_ID_VISUALIZATION = 0x008D, | ||
259 | SST_MODULE_ID_LOUDNESS_OPTIMIZER = 0x008E, | ||
260 | SST_MODULE_ID_REVERBERATION = 0x008F, | ||
261 | |||
262 | SST_MODULE_ID_CNI_TX = 0x0090, | ||
263 | SST_MODULE_ID_REF_LINE = 0x0091, | ||
264 | SST_MODULE_ID_VOLUME = 0x0092, | ||
265 | SST_MODULE_ID_FILT_DCR = 0x0094, | ||
266 | SST_MODULE_ID_SLV = 0x009A, | ||
267 | SST_MODULE_ID_NLF = 0x009B, | ||
268 | SST_MODULE_ID_TNR = 0x009C, | ||
269 | SST_MODULE_ID_WNR = 0x009D, | ||
270 | |||
271 | SST_MODULE_ID_LOG = 0xFF00, | ||
272 | |||
273 | SST_MODULE_ID_TASK = 0xFFFF, | ||
274 | }; | ||
275 | |||
276 | enum sst_cmd { | ||
277 | SBA_IDLE = 14, | ||
278 | SBA_VB_SET_SPEECH_PATH = 26, | ||
279 | MMX_SET_GAIN = 33, | ||
280 | SBA_VB_SET_GAIN = 33, | ||
281 | FBA_VB_RX_CNI = 35, | ||
282 | MMX_SET_GAIN_TIMECONST = 36, | ||
283 | SBA_VB_SET_TIMECONST = 36, | ||
284 | SBA_VB_START = 85, | ||
285 | SBA_SET_SWM = 114, | ||
286 | SBA_SET_MDRP = 116, | ||
287 | SBA_HW_SET_SSP = 117, | ||
288 | SBA_SET_MEDIA_LOOP_MAP = 118, | ||
289 | SBA_SET_MEDIA_PATH = 119, | ||
290 | MMX_SET_MEDIA_PATH = 119, | ||
291 | SBA_VB_LPRO = 126, | ||
292 | SBA_VB_SET_FIR = 128, | ||
293 | SBA_VB_SET_IIR = 129, | ||
294 | SBA_SET_SSP_SLOT_MAP = 130, | ||
295 | }; | ||
296 | |||
297 | enum sst_dsp_switch { | ||
298 | SST_SWITCH_OFF = 0, | ||
299 | SST_SWITCH_ON = 3, | ||
300 | }; | ||
301 | |||
302 | enum sst_path_switch { | ||
303 | SST_PATH_OFF = 0, | ||
304 | SST_PATH_ON = 1, | ||
305 | }; | ||
306 | |||
307 | enum sst_swm_state { | ||
308 | SST_SWM_OFF = 0, | ||
309 | SST_SWM_ON = 3, | ||
310 | }; | ||
311 | |||
312 | #define SST_FILL_LOCATION_IDS(dst, cell_idx, pipe_id) do { \ | ||
313 | dst.location_id.p.cell_nbr_idx = (cell_idx); \ | ||
314 | dst.location_id.p.path_id = (pipe_id); \ | ||
315 | } while (0) | ||
316 | #define SST_FILL_LOCATION_ID(dst, loc_id) (\ | ||
317 | dst.location_id.f = (loc_id)) | ||
318 | #define SST_FILL_MODULE_ID(dst, mod_id) (\ | ||
319 | dst.module_id = (mod_id)) | ||
320 | |||
321 | #define SST_FILL_DESTINATION1(dst, id) do { \ | ||
322 | SST_FILL_LOCATION_ID(dst, (id) & 0xFFFF); \ | ||
323 | SST_FILL_MODULE_ID(dst, ((id) & 0xFFFF0000) >> 16); \ | ||
324 | } while (0) | ||
325 | #define SST_FILL_DESTINATION2(dst, loc_id, mod_id) do { \ | ||
326 | SST_FILL_LOCATION_ID(dst, loc_id); \ | ||
327 | SST_FILL_MODULE_ID(dst, mod_id); \ | ||
328 | } while (0) | ||
329 | #define SST_FILL_DESTINATION3(dst, cell_idx, path_id, mod_id) do { \ | ||
330 | SST_FILL_LOCATION_IDS(dst, cell_idx, path_id); \ | ||
331 | SST_FILL_MODULE_ID(dst, mod_id); \ | ||
332 | } while (0) | ||
333 | |||
334 | #define SST_FILL_DESTINATION(level, dst, ...) \ | ||
335 | SST_FILL_DESTINATION##level(dst, __VA_ARGS__) | ||
336 | #define SST_FILL_DEFAULT_DESTINATION(dst) \ | ||
337 | SST_FILL_DESTINATION(2, dst, SST_DEFAULT_LOCATION_ID, SST_DEFAULT_MODULE_ID) | ||
338 | |||
339 | struct sst_destination_id { | ||
340 | union sst_location_id { | ||
341 | struct { | ||
342 | u8 cell_nbr_idx; /* module index */ | ||
343 | u8 path_id; /* pipe_id */ | ||
344 | } __packed p; /* part */ | ||
345 | u16 f; /* full */ | ||
346 | } __packed location_id; | ||
347 | u16 module_id; | ||
348 | } __packed; | ||
349 | struct sst_dsp_header { | ||
350 | struct sst_destination_id dst; | ||
351 | u16 command_id; | ||
352 | u16 length; | ||
353 | } __packed; | ||
354 | |||
355 | /* | ||
356 | * | ||
357 | * Common Commands | ||
358 | * | ||
359 | */ | ||
360 | struct sst_cmd_generic { | ||
361 | struct sst_dsp_header header; | ||
362 | } __packed; | ||
363 | struct sst_cmd_set_params { | ||
364 | struct sst_destination_id dst; | ||
365 | u16 command_id; | ||
366 | char params[0]; | ||
367 | } __packed; | ||
368 | #define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \ | ||
369 | xpname " " xmname " " #xinstance " " xtype | ||
370 | |||
371 | #define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \ | ||
372 | xpname " " xmname " " #xinstance " " xtype " " xsubmodule | ||
373 | enum sst_algo_kcontrol_type { | ||
374 | SST_ALGO_PARAMS, | ||
375 | SST_ALGO_BYPASS, | ||
376 | }; | ||
377 | |||
378 | struct sst_algo_control { | ||
379 | enum sst_algo_kcontrol_type type; | ||
380 | int max; | ||
381 | u16 module_id; | ||
382 | u16 pipe_id; | ||
383 | u16 task_id; | ||
384 | u16 cmd_id; | ||
385 | bool bypass; | ||
386 | unsigned char *params; | ||
387 | struct snd_soc_dapm_widget *w; | ||
388 | }; | ||
389 | |||
390 | /* size of the control = size of params + size of length field */ | ||
391 | #define SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, xmod, xtask, xcmd) \ | ||
392 | (struct sst_algo_control){ \ | ||
393 | .max = xcount + sizeof(u16), .type = xtype, .module_id = xmod, \ | ||
394 | .pipe_id = xpipe, .task_id = xtask, .cmd_id = xcmd, \ | ||
395 | } | ||
396 | |||
397 | #define SST_ALGO_KCONTROL(xname, xcount, xmod, xpipe, \ | ||
398 | xtask, xcmd, xtype, xinfo, xget, xput) \ | ||
399 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
400 | .name = xname, \ | ||
401 | .info = xinfo, .get = xget, .put = xput, \ | ||
402 | .private_value = (unsigned long)& \ | ||
403 | SST_ALGO_CTL_VALUE(xcount, xtype, xpipe, \ | ||
404 | xmod, xtask, xcmd), \ | ||
405 | } | ||
406 | |||
407 | #define SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, \ | ||
408 | xpipe, xinstance, xtask, xcmd) \ | ||
409 | SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "params"), \ | ||
410 | xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ | ||
411 | sst_algo_bytes_ctl_info, \ | ||
412 | sst_algo_control_get, sst_algo_control_set) | ||
413 | |||
414 | #define SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask) \ | ||
415 | SST_ALGO_KCONTROL(SST_CONTROL_NAME(xpname, xmname, xinstance, "bypass"), \ | ||
416 | 0, xmod, xpipe, xtask, 0, SST_ALGO_BYPASS, \ | ||
417 | snd_soc_info_bool_ext, \ | ||
418 | sst_algo_control_get, sst_algo_control_set) | ||
419 | |||
420 | #define SST_ALGO_BYPASS_PARAMS(xpname, xmname, xcount, xmod, xpipe, \ | ||
421 | xinstance, xtask, xcmd) \ | ||
422 | SST_ALGO_KCONTROL_BOOL(xpname, xmname, xmod, xpipe, xinstance, xtask), \ | ||
423 | SST_ALGO_KCONTROL_BYTES(xpname, xmname, xcount, xmod, xpipe, xinstance, xtask, xcmd) | ||
424 | |||
425 | #define SST_COMBO_ALGO_KCONTROL_BYTES(xpname, xmname, xsubmod, xcount, xmod, \ | ||
426 | xpipe, xinstance, xtask, xcmd) \ | ||
427 | SST_ALGO_KCONTROL(SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, "params", \ | ||
428 | xsubmod), \ | ||
429 | xcount, xmod, xpipe, xtask, xcmd, SST_ALGO_PARAMS, \ | ||
430 | sst_algo_bytes_ctl_info, \ | ||
431 | sst_algo_control_get, sst_algo_control_set) | ||
432 | |||
433 | |||
434 | struct sst_enum { | ||
435 | bool tx; | ||
436 | unsigned short reg; | ||
437 | unsigned int max; | ||
438 | const char * const *texts; | ||
439 | struct snd_soc_dapm_widget *w; | ||
440 | }; | ||
29 | 441 | ||
30 | #endif | 442 | #endif |
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c index 67673a2c0f41..b4ad98c43e5c 100644 --- a/sound/soc/intel/sst-baytrail-ipc.c +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
@@ -817,7 +817,7 @@ static struct sst_dsp_device byt_dev = { | |||
817 | .ops = &sst_byt_ops, | 817 | .ops = &sst_byt_ops, |
818 | }; | 818 | }; |
819 | 819 | ||
820 | int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata) | 820 | int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) |
821 | { | 821 | { |
822 | struct sst_byt *byt = pdata->dsp; | 822 | struct sst_byt *byt = pdata->dsp; |
823 | 823 | ||
@@ -826,14 +826,6 @@ int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata) | |||
826 | sst_byt_drop_all(byt); | 826 | sst_byt_drop_all(byt); |
827 | dev_dbg(byt->dev, "dsp in reset\n"); | 827 | dev_dbg(byt->dev, "dsp in reset\n"); |
828 | 828 | ||
829 | return 0; | ||
830 | } | ||
831 | EXPORT_SYMBOL_GPL(sst_byt_dsp_suspend_noirq); | ||
832 | |||
833 | int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata) | ||
834 | { | ||
835 | struct sst_byt *byt = pdata->dsp; | ||
836 | |||
837 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); | 829 | dev_dbg(byt->dev, "free all blocks and unload fw\n"); |
838 | sst_fw_unload(byt->fw); | 830 | sst_fw_unload(byt->fw); |
839 | 831 | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h index 06a4d202689b..8faff6dcf25d 100644 --- a/sound/soc/intel/sst-baytrail-ipc.h +++ b/sound/soc/intel/sst-baytrail-ipc.h | |||
@@ -66,7 +66,6 @@ int sst_byt_get_dsp_position(struct sst_byt *byt, | |||
66 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata); | 66 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata); |
67 | void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata); | 67 | void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata); |
68 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt); | 68 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt); |
69 | int sst_byt_dsp_suspend_noirq(struct device *dev, struct sst_pdata *pdata); | ||
70 | int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata); | 69 | int sst_byt_dsp_suspend_late(struct device *dev, struct sst_pdata *pdata); |
71 | int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata); | 70 | int sst_byt_dsp_boot(struct device *dev, struct sst_pdata *pdata); |
72 | int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata); | 71 | int sst_byt_dsp_wait_for_ready(struct device *dev, struct sst_pdata *pdata); |
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c index 599401c0c655..eab1c7d85187 100644 --- a/sound/soc/intel/sst-baytrail-pcm.c +++ b/sound/soc/intel/sst-baytrail-pcm.c | |||
@@ -59,6 +59,9 @@ struct sst_byt_priv_data { | |||
59 | 59 | ||
60 | /* DAI data */ | 60 | /* DAI data */ |
61 | struct sst_byt_pcm_data pcm[BYT_PCM_COUNT]; | 61 | struct sst_byt_pcm_data pcm[BYT_PCM_COUNT]; |
62 | |||
63 | /* flag indicating is stream context restore needed after suspend */ | ||
64 | bool restore_stream; | ||
62 | }; | 65 | }; |
63 | 66 | ||
64 | /* this may get called several times by oss emulation */ | 67 | /* this may get called several times by oss emulation */ |
@@ -184,7 +187,10 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
184 | sst_byt_stream_start(byt, pcm_data->stream, 0); | 187 | sst_byt_stream_start(byt, pcm_data->stream, 0); |
185 | break; | 188 | break; |
186 | case SNDRV_PCM_TRIGGER_RESUME: | 189 | case SNDRV_PCM_TRIGGER_RESUME: |
187 | schedule_work(&pcm_data->work); | 190 | if (pdata->restore_stream == true) |
191 | schedule_work(&pcm_data->work); | ||
192 | else | ||
193 | sst_byt_stream_resume(byt, pcm_data->stream); | ||
188 | break; | 194 | break; |
189 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 195 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
190 | sst_byt_stream_resume(byt, pcm_data->stream); | 196 | sst_byt_stream_resume(byt, pcm_data->stream); |
@@ -193,6 +199,7 @@ static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
193 | sst_byt_stream_stop(byt, pcm_data->stream); | 199 | sst_byt_stream_stop(byt, pcm_data->stream); |
194 | break; | 200 | break; |
195 | case SNDRV_PCM_TRIGGER_SUSPEND: | 201 | case SNDRV_PCM_TRIGGER_SUSPEND: |
202 | pdata->restore_stream = false; | ||
196 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 203 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
197 | sst_byt_stream_pause(byt, pcm_data->stream); | 204 | sst_byt_stream_pause(byt, pcm_data->stream); |
198 | break; | 205 | break; |
@@ -404,26 +411,10 @@ static const struct snd_soc_component_driver byt_dai_component = { | |||
404 | }; | 411 | }; |
405 | 412 | ||
406 | #ifdef CONFIG_PM | 413 | #ifdef CONFIG_PM |
407 | static int sst_byt_pcm_dev_suspend_noirq(struct device *dev) | ||
408 | { | ||
409 | struct sst_pdata *sst_pdata = dev_get_platdata(dev); | ||
410 | int ret; | ||
411 | |||
412 | dev_dbg(dev, "suspending noirq\n"); | ||
413 | |||
414 | /* at this point all streams will be stopped and context saved */ | ||
415 | ret = sst_byt_dsp_suspend_noirq(dev, sst_pdata); | ||
416 | if (ret < 0) { | ||
417 | dev_err(dev, "failed to suspend %d\n", ret); | ||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | return ret; | ||
422 | } | ||
423 | |||
424 | static int sst_byt_pcm_dev_suspend_late(struct device *dev) | 414 | static int sst_byt_pcm_dev_suspend_late(struct device *dev) |
425 | { | 415 | { |
426 | struct sst_pdata *sst_pdata = dev_get_platdata(dev); | 416 | struct sst_pdata *sst_pdata = dev_get_platdata(dev); |
417 | struct sst_byt_priv_data *priv_data = dev_get_drvdata(dev); | ||
427 | int ret; | 418 | int ret; |
428 | 419 | ||
429 | dev_dbg(dev, "suspending late\n"); | 420 | dev_dbg(dev, "suspending late\n"); |
@@ -434,34 +425,30 @@ static int sst_byt_pcm_dev_suspend_late(struct device *dev) | |||
434 | return ret; | 425 | return ret; |
435 | } | 426 | } |
436 | 427 | ||
428 | priv_data->restore_stream = true; | ||
429 | |||
437 | return ret; | 430 | return ret; |
438 | } | 431 | } |
439 | 432 | ||
440 | static int sst_byt_pcm_dev_resume_early(struct device *dev) | 433 | static int sst_byt_pcm_dev_resume_early(struct device *dev) |
441 | { | 434 | { |
442 | struct sst_pdata *sst_pdata = dev_get_platdata(dev); | 435 | struct sst_pdata *sst_pdata = dev_get_platdata(dev); |
436 | int ret; | ||
443 | 437 | ||
444 | dev_dbg(dev, "resume early\n"); | 438 | dev_dbg(dev, "resume early\n"); |
445 | 439 | ||
446 | /* load fw and boot DSP */ | 440 | /* load fw and boot DSP */ |
447 | return sst_byt_dsp_boot(dev, sst_pdata); | 441 | ret = sst_byt_dsp_boot(dev, sst_pdata); |
448 | } | 442 | if (ret) |
449 | 443 | return ret; | |
450 | static int sst_byt_pcm_dev_resume(struct device *dev) | ||
451 | { | ||
452 | struct sst_pdata *sst_pdata = dev_get_platdata(dev); | ||
453 | |||
454 | dev_dbg(dev, "resume\n"); | ||
455 | 444 | ||
456 | /* wait for FW to finish booting */ | 445 | /* wait for FW to finish booting */ |
457 | return sst_byt_dsp_wait_for_ready(dev, sst_pdata); | 446 | return sst_byt_dsp_wait_for_ready(dev, sst_pdata); |
458 | } | 447 | } |
459 | 448 | ||
460 | static const struct dev_pm_ops sst_byt_pm_ops = { | 449 | static const struct dev_pm_ops sst_byt_pm_ops = { |
461 | .suspend_noirq = sst_byt_pcm_dev_suspend_noirq, | ||
462 | .suspend_late = sst_byt_pcm_dev_suspend_late, | 450 | .suspend_late = sst_byt_pcm_dev_suspend_late, |
463 | .resume_early = sst_byt_pcm_dev_resume_early, | 451 | .resume_early = sst_byt_pcm_dev_resume_early, |
464 | .resume = sst_byt_pcm_dev_resume, | ||
465 | }; | 452 | }; |
466 | 453 | ||
467 | #define SST_BYT_PM_OPS (&sst_byt_pm_ops) | 454 | #define SST_BYT_PM_OPS (&sst_byt_pm_ops) |
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c index 61bf6da4bb02..33fc5c3abf55 100644 --- a/sound/soc/intel/sst-haswell-pcm.c +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -138,11 +138,10 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value) | |||
138 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | 138 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, |
139 | struct snd_ctl_elem_value *ucontrol) | 139 | struct snd_ctl_elem_value *ucontrol) |
140 | { | 140 | { |
141 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | 141 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
142 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | ||
142 | struct soc_mixer_control *mc = | 143 | struct soc_mixer_control *mc = |
143 | (struct soc_mixer_control *)kcontrol->private_value; | 144 | (struct soc_mixer_control *)kcontrol->private_value; |
144 | struct hsw_priv_data *pdata = | ||
145 | snd_soc_platform_get_drvdata(platform); | ||
146 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 145 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; |
147 | struct sst_hsw *hsw = pdata->hsw; | 146 | struct sst_hsw *hsw = pdata->hsw; |
148 | u32 volume; | 147 | u32 volume; |
@@ -176,11 +175,10 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | |||
176 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | 175 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, |
177 | struct snd_ctl_elem_value *ucontrol) | 176 | struct snd_ctl_elem_value *ucontrol) |
178 | { | 177 | { |
179 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | 178 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
179 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); | ||
180 | struct soc_mixer_control *mc = | 180 | struct soc_mixer_control *mc = |
181 | (struct soc_mixer_control *)kcontrol->private_value; | 181 | (struct soc_mixer_control *)kcontrol->private_value; |
182 | struct hsw_priv_data *pdata = | ||
183 | snd_soc_platform_get_drvdata(platform); | ||
184 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | 182 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; |
185 | struct sst_hsw *hsw = pdata->hsw; | 183 | struct sst_hsw *hsw = pdata->hsw; |
186 | u32 volume; | 184 | u32 volume; |
@@ -208,8 +206,8 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | |||
208 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, | 206 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, |
209 | struct snd_ctl_elem_value *ucontrol) | 207 | struct snd_ctl_elem_value *ucontrol) |
210 | { | 208 | { |
211 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | 209 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
212 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | 210 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); |
213 | struct sst_hsw *hsw = pdata->hsw; | 211 | struct sst_hsw *hsw = pdata->hsw; |
214 | u32 volume; | 212 | u32 volume; |
215 | 213 | ||
@@ -233,8 +231,8 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol, | |||
233 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, | 231 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, |
234 | struct snd_ctl_elem_value *ucontrol) | 232 | struct snd_ctl_elem_value *ucontrol) |
235 | { | 233 | { |
236 | struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol); | 234 | struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol); |
237 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | 235 | struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt); |
238 | struct sst_hsw *hsw = pdata->hsw; | 236 | struct sst_hsw *hsw = pdata->hsw; |
239 | unsigned int volume = 0; | 237 | unsigned int volume = 0; |
240 | 238 | ||
@@ -778,20 +776,11 @@ static const struct snd_soc_dapm_route graph[] = { | |||
778 | 776 | ||
779 | static int hsw_pcm_probe(struct snd_soc_platform *platform) | 777 | static int hsw_pcm_probe(struct snd_soc_platform *platform) |
780 | { | 778 | { |
779 | struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform); | ||
781 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | 780 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); |
782 | struct hsw_priv_data *priv_data; | 781 | struct device *dma_dev = pdata->dma_dev; |
783 | struct device *dma_dev; | ||
784 | int i, ret = 0; | 782 | int i, ret = 0; |
785 | 783 | ||
786 | if (!pdata) | ||
787 | return -ENODEV; | ||
788 | |||
789 | dma_dev = pdata->dma_dev; | ||
790 | |||
791 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); | ||
792 | priv_data->hsw = pdata->dsp; | ||
793 | snd_soc_platform_set_drvdata(platform, priv_data); | ||
794 | |||
795 | /* allocate DSP buffer page tables */ | 784 | /* allocate DSP buffer page tables */ |
796 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | 785 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { |
797 | 786 | ||
@@ -848,27 +837,38 @@ static struct snd_soc_platform_driver hsw_soc_platform = { | |||
848 | .ops = &hsw_pcm_ops, | 837 | .ops = &hsw_pcm_ops, |
849 | .pcm_new = hsw_pcm_new, | 838 | .pcm_new = hsw_pcm_new, |
850 | .pcm_free = hsw_pcm_free, | 839 | .pcm_free = hsw_pcm_free, |
851 | .controls = hsw_volume_controls, | ||
852 | .num_controls = ARRAY_SIZE(hsw_volume_controls), | ||
853 | .dapm_widgets = widgets, | ||
854 | .num_dapm_widgets = ARRAY_SIZE(widgets), | ||
855 | .dapm_routes = graph, | ||
856 | .num_dapm_routes = ARRAY_SIZE(graph), | ||
857 | }; | 840 | }; |
858 | 841 | ||
859 | static const struct snd_soc_component_driver hsw_dai_component = { | 842 | static const struct snd_soc_component_driver hsw_dai_component = { |
860 | .name = "haswell-dai", | 843 | .name = "haswell-dai", |
844 | .controls = hsw_volume_controls, | ||
845 | .num_controls = ARRAY_SIZE(hsw_volume_controls), | ||
846 | .dapm_widgets = widgets, | ||
847 | .num_dapm_widgets = ARRAY_SIZE(widgets), | ||
848 | .dapm_routes = graph, | ||
849 | .num_dapm_routes = ARRAY_SIZE(graph), | ||
861 | }; | 850 | }; |
862 | 851 | ||
863 | static int hsw_pcm_dev_probe(struct platform_device *pdev) | 852 | static int hsw_pcm_dev_probe(struct platform_device *pdev) |
864 | { | 853 | { |
865 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | 854 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); |
855 | struct hsw_priv_data *priv_data; | ||
866 | int ret; | 856 | int ret; |
867 | 857 | ||
858 | if (!sst_pdata) | ||
859 | return -EINVAL; | ||
860 | |||
861 | priv_data = devm_kzalloc(&pdev->dev, sizeof(*priv_data), GFP_KERNEL); | ||
862 | if (!priv_data) | ||
863 | return -ENOMEM; | ||
864 | |||
868 | ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); | 865 | ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); |
869 | if (ret < 0) | 866 | if (ret < 0) |
870 | return -ENODEV; | 867 | return -ENODEV; |
871 | 868 | ||
869 | priv_data->hsw = sst_pdata->dsp; | ||
870 | platform_set_drvdata(pdev, priv_data); | ||
871 | |||
872 | ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); | 872 | ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); |
873 | if (ret < 0) | 873 | if (ret < 0) |
874 | goto err_plat; | 874 | goto err_plat; |
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c index 29c059ca19e8..59467775c9b8 100644 --- a/sound/soc/intel/sst-mfld-platform-compress.c +++ b/sound/soc/intel/sst-mfld-platform-compress.c | |||
@@ -86,7 +86,7 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream) | |||
86 | /*need to check*/ | 86 | /*need to check*/ |
87 | str_id = stream->id; | 87 | str_id = stream->id; |
88 | if (str_id) | 88 | if (str_id) |
89 | ret_val = stream->compr_ops->close(str_id); | 89 | ret_val = stream->compr_ops->close(sst->dev, str_id); |
90 | module_put(sst->dev->driver->owner); | 90 | module_put(sst->dev->driver->owner); |
91 | kfree(stream); | 91 | kfree(stream); |
92 | pr_debug("%s: %d\n", __func__, ret_val); | 92 | pr_debug("%s: %d\n", __func__, ret_val); |
@@ -158,7 +158,7 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, | |||
158 | cb.drain_cb_param = cstream; | 158 | cb.drain_cb_param = cstream; |
159 | cb.drain_notify = sst_drain_notify; | 159 | cb.drain_notify = sst_drain_notify; |
160 | 160 | ||
161 | retval = stream->compr_ops->open(&str_params, &cb); | 161 | retval = stream->compr_ops->open(sst->dev, &str_params, &cb); |
162 | if (retval < 0) { | 162 | if (retval < 0) { |
163 | pr_err("stream allocation failed %d\n", retval); | 163 | pr_err("stream allocation failed %d\n", retval); |
164 | return retval; | 164 | return retval; |
@@ -170,10 +170,30 @@ static int sst_platform_compr_set_params(struct snd_compr_stream *cstream, | |||
170 | 170 | ||
171 | static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) | 171 | static int sst_platform_compr_trigger(struct snd_compr_stream *cstream, int cmd) |
172 | { | 172 | { |
173 | struct sst_runtime_stream *stream = | 173 | struct sst_runtime_stream *stream = cstream->runtime->private_data; |
174 | cstream->runtime->private_data; | 174 | |
175 | 175 | switch (cmd) { | |
176 | return stream->compr_ops->control(cmd, stream->id); | 176 | case SNDRV_PCM_TRIGGER_START: |
177 | if (stream->compr_ops->stream_start) | ||
178 | return stream->compr_ops->stream_start(sst->dev, stream->id); | ||
179 | case SNDRV_PCM_TRIGGER_STOP: | ||
180 | if (stream->compr_ops->stream_drop) | ||
181 | return stream->compr_ops->stream_drop(sst->dev, stream->id); | ||
182 | case SND_COMPR_TRIGGER_DRAIN: | ||
183 | if (stream->compr_ops->stream_drain) | ||
184 | return stream->compr_ops->stream_drain(sst->dev, stream->id); | ||
185 | case SND_COMPR_TRIGGER_PARTIAL_DRAIN: | ||
186 | if (stream->compr_ops->stream_partial_drain) | ||
187 | return stream->compr_ops->stream_partial_drain(sst->dev, stream->id); | ||
188 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
189 | if (stream->compr_ops->stream_pause) | ||
190 | return stream->compr_ops->stream_pause(sst->dev, stream->id); | ||
191 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
192 | if (stream->compr_ops->stream_pause_release) | ||
193 | return stream->compr_ops->stream_pause_release(sst->dev, stream->id); | ||
194 | default: | ||
195 | return -EINVAL; | ||
196 | } | ||
177 | } | 197 | } |
178 | 198 | ||
179 | static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, | 199 | static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, |
@@ -182,7 +202,7 @@ static int sst_platform_compr_pointer(struct snd_compr_stream *cstream, | |||
182 | struct sst_runtime_stream *stream; | 202 | struct sst_runtime_stream *stream; |
183 | 203 | ||
184 | stream = cstream->runtime->private_data; | 204 | stream = cstream->runtime->private_data; |
185 | stream->compr_ops->tstamp(stream->id, tstamp); | 205 | stream->compr_ops->tstamp(sst->dev, stream->id, tstamp); |
186 | tstamp->byte_offset = tstamp->copied_total % | 206 | tstamp->byte_offset = tstamp->copied_total % |
187 | (u32)cstream->runtime->buffer_size; | 207 | (u32)cstream->runtime->buffer_size; |
188 | pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); | 208 | pr_debug("calc bytes offset/copied bytes as %d\n", tstamp->byte_offset); |
@@ -195,7 +215,7 @@ static int sst_platform_compr_ack(struct snd_compr_stream *cstream, | |||
195 | struct sst_runtime_stream *stream; | 215 | struct sst_runtime_stream *stream; |
196 | 216 | ||
197 | stream = cstream->runtime->private_data; | 217 | stream = cstream->runtime->private_data; |
198 | stream->compr_ops->ack(stream->id, (unsigned long)bytes); | 218 | stream->compr_ops->ack(sst->dev, stream->id, (unsigned long)bytes); |
199 | stream->bytes_written += bytes; | 219 | stream->bytes_written += bytes; |
200 | 220 | ||
201 | return 0; | 221 | return 0; |
@@ -225,7 +245,7 @@ static int sst_platform_compr_set_metadata(struct snd_compr_stream *cstream, | |||
225 | struct sst_runtime_stream *stream = | 245 | struct sst_runtime_stream *stream = |
226 | cstream->runtime->private_data; | 246 | cstream->runtime->private_data; |
227 | 247 | ||
228 | return stream->compr_ops->set_metadata(stream->id, metadata); | 248 | return stream->compr_ops->set_metadata(sst->dev, stream->id, metadata); |
229 | } | 249 | } |
230 | 250 | ||
231 | struct snd_compr_ops sst_platform_compr_ops = { | 251 | struct snd_compr_ops sst_platform_compr_ops = { |
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c index 706212a6a68c..aa9b600dfc9b 100644 --- a/sound/soc/intel/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/sst-mfld-platform-pcm.c | |||
@@ -43,12 +43,12 @@ int sst_register_dsp(struct sst_device *dev) | |||
43 | return -ENODEV; | 43 | return -ENODEV; |
44 | mutex_lock(&sst_lock); | 44 | mutex_lock(&sst_lock); |
45 | if (sst) { | 45 | if (sst) { |
46 | pr_err("we already have a device %s\n", sst->name); | 46 | dev_err(dev->dev, "we already have a device %s\n", sst->name); |
47 | module_put(dev->dev->driver->owner); | 47 | module_put(dev->dev->driver->owner); |
48 | mutex_unlock(&sst_lock); | 48 | mutex_unlock(&sst_lock); |
49 | return -EEXIST; | 49 | return -EEXIST; |
50 | } | 50 | } |
51 | pr_debug("registering device %s\n", dev->name); | 51 | dev_dbg(dev->dev, "registering device %s\n", dev->name); |
52 | sst = dev; | 52 | sst = dev; |
53 | mutex_unlock(&sst_lock); | 53 | mutex_unlock(&sst_lock); |
54 | return 0; | 54 | return 0; |
@@ -70,7 +70,7 @@ int sst_unregister_dsp(struct sst_device *dev) | |||
70 | } | 70 | } |
71 | 71 | ||
72 | module_put(sst->dev->driver->owner); | 72 | module_put(sst->dev->driver->owner); |
73 | pr_debug("unreg %s\n", sst->name); | 73 | dev_dbg(dev->dev, "unreg %s\n", sst->name); |
74 | sst = NULL; | 74 | sst = NULL; |
75 | mutex_unlock(&sst_lock); | 75 | mutex_unlock(&sst_lock); |
76 | return 0; | 76 | return 0; |
@@ -252,7 +252,7 @@ int sst_fill_stream_params(void *substream, | |||
252 | } | 252 | } |
253 | 253 | ||
254 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, | 254 | static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, |
255 | struct snd_soc_platform *platform) | 255 | struct snd_soc_dai *dai) |
256 | { | 256 | { |
257 | struct sst_runtime_stream *stream = | 257 | struct sst_runtime_stream *stream = |
258 | substream->runtime->private_data; | 258 | substream->runtime->private_data; |
@@ -260,7 +260,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, | |||
260 | struct snd_sst_params str_params = {0}; | 260 | struct snd_sst_params str_params = {0}; |
261 | struct snd_sst_alloc_params_ext alloc_params = {0}; | 261 | struct snd_sst_alloc_params_ext alloc_params = {0}; |
262 | int ret_val = 0; | 262 | int ret_val = 0; |
263 | struct sst_data *ctx = snd_soc_platform_get_drvdata(platform); | 263 | struct sst_data *ctx = snd_soc_dai_get_drvdata(dai); |
264 | 264 | ||
265 | /* set codec params and inform SST driver the same */ | 265 | /* set codec params and inform SST driver the same */ |
266 | sst_fill_pcm_params(substream, ¶m); | 266 | sst_fill_pcm_params(substream, ¶m); |
@@ -277,7 +277,7 @@ static int sst_platform_alloc_stream(struct snd_pcm_substream *substream, | |||
277 | 277 | ||
278 | stream->stream_info.str_id = str_params.stream_id; | 278 | stream->stream_info.str_id = str_params.stream_id; |
279 | 279 | ||
280 | ret_val = stream->ops->open(&str_params); | 280 | ret_val = stream->ops->open(sst->dev, &str_params); |
281 | if (ret_val <= 0) | 281 | if (ret_val <= 0) |
282 | return ret_val; | 282 | return ret_val; |
283 | 283 | ||
@@ -306,22 +306,31 @@ static int sst_platform_init_stream(struct snd_pcm_substream *substream) | |||
306 | { | 306 | { |
307 | struct sst_runtime_stream *stream = | 307 | struct sst_runtime_stream *stream = |
308 | substream->runtime->private_data; | 308 | substream->runtime->private_data; |
309 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
309 | int ret_val; | 310 | int ret_val; |
310 | 311 | ||
311 | pr_debug("setting buffer ptr param\n"); | 312 | dev_dbg(rtd->dev, "setting buffer ptr param\n"); |
312 | sst_set_stream_status(stream, SST_PLATFORM_INIT); | 313 | sst_set_stream_status(stream, SST_PLATFORM_INIT); |
313 | stream->stream_info.period_elapsed = sst_period_elapsed; | 314 | stream->stream_info.period_elapsed = sst_period_elapsed; |
314 | stream->stream_info.arg = substream; | 315 | stream->stream_info.arg = substream; |
315 | stream->stream_info.buffer_ptr = 0; | 316 | stream->stream_info.buffer_ptr = 0; |
316 | stream->stream_info.sfreq = substream->runtime->rate; | 317 | stream->stream_info.sfreq = substream->runtime->rate; |
317 | ret_val = stream->ops->device_control( | 318 | ret_val = stream->ops->stream_init(sst->dev, &stream->stream_info); |
318 | SST_SND_STREAM_INIT, &stream->stream_info); | ||
319 | if (ret_val) | 319 | if (ret_val) |
320 | pr_err("control_set ret error %d\n", ret_val); | 320 | dev_err(rtd->dev, "control_set ret error %d\n", ret_val); |
321 | return ret_val; | 321 | return ret_val; |
322 | 322 | ||
323 | } | 323 | } |
324 | /* end -- helper functions */ | 324 | |
325 | static int power_up_sst(struct sst_runtime_stream *stream) | ||
326 | { | ||
327 | return stream->ops->power(sst->dev, true); | ||
328 | } | ||
329 | |||
330 | static void power_down_sst(struct sst_runtime_stream *stream) | ||
331 | { | ||
332 | stream->ops->power(sst->dev, false); | ||
333 | } | ||
325 | 334 | ||
326 | static int sst_media_open(struct snd_pcm_substream *substream, | 335 | static int sst_media_open(struct snd_pcm_substream *substream, |
327 | struct snd_soc_dai *dai) | 336 | struct snd_soc_dai *dai) |
@@ -339,7 +348,7 @@ static int sst_media_open(struct snd_pcm_substream *substream, | |||
339 | mutex_lock(&sst_lock); | 348 | mutex_lock(&sst_lock); |
340 | if (!sst || | 349 | if (!sst || |
341 | !try_module_get(sst->dev->driver->owner)) { | 350 | !try_module_get(sst->dev->driver->owner)) { |
342 | pr_err("no device available to run\n"); | 351 | dev_err(dai->dev, "no device available to run\n"); |
343 | ret_val = -ENODEV; | 352 | ret_val = -ENODEV; |
344 | goto out_ops; | 353 | goto out_ops; |
345 | } | 354 | } |
@@ -352,6 +361,10 @@ static int sst_media_open(struct snd_pcm_substream *substream, | |||
352 | /* allocate memory for SST API set */ | 361 | /* allocate memory for SST API set */ |
353 | runtime->private_data = stream; | 362 | runtime->private_data = stream; |
354 | 363 | ||
364 | ret_val = power_up_sst(stream); | ||
365 | if (ret_val < 0) | ||
366 | return ret_val; | ||
367 | |||
355 | /* Make sure, that the period size is always even */ | 368 | /* Make sure, that the period size is always even */ |
356 | snd_pcm_hw_constraint_step(substream->runtime, 0, | 369 | snd_pcm_hw_constraint_step(substream->runtime, 0, |
357 | SNDRV_PCM_HW_PARAM_PERIODS, 2); | 370 | SNDRV_PCM_HW_PARAM_PERIODS, 2); |
@@ -371,26 +384,29 @@ static void sst_media_close(struct snd_pcm_substream *substream, | |||
371 | int ret_val = 0, str_id; | 384 | int ret_val = 0, str_id; |
372 | 385 | ||
373 | stream = substream->runtime->private_data; | 386 | stream = substream->runtime->private_data; |
387 | power_down_sst(stream); | ||
388 | |||
374 | str_id = stream->stream_info.str_id; | 389 | str_id = stream->stream_info.str_id; |
375 | if (str_id) | 390 | if (str_id) |
376 | ret_val = stream->ops->close(str_id); | 391 | ret_val = stream->ops->close(sst->dev, str_id); |
377 | module_put(sst->dev->driver->owner); | 392 | module_put(sst->dev->driver->owner); |
378 | kfree(stream); | 393 | kfree(stream); |
379 | } | 394 | } |
380 | 395 | ||
381 | static inline unsigned int get_current_pipe_id(struct snd_soc_platform *platform, | 396 | static inline unsigned int get_current_pipe_id(struct snd_soc_dai *dai, |
382 | struct snd_pcm_substream *substream) | 397 | struct snd_pcm_substream *substream) |
383 | { | 398 | { |
384 | struct sst_data *sst = snd_soc_platform_get_drvdata(platform); | 399 | struct sst_data *sst = snd_soc_dai_get_drvdata(dai); |
385 | struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; | 400 | struct sst_dev_stream_map *map = sst->pdata->pdev_strm_map; |
386 | struct sst_runtime_stream *stream = | 401 | struct sst_runtime_stream *stream = |
387 | substream->runtime->private_data; | 402 | substream->runtime->private_data; |
388 | u32 str_id = stream->stream_info.str_id; | 403 | u32 str_id = stream->stream_info.str_id; |
389 | unsigned int pipe_id; | 404 | unsigned int pipe_id; |
405 | |||
390 | pipe_id = map[str_id].device_id; | 406 | pipe_id = map[str_id].device_id; |
391 | 407 | ||
392 | pr_debug("%s: got pipe_id = %#x for str_id = %d\n", | 408 | dev_dbg(dai->dev, "got pipe_id = %#x for str_id = %d\n", |
393 | __func__, pipe_id, str_id); | 409 | pipe_id, str_id); |
394 | return pipe_id; | 410 | return pipe_id; |
395 | } | 411 | } |
396 | 412 | ||
@@ -403,12 +419,11 @@ static int sst_media_prepare(struct snd_pcm_substream *substream, | |||
403 | stream = substream->runtime->private_data; | 419 | stream = substream->runtime->private_data; |
404 | str_id = stream->stream_info.str_id; | 420 | str_id = stream->stream_info.str_id; |
405 | if (stream->stream_info.str_id) { | 421 | if (stream->stream_info.str_id) { |
406 | ret_val = stream->ops->device_control( | 422 | ret_val = stream->ops->stream_drop(sst->dev, str_id); |
407 | SST_SND_DROP, &str_id); | ||
408 | return ret_val; | 423 | return ret_val; |
409 | } | 424 | } |
410 | 425 | ||
411 | ret_val = sst_platform_alloc_stream(substream, dai->platform); | 426 | ret_val = sst_platform_alloc_stream(substream, dai); |
412 | if (ret_val <= 0) | 427 | if (ret_val <= 0) |
413 | return ret_val; | 428 | return ret_val; |
414 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), | 429 | snprintf(substream->pcm->id, sizeof(substream->pcm->id), |
@@ -461,37 +476,40 @@ static int sst_platform_pcm_trigger(struct snd_pcm_substream *substream, | |||
461 | { | 476 | { |
462 | int ret_val = 0, str_id; | 477 | int ret_val = 0, str_id; |
463 | struct sst_runtime_stream *stream; | 478 | struct sst_runtime_stream *stream; |
464 | int str_cmd, status; | 479 | int status; |
480 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
465 | 481 | ||
466 | pr_debug("sst_platform_pcm_trigger called\n"); | 482 | dev_dbg(rtd->dev, "sst_platform_pcm_trigger called\n"); |
483 | if (substream->pcm->internal) | ||
484 | return 0; | ||
467 | stream = substream->runtime->private_data; | 485 | stream = substream->runtime->private_data; |
468 | str_id = stream->stream_info.str_id; | 486 | str_id = stream->stream_info.str_id; |
469 | switch (cmd) { | 487 | switch (cmd) { |
470 | case SNDRV_PCM_TRIGGER_START: | 488 | case SNDRV_PCM_TRIGGER_START: |
471 | pr_debug("sst: Trigger Start\n"); | 489 | dev_dbg(rtd->dev, "sst: Trigger Start\n"); |
472 | str_cmd = SST_SND_START; | ||
473 | status = SST_PLATFORM_RUNNING; | 490 | status = SST_PLATFORM_RUNNING; |
474 | stream->stream_info.arg = substream; | 491 | stream->stream_info.arg = substream; |
492 | ret_val = stream->ops->stream_start(sst->dev, str_id); | ||
475 | break; | 493 | break; |
476 | case SNDRV_PCM_TRIGGER_STOP: | 494 | case SNDRV_PCM_TRIGGER_STOP: |
477 | pr_debug("sst: in stop\n"); | 495 | dev_dbg(rtd->dev, "sst: in stop\n"); |
478 | str_cmd = SST_SND_DROP; | ||
479 | status = SST_PLATFORM_DROPPED; | 496 | status = SST_PLATFORM_DROPPED; |
497 | ret_val = stream->ops->stream_drop(sst->dev, str_id); | ||
480 | break; | 498 | break; |
481 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 499 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
482 | pr_debug("sst: in pause\n"); | 500 | dev_dbg(rtd->dev, "sst: in pause\n"); |
483 | str_cmd = SST_SND_PAUSE; | ||
484 | status = SST_PLATFORM_PAUSED; | 501 | status = SST_PLATFORM_PAUSED; |
502 | ret_val = stream->ops->stream_pause(sst->dev, str_id); | ||
485 | break; | 503 | break; |
486 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 504 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
487 | pr_debug("sst: in pause release\n"); | 505 | dev_dbg(rtd->dev, "sst: in pause release\n"); |
488 | str_cmd = SST_SND_RESUME; | ||
489 | status = SST_PLATFORM_RUNNING; | 506 | status = SST_PLATFORM_RUNNING; |
507 | ret_val = stream->ops->stream_pause_release(sst->dev, str_id); | ||
490 | break; | 508 | break; |
491 | default: | 509 | default: |
492 | return -EINVAL; | 510 | return -EINVAL; |
493 | } | 511 | } |
494 | ret_val = stream->ops->device_control(str_cmd, &str_id); | 512 | |
495 | if (!ret_val) | 513 | if (!ret_val) |
496 | sst_set_stream_status(stream, status); | 514 | sst_set_stream_status(stream, status); |
497 | 515 | ||
@@ -505,16 +523,16 @@ static snd_pcm_uframes_t sst_platform_pcm_pointer | |||
505 | struct sst_runtime_stream *stream; | 523 | struct sst_runtime_stream *stream; |
506 | int ret_val, status; | 524 | int ret_val, status; |
507 | struct pcm_stream_info *str_info; | 525 | struct pcm_stream_info *str_info; |
526 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
508 | 527 | ||
509 | stream = substream->runtime->private_data; | 528 | stream = substream->runtime->private_data; |
510 | status = sst_get_stream_status(stream); | 529 | status = sst_get_stream_status(stream); |
511 | if (status == SST_PLATFORM_INIT) | 530 | if (status == SST_PLATFORM_INIT) |
512 | return 0; | 531 | return 0; |
513 | str_info = &stream->stream_info; | 532 | str_info = &stream->stream_info; |
514 | ret_val = stream->ops->device_control( | 533 | ret_val = stream->ops->stream_read_tstamp(sst->dev, str_info); |
515 | SST_SND_BUFFER_POINTER, str_info); | ||
516 | if (ret_val) { | 534 | if (ret_val) { |
517 | pr_err("sst: error code = %d\n", ret_val); | 535 | dev_err(rtd->dev, "sst: error code = %d\n", ret_val); |
518 | return ret_val; | 536 | return ret_val; |
519 | } | 537 | } |
520 | substream->runtime->delay = str_info->pcm_delay; | 538 | substream->runtime->delay = str_info->pcm_delay; |
@@ -530,7 +548,7 @@ static struct snd_pcm_ops sst_platform_ops = { | |||
530 | 548 | ||
531 | static void sst_pcm_free(struct snd_pcm *pcm) | 549 | static void sst_pcm_free(struct snd_pcm *pcm) |
532 | { | 550 | { |
533 | pr_debug("sst_pcm_free called\n"); | 551 | dev_dbg(pcm->dev, "sst_pcm_free called\n"); |
534 | snd_pcm_lib_preallocate_free_for_all(pcm); | 552 | snd_pcm_lib_preallocate_free_for_all(pcm); |
535 | } | 553 | } |
536 | 554 | ||
@@ -547,14 +565,20 @@ static int sst_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
547 | snd_dma_continuous_data(GFP_DMA), | 565 | snd_dma_continuous_data(GFP_DMA), |
548 | SST_MIN_BUFFER, SST_MAX_BUFFER); | 566 | SST_MIN_BUFFER, SST_MAX_BUFFER); |
549 | if (retval) { | 567 | if (retval) { |
550 | pr_err("dma buffer allocationf fail\n"); | 568 | dev_err(rtd->dev, "dma buffer allocationf fail\n"); |
551 | return retval; | 569 | return retval; |
552 | } | 570 | } |
553 | } | 571 | } |
554 | return retval; | 572 | return retval; |
555 | } | 573 | } |
556 | 574 | ||
557 | static struct snd_soc_platform_driver sst_soc_platform_drv = { | 575 | static int sst_soc_probe(struct snd_soc_platform *platform) |
576 | { | ||
577 | return sst_dsp_init_v2_dpcm(platform); | ||
578 | } | ||
579 | |||
580 | static struct snd_soc_platform_driver sst_soc_platform_drv = { | ||
581 | .probe = sst_soc_probe, | ||
558 | .ops = &sst_platform_ops, | 582 | .ops = &sst_platform_ops, |
559 | .compr_ops = &sst_platform_compr_ops, | 583 | .compr_ops = &sst_platform_compr_ops, |
560 | .pcm_new = sst_pcm_new, | 584 | .pcm_new = sst_pcm_new, |
@@ -574,13 +598,11 @@ static int sst_platform_probe(struct platform_device *pdev) | |||
574 | 598 | ||
575 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); | 599 | drv = devm_kzalloc(&pdev->dev, sizeof(*drv), GFP_KERNEL); |
576 | if (drv == NULL) { | 600 | if (drv == NULL) { |
577 | pr_err("kzalloc failed\n"); | ||
578 | return -ENOMEM; | 601 | return -ENOMEM; |
579 | } | 602 | } |
580 | 603 | ||
581 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 604 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
582 | if (pdata == NULL) { | 605 | if (pdata == NULL) { |
583 | pr_err("kzalloc failed for pdata\n"); | ||
584 | return -ENOMEM; | 606 | return -ENOMEM; |
585 | } | 607 | } |
586 | 608 | ||
@@ -592,14 +614,14 @@ static int sst_platform_probe(struct platform_device *pdev) | |||
592 | 614 | ||
593 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); | 615 | ret = snd_soc_register_platform(&pdev->dev, &sst_soc_platform_drv); |
594 | if (ret) { | 616 | if (ret) { |
595 | pr_err("registering soc platform failed\n"); | 617 | dev_err(&pdev->dev, "registering soc platform failed\n"); |
596 | return ret; | 618 | return ret; |
597 | } | 619 | } |
598 | 620 | ||
599 | ret = snd_soc_register_component(&pdev->dev, &sst_component, | 621 | ret = snd_soc_register_component(&pdev->dev, &sst_component, |
600 | sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); | 622 | sst_platform_dai, ARRAY_SIZE(sst_platform_dai)); |
601 | if (ret) { | 623 | if (ret) { |
602 | pr_err("registering cpu dais failed\n"); | 624 | dev_err(&pdev->dev, "registering cpu dais failed\n"); |
603 | snd_soc_unregister_platform(&pdev->dev); | 625 | snd_soc_unregister_platform(&pdev->dev); |
604 | } | 626 | } |
605 | return ret; | 627 | return ret; |
@@ -610,7 +632,7 @@ static int sst_platform_remove(struct platform_device *pdev) | |||
610 | 632 | ||
611 | snd_soc_unregister_component(&pdev->dev); | 633 | snd_soc_unregister_component(&pdev->dev); |
612 | snd_soc_unregister_platform(&pdev->dev); | 634 | snd_soc_unregister_platform(&pdev->dev); |
613 | pr_debug("sst_platform_remove success\n"); | 635 | dev_dbg(&pdev->dev, "sst_platform_remove success\n"); |
614 | return 0; | 636 | return 0; |
615 | } | 637 | } |
616 | 638 | ||
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h index 6c6a42c08e24..19f83ec51613 100644 --- a/sound/soc/intel/sst-mfld-platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
@@ -54,20 +54,6 @@ enum sst_drv_status { | |||
54 | SST_PLATFORM_DROPPED, | 54 | SST_PLATFORM_DROPPED, |
55 | }; | 55 | }; |
56 | 56 | ||
57 | enum sst_controls { | ||
58 | SST_SND_ALLOC = 0x00, | ||
59 | SST_SND_PAUSE = 0x01, | ||
60 | SST_SND_RESUME = 0x02, | ||
61 | SST_SND_DROP = 0x03, | ||
62 | SST_SND_FREE = 0x04, | ||
63 | SST_SND_BUFFER_POINTER = 0x05, | ||
64 | SST_SND_STREAM_INIT = 0x06, | ||
65 | SST_SND_START = 0x07, | ||
66 | SST_SET_BYTE_STREAM = 0x100A, | ||
67 | SST_GET_BYTE_STREAM = 0x100B, | ||
68 | SST_MAX_CONTROLS = SST_GET_BYTE_STREAM, | ||
69 | }; | ||
70 | |||
71 | enum sst_stream_ops { | 57 | enum sst_stream_ops { |
72 | STREAM_OPS_PLAYBACK = 0, | 58 | STREAM_OPS_PLAYBACK = 0, |
73 | STREAM_OPS_CAPTURE, | 59 | STREAM_OPS_CAPTURE, |
@@ -113,24 +99,37 @@ struct sst_compress_cb { | |||
113 | 99 | ||
114 | struct compress_sst_ops { | 100 | struct compress_sst_ops { |
115 | const char *name; | 101 | const char *name; |
116 | int (*open) (struct snd_sst_params *str_params, | 102 | int (*open)(struct device *dev, |
117 | struct sst_compress_cb *cb); | 103 | struct snd_sst_params *str_params, struct sst_compress_cb *cb); |
118 | int (*control) (unsigned int cmd, unsigned int str_id); | 104 | int (*stream_start)(struct device *dev, unsigned int str_id); |
119 | int (*tstamp) (unsigned int str_id, struct snd_compr_tstamp *tstamp); | 105 | int (*stream_drop)(struct device *dev, unsigned int str_id); |
120 | int (*ack) (unsigned int str_id, unsigned long bytes); | 106 | int (*stream_drain)(struct device *dev, unsigned int str_id); |
121 | int (*close) (unsigned int str_id); | 107 | int (*stream_partial_drain)(struct device *dev, unsigned int str_id); |
122 | int (*get_caps) (struct snd_compr_caps *caps); | 108 | int (*stream_pause)(struct device *dev, unsigned int str_id); |
123 | int (*get_codec_caps) (struct snd_compr_codec_caps *codec); | 109 | int (*stream_pause_release)(struct device *dev, unsigned int str_id); |
124 | int (*set_metadata) (unsigned int str_id, | 110 | |
111 | int (*tstamp)(struct device *dev, unsigned int str_id, | ||
112 | struct snd_compr_tstamp *tstamp); | ||
113 | int (*ack)(struct device *dev, unsigned int str_id, | ||
114 | unsigned long bytes); | ||
115 | int (*close)(struct device *dev, unsigned int str_id); | ||
116 | int (*get_caps)(struct snd_compr_caps *caps); | ||
117 | int (*get_codec_caps)(struct snd_compr_codec_caps *codec); | ||
118 | int (*set_metadata)(struct device *dev, unsigned int str_id, | ||
125 | struct snd_compr_metadata *mdata); | 119 | struct snd_compr_metadata *mdata); |
126 | |||
127 | }; | 120 | }; |
128 | 121 | ||
129 | struct sst_ops { | 122 | struct sst_ops { |
130 | int (*open) (struct snd_sst_params *str_param); | 123 | int (*open)(struct device *dev, struct snd_sst_params *str_param); |
131 | int (*device_control) (int cmd, void *arg); | 124 | int (*stream_init)(struct device *dev, struct pcm_stream_info *str_info); |
132 | int (*set_generic_params)(enum sst_controls cmd, void *arg); | 125 | int (*stream_start)(struct device *dev, int str_id); |
133 | int (*close) (unsigned int str_id); | 126 | int (*stream_drop)(struct device *dev, int str_id); |
127 | int (*stream_pause)(struct device *dev, int str_id); | ||
128 | int (*stream_pause_release)(struct device *dev, int str_id); | ||
129 | int (*stream_read_tstamp)(struct device *dev, struct pcm_stream_info *str_info); | ||
130 | int (*send_byte_stream)(struct device *dev, struct snd_sst_bytes_v2 *bytes); | ||
131 | int (*close)(struct device *dev, unsigned int str_id); | ||
132 | int (*power)(struct device *dev, bool state); | ||
134 | }; | 133 | }; |
135 | 134 | ||
136 | struct sst_runtime_stream { | 135 | struct sst_runtime_stream { |
@@ -152,6 +151,8 @@ struct sst_device { | |||
152 | }; | 151 | }; |
153 | 152 | ||
154 | struct sst_data; | 153 | struct sst_data; |
154 | |||
155 | int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform); | ||
155 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); | 156 | void sst_set_stream_status(struct sst_runtime_stream *stream, int state); |
156 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, | 157 | int sst_fill_stream_params(void *substream, const struct sst_data *ctx, |
157 | struct snd_sst_params *str_params, bool is_compress); | 158 | struct snd_sst_params *str_params, bool is_compress); |
@@ -166,6 +167,7 @@ struct sst_algo_int_control_v2 { | |||
166 | struct sst_data { | 167 | struct sst_data { |
167 | struct platform_device *pdev; | 168 | struct platform_device *pdev; |
168 | struct sst_platform_data *pdata; | 169 | struct sst_platform_data *pdata; |
170 | struct snd_sst_bytes_v2 *byte_stream; | ||
169 | struct mutex lock; | 171 | struct mutex lock; |
170 | }; | 172 | }; |
171 | int sst_register_dsp(struct sst_device *sst); | 173 | int sst_register_dsp(struct sst_device *sst); |
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c index f8a6adc2d81c..4336d1831485 100644 --- a/sound/soc/omap/omap-twl4030.c +++ b/sound/soc/omap/omap-twl4030.c | |||
@@ -260,7 +260,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = { | |||
260 | .stream_name = "TWL4030 Voice", | 260 | .stream_name = "TWL4030 Voice", |
261 | .cpu_dai_name = "omap-mcbsp.3", | 261 | .cpu_dai_name = "omap-mcbsp.3", |
262 | .codec_dai_name = "twl4030-voice", | 262 | .codec_dai_name = "twl4030-voice", |
263 | .platform_name = "omap-mcbsp.2", | 263 | .platform_name = "omap-mcbsp.3", |
264 | .codec_name = "twl4030-codec", | 264 | .codec_name = "twl4030-codec", |
265 | .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | | 265 | .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | |
266 | SND_SOC_DAIFMT_CBM_CFM, | 266 | SND_SOC_DAIFMT_CBM_CFM, |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 943922c79f78..b10ae8074461 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
@@ -168,7 +168,7 @@ static int rx51_spk_event(struct snd_soc_dapm_widget *w, | |||
168 | static int rx51_hp_event(struct snd_soc_dapm_widget *w, | 168 | static int rx51_hp_event(struct snd_soc_dapm_widget *w, |
169 | struct snd_kcontrol *k, int event) | 169 | struct snd_kcontrol *k, int event) |
170 | { | 170 | { |
171 | struct snd_soc_codec *codec = w->dapm->codec; | 171 | struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); |
172 | 172 | ||
173 | if (SND_SOC_DAPM_EVENT_ON(event)) | 173 | if (SND_SOC_DAPM_EVENT_ON(event)) |
174 | tpa6130a2_stereo_enable(codec, 1); | 174 | tpa6130a2_stereo_enable(codec, 1); |
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index 0109f6c2334e..a8e097433074 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c | |||
@@ -765,9 +765,7 @@ static int pxa_ssp_remove(struct snd_soc_dai *dai) | |||
765 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ | 765 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | \ |
766 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) | 766 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) |
767 | 767 | ||
768 | #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ | 768 | #define PXA_SSP_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE) |
769 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
770 | SNDRV_PCM_FMTBIT_S32_LE) | ||
771 | 769 | ||
772 | static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { | 770 | static const struct snd_soc_dai_ops pxa_ssp_dai_ops = { |
773 | .startup = pxa_ssp_startup, | 771 | .startup = pxa_ssp_startup, |
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index c196a466eef6..78fc159559b0 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig | |||
@@ -2,11 +2,10 @@ config SND_SOC_ROCKCHIP | |||
2 | tristate "ASoC support for Rockchip" | 2 | tristate "ASoC support for Rockchip" |
3 | depends on COMPILE_TEST || ARCH_ROCKCHIP | 3 | depends on COMPILE_TEST || ARCH_ROCKCHIP |
4 | select SND_SOC_GENERIC_DMAENGINE_PCM | 4 | select SND_SOC_GENERIC_DMAENGINE_PCM |
5 | select SND_ROCKCHIP_I2S | ||
6 | help | 5 | help |
7 | Say Y or M if you want to add support for codecs attached to | 6 | Say Y or M if you want to add support for codecs attached to |
8 | the Rockchip SoCs' Audio interfaces. You will also need to | 7 | the Rockchip SoCs' Audio interfaces. You will also need to |
9 | select the audio interfaces to support below. | 8 | select the audio interfaces to support below. |
10 | 9 | ||
11 | config SND_ROCKCHIP_I2S | 10 | config SND_SOC_ROCKCHIP_I2S |
12 | tristate | 11 | tristate |
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index 1006418e1394..b9219092b47f 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | # ROCKCHIP Platform Support | 1 | # ROCKCHIP Platform Support |
2 | snd-soc-i2s-objs := rockchip_i2s.o | 2 | snd-soc-i2s-objs := rockchip_i2s.o |
3 | 3 | ||
4 | obj-$(CONFIG_SND_ROCKCHIP_I2S) += snd-soc-i2s.o | 4 | obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o |
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 8d8e4b59049f..033487c9a164 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c | |||
@@ -165,13 +165,14 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
165 | struct rk_i2s_dev *i2s = to_info(cpu_dai); | 165 | struct rk_i2s_dev *i2s = to_info(cpu_dai); |
166 | unsigned int mask = 0, val = 0; | 166 | unsigned int mask = 0, val = 0; |
167 | 167 | ||
168 | mask = I2S_CKR_MSS_SLAVE; | 168 | mask = I2S_CKR_MSS_MASK; |
169 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 169 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
170 | case SND_SOC_DAIFMT_CBS_CFS: | 170 | case SND_SOC_DAIFMT_CBS_CFS: |
171 | val = I2S_CKR_MSS_SLAVE; | 171 | /* Set source clock in Master mode */ |
172 | val = I2S_CKR_MSS_MASTER; | ||
172 | break; | 173 | break; |
173 | case SND_SOC_DAIFMT_CBM_CFM: | 174 | case SND_SOC_DAIFMT_CBM_CFM: |
174 | val = I2S_CKR_MSS_MASTER; | 175 | val = I2S_CKR_MSS_SLAVE; |
175 | break; | 176 | break; |
176 | default: | 177 | default: |
177 | return -EINVAL; | 178 | return -EINVAL; |
@@ -243,16 +244,6 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, | |||
243 | regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val); | 244 | regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val); |
244 | regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val); | 245 | regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val); |
245 | 246 | ||
246 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
247 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
248 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, | ||
249 | I2S_DMACR_TDL(1) | I2S_DMACR_TDE_ENABLE); | ||
250 | } else { | ||
251 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
252 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, | ||
253 | I2S_DMACR_RDL(1) | I2S_DMACR_RDE_ENABLE); | ||
254 | } | ||
255 | |||
256 | return 0; | 247 | return 0; |
257 | } | 248 | } |
258 | 249 | ||
@@ -300,6 +291,16 @@ static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, | |||
300 | return ret; | 291 | return ret; |
301 | } | 292 | } |
302 | 293 | ||
294 | static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai) | ||
295 | { | ||
296 | struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai); | ||
297 | |||
298 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
299 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
303 | static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { | 304 | static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { |
304 | .hw_params = rockchip_i2s_hw_params, | 305 | .hw_params = rockchip_i2s_hw_params, |
305 | .set_sysclk = rockchip_i2s_set_sysclk, | 306 | .set_sysclk = rockchip_i2s_set_sysclk, |
@@ -308,7 +309,9 @@ static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { | |||
308 | }; | 309 | }; |
309 | 310 | ||
310 | static struct snd_soc_dai_driver rockchip_i2s_dai = { | 311 | static struct snd_soc_dai_driver rockchip_i2s_dai = { |
312 | .probe = rockchip_i2s_dai_probe, | ||
311 | .playback = { | 313 | .playback = { |
314 | .stream_name = "Playback", | ||
312 | .channels_min = 2, | 315 | .channels_min = 2, |
313 | .channels_max = 8, | 316 | .channels_max = 8, |
314 | .rates = SNDRV_PCM_RATE_8000_192000, | 317 | .rates = SNDRV_PCM_RATE_8000_192000, |
@@ -318,6 +321,7 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = { | |||
318 | SNDRV_PCM_FMTBIT_S24_LE), | 321 | SNDRV_PCM_FMTBIT_S24_LE), |
319 | }, | 322 | }, |
320 | .capture = { | 323 | .capture = { |
324 | .stream_name = "Capture", | ||
321 | .channels_min = 2, | 325 | .channels_min = 2, |
322 | .channels_max = 2, | 326 | .channels_max = 2, |
323 | .rates = SNDRV_PCM_RATE_8000_192000, | 327 | .rates = SNDRV_PCM_RATE_8000_192000, |
@@ -361,6 +365,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) | |||
361 | case I2S_XFER: | 365 | case I2S_XFER: |
362 | case I2S_CLR: | 366 | case I2S_CLR: |
363 | case I2S_RXDR: | 367 | case I2S_RXDR: |
368 | case I2S_FIFOLR: | ||
369 | case I2S_INTSR: | ||
364 | return true; | 370 | return true; |
365 | default: | 371 | default: |
366 | return false; | 372 | return false; |
@@ -370,8 +376,8 @@ static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) | |||
370 | static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) | 376 | static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) |
371 | { | 377 | { |
372 | switch (reg) { | 378 | switch (reg) { |
373 | case I2S_FIFOLR: | ||
374 | case I2S_INTSR: | 379 | case I2S_INTSR: |
380 | case I2S_CLR: | ||
375 | return true; | 381 | return true; |
376 | default: | 382 | default: |
377 | return false; | 383 | return false; |
@@ -381,8 +387,6 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) | |||
381 | static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) | 387 | static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) |
382 | { | 388 | { |
383 | switch (reg) { | 389 | switch (reg) { |
384 | case I2S_FIFOLR: | ||
385 | return true; | ||
386 | default: | 390 | default: |
387 | return false; | 391 | return false; |
388 | } | 392 | } |
@@ -419,6 +423,11 @@ static int rockchip_i2s_probe(struct platform_device *pdev) | |||
419 | dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); | 423 | dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); |
420 | return PTR_ERR(i2s->hclk); | 424 | return PTR_ERR(i2s->hclk); |
421 | } | 425 | } |
426 | ret = clk_prepare_enable(i2s->hclk); | ||
427 | if (ret) { | ||
428 | dev_err(i2s->dev, "hclock enable failed %d\n", ret); | ||
429 | return ret; | ||
430 | } | ||
422 | 431 | ||
423 | i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); | 432 | i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); |
424 | if (IS_ERR(i2s->mclk)) { | 433 | if (IS_ERR(i2s->mclk)) { |
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 03eec22f0f46..9d513473b300 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c | |||
@@ -462,7 +462,7 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, | |||
462 | if (dir == SND_SOC_CLOCK_IN) | 462 | if (dir == SND_SOC_CLOCK_IN) |
463 | rfs = 0; | 463 | rfs = 0; |
464 | 464 | ||
465 | if ((rfs && other->rfs && (other->rfs != rfs)) || | 465 | if ((rfs && other && other->rfs && (other->rfs != rfs)) || |
466 | (any_active(i2s) && | 466 | (any_active(i2s) && |
467 | (((dir == SND_SOC_CLOCK_IN) | 467 | (((dir == SND_SOC_CLOCK_IN) |
468 | && !(mod & MOD_CDCLKCON)) || | 468 | && !(mod & MOD_CDCLKCON)) || |
@@ -762,7 +762,8 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, | |||
762 | } else { | 762 | } else { |
763 | u32 mod = readl(i2s->addr + I2SMOD); | 763 | u32 mod = readl(i2s->addr + I2SMOD); |
764 | i2s->cdclk_out = !(mod & MOD_CDCLKCON); | 764 | i2s->cdclk_out = !(mod & MOD_CDCLKCON); |
765 | other->cdclk_out = i2s->cdclk_out; | 765 | if (other) |
766 | other->cdclk_out = i2s->cdclk_out; | ||
766 | } | 767 | } |
767 | /* Reset any constraint on RFS and BFS */ | 768 | /* Reset any constraint on RFS and BFS */ |
768 | i2s->rfs = 0; | 769 | i2s->rfs = 0; |
diff --git a/sound/soc/samsung/idma.c b/sound/soc/samsung/idma.c index db6cefa18017..0e8dd985fcb3 100644 --- a/sound/soc/samsung/idma.c +++ b/sound/soc/samsung/idma.c | |||
@@ -351,7 +351,7 @@ static void idma_free(struct snd_pcm *pcm) | |||
351 | if (!buf->area) | 351 | if (!buf->area) |
352 | return; | 352 | return; |
353 | 353 | ||
354 | iounmap(buf->area); | 354 | iounmap((void __iomem *)buf->area); |
355 | 355 | ||
356 | buf->area = NULL; | 356 | buf->area = NULL; |
357 | buf->addr = 0; | 357 | buf->addr = 0; |
@@ -369,7 +369,7 @@ static int preallocate_idma_buffer(struct snd_pcm *pcm, int stream) | |||
369 | buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS; | 369 | buf->dev.type = SNDRV_DMA_TYPE_CONTINUOUS; |
370 | buf->addr = idma.lp_tx_addr; | 370 | buf->addr = idma.lp_tx_addr; |
371 | buf->bytes = idma_hardware.buffer_bytes_max; | 371 | buf->bytes = idma_hardware.buffer_bytes_max; |
372 | buf->area = (unsigned char *)ioremap(buf->addr, buf->bytes); | 372 | buf->area = (unsigned char * __force)ioremap(buf->addr, buf->bytes); |
373 | 373 | ||
374 | return 0; | 374 | return 0; |
375 | } | 375 | } |
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c index 278edf9e2a87..3c8f60423e82 100644 --- a/sound/soc/samsung/odroidx2_max98090.c +++ b/sound/soc/samsung/odroidx2_max98090.c | |||
@@ -66,12 +66,12 @@ static struct snd_soc_card odroidx2 = { | |||
66 | .late_probe = odroidx2_late_probe, | 66 | .late_probe = odroidx2_late_probe, |
67 | }; | 67 | }; |
68 | 68 | ||
69 | struct odroidx2_drv_data odroidx2_drvdata = { | 69 | static const struct odroidx2_drv_data odroidx2_drvdata = { |
70 | .dapm_widgets = odroidx2_dapm_widgets, | 70 | .dapm_widgets = odroidx2_dapm_widgets, |
71 | .num_dapm_widgets = ARRAY_SIZE(odroidx2_dapm_widgets), | 71 | .num_dapm_widgets = ARRAY_SIZE(odroidx2_dapm_widgets), |
72 | }; | 72 | }; |
73 | 73 | ||
74 | struct odroidx2_drv_data odroidu3_drvdata = { | 74 | static const struct odroidx2_drv_data odroidu3_drvdata = { |
75 | .dapm_widgets = odroidu3_dapm_widgets, | 75 | .dapm_widgets = odroidu3_dapm_widgets, |
76 | .num_dapm_widgets = ARRAY_SIZE(odroidu3_dapm_widgets), | 76 | .num_dapm_widgets = ARRAY_SIZE(odroidu3_dapm_widgets), |
77 | }; | 77 | }; |
diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 9902efcb8ea1..a05482651aae 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c | |||
@@ -228,10 +228,12 @@ static struct snd_soc_dai_link speyside_dai[] = { | |||
228 | }, | 228 | }, |
229 | }; | 229 | }; |
230 | 230 | ||
231 | static int speyside_wm9081_init(struct snd_soc_dapm_context *dapm) | 231 | static int speyside_wm9081_init(struct snd_soc_component *component) |
232 | { | 232 | { |
233 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); | ||
234 | |||
233 | /* At any time the WM9081 is active it will have this clock */ | 235 | /* At any time the WM9081 is active it will have this clock */ |
234 | return snd_soc_codec_set_sysclk(dapm->codec, WM9081_SYSCLK_MCLK, 0, | 236 | return snd_soc_codec_set_sysclk(codec, WM9081_SYSCLK_MCLK, 0, |
235 | MCLK_AUDIO_RATE, 0); | 237 | MCLK_AUDIO_RATE, 0); |
236 | } | 238 | } |
237 | 239 | ||
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index c76344350e44..66fddec9543d 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c | |||
@@ -1297,9 +1297,14 @@ static int fsi_dma_transfer(struct fsi_priv *fsi, struct fsi_stream *io) | |||
1297 | struct snd_pcm_substream *substream = io->substream; | 1297 | struct snd_pcm_substream *substream = io->substream; |
1298 | struct dma_async_tx_descriptor *desc; | 1298 | struct dma_async_tx_descriptor *desc; |
1299 | int is_play = fsi_stream_is_play(fsi, io); | 1299 | int is_play = fsi_stream_is_play(fsi, io); |
1300 | enum dma_data_direction dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 1300 | enum dma_transfer_direction dir; |
1301 | int ret = -EIO; | 1301 | int ret = -EIO; |
1302 | 1302 | ||
1303 | if (is_play) | ||
1304 | dir = DMA_MEM_TO_DEV; | ||
1305 | else | ||
1306 | dir = DMA_DEV_TO_MEM; | ||
1307 | |||
1303 | desc = dmaengine_prep_dma_cyclic(io->chan, | 1308 | desc = dmaengine_prep_dma_cyclic(io->chan, |
1304 | substream->runtime->dma_addr, | 1309 | substream->runtime->dma_addr, |
1305 | snd_pcm_lib_buffer_bytes(substream), | 1310 | snd_pcm_lib_buffer_bytes(substream), |
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 19f78963e8b9..1922ec57d10a 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -798,10 +798,8 @@ if (name##_node) { \ | |||
798 | mod_parse(src); | 798 | mod_parse(src); |
799 | mod_parse(dvc); | 799 | mod_parse(dvc); |
800 | 800 | ||
801 | if (playback) | 801 | of_node_put(playback); |
802 | of_node_put(playback); | 802 | of_node_put(capture); |
803 | if (capture) | ||
804 | of_node_put(capture); | ||
805 | } | 803 | } |
806 | 804 | ||
807 | dai_i++; | 805 | dai_i++; |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 3fdf3be7b99a..f95e7ab135e8 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -247,7 +247,7 @@ rsnd_gen2_dma_addr(struct rsnd_priv *priv, | |||
247 | }; | 247 | }; |
248 | 248 | ||
249 | /* it shouldn't happen */ | 249 | /* it shouldn't happen */ |
250 | if (use_dvc & !use_src) | 250 | if (use_dvc && !use_src) |
251 | dev_err(dev, "DVC is selected without SRC\n"); | 251 | dev_err(dev, "DVC is selected without SRC\n"); |
252 | 252 | ||
253 | /* use SSIU or SSI ? */ | 253 | /* use SSIU or SSI ? */ |
diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index 488f9becb44f..32eb6da2d2bd 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c | |||
@@ -139,7 +139,7 @@ static int siu_pcm_wr_set(struct siu_port *port_info, | |||
139 | 139 | ||
140 | desc->callback = siu_dma_tx_complete; | 140 | desc->callback = siu_dma_tx_complete; |
141 | desc->callback_param = siu_stream; | 141 | desc->callback_param = siu_stream; |
142 | cookie = desc->tx_submit(desc); | 142 | cookie = dmaengine_submit(desc); |
143 | if (cookie < 0) { | 143 | if (cookie < 0) { |
144 | dev_err(dev, "Failed to submit a dma transfer\n"); | 144 | dev_err(dev, "Failed to submit a dma transfer\n"); |
145 | return cookie; | 145 | return cookie; |
@@ -189,7 +189,7 @@ static int siu_pcm_rd_set(struct siu_port *port_info, | |||
189 | 189 | ||
190 | desc->callback = siu_dma_tx_complete; | 190 | desc->callback = siu_dma_tx_complete; |
191 | desc->callback_param = siu_stream; | 191 | desc->callback_param = siu_stream; |
192 | cookie = desc->tx_submit(desc); | 192 | cookie = dmaengine_submit(desc); |
193 | if (cookie < 0) { | 193 | if (cookie < 0) { |
194 | dev_err(dev, "Failed to submit dma descriptor\n"); | 194 | dev_err(dev, "Failed to submit dma descriptor\n"); |
195 | return cookie; | 195 | return cookie; |
diff --git a/sound/soc/sirf/sirf-usp.c b/sound/soc/sirf/sirf-usp.c index 3a730374e259..186dc7f33a55 100644 --- a/sound/soc/sirf/sirf-usp.c +++ b/sound/soc/sirf/sirf-usp.c | |||
@@ -100,6 +100,16 @@ static int sirf_usp_pcm_set_dai_fmt(struct snd_soc_dai *dai, | |||
100 | return -EINVAL; | 100 | return -EINVAL; |
101 | } | 101 | } |
102 | 102 | ||
103 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
104 | case SND_SOC_DAIFMT_NB_NF: | ||
105 | break; | ||
106 | case SND_SOC_DAIFMT_IB_NF: | ||
107 | usp->daifmt_format |= (fmt & SND_SOC_DAIFMT_INV_MASK); | ||
108 | break; | ||
109 | default: | ||
110 | return -EINVAL; | ||
111 | } | ||
112 | |||
103 | return 0; | 113 | return 0; |
104 | } | 114 | } |
105 | 115 | ||
@@ -177,7 +187,7 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, | |||
177 | 187 | ||
178 | shifter_len = data_len; | 188 | shifter_len = data_len; |
179 | 189 | ||
180 | switch (usp->daifmt_format) { | 190 | switch (usp->daifmt_format & SND_SOC_DAIFMT_FORMAT_MASK) { |
181 | case SND_SOC_DAIFMT_I2S: | 191 | case SND_SOC_DAIFMT_I2S: |
182 | regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, | 192 | regmap_update_bits(usp->regmap, USP_RX_FRAME_CTRL, |
183 | USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG); | 193 | USP_I2S_SYNC_CHG, USP_I2S_SYNC_CHG); |
@@ -193,6 +203,18 @@ static int sirf_usp_pcm_hw_params(struct snd_pcm_substream *substream, | |||
193 | return -EINVAL; | 203 | return -EINVAL; |
194 | } | 204 | } |
195 | 205 | ||
206 | switch (usp->daifmt_format & SND_SOC_DAIFMT_INV_MASK) { | ||
207 | case SND_SOC_DAIFMT_NB_NF: | ||
208 | break; | ||
209 | case SND_SOC_DAIFMT_IB_NF: | ||
210 | regmap_update_bits(usp->regmap, USP_MODE1, | ||
211 | USP_RXD_ACT_EDGE_FALLING | USP_TXD_ACT_EDGE_FALLING, | ||
212 | USP_RXD_ACT_EDGE_FALLING); | ||
213 | break; | ||
214 | default: | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
196 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 218 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
197 | regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL, | 219 | regmap_update_bits(usp->regmap, USP_TX_FRAME_CTRL, |
198 | USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK | 220 | USP_TXC_DATA_LEN_MASK | USP_TXC_FRAME_LEN_MASK |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 27c06acce205..cecfab3cc948 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -101,10 +101,12 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
101 | 101 | ||
102 | fe->dpcm[stream].runtime = fe_substream->runtime; | 102 | fe->dpcm[stream].runtime = fe_substream->runtime; |
103 | 103 | ||
104 | if (dpcm_path_get(fe, stream, &list) <= 0) { | 104 | ret = dpcm_path_get(fe, stream, &list); |
105 | if (ret < 0) | ||
106 | goto fe_err; | ||
107 | else if (ret == 0) | ||
105 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", | 108 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", |
106 | fe->dai_link->name, stream ? "capture" : "playback"); | 109 | fe->dai_link->name, stream ? "capture" : "playback"); |
107 | } | ||
108 | 110 | ||
109 | /* calculate valid and active FE <-> BE dpcms */ | 111 | /* calculate valid and active FE <-> BE dpcms */ |
110 | dpcm_process_paths(fe, stream, &list, 1); | 112 | dpcm_process_paths(fe, stream, &list, 1); |
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d4bfd4a9076f..3d8cff629a18 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -270,79 +270,54 @@ static const struct file_operations codec_reg_fops = { | |||
270 | .llseek = default_llseek, | 270 | .llseek = default_llseek, |
271 | }; | 271 | }; |
272 | 272 | ||
273 | static struct dentry *soc_debugfs_create_dir(struct dentry *parent, | 273 | static void soc_init_component_debugfs(struct snd_soc_component *component) |
274 | const char *fmt, ...) | ||
275 | { | 274 | { |
276 | struct dentry *de; | 275 | if (component->debugfs_prefix) { |
277 | va_list ap; | 276 | char *name; |
278 | char *s; | ||
279 | 277 | ||
280 | va_start(ap, fmt); | 278 | name = kasprintf(GFP_KERNEL, "%s:%s", |
281 | s = kvasprintf(GFP_KERNEL, fmt, ap); | 279 | component->debugfs_prefix, component->name); |
282 | va_end(ap); | 280 | if (name) { |
281 | component->debugfs_root = debugfs_create_dir(name, | ||
282 | component->card->debugfs_card_root); | ||
283 | kfree(name); | ||
284 | } | ||
285 | } else { | ||
286 | component->debugfs_root = debugfs_create_dir(component->name, | ||
287 | component->card->debugfs_card_root); | ||
288 | } | ||
283 | 289 | ||
284 | if (!s) | 290 | if (!component->debugfs_root) { |
285 | return NULL; | 291 | dev_warn(component->dev, |
292 | "ASoC: Failed to create component debugfs directory\n"); | ||
293 | return; | ||
294 | } | ||
286 | 295 | ||
287 | de = debugfs_create_dir(s, parent); | 296 | snd_soc_dapm_debugfs_init(snd_soc_component_get_dapm(component), |
288 | kfree(s); | 297 | component->debugfs_root); |
289 | 298 | ||
290 | return de; | 299 | if (component->init_debugfs) |
300 | component->init_debugfs(component); | ||
291 | } | 301 | } |
292 | 302 | ||
293 | static void soc_init_codec_debugfs(struct snd_soc_codec *codec) | 303 | static void soc_cleanup_component_debugfs(struct snd_soc_component *component) |
294 | { | 304 | { |
295 | struct dentry *debugfs_card_root = codec->component.card->debugfs_card_root; | 305 | debugfs_remove_recursive(component->debugfs_root); |
306 | } | ||
296 | 307 | ||
297 | codec->debugfs_codec_root = soc_debugfs_create_dir(debugfs_card_root, | 308 | static void soc_init_codec_debugfs(struct snd_soc_component *component) |
298 | "codec:%s", | 309 | { |
299 | codec->component.name); | 310 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); |
300 | if (!codec->debugfs_codec_root) { | ||
301 | dev_warn(codec->dev, | ||
302 | "ASoC: Failed to create codec debugfs directory\n"); | ||
303 | return; | ||
304 | } | ||
305 | 311 | ||
306 | debugfs_create_bool("cache_sync", 0444, codec->debugfs_codec_root, | 312 | debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root, |
307 | &codec->cache_sync); | 313 | &codec->cache_sync); |
308 | debugfs_create_bool("cache_only", 0444, codec->debugfs_codec_root, | ||
309 | &codec->cache_only); | ||
310 | 314 | ||
311 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, | 315 | codec->debugfs_reg = debugfs_create_file("codec_reg", 0644, |
312 | codec->debugfs_codec_root, | 316 | codec->component.debugfs_root, |
313 | codec, &codec_reg_fops); | 317 | codec, &codec_reg_fops); |
314 | if (!codec->debugfs_reg) | 318 | if (!codec->debugfs_reg) |
315 | dev_warn(codec->dev, | 319 | dev_warn(codec->dev, |
316 | "ASoC: Failed to create codec register debugfs file\n"); | 320 | "ASoC: Failed to create codec register debugfs file\n"); |
317 | |||
318 | snd_soc_dapm_debugfs_init(&codec->dapm, codec->debugfs_codec_root); | ||
319 | } | ||
320 | |||
321 | static void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | ||
322 | { | ||
323 | debugfs_remove_recursive(codec->debugfs_codec_root); | ||
324 | } | ||
325 | |||
326 | static void soc_init_platform_debugfs(struct snd_soc_platform *platform) | ||
327 | { | ||
328 | struct dentry *debugfs_card_root = platform->component.card->debugfs_card_root; | ||
329 | |||
330 | platform->debugfs_platform_root = soc_debugfs_create_dir(debugfs_card_root, | ||
331 | "platform:%s", | ||
332 | platform->component.name); | ||
333 | if (!platform->debugfs_platform_root) { | ||
334 | dev_warn(platform->dev, | ||
335 | "ASoC: Failed to create platform debugfs directory\n"); | ||
336 | return; | ||
337 | } | ||
338 | |||
339 | snd_soc_dapm_debugfs_init(&platform->component.dapm, | ||
340 | platform->debugfs_platform_root); | ||
341 | } | ||
342 | |||
343 | static void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) | ||
344 | { | ||
345 | debugfs_remove_recursive(platform->debugfs_platform_root); | ||
346 | } | 321 | } |
347 | 322 | ||
348 | static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, | 323 | static ssize_t codec_list_read_file(struct file *file, char __user *user_buf, |
@@ -474,19 +449,15 @@ static void soc_cleanup_card_debugfs(struct snd_soc_card *card) | |||
474 | 449 | ||
475 | #else | 450 | #else |
476 | 451 | ||
477 | static inline void soc_init_codec_debugfs(struct snd_soc_codec *codec) | 452 | #define soc_init_codec_debugfs NULL |
478 | { | ||
479 | } | ||
480 | |||
481 | static inline void soc_cleanup_codec_debugfs(struct snd_soc_codec *codec) | ||
482 | { | ||
483 | } | ||
484 | 453 | ||
485 | static inline void soc_init_platform_debugfs(struct snd_soc_platform *platform) | 454 | static inline void soc_init_component_debugfs( |
455 | struct snd_soc_component *component) | ||
486 | { | 456 | { |
487 | } | 457 | } |
488 | 458 | ||
489 | static inline void soc_cleanup_platform_debugfs(struct snd_soc_platform *platform) | 459 | static inline void soc_cleanup_component_debugfs( |
460 | struct snd_soc_component *component) | ||
490 | { | 461 | { |
491 | } | 462 | } |
492 | 463 | ||
@@ -579,10 +550,8 @@ int snd_soc_suspend(struct device *dev) | |||
579 | struct snd_soc_codec *codec; | 550 | struct snd_soc_codec *codec; |
580 | int i, j; | 551 | int i, j; |
581 | 552 | ||
582 | /* If the initialization of this soc device failed, there is no codec | 553 | /* If the card is not initialized yet there is nothing to do */ |
583 | * associated with it. Just bail out in this case. | 554 | if (!card->instantiated) |
584 | */ | ||
585 | if (list_empty(&card->codec_dev_list)) | ||
586 | return 0; | 555 | return 0; |
587 | 556 | ||
588 | /* Due to the resume being scheduled into a workqueue we could | 557 | /* Due to the resume being scheduled into a workqueue we could |
@@ -668,7 +637,7 @@ int snd_soc_suspend(struct device *dev) | |||
668 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | 637 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { |
669 | /* If there are paths active then the CODEC will be held with | 638 | /* If there are paths active then the CODEC will be held with |
670 | * bias _ON and should not be suspended. */ | 639 | * bias _ON and should not be suspended. */ |
671 | if (!codec->suspended && codec->driver->suspend) { | 640 | if (!codec->suspended) { |
672 | switch (codec->dapm.bias_level) { | 641 | switch (codec->dapm.bias_level) { |
673 | case SND_SOC_BIAS_STANDBY: | 642 | case SND_SOC_BIAS_STANDBY: |
674 | /* | 643 | /* |
@@ -682,8 +651,10 @@ int snd_soc_suspend(struct device *dev) | |||
682 | "ASoC: idle_bias_off CODEC on over suspend\n"); | 651 | "ASoC: idle_bias_off CODEC on over suspend\n"); |
683 | break; | 652 | break; |
684 | } | 653 | } |
654 | |||
685 | case SND_SOC_BIAS_OFF: | 655 | case SND_SOC_BIAS_OFF: |
686 | codec->driver->suspend(codec); | 656 | if (codec->driver->suspend) |
657 | codec->driver->suspend(codec); | ||
687 | codec->suspended = 1; | 658 | codec->suspended = 1; |
688 | codec->cache_sync = 1; | 659 | codec->cache_sync = 1; |
689 | if (codec->component.regmap) | 660 | if (codec->component.regmap) |
@@ -757,11 +728,12 @@ static void soc_resume_deferred(struct work_struct *work) | |||
757 | * left with bias OFF or STANDBY and suspended so we must now | 728 | * left with bias OFF or STANDBY and suspended so we must now |
758 | * resume. Otherwise the suspend was suppressed. | 729 | * resume. Otherwise the suspend was suppressed. |
759 | */ | 730 | */ |
760 | if (codec->driver->resume && codec->suspended) { | 731 | if (codec->suspended) { |
761 | switch (codec->dapm.bias_level) { | 732 | switch (codec->dapm.bias_level) { |
762 | case SND_SOC_BIAS_STANDBY: | 733 | case SND_SOC_BIAS_STANDBY: |
763 | case SND_SOC_BIAS_OFF: | 734 | case SND_SOC_BIAS_OFF: |
764 | codec->driver->resume(codec); | 735 | if (codec->driver->resume) |
736 | codec->driver->resume(codec); | ||
765 | codec->suspended = 0; | 737 | codec->suspended = 0; |
766 | break; | 738 | break; |
767 | default: | 739 | default: |
@@ -835,10 +807,8 @@ int snd_soc_resume(struct device *dev) | |||
835 | struct snd_soc_card *card = dev_get_drvdata(dev); | 807 | struct snd_soc_card *card = dev_get_drvdata(dev); |
836 | int i, ac97_control = 0; | 808 | int i, ac97_control = 0; |
837 | 809 | ||
838 | /* If the initialization of this soc device failed, there is no codec | 810 | /* If the card is not initialized yet there is nothing to do */ |
839 | * associated with it. Just bail out in this case. | 811 | if (!card->instantiated) |
840 | */ | ||
841 | if (list_empty(&card->codec_dev_list)) | ||
842 | return 0; | 812 | return 0; |
843 | 813 | ||
844 | /* activate pins from sleep state */ | 814 | /* activate pins from sleep state */ |
@@ -887,35 +857,40 @@ EXPORT_SYMBOL_GPL(snd_soc_resume); | |||
887 | static const struct snd_soc_dai_ops null_dai_ops = { | 857 | static const struct snd_soc_dai_ops null_dai_ops = { |
888 | }; | 858 | }; |
889 | 859 | ||
890 | static struct snd_soc_codec *soc_find_codec( | 860 | static struct snd_soc_component *soc_find_component( |
891 | const struct device_node *codec_of_node, | 861 | const struct device_node *of_node, const char *name) |
892 | const char *codec_name) | ||
893 | { | 862 | { |
894 | struct snd_soc_codec *codec; | 863 | struct snd_soc_component *component; |
895 | 864 | ||
896 | list_for_each_entry(codec, &codec_list, list) { | 865 | list_for_each_entry(component, &component_list, list) { |
897 | if (codec_of_node) { | 866 | if (of_node) { |
898 | if (codec->dev->of_node != codec_of_node) | 867 | if (component->dev->of_node == of_node) |
899 | continue; | 868 | return component; |
900 | } else { | 869 | } else if (strcmp(component->name, name) == 0) { |
901 | if (strcmp(codec->component.name, codec_name)) | 870 | return component; |
902 | continue; | ||
903 | } | 871 | } |
904 | |||
905 | return codec; | ||
906 | } | 872 | } |
907 | 873 | ||
908 | return NULL; | 874 | return NULL; |
909 | } | 875 | } |
910 | 876 | ||
911 | static struct snd_soc_dai *soc_find_codec_dai(struct snd_soc_codec *codec, | 877 | static struct snd_soc_dai *snd_soc_find_dai( |
912 | const char *codec_dai_name) | 878 | const struct snd_soc_dai_link_component *dlc) |
913 | { | 879 | { |
914 | struct snd_soc_dai *codec_dai; | 880 | struct snd_soc_component *component; |
881 | struct snd_soc_dai *dai; | ||
882 | |||
883 | /* Find CPU DAI from registered DAIs*/ | ||
884 | list_for_each_entry(component, &component_list, list) { | ||
885 | if (dlc->of_node && component->dev->of_node != dlc->of_node) | ||
886 | continue; | ||
887 | if (dlc->name && strcmp(dev_name(component->dev), dlc->name)) | ||
888 | continue; | ||
889 | list_for_each_entry(dai, &component->dai_list, list) { | ||
890 | if (dlc->dai_name && strcmp(dai->name, dlc->dai_name)) | ||
891 | continue; | ||
915 | 892 | ||
916 | list_for_each_entry(codec_dai, &codec->component.dai_list, list) { | 893 | return dai; |
917 | if (!strcmp(codec_dai->name, codec_dai_name)) { | ||
918 | return codec_dai; | ||
919 | } | 894 | } |
920 | } | 895 | } |
921 | 896 | ||
@@ -926,33 +901,19 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
926 | { | 901 | { |
927 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 902 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
928 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 903 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
929 | struct snd_soc_component *component; | ||
930 | struct snd_soc_dai_link_component *codecs = dai_link->codecs; | 904 | struct snd_soc_dai_link_component *codecs = dai_link->codecs; |
905 | struct snd_soc_dai_link_component cpu_dai_component; | ||
931 | struct snd_soc_dai **codec_dais = rtd->codec_dais; | 906 | struct snd_soc_dai **codec_dais = rtd->codec_dais; |
932 | struct snd_soc_platform *platform; | 907 | struct snd_soc_platform *platform; |
933 | struct snd_soc_dai *cpu_dai; | ||
934 | const char *platform_name; | 908 | const char *platform_name; |
935 | int i; | 909 | int i; |
936 | 910 | ||
937 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); | 911 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); |
938 | 912 | ||
939 | /* Find CPU DAI from registered DAIs*/ | 913 | cpu_dai_component.name = dai_link->cpu_name; |
940 | list_for_each_entry(component, &component_list, list) { | 914 | cpu_dai_component.of_node = dai_link->cpu_of_node; |
941 | if (dai_link->cpu_of_node && | 915 | cpu_dai_component.dai_name = dai_link->cpu_dai_name; |
942 | component->dev->of_node != dai_link->cpu_of_node) | 916 | rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); |
943 | continue; | ||
944 | if (dai_link->cpu_name && | ||
945 | strcmp(dev_name(component->dev), dai_link->cpu_name)) | ||
946 | continue; | ||
947 | list_for_each_entry(cpu_dai, &component->dai_list, list) { | ||
948 | if (dai_link->cpu_dai_name && | ||
949 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
950 | continue; | ||
951 | |||
952 | rtd->cpu_dai = cpu_dai; | ||
953 | } | ||
954 | } | ||
955 | |||
956 | if (!rtd->cpu_dai) { | 917 | if (!rtd->cpu_dai) { |
957 | dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", | 918 | dev_err(card->dev, "ASoC: CPU DAI %s not registered\n", |
958 | dai_link->cpu_dai_name); | 919 | dai_link->cpu_dai_name); |
@@ -963,15 +924,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
963 | 924 | ||
964 | /* Find CODEC from registered CODECs */ | 925 | /* Find CODEC from registered CODECs */ |
965 | for (i = 0; i < rtd->num_codecs; i++) { | 926 | for (i = 0; i < rtd->num_codecs; i++) { |
966 | struct snd_soc_codec *codec; | 927 | codec_dais[i] = snd_soc_find_dai(&codecs[i]); |
967 | codec = soc_find_codec(codecs[i].of_node, codecs[i].name); | ||
968 | if (!codec) { | ||
969 | dev_err(card->dev, "ASoC: CODEC %s not registered\n", | ||
970 | codecs[i].name); | ||
971 | return -EPROBE_DEFER; | ||
972 | } | ||
973 | |||
974 | codec_dais[i] = soc_find_codec_dai(codec, codecs[i].dai_name); | ||
975 | if (!codec_dais[i]) { | 928 | if (!codec_dais[i]) { |
976 | dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", | 929 | dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", |
977 | codecs[i].dai_name); | 930 | codecs[i].dai_name); |
@@ -1012,68 +965,46 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
1012 | return 0; | 965 | return 0; |
1013 | } | 966 | } |
1014 | 967 | ||
1015 | static int soc_remove_platform(struct snd_soc_platform *platform) | 968 | static void soc_remove_component(struct snd_soc_component *component) |
1016 | { | 969 | { |
1017 | int ret; | 970 | if (!component->probed) |
1018 | 971 | return; | |
1019 | if (platform->driver->remove) { | ||
1020 | ret = platform->driver->remove(platform); | ||
1021 | if (ret < 0) | ||
1022 | dev_err(platform->dev, "ASoC: failed to remove %d\n", | ||
1023 | ret); | ||
1024 | } | ||
1025 | |||
1026 | /* Make sure all DAPM widgets are freed */ | ||
1027 | snd_soc_dapm_free(&platform->component.dapm); | ||
1028 | |||
1029 | soc_cleanup_platform_debugfs(platform); | ||
1030 | platform->probed = 0; | ||
1031 | module_put(platform->dev->driver->owner); | ||
1032 | |||
1033 | return 0; | ||
1034 | } | ||
1035 | 972 | ||
1036 | static void soc_remove_codec(struct snd_soc_codec *codec) | 973 | /* This is a HACK and will be removed soon */ |
1037 | { | 974 | if (component->codec) |
1038 | int err; | 975 | list_del(&component->codec->card_list); |
1039 | 976 | ||
1040 | if (codec->driver->remove) { | 977 | if (component->remove) |
1041 | err = codec->driver->remove(codec); | 978 | component->remove(component); |
1042 | if (err < 0) | ||
1043 | dev_err(codec->dev, "ASoC: failed to remove %d\n", err); | ||
1044 | } | ||
1045 | 979 | ||
1046 | /* Make sure all DAPM widgets are freed */ | 980 | snd_soc_dapm_free(snd_soc_component_get_dapm(component)); |
1047 | snd_soc_dapm_free(&codec->dapm); | ||
1048 | 981 | ||
1049 | soc_cleanup_codec_debugfs(codec); | 982 | soc_cleanup_component_debugfs(component); |
1050 | codec->probed = 0; | 983 | component->probed = 0; |
1051 | list_del(&codec->card_list); | 984 | module_put(component->dev->driver->owner); |
1052 | module_put(codec->dev->driver->owner); | ||
1053 | } | 985 | } |
1054 | 986 | ||
1055 | static void soc_remove_codec_dai(struct snd_soc_dai *codec_dai, int order) | 987 | static void soc_remove_dai(struct snd_soc_dai *dai, int order) |
1056 | { | 988 | { |
1057 | int err; | 989 | int err; |
1058 | 990 | ||
1059 | if (codec_dai && codec_dai->probed && | 991 | if (dai && dai->probed && |
1060 | codec_dai->driver->remove_order == order) { | 992 | dai->driver->remove_order == order) { |
1061 | if (codec_dai->driver->remove) { | 993 | if (dai->driver->remove) { |
1062 | err = codec_dai->driver->remove(codec_dai); | 994 | err = dai->driver->remove(dai); |
1063 | if (err < 0) | 995 | if (err < 0) |
1064 | dev_err(codec_dai->dev, | 996 | dev_err(dai->dev, |
1065 | "ASoC: failed to remove %s: %d\n", | 997 | "ASoC: failed to remove %s: %d\n", |
1066 | codec_dai->name, err); | 998 | dai->name, err); |
1067 | } | 999 | } |
1068 | codec_dai->probed = 0; | 1000 | dai->probed = 0; |
1069 | } | 1001 | } |
1070 | } | 1002 | } |
1071 | 1003 | ||
1072 | static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) | 1004 | static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) |
1073 | { | 1005 | { |
1074 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1006 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1075 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1007 | int i; |
1076 | int i, err; | ||
1077 | 1008 | ||
1078 | /* unregister the rtd device */ | 1009 | /* unregister the rtd device */ |
1079 | if (rtd->dev_registered) { | 1010 | if (rtd->dev_registered) { |
@@ -1085,22 +1016,9 @@ static void soc_remove_link_dais(struct snd_soc_card *card, int num, int order) | |||
1085 | 1016 | ||
1086 | /* remove the CODEC DAI */ | 1017 | /* remove the CODEC DAI */ |
1087 | for (i = 0; i < rtd->num_codecs; i++) | 1018 | for (i = 0; i < rtd->num_codecs; i++) |
1088 | soc_remove_codec_dai(rtd->codec_dais[i], order); | 1019 | soc_remove_dai(rtd->codec_dais[i], order); |
1089 | 1020 | ||
1090 | /* remove the cpu_dai */ | 1021 | soc_remove_dai(rtd->cpu_dai, order); |
1091 | if (cpu_dai && cpu_dai->probed && | ||
1092 | cpu_dai->driver->remove_order == order) { | ||
1093 | if (cpu_dai->driver->remove) { | ||
1094 | err = cpu_dai->driver->remove(cpu_dai); | ||
1095 | if (err < 0) | ||
1096 | dev_err(cpu_dai->dev, | ||
1097 | "ASoC: failed to remove %s: %d\n", | ||
1098 | cpu_dai->name, err); | ||
1099 | } | ||
1100 | cpu_dai->probed = 0; | ||
1101 | if (!cpu_dai->codec) | ||
1102 | module_put(cpu_dai->dev->driver->owner); | ||
1103 | } | ||
1104 | } | 1022 | } |
1105 | 1023 | ||
1106 | static void soc_remove_link_components(struct snd_soc_card *card, int num, | 1024 | static void soc_remove_link_components(struct snd_soc_card *card, int num, |
@@ -1109,29 +1027,24 @@ static void soc_remove_link_components(struct snd_soc_card *card, int num, | |||
1109 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1027 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1110 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 1028 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
1111 | struct snd_soc_platform *platform = rtd->platform; | 1029 | struct snd_soc_platform *platform = rtd->platform; |
1112 | struct snd_soc_codec *codec; | 1030 | struct snd_soc_component *component; |
1113 | int i; | 1031 | int i; |
1114 | 1032 | ||
1115 | /* remove the platform */ | 1033 | /* remove the platform */ |
1116 | if (platform && platform->probed && | 1034 | if (platform && platform->component.driver->remove_order == order) |
1117 | platform->driver->remove_order == order) { | 1035 | soc_remove_component(&platform->component); |
1118 | soc_remove_platform(platform); | ||
1119 | } | ||
1120 | 1036 | ||
1121 | /* remove the CODEC-side CODEC */ | 1037 | /* remove the CODEC-side CODEC */ |
1122 | for (i = 0; i < rtd->num_codecs; i++) { | 1038 | for (i = 0; i < rtd->num_codecs; i++) { |
1123 | codec = rtd->codec_dais[i]->codec; | 1039 | component = rtd->codec_dais[i]->component; |
1124 | if (codec && codec->probed && | 1040 | if (component->driver->remove_order == order) |
1125 | codec->driver->remove_order == order) | 1041 | soc_remove_component(component); |
1126 | soc_remove_codec(codec); | ||
1127 | } | 1042 | } |
1128 | 1043 | ||
1129 | /* remove any CPU-side CODEC */ | 1044 | /* remove any CPU-side CODEC */ |
1130 | if (cpu_dai) { | 1045 | if (cpu_dai) { |
1131 | codec = cpu_dai->codec; | 1046 | if (cpu_dai->component->driver->remove_order == order) |
1132 | if (codec && codec->probed && | 1047 | soc_remove_component(cpu_dai->component); |
1133 | codec->driver->remove_order == order) | ||
1134 | soc_remove_codec(codec); | ||
1135 | } | 1048 | } |
1136 | } | 1049 | } |
1137 | 1050 | ||
@@ -1173,137 +1086,78 @@ static void soc_set_name_prefix(struct snd_soc_card *card, | |||
1173 | } | 1086 | } |
1174 | } | 1087 | } |
1175 | 1088 | ||
1176 | static int soc_probe_codec(struct snd_soc_card *card, | 1089 | static int soc_probe_component(struct snd_soc_card *card, |
1177 | struct snd_soc_codec *codec) | 1090 | struct snd_soc_component *component) |
1178 | { | 1091 | { |
1179 | int ret = 0; | 1092 | struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); |
1180 | const struct snd_soc_codec_driver *driver = codec->driver; | ||
1181 | struct snd_soc_dai *dai; | 1093 | struct snd_soc_dai *dai; |
1094 | int ret; | ||
1095 | |||
1096 | if (component->probed) | ||
1097 | return 0; | ||
1182 | 1098 | ||
1183 | codec->component.card = card; | 1099 | component->card = card; |
1184 | codec->dapm.card = card; | 1100 | dapm->card = card; |
1185 | soc_set_name_prefix(card, &codec->component); | 1101 | soc_set_name_prefix(card, component); |
1186 | 1102 | ||
1187 | if (!try_module_get(codec->dev->driver->owner)) | 1103 | if (!try_module_get(component->dev->driver->owner)) |
1188 | return -ENODEV; | 1104 | return -ENODEV; |
1189 | 1105 | ||
1190 | soc_init_codec_debugfs(codec); | 1106 | soc_init_component_debugfs(component); |
1191 | 1107 | ||
1192 | if (driver->dapm_widgets) { | 1108 | if (component->dapm_widgets) { |
1193 | ret = snd_soc_dapm_new_controls(&codec->dapm, | 1109 | ret = snd_soc_dapm_new_controls(dapm, component->dapm_widgets, |
1194 | driver->dapm_widgets, | 1110 | component->num_dapm_widgets); |
1195 | driver->num_dapm_widgets); | ||
1196 | 1111 | ||
1197 | if (ret != 0) { | 1112 | if (ret != 0) { |
1198 | dev_err(codec->dev, | 1113 | dev_err(component->dev, |
1199 | "Failed to create new controls %d\n", ret); | 1114 | "Failed to create new controls %d\n", ret); |
1200 | goto err_probe; | 1115 | goto err_probe; |
1201 | } | 1116 | } |
1202 | } | 1117 | } |
1203 | 1118 | ||
1204 | /* Create DAPM widgets for each DAI stream */ | 1119 | list_for_each_entry(dai, &component->dai_list, list) { |
1205 | list_for_each_entry(dai, &codec->component.dai_list, list) { | 1120 | ret = snd_soc_dapm_new_dai_widgets(dapm, dai); |
1206 | ret = snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); | ||
1207 | |||
1208 | if (ret != 0) { | 1121 | if (ret != 0) { |
1209 | dev_err(codec->dev, | 1122 | dev_err(component->dev, |
1210 | "Failed to create DAI widgets %d\n", ret); | 1123 | "Failed to create DAI widgets %d\n", ret); |
1211 | goto err_probe; | 1124 | goto err_probe; |
1212 | } | 1125 | } |
1213 | } | 1126 | } |
1214 | 1127 | ||
1215 | codec->dapm.idle_bias_off = driver->idle_bias_off; | 1128 | if (component->probe) { |
1216 | 1129 | ret = component->probe(component); | |
1217 | if (driver->probe) { | ||
1218 | ret = driver->probe(codec); | ||
1219 | if (ret < 0) { | 1130 | if (ret < 0) { |
1220 | dev_err(codec->dev, | 1131 | dev_err(component->dev, |
1221 | "ASoC: failed to probe CODEC %d\n", ret); | 1132 | "ASoC: failed to probe component %d\n", ret); |
1222 | goto err_probe; | 1133 | goto err_probe; |
1223 | } | 1134 | } |
1224 | WARN(codec->dapm.idle_bias_off && | ||
1225 | codec->dapm.bias_level != SND_SOC_BIAS_OFF, | ||
1226 | "codec %s can not start from non-off bias with idle_bias_off==1\n", | ||
1227 | codec->component.name); | ||
1228 | } | ||
1229 | |||
1230 | if (driver->controls) | ||
1231 | snd_soc_add_codec_controls(codec, driver->controls, | ||
1232 | driver->num_controls); | ||
1233 | if (driver->dapm_routes) | ||
1234 | snd_soc_dapm_add_routes(&codec->dapm, driver->dapm_routes, | ||
1235 | driver->num_dapm_routes); | ||
1236 | |||
1237 | /* mark codec as probed and add to card codec list */ | ||
1238 | codec->probed = 1; | ||
1239 | list_add(&codec->card_list, &card->codec_dev_list); | ||
1240 | list_add(&codec->dapm.list, &card->dapm_list); | ||
1241 | 1135 | ||
1242 | return 0; | 1136 | WARN(dapm->idle_bias_off && |
1243 | 1137 | dapm->bias_level != SND_SOC_BIAS_OFF, | |
1244 | err_probe: | 1138 | "codec %s can not start from non-off bias with idle_bias_off==1\n", |
1245 | soc_cleanup_codec_debugfs(codec); | 1139 | component->name); |
1246 | module_put(codec->dev->driver->owner); | ||
1247 | |||
1248 | return ret; | ||
1249 | } | ||
1250 | |||
1251 | static int soc_probe_platform(struct snd_soc_card *card, | ||
1252 | struct snd_soc_platform *platform) | ||
1253 | { | ||
1254 | int ret = 0; | ||
1255 | const struct snd_soc_platform_driver *driver = platform->driver; | ||
1256 | struct snd_soc_component *component; | ||
1257 | struct snd_soc_dai *dai; | ||
1258 | |||
1259 | platform->component.card = card; | ||
1260 | platform->component.dapm.card = card; | ||
1261 | |||
1262 | if (!try_module_get(platform->dev->driver->owner)) | ||
1263 | return -ENODEV; | ||
1264 | |||
1265 | soc_init_platform_debugfs(platform); | ||
1266 | |||
1267 | if (driver->dapm_widgets) | ||
1268 | snd_soc_dapm_new_controls(&platform->component.dapm, | ||
1269 | driver->dapm_widgets, driver->num_dapm_widgets); | ||
1270 | |||
1271 | /* Create DAPM widgets for each DAI stream */ | ||
1272 | list_for_each_entry(component, &component_list, list) { | ||
1273 | if (component->dev != platform->dev) | ||
1274 | continue; | ||
1275 | list_for_each_entry(dai, &component->dai_list, list) | ||
1276 | snd_soc_dapm_new_dai_widgets(&platform->component.dapm, | ||
1277 | dai); | ||
1278 | } | 1140 | } |
1279 | 1141 | ||
1280 | platform->component.dapm.idle_bias_off = 1; | 1142 | if (component->controls) |
1281 | 1143 | snd_soc_add_component_controls(component, component->controls, | |
1282 | if (driver->probe) { | 1144 | component->num_controls); |
1283 | ret = driver->probe(platform); | 1145 | if (component->dapm_routes) |
1284 | if (ret < 0) { | 1146 | snd_soc_dapm_add_routes(dapm, component->dapm_routes, |
1285 | dev_err(platform->dev, | 1147 | component->num_dapm_routes); |
1286 | "ASoC: failed to probe platform %d\n", ret); | ||
1287 | goto err_probe; | ||
1288 | } | ||
1289 | } | ||
1290 | 1148 | ||
1291 | if (driver->controls) | 1149 | component->probed = 1; |
1292 | snd_soc_add_platform_controls(platform, driver->controls, | 1150 | list_add(&dapm->list, &card->dapm_list); |
1293 | driver->num_controls); | ||
1294 | if (driver->dapm_routes) | ||
1295 | snd_soc_dapm_add_routes(&platform->component.dapm, | ||
1296 | driver->dapm_routes, driver->num_dapm_routes); | ||
1297 | 1151 | ||
1298 | /* mark platform as probed and add to card platform list */ | 1152 | /* This is a HACK and will be removed soon */ |
1299 | platform->probed = 1; | 1153 | if (component->codec) |
1300 | list_add(&platform->component.dapm.list, &card->dapm_list); | 1154 | list_add(&component->codec->card_list, &card->codec_dev_list); |
1301 | 1155 | ||
1302 | return 0; | 1156 | return 0; |
1303 | 1157 | ||
1304 | err_probe: | 1158 | err_probe: |
1305 | soc_cleanup_platform_debugfs(platform); | 1159 | soc_cleanup_component_debugfs(component); |
1306 | module_put(platform->dev->driver->owner); | 1160 | module_put(component->dev->driver->owner); |
1307 | 1161 | ||
1308 | return ret; | 1162 | return ret; |
1309 | } | 1163 | } |
@@ -1325,7 +1179,7 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, | |||
1325 | device_initialize(rtd->dev); | 1179 | device_initialize(rtd->dev); |
1326 | rtd->dev->parent = rtd->card->dev; | 1180 | rtd->dev->parent = rtd->card->dev; |
1327 | rtd->dev->release = rtd_release; | 1181 | rtd->dev->release = rtd_release; |
1328 | rtd->dev->init_name = name; | 1182 | dev_set_name(rtd->dev, "%s", name); |
1329 | dev_set_drvdata(rtd->dev, rtd); | 1183 | dev_set_drvdata(rtd->dev, rtd); |
1330 | mutex_init(&rtd->pcm_mutex); | 1184 | mutex_init(&rtd->pcm_mutex); |
1331 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); | 1185 | INIT_LIST_HEAD(&rtd->dpcm[SNDRV_PCM_STREAM_PLAYBACK].be_clients); |
@@ -1342,17 +1196,21 @@ static int soc_post_component_init(struct snd_soc_pcm_runtime *rtd, | |||
1342 | } | 1196 | } |
1343 | rtd->dev_registered = 1; | 1197 | rtd->dev_registered = 1; |
1344 | 1198 | ||
1345 | /* add DAPM sysfs entries for this codec */ | 1199 | if (rtd->codec) { |
1346 | ret = snd_soc_dapm_sys_add(rtd->dev); | 1200 | /* add DAPM sysfs entries for this codec */ |
1347 | if (ret < 0) | 1201 | ret = snd_soc_dapm_sys_add(rtd->dev); |
1348 | dev_err(rtd->dev, | 1202 | if (ret < 0) |
1349 | "ASoC: failed to add codec dapm sysfs entries: %d\n", ret); | 1203 | dev_err(rtd->dev, |
1204 | "ASoC: failed to add codec dapm sysfs entries: %d\n", | ||
1205 | ret); | ||
1350 | 1206 | ||
1351 | /* add codec sysfs entries */ | 1207 | /* add codec sysfs entries */ |
1352 | ret = device_create_file(rtd->dev, &dev_attr_codec_reg); | 1208 | ret = device_create_file(rtd->dev, &dev_attr_codec_reg); |
1353 | if (ret < 0) | 1209 | if (ret < 0) |
1354 | dev_err(rtd->dev, | 1210 | dev_err(rtd->dev, |
1355 | "ASoC: failed to add codec sysfs files: %d\n", ret); | 1211 | "ASoC: failed to add codec sysfs files: %d\n", |
1212 | ret); | ||
1213 | } | ||
1356 | 1214 | ||
1357 | return 0; | 1215 | return 0; |
1358 | } | 1216 | } |
@@ -1361,33 +1219,31 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num, | |||
1361 | int order) | 1219 | int order) |
1362 | { | 1220 | { |
1363 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 1221 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
1364 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
1365 | struct snd_soc_platform *platform = rtd->platform; | 1222 | struct snd_soc_platform *platform = rtd->platform; |
1223 | struct snd_soc_component *component; | ||
1366 | int i, ret; | 1224 | int i, ret; |
1367 | 1225 | ||
1368 | /* probe the CPU-side component, if it is a CODEC */ | 1226 | /* probe the CPU-side component, if it is a CODEC */ |
1369 | if (cpu_dai->codec && | 1227 | component = rtd->cpu_dai->component; |
1370 | !cpu_dai->codec->probed && | 1228 | if (component->driver->probe_order == order) { |
1371 | cpu_dai->codec->driver->probe_order == order) { | 1229 | ret = soc_probe_component(card, component); |
1372 | ret = soc_probe_codec(card, cpu_dai->codec); | ||
1373 | if (ret < 0) | 1230 | if (ret < 0) |
1374 | return ret; | 1231 | return ret; |
1375 | } | 1232 | } |
1376 | 1233 | ||
1377 | /* probe the CODEC-side components */ | 1234 | /* probe the CODEC-side components */ |
1378 | for (i = 0; i < rtd->num_codecs; i++) { | 1235 | for (i = 0; i < rtd->num_codecs; i++) { |
1379 | if (!rtd->codec_dais[i]->codec->probed && | 1236 | component = rtd->codec_dais[i]->component; |
1380 | rtd->codec_dais[i]->codec->driver->probe_order == order) { | 1237 | if (component->driver->probe_order == order) { |
1381 | ret = soc_probe_codec(card, rtd->codec_dais[i]->codec); | 1238 | ret = soc_probe_component(card, component); |
1382 | if (ret < 0) | 1239 | if (ret < 0) |
1383 | return ret; | 1240 | return ret; |
1384 | } | 1241 | } |
1385 | } | 1242 | } |
1386 | 1243 | ||
1387 | /* probe the platform */ | 1244 | /* probe the platform */ |
1388 | if (!platform->probed && | 1245 | if (platform->component.driver->probe_order == order) { |
1389 | platform->driver->probe_order == order) { | 1246 | ret = soc_probe_component(card, &platform->component); |
1390 | ret = soc_probe_platform(card, platform); | ||
1391 | if (ret < 0) | 1247 | if (ret < 0) |
1392 | return ret; | 1248 | return ret; |
1393 | } | 1249 | } |
@@ -1482,18 +1338,12 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) | |||
1482 | /* probe the cpu_dai */ | 1338 | /* probe the cpu_dai */ |
1483 | if (!cpu_dai->probed && | 1339 | if (!cpu_dai->probed && |
1484 | cpu_dai->driver->probe_order == order) { | 1340 | cpu_dai->driver->probe_order == order) { |
1485 | if (!cpu_dai->codec) { | ||
1486 | if (!try_module_get(cpu_dai->dev->driver->owner)) | ||
1487 | return -ENODEV; | ||
1488 | } | ||
1489 | |||
1490 | if (cpu_dai->driver->probe) { | 1341 | if (cpu_dai->driver->probe) { |
1491 | ret = cpu_dai->driver->probe(cpu_dai); | 1342 | ret = cpu_dai->driver->probe(cpu_dai); |
1492 | if (ret < 0) { | 1343 | if (ret < 0) { |
1493 | dev_err(cpu_dai->dev, | 1344 | dev_err(cpu_dai->dev, |
1494 | "ASoC: failed to probe CPU DAI %s: %d\n", | 1345 | "ASoC: failed to probe CPU DAI %s: %d\n", |
1495 | cpu_dai->name, ret); | 1346 | cpu_dai->name, ret); |
1496 | module_put(cpu_dai->dev->driver->owner); | ||
1497 | return ret; | 1347 | return ret; |
1498 | } | 1348 | } |
1499 | } | 1349 | } |
@@ -1654,17 +1504,24 @@ static int soc_bind_aux_dev(struct snd_soc_card *card, int num) | |||
1654 | { | 1504 | { |
1655 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | 1505 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; |
1656 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | 1506 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; |
1657 | const char *codecname = aux_dev->codec_name; | 1507 | const char *name = aux_dev->codec_name; |
1658 | 1508 | ||
1659 | rtd->codec = soc_find_codec(aux_dev->codec_of_node, codecname); | 1509 | rtd->component = soc_find_component(aux_dev->codec_of_node, name); |
1660 | if (!rtd->codec) { | 1510 | if (!rtd->component) { |
1661 | if (aux_dev->codec_of_node) | 1511 | if (aux_dev->codec_of_node) |
1662 | codecname = of_node_full_name(aux_dev->codec_of_node); | 1512 | name = of_node_full_name(aux_dev->codec_of_node); |
1663 | 1513 | ||
1664 | dev_err(card->dev, "ASoC: %s not registered\n", codecname); | 1514 | dev_err(card->dev, "ASoC: %s not registered\n", name); |
1665 | return -EPROBE_DEFER; | 1515 | return -EPROBE_DEFER; |
1666 | } | 1516 | } |
1667 | 1517 | ||
1518 | /* | ||
1519 | * Some places still reference rtd->codec, so we have to keep that | ||
1520 | * initialized if the component is a CODEC. Once all those references | ||
1521 | * have been removed, this code can be removed as well. | ||
1522 | */ | ||
1523 | rtd->codec = rtd->component->codec; | ||
1524 | |||
1668 | return 0; | 1525 | return 0; |
1669 | } | 1526 | } |
1670 | 1527 | ||
@@ -1674,18 +1531,13 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) | |||
1674 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; | 1531 | struct snd_soc_aux_dev *aux_dev = &card->aux_dev[num]; |
1675 | int ret; | 1532 | int ret; |
1676 | 1533 | ||
1677 | if (rtd->codec->probed) { | 1534 | ret = soc_probe_component(card, rtd->component); |
1678 | dev_err(rtd->codec->dev, "ASoC: codec already probed\n"); | ||
1679 | return -EBUSY; | ||
1680 | } | ||
1681 | |||
1682 | ret = soc_probe_codec(card, rtd->codec); | ||
1683 | if (ret < 0) | 1535 | if (ret < 0) |
1684 | return ret; | 1536 | return ret; |
1685 | 1537 | ||
1686 | /* do machine specific initialization */ | 1538 | /* do machine specific initialization */ |
1687 | if (aux_dev->init) { | 1539 | if (aux_dev->init) { |
1688 | ret = aux_dev->init(&rtd->codec->dapm); | 1540 | ret = aux_dev->init(rtd->component); |
1689 | if (ret < 0) { | 1541 | if (ret < 0) { |
1690 | dev_err(card->dev, "ASoC: failed to init %s: %d\n", | 1542 | dev_err(card->dev, "ASoC: failed to init %s: %d\n", |
1691 | aux_dev->name, ret); | 1543 | aux_dev->name, ret); |
@@ -1699,7 +1551,7 @@ static int soc_probe_aux_dev(struct snd_soc_card *card, int num) | |||
1699 | static void soc_remove_aux_dev(struct snd_soc_card *card, int num) | 1551 | static void soc_remove_aux_dev(struct snd_soc_card *card, int num) |
1700 | { | 1552 | { |
1701 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; | 1553 | struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; |
1702 | struct snd_soc_codec *codec = rtd->codec; | 1554 | struct snd_soc_component *component = rtd->component; |
1703 | 1555 | ||
1704 | /* unregister the rtd device */ | 1556 | /* unregister the rtd device */ |
1705 | if (rtd->dev_registered) { | 1557 | if (rtd->dev_registered) { |
@@ -1708,8 +1560,8 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) | |||
1708 | rtd->dev_registered = 0; | 1560 | rtd->dev_registered = 0; |
1709 | } | 1561 | } |
1710 | 1562 | ||
1711 | if (codec && codec->probed) | 1563 | if (component && component->probed) |
1712 | soc_remove_codec(codec); | 1564 | soc_remove_component(component); |
1713 | } | 1565 | } |
1714 | 1566 | ||
1715 | static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) | 1567 | static int snd_soc_init_codec_cache(struct snd_soc_codec *codec) |
@@ -2107,19 +1959,14 @@ static struct platform_driver soc_driver = { | |||
2107 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | 1959 | int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, |
2108 | struct snd_ac97_bus_ops *ops, int num) | 1960 | struct snd_ac97_bus_ops *ops, int num) |
2109 | { | 1961 | { |
2110 | mutex_lock(&codec->mutex); | ||
2111 | |||
2112 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); | 1962 | codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); |
2113 | if (codec->ac97 == NULL) { | 1963 | if (codec->ac97 == NULL) |
2114 | mutex_unlock(&codec->mutex); | ||
2115 | return -ENOMEM; | 1964 | return -ENOMEM; |
2116 | } | ||
2117 | 1965 | ||
2118 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); | 1966 | codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); |
2119 | if (codec->ac97->bus == NULL) { | 1967 | if (codec->ac97->bus == NULL) { |
2120 | kfree(codec->ac97); | 1968 | kfree(codec->ac97); |
2121 | codec->ac97 = NULL; | 1969 | codec->ac97 = NULL; |
2122 | mutex_unlock(&codec->mutex); | ||
2123 | return -ENOMEM; | 1970 | return -ENOMEM; |
2124 | } | 1971 | } |
2125 | 1972 | ||
@@ -2132,7 +1979,6 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, | |||
2132 | */ | 1979 | */ |
2133 | codec->ac97_created = 1; | 1980 | codec->ac97_created = 1; |
2134 | 1981 | ||
2135 | mutex_unlock(&codec->mutex); | ||
2136 | return 0; | 1982 | return 0; |
2137 | } | 1983 | } |
2138 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); | 1984 | EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); |
@@ -2302,7 +2148,6 @@ EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); | |||
2302 | */ | 2148 | */ |
2303 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | 2149 | void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) |
2304 | { | 2150 | { |
2305 | mutex_lock(&codec->mutex); | ||
2306 | #ifdef CONFIG_SND_SOC_AC97_BUS | 2151 | #ifdef CONFIG_SND_SOC_AC97_BUS |
2307 | soc_unregister_ac97_codec(codec); | 2152 | soc_unregister_ac97_codec(codec); |
2308 | #endif | 2153 | #endif |
@@ -2310,7 +2155,6 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) | |||
2310 | kfree(codec->ac97); | 2155 | kfree(codec->ac97); |
2311 | codec->ac97 = NULL; | 2156 | codec->ac97 = NULL; |
2312 | codec->ac97_created = 0; | 2157 | codec->ac97_created = 0; |
2313 | mutex_unlock(&codec->mutex); | ||
2314 | } | 2158 | } |
2315 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); | 2159 | EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); |
2316 | 2160 | ||
@@ -3027,9 +2871,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | |||
3027 | unsigned int val, val_mask; | 2871 | unsigned int val, val_mask; |
3028 | int ret; | 2872 | int ret; |
3029 | 2873 | ||
3030 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
3031 | if (invert) | 2874 | if (invert) |
3032 | val = max - val; | 2875 | val = (max - ucontrol->value.integer.value[0]) & mask; |
2876 | else | ||
2877 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
3033 | val_mask = mask << shift; | 2878 | val_mask = mask << shift; |
3034 | val = val << shift; | 2879 | val = val << shift; |
3035 | 2880 | ||
@@ -3038,9 +2883,10 @@ int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, | |||
3038 | return ret; | 2883 | return ret; |
3039 | 2884 | ||
3040 | if (snd_soc_volsw_is_stereo(mc)) { | 2885 | if (snd_soc_volsw_is_stereo(mc)) { |
3041 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
3042 | if (invert) | 2886 | if (invert) |
3043 | val = max - val; | 2887 | val = (max - ucontrol->value.integer.value[1]) & mask; |
2888 | else | ||
2889 | val = ((ucontrol->value.integer.value[1] + min) & mask); | ||
3044 | val_mask = mask << shift; | 2890 | val_mask = mask << shift; |
3045 | val = val << shift; | 2891 | val = val << shift; |
3046 | 2892 | ||
@@ -3085,8 +2931,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | |||
3085 | if (invert) | 2931 | if (invert) |
3086 | ucontrol->value.integer.value[0] = | 2932 | ucontrol->value.integer.value[0] = |
3087 | max - ucontrol->value.integer.value[0]; | 2933 | max - ucontrol->value.integer.value[0]; |
3088 | ucontrol->value.integer.value[0] = | 2934 | else |
3089 | ucontrol->value.integer.value[0] - min; | 2935 | ucontrol->value.integer.value[0] = |
2936 | ucontrol->value.integer.value[0] - min; | ||
3090 | 2937 | ||
3091 | if (snd_soc_volsw_is_stereo(mc)) { | 2938 | if (snd_soc_volsw_is_stereo(mc)) { |
3092 | ret = snd_soc_component_read(component, rreg, &val); | 2939 | ret = snd_soc_component_read(component, rreg, &val); |
@@ -3097,8 +2944,9 @@ int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, | |||
3097 | if (invert) | 2944 | if (invert) |
3098 | ucontrol->value.integer.value[1] = | 2945 | ucontrol->value.integer.value[1] = |
3099 | max - ucontrol->value.integer.value[1]; | 2946 | max - ucontrol->value.integer.value[1]; |
3100 | ucontrol->value.integer.value[1] = | 2947 | else |
3101 | ucontrol->value.integer.value[1] - min; | 2948 | ucontrol->value.integer.value[1] = |
2949 | ucontrol->value.integer.value[1] - min; | ||
3102 | } | 2950 | } |
3103 | 2951 | ||
3104 | return 0; | 2952 | return 0; |
@@ -3203,7 +3051,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
3203 | unsigned int val, mask; | 3051 | unsigned int val, mask; |
3204 | void *data; | 3052 | void *data; |
3205 | 3053 | ||
3206 | if (!component->regmap) | 3054 | if (!component->regmap || !params->num_regs) |
3207 | return -EINVAL; | 3055 | return -EINVAL; |
3208 | 3056 | ||
3209 | len = params->num_regs * component->val_bytes; | 3057 | len = params->num_regs * component->val_bytes; |
@@ -3928,8 +3776,11 @@ EXPORT_SYMBOL_GPL(snd_soc_register_card); | |||
3928 | */ | 3776 | */ |
3929 | int snd_soc_unregister_card(struct snd_soc_card *card) | 3777 | int snd_soc_unregister_card(struct snd_soc_card *card) |
3930 | { | 3778 | { |
3931 | if (card->instantiated) | 3779 | if (card->instantiated) { |
3780 | card->instantiated = false; | ||
3781 | snd_soc_dapm_shutdown(card); | ||
3932 | soc_cleanup_card_resources(card); | 3782 | soc_cleanup_card_resources(card); |
3783 | } | ||
3933 | dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); | 3784 | dev_dbg(card->dev, "ASoC: Unregistered card '%s'\n", card->name); |
3934 | 3785 | ||
3935 | return 0; | 3786 | return 0; |
@@ -4116,6 +3967,8 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, | |||
4116 | 3967 | ||
4117 | component->dev = dev; | 3968 | component->dev = dev; |
4118 | component->driver = driver; | 3969 | component->driver = driver; |
3970 | component->probe = component->driver->probe; | ||
3971 | component->remove = component->driver->remove; | ||
4119 | 3972 | ||
4120 | if (!component->dapm_ptr) | 3973 | if (!component->dapm_ptr) |
4121 | component->dapm_ptr = &component->dapm; | 3974 | component->dapm_ptr = &component->dapm; |
@@ -4124,19 +3977,42 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, | |||
4124 | dapm->dev = dev; | 3977 | dapm->dev = dev; |
4125 | dapm->component = component; | 3978 | dapm->component = component; |
4126 | dapm->bias_level = SND_SOC_BIAS_OFF; | 3979 | dapm->bias_level = SND_SOC_BIAS_OFF; |
3980 | dapm->idle_bias_off = true; | ||
4127 | if (driver->seq_notifier) | 3981 | if (driver->seq_notifier) |
4128 | dapm->seq_notifier = snd_soc_component_seq_notifier; | 3982 | dapm->seq_notifier = snd_soc_component_seq_notifier; |
4129 | if (driver->stream_event) | 3983 | if (driver->stream_event) |
4130 | dapm->stream_event = snd_soc_component_stream_event; | 3984 | dapm->stream_event = snd_soc_component_stream_event; |
4131 | 3985 | ||
3986 | component->controls = driver->controls; | ||
3987 | component->num_controls = driver->num_controls; | ||
3988 | component->dapm_widgets = driver->dapm_widgets; | ||
3989 | component->num_dapm_widgets = driver->num_dapm_widgets; | ||
3990 | component->dapm_routes = driver->dapm_routes; | ||
3991 | component->num_dapm_routes = driver->num_dapm_routes; | ||
3992 | |||
4132 | INIT_LIST_HEAD(&component->dai_list); | 3993 | INIT_LIST_HEAD(&component->dai_list); |
4133 | mutex_init(&component->io_mutex); | 3994 | mutex_init(&component->io_mutex); |
4134 | 3995 | ||
4135 | return 0; | 3996 | return 0; |
4136 | } | 3997 | } |
4137 | 3998 | ||
3999 | static void snd_soc_component_init_regmap(struct snd_soc_component *component) | ||
4000 | { | ||
4001 | if (!component->regmap) | ||
4002 | component->regmap = dev_get_regmap(component->dev, NULL); | ||
4003 | if (component->regmap) { | ||
4004 | int val_bytes = regmap_get_val_bytes(component->regmap); | ||
4005 | /* Errors are legitimate for non-integer byte multiples */ | ||
4006 | if (val_bytes > 0) | ||
4007 | component->val_bytes = val_bytes; | ||
4008 | } | ||
4009 | } | ||
4010 | |||
4138 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) | 4011 | static void snd_soc_component_add_unlocked(struct snd_soc_component *component) |
4139 | { | 4012 | { |
4013 | if (!component->write && !component->read) | ||
4014 | snd_soc_component_init_regmap(component); | ||
4015 | |||
4140 | list_add(&component->list, &component_list); | 4016 | list_add(&component->list, &component_list); |
4141 | } | 4017 | } |
4142 | 4018 | ||
@@ -4225,22 +4101,18 @@ found: | |||
4225 | } | 4101 | } |
4226 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); | 4102 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); |
4227 | 4103 | ||
4228 | static int snd_soc_platform_drv_write(struct snd_soc_component *component, | 4104 | static int snd_soc_platform_drv_probe(struct snd_soc_component *component) |
4229 | unsigned int reg, unsigned int val) | ||
4230 | { | 4105 | { |
4231 | struct snd_soc_platform *platform = snd_soc_component_to_platform(component); | 4106 | struct snd_soc_platform *platform = snd_soc_component_to_platform(component); |
4232 | 4107 | ||
4233 | return platform->driver->write(platform, reg, val); | 4108 | return platform->driver->probe(platform); |
4234 | } | 4109 | } |
4235 | 4110 | ||
4236 | static int snd_soc_platform_drv_read(struct snd_soc_component *component, | 4111 | static void snd_soc_platform_drv_remove(struct snd_soc_component *component) |
4237 | unsigned int reg, unsigned int *val) | ||
4238 | { | 4112 | { |
4239 | struct snd_soc_platform *platform = snd_soc_component_to_platform(component); | 4113 | struct snd_soc_platform *platform = snd_soc_component_to_platform(component); |
4240 | 4114 | ||
4241 | *val = platform->driver->read(platform, reg); | 4115 | platform->driver->remove(platform); |
4242 | |||
4243 | return 0; | ||
4244 | } | 4116 | } |
4245 | 4117 | ||
4246 | /** | 4118 | /** |
@@ -4261,10 +4133,15 @@ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, | |||
4261 | 4133 | ||
4262 | platform->dev = dev; | 4134 | platform->dev = dev; |
4263 | platform->driver = platform_drv; | 4135 | platform->driver = platform_drv; |
4264 | if (platform_drv->write) | 4136 | |
4265 | platform->component.write = snd_soc_platform_drv_write; | 4137 | if (platform_drv->probe) |
4266 | if (platform_drv->read) | 4138 | platform->component.probe = snd_soc_platform_drv_probe; |
4267 | platform->component.read = snd_soc_platform_drv_read; | 4139 | if (platform_drv->remove) |
4140 | platform->component.remove = snd_soc_platform_drv_remove; | ||
4141 | |||
4142 | #ifdef CONFIG_DEBUG_FS | ||
4143 | platform->component.debugfs_prefix = "platform"; | ||
4144 | #endif | ||
4268 | 4145 | ||
4269 | mutex_lock(&client_mutex); | 4146 | mutex_lock(&client_mutex); |
4270 | snd_soc_component_add_unlocked(&platform->component); | 4147 | snd_soc_component_add_unlocked(&platform->component); |
@@ -4386,6 +4263,20 @@ static void fixup_codec_formats(struct snd_soc_pcm_stream *stream) | |||
4386 | stream->formats |= codec_format_map[i]; | 4263 | stream->formats |= codec_format_map[i]; |
4387 | } | 4264 | } |
4388 | 4265 | ||
4266 | static int snd_soc_codec_drv_probe(struct snd_soc_component *component) | ||
4267 | { | ||
4268 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); | ||
4269 | |||
4270 | return codec->driver->probe(codec); | ||
4271 | } | ||
4272 | |||
4273 | static void snd_soc_codec_drv_remove(struct snd_soc_component *component) | ||
4274 | { | ||
4275 | struct snd_soc_codec *codec = snd_soc_component_to_codec(component); | ||
4276 | |||
4277 | codec->driver->remove(codec); | ||
4278 | } | ||
4279 | |||
4389 | static int snd_soc_codec_drv_write(struct snd_soc_component *component, | 4280 | static int snd_soc_codec_drv_write(struct snd_soc_component *component, |
4390 | unsigned int reg, unsigned int val) | 4281 | unsigned int reg, unsigned int val) |
4391 | { | 4282 | { |
@@ -4424,7 +4315,6 @@ int snd_soc_register_codec(struct device *dev, | |||
4424 | { | 4315 | { |
4425 | struct snd_soc_codec *codec; | 4316 | struct snd_soc_codec *codec; |
4426 | struct snd_soc_dai *dai; | 4317 | struct snd_soc_dai *dai; |
4427 | struct regmap *regmap; | ||
4428 | int ret, i; | 4318 | int ret, i; |
4429 | 4319 | ||
4430 | dev_dbg(dev, "codec register %s\n", dev_name(dev)); | 4320 | dev_dbg(dev, "codec register %s\n", dev_name(dev)); |
@@ -4434,18 +4324,37 @@ int snd_soc_register_codec(struct device *dev, | |||
4434 | return -ENOMEM; | 4324 | return -ENOMEM; |
4435 | 4325 | ||
4436 | codec->component.dapm_ptr = &codec->dapm; | 4326 | codec->component.dapm_ptr = &codec->dapm; |
4327 | codec->component.codec = codec; | ||
4437 | 4328 | ||
4438 | ret = snd_soc_component_initialize(&codec->component, | 4329 | ret = snd_soc_component_initialize(&codec->component, |
4439 | &codec_drv->component_driver, dev); | 4330 | &codec_drv->component_driver, dev); |
4440 | if (ret) | 4331 | if (ret) |
4441 | goto err_free; | 4332 | goto err_free; |
4442 | 4333 | ||
4334 | if (codec_drv->controls) { | ||
4335 | codec->component.controls = codec_drv->controls; | ||
4336 | codec->component.num_controls = codec_drv->num_controls; | ||
4337 | } | ||
4338 | if (codec_drv->dapm_widgets) { | ||
4339 | codec->component.dapm_widgets = codec_drv->dapm_widgets; | ||
4340 | codec->component.num_dapm_widgets = codec_drv->num_dapm_widgets; | ||
4341 | } | ||
4342 | if (codec_drv->dapm_routes) { | ||
4343 | codec->component.dapm_routes = codec_drv->dapm_routes; | ||
4344 | codec->component.num_dapm_routes = codec_drv->num_dapm_routes; | ||
4345 | } | ||
4346 | |||
4347 | if (codec_drv->probe) | ||
4348 | codec->component.probe = snd_soc_codec_drv_probe; | ||
4349 | if (codec_drv->remove) | ||
4350 | codec->component.remove = snd_soc_codec_drv_remove; | ||
4443 | if (codec_drv->write) | 4351 | if (codec_drv->write) |
4444 | codec->component.write = snd_soc_codec_drv_write; | 4352 | codec->component.write = snd_soc_codec_drv_write; |
4445 | if (codec_drv->read) | 4353 | if (codec_drv->read) |
4446 | codec->component.read = snd_soc_codec_drv_read; | 4354 | codec->component.read = snd_soc_codec_drv_read; |
4447 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; | 4355 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; |
4448 | codec->dapm.codec = codec; | 4356 | codec->dapm.idle_bias_off = codec_drv->idle_bias_off; |
4357 | codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off; | ||
4449 | if (codec_drv->seq_notifier) | 4358 | if (codec_drv->seq_notifier) |
4450 | codec->dapm.seq_notifier = codec_drv->seq_notifier; | 4359 | codec->dapm.seq_notifier = codec_drv->seq_notifier; |
4451 | if (codec_drv->set_bias_level) | 4360 | if (codec_drv->set_bias_level) |
@@ -4455,23 +4364,13 @@ int snd_soc_register_codec(struct device *dev, | |||
4455 | codec->component.val_bytes = codec_drv->reg_word_size; | 4364 | codec->component.val_bytes = codec_drv->reg_word_size; |
4456 | mutex_init(&codec->mutex); | 4365 | mutex_init(&codec->mutex); |
4457 | 4366 | ||
4458 | if (!codec->component.write) { | 4367 | #ifdef CONFIG_DEBUG_FS |
4459 | if (codec_drv->get_regmap) | 4368 | codec->component.init_debugfs = soc_init_codec_debugfs; |
4460 | regmap = codec_drv->get_regmap(dev); | 4369 | codec->component.debugfs_prefix = "codec"; |
4461 | else | 4370 | #endif |
4462 | regmap = dev_get_regmap(dev, NULL); | 4371 | |
4463 | 4372 | if (codec_drv->get_regmap) | |
4464 | if (regmap) { | 4373 | codec->component.regmap = codec_drv->get_regmap(dev); |
4465 | ret = snd_soc_component_init_io(&codec->component, | ||
4466 | regmap); | ||
4467 | if (ret) { | ||
4468 | dev_err(codec->dev, | ||
4469 | "Failed to set cache I/O:%d\n", | ||
4470 | ret); | ||
4471 | goto err_cleanup; | ||
4472 | } | ||
4473 | } | ||
4474 | } | ||
4475 | 4374 | ||
4476 | for (i = 0; i < num_dai; i++) { | 4375 | for (i = 0; i < num_dai; i++) { |
4477 | fixup_codec_formats(&dai_drv[i].playback); | 4376 | fixup_codec_formats(&dai_drv[i].playback); |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 8348352dc2c6..2c456a376ade 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -326,12 +326,13 @@ static struct list_head *dapm_kcontrol_get_path_list( | |||
326 | list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ | 326 | list_for_each_entry(path, dapm_kcontrol_get_path_list(kcontrol), \ |
327 | list_kcontrol) | 327 | list_kcontrol) |
328 | 328 | ||
329 | static unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) | 329 | unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol) |
330 | { | 330 | { |
331 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); | 331 | struct dapm_kcontrol_data *data = snd_kcontrol_chip(kcontrol); |
332 | 332 | ||
333 | return data->value; | 333 | return data->value; |
334 | } | 334 | } |
335 | EXPORT_SYMBOL_GPL(dapm_kcontrol_get_value); | ||
335 | 336 | ||
336 | static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, | 337 | static bool dapm_kcontrol_set_value(const struct snd_kcontrol *kcontrol, |
337 | unsigned int value) | 338 | unsigned int value) |
@@ -1683,6 +1684,22 @@ static void dapm_power_one_widget(struct snd_soc_dapm_widget *w, | |||
1683 | } | 1684 | } |
1684 | } | 1685 | } |
1685 | 1686 | ||
1687 | static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm) | ||
1688 | { | ||
1689 | if (dapm->idle_bias_off) | ||
1690 | return true; | ||
1691 | |||
1692 | switch (snd_power_get_state(dapm->card->snd_card)) { | ||
1693 | case SNDRV_CTL_POWER_D3hot: | ||
1694 | case SNDRV_CTL_POWER_D3cold: | ||
1695 | return dapm->suspend_bias_off; | ||
1696 | default: | ||
1697 | break; | ||
1698 | } | ||
1699 | |||
1700 | return false; | ||
1701 | } | ||
1702 | |||
1686 | /* | 1703 | /* |
1687 | * Scan each dapm widget for complete audio path. | 1704 | * Scan each dapm widget for complete audio path. |
1688 | * A complete path is a route that has valid endpoints i.e.:- | 1705 | * A complete path is a route that has valid endpoints i.e.:- |
@@ -1706,7 +1723,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1706 | trace_snd_soc_dapm_start(card); | 1723 | trace_snd_soc_dapm_start(card); |
1707 | 1724 | ||
1708 | list_for_each_entry(d, &card->dapm_list, list) { | 1725 | list_for_each_entry(d, &card->dapm_list, list) { |
1709 | if (d->idle_bias_off) | 1726 | if (dapm_idle_bias_off(d)) |
1710 | d->target_bias_level = SND_SOC_BIAS_OFF; | 1727 | d->target_bias_level = SND_SOC_BIAS_OFF; |
1711 | else | 1728 | else |
1712 | d->target_bias_level = SND_SOC_BIAS_STANDBY; | 1729 | d->target_bias_level = SND_SOC_BIAS_STANDBY; |
@@ -1772,7 +1789,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1772 | if (d->target_bias_level > bias) | 1789 | if (d->target_bias_level > bias) |
1773 | bias = d->target_bias_level; | 1790 | bias = d->target_bias_level; |
1774 | list_for_each_entry(d, &card->dapm_list, list) | 1791 | list_for_each_entry(d, &card->dapm_list, list) |
1775 | if (!d->idle_bias_off) | 1792 | if (!dapm_idle_bias_off(d)) |
1776 | d->target_bias_level = bias; | 1793 | d->target_bias_level = bias; |
1777 | 1794 | ||
1778 | trace_snd_soc_dapm_walk_done(card); | 1795 | trace_snd_soc_dapm_walk_done(card); |
@@ -2860,12 +2877,14 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2860 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); | 2877 | struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); |
2861 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2878 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2862 | unsigned int reg_val, val; | 2879 | unsigned int reg_val, val; |
2863 | int ret = 0; | ||
2864 | 2880 | ||
2865 | if (e->reg != SND_SOC_NOPM) | 2881 | if (e->reg != SND_SOC_NOPM) { |
2866 | ret = soc_dapm_read(dapm, e->reg, ®_val); | 2882 | int ret = soc_dapm_read(dapm, e->reg, ®_val); |
2867 | else | 2883 | if (ret) |
2884 | return ret; | ||
2885 | } else { | ||
2868 | reg_val = dapm_kcontrol_get_value(kcontrol); | 2886 | reg_val = dapm_kcontrol_get_value(kcontrol); |
2887 | } | ||
2869 | 2888 | ||
2870 | val = (reg_val >> e->shift_l) & e->mask; | 2889 | val = (reg_val >> e->shift_l) & e->mask; |
2871 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); | 2890 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); |
@@ -2875,7 +2894,7 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2875 | ucontrol->value.enumerated.item[1] = val; | 2894 | ucontrol->value.enumerated.item[1] = val; |
2876 | } | 2895 | } |
2877 | 2896 | ||
2878 | return ret; | 2897 | return 0; |
2879 | } | 2898 | } |
2880 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | 2899 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); |
2881 | 2900 | ||
@@ -3107,7 +3126,8 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3107 | } | 3126 | } |
3108 | 3127 | ||
3109 | w->dapm = dapm; | 3128 | w->dapm = dapm; |
3110 | w->codec = dapm->codec; | 3129 | if (dapm->component) |
3130 | w->codec = dapm->component->codec; | ||
3111 | INIT_LIST_HEAD(&w->sources); | 3131 | INIT_LIST_HEAD(&w->sources); |
3112 | INIT_LIST_HEAD(&w->sinks); | 3132 | INIT_LIST_HEAD(&w->sinks); |
3113 | INIT_LIST_HEAD(&w->list); | 3133 | INIT_LIST_HEAD(&w->list); |
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 6307f85e871b..b329b84bc5af 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c | |||
@@ -336,10 +336,12 @@ static const struct snd_pcm_ops dmaengine_pcm_ops = { | |||
336 | }; | 336 | }; |
337 | 337 | ||
338 | static const struct snd_soc_platform_driver dmaengine_pcm_platform = { | 338 | static const struct snd_soc_platform_driver dmaengine_pcm_platform = { |
339 | .component_driver = { | ||
340 | .probe_order = SND_SOC_COMP_ORDER_LATE, | ||
341 | }, | ||
339 | .ops = &dmaengine_pcm_ops, | 342 | .ops = &dmaengine_pcm_ops, |
340 | .pcm_new = dmaengine_pcm_new, | 343 | .pcm_new = dmaengine_pcm_new, |
341 | .pcm_free = dmaengine_pcm_free, | 344 | .pcm_free = dmaengine_pcm_free, |
342 | .probe_order = SND_SOC_COMP_ORDER_LATE, | ||
343 | }; | 345 | }; |
344 | 346 | ||
345 | static const char * const dmaengine_pcm_dma_channel_names[] = { | 347 | static const char * const dmaengine_pcm_dma_channel_names[] = { |
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c index 7767fbd73eb7..9b3939049cef 100644 --- a/sound/soc/soc-io.c +++ b/sound/soc/soc-io.c | |||
@@ -271,31 +271,3 @@ int snd_soc_platform_write(struct snd_soc_platform *platform, | |||
271 | return snd_soc_component_write(&platform->component, reg, val); | 271 | return snd_soc_component_write(&platform->component, reg, val); |
272 | } | 272 | } |
273 | EXPORT_SYMBOL_GPL(snd_soc_platform_write); | 273 | EXPORT_SYMBOL_GPL(snd_soc_platform_write); |
274 | |||
275 | /** | ||
276 | * snd_soc_component_init_io() - Initialize regmap IO | ||
277 | * | ||
278 | * @component: component to initialize | ||
279 | * @regmap: regmap instance to use for IO operations | ||
280 | * | ||
281 | * Return: 0 on success, a negative error code otherwise | ||
282 | */ | ||
283 | int snd_soc_component_init_io(struct snd_soc_component *component, | ||
284 | struct regmap *regmap) | ||
285 | { | ||
286 | int ret; | ||
287 | |||
288 | if (!regmap) | ||
289 | return -EINVAL; | ||
290 | |||
291 | ret = regmap_get_val_bytes(regmap); | ||
292 | /* Errors are legitimate for non-integer byte | ||
293 | * multiples */ | ||
294 | if (ret > 0) | ||
295 | component->val_bytes = ret; | ||
296 | |||
297 | component->regmap = regmap; | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | EXPORT_SYMBOL_GPL(snd_soc_component_init_io); | ||
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 731fdb5b5f9b..642c86240752 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -2352,7 +2352,11 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) | |||
2352 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 2352 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
2353 | fe->dpcm[stream].runtime = fe_substream->runtime; | 2353 | fe->dpcm[stream].runtime = fe_substream->runtime; |
2354 | 2354 | ||
2355 | if (dpcm_path_get(fe, stream, &list) <= 0) { | 2355 | ret = dpcm_path_get(fe, stream, &list); |
2356 | if (ret < 0) { | ||
2357 | mutex_unlock(&fe->card->mutex); | ||
2358 | return ret; | ||
2359 | } else if (ret == 0) { | ||
2356 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", | 2360 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", |
2357 | fe->dai_link->name, stream ? "capture" : "playback"); | 2361 | fe->dai_link->name, stream ? "capture" : "playback"); |
2358 | } | 2362 | } |
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index 0e5a8f35d0ad..a7dc3c56f44d 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * sound/soc/spear/spear_pcm.c | 4 | * sound/soc/spear/spear_pcm.c |
5 | * | 5 | * |
6 | * Copyright (C) 2012 ST Microelectronics | 6 | * Copyright (C) 2012 ST Microelectronics |
7 | * Rajeev Kumar<rajeev-dlh.kumar@st.com> | 7 | * Rajeev Kumar<rajeevkumar.linux@gmail.com> |
8 | * | 8 | * |
9 | * This file is licensed under the terms of the GNU General Public | 9 | * This file is licensed under the terms of the GNU General Public |
10 | * License version 2. This program is licensed "as is" without any | 10 | * License version 2. This program is licensed "as is" without any |
@@ -50,6 +50,6 @@ int devm_spear_pcm_platform_register(struct device *dev, | |||
50 | } | 50 | } |
51 | EXPORT_SYMBOL_GPL(devm_spear_pcm_platform_register); | 51 | EXPORT_SYMBOL_GPL(devm_spear_pcm_platform_register); |
52 | 52 | ||
53 | MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>"); | 53 | MODULE_AUTHOR("Rajeev Kumar <rajeevkumar.linux@gmail.com>"); |
54 | MODULE_DESCRIPTION("SPEAr PCM DMA module"); | 54 | MODULE_DESCRIPTION("SPEAr PCM DMA module"); |
55 | MODULE_LICENSE("GPL"); | 55 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/tegra/tegra_asoc_utils.h b/sound/soc/tegra/tegra_asoc_utils.h index 9577121ce971..ca8037634100 100644 --- a/sound/soc/tegra/tegra_asoc_utils.h +++ b/sound/soc/tegra/tegra_asoc_utils.h | |||
@@ -21,7 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #ifndef __TEGRA_ASOC_UTILS_H__ | 23 | #ifndef __TEGRA_ASOC_UTILS_H__ |
24 | #define __TEGRA_ASOC_UTILS_H_ | 24 | #define __TEGRA_ASOC_UTILS_H__ |
25 | 25 | ||
26 | struct clk; | 26 | struct clk; |
27 | struct device; | 27 | struct device; |
diff --git a/sound/soc/tegra/tegra_max98090.c b/sound/soc/tegra/tegra_max98090.c index b86cd9936ef1..01921d7e73fa 100644 --- a/sound/soc/tegra/tegra_max98090.c +++ b/sound/soc/tegra/tegra_max98090.c | |||
@@ -42,6 +42,7 @@ | |||
42 | struct tegra_max98090 { | 42 | struct tegra_max98090 { |
43 | struct tegra_asoc_utils_data util_data; | 43 | struct tegra_asoc_utils_data util_data; |
44 | int gpio_hp_det; | 44 | int gpio_hp_det; |
45 | int gpio_mic_det; | ||
45 | }; | 46 | }; |
46 | 47 | ||
47 | static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, | 48 | static int tegra_max98090_asoc_hw_params(struct snd_pcm_substream *substream, |
@@ -112,6 +113,22 @@ static struct snd_soc_jack_gpio tegra_max98090_hp_jack_gpio = { | |||
112 | .invert = 1, | 113 | .invert = 1, |
113 | }; | 114 | }; |
114 | 115 | ||
116 | static struct snd_soc_jack tegra_max98090_mic_jack; | ||
117 | |||
118 | static struct snd_soc_jack_pin tegra_max98090_mic_jack_pins[] = { | ||
119 | { | ||
120 | .pin = "Mic Jack", | ||
121 | .mask = SND_JACK_MICROPHONE, | ||
122 | }, | ||
123 | }; | ||
124 | |||
125 | static struct snd_soc_jack_gpio tegra_max98090_mic_jack_gpio = { | ||
126 | .name = "Mic detection", | ||
127 | .report = SND_JACK_MICROPHONE, | ||
128 | .debounce_time = 150, | ||
129 | .invert = 1, | ||
130 | }; | ||
131 | |||
115 | static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { | 132 | static const struct snd_soc_dapm_widget tegra_max98090_dapm_widgets[] = { |
116 | SND_SOC_DAPM_HP("Headphones", NULL), | 133 | SND_SOC_DAPM_HP("Headphones", NULL), |
117 | SND_SOC_DAPM_SPK("Speakers", NULL), | 134 | SND_SOC_DAPM_SPK("Speakers", NULL), |
@@ -141,6 +158,19 @@ static int tegra_max98090_asoc_init(struct snd_soc_pcm_runtime *rtd) | |||
141 | &tegra_max98090_hp_jack_gpio); | 158 | &tegra_max98090_hp_jack_gpio); |
142 | } | 159 | } |
143 | 160 | ||
161 | if (gpio_is_valid(machine->gpio_mic_det)) { | ||
162 | snd_soc_jack_new(codec, "Mic Jack", SND_JACK_MICROPHONE, | ||
163 | &tegra_max98090_mic_jack); | ||
164 | snd_soc_jack_add_pins(&tegra_max98090_mic_jack, | ||
165 | ARRAY_SIZE(tegra_max98090_mic_jack_pins), | ||
166 | tegra_max98090_mic_jack_pins); | ||
167 | |||
168 | tegra_max98090_mic_jack_gpio.gpio = machine->gpio_mic_det; | ||
169 | snd_soc_jack_add_gpios(&tegra_max98090_mic_jack, | ||
170 | 1, | ||
171 | &tegra_max98090_mic_jack_gpio); | ||
172 | } | ||
173 | |||
144 | return 0; | 174 | return 0; |
145 | } | 175 | } |
146 | 176 | ||
@@ -153,6 +183,11 @@ static int tegra_max98090_card_remove(struct snd_soc_card *card) | |||
153 | &tegra_max98090_hp_jack_gpio); | 183 | &tegra_max98090_hp_jack_gpio); |
154 | } | 184 | } |
155 | 185 | ||
186 | if (gpio_is_valid(machine->gpio_mic_det)) { | ||
187 | snd_soc_jack_free_gpios(&tegra_max98090_mic_jack, 1, | ||
188 | &tegra_max98090_mic_jack_gpio); | ||
189 | } | ||
190 | |||
156 | return 0; | 191 | return 0; |
157 | } | 192 | } |
158 | 193 | ||
@@ -201,6 +236,11 @@ static int tegra_max98090_probe(struct platform_device *pdev) | |||
201 | if (machine->gpio_hp_det == -EPROBE_DEFER) | 236 | if (machine->gpio_hp_det == -EPROBE_DEFER) |
202 | return -EPROBE_DEFER; | 237 | return -EPROBE_DEFER; |
203 | 238 | ||
239 | machine->gpio_mic_det = | ||
240 | of_get_named_gpio(np, "nvidia,mic-det-gpios", 0); | ||
241 | if (machine->gpio_mic_det == -EPROBE_DEFER) | ||
242 | return -EPROBE_DEFER; | ||
243 | |||
204 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); | 244 | ret = snd_soc_of_parse_card_name(card, "nvidia,model"); |
205 | if (ret) | 245 | if (ret) |
206 | goto err; | 246 | goto err; |
diff --git a/sound/usb/caiaq/control.c b/sound/usb/caiaq/control.c index f65fc0987cfb..b7a7c805d63f 100644 --- a/sound/usb/caiaq/control.c +++ b/sound/usb/caiaq/control.c | |||
@@ -100,15 +100,19 @@ static int control_put(struct snd_kcontrol *kcontrol, | |||
100 | struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card); | 100 | struct snd_usb_caiaqdev *cdev = caiaqdev(chip->card); |
101 | int pos = kcontrol->private_value; | 101 | int pos = kcontrol->private_value; |
102 | int v = ucontrol->value.integer.value[0]; | 102 | int v = ucontrol->value.integer.value[0]; |
103 | unsigned char cmd = EP1_CMD_WRITE_IO; | 103 | unsigned char cmd; |
104 | 104 | ||
105 | if (cdev->chip.usb_id == | 105 | switch (cdev->chip.usb_id) { |
106 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1)) | 106 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER): |
107 | cmd = EP1_CMD_DIMM_LEDS; | 107 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1): |
108 | 108 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2): | |
109 | if (cdev->chip.usb_id == | 109 | case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER): |
110 | USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_MASCHINECONTROLLER)) | ||
111 | cmd = EP1_CMD_DIMM_LEDS; | 110 | cmd = EP1_CMD_DIMM_LEDS; |
111 | break; | ||
112 | default: | ||
113 | cmd = EP1_CMD_WRITE_IO; | ||
114 | break; | ||
115 | } | ||
112 | 116 | ||
113 | if (pos & CNT_INTVAL) { | 117 | if (pos & CNT_INTVAL) { |
114 | int i = pos & ~CNT_INTVAL; | 118 | int i = pos & ~CNT_INTVAL; |