diff options
Diffstat (limited to 'sound')
161 files changed, 14937 insertions, 3824 deletions
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a2104671f51d..5dcf88bed9b7 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -1242,6 +1242,7 @@ int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_par | |||
1242 | return -EINVAL; | 1242 | return -EINVAL; |
1243 | return 0; | 1243 | return 0; |
1244 | } | 1244 | } |
1245 | EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64); | ||
1245 | 1246 | ||
1246 | /** | 1247 | /** |
1247 | * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval | 1248 | * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index ec4536c8d8d4..dafcf82139e2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -932,7 +932,7 @@ int snd_hda_bus_new(struct snd_card *card, | |||
932 | } | 932 | } |
933 | EXPORT_SYMBOL_GPL(snd_hda_bus_new); | 933 | EXPORT_SYMBOL_GPL(snd_hda_bus_new); |
934 | 934 | ||
935 | #ifdef CONFIG_SND_HDA_GENERIC | 935 | #if IS_ENABLED(CONFIG_SND_HDA_GENERIC) |
936 | #define is_generic_config(codec) \ | 936 | #define is_generic_config(codec) \ |
937 | (codec->modelname && !strcmp(codec->modelname, "generic")) | 937 | (codec->modelname && !strcmp(codec->modelname, "generic")) |
938 | #else | 938 | #else |
@@ -1339,23 +1339,15 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) | |||
1339 | /* | 1339 | /* |
1340 | * Dynamic symbol binding for the codec parsers | 1340 | * Dynamic symbol binding for the codec parsers |
1341 | */ | 1341 | */ |
1342 | #ifdef MODULE | ||
1343 | #define load_parser_sym(sym) ((int (*)(struct hda_codec *))symbol_request(sym)) | ||
1344 | #define unload_parser_addr(addr) symbol_put_addr(addr) | ||
1345 | #else | ||
1346 | #define load_parser_sym(sym) (sym) | ||
1347 | #define unload_parser_addr(addr) do {} while (0) | ||
1348 | #endif | ||
1349 | 1342 | ||
1350 | #define load_parser(codec, sym) \ | 1343 | #define load_parser(codec, sym) \ |
1351 | ((codec)->parser = load_parser_sym(sym)) | 1344 | ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym)) |
1352 | 1345 | ||
1353 | static void unload_parser(struct hda_codec *codec) | 1346 | static void unload_parser(struct hda_codec *codec) |
1354 | { | 1347 | { |
1355 | if (codec->parser) { | 1348 | if (codec->parser) |
1356 | unload_parser_addr(codec->parser); | 1349 | symbol_put_addr(codec->parser); |
1357 | codec->parser = NULL; | 1350 | codec->parser = NULL; |
1358 | } | ||
1359 | } | 1351 | } |
1360 | 1352 | ||
1361 | /* | 1353 | /* |
@@ -1570,7 +1562,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) | |||
1570 | EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets); | 1562 | EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets); |
1571 | 1563 | ||
1572 | 1564 | ||
1573 | #ifdef CONFIG_SND_HDA_CODEC_HDMI | 1565 | #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) |
1574 | /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ | 1566 | /* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ |
1575 | static bool is_likely_hdmi_codec(struct hda_codec *codec) | 1567 | static bool is_likely_hdmi_codec(struct hda_codec *codec) |
1576 | { | 1568 | { |
@@ -1620,12 +1612,20 @@ int snd_hda_codec_configure(struct hda_codec *codec) | |||
1620 | patch = codec->preset->patch; | 1612 | patch = codec->preset->patch; |
1621 | if (!patch) { | 1613 | if (!patch) { |
1622 | unload_parser(codec); /* to be sure */ | 1614 | unload_parser(codec); /* to be sure */ |
1623 | if (is_likely_hdmi_codec(codec)) | 1615 | if (is_likely_hdmi_codec(codec)) { |
1616 | #if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) | ||
1624 | patch = load_parser(codec, snd_hda_parse_hdmi_codec); | 1617 | patch = load_parser(codec, snd_hda_parse_hdmi_codec); |
1625 | #ifdef CONFIG_SND_HDA_GENERIC | 1618 | #elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI) |
1626 | if (!patch) | 1619 | patch = snd_hda_parse_hdmi_codec; |
1620 | #endif | ||
1621 | } | ||
1622 | if (!patch) { | ||
1623 | #if IS_MODULE(CONFIG_SND_HDA_GENERIC) | ||
1627 | patch = load_parser(codec, snd_hda_parse_generic_codec); | 1624 | patch = load_parser(codec, snd_hda_parse_generic_codec); |
1625 | #elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC) | ||
1626 | patch = snd_hda_parse_generic_codec; | ||
1628 | #endif | 1627 | #endif |
1628 | } | ||
1629 | if (!patch) { | 1629 | if (!patch) { |
1630 | printk(KERN_ERR "hda-codec: No codec parser is available\n"); | 1630 | printk(KERN_ERR "hda-codec: No codec parser is available\n"); |
1631 | return -ENODEV; | 1631 | return -ENODEV; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 8321a97d5c05..d9a09bdd09db 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -3269,7 +3269,7 @@ static int cap_put_caller(struct snd_kcontrol *kcontrol, | |||
3269 | mutex_unlock(&codec->control_mutex); | 3269 | mutex_unlock(&codec->control_mutex); |
3270 | snd_hda_codec_flush_cache(codec); /* flush the updates */ | 3270 | snd_hda_codec_flush_cache(codec); /* flush the updates */ |
3271 | if (err >= 0 && spec->cap_sync_hook) | 3271 | if (err >= 0 && spec->cap_sync_hook) |
3272 | spec->cap_sync_hook(codec, ucontrol); | 3272 | spec->cap_sync_hook(codec, kcontrol, ucontrol); |
3273 | return err; | 3273 | return err; |
3274 | } | 3274 | } |
3275 | 3275 | ||
@@ -3390,7 +3390,7 @@ static int cap_single_sw_put(struct snd_kcontrol *kcontrol, | |||
3390 | return ret; | 3390 | return ret; |
3391 | 3391 | ||
3392 | if (spec->cap_sync_hook) | 3392 | if (spec->cap_sync_hook) |
3393 | spec->cap_sync_hook(codec, ucontrol); | 3393 | spec->cap_sync_hook(codec, kcontrol, ucontrol); |
3394 | 3394 | ||
3395 | return ret; | 3395 | return ret; |
3396 | } | 3396 | } |
@@ -3795,7 +3795,7 @@ static int mux_select(struct hda_codec *codec, unsigned int adc_idx, | |||
3795 | return 0; | 3795 | return 0; |
3796 | snd_hda_activate_path(codec, path, true, false); | 3796 | snd_hda_activate_path(codec, path, true, false); |
3797 | if (spec->cap_sync_hook) | 3797 | if (spec->cap_sync_hook) |
3798 | spec->cap_sync_hook(codec, NULL); | 3798 | spec->cap_sync_hook(codec, NULL, NULL); |
3799 | path_power_down_sync(codec, old_path); | 3799 | path_power_down_sync(codec, old_path); |
3800 | return 1; | 3800 | return 1; |
3801 | } | 3801 | } |
@@ -5270,7 +5270,7 @@ static void init_input_src(struct hda_codec *codec) | |||
5270 | } | 5270 | } |
5271 | 5271 | ||
5272 | if (spec->cap_sync_hook) | 5272 | if (spec->cap_sync_hook) |
5273 | spec->cap_sync_hook(codec, NULL); | 5273 | spec->cap_sync_hook(codec, NULL, NULL); |
5274 | } | 5274 | } |
5275 | 5275 | ||
5276 | /* set right pin controls for digital I/O */ | 5276 | /* set right pin controls for digital I/O */ |
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h index 07f767231c9f..c908afbe4d94 100644 --- a/sound/pci/hda/hda_generic.h +++ b/sound/pci/hda/hda_generic.h | |||
@@ -274,6 +274,7 @@ struct hda_gen_spec { | |||
274 | void (*init_hook)(struct hda_codec *codec); | 274 | void (*init_hook)(struct hda_codec *codec); |
275 | void (*automute_hook)(struct hda_codec *codec); | 275 | void (*automute_hook)(struct hda_codec *codec); |
276 | void (*cap_sync_hook)(struct hda_codec *codec, | 276 | void (*cap_sync_hook)(struct hda_codec *codec, |
277 | struct snd_kcontrol *kcontrol, | ||
277 | struct snd_ctl_elem_value *ucontrol); | 278 | struct snd_ctl_elem_value *ucontrol); |
278 | 279 | ||
279 | /* PCM hooks */ | 280 | /* PCM hooks */ |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index fa2879a21a50..e354ab1ec20f 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -198,7 +198,7 @@ MODULE_DESCRIPTION("Intel HDA driver"); | |||
198 | #endif | 198 | #endif |
199 | 199 | ||
200 | #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO) | 200 | #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO) |
201 | #ifdef CONFIG_SND_HDA_CODEC_HDMI | 201 | #if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) |
202 | #define SUPPORT_VGA_SWITCHEROO | 202 | #define SUPPORT_VGA_SWITCHEROO |
203 | #endif | 203 | #endif |
204 | #endif | 204 | #endif |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 7a426ed491f2..8ed0bcc01386 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
@@ -244,6 +244,19 @@ static void ad_fixup_inv_jack_detect(struct hda_codec *codec, | |||
244 | } | 244 | } |
245 | } | 245 | } |
246 | 246 | ||
247 | /* Toshiba Satellite L40 implements EAPD in a standard way unlike others */ | ||
248 | static void ad1986a_fixup_eapd(struct hda_codec *codec, | ||
249 | const struct hda_fixup *fix, int action) | ||
250 | { | ||
251 | struct ad198x_spec *spec = codec->spec; | ||
252 | |||
253 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
254 | codec->inv_eapd = 0; | ||
255 | spec->gen.keep_eapd_on = 1; | ||
256 | spec->eapd_nid = 0x1b; | ||
257 | } | ||
258 | } | ||
259 | |||
247 | enum { | 260 | enum { |
248 | AD1986A_FIXUP_INV_JACK_DETECT, | 261 | AD1986A_FIXUP_INV_JACK_DETECT, |
249 | AD1986A_FIXUP_ULTRA, | 262 | AD1986A_FIXUP_ULTRA, |
@@ -251,6 +264,7 @@ enum { | |||
251 | AD1986A_FIXUP_3STACK, | 264 | AD1986A_FIXUP_3STACK, |
252 | AD1986A_FIXUP_LAPTOP, | 265 | AD1986A_FIXUP_LAPTOP, |
253 | AD1986A_FIXUP_LAPTOP_IMIC, | 266 | AD1986A_FIXUP_LAPTOP_IMIC, |
267 | AD1986A_FIXUP_EAPD, | ||
254 | }; | 268 | }; |
255 | 269 | ||
256 | static const struct hda_fixup ad1986a_fixups[] = { | 270 | static const struct hda_fixup ad1986a_fixups[] = { |
@@ -311,6 +325,10 @@ static const struct hda_fixup ad1986a_fixups[] = { | |||
311 | .chained_before = 1, | 325 | .chained_before = 1, |
312 | .chain_id = AD1986A_FIXUP_LAPTOP, | 326 | .chain_id = AD1986A_FIXUP_LAPTOP, |
313 | }, | 327 | }, |
328 | [AD1986A_FIXUP_EAPD] = { | ||
329 | .type = HDA_FIXUP_FUNC, | ||
330 | .v.func = ad1986a_fixup_eapd, | ||
331 | }, | ||
314 | }; | 332 | }; |
315 | 333 | ||
316 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { | 334 | static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { |
@@ -318,6 +336,7 @@ static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { | |||
318 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), | 336 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), |
319 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), | 337 | SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), |
320 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), | 338 | SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), |
339 | SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD), | ||
321 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), | 340 | SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), |
322 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), | 341 | SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), |
323 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), | 342 | SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), |
@@ -472,6 +491,8 @@ static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) | |||
472 | static int patch_ad1983(struct hda_codec *codec) | 491 | static int patch_ad1983(struct hda_codec *codec) |
473 | { | 492 | { |
474 | struct ad198x_spec *spec; | 493 | struct ad198x_spec *spec; |
494 | static hda_nid_t conn_0c[] = { 0x08 }; | ||
495 | static hda_nid_t conn_0d[] = { 0x09 }; | ||
475 | int err; | 496 | int err; |
476 | 497 | ||
477 | err = alloc_ad_spec(codec); | 498 | err = alloc_ad_spec(codec); |
@@ -479,8 +500,14 @@ static int patch_ad1983(struct hda_codec *codec) | |||
479 | return err; | 500 | return err; |
480 | spec = codec->spec; | 501 | spec = codec->spec; |
481 | 502 | ||
503 | spec->gen.mixer_nid = 0x0e; | ||
482 | spec->gen.beep_nid = 0x10; | 504 | spec->gen.beep_nid = 0x10; |
483 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | 505 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); |
506 | |||
507 | /* limit the loopback routes not to confuse the parser */ | ||
508 | snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c); | ||
509 | snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d); | ||
510 | |||
484 | err = ad198x_parse_auto_config(codec, false); | 511 | err = ad198x_parse_auto_config(codec, false); |
485 | if (err < 0) | 512 | if (err < 0) |
486 | goto error; | 513 | goto error; |
@@ -999,6 +1026,9 @@ static void ad1884_fixup_thinkpad(struct hda_codec *codec, | |||
999 | spec->gen.keep_eapd_on = 1; | 1026 | spec->gen.keep_eapd_on = 1; |
1000 | spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; | 1027 | spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; |
1001 | spec->eapd_nid = 0x12; | 1028 | spec->eapd_nid = 0x12; |
1029 | /* Analog PC Beeper - allow firmware/ACPI beeps */ | ||
1030 | spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT); | ||
1031 | spec->gen.beep_nid = 0; /* no digital beep */ | ||
1002 | } | 1032 | } |
1003 | } | 1033 | } |
1004 | 1034 | ||
@@ -1065,6 +1095,7 @@ static int patch_ad1884(struct hda_codec *codec) | |||
1065 | spec = codec->spec; | 1095 | spec = codec->spec; |
1066 | 1096 | ||
1067 | spec->gen.mixer_nid = 0x20; | 1097 | spec->gen.mixer_nid = 0x20; |
1098 | spec->gen.mixer_merge_nid = 0x21; | ||
1068 | spec->gen.beep_nid = 0x10; | 1099 | spec->gen.beep_nid = 0x10; |
1069 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); | 1100 | set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); |
1070 | 1101 | ||
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 54d14793725a..46ecdbb9053f 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c | |||
@@ -2662,60 +2662,6 @@ static bool dspload_wait_loaded(struct hda_codec *codec) | |||
2662 | } | 2662 | } |
2663 | 2663 | ||
2664 | /* | 2664 | /* |
2665 | * PCM stuffs | ||
2666 | */ | ||
2667 | static void ca0132_setup_stream(struct hda_codec *codec, hda_nid_t nid, | ||
2668 | u32 stream_tag, | ||
2669 | int channel_id, int format) | ||
2670 | { | ||
2671 | unsigned int oldval, newval; | ||
2672 | |||
2673 | if (!nid) | ||
2674 | return; | ||
2675 | |||
2676 | snd_printdd( | ||
2677 | "ca0132_setup_stream: NID=0x%x, stream=0x%x, " | ||
2678 | "channel=%d, format=0x%x\n", | ||
2679 | nid, stream_tag, channel_id, format); | ||
2680 | |||
2681 | /* update the format-id if changed */ | ||
2682 | oldval = snd_hda_codec_read(codec, nid, 0, | ||
2683 | AC_VERB_GET_STREAM_FORMAT, | ||
2684 | 0); | ||
2685 | if (oldval != format) { | ||
2686 | msleep(20); | ||
2687 | snd_hda_codec_write(codec, nid, 0, | ||
2688 | AC_VERB_SET_STREAM_FORMAT, | ||
2689 | format); | ||
2690 | } | ||
2691 | |||
2692 | oldval = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
2693 | newval = (stream_tag << 4) | channel_id; | ||
2694 | if (oldval != newval) { | ||
2695 | snd_hda_codec_write(codec, nid, 0, | ||
2696 | AC_VERB_SET_CHANNEL_STREAMID, | ||
2697 | newval); | ||
2698 | } | ||
2699 | } | ||
2700 | |||
2701 | static void ca0132_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) | ||
2702 | { | ||
2703 | unsigned int val; | ||
2704 | |||
2705 | if (!nid) | ||
2706 | return; | ||
2707 | |||
2708 | snd_printdd(KERN_INFO "ca0132_cleanup_stream: NID=0x%x\n", nid); | ||
2709 | |||
2710 | val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); | ||
2711 | if (!val) | ||
2712 | return; | ||
2713 | |||
2714 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_STREAM_FORMAT, 0); | ||
2715 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); | ||
2716 | } | ||
2717 | |||
2718 | /* | ||
2719 | * PCM callbacks | 2665 | * PCM callbacks |
2720 | */ | 2666 | */ |
2721 | static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 2667 | static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
@@ -2726,7 +2672,7 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
2726 | { | 2672 | { |
2727 | struct ca0132_spec *spec = codec->spec; | 2673 | struct ca0132_spec *spec = codec->spec; |
2728 | 2674 | ||
2729 | ca0132_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); | 2675 | snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); |
2730 | 2676 | ||
2731 | return 0; | 2677 | return 0; |
2732 | } | 2678 | } |
@@ -2745,7 +2691,7 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
2745 | if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) | 2691 | if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) |
2746 | msleep(50); | 2692 | msleep(50); |
2747 | 2693 | ||
2748 | ca0132_cleanup_stream(codec, spec->dacs[0]); | 2694 | snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); |
2749 | 2695 | ||
2750 | return 0; | 2696 | return 0; |
2751 | } | 2697 | } |
@@ -2822,10 +2768,8 @@ static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
2822 | unsigned int format, | 2768 | unsigned int format, |
2823 | struct snd_pcm_substream *substream) | 2769 | struct snd_pcm_substream *substream) |
2824 | { | 2770 | { |
2825 | struct ca0132_spec *spec = codec->spec; | 2771 | snd_hda_codec_setup_stream(codec, hinfo->nid, |
2826 | 2772 | stream_tag, 0, format); | |
2827 | ca0132_setup_stream(codec, spec->adcs[substream->number], | ||
2828 | stream_tag, 0, format); | ||
2829 | 2773 | ||
2830 | return 0; | 2774 | return 0; |
2831 | } | 2775 | } |
@@ -2839,7 +2783,7 @@ static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
2839 | if (spec->dsp_state == DSP_DOWNLOADING) | 2783 | if (spec->dsp_state == DSP_DOWNLOADING) |
2840 | return 0; | 2784 | return 0; |
2841 | 2785 | ||
2842 | ca0132_cleanup_stream(codec, hinfo->nid); | 2786 | snd_hda_codec_cleanup_stream(codec, hinfo->nid); |
2843 | return 0; | 2787 | return 0; |
2844 | } | 2788 | } |
2845 | 2789 | ||
@@ -4742,6 +4686,8 @@ static int patch_ca0132(struct hda_codec *codec) | |||
4742 | return err; | 4686 | return err; |
4743 | 4687 | ||
4744 | codec->patch_ops = ca0132_patch_ops; | 4688 | codec->patch_ops = ca0132_patch_ops; |
4689 | codec->pcm_format_first = 1; | ||
4690 | codec->no_sticky_stream = 1; | ||
4745 | 4691 | ||
4746 | return 0; | 4692 | return 0; |
4747 | } | 4693 | } |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 4e0ec146553d..bcf91bea3317 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -3291,7 +3291,8 @@ static void cxt_update_headset_mode(struct hda_codec *codec) | |||
3291 | } | 3291 | } |
3292 | 3292 | ||
3293 | static void cxt_update_headset_mode_hook(struct hda_codec *codec, | 3293 | static void cxt_update_headset_mode_hook(struct hda_codec *codec, |
3294 | struct snd_ctl_elem_value *ucontrol) | 3294 | struct snd_kcontrol *kcontrol, |
3295 | struct snd_ctl_elem_value *ucontrol) | ||
3295 | { | 3296 | { |
3296 | cxt_update_headset_mode(codec); | 3297 | cxt_update_headset_mode(codec); |
3297 | } | 3298 | } |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 56a8f1876603..850296a1e0ff 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -708,7 +708,8 @@ static void alc_inv_dmic_sync(struct hda_codec *codec, bool force) | |||
708 | } | 708 | } |
709 | 709 | ||
710 | static void alc_inv_dmic_hook(struct hda_codec *codec, | 710 | static void alc_inv_dmic_hook(struct hda_codec *codec, |
711 | struct snd_ctl_elem_value *ucontrol) | 711 | struct snd_kcontrol *kcontrol, |
712 | struct snd_ctl_elem_value *ucontrol) | ||
712 | { | 713 | { |
713 | alc_inv_dmic_sync(codec, false); | 714 | alc_inv_dmic_sync(codec, false); |
714 | } | 715 | } |
@@ -1821,6 +1822,7 @@ enum { | |||
1821 | ALC889_FIXUP_IMAC91_VREF, | 1822 | ALC889_FIXUP_IMAC91_VREF, |
1822 | ALC889_FIXUP_MBA11_VREF, | 1823 | ALC889_FIXUP_MBA11_VREF, |
1823 | ALC889_FIXUP_MBA21_VREF, | 1824 | ALC889_FIXUP_MBA21_VREF, |
1825 | ALC889_FIXUP_MP11_VREF, | ||
1824 | ALC882_FIXUP_INV_DMIC, | 1826 | ALC882_FIXUP_INV_DMIC, |
1825 | ALC882_FIXUP_NO_PRIMARY_HP, | 1827 | ALC882_FIXUP_NO_PRIMARY_HP, |
1826 | ALC887_FIXUP_ASUS_BASS, | 1828 | ALC887_FIXUP_ASUS_BASS, |
@@ -2190,6 +2192,12 @@ static const struct hda_fixup alc882_fixups[] = { | |||
2190 | .chained = true, | 2192 | .chained = true, |
2191 | .chain_id = ALC889_FIXUP_MBP_VREF, | 2193 | .chain_id = ALC889_FIXUP_MBP_VREF, |
2192 | }, | 2194 | }, |
2195 | [ALC889_FIXUP_MP11_VREF] = { | ||
2196 | .type = HDA_FIXUP_FUNC, | ||
2197 | .v.func = alc889_fixup_mba11_vref, | ||
2198 | .chained = true, | ||
2199 | .chain_id = ALC885_FIXUP_MACPRO_GPIO, | ||
2200 | }, | ||
2193 | [ALC882_FIXUP_INV_DMIC] = { | 2201 | [ALC882_FIXUP_INV_DMIC] = { |
2194 | .type = HDA_FIXUP_FUNC, | 2202 | .type = HDA_FIXUP_FUNC, |
2195 | .v.func = alc_fixup_inv_dmic_0x12, | 2203 | .v.func = alc_fixup_inv_dmic_0x12, |
@@ -2253,7 +2261,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { | |||
2253 | SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), | 2261 | SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), |
2254 | SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), | 2262 | SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), |
2255 | SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), | 2263 | SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), |
2256 | SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO), | 2264 | SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF), |
2257 | SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), | 2265 | SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), |
2258 | SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), | 2266 | SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), |
2259 | SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), | 2267 | SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), |
@@ -3211,7 +3219,8 @@ static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled) | |||
3211 | 3219 | ||
3212 | /* turn on/off mic-mute LED per capture hook */ | 3220 | /* turn on/off mic-mute LED per capture hook */ |
3213 | static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec, | 3221 | static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec, |
3214 | struct snd_ctl_elem_value *ucontrol) | 3222 | struct snd_kcontrol *kcontrol, |
3223 | struct snd_ctl_elem_value *ucontrol) | ||
3215 | { | 3224 | { |
3216 | struct alc_spec *spec = codec->spec; | 3225 | struct alc_spec *spec = codec->spec; |
3217 | unsigned int oldval = spec->gpio_led; | 3226 | unsigned int oldval = spec->gpio_led; |
@@ -3521,7 +3530,8 @@ static void alc_update_headset_mode(struct hda_codec *codec) | |||
3521 | } | 3530 | } |
3522 | 3531 | ||
3523 | static void alc_update_headset_mode_hook(struct hda_codec *codec, | 3532 | static void alc_update_headset_mode_hook(struct hda_codec *codec, |
3524 | struct snd_ctl_elem_value *ucontrol) | 3533 | struct snd_kcontrol *kcontrol, |
3534 | struct snd_ctl_elem_value *ucontrol) | ||
3525 | { | 3535 | { |
3526 | alc_update_headset_mode(codec); | 3536 | alc_update_headset_mode(codec); |
3527 | } | 3537 | } |
@@ -4243,6 +4253,7 @@ static const struct hda_fixup alc269_fixups[] = { | |||
4243 | }; | 4253 | }; |
4244 | 4254 | ||
4245 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 4255 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
4256 | SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC), | ||
4246 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), | 4257 | SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), |
4247 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), | 4258 | SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), |
4248 | SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), | 4259 | SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), |
@@ -4298,7 +4309,9 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4298 | SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | 4309 | SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), |
4299 | SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | 4310 | SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), |
4300 | SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | 4311 | SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), |
4312 | SND_PCI_QUIRK(0x1028, 0x0657, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
4301 | SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), | 4313 | SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), |
4314 | SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | ||
4302 | SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), | 4315 | SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), |
4303 | SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 4316 | SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
4304 | SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), | 4317 | SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), |
@@ -4307,6 +4320,54 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4307 | SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4320 | SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
4308 | SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 4321 | SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
4309 | SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), | 4322 | SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), |
4323 | /* ALC282 */ | ||
4324 | SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4325 | SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4326 | SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4327 | SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4328 | SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4329 | SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4330 | SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4331 | SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4332 | SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4333 | SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4334 | SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4335 | SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4336 | SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4337 | SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4338 | SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4339 | SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4340 | SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4341 | SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4342 | SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4343 | SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4344 | SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4345 | SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4346 | /* ALC290 */ | ||
4347 | SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4348 | SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4349 | SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4350 | SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4351 | SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4352 | SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4353 | SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4354 | SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4355 | SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4356 | SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4357 | SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4358 | SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4359 | SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4360 | SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4361 | SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4362 | SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4363 | SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4364 | SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4365 | SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4366 | SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4367 | SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4368 | SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4369 | SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4370 | SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | ||
4310 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), | 4371 | SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), |
4311 | SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), | 4372 | SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), |
4312 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), | 4373 | SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), |
@@ -4322,6 +4383,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
4322 | SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), | 4383 | SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), |
4323 | SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), | 4384 | SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), |
4324 | SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), | 4385 | SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), |
4386 | SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), | ||
4325 | SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), | 4387 | SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), |
4326 | SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), | 4388 | SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), |
4327 | SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), | 4389 | SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), |
@@ -5096,12 +5158,13 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { | |||
5096 | SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), | 5158 | SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), |
5097 | SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 5159 | SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
5098 | SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 5160 | SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
5161 | SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | ||
5099 | SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_AUTO_MUTE), | 5162 | SND_PCI_QUIRK(0x1028, 0x0623, "Dell", ALC668_FIXUP_AUTO_MUTE), |
5100 | SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_AUTO_MUTE), | 5163 | SND_PCI_QUIRK(0x1028, 0x0624, "Dell", ALC668_FIXUP_AUTO_MUTE), |
5101 | SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 5164 | SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
5102 | SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 5165 | SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), |
5103 | SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE), | 5166 | SND_PCI_QUIRK(0x1028, 0x0628, "Dell", ALC668_FIXUP_AUTO_MUTE), |
5104 | SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), | 5167 | SND_PCI_QUIRK(0x1028, 0x064e, "Dell", ALC668_FIXUP_AUTO_MUTE), |
5105 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), | 5168 | SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), |
5106 | SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP), | 5169 | SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A_CHMAP), |
5107 | SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP), | 5170 | SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_CHMAP), |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6998cf29b9bc..3bc29c9b2529 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -83,6 +83,7 @@ enum { | |||
83 | STAC_DELL_M6_BOTH, | 83 | STAC_DELL_M6_BOTH, |
84 | STAC_DELL_EQ, | 84 | STAC_DELL_EQ, |
85 | STAC_ALIENWARE_M17X, | 85 | STAC_ALIENWARE_M17X, |
86 | STAC_92HD89XX_HP_FRONT_JACK, | ||
86 | STAC_92HD73XX_MODELS | 87 | STAC_92HD73XX_MODELS |
87 | }; | 88 | }; |
88 | 89 | ||
@@ -97,6 +98,7 @@ enum { | |||
97 | STAC_92HD83XXX_HP_LED, | 98 | STAC_92HD83XXX_HP_LED, |
98 | STAC_92HD83XXX_HP_INV_LED, | 99 | STAC_92HD83XXX_HP_INV_LED, |
99 | STAC_92HD83XXX_HP_MIC_LED, | 100 | STAC_92HD83XXX_HP_MIC_LED, |
101 | STAC_HP_LED_GPIO10, | ||
100 | STAC_92HD83XXX_HEADSET_JACK, | 102 | STAC_92HD83XXX_HEADSET_JACK, |
101 | STAC_92HD83XXX_HP, | 103 | STAC_92HD83XXX_HP, |
102 | STAC_HP_ENVY_BASS, | 104 | STAC_HP_ENVY_BASS, |
@@ -194,7 +196,7 @@ struct sigmatel_spec { | |||
194 | int default_polarity; | 196 | int default_polarity; |
195 | 197 | ||
196 | unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ | 198 | unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ |
197 | bool mic_mute_led_on; /* current mic mute state */ | 199 | unsigned int mic_enabled; /* current mic mute state (bitmask) */ |
198 | 200 | ||
199 | /* stream */ | 201 | /* stream */ |
200 | unsigned int stream_delay; | 202 | unsigned int stream_delay; |
@@ -324,19 +326,26 @@ static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, | |||
324 | 326 | ||
325 | /* hook for controlling mic-mute LED GPIO */ | 327 | /* hook for controlling mic-mute LED GPIO */ |
326 | static void stac_capture_led_hook(struct hda_codec *codec, | 328 | static void stac_capture_led_hook(struct hda_codec *codec, |
327 | struct snd_ctl_elem_value *ucontrol) | 329 | struct snd_kcontrol *kcontrol, |
330 | struct snd_ctl_elem_value *ucontrol) | ||
328 | { | 331 | { |
329 | struct sigmatel_spec *spec = codec->spec; | 332 | struct sigmatel_spec *spec = codec->spec; |
330 | bool mute; | 333 | unsigned int mask; |
334 | bool cur_mute, prev_mute; | ||
331 | 335 | ||
332 | if (!ucontrol) | 336 | if (!kcontrol || !ucontrol) |
333 | return; | 337 | return; |
334 | 338 | ||
335 | mute = !(ucontrol->value.integer.value[0] || | 339 | mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
336 | ucontrol->value.integer.value[1]); | 340 | prev_mute = !spec->mic_enabled; |
337 | if (spec->mic_mute_led_on != mute) { | 341 | if (ucontrol->value.integer.value[0] || |
338 | spec->mic_mute_led_on = mute; | 342 | ucontrol->value.integer.value[1]) |
339 | if (mute) | 343 | spec->mic_enabled |= mask; |
344 | else | ||
345 | spec->mic_enabled &= ~mask; | ||
346 | cur_mute = !spec->mic_enabled; | ||
347 | if (cur_mute != prev_mute) { | ||
348 | if (cur_mute) | ||
340 | spec->gpio_data |= spec->mic_mute_led_gpio; | 349 | spec->gpio_data |= spec->mic_mute_led_gpio; |
341 | else | 350 | else |
342 | spec->gpio_data &= ~spec->mic_mute_led_gpio; | 351 | spec->gpio_data &= ~spec->mic_mute_led_gpio; |
@@ -1788,6 +1797,12 @@ static const struct hda_pintbl intel_dg45id_pin_configs[] = { | |||
1788 | {} | 1797 | {} |
1789 | }; | 1798 | }; |
1790 | 1799 | ||
1800 | static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { | ||
1801 | { 0x0a, 0x02214030 }, | ||
1802 | { 0x0b, 0x02A19010 }, | ||
1803 | {} | ||
1804 | }; | ||
1805 | |||
1791 | static void stac92hd73xx_fixup_ref(struct hda_codec *codec, | 1806 | static void stac92hd73xx_fixup_ref(struct hda_codec *codec, |
1792 | const struct hda_fixup *fix, int action) | 1807 | const struct hda_fixup *fix, int action) |
1793 | { | 1808 | { |
@@ -1906,6 +1921,10 @@ static const struct hda_fixup stac92hd73xx_fixups[] = { | |||
1906 | [STAC_92HD73XX_NO_JD] = { | 1921 | [STAC_92HD73XX_NO_JD] = { |
1907 | .type = HDA_FIXUP_FUNC, | 1922 | .type = HDA_FIXUP_FUNC, |
1908 | .v.func = stac92hd73xx_fixup_no_jd, | 1923 | .v.func = stac92hd73xx_fixup_no_jd, |
1924 | }, | ||
1925 | [STAC_92HD89XX_HP_FRONT_JACK] = { | ||
1926 | .type = HDA_FIXUP_PINS, | ||
1927 | .v.pins = stac92hd89xx_hp_front_jack_pin_configs, | ||
1909 | } | 1928 | } |
1910 | }; | 1929 | }; |
1911 | 1930 | ||
@@ -1966,6 +1985,8 @@ static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { | |||
1966 | "Alienware M17x", STAC_ALIENWARE_M17X), | 1985 | "Alienware M17x", STAC_ALIENWARE_M17X), |
1967 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, | 1986 | SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, |
1968 | "Alienware M17x R3", STAC_DELL_EQ), | 1987 | "Alienware M17x R3", STAC_DELL_EQ), |
1988 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, | ||
1989 | "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), | ||
1969 | {} /* terminator */ | 1990 | {} /* terminator */ |
1970 | }; | 1991 | }; |
1971 | 1992 | ||
@@ -2110,6 +2131,17 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, | |||
2110 | } | 2131 | } |
2111 | } | 2132 | } |
2112 | 2133 | ||
2134 | static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec, | ||
2135 | const struct hda_fixup *fix, int action) | ||
2136 | { | ||
2137 | struct sigmatel_spec *spec = codec->spec; | ||
2138 | |||
2139 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | ||
2140 | spec->gpio_led = 0x10; /* GPIO4 */ | ||
2141 | spec->default_polarity = 0; | ||
2142 | } | ||
2143 | } | ||
2144 | |||
2113 | static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, | 2145 | static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, |
2114 | const struct hda_fixup *fix, int action) | 2146 | const struct hda_fixup *fix, int action) |
2115 | { | 2147 | { |
@@ -2604,6 +2636,12 @@ static const struct hda_fixup stac92hd83xxx_fixups[] = { | |||
2604 | .chained = true, | 2636 | .chained = true, |
2605 | .chain_id = STAC_92HD83XXX_HP, | 2637 | .chain_id = STAC_92HD83XXX_HP, |
2606 | }, | 2638 | }, |
2639 | [STAC_HP_LED_GPIO10] = { | ||
2640 | .type = HDA_FIXUP_FUNC, | ||
2641 | .v.func = stac92hd83xxx_fixup_hp_led_gpio10, | ||
2642 | .chained = true, | ||
2643 | .chain_id = STAC_92HD83XXX_HP, | ||
2644 | }, | ||
2607 | [STAC_92HD83XXX_HEADSET_JACK] = { | 2645 | [STAC_92HD83XXX_HEADSET_JACK] = { |
2608 | .type = HDA_FIXUP_FUNC, | 2646 | .type = HDA_FIXUP_FUNC, |
2609 | .v.func = stac92hd83xxx_fixup_headset_jack, | 2647 | .v.func = stac92hd83xxx_fixup_headset_jack, |
@@ -2682,6 +2720,8 @@ static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { | |||
2682 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), | 2720 | "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), |
2683 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888, | 2721 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888, |
2684 | "HP Envy Spectre", STAC_HP_ENVY_BASS), | 2722 | "HP Envy Spectre", STAC_HP_ENVY_BASS), |
2723 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899, | ||
2724 | "HP Folio 13", STAC_HP_LED_GPIO10), | ||
2685 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, | 2725 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, |
2686 | "HP Folio", STAC_HP_BNB13_EQ), | 2726 | "HP Folio", STAC_HP_BNB13_EQ), |
2687 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8, | 2727 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8, |
@@ -4462,7 +4502,7 @@ static void stac_setup_gpio(struct hda_codec *codec) | |||
4462 | if (spec->mic_mute_led_gpio) { | 4502 | if (spec->mic_mute_led_gpio) { |
4463 | spec->gpio_mask |= spec->mic_mute_led_gpio; | 4503 | spec->gpio_mask |= spec->mic_mute_led_gpio; |
4464 | spec->gpio_dir |= spec->mic_mute_led_gpio; | 4504 | spec->gpio_dir |= spec->mic_mute_led_gpio; |
4465 | spec->mic_mute_led_on = true; | 4505 | spec->mic_enabled = 0; |
4466 | spec->gpio_data |= spec->mic_mute_led_gpio; | 4506 | spec->gpio_data |= spec->mic_mute_led_gpio; |
4467 | 4507 | ||
4468 | spec->gen.cap_sync_hook = stac_capture_led_hook; | 4508 | spec->gen.cap_sync_hook = stac_capture_led_hook; |
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c index 5799fbc24c28..8fe3b8c18ed4 100644 --- a/sound/pci/hda/thinkpad_helper.c +++ b/sound/pci/hda/thinkpad_helper.c | |||
@@ -39,6 +39,7 @@ static void update_tpacpi_mute_led(void *private_data, int enabled) | |||
39 | } | 39 | } |
40 | 40 | ||
41 | static void update_tpacpi_micmute_led(struct hda_codec *codec, | 41 | static void update_tpacpi_micmute_led(struct hda_codec *codec, |
42 | struct snd_kcontrol *kcontrol, | ||
42 | struct snd_ctl_elem_value *ucontrol) | 43 | struct snd_ctl_elem_value *ucontrol) |
43 | { | 44 | { |
44 | if (!ucontrol || !led_set_func) | 45 | if (!ucontrol || !led_set_func) |
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig index e634eb78ed03..4789619a52d8 100644 --- a/sound/soc/atmel/Kconfig +++ b/sound/soc/atmel/Kconfig | |||
@@ -58,6 +58,6 @@ config SND_AT91_SOC_AFEB9260 | |||
58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC | 58 | depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC |
59 | select SND_ATMEL_SOC_PDC | 59 | select SND_ATMEL_SOC_PDC |
60 | select SND_ATMEL_SOC_SSC | 60 | select SND_ATMEL_SOC_SSC |
61 | select SND_SOC_TLV320AIC23 | 61 | select SND_SOC_TLV320AIC23_I2C |
62 | help | 62 | help |
63 | Say Y here to support sound on AFEB9260 board. | 63 | Say Y here to support sound on AFEB9260 board. |
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c index 1ead3c977a51..de433cfd044c 100644 --- a/sound/soc/atmel/atmel_ssc_dai.c +++ b/sound/soc/atmel/atmel_ssc_dai.c | |||
@@ -341,6 +341,7 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
341 | { | 341 | { |
342 | int id = dai->id; | 342 | int id = dai->id; |
343 | struct atmel_ssc_info *ssc_p = &ssc_info[id]; | 343 | struct atmel_ssc_info *ssc_p = &ssc_info[id]; |
344 | struct ssc_device *ssc = ssc_p->ssc; | ||
344 | struct atmel_pcm_dma_params *dma_params; | 345 | struct atmel_pcm_dma_params *dma_params; |
345 | int dir, channels, bits; | 346 | int dir, channels, bits; |
346 | u32 tfmr, rfmr, tcmr, rcmr; | 347 | u32 tfmr, rfmr, tcmr, rcmr; |
@@ -466,7 +467,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
466 | | SSC_BF(RCMR_START, start_event) | 467 | | SSC_BF(RCMR_START, start_event) |
467 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 468 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
468 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 469 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
469 | | SSC_BF(RCMR_CKS, SSC_CKS_CLOCK); | 470 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
471 | SSC_CKS_PIN : SSC_CKS_CLOCK); | ||
470 | 472 | ||
471 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 473 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
472 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | 474 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
@@ -481,7 +483,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
481 | | SSC_BF(TCMR_START, start_event) | 483 | | SSC_BF(TCMR_START, start_event) |
482 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 484 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
483 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | 485 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
484 | | SSC_BF(TCMR_CKS, SSC_CKS_PIN); | 486 | | SSC_BF(TCMR_CKS, ssc->clk_from_rk_pin ? |
487 | SSC_CKS_CLOCK : SSC_CKS_PIN); | ||
485 | 488 | ||
486 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 489 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
487 | | SSC_BF(TFMR_FSDEN, 0) | 490 | | SSC_BF(TFMR_FSDEN, 0) |
@@ -550,7 +553,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
550 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) | 553 | | SSC_BF(RCMR_START, SSC_START_RISING_RF) |
551 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) | 554 | | SSC_BF(RCMR_CKI, SSC_CKI_RISING) |
552 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) | 555 | | SSC_BF(RCMR_CKO, SSC_CKO_NONE) |
553 | | SSC_BF(RCMR_CKS, SSC_CKS_PIN); | 556 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
557 | SSC_CKS_PIN : SSC_CKS_CLOCK); | ||
554 | 558 | ||
555 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 559 | rfmr = SSC_BF(RFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
556 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) | 560 | | SSC_BF(RFMR_FSOS, SSC_FSOS_NONE) |
@@ -565,7 +569,8 @@ static int atmel_ssc_hw_params(struct snd_pcm_substream *substream, | |||
565 | | SSC_BF(TCMR_START, SSC_START_RISING_RF) | 569 | | SSC_BF(TCMR_START, SSC_START_RISING_RF) |
566 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) | 570 | | SSC_BF(TCMR_CKI, SSC_CKI_FALLING) |
567 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) | 571 | | SSC_BF(TCMR_CKO, SSC_CKO_NONE) |
568 | | SSC_BF(TCMR_CKS, SSC_CKS_PIN); | 572 | | SSC_BF(RCMR_CKS, ssc->clk_from_rk_pin ? |
573 | SSC_CKS_CLOCK : SSC_CKS_PIN); | ||
569 | 574 | ||
570 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) | 575 | tfmr = SSC_BF(TFMR_FSEDGE, SSC_FSEDGE_POSITIVE) |
571 | | SSC_BF(TFMR_FSDEN, 0) | 576 | | SSC_BF(TFMR_FSDEN, 0) |
diff --git a/sound/soc/atmel/sam9g20_wm8731.c b/sound/soc/atmel/sam9g20_wm8731.c index f15bff1548f8..174bd546c08b 100644 --- a/sound/soc/atmel/sam9g20_wm8731.c +++ b/sound/soc/atmel/sam9g20_wm8731.c | |||
@@ -155,25 +155,14 @@ static int at91sam9g20ek_wm8731_init(struct snd_soc_pcm_runtime *rtd) | |||
155 | return ret; | 155 | return ret; |
156 | } | 156 | } |
157 | 157 | ||
158 | /* Add specific widgets */ | ||
159 | snd_soc_dapm_new_controls(dapm, at91sam9g20ek_dapm_widgets, | ||
160 | ARRAY_SIZE(at91sam9g20ek_dapm_widgets)); | ||
161 | /* Set up specific audio path interconnects */ | ||
162 | snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon)); | ||
163 | |||
164 | /* not connected */ | 158 | /* not connected */ |
165 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); | 159 | snd_soc_dapm_nc_pin(dapm, "RLINEIN"); |
166 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); | 160 | snd_soc_dapm_nc_pin(dapm, "LLINEIN"); |
167 | 161 | ||
168 | #ifdef ENABLE_MIC_INPUT | 162 | #ifndef ENABLE_MIC_INPUT |
169 | snd_soc_dapm_enable_pin(dapm, "Int Mic"); | 163 | snd_soc_dapm_nc_pin(&rtd->card->dapm, "Int Mic"); |
170 | #else | ||
171 | snd_soc_dapm_nc_pin(dapm, "Int Mic"); | ||
172 | #endif | 164 | #endif |
173 | 165 | ||
174 | /* always connected */ | ||
175 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | ||
176 | |||
177 | return 0; | 166 | return 0; |
178 | } | 167 | } |
179 | 168 | ||
@@ -194,6 +183,11 @@ static struct snd_soc_card snd_soc_at91sam9g20ek = { | |||
194 | .dai_link = &at91sam9g20ek_dai, | 183 | .dai_link = &at91sam9g20ek_dai, |
195 | .num_links = 1, | 184 | .num_links = 1, |
196 | .set_bias_level = at91sam9g20ek_set_bias_level, | 185 | .set_bias_level = at91sam9g20ek_set_bias_level, |
186 | |||
187 | .dapm_widgets = at91sam9g20ek_dapm_widgets, | ||
188 | .num_dapm_widgets = ARRAY_SIZE(at91sam9g20ek_dapm_widgets), | ||
189 | .dapm_routes = intercon, | ||
190 | .num_dapm_routes = ARRAY_SIZE(intercon), | ||
197 | }; | 191 | }; |
198 | 192 | ||
199 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) | 193 | static int at91sam9g20ek_audio_probe(struct platform_device *pdev) |
diff --git a/sound/soc/blackfin/Kconfig b/sound/soc/blackfin/Kconfig index 54f74f8cbb75..b2107918f0ad 100644 --- a/sound/soc/blackfin/Kconfig +++ b/sound/soc/blackfin/Kconfig | |||
@@ -11,7 +11,7 @@ config SND_BF5XX_I2S | |||
11 | 11 | ||
12 | config SND_BF5XX_SOC_SSM2602 | 12 | config SND_BF5XX_SOC_SSM2602 |
13 | tristate "SoC SSM2602 Audio Codec Add-On Card support" | 13 | tristate "SoC SSM2602 Audio Codec Add-On Card support" |
14 | depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) | 14 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI |
15 | select SND_BF5XX_SOC_I2S if !BF60x | 15 | select SND_BF5XX_SOC_I2S if !BF60x |
16 | select SND_BF6XX_SOC_I2S if BF60x | 16 | select SND_BF6XX_SOC_I2S if BF60x |
17 | select SND_SOC_SSM2602 | 17 | select SND_SOC_SSM2602 |
@@ -21,10 +21,9 @@ config SND_BF5XX_SOC_SSM2602 | |||
21 | 21 | ||
22 | config SND_SOC_BFIN_EVAL_ADAU1701 | 22 | config SND_SOC_BFIN_EVAL_ADAU1701 |
23 | tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" | 23 | tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" |
24 | depends on SND_BF5XX_I2S | 24 | depends on SND_BF5XX_I2S && I2C |
25 | select SND_BF5XX_SOC_I2S | 25 | select SND_BF5XX_SOC_I2S |
26 | select SND_SOC_ADAU1701 | 26 | select SND_SOC_ADAU1701 |
27 | select I2C | ||
28 | help | 27 | help |
29 | Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ | 28 | Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ |
30 | board connected to one of the Blackfin evaluation boards like the | 29 | board connected to one of the Blackfin evaluation boards like the |
@@ -45,9 +44,10 @@ config SND_SOC_BFIN_EVAL_ADAU1373 | |||
45 | 44 | ||
46 | config SND_SOC_BFIN_EVAL_ADAV80X | 45 | config SND_SOC_BFIN_EVAL_ADAV80X |
47 | tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" | 46 | tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" |
48 | depends on SND_BF5XX_I2S && (SPI_MASTER || I2C) | 47 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI |
49 | select SND_BF5XX_SOC_I2S | 48 | select SND_BF5XX_SOC_I2S |
50 | select SND_SOC_ADAV80X | 49 | select SND_SOC_ADAV801 if SPI_MASTER |
50 | select SND_SOC_ADAV803 if I2C | ||
51 | help | 51 | help |
52 | Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or | 52 | Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or |
53 | EVAL-ADAV803 board connected to one of the Blackfin evaluation boards | 53 | EVAL-ADAV803 board connected to one of the Blackfin evaluation boards |
@@ -58,7 +58,7 @@ config SND_SOC_BFIN_EVAL_ADAV80X | |||
58 | 58 | ||
59 | config SND_BF5XX_SOC_AD1836 | 59 | config SND_BF5XX_SOC_AD1836 |
60 | tristate "SoC AD1836 Audio support for BF5xx" | 60 | tristate "SoC AD1836 Audio support for BF5xx" |
61 | depends on SND_BF5XX_I2S | 61 | depends on SND_BF5XX_I2S && SPI_MASTER |
62 | select SND_BF5XX_SOC_I2S | 62 | select SND_BF5XX_SOC_I2S |
63 | select SND_SOC_AD1836 | 63 | select SND_SOC_AD1836 |
64 | help | 64 | help |
@@ -66,9 +66,10 @@ config SND_BF5XX_SOC_AD1836 | |||
66 | 66 | ||
67 | config SND_BF5XX_SOC_AD193X | 67 | config SND_BF5XX_SOC_AD193X |
68 | tristate "SoC AD193X Audio support for Blackfin" | 68 | tristate "SoC AD193X Audio support for Blackfin" |
69 | depends on SND_BF5XX_I2S | 69 | depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI |
70 | select SND_BF5XX_SOC_I2S | 70 | select SND_BF5XX_SOC_I2S |
71 | select SND_SOC_AD193X | 71 | select SND_SOC_AD193X_I2C if I2C |
72 | select SND_SOC_AD193X_SPI if SPI_MASTER | ||
72 | help | 73 | help |
73 | Say Y if you want to add support for AD193X codec on Blackfin. | 74 | Say Y if you want to add support for AD193X codec on Blackfin. |
74 | This driver supports AD1936, AD1937, AD1938 and AD1939. | 75 | This driver supports AD1936, AD1937, AD1938 and AD1939. |
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig index 06f938deda15..5477c5475923 100644 --- a/sound/soc/cirrus/Kconfig +++ b/sound/soc/cirrus/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config SND_EP93XX_SOC | 1 | config SND_EP93XX_SOC |
2 | tristate "SoC Audio support for the Cirrus Logic EP93xx series" | 2 | tristate "SoC Audio support for the Cirrus Logic EP93xx series" |
3 | depends on (ARCH_EP93XX || COMPILE_TEST) && SND_SOC | 3 | depends on ARCH_EP93XX || COMPILE_TEST |
4 | select SND_SOC_GENERIC_DMAENGINE_PCM | 4 | select SND_SOC_GENERIC_DMAENGINE_PCM |
5 | help | 5 | help |
6 | 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 |
@@ -18,7 +18,7 @@ config SND_EP93XX_SOC_SNAPPERCL15 | |||
18 | tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" | 18 | tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" |
19 | depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 | 19 | depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 |
20 | select SND_EP93XX_SOC_I2S | 20 | select SND_EP93XX_SOC_I2S |
21 | select SND_SOC_TLV320AIC23 | 21 | select SND_SOC_TLV320AIC23_I2C |
22 | help | 22 | help |
23 | Say Y or M here if you want to add support for I2S audio on the | 23 | Say Y or M here if you want to add support for I2S audio on the |
24 | Bluewater Systems Snapper CL15 module. | 24 | Bluewater Systems Snapper CL15 module. |
diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 75d0ad5d2dcb..8703244ee9fb 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c | |||
@@ -448,38 +448,38 @@ static const char *pm860x_opamp_texts[] = {"-50%", "-25%", "0%", "75%"}; | |||
448 | 448 | ||
449 | static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; | 449 | static const char *pm860x_pa_texts[] = {"-33%", "0%", "33%", "66%"}; |
450 | 450 | ||
451 | static const struct soc_enum pm860x_hs1_opamp_enum = | 451 | static SOC_ENUM_SINGLE_DECL(pm860x_hs1_opamp_enum, |
452 | SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 5, 4, pm860x_opamp_texts); | 452 | PM860X_HS1_CTRL, 5, pm860x_opamp_texts); |
453 | 453 | ||
454 | static const struct soc_enum pm860x_hs2_opamp_enum = | 454 | static SOC_ENUM_SINGLE_DECL(pm860x_hs2_opamp_enum, |
455 | SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 5, 4, pm860x_opamp_texts); | 455 | PM860X_HS2_CTRL, 5, pm860x_opamp_texts); |
456 | 456 | ||
457 | static const struct soc_enum pm860x_hs1_pa_enum = | 457 | static SOC_ENUM_SINGLE_DECL(pm860x_hs1_pa_enum, |
458 | SOC_ENUM_SINGLE(PM860X_HS1_CTRL, 3, 4, pm860x_pa_texts); | 458 | PM860X_HS1_CTRL, 3, pm860x_pa_texts); |
459 | 459 | ||
460 | static const struct soc_enum pm860x_hs2_pa_enum = | 460 | static SOC_ENUM_SINGLE_DECL(pm860x_hs2_pa_enum, |
461 | SOC_ENUM_SINGLE(PM860X_HS2_CTRL, 3, 4, pm860x_pa_texts); | 461 | PM860X_HS2_CTRL, 3, pm860x_pa_texts); |
462 | 462 | ||
463 | static const struct soc_enum pm860x_lo1_opamp_enum = | 463 | static SOC_ENUM_SINGLE_DECL(pm860x_lo1_opamp_enum, |
464 | SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 5, 4, pm860x_opamp_texts); | 464 | PM860X_LO1_CTRL, 5, pm860x_opamp_texts); |
465 | 465 | ||
466 | static const struct soc_enum pm860x_lo2_opamp_enum = | 466 | static SOC_ENUM_SINGLE_DECL(pm860x_lo2_opamp_enum, |
467 | SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 5, 4, pm860x_opamp_texts); | 467 | PM860X_LO2_CTRL, 5, pm860x_opamp_texts); |
468 | 468 | ||
469 | static const struct soc_enum pm860x_lo1_pa_enum = | 469 | static SOC_ENUM_SINGLE_DECL(pm860x_lo1_pa_enum, |
470 | SOC_ENUM_SINGLE(PM860X_LO1_CTRL, 3, 4, pm860x_pa_texts); | 470 | PM860X_LO1_CTRL, 3, pm860x_pa_texts); |
471 | 471 | ||
472 | static const struct soc_enum pm860x_lo2_pa_enum = | 472 | static SOC_ENUM_SINGLE_DECL(pm860x_lo2_pa_enum, |
473 | SOC_ENUM_SINGLE(PM860X_LO2_CTRL, 3, 4, pm860x_pa_texts); | 473 | PM860X_LO2_CTRL, 3, pm860x_pa_texts); |
474 | 474 | ||
475 | static const struct soc_enum pm860x_spk_pa_enum = | 475 | static SOC_ENUM_SINGLE_DECL(pm860x_spk_pa_enum, |
476 | SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 5, 4, pm860x_pa_texts); | 476 | PM860X_EAR_CTRL_1, 5, pm860x_pa_texts); |
477 | 477 | ||
478 | static const struct soc_enum pm860x_ear_pa_enum = | 478 | static SOC_ENUM_SINGLE_DECL(pm860x_ear_pa_enum, |
479 | SOC_ENUM_SINGLE(PM860X_EAR_CTRL_2, 0, 4, pm860x_pa_texts); | 479 | PM860X_EAR_CTRL_2, 0, pm860x_pa_texts); |
480 | 480 | ||
481 | static const struct soc_enum pm860x_spk_ear_opamp_enum = | 481 | static SOC_ENUM_SINGLE_DECL(pm860x_spk_ear_opamp_enum, |
482 | SOC_ENUM_SINGLE(PM860X_EAR_CTRL_1, 3, 4, pm860x_opamp_texts); | 482 | PM860X_EAR_CTRL_1, 3, pm860x_opamp_texts); |
483 | 483 | ||
484 | static const struct snd_kcontrol_new pm860x_snd_controls[] = { | 484 | static const struct snd_kcontrol_new pm860x_snd_controls[] = { |
485 | SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, | 485 | SOC_DOUBLE_R_TLV("ADC Capture Volume", PM860X_ADC_ANA_2, |
@@ -561,8 +561,8 @@ static const char *aif1_text[] = { | |||
561 | "PCM L", "PCM R", | 561 | "PCM L", "PCM R", |
562 | }; | 562 | }; |
563 | 563 | ||
564 | static const struct soc_enum aif1_enum = | 564 | static SOC_ENUM_SINGLE_DECL(aif1_enum, |
565 | SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 6, 2, aif1_text); | 565 | PM860X_PCM_IFACE_3, 6, aif1_text); |
566 | 566 | ||
567 | static const struct snd_kcontrol_new aif1_mux = | 567 | static const struct snd_kcontrol_new aif1_mux = |
568 | SOC_DAPM_ENUM("PCM Mux", aif1_enum); | 568 | SOC_DAPM_ENUM("PCM Mux", aif1_enum); |
@@ -572,8 +572,8 @@ static const char *i2s_din_text[] = { | |||
572 | "DIN", "DIN1", | 572 | "DIN", "DIN1", |
573 | }; | 573 | }; |
574 | 574 | ||
575 | static const struct soc_enum i2s_din_enum = | 575 | static SOC_ENUM_SINGLE_DECL(i2s_din_enum, |
576 | SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 1, 2, i2s_din_text); | 576 | PM860X_I2S_IFACE_3, 1, i2s_din_text); |
577 | 577 | ||
578 | static const struct snd_kcontrol_new i2s_din_mux = | 578 | static const struct snd_kcontrol_new i2s_din_mux = |
579 | SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); | 579 | SOC_DAPM_ENUM("I2S DIN Mux", i2s_din_enum); |
@@ -583,8 +583,8 @@ static const char *i2s_mic_text[] = { | |||
583 | "Ex PA", "ADC", | 583 | "Ex PA", "ADC", |
584 | }; | 584 | }; |
585 | 585 | ||
586 | static const struct soc_enum i2s_mic_enum = | 586 | static SOC_ENUM_SINGLE_DECL(i2s_mic_enum, |
587 | SOC_ENUM_SINGLE(PM860X_I2S_IFACE_3, 4, 2, i2s_mic_text); | 587 | PM860X_I2S_IFACE_3, 4, i2s_mic_text); |
588 | 588 | ||
589 | static const struct snd_kcontrol_new i2s_mic_mux = | 589 | static const struct snd_kcontrol_new i2s_mic_mux = |
590 | SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); | 590 | SOC_DAPM_ENUM("I2S Mic Mux", i2s_mic_enum); |
@@ -594,8 +594,8 @@ static const char *adcl_text[] = { | |||
594 | "ADCR", "ADCL", | 594 | "ADCR", "ADCL", |
595 | }; | 595 | }; |
596 | 596 | ||
597 | static const struct soc_enum adcl_enum = | 597 | static SOC_ENUM_SINGLE_DECL(adcl_enum, |
598 | SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 4, 2, adcl_text); | 598 | PM860X_PCM_IFACE_3, 4, adcl_text); |
599 | 599 | ||
600 | static const struct snd_kcontrol_new adcl_mux = | 600 | static const struct snd_kcontrol_new adcl_mux = |
601 | SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); | 601 | SOC_DAPM_ENUM("ADC Left Mux", adcl_enum); |
@@ -605,8 +605,8 @@ static const char *adcr_text[] = { | |||
605 | "ADCL", "ADCR", | 605 | "ADCL", "ADCR", |
606 | }; | 606 | }; |
607 | 607 | ||
608 | static const struct soc_enum adcr_enum = | 608 | static SOC_ENUM_SINGLE_DECL(adcr_enum, |
609 | SOC_ENUM_SINGLE(PM860X_PCM_IFACE_3, 2, 2, adcr_text); | 609 | PM860X_PCM_IFACE_3, 2, adcr_text); |
610 | 610 | ||
611 | static const struct snd_kcontrol_new adcr_mux = | 611 | static const struct snd_kcontrol_new adcr_mux = |
612 | SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); | 612 | SOC_DAPM_ENUM("ADC Right Mux", adcr_enum); |
@@ -616,8 +616,8 @@ static const char *adcr_ec_text[] = { | |||
616 | "ADCR", "EC", | 616 | "ADCR", "EC", |
617 | }; | 617 | }; |
618 | 618 | ||
619 | static const struct soc_enum adcr_ec_enum = | 619 | static SOC_ENUM_SINGLE_DECL(adcr_ec_enum, |
620 | SOC_ENUM_SINGLE(PM860X_ADC_EN_2, 3, 2, adcr_ec_text); | 620 | PM860X_ADC_EN_2, 3, adcr_ec_text); |
621 | 621 | ||
622 | static const struct snd_kcontrol_new adcr_ec_mux = | 622 | static const struct snd_kcontrol_new adcr_ec_mux = |
623 | SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); | 623 | SOC_DAPM_ENUM("ADCR EC Mux", adcr_ec_enum); |
@@ -627,8 +627,8 @@ static const char *ec_text[] = { | |||
627 | "Left", "Right", "Left + Right", | 627 | "Left", "Right", "Left + Right", |
628 | }; | 628 | }; |
629 | 629 | ||
630 | static const struct soc_enum ec_enum = | 630 | static SOC_ENUM_SINGLE_DECL(ec_enum, |
631 | SOC_ENUM_SINGLE(PM860X_EC_PATH, 1, 3, ec_text); | 631 | PM860X_EC_PATH, 1, ec_text); |
632 | 632 | ||
633 | static const struct snd_kcontrol_new ec_mux = | 633 | static const struct snd_kcontrol_new ec_mux = |
634 | SOC_DAPM_ENUM("EC Mux", ec_enum); | 634 | SOC_DAPM_ENUM("EC Mux", ec_enum); |
@@ -638,36 +638,36 @@ static const char *dac_text[] = { | |||
638 | }; | 638 | }; |
639 | 639 | ||
640 | /* DAC Headset 1 Mux / Mux10 */ | 640 | /* DAC Headset 1 Mux / Mux10 */ |
641 | static const struct soc_enum dac_hs1_enum = | 641 | static SOC_ENUM_SINGLE_DECL(dac_hs1_enum, |
642 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 0, 4, dac_text); | 642 | PM860X_ANA_INPUT_SEL_1, 0, dac_text); |
643 | 643 | ||
644 | static const struct snd_kcontrol_new dac_hs1_mux = | 644 | static const struct snd_kcontrol_new dac_hs1_mux = |
645 | SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum); | 645 | SOC_DAPM_ENUM("DAC HS1 Mux", dac_hs1_enum); |
646 | 646 | ||
647 | /* DAC Headset 2 Mux / Mux11 */ | 647 | /* DAC Headset 2 Mux / Mux11 */ |
648 | static const struct soc_enum dac_hs2_enum = | 648 | static SOC_ENUM_SINGLE_DECL(dac_hs2_enum, |
649 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 2, 4, dac_text); | 649 | PM860X_ANA_INPUT_SEL_1, 2, dac_text); |
650 | 650 | ||
651 | static const struct snd_kcontrol_new dac_hs2_mux = | 651 | static const struct snd_kcontrol_new dac_hs2_mux = |
652 | SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum); | 652 | SOC_DAPM_ENUM("DAC HS2 Mux", dac_hs2_enum); |
653 | 653 | ||
654 | /* DAC Lineout 1 Mux / Mux12 */ | 654 | /* DAC Lineout 1 Mux / Mux12 */ |
655 | static const struct soc_enum dac_lo1_enum = | 655 | static SOC_ENUM_SINGLE_DECL(dac_lo1_enum, |
656 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 4, 4, dac_text); | 656 | PM860X_ANA_INPUT_SEL_1, 4, dac_text); |
657 | 657 | ||
658 | static const struct snd_kcontrol_new dac_lo1_mux = | 658 | static const struct snd_kcontrol_new dac_lo1_mux = |
659 | SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum); | 659 | SOC_DAPM_ENUM("DAC LO1 Mux", dac_lo1_enum); |
660 | 660 | ||
661 | /* DAC Lineout 2 Mux / Mux13 */ | 661 | /* DAC Lineout 2 Mux / Mux13 */ |
662 | static const struct soc_enum dac_lo2_enum = | 662 | static SOC_ENUM_SINGLE_DECL(dac_lo2_enum, |
663 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_1, 6, 4, dac_text); | 663 | PM860X_ANA_INPUT_SEL_1, 6, dac_text); |
664 | 664 | ||
665 | static const struct snd_kcontrol_new dac_lo2_mux = | 665 | static const struct snd_kcontrol_new dac_lo2_mux = |
666 | SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum); | 666 | SOC_DAPM_ENUM("DAC LO2 Mux", dac_lo2_enum); |
667 | 667 | ||
668 | /* DAC Spearker Earphone Mux / Mux14 */ | 668 | /* DAC Spearker Earphone Mux / Mux14 */ |
669 | static const struct soc_enum dac_spk_ear_enum = | 669 | static SOC_ENUM_SINGLE_DECL(dac_spk_ear_enum, |
670 | SOC_ENUM_SINGLE(PM860X_ANA_INPUT_SEL_2, 0, 4, dac_text); | 670 | PM860X_ANA_INPUT_SEL_2, 0, dac_text); |
671 | 671 | ||
672 | static const struct snd_kcontrol_new dac_spk_ear_mux = | 672 | static const struct snd_kcontrol_new dac_spk_ear_mux = |
673 | SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); | 673 | SOC_DAPM_ENUM("DAC SP Mux", dac_spk_ear_enum); |
@@ -677,29 +677,29 @@ static const char *in_text[] = { | |||
677 | "Digital", "Analog", | 677 | "Digital", "Analog", |
678 | }; | 678 | }; |
679 | 679 | ||
680 | static const struct soc_enum hs1_enum = | 680 | static SOC_ENUM_SINGLE_DECL(hs1_enum, |
681 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 0, 2, in_text); | 681 | PM860X_ANA_TO_ANA, 0, in_text); |
682 | 682 | ||
683 | static const struct snd_kcontrol_new hs1_mux = | 683 | static const struct snd_kcontrol_new hs1_mux = |
684 | SOC_DAPM_ENUM("Headset1 Mux", hs1_enum); | 684 | SOC_DAPM_ENUM("Headset1 Mux", hs1_enum); |
685 | 685 | ||
686 | /* Headset 2 Mux / Mux16 */ | 686 | /* Headset 2 Mux / Mux16 */ |
687 | static const struct soc_enum hs2_enum = | 687 | static SOC_ENUM_SINGLE_DECL(hs2_enum, |
688 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 1, 2, in_text); | 688 | PM860X_ANA_TO_ANA, 1, in_text); |
689 | 689 | ||
690 | static const struct snd_kcontrol_new hs2_mux = | 690 | static const struct snd_kcontrol_new hs2_mux = |
691 | SOC_DAPM_ENUM("Headset2 Mux", hs2_enum); | 691 | SOC_DAPM_ENUM("Headset2 Mux", hs2_enum); |
692 | 692 | ||
693 | /* Lineout 1 Mux / Mux17 */ | 693 | /* Lineout 1 Mux / Mux17 */ |
694 | static const struct soc_enum lo1_enum = | 694 | static SOC_ENUM_SINGLE_DECL(lo1_enum, |
695 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 2, 2, in_text); | 695 | PM860X_ANA_TO_ANA, 2, in_text); |
696 | 696 | ||
697 | static const struct snd_kcontrol_new lo1_mux = | 697 | static const struct snd_kcontrol_new lo1_mux = |
698 | SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum); | 698 | SOC_DAPM_ENUM("Lineout1 Mux", lo1_enum); |
699 | 699 | ||
700 | /* Lineout 2 Mux / Mux18 */ | 700 | /* Lineout 2 Mux / Mux18 */ |
701 | static const struct soc_enum lo2_enum = | 701 | static SOC_ENUM_SINGLE_DECL(lo2_enum, |
702 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 3, 2, in_text); | 702 | PM860X_ANA_TO_ANA, 3, in_text); |
703 | 703 | ||
704 | static const struct snd_kcontrol_new lo2_mux = | 704 | static const struct snd_kcontrol_new lo2_mux = |
705 | SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); | 705 | SOC_DAPM_ENUM("Lineout2 Mux", lo2_enum); |
@@ -709,8 +709,8 @@ static const char *spk_text[] = { | |||
709 | "Earpiece", "Speaker", | 709 | "Earpiece", "Speaker", |
710 | }; | 710 | }; |
711 | 711 | ||
712 | static const struct soc_enum spk_enum = | 712 | static SOC_ENUM_SINGLE_DECL(spk_enum, |
713 | SOC_ENUM_SINGLE(PM860X_ANA_TO_ANA, 6, 2, spk_text); | 713 | PM860X_ANA_TO_ANA, 6, spk_text); |
714 | 714 | ||
715 | static const struct snd_kcontrol_new spk_demux = | 715 | static const struct snd_kcontrol_new spk_demux = |
716 | SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); | 716 | SOC_DAPM_ENUM("Speaker Earpiece Demux", spk_enum); |
@@ -720,8 +720,8 @@ static const char *mic_text[] = { | |||
720 | "Mic 1", "Mic 2", | 720 | "Mic 1", "Mic 2", |
721 | }; | 721 | }; |
722 | 722 | ||
723 | static const struct soc_enum mic_enum = | 723 | static SOC_ENUM_SINGLE_DECL(mic_enum, |
724 | SOC_ENUM_SINGLE(PM860X_ADC_ANA_4, 4, 2, mic_text); | 724 | PM860X_ADC_ANA_4, 4, mic_text); |
725 | 725 | ||
726 | static const struct snd_kcontrol_new mic_mux = | 726 | static const struct snd_kcontrol_new mic_mux = |
727 | SOC_DAPM_ENUM("MIC Mux", mic_enum); | 727 | SOC_DAPM_ENUM("MIC Mux", mic_enum); |
@@ -1328,6 +1328,9 @@ static int pm860x_probe(struct snd_soc_codec *codec) | |||
1328 | pm860x->codec = codec; | 1328 | pm860x->codec = codec; |
1329 | 1329 | ||
1330 | codec->control_data = pm860x->regmap; | 1330 | codec->control_data = pm860x->regmap; |
1331 | ret = snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); | ||
1332 | if (ret) | ||
1333 | return ret; | ||
1331 | 1334 | ||
1332 | for (i = 0; i < 4; i++) { | 1335 | for (i = 0; i < 4; i++) { |
1333 | ret = request_threaded_irq(pm860x->irq[i], NULL, | 1336 | ret = request_threaded_irq(pm860x->irq[i], NULL, |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 983d087aa92a..cf7f169adb12 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -8,6 +8,8 @@ config SND_SOC_I2C_AND_SPI | |||
8 | default y if I2C=y | 8 | default y if I2C=y |
9 | default y if SPI_MASTER=y | 9 | default y if SPI_MASTER=y |
10 | 10 | ||
11 | menu "CODEC drivers" | ||
12 | |||
11 | config SND_SOC_ALL_CODECS | 13 | config SND_SOC_ALL_CODECS |
12 | tristate "Build all ASoC CODEC drivers" | 14 | tristate "Build all ASoC CODEC drivers" |
13 | depends on COMPILE_TEST | 15 | depends on COMPILE_TEST |
@@ -16,15 +18,20 @@ config SND_SOC_ALL_CODECS | |||
16 | select SND_SOC_AB8500_CODEC if ABX500_CORE | 18 | select SND_SOC_AB8500_CODEC if ABX500_CORE |
17 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS | 19 | select SND_SOC_AC97_CODEC if SND_SOC_AC97_BUS |
18 | select SND_SOC_AD1836 if SPI_MASTER | 20 | select SND_SOC_AD1836 if SPI_MASTER |
19 | select SND_SOC_AD193X if SND_SOC_I2C_AND_SPI | 21 | select SND_SOC_AD193X_SPI if SPI_MASTER |
22 | select SND_SOC_AD193X_I2C if I2C | ||
20 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS | 23 | select SND_SOC_AD1980 if SND_SOC_AC97_BUS |
21 | select SND_SOC_AD73311 | 24 | select SND_SOC_AD73311 |
22 | select SND_SOC_ADAU1373 if I2C | 25 | select SND_SOC_ADAU1373 if I2C |
23 | select SND_SOC_ADAV80X if SND_SOC_I2C_AND_SPI | 26 | select SND_SOC_ADAV801 if SPI_MASTER |
27 | select SND_SOC_ADAV803 if I2C | ||
28 | select SND_SOC_ADAU1977_SPI if SPI_MASTER | ||
29 | select SND_SOC_ADAU1977_I2C if I2C | ||
24 | select SND_SOC_ADAU1701 if I2C | 30 | select SND_SOC_ADAU1701 if I2C |
25 | select SND_SOC_ADS117X | 31 | select SND_SOC_ADS117X |
26 | select SND_SOC_AK4104 if SPI_MASTER | 32 | select SND_SOC_AK4104 if SPI_MASTER |
27 | select SND_SOC_AK4535 if I2C | 33 | select SND_SOC_AK4535 if I2C |
34 | select SND_SOC_AK4554 | ||
28 | select SND_SOC_AK4641 if I2C | 35 | select SND_SOC_AK4641 if I2C |
29 | select SND_SOC_AK4642 if I2C | 36 | select SND_SOC_AK4642 if I2C |
30 | select SND_SOC_AK4671 if I2C | 37 | select SND_SOC_AK4671 if I2C |
@@ -59,6 +66,8 @@ config SND_SOC_ALL_CODECS | |||
59 | select SND_SOC_PCM1681 if I2C | 66 | select SND_SOC_PCM1681 if I2C |
60 | select SND_SOC_PCM1792A if SPI_MASTER | 67 | select SND_SOC_PCM1792A if SPI_MASTER |
61 | select SND_SOC_PCM3008 | 68 | select SND_SOC_PCM3008 |
69 | select SND_SOC_PCM512x_I2C if I2C | ||
70 | select SND_SOC_PCM512x_SPI if SPI_MASTER | ||
62 | select SND_SOC_RT5631 if I2C | 71 | select SND_SOC_RT5631 if I2C |
63 | select SND_SOC_RT5640 if I2C | 72 | select SND_SOC_RT5640 if I2C |
64 | select SND_SOC_SGTL5000 if I2C | 73 | select SND_SOC_SGTL5000 if I2C |
@@ -71,7 +80,8 @@ config SND_SOC_ALL_CODECS | |||
71 | select SND_SOC_STA529 if I2C | 80 | select SND_SOC_STA529 if I2C |
72 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 81 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
73 | select SND_SOC_TAS5086 if I2C | 82 | select SND_SOC_TAS5086 if I2C |
74 | select SND_SOC_TLV320AIC23 if I2C | 83 | select SND_SOC_TLV320AIC23_I2C if I2C |
84 | select SND_SOC_TLV320AIC23_SPI if SPI_MASTER | ||
75 | select SND_SOC_TLV320AIC26 if SPI_MASTER | 85 | select SND_SOC_TLV320AIC26 if SPI_MASTER |
76 | select SND_SOC_TLV320AIC32X4 if I2C | 86 | select SND_SOC_TLV320AIC32X4 if I2C |
77 | select SND_SOC_TLV320AIC3X if I2C | 87 | select SND_SOC_TLV320AIC3X if I2C |
@@ -182,6 +192,14 @@ config SND_SOC_AD1836 | |||
182 | config SND_SOC_AD193X | 192 | config SND_SOC_AD193X |
183 | tristate | 193 | tristate |
184 | 194 | ||
195 | config SND_SOC_AD193X_SPI | ||
196 | tristate | ||
197 | select SND_SOC_AD193X | ||
198 | |||
199 | config SND_SOC_AD193X_I2C | ||
200 | tristate | ||
201 | select SND_SOC_AD193X | ||
202 | |||
185 | config SND_SOC_AD1980 | 203 | config SND_SOC_AD1980 |
186 | tristate | 204 | tristate |
187 | 205 | ||
@@ -189,41 +207,66 @@ config SND_SOC_AD73311 | |||
189 | tristate | 207 | tristate |
190 | 208 | ||
191 | config SND_SOC_ADAU1701 | 209 | config SND_SOC_ADAU1701 |
210 | tristate "Analog Devices ADAU1701 CODEC" | ||
211 | depends on I2C | ||
192 | select SND_SOC_SIGMADSP | 212 | select SND_SOC_SIGMADSP |
193 | tristate | ||
194 | 213 | ||
195 | config SND_SOC_ADAU1373 | 214 | config SND_SOC_ADAU1373 |
196 | tristate | 215 | tristate |
197 | 216 | ||
217 | config SND_SOC_ADAU1977 | ||
218 | tristate | ||
219 | |||
220 | config SND_SOC_ADAU1977_SPI | ||
221 | tristate | ||
222 | select SND_SOC_ADAU1977 | ||
223 | select REGMAP_SPI | ||
224 | |||
225 | config SND_SOC_ADAU1977_I2C | ||
226 | tristate | ||
227 | select SND_SOC_ADAU1977 | ||
228 | select REGMAP_I2C | ||
229 | |||
198 | config SND_SOC_ADAV80X | 230 | config SND_SOC_ADAV80X |
199 | tristate | 231 | tristate |
200 | 232 | ||
233 | config SND_SOC_ADAV801 | ||
234 | tristate | ||
235 | select SND_SOC_ADAV80X | ||
236 | |||
237 | config SND_SOC_ADAV803 | ||
238 | tristate | ||
239 | select SND_SOC_ADAV80X | ||
240 | |||
201 | config SND_SOC_ADS117X | 241 | config SND_SOC_ADS117X |
202 | tristate | 242 | tristate |
203 | 243 | ||
204 | config SND_SOC_AK4104 | 244 | config SND_SOC_AK4104 |
205 | tristate | 245 | tristate "AKM AK4104 CODEC" |
246 | depends on SPI_MASTER | ||
206 | 247 | ||
207 | config SND_SOC_AK4535 | 248 | config SND_SOC_AK4535 |
208 | tristate | 249 | tristate |
209 | 250 | ||
210 | config SND_SOC_AK4554 | 251 | config SND_SOC_AK4554 |
211 | tristate | 252 | tristate "AKM AK4554 CODEC" |
212 | 253 | ||
213 | config SND_SOC_AK4641 | 254 | config SND_SOC_AK4641 |
214 | tristate | 255 | tristate |
215 | 256 | ||
216 | config SND_SOC_AK4642 | 257 | config SND_SOC_AK4642 |
217 | tristate | 258 | tristate "AKM AK4642 CODEC" |
259 | depends on I2C | ||
218 | 260 | ||
219 | config SND_SOC_AK4671 | 261 | config SND_SOC_AK4671 |
220 | tristate | 262 | tristate |
221 | 263 | ||
222 | config SND_SOC_AK5386 | 264 | config SND_SOC_AK5386 |
223 | tristate | 265 | tristate "AKM AK5638 CODEC" |
224 | 266 | ||
225 | config SND_SOC_ALC5623 | 267 | config SND_SOC_ALC5623 |
226 | tristate | 268 | tristate |
269 | |||
227 | config SND_SOC_ALC5632 | 270 | config SND_SOC_ALC5632 |
228 | tristate | 271 | tristate |
229 | 272 | ||
@@ -234,14 +277,17 @@ config SND_SOC_CS42L51 | |||
234 | tristate | 277 | tristate |
235 | 278 | ||
236 | config SND_SOC_CS42L52 | 279 | config SND_SOC_CS42L52 |
237 | tristate | 280 | tristate "Cirrus Logic CS42L52 CODEC" |
281 | depends on I2C | ||
238 | 282 | ||
239 | config SND_SOC_CS42L73 | 283 | config SND_SOC_CS42L73 |
240 | tristate | 284 | tristate "Cirrus Logic CS42L73 CODEC" |
285 | depends on I2C | ||
241 | 286 | ||
242 | # Cirrus Logic CS4270 Codec | 287 | # Cirrus Logic CS4270 Codec |
243 | config SND_SOC_CS4270 | 288 | config SND_SOC_CS4270 |
244 | tristate | 289 | tristate "Cirrus Logic CS4270 CODEC" |
290 | depends on I2C | ||
245 | 291 | ||
246 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata | 292 | # Cirrus Logic CS4270 Codec VD = 3.3V Errata |
247 | # Select if you are affected by the errata where the part will not function | 293 | # Select if you are affected by the errata where the part will not function |
@@ -252,7 +298,8 @@ config SND_SOC_CS4270_VD33_ERRATA | |||
252 | depends on SND_SOC_CS4270 | 298 | depends on SND_SOC_CS4270 |
253 | 299 | ||
254 | config SND_SOC_CS4271 | 300 | config SND_SOC_CS4271 |
255 | tristate | 301 | tristate "Cirrus Logic CS4271 CODEC" |
302 | depends on SND_SOC_I2C_AND_SPI | ||
256 | 303 | ||
257 | config SND_SOC_CX20442 | 304 | config SND_SOC_CX20442 |
258 | tristate | 305 | tristate |
@@ -283,6 +330,9 @@ config SND_SOC_BT_SCO | |||
283 | config SND_SOC_DMIC | 330 | config SND_SOC_DMIC |
284 | tristate | 331 | tristate |
285 | 332 | ||
333 | config SND_SOC_HDMI_CODEC | ||
334 | tristate "HDMI stub CODEC" | ||
335 | |||
286 | config SND_SOC_ISABELLE | 336 | config SND_SOC_ISABELLE |
287 | tristate | 337 | tristate |
288 | 338 | ||
@@ -301,18 +351,32 @@ config SND_SOC_MAX98095 | |||
301 | config SND_SOC_MAX9850 | 351 | config SND_SOC_MAX9850 |
302 | tristate | 352 | tristate |
303 | 353 | ||
304 | config SND_SOC_HDMI_CODEC | ||
305 | tristate | ||
306 | |||
307 | config SND_SOC_PCM1681 | 354 | config SND_SOC_PCM1681 |
308 | tristate | 355 | tristate "Texas Instruments PCM1681 CODEC" |
356 | depends on I2C | ||
309 | 357 | ||
310 | config SND_SOC_PCM1792A | 358 | config SND_SOC_PCM1792A |
311 | tristate | 359 | tristate "Texas Instruments PCM1792A CODEC" |
360 | depends on SPI_MASTER | ||
312 | 361 | ||
313 | config SND_SOC_PCM3008 | 362 | config SND_SOC_PCM3008 |
314 | tristate | 363 | tristate |
315 | 364 | ||
365 | config SND_SOC_PCM512x | ||
366 | tristate | ||
367 | |||
368 | config SND_SOC_PCM512x_I2C | ||
369 | tristate "Texas Instruments PCM512x CODECs - I2C" | ||
370 | depends on I2C | ||
371 | select SND_SOC_PCM512x | ||
372 | select REGMAP_I2C | ||
373 | |||
374 | config SND_SOC_PCM512x_SPI | ||
375 | tristate "Texas Instruments PCM512x CODECs - SPI" | ||
376 | depends on SPI_MASTER | ||
377 | select SND_SOC_PCM512x | ||
378 | select REGMAP_SPI | ||
379 | |||
316 | config SND_SOC_RT5631 | 380 | config SND_SOC_RT5631 |
317 | tristate | 381 | tristate |
318 | 382 | ||
@@ -321,7 +385,8 @@ config SND_SOC_RT5640 | |||
321 | 385 | ||
322 | #Freescale sgtl5000 codec | 386 | #Freescale sgtl5000 codec |
323 | config SND_SOC_SGTL5000 | 387 | config SND_SOC_SGTL5000 |
324 | tristate | 388 | tristate "Freescale SGTL5000 CODEC" |
389 | depends on I2C | ||
325 | 390 | ||
326 | config SND_SOC_SI476X | 391 | config SND_SOC_SI476X |
327 | tristate | 392 | tristate |
@@ -334,7 +399,7 @@ config SND_SOC_SN95031 | |||
334 | tristate | 399 | tristate |
335 | 400 | ||
336 | config SND_SOC_SPDIF | 401 | config SND_SOC_SPDIF |
337 | tristate | 402 | tristate "S/PDIF CODEC" |
338 | 403 | ||
339 | config SND_SOC_SSM2518 | 404 | config SND_SOC_SSM2518 |
340 | tristate | 405 | tristate |
@@ -352,11 +417,20 @@ config SND_SOC_STAC9766 | |||
352 | tristate | 417 | tristate |
353 | 418 | ||
354 | config SND_SOC_TAS5086 | 419 | config SND_SOC_TAS5086 |
355 | tristate | 420 | tristate "Texas Instruments TAS5086 speaker amplifier" |
421 | depends on I2C | ||
356 | 422 | ||
357 | config SND_SOC_TLV320AIC23 | 423 | config SND_SOC_TLV320AIC23 |
358 | tristate | 424 | tristate |
359 | 425 | ||
426 | config SND_SOC_TLV320AIC23_I2C | ||
427 | tristate | ||
428 | select SND_SOC_TLV320AIC23 | ||
429 | |||
430 | config SND_SOC_TLV320AIC23_SPI | ||
431 | tristate | ||
432 | select SND_SOC_TLV320AIC23 | ||
433 | |||
360 | config SND_SOC_TLV320AIC26 | 434 | config SND_SOC_TLV320AIC26 |
361 | tristate | 435 | tristate |
362 | depends on SPI | 436 | depends on SPI |
@@ -365,7 +439,8 @@ config SND_SOC_TLV320AIC32X4 | |||
365 | tristate | 439 | tristate |
366 | 440 | ||
367 | config SND_SOC_TLV320AIC3X | 441 | config SND_SOC_TLV320AIC3X |
368 | tristate | 442 | tristate "Texas Instruments TLV320AIC3x CODECs" |
443 | depends on I2C | ||
369 | 444 | ||
370 | config SND_SOC_TLV320DAC33 | 445 | config SND_SOC_TLV320DAC33 |
371 | tristate | 446 | tristate |
@@ -414,55 +489,69 @@ config SND_SOC_WM8400 | |||
414 | tristate | 489 | tristate |
415 | 490 | ||
416 | config SND_SOC_WM8510 | 491 | config SND_SOC_WM8510 |
417 | tristate | 492 | tristate "Wolfson Microelectronics WM8510 CODEC" |
493 | depends on SND_SOC_I2C_AND_SPI | ||
418 | 494 | ||
419 | config SND_SOC_WM8523 | 495 | config SND_SOC_WM8523 |
420 | tristate | 496 | tristate "Wolfson Microelectronics WM8523 DAC" |
497 | depends on I2C | ||
421 | 498 | ||
422 | config SND_SOC_WM8580 | 499 | config SND_SOC_WM8580 |
423 | tristate | 500 | tristate "Wolfson Microelectronics WM8523 CODEC" |
501 | depends on I2C | ||
424 | 502 | ||
425 | config SND_SOC_WM8711 | 503 | config SND_SOC_WM8711 |
426 | tristate | 504 | tristate "Wolfson Microelectronics WM8711 CODEC" |
505 | depends on SND_SOC_I2C_AND_SPI | ||
427 | 506 | ||
428 | config SND_SOC_WM8727 | 507 | config SND_SOC_WM8727 |
429 | tristate | 508 | tristate |
430 | 509 | ||
431 | config SND_SOC_WM8728 | 510 | config SND_SOC_WM8728 |
432 | tristate | 511 | tristate "Wolfson Microelectronics WM8728 DAC" |
512 | depends on SND_SOC_I2C_AND_SPI | ||
433 | 513 | ||
434 | config SND_SOC_WM8731 | 514 | config SND_SOC_WM8731 |
435 | tristate | 515 | tristate "Wolfson Microelectronics WM8731 CODEC" |
516 | depends on SND_SOC_I2C_AND_SPI | ||
436 | 517 | ||
437 | config SND_SOC_WM8737 | 518 | config SND_SOC_WM8737 |
438 | tristate | 519 | tristate "Wolfson Microelectronics WM8737 ADC" |
520 | depends on SND_SOC_I2C_AND_SPI | ||
439 | 521 | ||
440 | config SND_SOC_WM8741 | 522 | config SND_SOC_WM8741 |
441 | tristate | 523 | tristate "Wolfson Microelectronics WM8737 DAC" |
524 | depends on SND_SOC_I2C_AND_SPI | ||
442 | 525 | ||
443 | config SND_SOC_WM8750 | 526 | config SND_SOC_WM8750 |
444 | tristate | 527 | tristate "Wolfson Microelectronics WM8750 CODEC" |
528 | depends on SND_SOC_I2C_AND_SPI | ||
445 | 529 | ||
446 | config SND_SOC_WM8753 | 530 | config SND_SOC_WM8753 |
447 | tristate | 531 | tristate "Wolfson Microelectronics WM8753 CODEC" |
532 | depends on SND_SOC_I2C_AND_SPI | ||
448 | 533 | ||
449 | config SND_SOC_WM8770 | 534 | config SND_SOC_WM8770 |
450 | tristate | 535 | tristate "Wolfson Microelectronics WM8770 CODEC" |
536 | depends on SPI_MASTER | ||
451 | 537 | ||
452 | config SND_SOC_WM8776 | 538 | config SND_SOC_WM8776 |
453 | tristate | 539 | tristate "Wolfson Microelectronics WM8776 CODEC" |
540 | depends on SND_SOC_I2C_AND_SPI | ||
454 | 541 | ||
455 | config SND_SOC_WM8782 | 542 | config SND_SOC_WM8782 |
456 | tristate | 543 | tristate |
457 | 544 | ||
458 | config SND_SOC_WM8804 | 545 | config SND_SOC_WM8804 |
459 | tristate | 546 | tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver" |
547 | depends on SND_SOC_I2C_AND_SPI | ||
460 | 548 | ||
461 | config SND_SOC_WM8900 | 549 | config SND_SOC_WM8900 |
462 | tristate | 550 | tristate |
463 | 551 | ||
464 | config SND_SOC_WM8903 | 552 | config SND_SOC_WM8903 |
465 | tristate | 553 | tristate "Wolfson Microelectronics WM8903 CODEC" |
554 | depends on I2C | ||
466 | 555 | ||
467 | config SND_SOC_WM8904 | 556 | config SND_SOC_WM8904 |
468 | tristate | 557 | tristate |
@@ -480,7 +569,8 @@ config SND_SOC_WM8961 | |||
480 | tristate | 569 | tristate |
481 | 570 | ||
482 | config SND_SOC_WM8962 | 571 | config SND_SOC_WM8962 |
483 | tristate | 572 | tristate "Wolfson Microelectronics WM8962 CODEC" |
573 | depends on I2C | ||
484 | 574 | ||
485 | config SND_SOC_WM8971 | 575 | config SND_SOC_WM8971 |
486 | tristate | 576 | tristate |
@@ -553,4 +643,7 @@ config SND_SOC_ML26124 | |||
553 | tristate | 643 | tristate |
554 | 644 | ||
555 | config SND_SOC_TPA6130A2 | 645 | config SND_SOC_TPA6130A2 |
556 | tristate | 646 | tristate "Texas Instruments TPA6130A2 headphone amplifier" |
647 | depends on I2C | ||
648 | |||
649 | endmenu | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index bc126764a44d..08540dae0090 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -3,11 +3,18 @@ snd-soc-ab8500-codec-objs := ab8500-codec.o | |||
3 | snd-soc-ac97-objs := ac97.o | 3 | snd-soc-ac97-objs := ac97.o |
4 | snd-soc-ad1836-objs := ad1836.o | 4 | snd-soc-ad1836-objs := ad1836.o |
5 | snd-soc-ad193x-objs := ad193x.o | 5 | snd-soc-ad193x-objs := ad193x.o |
6 | snd-soc-ad193x-spi-objs := ad193x-spi.o | ||
7 | snd-soc-ad193x-i2c-objs := ad193x-i2c.o | ||
6 | snd-soc-ad1980-objs := ad1980.o | 8 | snd-soc-ad1980-objs := ad1980.o |
7 | snd-soc-ad73311-objs := ad73311.o | 9 | snd-soc-ad73311-objs := ad73311.o |
8 | snd-soc-adau1701-objs := adau1701.o | 10 | snd-soc-adau1701-objs := adau1701.o |
9 | snd-soc-adau1373-objs := adau1373.o | 11 | snd-soc-adau1373-objs := adau1373.o |
12 | snd-soc-adau1977-objs := adau1977.o | ||
13 | snd-soc-adau1977-spi-objs := adau1977-spi.o | ||
14 | snd-soc-adau1977-i2c-objs := adau1977-i2c.o | ||
10 | snd-soc-adav80x-objs := adav80x.o | 15 | snd-soc-adav80x-objs := adav80x.o |
16 | snd-soc-adav801-objs := adav801.o | ||
17 | snd-soc-adav803-objs := adav803.o | ||
11 | snd-soc-ads117x-objs := ads117x.o | 18 | snd-soc-ads117x-objs := ads117x.o |
12 | snd-soc-ak4104-objs := ak4104.o | 19 | snd-soc-ak4104-objs := ak4104.o |
13 | snd-soc-ak4535-objs := ak4535.o | 20 | snd-soc-ak4535-objs := ak4535.o |
@@ -46,6 +53,9 @@ snd-soc-hdmi-codec-objs := hdmi.o | |||
46 | snd-soc-pcm1681-objs := pcm1681.o | 53 | snd-soc-pcm1681-objs := pcm1681.o |
47 | snd-soc-pcm1792a-codec-objs := pcm1792a.o | 54 | snd-soc-pcm1792a-codec-objs := pcm1792a.o |
48 | snd-soc-pcm3008-objs := pcm3008.o | 55 | snd-soc-pcm3008-objs := pcm3008.o |
56 | snd-soc-pcm512x-objs := pcm512x.o | ||
57 | snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o | ||
58 | snd-soc-pcm512x-spi-objs := pcm512x-spi.o | ||
49 | snd-soc-rt5631-objs := rt5631.o | 59 | snd-soc-rt5631-objs := rt5631.o |
50 | snd-soc-rt5640-objs := rt5640.o | 60 | snd-soc-rt5640-objs := rt5640.o |
51 | snd-soc-sgtl5000-objs := sgtl5000.o | 61 | snd-soc-sgtl5000-objs := sgtl5000.o |
@@ -63,6 +73,8 @@ snd-soc-sta529-objs := sta529.o | |||
63 | snd-soc-stac9766-objs := stac9766.o | 73 | snd-soc-stac9766-objs := stac9766.o |
64 | snd-soc-tas5086-objs := tas5086.o | 74 | snd-soc-tas5086-objs := tas5086.o |
65 | snd-soc-tlv320aic23-objs := tlv320aic23.o | 75 | snd-soc-tlv320aic23-objs := tlv320aic23.o |
76 | snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o | ||
77 | snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o | ||
66 | snd-soc-tlv320aic26-objs := tlv320aic26.o | 78 | snd-soc-tlv320aic26-objs := tlv320aic26.o |
67 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o | 79 | snd-soc-tlv320aic3x-objs := tlv320aic3x.o |
68 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o | 80 | snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o |
@@ -134,11 +146,18 @@ obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o | |||
134 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o | 146 | obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o |
135 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o | 147 | obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o |
136 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o | 148 | obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o |
149 | obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o | ||
150 | obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o | ||
137 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o | 151 | obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o |
138 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o | 152 | obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o |
139 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o | 153 | obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o |
154 | obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o | ||
155 | obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o | ||
156 | obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o | ||
140 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o | 157 | obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o |
141 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o | 158 | obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o |
159 | obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o | ||
160 | obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o | ||
142 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o | 161 | obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o |
143 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o | 162 | obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o |
144 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o | 163 | obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o |
@@ -179,6 +198,9 @@ obj-$(CONFIG_SND_SOC_HDMI_CODEC) += snd-soc-hdmi-codec.o | |||
179 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o | 198 | obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o |
180 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o | 199 | obj-$(CONFIG_SND_SOC_PCM1792A) += snd-soc-pcm1792a-codec.o |
181 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o | 200 | obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o |
201 | obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o | ||
202 | obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o | ||
203 | obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o | ||
182 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o | 204 | obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o |
183 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o | 205 | obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o |
184 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o | 206 | obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o |
@@ -193,6 +215,8 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | |||
193 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 215 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
194 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 216 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
195 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o | 217 | obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o |
218 | obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o | ||
219 | obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o | ||
196 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o | 220 | obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o |
197 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o | 221 | obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o |
198 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o | 222 | obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o |
diff --git a/sound/soc/codecs/ad1836.c b/sound/soc/codecs/ad1836.c index 77f459868579..685998dd086e 100644 --- a/sound/soc/codecs/ad1836.c +++ b/sound/soc/codecs/ad1836.c | |||
@@ -40,8 +40,8 @@ struct ad1836_priv { | |||
40 | */ | 40 | */ |
41 | static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; | 41 | static const char *ad1836_deemp[] = {"None", "44.1kHz", "32kHz", "48kHz"}; |
42 | 42 | ||
43 | static const struct soc_enum ad1836_deemp_enum = | 43 | static SOC_ENUM_SINGLE_DECL(ad1836_deemp_enum, |
44 | SOC_ENUM_SINGLE(AD1836_DAC_CTRL1, 8, 4, ad1836_deemp); | 44 | AD1836_DAC_CTRL1, 8, ad1836_deemp); |
45 | 45 | ||
46 | #define AD1836_DAC_VOLUME(x) \ | 46 | #define AD1836_DAC_VOLUME(x) \ |
47 | SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ | 47 | SOC_DOUBLE_R("DAC" #x " Playback Volume", AD1836_DAC_L_VOL(x), \ |
diff --git a/sound/soc/codecs/ad193x-i2c.c b/sound/soc/codecs/ad193x-i2c.c new file mode 100644 index 000000000000..df3a1a415825 --- /dev/null +++ b/sound/soc/codecs/ad193x-i2c.c | |||
@@ -0,0 +1,54 @@ | |||
1 | /* | ||
2 | * AD1936/AD1937 audio driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/regmap.h> | ||
12 | |||
13 | #include <sound/soc.h> | ||
14 | |||
15 | #include "ad193x.h" | ||
16 | |||
17 | static const struct i2c_device_id ad193x_id[] = { | ||
18 | { "ad1936", 0 }, | ||
19 | { "ad1937", 0 }, | ||
20 | { } | ||
21 | }; | ||
22 | MODULE_DEVICE_TABLE(i2c, ad193x_id); | ||
23 | |||
24 | static int ad193x_i2c_probe(struct i2c_client *client, | ||
25 | const struct i2c_device_id *id) | ||
26 | { | ||
27 | struct regmap_config config; | ||
28 | |||
29 | config = ad193x_regmap_config; | ||
30 | config.val_bits = 8; | ||
31 | config.reg_bits = 8; | ||
32 | |||
33 | return ad193x_probe(&client->dev, devm_regmap_init_i2c(client, &config)); | ||
34 | } | ||
35 | |||
36 | static int ad193x_i2c_remove(struct i2c_client *client) | ||
37 | { | ||
38 | snd_soc_unregister_codec(&client->dev); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | static struct i2c_driver ad193x_i2c_driver = { | ||
43 | .driver = { | ||
44 | .name = "ad193x", | ||
45 | }, | ||
46 | .probe = ad193x_i2c_probe, | ||
47 | .remove = ad193x_i2c_remove, | ||
48 | .id_table = ad193x_id, | ||
49 | }; | ||
50 | module_i2c_driver(ad193x_i2c_driver); | ||
51 | |||
52 | MODULE_DESCRIPTION("ASoC AD1936/AD1937 audio CODEC driver"); | ||
53 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
54 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad193x-spi.c b/sound/soc/codecs/ad193x-spi.c new file mode 100644 index 000000000000..390cef9b9dc2 --- /dev/null +++ b/sound/soc/codecs/ad193x-spi.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * AD1938/AD1939 audio driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/spi/spi.h> | ||
11 | #include <linux/regmap.h> | ||
12 | |||
13 | #include <sound/soc.h> | ||
14 | |||
15 | #include "ad193x.h" | ||
16 | |||
17 | static int ad193x_spi_probe(struct spi_device *spi) | ||
18 | { | ||
19 | struct regmap_config config; | ||
20 | |||
21 | config = ad193x_regmap_config; | ||
22 | config.val_bits = 8; | ||
23 | config.reg_bits = 16; | ||
24 | config.read_flag_mask = 0x09; | ||
25 | config.write_flag_mask = 0x08; | ||
26 | |||
27 | return ad193x_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); | ||
28 | } | ||
29 | |||
30 | static int ad193x_spi_remove(struct spi_device *spi) | ||
31 | { | ||
32 | snd_soc_unregister_codec(&spi->dev); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static struct spi_driver ad193x_spi_driver = { | ||
37 | .driver = { | ||
38 | .name = "ad193x", | ||
39 | .owner = THIS_MODULE, | ||
40 | }, | ||
41 | .probe = ad193x_spi_probe, | ||
42 | .remove = ad193x_spi_remove, | ||
43 | }; | ||
44 | module_spi_driver(ad193x_spi_driver); | ||
45 | |||
46 | MODULE_DESCRIPTION("ASoC AD1938/AD1939 audio CODEC driver"); | ||
47 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | ||
48 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c index 5a42dca535b7..9381a767e75f 100644 --- a/sound/soc/codecs/ad193x.c +++ b/sound/soc/codecs/ad193x.c | |||
@@ -6,12 +6,10 @@ | |||
6 | * Licensed under the GPL-2 or later. | 6 | * Licensed under the GPL-2 or later. |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/module.h> | 9 | #include <linux/module.h> |
11 | #include <linux/kernel.h> | 10 | #include <linux/kernel.h> |
12 | #include <linux/device.h> | 11 | #include <linux/device.h> |
13 | #include <linux/i2c.h> | 12 | #include <linux/regmap.h> |
14 | #include <linux/spi/spi.h> | ||
15 | #include <linux/slab.h> | 13 | #include <linux/slab.h> |
16 | #include <sound/core.h> | 14 | #include <sound/core.h> |
17 | #include <sound/pcm.h> | 15 | #include <sound/pcm.h> |
@@ -19,6 +17,7 @@ | |||
19 | #include <sound/initval.h> | 17 | #include <sound/initval.h> |
20 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
21 | #include <sound/tlv.h> | 19 | #include <sound/tlv.h> |
20 | |||
22 | #include "ad193x.h" | 21 | #include "ad193x.h" |
23 | 22 | ||
24 | /* codec private data */ | 23 | /* codec private data */ |
@@ -32,8 +31,8 @@ struct ad193x_priv { | |||
32 | */ | 31 | */ |
33 | static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; | 32 | static const char * const ad193x_deemp[] = {"None", "48kHz", "44.1kHz", "32kHz"}; |
34 | 33 | ||
35 | static const struct soc_enum ad193x_deemp_enum = | 34 | static SOC_ENUM_SINGLE_DECL(ad193x_deemp_enum, AD193X_DAC_CTRL2, 1, |
36 | SOC_ENUM_SINGLE(AD193X_DAC_CTRL2, 1, 4, ad193x_deemp); | 35 | ad193x_deemp); |
37 | 36 | ||
38 | static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); | 37 | static const DECLARE_TLV_DB_MINMAX(adau193x_tlv, -9563, 0); |
39 | 38 | ||
@@ -320,7 +319,7 @@ static struct snd_soc_dai_driver ad193x_dai = { | |||
320 | .ops = &ad193x_dai_ops, | 319 | .ops = &ad193x_dai_ops, |
321 | }; | 320 | }; |
322 | 321 | ||
323 | static int ad193x_probe(struct snd_soc_codec *codec) | 322 | static int ad193x_codec_probe(struct snd_soc_codec *codec) |
324 | { | 323 | { |
325 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); | 324 | struct ad193x_priv *ad193x = snd_soc_codec_get_drvdata(codec); |
326 | int ret; | 325 | int ret; |
@@ -352,7 +351,7 @@ static int ad193x_probe(struct snd_soc_codec *codec) | |||
352 | } | 351 | } |
353 | 352 | ||
354 | static struct snd_soc_codec_driver soc_codec_dev_ad193x = { | 353 | static struct snd_soc_codec_driver soc_codec_dev_ad193x = { |
355 | .probe = ad193x_probe, | 354 | .probe = ad193x_codec_probe, |
356 | .controls = ad193x_snd_controls, | 355 | .controls = ad193x_snd_controls, |
357 | .num_controls = ARRAY_SIZE(ad193x_snd_controls), | 356 | .num_controls = ARRAY_SIZE(ad193x_snd_controls), |
358 | .dapm_widgets = ad193x_dapm_widgets, | 357 | .dapm_widgets = ad193x_dapm_widgets, |
@@ -366,140 +365,31 @@ static bool adau193x_reg_volatile(struct device *dev, unsigned int reg) | |||
366 | return false; | 365 | return false; |
367 | } | 366 | } |
368 | 367 | ||
369 | #if defined(CONFIG_SPI_MASTER) | 368 | const struct regmap_config ad193x_regmap_config = { |
370 | |||
371 | static const struct regmap_config ad193x_spi_regmap_config = { | ||
372 | .val_bits = 8, | ||
373 | .reg_bits = 16, | ||
374 | .read_flag_mask = 0x09, | ||
375 | .write_flag_mask = 0x08, | ||
376 | |||
377 | .max_register = AD193X_NUM_REGS - 1, | 369 | .max_register = AD193X_NUM_REGS - 1, |
378 | .volatile_reg = adau193x_reg_volatile, | 370 | .volatile_reg = adau193x_reg_volatile, |
379 | }; | 371 | }; |
372 | EXPORT_SYMBOL_GPL(ad193x_regmap_config); | ||
380 | 373 | ||
381 | static int ad193x_spi_probe(struct spi_device *spi) | 374 | int ad193x_probe(struct device *dev, struct regmap *regmap) |
382 | { | 375 | { |
383 | struct ad193x_priv *ad193x; | 376 | struct ad193x_priv *ad193x; |
384 | 377 | ||
385 | ad193x = devm_kzalloc(&spi->dev, sizeof(struct ad193x_priv), | 378 | if (IS_ERR(regmap)) |
386 | GFP_KERNEL); | 379 | return PTR_ERR(regmap); |
387 | if (ad193x == NULL) | ||
388 | return -ENOMEM; | ||
389 | |||
390 | ad193x->regmap = devm_regmap_init_spi(spi, &ad193x_spi_regmap_config); | ||
391 | if (IS_ERR(ad193x->regmap)) | ||
392 | return PTR_ERR(ad193x->regmap); | ||
393 | |||
394 | spi_set_drvdata(spi, ad193x); | ||
395 | |||
396 | return snd_soc_register_codec(&spi->dev, &soc_codec_dev_ad193x, | ||
397 | &ad193x_dai, 1); | ||
398 | } | ||
399 | |||
400 | static int ad193x_spi_remove(struct spi_device *spi) | ||
401 | { | ||
402 | snd_soc_unregister_codec(&spi->dev); | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | static struct spi_driver ad193x_spi_driver = { | ||
407 | .driver = { | ||
408 | .name = "ad193x", | ||
409 | .owner = THIS_MODULE, | ||
410 | }, | ||
411 | .probe = ad193x_spi_probe, | ||
412 | .remove = ad193x_spi_remove, | ||
413 | }; | ||
414 | #endif | ||
415 | |||
416 | #if IS_ENABLED(CONFIG_I2C) | ||
417 | |||
418 | static const struct regmap_config ad193x_i2c_regmap_config = { | ||
419 | .val_bits = 8, | ||
420 | .reg_bits = 8, | ||
421 | |||
422 | .max_register = AD193X_NUM_REGS - 1, | ||
423 | .volatile_reg = adau193x_reg_volatile, | ||
424 | }; | ||
425 | |||
426 | static const struct i2c_device_id ad193x_id[] = { | ||
427 | { "ad1936", 0 }, | ||
428 | { "ad1937", 0 }, | ||
429 | { } | ||
430 | }; | ||
431 | MODULE_DEVICE_TABLE(i2c, ad193x_id); | ||
432 | 380 | ||
433 | static int ad193x_i2c_probe(struct i2c_client *client, | 381 | ad193x = devm_kzalloc(dev, sizeof(*ad193x), GFP_KERNEL); |
434 | const struct i2c_device_id *id) | ||
435 | { | ||
436 | struct ad193x_priv *ad193x; | ||
437 | |||
438 | ad193x = devm_kzalloc(&client->dev, sizeof(struct ad193x_priv), | ||
439 | GFP_KERNEL); | ||
440 | if (ad193x == NULL) | 382 | if (ad193x == NULL) |
441 | return -ENOMEM; | 383 | return -ENOMEM; |
442 | 384 | ||
443 | ad193x->regmap = devm_regmap_init_i2c(client, &ad193x_i2c_regmap_config); | 385 | ad193x->regmap = regmap; |
444 | if (IS_ERR(ad193x->regmap)) | ||
445 | return PTR_ERR(ad193x->regmap); | ||
446 | |||
447 | i2c_set_clientdata(client, ad193x); | ||
448 | |||
449 | return snd_soc_register_codec(&client->dev, &soc_codec_dev_ad193x, | ||
450 | &ad193x_dai, 1); | ||
451 | } | ||
452 | |||
453 | static int ad193x_i2c_remove(struct i2c_client *client) | ||
454 | { | ||
455 | snd_soc_unregister_codec(&client->dev); | ||
456 | return 0; | ||
457 | } | ||
458 | 386 | ||
459 | static struct i2c_driver ad193x_i2c_driver = { | 387 | dev_set_drvdata(dev, ad193x); |
460 | .driver = { | ||
461 | .name = "ad193x", | ||
462 | }, | ||
463 | .probe = ad193x_i2c_probe, | ||
464 | .remove = ad193x_i2c_remove, | ||
465 | .id_table = ad193x_id, | ||
466 | }; | ||
467 | #endif | ||
468 | |||
469 | static int __init ad193x_modinit(void) | ||
470 | { | ||
471 | int ret; | ||
472 | |||
473 | #if IS_ENABLED(CONFIG_I2C) | ||
474 | ret = i2c_add_driver(&ad193x_i2c_driver); | ||
475 | if (ret != 0) { | ||
476 | printk(KERN_ERR "Failed to register AD193X I2C driver: %d\n", | ||
477 | ret); | ||
478 | } | ||
479 | #endif | ||
480 | |||
481 | #if defined(CONFIG_SPI_MASTER) | ||
482 | ret = spi_register_driver(&ad193x_spi_driver); | ||
483 | if (ret != 0) { | ||
484 | printk(KERN_ERR "Failed to register AD193X SPI driver: %d\n", | ||
485 | ret); | ||
486 | } | ||
487 | #endif | ||
488 | return ret; | ||
489 | } | ||
490 | module_init(ad193x_modinit); | ||
491 | |||
492 | static void __exit ad193x_modexit(void) | ||
493 | { | ||
494 | #if defined(CONFIG_SPI_MASTER) | ||
495 | spi_unregister_driver(&ad193x_spi_driver); | ||
496 | #endif | ||
497 | 388 | ||
498 | #if IS_ENABLED(CONFIG_I2C) | 389 | return snd_soc_register_codec(dev, &soc_codec_dev_ad193x, |
499 | i2c_del_driver(&ad193x_i2c_driver); | 390 | &ad193x_dai, 1); |
500 | #endif | ||
501 | } | 391 | } |
502 | module_exit(ad193x_modexit); | 392 | EXPORT_SYMBOL_GPL(ad193x_probe); |
503 | 393 | ||
504 | MODULE_DESCRIPTION("ASoC ad193x driver"); | 394 | MODULE_DESCRIPTION("ASoC ad193x driver"); |
505 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); | 395 | MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>"); |
diff --git a/sound/soc/codecs/ad193x.h b/sound/soc/codecs/ad193x.h index 473388049992..ab9a998f15be 100644 --- a/sound/soc/codecs/ad193x.h +++ b/sound/soc/codecs/ad193x.h | |||
@@ -9,6 +9,13 @@ | |||
9 | #ifndef __AD193X_H__ | 9 | #ifndef __AD193X_H__ |
10 | #define __AD193X_H__ | 10 | #define __AD193X_H__ |
11 | 11 | ||
12 | #include <linux/regmap.h> | ||
13 | |||
14 | struct device; | ||
15 | |||
16 | extern const struct regmap_config ad193x_regmap_config; | ||
17 | int ad193x_probe(struct device *dev, struct regmap *regmap); | ||
18 | |||
12 | #define AD193X_PLL_CLK_CTRL0 0x00 | 19 | #define AD193X_PLL_CLK_CTRL0 0x00 |
13 | #define AD193X_PLL_POWERDOWN 0x01 | 20 | #define AD193X_PLL_POWERDOWN 0x01 |
14 | #define AD193X_PLL_INPUT_MASK 0x6 | 21 | #define AD193X_PLL_INPUT_MASK 0x6 |
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 7257a8885f42..34d965a4a040 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c | |||
@@ -57,8 +57,8 @@ static const u16 ad1980_reg[] = { | |||
57 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", | 57 | static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line", |
58 | "Stereo Mix", "Mono Mix", "Phone"}; | 58 | "Stereo Mix", "Mono Mix", "Phone"}; |
59 | 59 | ||
60 | static const struct soc_enum ad1980_cap_src = | 60 | static SOC_ENUM_DOUBLE_DECL(ad1980_cap_src, |
61 | SOC_ENUM_DOUBLE(AC97_REC_SEL, 8, 0, 7, ad1980_rec_sel); | 61 | AC97_REC_SEL, 8, 0, ad1980_rec_sel); |
62 | 62 | ||
63 | static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { | 63 | static const struct snd_kcontrol_new ad1980_snd_ac97_controls[] = { |
64 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), | 64 | SOC_DOUBLE("Master Playback Volume", AC97_MASTER, 8, 0, 31, 1), |
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index eb836ed5271f..5223800775ad 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c | |||
@@ -345,15 +345,15 @@ static const char *adau1373_fdsp_sel_text[] = { | |||
345 | "Channel 5", | 345 | "Channel 5", |
346 | }; | 346 | }; |
347 | 347 | ||
348 | static const SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, | 348 | static SOC_ENUM_SINGLE_DECL(adau1373_drc1_channel_enum, |
349 | ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text); | 349 | ADAU1373_FDSP_SEL1, 4, adau1373_fdsp_sel_text); |
350 | static const SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, | 350 | static SOC_ENUM_SINGLE_DECL(adau1373_drc2_channel_enum, |
351 | ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text); | 351 | ADAU1373_FDSP_SEL1, 0, adau1373_fdsp_sel_text); |
352 | static const SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, | 352 | static SOC_ENUM_SINGLE_DECL(adau1373_drc3_channel_enum, |
353 | ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text); | 353 | ADAU1373_FDSP_SEL2, 0, adau1373_fdsp_sel_text); |
354 | static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, | 354 | static SOC_ENUM_SINGLE_DECL(adau1373_hpf_channel_enum, |
355 | ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text); | 355 | ADAU1373_FDSP_SEL3, 0, adau1373_fdsp_sel_text); |
356 | static const SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, | 356 | static SOC_ENUM_SINGLE_DECL(adau1373_bass_channel_enum, |
357 | ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text); | 357 | ADAU1373_FDSP_SEL4, 4, adau1373_fdsp_sel_text); |
358 | 358 | ||
359 | static const char *adau1373_hpf_cutoff_text[] = { | 359 | static const char *adau1373_hpf_cutoff_text[] = { |
@@ -362,7 +362,7 @@ static const char *adau1373_hpf_cutoff_text[] = { | |||
362 | "800Hz", | 362 | "800Hz", |
363 | }; | 363 | }; |
364 | 364 | ||
365 | static const SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, | 365 | static SOC_ENUM_SINGLE_DECL(adau1373_hpf_cutoff_enum, |
366 | ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text); | 366 | ADAU1373_HPF_CTRL, 3, adau1373_hpf_cutoff_text); |
367 | 367 | ||
368 | static const char *adau1373_bass_lpf_cutoff_text[] = { | 368 | static const char *adau1373_bass_lpf_cutoff_text[] = { |
@@ -388,14 +388,14 @@ static const unsigned int adau1373_bass_tlv[] = { | |||
388 | 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0), | 388 | 5, 7, TLV_DB_SCALE_ITEM(1400, 150, 0), |
389 | }; | 389 | }; |
390 | 390 | ||
391 | static const SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, | 391 | static SOC_ENUM_SINGLE_DECL(adau1373_bass_lpf_cutoff_enum, |
392 | ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); | 392 | ADAU1373_BASS1, 5, adau1373_bass_lpf_cutoff_text); |
393 | 393 | ||
394 | static const SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, | 394 | static SOC_VALUE_ENUM_SINGLE_DECL(adau1373_bass_clip_level_enum, |
395 | ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text, | 395 | ADAU1373_BASS1, 2, 7, adau1373_bass_clip_level_text, |
396 | adau1373_bass_clip_level_values); | 396 | adau1373_bass_clip_level_values); |
397 | 397 | ||
398 | static const SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, | 398 | static SOC_ENUM_SINGLE_DECL(adau1373_bass_hpf_cutoff_enum, |
399 | ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text); | 399 | ADAU1373_BASS1, 0, adau1373_bass_hpf_cutoff_text); |
400 | 400 | ||
401 | static const char *adau1373_3d_level_text[] = { | 401 | static const char *adau1373_3d_level_text[] = { |
@@ -409,9 +409,9 @@ static const char *adau1373_3d_cutoff_text[] = { | |||
409 | "0.16875 fs", "0.27083 fs" | 409 | "0.16875 fs", "0.27083 fs" |
410 | }; | 410 | }; |
411 | 411 | ||
412 | static const SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, | 412 | static SOC_ENUM_SINGLE_DECL(adau1373_3d_level_enum, |
413 | ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text); | 413 | ADAU1373_3D_CTRL1, 4, adau1373_3d_level_text); |
414 | static const SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, | 414 | static SOC_ENUM_SINGLE_DECL(adau1373_3d_cutoff_enum, |
415 | ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text); | 415 | ADAU1373_3D_CTRL1, 0, adau1373_3d_cutoff_text); |
416 | 416 | ||
417 | static const unsigned int adau1373_3d_tlv[] = { | 417 | static const unsigned int adau1373_3d_tlv[] = { |
@@ -427,11 +427,11 @@ static const char *adau1373_lr_mux_text[] = { | |||
427 | "Stereo", | 427 | "Stereo", |
428 | }; | 428 | }; |
429 | 429 | ||
430 | static const SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, | 430 | static SOC_ENUM_SINGLE_DECL(adau1373_lineout1_lr_mux_enum, |
431 | ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text); | 431 | ADAU1373_OUTPUT_CTRL, 4, adau1373_lr_mux_text); |
432 | static const SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, | 432 | static SOC_ENUM_SINGLE_DECL(adau1373_lineout2_lr_mux_enum, |
433 | ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text); | 433 | ADAU1373_OUTPUT_CTRL, 6, adau1373_lr_mux_text); |
434 | static const SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, | 434 | static SOC_ENUM_SINGLE_DECL(adau1373_speaker_lr_mux_enum, |
435 | ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text); | 435 | ADAU1373_LS_CTRL, 4, adau1373_lr_mux_text); |
436 | 436 | ||
437 | static const struct snd_kcontrol_new adau1373_controls[] = { | 437 | static const struct snd_kcontrol_new adau1373_controls[] = { |
@@ -576,8 +576,8 @@ static const char *adau1373_decimator_text[] = { | |||
576 | "DMIC1", | 576 | "DMIC1", |
577 | }; | 577 | }; |
578 | 578 | ||
579 | static const struct soc_enum adau1373_decimator_enum = | 579 | static SOC_ENUM_SINGLE_VIRT_DECL(adau1373_decimator_enum, |
580 | SOC_ENUM_SINGLE(0, 0, 2, adau1373_decimator_text); | 580 | adau1373_decimator_text); |
581 | 581 | ||
582 | static const struct snd_kcontrol_new adau1373_decimator_mux = | 582 | static const struct snd_kcontrol_new adau1373_decimator_mux = |
583 | SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); | 583 | SOC_DAPM_ENUM_VIRT("Decimator Mux", adau1373_decimator_enum); |
diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c new file mode 100644 index 000000000000..9700e8c838c9 --- /dev/null +++ b/sound/soc/codecs/adau1977-i2c.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/mod_devicetable.h> | ||
12 | #include <linux/module.h> | ||
13 | #include <linux/regmap.h> | ||
14 | #include <sound/soc.h> | ||
15 | |||
16 | #include "adau1977.h" | ||
17 | |||
18 | static int adau1977_i2c_probe(struct i2c_client *client, | ||
19 | const struct i2c_device_id *id) | ||
20 | { | ||
21 | struct regmap_config config; | ||
22 | |||
23 | config = adau1977_regmap_config; | ||
24 | config.val_bits = 8; | ||
25 | config.reg_bits = 8; | ||
26 | |||
27 | return adau1977_probe(&client->dev, | ||
28 | devm_regmap_init_i2c(client, &config), | ||
29 | id->driver_data, NULL); | ||
30 | } | ||
31 | |||
32 | static int adau1977_i2c_remove(struct i2c_client *client) | ||
33 | { | ||
34 | snd_soc_unregister_codec(&client->dev); | ||
35 | return 0; | ||
36 | } | ||
37 | |||
38 | static const struct i2c_device_id adau1977_i2c_ids[] = { | ||
39 | { "adau1977", ADAU1977 }, | ||
40 | { "adau1978", ADAU1978 }, | ||
41 | { "adau1979", ADAU1978 }, | ||
42 | { } | ||
43 | }; | ||
44 | MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); | ||
45 | |||
46 | static struct i2c_driver adau1977_i2c_driver = { | ||
47 | .driver = { | ||
48 | .name = "adau1977", | ||
49 | .owner = THIS_MODULE, | ||
50 | }, | ||
51 | .probe = adau1977_i2c_probe, | ||
52 | .remove = adau1977_i2c_remove, | ||
53 | .id_table = adau1977_i2c_ids, | ||
54 | }; | ||
55 | module_i2c_driver(adau1977_i2c_driver); | ||
56 | |||
57 | MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); | ||
58 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
59 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1977-spi.c b/sound/soc/codecs/adau1977-spi.c new file mode 100644 index 000000000000..b05cf5da3a94 --- /dev/null +++ b/sound/soc/codecs/adau1977-spi.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/mod_devicetable.h> | ||
11 | #include <linux/module.h> | ||
12 | #include <linux/regmap.h> | ||
13 | #include <linux/spi/spi.h> | ||
14 | #include <sound/soc.h> | ||
15 | |||
16 | #include "adau1977.h" | ||
17 | |||
18 | static void adau1977_spi_switch_mode(struct device *dev) | ||
19 | { | ||
20 | struct spi_device *spi = to_spi_device(dev); | ||
21 | |||
22 | /* | ||
23 | * To get the device into SPI mode CLATCH has to be pulled low three | ||
24 | * times. Do this by issuing three dummy reads. | ||
25 | */ | ||
26 | spi_w8r8(spi, 0x00); | ||
27 | spi_w8r8(spi, 0x00); | ||
28 | spi_w8r8(spi, 0x00); | ||
29 | } | ||
30 | |||
31 | static int adau1977_spi_probe(struct spi_device *spi) | ||
32 | { | ||
33 | const struct spi_device_id *id = spi_get_device_id(spi); | ||
34 | struct regmap_config config; | ||
35 | |||
36 | if (!id) | ||
37 | return -EINVAL; | ||
38 | |||
39 | config = adau1977_regmap_config; | ||
40 | config.val_bits = 8; | ||
41 | config.reg_bits = 16; | ||
42 | config.read_flag_mask = 0x1; | ||
43 | |||
44 | return adau1977_probe(&spi->dev, | ||
45 | devm_regmap_init_spi(spi, &config), | ||
46 | id->driver_data, adau1977_spi_switch_mode); | ||
47 | } | ||
48 | |||
49 | static int adau1977_spi_remove(struct spi_device *spi) | ||
50 | { | ||
51 | snd_soc_unregister_codec(&spi->dev); | ||
52 | return 0; | ||
53 | } | ||
54 | |||
55 | static const struct spi_device_id adau1977_spi_ids[] = { | ||
56 | { "adau1977", ADAU1977 }, | ||
57 | { "adau1978", ADAU1978 }, | ||
58 | { "adau1979", ADAU1978 }, | ||
59 | { } | ||
60 | }; | ||
61 | MODULE_DEVICE_TABLE(spi, adau1977_spi_ids); | ||
62 | |||
63 | static struct spi_driver adau1977_spi_driver = { | ||
64 | .driver = { | ||
65 | .name = "adau1977", | ||
66 | .owner = THIS_MODULE, | ||
67 | }, | ||
68 | .probe = adau1977_spi_probe, | ||
69 | .remove = adau1977_spi_remove, | ||
70 | .id_table = adau1977_spi_ids, | ||
71 | }; | ||
72 | module_spi_driver(adau1977_spi_driver); | ||
73 | |||
74 | MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); | ||
75 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
76 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1977.c b/sound/soc/codecs/adau1977.c new file mode 100644 index 000000000000..fd55da7cb9d4 --- /dev/null +++ b/sound/soc/codecs/adau1977.c | |||
@@ -0,0 +1,1018 @@ | |||
1 | /* | ||
2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #include <linux/delay.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/gpio/consumer.h> | ||
13 | #include <linux/i2c.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_data/adau1977.h> | ||
17 | #include <linux/regmap.h> | ||
18 | #include <linux/regulator/consumer.h> | ||
19 | #include <linux/slab.h> | ||
20 | |||
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 | |||
28 | #include "adau1977.h" | ||
29 | |||
30 | #define ADAU1977_REG_POWER 0x00 | ||
31 | #define ADAU1977_REG_PLL 0x01 | ||
32 | #define ADAU1977_REG_BOOST 0x02 | ||
33 | #define ADAU1977_REG_MICBIAS 0x03 | ||
34 | #define ADAU1977_REG_BLOCK_POWER_SAI 0x04 | ||
35 | #define ADAU1977_REG_SAI_CTRL0 0x05 | ||
36 | #define ADAU1977_REG_SAI_CTRL1 0x06 | ||
37 | #define ADAU1977_REG_CMAP12 0x07 | ||
38 | #define ADAU1977_REG_CMAP34 0x08 | ||
39 | #define ADAU1977_REG_SAI_OVERTEMP 0x09 | ||
40 | #define ADAU1977_REG_POST_ADC_GAIN(x) (0x0a + (x)) | ||
41 | #define ADAU1977_REG_MISC_CONTROL 0x0e | ||
42 | #define ADAU1977_REG_DIAG_CONTROL 0x10 | ||
43 | #define ADAU1977_REG_STATUS(x) (0x11 + (x)) | ||
44 | #define ADAU1977_REG_DIAG_IRQ1 0x15 | ||
45 | #define ADAU1977_REG_DIAG_IRQ2 0x16 | ||
46 | #define ADAU1977_REG_ADJUST1 0x17 | ||
47 | #define ADAU1977_REG_ADJUST2 0x18 | ||
48 | #define ADAU1977_REG_ADC_CLIP 0x19 | ||
49 | #define ADAU1977_REG_DC_HPF_CAL 0x1a | ||
50 | |||
51 | #define ADAU1977_POWER_RESET BIT(7) | ||
52 | #define ADAU1977_POWER_PWUP BIT(0) | ||
53 | |||
54 | #define ADAU1977_PLL_CLK_S BIT(4) | ||
55 | #define ADAU1977_PLL_MCS_MASK 0x7 | ||
56 | |||
57 | #define ADAU1977_MICBIAS_MB_VOLTS_MASK 0xf0 | ||
58 | #define ADAU1977_MICBIAS_MB_VOLTS_OFFSET 4 | ||
59 | |||
60 | #define ADAU1977_BLOCK_POWER_SAI_LR_POL BIT(7) | ||
61 | #define ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE BIT(6) | ||
62 | #define ADAU1977_BLOCK_POWER_SAI_LDO_EN BIT(5) | ||
63 | |||
64 | #define ADAU1977_SAI_CTRL0_FMT_MASK (0x3 << 6) | ||
65 | #define ADAU1977_SAI_CTRL0_FMT_I2S (0x0 << 6) | ||
66 | #define ADAU1977_SAI_CTRL0_FMT_LJ (0x1 << 6) | ||
67 | #define ADAU1977_SAI_CTRL0_FMT_RJ_24BIT (0x2 << 6) | ||
68 | #define ADAU1977_SAI_CTRL0_FMT_RJ_16BIT (0x3 << 6) | ||
69 | |||
70 | #define ADAU1977_SAI_CTRL0_SAI_MASK (0x7 << 3) | ||
71 | #define ADAU1977_SAI_CTRL0_SAI_I2S (0x0 << 3) | ||
72 | #define ADAU1977_SAI_CTRL0_SAI_TDM_2 (0x1 << 3) | ||
73 | #define ADAU1977_SAI_CTRL0_SAI_TDM_4 (0x2 << 3) | ||
74 | #define ADAU1977_SAI_CTRL0_SAI_TDM_8 (0x3 << 3) | ||
75 | #define ADAU1977_SAI_CTRL0_SAI_TDM_16 (0x4 << 3) | ||
76 | |||
77 | #define ADAU1977_SAI_CTRL0_FS_MASK (0x7) | ||
78 | #define ADAU1977_SAI_CTRL0_FS_8000_12000 (0x0) | ||
79 | #define ADAU1977_SAI_CTRL0_FS_16000_24000 (0x1) | ||
80 | #define ADAU1977_SAI_CTRL0_FS_32000_48000 (0x2) | ||
81 | #define ADAU1977_SAI_CTRL0_FS_64000_96000 (0x3) | ||
82 | #define ADAU1977_SAI_CTRL0_FS_128000_192000 (0x4) | ||
83 | |||
84 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK (0x3 << 5) | ||
85 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_32 (0x0 << 5) | ||
86 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_24 (0x1 << 5) | ||
87 | #define ADAU1977_SAI_CTRL1_SLOT_WIDTH_16 (0x2 << 5) | ||
88 | #define ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK (0x1 << 4) | ||
89 | #define ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT (0x1 << 4) | ||
90 | #define ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT (0x0 << 4) | ||
91 | #define ADAU1977_SAI_CTRL1_LRCLK_PULSE BIT(3) | ||
92 | #define ADAU1977_SAI_CTRL1_MSB BIT(2) | ||
93 | #define ADAU1977_SAI_CTRL1_BCLKRATE_16 (0x1 << 1) | ||
94 | #define ADAU1977_SAI_CTRL1_BCLKRATE_32 (0x0 << 1) | ||
95 | #define ADAU1977_SAI_CTRL1_BCLKRATE_MASK (0x1 << 1) | ||
96 | #define ADAU1977_SAI_CTRL1_MASTER BIT(0) | ||
97 | |||
98 | #define ADAU1977_SAI_OVERTEMP_DRV_C(x) BIT(4 + (x)) | ||
99 | #define ADAU1977_SAI_OVERTEMP_DRV_HIZ BIT(3) | ||
100 | |||
101 | #define ADAU1977_MISC_CONTROL_SUM_MODE_MASK (0x3 << 6) | ||
102 | #define ADAU1977_MISC_CONTROL_SUM_MODE_1CH (0x2 << 6) | ||
103 | #define ADAU1977_MISC_CONTROL_SUM_MODE_2CH (0x1 << 6) | ||
104 | #define ADAU1977_MISC_CONTROL_SUM_MODE_4CH (0x0 << 6) | ||
105 | #define ADAU1977_MISC_CONTROL_MMUTE BIT(4) | ||
106 | #define ADAU1977_MISC_CONTROL_DC_CAL BIT(0) | ||
107 | |||
108 | #define ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET 4 | ||
109 | #define ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET 0 | ||
110 | |||
111 | struct adau1977 { | ||
112 | struct regmap *regmap; | ||
113 | bool right_j; | ||
114 | unsigned int sysclk; | ||
115 | enum adau1977_sysclk_src sysclk_src; | ||
116 | struct gpio_desc *reset_gpio; | ||
117 | enum adau1977_type type; | ||
118 | |||
119 | struct regulator *avdd_reg; | ||
120 | struct regulator *dvdd_reg; | ||
121 | |||
122 | struct snd_pcm_hw_constraint_list constraints; | ||
123 | |||
124 | struct device *dev; | ||
125 | void (*switch_mode)(struct device *dev); | ||
126 | |||
127 | unsigned int max_master_fs; | ||
128 | unsigned int slot_width; | ||
129 | bool enabled; | ||
130 | bool master; | ||
131 | }; | ||
132 | |||
133 | static const struct reg_default adau1977_reg_defaults[] = { | ||
134 | { 0x00, 0x00 }, | ||
135 | { 0x01, 0x41 }, | ||
136 | { 0x02, 0x4a }, | ||
137 | { 0x03, 0x7d }, | ||
138 | { 0x04, 0x3d }, | ||
139 | { 0x05, 0x02 }, | ||
140 | { 0x06, 0x00 }, | ||
141 | { 0x07, 0x10 }, | ||
142 | { 0x08, 0x32 }, | ||
143 | { 0x09, 0xf0 }, | ||
144 | { 0x0a, 0xa0 }, | ||
145 | { 0x0b, 0xa0 }, | ||
146 | { 0x0c, 0xa0 }, | ||
147 | { 0x0d, 0xa0 }, | ||
148 | { 0x0e, 0x02 }, | ||
149 | { 0x10, 0x0f }, | ||
150 | { 0x15, 0x20 }, | ||
151 | { 0x16, 0x00 }, | ||
152 | { 0x17, 0x00 }, | ||
153 | { 0x18, 0x00 }, | ||
154 | { 0x1a, 0x00 }, | ||
155 | }; | ||
156 | |||
157 | static const DECLARE_TLV_DB_MINMAX_MUTE(adau1977_adc_gain, -3562, 6000); | ||
158 | |||
159 | static const struct snd_soc_dapm_widget adau1977_micbias_dapm_widgets[] = { | ||
160 | SND_SOC_DAPM_SUPPLY("MICBIAS", ADAU1977_REG_MICBIAS, | ||
161 | 3, 0, NULL, 0) | ||
162 | }; | ||
163 | |||
164 | static const struct snd_soc_dapm_widget adau1977_dapm_widgets[] = { | ||
165 | SND_SOC_DAPM_SUPPLY("Vref", ADAU1977_REG_BLOCK_POWER_SAI, | ||
166 | 4, 0, NULL, 0), | ||
167 | |||
168 | SND_SOC_DAPM_ADC("ADC1", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 0, 0), | ||
169 | SND_SOC_DAPM_ADC("ADC2", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 1, 0), | ||
170 | SND_SOC_DAPM_ADC("ADC3", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 2, 0), | ||
171 | SND_SOC_DAPM_ADC("ADC4", "Capture", ADAU1977_REG_BLOCK_POWER_SAI, 3, 0), | ||
172 | |||
173 | SND_SOC_DAPM_INPUT("AIN1"), | ||
174 | SND_SOC_DAPM_INPUT("AIN2"), | ||
175 | SND_SOC_DAPM_INPUT("AIN3"), | ||
176 | SND_SOC_DAPM_INPUT("AIN4"), | ||
177 | |||
178 | SND_SOC_DAPM_OUTPUT("VREF"), | ||
179 | }; | ||
180 | |||
181 | static const struct snd_soc_dapm_route adau1977_dapm_routes[] = { | ||
182 | { "ADC1", NULL, "AIN1" }, | ||
183 | { "ADC2", NULL, "AIN2" }, | ||
184 | { "ADC3", NULL, "AIN3" }, | ||
185 | { "ADC4", NULL, "AIN4" }, | ||
186 | |||
187 | { "ADC1", NULL, "Vref" }, | ||
188 | { "ADC2", NULL, "Vref" }, | ||
189 | { "ADC3", NULL, "Vref" }, | ||
190 | { "ADC4", NULL, "Vref" }, | ||
191 | |||
192 | { "VREF", NULL, "Vref" }, | ||
193 | }; | ||
194 | |||
195 | #define ADAU1977_VOLUME(x) \ | ||
196 | SOC_SINGLE_TLV("ADC" #x " Capture Volume", \ | ||
197 | ADAU1977_REG_POST_ADC_GAIN((x) - 1), \ | ||
198 | 0, 255, 1, adau1977_adc_gain) | ||
199 | |||
200 | #define ADAU1977_HPF_SWITCH(x) \ | ||
201 | SOC_SINGLE("ADC" #x " Highpass-Filter Capture Switch", \ | ||
202 | ADAU1977_REG_DC_HPF_CAL, (x) - 1, 1, 0) | ||
203 | |||
204 | #define ADAU1977_DC_SUB_SWITCH(x) \ | ||
205 | SOC_SINGLE("ADC" #x " DC Substraction Capture Switch", \ | ||
206 | ADAU1977_REG_DC_HPF_CAL, (x) + 3, 1, 0) | ||
207 | |||
208 | static const struct snd_kcontrol_new adau1977_snd_controls[] = { | ||
209 | ADAU1977_VOLUME(1), | ||
210 | ADAU1977_VOLUME(2), | ||
211 | ADAU1977_VOLUME(3), | ||
212 | ADAU1977_VOLUME(4), | ||
213 | |||
214 | ADAU1977_HPF_SWITCH(1), | ||
215 | ADAU1977_HPF_SWITCH(2), | ||
216 | ADAU1977_HPF_SWITCH(3), | ||
217 | ADAU1977_HPF_SWITCH(4), | ||
218 | |||
219 | ADAU1977_DC_SUB_SWITCH(1), | ||
220 | ADAU1977_DC_SUB_SWITCH(2), | ||
221 | ADAU1977_DC_SUB_SWITCH(3), | ||
222 | ADAU1977_DC_SUB_SWITCH(4), | ||
223 | }; | ||
224 | |||
225 | static int adau1977_reset(struct adau1977 *adau1977) | ||
226 | { | ||
227 | int ret; | ||
228 | |||
229 | /* | ||
230 | * The reset bit is obviously volatile, but we need to be able to cache | ||
231 | * the other bits in the register, so we can't just mark the whole | ||
232 | * register as volatile. Since this is the only place where we'll ever | ||
233 | * touch the reset bit just bypass the cache for this operation. | ||
234 | */ | ||
235 | regcache_cache_bypass(adau1977->regmap, true); | ||
236 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_POWER, | ||
237 | ADAU1977_POWER_RESET); | ||
238 | regcache_cache_bypass(adau1977->regmap, false); | ||
239 | if (ret) | ||
240 | return ret; | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * Returns the appropriate setting for ths FS field in the CTRL0 register | ||
247 | * depending on the rate. | ||
248 | */ | ||
249 | static int adau1977_lookup_fs(unsigned int rate) | ||
250 | { | ||
251 | if (rate >= 8000 && rate <= 12000) | ||
252 | return ADAU1977_SAI_CTRL0_FS_8000_12000; | ||
253 | else if (rate >= 16000 && rate <= 24000) | ||
254 | return ADAU1977_SAI_CTRL0_FS_16000_24000; | ||
255 | else if (rate >= 32000 && rate <= 48000) | ||
256 | return ADAU1977_SAI_CTRL0_FS_32000_48000; | ||
257 | else if (rate >= 64000 && rate <= 96000) | ||
258 | return ADAU1977_SAI_CTRL0_FS_64000_96000; | ||
259 | else if (rate >= 128000 && rate <= 192000) | ||
260 | return ADAU1977_SAI_CTRL0_FS_128000_192000; | ||
261 | else | ||
262 | return -EINVAL; | ||
263 | } | ||
264 | |||
265 | static int adau1977_lookup_mcs(struct adau1977 *adau1977, unsigned int rate, | ||
266 | unsigned int fs) | ||
267 | { | ||
268 | unsigned int mcs; | ||
269 | |||
270 | /* | ||
271 | * rate = sysclk / (512 * mcs_lut[mcs]) * 2**fs | ||
272 | * => mcs_lut[mcs] = sysclk / (512 * rate) * 2**fs | ||
273 | * => mcs_lut[mcs] = sysclk / ((512 / 2**fs) * rate) | ||
274 | */ | ||
275 | |||
276 | rate *= 512 >> fs; | ||
277 | |||
278 | if (adau1977->sysclk % rate != 0) | ||
279 | return -EINVAL; | ||
280 | |||
281 | mcs = adau1977->sysclk / rate; | ||
282 | |||
283 | /* The factors configured by MCS are 1, 2, 3, 4, 6 */ | ||
284 | if (mcs < 1 || mcs > 6 || mcs == 5) | ||
285 | return -EINVAL; | ||
286 | |||
287 | mcs = mcs - 1; | ||
288 | if (mcs == 5) | ||
289 | mcs = 4; | ||
290 | |||
291 | return mcs; | ||
292 | } | ||
293 | |||
294 | static int adau1977_hw_params(struct snd_pcm_substream *substream, | ||
295 | struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) | ||
296 | { | ||
297 | struct snd_soc_codec *codec = dai->codec; | ||
298 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
299 | unsigned int rate = params_rate(params); | ||
300 | unsigned int slot_width; | ||
301 | unsigned int ctrl0, ctrl0_mask; | ||
302 | unsigned int ctrl1; | ||
303 | int mcs, fs; | ||
304 | int ret; | ||
305 | |||
306 | fs = adau1977_lookup_fs(rate); | ||
307 | if (fs < 0) | ||
308 | return fs; | ||
309 | |||
310 | if (adau1977->sysclk_src == ADAU1977_SYSCLK_SRC_MCLK) { | ||
311 | mcs = adau1977_lookup_mcs(adau1977, rate, fs); | ||
312 | if (mcs < 0) | ||
313 | return mcs; | ||
314 | } else { | ||
315 | mcs = 0; | ||
316 | } | ||
317 | |||
318 | ctrl0_mask = ADAU1977_SAI_CTRL0_FS_MASK; | ||
319 | ctrl0 = fs; | ||
320 | |||
321 | if (adau1977->right_j) { | ||
322 | switch (params_width(params)) { | ||
323 | case 16: | ||
324 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_16BIT; | ||
325 | break; | ||
326 | case 24: | ||
327 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; | ||
328 | break; | ||
329 | default: | ||
330 | return -EINVAL; | ||
331 | } | ||
332 | ctrl0_mask |= ADAU1977_SAI_CTRL0_FMT_MASK; | ||
333 | } | ||
334 | |||
335 | if (adau1977->master) { | ||
336 | switch (params_width(params)) { | ||
337 | case 16: | ||
338 | ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_16BIT; | ||
339 | slot_width = 16; | ||
340 | break; | ||
341 | case 24: | ||
342 | case 32: | ||
343 | ctrl1 = ADAU1977_SAI_CTRL1_DATA_WIDTH_24BIT; | ||
344 | slot_width = 32; | ||
345 | break; | ||
346 | default: | ||
347 | return -EINVAL; | ||
348 | } | ||
349 | |||
350 | /* In TDM mode there is a fixed slot width */ | ||
351 | if (adau1977->slot_width) | ||
352 | slot_width = adau1977->slot_width; | ||
353 | |||
354 | if (slot_width == 16) | ||
355 | ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_16; | ||
356 | else | ||
357 | ctrl1 |= ADAU1977_SAI_CTRL1_BCLKRATE_32; | ||
358 | |||
359 | ret = regmap_update_bits(adau1977->regmap, | ||
360 | ADAU1977_REG_SAI_CTRL1, | ||
361 | ADAU1977_SAI_CTRL1_DATA_WIDTH_MASK | | ||
362 | ADAU1977_SAI_CTRL1_BCLKRATE_MASK, | ||
363 | ctrl1); | ||
364 | if (ret < 0) | ||
365 | return ret; | ||
366 | } | ||
367 | |||
368 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, | ||
369 | ctrl0_mask, ctrl0); | ||
370 | if (ret < 0) | ||
371 | return ret; | ||
372 | |||
373 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, | ||
374 | ADAU1977_PLL_MCS_MASK, mcs); | ||
375 | } | ||
376 | |||
377 | static int adau1977_power_disable(struct adau1977 *adau1977) | ||
378 | { | ||
379 | int ret = 0; | ||
380 | |||
381 | if (!adau1977->enabled) | ||
382 | return 0; | ||
383 | |||
384 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, | ||
385 | ADAU1977_POWER_PWUP, 0); | ||
386 | if (ret) | ||
387 | return ret; | ||
388 | |||
389 | regcache_mark_dirty(adau1977->regmap); | ||
390 | |||
391 | if (adau1977->reset_gpio) | ||
392 | gpiod_set_value_cansleep(adau1977->reset_gpio, 0); | ||
393 | |||
394 | regcache_cache_only(adau1977->regmap, true); | ||
395 | |||
396 | regulator_disable(adau1977->avdd_reg); | ||
397 | if (adau1977->dvdd_reg) | ||
398 | regulator_disable(adau1977->dvdd_reg); | ||
399 | |||
400 | adau1977->enabled = false; | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static int adau1977_power_enable(struct adau1977 *adau1977) | ||
406 | { | ||
407 | unsigned int val; | ||
408 | int ret = 0; | ||
409 | |||
410 | if (adau1977->enabled) | ||
411 | return 0; | ||
412 | |||
413 | ret = regulator_enable(adau1977->avdd_reg); | ||
414 | if (ret) | ||
415 | return ret; | ||
416 | |||
417 | if (adau1977->dvdd_reg) { | ||
418 | ret = regulator_enable(adau1977->dvdd_reg); | ||
419 | if (ret) | ||
420 | goto err_disable_avdd; | ||
421 | } | ||
422 | |||
423 | if (adau1977->reset_gpio) | ||
424 | gpiod_set_value_cansleep(adau1977->reset_gpio, 1); | ||
425 | |||
426 | regcache_cache_only(adau1977->regmap, false); | ||
427 | |||
428 | if (adau1977->switch_mode) | ||
429 | adau1977->switch_mode(adau1977->dev); | ||
430 | |||
431 | ret = adau1977_reset(adau1977); | ||
432 | if (ret) | ||
433 | goto err_disable_dvdd; | ||
434 | |||
435 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_POWER, | ||
436 | ADAU1977_POWER_PWUP, ADAU1977_POWER_PWUP); | ||
437 | if (ret) | ||
438 | goto err_disable_dvdd; | ||
439 | |||
440 | ret = regcache_sync(adau1977->regmap); | ||
441 | if (ret) | ||
442 | goto err_disable_dvdd; | ||
443 | |||
444 | /* | ||
445 | * The PLL register is not affected by the software reset. It is | ||
446 | * possible that the value of the register was changed to the | ||
447 | * default value while we were in cache only mode. In this case | ||
448 | * regcache_sync will skip over it and we have to manually sync | ||
449 | * it. | ||
450 | */ | ||
451 | ret = regmap_read(adau1977->regmap, ADAU1977_REG_PLL, &val); | ||
452 | if (ret) | ||
453 | goto err_disable_dvdd; | ||
454 | |||
455 | if (val == 0x41) { | ||
456 | regcache_cache_bypass(adau1977->regmap, true); | ||
457 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_PLL, | ||
458 | 0x41); | ||
459 | if (ret) | ||
460 | goto err_disable_dvdd; | ||
461 | regcache_cache_bypass(adau1977->regmap, false); | ||
462 | } | ||
463 | |||
464 | adau1977->enabled = true; | ||
465 | |||
466 | return ret; | ||
467 | |||
468 | err_disable_dvdd: | ||
469 | if (adau1977->dvdd_reg) | ||
470 | regulator_disable(adau1977->dvdd_reg); | ||
471 | err_disable_avdd: | ||
472 | regulator_disable(adau1977->avdd_reg); | ||
473 | return ret; | ||
474 | } | ||
475 | |||
476 | static int adau1977_set_bias_level(struct snd_soc_codec *codec, | ||
477 | enum snd_soc_bias_level level) | ||
478 | { | ||
479 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
480 | int ret = 0; | ||
481 | |||
482 | switch (level) { | ||
483 | case SND_SOC_BIAS_ON: | ||
484 | break; | ||
485 | case SND_SOC_BIAS_PREPARE: | ||
486 | break; | ||
487 | case SND_SOC_BIAS_STANDBY: | ||
488 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) | ||
489 | ret = adau1977_power_enable(adau1977); | ||
490 | break; | ||
491 | case SND_SOC_BIAS_OFF: | ||
492 | ret = adau1977_power_disable(adau1977); | ||
493 | break; | ||
494 | } | ||
495 | |||
496 | if (ret) | ||
497 | return ret; | ||
498 | |||
499 | codec->dapm.bias_level = level; | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | static int adau1977_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, | ||
505 | unsigned int rx_mask, int slots, int width) | ||
506 | { | ||
507 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
508 | unsigned int ctrl0, ctrl1, drv; | ||
509 | unsigned int slot[4]; | ||
510 | unsigned int i; | ||
511 | int ret; | ||
512 | |||
513 | if (slots == 0) { | ||
514 | /* 0 = No fixed slot width */ | ||
515 | adau1977->slot_width = 0; | ||
516 | adau1977->max_master_fs = 192000; | ||
517 | return regmap_update_bits(adau1977->regmap, | ||
518 | ADAU1977_REG_SAI_CTRL0, ADAU1977_SAI_CTRL0_SAI_MASK, | ||
519 | ADAU1977_SAI_CTRL0_SAI_I2S); | ||
520 | } | ||
521 | |||
522 | if (rx_mask == 0 || tx_mask != 0) | ||
523 | return -EINVAL; | ||
524 | |||
525 | drv = 0; | ||
526 | for (i = 0; i < 4; i++) { | ||
527 | slot[i] = __ffs(rx_mask); | ||
528 | drv |= ADAU1977_SAI_OVERTEMP_DRV_C(i); | ||
529 | rx_mask &= ~(1 << slot[i]); | ||
530 | if (slot[i] >= slots) | ||
531 | return -EINVAL; | ||
532 | if (rx_mask == 0) | ||
533 | break; | ||
534 | } | ||
535 | |||
536 | if (rx_mask != 0) | ||
537 | return -EINVAL; | ||
538 | |||
539 | switch (width) { | ||
540 | case 16: | ||
541 | ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_16; | ||
542 | break; | ||
543 | case 24: | ||
544 | /* We can only generate 16 bit or 32 bit wide slots */ | ||
545 | if (adau1977->master) | ||
546 | return -EINVAL; | ||
547 | ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_24; | ||
548 | break; | ||
549 | case 32: | ||
550 | ctrl1 = ADAU1977_SAI_CTRL1_SLOT_WIDTH_32; | ||
551 | break; | ||
552 | default: | ||
553 | return -EINVAL; | ||
554 | } | ||
555 | |||
556 | switch (slots) { | ||
557 | case 2: | ||
558 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_2; | ||
559 | break; | ||
560 | case 4: | ||
561 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_4; | ||
562 | break; | ||
563 | case 8: | ||
564 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_8; | ||
565 | break; | ||
566 | case 16: | ||
567 | ctrl0 = ADAU1977_SAI_CTRL0_SAI_TDM_16; | ||
568 | break; | ||
569 | default: | ||
570 | return -EINVAL; | ||
571 | } | ||
572 | |||
573 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, | ||
574 | ADAU1977_SAI_OVERTEMP_DRV_C(0) | | ||
575 | ADAU1977_SAI_OVERTEMP_DRV_C(1) | | ||
576 | ADAU1977_SAI_OVERTEMP_DRV_C(2) | | ||
577 | ADAU1977_SAI_OVERTEMP_DRV_C(3), drv); | ||
578 | if (ret) | ||
579 | return ret; | ||
580 | |||
581 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP12, | ||
582 | (slot[1] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | | ||
583 | (slot[0] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); | ||
584 | if (ret) | ||
585 | return ret; | ||
586 | |||
587 | ret = regmap_write(adau1977->regmap, ADAU1977_REG_CMAP34, | ||
588 | (slot[3] << ADAU1977_CHAN_MAP_SECOND_SLOT_OFFSET) | | ||
589 | (slot[2] << ADAU1977_CHAN_MAP_FIRST_SLOT_OFFSET)); | ||
590 | if (ret) | ||
591 | return ret; | ||
592 | |||
593 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, | ||
594 | ADAU1977_SAI_CTRL0_SAI_MASK, ctrl0); | ||
595 | if (ret) | ||
596 | return ret; | ||
597 | |||
598 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, | ||
599 | ADAU1977_SAI_CTRL1_SLOT_WIDTH_MASK, ctrl1); | ||
600 | if (ret) | ||
601 | return ret; | ||
602 | |||
603 | adau1977->slot_width = width; | ||
604 | |||
605 | /* In master mode the maximum bitclock is 24.576 MHz */ | ||
606 | adau1977->max_master_fs = min(192000, 24576000 / width / slots); | ||
607 | |||
608 | return 0; | ||
609 | } | ||
610 | |||
611 | static int adau1977_mute(struct snd_soc_dai *dai, int mute, int stream) | ||
612 | { | ||
613 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
614 | unsigned int val; | ||
615 | |||
616 | if (mute) | ||
617 | val = ADAU1977_MISC_CONTROL_MMUTE; | ||
618 | else | ||
619 | val = 0; | ||
620 | |||
621 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MISC_CONTROL, | ||
622 | ADAU1977_MISC_CONTROL_MMUTE, val); | ||
623 | } | ||
624 | |||
625 | static int adau1977_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
626 | { | ||
627 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
628 | unsigned int ctrl0 = 0, ctrl1 = 0, block_power = 0; | ||
629 | bool invert_lrclk; | ||
630 | int ret; | ||
631 | |||
632 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
633 | case SND_SOC_DAIFMT_CBS_CFS: | ||
634 | adau1977->master = false; | ||
635 | break; | ||
636 | case SND_SOC_DAIFMT_CBM_CFM: | ||
637 | ctrl1 |= ADAU1977_SAI_CTRL1_MASTER; | ||
638 | adau1977->master = true; | ||
639 | break; | ||
640 | default: | ||
641 | return -EINVAL; | ||
642 | } | ||
643 | |||
644 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
645 | case SND_SOC_DAIFMT_NB_NF: | ||
646 | invert_lrclk = false; | ||
647 | break; | ||
648 | case SND_SOC_DAIFMT_IB_NF: | ||
649 | block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; | ||
650 | invert_lrclk = false; | ||
651 | break; | ||
652 | case SND_SOC_DAIFMT_NB_IF: | ||
653 | invert_lrclk = true; | ||
654 | break; | ||
655 | case SND_SOC_DAIFMT_IB_IF: | ||
656 | block_power |= ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE; | ||
657 | invert_lrclk = true; | ||
658 | break; | ||
659 | default: | ||
660 | return -EINVAL; | ||
661 | } | ||
662 | |||
663 | adau1977->right_j = false; | ||
664 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
665 | case SND_SOC_DAIFMT_I2S: | ||
666 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; | ||
667 | break; | ||
668 | case SND_SOC_DAIFMT_LEFT_J: | ||
669 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; | ||
670 | invert_lrclk = !invert_lrclk; | ||
671 | break; | ||
672 | case SND_SOC_DAIFMT_RIGHT_J: | ||
673 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_RJ_24BIT; | ||
674 | adau1977->right_j = true; | ||
675 | invert_lrclk = !invert_lrclk; | ||
676 | break; | ||
677 | case SND_SOC_DAIFMT_DSP_A: | ||
678 | ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; | ||
679 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_I2S; | ||
680 | invert_lrclk = false; | ||
681 | break; | ||
682 | case SND_SOC_DAIFMT_DSP_B: | ||
683 | ctrl1 |= ADAU1977_SAI_CTRL1_LRCLK_PULSE; | ||
684 | ctrl0 |= ADAU1977_SAI_CTRL0_FMT_LJ; | ||
685 | invert_lrclk = false; | ||
686 | break; | ||
687 | default: | ||
688 | return -EINVAL; | ||
689 | } | ||
690 | |||
691 | if (invert_lrclk) | ||
692 | block_power |= ADAU1977_BLOCK_POWER_SAI_LR_POL; | ||
693 | |||
694 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, | ||
695 | ADAU1977_BLOCK_POWER_SAI_LR_POL | | ||
696 | ADAU1977_BLOCK_POWER_SAI_BCLK_EDGE, block_power); | ||
697 | if (ret) | ||
698 | return ret; | ||
699 | |||
700 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL0, | ||
701 | ADAU1977_SAI_CTRL0_FMT_MASK, | ||
702 | ctrl0); | ||
703 | if (ret) | ||
704 | return ret; | ||
705 | |||
706 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_CTRL1, | ||
707 | ADAU1977_SAI_CTRL1_MASTER | ADAU1977_SAI_CTRL1_LRCLK_PULSE, | ||
708 | ctrl1); | ||
709 | } | ||
710 | |||
711 | static int adau1977_startup(struct snd_pcm_substream *substream, | ||
712 | struct snd_soc_dai *dai) | ||
713 | { | ||
714 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
715 | u64 formats = 0; | ||
716 | |||
717 | if (adau1977->slot_width == 16) | ||
718 | formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE; | ||
719 | else if (adau1977->right_j || adau1977->slot_width == 24) | ||
720 | formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | | ||
721 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE; | ||
722 | |||
723 | snd_pcm_hw_constraint_list(substream->runtime, 0, | ||
724 | SNDRV_PCM_HW_PARAM_RATE, &adau1977->constraints); | ||
725 | |||
726 | if (adau1977->master) | ||
727 | snd_pcm_hw_constraint_minmax(substream->runtime, | ||
728 | SNDRV_PCM_HW_PARAM_RATE, 8000, adau1977->max_master_fs); | ||
729 | |||
730 | if (formats != 0) | ||
731 | snd_pcm_hw_constraint_mask64(substream->runtime, | ||
732 | SNDRV_PCM_HW_PARAM_FORMAT, formats); | ||
733 | |||
734 | return 0; | ||
735 | } | ||
736 | |||
737 | static int adau1977_set_tristate(struct snd_soc_dai *dai, int tristate) | ||
738 | { | ||
739 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(dai->codec); | ||
740 | unsigned int val; | ||
741 | |||
742 | if (tristate) | ||
743 | val = ADAU1977_SAI_OVERTEMP_DRV_HIZ; | ||
744 | else | ||
745 | val = 0; | ||
746 | |||
747 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_SAI_OVERTEMP, | ||
748 | ADAU1977_SAI_OVERTEMP_DRV_HIZ, val); | ||
749 | } | ||
750 | |||
751 | static const struct snd_soc_dai_ops adau1977_dai_ops = { | ||
752 | .startup = adau1977_startup, | ||
753 | .hw_params = adau1977_hw_params, | ||
754 | .mute_stream = adau1977_mute, | ||
755 | .set_fmt = adau1977_set_dai_fmt, | ||
756 | .set_tdm_slot = adau1977_set_tdm_slot, | ||
757 | .set_tristate = adau1977_set_tristate, | ||
758 | }; | ||
759 | |||
760 | static struct snd_soc_dai_driver adau1977_dai = { | ||
761 | .name = "adau1977-hifi", | ||
762 | .capture = { | ||
763 | .stream_name = "Capture", | ||
764 | .channels_min = 1, | ||
765 | .channels_max = 4, | ||
766 | .rates = SNDRV_PCM_RATE_KNOT, | ||
767 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | | ||
768 | SNDRV_PCM_FMTBIT_S32_LE, | ||
769 | .sig_bits = 24, | ||
770 | }, | ||
771 | .ops = &adau1977_dai_ops, | ||
772 | }; | ||
773 | |||
774 | static const unsigned int adau1977_rates[] = { | ||
775 | 8000, 16000, 32000, 64000, 128000, | ||
776 | 11025, 22050, 44100, 88200, 172400, | ||
777 | 12000, 24000, 48000, 96000, 192000, | ||
778 | }; | ||
779 | |||
780 | #define ADAU1977_RATE_CONSTRAINT_MASK_32000 0x001f | ||
781 | #define ADAU1977_RATE_CONSTRAINT_MASK_44100 0x03e0 | ||
782 | #define ADAU1977_RATE_CONSTRAINT_MASK_48000 0x7c00 | ||
783 | /* All rates >= 32000 */ | ||
784 | #define ADAU1977_RATE_CONSTRAINT_MASK_LRCLK 0x739c | ||
785 | |||
786 | static bool adau1977_check_sysclk(unsigned int mclk, unsigned int base_freq) | ||
787 | { | ||
788 | unsigned int mcs; | ||
789 | |||
790 | if (mclk % (base_freq * 128) != 0) | ||
791 | return false; | ||
792 | |||
793 | mcs = mclk / (128 * base_freq); | ||
794 | if (mcs < 1 || mcs > 6 || mcs == 5) | ||
795 | return false; | ||
796 | |||
797 | return true; | ||
798 | } | ||
799 | |||
800 | static int adau1977_set_sysclk(struct snd_soc_codec *codec, | ||
801 | int clk_id, int source, unsigned int freq, int dir) | ||
802 | { | ||
803 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
804 | unsigned int mask = 0; | ||
805 | unsigned int clk_src; | ||
806 | unsigned int ret; | ||
807 | |||
808 | if (dir != SND_SOC_CLOCK_IN) | ||
809 | return -EINVAL; | ||
810 | |||
811 | if (clk_id != ADAU1977_SYSCLK) | ||
812 | return -EINVAL; | ||
813 | |||
814 | switch (source) { | ||
815 | case ADAU1977_SYSCLK_SRC_MCLK: | ||
816 | clk_src = 0; | ||
817 | break; | ||
818 | case ADAU1977_SYSCLK_SRC_LRCLK: | ||
819 | clk_src = ADAU1977_PLL_CLK_S; | ||
820 | break; | ||
821 | default: | ||
822 | return -EINVAL; | ||
823 | } | ||
824 | |||
825 | if (freq != 0 && source == ADAU1977_SYSCLK_SRC_MCLK) { | ||
826 | if (freq < 4000000 || freq > 36864000) | ||
827 | return -EINVAL; | ||
828 | |||
829 | if (adau1977_check_sysclk(freq, 32000)) | ||
830 | mask |= ADAU1977_RATE_CONSTRAINT_MASK_32000; | ||
831 | if (adau1977_check_sysclk(freq, 44100)) | ||
832 | mask |= ADAU1977_RATE_CONSTRAINT_MASK_44100; | ||
833 | if (adau1977_check_sysclk(freq, 48000)) | ||
834 | mask |= ADAU1977_RATE_CONSTRAINT_MASK_48000; | ||
835 | |||
836 | if (mask == 0) | ||
837 | return -EINVAL; | ||
838 | } else if (source == ADAU1977_SYSCLK_SRC_LRCLK) { | ||
839 | mask = ADAU1977_RATE_CONSTRAINT_MASK_LRCLK; | ||
840 | } | ||
841 | |||
842 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_PLL, | ||
843 | ADAU1977_PLL_CLK_S, clk_src); | ||
844 | if (ret) | ||
845 | return ret; | ||
846 | |||
847 | adau1977->constraints.mask = mask; | ||
848 | adau1977->sysclk_src = source; | ||
849 | adau1977->sysclk = freq; | ||
850 | |||
851 | return 0; | ||
852 | } | ||
853 | |||
854 | static int adau1977_codec_probe(struct snd_soc_codec *codec) | ||
855 | { | ||
856 | struct adau1977 *adau1977 = snd_soc_codec_get_drvdata(codec); | ||
857 | int ret; | ||
858 | |||
859 | switch (adau1977->type) { | ||
860 | case ADAU1977: | ||
861 | ret = snd_soc_dapm_new_controls(&codec->dapm, | ||
862 | adau1977_micbias_dapm_widgets, | ||
863 | ARRAY_SIZE(adau1977_micbias_dapm_widgets)); | ||
864 | if (ret < 0) | ||
865 | return ret; | ||
866 | break; | ||
867 | default: | ||
868 | break; | ||
869 | } | ||
870 | |||
871 | return 0; | ||
872 | } | ||
873 | |||
874 | static struct snd_soc_codec_driver adau1977_codec_driver = { | ||
875 | .probe = adau1977_codec_probe, | ||
876 | .set_bias_level = adau1977_set_bias_level, | ||
877 | .set_sysclk = adau1977_set_sysclk, | ||
878 | .idle_bias_off = true, | ||
879 | |||
880 | .controls = adau1977_snd_controls, | ||
881 | .num_controls = ARRAY_SIZE(adau1977_snd_controls), | ||
882 | .dapm_widgets = adau1977_dapm_widgets, | ||
883 | .num_dapm_widgets = ARRAY_SIZE(adau1977_dapm_widgets), | ||
884 | .dapm_routes = adau1977_dapm_routes, | ||
885 | .num_dapm_routes = ARRAY_SIZE(adau1977_dapm_routes), | ||
886 | }; | ||
887 | |||
888 | static int adau1977_setup_micbias(struct adau1977 *adau1977) | ||
889 | { | ||
890 | struct adau1977_platform_data *pdata = adau1977->dev->platform_data; | ||
891 | unsigned int micbias; | ||
892 | |||
893 | if (pdata) { | ||
894 | micbias = pdata->micbias; | ||
895 | if (micbias > ADAU1977_MICBIAS_9V0) | ||
896 | return -EINVAL; | ||
897 | |||
898 | } else { | ||
899 | micbias = ADAU1977_MICBIAS_8V5; | ||
900 | } | ||
901 | |||
902 | return regmap_update_bits(adau1977->regmap, ADAU1977_REG_MICBIAS, | ||
903 | ADAU1977_MICBIAS_MB_VOLTS_MASK, | ||
904 | micbias << ADAU1977_MICBIAS_MB_VOLTS_OFFSET); | ||
905 | } | ||
906 | |||
907 | int adau1977_probe(struct device *dev, struct regmap *regmap, | ||
908 | enum adau1977_type type, void (*switch_mode)(struct device *dev)) | ||
909 | { | ||
910 | unsigned int power_off_mask; | ||
911 | struct adau1977 *adau1977; | ||
912 | int ret; | ||
913 | |||
914 | if (IS_ERR(regmap)) | ||
915 | return PTR_ERR(regmap); | ||
916 | |||
917 | adau1977 = devm_kzalloc(dev, sizeof(*adau1977), GFP_KERNEL); | ||
918 | if (adau1977 == NULL) | ||
919 | return -ENOMEM; | ||
920 | |||
921 | adau1977->dev = dev; | ||
922 | adau1977->type = type; | ||
923 | adau1977->regmap = regmap; | ||
924 | adau1977->switch_mode = switch_mode; | ||
925 | adau1977->max_master_fs = 192000; | ||
926 | |||
927 | adau1977->constraints.list = adau1977_rates; | ||
928 | adau1977->constraints.count = ARRAY_SIZE(adau1977_rates); | ||
929 | |||
930 | adau1977->avdd_reg = devm_regulator_get(dev, "AVDD"); | ||
931 | if (IS_ERR(adau1977->avdd_reg)) | ||
932 | return PTR_ERR(adau1977->avdd_reg); | ||
933 | |||
934 | adau1977->dvdd_reg = devm_regulator_get_optional(dev, "DVDD"); | ||
935 | if (IS_ERR(adau1977->dvdd_reg)) { | ||
936 | if (PTR_ERR(adau1977->dvdd_reg) != -ENODEV) | ||
937 | return PTR_ERR(adau1977->dvdd_reg); | ||
938 | adau1977->dvdd_reg = NULL; | ||
939 | } | ||
940 | |||
941 | adau1977->reset_gpio = devm_gpiod_get(dev, "reset"); | ||
942 | if (IS_ERR(adau1977->reset_gpio)) { | ||
943 | ret = PTR_ERR(adau1977->reset_gpio); | ||
944 | if (ret != -ENOENT && ret != -ENOSYS) | ||
945 | return PTR_ERR(adau1977->reset_gpio); | ||
946 | adau1977->reset_gpio = NULL; | ||
947 | } | ||
948 | |||
949 | dev_set_drvdata(dev, adau1977); | ||
950 | |||
951 | if (adau1977->reset_gpio) { | ||
952 | ret = gpiod_direction_output(adau1977->reset_gpio, 0); | ||
953 | if (ret) | ||
954 | return ret; | ||
955 | ndelay(100); | ||
956 | } | ||
957 | |||
958 | ret = adau1977_power_enable(adau1977); | ||
959 | if (ret) | ||
960 | return ret; | ||
961 | |||
962 | if (type == ADAU1977) { | ||
963 | ret = adau1977_setup_micbias(adau1977); | ||
964 | if (ret) | ||
965 | goto err_poweroff; | ||
966 | } | ||
967 | |||
968 | if (adau1977->dvdd_reg) | ||
969 | power_off_mask = ~0; | ||
970 | else | ||
971 | power_off_mask = ~ADAU1977_BLOCK_POWER_SAI_LDO_EN; | ||
972 | |||
973 | ret = regmap_update_bits(adau1977->regmap, ADAU1977_REG_BLOCK_POWER_SAI, | ||
974 | power_off_mask, 0x00); | ||
975 | if (ret) | ||
976 | goto err_poweroff; | ||
977 | |||
978 | ret = adau1977_power_disable(adau1977); | ||
979 | if (ret) | ||
980 | return ret; | ||
981 | |||
982 | return snd_soc_register_codec(dev, &adau1977_codec_driver, | ||
983 | &adau1977_dai, 1); | ||
984 | |||
985 | err_poweroff: | ||
986 | adau1977_power_disable(adau1977); | ||
987 | return ret; | ||
988 | |||
989 | } | ||
990 | EXPORT_SYMBOL_GPL(adau1977_probe); | ||
991 | |||
992 | static bool adau1977_register_volatile(struct device *dev, unsigned int reg) | ||
993 | { | ||
994 | switch (reg) { | ||
995 | case ADAU1977_REG_STATUS(0): | ||
996 | case ADAU1977_REG_STATUS(1): | ||
997 | case ADAU1977_REG_STATUS(2): | ||
998 | case ADAU1977_REG_STATUS(3): | ||
999 | case ADAU1977_REG_ADC_CLIP: | ||
1000 | return true; | ||
1001 | } | ||
1002 | |||
1003 | return false; | ||
1004 | } | ||
1005 | |||
1006 | const struct regmap_config adau1977_regmap_config = { | ||
1007 | .max_register = ADAU1977_REG_DC_HPF_CAL, | ||
1008 | .volatile_reg = adau1977_register_volatile, | ||
1009 | |||
1010 | .cache_type = REGCACHE_RBTREE, | ||
1011 | .reg_defaults = adau1977_reg_defaults, | ||
1012 | .num_reg_defaults = ARRAY_SIZE(adau1977_reg_defaults), | ||
1013 | }; | ||
1014 | EXPORT_SYMBOL_GPL(adau1977_regmap_config); | ||
1015 | |||
1016 | MODULE_DESCRIPTION("ASoC ADAU1977/ADAU1978/ADAU1979 driver"); | ||
1017 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
1018 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adau1977.h b/sound/soc/codecs/adau1977.h new file mode 100644 index 000000000000..95e714345a86 --- /dev/null +++ b/sound/soc/codecs/adau1977.h | |||
@@ -0,0 +1,37 @@ | |||
1 | /* | ||
2 | * ADAU1977/ADAU1978/ADAU1979 driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * Author: Lars-Peter Clausen <lars@metafoo.de> | ||
6 | * | ||
7 | * Licensed under the GPL-2. | ||
8 | */ | ||
9 | |||
10 | #ifndef __SOUND_SOC_CODECS_ADAU1977_H__ | ||
11 | #define __SOUND_SOC_CODECS_ADAU1977_H__ | ||
12 | |||
13 | #include <linux/regmap.h> | ||
14 | |||
15 | struct device; | ||
16 | |||
17 | enum adau1977_type { | ||
18 | ADAU1977, | ||
19 | ADAU1978, | ||
20 | ADAU1979, | ||
21 | }; | ||
22 | |||
23 | int adau1977_probe(struct device *dev, struct regmap *regmap, | ||
24 | enum adau1977_type type, void (*switch_mode)(struct device *dev)); | ||
25 | |||
26 | extern const struct regmap_config adau1977_regmap_config; | ||
27 | |||
28 | enum adau1977_clk_id { | ||
29 | ADAU1977_SYSCLK, | ||
30 | }; | ||
31 | |||
32 | enum adau1977_sysclk_src { | ||
33 | ADAU1977_SYSCLK_SRC_MCLK, | ||
34 | ADAU1977_SYSCLK_SRC_LRCLK, | ||
35 | }; | ||
36 | |||
37 | #endif | ||
diff --git a/sound/soc/codecs/adav801.c b/sound/soc/codecs/adav801.c new file mode 100644 index 000000000000..790fce33ab10 --- /dev/null +++ b/sound/soc/codecs/adav801.c | |||
@@ -0,0 +1,53 @@ | |||
1 | /* | ||
2 | * ADAV801 audio driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/spi/spi.h> | ||
11 | #include <linux/regmap.h> | ||
12 | |||
13 | #include <sound/soc.h> | ||
14 | |||
15 | #include "adav80x.h" | ||
16 | |||
17 | static const struct spi_device_id adav80x_spi_id[] = { | ||
18 | { "adav801", 0 }, | ||
19 | { } | ||
20 | }; | ||
21 | MODULE_DEVICE_TABLE(spi, adav80x_spi_id); | ||
22 | |||
23 | static int adav80x_spi_probe(struct spi_device *spi) | ||
24 | { | ||
25 | struct regmap_config config; | ||
26 | |||
27 | config = adav80x_regmap_config; | ||
28 | config.read_flag_mask = 0x01; | ||
29 | |||
30 | return adav80x_bus_probe(&spi->dev, devm_regmap_init_spi(spi, &config)); | ||
31 | } | ||
32 | |||
33 | static int adav80x_spi_remove(struct spi_device *spi) | ||
34 | { | ||
35 | snd_soc_unregister_codec(&spi->dev); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static struct spi_driver adav80x_spi_driver = { | ||
40 | .driver = { | ||
41 | .name = "adav801", | ||
42 | .owner = THIS_MODULE, | ||
43 | }, | ||
44 | .probe = adav80x_spi_probe, | ||
45 | .remove = adav80x_spi_remove, | ||
46 | .id_table = adav80x_spi_id, | ||
47 | }; | ||
48 | module_spi_driver(adav80x_spi_driver); | ||
49 | |||
50 | MODULE_DESCRIPTION("ASoC ADAV801 driver"); | ||
51 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
52 | MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); | ||
53 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c new file mode 100644 index 000000000000..66d9fce34e62 --- /dev/null +++ b/sound/soc/codecs/adav803.c | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * ADAV803 audio driver | ||
3 | * | ||
4 | * Copyright 2014 Analog Devices Inc. | ||
5 | * | ||
6 | * Licensed under the GPL-2. | ||
7 | */ | ||
8 | |||
9 | #include <linux/module.h> | ||
10 | #include <linux/i2c.h> | ||
11 | #include <linux/regmap.h> | ||
12 | |||
13 | #include <sound/soc.h> | ||
14 | |||
15 | #include "adav80x.h" | ||
16 | |||
17 | static const struct i2c_device_id adav803_id[] = { | ||
18 | { "adav803", 0 }, | ||
19 | { } | ||
20 | }; | ||
21 | MODULE_DEVICE_TABLE(i2c, adav803_id); | ||
22 | |||
23 | static int adav803_probe(struct i2c_client *client, | ||
24 | const struct i2c_device_id *id) | ||
25 | { | ||
26 | return adav80x_bus_probe(&client->dev, | ||
27 | devm_regmap_init_i2c(client, &adav80x_regmap_config)); | ||
28 | } | ||
29 | |||
30 | static int adav803_remove(struct i2c_client *client) | ||
31 | { | ||
32 | snd_soc_unregister_codec(&client->dev); | ||
33 | return 0; | ||
34 | } | ||
35 | |||
36 | static struct i2c_driver adav803_driver = { | ||
37 | .driver = { | ||
38 | .name = "adav803", | ||
39 | .owner = THIS_MODULE, | ||
40 | }, | ||
41 | .probe = adav803_probe, | ||
42 | .remove = adav803_remove, | ||
43 | .id_table = adav803_id, | ||
44 | }; | ||
45 | module_i2c_driver(adav803_driver); | ||
46 | |||
47 | MODULE_DESCRIPTION("ASoC ADAV803 driver"); | ||
48 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | ||
49 | MODULE_AUTHOR("Yi Li <yi.li@analog.com>>"); | ||
50 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index f78b27a7c461..7470831ba756 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
@@ -8,17 +8,15 @@ | |||
8 | * Licensed under the GPL-2 or later. | 8 | * Licensed under the GPL-2 or later. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/init.h> | ||
12 | #include <linux/module.h> | 11 | #include <linux/module.h> |
13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
14 | #include <linux/i2c.h> | 13 | #include <linux/regmap.h> |
15 | #include <linux/spi/spi.h> | ||
16 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
17 | #include <sound/core.h> | 15 | |
18 | #include <sound/pcm.h> | 16 | #include <sound/pcm.h> |
19 | #include <sound/pcm_params.h> | 17 | #include <sound/pcm_params.h> |
20 | #include <sound/tlv.h> | ||
21 | #include <sound/soc.h> | 18 | #include <sound/soc.h> |
19 | #include <sound/tlv.h> | ||
22 | 20 | ||
23 | #include "adav80x.h" | 21 | #include "adav80x.h" |
24 | 22 | ||
@@ -541,6 +539,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
541 | unsigned int freq, int dir) | 539 | unsigned int freq, int dir) |
542 | { | 540 | { |
543 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 541 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
542 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
544 | 543 | ||
545 | if (dir == SND_SOC_CLOCK_IN) { | 544 | if (dir == SND_SOC_CLOCK_IN) { |
546 | switch (clk_id) { | 545 | switch (clk_id) { |
@@ -573,7 +572,7 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
573 | regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, | 572 | regmap_write(adav80x->regmap, ADAV80X_ICLK_CTRL2, |
574 | iclk_ctrl2); | 573 | iclk_ctrl2); |
575 | 574 | ||
576 | snd_soc_dapm_sync(&codec->dapm); | 575 | snd_soc_dapm_sync(dapm); |
577 | } | 576 | } |
578 | } else { | 577 | } else { |
579 | unsigned int mask; | 578 | unsigned int mask; |
@@ -600,17 +599,21 @@ static int adav80x_set_sysclk(struct snd_soc_codec *codec, | |||
600 | adav80x->sysclk_pd[clk_id] = false; | 599 | adav80x->sysclk_pd[clk_id] = false; |
601 | } | 600 | } |
602 | 601 | ||
602 | snd_soc_dapm_mutex_lock(dapm); | ||
603 | |||
603 | if (adav80x->sysclk_pd[0]) | 604 | if (adav80x->sysclk_pd[0]) |
604 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL1"); | 605 | snd_soc_dapm_disable_pin_unlocked(dapm, "PLL1"); |
605 | else | 606 | else |
606 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL1"); | 607 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL1"); |
607 | 608 | ||
608 | if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) | 609 | if (adav80x->sysclk_pd[1] || adav80x->sysclk_pd[2]) |
609 | snd_soc_dapm_disable_pin(&codec->dapm, "PLL2"); | 610 | snd_soc_dapm_disable_pin_unlocked(dapm, "PLL2"); |
610 | else | 611 | else |
611 | snd_soc_dapm_force_enable_pin(&codec->dapm, "PLL2"); | 612 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "PLL2"); |
612 | 613 | ||
613 | snd_soc_dapm_sync(&codec->dapm); | 614 | snd_soc_dapm_sync_unlocked(dapm); |
615 | |||
616 | snd_soc_dapm_mutex_unlock(dapm); | ||
614 | } | 617 | } |
615 | 618 | ||
616 | return 0; | 619 | return 0; |
@@ -722,7 +725,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream, | |||
722 | struct snd_soc_codec *codec = dai->codec; | 725 | struct snd_soc_codec *codec = dai->codec; |
723 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 726 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
724 | 727 | ||
725 | if (!codec->active || !adav80x->rate) | 728 | if (!snd_soc_codec_is_active(codec) || !adav80x->rate) |
726 | return 0; | 729 | return 0; |
727 | 730 | ||
728 | return snd_pcm_hw_constraint_minmax(substream->runtime, | 731 | return snd_pcm_hw_constraint_minmax(substream->runtime, |
@@ -735,7 +738,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, | |||
735 | struct snd_soc_codec *codec = dai->codec; | 738 | struct snd_soc_codec *codec = dai->codec; |
736 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 739 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
737 | 740 | ||
738 | if (!codec->active) | 741 | if (!snd_soc_codec_is_active(codec)) |
739 | adav80x->rate = 0; | 742 | adav80x->rate = 0; |
740 | } | 743 | } |
741 | 744 | ||
@@ -864,39 +867,26 @@ static struct snd_soc_codec_driver adav80x_codec_driver = { | |||
864 | .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), | 867 | .num_dapm_routes = ARRAY_SIZE(adav80x_dapm_routes), |
865 | }; | 868 | }; |
866 | 869 | ||
867 | static int adav80x_bus_probe(struct device *dev, struct regmap *regmap) | 870 | int adav80x_bus_probe(struct device *dev, struct regmap *regmap) |
868 | { | 871 | { |
869 | struct adav80x *adav80x; | 872 | struct adav80x *adav80x; |
870 | int ret; | ||
871 | 873 | ||
872 | if (IS_ERR(regmap)) | 874 | if (IS_ERR(regmap)) |
873 | return PTR_ERR(regmap); | 875 | return PTR_ERR(regmap); |
874 | 876 | ||
875 | adav80x = kzalloc(sizeof(*adav80x), GFP_KERNEL); | 877 | adav80x = devm_kzalloc(dev, sizeof(*adav80x), GFP_KERNEL); |
876 | if (!adav80x) | 878 | if (!adav80x) |
877 | return -ENOMEM; | 879 | return -ENOMEM; |
878 | 880 | ||
879 | |||
880 | dev_set_drvdata(dev, adav80x); | 881 | dev_set_drvdata(dev, adav80x); |
881 | adav80x->regmap = regmap; | 882 | adav80x->regmap = regmap; |
882 | 883 | ||
883 | ret = snd_soc_register_codec(dev, &adav80x_codec_driver, | 884 | return snd_soc_register_codec(dev, &adav80x_codec_driver, |
884 | adav80x_dais, ARRAY_SIZE(adav80x_dais)); | 885 | adav80x_dais, ARRAY_SIZE(adav80x_dais)); |
885 | if (ret) | ||
886 | kfree(adav80x); | ||
887 | |||
888 | return ret; | ||
889 | } | 886 | } |
887 | EXPORT_SYMBOL_GPL(adav80x_bus_probe); | ||
890 | 888 | ||
891 | static int adav80x_bus_remove(struct device *dev) | 889 | const struct regmap_config adav80x_regmap_config = { |
892 | { | ||
893 | snd_soc_unregister_codec(dev); | ||
894 | kfree(dev_get_drvdata(dev)); | ||
895 | return 0; | ||
896 | } | ||
897 | |||
898 | #if defined(CONFIG_SPI_MASTER) | ||
899 | static const struct regmap_config adav80x_spi_regmap_config = { | ||
900 | .val_bits = 8, | 890 | .val_bits = 8, |
901 | .pad_bits = 1, | 891 | .pad_bits = 1, |
902 | .reg_bits = 7, | 892 | .reg_bits = 7, |
@@ -908,105 +898,7 @@ static const struct regmap_config adav80x_spi_regmap_config = { | |||
908 | .reg_defaults = adav80x_reg_defaults, | 898 | .reg_defaults = adav80x_reg_defaults, |
909 | .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), | 899 | .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), |
910 | }; | 900 | }; |
911 | 901 | EXPORT_SYMBOL_GPL(adav80x_regmap_config); | |
912 | static const struct spi_device_id adav80x_spi_id[] = { | ||
913 | { "adav801", 0 }, | ||
914 | { } | ||
915 | }; | ||
916 | MODULE_DEVICE_TABLE(spi, adav80x_spi_id); | ||
917 | |||
918 | static int adav80x_spi_probe(struct spi_device *spi) | ||
919 | { | ||
920 | return adav80x_bus_probe(&spi->dev, | ||
921 | devm_regmap_init_spi(spi, &adav80x_spi_regmap_config)); | ||
922 | } | ||
923 | |||
924 | static int adav80x_spi_remove(struct spi_device *spi) | ||
925 | { | ||
926 | return adav80x_bus_remove(&spi->dev); | ||
927 | } | ||
928 | |||
929 | static struct spi_driver adav80x_spi_driver = { | ||
930 | .driver = { | ||
931 | .name = "adav801", | ||
932 | .owner = THIS_MODULE, | ||
933 | }, | ||
934 | .probe = adav80x_spi_probe, | ||
935 | .remove = adav80x_spi_remove, | ||
936 | .id_table = adav80x_spi_id, | ||
937 | }; | ||
938 | #endif | ||
939 | |||
940 | #if IS_ENABLED(CONFIG_I2C) | ||
941 | static const struct regmap_config adav80x_i2c_regmap_config = { | ||
942 | .val_bits = 8, | ||
943 | .pad_bits = 1, | ||
944 | .reg_bits = 7, | ||
945 | |||
946 | .max_register = ADAV80X_PLL_OUTE, | ||
947 | |||
948 | .cache_type = REGCACHE_RBTREE, | ||
949 | .reg_defaults = adav80x_reg_defaults, | ||
950 | .num_reg_defaults = ARRAY_SIZE(adav80x_reg_defaults), | ||
951 | }; | ||
952 | |||
953 | static const struct i2c_device_id adav80x_i2c_id[] = { | ||
954 | { "adav803", 0 }, | ||
955 | { } | ||
956 | }; | ||
957 | MODULE_DEVICE_TABLE(i2c, adav80x_i2c_id); | ||
958 | |||
959 | static int adav80x_i2c_probe(struct i2c_client *client, | ||
960 | const struct i2c_device_id *id) | ||
961 | { | ||
962 | return adav80x_bus_probe(&client->dev, | ||
963 | devm_regmap_init_i2c(client, &adav80x_i2c_regmap_config)); | ||
964 | } | ||
965 | |||
966 | static int adav80x_i2c_remove(struct i2c_client *client) | ||
967 | { | ||
968 | return adav80x_bus_remove(&client->dev); | ||
969 | } | ||
970 | |||
971 | static struct i2c_driver adav80x_i2c_driver = { | ||
972 | .driver = { | ||
973 | .name = "adav803", | ||
974 | .owner = THIS_MODULE, | ||
975 | }, | ||
976 | .probe = adav80x_i2c_probe, | ||
977 | .remove = adav80x_i2c_remove, | ||
978 | .id_table = adav80x_i2c_id, | ||
979 | }; | ||
980 | #endif | ||
981 | |||
982 | static int __init adav80x_init(void) | ||
983 | { | ||
984 | int ret = 0; | ||
985 | |||
986 | #if IS_ENABLED(CONFIG_I2C) | ||
987 | ret = i2c_add_driver(&adav80x_i2c_driver); | ||
988 | if (ret) | ||
989 | return ret; | ||
990 | #endif | ||
991 | |||
992 | #if defined(CONFIG_SPI_MASTER) | ||
993 | ret = spi_register_driver(&adav80x_spi_driver); | ||
994 | #endif | ||
995 | |||
996 | return ret; | ||
997 | } | ||
998 | module_init(adav80x_init); | ||
999 | |||
1000 | static void __exit adav80x_exit(void) | ||
1001 | { | ||
1002 | #if IS_ENABLED(CONFIG_I2C) | ||
1003 | i2c_del_driver(&adav80x_i2c_driver); | ||
1004 | #endif | ||
1005 | #if defined(CONFIG_SPI_MASTER) | ||
1006 | spi_unregister_driver(&adav80x_spi_driver); | ||
1007 | #endif | ||
1008 | } | ||
1009 | module_exit(adav80x_exit); | ||
1010 | 902 | ||
1011 | MODULE_DESCRIPTION("ASoC ADAV80x driver"); | 903 | MODULE_DESCRIPTION("ASoC ADAV80x driver"); |
1012 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); | 904 | MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); |
diff --git a/sound/soc/codecs/adav80x.h b/sound/soc/codecs/adav80x.h index adb0fc76d4e3..8a1d7c09dca5 100644 --- a/sound/soc/codecs/adav80x.h +++ b/sound/soc/codecs/adav80x.h | |||
@@ -9,6 +9,13 @@ | |||
9 | #ifndef _ADAV80X_H | 9 | #ifndef _ADAV80X_H |
10 | #define _ADAV80X_H | 10 | #define _ADAV80X_H |
11 | 11 | ||
12 | #include <linux/regmap.h> | ||
13 | |||
14 | struct device; | ||
15 | |||
16 | extern const struct regmap_config adav80x_regmap_config; | ||
17 | int adav80x_bus_probe(struct device *dev, struct regmap *regmap); | ||
18 | |||
12 | enum adav80x_pll_src { | 19 | enum adav80x_pll_src { |
13 | ADAV80X_PLL_SRC_XIN, | 20 | ADAV80X_PLL_SRC_XIN, |
14 | ADAV80X_PLL_SRC_XTAL, | 21 | ADAV80X_PLL_SRC_XTAL, |
diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index b4819dcd4f4d..10adf25d4c14 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c | |||
@@ -174,8 +174,6 @@ static int ak4104_probe(struct snd_soc_codec *codec) | |||
174 | struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); | 174 | struct ak4104_private *ak4104 = snd_soc_codec_get_drvdata(codec); |
175 | int ret; | 175 | int ret; |
176 | 176 | ||
177 | codec->control_data = ak4104->regmap; | ||
178 | |||
179 | /* set power-up and non-reset bits */ | 177 | /* set power-up and non-reset bits */ |
180 | ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, | 178 | ret = regmap_update_bits(ak4104->regmap, AK4104_REG_CONTROL1, |
181 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, | 179 | AK4104_CONTROL1_PW | AK4104_CONTROL1_RSTN, |
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 94cbe508dd37..684b56f2856a 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c | |||
@@ -113,14 +113,14 @@ static const DECLARE_TLV_DB_SCALE(alc_tlv, -800, 50, 0); | |||
113 | static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); | 113 | static const DECLARE_TLV_DB_SCALE(aux_in_tlv, -2100, 300, 0); |
114 | 114 | ||
115 | 115 | ||
116 | static const struct soc_enum ak4641_mono_out_enum = | 116 | static SOC_ENUM_SINGLE_DECL(ak4641_mono_out_enum, |
117 | SOC_ENUM_SINGLE(AK4641_SIG1, 6, 2, ak4641_mono_out); | 117 | AK4641_SIG1, 6, ak4641_mono_out); |
118 | static const struct soc_enum ak4641_hp_out_enum = | 118 | static SOC_ENUM_SINGLE_DECL(ak4641_hp_out_enum, |
119 | SOC_ENUM_SINGLE(AK4641_MODE2, 2, 2, ak4641_hp_out); | 119 | AK4641_MODE2, 2, ak4641_hp_out); |
120 | static const struct soc_enum ak4641_mic_select_enum = | 120 | static SOC_ENUM_SINGLE_DECL(ak4641_mic_select_enum, |
121 | SOC_ENUM_SINGLE(AK4641_MIC, 1, 2, ak4641_mic_select); | 121 | AK4641_MIC, 1, ak4641_mic_select); |
122 | static const struct soc_enum ak4641_mic_or_dac_enum = | 122 | static SOC_ENUM_SINGLE_DECL(ak4641_mic_or_dac_enum, |
123 | SOC_ENUM_SINGLE(AK4641_BTIF, 4, 2, ak4641_mic_or_dac); | 123 | AK4641_BTIF, 4, ak4641_mic_or_dac); |
124 | 124 | ||
125 | static const struct snd_kcontrol_new ak4641_snd_controls[] = { | 125 | static const struct snd_kcontrol_new ak4641_snd_controls[] = { |
126 | SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), | 126 | SOC_ENUM("Mono 1 Output", ak4641_mono_out_enum), |
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 25bdf6ad4a54..deb2b44669de 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/i2c.h> | 16 | #include <linux/i2c.h> |
17 | #include <linux/delay.h> | 17 | #include <linux/delay.h> |
18 | #include <linux/regmap.h> | ||
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | #include <sound/soc.h> | 20 | #include <sound/soc.h> |
20 | #include <sound/initval.h> | 21 | #include <sound/initval.h> |
@@ -23,104 +24,99 @@ | |||
23 | #include "ak4671.h" | 24 | #include "ak4671.h" |
24 | 25 | ||
25 | 26 | ||
26 | /* codec private data */ | ||
27 | struct ak4671_priv { | ||
28 | enum snd_soc_control_type control_type; | ||
29 | }; | ||
30 | |||
31 | /* ak4671 register cache & default register settings */ | 27 | /* ak4671 register cache & default register settings */ |
32 | static const u8 ak4671_reg[AK4671_CACHEREGNUM] = { | 28 | static const struct reg_default ak4671_reg_defaults[] = { |
33 | 0x00, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ | 29 | { 0x00, 0x00 }, /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) */ |
34 | 0xf6, /* AK4671_PLL_MODE_SELECT0 (0x01) */ | 30 | { 0x01, 0xf6 }, /* AK4671_PLL_MODE_SELECT0 (0x01) */ |
35 | 0x00, /* AK4671_PLL_MODE_SELECT1 (0x02) */ | 31 | { 0x02, 0x00 }, /* AK4671_PLL_MODE_SELECT1 (0x02) */ |
36 | 0x02, /* AK4671_FORMAT_SELECT (0x03) */ | 32 | { 0x03, 0x02 }, /* AK4671_FORMAT_SELECT (0x03) */ |
37 | 0x00, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ | 33 | { 0x04, 0x00 }, /* AK4671_MIC_SIGNAL_SELECT (0x04) */ |
38 | 0x55, /* AK4671_MIC_AMP_GAIN (0x05) */ | 34 | { 0x05, 0x55 }, /* AK4671_MIC_AMP_GAIN (0x05) */ |
39 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ | 35 | { 0x06, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT0 (0x06) */ |
40 | 0x00, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ | 36 | { 0x07, 0x00 }, /* AK4671_MIXING_POWER_MANAGEMENT1 (0x07) */ |
41 | 0xb5, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ | 37 | { 0x08, 0xb5 }, /* AK4671_OUTPUT_VOLUME_CONTROL (0x08) */ |
42 | 0x00, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ | 38 | { 0x09, 0x00 }, /* AK4671_LOUT1_SIGNAL_SELECT (0x09) */ |
43 | 0x00, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ | 39 | { 0x0a, 0x00 }, /* AK4671_ROUT1_SIGNAL_SELECT (0x0a) */ |
44 | 0x00, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ | 40 | { 0x0b, 0x00 }, /* AK4671_LOUT2_SIGNAL_SELECT (0x0b) */ |
45 | 0x00, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ | 41 | { 0x0c, 0x00 }, /* AK4671_ROUT2_SIGNAL_SELECT (0x0c) */ |
46 | 0x00, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ | 42 | { 0x0d, 0x00 }, /* AK4671_LOUT3_SIGNAL_SELECT (0x0d) */ |
47 | 0x00, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ | 43 | { 0x0e, 0x00 }, /* AK4671_ROUT3_SIGNAL_SELECT (0x0e) */ |
48 | 0x00, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ | 44 | { 0x0f, 0x00 }, /* AK4671_LOUT1_POWER_MANAGERMENT (0x0f) */ |
49 | 0x00, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ | 45 | { 0x10, 0x00 }, /* AK4671_LOUT2_POWER_MANAGERMENT (0x10) */ |
50 | 0x80, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ | 46 | { 0x11, 0x80 }, /* AK4671_LOUT3_POWER_MANAGERMENT (0x11) */ |
51 | 0x91, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ | 47 | { 0x12, 0x91 }, /* AK4671_LCH_INPUT_VOLUME_CONTROL (0x12) */ |
52 | 0x91, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ | 48 | { 0x13, 0x91 }, /* AK4671_RCH_INPUT_VOLUME_CONTROL (0x13) */ |
53 | 0xe1, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ | 49 | { 0x14, 0xe1 }, /* AK4671_ALC_REFERENCE_SELECT (0x14) */ |
54 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ | 50 | { 0x15, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL (0x15) */ |
55 | 0x00, /* AK4671_ALC_TIMER_SELECT (0x16) */ | 51 | { 0x16, 0x00 }, /* AK4671_ALC_TIMER_SELECT (0x16) */ |
56 | 0x00, /* AK4671_ALC_MODE_CONTROL (0x17) */ | 52 | { 0x17, 0x00 }, /* AK4671_ALC_MODE_CONTROL (0x17) */ |
57 | 0x02, /* AK4671_MODE_CONTROL1 (0x18) */ | 53 | { 0x18, 0x02 }, /* AK4671_MODE_CONTROL1 (0x18) */ |
58 | 0x01, /* AK4671_MODE_CONTROL2 (0x19) */ | 54 | { 0x19, 0x01 }, /* AK4671_MODE_CONTROL2 (0x19) */ |
59 | 0x18, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ | 55 | { 0x1a, 0x18 }, /* AK4671_LCH_OUTPUT_VOLUME_CONTROL (0x1a) */ |
60 | 0x18, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ | 56 | { 0x1b, 0x18 }, /* AK4671_RCH_OUTPUT_VOLUME_CONTROL (0x1b) */ |
61 | 0x00, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ | 57 | { 0x1c, 0x00 }, /* AK4671_SIDETONE_A_CONTROL (0x1c) */ |
62 | 0x02, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ | 58 | { 0x1d, 0x02 }, /* AK4671_DIGITAL_FILTER_SELECT (0x1d) */ |
63 | 0x00, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ | 59 | { 0x1e, 0x00 }, /* AK4671_FIL3_COEFFICIENT0 (0x1e) */ |
64 | 0x00, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ | 60 | { 0x1f, 0x00 }, /* AK4671_FIL3_COEFFICIENT1 (0x1f) */ |
65 | 0x00, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ | 61 | { 0x20, 0x00 }, /* AK4671_FIL3_COEFFICIENT2 (0x20) */ |
66 | 0x00, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ | 62 | { 0x21, 0x00 }, /* AK4671_FIL3_COEFFICIENT3 (0x21) */ |
67 | 0x00, /* AK4671_EQ_COEFFICIENT0 (0x22) */ | 63 | { 0x22, 0x00 }, /* AK4671_EQ_COEFFICIENT0 (0x22) */ |
68 | 0x00, /* AK4671_EQ_COEFFICIENT1 (0x23) */ | 64 | { 0x23, 0x00 }, /* AK4671_EQ_COEFFICIENT1 (0x23) */ |
69 | 0x00, /* AK4671_EQ_COEFFICIENT2 (0x24) */ | 65 | { 0x24, 0x00 }, /* AK4671_EQ_COEFFICIENT2 (0x24) */ |
70 | 0x00, /* AK4671_EQ_COEFFICIENT3 (0x25) */ | 66 | { 0x25, 0x00 }, /* AK4671_EQ_COEFFICIENT3 (0x25) */ |
71 | 0x00, /* AK4671_EQ_COEFFICIENT4 (0x26) */ | 67 | { 0x26, 0x00 }, /* AK4671_EQ_COEFFICIENT4 (0x26) */ |
72 | 0x00, /* AK4671_EQ_COEFFICIENT5 (0x27) */ | 68 | { 0x27, 0x00 }, /* AK4671_EQ_COEFFICIENT5 (0x27) */ |
73 | 0xa9, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ | 69 | { 0x28, 0xa9 }, /* AK4671_FIL1_COEFFICIENT0 (0x28) */ |
74 | 0x1f, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ | 70 | { 0x29, 0x1f }, /* AK4671_FIL1_COEFFICIENT1 (0x29) */ |
75 | 0xad, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ | 71 | { 0x2a, 0xad }, /* AK4671_FIL1_COEFFICIENT2 (0x2a) */ |
76 | 0x20, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ | 72 | { 0x2b, 0x20 }, /* AK4671_FIL1_COEFFICIENT3 (0x2b) */ |
77 | 0x00, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ | 73 | { 0x2c, 0x00 }, /* AK4671_FIL2_COEFFICIENT0 (0x2c) */ |
78 | 0x00, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ | 74 | { 0x2d, 0x00 }, /* AK4671_FIL2_COEFFICIENT1 (0x2d) */ |
79 | 0x00, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ | 75 | { 0x2e, 0x00 }, /* AK4671_FIL2_COEFFICIENT2 (0x2e) */ |
80 | 0x00, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ | 76 | { 0x2f, 0x00 }, /* AK4671_FIL2_COEFFICIENT3 (0x2f) */ |
81 | 0x00, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ | 77 | { 0x30, 0x00 }, /* AK4671_DIGITAL_FILTER_SELECT2 (0x30) */ |
82 | 0x00, /* this register not used */ | 78 | |
83 | 0x00, /* AK4671_E1_COEFFICIENT0 (0x32) */ | 79 | { 0x32, 0x00 }, /* AK4671_E1_COEFFICIENT0 (0x32) */ |
84 | 0x00, /* AK4671_E1_COEFFICIENT1 (0x33) */ | 80 | { 0x33, 0x00 }, /* AK4671_E1_COEFFICIENT1 (0x33) */ |
85 | 0x00, /* AK4671_E1_COEFFICIENT2 (0x34) */ | 81 | { 0x34, 0x00 }, /* AK4671_E1_COEFFICIENT2 (0x34) */ |
86 | 0x00, /* AK4671_E1_COEFFICIENT3 (0x35) */ | 82 | { 0x35, 0x00 }, /* AK4671_E1_COEFFICIENT3 (0x35) */ |
87 | 0x00, /* AK4671_E1_COEFFICIENT4 (0x36) */ | 83 | { 0x36, 0x00 }, /* AK4671_E1_COEFFICIENT4 (0x36) */ |
88 | 0x00, /* AK4671_E1_COEFFICIENT5 (0x37) */ | 84 | { 0x37, 0x00 }, /* AK4671_E1_COEFFICIENT5 (0x37) */ |
89 | 0x00, /* AK4671_E2_COEFFICIENT0 (0x38) */ | 85 | { 0x38, 0x00 }, /* AK4671_E2_COEFFICIENT0 (0x38) */ |
90 | 0x00, /* AK4671_E2_COEFFICIENT1 (0x39) */ | 86 | { 0x39, 0x00 }, /* AK4671_E2_COEFFICIENT1 (0x39) */ |
91 | 0x00, /* AK4671_E2_COEFFICIENT2 (0x3a) */ | 87 | { 0x3a, 0x00 }, /* AK4671_E2_COEFFICIENT2 (0x3a) */ |
92 | 0x00, /* AK4671_E2_COEFFICIENT3 (0x3b) */ | 88 | { 0x3b, 0x00 }, /* AK4671_E2_COEFFICIENT3 (0x3b) */ |
93 | 0x00, /* AK4671_E2_COEFFICIENT4 (0x3c) */ | 89 | { 0x3c, 0x00 }, /* AK4671_E2_COEFFICIENT4 (0x3c) */ |
94 | 0x00, /* AK4671_E2_COEFFICIENT5 (0x3d) */ | 90 | { 0x3d, 0x00 }, /* AK4671_E2_COEFFICIENT5 (0x3d) */ |
95 | 0x00, /* AK4671_E3_COEFFICIENT0 (0x3e) */ | 91 | { 0x3e, 0x00 }, /* AK4671_E3_COEFFICIENT0 (0x3e) */ |
96 | 0x00, /* AK4671_E3_COEFFICIENT1 (0x3f) */ | 92 | { 0x3f, 0x00 }, /* AK4671_E3_COEFFICIENT1 (0x3f) */ |
97 | 0x00, /* AK4671_E3_COEFFICIENT2 (0x40) */ | 93 | { 0x40, 0x00 }, /* AK4671_E3_COEFFICIENT2 (0x40) */ |
98 | 0x00, /* AK4671_E3_COEFFICIENT3 (0x41) */ | 94 | { 0x41, 0x00 }, /* AK4671_E3_COEFFICIENT3 (0x41) */ |
99 | 0x00, /* AK4671_E3_COEFFICIENT4 (0x42) */ | 95 | { 0x42, 0x00 }, /* AK4671_E3_COEFFICIENT4 (0x42) */ |
100 | 0x00, /* AK4671_E3_COEFFICIENT5 (0x43) */ | 96 | { 0x43, 0x00 }, /* AK4671_E3_COEFFICIENT5 (0x43) */ |
101 | 0x00, /* AK4671_E4_COEFFICIENT0 (0x44) */ | 97 | { 0x44, 0x00 }, /* AK4671_E4_COEFFICIENT0 (0x44) */ |
102 | 0x00, /* AK4671_E4_COEFFICIENT1 (0x45) */ | 98 | { 0x45, 0x00 }, /* AK4671_E4_COEFFICIENT1 (0x45) */ |
103 | 0x00, /* AK4671_E4_COEFFICIENT2 (0x46) */ | 99 | { 0x46, 0x00 }, /* AK4671_E4_COEFFICIENT2 (0x46) */ |
104 | 0x00, /* AK4671_E4_COEFFICIENT3 (0x47) */ | 100 | { 0x47, 0x00 }, /* AK4671_E4_COEFFICIENT3 (0x47) */ |
105 | 0x00, /* AK4671_E4_COEFFICIENT4 (0x48) */ | 101 | { 0x48, 0x00 }, /* AK4671_E4_COEFFICIENT4 (0x48) */ |
106 | 0x00, /* AK4671_E4_COEFFICIENT5 (0x49) */ | 102 | { 0x49, 0x00 }, /* AK4671_E4_COEFFICIENT5 (0x49) */ |
107 | 0x00, /* AK4671_E5_COEFFICIENT0 (0x4a) */ | 103 | { 0x4a, 0x00 }, /* AK4671_E5_COEFFICIENT0 (0x4a) */ |
108 | 0x00, /* AK4671_E5_COEFFICIENT1 (0x4b) */ | 104 | { 0x4b, 0x00 }, /* AK4671_E5_COEFFICIENT1 (0x4b) */ |
109 | 0x00, /* AK4671_E5_COEFFICIENT2 (0x4c) */ | 105 | { 0x4c, 0x00 }, /* AK4671_E5_COEFFICIENT2 (0x4c) */ |
110 | 0x00, /* AK4671_E5_COEFFICIENT3 (0x4d) */ | 106 | { 0x4d, 0x00 }, /* AK4671_E5_COEFFICIENT3 (0x4d) */ |
111 | 0x00, /* AK4671_E5_COEFFICIENT4 (0x4e) */ | 107 | { 0x4e, 0x00 }, /* AK4671_E5_COEFFICIENT4 (0x4e) */ |
112 | 0x00, /* AK4671_E5_COEFFICIENT5 (0x4f) */ | 108 | { 0x4f, 0x00 }, /* AK4671_E5_COEFFICIENT5 (0x4f) */ |
113 | 0x88, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ | 109 | { 0x50, 0x88 }, /* AK4671_EQ_CONTROL_250HZ_100HZ (0x50) */ |
114 | 0x88, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ | 110 | { 0x51, 0x88 }, /* AK4671_EQ_CONTROL_3500HZ_1KHZ (0x51) */ |
115 | 0x08, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ | 111 | { 0x52, 0x08 }, /* AK4671_EQ_CONTRO_10KHZ (0x52) */ |
116 | 0x00, /* AK4671_PCM_IF_CONTROL0 (0x53) */ | 112 | { 0x53, 0x00 }, /* AK4671_PCM_IF_CONTROL0 (0x53) */ |
117 | 0x00, /* AK4671_PCM_IF_CONTROL1 (0x54) */ | 113 | { 0x54, 0x00 }, /* AK4671_PCM_IF_CONTROL1 (0x54) */ |
118 | 0x00, /* AK4671_PCM_IF_CONTROL2 (0x55) */ | 114 | { 0x55, 0x00 }, /* AK4671_PCM_IF_CONTROL2 (0x55) */ |
119 | 0x18, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ | 115 | { 0x56, 0x18 }, /* AK4671_DIGITAL_VOLUME_B_CONTROL (0x56) */ |
120 | 0x18, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ | 116 | { 0x57, 0x18 }, /* AK4671_DIGITAL_VOLUME_C_CONTROL (0x57) */ |
121 | 0x00, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ | 117 | { 0x58, 0x00 }, /* AK4671_SIDETONE_VOLUME_CONTROL (0x58) */ |
122 | 0x00, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ | 118 | { 0x59, 0x00 }, /* AK4671_DIGITAL_MIXING_CONTROL2 (0x59) */ |
123 | 0x00, /* AK4671_SAR_ADC_CONTROL (0x5a) */ | 119 | { 0x5a, 0x00 }, /* AK4671_SAR_ADC_CONTROL (0x5a) */ |
124 | }; | 120 | }; |
125 | 121 | ||
126 | /* | 122 | /* |
@@ -241,19 +237,17 @@ static const struct snd_kcontrol_new ak4671_rout3_mixer_controls[] = { | |||
241 | /* Input MUXs */ | 237 | /* Input MUXs */ |
242 | static const char *ak4671_lin_mux_texts[] = | 238 | static const char *ak4671_lin_mux_texts[] = |
243 | {"LIN1", "LIN2", "LIN3", "LIN4"}; | 239 | {"LIN1", "LIN2", "LIN3", "LIN4"}; |
244 | static const struct soc_enum ak4671_lin_mux_enum = | 240 | static SOC_ENUM_SINGLE_DECL(ak4671_lin_mux_enum, |
245 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 0, | 241 | AK4671_MIC_SIGNAL_SELECT, 0, |
246 | ARRAY_SIZE(ak4671_lin_mux_texts), | 242 | ak4671_lin_mux_texts); |
247 | ak4671_lin_mux_texts); | ||
248 | static const struct snd_kcontrol_new ak4671_lin_mux_control = | 243 | static const struct snd_kcontrol_new ak4671_lin_mux_control = |
249 | SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); | 244 | SOC_DAPM_ENUM("Route", ak4671_lin_mux_enum); |
250 | 245 | ||
251 | static const char *ak4671_rin_mux_texts[] = | 246 | static const char *ak4671_rin_mux_texts[] = |
252 | {"RIN1", "RIN2", "RIN3", "RIN4"}; | 247 | {"RIN1", "RIN2", "RIN3", "RIN4"}; |
253 | static const struct soc_enum ak4671_rin_mux_enum = | 248 | static SOC_ENUM_SINGLE_DECL(ak4671_rin_mux_enum, |
254 | SOC_ENUM_SINGLE(AK4671_MIC_SIGNAL_SELECT, 2, | 249 | AK4671_MIC_SIGNAL_SELECT, 2, |
255 | ARRAY_SIZE(ak4671_rin_mux_texts), | 250 | ak4671_rin_mux_texts); |
256 | ak4671_rin_mux_texts); | ||
257 | static const struct snd_kcontrol_new ak4671_rin_mux_control = | 251 | static const struct snd_kcontrol_new ak4671_rin_mux_control = |
258 | SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); | 252 | SOC_DAPM_ENUM("Route", ak4671_rin_mux_enum); |
259 | 253 | ||
@@ -619,18 +613,14 @@ static struct snd_soc_dai_driver ak4671_dai = { | |||
619 | 613 | ||
620 | static int ak4671_probe(struct snd_soc_codec *codec) | 614 | static int ak4671_probe(struct snd_soc_codec *codec) |
621 | { | 615 | { |
622 | struct ak4671_priv *ak4671 = snd_soc_codec_get_drvdata(codec); | ||
623 | int ret; | 616 | int ret; |
624 | 617 | ||
625 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, ak4671->control_type); | 618 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
626 | if (ret < 0) { | 619 | if (ret < 0) { |
627 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 620 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
628 | return ret; | 621 | return ret; |
629 | } | 622 | } |
630 | 623 | ||
631 | snd_soc_add_codec_controls(codec, ak4671_snd_controls, | ||
632 | ARRAY_SIZE(ak4671_snd_controls)); | ||
633 | |||
634 | ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 624 | ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
635 | 625 | ||
636 | return ret; | 626 | return ret; |
@@ -646,28 +636,36 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4671 = { | |||
646 | .probe = ak4671_probe, | 636 | .probe = ak4671_probe, |
647 | .remove = ak4671_remove, | 637 | .remove = ak4671_remove, |
648 | .set_bias_level = ak4671_set_bias_level, | 638 | .set_bias_level = ak4671_set_bias_level, |
649 | .reg_cache_size = AK4671_CACHEREGNUM, | 639 | .controls = ak4671_snd_controls, |
650 | .reg_word_size = sizeof(u8), | 640 | .num_controls = ARRAY_SIZE(ak4671_snd_controls), |
651 | .reg_cache_default = ak4671_reg, | ||
652 | .dapm_widgets = ak4671_dapm_widgets, | 641 | .dapm_widgets = ak4671_dapm_widgets, |
653 | .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), | 642 | .num_dapm_widgets = ARRAY_SIZE(ak4671_dapm_widgets), |
654 | .dapm_routes = ak4671_intercon, | 643 | .dapm_routes = ak4671_intercon, |
655 | .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), | 644 | .num_dapm_routes = ARRAY_SIZE(ak4671_intercon), |
656 | }; | 645 | }; |
657 | 646 | ||
647 | static const struct regmap_config ak4671_regmap = { | ||
648 | .reg_bits = 8, | ||
649 | .val_bits = 8, | ||
650 | |||
651 | .max_register = AK4671_SAR_ADC_CONTROL, | ||
652 | .reg_defaults = ak4671_reg_defaults, | ||
653 | .num_reg_defaults = ARRAY_SIZE(ak4671_reg_defaults), | ||
654 | .cache_type = REGCACHE_RBTREE, | ||
655 | }; | ||
656 | |||
658 | static int ak4671_i2c_probe(struct i2c_client *client, | 657 | static int ak4671_i2c_probe(struct i2c_client *client, |
659 | const struct i2c_device_id *id) | 658 | const struct i2c_device_id *id) |
660 | { | 659 | { |
661 | struct ak4671_priv *ak4671; | 660 | struct regmap *regmap; |
662 | int ret; | 661 | int ret; |
663 | 662 | ||
664 | ak4671 = devm_kzalloc(&client->dev, sizeof(struct ak4671_priv), | 663 | regmap = devm_regmap_init_i2c(client, &ak4671_regmap); |
665 | GFP_KERNEL); | 664 | if (IS_ERR(regmap)) { |
666 | if (ak4671 == NULL) | 665 | ret = PTR_ERR(regmap); |
667 | return -ENOMEM; | 666 | dev_err(&client->dev, "Failed to create regmap: %d\n", ret); |
668 | 667 | return ret; | |
669 | i2c_set_clientdata(client, ak4671); | 668 | } |
670 | ak4671->control_type = SND_SOC_I2C; | ||
671 | 669 | ||
672 | ret = snd_soc_register_codec(&client->dev, | 670 | ret = snd_soc_register_codec(&client->dev, |
673 | &soc_codec_dev_ak4671, &ak4671_dai, 1); | 671 | &soc_codec_dev_ak4671, &ak4671_dai, 1); |
diff --git a/sound/soc/codecs/ak4671.h b/sound/soc/codecs/ak4671.h index 61cb7ab7552c..394a34d3f50a 100644 --- a/sound/soc/codecs/ak4671.h +++ b/sound/soc/codecs/ak4671.h | |||
@@ -105,8 +105,6 @@ | |||
105 | #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 | 105 | #define AK4671_DIGITAL_MIXING_CONTROL2 0x59 |
106 | #define AK4671_SAR_ADC_CONTROL 0x5a | 106 | #define AK4671_SAR_ADC_CONTROL 0x5a |
107 | 107 | ||
108 | #define AK4671_CACHEREGNUM (AK4671_SAR_ADC_CONTROL + 1) | ||
109 | |||
110 | /* Bitfield Definitions */ | 108 | /* Bitfield Definitions */ |
111 | 109 | ||
112 | /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ | 110 | /* AK4671_AD_DA_POWER_MANAGEMENT (0x00) Fields */ |
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index d3036283482a..ed506253a914 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/delay.h> | 21 | #include <linux/delay.h> |
22 | #include <linux/pm.h> | 22 | #include <linux/pm.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include <linux/regmap.h> | ||
24 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
25 | #include <sound/core.h> | 26 | #include <sound/core.h> |
26 | #include <sound/pcm.h> | 27 | #include <sound/pcm.h> |
@@ -38,26 +39,13 @@ MODULE_PARM_DESC(caps_charge, "ALC5623 cap charge time (msecs)"); | |||
38 | 39 | ||
39 | /* codec private data */ | 40 | /* codec private data */ |
40 | struct alc5623_priv { | 41 | struct alc5623_priv { |
41 | enum snd_soc_control_type control_type; | 42 | struct regmap *regmap; |
42 | u8 id; | 43 | u8 id; |
43 | unsigned int sysclk; | 44 | unsigned int sysclk; |
44 | u16 reg_cache[ALC5623_VENDOR_ID2+2]; | ||
45 | unsigned int add_ctrl; | 45 | unsigned int add_ctrl; |
46 | unsigned int jack_det_ctrl; | 46 | unsigned int jack_det_ctrl; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | static void alc5623_fill_cache(struct snd_soc_codec *codec) | ||
50 | { | ||
51 | int i, step = codec->driver->reg_cache_step; | ||
52 | u16 *cache = codec->reg_cache; | ||
53 | |||
54 | /* not really efficient ... */ | ||
55 | codec->cache_bypass = 1; | ||
56 | for (i = 0 ; i < codec->driver->reg_cache_size ; i += step) | ||
57 | cache[i] = snd_soc_read(codec, i); | ||
58 | codec->cache_bypass = 0; | ||
59 | } | ||
60 | |||
61 | static inline int alc5623_reset(struct snd_soc_codec *codec) | 49 | static inline int alc5623_reset(struct snd_soc_codec *codec) |
62 | { | 50 | { |
63 | return snd_soc_write(codec, ALC5623_RESET, 0); | 51 | return snd_soc_write(codec, ALC5623_RESET, 0); |
@@ -228,32 +216,37 @@ static const char *alc5623_aux_out_input_sel[] = { | |||
228 | "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; | 216 | "Vmid", "HPOut Mix", "Speaker Mix", "Mono Mix"}; |
229 | 217 | ||
230 | /* auxout output mux */ | 218 | /* auxout output mux */ |
231 | static const struct soc_enum alc5623_aux_out_input_enum = | 219 | static SOC_ENUM_SINGLE_DECL(alc5623_aux_out_input_enum, |
232 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 6, 4, alc5623_aux_out_input_sel); | 220 | ALC5623_OUTPUT_MIXER_CTRL, 6, |
221 | alc5623_aux_out_input_sel); | ||
233 | static const struct snd_kcontrol_new alc5623_auxout_mux_controls = | 222 | static const struct snd_kcontrol_new alc5623_auxout_mux_controls = |
234 | SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); | 223 | SOC_DAPM_ENUM("Route", alc5623_aux_out_input_enum); |
235 | 224 | ||
236 | /* speaker output mux */ | 225 | /* speaker output mux */ |
237 | static const struct soc_enum alc5623_spkout_input_enum = | 226 | static SOC_ENUM_SINGLE_DECL(alc5623_spkout_input_enum, |
238 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 10, 4, alc5623_spkout_input_sel); | 227 | ALC5623_OUTPUT_MIXER_CTRL, 10, |
228 | alc5623_spkout_input_sel); | ||
239 | static const struct snd_kcontrol_new alc5623_spkout_mux_controls = | 229 | static const struct snd_kcontrol_new alc5623_spkout_mux_controls = |
240 | SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); | 230 | SOC_DAPM_ENUM("Route", alc5623_spkout_input_enum); |
241 | 231 | ||
242 | /* headphone left output mux */ | 232 | /* headphone left output mux */ |
243 | static const struct soc_enum alc5623_hpl_out_input_enum = | 233 | static SOC_ENUM_SINGLE_DECL(alc5623_hpl_out_input_enum, |
244 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 9, 2, alc5623_hpl_out_input_sel); | 234 | ALC5623_OUTPUT_MIXER_CTRL, 9, |
235 | alc5623_hpl_out_input_sel); | ||
245 | static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = | 236 | static const struct snd_kcontrol_new alc5623_hpl_out_mux_controls = |
246 | SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); | 237 | SOC_DAPM_ENUM("Route", alc5623_hpl_out_input_enum); |
247 | 238 | ||
248 | /* headphone right output mux */ | 239 | /* headphone right output mux */ |
249 | static const struct soc_enum alc5623_hpr_out_input_enum = | 240 | static SOC_ENUM_SINGLE_DECL(alc5623_hpr_out_input_enum, |
250 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 8, 2, alc5623_hpr_out_input_sel); | 241 | ALC5623_OUTPUT_MIXER_CTRL, 8, |
242 | alc5623_hpr_out_input_sel); | ||
251 | static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = | 243 | static const struct snd_kcontrol_new alc5623_hpr_out_mux_controls = |
252 | SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); | 244 | SOC_DAPM_ENUM("Route", alc5623_hpr_out_input_enum); |
253 | 245 | ||
254 | /* speaker output N select */ | 246 | /* speaker output N select */ |
255 | static const struct soc_enum alc5623_spk_n_sour_enum = | 247 | static SOC_ENUM_SINGLE_DECL(alc5623_spk_n_sour_enum, |
256 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 14, 4, alc5623_spk_n_sour_sel); | 248 | ALC5623_OUTPUT_MIXER_CTRL, 14, |
249 | alc5623_spk_n_sour_sel); | ||
257 | static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = | 250 | static const struct snd_kcontrol_new alc5623_spkoutn_mux_controls = |
258 | SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); | 251 | SOC_DAPM_ENUM("Route", alc5623_spk_n_sour_enum); |
259 | 252 | ||
@@ -338,8 +331,9 @@ SND_SOC_DAPM_VMID("Vmid"), | |||
338 | }; | 331 | }; |
339 | 332 | ||
340 | static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; | 333 | static const char *alc5623_amp_names[] = {"AB Amp", "D Amp"}; |
341 | static const struct soc_enum alc5623_amp_enum = | 334 | static SOC_ENUM_SINGLE_DECL(alc5623_amp_enum, |
342 | SOC_ENUM_SINGLE(ALC5623_OUTPUT_MIXER_CTRL, 13, 2, alc5623_amp_names); | 335 | ALC5623_OUTPUT_MIXER_CTRL, 13, |
336 | alc5623_amp_names); | ||
343 | static const struct snd_kcontrol_new alc5623_amp_mux_controls = | 337 | static const struct snd_kcontrol_new alc5623_amp_mux_controls = |
344 | SOC_DAPM_ENUM("Route", alc5623_amp_enum); | 338 | SOC_DAPM_ENUM("Route", alc5623_amp_enum); |
345 | 339 | ||
@@ -869,18 +863,28 @@ static struct snd_soc_dai_driver alc5623_dai = { | |||
869 | 863 | ||
870 | static int alc5623_suspend(struct snd_soc_codec *codec) | 864 | static int alc5623_suspend(struct snd_soc_codec *codec) |
871 | { | 865 | { |
866 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); | ||
867 | |||
872 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); | 868 | alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF); |
869 | regcache_cache_only(alc5623->regmap, true); | ||
870 | |||
873 | return 0; | 871 | return 0; |
874 | } | 872 | } |
875 | 873 | ||
876 | static int alc5623_resume(struct snd_soc_codec *codec) | 874 | static int alc5623_resume(struct snd_soc_codec *codec) |
877 | { | 875 | { |
878 | int i, step = codec->driver->reg_cache_step; | 876 | struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec); |
879 | u16 *cache = codec->reg_cache; | 877 | int ret; |
880 | 878 | ||
881 | /* Sync reg_cache with the hardware */ | 879 | /* Sync reg_cache with the hardware */ |
882 | for (i = 2 ; i < codec->driver->reg_cache_size ; i += step) | 880 | regcache_cache_only(alc5623->regmap, false); |
883 | snd_soc_write(codec, i, cache[i]); | 881 | ret = regcache_sync(alc5623->regmap); |
882 | if (ret != 0) { | ||
883 | dev_err(codec->dev, "Failed to sync register cache: %d\n", | ||
884 | ret); | ||
885 | regcache_cache_only(alc5623->regmap, true); | ||
886 | return ret; | ||
887 | } | ||
884 | 888 | ||
885 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 889 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
886 | 890 | ||
@@ -900,14 +904,14 @@ static int alc5623_probe(struct snd_soc_codec *codec) | |||
900 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 904 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
901 | int ret; | 905 | int ret; |
902 | 906 | ||
903 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, alc5623->control_type); | 907 | codec->control_data = alc5623->regmap; |
908 | ret = snd_soc_codec_set_cache_io(codec, 8, 16, SND_SOC_REGMAP); | ||
904 | if (ret < 0) { | 909 | if (ret < 0) { |
905 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 910 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
906 | return ret; | 911 | return ret; |
907 | } | 912 | } |
908 | 913 | ||
909 | alc5623_reset(codec); | 914 | alc5623_reset(codec); |
910 | alc5623_fill_cache(codec); | ||
911 | 915 | ||
912 | /* power on device */ | 916 | /* power on device */ |
913 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); | 917 | alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY); |
@@ -980,9 +984,15 @@ static struct snd_soc_codec_driver soc_codec_device_alc5623 = { | |||
980 | .suspend = alc5623_suspend, | 984 | .suspend = alc5623_suspend, |
981 | .resume = alc5623_resume, | 985 | .resume = alc5623_resume, |
982 | .set_bias_level = alc5623_set_bias_level, | 986 | .set_bias_level = alc5623_set_bias_level, |
983 | .reg_cache_size = ALC5623_VENDOR_ID2+2, | 987 | }; |
984 | .reg_word_size = sizeof(u16), | 988 | |
985 | .reg_cache_step = 2, | 989 | static const struct regmap_config alc5623_regmap = { |
990 | .reg_bits = 8, | ||
991 | .val_bits = 16, | ||
992 | .reg_stride = 2, | ||
993 | |||
994 | .max_register = ALC5623_VENDOR_ID2, | ||
995 | .cache_type = REGCACHE_RBTREE, | ||
986 | }; | 996 | }; |
987 | 997 | ||
988 | /* | 998 | /* |
@@ -996,19 +1006,32 @@ static int alc5623_i2c_probe(struct i2c_client *client, | |||
996 | { | 1006 | { |
997 | struct alc5623_platform_data *pdata; | 1007 | struct alc5623_platform_data *pdata; |
998 | struct alc5623_priv *alc5623; | 1008 | struct alc5623_priv *alc5623; |
999 | int ret, vid1, vid2; | 1009 | unsigned int vid1, vid2; |
1010 | int ret; | ||
1000 | 1011 | ||
1001 | vid1 = i2c_smbus_read_word_data(client, ALC5623_VENDOR_ID1); | 1012 | alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), |
1002 | if (vid1 < 0) { | 1013 | GFP_KERNEL); |
1003 | dev_err(&client->dev, "failed to read I2C\n"); | 1014 | if (alc5623 == NULL) |
1004 | return -EIO; | 1015 | return -ENOMEM; |
1016 | |||
1017 | alc5623->regmap = devm_regmap_init_i2c(client, &alc5623_regmap); | ||
1018 | if (IS_ERR(alc5623->regmap)) { | ||
1019 | ret = PTR_ERR(alc5623->regmap); | ||
1020 | dev_err(&client->dev, "Failed to initialise I/O: %d\n", ret); | ||
1021 | return ret; | ||
1022 | } | ||
1023 | |||
1024 | ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID1, &vid1); | ||
1025 | if (ret < 0) { | ||
1026 | dev_err(&client->dev, "failed to read vendor ID1: %d\n", ret); | ||
1027 | return ret; | ||
1005 | } | 1028 | } |
1006 | vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); | 1029 | vid1 = ((vid1 & 0xff) << 8) | (vid1 >> 8); |
1007 | 1030 | ||
1008 | vid2 = i2c_smbus_read_byte_data(client, ALC5623_VENDOR_ID2); | 1031 | ret = regmap_read(alc5623->regmap, ALC5623_VENDOR_ID2, &vid2); |
1009 | if (vid2 < 0) { | 1032 | if (ret < 0) { |
1010 | dev_err(&client->dev, "failed to read I2C\n"); | 1033 | dev_err(&client->dev, "failed to read vendor ID2: %d\n", ret); |
1011 | return -EIO; | 1034 | return ret; |
1012 | } | 1035 | } |
1013 | 1036 | ||
1014 | if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { | 1037 | if ((vid1 != 0x10ec) || (vid2 != id->driver_data)) { |
@@ -1021,11 +1044,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, | |||
1021 | 1044 | ||
1022 | dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); | 1045 | dev_dbg(&client->dev, "Found codec id : alc56%02x\n", vid2); |
1023 | 1046 | ||
1024 | alc5623 = devm_kzalloc(&client->dev, sizeof(struct alc5623_priv), | ||
1025 | GFP_KERNEL); | ||
1026 | if (alc5623 == NULL) | ||
1027 | return -ENOMEM; | ||
1028 | |||
1029 | pdata = client->dev.platform_data; | 1047 | pdata = client->dev.platform_data; |
1030 | if (pdata) { | 1048 | if (pdata) { |
1031 | alc5623->add_ctrl = pdata->add_ctrl; | 1049 | alc5623->add_ctrl = pdata->add_ctrl; |
@@ -1048,7 +1066,6 @@ static int alc5623_i2c_probe(struct i2c_client *client, | |||
1048 | } | 1066 | } |
1049 | 1067 | ||
1050 | i2c_set_clientdata(client, alc5623); | 1068 | i2c_set_clientdata(client, alc5623); |
1051 | alc5623->control_type = SND_SOC_I2C; | ||
1052 | 1069 | ||
1053 | ret = snd_soc_register_codec(&client->dev, | 1070 | ret = snd_soc_register_codec(&client->dev, |
1054 | &soc_codec_device_alc5623, &alc5623_dai, 1); | 1071 | &soc_codec_device_alc5623, &alc5623_dai, 1); |
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index fb001c56cf8d..d885056ad8f2 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c | |||
@@ -293,51 +293,59 @@ static const char * const alc5632_i2s_out_sel[] = { | |||
293 | "ADC LR", "Voice Stereo Digital"}; | 293 | "ADC LR", "Voice Stereo Digital"}; |
294 | 294 | ||
295 | /* auxout output mux */ | 295 | /* auxout output mux */ |
296 | static const struct soc_enum alc5632_aux_out_input_enum = | 296 | static SOC_ENUM_SINGLE_DECL(alc5632_aux_out_input_enum, |
297 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 6, 4, alc5632_aux_out_input_sel); | 297 | ALC5632_OUTPUT_MIXER_CTRL, 6, |
298 | alc5632_aux_out_input_sel); | ||
298 | static const struct snd_kcontrol_new alc5632_auxout_mux_controls = | 299 | static const struct snd_kcontrol_new alc5632_auxout_mux_controls = |
299 | SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum); | 300 | SOC_DAPM_ENUM("AuxOut Mux", alc5632_aux_out_input_enum); |
300 | 301 | ||
301 | /* speaker output mux */ | 302 | /* speaker output mux */ |
302 | static const struct soc_enum alc5632_spkout_input_enum = | 303 | static SOC_ENUM_SINGLE_DECL(alc5632_spkout_input_enum, |
303 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 10, 4, alc5632_spkout_input_sel); | 304 | ALC5632_OUTPUT_MIXER_CTRL, 10, |
305 | alc5632_spkout_input_sel); | ||
304 | static const struct snd_kcontrol_new alc5632_spkout_mux_controls = | 306 | static const struct snd_kcontrol_new alc5632_spkout_mux_controls = |
305 | SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum); | 307 | SOC_DAPM_ENUM("SpeakerOut Mux", alc5632_spkout_input_enum); |
306 | 308 | ||
307 | /* headphone left output mux */ | 309 | /* headphone left output mux */ |
308 | static const struct soc_enum alc5632_hpl_out_input_enum = | 310 | static SOC_ENUM_SINGLE_DECL(alc5632_hpl_out_input_enum, |
309 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 9, 2, alc5632_hpl_out_input_sel); | 311 | ALC5632_OUTPUT_MIXER_CTRL, 9, |
312 | alc5632_hpl_out_input_sel); | ||
310 | static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls = | 313 | static const struct snd_kcontrol_new alc5632_hpl_out_mux_controls = |
311 | SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum); | 314 | SOC_DAPM_ENUM("Left Headphone Mux", alc5632_hpl_out_input_enum); |
312 | 315 | ||
313 | /* headphone right output mux */ | 316 | /* headphone right output mux */ |
314 | static const struct soc_enum alc5632_hpr_out_input_enum = | 317 | static SOC_ENUM_SINGLE_DECL(alc5632_hpr_out_input_enum, |
315 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 8, 2, alc5632_hpr_out_input_sel); | 318 | ALC5632_OUTPUT_MIXER_CTRL, 8, |
319 | alc5632_hpr_out_input_sel); | ||
316 | static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls = | 320 | static const struct snd_kcontrol_new alc5632_hpr_out_mux_controls = |
317 | SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum); | 321 | SOC_DAPM_ENUM("Right Headphone Mux", alc5632_hpr_out_input_enum); |
318 | 322 | ||
319 | /* speaker output N select */ | 323 | /* speaker output N select */ |
320 | static const struct soc_enum alc5632_spk_n_sour_enum = | 324 | static SOC_ENUM_SINGLE_DECL(alc5632_spk_n_sour_enum, |
321 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 14, 4, alc5632_spk_n_sour_sel); | 325 | ALC5632_OUTPUT_MIXER_CTRL, 14, |
326 | alc5632_spk_n_sour_sel); | ||
322 | static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls = | 327 | static const struct snd_kcontrol_new alc5632_spkoutn_mux_controls = |
323 | SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum); | 328 | SOC_DAPM_ENUM("SpeakerOut N Mux", alc5632_spk_n_sour_enum); |
324 | 329 | ||
325 | /* speaker amplifier */ | 330 | /* speaker amplifier */ |
326 | static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; | 331 | static const char *alc5632_amp_names[] = {"AB Amp", "D Amp"}; |
327 | static const struct soc_enum alc5632_amp_enum = | 332 | static SOC_ENUM_SINGLE_DECL(alc5632_amp_enum, |
328 | SOC_ENUM_SINGLE(ALC5632_OUTPUT_MIXER_CTRL, 13, 2, alc5632_amp_names); | 333 | ALC5632_OUTPUT_MIXER_CTRL, 13, |
334 | alc5632_amp_names); | ||
329 | static const struct snd_kcontrol_new alc5632_amp_mux_controls = | 335 | static const struct snd_kcontrol_new alc5632_amp_mux_controls = |
330 | SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); | 336 | SOC_DAPM_ENUM("AB-D Amp Mux", alc5632_amp_enum); |
331 | 337 | ||
332 | /* ADC output select */ | 338 | /* ADC output select */ |
333 | static const struct soc_enum alc5632_adcr_func_enum = | 339 | static SOC_ENUM_SINGLE_DECL(alc5632_adcr_func_enum, |
334 | SOC_ENUM_SINGLE(ALC5632_DAC_FUNC_SELECT, 5, 2, alc5632_adcr_func_sel); | 340 | ALC5632_DAC_FUNC_SELECT, 5, |
341 | alc5632_adcr_func_sel); | ||
335 | static const struct snd_kcontrol_new alc5632_adcr_func_controls = | 342 | static const struct snd_kcontrol_new alc5632_adcr_func_controls = |
336 | SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); | 343 | SOC_DAPM_ENUM("ADCR Mux", alc5632_adcr_func_enum); |
337 | 344 | ||
338 | /* I2S out select */ | 345 | /* I2S out select */ |
339 | static const struct soc_enum alc5632_i2s_out_enum = | 346 | static SOC_ENUM_SINGLE_DECL(alc5632_i2s_out_enum, |
340 | SOC_ENUM_SINGLE(ALC5632_I2S_OUT_CTL, 5, 2, alc5632_i2s_out_sel); | 347 | ALC5632_I2S_OUT_CTL, 5, |
348 | alc5632_i2s_out_sel); | ||
341 | static const struct snd_kcontrol_new alc5632_i2s_out_controls = | 349 | static const struct snd_kcontrol_new alc5632_i2s_out_controls = |
342 | SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); | 350 | SOC_DAPM_ENUM("I2SOut Mux", alc5632_i2s_out_enum); |
343 | 351 | ||
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index e4295fee8f13..29e198f57d4c 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c | |||
@@ -53,6 +53,14 @@ | |||
53 | #define ARIZONA_AIF_RX_ENABLES 0x1A | 53 | #define ARIZONA_AIF_RX_ENABLES 0x1A |
54 | #define ARIZONA_AIF_FORCE_WRITE 0x1B | 54 | #define ARIZONA_AIF_FORCE_WRITE 0x1B |
55 | 55 | ||
56 | #define ARIZONA_FLL_VCO_CORNER 141900000 | ||
57 | #define ARIZONA_FLL_MAX_FREF 13500000 | ||
58 | #define ARIZONA_FLL_MIN_FVCO 90000000 | ||
59 | #define ARIZONA_FLL_MAX_FRATIO 16 | ||
60 | #define ARIZONA_FLL_MAX_REFDIV 8 | ||
61 | #define ARIZONA_FLL_MIN_OUTDIV 2 | ||
62 | #define ARIZONA_FLL_MAX_OUTDIV 7 | ||
63 | |||
56 | #define arizona_fll_err(_fll, fmt, ...) \ | 64 | #define arizona_fll_err(_fll, fmt, ...) \ |
57 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) | 65 | dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__) |
58 | #define arizona_fll_warn(_fll, fmt, ...) \ | 66 | #define arizona_fll_warn(_fll, fmt, ...) \ |
@@ -542,67 +550,76 @@ static const char *arizona_vol_ramp_text[] = { | |||
542 | "15ms/6dB", "30ms/6dB", | 550 | "15ms/6dB", "30ms/6dB", |
543 | }; | 551 | }; |
544 | 552 | ||
545 | const struct soc_enum arizona_in_vd_ramp = | 553 | SOC_ENUM_SINGLE_DECL(arizona_in_vd_ramp, |
546 | SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, | 554 | ARIZONA_INPUT_VOLUME_RAMP, |
547 | ARIZONA_IN_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 555 | ARIZONA_IN_VD_RAMP_SHIFT, |
556 | arizona_vol_ramp_text); | ||
548 | EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); | 557 | EXPORT_SYMBOL_GPL(arizona_in_vd_ramp); |
549 | 558 | ||
550 | const struct soc_enum arizona_in_vi_ramp = | 559 | SOC_ENUM_SINGLE_DECL(arizona_in_vi_ramp, |
551 | SOC_ENUM_SINGLE(ARIZONA_INPUT_VOLUME_RAMP, | 560 | ARIZONA_INPUT_VOLUME_RAMP, |
552 | ARIZONA_IN_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 561 | ARIZONA_IN_VI_RAMP_SHIFT, |
562 | arizona_vol_ramp_text); | ||
553 | EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); | 563 | EXPORT_SYMBOL_GPL(arizona_in_vi_ramp); |
554 | 564 | ||
555 | const struct soc_enum arizona_out_vd_ramp = | 565 | SOC_ENUM_SINGLE_DECL(arizona_out_vd_ramp, |
556 | SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, | 566 | ARIZONA_OUTPUT_VOLUME_RAMP, |
557 | ARIZONA_OUT_VD_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 567 | ARIZONA_OUT_VD_RAMP_SHIFT, |
568 | arizona_vol_ramp_text); | ||
558 | EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); | 569 | EXPORT_SYMBOL_GPL(arizona_out_vd_ramp); |
559 | 570 | ||
560 | const struct soc_enum arizona_out_vi_ramp = | 571 | SOC_ENUM_SINGLE_DECL(arizona_out_vi_ramp, |
561 | SOC_ENUM_SINGLE(ARIZONA_OUTPUT_VOLUME_RAMP, | 572 | ARIZONA_OUTPUT_VOLUME_RAMP, |
562 | ARIZONA_OUT_VI_RAMP_SHIFT, 7, arizona_vol_ramp_text); | 573 | ARIZONA_OUT_VI_RAMP_SHIFT, |
574 | arizona_vol_ramp_text); | ||
563 | EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); | 575 | EXPORT_SYMBOL_GPL(arizona_out_vi_ramp); |
564 | 576 | ||
565 | static const char *arizona_lhpf_mode_text[] = { | 577 | static const char *arizona_lhpf_mode_text[] = { |
566 | "Low-pass", "High-pass" | 578 | "Low-pass", "High-pass" |
567 | }; | 579 | }; |
568 | 580 | ||
569 | const struct soc_enum arizona_lhpf1_mode = | 581 | SOC_ENUM_SINGLE_DECL(arizona_lhpf1_mode, |
570 | SOC_ENUM_SINGLE(ARIZONA_HPLPF1_1, ARIZONA_LHPF1_MODE_SHIFT, 2, | 582 | ARIZONA_HPLPF1_1, |
571 | arizona_lhpf_mode_text); | 583 | ARIZONA_LHPF1_MODE_SHIFT, |
584 | arizona_lhpf_mode_text); | ||
572 | EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); | 585 | EXPORT_SYMBOL_GPL(arizona_lhpf1_mode); |
573 | 586 | ||
574 | const struct soc_enum arizona_lhpf2_mode = | 587 | SOC_ENUM_SINGLE_DECL(arizona_lhpf2_mode, |
575 | SOC_ENUM_SINGLE(ARIZONA_HPLPF2_1, ARIZONA_LHPF2_MODE_SHIFT, 2, | 588 | ARIZONA_HPLPF2_1, |
576 | arizona_lhpf_mode_text); | 589 | ARIZONA_LHPF2_MODE_SHIFT, |
590 | arizona_lhpf_mode_text); | ||
577 | EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); | 591 | EXPORT_SYMBOL_GPL(arizona_lhpf2_mode); |
578 | 592 | ||
579 | const struct soc_enum arizona_lhpf3_mode = | 593 | SOC_ENUM_SINGLE_DECL(arizona_lhpf3_mode, |
580 | SOC_ENUM_SINGLE(ARIZONA_HPLPF3_1, ARIZONA_LHPF3_MODE_SHIFT, 2, | 594 | ARIZONA_HPLPF3_1, |
581 | arizona_lhpf_mode_text); | 595 | ARIZONA_LHPF3_MODE_SHIFT, |
596 | arizona_lhpf_mode_text); | ||
582 | EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); | 597 | EXPORT_SYMBOL_GPL(arizona_lhpf3_mode); |
583 | 598 | ||
584 | const struct soc_enum arizona_lhpf4_mode = | 599 | SOC_ENUM_SINGLE_DECL(arizona_lhpf4_mode, |
585 | SOC_ENUM_SINGLE(ARIZONA_HPLPF4_1, ARIZONA_LHPF4_MODE_SHIFT, 2, | 600 | ARIZONA_HPLPF4_1, |
586 | arizona_lhpf_mode_text); | 601 | ARIZONA_LHPF4_MODE_SHIFT, |
602 | arizona_lhpf_mode_text); | ||
587 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); | 603 | EXPORT_SYMBOL_GPL(arizona_lhpf4_mode); |
588 | 604 | ||
589 | static const char *arizona_ng_hold_text[] = { | 605 | static const char *arizona_ng_hold_text[] = { |
590 | "30ms", "120ms", "250ms", "500ms", | 606 | "30ms", "120ms", "250ms", "500ms", |
591 | }; | 607 | }; |
592 | 608 | ||
593 | const struct soc_enum arizona_ng_hold = | 609 | SOC_ENUM_SINGLE_DECL(arizona_ng_hold, |
594 | SOC_ENUM_SINGLE(ARIZONA_NOISE_GATE_CONTROL, ARIZONA_NGATE_HOLD_SHIFT, | 610 | ARIZONA_NOISE_GATE_CONTROL, |
595 | 4, arizona_ng_hold_text); | 611 | ARIZONA_NGATE_HOLD_SHIFT, |
612 | arizona_ng_hold_text); | ||
596 | EXPORT_SYMBOL_GPL(arizona_ng_hold); | 613 | EXPORT_SYMBOL_GPL(arizona_ng_hold); |
597 | 614 | ||
598 | static const char * const arizona_in_hpf_cut_text[] = { | 615 | static const char * const arizona_in_hpf_cut_text[] = { |
599 | "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" | 616 | "2.5Hz", "5Hz", "10Hz", "20Hz", "40Hz" |
600 | }; | 617 | }; |
601 | 618 | ||
602 | const struct soc_enum arizona_in_hpf_cut_enum = | 619 | SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum, |
603 | SOC_ENUM_SINGLE(ARIZONA_HPF_CONTROL, ARIZONA_IN_HPF_CUT_SHIFT, | 620 | ARIZONA_HPF_CONTROL, |
604 | ARRAY_SIZE(arizona_in_hpf_cut_text), | 621 | ARIZONA_IN_HPF_CUT_SHIFT, |
605 | arizona_in_hpf_cut_text); | 622 | arizona_in_hpf_cut_text); |
606 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); | 623 | EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum); |
607 | 624 | ||
608 | static const char * const arizona_in_dmic_osr_text[] = { | 625 | static const char * const arizona_in_dmic_osr_text[] = { |
@@ -1377,74 +1394,147 @@ struct arizona_fll_cfg { | |||
1377 | int gain; | 1394 | int gain; |
1378 | }; | 1395 | }; |
1379 | 1396 | ||
1380 | static int arizona_calc_fll(struct arizona_fll *fll, | 1397 | static int arizona_validate_fll(struct arizona_fll *fll, |
1381 | struct arizona_fll_cfg *cfg, | 1398 | unsigned int Fref, |
1382 | unsigned int Fref, | 1399 | unsigned int Fout) |
1383 | unsigned int Fout) | ||
1384 | { | 1400 | { |
1385 | unsigned int target, div, gcd_fll; | 1401 | unsigned int Fvco_min; |
1386 | int i, ratio; | 1402 | |
1403 | if (Fref / ARIZONA_FLL_MAX_REFDIV > ARIZONA_FLL_MAX_FREF) { | ||
1404 | arizona_fll_err(fll, | ||
1405 | "Can't scale %dMHz in to <=13.5MHz\n", | ||
1406 | Fref); | ||
1407 | return -EINVAL; | ||
1408 | } | ||
1387 | 1409 | ||
1388 | arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, Fout); | 1410 | Fvco_min = ARIZONA_FLL_MIN_FVCO * fll->vco_mult; |
1411 | if (Fout * ARIZONA_FLL_MAX_OUTDIV < Fvco_min) { | ||
1412 | arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", | ||
1413 | Fout); | ||
1414 | return -EINVAL; | ||
1415 | } | ||
1416 | |||
1417 | return 0; | ||
1418 | } | ||
1419 | |||
1420 | static int arizona_find_fratio(unsigned int Fref, int *fratio) | ||
1421 | { | ||
1422 | int i; | ||
1423 | |||
1424 | /* Find an appropriate FLL_FRATIO */ | ||
1425 | for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { | ||
1426 | if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { | ||
1427 | if (fratio) | ||
1428 | *fratio = fll_fratios[i].fratio; | ||
1429 | return fll_fratios[i].ratio; | ||
1430 | } | ||
1431 | } | ||
1432 | |||
1433 | return -EINVAL; | ||
1434 | } | ||
1435 | |||
1436 | static int arizona_calc_fratio(struct arizona_fll *fll, | ||
1437 | struct arizona_fll_cfg *cfg, | ||
1438 | unsigned int target, | ||
1439 | unsigned int Fref, bool sync) | ||
1440 | { | ||
1441 | int init_ratio, ratio; | ||
1442 | int refdiv, div; | ||
1389 | 1443 | ||
1390 | /* Fref must be <=13.5MHz */ | 1444 | /* Fref must be <=13.5MHz, find initial refdiv */ |
1391 | div = 1; | 1445 | div = 1; |
1392 | cfg->refdiv = 0; | 1446 | cfg->refdiv = 0; |
1393 | while ((Fref / div) > 13500000) { | 1447 | while (Fref > ARIZONA_FLL_MAX_FREF) { |
1394 | div *= 2; | 1448 | div *= 2; |
1449 | Fref /= 2; | ||
1395 | cfg->refdiv++; | 1450 | cfg->refdiv++; |
1396 | 1451 | ||
1397 | if (div > 8) { | 1452 | if (div > ARIZONA_FLL_MAX_REFDIV) |
1398 | arizona_fll_err(fll, | ||
1399 | "Can't scale %dMHz in to <=13.5MHz\n", | ||
1400 | Fref); | ||
1401 | return -EINVAL; | 1453 | return -EINVAL; |
1454 | } | ||
1455 | |||
1456 | /* Find an appropriate FLL_FRATIO */ | ||
1457 | init_ratio = arizona_find_fratio(Fref, &cfg->fratio); | ||
1458 | if (init_ratio < 0) { | ||
1459 | arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", | ||
1460 | Fref); | ||
1461 | return init_ratio; | ||
1462 | } | ||
1463 | |||
1464 | switch (fll->arizona->type) { | ||
1465 | case WM5110: | ||
1466 | if (fll->arizona->rev < 3 || sync) | ||
1467 | return init_ratio; | ||
1468 | break; | ||
1469 | default: | ||
1470 | return init_ratio; | ||
1471 | } | ||
1472 | |||
1473 | cfg->fratio = init_ratio - 1; | ||
1474 | |||
1475 | /* Adjust FRATIO/refdiv to avoid integer mode if possible */ | ||
1476 | refdiv = cfg->refdiv; | ||
1477 | |||
1478 | while (div <= ARIZONA_FLL_MAX_REFDIV) { | ||
1479 | for (ratio = init_ratio; ratio <= ARIZONA_FLL_MAX_FRATIO; | ||
1480 | ratio++) { | ||
1481 | if (target % (ratio * Fref)) { | ||
1482 | cfg->refdiv = refdiv; | ||
1483 | cfg->fratio = ratio - 1; | ||
1484 | return ratio; | ||
1485 | } | ||
1402 | } | 1486 | } |
1487 | |||
1488 | for (ratio = init_ratio - 1; ratio >= 0; ratio--) { | ||
1489 | if (ARIZONA_FLL_VCO_CORNER / (fll->vco_mult * ratio) < | ||
1490 | Fref) | ||
1491 | break; | ||
1492 | |||
1493 | if (target % (ratio * Fref)) { | ||
1494 | cfg->refdiv = refdiv; | ||
1495 | cfg->fratio = ratio - 1; | ||
1496 | return ratio; | ||
1497 | } | ||
1498 | } | ||
1499 | |||
1500 | div *= 2; | ||
1501 | Fref /= 2; | ||
1502 | refdiv++; | ||
1503 | init_ratio = arizona_find_fratio(Fref, NULL); | ||
1403 | } | 1504 | } |
1404 | 1505 | ||
1405 | /* Apply the division for our remaining calculations */ | 1506 | arizona_fll_warn(fll, "Falling back to integer mode operation\n"); |
1406 | Fref /= div; | 1507 | return cfg->fratio + 1; |
1508 | } | ||
1509 | |||
1510 | static int arizona_calc_fll(struct arizona_fll *fll, | ||
1511 | struct arizona_fll_cfg *cfg, | ||
1512 | unsigned int Fref, bool sync) | ||
1513 | { | ||
1514 | unsigned int target, div, gcd_fll; | ||
1515 | int i, ratio; | ||
1516 | |||
1517 | arizona_fll_dbg(fll, "Fref=%u Fout=%u\n", Fref, fll->fout); | ||
1407 | 1518 | ||
1408 | /* Fvco should be over the targt; don't check the upper bound */ | 1519 | /* Fvco should be over the targt; don't check the upper bound */ |
1409 | div = 1; | 1520 | div = ARIZONA_FLL_MIN_OUTDIV; |
1410 | while (Fout * div < 90000000 * fll->vco_mult) { | 1521 | while (fll->fout * div < ARIZONA_FLL_MIN_FVCO * fll->vco_mult) { |
1411 | div++; | 1522 | div++; |
1412 | if (div > 7) { | 1523 | if (div > ARIZONA_FLL_MAX_OUTDIV) |
1413 | arizona_fll_err(fll, "No FLL_OUTDIV for Fout=%uHz\n", | ||
1414 | Fout); | ||
1415 | return -EINVAL; | 1524 | return -EINVAL; |
1416 | } | ||
1417 | } | 1525 | } |
1418 | target = Fout * div / fll->vco_mult; | 1526 | target = fll->fout * div / fll->vco_mult; |
1419 | cfg->outdiv = div; | 1527 | cfg->outdiv = div; |
1420 | 1528 | ||
1421 | arizona_fll_dbg(fll, "Fvco=%dHz\n", target); | 1529 | arizona_fll_dbg(fll, "Fvco=%dHz\n", target); |
1422 | 1530 | ||
1423 | /* Find an appropraite FLL_FRATIO and factor it out of the target */ | 1531 | /* Find an appropriate FLL_FRATIO and refdiv */ |
1424 | for (i = 0; i < ARRAY_SIZE(fll_fratios); i++) { | 1532 | ratio = arizona_calc_fratio(fll, cfg, target, Fref, sync); |
1425 | if (fll_fratios[i].min <= Fref && Fref <= fll_fratios[i].max) { | 1533 | if (ratio < 0) |
1426 | cfg->fratio = fll_fratios[i].fratio; | 1534 | return ratio; |
1427 | ratio = fll_fratios[i].ratio; | ||
1428 | break; | ||
1429 | } | ||
1430 | } | ||
1431 | if (i == ARRAY_SIZE(fll_fratios)) { | ||
1432 | arizona_fll_err(fll, "Unable to find FRATIO for Fref=%uHz\n", | ||
1433 | Fref); | ||
1434 | return -EINVAL; | ||
1435 | } | ||
1436 | 1535 | ||
1437 | for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { | 1536 | /* Apply the division for our remaining calculations */ |
1438 | if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { | 1537 | Fref = Fref / (1 << cfg->refdiv); |
1439 | cfg->gain = fll_gains[i].gain; | ||
1440 | break; | ||
1441 | } | ||
1442 | } | ||
1443 | if (i == ARRAY_SIZE(fll_gains)) { | ||
1444 | arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", | ||
1445 | Fref); | ||
1446 | return -EINVAL; | ||
1447 | } | ||
1448 | 1538 | ||
1449 | cfg->n = target / (ratio * Fref); | 1539 | cfg->n = target / (ratio * Fref); |
1450 | 1540 | ||
@@ -1469,6 +1559,18 @@ static int arizona_calc_fll(struct arizona_fll *fll, | |||
1469 | cfg->lambda >>= 1; | 1559 | cfg->lambda >>= 1; |
1470 | } | 1560 | } |
1471 | 1561 | ||
1562 | for (i = 0; i < ARRAY_SIZE(fll_gains); i++) { | ||
1563 | if (fll_gains[i].min <= Fref && Fref <= fll_gains[i].max) { | ||
1564 | cfg->gain = fll_gains[i].gain; | ||
1565 | break; | ||
1566 | } | ||
1567 | } | ||
1568 | if (i == ARRAY_SIZE(fll_gains)) { | ||
1569 | arizona_fll_err(fll, "Unable to find gain for Fref=%uHz\n", | ||
1570 | Fref); | ||
1571 | return -EINVAL; | ||
1572 | } | ||
1573 | |||
1472 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", | 1574 | arizona_fll_dbg(fll, "N=%x THETA=%x LAMBDA=%x\n", |
1473 | cfg->n, cfg->theta, cfg->lambda); | 1575 | cfg->n, cfg->theta, cfg->lambda); |
1474 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", | 1576 | arizona_fll_dbg(fll, "FRATIO=%x(%d) OUTDIV=%x REFCLK_DIV=%x\n", |
@@ -1496,14 +1598,18 @@ static void arizona_apply_fll(struct arizona *arizona, unsigned int base, | |||
1496 | cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | | 1598 | cfg->refdiv << ARIZONA_FLL1_CLK_REF_DIV_SHIFT | |
1497 | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); | 1599 | source << ARIZONA_FLL1_CLK_REF_SRC_SHIFT); |
1498 | 1600 | ||
1499 | if (sync) | 1601 | if (sync) { |
1500 | regmap_update_bits_async(arizona->regmap, base + 0x7, | 1602 | regmap_update_bits(arizona->regmap, base + 0x7, |
1501 | ARIZONA_FLL1_GAIN_MASK, | 1603 | ARIZONA_FLL1_GAIN_MASK, |
1502 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); | 1604 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); |
1503 | else | 1605 | } else { |
1504 | regmap_update_bits_async(arizona->regmap, base + 0x9, | 1606 | regmap_update_bits(arizona->regmap, base + 0x5, |
1505 | ARIZONA_FLL1_GAIN_MASK, | 1607 | ARIZONA_FLL1_OUTDIV_MASK, |
1506 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); | 1608 | cfg->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); |
1609 | regmap_update_bits(arizona->regmap, base + 0x9, | ||
1610 | ARIZONA_FLL1_GAIN_MASK, | ||
1611 | cfg->gain << ARIZONA_FLL1_GAIN_SHIFT); | ||
1612 | } | ||
1507 | 1613 | ||
1508 | regmap_update_bits_async(arizona->regmap, base + 2, | 1614 | regmap_update_bits_async(arizona->regmap, base + 2, |
1509 | ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, | 1615 | ARIZONA_FLL1_CTRL_UPD | ARIZONA_FLL1_N_MASK, |
@@ -1526,13 +1632,12 @@ static bool arizona_is_enabled_fll(struct arizona_fll *fll) | |||
1526 | return reg & ARIZONA_FLL1_ENA; | 1632 | return reg & ARIZONA_FLL1_ENA; |
1527 | } | 1633 | } |
1528 | 1634 | ||
1529 | static void arizona_enable_fll(struct arizona_fll *fll, | 1635 | static void arizona_enable_fll(struct arizona_fll *fll) |
1530 | struct arizona_fll_cfg *ref, | ||
1531 | struct arizona_fll_cfg *sync) | ||
1532 | { | 1636 | { |
1533 | struct arizona *arizona = fll->arizona; | 1637 | struct arizona *arizona = fll->arizona; |
1534 | int ret; | 1638 | int ret; |
1535 | bool use_sync = false; | 1639 | bool use_sync = false; |
1640 | struct arizona_fll_cfg cfg; | ||
1536 | 1641 | ||
1537 | /* | 1642 | /* |
1538 | * If we have both REFCLK and SYNCCLK then enable both, | 1643 | * If we have both REFCLK and SYNCCLK then enable both, |
@@ -1540,23 +1645,21 @@ static void arizona_enable_fll(struct arizona_fll *fll, | |||
1540 | */ | 1645 | */ |
1541 | if (fll->ref_src >= 0 && fll->ref_freq && | 1646 | if (fll->ref_src >= 0 && fll->ref_freq && |
1542 | fll->ref_src != fll->sync_src) { | 1647 | fll->ref_src != fll->sync_src) { |
1543 | regmap_update_bits_async(arizona->regmap, fll->base + 5, | 1648 | arizona_calc_fll(fll, &cfg, fll->ref_freq, false); |
1544 | ARIZONA_FLL1_OUTDIV_MASK, | ||
1545 | ref->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); | ||
1546 | 1649 | ||
1547 | arizona_apply_fll(arizona, fll->base, ref, fll->ref_src, | 1650 | arizona_apply_fll(arizona, fll->base, &cfg, fll->ref_src, |
1548 | false); | 1651 | false); |
1549 | if (fll->sync_src >= 0) { | 1652 | if (fll->sync_src >= 0) { |
1550 | arizona_apply_fll(arizona, fll->base + 0x10, sync, | 1653 | arizona_calc_fll(fll, &cfg, fll->sync_freq, true); |
1654 | |||
1655 | arizona_apply_fll(arizona, fll->base + 0x10, &cfg, | ||
1551 | fll->sync_src, true); | 1656 | fll->sync_src, true); |
1552 | use_sync = true; | 1657 | use_sync = true; |
1553 | } | 1658 | } |
1554 | } else if (fll->sync_src >= 0) { | 1659 | } else if (fll->sync_src >= 0) { |
1555 | regmap_update_bits_async(arizona->regmap, fll->base + 5, | 1660 | arizona_calc_fll(fll, &cfg, fll->sync_freq, false); |
1556 | ARIZONA_FLL1_OUTDIV_MASK, | ||
1557 | sync->outdiv << ARIZONA_FLL1_OUTDIV_SHIFT); | ||
1558 | 1661 | ||
1559 | arizona_apply_fll(arizona, fll->base, sync, | 1662 | arizona_apply_fll(arizona, fll->base, &cfg, |
1560 | fll->sync_src, false); | 1663 | fll->sync_src, false); |
1561 | 1664 | ||
1562 | regmap_update_bits_async(arizona->regmap, fll->base + 0x11, | 1665 | regmap_update_bits_async(arizona->regmap, fll->base + 0x11, |
@@ -1618,32 +1721,22 @@ static void arizona_disable_fll(struct arizona_fll *fll) | |||
1618 | int arizona_set_fll_refclk(struct arizona_fll *fll, int source, | 1721 | int arizona_set_fll_refclk(struct arizona_fll *fll, int source, |
1619 | unsigned int Fref, unsigned int Fout) | 1722 | unsigned int Fref, unsigned int Fout) |
1620 | { | 1723 | { |
1621 | struct arizona_fll_cfg ref, sync; | ||
1622 | int ret; | 1724 | int ret; |
1623 | 1725 | ||
1624 | if (fll->ref_src == source && fll->ref_freq == Fref) | 1726 | if (fll->ref_src == source && fll->ref_freq == Fref) |
1625 | return 0; | 1727 | return 0; |
1626 | 1728 | ||
1627 | if (fll->fout) { | 1729 | if (fll->fout && Fref > 0) { |
1628 | if (Fref > 0) { | 1730 | ret = arizona_validate_fll(fll, Fref, fll->fout); |
1629 | ret = arizona_calc_fll(fll, &ref, Fref, fll->fout); | 1731 | if (ret != 0) |
1630 | if (ret != 0) | 1732 | return ret; |
1631 | return ret; | ||
1632 | } | ||
1633 | |||
1634 | if (fll->sync_src >= 0) { | ||
1635 | ret = arizona_calc_fll(fll, &sync, fll->sync_freq, | ||
1636 | fll->fout); | ||
1637 | if (ret != 0) | ||
1638 | return ret; | ||
1639 | } | ||
1640 | } | 1733 | } |
1641 | 1734 | ||
1642 | fll->ref_src = source; | 1735 | fll->ref_src = source; |
1643 | fll->ref_freq = Fref; | 1736 | fll->ref_freq = Fref; |
1644 | 1737 | ||
1645 | if (fll->fout && Fref > 0) { | 1738 | if (fll->fout && Fref > 0) { |
1646 | arizona_enable_fll(fll, &ref, &sync); | 1739 | arizona_enable_fll(fll); |
1647 | } | 1740 | } |
1648 | 1741 | ||
1649 | return 0; | 1742 | return 0; |
@@ -1653,7 +1746,6 @@ EXPORT_SYMBOL_GPL(arizona_set_fll_refclk); | |||
1653 | int arizona_set_fll(struct arizona_fll *fll, int source, | 1746 | int arizona_set_fll(struct arizona_fll *fll, int source, |
1654 | unsigned int Fref, unsigned int Fout) | 1747 | unsigned int Fref, unsigned int Fout) |
1655 | { | 1748 | { |
1656 | struct arizona_fll_cfg ref, sync; | ||
1657 | int ret; | 1749 | int ret; |
1658 | 1750 | ||
1659 | if (fll->sync_src == source && | 1751 | if (fll->sync_src == source && |
@@ -1662,13 +1754,12 @@ int arizona_set_fll(struct arizona_fll *fll, int source, | |||
1662 | 1754 | ||
1663 | if (Fout) { | 1755 | if (Fout) { |
1664 | if (fll->ref_src >= 0) { | 1756 | if (fll->ref_src >= 0) { |
1665 | ret = arizona_calc_fll(fll, &ref, fll->ref_freq, | 1757 | ret = arizona_validate_fll(fll, fll->ref_freq, Fout); |
1666 | Fout); | ||
1667 | if (ret != 0) | 1758 | if (ret != 0) |
1668 | return ret; | 1759 | return ret; |
1669 | } | 1760 | } |
1670 | 1761 | ||
1671 | ret = arizona_calc_fll(fll, &sync, Fref, Fout); | 1762 | ret = arizona_validate_fll(fll, Fref, Fout); |
1672 | if (ret != 0) | 1763 | if (ret != 0) |
1673 | return ret; | 1764 | return ret; |
1674 | } | 1765 | } |
@@ -1678,7 +1769,7 @@ int arizona_set_fll(struct arizona_fll *fll, int source, | |||
1678 | fll->fout = Fout; | 1769 | fll->fout = Fout; |
1679 | 1770 | ||
1680 | if (Fout) { | 1771 | if (Fout) { |
1681 | arizona_enable_fll(fll, &ref, &sync); | 1772 | arizona_enable_fll(fll); |
1682 | } else { | 1773 | } else { |
1683 | arizona_disable_fll(fll); | 1774 | arizona_disable_fll(fll); |
1684 | } | 1775 | } |
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index ce05fd93dc74..aef4965750c7 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c | |||
@@ -159,7 +159,6 @@ static bool cs4271_volatile_reg(struct device *dev, unsigned int reg) | |||
159 | } | 159 | } |
160 | 160 | ||
161 | struct cs4271_private { | 161 | struct cs4271_private { |
162 | /* SND_SOC_I2C or SND_SOC_SPI */ | ||
163 | unsigned int mclk; | 162 | unsigned int mclk; |
164 | bool master; | 163 | bool master; |
165 | bool deemph; | 164 | bool deemph; |
@@ -540,14 +539,10 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
540 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); | 539 | struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec); |
541 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; | 540 | struct cs4271_platform_data *cs4271plat = codec->dev->platform_data; |
542 | int ret; | 541 | int ret; |
543 | int gpio_nreset = -EINVAL; | ||
544 | bool amutec_eq_bmutec = false; | 542 | bool amutec_eq_bmutec = false; |
545 | 543 | ||
546 | #ifdef CONFIG_OF | 544 | #ifdef CONFIG_OF |
547 | if (of_match_device(cs4271_dt_ids, codec->dev)) { | 545 | if (of_match_device(cs4271_dt_ids, codec->dev)) { |
548 | gpio_nreset = of_get_named_gpio(codec->dev->of_node, | ||
549 | "reset-gpio", 0); | ||
550 | |||
551 | if (of_get_property(codec->dev->of_node, | 546 | if (of_get_property(codec->dev->of_node, |
552 | "cirrus,amutec-eq-bmutec", NULL)) | 547 | "cirrus,amutec-eq-bmutec", NULL)) |
553 | amutec_eq_bmutec = true; | 548 | amutec_eq_bmutec = true; |
@@ -559,27 +554,19 @@ static int cs4271_probe(struct snd_soc_codec *codec) | |||
559 | #endif | 554 | #endif |
560 | 555 | ||
561 | if (cs4271plat) { | 556 | if (cs4271plat) { |
562 | if (gpio_is_valid(cs4271plat->gpio_nreset)) | ||
563 | gpio_nreset = cs4271plat->gpio_nreset; | ||
564 | |||
565 | amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; | 557 | amutec_eq_bmutec = cs4271plat->amutec_eq_bmutec; |
566 | cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; | 558 | cs4271->enable_soft_reset = cs4271plat->enable_soft_reset; |
567 | } | 559 | } |
568 | 560 | ||
569 | if (gpio_nreset >= 0) | 561 | if (gpio_is_valid(cs4271->gpio_nreset)) { |
570 | if (devm_gpio_request(codec->dev, gpio_nreset, "CS4271 Reset")) | ||
571 | gpio_nreset = -EINVAL; | ||
572 | if (gpio_nreset >= 0) { | ||
573 | /* Reset codec */ | 562 | /* Reset codec */ |
574 | gpio_direction_output(gpio_nreset, 0); | 563 | gpio_direction_output(cs4271->gpio_nreset, 0); |
575 | udelay(1); | 564 | udelay(1); |
576 | gpio_set_value(gpio_nreset, 1); | 565 | gpio_set_value(cs4271->gpio_nreset, 1); |
577 | /* Give the codec time to wake up */ | 566 | /* Give the codec time to wake up */ |
578 | udelay(1); | 567 | udelay(1); |
579 | } | 568 | } |
580 | 569 | ||
581 | cs4271->gpio_nreset = gpio_nreset; | ||
582 | |||
583 | ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, | 570 | ret = regmap_update_bits(cs4271->regmap, CS4271_MODE2, |
584 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN, | 571 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN, |
585 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN); | 572 | CS4271_MODE2_PDN | CS4271_MODE2_CPEN); |
@@ -625,6 +612,36 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4271 = { | |||
625 | .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), | 612 | .num_dapm_routes = ARRAY_SIZE(cs4271_dapm_routes), |
626 | }; | 613 | }; |
627 | 614 | ||
615 | static int cs4271_common_probe(struct device *dev, | ||
616 | struct cs4271_private **c) | ||
617 | { | ||
618 | struct cs4271_platform_data *cs4271plat = dev->platform_data; | ||
619 | struct cs4271_private *cs4271; | ||
620 | |||
621 | cs4271 = devm_kzalloc(dev, sizeof(*cs4271), GFP_KERNEL); | ||
622 | if (!cs4271) | ||
623 | return -ENOMEM; | ||
624 | |||
625 | if (of_match_device(cs4271_dt_ids, dev)) | ||
626 | cs4271->gpio_nreset = | ||
627 | of_get_named_gpio(dev->of_node, "reset-gpio", 0); | ||
628 | |||
629 | if (cs4271plat) | ||
630 | cs4271->gpio_nreset = cs4271plat->gpio_nreset; | ||
631 | |||
632 | if (gpio_is_valid(cs4271->gpio_nreset)) { | ||
633 | int ret; | ||
634 | |||
635 | ret = devm_gpio_request(dev, cs4271->gpio_nreset, | ||
636 | "CS4271 Reset"); | ||
637 | if (ret < 0) | ||
638 | return ret; | ||
639 | } | ||
640 | |||
641 | *c = cs4271; | ||
642 | return 0; | ||
643 | } | ||
644 | |||
628 | #if defined(CONFIG_SPI_MASTER) | 645 | #if defined(CONFIG_SPI_MASTER) |
629 | 646 | ||
630 | static const struct regmap_config cs4271_spi_regmap = { | 647 | static const struct regmap_config cs4271_spi_regmap = { |
@@ -644,10 +661,11 @@ static const struct regmap_config cs4271_spi_regmap = { | |||
644 | static int cs4271_spi_probe(struct spi_device *spi) | 661 | static int cs4271_spi_probe(struct spi_device *spi) |
645 | { | 662 | { |
646 | struct cs4271_private *cs4271; | 663 | struct cs4271_private *cs4271; |
664 | int ret; | ||
647 | 665 | ||
648 | cs4271 = devm_kzalloc(&spi->dev, sizeof(*cs4271), GFP_KERNEL); | 666 | ret = cs4271_common_probe(&spi->dev, &cs4271); |
649 | if (!cs4271) | 667 | if (ret < 0) |
650 | return -ENOMEM; | 668 | return ret; |
651 | 669 | ||
652 | spi_set_drvdata(spi, cs4271); | 670 | spi_set_drvdata(spi, cs4271); |
653 | cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); | 671 | cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap); |
@@ -698,10 +716,11 @@ static int cs4271_i2c_probe(struct i2c_client *client, | |||
698 | const struct i2c_device_id *id) | 716 | const struct i2c_device_id *id) |
699 | { | 717 | { |
700 | struct cs4271_private *cs4271; | 718 | struct cs4271_private *cs4271; |
719 | int ret; | ||
701 | 720 | ||
702 | cs4271 = devm_kzalloc(&client->dev, sizeof(*cs4271), GFP_KERNEL); | 721 | ret = cs4271_common_probe(&client->dev, &cs4271); |
703 | if (!cs4271) | 722 | if (ret < 0) |
704 | return -ENOMEM; | 723 | return ret; |
705 | 724 | ||
706 | i2c_set_clientdata(client, cs4271); | 725 | i2c_set_clientdata(client, cs4271); |
707 | cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); | 726 | cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap); |
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 6e9ea8379a91..3eab46020a30 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/pcm_params.h> | 30 | #include <sound/pcm_params.h> |
31 | #include <sound/pcm.h> | 31 | #include <sound/pcm.h> |
32 | #include <linux/i2c.h> | 32 | #include <linux/i2c.h> |
33 | #include <linux/regmap.h> | ||
33 | 34 | ||
34 | #include "cs42l51.h" | 35 | #include "cs42l51.h" |
35 | 36 | ||
@@ -40,7 +41,6 @@ enum master_slave_mode { | |||
40 | }; | 41 | }; |
41 | 42 | ||
42 | struct cs42l51_private { | 43 | struct cs42l51_private { |
43 | enum snd_soc_control_type control_type; | ||
44 | unsigned int mclk; | 44 | unsigned int mclk; |
45 | unsigned int audio_mode; /* The mode (I2S or left-justified) */ | 45 | unsigned int audio_mode; /* The mode (I2S or left-justified) */ |
46 | enum master_slave_mode func; | 46 | enum master_slave_mode func; |
@@ -52,24 +52,6 @@ struct cs42l51_private { | |||
52 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ | 52 | SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ |
53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) | 53 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) |
54 | 54 | ||
55 | static int cs42l51_fill_cache(struct snd_soc_codec *codec) | ||
56 | { | ||
57 | u8 *cache = codec->reg_cache + 1; | ||
58 | struct i2c_client *i2c_client = to_i2c_client(codec->dev); | ||
59 | s32 length; | ||
60 | |||
61 | length = i2c_smbus_read_i2c_block_data(i2c_client, | ||
62 | CS42L51_FIRSTREG | 0x80, CS42L51_NUMREGS, cache); | ||
63 | if (length != CS42L51_NUMREGS) { | ||
64 | dev_err(&i2c_client->dev, | ||
65 | "I2C read failure, addr=0x%x (ret=%d vs %d)\n", | ||
66 | i2c_client->addr, length, CS42L51_NUMREGS); | ||
67 | return -EIO; | ||
68 | } | ||
69 | |||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, | 55 | static int cs42l51_get_chan_mix(struct snd_kcontrol *kcontrol, |
74 | struct snd_ctl_elem_value *ucontrol) | 56 | struct snd_ctl_elem_value *ucontrol) |
75 | { | 57 | { |
@@ -505,16 +487,9 @@ static struct snd_soc_dai_driver cs42l51_dai = { | |||
505 | 487 | ||
506 | static int cs42l51_probe(struct snd_soc_codec *codec) | 488 | static int cs42l51_probe(struct snd_soc_codec *codec) |
507 | { | 489 | { |
508 | struct cs42l51_private *cs42l51 = snd_soc_codec_get_drvdata(codec); | ||
509 | int ret, reg; | 490 | int ret, reg; |
510 | 491 | ||
511 | ret = cs42l51_fill_cache(codec); | 492 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP); |
512 | if (ret < 0) { | ||
513 | dev_err(codec->dev, "failed to fill register cache\n"); | ||
514 | return ret; | ||
515 | } | ||
516 | |||
517 | ret = snd_soc_codec_set_cache_io(codec, 8, 8, cs42l51->control_type); | ||
518 | if (ret < 0) { | 493 | if (ret < 0) { |
519 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); | 494 | dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret); |
520 | return ret; | 495 | return ret; |
@@ -538,8 +513,6 @@ static int cs42l51_probe(struct snd_soc_codec *codec) | |||
538 | 513 | ||
539 | static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { | 514 | static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { |
540 | .probe = cs42l51_probe, | 515 | .probe = cs42l51_probe, |
541 | .reg_cache_size = CS42L51_NUMREGS + 1, | ||
542 | .reg_word_size = sizeof(u8), | ||
543 | 516 | ||
544 | .controls = cs42l51_snd_controls, | 517 | .controls = cs42l51_snd_controls, |
545 | .num_controls = ARRAY_SIZE(cs42l51_snd_controls), | 518 | .num_controls = ARRAY_SIZE(cs42l51_snd_controls), |
@@ -549,38 +522,53 @@ static struct snd_soc_codec_driver soc_codec_device_cs42l51 = { | |||
549 | .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), | 522 | .num_dapm_routes = ARRAY_SIZE(cs42l51_routes), |
550 | }; | 523 | }; |
551 | 524 | ||
525 | static const struct regmap_config cs42l51_regmap = { | ||
526 | .reg_bits = 8, | ||
527 | .val_bits = 8, | ||
528 | |||
529 | .max_register = CS42L51_CHARGE_FREQ, | ||
530 | .cache_type = REGCACHE_RBTREE, | ||
531 | }; | ||
532 | |||
552 | static int cs42l51_i2c_probe(struct i2c_client *i2c_client, | 533 | static int cs42l51_i2c_probe(struct i2c_client *i2c_client, |
553 | const struct i2c_device_id *id) | 534 | const struct i2c_device_id *id) |
554 | { | 535 | { |
555 | struct cs42l51_private *cs42l51; | 536 | struct cs42l51_private *cs42l51; |
537 | struct regmap *regmap; | ||
538 | unsigned int val; | ||
556 | int ret; | 539 | int ret; |
557 | 540 | ||
541 | regmap = devm_regmap_init_i2c(i2c_client, &cs42l51_regmap); | ||
542 | if (IS_ERR(regmap)) { | ||
543 | ret = PTR_ERR(regmap); | ||
544 | dev_err(&i2c_client->dev, "Failed to create regmap: %d\n", | ||
545 | ret); | ||
546 | return ret; | ||
547 | } | ||
548 | |||
558 | /* Verify that we have a CS42L51 */ | 549 | /* Verify that we have a CS42L51 */ |
559 | ret = i2c_smbus_read_byte_data(i2c_client, CS42L51_CHIP_REV_ID); | 550 | ret = regmap_read(regmap, CS42L51_CHIP_REV_ID, &val); |
560 | if (ret < 0) { | 551 | if (ret < 0) { |
561 | dev_err(&i2c_client->dev, "failed to read I2C\n"); | 552 | dev_err(&i2c_client->dev, "failed to read I2C\n"); |
562 | goto error; | 553 | goto error; |
563 | } | 554 | } |
564 | 555 | ||
565 | if ((ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && | 556 | if ((val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_A)) && |
566 | (ret != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { | 557 | (val != CS42L51_MK_CHIP_REV(CS42L51_CHIP_ID, CS42L51_CHIP_REV_B))) { |
567 | dev_err(&i2c_client->dev, "Invalid chip id\n"); | 558 | dev_err(&i2c_client->dev, "Invalid chip id: %x\n", val); |
568 | ret = -ENODEV; | 559 | ret = -ENODEV; |
569 | goto error; | 560 | goto error; |
570 | } | 561 | } |
571 | 562 | ||
572 | dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", | 563 | dev_info(&i2c_client->dev, "found device cs42l51 rev %d\n", |
573 | ret & 7); | 564 | val & 7); |
574 | 565 | ||
575 | cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), | 566 | cs42l51 = devm_kzalloc(&i2c_client->dev, sizeof(struct cs42l51_private), |
576 | GFP_KERNEL); | 567 | GFP_KERNEL); |
577 | if (!cs42l51) { | 568 | if (!cs42l51) |
578 | dev_err(&i2c_client->dev, "could not allocate codec\n"); | ||
579 | return -ENOMEM; | 569 | return -ENOMEM; |
580 | } | ||
581 | 570 | ||
582 | i2c_set_clientdata(i2c_client, cs42l51); | 571 | i2c_set_clientdata(i2c_client, cs42l51); |
583 | cs42l51->control_type = SND_SOC_I2C; | ||
584 | 572 | ||
585 | ret = snd_soc_register_codec(&i2c_client->dev, | 573 | ret = snd_soc_register_codec(&i2c_client->dev, |
586 | &soc_codec_device_cs42l51, &cs42l51_dai, 1); | 574 | &soc_codec_device_cs42l51, &cs42l51_dai, 1); |
@@ -600,10 +588,17 @@ static const struct i2c_device_id cs42l51_id[] = { | |||
600 | }; | 588 | }; |
601 | MODULE_DEVICE_TABLE(i2c, cs42l51_id); | 589 | MODULE_DEVICE_TABLE(i2c, cs42l51_id); |
602 | 590 | ||
591 | static const struct of_device_id cs42l51_of_match[] = { | ||
592 | { .compatible = "cirrus,cs42l51", }, | ||
593 | { } | ||
594 | }; | ||
595 | MODULE_DEVICE_TABLE(of, cs42l51_of_match); | ||
596 | |||
603 | static struct i2c_driver cs42l51_i2c_driver = { | 597 | static struct i2c_driver cs42l51_i2c_driver = { |
604 | .driver = { | 598 | .driver = { |
605 | .name = "cs42l51-codec", | 599 | .name = "cs42l51-codec", |
606 | .owner = THIS_MODULE, | 600 | .owner = THIS_MODULE, |
601 | .of_match_table = cs42l51_of_match, | ||
607 | }, | 602 | }, |
608 | .id_table = cs42l51_id, | 603 | .id_table = cs42l51_id, |
609 | .probe = cs42l51_i2c_probe, | 604 | .probe = cs42l51_i2c_probe, |
diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 0bac6d5a4ac8..be455ea5f2fe 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c | |||
@@ -210,13 +210,11 @@ static const char * const cs42l52_adca_text[] = { | |||
210 | static const char * const cs42l52_adcb_text[] = { | 210 | static const char * const cs42l52_adcb_text[] = { |
211 | "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"}; | 211 | "Input1B", "Input2B", "Input3B", "Input4B", "PGA Input Right"}; |
212 | 212 | ||
213 | static const struct soc_enum adca_enum = | 213 | static SOC_ENUM_SINGLE_DECL(adca_enum, |
214 | SOC_ENUM_SINGLE(CS42L52_ADC_PGA_A, 5, | 214 | CS42L52_ADC_PGA_A, 5, cs42l52_adca_text); |
215 | ARRAY_SIZE(cs42l52_adca_text), cs42l52_adca_text); | ||
216 | 215 | ||
217 | static const struct soc_enum adcb_enum = | 216 | static SOC_ENUM_SINGLE_DECL(adcb_enum, |
218 | SOC_ENUM_SINGLE(CS42L52_ADC_PGA_B, 5, | 217 | CS42L52_ADC_PGA_B, 5, cs42l52_adcb_text); |
219 | ARRAY_SIZE(cs42l52_adcb_text), cs42l52_adcb_text); | ||
220 | 218 | ||
221 | static const struct snd_kcontrol_new adca_mux = | 219 | static const struct snd_kcontrol_new adca_mux = |
222 | SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum); | 220 | SOC_DAPM_ENUM("Left ADC Input Capture Mux", adca_enum); |
@@ -229,26 +227,22 @@ static const char * const mic_bias_level_text[] = { | |||
229 | "0.8 +VA", "0.83 +VA", "0.91 +VA" | 227 | "0.8 +VA", "0.83 +VA", "0.91 +VA" |
230 | }; | 228 | }; |
231 | 229 | ||
232 | static const struct soc_enum mic_bias_level_enum = | 230 | static SOC_ENUM_SINGLE_DECL(mic_bias_level_enum, |
233 | SOC_ENUM_SINGLE(CS42L52_IFACE_CTL2, 0, | 231 | CS42L52_IFACE_CTL2, 0, mic_bias_level_text); |
234 | ARRAY_SIZE(mic_bias_level_text), mic_bias_level_text); | ||
235 | 232 | ||
236 | static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; | 233 | static const char * const cs42l52_mic_text[] = { "MIC1", "MIC2" }; |
237 | 234 | ||
238 | static const struct soc_enum mica_enum = | 235 | static SOC_ENUM_SINGLE_DECL(mica_enum, |
239 | SOC_ENUM_SINGLE(CS42L52_MICA_CTL, 5, | 236 | CS42L52_MICA_CTL, 5, cs42l52_mic_text); |
240 | ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); | ||
241 | 237 | ||
242 | static const struct soc_enum micb_enum = | 238 | static SOC_ENUM_SINGLE_DECL(micb_enum, |
243 | SOC_ENUM_SINGLE(CS42L52_MICB_CTL, 5, | 239 | CS42L52_MICB_CTL, 5, cs42l52_mic_text); |
244 | ARRAY_SIZE(cs42l52_mic_text), cs42l52_mic_text); | ||
245 | 240 | ||
246 | static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; | 241 | static const char * const digital_output_mux_text[] = {"ADC", "DSP"}; |
247 | 242 | ||
248 | static const struct soc_enum digital_output_mux_enum = | 243 | static SOC_ENUM_SINGLE_DECL(digital_output_mux_enum, |
249 | SOC_ENUM_SINGLE(CS42L52_ADC_MISC_CTL, 6, | 244 | CS42L52_ADC_MISC_CTL, 6, |
250 | ARRAY_SIZE(digital_output_mux_text), | 245 | digital_output_mux_text); |
251 | digital_output_mux_text); | ||
252 | 246 | ||
253 | static const struct snd_kcontrol_new digital_output_mux = | 247 | static const struct snd_kcontrol_new digital_output_mux = |
254 | SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum); | 248 | SOC_DAPM_ENUM("Digital Output Mux", digital_output_mux_enum); |
@@ -258,18 +252,18 @@ static const char * const hp_gain_num_text[] = { | |||
258 | "0.7099", "0.8399", "1.000", "1.1430" | 252 | "0.7099", "0.8399", "1.000", "1.1430" |
259 | }; | 253 | }; |
260 | 254 | ||
261 | static const struct soc_enum hp_gain_enum = | 255 | static SOC_ENUM_SINGLE_DECL(hp_gain_enum, |
262 | SOC_ENUM_SINGLE(CS42L52_PB_CTL1, 5, | 256 | CS42L52_PB_CTL1, 5, |
263 | ARRAY_SIZE(hp_gain_num_text), hp_gain_num_text); | 257 | hp_gain_num_text); |
264 | 258 | ||
265 | static const char * const beep_pitch_text[] = { | 259 | static const char * const beep_pitch_text[] = { |
266 | "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", | 260 | "C4", "C5", "D5", "E5", "F5", "G5", "A5", "B5", |
267 | "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" | 261 | "C6", "D6", "E6", "F6", "G6", "A6", "B6", "C7" |
268 | }; | 262 | }; |
269 | 263 | ||
270 | static const struct soc_enum beep_pitch_enum = | 264 | static SOC_ENUM_SINGLE_DECL(beep_pitch_enum, |
271 | SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 4, | 265 | CS42L52_BEEP_FREQ, 4, |
272 | ARRAY_SIZE(beep_pitch_text), beep_pitch_text); | 266 | beep_pitch_text); |
273 | 267 | ||
274 | static const char * const beep_ontime_text[] = { | 268 | static const char * const beep_ontime_text[] = { |
275 | "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", | 269 | "86 ms", "430 ms", "780 ms", "1.20 s", "1.50 s", |
@@ -277,66 +271,66 @@ static const char * const beep_ontime_text[] = { | |||
277 | "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" | 271 | "3.50 s", "3.80 s", "4.20 s", "4.50 s", "4.80 s", "5.20 s" |
278 | }; | 272 | }; |
279 | 273 | ||
280 | static const struct soc_enum beep_ontime_enum = | 274 | static SOC_ENUM_SINGLE_DECL(beep_ontime_enum, |
281 | SOC_ENUM_SINGLE(CS42L52_BEEP_FREQ, 0, | 275 | CS42L52_BEEP_FREQ, 0, |
282 | ARRAY_SIZE(beep_ontime_text), beep_ontime_text); | 276 | beep_ontime_text); |
283 | 277 | ||
284 | static const char * const beep_offtime_text[] = { | 278 | static const char * const beep_offtime_text[] = { |
285 | "1.23 s", "2.58 s", "3.90 s", "5.20 s", | 279 | "1.23 s", "2.58 s", "3.90 s", "5.20 s", |
286 | "6.60 s", "8.05 s", "9.35 s", "10.80 s" | 280 | "6.60 s", "8.05 s", "9.35 s", "10.80 s" |
287 | }; | 281 | }; |
288 | 282 | ||
289 | static const struct soc_enum beep_offtime_enum = | 283 | static SOC_ENUM_SINGLE_DECL(beep_offtime_enum, |
290 | SOC_ENUM_SINGLE(CS42L52_BEEP_VOL, 5, | 284 | CS42L52_BEEP_VOL, 5, |
291 | ARRAY_SIZE(beep_offtime_text), beep_offtime_text); | 285 | beep_offtime_text); |
292 | 286 | ||
293 | static const char * const beep_config_text[] = { | 287 | static const char * const beep_config_text[] = { |
294 | "Off", "Single", "Multiple", "Continuous" | 288 | "Off", "Single", "Multiple", "Continuous" |
295 | }; | 289 | }; |
296 | 290 | ||
297 | static const struct soc_enum beep_config_enum = | 291 | static SOC_ENUM_SINGLE_DECL(beep_config_enum, |
298 | SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 6, | 292 | CS42L52_BEEP_TONE_CTL, 6, |
299 | ARRAY_SIZE(beep_config_text), beep_config_text); | 293 | beep_config_text); |
300 | 294 | ||
301 | static const char * const beep_bass_text[] = { | 295 | static const char * const beep_bass_text[] = { |
302 | "50 Hz", "100 Hz", "200 Hz", "250 Hz" | 296 | "50 Hz", "100 Hz", "200 Hz", "250 Hz" |
303 | }; | 297 | }; |
304 | 298 | ||
305 | static const struct soc_enum beep_bass_enum = | 299 | static SOC_ENUM_SINGLE_DECL(beep_bass_enum, |
306 | SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 1, | 300 | CS42L52_BEEP_TONE_CTL, 1, |
307 | ARRAY_SIZE(beep_bass_text), beep_bass_text); | 301 | beep_bass_text); |
308 | 302 | ||
309 | static const char * const beep_treble_text[] = { | 303 | static const char * const beep_treble_text[] = { |
310 | "5 kHz", "7 kHz", "10 kHz", " 15 kHz" | 304 | "5 kHz", "7 kHz", "10 kHz", " 15 kHz" |
311 | }; | 305 | }; |
312 | 306 | ||
313 | static const struct soc_enum beep_treble_enum = | 307 | static SOC_ENUM_SINGLE_DECL(beep_treble_enum, |
314 | SOC_ENUM_SINGLE(CS42L52_BEEP_TONE_CTL, 3, | 308 | CS42L52_BEEP_TONE_CTL, 3, |
315 | ARRAY_SIZE(beep_treble_text), beep_treble_text); | 309 | beep_treble_text); |
316 | 310 | ||
317 | static const char * const ng_threshold_text[] = { | 311 | static const char * const ng_threshold_text[] = { |
318 | "-34dB", "-37dB", "-40dB", "-43dB", | 312 | "-34dB", "-37dB", "-40dB", "-43dB", |
319 | "-46dB", "-52dB", "-58dB", "-64dB" | 313 | "-46dB", "-52dB", "-58dB", "-64dB" |
320 | }; | 314 | }; |
321 | 315 | ||
322 | static const struct soc_enum ng_threshold_enum = | 316 | static SOC_ENUM_SINGLE_DECL(ng_threshold_enum, |
323 | SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 2, | 317 | CS42L52_NOISE_GATE_CTL, 2, |
324 | ARRAY_SIZE(ng_threshold_text), ng_threshold_text); | 318 | ng_threshold_text); |
325 | 319 | ||
326 | static const char * const cs42l52_ng_delay_text[] = { | 320 | static const char * const cs42l52_ng_delay_text[] = { |
327 | "50ms", "100ms", "150ms", "200ms"}; | 321 | "50ms", "100ms", "150ms", "200ms"}; |
328 | 322 | ||
329 | static const struct soc_enum ng_delay_enum = | 323 | static SOC_ENUM_SINGLE_DECL(ng_delay_enum, |
330 | SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 0, | 324 | CS42L52_NOISE_GATE_CTL, 0, |
331 | ARRAY_SIZE(cs42l52_ng_delay_text), cs42l52_ng_delay_text); | 325 | cs42l52_ng_delay_text); |
332 | 326 | ||
333 | static const char * const cs42l52_ng_type_text[] = { | 327 | static const char * const cs42l52_ng_type_text[] = { |
334 | "Apply Specific", "Apply All" | 328 | "Apply Specific", "Apply All" |
335 | }; | 329 | }; |
336 | 330 | ||
337 | static const struct soc_enum ng_type_enum = | 331 | static SOC_ENUM_SINGLE_DECL(ng_type_enum, |
338 | SOC_ENUM_SINGLE(CS42L52_NOISE_GATE_CTL, 6, | 332 | CS42L52_NOISE_GATE_CTL, 6, |
339 | ARRAY_SIZE(cs42l52_ng_type_text), cs42l52_ng_type_text); | 333 | cs42l52_ng_type_text); |
340 | 334 | ||
341 | static const char * const left_swap_text[] = { | 335 | static const char * const left_swap_text[] = { |
342 | "Left", "LR 2", "Right"}; | 336 | "Left", "LR 2", "Right"}; |
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 549d5d6a3fef..06f429184821 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c | |||
@@ -278,13 +278,13 @@ static const DECLARE_TLV_DB_SCALE(attn_tlv, -6300, 100, 1); | |||
278 | static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" }; | 278 | static const char * const cs42l73_pgaa_text[] = { "Line A", "Mic 1" }; |
279 | static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" }; | 279 | static const char * const cs42l73_pgab_text[] = { "Line B", "Mic 2" }; |
280 | 280 | ||
281 | static const struct soc_enum pgaa_enum = | 281 | static SOC_ENUM_SINGLE_DECL(pgaa_enum, |
282 | SOC_ENUM_SINGLE(CS42L73_ADCIPC, 3, | 282 | CS42L73_ADCIPC, 3, |
283 | ARRAY_SIZE(cs42l73_pgaa_text), cs42l73_pgaa_text); | 283 | cs42l73_pgaa_text); |
284 | 284 | ||
285 | static const struct soc_enum pgab_enum = | 285 | static SOC_ENUM_SINGLE_DECL(pgab_enum, |
286 | SOC_ENUM_SINGLE(CS42L73_ADCIPC, 7, | 286 | CS42L73_ADCIPC, 7, |
287 | ARRAY_SIZE(cs42l73_pgab_text), cs42l73_pgab_text); | 287 | cs42l73_pgab_text); |
288 | 288 | ||
289 | static const struct snd_kcontrol_new pgaa_mux = | 289 | static const struct snd_kcontrol_new pgaa_mux = |
290 | SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); | 290 | SOC_DAPM_ENUM("Left Analog Input Capture Mux", pgaa_enum); |
@@ -309,9 +309,9 @@ static const struct snd_kcontrol_new input_right_mixer[] = { | |||
309 | static const char * const cs42l73_ng_delay_text[] = { | 309 | static const char * const cs42l73_ng_delay_text[] = { |
310 | "50ms", "100ms", "150ms", "200ms" }; | 310 | "50ms", "100ms", "150ms", "200ms" }; |
311 | 311 | ||
312 | static const struct soc_enum ng_delay_enum = | 312 | static SOC_ENUM_SINGLE_DECL(ng_delay_enum, |
313 | SOC_ENUM_SINGLE(CS42L73_NGCAB, 0, | 313 | CS42L73_NGCAB, 0, |
314 | ARRAY_SIZE(cs42l73_ng_delay_text), cs42l73_ng_delay_text); | 314 | cs42l73_ng_delay_text); |
315 | 315 | ||
316 | static const char * const cs42l73_mono_mix_texts[] = { | 316 | static const char * const cs42l73_mono_mix_texts[] = { |
317 | "Left", "Right", "Mono Mix"}; | 317 | "Left", "Right", "Mono Mix"}; |
@@ -357,19 +357,19 @@ static const struct snd_kcontrol_new esl_xsp_mixer = | |||
357 | static const char * const cs42l73_ip_swap_text[] = { | 357 | static const char * const cs42l73_ip_swap_text[] = { |
358 | "Stereo", "Mono A", "Mono B", "Swap A-B"}; | 358 | "Stereo", "Mono A", "Mono B", "Swap A-B"}; |
359 | 359 | ||
360 | static const struct soc_enum ip_swap_enum = | 360 | static SOC_ENUM_SINGLE_DECL(ip_swap_enum, |
361 | SOC_ENUM_SINGLE(CS42L73_MIOPC, 6, | 361 | CS42L73_MIOPC, 6, |
362 | ARRAY_SIZE(cs42l73_ip_swap_text), cs42l73_ip_swap_text); | 362 | cs42l73_ip_swap_text); |
363 | 363 | ||
364 | static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"}; | 364 | static const char * const cs42l73_spo_mixer_text[] = {"Mono", "Stereo"}; |
365 | 365 | ||
366 | static const struct soc_enum vsp_output_mux_enum = | 366 | static SOC_ENUM_SINGLE_DECL(vsp_output_mux_enum, |
367 | SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 5, | 367 | CS42L73_MIXERCTL, 5, |
368 | ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); | 368 | cs42l73_spo_mixer_text); |
369 | 369 | ||
370 | static const struct soc_enum xsp_output_mux_enum = | 370 | static SOC_ENUM_SINGLE_DECL(xsp_output_mux_enum, |
371 | SOC_ENUM_SINGLE(CS42L73_MIXERCTL, 4, | 371 | CS42L73_MIXERCTL, 4, |
372 | ARRAY_SIZE(cs42l73_spo_mixer_text), cs42l73_spo_mixer_text); | 372 | cs42l73_spo_mixer_text); |
373 | 373 | ||
374 | static const struct snd_kcontrol_new vsp_output_mux = | 374 | static const struct snd_kcontrol_new vsp_output_mux = |
375 | SOC_DAPM_ENUM("Route", vsp_output_mux_enum); | 375 | SOC_DAPM_ENUM("Route", vsp_output_mux_enum); |
@@ -1108,7 +1108,7 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) | |||
1108 | return 0; | 1108 | return 0; |
1109 | } | 1109 | } |
1110 | 1110 | ||
1111 | static u32 cs42l73_asrc_rates[] = { | 1111 | static const unsigned int cs42l73_asrc_rates[] = { |
1112 | 8000, 11025, 12000, 16000, 22050, | 1112 | 8000, 11025, 12000, 16000, 22050, |
1113 | 24000, 32000, 44100, 48000 | 1113 | 24000, 32000, 44100, 48000 |
1114 | }; | 1114 | }; |
@@ -1241,7 +1241,7 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate) | |||
1241 | 0x7F, tristate << 7); | 1241 | 0x7F, tristate << 7); |
1242 | } | 1242 | } |
1243 | 1243 | ||
1244 | static struct snd_pcm_hw_constraint_list constraints_12_24 = { | 1244 | static const struct snd_pcm_hw_constraint_list constraints_12_24 = { |
1245 | .count = ARRAY_SIZE(cs42l73_asrc_rates), | 1245 | .count = ARRAY_SIZE(cs42l73_asrc_rates), |
1246 | .list = cs42l73_asrc_rates, | 1246 | .list = cs42l73_asrc_rates, |
1247 | }; | 1247 | }; |
@@ -1255,9 +1255,6 @@ static int cs42l73_pcm_startup(struct snd_pcm_substream *substream, | |||
1255 | return 0; | 1255 | return 0; |
1256 | } | 1256 | } |
1257 | 1257 | ||
1258 | /* SNDRV_PCM_RATE_KNOT -> 12000, 24000 Hz, limit with constraint list */ | ||
1259 | #define CS42L73_RATES (SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_KNOT) | ||
1260 | |||
1261 | 1258 | ||
1262 | #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ | 1259 | #define CS42L73_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ |
1263 | SNDRV_PCM_FMTBIT_S24_LE) | 1260 | SNDRV_PCM_FMTBIT_S24_LE) |
@@ -1278,14 +1275,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
1278 | .stream_name = "XSP Playback", | 1275 | .stream_name = "XSP Playback", |
1279 | .channels_min = 1, | 1276 | .channels_min = 1, |
1280 | .channels_max = 2, | 1277 | .channels_max = 2, |
1281 | .rates = CS42L73_RATES, | 1278 | .rates = SNDRV_PCM_RATE_KNOT, |
1282 | .formats = CS42L73_FORMATS, | 1279 | .formats = CS42L73_FORMATS, |
1283 | }, | 1280 | }, |
1284 | .capture = { | 1281 | .capture = { |
1285 | .stream_name = "XSP Capture", | 1282 | .stream_name = "XSP Capture", |
1286 | .channels_min = 1, | 1283 | .channels_min = 1, |
1287 | .channels_max = 2, | 1284 | .channels_max = 2, |
1288 | .rates = CS42L73_RATES, | 1285 | .rates = SNDRV_PCM_RATE_KNOT, |
1289 | .formats = CS42L73_FORMATS, | 1286 | .formats = CS42L73_FORMATS, |
1290 | }, | 1287 | }, |
1291 | .ops = &cs42l73_ops, | 1288 | .ops = &cs42l73_ops, |
@@ -1298,14 +1295,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
1298 | .stream_name = "ASP Playback", | 1295 | .stream_name = "ASP Playback", |
1299 | .channels_min = 2, | 1296 | .channels_min = 2, |
1300 | .channels_max = 2, | 1297 | .channels_max = 2, |
1301 | .rates = CS42L73_RATES, | 1298 | .rates = SNDRV_PCM_RATE_KNOT, |
1302 | .formats = CS42L73_FORMATS, | 1299 | .formats = CS42L73_FORMATS, |
1303 | }, | 1300 | }, |
1304 | .capture = { | 1301 | .capture = { |
1305 | .stream_name = "ASP Capture", | 1302 | .stream_name = "ASP Capture", |
1306 | .channels_min = 2, | 1303 | .channels_min = 2, |
1307 | .channels_max = 2, | 1304 | .channels_max = 2, |
1308 | .rates = CS42L73_RATES, | 1305 | .rates = SNDRV_PCM_RATE_KNOT, |
1309 | .formats = CS42L73_FORMATS, | 1306 | .formats = CS42L73_FORMATS, |
1310 | }, | 1307 | }, |
1311 | .ops = &cs42l73_ops, | 1308 | .ops = &cs42l73_ops, |
@@ -1318,14 +1315,14 @@ static struct snd_soc_dai_driver cs42l73_dai[] = { | |||
1318 | .stream_name = "VSP Playback", | 1315 | .stream_name = "VSP Playback", |
1319 | .channels_min = 1, | 1316 | .channels_min = 1, |
1320 | .channels_max = 2, | 1317 | .channels_max = 2, |
1321 | .rates = CS42L73_RATES, | 1318 | .rates = SNDRV_PCM_RATE_KNOT, |
1322 | .formats = CS42L73_FORMATS, | 1319 | .formats = CS42L73_FORMATS, |
1323 | }, | 1320 | }, |
1324 | .capture = { | 1321 | .capture = { |
1325 | .stream_name = "VSP Capture", | 1322 | .stream_name = "VSP Capture", |
1326 | .channels_min = 1, | 1323 | .channels_min = 1, |
1327 | .channels_max = 2, | 1324 | .channels_max = 2, |
1328 | .rates = CS42L73_RATES, | 1325 | .rates = SNDRV_PCM_RATE_KNOT, |
1329 | .formats = CS42L73_FORMATS, | 1326 | .formats = CS42L73_FORMATS, |
1330 | }, | 1327 | }, |
1331 | .ops = &cs42l73_ops, | 1328 | .ops = &cs42l73_ops, |
diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index e62e294a8033..01e55fc72307 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c | |||
@@ -307,29 +307,29 @@ static const char * const da7210_hpf_cutoff_txt[] = { | |||
307 | "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi" | 307 | "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi" |
308 | }; | 308 | }; |
309 | 309 | ||
310 | static const struct soc_enum da7210_dac_hpf_cutoff = | 310 | static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff, |
311 | SOC_ENUM_SINGLE(DA7210_DAC_HPF, 0, 4, da7210_hpf_cutoff_txt); | 311 | DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt); |
312 | 312 | ||
313 | static const struct soc_enum da7210_adc_hpf_cutoff = | 313 | static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff, |
314 | SOC_ENUM_SINGLE(DA7210_ADC_HPF, 0, 4, da7210_hpf_cutoff_txt); | 314 | DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt); |
315 | 315 | ||
316 | /* ADC and DAC voice (8kHz) high pass cutoff value */ | 316 | /* ADC and DAC voice (8kHz) high pass cutoff value */ |
317 | static const char * const da7210_vf_cutoff_txt[] = { | 317 | static const char * const da7210_vf_cutoff_txt[] = { |
318 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 318 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
319 | }; | 319 | }; |
320 | 320 | ||
321 | static const struct soc_enum da7210_dac_vf_cutoff = | 321 | static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff, |
322 | SOC_ENUM_SINGLE(DA7210_DAC_HPF, 4, 8, da7210_vf_cutoff_txt); | 322 | DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt); |
323 | 323 | ||
324 | static const struct soc_enum da7210_adc_vf_cutoff = | 324 | static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff, |
325 | SOC_ENUM_SINGLE(DA7210_ADC_HPF, 4, 8, da7210_vf_cutoff_txt); | 325 | DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt); |
326 | 326 | ||
327 | static const char *da7210_hp_mode_txt[] = { | 327 | static const char *da7210_hp_mode_txt[] = { |
328 | "Class H", "Class G" | 328 | "Class H", "Class G" |
329 | }; | 329 | }; |
330 | 330 | ||
331 | static const struct soc_enum da7210_hp_mode_sel = | 331 | static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, |
332 | SOC_ENUM_SINGLE(DA7210_HP_CFG, 0, 2, da7210_hp_mode_txt); | 332 | DA7210_HP_CFG, 0, da7210_hp_mode_txt); |
333 | 333 | ||
334 | /* ALC can be enabled only if noise suppression is disabled */ | 334 | /* ALC can be enabled only if noise suppression is disabled */ |
335 | static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, | 335 | static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, |
diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 0c77e7ad7423..439d10387f10 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c | |||
@@ -63,30 +63,30 @@ static const char * const da7213_voice_hpf_corner_txt[] = { | |||
63 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 63 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
64 | }; | 64 | }; |
65 | 65 | ||
66 | static const struct soc_enum da7213_dac_voice_hpf_corner = | 66 | static SOC_ENUM_SINGLE_DECL(da7213_dac_voice_hpf_corner, |
67 | SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, | 67 | DA7213_DAC_FILTERS1, |
68 | DA7213_VOICE_HPF_CORNER_MAX, | 68 | DA7213_VOICE_HPF_CORNER_SHIFT, |
69 | da7213_voice_hpf_corner_txt); | 69 | da7213_voice_hpf_corner_txt); |
70 | 70 | ||
71 | static const struct soc_enum da7213_adc_voice_hpf_corner = | 71 | static SOC_ENUM_SINGLE_DECL(da7213_adc_voice_hpf_corner, |
72 | SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_VOICE_HPF_CORNER_SHIFT, | 72 | DA7213_ADC_FILTERS1, |
73 | DA7213_VOICE_HPF_CORNER_MAX, | 73 | DA7213_VOICE_HPF_CORNER_SHIFT, |
74 | da7213_voice_hpf_corner_txt); | 74 | da7213_voice_hpf_corner_txt); |
75 | 75 | ||
76 | /* ADC and DAC high pass filter cutoff value */ | 76 | /* ADC and DAC high pass filter cutoff value */ |
77 | static const char * const da7213_audio_hpf_corner_txt[] = { | 77 | static const char * const da7213_audio_hpf_corner_txt[] = { |
78 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" | 78 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" |
79 | }; | 79 | }; |
80 | 80 | ||
81 | static const struct soc_enum da7213_dac_audio_hpf_corner = | 81 | static SOC_ENUM_SINGLE_DECL(da7213_dac_audio_hpf_corner, |
82 | SOC_ENUM_SINGLE(DA7213_DAC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, | 82 | DA7213_DAC_FILTERS1 |
83 | DA7213_AUDIO_HPF_CORNER_MAX, | 83 | , DA7213_AUDIO_HPF_CORNER_SHIFT, |
84 | da7213_audio_hpf_corner_txt); | 84 | da7213_audio_hpf_corner_txt); |
85 | 85 | ||
86 | static const struct soc_enum da7213_adc_audio_hpf_corner = | 86 | static SOC_ENUM_SINGLE_DECL(da7213_adc_audio_hpf_corner, |
87 | SOC_ENUM_SINGLE(DA7213_ADC_FILTERS1, DA7213_AUDIO_HPF_CORNER_SHIFT, | 87 | DA7213_ADC_FILTERS1, |
88 | DA7213_AUDIO_HPF_CORNER_MAX, | 88 | DA7213_AUDIO_HPF_CORNER_SHIFT, |
89 | da7213_audio_hpf_corner_txt); | 89 | da7213_audio_hpf_corner_txt); |
90 | 90 | ||
91 | /* Gain ramping rate value */ | 91 | /* Gain ramping rate value */ |
92 | static const char * const da7213_gain_ramp_rate_txt[] = { | 92 | static const char * const da7213_gain_ramp_rate_txt[] = { |
@@ -94,52 +94,50 @@ static const char * const da7213_gain_ramp_rate_txt[] = { | |||
94 | "nominal rate / 32" | 94 | "nominal rate / 32" |
95 | }; | 95 | }; |
96 | 96 | ||
97 | static const struct soc_enum da7213_gain_ramp_rate = | 97 | static SOC_ENUM_SINGLE_DECL(da7213_gain_ramp_rate, |
98 | SOC_ENUM_SINGLE(DA7213_GAIN_RAMP_CTRL, DA7213_GAIN_RAMP_RATE_SHIFT, | 98 | DA7213_GAIN_RAMP_CTRL, |
99 | DA7213_GAIN_RAMP_RATE_MAX, da7213_gain_ramp_rate_txt); | 99 | DA7213_GAIN_RAMP_RATE_SHIFT, |
100 | da7213_gain_ramp_rate_txt); | ||
100 | 101 | ||
101 | /* DAC noise gate setup time value */ | 102 | /* DAC noise gate setup time value */ |
102 | static const char * const da7213_dac_ng_setup_time_txt[] = { | 103 | static const char * const da7213_dac_ng_setup_time_txt[] = { |
103 | "256 samples", "512 samples", "1024 samples", "2048 samples" | 104 | "256 samples", "512 samples", "1024 samples", "2048 samples" |
104 | }; | 105 | }; |
105 | 106 | ||
106 | static const struct soc_enum da7213_dac_ng_setup_time = | 107 | static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_setup_time, |
107 | SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, | 108 | DA7213_DAC_NG_SETUP_TIME, |
108 | DA7213_DAC_NG_SETUP_TIME_SHIFT, | 109 | DA7213_DAC_NG_SETUP_TIME_SHIFT, |
109 | DA7213_DAC_NG_SETUP_TIME_MAX, | 110 | da7213_dac_ng_setup_time_txt); |
110 | da7213_dac_ng_setup_time_txt); | ||
111 | 111 | ||
112 | /* DAC noise gate rampup rate value */ | 112 | /* DAC noise gate rampup rate value */ |
113 | static const char * const da7213_dac_ng_rampup_txt[] = { | 113 | static const char * const da7213_dac_ng_rampup_txt[] = { |
114 | "0.02 ms/dB", "0.16 ms/dB" | 114 | "0.02 ms/dB", "0.16 ms/dB" |
115 | }; | 115 | }; |
116 | 116 | ||
117 | static const struct soc_enum da7213_dac_ng_rampup_rate = | 117 | static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampup_rate, |
118 | SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, | 118 | DA7213_DAC_NG_SETUP_TIME, |
119 | DA7213_DAC_NG_RAMPUP_RATE_SHIFT, | 119 | DA7213_DAC_NG_RAMPUP_RATE_SHIFT, |
120 | DA7213_DAC_NG_RAMP_RATE_MAX, | 120 | da7213_dac_ng_rampup_txt); |
121 | da7213_dac_ng_rampup_txt); | ||
122 | 121 | ||
123 | /* DAC noise gate rampdown rate value */ | 122 | /* DAC noise gate rampdown rate value */ |
124 | static const char * const da7213_dac_ng_rampdown_txt[] = { | 123 | static const char * const da7213_dac_ng_rampdown_txt[] = { |
125 | "0.64 ms/dB", "20.48 ms/dB" | 124 | "0.64 ms/dB", "20.48 ms/dB" |
126 | }; | 125 | }; |
127 | 126 | ||
128 | static const struct soc_enum da7213_dac_ng_rampdown_rate = | 127 | static SOC_ENUM_SINGLE_DECL(da7213_dac_ng_rampdown_rate, |
129 | SOC_ENUM_SINGLE(DA7213_DAC_NG_SETUP_TIME, | 128 | DA7213_DAC_NG_SETUP_TIME, |
130 | DA7213_DAC_NG_RAMPDN_RATE_SHIFT, | 129 | DA7213_DAC_NG_RAMPDN_RATE_SHIFT, |
131 | DA7213_DAC_NG_RAMP_RATE_MAX, | 130 | da7213_dac_ng_rampdown_txt); |
132 | da7213_dac_ng_rampdown_txt); | ||
133 | 131 | ||
134 | /* DAC soft mute rate value */ | 132 | /* DAC soft mute rate value */ |
135 | static const char * const da7213_dac_soft_mute_rate_txt[] = { | 133 | static const char * const da7213_dac_soft_mute_rate_txt[] = { |
136 | "1", "2", "4", "8", "16", "32", "64" | 134 | "1", "2", "4", "8", "16", "32", "64" |
137 | }; | 135 | }; |
138 | 136 | ||
139 | static const struct soc_enum da7213_dac_soft_mute_rate = | 137 | static SOC_ENUM_SINGLE_DECL(da7213_dac_soft_mute_rate, |
140 | SOC_ENUM_SINGLE(DA7213_DAC_FILTERS5, DA7213_DAC_SOFTMUTE_RATE_SHIFT, | 138 | DA7213_DAC_FILTERS5, |
141 | DA7213_DAC_SOFTMUTE_RATE_MAX, | 139 | DA7213_DAC_SOFTMUTE_RATE_SHIFT, |
142 | da7213_dac_soft_mute_rate_txt); | 140 | da7213_dac_soft_mute_rate_txt); |
143 | 141 | ||
144 | /* ALC Attack Rate select */ | 142 | /* ALC Attack Rate select */ |
145 | static const char * const da7213_alc_attack_rate_txt[] = { | 143 | static const char * const da7213_alc_attack_rate_txt[] = { |
@@ -147,9 +145,10 @@ static const char * const da7213_alc_attack_rate_txt[] = { | |||
147 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 145 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
148 | }; | 146 | }; |
149 | 147 | ||
150 | static const struct soc_enum da7213_alc_attack_rate = | 148 | static SOC_ENUM_SINGLE_DECL(da7213_alc_attack_rate, |
151 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_ATTACK_SHIFT, | 149 | DA7213_ALC_CTRL2, |
152 | DA7213_ALC_ATTACK_MAX, da7213_alc_attack_rate_txt); | 150 | DA7213_ALC_ATTACK_SHIFT, |
151 | da7213_alc_attack_rate_txt); | ||
153 | 152 | ||
154 | /* ALC Release Rate select */ | 153 | /* ALC Release Rate select */ |
155 | static const char * const da7213_alc_release_rate_txt[] = { | 154 | static const char * const da7213_alc_release_rate_txt[] = { |
@@ -157,9 +156,10 @@ static const char * const da7213_alc_release_rate_txt[] = { | |||
157 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 156 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
158 | }; | 157 | }; |
159 | 158 | ||
160 | static const struct soc_enum da7213_alc_release_rate = | 159 | static SOC_ENUM_SINGLE_DECL(da7213_alc_release_rate, |
161 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL2, DA7213_ALC_RELEASE_SHIFT, | 160 | DA7213_ALC_CTRL2, |
162 | DA7213_ALC_RELEASE_MAX, da7213_alc_release_rate_txt); | 161 | DA7213_ALC_RELEASE_SHIFT, |
162 | da7213_alc_release_rate_txt); | ||
163 | 163 | ||
164 | /* ALC Hold Time select */ | 164 | /* ALC Hold Time select */ |
165 | static const char * const da7213_alc_hold_time_txt[] = { | 165 | static const char * const da7213_alc_hold_time_txt[] = { |
@@ -168,22 +168,25 @@ static const char * const da7213_alc_hold_time_txt[] = { | |||
168 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" | 168 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" |
169 | }; | 169 | }; |
170 | 170 | ||
171 | static const struct soc_enum da7213_alc_hold_time = | 171 | static SOC_ENUM_SINGLE_DECL(da7213_alc_hold_time, |
172 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_HOLD_SHIFT, | 172 | DA7213_ALC_CTRL3, |
173 | DA7213_ALC_HOLD_MAX, da7213_alc_hold_time_txt); | 173 | DA7213_ALC_HOLD_SHIFT, |
174 | da7213_alc_hold_time_txt); | ||
174 | 175 | ||
175 | /* ALC Input Signal Tracking rate select */ | 176 | /* ALC Input Signal Tracking rate select */ |
176 | static const char * const da7213_alc_integ_rate_txt[] = { | 177 | static const char * const da7213_alc_integ_rate_txt[] = { |
177 | "1/4", "1/16", "1/256", "1/65536" | 178 | "1/4", "1/16", "1/256", "1/65536" |
178 | }; | 179 | }; |
179 | 180 | ||
180 | static const struct soc_enum da7213_alc_integ_attack_rate = | 181 | static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_attack_rate, |
181 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_ATTACK_SHIFT, | 182 | DA7213_ALC_CTRL3, |
182 | DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); | 183 | DA7213_ALC_INTEG_ATTACK_SHIFT, |
184 | da7213_alc_integ_rate_txt); | ||
183 | 185 | ||
184 | static const struct soc_enum da7213_alc_integ_release_rate = | 186 | static SOC_ENUM_SINGLE_DECL(da7213_alc_integ_release_rate, |
185 | SOC_ENUM_SINGLE(DA7213_ALC_CTRL3, DA7213_ALC_INTEG_RELEASE_SHIFT, | 187 | DA7213_ALC_CTRL3, |
186 | DA7213_ALC_INTEG_MAX, da7213_alc_integ_rate_txt); | 188 | DA7213_ALC_INTEG_RELEASE_SHIFT, |
189 | da7213_alc_integ_rate_txt); | ||
187 | 190 | ||
188 | 191 | ||
189 | /* | 192 | /* |
@@ -584,15 +587,17 @@ static const char * const da7213_mic_amp_in_sel_txt[] = { | |||
584 | "Differential", "MIC_P", "MIC_N" | 587 | "Differential", "MIC_P", "MIC_N" |
585 | }; | 588 | }; |
586 | 589 | ||
587 | static const struct soc_enum da7213_mic_1_amp_in_sel = | 590 | static SOC_ENUM_SINGLE_DECL(da7213_mic_1_amp_in_sel, |
588 | SOC_ENUM_SINGLE(DA7213_MIC_1_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, | 591 | DA7213_MIC_1_CTRL, |
589 | DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); | 592 | DA7213_MIC_AMP_IN_SEL_SHIFT, |
593 | da7213_mic_amp_in_sel_txt); | ||
590 | static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = | 594 | static const struct snd_kcontrol_new da7213_mic_1_amp_in_sel_mux = |
591 | SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); | 595 | SOC_DAPM_ENUM("Mic 1 Amp Source MUX", da7213_mic_1_amp_in_sel); |
592 | 596 | ||
593 | static const struct soc_enum da7213_mic_2_amp_in_sel = | 597 | static SOC_ENUM_SINGLE_DECL(da7213_mic_2_amp_in_sel, |
594 | SOC_ENUM_SINGLE(DA7213_MIC_2_CTRL, DA7213_MIC_AMP_IN_SEL_SHIFT, | 598 | DA7213_MIC_2_CTRL, |
595 | DA7213_MIC_AMP_IN_SEL_MAX, da7213_mic_amp_in_sel_txt); | 599 | DA7213_MIC_AMP_IN_SEL_SHIFT, |
600 | da7213_mic_amp_in_sel_txt); | ||
596 | static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = | 601 | static const struct snd_kcontrol_new da7213_mic_2_amp_in_sel_mux = |
597 | SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); | 602 | SOC_DAPM_ENUM("Mic 2 Amp Source MUX", da7213_mic_2_amp_in_sel); |
598 | 603 | ||
@@ -601,15 +606,17 @@ static const char * const da7213_dai_src_txt[] = { | |||
601 | "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" | 606 | "ADC Left", "ADC Right", "DAI Input Left", "DAI Input Right" |
602 | }; | 607 | }; |
603 | 608 | ||
604 | static const struct soc_enum da7213_dai_l_src = | 609 | static SOC_ENUM_SINGLE_DECL(da7213_dai_l_src, |
605 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_L_SRC_SHIFT, | 610 | DA7213_DIG_ROUTING_DAI, |
606 | DA7213_DAI_SRC_MAX, da7213_dai_src_txt); | 611 | DA7213_DAI_L_SRC_SHIFT, |
612 | da7213_dai_src_txt); | ||
607 | static const struct snd_kcontrol_new da7213_dai_l_src_mux = | 613 | static const struct snd_kcontrol_new da7213_dai_l_src_mux = |
608 | SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); | 614 | SOC_DAPM_ENUM("DAI Left Source MUX", da7213_dai_l_src); |
609 | 615 | ||
610 | static const struct soc_enum da7213_dai_r_src = | 616 | static SOC_ENUM_SINGLE_DECL(da7213_dai_r_src, |
611 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAI, DA7213_DAI_R_SRC_SHIFT, | 617 | DA7213_DIG_ROUTING_DAI, |
612 | DA7213_DAI_SRC_MAX, da7213_dai_src_txt); | 618 | DA7213_DAI_R_SRC_SHIFT, |
619 | da7213_dai_src_txt); | ||
613 | static const struct snd_kcontrol_new da7213_dai_r_src_mux = | 620 | static const struct snd_kcontrol_new da7213_dai_r_src_mux = |
614 | SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); | 621 | SOC_DAPM_ENUM("DAI Right Source MUX", da7213_dai_r_src); |
615 | 622 | ||
@@ -619,15 +626,17 @@ static const char * const da7213_dac_src_txt[] = { | |||
619 | "DAI Input Right" | 626 | "DAI Input Right" |
620 | }; | 627 | }; |
621 | 628 | ||
622 | static const struct soc_enum da7213_dac_l_src = | 629 | static SOC_ENUM_SINGLE_DECL(da7213_dac_l_src, |
623 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_L_SRC_SHIFT, | 630 | DA7213_DIG_ROUTING_DAC, |
624 | DA7213_DAC_SRC_MAX, da7213_dac_src_txt); | 631 | DA7213_DAC_L_SRC_SHIFT, |
632 | da7213_dac_src_txt); | ||
625 | static const struct snd_kcontrol_new da7213_dac_l_src_mux = | 633 | static const struct snd_kcontrol_new da7213_dac_l_src_mux = |
626 | SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); | 634 | SOC_DAPM_ENUM("DAC Left Source MUX", da7213_dac_l_src); |
627 | 635 | ||
628 | static const struct soc_enum da7213_dac_r_src = | 636 | static SOC_ENUM_SINGLE_DECL(da7213_dac_r_src, |
629 | SOC_ENUM_SINGLE(DA7213_DIG_ROUTING_DAC, DA7213_DAC_R_SRC_SHIFT, | 637 | DA7213_DIG_ROUTING_DAC, |
630 | DA7213_DAC_SRC_MAX, da7213_dac_src_txt); | 638 | DA7213_DAC_R_SRC_SHIFT, |
639 | da7213_dac_src_txt); | ||
631 | static const struct snd_kcontrol_new da7213_dac_r_src_mux = | 640 | static const struct snd_kcontrol_new da7213_dac_r_src_mux = |
632 | SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); | 641 | SOC_DAPM_ENUM("DAC Right Source MUX", da7213_dac_r_src); |
633 | 642 | ||
diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index f295b6569910..4d1c302f5a76 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c | |||
@@ -269,81 +269,65 @@ static const char *da732x_hpf_voice[] = { | |||
269 | "150Hz", "200Hz", "300Hz", "400Hz" | 269 | "150Hz", "200Hz", "300Hz", "400Hz" |
270 | }; | 270 | }; |
271 | 271 | ||
272 | static const struct soc_enum da732x_dac1_hpf_mode_enum[] = { | 272 | static SOC_ENUM_SINGLE_DECL(da732x_dac1_hpf_mode_enum, |
273 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, | 273 | DA732X_REG_DAC1_HPF, DA732X_HPF_MODE_SHIFT, |
274 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 274 | da732x_hpf_mode); |
275 | }; | ||
276 | 275 | ||
277 | static const struct soc_enum da732x_dac2_hpf_mode_enum[] = { | 276 | static SOC_ENUM_SINGLE_DECL(da732x_dac2_hpf_mode_enum, |
278 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, | 277 | DA732X_REG_DAC2_HPF, DA732X_HPF_MODE_SHIFT, |
279 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 278 | da732x_hpf_mode); |
280 | }; | ||
281 | 279 | ||
282 | static const struct soc_enum da732x_dac3_hpf_mode_enum[] = { | 280 | static SOC_ENUM_SINGLE_DECL(da732x_dac3_hpf_mode_enum, |
283 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, | 281 | DA732X_REG_DAC3_HPF, DA732X_HPF_MODE_SHIFT, |
284 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 282 | da732x_hpf_mode); |
285 | }; | ||
286 | 283 | ||
287 | static const struct soc_enum da732x_adc1_hpf_mode_enum[] = { | 284 | static SOC_ENUM_SINGLE_DECL(da732x_adc1_hpf_mode_enum, |
288 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, | 285 | DA732X_REG_ADC1_HPF, DA732X_HPF_MODE_SHIFT, |
289 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 286 | da732x_hpf_mode); |
290 | }; | ||
291 | 287 | ||
292 | static const struct soc_enum da732x_adc2_hpf_mode_enum[] = { | 288 | static SOC_ENUM_SINGLE_DECL(da732x_adc2_hpf_mode_enum, |
293 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, | 289 | DA732X_REG_ADC2_HPF, DA732X_HPF_MODE_SHIFT, |
294 | DA732X_HPF_MODE_MAX, da732x_hpf_mode) | 290 | da732x_hpf_mode); |
295 | }; | ||
296 | 291 | ||
297 | static const struct soc_enum da732x_dac1_hp_filter_enum[] = { | 292 | static SOC_ENUM_SINGLE_DECL(da732x_dac1_hp_filter_enum, |
298 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, | 293 | DA732X_REG_DAC1_HPF, DA732X_HPF_MUSIC_SHIFT, |
299 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 294 | da732x_hpf_music); |
300 | }; | ||
301 | 295 | ||
302 | static const struct soc_enum da732x_dac2_hp_filter_enum[] = { | 296 | static SOC_ENUM_SINGLE_DECL(da732x_dac2_hp_filter_enum, |
303 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, | 297 | DA732X_REG_DAC2_HPF, DA732X_HPF_MUSIC_SHIFT, |
304 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 298 | da732x_hpf_music); |
305 | }; | ||
306 | 299 | ||
307 | static const struct soc_enum da732x_dac3_hp_filter_enum[] = { | 300 | static SOC_ENUM_SINGLE_DECL(da732x_dac3_hp_filter_enum, |
308 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, | 301 | DA732X_REG_DAC3_HPF, DA732X_HPF_MUSIC_SHIFT, |
309 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 302 | da732x_hpf_music); |
310 | }; | ||
311 | 303 | ||
312 | static const struct soc_enum da732x_adc1_hp_filter_enum[] = { | 304 | static SOC_ENUM_SINGLE_DECL(da732x_adc1_hp_filter_enum, |
313 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, | 305 | DA732X_REG_ADC1_HPF, DA732X_HPF_MUSIC_SHIFT, |
314 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 306 | da732x_hpf_music); |
315 | }; | ||
316 | 307 | ||
317 | static const struct soc_enum da732x_adc2_hp_filter_enum[] = { | 308 | static SOC_ENUM_SINGLE_DECL(da732x_adc2_hp_filter_enum, |
318 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, | 309 | DA732X_REG_ADC2_HPF, DA732X_HPF_MUSIC_SHIFT, |
319 | DA732X_HPF_MUSIC_MAX, da732x_hpf_music) | 310 | da732x_hpf_music); |
320 | }; | ||
321 | 311 | ||
322 | static const struct soc_enum da732x_dac1_voice_filter_enum[] = { | 312 | static SOC_ENUM_SINGLE_DECL(da732x_dac1_voice_filter_enum, |
323 | SOC_ENUM_SINGLE(DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, | 313 | DA732X_REG_DAC1_HPF, DA732X_HPF_VOICE_SHIFT, |
324 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 314 | da732x_hpf_voice); |
325 | }; | ||
326 | 315 | ||
327 | static const struct soc_enum da732x_dac2_voice_filter_enum[] = { | 316 | static SOC_ENUM_SINGLE_DECL(da732x_dac2_voice_filter_enum, |
328 | SOC_ENUM_SINGLE(DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, | 317 | DA732X_REG_DAC2_HPF, DA732X_HPF_VOICE_SHIFT, |
329 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 318 | da732x_hpf_voice); |
330 | }; | ||
331 | 319 | ||
332 | static const struct soc_enum da732x_dac3_voice_filter_enum[] = { | 320 | static SOC_ENUM_SINGLE_DECL(da732x_dac3_voice_filter_enum, |
333 | SOC_ENUM_SINGLE(DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, | 321 | DA732X_REG_DAC3_HPF, DA732X_HPF_VOICE_SHIFT, |
334 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 322 | da732x_hpf_voice); |
335 | }; | ||
336 | 323 | ||
337 | static const struct soc_enum da732x_adc1_voice_filter_enum[] = { | 324 | static SOC_ENUM_SINGLE_DECL(da732x_adc1_voice_filter_enum, |
338 | SOC_ENUM_SINGLE(DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, | 325 | DA732X_REG_ADC1_HPF, DA732X_HPF_VOICE_SHIFT, |
339 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | 326 | da732x_hpf_voice); |
340 | }; | ||
341 | |||
342 | static const struct soc_enum da732x_adc2_voice_filter_enum[] = { | ||
343 | SOC_ENUM_SINGLE(DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, | ||
344 | DA732X_HPF_VOICE_MAX, da732x_hpf_voice) | ||
345 | }; | ||
346 | 327 | ||
328 | static SOC_ENUM_SINGLE_DECL(da732x_adc2_voice_filter_enum, | ||
329 | DA732X_REG_ADC2_HPF, DA732X_HPF_VOICE_SHIFT, | ||
330 | da732x_hpf_voice); | ||
347 | 331 | ||
348 | static int da732x_hpf_set(struct snd_kcontrol *kcontrol, | 332 | static int da732x_hpf_set(struct snd_kcontrol *kcontrol, |
349 | struct snd_ctl_elem_value *ucontrol) | 333 | struct snd_ctl_elem_value *ucontrol) |
@@ -714,65 +698,65 @@ static const char *enable_text[] = { | |||
714 | }; | 698 | }; |
715 | 699 | ||
716 | /* ADC1LMUX */ | 700 | /* ADC1LMUX */ |
717 | static const struct soc_enum adc1l_enum = | 701 | static SOC_ENUM_SINGLE_DECL(adc1l_enum, |
718 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, | 702 | DA732X_REG_INP_MUX, DA732X_ADC1L_MUX_SEL_SHIFT, |
719 | DA732X_ADCL_MUX_MAX, adcl_text); | 703 | adcl_text); |
720 | static const struct snd_kcontrol_new adc1l_mux = | 704 | static const struct snd_kcontrol_new adc1l_mux = |
721 | SOC_DAPM_ENUM("ADC Route", adc1l_enum); | 705 | SOC_DAPM_ENUM("ADC Route", adc1l_enum); |
722 | 706 | ||
723 | /* ADC1RMUX */ | 707 | /* ADC1RMUX */ |
724 | static const struct soc_enum adc1r_enum = | 708 | static SOC_ENUM_SINGLE_DECL(adc1r_enum, |
725 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, | 709 | DA732X_REG_INP_MUX, DA732X_ADC1R_MUX_SEL_SHIFT, |
726 | DA732X_ADCR_MUX_MAX, adcr_text); | 710 | adcr_text); |
727 | static const struct snd_kcontrol_new adc1r_mux = | 711 | static const struct snd_kcontrol_new adc1r_mux = |
728 | SOC_DAPM_ENUM("ADC Route", adc1r_enum); | 712 | SOC_DAPM_ENUM("ADC Route", adc1r_enum); |
729 | 713 | ||
730 | /* ADC2LMUX */ | 714 | /* ADC2LMUX */ |
731 | static const struct soc_enum adc2l_enum = | 715 | static SOC_ENUM_SINGLE_DECL(adc2l_enum, |
732 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, | 716 | DA732X_REG_INP_MUX, DA732X_ADC2L_MUX_SEL_SHIFT, |
733 | DA732X_ADCL_MUX_MAX, adcl_text); | 717 | adcl_text); |
734 | static const struct snd_kcontrol_new adc2l_mux = | 718 | static const struct snd_kcontrol_new adc2l_mux = |
735 | SOC_DAPM_ENUM("ADC Route", adc2l_enum); | 719 | SOC_DAPM_ENUM("ADC Route", adc2l_enum); |
736 | 720 | ||
737 | /* ADC2RMUX */ | 721 | /* ADC2RMUX */ |
738 | static const struct soc_enum adc2r_enum = | 722 | static SOC_ENUM_SINGLE_DECL(adc2r_enum, |
739 | SOC_ENUM_SINGLE(DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, | 723 | DA732X_REG_INP_MUX, DA732X_ADC2R_MUX_SEL_SHIFT, |
740 | DA732X_ADCR_MUX_MAX, adcr_text); | 724 | adcr_text); |
741 | 725 | ||
742 | static const struct snd_kcontrol_new adc2r_mux = | 726 | static const struct snd_kcontrol_new adc2r_mux = |
743 | SOC_DAPM_ENUM("ADC Route", adc2r_enum); | 727 | SOC_DAPM_ENUM("ADC Route", adc2r_enum); |
744 | 728 | ||
745 | static const struct soc_enum da732x_hp_left_output = | 729 | static SOC_ENUM_SINGLE_DECL(da732x_hp_left_output, |
746 | SOC_ENUM_SINGLE(DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, | 730 | DA732X_REG_HPL, DA732X_HP_OUT_DAC_EN_SHIFT, |
747 | DA732X_DAC_EN_MAX, enable_text); | 731 | enable_text); |
748 | 732 | ||
749 | static const struct snd_kcontrol_new hpl_mux = | 733 | static const struct snd_kcontrol_new hpl_mux = |
750 | SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); | 734 | SOC_DAPM_ENUM("HPL Switch", da732x_hp_left_output); |
751 | 735 | ||
752 | static const struct soc_enum da732x_hp_right_output = | 736 | static SOC_ENUM_SINGLE_DECL(da732x_hp_right_output, |
753 | SOC_ENUM_SINGLE(DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, | 737 | DA732X_REG_HPR, DA732X_HP_OUT_DAC_EN_SHIFT, |
754 | DA732X_DAC_EN_MAX, enable_text); | 738 | enable_text); |
755 | 739 | ||
756 | static const struct snd_kcontrol_new hpr_mux = | 740 | static const struct snd_kcontrol_new hpr_mux = |
757 | SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); | 741 | SOC_DAPM_ENUM("HPR Switch", da732x_hp_right_output); |
758 | 742 | ||
759 | static const struct soc_enum da732x_speaker_output = | 743 | static SOC_ENUM_SINGLE_DECL(da732x_speaker_output, |
760 | SOC_ENUM_SINGLE(DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, | 744 | DA732X_REG_LIN3, DA732X_LOUT_DAC_EN_SHIFT, |
761 | DA732X_DAC_EN_MAX, enable_text); | 745 | enable_text); |
762 | 746 | ||
763 | static const struct snd_kcontrol_new spk_mux = | 747 | static const struct snd_kcontrol_new spk_mux = |
764 | SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); | 748 | SOC_DAPM_ENUM("SPK Switch", da732x_speaker_output); |
765 | 749 | ||
766 | static const struct soc_enum da732x_lout4_output = | 750 | static SOC_ENUM_SINGLE_DECL(da732x_lout4_output, |
767 | SOC_ENUM_SINGLE(DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, | 751 | DA732X_REG_LIN4, DA732X_LOUT_DAC_EN_SHIFT, |
768 | DA732X_DAC_EN_MAX, enable_text); | 752 | enable_text); |
769 | 753 | ||
770 | static const struct snd_kcontrol_new lout4_mux = | 754 | static const struct snd_kcontrol_new lout4_mux = |
771 | SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); | 755 | SOC_DAPM_ENUM("LOUT4 Switch", da732x_lout4_output); |
772 | 756 | ||
773 | static const struct soc_enum da732x_lout2_output = | 757 | static SOC_ENUM_SINGLE_DECL(da732x_lout2_output, |
774 | SOC_ENUM_SINGLE(DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, | 758 | DA732X_REG_LIN2, DA732X_LOUT_DAC_EN_SHIFT, |
775 | DA732X_DAC_EN_MAX, enable_text); | 759 | enable_text); |
776 | 760 | ||
777 | static const struct snd_kcontrol_new lout2_mux = | 761 | static const struct snd_kcontrol_new lout2_mux = |
778 | SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); | 762 | SOC_DAPM_ENUM("LOUT2 Switch", da732x_lout2_output); |
@@ -1268,11 +1252,23 @@ static struct snd_soc_dai_driver da732x_dai[] = { | |||
1268 | }, | 1252 | }, |
1269 | }; | 1253 | }; |
1270 | 1254 | ||
1255 | static bool da732x_volatile(struct device *dev, unsigned int reg) | ||
1256 | { | ||
1257 | switch (reg) { | ||
1258 | case DA732X_REG_HPL_DAC_OFF_CNTL: | ||
1259 | case DA732X_REG_HPR_DAC_OFF_CNTL: | ||
1260 | return true; | ||
1261 | default: | ||
1262 | return false; | ||
1263 | } | ||
1264 | } | ||
1265 | |||
1271 | static const struct regmap_config da732x_regmap = { | 1266 | static const struct regmap_config da732x_regmap = { |
1272 | .reg_bits = 8, | 1267 | .reg_bits = 8, |
1273 | .val_bits = 8, | 1268 | .val_bits = 8, |
1274 | 1269 | ||
1275 | .max_register = DA732X_MAX_REG, | 1270 | .max_register = DA732X_MAX_REG, |
1271 | .volatile_reg = da732x_volatile, | ||
1276 | .reg_defaults = da732x_reg_cache, | 1272 | .reg_defaults = da732x_reg_cache, |
1277 | .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), | 1273 | .num_reg_defaults = ARRAY_SIZE(da732x_reg_cache), |
1278 | .cache_type = REGCACHE_RBTREE, | 1274 | .cache_type = REGCACHE_RBTREE, |
@@ -1487,8 +1483,8 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
1487 | 1483 | ||
1488 | da732x_hp_dc_offset_cancellation(codec); | 1484 | da732x_hp_dc_offset_cancellation(codec); |
1489 | 1485 | ||
1490 | regcache_cache_only(codec->control_data, false); | 1486 | regcache_cache_only(da732x->regmap, false); |
1491 | regcache_sync(codec->control_data); | 1487 | regcache_sync(da732x->regmap); |
1492 | } else { | 1488 | } else { |
1493 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, | 1489 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, |
1494 | DA732X_BIAS_BOOST_MASK, | 1490 | DA732X_BIAS_BOOST_MASK, |
@@ -1499,7 +1495,7 @@ static int da732x_set_bias_level(struct snd_soc_codec *codec, | |||
1499 | } | 1495 | } |
1500 | break; | 1496 | break; |
1501 | case SND_SOC_BIAS_OFF: | 1497 | case SND_SOC_BIAS_OFF: |
1502 | regcache_cache_only(codec->control_data, true); | 1498 | regcache_cache_only(da732x->regmap, true); |
1503 | da732x_set_charge_pump(codec, DA732X_DISABLE_CP); | 1499 | da732x_set_charge_pump(codec, DA732X_DISABLE_CP); |
1504 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, | 1500 | snd_soc_update_bits(codec, DA732X_REG_BIAS_EN, DA732X_BIAS_EN, |
1505 | DA732X_BIAS_DIS); | 1501 | DA732X_BIAS_DIS); |
@@ -1554,7 +1550,6 @@ static struct snd_soc_codec_driver soc_codec_dev_da732x = { | |||
1554 | .dapm_routes = da732x_dapm_routes, | 1550 | .dapm_routes = da732x_dapm_routes, |
1555 | .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), | 1551 | .num_dapm_routes = ARRAY_SIZE(da732x_dapm_routes), |
1556 | .set_pll = da732x_set_dai_pll, | 1552 | .set_pll = da732x_set_dai_pll, |
1557 | .reg_cache_size = ARRAY_SIZE(da732x_reg_cache), | ||
1558 | }; | 1553 | }; |
1559 | 1554 | ||
1560 | static int da732x_i2c_probe(struct i2c_client *i2c, | 1555 | static int da732x_i2c_probe(struct i2c_client *i2c, |
diff --git a/sound/soc/codecs/da732x.h b/sound/soc/codecs/da732x.h index c8ce5475de22..1dceafeec415 100644 --- a/sound/soc/codecs/da732x.h +++ b/sound/soc/codecs/da732x.h | |||
@@ -113,9 +113,6 @@ | |||
113 | #define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 | 113 | #define DA732X_EQ_OVERALL_VOL_DB_MIN -1800 |
114 | #define DA732X_EQ_OVERALL_VOL_DB_INC 600 | 114 | #define DA732X_EQ_OVERALL_VOL_DB_INC 600 |
115 | 115 | ||
116 | #define DA732X_SOC_ENUM_DOUBLE_R(xreg, xrreg, xmax, xtext) \ | ||
117 | {.reg = xreg, .reg2 = xrreg, .max = xmax, .texts = xtext} | ||
118 | |||
119 | enum da732x_sysctl { | 116 | enum da732x_sysctl { |
120 | DA732X_SR_8KHZ = 0x1, | 117 | DA732X_SR_8KHZ = 0x1, |
121 | DA732X_SR_11_025KHZ = 0x2, | 118 | DA732X_SR_11_025KHZ = 0x2, |
diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 52b79a487ac7..f118daa91234 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/regmap.h> | 18 | #include <linux/regmap.h> |
19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
21 | #include <linux/of.h> | ||
22 | #include <linux/of_device.h> | ||
21 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
22 | #include <sound/pcm_params.h> | 24 | #include <sound/pcm_params.h> |
23 | #include <sound/soc.h> | 25 | #include <sound/soc.h> |
@@ -321,22 +323,22 @@ static const char * const da9055_hpf_cutoff_txt[] = { | |||
321 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" | 323 | "Fs/24000", "Fs/12000", "Fs/6000", "Fs/3000" |
322 | }; | 324 | }; |
323 | 325 | ||
324 | static const struct soc_enum da9055_dac_hpf_cutoff = | 326 | static SOC_ENUM_SINGLE_DECL(da9055_dac_hpf_cutoff, |
325 | SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); | 327 | DA9055_DAC_FILTERS1, 4, da9055_hpf_cutoff_txt); |
326 | 328 | ||
327 | static const struct soc_enum da9055_adc_hpf_cutoff = | 329 | static SOC_ENUM_SINGLE_DECL(da9055_adc_hpf_cutoff, |
328 | SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 4, 4, da9055_hpf_cutoff_txt); | 330 | DA9055_ADC_FILTERS1, 4, da9055_hpf_cutoff_txt); |
329 | 331 | ||
330 | /* ADC and DAC voice mode (8kHz) high pass cutoff value */ | 332 | /* ADC and DAC voice mode (8kHz) high pass cutoff value */ |
331 | static const char * const da9055_vf_cutoff_txt[] = { | 333 | static const char * const da9055_vf_cutoff_txt[] = { |
332 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" | 334 | "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" |
333 | }; | 335 | }; |
334 | 336 | ||
335 | static const struct soc_enum da9055_dac_vf_cutoff = | 337 | static SOC_ENUM_SINGLE_DECL(da9055_dac_vf_cutoff, |
336 | SOC_ENUM_SINGLE(DA9055_DAC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); | 338 | DA9055_DAC_FILTERS1, 0, da9055_vf_cutoff_txt); |
337 | 339 | ||
338 | static const struct soc_enum da9055_adc_vf_cutoff = | 340 | static SOC_ENUM_SINGLE_DECL(da9055_adc_vf_cutoff, |
339 | SOC_ENUM_SINGLE(DA9055_ADC_FILTERS1, 0, 8, da9055_vf_cutoff_txt); | 341 | DA9055_ADC_FILTERS1, 0, da9055_vf_cutoff_txt); |
340 | 342 | ||
341 | /* Gain ramping rate value */ | 343 | /* Gain ramping rate value */ |
342 | static const char * const da9055_gain_ramping_txt[] = { | 344 | static const char * const da9055_gain_ramping_txt[] = { |
@@ -344,44 +346,44 @@ static const char * const da9055_gain_ramping_txt[] = { | |||
344 | "nominal rate / 8" | 346 | "nominal rate / 8" |
345 | }; | 347 | }; |
346 | 348 | ||
347 | static const struct soc_enum da9055_gain_ramping_rate = | 349 | static SOC_ENUM_SINGLE_DECL(da9055_gain_ramping_rate, |
348 | SOC_ENUM_SINGLE(DA9055_GAIN_RAMP_CTRL, 0, 4, da9055_gain_ramping_txt); | 350 | DA9055_GAIN_RAMP_CTRL, 0, da9055_gain_ramping_txt); |
349 | 351 | ||
350 | /* DAC noise gate setup time value */ | 352 | /* DAC noise gate setup time value */ |
351 | static const char * const da9055_dac_ng_setup_time_txt[] = { | 353 | static const char * const da9055_dac_ng_setup_time_txt[] = { |
352 | "256 samples", "512 samples", "1024 samples", "2048 samples" | 354 | "256 samples", "512 samples", "1024 samples", "2048 samples" |
353 | }; | 355 | }; |
354 | 356 | ||
355 | static const struct soc_enum da9055_dac_ng_setup_time = | 357 | static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_setup_time, |
356 | SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 0, 4, | 358 | DA9055_DAC_NG_SETUP_TIME, 0, |
357 | da9055_dac_ng_setup_time_txt); | 359 | da9055_dac_ng_setup_time_txt); |
358 | 360 | ||
359 | /* DAC noise gate rampup rate value */ | 361 | /* DAC noise gate rampup rate value */ |
360 | static const char * const da9055_dac_ng_rampup_txt[] = { | 362 | static const char * const da9055_dac_ng_rampup_txt[] = { |
361 | "0.02 ms/dB", "0.16 ms/dB" | 363 | "0.02 ms/dB", "0.16 ms/dB" |
362 | }; | 364 | }; |
363 | 365 | ||
364 | static const struct soc_enum da9055_dac_ng_rampup_rate = | 366 | static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampup_rate, |
365 | SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 2, 2, | 367 | DA9055_DAC_NG_SETUP_TIME, 2, |
366 | da9055_dac_ng_rampup_txt); | 368 | da9055_dac_ng_rampup_txt); |
367 | 369 | ||
368 | /* DAC noise gate rampdown rate value */ | 370 | /* DAC noise gate rampdown rate value */ |
369 | static const char * const da9055_dac_ng_rampdown_txt[] = { | 371 | static const char * const da9055_dac_ng_rampdown_txt[] = { |
370 | "0.64 ms/dB", "20.48 ms/dB" | 372 | "0.64 ms/dB", "20.48 ms/dB" |
371 | }; | 373 | }; |
372 | 374 | ||
373 | static const struct soc_enum da9055_dac_ng_rampdown_rate = | 375 | static SOC_ENUM_SINGLE_DECL(da9055_dac_ng_rampdown_rate, |
374 | SOC_ENUM_SINGLE(DA9055_DAC_NG_SETUP_TIME, 3, 2, | 376 | DA9055_DAC_NG_SETUP_TIME, 3, |
375 | da9055_dac_ng_rampdown_txt); | 377 | da9055_dac_ng_rampdown_txt); |
376 | 378 | ||
377 | /* DAC soft mute rate value */ | 379 | /* DAC soft mute rate value */ |
378 | static const char * const da9055_dac_soft_mute_rate_txt[] = { | 380 | static const char * const da9055_dac_soft_mute_rate_txt[] = { |
379 | "1", "2", "4", "8", "16", "32", "64" | 381 | "1", "2", "4", "8", "16", "32", "64" |
380 | }; | 382 | }; |
381 | 383 | ||
382 | static const struct soc_enum da9055_dac_soft_mute_rate = | 384 | static SOC_ENUM_SINGLE_DECL(da9055_dac_soft_mute_rate, |
383 | SOC_ENUM_SINGLE(DA9055_DAC_FILTERS5, 4, 7, | 385 | DA9055_DAC_FILTERS5, 4, |
384 | da9055_dac_soft_mute_rate_txt); | 386 | da9055_dac_soft_mute_rate_txt); |
385 | 387 | ||
386 | /* DAC routing select */ | 388 | /* DAC routing select */ |
387 | static const char * const da9055_dac_src_txt[] = { | 389 | static const char * const da9055_dac_src_txt[] = { |
@@ -389,40 +391,40 @@ static const char * const da9055_dac_src_txt[] = { | |||
389 | "AIF input right" | 391 | "AIF input right" |
390 | }; | 392 | }; |
391 | 393 | ||
392 | static const struct soc_enum da9055_dac_l_src = | 394 | static SOC_ENUM_SINGLE_DECL(da9055_dac_l_src, |
393 | SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 0, 4, da9055_dac_src_txt); | 395 | DA9055_DIG_ROUTING_DAC, 0, da9055_dac_src_txt); |
394 | 396 | ||
395 | static const struct soc_enum da9055_dac_r_src = | 397 | static SOC_ENUM_SINGLE_DECL(da9055_dac_r_src, |
396 | SOC_ENUM_SINGLE(DA9055_DIG_ROUTING_DAC, 4, 4, da9055_dac_src_txt); | 398 | DA9055_DIG_ROUTING_DAC, 4, da9055_dac_src_txt); |
397 | 399 | ||
398 | /* MIC PGA Left source select */ | 400 | /* MIC PGA Left source select */ |
399 | static const char * const da9055_mic_l_src_txt[] = { | 401 | static const char * const da9055_mic_l_src_txt[] = { |
400 | "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L" | 402 | "MIC1_P_N", "MIC1_P", "MIC1_N", "MIC2_L" |
401 | }; | 403 | }; |
402 | 404 | ||
403 | static const struct soc_enum da9055_mic_l_src = | 405 | static SOC_ENUM_SINGLE_DECL(da9055_mic_l_src, |
404 | SOC_ENUM_SINGLE(DA9055_MIXIN_L_SELECT, 4, 4, da9055_mic_l_src_txt); | 406 | DA9055_MIXIN_L_SELECT, 4, da9055_mic_l_src_txt); |
405 | 407 | ||
406 | /* MIC PGA Right source select */ | 408 | /* MIC PGA Right source select */ |
407 | static const char * const da9055_mic_r_src_txt[] = { | 409 | static const char * const da9055_mic_r_src_txt[] = { |
408 | "MIC2_R_L", "MIC2_R", "MIC2_L" | 410 | "MIC2_R_L", "MIC2_R", "MIC2_L" |
409 | }; | 411 | }; |
410 | 412 | ||
411 | static const struct soc_enum da9055_mic_r_src = | 413 | static SOC_ENUM_SINGLE_DECL(da9055_mic_r_src, |
412 | SOC_ENUM_SINGLE(DA9055_MIXIN_R_SELECT, 4, 3, da9055_mic_r_src_txt); | 414 | DA9055_MIXIN_R_SELECT, 4, da9055_mic_r_src_txt); |
413 | 415 | ||
414 | /* ALC Input Signal Tracking rate select */ | 416 | /* ALC Input Signal Tracking rate select */ |
415 | static const char * const da9055_signal_tracking_rate_txt[] = { | 417 | static const char * const da9055_signal_tracking_rate_txt[] = { |
416 | "1/4", "1/16", "1/256", "1/65536" | 418 | "1/4", "1/16", "1/256", "1/65536" |
417 | }; | 419 | }; |
418 | 420 | ||
419 | static const struct soc_enum da9055_integ_attack_rate = | 421 | static SOC_ENUM_SINGLE_DECL(da9055_integ_attack_rate, |
420 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 4, 4, | 422 | DA9055_ALC_CTRL3, 4, |
421 | da9055_signal_tracking_rate_txt); | 423 | da9055_signal_tracking_rate_txt); |
422 | 424 | ||
423 | static const struct soc_enum da9055_integ_release_rate = | 425 | static SOC_ENUM_SINGLE_DECL(da9055_integ_release_rate, |
424 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 6, 4, | 426 | DA9055_ALC_CTRL3, 6, |
425 | da9055_signal_tracking_rate_txt); | 427 | da9055_signal_tracking_rate_txt); |
426 | 428 | ||
427 | /* ALC Attack Rate select */ | 429 | /* ALC Attack Rate select */ |
428 | static const char * const da9055_attack_rate_txt[] = { | 430 | static const char * const da9055_attack_rate_txt[] = { |
@@ -430,8 +432,8 @@ static const char * const da9055_attack_rate_txt[] = { | |||
430 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 432 | "5632/fs", "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
431 | }; | 433 | }; |
432 | 434 | ||
433 | static const struct soc_enum da9055_attack_rate = | 435 | static SOC_ENUM_SINGLE_DECL(da9055_attack_rate, |
434 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 0, 13, da9055_attack_rate_txt); | 436 | DA9055_ALC_CTRL2, 0, da9055_attack_rate_txt); |
435 | 437 | ||
436 | /* ALC Release Rate select */ | 438 | /* ALC Release Rate select */ |
437 | static const char * const da9055_release_rate_txt[] = { | 439 | static const char * const da9055_release_rate_txt[] = { |
@@ -439,8 +441,8 @@ static const char * const da9055_release_rate_txt[] = { | |||
439 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" | 441 | "11264/fs", "22528/fs", "45056/fs", "90112/fs", "180224/fs" |
440 | }; | 442 | }; |
441 | 443 | ||
442 | static const struct soc_enum da9055_release_rate = | 444 | static SOC_ENUM_SINGLE_DECL(da9055_release_rate, |
443 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL2, 4, 11, da9055_release_rate_txt); | 445 | DA9055_ALC_CTRL2, 4, da9055_release_rate_txt); |
444 | 446 | ||
445 | /* ALC Hold Time select */ | 447 | /* ALC Hold Time select */ |
446 | static const char * const da9055_hold_time_txt[] = { | 448 | static const char * const da9055_hold_time_txt[] = { |
@@ -449,8 +451,8 @@ static const char * const da9055_hold_time_txt[] = { | |||
449 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" | 451 | "253952/fs", "507904/fs", "1015808/fs", "2031616/fs" |
450 | }; | 452 | }; |
451 | 453 | ||
452 | static const struct soc_enum da9055_hold_time = | 454 | static SOC_ENUM_SINGLE_DECL(da9055_hold_time, |
453 | SOC_ENUM_SINGLE(DA9055_ALC_CTRL3, 0, 16, da9055_hold_time_txt); | 455 | DA9055_ALC_CTRL3, 0, da9055_hold_time_txt); |
454 | 456 | ||
455 | static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) | 457 | static int da9055_get_alc_data(struct snd_soc_codec *codec, u8 reg_val) |
456 | { | 458 | { |
@@ -1523,17 +1525,30 @@ static int da9055_remove(struct i2c_client *client) | |||
1523 | return 0; | 1525 | return 0; |
1524 | } | 1526 | } |
1525 | 1527 | ||
1528 | /* | ||
1529 | * DO NOT change the device Ids. The naming is intentionally specific as both | ||
1530 | * the CODEC and PMIC parts of this chip are instantiated separately as I2C | ||
1531 | * devices (both have configurable I2C addresses, and are to all intents and | ||
1532 | * purposes separate). As a result there are specific DA9055 Ids for CODEC | ||
1533 | * and PMIC, which must be different to operate together. | ||
1534 | */ | ||
1526 | static const struct i2c_device_id da9055_i2c_id[] = { | 1535 | static const struct i2c_device_id da9055_i2c_id[] = { |
1527 | { "da9055", 0 }, | 1536 | { "da9055-codec", 0 }, |
1528 | { } | 1537 | { } |
1529 | }; | 1538 | }; |
1530 | MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); | 1539 | MODULE_DEVICE_TABLE(i2c, da9055_i2c_id); |
1531 | 1540 | ||
1541 | static const struct of_device_id da9055_of_match[] = { | ||
1542 | { .compatible = "dlg,da9055-codec", }, | ||
1543 | { } | ||
1544 | }; | ||
1545 | |||
1532 | /* I2C codec control layer */ | 1546 | /* I2C codec control layer */ |
1533 | static struct i2c_driver da9055_i2c_driver = { | 1547 | static struct i2c_driver da9055_i2c_driver = { |
1534 | .driver = { | 1548 | .driver = { |
1535 | .name = "da9055", | 1549 | .name = "da9055-codec", |
1536 | .owner = THIS_MODULE, | 1550 | .owner = THIS_MODULE, |
1551 | .of_match_table = of_match_ptr(da9055_of_match), | ||
1537 | }, | 1552 | }, |
1538 | .probe = da9055_i2c_probe, | 1553 | .probe = da9055_i2c_probe, |
1539 | .remove = da9055_remove, | 1554 | .remove = da9055_remove, |
diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index 5839048ec467..cb736ddc446d 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c | |||
@@ -140,13 +140,17 @@ static const char *isabelle_rx1_texts[] = {"VRX1", "ARX1"}; | |||
140 | static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"}; | 140 | static const char *isabelle_rx2_texts[] = {"VRX2", "ARX2"}; |
141 | 141 | ||
142 | static const struct soc_enum isabelle_rx1_enum[] = { | 142 | static const struct soc_enum isabelle_rx1_enum[] = { |
143 | SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, 1, isabelle_rx1_texts), | 143 | SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 3, |
144 | SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, 1, isabelle_rx1_texts), | 144 | ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), |
145 | SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 5, | ||
146 | ARRAY_SIZE(isabelle_rx1_texts), isabelle_rx1_texts), | ||
145 | }; | 147 | }; |
146 | 148 | ||
147 | static const struct soc_enum isabelle_rx2_enum[] = { | 149 | static const struct soc_enum isabelle_rx2_enum[] = { |
148 | SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, 1, isabelle_rx2_texts), | 150 | SOC_ENUM_SINGLE(ISABELLE_VOICE_HPF_CFG_REG, 2, |
149 | SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, 1, isabelle_rx2_texts), | 151 | ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), |
152 | SOC_ENUM_SINGLE(ISABELLE_AUDIO_HPF_CFG_REG, 4, | ||
153 | ARRAY_SIZE(isabelle_rx2_texts), isabelle_rx2_texts), | ||
150 | }; | 154 | }; |
151 | 155 | ||
152 | /* Headset DAC playback switches */ | 156 | /* Headset DAC playback switches */ |
@@ -161,13 +165,17 @@ static const char *isabelle_atx_texts[] = {"AMIC1", "DMIC"}; | |||
161 | static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"}; | 165 | static const char *isabelle_vtx_texts[] = {"AMIC2", "DMIC"}; |
162 | 166 | ||
163 | static const struct soc_enum isabelle_atx_enum[] = { | 167 | static const struct soc_enum isabelle_atx_enum[] = { |
164 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, 1, isabelle_atx_texts), | 168 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 7, |
165 | SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_atx_texts), | 169 | ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), |
170 | SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, | ||
171 | ARRAY_SIZE(isabelle_atx_texts), isabelle_atx_texts), | ||
166 | }; | 172 | }; |
167 | 173 | ||
168 | static const struct soc_enum isabelle_vtx_enum[] = { | 174 | static const struct soc_enum isabelle_vtx_enum[] = { |
169 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, 1, isabelle_vtx_texts), | 175 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 6, |
170 | SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, 1, isabelle_vtx_texts), | 176 | ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), |
177 | SOC_ENUM_SINGLE(ISABELLE_DMIC_CFG_REG, 0, | ||
178 | ARRAY_SIZE(isabelle_vtx_texts), isabelle_vtx_texts), | ||
171 | }; | 179 | }; |
172 | 180 | ||
173 | static const struct snd_kcontrol_new atx_mux_controls = | 181 | static const struct snd_kcontrol_new atx_mux_controls = |
@@ -183,17 +191,13 @@ static const char *isabelle_amic1_texts[] = { | |||
183 | /* Left analog microphone selection */ | 191 | /* Left analog microphone selection */ |
184 | static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; | 192 | static const char *isabelle_amic2_texts[] = {"Sub Mic", "Aux/FM Right"}; |
185 | 193 | ||
186 | static const struct soc_enum isabelle_amic1_enum[] = { | 194 | static SOC_ENUM_SINGLE_DECL(isabelle_amic1_enum, |
187 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 5, | 195 | ISABELLE_AMIC_CFG_REG, 5, |
188 | ARRAY_SIZE(isabelle_amic1_texts), | 196 | isabelle_amic1_texts); |
189 | isabelle_amic1_texts), | ||
190 | }; | ||
191 | 197 | ||
192 | static const struct soc_enum isabelle_amic2_enum[] = { | 198 | static SOC_ENUM_SINGLE_DECL(isabelle_amic2_enum, |
193 | SOC_ENUM_SINGLE(ISABELLE_AMIC_CFG_REG, 4, | 199 | ISABELLE_AMIC_CFG_REG, 4, |
194 | ARRAY_SIZE(isabelle_amic2_texts), | 200 | isabelle_amic2_texts); |
195 | isabelle_amic2_texts), | ||
196 | }; | ||
197 | 201 | ||
198 | static const struct snd_kcontrol_new amic1_control = | 202 | static const struct snd_kcontrol_new amic1_control = |
199 | SOC_DAPM_ENUM("Route", isabelle_amic1_enum); | 203 | SOC_DAPM_ENUM("Route", isabelle_amic1_enum); |
@@ -206,16 +210,20 @@ static const char *isabelle_st_audio_texts[] = {"ATX1", "ATX2"}; | |||
206 | static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"}; | 210 | static const char *isabelle_st_voice_texts[] = {"VTX1", "VTX2"}; |
207 | 211 | ||
208 | static const struct soc_enum isabelle_st_audio_enum[] = { | 212 | static const struct soc_enum isabelle_st_audio_enum[] = { |
209 | SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, 1, | 213 | SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA1_CFG_REG, 7, |
214 | ARRAY_SIZE(isabelle_st_audio_texts), | ||
210 | isabelle_st_audio_texts), | 215 | isabelle_st_audio_texts), |
211 | SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, 1, | 216 | SOC_ENUM_SINGLE(ISABELLE_ATX_STPGA2_CFG_REG, 7, |
217 | ARRAY_SIZE(isabelle_st_audio_texts), | ||
212 | isabelle_st_audio_texts), | 218 | isabelle_st_audio_texts), |
213 | }; | 219 | }; |
214 | 220 | ||
215 | static const struct soc_enum isabelle_st_voice_enum[] = { | 221 | static const struct soc_enum isabelle_st_voice_enum[] = { |
216 | SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, 1, | 222 | SOC_ENUM_SINGLE(ISABELLE_VTX_STPGA1_CFG_REG, 7, |
223 | ARRAY_SIZE(isabelle_st_voice_texts), | ||
217 | isabelle_st_voice_texts), | 224 | isabelle_st_voice_texts), |
218 | SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, 1, | 225 | SOC_ENUM_SINGLE(ISABELLE_VTX2_STPGA2_CFG_REG, 7, |
226 | ARRAY_SIZE(isabelle_st_voice_texts), | ||
219 | isabelle_st_voice_texts), | 227 | isabelle_st_voice_texts), |
220 | }; | 228 | }; |
221 | 229 | ||
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index e19490cfb3a8..6b7fe5e54881 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c | |||
@@ -195,18 +195,18 @@ struct lm49453_priv { | |||
195 | 195 | ||
196 | static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"}; | 196 | static const char *lm49453_mic2mode_text[] = {"Single Ended", "Differential"}; |
197 | 197 | ||
198 | static const SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, | 198 | static SOC_ENUM_SINGLE_DECL(lm49453_mic2mode_enum, LM49453_P0_MICR_REG, 5, |
199 | lm49453_mic2mode_text); | 199 | lm49453_mic2mode_text); |
200 | 200 | ||
201 | static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"}; | 201 | static const char *lm49453_dmic_cfg_text[] = {"DMICDAT1", "DMICDAT2"}; |
202 | 202 | ||
203 | static const SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, | 203 | static SOC_ENUM_SINGLE_DECL(lm49453_dmic12_cfg_enum, |
204 | LM49453_P0_DIGITAL_MIC1_CONFIG_REG, | 204 | LM49453_P0_DIGITAL_MIC1_CONFIG_REG, 7, |
205 | 7, lm49453_dmic_cfg_text); | 205 | lm49453_dmic_cfg_text); |
206 | 206 | ||
207 | static const SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, | 207 | static SOC_ENUM_SINGLE_DECL(lm49453_dmic34_cfg_enum, |
208 | LM49453_P0_DIGITAL_MIC2_CONFIG_REG, | 208 | LM49453_P0_DIGITAL_MIC2_CONFIG_REG, 7, |
209 | 7, lm49453_dmic_cfg_text); | 209 | lm49453_dmic_cfg_text); |
210 | 210 | ||
211 | /* MUX Controls */ | 211 | /* MUX Controls */ |
212 | static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" }; | 212 | static const char *lm49453_adcl_mux_text[] = { "MIC1", "Aux_L" }; |
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index ee660e2d3df3..bb1ecfc4459b 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c | |||
@@ -1849,7 +1849,7 @@ static void max98088_handle_eq_pdata(struct snd_soc_codec *codec) | |||
1849 | 1849 | ||
1850 | /* Now point the soc_enum to .texts array items */ | 1850 | /* Now point the soc_enum to .texts array items */ |
1851 | max98088->eq_enum.texts = max98088->eq_texts; | 1851 | max98088->eq_enum.texts = max98088->eq_texts; |
1852 | max98088->eq_enum.max = max98088->eq_textcnt; | 1852 | max98088->eq_enum.items = max98088->eq_textcnt; |
1853 | 1853 | ||
1854 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 1854 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
1855 | if (ret != 0) | 1855 | if (ret != 0) |
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 51f9b3d16b41..f363de19be07 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c | |||
@@ -336,6 +336,7 @@ static bool max98090_readable_register(struct device *dev, unsigned int reg) | |||
336 | case M98090_REG_RECORD_TDM_SLOT: | 336 | case M98090_REG_RECORD_TDM_SLOT: |
337 | case M98090_REG_SAMPLE_RATE: | 337 | case M98090_REG_SAMPLE_RATE: |
338 | case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: | 338 | case M98090_REG_DMIC34_BIQUAD_BASE ... M98090_REG_DMIC34_BIQUAD_BASE + 0x0E: |
339 | case M98090_REG_REVISION_ID: | ||
339 | return true; | 340 | return true; |
340 | default: | 341 | default: |
341 | return false; | 342 | return false; |
@@ -512,65 +513,75 @@ static const char *max98090_perf_pwr_text[] = | |||
512 | static const char *max98090_pwr_perf_text[] = | 513 | static const char *max98090_pwr_perf_text[] = |
513 | { "Low Power", "High Performance" }; | 514 | { "Low Power", "High Performance" }; |
514 | 515 | ||
515 | static const struct soc_enum max98090_vcmbandgap_enum = | 516 | static SOC_ENUM_SINGLE_DECL(max98090_vcmbandgap_enum, |
516 | SOC_ENUM_SINGLE(M98090_REG_BIAS_CONTROL, M98090_VCM_MODE_SHIFT, | 517 | M98090_REG_BIAS_CONTROL, |
517 | ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); | 518 | M98090_VCM_MODE_SHIFT, |
519 | max98090_pwr_perf_text); | ||
518 | 520 | ||
519 | static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; | 521 | static const char *max98090_osr128_text[] = { "64*fs", "128*fs" }; |
520 | 522 | ||
521 | static const struct soc_enum max98090_osr128_enum = | 523 | static SOC_ENUM_SINGLE_DECL(max98090_osr128_enum, |
522 | SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_OSR128_SHIFT, | 524 | M98090_REG_ADC_CONTROL, |
523 | ARRAY_SIZE(max98090_osr128_text), max98090_osr128_text); | 525 | M98090_OSR128_SHIFT, |
526 | max98090_osr128_text); | ||
524 | 527 | ||
525 | static const char *max98090_mode_text[] = { "Voice", "Music" }; | 528 | static const char *max98090_mode_text[] = { "Voice", "Music" }; |
526 | 529 | ||
527 | static const struct soc_enum max98090_mode_enum = | 530 | static SOC_ENUM_SINGLE_DECL(max98090_mode_enum, |
528 | SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, M98090_MODE_SHIFT, | 531 | M98090_REG_FILTER_CONFIG, |
529 | ARRAY_SIZE(max98090_mode_text), max98090_mode_text); | 532 | M98090_MODE_SHIFT, |
533 | max98090_mode_text); | ||
530 | 534 | ||
531 | static const struct soc_enum max98090_filter_dmic34mode_enum = | 535 | static SOC_ENUM_SINGLE_DECL(max98090_filter_dmic34mode_enum, |
532 | SOC_ENUM_SINGLE(M98090_REG_FILTER_CONFIG, | 536 | M98090_REG_FILTER_CONFIG, |
533 | M98090_FLT_DMIC34MODE_SHIFT, | 537 | M98090_FLT_DMIC34MODE_SHIFT, |
534 | ARRAY_SIZE(max98090_mode_text), max98090_mode_text); | 538 | max98090_mode_text); |
535 | 539 | ||
536 | static const char *max98090_drcatk_text[] = | 540 | static const char *max98090_drcatk_text[] = |
537 | { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; | 541 | { "0.5ms", "1ms", "5ms", "10ms", "25ms", "50ms", "100ms", "200ms" }; |
538 | 542 | ||
539 | static const struct soc_enum max98090_drcatk_enum = | 543 | static SOC_ENUM_SINGLE_DECL(max98090_drcatk_enum, |
540 | SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCATK_SHIFT, | 544 | M98090_REG_DRC_TIMING, |
541 | ARRAY_SIZE(max98090_drcatk_text), max98090_drcatk_text); | 545 | M98090_DRCATK_SHIFT, |
546 | max98090_drcatk_text); | ||
542 | 547 | ||
543 | static const char *max98090_drcrls_text[] = | 548 | static const char *max98090_drcrls_text[] = |
544 | { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; | 549 | { "8s", "4s", "2s", "1s", "0.5s", "0.25s", "0.125s", "0.0625s" }; |
545 | 550 | ||
546 | static const struct soc_enum max98090_drcrls_enum = | 551 | static SOC_ENUM_SINGLE_DECL(max98090_drcrls_enum, |
547 | SOC_ENUM_SINGLE(M98090_REG_DRC_TIMING, M98090_DRCRLS_SHIFT, | 552 | M98090_REG_DRC_TIMING, |
548 | ARRAY_SIZE(max98090_drcrls_text), max98090_drcrls_text); | 553 | M98090_DRCRLS_SHIFT, |
554 | max98090_drcrls_text); | ||
549 | 555 | ||
550 | static const char *max98090_alccmp_text[] = | 556 | static const char *max98090_alccmp_text[] = |
551 | { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; | 557 | { "1:1", "1:1.5", "1:2", "1:4", "1:INF" }; |
552 | 558 | ||
553 | static const struct soc_enum max98090_alccmp_enum = | 559 | static SOC_ENUM_SINGLE_DECL(max98090_alccmp_enum, |
554 | SOC_ENUM_SINGLE(M98090_REG_DRC_COMPRESSOR, M98090_DRCCMP_SHIFT, | 560 | M98090_REG_DRC_COMPRESSOR, |
555 | ARRAY_SIZE(max98090_alccmp_text), max98090_alccmp_text); | 561 | M98090_DRCCMP_SHIFT, |
562 | max98090_alccmp_text); | ||
556 | 563 | ||
557 | static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; | 564 | static const char *max98090_drcexp_text[] = { "1:1", "2:1", "3:1" }; |
558 | 565 | ||
559 | static const struct soc_enum max98090_drcexp_enum = | 566 | static SOC_ENUM_SINGLE_DECL(max98090_drcexp_enum, |
560 | SOC_ENUM_SINGLE(M98090_REG_DRC_EXPANDER, M98090_DRCEXP_SHIFT, | 567 | M98090_REG_DRC_EXPANDER, |
561 | ARRAY_SIZE(max98090_drcexp_text), max98090_drcexp_text); | 568 | M98090_DRCEXP_SHIFT, |
569 | max98090_drcexp_text); | ||
562 | 570 | ||
563 | static const struct soc_enum max98090_dac_perfmode_enum = | 571 | static SOC_ENUM_SINGLE_DECL(max98090_dac_perfmode_enum, |
564 | SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_PERFMODE_SHIFT, | 572 | M98090_REG_DAC_CONTROL, |
565 | ARRAY_SIZE(max98090_perf_pwr_text), max98090_perf_pwr_text); | 573 | M98090_PERFMODE_SHIFT, |
574 | max98090_perf_pwr_text); | ||
566 | 575 | ||
567 | static const struct soc_enum max98090_dachp_enum = | 576 | static SOC_ENUM_SINGLE_DECL(max98090_dachp_enum, |
568 | SOC_ENUM_SINGLE(M98090_REG_DAC_CONTROL, M98090_DACHP_SHIFT, | 577 | M98090_REG_DAC_CONTROL, |
569 | ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); | 578 | M98090_DACHP_SHIFT, |
579 | max98090_pwr_perf_text); | ||
570 | 580 | ||
571 | static const struct soc_enum max98090_adchp_enum = | 581 | static SOC_ENUM_SINGLE_DECL(max98090_adchp_enum, |
572 | SOC_ENUM_SINGLE(M98090_REG_ADC_CONTROL, M98090_ADCHP_SHIFT, | 582 | M98090_REG_ADC_CONTROL, |
573 | ARRAY_SIZE(max98090_pwr_perf_text), max98090_pwr_perf_text); | 583 | M98090_ADCHP_SHIFT, |
584 | max98090_pwr_perf_text); | ||
574 | 585 | ||
575 | static const struct snd_kcontrol_new max98090_snd_controls[] = { | 586 | static const struct snd_kcontrol_new max98090_snd_controls[] = { |
576 | SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), | 587 | SOC_ENUM("MIC Bias VCM Bandgap", max98090_vcmbandgap_enum), |
@@ -841,39 +852,42 @@ static int max98090_micinput_event(struct snd_soc_dapm_widget *w, | |||
841 | 852 | ||
842 | static const char *mic1_mux_text[] = { "IN12", "IN56" }; | 853 | static const char *mic1_mux_text[] = { "IN12", "IN56" }; |
843 | 854 | ||
844 | static const struct soc_enum mic1_mux_enum = | 855 | static SOC_ENUM_SINGLE_DECL(mic1_mux_enum, |
845 | SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC1_SHIFT, | 856 | M98090_REG_INPUT_MODE, |
846 | ARRAY_SIZE(mic1_mux_text), mic1_mux_text); | 857 | M98090_EXTMIC1_SHIFT, |
858 | mic1_mux_text); | ||
847 | 859 | ||
848 | static const struct snd_kcontrol_new max98090_mic1_mux = | 860 | static const struct snd_kcontrol_new max98090_mic1_mux = |
849 | SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum); | 861 | SOC_DAPM_ENUM("MIC1 Mux", mic1_mux_enum); |
850 | 862 | ||
851 | static const char *mic2_mux_text[] = { "IN34", "IN56" }; | 863 | static const char *mic2_mux_text[] = { "IN34", "IN56" }; |
852 | 864 | ||
853 | static const struct soc_enum mic2_mux_enum = | 865 | static SOC_ENUM_SINGLE_DECL(mic2_mux_enum, |
854 | SOC_ENUM_SINGLE(M98090_REG_INPUT_MODE, M98090_EXTMIC2_SHIFT, | 866 | M98090_REG_INPUT_MODE, |
855 | ARRAY_SIZE(mic2_mux_text), mic2_mux_text); | 867 | M98090_EXTMIC2_SHIFT, |
868 | mic2_mux_text); | ||
856 | 869 | ||
857 | static const struct snd_kcontrol_new max98090_mic2_mux = | 870 | static const struct snd_kcontrol_new max98090_mic2_mux = |
858 | SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); | 871 | SOC_DAPM_ENUM("MIC2 Mux", mic2_mux_enum); |
859 | 872 | ||
860 | static const char *dmic_mux_text[] = { "ADC", "DMIC" }; | 873 | static const char *dmic_mux_text[] = { "ADC", "DMIC" }; |
861 | 874 | ||
862 | static const struct soc_enum dmic_mux_enum = | 875 | static SOC_ENUM_SINGLE_VIRT_DECL(dmic_mux_enum, dmic_mux_text); |
863 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(dmic_mux_text), dmic_mux_text); | ||
864 | 876 | ||
865 | static const struct snd_kcontrol_new max98090_dmic_mux = | 877 | static const struct snd_kcontrol_new max98090_dmic_mux = |
866 | SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); | 878 | SOC_DAPM_ENUM_VIRT("DMIC Mux", dmic_mux_enum); |
867 | 879 | ||
868 | static const char *max98090_micpre_text[] = { "Off", "On" }; | 880 | static const char *max98090_micpre_text[] = { "Off", "On" }; |
869 | 881 | ||
870 | static const struct soc_enum max98090_pa1en_enum = | 882 | static SOC_ENUM_SINGLE_DECL(max98090_pa1en_enum, |
871 | SOC_ENUM_SINGLE(M98090_REG_MIC1_INPUT_LEVEL, M98090_MIC_PA1EN_SHIFT, | 883 | M98090_REG_MIC1_INPUT_LEVEL, |
872 | ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); | 884 | M98090_MIC_PA1EN_SHIFT, |
885 | max98090_micpre_text); | ||
873 | 886 | ||
874 | static const struct soc_enum max98090_pa2en_enum = | 887 | static SOC_ENUM_SINGLE_DECL(max98090_pa2en_enum, |
875 | SOC_ENUM_SINGLE(M98090_REG_MIC2_INPUT_LEVEL, M98090_MIC_PA2EN_SHIFT, | 888 | M98090_REG_MIC2_INPUT_LEVEL, |
876 | ARRAY_SIZE(max98090_micpre_text), max98090_micpre_text); | 889 | M98090_MIC_PA2EN_SHIFT, |
890 | max98090_micpre_text); | ||
877 | 891 | ||
878 | /* LINEA mixer switch */ | 892 | /* LINEA mixer switch */ |
879 | static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { | 893 | static const struct snd_kcontrol_new max98090_linea_mixer_controls[] = { |
@@ -937,13 +951,15 @@ static const struct snd_kcontrol_new max98090_right_adc_mixer_controls[] = { | |||
937 | 951 | ||
938 | static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; | 952 | static const char *lten_mux_text[] = { "Normal", "Loopthrough" }; |
939 | 953 | ||
940 | static const struct soc_enum ltenl_mux_enum = | 954 | static SOC_ENUM_SINGLE_DECL(ltenl_mux_enum, |
941 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, | 955 | M98090_REG_IO_CONFIGURATION, |
942 | ARRAY_SIZE(lten_mux_text), lten_mux_text); | 956 | M98090_LTEN_SHIFT, |
957 | lten_mux_text); | ||
943 | 958 | ||
944 | static const struct soc_enum ltenr_mux_enum = | 959 | static SOC_ENUM_SINGLE_DECL(ltenr_mux_enum, |
945 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LTEN_SHIFT, | 960 | M98090_REG_IO_CONFIGURATION, |
946 | ARRAY_SIZE(lten_mux_text), lten_mux_text); | 961 | M98090_LTEN_SHIFT, |
962 | lten_mux_text); | ||
947 | 963 | ||
948 | static const struct snd_kcontrol_new max98090_ltenl_mux = | 964 | static const struct snd_kcontrol_new max98090_ltenl_mux = |
949 | SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); | 965 | SOC_DAPM_ENUM("LTENL Mux", ltenl_mux_enum); |
@@ -953,13 +969,15 @@ static const struct snd_kcontrol_new max98090_ltenr_mux = | |||
953 | 969 | ||
954 | static const char *lben_mux_text[] = { "Normal", "Loopback" }; | 970 | static const char *lben_mux_text[] = { "Normal", "Loopback" }; |
955 | 971 | ||
956 | static const struct soc_enum lbenl_mux_enum = | 972 | static SOC_ENUM_SINGLE_DECL(lbenl_mux_enum, |
957 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, | 973 | M98090_REG_IO_CONFIGURATION, |
958 | ARRAY_SIZE(lben_mux_text), lben_mux_text); | 974 | M98090_LBEN_SHIFT, |
975 | lben_mux_text); | ||
959 | 976 | ||
960 | static const struct soc_enum lbenr_mux_enum = | 977 | static SOC_ENUM_SINGLE_DECL(lbenr_mux_enum, |
961 | SOC_ENUM_SINGLE(M98090_REG_IO_CONFIGURATION, M98090_LBEN_SHIFT, | 978 | M98090_REG_IO_CONFIGURATION, |
962 | ARRAY_SIZE(lben_mux_text), lben_mux_text); | 979 | M98090_LBEN_SHIFT, |
980 | lben_mux_text); | ||
963 | 981 | ||
964 | static const struct snd_kcontrol_new max98090_lbenl_mux = | 982 | static const struct snd_kcontrol_new max98090_lbenl_mux = |
965 | SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); | 983 | SOC_DAPM_ENUM("LBENL Mux", lbenl_mux_enum); |
@@ -971,13 +989,15 @@ static const char *stenl_mux_text[] = { "Normal", "Sidetone Left" }; | |||
971 | 989 | ||
972 | static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; | 990 | static const char *stenr_mux_text[] = { "Normal", "Sidetone Right" }; |
973 | 991 | ||
974 | static const struct soc_enum stenl_mux_enum = | 992 | static SOC_ENUM_SINGLE_DECL(stenl_mux_enum, |
975 | SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSL_SHIFT, | 993 | M98090_REG_ADC_SIDETONE, |
976 | ARRAY_SIZE(stenl_mux_text), stenl_mux_text); | 994 | M98090_DSTSL_SHIFT, |
995 | stenl_mux_text); | ||
977 | 996 | ||
978 | static const struct soc_enum stenr_mux_enum = | 997 | static SOC_ENUM_SINGLE_DECL(stenr_mux_enum, |
979 | SOC_ENUM_SINGLE(M98090_REG_ADC_SIDETONE, M98090_DSTSR_SHIFT, | 998 | M98090_REG_ADC_SIDETONE, |
980 | ARRAY_SIZE(stenr_mux_text), stenr_mux_text); | 999 | M98090_DSTSR_SHIFT, |
1000 | stenr_mux_text); | ||
981 | 1001 | ||
982 | static const struct snd_kcontrol_new max98090_stenl_mux = | 1002 | static const struct snd_kcontrol_new max98090_stenl_mux = |
983 | SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); | 1003 | SOC_DAPM_ENUM("STENL Mux", stenl_mux_enum); |
@@ -1085,9 +1105,10 @@ static const struct snd_kcontrol_new max98090_right_rcv_mixer_controls[] = { | |||
1085 | 1105 | ||
1086 | static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; | 1106 | static const char *linmod_mux_text[] = { "Left Only", "Left and Right" }; |
1087 | 1107 | ||
1088 | static const struct soc_enum linmod_mux_enum = | 1108 | static SOC_ENUM_SINGLE_DECL(linmod_mux_enum, |
1089 | SOC_ENUM_SINGLE(M98090_REG_LOUTR_MIXER, M98090_LINMOD_SHIFT, | 1109 | M98090_REG_LOUTR_MIXER, |
1090 | ARRAY_SIZE(linmod_mux_text), linmod_mux_text); | 1110 | M98090_LINMOD_SHIFT, |
1111 | linmod_mux_text); | ||
1091 | 1112 | ||
1092 | static const struct snd_kcontrol_new max98090_linmod_mux = | 1113 | static const struct snd_kcontrol_new max98090_linmod_mux = |
1093 | SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); | 1114 | SOC_DAPM_ENUM("LINMOD Mux", linmod_mux_enum); |
@@ -1097,16 +1118,18 @@ static const char *mixhpsel_mux_text[] = { "DAC Only", "HP Mixer" }; | |||
1097 | /* | 1118 | /* |
1098 | * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable | 1119 | * This is a mux as it selects the HP output, but to DAPM it is a Mixer enable |
1099 | */ | 1120 | */ |
1100 | static const struct soc_enum mixhplsel_mux_enum = | 1121 | static SOC_ENUM_SINGLE_DECL(mixhplsel_mux_enum, |
1101 | SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPLSEL_SHIFT, | 1122 | M98090_REG_HP_CONTROL, |
1102 | ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); | 1123 | M98090_MIXHPLSEL_SHIFT, |
1124 | mixhpsel_mux_text); | ||
1103 | 1125 | ||
1104 | static const struct snd_kcontrol_new max98090_mixhplsel_mux = | 1126 | static const struct snd_kcontrol_new max98090_mixhplsel_mux = |
1105 | SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); | 1127 | SOC_DAPM_ENUM("MIXHPLSEL Mux", mixhplsel_mux_enum); |
1106 | 1128 | ||
1107 | static const struct soc_enum mixhprsel_mux_enum = | 1129 | static SOC_ENUM_SINGLE_DECL(mixhprsel_mux_enum, |
1108 | SOC_ENUM_SINGLE(M98090_REG_HP_CONTROL, M98090_MIXHPRSEL_SHIFT, | 1130 | M98090_REG_HP_CONTROL, |
1109 | ARRAY_SIZE(mixhpsel_mux_text), mixhpsel_mux_text); | 1131 | M98090_MIXHPRSEL_SHIFT, |
1132 | mixhpsel_mux_text); | ||
1110 | 1133 | ||
1111 | static const struct snd_kcontrol_new max98090_mixhprsel_mux = | 1134 | static const struct snd_kcontrol_new max98090_mixhprsel_mux = |
1112 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); | 1135 | SOC_DAPM_ENUM("MIXHPRSEL Mux", mixhprsel_mux_enum); |
@@ -1769,16 +1792,6 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, | |||
1769 | 1792 | ||
1770 | switch (level) { | 1793 | switch (level) { |
1771 | case SND_SOC_BIAS_ON: | 1794 | case SND_SOC_BIAS_ON: |
1772 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
1773 | ret = regcache_sync(max98090->regmap); | ||
1774 | |||
1775 | if (ret != 0) { | ||
1776 | dev_err(codec->dev, | ||
1777 | "Failed to sync cache: %d\n", ret); | ||
1778 | return ret; | ||
1779 | } | ||
1780 | } | ||
1781 | |||
1782 | if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { | 1795 | if (max98090->jack_state == M98090_JACK_STATE_HEADSET) { |
1783 | /* | 1796 | /* |
1784 | * Set to normal bias level. | 1797 | * Set to normal bias level. |
@@ -1792,6 +1805,16 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, | |||
1792 | break; | 1805 | break; |
1793 | 1806 | ||
1794 | case SND_SOC_BIAS_STANDBY: | 1807 | case SND_SOC_BIAS_STANDBY: |
1808 | if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { | ||
1809 | ret = regcache_sync(max98090->regmap); | ||
1810 | if (ret != 0) { | ||
1811 | dev_err(codec->dev, | ||
1812 | "Failed to sync cache: %d\n", ret); | ||
1813 | return ret; | ||
1814 | } | ||
1815 | } | ||
1816 | break; | ||
1817 | |||
1795 | case SND_SOC_BIAS_OFF: | 1818 | case SND_SOC_BIAS_OFF: |
1796 | /* Set internal pull-up to lowest power mode */ | 1819 | /* Set internal pull-up to lowest power mode */ |
1797 | snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, | 1820 | snd_soc_update_bits(codec, M98090_REG_JACK_DETECT, |
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 3ba1170ebb53..5bce9cde4a6d 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c | |||
@@ -1861,7 +1861,7 @@ static void max98095_handle_eq_pdata(struct snd_soc_codec *codec) | |||
1861 | 1861 | ||
1862 | /* Now point the soc_enum to .texts array items */ | 1862 | /* Now point the soc_enum to .texts array items */ |
1863 | max98095->eq_enum.texts = max98095->eq_texts; | 1863 | max98095->eq_enum.texts = max98095->eq_texts; |
1864 | max98095->eq_enum.max = max98095->eq_textcnt; | 1864 | max98095->eq_enum.items = max98095->eq_textcnt; |
1865 | 1865 | ||
1866 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 1866 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
1867 | if (ret != 0) | 1867 | if (ret != 0) |
@@ -2016,7 +2016,7 @@ static void max98095_handle_bq_pdata(struct snd_soc_codec *codec) | |||
2016 | 2016 | ||
2017 | /* Now point the soc_enum to .texts array items */ | 2017 | /* Now point the soc_enum to .texts array items */ |
2018 | max98095->bq_enum.texts = max98095->bq_texts; | 2018 | max98095->bq_enum.texts = max98095->bq_texts; |
2019 | max98095->bq_enum.max = max98095->bq_textcnt; | 2019 | max98095->bq_enum.items = max98095->bq_textcnt; |
2020 | 2020 | ||
2021 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 2021 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
2022 | if (ret != 0) | 2022 | if (ret != 0) |
diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 582c2bbd42cb..ec89b8f90a64 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c | |||
@@ -408,8 +408,7 @@ static const char * const adcl_enum_text[] = { | |||
408 | "MC1L", "RXINL", | 408 | "MC1L", "RXINL", |
409 | }; | 409 | }; |
410 | 410 | ||
411 | static const struct soc_enum adcl_enum = | 411 | static SOC_ENUM_SINGLE_VIRT_DECL(adcl_enum, adcl_enum_text); |
412 | SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcl_enum_text), adcl_enum_text); | ||
413 | 412 | ||
414 | static const struct snd_kcontrol_new left_input_mux = | 413 | static const struct snd_kcontrol_new left_input_mux = |
415 | SOC_DAPM_ENUM_VIRT("Route", adcl_enum); | 414 | SOC_DAPM_ENUM_VIRT("Route", adcl_enum); |
@@ -418,8 +417,7 @@ static const char * const adcr_enum_text[] = { | |||
418 | "MC1R", "MC2", "RXINR", "TXIN", | 417 | "MC1R", "MC2", "RXINR", "TXIN", |
419 | }; | 418 | }; |
420 | 419 | ||
421 | static const struct soc_enum adcr_enum = | 420 | static SOC_ENUM_SINGLE_VIRT_DECL(adcr_enum, adcr_enum_text); |
422 | SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(adcr_enum_text), adcr_enum_text); | ||
423 | 421 | ||
424 | static const struct snd_kcontrol_new right_input_mux = | 422 | static const struct snd_kcontrol_new right_input_mux = |
425 | SOC_DAPM_ENUM_VIRT("Route", adcr_enum); | 423 | SOC_DAPM_ENUM_VIRT("Route", adcr_enum); |
@@ -430,8 +428,8 @@ static const struct snd_kcontrol_new samp_ctl = | |||
430 | static const char * const speaker_amp_source_text[] = { | 428 | static const char * const speaker_amp_source_text[] = { |
431 | "CODEC", "Right" | 429 | "CODEC", "Right" |
432 | }; | 430 | }; |
433 | static const SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, | 431 | static SOC_ENUM_SINGLE_DECL(speaker_amp_source, MC13783_AUDIO_RX0, 4, |
434 | speaker_amp_source_text); | 432 | speaker_amp_source_text); |
435 | static const struct snd_kcontrol_new speaker_amp_source_mux = | 433 | static const struct snd_kcontrol_new speaker_amp_source_mux = |
436 | SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); | 434 | SOC_DAPM_ENUM("Speaker Amp Source MUX", speaker_amp_source); |
437 | 435 | ||
@@ -439,8 +437,8 @@ static const char * const headset_amp_source_text[] = { | |||
439 | "CODEC", "Mixer" | 437 | "CODEC", "Mixer" |
440 | }; | 438 | }; |
441 | 439 | ||
442 | static const SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, | 440 | static SOC_ENUM_SINGLE_DECL(headset_amp_source, MC13783_AUDIO_RX0, 11, |
443 | headset_amp_source_text); | 441 | headset_amp_source_text); |
444 | static const struct snd_kcontrol_new headset_amp_source_mux = | 442 | static const struct snd_kcontrol_new headset_amp_source_mux = |
445 | SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); | 443 | SOC_DAPM_ENUM("Headset Amp Source MUX", headset_amp_source); |
446 | 444 | ||
@@ -580,9 +578,9 @@ static struct snd_soc_dapm_route mc13783_routes[] = { | |||
580 | static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", | 578 | static const char * const mc13783_3d_mixer[] = {"Stereo", "Phase Mix", |
581 | "Mono", "Mono Mix"}; | 579 | "Mono", "Mono Mix"}; |
582 | 580 | ||
583 | static const struct soc_enum mc13783_enum_3d_mixer = | 581 | static SOC_ENUM_SINGLE_DECL(mc13783_enum_3d_mixer, |
584 | SOC_ENUM_SINGLE(MC13783_AUDIO_RX1, 16, ARRAY_SIZE(mc13783_3d_mixer), | 582 | MC13783_AUDIO_RX1, 16, |
585 | mc13783_3d_mixer); | 583 | mc13783_3d_mixer); |
586 | 584 | ||
587 | static struct snd_kcontrol_new mc13783_control_list[] = { | 585 | static struct snd_kcontrol_new mc13783_control_list[] = { |
588 | SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0), | 586 | SOC_SINGLE("Loudspeaker enable", MC13783_AUDIO_RX0, 5, 1, 0), |
diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index 185fa3bc3052..577fb8776ce7 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c | |||
@@ -73,11 +73,11 @@ static const DECLARE_TLV_DB_SCALE(ngth, -7650, 150, 0); | |||
73 | static const char * const ml26124_companding[] = {"16bit PCM", "u-law", | 73 | static const char * const ml26124_companding[] = {"16bit PCM", "u-law", |
74 | "A-law"}; | 74 | "A-law"}; |
75 | 75 | ||
76 | static const struct soc_enum ml26124_adc_companding_enum | 76 | static SOC_ENUM_SINGLE_DECL(ml26124_adc_companding_enum, |
77 | = SOC_ENUM_SINGLE(ML26124_SAI_TRANS_CTL, 6, 3, ml26124_companding); | 77 | ML26124_SAI_TRANS_CTL, 6, ml26124_companding); |
78 | 78 | ||
79 | static const struct soc_enum ml26124_dac_companding_enum | 79 | static SOC_ENUM_SINGLE_DECL(ml26124_dac_companding_enum, |
80 | = SOC_ENUM_SINGLE(ML26124_SAI_RCV_CTL, 6, 3, ml26124_companding); | 80 | ML26124_SAI_RCV_CTL, 6, ml26124_companding); |
81 | 81 | ||
82 | static const struct snd_kcontrol_new ml26124_snd_controls[] = { | 82 | static const struct snd_kcontrol_new ml26124_snd_controls[] = { |
83 | SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0, | 83 | SOC_SINGLE_TLV("Capture Digital Volume", ML26124_RECORD_DIG_VOL, 0, |
@@ -136,8 +136,8 @@ static const struct snd_kcontrol_new ml26124_output_mixer_controls[] = { | |||
136 | static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in", | 136 | static const char * const ml26124_input_select[] = {"Analog MIC SingleEnded in", |
137 | "Digital MIC in", "Analog MIC Differential in"}; | 137 | "Digital MIC in", "Analog MIC Differential in"}; |
138 | 138 | ||
139 | static const struct soc_enum ml26124_insel_enum = | 139 | static SOC_ENUM_SINGLE_DECL(ml26124_insel_enum, |
140 | SOC_ENUM_SINGLE(ML26124_MIC_IF_CTL, 0, 3, ml26124_input_select); | 140 | ML26124_MIC_IF_CTL, 0, ml26124_input_select); |
141 | 141 | ||
142 | static const struct snd_kcontrol_new ml26124_input_mux_controls = | 142 | static const struct snd_kcontrol_new ml26124_input_mux_controls = |
143 | SOC_DAPM_ENUM("Input Select", ml26124_insel_enum); | 143 | SOC_DAPM_ENUM("Input Select", ml26124_insel_enum); |
diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 73f9c3630e2c..e427544183d7 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c | |||
@@ -172,16 +172,21 @@ static int pcm1681_hw_params(struct snd_pcm_substream *substream, | |||
172 | struct snd_soc_codec *codec = dai->codec; | 172 | struct snd_soc_codec *codec = dai->codec; |
173 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); | 173 | struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); |
174 | int val = 0, ret; | 174 | int val = 0, ret; |
175 | int pcm_format = params_format(params); | ||
176 | 175 | ||
177 | priv->rate = params_rate(params); | 176 | priv->rate = params_rate(params); |
178 | 177 | ||
179 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | 178 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
180 | case SND_SOC_DAIFMT_RIGHT_J: | 179 | case SND_SOC_DAIFMT_RIGHT_J: |
181 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE) | 180 | switch (params_width(params)) { |
182 | val = 0x00; | 181 | case 24: |
183 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | 182 | val = 0; |
184 | val = 0x03; | 183 | break; |
184 | case 16: | ||
185 | val = 3; | ||
186 | break; | ||
187 | default: | ||
188 | return -EINVAL; | ||
189 | } | ||
185 | break; | 190 | break; |
186 | case SND_SOC_DAIFMT_I2S: | 191 | case SND_SOC_DAIFMT_I2S: |
187 | val = 0x04; | 192 | val = 0x04; |
diff --git a/sound/soc/codecs/pcm1792a.c b/sound/soc/codecs/pcm1792a.c index 7146653a8e16..3a80ba4452df 100644 --- a/sound/soc/codecs/pcm1792a.c +++ b/sound/soc/codecs/pcm1792a.c | |||
@@ -107,24 +107,35 @@ static int pcm1792a_hw_params(struct snd_pcm_substream *substream, | |||
107 | struct snd_soc_codec *codec = dai->codec; | 107 | struct snd_soc_codec *codec = dai->codec; |
108 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); | 108 | struct pcm1792a_private *priv = snd_soc_codec_get_drvdata(codec); |
109 | int val = 0, ret; | 109 | int val = 0, ret; |
110 | int pcm_format = params_format(params); | ||
111 | 110 | ||
112 | priv->rate = params_rate(params); | 111 | priv->rate = params_rate(params); |
113 | 112 | ||
114 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { | 113 | switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { |
115 | case SND_SOC_DAIFMT_RIGHT_J: | 114 | case SND_SOC_DAIFMT_RIGHT_J: |
116 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || | 115 | switch (params_width(params)) { |
117 | pcm_format == SNDRV_PCM_FORMAT_S32_LE) | 116 | case 24: |
118 | val = 0x02; | 117 | case 32: |
119 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | 118 | val = 2; |
120 | val = 0x00; | 119 | break; |
120 | case 16: | ||
121 | val = 0; | ||
122 | break; | ||
123 | default: | ||
124 | return -EINVAL; | ||
125 | } | ||
121 | break; | 126 | break; |
122 | case SND_SOC_DAIFMT_I2S: | 127 | case SND_SOC_DAIFMT_I2S: |
123 | if (pcm_format == SNDRV_PCM_FORMAT_S24_LE || | 128 | switch (params_width(params)) { |
124 | pcm_format == SNDRV_PCM_FORMAT_S32_LE) | 129 | case 24: |
125 | val = 0x05; | 130 | case 32: |
126 | else if (pcm_format == SNDRV_PCM_FORMAT_S16_LE) | 131 | val = 5; |
127 | val = 0x04; | 132 | break; |
133 | case 16: | ||
134 | val = 4; | ||
135 | break; | ||
136 | default: | ||
137 | return -EINVAL; | ||
138 | } | ||
128 | break; | 139 | break; |
129 | default: | 140 | default: |
130 | dev_err(codec->dev, "Invalid DAI format\n"); | 141 | dev_err(codec->dev, "Invalid DAI format\n"); |
diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c new file mode 100644 index 000000000000..4d62230bd378 --- /dev/null +++ b/sound/soc/codecs/pcm512x-i2c.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/i2c.h> | ||
20 | |||
21 | #include "pcm512x.h" | ||
22 | |||
23 | static int pcm512x_i2c_probe(struct i2c_client *i2c, | ||
24 | const struct i2c_device_id *id) | ||
25 | { | ||
26 | struct regmap *regmap; | ||
27 | |||
28 | regmap = devm_regmap_init_i2c(i2c, &pcm512x_regmap); | ||
29 | if (IS_ERR(regmap)) | ||
30 | return PTR_ERR(regmap); | ||
31 | |||
32 | return pcm512x_probe(&i2c->dev, regmap); | ||
33 | } | ||
34 | |||
35 | static int pcm512x_i2c_remove(struct i2c_client *i2c) | ||
36 | { | ||
37 | pcm512x_remove(&i2c->dev); | ||
38 | return 0; | ||
39 | } | ||
40 | |||
41 | static const struct i2c_device_id pcm512x_i2c_id[] = { | ||
42 | { "pcm5121", }, | ||
43 | { "pcm5122", }, | ||
44 | { } | ||
45 | }; | ||
46 | MODULE_DEVICE_TABLE(i2c, pcm512x_i2c_id); | ||
47 | |||
48 | static const struct of_device_id pcm512x_of_match[] = { | ||
49 | { .compatible = "ti,pcm5121", }, | ||
50 | { .compatible = "ti,pcm5122", }, | ||
51 | { } | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(of, pcm512x_of_match); | ||
54 | |||
55 | static struct i2c_driver pcm512x_i2c_driver = { | ||
56 | .probe = pcm512x_i2c_probe, | ||
57 | .remove = pcm512x_i2c_remove, | ||
58 | .id_table = pcm512x_i2c_id, | ||
59 | .driver = { | ||
60 | .name = "pcm512x", | ||
61 | .owner = THIS_MODULE, | ||
62 | .of_match_table = pcm512x_of_match, | ||
63 | .pm = &pcm512x_pm_ops, | ||
64 | }, | ||
65 | }; | ||
66 | |||
67 | module_i2c_driver(pcm512x_i2c_driver); | ||
68 | |||
69 | MODULE_DESCRIPTION("ASoC PCM512x codec driver - I2C"); | ||
70 | MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); | ||
71 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c new file mode 100644 index 000000000000..f297058c0038 --- /dev/null +++ b/sound/soc/codecs/pcm512x-spi.c | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/init.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/spi/spi.h> | ||
20 | |||
21 | #include "pcm512x.h" | ||
22 | |||
23 | static int pcm512x_spi_probe(struct spi_device *spi) | ||
24 | { | ||
25 | struct regmap *regmap; | ||
26 | int ret; | ||
27 | |||
28 | regmap = devm_regmap_init_spi(spi, &pcm512x_regmap); | ||
29 | if (IS_ERR(regmap)) { | ||
30 | ret = PTR_ERR(regmap); | ||
31 | return ret; | ||
32 | } | ||
33 | |||
34 | return pcm512x_probe(&spi->dev, regmap); | ||
35 | } | ||
36 | |||
37 | static int pcm512x_spi_remove(struct spi_device *spi) | ||
38 | { | ||
39 | pcm512x_remove(&spi->dev); | ||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static const struct spi_device_id pcm512x_spi_id[] = { | ||
44 | { "pcm5121", }, | ||
45 | { "pcm5122", }, | ||
46 | { }, | ||
47 | }; | ||
48 | MODULE_DEVICE_TABLE(spi, pcm512x_spi_id); | ||
49 | |||
50 | static const struct of_device_id pcm512x_of_match[] = { | ||
51 | { .compatible = "ti,pcm5121", }, | ||
52 | { .compatible = "ti,pcm5122", }, | ||
53 | { } | ||
54 | }; | ||
55 | MODULE_DEVICE_TABLE(of, pcm512x_of_match); | ||
56 | |||
57 | static struct spi_driver pcm512x_spi_driver = { | ||
58 | .probe = pcm512x_spi_probe, | ||
59 | .remove = pcm512x_spi_remove, | ||
60 | .id_table = pcm512x_spi_id, | ||
61 | .driver = { | ||
62 | .name = "pcm512x", | ||
63 | .owner = THIS_MODULE, | ||
64 | .of_match_table = pcm512x_of_match, | ||
65 | .pm = &pcm512x_pm_ops, | ||
66 | }, | ||
67 | }; | ||
68 | |||
69 | module_spi_driver(pcm512x_spi_driver); | ||
diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c new file mode 100644 index 000000000000..4b4c0c7bb918 --- /dev/null +++ b/sound/soc/codecs/pcm512x.c | |||
@@ -0,0 +1,589 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | |||
18 | #include <linux/init.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/clk.h> | ||
21 | #include <linux/pm_runtime.h> | ||
22 | #include <linux/regmap.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <sound/soc.h> | ||
25 | #include <sound/soc-dapm.h> | ||
26 | #include <sound/tlv.h> | ||
27 | |||
28 | #include "pcm512x.h" | ||
29 | |||
30 | #define PCM512x_NUM_SUPPLIES 3 | ||
31 | static const char * const pcm512x_supply_names[PCM512x_NUM_SUPPLIES] = { | ||
32 | "AVDD", | ||
33 | "DVDD", | ||
34 | "CPVDD", | ||
35 | }; | ||
36 | |||
37 | struct pcm512x_priv { | ||
38 | struct regmap *regmap; | ||
39 | struct clk *sclk; | ||
40 | struct regulator_bulk_data supplies[PCM512x_NUM_SUPPLIES]; | ||
41 | struct notifier_block supply_nb[PCM512x_NUM_SUPPLIES]; | ||
42 | }; | ||
43 | |||
44 | /* | ||
45 | * We can't use the same notifier block for more than one supply and | ||
46 | * there's no way I can see to get from a callback to the caller | ||
47 | * except container_of(). | ||
48 | */ | ||
49 | #define PCM512x_REGULATOR_EVENT(n) \ | ||
50 | static int pcm512x_regulator_event_##n(struct notifier_block *nb, \ | ||
51 | unsigned long event, void *data) \ | ||
52 | { \ | ||
53 | struct pcm512x_priv *pcm512x = container_of(nb, struct pcm512x_priv, \ | ||
54 | supply_nb[n]); \ | ||
55 | if (event & REGULATOR_EVENT_DISABLE) { \ | ||
56 | regcache_mark_dirty(pcm512x->regmap); \ | ||
57 | regcache_cache_only(pcm512x->regmap, true); \ | ||
58 | } \ | ||
59 | return 0; \ | ||
60 | } | ||
61 | |||
62 | PCM512x_REGULATOR_EVENT(0) | ||
63 | PCM512x_REGULATOR_EVENT(1) | ||
64 | PCM512x_REGULATOR_EVENT(2) | ||
65 | |||
66 | static const struct reg_default pcm512x_reg_defaults[] = { | ||
67 | { PCM512x_RESET, 0x00 }, | ||
68 | { PCM512x_POWER, 0x00 }, | ||
69 | { PCM512x_MUTE, 0x00 }, | ||
70 | { PCM512x_DSP, 0x00 }, | ||
71 | { PCM512x_PLL_REF, 0x00 }, | ||
72 | { PCM512x_DAC_ROUTING, 0x11 }, | ||
73 | { PCM512x_DSP_PROGRAM, 0x01 }, | ||
74 | { PCM512x_CLKDET, 0x00 }, | ||
75 | { PCM512x_AUTO_MUTE, 0x00 }, | ||
76 | { PCM512x_ERROR_DETECT, 0x00 }, | ||
77 | { PCM512x_DIGITAL_VOLUME_1, 0x00 }, | ||
78 | { PCM512x_DIGITAL_VOLUME_2, 0x30 }, | ||
79 | { PCM512x_DIGITAL_VOLUME_3, 0x30 }, | ||
80 | { PCM512x_DIGITAL_MUTE_1, 0x22 }, | ||
81 | { PCM512x_DIGITAL_MUTE_2, 0x00 }, | ||
82 | { PCM512x_DIGITAL_MUTE_3, 0x07 }, | ||
83 | { PCM512x_OUTPUT_AMPLITUDE, 0x00 }, | ||
84 | { PCM512x_ANALOG_GAIN_CTRL, 0x00 }, | ||
85 | { PCM512x_UNDERVOLTAGE_PROT, 0x00 }, | ||
86 | { PCM512x_ANALOG_MUTE_CTRL, 0x00 }, | ||
87 | { PCM512x_ANALOG_GAIN_BOOST, 0x00 }, | ||
88 | { PCM512x_VCOM_CTRL_1, 0x00 }, | ||
89 | { PCM512x_VCOM_CTRL_2, 0x01 }, | ||
90 | }; | ||
91 | |||
92 | static bool pcm512x_readable(struct device *dev, unsigned int reg) | ||
93 | { | ||
94 | switch (reg) { | ||
95 | case PCM512x_RESET: | ||
96 | case PCM512x_POWER: | ||
97 | case PCM512x_MUTE: | ||
98 | case PCM512x_PLL_EN: | ||
99 | case PCM512x_SPI_MISO_FUNCTION: | ||
100 | case PCM512x_DSP: | ||
101 | case PCM512x_GPIO_EN: | ||
102 | case PCM512x_BCLK_LRCLK_CFG: | ||
103 | case PCM512x_DSP_GPIO_INPUT: | ||
104 | case PCM512x_MASTER_MODE: | ||
105 | case PCM512x_PLL_REF: | ||
106 | case PCM512x_PLL_COEFF_0: | ||
107 | case PCM512x_PLL_COEFF_1: | ||
108 | case PCM512x_PLL_COEFF_2: | ||
109 | case PCM512x_PLL_COEFF_3: | ||
110 | case PCM512x_PLL_COEFF_4: | ||
111 | case PCM512x_DSP_CLKDIV: | ||
112 | case PCM512x_DAC_CLKDIV: | ||
113 | case PCM512x_NCP_CLKDIV: | ||
114 | case PCM512x_OSR_CLKDIV: | ||
115 | case PCM512x_MASTER_CLKDIV_1: | ||
116 | case PCM512x_MASTER_CLKDIV_2: | ||
117 | case PCM512x_FS_SPEED_MODE: | ||
118 | case PCM512x_IDAC_1: | ||
119 | case PCM512x_IDAC_2: | ||
120 | case PCM512x_ERROR_DETECT: | ||
121 | case PCM512x_I2S_1: | ||
122 | case PCM512x_I2S_2: | ||
123 | case PCM512x_DAC_ROUTING: | ||
124 | case PCM512x_DSP_PROGRAM: | ||
125 | case PCM512x_CLKDET: | ||
126 | case PCM512x_AUTO_MUTE: | ||
127 | case PCM512x_DIGITAL_VOLUME_1: | ||
128 | case PCM512x_DIGITAL_VOLUME_2: | ||
129 | case PCM512x_DIGITAL_VOLUME_3: | ||
130 | case PCM512x_DIGITAL_MUTE_1: | ||
131 | case PCM512x_DIGITAL_MUTE_2: | ||
132 | case PCM512x_DIGITAL_MUTE_3: | ||
133 | case PCM512x_GPIO_OUTPUT_1: | ||
134 | case PCM512x_GPIO_OUTPUT_2: | ||
135 | case PCM512x_GPIO_OUTPUT_3: | ||
136 | case PCM512x_GPIO_OUTPUT_4: | ||
137 | case PCM512x_GPIO_OUTPUT_5: | ||
138 | case PCM512x_GPIO_OUTPUT_6: | ||
139 | case PCM512x_GPIO_CONTROL_1: | ||
140 | case PCM512x_GPIO_CONTROL_2: | ||
141 | case PCM512x_OVERFLOW: | ||
142 | case PCM512x_RATE_DET_1: | ||
143 | case PCM512x_RATE_DET_2: | ||
144 | case PCM512x_RATE_DET_3: | ||
145 | case PCM512x_RATE_DET_4: | ||
146 | case PCM512x_ANALOG_MUTE_DET: | ||
147 | case PCM512x_GPIN: | ||
148 | case PCM512x_DIGITAL_MUTE_DET: | ||
149 | case PCM512x_OUTPUT_AMPLITUDE: | ||
150 | case PCM512x_ANALOG_GAIN_CTRL: | ||
151 | case PCM512x_UNDERVOLTAGE_PROT: | ||
152 | case PCM512x_ANALOG_MUTE_CTRL: | ||
153 | case PCM512x_ANALOG_GAIN_BOOST: | ||
154 | case PCM512x_VCOM_CTRL_1: | ||
155 | case PCM512x_VCOM_CTRL_2: | ||
156 | case PCM512x_CRAM_CTRL: | ||
157 | return true; | ||
158 | default: | ||
159 | /* There are 256 raw register addresses */ | ||
160 | return reg < 0xff; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | static bool pcm512x_volatile(struct device *dev, unsigned int reg) | ||
165 | { | ||
166 | switch (reg) { | ||
167 | case PCM512x_PLL_EN: | ||
168 | case PCM512x_OVERFLOW: | ||
169 | case PCM512x_RATE_DET_1: | ||
170 | case PCM512x_RATE_DET_2: | ||
171 | case PCM512x_RATE_DET_3: | ||
172 | case PCM512x_RATE_DET_4: | ||
173 | case PCM512x_ANALOG_MUTE_DET: | ||
174 | case PCM512x_GPIN: | ||
175 | case PCM512x_DIGITAL_MUTE_DET: | ||
176 | case PCM512x_CRAM_CTRL: | ||
177 | return true; | ||
178 | default: | ||
179 | /* There are 256 raw register addresses */ | ||
180 | return reg < 0xff; | ||
181 | } | ||
182 | } | ||
183 | |||
184 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -10350, 50, 1); | ||
185 | static const DECLARE_TLV_DB_SCALE(analog_tlv, -600, 600, 0); | ||
186 | static const DECLARE_TLV_DB_SCALE(boost_tlv, 0, 80, 0); | ||
187 | |||
188 | static const char * const pcm512x_dsp_program_texts[] = { | ||
189 | "FIR interpolation with de-emphasis", | ||
190 | "Low latency IIR with de-emphasis", | ||
191 | "Fixed process flow", | ||
192 | "High attenuation with de-emphasis", | ||
193 | "Ringing-less low latency FIR", | ||
194 | }; | ||
195 | |||
196 | static const unsigned int pcm512x_dsp_program_values[] = { | ||
197 | 1, | ||
198 | 2, | ||
199 | 3, | ||
200 | 5, | ||
201 | 7, | ||
202 | }; | ||
203 | |||
204 | static SOC_VALUE_ENUM_SINGLE_DECL(pcm512x_dsp_program, | ||
205 | PCM512x_DSP_PROGRAM, 0, 0x1f, | ||
206 | pcm512x_dsp_program_texts, | ||
207 | pcm512x_dsp_program_values); | ||
208 | |||
209 | static const char * const pcm512x_clk_missing_text[] = { | ||
210 | "1s", "2s", "3s", "4s", "5s", "6s", "7s", "8s" | ||
211 | }; | ||
212 | |||
213 | static const struct soc_enum pcm512x_clk_missing = | ||
214 | SOC_ENUM_SINGLE(PCM512x_CLKDET, 0, 8, pcm512x_clk_missing_text); | ||
215 | |||
216 | static const char * const pcm512x_autom_text[] = { | ||
217 | "21ms", "106ms", "213ms", "533ms", "1.07s", "2.13s", "5.33s", "10.66s" | ||
218 | }; | ||
219 | |||
220 | static const struct soc_enum pcm512x_autom_l = | ||
221 | SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATML_SHIFT, 8, | ||
222 | pcm512x_autom_text); | ||
223 | |||
224 | static const struct soc_enum pcm512x_autom_r = | ||
225 | SOC_ENUM_SINGLE(PCM512x_AUTO_MUTE, PCM512x_ATMR_SHIFT, 8, | ||
226 | pcm512x_autom_text); | ||
227 | |||
228 | static const char * const pcm512x_ramp_rate_text[] = { | ||
229 | "1 sample/update", "2 samples/update", "4 samples/update", | ||
230 | "Immediate" | ||
231 | }; | ||
232 | |||
233 | static const struct soc_enum pcm512x_vndf = | ||
234 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDF_SHIFT, 4, | ||
235 | pcm512x_ramp_rate_text); | ||
236 | |||
237 | static const struct soc_enum pcm512x_vnuf = | ||
238 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUF_SHIFT, 4, | ||
239 | pcm512x_ramp_rate_text); | ||
240 | |||
241 | static const struct soc_enum pcm512x_vedf = | ||
242 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDF_SHIFT, 4, | ||
243 | pcm512x_ramp_rate_text); | ||
244 | |||
245 | static const char * const pcm512x_ramp_step_text[] = { | ||
246 | "4dB/step", "2dB/step", "1dB/step", "0.5dB/step" | ||
247 | }; | ||
248 | |||
249 | static const struct soc_enum pcm512x_vnds = | ||
250 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNDS_SHIFT, 4, | ||
251 | pcm512x_ramp_step_text); | ||
252 | |||
253 | static const struct soc_enum pcm512x_vnus = | ||
254 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_1, PCM512x_VNUS_SHIFT, 4, | ||
255 | pcm512x_ramp_step_text); | ||
256 | |||
257 | static const struct soc_enum pcm512x_veds = | ||
258 | SOC_ENUM_SINGLE(PCM512x_DIGITAL_MUTE_2, PCM512x_VEDS_SHIFT, 4, | ||
259 | pcm512x_ramp_step_text); | ||
260 | |||
261 | static const struct snd_kcontrol_new pcm512x_controls[] = { | ||
262 | SOC_DOUBLE_R_TLV("Playback Digital Volume", PCM512x_DIGITAL_VOLUME_2, | ||
263 | PCM512x_DIGITAL_VOLUME_3, 0, 255, 1, digital_tlv), | ||
264 | SOC_DOUBLE_TLV("Playback Volume", PCM512x_ANALOG_GAIN_CTRL, | ||
265 | PCM512x_LAGN_SHIFT, PCM512x_RAGN_SHIFT, 1, 1, analog_tlv), | ||
266 | SOC_DOUBLE_TLV("Playback Boost Volume", PCM512x_ANALOG_GAIN_BOOST, | ||
267 | PCM512x_AGBL_SHIFT, PCM512x_AGBR_SHIFT, 1, 0, boost_tlv), | ||
268 | SOC_DOUBLE("Playback Digital Switch", PCM512x_MUTE, PCM512x_RQML_SHIFT, | ||
269 | PCM512x_RQMR_SHIFT, 1, 1), | ||
270 | |||
271 | SOC_SINGLE("Deemphasis Switch", PCM512x_DSP, PCM512x_DEMP_SHIFT, 1, 1), | ||
272 | SOC_VALUE_ENUM("DSP Program", pcm512x_dsp_program), | ||
273 | |||
274 | SOC_ENUM("Clock Missing Period", pcm512x_clk_missing), | ||
275 | SOC_ENUM("Auto Mute Time Left", pcm512x_autom_l), | ||
276 | SOC_ENUM("Auto Mute Time Right", pcm512x_autom_r), | ||
277 | SOC_SINGLE("Auto Mute Mono Switch", PCM512x_DIGITAL_MUTE_3, | ||
278 | PCM512x_ACTL_SHIFT, 1, 0), | ||
279 | SOC_DOUBLE("Auto Mute Switch", PCM512x_DIGITAL_MUTE_3, PCM512x_AMLE_SHIFT, | ||
280 | PCM512x_AMLR_SHIFT, 1, 0), | ||
281 | |||
282 | SOC_ENUM("Volume Ramp Down Rate", pcm512x_vndf), | ||
283 | SOC_ENUM("Volume Ramp Down Step", pcm512x_vnds), | ||
284 | SOC_ENUM("Volume Ramp Up Rate", pcm512x_vnuf), | ||
285 | SOC_ENUM("Volume Ramp Up Step", pcm512x_vnus), | ||
286 | SOC_ENUM("Volume Ramp Down Emergency Rate", pcm512x_vedf), | ||
287 | SOC_ENUM("Volume Ramp Down Emergency Step", pcm512x_veds), | ||
288 | }; | ||
289 | |||
290 | static const struct snd_soc_dapm_widget pcm512x_dapm_widgets[] = { | ||
291 | SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), | ||
292 | SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), | ||
293 | |||
294 | SND_SOC_DAPM_OUTPUT("OUTL"), | ||
295 | SND_SOC_DAPM_OUTPUT("OUTR"), | ||
296 | }; | ||
297 | |||
298 | static const struct snd_soc_dapm_route pcm512x_dapm_routes[] = { | ||
299 | { "DACL", NULL, "Playback" }, | ||
300 | { "DACR", NULL, "Playback" }, | ||
301 | |||
302 | { "OUTL", NULL, "DACL" }, | ||
303 | { "OUTR", NULL, "DACR" }, | ||
304 | }; | ||
305 | |||
306 | static int pcm512x_set_bias_level(struct snd_soc_codec *codec, | ||
307 | enum snd_soc_bias_level level) | ||
308 | { | ||
309 | struct pcm512x_priv *pcm512x = dev_get_drvdata(codec->dev); | ||
310 | int ret; | ||
311 | |||
312 | switch (level) { | ||
313 | case SND_SOC_BIAS_ON: | ||
314 | case SND_SOC_BIAS_PREPARE: | ||
315 | break; | ||
316 | |||
317 | case SND_SOC_BIAS_STANDBY: | ||
318 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
319 | PCM512x_RQST, 0); | ||
320 | if (ret != 0) { | ||
321 | dev_err(codec->dev, "Failed to remove standby: %d\n", | ||
322 | ret); | ||
323 | return ret; | ||
324 | } | ||
325 | break; | ||
326 | |||
327 | case SND_SOC_BIAS_OFF: | ||
328 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
329 | PCM512x_RQST, PCM512x_RQST); | ||
330 | if (ret != 0) { | ||
331 | dev_err(codec->dev, "Failed to request standby: %d\n", | ||
332 | ret); | ||
333 | return ret; | ||
334 | } | ||
335 | break; | ||
336 | } | ||
337 | |||
338 | codec->dapm.bias_level = level; | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static struct snd_soc_dai_driver pcm512x_dai = { | ||
344 | .name = "pcm512x-hifi", | ||
345 | .playback = { | ||
346 | .stream_name = "Playback", | ||
347 | .channels_min = 2, | ||
348 | .channels_max = 2, | ||
349 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
350 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
351 | SNDRV_PCM_FMTBIT_S24_LE | | ||
352 | SNDRV_PCM_FMTBIT_S32_LE | ||
353 | }, | ||
354 | }; | ||
355 | |||
356 | static struct snd_soc_codec_driver pcm512x_codec_driver = { | ||
357 | .set_bias_level = pcm512x_set_bias_level, | ||
358 | .idle_bias_off = true, | ||
359 | |||
360 | .controls = pcm512x_controls, | ||
361 | .num_controls = ARRAY_SIZE(pcm512x_controls), | ||
362 | .dapm_widgets = pcm512x_dapm_widgets, | ||
363 | .num_dapm_widgets = ARRAY_SIZE(pcm512x_dapm_widgets), | ||
364 | .dapm_routes = pcm512x_dapm_routes, | ||
365 | .num_dapm_routes = ARRAY_SIZE(pcm512x_dapm_routes), | ||
366 | }; | ||
367 | |||
368 | static const struct regmap_range_cfg pcm512x_range = { | ||
369 | .name = "Pages", .range_min = PCM512x_VIRT_BASE, | ||
370 | .range_max = PCM512x_MAX_REGISTER, | ||
371 | .selector_reg = PCM512x_PAGE, | ||
372 | .selector_mask = 0xff, | ||
373 | .window_start = 0, .window_len = 0x100, | ||
374 | }; | ||
375 | |||
376 | const struct regmap_config pcm512x_regmap = { | ||
377 | .reg_bits = 8, | ||
378 | .val_bits = 8, | ||
379 | |||
380 | .readable_reg = pcm512x_readable, | ||
381 | .volatile_reg = pcm512x_volatile, | ||
382 | |||
383 | .ranges = &pcm512x_range, | ||
384 | .num_ranges = 1, | ||
385 | |||
386 | .max_register = PCM512x_MAX_REGISTER, | ||
387 | .reg_defaults = pcm512x_reg_defaults, | ||
388 | .num_reg_defaults = ARRAY_SIZE(pcm512x_reg_defaults), | ||
389 | .cache_type = REGCACHE_RBTREE, | ||
390 | }; | ||
391 | EXPORT_SYMBOL_GPL(pcm512x_regmap); | ||
392 | |||
393 | int pcm512x_probe(struct device *dev, struct regmap *regmap) | ||
394 | { | ||
395 | struct pcm512x_priv *pcm512x; | ||
396 | int i, ret; | ||
397 | |||
398 | pcm512x = devm_kzalloc(dev, sizeof(struct pcm512x_priv), GFP_KERNEL); | ||
399 | if (!pcm512x) | ||
400 | return -ENOMEM; | ||
401 | |||
402 | dev_set_drvdata(dev, pcm512x); | ||
403 | pcm512x->regmap = regmap; | ||
404 | |||
405 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) | ||
406 | pcm512x->supplies[i].supply = pcm512x_supply_names[i]; | ||
407 | |||
408 | ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(pcm512x->supplies), | ||
409 | pcm512x->supplies); | ||
410 | if (ret != 0) { | ||
411 | dev_err(dev, "Failed to get supplies: %d\n", ret); | ||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | pcm512x->supply_nb[0].notifier_call = pcm512x_regulator_event_0; | ||
416 | pcm512x->supply_nb[1].notifier_call = pcm512x_regulator_event_1; | ||
417 | pcm512x->supply_nb[2].notifier_call = pcm512x_regulator_event_2; | ||
418 | |||
419 | for (i = 0; i < ARRAY_SIZE(pcm512x->supplies); i++) { | ||
420 | ret = regulator_register_notifier(pcm512x->supplies[i].consumer, | ||
421 | &pcm512x->supply_nb[i]); | ||
422 | if (ret != 0) { | ||
423 | dev_err(dev, | ||
424 | "Failed to register regulator notifier: %d\n", | ||
425 | ret); | ||
426 | } | ||
427 | } | ||
428 | |||
429 | ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), | ||
430 | pcm512x->supplies); | ||
431 | if (ret != 0) { | ||
432 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
433 | return ret; | ||
434 | } | ||
435 | |||
436 | /* Reset the device, verifying I/O in the process for I2C */ | ||
437 | ret = regmap_write(regmap, PCM512x_RESET, | ||
438 | PCM512x_RSTM | PCM512x_RSTR); | ||
439 | if (ret != 0) { | ||
440 | dev_err(dev, "Failed to reset device: %d\n", ret); | ||
441 | goto err; | ||
442 | } | ||
443 | |||
444 | ret = regmap_write(regmap, PCM512x_RESET, 0); | ||
445 | if (ret != 0) { | ||
446 | dev_err(dev, "Failed to reset device: %d\n", ret); | ||
447 | goto err; | ||
448 | } | ||
449 | |||
450 | pcm512x->sclk = devm_clk_get(dev, NULL); | ||
451 | if (IS_ERR(pcm512x->sclk)) { | ||
452 | if (PTR_ERR(pcm512x->sclk) == -EPROBE_DEFER) | ||
453 | return -EPROBE_DEFER; | ||
454 | |||
455 | dev_info(dev, "No SCLK, using BCLK: %ld\n", | ||
456 | PTR_ERR(pcm512x->sclk)); | ||
457 | |||
458 | /* Disable reporting of missing SCLK as an error */ | ||
459 | regmap_update_bits(regmap, PCM512x_ERROR_DETECT, | ||
460 | PCM512x_IDCH, PCM512x_IDCH); | ||
461 | |||
462 | /* Switch PLL input to BCLK */ | ||
463 | regmap_update_bits(regmap, PCM512x_PLL_REF, | ||
464 | PCM512x_SREF, PCM512x_SREF); | ||
465 | } else { | ||
466 | ret = clk_prepare_enable(pcm512x->sclk); | ||
467 | if (ret != 0) { | ||
468 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | ||
469 | return ret; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | /* Default to standby mode */ | ||
474 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
475 | PCM512x_RQST, PCM512x_RQST); | ||
476 | if (ret != 0) { | ||
477 | dev_err(dev, "Failed to request standby: %d\n", | ||
478 | ret); | ||
479 | goto err_clk; | ||
480 | } | ||
481 | |||
482 | pm_runtime_set_active(dev); | ||
483 | pm_runtime_enable(dev); | ||
484 | pm_runtime_idle(dev); | ||
485 | |||
486 | ret = snd_soc_register_codec(dev, &pcm512x_codec_driver, | ||
487 | &pcm512x_dai, 1); | ||
488 | if (ret != 0) { | ||
489 | dev_err(dev, "Failed to register CODEC: %d\n", ret); | ||
490 | goto err_pm; | ||
491 | } | ||
492 | |||
493 | return 0; | ||
494 | |||
495 | err_pm: | ||
496 | pm_runtime_disable(dev); | ||
497 | err_clk: | ||
498 | if (!IS_ERR(pcm512x->sclk)) | ||
499 | clk_disable_unprepare(pcm512x->sclk); | ||
500 | err: | ||
501 | regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
502 | pcm512x->supplies); | ||
503 | return ret; | ||
504 | } | ||
505 | EXPORT_SYMBOL_GPL(pcm512x_probe); | ||
506 | |||
507 | void pcm512x_remove(struct device *dev) | ||
508 | { | ||
509 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
510 | |||
511 | snd_soc_unregister_codec(dev); | ||
512 | pm_runtime_disable(dev); | ||
513 | if (!IS_ERR(pcm512x->sclk)) | ||
514 | clk_disable_unprepare(pcm512x->sclk); | ||
515 | regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
516 | pcm512x->supplies); | ||
517 | } | ||
518 | EXPORT_SYMBOL_GPL(pcm512x_remove); | ||
519 | |||
520 | static int pcm512x_suspend(struct device *dev) | ||
521 | { | ||
522 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
523 | int ret; | ||
524 | |||
525 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
526 | PCM512x_RQPD, PCM512x_RQPD); | ||
527 | if (ret != 0) { | ||
528 | dev_err(dev, "Failed to request power down: %d\n", ret); | ||
529 | return ret; | ||
530 | } | ||
531 | |||
532 | ret = regulator_bulk_disable(ARRAY_SIZE(pcm512x->supplies), | ||
533 | pcm512x->supplies); | ||
534 | if (ret != 0) { | ||
535 | dev_err(dev, "Failed to disable supplies: %d\n", ret); | ||
536 | return ret; | ||
537 | } | ||
538 | |||
539 | if (!IS_ERR(pcm512x->sclk)) | ||
540 | clk_disable_unprepare(pcm512x->sclk); | ||
541 | |||
542 | return 0; | ||
543 | } | ||
544 | |||
545 | static int pcm512x_resume(struct device *dev) | ||
546 | { | ||
547 | struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); | ||
548 | int ret; | ||
549 | |||
550 | if (!IS_ERR(pcm512x->sclk)) { | ||
551 | ret = clk_prepare_enable(pcm512x->sclk); | ||
552 | if (ret != 0) { | ||
553 | dev_err(dev, "Failed to enable SCLK: %d\n", ret); | ||
554 | return ret; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | ret = regulator_bulk_enable(ARRAY_SIZE(pcm512x->supplies), | ||
559 | pcm512x->supplies); | ||
560 | if (ret != 0) { | ||
561 | dev_err(dev, "Failed to enable supplies: %d\n", ret); | ||
562 | return ret; | ||
563 | } | ||
564 | |||
565 | regcache_cache_only(pcm512x->regmap, false); | ||
566 | ret = regcache_sync(pcm512x->regmap); | ||
567 | if (ret != 0) { | ||
568 | dev_err(dev, "Failed to sync cache: %d\n", ret); | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | ret = regmap_update_bits(pcm512x->regmap, PCM512x_POWER, | ||
573 | PCM512x_RQPD, 0); | ||
574 | if (ret != 0) { | ||
575 | dev_err(dev, "Failed to remove power down: %d\n", ret); | ||
576 | return ret; | ||
577 | } | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | const struct dev_pm_ops pcm512x_pm_ops = { | ||
583 | SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) | ||
584 | }; | ||
585 | EXPORT_SYMBOL_GPL(pcm512x_pm_ops); | ||
586 | |||
587 | MODULE_DESCRIPTION("ASoC PCM512x codec driver"); | ||
588 | MODULE_AUTHOR("Mark Brown <broonie@linaro.org>"); | ||
589 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/codecs/pcm512x.h b/sound/soc/codecs/pcm512x.h new file mode 100644 index 000000000000..6ee76aaca09a --- /dev/null +++ b/sound/soc/codecs/pcm512x.h | |||
@@ -0,0 +1,171 @@ | |||
1 | /* | ||
2 | * Driver for the PCM512x CODECs | ||
3 | * | ||
4 | * Author: Mark Brown <broonie@linaro.org> | ||
5 | * Copyright 2014 Linaro Ltd | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or | ||
8 | * modify it under the terms of the GNU General Public License | ||
9 | * version 2 as published by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, but | ||
12 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _SND_SOC_PCM512X | ||
18 | #define _SND_SOC_PCM512X | ||
19 | |||
20 | #include <linux/pm.h> | ||
21 | #include <linux/regmap.h> | ||
22 | |||
23 | #define PCM512x_VIRT_BASE 0x100 | ||
24 | #define PCM512x_PAGE_LEN 0x100 | ||
25 | #define PCM512x_PAGE_BASE(n) (PCM512x_VIRT_BASE + (PCM512x_PAGE_LEN * n)) | ||
26 | |||
27 | #define PCM512x_PAGE 0 | ||
28 | |||
29 | #define PCM512x_RESET (PCM512x_PAGE_BASE(0) + 1) | ||
30 | #define PCM512x_POWER (PCM512x_PAGE_BASE(0) + 2) | ||
31 | #define PCM512x_MUTE (PCM512x_PAGE_BASE(0) + 3) | ||
32 | #define PCM512x_PLL_EN (PCM512x_PAGE_BASE(0) + 4) | ||
33 | #define PCM512x_SPI_MISO_FUNCTION (PCM512x_PAGE_BASE(0) + 6) | ||
34 | #define PCM512x_DSP (PCM512x_PAGE_BASE(0) + 7) | ||
35 | #define PCM512x_GPIO_EN (PCM512x_PAGE_BASE(0) + 8) | ||
36 | #define PCM512x_BCLK_LRCLK_CFG (PCM512x_PAGE_BASE(0) + 9) | ||
37 | #define PCM512x_DSP_GPIO_INPUT (PCM512x_PAGE_BASE(0) + 10) | ||
38 | #define PCM512x_MASTER_MODE (PCM512x_PAGE_BASE(0) + 12) | ||
39 | #define PCM512x_PLL_REF (PCM512x_PAGE_BASE(0) + 13) | ||
40 | #define PCM512x_PLL_COEFF_0 (PCM512x_PAGE_BASE(0) + 20) | ||
41 | #define PCM512x_PLL_COEFF_1 (PCM512x_PAGE_BASE(0) + 21) | ||
42 | #define PCM512x_PLL_COEFF_2 (PCM512x_PAGE_BASE(0) + 22) | ||
43 | #define PCM512x_PLL_COEFF_3 (PCM512x_PAGE_BASE(0) + 23) | ||
44 | #define PCM512x_PLL_COEFF_4 (PCM512x_PAGE_BASE(0) + 24) | ||
45 | #define PCM512x_DSP_CLKDIV (PCM512x_PAGE_BASE(0) + 27) | ||
46 | #define PCM512x_DAC_CLKDIV (PCM512x_PAGE_BASE(0) + 28) | ||
47 | #define PCM512x_NCP_CLKDIV (PCM512x_PAGE_BASE(0) + 29) | ||
48 | #define PCM512x_OSR_CLKDIV (PCM512x_PAGE_BASE(0) + 30) | ||
49 | #define PCM512x_MASTER_CLKDIV_1 (PCM512x_PAGE_BASE(0) + 32) | ||
50 | #define PCM512x_MASTER_CLKDIV_2 (PCM512x_PAGE_BASE(0) + 33) | ||
51 | #define PCM512x_FS_SPEED_MODE (PCM512x_PAGE_BASE(0) + 34) | ||
52 | #define PCM512x_IDAC_1 (PCM512x_PAGE_BASE(0) + 35) | ||
53 | #define PCM512x_IDAC_2 (PCM512x_PAGE_BASE(0) + 36) | ||
54 | #define PCM512x_ERROR_DETECT (PCM512x_PAGE_BASE(0) + 37) | ||
55 | #define PCM512x_I2S_1 (PCM512x_PAGE_BASE(0) + 40) | ||
56 | #define PCM512x_I2S_2 (PCM512x_PAGE_BASE(0) + 41) | ||
57 | #define PCM512x_DAC_ROUTING (PCM512x_PAGE_BASE(0) + 42) | ||
58 | #define PCM512x_DSP_PROGRAM (PCM512x_PAGE_BASE(0) + 43) | ||
59 | #define PCM512x_CLKDET (PCM512x_PAGE_BASE(0) + 44) | ||
60 | #define PCM512x_AUTO_MUTE (PCM512x_PAGE_BASE(0) + 59) | ||
61 | #define PCM512x_DIGITAL_VOLUME_1 (PCM512x_PAGE_BASE(0) + 60) | ||
62 | #define PCM512x_DIGITAL_VOLUME_2 (PCM512x_PAGE_BASE(0) + 61) | ||
63 | #define PCM512x_DIGITAL_VOLUME_3 (PCM512x_PAGE_BASE(0) + 62) | ||
64 | #define PCM512x_DIGITAL_MUTE_1 (PCM512x_PAGE_BASE(0) + 63) | ||
65 | #define PCM512x_DIGITAL_MUTE_2 (PCM512x_PAGE_BASE(0) + 64) | ||
66 | #define PCM512x_DIGITAL_MUTE_3 (PCM512x_PAGE_BASE(0) + 65) | ||
67 | #define PCM512x_GPIO_OUTPUT_1 (PCM512x_PAGE_BASE(0) + 80) | ||
68 | #define PCM512x_GPIO_OUTPUT_2 (PCM512x_PAGE_BASE(0) + 81) | ||
69 | #define PCM512x_GPIO_OUTPUT_3 (PCM512x_PAGE_BASE(0) + 82) | ||
70 | #define PCM512x_GPIO_OUTPUT_4 (PCM512x_PAGE_BASE(0) + 83) | ||
71 | #define PCM512x_GPIO_OUTPUT_5 (PCM512x_PAGE_BASE(0) + 84) | ||
72 | #define PCM512x_GPIO_OUTPUT_6 (PCM512x_PAGE_BASE(0) + 85) | ||
73 | #define PCM512x_GPIO_CONTROL_1 (PCM512x_PAGE_BASE(0) + 86) | ||
74 | #define PCM512x_GPIO_CONTROL_2 (PCM512x_PAGE_BASE(0) + 87) | ||
75 | #define PCM512x_OVERFLOW (PCM512x_PAGE_BASE(0) + 90) | ||
76 | #define PCM512x_RATE_DET_1 (PCM512x_PAGE_BASE(0) + 91) | ||
77 | #define PCM512x_RATE_DET_2 (PCM512x_PAGE_BASE(0) + 92) | ||
78 | #define PCM512x_RATE_DET_3 (PCM512x_PAGE_BASE(0) + 93) | ||
79 | #define PCM512x_RATE_DET_4 (PCM512x_PAGE_BASE(0) + 94) | ||
80 | #define PCM512x_ANALOG_MUTE_DET (PCM512x_PAGE_BASE(0) + 108) | ||
81 | #define PCM512x_GPIN (PCM512x_PAGE_BASE(0) + 119) | ||
82 | #define PCM512x_DIGITAL_MUTE_DET (PCM512x_PAGE_BASE(0) + 120) | ||
83 | |||
84 | #define PCM512x_OUTPUT_AMPLITUDE (PCM512x_PAGE_BASE(1) + 1) | ||
85 | #define PCM512x_ANALOG_GAIN_CTRL (PCM512x_PAGE_BASE(1) + 2) | ||
86 | #define PCM512x_UNDERVOLTAGE_PROT (PCM512x_PAGE_BASE(1) + 5) | ||
87 | #define PCM512x_ANALOG_MUTE_CTRL (PCM512x_PAGE_BASE(1) + 6) | ||
88 | #define PCM512x_ANALOG_GAIN_BOOST (PCM512x_PAGE_BASE(1) + 7) | ||
89 | #define PCM512x_VCOM_CTRL_1 (PCM512x_PAGE_BASE(1) + 8) | ||
90 | #define PCM512x_VCOM_CTRL_2 (PCM512x_PAGE_BASE(1) + 9) | ||
91 | |||
92 | #define PCM512x_CRAM_CTRL (PCM512x_PAGE_BASE(44) + 1) | ||
93 | |||
94 | #define PCM512x_MAX_REGISTER (PCM512x_PAGE_BASE(44) + 1) | ||
95 | |||
96 | /* Page 0, Register 1 - reset */ | ||
97 | #define PCM512x_RSTR (1 << 0) | ||
98 | #define PCM512x_RSTM (1 << 4) | ||
99 | |||
100 | /* Page 0, Register 2 - power */ | ||
101 | #define PCM512x_RQPD (1 << 0) | ||
102 | #define PCM512x_RQPD_SHIFT 0 | ||
103 | #define PCM512x_RQST (1 << 4) | ||
104 | #define PCM512x_RQST_SHIFT 4 | ||
105 | |||
106 | /* Page 0, Register 3 - mute */ | ||
107 | #define PCM512x_RQMR_SHIFT 0 | ||
108 | #define PCM512x_RQML_SHIFT 4 | ||
109 | |||
110 | /* Page 0, Register 4 - PLL */ | ||
111 | #define PCM512x_PLCE (1 << 0) | ||
112 | #define PCM512x_RLCE_SHIFT 0 | ||
113 | #define PCM512x_PLCK (1 << 4) | ||
114 | #define PCM512x_PLCK_SHIFT 4 | ||
115 | |||
116 | /* Page 0, Register 7 - DSP */ | ||
117 | #define PCM512x_SDSL (1 << 0) | ||
118 | #define PCM512x_SDSL_SHIFT 0 | ||
119 | #define PCM512x_DEMP (1 << 4) | ||
120 | #define PCM512x_DEMP_SHIFT 4 | ||
121 | |||
122 | /* Page 0, Register 13 - PLL reference */ | ||
123 | #define PCM512x_SREF (1 << 4) | ||
124 | |||
125 | /* Page 0, Register 37 - Error detection */ | ||
126 | #define PCM512x_IPLK (1 << 0) | ||
127 | #define PCM512x_DCAS (1 << 1) | ||
128 | #define PCM512x_IDCM (1 << 2) | ||
129 | #define PCM512x_IDCH (1 << 3) | ||
130 | #define PCM512x_IDSK (1 << 4) | ||
131 | #define PCM512x_IDBK (1 << 5) | ||
132 | #define PCM512x_IDFS (1 << 6) | ||
133 | |||
134 | /* Page 0, Register 42 - DAC routing */ | ||
135 | #define PCM512x_AUPR_SHIFT 0 | ||
136 | #define PCM512x_AUPL_SHIFT 4 | ||
137 | |||
138 | /* Page 0, Register 59 - auto mute */ | ||
139 | #define PCM512x_ATMR_SHIFT 0 | ||
140 | #define PCM512x_ATML_SHIFT 4 | ||
141 | |||
142 | /* Page 0, Register 63 - ramp rates */ | ||
143 | #define PCM512x_VNDF_SHIFT 6 | ||
144 | #define PCM512x_VNDS_SHIFT 4 | ||
145 | #define PCM512x_VNUF_SHIFT 2 | ||
146 | #define PCM512x_VNUS_SHIFT 0 | ||
147 | |||
148 | /* Page 0, Register 64 - emergency ramp rates */ | ||
149 | #define PCM512x_VEDF_SHIFT 6 | ||
150 | #define PCM512x_VEDS_SHIFT 4 | ||
151 | |||
152 | /* Page 0, Register 65 - Digital mute enables */ | ||
153 | #define PCM512x_ACTL_SHIFT 2 | ||
154 | #define PCM512x_AMLE_SHIFT 1 | ||
155 | #define PCM512x_AMLR_SHIFT 0 | ||
156 | |||
157 | /* Page 1, Register 2 - analog volume control */ | ||
158 | #define PCM512x_RAGN_SHIFT 0 | ||
159 | #define PCM512x_LAGN_SHIFT 4 | ||
160 | |||
161 | /* Page 1, Register 7 - analog boost control */ | ||
162 | #define PCM512x_AGBR_SHIFT 0 | ||
163 | #define PCM512x_AGBL_SHIFT 4 | ||
164 | |||
165 | extern const struct dev_pm_ops pcm512x_pm_ops; | ||
166 | extern const struct regmap_config pcm512x_regmap; | ||
167 | |||
168 | int pcm512x_probe(struct device *dev, struct regmap *regmap); | ||
169 | void pcm512x_remove(struct device *dev); | ||
170 | |||
171 | #endif | ||
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 912c9cbc2724..ce199d375209 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c | |||
@@ -210,26 +210,22 @@ static int rt5631_dmic_put(struct snd_kcontrol *kcontrol, | |||
210 | static const char *rt5631_input_mode[] = { | 210 | static const char *rt5631_input_mode[] = { |
211 | "Single ended", "Differential"}; | 211 | "Single ended", "Differential"}; |
212 | 212 | ||
213 | static const SOC_ENUM_SINGLE_DECL( | 213 | static SOC_ENUM_SINGLE_DECL(rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, |
214 | rt5631_mic1_mode_enum, RT5631_MIC_CTRL_1, | 214 | RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); |
215 | RT5631_MIC1_DIFF_INPUT_SHIFT, rt5631_input_mode); | ||
216 | 215 | ||
217 | static const SOC_ENUM_SINGLE_DECL( | 216 | static SOC_ENUM_SINGLE_DECL(rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, |
218 | rt5631_mic2_mode_enum, RT5631_MIC_CTRL_1, | 217 | RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); |
219 | RT5631_MIC2_DIFF_INPUT_SHIFT, rt5631_input_mode); | ||
220 | 218 | ||
221 | /* MONO Input Type */ | 219 | /* MONO Input Type */ |
222 | static const SOC_ENUM_SINGLE_DECL( | 220 | static SOC_ENUM_SINGLE_DECL(rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, |
223 | rt5631_monoin_mode_enum, RT5631_MONO_INPUT_VOL, | 221 | RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); |
224 | RT5631_MONO_DIFF_INPUT_SHIFT, rt5631_input_mode); | ||
225 | 222 | ||
226 | /* SPK Ratio Gain Control */ | 223 | /* SPK Ratio Gain Control */ |
227 | static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x", | 224 | static const char *rt5631_spk_ratio[] = {"1.00x", "1.09x", "1.27x", "1.44x", |
228 | "1.56x", "1.68x", "1.99x", "2.34x"}; | 225 | "1.56x", "1.68x", "1.99x", "2.34x"}; |
229 | 226 | ||
230 | static const SOC_ENUM_SINGLE_DECL( | 227 | static SOC_ENUM_SINGLE_DECL(rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, |
231 | rt5631_spk_ratio_enum, RT5631_GEN_PUR_CTRL_REG, | 228 | RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); |
232 | RT5631_SPK_AMP_RATIO_CTRL_SHIFT, rt5631_spk_ratio); | ||
233 | 229 | ||
234 | static const struct snd_kcontrol_new rt5631_snd_controls[] = { | 230 | static const struct snd_kcontrol_new rt5631_snd_controls[] = { |
235 | /* MIC */ | 231 | /* MIC */ |
@@ -759,9 +755,8 @@ static const struct snd_kcontrol_new rt5631_monomix_mixer_controls[] = { | |||
759 | /* Left SPK Volume Input */ | 755 | /* Left SPK Volume Input */ |
760 | static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; | 756 | static const char *rt5631_spkvoll_sel[] = {"Vmid", "SPKMIXL"}; |
761 | 757 | ||
762 | static const SOC_ENUM_SINGLE_DECL( | 758 | static SOC_ENUM_SINGLE_DECL(rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, |
763 | rt5631_spkvoll_enum, RT5631_SPK_OUT_VOL, | 759 | RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); |
764 | RT5631_L_EN_SHIFT, rt5631_spkvoll_sel); | ||
765 | 760 | ||
766 | static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = | 761 | static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = |
767 | SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); | 762 | SOC_DAPM_ENUM("Left SPKVOL SRC", rt5631_spkvoll_enum); |
@@ -769,9 +764,8 @@ static const struct snd_kcontrol_new rt5631_spkvoll_mux_control = | |||
769 | /* Left HP Volume Input */ | 764 | /* Left HP Volume Input */ |
770 | static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; | 765 | static const char *rt5631_hpvoll_sel[] = {"Vmid", "OUTMIXL"}; |
771 | 766 | ||
772 | static const SOC_ENUM_SINGLE_DECL( | 767 | static SOC_ENUM_SINGLE_DECL(rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, |
773 | rt5631_hpvoll_enum, RT5631_HP_OUT_VOL, | 768 | RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); |
774 | RT5631_L_EN_SHIFT, rt5631_hpvoll_sel); | ||
775 | 769 | ||
776 | static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = | 770 | static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = |
777 | SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); | 771 | SOC_DAPM_ENUM("Left HPVOL SRC", rt5631_hpvoll_enum); |
@@ -779,9 +773,8 @@ static const struct snd_kcontrol_new rt5631_hpvoll_mux_control = | |||
779 | /* Left Out Volume Input */ | 773 | /* Left Out Volume Input */ |
780 | static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; | 774 | static const char *rt5631_outvoll_sel[] = {"Vmid", "OUTMIXL"}; |
781 | 775 | ||
782 | static const SOC_ENUM_SINGLE_DECL( | 776 | static SOC_ENUM_SINGLE_DECL(rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, |
783 | rt5631_outvoll_enum, RT5631_MONO_AXO_1_2_VOL, | 777 | RT5631_L_EN_SHIFT, rt5631_outvoll_sel); |
784 | RT5631_L_EN_SHIFT, rt5631_outvoll_sel); | ||
785 | 778 | ||
786 | static const struct snd_kcontrol_new rt5631_outvoll_mux_control = | 779 | static const struct snd_kcontrol_new rt5631_outvoll_mux_control = |
787 | SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); | 780 | SOC_DAPM_ENUM("Left OUTVOL SRC", rt5631_outvoll_enum); |
@@ -789,9 +782,8 @@ static const struct snd_kcontrol_new rt5631_outvoll_mux_control = | |||
789 | /* Right Out Volume Input */ | 782 | /* Right Out Volume Input */ |
790 | static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; | 783 | static const char *rt5631_outvolr_sel[] = {"Vmid", "OUTMIXR"}; |
791 | 784 | ||
792 | static const SOC_ENUM_SINGLE_DECL( | 785 | static SOC_ENUM_SINGLE_DECL(rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, |
793 | rt5631_outvolr_enum, RT5631_MONO_AXO_1_2_VOL, | 786 | RT5631_R_EN_SHIFT, rt5631_outvolr_sel); |
794 | RT5631_R_EN_SHIFT, rt5631_outvolr_sel); | ||
795 | 787 | ||
796 | static const struct snd_kcontrol_new rt5631_outvolr_mux_control = | 788 | static const struct snd_kcontrol_new rt5631_outvolr_mux_control = |
797 | SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); | 789 | SOC_DAPM_ENUM("Right OUTVOL SRC", rt5631_outvolr_enum); |
@@ -799,9 +791,8 @@ static const struct snd_kcontrol_new rt5631_outvolr_mux_control = | |||
799 | /* Right HP Volume Input */ | 791 | /* Right HP Volume Input */ |
800 | static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; | 792 | static const char *rt5631_hpvolr_sel[] = {"Vmid", "OUTMIXR"}; |
801 | 793 | ||
802 | static const SOC_ENUM_SINGLE_DECL( | 794 | static SOC_ENUM_SINGLE_DECL(rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, |
803 | rt5631_hpvolr_enum, RT5631_HP_OUT_VOL, | 795 | RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); |
804 | RT5631_R_EN_SHIFT, rt5631_hpvolr_sel); | ||
805 | 796 | ||
806 | static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = | 797 | static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = |
807 | SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); | 798 | SOC_DAPM_ENUM("Right HPVOL SRC", rt5631_hpvolr_enum); |
@@ -809,9 +800,8 @@ static const struct snd_kcontrol_new rt5631_hpvolr_mux_control = | |||
809 | /* Right SPK Volume Input */ | 800 | /* Right SPK Volume Input */ |
810 | static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; | 801 | static const char *rt5631_spkvolr_sel[] = {"Vmid", "SPKMIXR"}; |
811 | 802 | ||
812 | static const SOC_ENUM_SINGLE_DECL( | 803 | static SOC_ENUM_SINGLE_DECL(rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, |
813 | rt5631_spkvolr_enum, RT5631_SPK_OUT_VOL, | 804 | RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); |
814 | RT5631_R_EN_SHIFT, rt5631_spkvolr_sel); | ||
815 | 805 | ||
816 | static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = | 806 | static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = |
817 | SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); | 807 | SOC_DAPM_ENUM("Right SPKVOL SRC", rt5631_spkvolr_enum); |
@@ -820,9 +810,8 @@ static const struct snd_kcontrol_new rt5631_spkvolr_mux_control = | |||
820 | static const char *rt5631_spol_src_sel[] = { | 810 | static const char *rt5631_spol_src_sel[] = { |
821 | "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; | 811 | "SPOLMIX", "MONOIN_RX", "VDAC", "DACL"}; |
822 | 812 | ||
823 | static const SOC_ENUM_SINGLE_DECL( | 813 | static SOC_ENUM_SINGLE_DECL(rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
824 | rt5631_spol_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 814 | RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); |
825 | RT5631_SPK_L_MUX_SEL_SHIFT, rt5631_spol_src_sel); | ||
826 | 815 | ||
827 | static const struct snd_kcontrol_new rt5631_spol_mux_control = | 816 | static const struct snd_kcontrol_new rt5631_spol_mux_control = |
828 | SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); | 817 | SOC_DAPM_ENUM("SPOL SRC", rt5631_spol_src_enum); |
@@ -831,9 +820,8 @@ static const struct snd_kcontrol_new rt5631_spol_mux_control = | |||
831 | static const char *rt5631_spor_src_sel[] = { | 820 | static const char *rt5631_spor_src_sel[] = { |
832 | "SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; | 821 | "SPORMIX", "MONOIN_RX", "VDAC", "DACR"}; |
833 | 822 | ||
834 | static const SOC_ENUM_SINGLE_DECL( | 823 | static SOC_ENUM_SINGLE_DECL(rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
835 | rt5631_spor_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 824 | RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); |
836 | RT5631_SPK_R_MUX_SEL_SHIFT, rt5631_spor_src_sel); | ||
837 | 825 | ||
838 | static const struct snd_kcontrol_new rt5631_spor_mux_control = | 826 | static const struct snd_kcontrol_new rt5631_spor_mux_control = |
839 | SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); | 827 | SOC_DAPM_ENUM("SPOR SRC", rt5631_spor_src_enum); |
@@ -841,9 +829,8 @@ static const struct snd_kcontrol_new rt5631_spor_mux_control = | |||
841 | /* MONO Input */ | 829 | /* MONO Input */ |
842 | static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; | 830 | static const char *rt5631_mono_src_sel[] = {"MONOMIX", "MONOIN_RX", "VDAC"}; |
843 | 831 | ||
844 | static const SOC_ENUM_SINGLE_DECL( | 832 | static SOC_ENUM_SINGLE_DECL(rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
845 | rt5631_mono_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 833 | RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); |
846 | RT5631_MONO_MUX_SEL_SHIFT, rt5631_mono_src_sel); | ||
847 | 834 | ||
848 | static const struct snd_kcontrol_new rt5631_mono_mux_control = | 835 | static const struct snd_kcontrol_new rt5631_mono_mux_control = |
849 | SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); | 836 | SOC_DAPM_ENUM("MONO SRC", rt5631_mono_src_enum); |
@@ -851,9 +838,8 @@ static const struct snd_kcontrol_new rt5631_mono_mux_control = | |||
851 | /* Left HPO Input */ | 838 | /* Left HPO Input */ |
852 | static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; | 839 | static const char *rt5631_hpl_src_sel[] = {"Left HPVOL", "Left DAC"}; |
853 | 840 | ||
854 | static const SOC_ENUM_SINGLE_DECL( | 841 | static SOC_ENUM_SINGLE_DECL(rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
855 | rt5631_hpl_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 842 | RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); |
856 | RT5631_HP_L_MUX_SEL_SHIFT, rt5631_hpl_src_sel); | ||
857 | 843 | ||
858 | static const struct snd_kcontrol_new rt5631_hpl_mux_control = | 844 | static const struct snd_kcontrol_new rt5631_hpl_mux_control = |
859 | SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); | 845 | SOC_DAPM_ENUM("HPL SRC", rt5631_hpl_src_enum); |
@@ -861,9 +847,8 @@ static const struct snd_kcontrol_new rt5631_hpl_mux_control = | |||
861 | /* Right HPO Input */ | 847 | /* Right HPO Input */ |
862 | static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; | 848 | static const char *rt5631_hpr_src_sel[] = {"Right HPVOL", "Right DAC"}; |
863 | 849 | ||
864 | static const SOC_ENUM_SINGLE_DECL( | 850 | static SOC_ENUM_SINGLE_DECL(rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, |
865 | rt5631_hpr_src_enum, RT5631_SPK_MONO_HP_OUT_CTRL, | 851 | RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); |
866 | RT5631_HP_R_MUX_SEL_SHIFT, rt5631_hpr_src_sel); | ||
867 | 852 | ||
868 | static const struct snd_kcontrol_new rt5631_hpr_mux_control = | 853 | static const struct snd_kcontrol_new rt5631_hpr_mux_control = |
869 | SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); | 854 | SOC_DAPM_ENUM("HPR SRC", rt5631_hpr_src_enum); |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index a3fb41179636..1a1e1150237d 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
@@ -361,25 +361,24 @@ static unsigned int bst_tlv[] = { | |||
361 | static const char * const rt5640_data_select[] = { | 361 | static const char * const rt5640_data_select[] = { |
362 | "Normal", "left copy to right", "right copy to left", "Swap"}; | 362 | "Normal", "left copy to right", "right copy to left", "Swap"}; |
363 | 363 | ||
364 | static const SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, | 364 | static SOC_ENUM_SINGLE_DECL(rt5640_if1_dac_enum, RT5640_DIG_INF_DATA, |
365 | RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); | 365 | RT5640_IF1_DAC_SEL_SFT, rt5640_data_select); |
366 | 366 | ||
367 | static const SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, | 367 | static SOC_ENUM_SINGLE_DECL(rt5640_if1_adc_enum, RT5640_DIG_INF_DATA, |
368 | RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); | 368 | RT5640_IF1_ADC_SEL_SFT, rt5640_data_select); |
369 | 369 | ||
370 | static const SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, | 370 | static SOC_ENUM_SINGLE_DECL(rt5640_if2_dac_enum, RT5640_DIG_INF_DATA, |
371 | RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); | 371 | RT5640_IF2_DAC_SEL_SFT, rt5640_data_select); |
372 | 372 | ||
373 | static const SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, | 373 | static SOC_ENUM_SINGLE_DECL(rt5640_if2_adc_enum, RT5640_DIG_INF_DATA, |
374 | RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); | 374 | RT5640_IF2_ADC_SEL_SFT, rt5640_data_select); |
375 | 375 | ||
376 | /* Class D speaker gain ratio */ | 376 | /* Class D speaker gain ratio */ |
377 | static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x", | 377 | static const char * const rt5640_clsd_spk_ratio[] = {"1.66x", "1.83x", "1.94x", |
378 | "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; | 378 | "2x", "2.11x", "2.22x", "2.33x", "2.44x", "2.55x", "2.66x", "2.77x"}; |
379 | 379 | ||
380 | static const SOC_ENUM_SINGLE_DECL( | 380 | static SOC_ENUM_SINGLE_DECL(rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, |
381 | rt5640_clsd_spk_ratio_enum, RT5640_CLS_D_OUT, | 381 | RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); |
382 | RT5640_CLSD_RATIO_SFT, rt5640_clsd_spk_ratio); | ||
383 | 382 | ||
384 | static const struct snd_kcontrol_new rt5640_snd_controls[] = { | 383 | static const struct snd_kcontrol_new rt5640_snd_controls[] = { |
385 | /* Speaker Output Volume */ | 384 | /* Speaker Output Volume */ |
@@ -753,9 +752,8 @@ static const char * const rt5640_stereo_adc1_src[] = { | |||
753 | "DIG MIX", "ADC" | 752 | "DIG MIX", "ADC" |
754 | }; | 753 | }; |
755 | 754 | ||
756 | static const SOC_ENUM_SINGLE_DECL( | 755 | static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, |
757 | rt5640_stereo_adc1_enum, RT5640_STO_ADC_MIXER, | 756 | RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); |
758 | RT5640_ADC_1_SRC_SFT, rt5640_stereo_adc1_src); | ||
759 | 757 | ||
760 | static const struct snd_kcontrol_new rt5640_sto_adc_1_mux = | 758 | static const struct snd_kcontrol_new rt5640_sto_adc_1_mux = |
761 | SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); | 759 | SOC_DAPM_ENUM("Stereo ADC1 Mux", rt5640_stereo_adc1_enum); |
@@ -764,9 +762,8 @@ static const char * const rt5640_stereo_adc2_src[] = { | |||
764 | "DMIC1", "DMIC2", "DIG MIX" | 762 | "DMIC1", "DMIC2", "DIG MIX" |
765 | }; | 763 | }; |
766 | 764 | ||
767 | static const SOC_ENUM_SINGLE_DECL( | 765 | static SOC_ENUM_SINGLE_DECL(rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, |
768 | rt5640_stereo_adc2_enum, RT5640_STO_ADC_MIXER, | 766 | RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); |
769 | RT5640_ADC_2_SRC_SFT, rt5640_stereo_adc2_src); | ||
770 | 767 | ||
771 | static const struct snd_kcontrol_new rt5640_sto_adc_2_mux = | 768 | static const struct snd_kcontrol_new rt5640_sto_adc_2_mux = |
772 | SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); | 769 | SOC_DAPM_ENUM("Stereo ADC2 Mux", rt5640_stereo_adc2_enum); |
@@ -776,9 +773,8 @@ static const char * const rt5640_mono_adc_l1_src[] = { | |||
776 | "Mono DAC MIXL", "ADCL" | 773 | "Mono DAC MIXL", "ADCL" |
777 | }; | 774 | }; |
778 | 775 | ||
779 | static const SOC_ENUM_SINGLE_DECL( | 776 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, |
780 | rt5640_mono_adc_l1_enum, RT5640_MONO_ADC_MIXER, | 777 | RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); |
781 | RT5640_MONO_ADC_L1_SRC_SFT, rt5640_mono_adc_l1_src); | ||
782 | 778 | ||
783 | static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux = | 779 | static const struct snd_kcontrol_new rt5640_mono_adc_l1_mux = |
784 | SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); | 780 | SOC_DAPM_ENUM("Mono ADC1 left source", rt5640_mono_adc_l1_enum); |
@@ -787,9 +783,8 @@ static const char * const rt5640_mono_adc_l2_src[] = { | |||
787 | "DMIC L1", "DMIC L2", "Mono DAC MIXL" | 783 | "DMIC L1", "DMIC L2", "Mono DAC MIXL" |
788 | }; | 784 | }; |
789 | 785 | ||
790 | static const SOC_ENUM_SINGLE_DECL( | 786 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, |
791 | rt5640_mono_adc_l2_enum, RT5640_MONO_ADC_MIXER, | 787 | RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); |
792 | RT5640_MONO_ADC_L2_SRC_SFT, rt5640_mono_adc_l2_src); | ||
793 | 788 | ||
794 | static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux = | 789 | static const struct snd_kcontrol_new rt5640_mono_adc_l2_mux = |
795 | SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); | 790 | SOC_DAPM_ENUM("Mono ADC2 left source", rt5640_mono_adc_l2_enum); |
@@ -798,9 +793,8 @@ static const char * const rt5640_mono_adc_r1_src[] = { | |||
798 | "Mono DAC MIXR", "ADCR" | 793 | "Mono DAC MIXR", "ADCR" |
799 | }; | 794 | }; |
800 | 795 | ||
801 | static const SOC_ENUM_SINGLE_DECL( | 796 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, |
802 | rt5640_mono_adc_r1_enum, RT5640_MONO_ADC_MIXER, | 797 | RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); |
803 | RT5640_MONO_ADC_R1_SRC_SFT, rt5640_mono_adc_r1_src); | ||
804 | 798 | ||
805 | static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux = | 799 | static const struct snd_kcontrol_new rt5640_mono_adc_r1_mux = |
806 | SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); | 800 | SOC_DAPM_ENUM("Mono ADC1 right source", rt5640_mono_adc_r1_enum); |
@@ -809,9 +803,8 @@ static const char * const rt5640_mono_adc_r2_src[] = { | |||
809 | "DMIC R1", "DMIC R2", "Mono DAC MIXR" | 803 | "DMIC R1", "DMIC R2", "Mono DAC MIXR" |
810 | }; | 804 | }; |
811 | 805 | ||
812 | static const SOC_ENUM_SINGLE_DECL( | 806 | static SOC_ENUM_SINGLE_DECL(rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, |
813 | rt5640_mono_adc_r2_enum, RT5640_MONO_ADC_MIXER, | 807 | RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); |
814 | RT5640_MONO_ADC_R2_SRC_SFT, rt5640_mono_adc_r2_src); | ||
815 | 808 | ||
816 | static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux = | 809 | static const struct snd_kcontrol_new rt5640_mono_adc_r2_mux = |
817 | SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); | 810 | SOC_DAPM_ENUM("Mono ADC2 right source", rt5640_mono_adc_r2_enum); |
@@ -826,9 +819,9 @@ static int rt5640_dac_l2_values[] = { | |||
826 | 3, | 819 | 3, |
827 | }; | 820 | }; |
828 | 821 | ||
829 | static const SOC_VALUE_ENUM_SINGLE_DECL( | 822 | static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_l2_enum, |
830 | rt5640_dac_l2_enum, RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, | 823 | RT5640_DSP_PATH2, RT5640_DAC_L2_SEL_SFT, |
831 | 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); | 824 | 0x3, rt5640_dac_l2_src, rt5640_dac_l2_values); |
832 | 825 | ||
833 | static const struct snd_kcontrol_new rt5640_dac_l2_mux = | 826 | static const struct snd_kcontrol_new rt5640_dac_l2_mux = |
834 | SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); | 827 | SOC_DAPM_VALUE_ENUM("DAC2 left channel source", rt5640_dac_l2_enum); |
@@ -841,9 +834,9 @@ static int rt5640_dac_r2_values[] = { | |||
841 | 0, | 834 | 0, |
842 | }; | 835 | }; |
843 | 836 | ||
844 | static const SOC_VALUE_ENUM_SINGLE_DECL( | 837 | static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dac_r2_enum, |
845 | rt5640_dac_r2_enum, RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, | 838 | RT5640_DSP_PATH2, RT5640_DAC_R2_SEL_SFT, |
846 | 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); | 839 | 0x3, rt5640_dac_r2_src, rt5640_dac_r2_values); |
847 | 840 | ||
848 | static const struct snd_kcontrol_new rt5640_dac_r2_mux = | 841 | static const struct snd_kcontrol_new rt5640_dac_r2_mux = |
849 | SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); | 842 | SOC_DAPM_ENUM("DAC2 right channel source", rt5640_dac_r2_enum); |
@@ -860,9 +853,10 @@ static int rt5640_dai_iis_map_values[] = { | |||
860 | 7, | 853 | 7, |
861 | }; | 854 | }; |
862 | 855 | ||
863 | static const SOC_VALUE_ENUM_SINGLE_DECL( | 856 | static SOC_VALUE_ENUM_SINGLE_DECL(rt5640_dai_iis_map_enum, |
864 | rt5640_dai_iis_map_enum, RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, | 857 | RT5640_I2S1_SDP, RT5640_I2S_IF_SFT, |
865 | 0x7, rt5640_dai_iis_map, rt5640_dai_iis_map_values); | 858 | 0x7, rt5640_dai_iis_map, |
859 | rt5640_dai_iis_map_values); | ||
866 | 860 | ||
867 | static const struct snd_kcontrol_new rt5640_dai_mux = | 861 | static const struct snd_kcontrol_new rt5640_dai_mux = |
868 | SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); | 862 | SOC_DAPM_VALUE_ENUM("DAI select", rt5640_dai_iis_map_enum); |
@@ -872,9 +866,8 @@ static const char * const rt5640_sdi_sel[] = { | |||
872 | "IF1", "IF2" | 866 | "IF1", "IF2" |
873 | }; | 867 | }; |
874 | 868 | ||
875 | static const SOC_ENUM_SINGLE_DECL( | 869 | static SOC_ENUM_SINGLE_DECL(rt5640_sdi_sel_enum, RT5640_I2S2_SDP, |
876 | rt5640_sdi_sel_enum, RT5640_I2S2_SDP, | 870 | RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); |
877 | RT5640_I2S2_SDI_SFT, rt5640_sdi_sel); | ||
878 | 871 | ||
879 | static const struct snd_kcontrol_new rt5640_sdi_mux = | 872 | static const struct snd_kcontrol_new rt5640_sdi_mux = |
880 | SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); | 873 | SOC_DAPM_ENUM("SDI select", rt5640_sdi_sel_enum); |
@@ -2093,6 +2086,7 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); | |||
2093 | #ifdef CONFIG_ACPI | 2086 | #ifdef CONFIG_ACPI |
2094 | static struct acpi_device_id rt5640_acpi_match[] = { | 2087 | static struct acpi_device_id rt5640_acpi_match[] = { |
2095 | { "INT33CA", 0 }, | 2088 | { "INT33CA", 0 }, |
2089 | { "10EC5640", 0 }, | ||
2096 | { }, | 2090 | { }, |
2097 | }; | 2091 | }; |
2098 | MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); | 2092 | MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); |
diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 52e7cb08434b..fa2b8e07f420 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c | |||
@@ -210,7 +210,7 @@ out: | |||
210 | static int si476x_codec_probe(struct snd_soc_codec *codec) | 210 | static int si476x_codec_probe(struct snd_soc_codec *codec) |
211 | { | 211 | { |
212 | codec->control_data = dev_get_regmap(codec->dev->parent, NULL); | 212 | codec->control_data = dev_get_regmap(codec->dev->parent, NULL); |
213 | return 0; | 213 | return snd_soc_codec_set_cache_io(codec, 0, 0, SND_SOC_REGMAP); |
214 | } | 214 | } |
215 | 215 | ||
216 | static struct snd_soc_dai_ops si476x_dai_ops = { | 216 | static struct snd_soc_dai_ops si476x_dai_ops = { |
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index cc8debce752f..806f3d826ffb 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c | |||
@@ -169,19 +169,19 @@ static const char * const ssm2518_drc_hold_time_text[] = { | |||
169 | "682.24 ms", "1364 ms", | 169 | "682.24 ms", "1364 ms", |
170 | }; | 170 | }; |
171 | 171 | ||
172 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, | 172 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_attack_time_enum, |
173 | SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); | 173 | SSM2518_REG_DRC_2, 4, ssm2518_drc_peak_detector_attack_time_text); |
174 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, | 174 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_peak_detector_release_time_enum, |
175 | SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); | 175 | SSM2518_REG_DRC_2, 0, ssm2518_drc_peak_detector_release_time_text); |
176 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, | 176 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_attack_time_enum, |
177 | SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); | 177 | SSM2518_REG_DRC_6, 4, ssm2518_drc_peak_detector_attack_time_text); |
178 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, | 178 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_decay_time_enum, |
179 | SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); | 179 | SSM2518_REG_DRC_6, 0, ssm2518_drc_peak_detector_release_time_text); |
180 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, | 180 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_hold_time_enum, |
181 | SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); | 181 | SSM2518_REG_DRC_7, 4, ssm2518_drc_hold_time_text); |
182 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, | 182 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_noise_gate_hold_time_enum, |
183 | SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); | 183 | SSM2518_REG_DRC_7, 0, ssm2518_drc_hold_time_text); |
184 | static const SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, | 184 | static SOC_ENUM_SINGLE_DECL(ssm2518_drc_rms_averaging_time_enum, |
185 | SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text); | 185 | SSM2518_REG_DRC_9, 0, ssm2518_drc_peak_detector_release_time_text); |
186 | 186 | ||
187 | static const struct snd_kcontrol_new ssm2518_snd_controls[] = { | 187 | static const struct snd_kcontrol_new ssm2518_snd_controls[] = { |
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 06edb396e733..2735361a4c3c 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c | |||
@@ -187,42 +187,42 @@ static const unsigned int sta32x_limiter_drc_release_tlv[] = { | |||
187 | 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), | 187 | 13, 16, TLV_DB_SCALE_ITEM(-1500, 300, 0), |
188 | }; | 188 | }; |
189 | 189 | ||
190 | static const struct soc_enum sta32x_drc_ac_enum = | 190 | static SOC_ENUM_SINGLE_DECL(sta32x_drc_ac_enum, |
191 | SOC_ENUM_SINGLE(STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, | 191 | STA32X_CONFD, STA32X_CONFD_DRC_SHIFT, |
192 | 2, sta32x_drc_ac); | 192 | sta32x_drc_ac); |
193 | static const struct soc_enum sta32x_auto_eq_enum = | 193 | static SOC_ENUM_SINGLE_DECL(sta32x_auto_eq_enum, |
194 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, | 194 | STA32X_AUTO1, STA32X_AUTO1_AMEQ_SHIFT, |
195 | 3, sta32x_auto_eq_mode); | 195 | sta32x_auto_eq_mode); |
196 | static const struct soc_enum sta32x_auto_gc_enum = | 196 | static SOC_ENUM_SINGLE_DECL(sta32x_auto_gc_enum, |
197 | SOC_ENUM_SINGLE(STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, | 197 | STA32X_AUTO1, STA32X_AUTO1_AMGC_SHIFT, |
198 | 4, sta32x_auto_gc_mode); | 198 | sta32x_auto_gc_mode); |
199 | static const struct soc_enum sta32x_auto_xo_enum = | 199 | static SOC_ENUM_SINGLE_DECL(sta32x_auto_xo_enum, |
200 | SOC_ENUM_SINGLE(STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, | 200 | STA32X_AUTO2, STA32X_AUTO2_XO_SHIFT, |
201 | 16, sta32x_auto_xo_mode); | 201 | sta32x_auto_xo_mode); |
202 | static const struct soc_enum sta32x_preset_eq_enum = | 202 | static SOC_ENUM_SINGLE_DECL(sta32x_preset_eq_enum, |
203 | SOC_ENUM_SINGLE(STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, | 203 | STA32X_AUTO3, STA32X_AUTO3_PEQ_SHIFT, |
204 | 32, sta32x_preset_eq_mode); | 204 | sta32x_preset_eq_mode); |
205 | static const struct soc_enum sta32x_limiter_ch1_enum = | 205 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch1_enum, |
206 | SOC_ENUM_SINGLE(STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, | 206 | STA32X_C1CFG, STA32X_CxCFG_LS_SHIFT, |
207 | 3, sta32x_limiter_select); | 207 | sta32x_limiter_select); |
208 | static const struct soc_enum sta32x_limiter_ch2_enum = | 208 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch2_enum, |
209 | SOC_ENUM_SINGLE(STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, | 209 | STA32X_C2CFG, STA32X_CxCFG_LS_SHIFT, |
210 | 3, sta32x_limiter_select); | 210 | sta32x_limiter_select); |
211 | static const struct soc_enum sta32x_limiter_ch3_enum = | 211 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter_ch3_enum, |
212 | SOC_ENUM_SINGLE(STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, | 212 | STA32X_C3CFG, STA32X_CxCFG_LS_SHIFT, |
213 | 3, sta32x_limiter_select); | 213 | sta32x_limiter_select); |
214 | static const struct soc_enum sta32x_limiter1_attack_rate_enum = | 214 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_attack_rate_enum, |
215 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxA_SHIFT, | 215 | STA32X_L1AR, STA32X_LxA_SHIFT, |
216 | 16, sta32x_limiter_attack_rate); | 216 | sta32x_limiter_attack_rate); |
217 | static const struct soc_enum sta32x_limiter2_attack_rate_enum = | 217 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_attack_rate_enum, |
218 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxA_SHIFT, | 218 | STA32X_L2AR, STA32X_LxA_SHIFT, |
219 | 16, sta32x_limiter_attack_rate); | 219 | sta32x_limiter_attack_rate); |
220 | static const struct soc_enum sta32x_limiter1_release_rate_enum = | 220 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter1_release_rate_enum, |
221 | SOC_ENUM_SINGLE(STA32X_L1AR, STA32X_LxR_SHIFT, | 221 | STA32X_L1AR, STA32X_LxR_SHIFT, |
222 | 16, sta32x_limiter_release_rate); | 222 | sta32x_limiter_release_rate); |
223 | static const struct soc_enum sta32x_limiter2_release_rate_enum = | 223 | static SOC_ENUM_SINGLE_DECL(sta32x_limiter2_release_rate_enum, |
224 | SOC_ENUM_SINGLE(STA32X_L2AR, STA32X_LxR_SHIFT, | 224 | STA32X_L2AR, STA32X_LxR_SHIFT, |
225 | 16, sta32x_limiter_release_rate); | 225 | sta32x_limiter_release_rate); |
226 | 226 | ||
227 | /* byte array controls for setting biquad, mixer, scaling coefficients; | 227 | /* byte array controls for setting biquad, mixer, scaling coefficients; |
228 | * for biquads all five coefficients need to be set in one go, | 228 | * for biquads all five coefficients need to be set in one go, |
@@ -331,7 +331,7 @@ static int sta32x_sync_coef_shadow(struct snd_soc_codec *codec) | |||
331 | 331 | ||
332 | static int sta32x_cache_sync(struct snd_soc_codec *codec) | 332 | static int sta32x_cache_sync(struct snd_soc_codec *codec) |
333 | { | 333 | { |
334 | struct sta32x_priv *sta32x = codec->control_data; | 334 | struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec); |
335 | unsigned int mute; | 335 | unsigned int mute; |
336 | int rc; | 336 | int rc; |
337 | 337 | ||
@@ -434,7 +434,7 @@ SOC_SINGLE_TLV("Treble Tone Control", STA32X_TONE, STA32X_TONE_TTC_SHIFT, 15, 0, | |||
434 | SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), | 434 | SOC_ENUM("Limiter1 Attack Rate (dB/ms)", sta32x_limiter1_attack_rate_enum), |
435 | SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), | 435 | SOC_ENUM("Limiter2 Attack Rate (dB/ms)", sta32x_limiter2_attack_rate_enum), |
436 | SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | 436 | SOC_ENUM("Limiter1 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), |
437 | SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter1_release_rate_enum), | 437 | SOC_ENUM("Limiter2 Release Rate (dB/ms)", sta32x_limiter2_release_rate_enum), |
438 | 438 | ||
439 | /* depending on mode, the attack/release thresholds have | 439 | /* depending on mode, the attack/release thresholds have |
440 | * two different enum definitions; provide both | 440 | * two different enum definitions; provide both |
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 40c07be9b581..f15b0e37274c 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -141,7 +141,7 @@ static const char *pwm_mode_text[] = { "Binary", "Headphone", "Ternary", | |||
141 | 141 | ||
142 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0); | 142 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -9150, 50, 0); |
143 | static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); | 143 | static const DECLARE_TLV_DB_SCALE(master_vol_tlv, -12750, 50, 0); |
144 | static const SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); | 144 | static SOC_ENUM_SINGLE_DECL(pwm_src, STA529_FFXCFG1, 4, pwm_mode_text); |
145 | 145 | ||
146 | static const struct snd_kcontrol_new sta529_snd_controls[] = { | 146 | static const struct snd_kcontrol_new sta529_snd_controls[] = { |
147 | SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, | 147 | SOC_DOUBLE_R_TLV("Digital Playback Volume", STA529_LVOL, STA529_RVOL, 0, |
diff --git a/sound/soc/codecs/tlv320aic23-i2c.c b/sound/soc/codecs/tlv320aic23-i2c.c new file mode 100644 index 000000000000..20fc46092c2c --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-i2c.c | |||
@@ -0,0 +1,59 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC23 codec driver I2C interface | ||
3 | * | ||
4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., | ||
6 | * | ||
7 | * Based on sound/soc/codecs/wm8731.c by Richard Purdie | ||
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 version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/i2c.h> | ||
15 | #include <linux/module.h> | ||
16 | #include <linux/regmap.h> | ||
17 | #include <sound/soc.h> | ||
18 | |||
19 | #include "tlv320aic23.h" | ||
20 | |||
21 | static int tlv320aic23_i2c_probe(struct i2c_client *i2c, | ||
22 | const struct i2c_device_id *i2c_id) | ||
23 | { | ||
24 | struct regmap *regmap; | ||
25 | |||
26 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
27 | return -EINVAL; | ||
28 | |||
29 | regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); | ||
30 | return tlv320aic23_probe(&i2c->dev, regmap); | ||
31 | } | ||
32 | |||
33 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | ||
34 | { | ||
35 | snd_soc_unregister_codec(&i2c->dev); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static const struct i2c_device_id tlv320aic23_id[] = { | ||
40 | {"tlv320aic23", 0}, | ||
41 | {} | ||
42 | }; | ||
43 | |||
44 | MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | ||
45 | |||
46 | static struct i2c_driver tlv320aic23_i2c_driver = { | ||
47 | .driver = { | ||
48 | .name = "tlv320aic23-codec", | ||
49 | }, | ||
50 | .probe = tlv320aic23_i2c_probe, | ||
51 | .remove = __exit_p(tlv320aic23_i2c_remove), | ||
52 | .id_table = tlv320aic23_id, | ||
53 | }; | ||
54 | |||
55 | module_i2c_driver(tlv320aic23_i2c_driver); | ||
56 | |||
57 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver I2C"); | ||
58 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
59 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic23-spi.c b/sound/soc/codecs/tlv320aic23-spi.c new file mode 100644 index 000000000000..585aea436c6a --- /dev/null +++ b/sound/soc/codecs/tlv320aic23-spi.c | |||
@@ -0,0 +1,57 @@ | |||
1 | /* | ||
2 | * ALSA SoC TLV320AIC23 codec driver SPI interface | ||
3 | * | ||
4 | * Author: Arun KS, <arunks@mistralsolutions.com> | ||
5 | * Copyright: (C) 2008 Mistral Solutions Pvt Ltd., | ||
6 | * | ||
7 | * Based on sound/soc/codecs/wm8731.c by Richard Purdie | ||
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 version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | */ | ||
13 | |||
14 | #include <linux/module.h> | ||
15 | #include <linux/regmap.h> | ||
16 | #include <linux/spi/spi.h> | ||
17 | #include <sound/soc.h> | ||
18 | |||
19 | #include "tlv320aic23.h" | ||
20 | |||
21 | static int aic23_spi_probe(struct spi_device *spi) | ||
22 | { | ||
23 | int ret; | ||
24 | struct regmap *regmap; | ||
25 | |||
26 | dev_dbg(&spi->dev, "probing tlv320aic23 spi device\n"); | ||
27 | |||
28 | spi->bits_per_word = 16; | ||
29 | spi->mode = SPI_MODE_0; | ||
30 | ret = spi_setup(spi); | ||
31 | if (ret < 0) | ||
32 | return ret; | ||
33 | |||
34 | regmap = devm_regmap_init_spi(spi, &tlv320aic23_regmap); | ||
35 | return tlv320aic23_probe(&spi->dev, regmap); | ||
36 | } | ||
37 | |||
38 | static int aic23_spi_remove(struct spi_device *spi) | ||
39 | { | ||
40 | snd_soc_unregister_codec(&spi->dev); | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static struct spi_driver aic23_spi = { | ||
45 | .driver = { | ||
46 | .name = "tlv320aic23", | ||
47 | .owner = THIS_MODULE, | ||
48 | }, | ||
49 | .probe = aic23_spi_probe, | ||
50 | .remove = aic23_spi_remove, | ||
51 | }; | ||
52 | |||
53 | module_spi_driver(aic23_spi); | ||
54 | |||
55 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver SPI"); | ||
56 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | ||
57 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 5d430cc56f51..27261e4b27c7 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <linux/init.h> | 23 | #include <linux/init.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/pm.h> | 25 | #include <linux/pm.h> |
26 | #include <linux/i2c.h> | ||
27 | #include <linux/regmap.h> | 26 | #include <linux/regmap.h> |
28 | #include <linux/slab.h> | 27 | #include <linux/slab.h> |
29 | #include <sound/core.h> | 28 | #include <sound/core.h> |
@@ -51,7 +50,7 @@ static const struct reg_default tlv320aic23_reg[] = { | |||
51 | { 9, 0x0000 }, | 50 | { 9, 0x0000 }, |
52 | }; | 51 | }; |
53 | 52 | ||
54 | static const struct regmap_config tlv320aic23_regmap = { | 53 | const struct regmap_config tlv320aic23_regmap = { |
55 | .reg_bits = 7, | 54 | .reg_bits = 7, |
56 | .val_bits = 9, | 55 | .val_bits = 9, |
57 | 56 | ||
@@ -64,16 +63,16 @@ static const struct regmap_config tlv320aic23_regmap = { | |||
64 | static const char *rec_src_text[] = { "Line", "Mic" }; | 63 | static const char *rec_src_text[] = { "Line", "Mic" }; |
65 | static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; | 64 | static const char *deemph_text[] = {"None", "32Khz", "44.1Khz", "48Khz"}; |
66 | 65 | ||
67 | static const struct soc_enum rec_src_enum = | 66 | static SOC_ENUM_SINGLE_DECL(rec_src_enum, |
68 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | 67 | TLV320AIC23_ANLG, 2, rec_src_text); |
69 | 68 | ||
70 | static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = | 69 | static const struct snd_kcontrol_new tlv320aic23_rec_src_mux_controls = |
71 | SOC_DAPM_ENUM("Input Select", rec_src_enum); | 70 | SOC_DAPM_ENUM("Input Select", rec_src_enum); |
72 | 71 | ||
73 | static const struct soc_enum tlv320aic23_rec_src = | 72 | static SOC_ENUM_SINGLE_DECL(tlv320aic23_rec_src, |
74 | SOC_ENUM_SINGLE(TLV320AIC23_ANLG, 2, 2, rec_src_text); | 73 | TLV320AIC23_ANLG, 2, rec_src_text); |
75 | static const struct soc_enum tlv320aic23_deemph = | 74 | static SOC_ENUM_SINGLE_DECL(tlv320aic23_deemph, |
76 | SOC_ENUM_SINGLE(TLV320AIC23_DIGT, 1, 4, deemph_text); | 75 | TLV320AIC23_DIGT, 1, deemph_text); |
77 | 76 | ||
78 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); | 77 | static const DECLARE_TLV_DB_SCALE(out_gain_tlv, -12100, 100, 0); |
79 | static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); | 78 | static const DECLARE_TLV_DB_SCALE(input_gain_tlv, -1725, 75, 0); |
@@ -400,7 +399,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, | |||
400 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); | 399 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
401 | 400 | ||
402 | /* deactivate */ | 401 | /* deactivate */ |
403 | if (!codec->active) { | 402 | if (!snd_soc_codec_is_active(codec)) { |
404 | udelay(50); | 403 | udelay(50); |
405 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); | 404 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); |
406 | } | 405 | } |
@@ -557,7 +556,7 @@ static int tlv320aic23_resume(struct snd_soc_codec *codec) | |||
557 | return 0; | 556 | return 0; |
558 | } | 557 | } |
559 | 558 | ||
560 | static int tlv320aic23_probe(struct snd_soc_codec *codec) | 559 | static int tlv320aic23_codec_probe(struct snd_soc_codec *codec) |
561 | { | 560 | { |
562 | int ret; | 561 | int ret; |
563 | 562 | ||
@@ -604,7 +603,7 @@ static int tlv320aic23_remove(struct snd_soc_codec *codec) | |||
604 | } | 603 | } |
605 | 604 | ||
606 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | 605 | static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { |
607 | .probe = tlv320aic23_probe, | 606 | .probe = tlv320aic23_codec_probe, |
608 | .remove = tlv320aic23_remove, | 607 | .remove = tlv320aic23_remove, |
609 | .suspend = tlv320aic23_suspend, | 608 | .suspend = tlv320aic23_suspend, |
610 | .resume = tlv320aic23_resume, | 609 | .resume = tlv320aic23_resume, |
@@ -617,57 +616,25 @@ static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = { | |||
617 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), | 616 | .num_dapm_routes = ARRAY_SIZE(tlv320aic23_intercon), |
618 | }; | 617 | }; |
619 | 618 | ||
620 | /* | 619 | int tlv320aic23_probe(struct device *dev, struct regmap *regmap) |
621 | * If the i2c layer weren't so broken, we could pass this kind of data | ||
622 | * around | ||
623 | */ | ||
624 | static int tlv320aic23_codec_probe(struct i2c_client *i2c, | ||
625 | const struct i2c_device_id *i2c_id) | ||
626 | { | 620 | { |
627 | struct aic23 *aic23; | 621 | struct aic23 *aic23; |
628 | int ret; | ||
629 | 622 | ||
630 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | 623 | if (IS_ERR(regmap)) |
631 | return -EINVAL; | 624 | return PTR_ERR(regmap); |
632 | 625 | ||
633 | aic23 = devm_kzalloc(&i2c->dev, sizeof(struct aic23), GFP_KERNEL); | 626 | aic23 = devm_kzalloc(dev, sizeof(struct aic23), GFP_KERNEL); |
634 | if (aic23 == NULL) | 627 | if (aic23 == NULL) |
635 | return -ENOMEM; | 628 | return -ENOMEM; |
636 | 629 | ||
637 | aic23->regmap = devm_regmap_init_i2c(i2c, &tlv320aic23_regmap); | 630 | aic23->regmap = regmap; |
638 | if (IS_ERR(aic23->regmap)) | ||
639 | return PTR_ERR(aic23->regmap); | ||
640 | 631 | ||
641 | i2c_set_clientdata(i2c, aic23); | 632 | dev_set_drvdata(dev, aic23); |
642 | 633 | ||
643 | ret = snd_soc_register_codec(&i2c->dev, | 634 | return snd_soc_register_codec(dev, &soc_codec_dev_tlv320aic23, |
644 | &soc_codec_dev_tlv320aic23, &tlv320aic23_dai, 1); | 635 | &tlv320aic23_dai, 1); |
645 | return ret; | ||
646 | } | ||
647 | static int __exit tlv320aic23_i2c_remove(struct i2c_client *i2c) | ||
648 | { | ||
649 | snd_soc_unregister_codec(&i2c->dev); | ||
650 | return 0; | ||
651 | } | 636 | } |
652 | 637 | ||
653 | static const struct i2c_device_id tlv320aic23_id[] = { | ||
654 | {"tlv320aic23", 0}, | ||
655 | {} | ||
656 | }; | ||
657 | |||
658 | MODULE_DEVICE_TABLE(i2c, tlv320aic23_id); | ||
659 | |||
660 | static struct i2c_driver tlv320aic23_i2c_driver = { | ||
661 | .driver = { | ||
662 | .name = "tlv320aic23-codec", | ||
663 | }, | ||
664 | .probe = tlv320aic23_codec_probe, | ||
665 | .remove = __exit_p(tlv320aic23_i2c_remove), | ||
666 | .id_table = tlv320aic23_id, | ||
667 | }; | ||
668 | |||
669 | module_i2c_driver(tlv320aic23_i2c_driver); | ||
670 | |||
671 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); | 638 | MODULE_DESCRIPTION("ASoC TLV320AIC23 codec driver"); |
672 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); | 639 | MODULE_AUTHOR("Arun KS <arunks@mistralsolutions.com>"); |
673 | MODULE_LICENSE("GPL"); | 640 | MODULE_LICENSE("GPL"); |
diff --git a/sound/soc/codecs/tlv320aic23.h b/sound/soc/codecs/tlv320aic23.h index e804120bd3da..3a7235a04a89 100644 --- a/sound/soc/codecs/tlv320aic23.h +++ b/sound/soc/codecs/tlv320aic23.h | |||
@@ -12,6 +12,12 @@ | |||
12 | #ifndef _TLV320AIC23_H | 12 | #ifndef _TLV320AIC23_H |
13 | #define _TLV320AIC23_H | 13 | #define _TLV320AIC23_H |
14 | 14 | ||
15 | struct device; | ||
16 | struct regmap_config; | ||
17 | |||
18 | extern const struct regmap_config tlv320aic23_regmap; | ||
19 | int tlv320aic23_probe(struct device *dev, struct regmap *regmap); | ||
20 | |||
15 | /* Codec TLV320AIC23 */ | 21 | /* Codec TLV320AIC23 */ |
16 | #define TLV320AIC23_LINVOL 0x00 | 22 | #define TLV320AIC23_LINVOL 0x00 |
17 | #define TLV320AIC23_RINVOL 0x01 | 23 | #define TLV320AIC23_RINVOL 0x01 |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 4f358393d6d6..35b2d244e42e 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
@@ -461,7 +461,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, | |||
461 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) | 461 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) |
462 | return 0; | 462 | return 0; |
463 | /* Do not allow changes while stream is running*/ | 463 | /* Do not allow changes while stream is running*/ |
464 | if (codec->active) | 464 | if (snd_soc_codec_is_active(codec)) |
465 | return -EPERM; | 465 | return -EPERM; |
466 | 466 | ||
467 | if (ucontrol->value.integer.value[0] < 0 || | 467 | if (ucontrol->value.integer.value[0] < 0 || |
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 00665ada23e2..682e4ac88939 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c | |||
@@ -965,9 +965,6 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, | |||
965 | { | 965 | { |
966 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 966 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
967 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); | 967 | struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec); |
968 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
969 | unsigned short val; | ||
970 | unsigned short mask; | ||
971 | 968 | ||
972 | if (twl4030->configured) { | 969 | if (twl4030->configured) { |
973 | dev_err(codec->dev, | 970 | dev_err(codec->dev, |
@@ -975,19 +972,7 @@ static int snd_soc_put_twl4030_opmode_enum_double(struct snd_kcontrol *kcontrol, | |||
975 | return -EBUSY; | 972 | return -EBUSY; |
976 | } | 973 | } |
977 | 974 | ||
978 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 975 | return snd_soc_put_enum_double(kcontrol, ucontrol); |
979 | return -EINVAL; | ||
980 | |||
981 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | ||
982 | mask = e->mask << e->shift_l; | ||
983 | if (e->shift_l != e->shift_r) { | ||
984 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
985 | return -EINVAL; | ||
986 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
987 | mask |= e->mask << e->shift_r; | ||
988 | } | ||
989 | |||
990 | return snd_soc_update_bits(codec, e->reg, mask, val); | ||
991 | } | 976 | } |
992 | 977 | ||
993 | /* | 978 | /* |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 726df6d43c2b..8e3940dcff20 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
@@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | |||
108 | /* the interpolator & decimator regs must only be written when the | 108 | /* the interpolator & decimator regs must only be written when the |
109 | * codec DAI is active. | 109 | * codec DAI is active. |
110 | */ | 110 | */ |
111 | if (!codec->active && (reg >= UDA1380_MVOL)) | 111 | if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL)) |
112 | return 0; | 112 | return 0; |
113 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | 113 | pr_debug("uda1380: hw write %x val %x\n", reg, value); |
114 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | 114 | if (codec->hw_write(codec->control_data, data, 3) == 3) { |
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index b7ab2ef567c8..47e96ff30064 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c | |||
@@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, | |||
197 | return 0; | 197 | return 0; |
198 | 198 | ||
199 | /* Do not allow changes while stream is running */ | 199 | /* Do not allow changes while stream is running */ |
200 | if (codec->active) | 200 | if (snd_soc_codec_is_active(codec)) |
201 | return -EPERM; | 201 | return -EPERM; |
202 | 202 | ||
203 | if (ucontrol->value.integer.value[0] < 0 || | 203 | if (ucontrol->value.integer.value[0] < 0 || |
diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4e3e31aaf509..492fe846ae68 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c | |||
@@ -2100,6 +2100,7 @@ static void wm5100_micd_irq(struct wm5100_priv *wm5100) | |||
2100 | int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 2100 | int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
2101 | { | 2101 | { |
2102 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); | 2102 | struct wm5100_priv *wm5100 = snd_soc_codec_get_drvdata(codec); |
2103 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
2103 | 2104 | ||
2104 | if (jack) { | 2105 | if (jack) { |
2105 | wm5100->jack = jack; | 2106 | wm5100->jack = jack; |
@@ -2117,9 +2118,14 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
2117 | WM5100_ACCDET_RATE_MASK); | 2118 | WM5100_ACCDET_RATE_MASK); |
2118 | 2119 | ||
2119 | /* We need the charge pump to power MICBIAS */ | 2120 | /* We need the charge pump to power MICBIAS */ |
2120 | snd_soc_dapm_force_enable_pin(&codec->dapm, "CP2"); | 2121 | snd_soc_dapm_mutex_lock(dapm); |
2121 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); | 2122 | |
2122 | snd_soc_dapm_sync(&codec->dapm); | 2123 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "CP2"); |
2124 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); | ||
2125 | |||
2126 | snd_soc_dapm_sync_unlocked(dapm); | ||
2127 | |||
2128 | snd_soc_dapm_mutex_unlock(dapm); | ||
2123 | 2129 | ||
2124 | /* We start off just enabling microphone detection - even a | 2130 | /* We start off just enabling microphone detection - even a |
2125 | * plain headphone will trigger detection. | 2131 | * plain headphone will trigger detection. |
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index ce9c8e14d4bd..34109050ceed 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c | |||
@@ -582,7 +582,7 @@ static int wm5102_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
582 | { | 582 | { |
583 | struct snd_soc_codec *codec = w->codec; | 583 | struct snd_soc_codec *codec = w->codec; |
584 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 584 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
585 | struct regmap *regmap = codec->control_data; | 585 | struct regmap *regmap = arizona->regmap; |
586 | const struct reg_default *patch = NULL; | 586 | const struct reg_default *patch = NULL; |
587 | int i, patch_size; | 587 | int i, patch_size; |
588 | 588 | ||
@@ -622,13 +622,16 @@ static const unsigned int wm5102_osr_val[] = { | |||
622 | 622 | ||
623 | static const struct soc_enum wm5102_hpout_osr[] = { | 623 | static const struct soc_enum wm5102_hpout_osr[] = { |
624 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, | 624 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, |
625 | ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, | 625 | ARIZONA_OUT1_OSR_SHIFT, 0x7, |
626 | ARRAY_SIZE(wm5102_osr_text), | ||
626 | wm5102_osr_text, wm5102_osr_val), | 627 | wm5102_osr_text, wm5102_osr_val), |
627 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, | 628 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_2L, |
628 | ARIZONA_OUT2_OSR_SHIFT, 0x7, 3, | 629 | ARIZONA_OUT2_OSR_SHIFT, 0x7, |
630 | ARRAY_SIZE(wm5102_osr_text), | ||
629 | wm5102_osr_text, wm5102_osr_val), | 631 | wm5102_osr_text, wm5102_osr_val), |
630 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, | 632 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, |
631 | ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, | 633 | ARIZONA_OUT3_OSR_SHIFT, 0x7, |
634 | ARRAY_SIZE(wm5102_osr_text), | ||
632 | wm5102_osr_text, wm5102_osr_val), | 635 | wm5102_osr_text, wm5102_osr_val), |
633 | }; | 636 | }; |
634 | 637 | ||
@@ -685,15 +688,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | |||
685 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | 688 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), |
686 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | 689 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), |
687 | 690 | ||
688 | SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, | 691 | SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), |
689 | ARIZONA_EQ1_ENA_MASK), | 692 | SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), |
690 | SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, | ||
691 | ARIZONA_EQ2_ENA_MASK), | ||
692 | SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, | ||
693 | ARIZONA_EQ3_ENA_MASK), | ||
694 | SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, | ||
695 | ARIZONA_EQ4_ENA_MASK), | ||
696 | |||
697 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | 693 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, |
698 | 24, 0, eq_tlv), | 694 | 24, 0, eq_tlv), |
699 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | 695 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, |
@@ -705,6 +701,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | |||
705 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | 701 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, |
706 | 24, 0, eq_tlv), | 702 | 24, 0, eq_tlv), |
707 | 703 | ||
704 | SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), | ||
705 | SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), | ||
708 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | 706 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, |
709 | 24, 0, eq_tlv), | 707 | 24, 0, eq_tlv), |
710 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | 708 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, |
@@ -716,6 +714,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | |||
716 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | 714 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, |
717 | 24, 0, eq_tlv), | 715 | 24, 0, eq_tlv), |
718 | 716 | ||
717 | SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), | ||
718 | SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), | ||
719 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | 719 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, |
720 | 24, 0, eq_tlv), | 720 | 24, 0, eq_tlv), |
721 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | 721 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, |
@@ -727,6 +727,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | |||
727 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | 727 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, |
728 | 24, 0, eq_tlv), | 728 | 24, 0, eq_tlv), |
729 | 729 | ||
730 | SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), | ||
731 | SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), | ||
730 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | 732 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, |
731 | 24, 0, eq_tlv), | 733 | 24, 0, eq_tlv), |
732 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | 734 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, |
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 2c3c962d9a85..d7bf8848174a 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c | |||
@@ -136,7 +136,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
136 | { | 136 | { |
137 | struct snd_soc_codec *codec = w->codec; | 137 | struct snd_soc_codec *codec = w->codec; |
138 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 138 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
139 | struct regmap *regmap = codec->control_data; | 139 | struct regmap *regmap = arizona->regmap; |
140 | const struct reg_default *patch = NULL; | 140 | const struct reg_default *patch = NULL; |
141 | int i, patch_size; | 141 | int i, patch_size; |
142 | 142 | ||
@@ -247,15 +247,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | |||
247 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | 247 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), |
248 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | 248 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), |
249 | 249 | ||
250 | SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, | 250 | SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), |
251 | ARIZONA_EQ1_ENA_MASK), | 251 | SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), |
252 | SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, | ||
253 | ARIZONA_EQ2_ENA_MASK), | ||
254 | SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, | ||
255 | ARIZONA_EQ3_ENA_MASK), | ||
256 | SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, | ||
257 | ARIZONA_EQ4_ENA_MASK), | ||
258 | |||
259 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | 252 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, |
260 | 24, 0, eq_tlv), | 253 | 24, 0, eq_tlv), |
261 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | 254 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, |
@@ -267,6 +260,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | |||
267 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | 260 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, |
268 | 24, 0, eq_tlv), | 261 | 24, 0, eq_tlv), |
269 | 262 | ||
263 | SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), | ||
264 | SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), | ||
270 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | 265 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, |
271 | 24, 0, eq_tlv), | 266 | 24, 0, eq_tlv), |
272 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | 267 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, |
@@ -278,6 +273,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | |||
278 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | 273 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, |
279 | 24, 0, eq_tlv), | 274 | 24, 0, eq_tlv), |
280 | 275 | ||
276 | SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), | ||
277 | SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), | ||
281 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | 278 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, |
282 | 24, 0, eq_tlv), | 279 | 24, 0, eq_tlv), |
283 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | 280 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, |
@@ -289,6 +286,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | |||
289 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | 286 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, |
290 | 24, 0, eq_tlv), | 287 | 24, 0, eq_tlv), |
291 | 288 | ||
289 | SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), | ||
290 | SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), | ||
292 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | 291 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, |
293 | 24, 0, eq_tlv), | 292 | 24, 0, eq_tlv), |
294 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | 293 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, |
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 48dc7d2fee36..6d684d934f4d 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c | |||
@@ -117,19 +117,23 @@ static int wm8400_outpga_put_volsw_vu(struct snd_kcontrol *kcontrol, | |||
117 | static const char *wm8400_digital_sidetone[] = | 117 | static const char *wm8400_digital_sidetone[] = |
118 | {"None", "Left ADC", "Right ADC", "Reserved"}; | 118 | {"None", "Left ADC", "Right ADC", "Reserved"}; |
119 | 119 | ||
120 | static const struct soc_enum wm8400_left_digital_sidetone_enum = | 120 | static SOC_ENUM_SINGLE_DECL(wm8400_left_digital_sidetone_enum, |
121 | SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, | 121 | WM8400_DIGITAL_SIDE_TONE, |
122 | WM8400_ADC_TO_DACL_SHIFT, 2, wm8400_digital_sidetone); | 122 | WM8400_ADC_TO_DACL_SHIFT, |
123 | wm8400_digital_sidetone); | ||
123 | 124 | ||
124 | static const struct soc_enum wm8400_right_digital_sidetone_enum = | 125 | static SOC_ENUM_SINGLE_DECL(wm8400_right_digital_sidetone_enum, |
125 | SOC_ENUM_SINGLE(WM8400_DIGITAL_SIDE_TONE, | 126 | WM8400_DIGITAL_SIDE_TONE, |
126 | WM8400_ADC_TO_DACR_SHIFT, 2, wm8400_digital_sidetone); | 127 | WM8400_ADC_TO_DACR_SHIFT, |
128 | wm8400_digital_sidetone); | ||
127 | 129 | ||
128 | static const char *wm8400_adcmode[] = | 130 | static const char *wm8400_adcmode[] = |
129 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; | 131 | {"Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3"}; |
130 | 132 | ||
131 | static const struct soc_enum wm8400_right_adcmode_enum = | 133 | static SOC_ENUM_SINGLE_DECL(wm8400_right_adcmode_enum, |
132 | SOC_ENUM_SINGLE(WM8400_ADC_CTRL, WM8400_ADC_HPF_CUT_SHIFT, 3, wm8400_adcmode); | 134 | WM8400_ADC_CTRL, |
135 | WM8400_ADC_HPF_CUT_SHIFT, | ||
136 | wm8400_adcmode); | ||
133 | 137 | ||
134 | static const struct snd_kcontrol_new wm8400_snd_controls[] = { | 138 | static const struct snd_kcontrol_new wm8400_snd_controls[] = { |
135 | /* INMIXL */ | 139 | /* INMIXL */ |
@@ -422,9 +426,10 @@ SOC_DAPM_SINGLE("RINPGA34 Switch", WM8400_INPUT_MIXER3, WM8400_L34MNB_SHIFT, | |||
422 | static const char *wm8400_ainlmux[] = | 426 | static const char *wm8400_ainlmux[] = |
423 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; | 427 | {"INMIXL Mix", "RXVOICE Mix", "DIFFINL Mix"}; |
424 | 428 | ||
425 | static const struct soc_enum wm8400_ainlmux_enum = | 429 | static SOC_ENUM_SINGLE_DECL(wm8400_ainlmux_enum, |
426 | SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINLMODE_SHIFT, | 430 | WM8400_INPUT_MIXER1, |
427 | ARRAY_SIZE(wm8400_ainlmux), wm8400_ainlmux); | 431 | WM8400_AINLMODE_SHIFT, |
432 | wm8400_ainlmux); | ||
428 | 433 | ||
429 | static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls = | 434 | static const struct snd_kcontrol_new wm8400_dapm_ainlmux_controls = |
430 | SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); | 435 | SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); |
@@ -435,9 +440,10 @@ SOC_DAPM_ENUM("Route", wm8400_ainlmux_enum); | |||
435 | static const char *wm8400_ainrmux[] = | 440 | static const char *wm8400_ainrmux[] = |
436 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; | 441 | {"INMIXR Mix", "RXVOICE Mix", "DIFFINR Mix"}; |
437 | 442 | ||
438 | static const struct soc_enum wm8400_ainrmux_enum = | 443 | static SOC_ENUM_SINGLE_DECL(wm8400_ainrmux_enum, |
439 | SOC_ENUM_SINGLE( WM8400_INPUT_MIXER1, WM8400_AINRMODE_SHIFT, | 444 | WM8400_INPUT_MIXER1, |
440 | ARRAY_SIZE(wm8400_ainrmux), wm8400_ainrmux); | 445 | WM8400_AINRMODE_SHIFT, |
446 | wm8400_ainrmux); | ||
441 | 447 | ||
442 | static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls = | 448 | static const struct snd_kcontrol_new wm8400_dapm_ainrmux_controls = |
443 | SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); | 449 | SOC_DAPM_ENUM("Route", wm8400_ainrmux_enum); |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index d99f948c513c..6efcc40a7cb3 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
@@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream, | |||
201 | struct snd_soc_codec *codec = dai->codec; | 201 | struct snd_soc_codec *codec = dai->codec; |
202 | 202 | ||
203 | /* deactivate */ | 203 | /* deactivate */ |
204 | if (!codec->active) { | 204 | if (!snd_soc_codec_is_active(codec)) { |
205 | udelay(50); | 205 | udelay(50); |
206 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | 206 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); |
207 | } | 207 | } |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index be85da93a268..5cf4bebc5d89 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
@@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
251 | if (wm8753->dai_func == ucontrol->value.integer.value[0]) | 251 | if (wm8753->dai_func == ucontrol->value.integer.value[0]) |
252 | return 0; | 252 | return 0; |
253 | 253 | ||
254 | if (codec->active) | 254 | if (snd_soc_codec_is_active(codec)) |
255 | return -EBUSY; | 255 | return -EBUSY; |
256 | 256 | ||
257 | ioctl = snd_soc_read(codec, WM8753_IOCTL); | 257 | ioctl = snd_soc_read(codec, WM8753_IOCTL); |
@@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) | |||
1314 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. | 1314 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. |
1315 | * make sure we check if they are not both active when we mute */ | 1315 | * make sure we check if they are not both active when we mute */ |
1316 | if (mute && wm8753->dai_func == 1) { | 1316 | if (mute && wm8753->dai_func == 1) { |
1317 | if (!codec->active) | 1317 | if (!snd_soc_codec_is_active(codec)) |
1318 | snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); | 1318 | snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); |
1319 | } else { | 1319 | } else { |
1320 | if (mute) | 1320 | if (mute) |
diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 89a18d82f303..5bce21013485 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c | |||
@@ -196,8 +196,8 @@ static const char *ain_text[] = { | |||
196 | "AIN5", "AIN6", "AIN7", "AIN8" | 196 | "AIN5", "AIN6", "AIN7", "AIN8" |
197 | }; | 197 | }; |
198 | 198 | ||
199 | static const struct soc_enum ain_enum = | 199 | static SOC_ENUM_DOUBLE_DECL(ain_enum, |
200 | SOC_ENUM_DOUBLE(WM8770_ADCMUX, 0, 4, 8, ain_text); | 200 | WM8770_ADCMUX, 0, 4, ain_text); |
201 | 201 | ||
202 | static const struct snd_kcontrol_new ain_mux = | 202 | static const struct snd_kcontrol_new ain_mux = |
203 | SOC_DAPM_ENUM("Capture Mux", ain_enum); | 203 | SOC_DAPM_ENUM("Capture Mux", ain_enum); |
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index 9bc8206a6807..72d12bbe1a56 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c | |||
@@ -92,7 +92,7 @@ WM8804_REGULATOR_EVENT(0) | |||
92 | WM8804_REGULATOR_EVENT(1) | 92 | WM8804_REGULATOR_EVENT(1) |
93 | 93 | ||
94 | static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; | 94 | static const char *txsrc_text[] = { "S/PDIF RX", "AIF" }; |
95 | static const SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); | 95 | static SOC_ENUM_SINGLE_EXT_DECL(txsrc, txsrc_text); |
96 | 96 | ||
97 | static const struct snd_kcontrol_new wm8804_snd_controls[] = { | 97 | static const struct snd_kcontrol_new wm8804_snd_controls[] = { |
98 | SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), | 98 | SOC_ENUM_EXT("Input Source", txsrc, txsrc_get, txsrc_put), |
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index e98bc7038a08..43c2201cb901 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c | |||
@@ -304,53 +304,53 @@ static const DECLARE_TLV_DB_SCALE(adc_tlv, -7200, 75, 1); | |||
304 | 304 | ||
305 | static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; | 305 | static const char *mic_bias_level_txt[] = { "0.9*AVDD", "0.65*AVDD" }; |
306 | 306 | ||
307 | static const struct soc_enum mic_bias_level = | 307 | static SOC_ENUM_SINGLE_DECL(mic_bias_level, |
308 | SOC_ENUM_SINGLE(WM8900_REG_INCTL, 8, 2, mic_bias_level_txt); | 308 | WM8900_REG_INCTL, 8, mic_bias_level_txt); |
309 | 309 | ||
310 | static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; | 310 | static const char *dac_mute_rate_txt[] = { "Fast", "Slow" }; |
311 | 311 | ||
312 | static const struct soc_enum dac_mute_rate = | 312 | static SOC_ENUM_SINGLE_DECL(dac_mute_rate, |
313 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 7, 2, dac_mute_rate_txt); | 313 | WM8900_REG_DACCTRL, 7, dac_mute_rate_txt); |
314 | 314 | ||
315 | static const char *dac_deemphasis_txt[] = { | 315 | static const char *dac_deemphasis_txt[] = { |
316 | "Disabled", "32kHz", "44.1kHz", "48kHz" | 316 | "Disabled", "32kHz", "44.1kHz", "48kHz" |
317 | }; | 317 | }; |
318 | 318 | ||
319 | static const struct soc_enum dac_deemphasis = | 319 | static SOC_ENUM_SINGLE_DECL(dac_deemphasis, |
320 | SOC_ENUM_SINGLE(WM8900_REG_DACCTRL, 4, 4, dac_deemphasis_txt); | 320 | WM8900_REG_DACCTRL, 4, dac_deemphasis_txt); |
321 | 321 | ||
322 | static const char *adc_hpf_cut_txt[] = { | 322 | static const char *adc_hpf_cut_txt[] = { |
323 | "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" | 323 | "Hi-fi mode", "Voice mode 1", "Voice mode 2", "Voice mode 3" |
324 | }; | 324 | }; |
325 | 325 | ||
326 | static const struct soc_enum adc_hpf_cut = | 326 | static SOC_ENUM_SINGLE_DECL(adc_hpf_cut, |
327 | SOC_ENUM_SINGLE(WM8900_REG_ADCCTRL, 5, 4, adc_hpf_cut_txt); | 327 | WM8900_REG_ADCCTRL, 5, adc_hpf_cut_txt); |
328 | 328 | ||
329 | static const char *lr_txt[] = { | 329 | static const char *lr_txt[] = { |
330 | "Left", "Right" | 330 | "Left", "Right" |
331 | }; | 331 | }; |
332 | 332 | ||
333 | static const struct soc_enum aifl_src = | 333 | static SOC_ENUM_SINGLE_DECL(aifl_src, |
334 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 15, 2, lr_txt); | 334 | WM8900_REG_AUDIO1, 15, lr_txt); |
335 | 335 | ||
336 | static const struct soc_enum aifr_src = | 336 | static SOC_ENUM_SINGLE_DECL(aifr_src, |
337 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO1, 14, 2, lr_txt); | 337 | WM8900_REG_AUDIO1, 14, lr_txt); |
338 | 338 | ||
339 | static const struct soc_enum dacl_src = | 339 | static SOC_ENUM_SINGLE_DECL(dacl_src, |
340 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 15, 2, lr_txt); | 340 | WM8900_REG_AUDIO2, 15, lr_txt); |
341 | 341 | ||
342 | static const struct soc_enum dacr_src = | 342 | static SOC_ENUM_SINGLE_DECL(dacr_src, |
343 | SOC_ENUM_SINGLE(WM8900_REG_AUDIO2, 14, 2, lr_txt); | 343 | WM8900_REG_AUDIO2, 14, lr_txt); |
344 | 344 | ||
345 | static const char *sidetone_txt[] = { | 345 | static const char *sidetone_txt[] = { |
346 | "Disabled", "Left ADC", "Right ADC" | 346 | "Disabled", "Left ADC", "Right ADC" |
347 | }; | 347 | }; |
348 | 348 | ||
349 | static const struct soc_enum dacl_sidetone = | 349 | static SOC_ENUM_SINGLE_DECL(dacl_sidetone, |
350 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 2, 3, sidetone_txt); | 350 | WM8900_REG_SIDETONE, 2, sidetone_txt); |
351 | 351 | ||
352 | static const struct soc_enum dacr_sidetone = | 352 | static SOC_ENUM_SINGLE_DECL(dacr_sidetone, |
353 | SOC_ENUM_SINGLE(WM8900_REG_SIDETONE, 0, 3, sidetone_txt); | 353 | WM8900_REG_SIDETONE, 0, sidetone_txt); |
354 | 354 | ||
355 | static const struct snd_kcontrol_new wm8900_snd_controls[] = { | 355 | static const struct snd_kcontrol_new wm8900_snd_controls[] = { |
356 | SOC_ENUM("Mic Bias Level", mic_bias_level), | 356 | SOC_ENUM("Mic Bias Level", mic_bias_level), |
@@ -496,8 +496,8 @@ SOC_DAPM_SINGLE("RINPUT3 Switch", WM8900_REG_INCTL, 0, 1, 0), | |||
496 | 496 | ||
497 | static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" }; | 497 | static const char *wm8900_lp_mux[] = { "Disabled", "Enabled" }; |
498 | 498 | ||
499 | static const struct soc_enum wm8900_lineout2_lp_mux = | 499 | static SOC_ENUM_SINGLE_DECL(wm8900_lineout2_lp_mux, |
500 | SOC_ENUM_SINGLE(WM8900_REG_LOUTMIXCTL1, 1, 2, wm8900_lp_mux); | 500 | WM8900_REG_LOUTMIXCTL1, 1, wm8900_lp_mux); |
501 | 501 | ||
502 | static const struct snd_kcontrol_new wm8900_lineout2_lp = | 502 | static const struct snd_kcontrol_new wm8900_lineout2_lp = |
503 | SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); | 503 | SOC_DAPM_ENUM("Route", wm8900_lineout2_lp_mux); |
diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 53bbfac6a83a..b2664ec901b9 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c | |||
@@ -1981,7 +1981,7 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_codec *codec) | |||
1981 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | 1981 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", |
1982 | wm8904->num_retune_mobile_texts); | 1982 | wm8904->num_retune_mobile_texts); |
1983 | 1983 | ||
1984 | wm8904->retune_mobile_enum.max = wm8904->num_retune_mobile_texts; | 1984 | wm8904->retune_mobile_enum.items = wm8904->num_retune_mobile_texts; |
1985 | wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; | 1985 | wm8904->retune_mobile_enum.texts = wm8904->retune_mobile_texts; |
1986 | 1986 | ||
1987 | ret = snd_soc_add_codec_controls(codec, &control, 1); | 1987 | ret = snd_soc_add_codec_controls(codec, &control, 1); |
@@ -2022,7 +2022,7 @@ static void wm8904_handle_pdata(struct snd_soc_codec *codec) | |||
2022 | for (i = 0; i < pdata->num_drc_cfgs; i++) | 2022 | for (i = 0; i < pdata->num_drc_cfgs; i++) |
2023 | wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; | 2023 | wm8904->drc_texts[i] = pdata->drc_cfgs[i].name; |
2024 | 2024 | ||
2025 | wm8904->drc_enum.max = pdata->num_drc_cfgs; | 2025 | wm8904->drc_enum.items = pdata->num_drc_cfgs; |
2026 | wm8904->drc_enum.texts = wm8904->drc_texts; | 2026 | wm8904->drc_enum.texts = wm8904->drc_texts; |
2027 | 2027 | ||
2028 | ret = snd_soc_add_codec_controls(codec, &control, 1); | 2028 | ret = snd_soc_add_codec_controls(codec, &control, 1); |
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c index b7488f190d2b..7ac2e511403c 100644 --- a/sound/soc/codecs/wm8958-dsp2.c +++ b/sound/soc/codecs/wm8958-dsp2.c | |||
@@ -153,7 +153,7 @@ static int wm8958_dsp2_fw(struct snd_soc_codec *codec, const char *name, | |||
153 | 153 | ||
154 | data32 &= 0xffffff; | 154 | data32 &= 0xffffff; |
155 | 155 | ||
156 | wm8994_bulk_write(codec->control_data, | 156 | wm8994_bulk_write(wm8994->wm8994, |
157 | data32 & 0xffffff, | 157 | data32 & 0xffffff, |
158 | block_len / 2, | 158 | block_len / 2, |
159 | (void *)(data + 8)); | 159 | (void *)(data + 8)); |
@@ -944,7 +944,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
944 | for (i = 0; i < pdata->num_mbc_cfgs; i++) | 944 | for (i = 0; i < pdata->num_mbc_cfgs; i++) |
945 | wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; | 945 | wm8994->mbc_texts[i] = pdata->mbc_cfgs[i].name; |
946 | 946 | ||
947 | wm8994->mbc_enum.max = pdata->num_mbc_cfgs; | 947 | wm8994->mbc_enum.items = pdata->num_mbc_cfgs; |
948 | wm8994->mbc_enum.texts = wm8994->mbc_texts; | 948 | wm8994->mbc_enum.texts = wm8994->mbc_texts; |
949 | 949 | ||
950 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 950 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
@@ -973,7 +973,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
973 | for (i = 0; i < pdata->num_vss_cfgs; i++) | 973 | for (i = 0; i < pdata->num_vss_cfgs; i++) |
974 | wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; | 974 | wm8994->vss_texts[i] = pdata->vss_cfgs[i].name; |
975 | 975 | ||
976 | wm8994->vss_enum.max = pdata->num_vss_cfgs; | 976 | wm8994->vss_enum.items = pdata->num_vss_cfgs; |
977 | wm8994->vss_enum.texts = wm8994->vss_texts; | 977 | wm8994->vss_enum.texts = wm8994->vss_texts; |
978 | 978 | ||
979 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 979 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
@@ -1003,7 +1003,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
1003 | for (i = 0; i < pdata->num_vss_hpf_cfgs; i++) | 1003 | for (i = 0; i < pdata->num_vss_hpf_cfgs; i++) |
1004 | wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; | 1004 | wm8994->vss_hpf_texts[i] = pdata->vss_hpf_cfgs[i].name; |
1005 | 1005 | ||
1006 | wm8994->vss_hpf_enum.max = pdata->num_vss_hpf_cfgs; | 1006 | wm8994->vss_hpf_enum.items = pdata->num_vss_hpf_cfgs; |
1007 | wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; | 1007 | wm8994->vss_hpf_enum.texts = wm8994->vss_hpf_texts; |
1008 | 1008 | ||
1009 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 1009 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
@@ -1034,7 +1034,7 @@ void wm8958_dsp2_init(struct snd_soc_codec *codec) | |||
1034 | for (i = 0; i < pdata->num_enh_eq_cfgs; i++) | 1034 | for (i = 0; i < pdata->num_enh_eq_cfgs; i++) |
1035 | wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; | 1035 | wm8994->enh_eq_texts[i] = pdata->enh_eq_cfgs[i].name; |
1036 | 1036 | ||
1037 | wm8994->enh_eq_enum.max = pdata->num_enh_eq_cfgs; | 1037 | wm8994->enh_eq_enum.items = pdata->num_enh_eq_cfgs; |
1038 | wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; | 1038 | wm8994->enh_eq_enum.texts = wm8994->enh_eq_texts; |
1039 | 1039 | ||
1040 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, | 1040 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, |
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 97db3b45b411..9e6233633c44 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c | |||
@@ -3089,6 +3089,7 @@ static irqreturn_t wm8962_irq(int irq, void *data) | |||
3089 | int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | 3089 | int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) |
3090 | { | 3090 | { |
3091 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); | 3091 | struct wm8962_priv *wm8962 = snd_soc_codec_get_drvdata(codec); |
3092 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
3092 | int irq_mask, enable; | 3093 | int irq_mask, enable; |
3093 | 3094 | ||
3094 | wm8962->jack = jack; | 3095 | wm8962->jack = jack; |
@@ -3109,14 +3110,18 @@ int wm8962_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) | |||
3109 | snd_soc_jack_report(wm8962->jack, 0, | 3110 | snd_soc_jack_report(wm8962->jack, 0, |
3110 | SND_JACK_MICROPHONE | SND_JACK_BTN_0); | 3111 | SND_JACK_MICROPHONE | SND_JACK_BTN_0); |
3111 | 3112 | ||
3113 | snd_soc_dapm_mutex_lock(dapm); | ||
3114 | |||
3112 | if (jack) { | 3115 | if (jack) { |
3113 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); | 3116 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); |
3114 | snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); | 3117 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "MICBIAS"); |
3115 | } else { | 3118 | } else { |
3116 | snd_soc_dapm_disable_pin(&codec->dapm, "SYSCLK"); | 3119 | snd_soc_dapm_disable_pin_unlocked(dapm, "SYSCLK"); |
3117 | snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); | 3120 | snd_soc_dapm_disable_pin_unlocked(dapm, "MICBIAS"); |
3118 | } | 3121 | } |
3119 | 3122 | ||
3123 | snd_soc_dapm_mutex_unlock(dapm); | ||
3124 | |||
3120 | return 0; | 3125 | return 0; |
3121 | } | 3126 | } |
3122 | EXPORT_SYMBOL_GPL(wm8962_mic_detect); | 3127 | EXPORT_SYMBOL_GPL(wm8962_mic_detect); |
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index d8fc531c0e59..a9e2f465c331 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c | |||
@@ -117,21 +117,21 @@ static const char *wm8978_eq5[] = {"5.3kHz", "6.9kHz", "9kHz", "11.7kHz"}; | |||
117 | static const char *wm8978_alc3[] = {"ALC", "Limiter"}; | 117 | static const char *wm8978_alc3[] = {"ALC", "Limiter"}; |
118 | static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; | 118 | static const char *wm8978_alc1[] = {"Off", "Right", "Left", "Both"}; |
119 | 119 | ||
120 | static const SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, | 120 | static SOC_ENUM_SINGLE_DECL(adc_compand, WM8978_COMPANDING_CONTROL, 1, |
121 | wm8978_companding); | 121 | wm8978_companding); |
122 | static const SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, | 122 | static SOC_ENUM_SINGLE_DECL(dac_compand, WM8978_COMPANDING_CONTROL, 3, |
123 | wm8978_companding); | 123 | wm8978_companding); |
124 | static const SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); | 124 | static SOC_ENUM_SINGLE_DECL(eqmode, WM8978_EQ1, 8, wm8978_eqmode); |
125 | static const SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); | 125 | static SOC_ENUM_SINGLE_DECL(eq1, WM8978_EQ1, 5, wm8978_eq1); |
126 | static const SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); | 126 | static SOC_ENUM_SINGLE_DECL(eq2bw, WM8978_EQ2, 8, wm8978_bw); |
127 | static const SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); | 127 | static SOC_ENUM_SINGLE_DECL(eq2, WM8978_EQ2, 5, wm8978_eq2); |
128 | static const SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); | 128 | static SOC_ENUM_SINGLE_DECL(eq3bw, WM8978_EQ3, 8, wm8978_bw); |
129 | static const SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); | 129 | static SOC_ENUM_SINGLE_DECL(eq3, WM8978_EQ3, 5, wm8978_eq3); |
130 | static const SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); | 130 | static SOC_ENUM_SINGLE_DECL(eq4bw, WM8978_EQ4, 8, wm8978_bw); |
131 | static const SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); | 131 | static SOC_ENUM_SINGLE_DECL(eq4, WM8978_EQ4, 5, wm8978_eq4); |
132 | static const SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); | 132 | static SOC_ENUM_SINGLE_DECL(eq5, WM8978_EQ5, 5, wm8978_eq5); |
133 | static const SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); | 133 | static SOC_ENUM_SINGLE_DECL(alc3, WM8978_ALC_CONTROL_3, 8, wm8978_alc3); |
134 | static const SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); | 134 | static SOC_ENUM_SINGLE_DECL(alc1, WM8978_ALC_CONTROL_1, 7, wm8978_alc1); |
135 | 135 | ||
136 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); | 136 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -12750, 50, 1); |
137 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); | 137 | static const DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); |
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index aa41ba0dfff4..770e5a705851 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c | |||
@@ -205,49 +205,44 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | |||
205 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); | 205 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); |
206 | 206 | ||
207 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; | 207 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; |
208 | static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, | 208 | static SOC_ENUM_SINGLE_DECL(alc_sel, WM8983_ALC_CONTROL_1, 7, alc_sel_text); |
209 | alc_sel_text); | ||
210 | 209 | ||
211 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; | 210 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; |
212 | static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, | 211 | static SOC_ENUM_SINGLE_DECL(alc_mode, WM8983_ALC_CONTROL_3, 8, alc_mode_text); |
213 | alc_mode_text); | ||
214 | 212 | ||
215 | static const char *filter_mode_text[] = { "Audio", "Application" }; | 213 | static const char *filter_mode_text[] = { "Audio", "Application" }; |
216 | static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, | 214 | static SOC_ENUM_SINGLE_DECL(filter_mode, WM8983_ADC_CONTROL, 7, |
217 | filter_mode_text); | 215 | filter_mode_text); |
218 | 216 | ||
219 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; | 217 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; |
220 | static const char *eqmode_text[] = { "Capture", "Playback" }; | 218 | static const char *eqmode_text[] = { "Capture", "Playback" }; |
221 | static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); | 219 | static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); |
222 | 220 | ||
223 | static const char *eq1_cutoff_text[] = { | 221 | static const char *eq1_cutoff_text[] = { |
224 | "80Hz", "105Hz", "135Hz", "175Hz" | 222 | "80Hz", "105Hz", "135Hz", "175Hz" |
225 | }; | 223 | }; |
226 | static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, | 224 | static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8983_EQ1_LOW_SHELF, 5, |
227 | eq1_cutoff_text); | 225 | eq1_cutoff_text); |
228 | static const char *eq2_cutoff_text[] = { | 226 | static const char *eq2_cutoff_text[] = { |
229 | "230Hz", "300Hz", "385Hz", "500Hz" | 227 | "230Hz", "300Hz", "385Hz", "500Hz" |
230 | }; | 228 | }; |
231 | static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); | 229 | static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8983_EQ2_PEAK_1, 8, eq_bw_text); |
232 | static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, | 230 | static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8983_EQ2_PEAK_1, 5, eq2_cutoff_text); |
233 | eq2_cutoff_text); | ||
234 | static const char *eq3_cutoff_text[] = { | 231 | static const char *eq3_cutoff_text[] = { |
235 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" | 232 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" |
236 | }; | 233 | }; |
237 | static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); | 234 | static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8983_EQ3_PEAK_2, 8, eq_bw_text); |
238 | static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, | 235 | static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8983_EQ3_PEAK_2, 5, eq3_cutoff_text); |
239 | eq3_cutoff_text); | ||
240 | static const char *eq4_cutoff_text[] = { | 236 | static const char *eq4_cutoff_text[] = { |
241 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" | 237 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" |
242 | }; | 238 | }; |
243 | static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); | 239 | static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8983_EQ4_PEAK_3, 8, eq_bw_text); |
244 | static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, | 240 | static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8983_EQ4_PEAK_3, 5, eq4_cutoff_text); |
245 | eq4_cutoff_text); | ||
246 | static const char *eq5_cutoff_text[] = { | 241 | static const char *eq5_cutoff_text[] = { |
247 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" | 242 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" |
248 | }; | 243 | }; |
249 | static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, | 244 | static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8983_EQ5_HIGH_SHELF, 5, |
250 | eq5_cutoff_text); | 245 | eq5_cutoff_text); |
251 | 246 | ||
252 | static const char *depth_3d_text[] = { | 247 | static const char *depth_3d_text[] = { |
253 | "Off", | 248 | "Off", |
@@ -267,8 +262,8 @@ static const char *depth_3d_text[] = { | |||
267 | "93.3%", | 262 | "93.3%", |
268 | "100%" | 263 | "100%" |
269 | }; | 264 | }; |
270 | static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, | 265 | static SOC_ENUM_SINGLE_DECL(depth_3d, WM8983_3D_CONTROL, 0, |
271 | depth_3d_text); | 266 | depth_3d_text); |
272 | 267 | ||
273 | static const struct snd_kcontrol_new wm8983_snd_controls[] = { | 268 | static const struct snd_kcontrol_new wm8983_snd_controls[] = { |
274 | SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, | 269 | SOC_SINGLE("Digital Loopback Switch", WM8983_COMPANDING_CONTROL, |
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 271b517911a4..d786f2b39764 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c | |||
@@ -226,52 +226,48 @@ static const DECLARE_TLV_DB_SCALE(bypass_tlv, -1500, 300, 0); | |||
226 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); | 226 | static const DECLARE_TLV_DB_SCALE(pga_boost_tlv, 0, 2000, 0); |
227 | 227 | ||
228 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; | 228 | static const char *alc_sel_text[] = { "Off", "Right", "Left", "Stereo" }; |
229 | static const SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, | 229 | static SOC_ENUM_SINGLE_DECL(alc_sel, WM8985_ALC_CONTROL_1, 7, alc_sel_text); |
230 | alc_sel_text); | ||
231 | 230 | ||
232 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; | 231 | static const char *alc_mode_text[] = { "ALC", "Limiter" }; |
233 | static const SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, | 232 | static SOC_ENUM_SINGLE_DECL(alc_mode, WM8985_ALC_CONTROL_3, 8, alc_mode_text); |
234 | alc_mode_text); | ||
235 | 233 | ||
236 | static const char *filter_mode_text[] = { "Audio", "Application" }; | 234 | static const char *filter_mode_text[] = { "Audio", "Application" }; |
237 | static const SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, | 235 | static SOC_ENUM_SINGLE_DECL(filter_mode, WM8985_ADC_CONTROL, 7, |
238 | filter_mode_text); | 236 | filter_mode_text); |
239 | 237 | ||
240 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; | 238 | static const char *eq_bw_text[] = { "Narrow", "Wide" }; |
241 | static const char *eqmode_text[] = { "Capture", "Playback" }; | 239 | static const char *eqmode_text[] = { "Capture", "Playback" }; |
242 | static const SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); | 240 | static SOC_ENUM_SINGLE_EXT_DECL(eqmode, eqmode_text); |
243 | 241 | ||
244 | static const char *eq1_cutoff_text[] = { | 242 | static const char *eq1_cutoff_text[] = { |
245 | "80Hz", "105Hz", "135Hz", "175Hz" | 243 | "80Hz", "105Hz", "135Hz", "175Hz" |
246 | }; | 244 | }; |
247 | static const SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, | 245 | static SOC_ENUM_SINGLE_DECL(eq1_cutoff, WM8985_EQ1_LOW_SHELF, 5, |
248 | eq1_cutoff_text); | 246 | eq1_cutoff_text); |
249 | static const char *eq2_cutoff_text[] = { | 247 | static const char *eq2_cutoff_text[] = { |
250 | "230Hz", "300Hz", "385Hz", "500Hz" | 248 | "230Hz", "300Hz", "385Hz", "500Hz" |
251 | }; | 249 | }; |
252 | static const SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); | 250 | static SOC_ENUM_SINGLE_DECL(eq2_bw, WM8985_EQ2_PEAK_1, 8, eq_bw_text); |
253 | static const SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, | 251 | static SOC_ENUM_SINGLE_DECL(eq2_cutoff, WM8985_EQ2_PEAK_1, 5, eq2_cutoff_text); |
254 | eq2_cutoff_text); | ||
255 | static const char *eq3_cutoff_text[] = { | 252 | static const char *eq3_cutoff_text[] = { |
256 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" | 253 | "650Hz", "850Hz", "1.1kHz", "1.4kHz" |
257 | }; | 254 | }; |
258 | static const SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); | 255 | static SOC_ENUM_SINGLE_DECL(eq3_bw, WM8985_EQ3_PEAK_2, 8, eq_bw_text); |
259 | static const SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, | 256 | static SOC_ENUM_SINGLE_DECL(eq3_cutoff, WM8985_EQ3_PEAK_2, 5, |
260 | eq3_cutoff_text); | 257 | eq3_cutoff_text); |
261 | static const char *eq4_cutoff_text[] = { | 258 | static const char *eq4_cutoff_text[] = { |
262 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" | 259 | "1.8kHz", "2.4kHz", "3.2kHz", "4.1kHz" |
263 | }; | 260 | }; |
264 | static const SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); | 261 | static SOC_ENUM_SINGLE_DECL(eq4_bw, WM8985_EQ4_PEAK_3, 8, eq_bw_text); |
265 | static const SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, | 262 | static SOC_ENUM_SINGLE_DECL(eq4_cutoff, WM8985_EQ4_PEAK_3, 5, eq4_cutoff_text); |
266 | eq4_cutoff_text); | ||
267 | static const char *eq5_cutoff_text[] = { | 263 | static const char *eq5_cutoff_text[] = { |
268 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" | 264 | "5.3kHz", "6.9kHz", "9kHz", "11.7kHz" |
269 | }; | 265 | }; |
270 | static const SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, | 266 | static SOC_ENUM_SINGLE_DECL(eq5_cutoff, WM8985_EQ5_HIGH_SHELF, 5, |
271 | eq5_cutoff_text); | 267 | eq5_cutoff_text); |
272 | 268 | ||
273 | static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; | 269 | static const char *speaker_mode_text[] = { "Class A/B", "Class D" }; |
274 | static const SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); | 270 | static SOC_ENUM_SINGLE_DECL(speaker_mode, 0x17, 8, speaker_mode_text); |
275 | 271 | ||
276 | static const char *depth_3d_text[] = { | 272 | static const char *depth_3d_text[] = { |
277 | "Off", | 273 | "Off", |
@@ -291,8 +287,7 @@ static const char *depth_3d_text[] = { | |||
291 | "93.3%", | 287 | "93.3%", |
292 | "100%" | 288 | "100%" |
293 | }; | 289 | }; |
294 | static const SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, | 290 | static SOC_ENUM_SINGLE_DECL(depth_3d, WM8985_3D_CONTROL, 0, depth_3d_text); |
295 | depth_3d_text); | ||
296 | 291 | ||
297 | static const struct snd_kcontrol_new wm8985_snd_controls[] = { | 292 | static const struct snd_kcontrol_new wm8985_snd_controls[] = { |
298 | SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, | 293 | SOC_SINGLE("Digital Loopback Switch", WM8985_COMPANDING_CONTROL, |
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 433d59a0f3ef..2ee23a39622c 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c | |||
@@ -1562,7 +1562,6 @@ static int wm8993_remove(struct snd_soc_codec *codec) | |||
1562 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); | 1562 | struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec); |
1563 | 1563 | ||
1564 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); | 1564 | wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF); |
1565 | regulator_bulk_free(ARRAY_SIZE(wm8993->supplies), wm8993->supplies); | ||
1566 | return 0; | 1565 | return 0; |
1567 | } | 1566 | } |
1568 | 1567 | ||
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index b9be9cbc4603..79854cb7feb6 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c | |||
@@ -265,21 +265,21 @@ static const char *sidetone_hpf_text[] = { | |||
265 | "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz" | 265 | "2.7kHz", "1.35kHz", "675Hz", "370Hz", "180Hz", "90Hz", "45Hz" |
266 | }; | 266 | }; |
267 | 267 | ||
268 | static const struct soc_enum sidetone_hpf = | 268 | static SOC_ENUM_SINGLE_DECL(sidetone_hpf, |
269 | SOC_ENUM_SINGLE(WM8994_SIDETONE, 7, 7, sidetone_hpf_text); | 269 | WM8994_SIDETONE, 7, sidetone_hpf_text); |
270 | 270 | ||
271 | static const char *adc_hpf_text[] = { | 271 | static const char *adc_hpf_text[] = { |
272 | "HiFi", "Voice 1", "Voice 2", "Voice 3" | 272 | "HiFi", "Voice 1", "Voice 2", "Voice 3" |
273 | }; | 273 | }; |
274 | 274 | ||
275 | static const struct soc_enum aif1adc1_hpf = | 275 | static SOC_ENUM_SINGLE_DECL(aif1adc1_hpf, |
276 | SOC_ENUM_SINGLE(WM8994_AIF1_ADC1_FILTERS, 13, 4, adc_hpf_text); | 276 | WM8994_AIF1_ADC1_FILTERS, 13, adc_hpf_text); |
277 | 277 | ||
278 | static const struct soc_enum aif1adc2_hpf = | 278 | static SOC_ENUM_SINGLE_DECL(aif1adc2_hpf, |
279 | SOC_ENUM_SINGLE(WM8994_AIF1_ADC2_FILTERS, 13, 4, adc_hpf_text); | 279 | WM8994_AIF1_ADC2_FILTERS, 13, adc_hpf_text); |
280 | 280 | ||
281 | static const struct soc_enum aif2adc_hpf = | 281 | static SOC_ENUM_SINGLE_DECL(aif2adc_hpf, |
282 | SOC_ENUM_SINGLE(WM8994_AIF2_ADC_FILTERS, 13, 4, adc_hpf_text); | 282 | WM8994_AIF2_ADC_FILTERS, 13, adc_hpf_text); |
283 | 283 | ||
284 | static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0); | 284 | static const DECLARE_TLV_DB_SCALE(aif_tlv, 0, 600, 0); |
285 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); | 285 | static const DECLARE_TLV_DB_SCALE(digital_tlv, -7200, 75, 1); |
@@ -501,39 +501,39 @@ static const char *aif_chan_src_text[] = { | |||
501 | "Left", "Right" | 501 | "Left", "Right" |
502 | }; | 502 | }; |
503 | 503 | ||
504 | static const struct soc_enum aif1adcl_src = | 504 | static SOC_ENUM_SINGLE_DECL(aif1adcl_src, |
505 | SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 15, 2, aif_chan_src_text); | 505 | WM8994_AIF1_CONTROL_1, 15, aif_chan_src_text); |
506 | 506 | ||
507 | static const struct soc_enum aif1adcr_src = | 507 | static SOC_ENUM_SINGLE_DECL(aif1adcr_src, |
508 | SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_1, 14, 2, aif_chan_src_text); | 508 | WM8994_AIF1_CONTROL_1, 14, aif_chan_src_text); |
509 | 509 | ||
510 | static const struct soc_enum aif2adcl_src = | 510 | static SOC_ENUM_SINGLE_DECL(aif2adcl_src, |
511 | SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 15, 2, aif_chan_src_text); | 511 | WM8994_AIF2_CONTROL_1, 15, aif_chan_src_text); |
512 | 512 | ||
513 | static const struct soc_enum aif2adcr_src = | 513 | static SOC_ENUM_SINGLE_DECL(aif2adcr_src, |
514 | SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_1, 14, 2, aif_chan_src_text); | 514 | WM8994_AIF2_CONTROL_1, 14, aif_chan_src_text); |
515 | 515 | ||
516 | static const struct soc_enum aif1dacl_src = | 516 | static SOC_ENUM_SINGLE_DECL(aif1dacl_src, |
517 | SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 15, 2, aif_chan_src_text); | 517 | WM8994_AIF1_CONTROL_2, 15, aif_chan_src_text); |
518 | 518 | ||
519 | static const struct soc_enum aif1dacr_src = | 519 | static SOC_ENUM_SINGLE_DECL(aif1dacr_src, |
520 | SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, 14, 2, aif_chan_src_text); | 520 | WM8994_AIF1_CONTROL_2, 14, aif_chan_src_text); |
521 | 521 | ||
522 | static const struct soc_enum aif2dacl_src = | 522 | static SOC_ENUM_SINGLE_DECL(aif2dacl_src, |
523 | SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 15, 2, aif_chan_src_text); | 523 | WM8994_AIF2_CONTROL_2, 15, aif_chan_src_text); |
524 | 524 | ||
525 | static const struct soc_enum aif2dacr_src = | 525 | static SOC_ENUM_SINGLE_DECL(aif2dacr_src, |
526 | SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, 14, 2, aif_chan_src_text); | 526 | WM8994_AIF2_CONTROL_2, 14, aif_chan_src_text); |
527 | 527 | ||
528 | static const char *osr_text[] = { | 528 | static const char *osr_text[] = { |
529 | "Low Power", "High Performance", | 529 | "Low Power", "High Performance", |
530 | }; | 530 | }; |
531 | 531 | ||
532 | static const struct soc_enum dac_osr = | 532 | static SOC_ENUM_SINGLE_DECL(dac_osr, |
533 | SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 0, 2, osr_text); | 533 | WM8994_OVERSAMPLING, 0, osr_text); |
534 | 534 | ||
535 | static const struct soc_enum adc_osr = | 535 | static SOC_ENUM_SINGLE_DECL(adc_osr, |
536 | SOC_ENUM_SINGLE(WM8994_OVERSAMPLING, 1, 2, osr_text); | 536 | WM8994_OVERSAMPLING, 1, osr_text); |
537 | 537 | ||
538 | static const struct snd_kcontrol_new wm8994_snd_controls[] = { | 538 | static const struct snd_kcontrol_new wm8994_snd_controls[] = { |
539 | SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, | 539 | SOC_DOUBLE_R_TLV("AIF1ADC1 Volume", WM8994_AIF1_ADC1_LEFT_VOLUME, |
@@ -690,17 +690,20 @@ static const char *wm8958_ng_text[] = { | |||
690 | "30ms", "125ms", "250ms", "500ms", | 690 | "30ms", "125ms", "250ms", "500ms", |
691 | }; | 691 | }; |
692 | 692 | ||
693 | static const struct soc_enum wm8958_aif1dac1_ng_hold = | 693 | static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac1_ng_hold, |
694 | SOC_ENUM_SINGLE(WM8958_AIF1_DAC1_NOISE_GATE, | 694 | WM8958_AIF1_DAC1_NOISE_GATE, |
695 | WM8958_AIF1DAC1_NG_THR_SHIFT, 4, wm8958_ng_text); | 695 | WM8958_AIF1DAC1_NG_THR_SHIFT, |
696 | wm8958_ng_text); | ||
696 | 697 | ||
697 | static const struct soc_enum wm8958_aif1dac2_ng_hold = | 698 | static SOC_ENUM_SINGLE_DECL(wm8958_aif1dac2_ng_hold, |
698 | SOC_ENUM_SINGLE(WM8958_AIF1_DAC2_NOISE_GATE, | 699 | WM8958_AIF1_DAC2_NOISE_GATE, |
699 | WM8958_AIF1DAC2_NG_THR_SHIFT, 4, wm8958_ng_text); | 700 | WM8958_AIF1DAC2_NG_THR_SHIFT, |
701 | wm8958_ng_text); | ||
700 | 702 | ||
701 | static const struct soc_enum wm8958_aif2dac_ng_hold = | 703 | static SOC_ENUM_SINGLE_DECL(wm8958_aif2dac_ng_hold, |
702 | SOC_ENUM_SINGLE(WM8958_AIF2_DAC_NOISE_GATE, | 704 | WM8958_AIF2_DAC_NOISE_GATE, |
703 | WM8958_AIF2DAC_NG_THR_SHIFT, 4, wm8958_ng_text); | 705 | WM8958_AIF2DAC_NG_THR_SHIFT, |
706 | wm8958_ng_text); | ||
704 | 707 | ||
705 | static const struct snd_kcontrol_new wm8958_snd_controls[] = { | 708 | static const struct snd_kcontrol_new wm8958_snd_controls[] = { |
706 | SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), | 709 | SOC_SINGLE_TLV("AIF3 Boost Volume", WM8958_AIF3_CONTROL_2, 10, 3, 0, aif_tlv), |
@@ -1341,8 +1344,7 @@ static const char *adc_mux_text[] = { | |||
1341 | "DMIC", | 1344 | "DMIC", |
1342 | }; | 1345 | }; |
1343 | 1346 | ||
1344 | static const struct soc_enum adc_enum = | 1347 | static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); |
1345 | SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); | ||
1346 | 1348 | ||
1347 | static const struct snd_kcontrol_new adcl_mux = | 1349 | static const struct snd_kcontrol_new adcl_mux = |
1348 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); | 1350 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); |
@@ -1478,14 +1480,14 @@ static const char *sidetone_text[] = { | |||
1478 | "ADC/DMIC1", "DMIC2", | 1480 | "ADC/DMIC1", "DMIC2", |
1479 | }; | 1481 | }; |
1480 | 1482 | ||
1481 | static const struct soc_enum sidetone1_enum = | 1483 | static SOC_ENUM_SINGLE_DECL(sidetone1_enum, |
1482 | SOC_ENUM_SINGLE(WM8994_SIDETONE, 0, 2, sidetone_text); | 1484 | WM8994_SIDETONE, 0, sidetone_text); |
1483 | 1485 | ||
1484 | static const struct snd_kcontrol_new sidetone1_mux = | 1486 | static const struct snd_kcontrol_new sidetone1_mux = |
1485 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); | 1487 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); |
1486 | 1488 | ||
1487 | static const struct soc_enum sidetone2_enum = | 1489 | static SOC_ENUM_SINGLE_DECL(sidetone2_enum, |
1488 | SOC_ENUM_SINGLE(WM8994_SIDETONE, 1, 2, sidetone_text); | 1490 | WM8994_SIDETONE, 1, sidetone_text); |
1489 | 1491 | ||
1490 | static const struct snd_kcontrol_new sidetone2_mux = | 1492 | static const struct snd_kcontrol_new sidetone2_mux = |
1491 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); | 1493 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); |
@@ -1498,22 +1500,24 @@ static const char *loopback_text[] = { | |||
1498 | "None", "ADCDAT", | 1500 | "None", "ADCDAT", |
1499 | }; | 1501 | }; |
1500 | 1502 | ||
1501 | static const struct soc_enum aif1_loopback_enum = | 1503 | static SOC_ENUM_SINGLE_DECL(aif1_loopback_enum, |
1502 | SOC_ENUM_SINGLE(WM8994_AIF1_CONTROL_2, WM8994_AIF1_LOOPBACK_SHIFT, 2, | 1504 | WM8994_AIF1_CONTROL_2, |
1503 | loopback_text); | 1505 | WM8994_AIF1_LOOPBACK_SHIFT, |
1506 | loopback_text); | ||
1504 | 1507 | ||
1505 | static const struct snd_kcontrol_new aif1_loopback = | 1508 | static const struct snd_kcontrol_new aif1_loopback = |
1506 | SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); | 1509 | SOC_DAPM_ENUM("AIF1 Loopback", aif1_loopback_enum); |
1507 | 1510 | ||
1508 | static const struct soc_enum aif2_loopback_enum = | 1511 | static SOC_ENUM_SINGLE_DECL(aif2_loopback_enum, |
1509 | SOC_ENUM_SINGLE(WM8994_AIF2_CONTROL_2, WM8994_AIF2_LOOPBACK_SHIFT, 2, | 1512 | WM8994_AIF2_CONTROL_2, |
1510 | loopback_text); | 1513 | WM8994_AIF2_LOOPBACK_SHIFT, |
1514 | loopback_text); | ||
1511 | 1515 | ||
1512 | static const struct snd_kcontrol_new aif2_loopback = | 1516 | static const struct snd_kcontrol_new aif2_loopback = |
1513 | SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); | 1517 | SOC_DAPM_ENUM("AIF2 Loopback", aif2_loopback_enum); |
1514 | 1518 | ||
1515 | static const struct soc_enum aif1dac_enum = | 1519 | static SOC_ENUM_SINGLE_DECL(aif1dac_enum, |
1516 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 0, 2, aif1dac_text); | 1520 | WM8994_POWER_MANAGEMENT_6, 0, aif1dac_text); |
1517 | 1521 | ||
1518 | static const struct snd_kcontrol_new aif1dac_mux = | 1522 | static const struct snd_kcontrol_new aif1dac_mux = |
1519 | SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); | 1523 | SOC_DAPM_ENUM("AIF1DAC Mux", aif1dac_enum); |
@@ -1522,8 +1526,8 @@ static const char *aif2dac_text[] = { | |||
1522 | "AIF2DACDAT", "AIF3DACDAT", | 1526 | "AIF2DACDAT", "AIF3DACDAT", |
1523 | }; | 1527 | }; |
1524 | 1528 | ||
1525 | static const struct soc_enum aif2dac_enum = | 1529 | static SOC_ENUM_SINGLE_DECL(aif2dac_enum, |
1526 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 1, 2, aif2dac_text); | 1530 | WM8994_POWER_MANAGEMENT_6, 1, aif2dac_text); |
1527 | 1531 | ||
1528 | static const struct snd_kcontrol_new aif2dac_mux = | 1532 | static const struct snd_kcontrol_new aif2dac_mux = |
1529 | SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); | 1533 | SOC_DAPM_ENUM("AIF2DAC Mux", aif2dac_enum); |
@@ -1532,8 +1536,8 @@ static const char *aif2adc_text[] = { | |||
1532 | "AIF2ADCDAT", "AIF3DACDAT", | 1536 | "AIF2ADCDAT", "AIF3DACDAT", |
1533 | }; | 1537 | }; |
1534 | 1538 | ||
1535 | static const struct soc_enum aif2adc_enum = | 1539 | static SOC_ENUM_SINGLE_DECL(aif2adc_enum, |
1536 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 2, 2, aif2adc_text); | 1540 | WM8994_POWER_MANAGEMENT_6, 2, aif2adc_text); |
1537 | 1541 | ||
1538 | static const struct snd_kcontrol_new aif2adc_mux = | 1542 | static const struct snd_kcontrol_new aif2adc_mux = |
1539 | SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); | 1543 | SOC_DAPM_ENUM("AIF2ADC Mux", aif2adc_enum); |
@@ -1542,14 +1546,14 @@ static const char *aif3adc_text[] = { | |||
1542 | "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM", | 1546 | "AIF1ADCDAT", "AIF2ADCDAT", "AIF2DACDAT", "Mono PCM", |
1543 | }; | 1547 | }; |
1544 | 1548 | ||
1545 | static const struct soc_enum wm8994_aif3adc_enum = | 1549 | static SOC_ENUM_SINGLE_DECL(wm8994_aif3adc_enum, |
1546 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 3, aif3adc_text); | 1550 | WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text); |
1547 | 1551 | ||
1548 | static const struct snd_kcontrol_new wm8994_aif3adc_mux = | 1552 | static const struct snd_kcontrol_new wm8994_aif3adc_mux = |
1549 | SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum); | 1553 | SOC_DAPM_ENUM("AIF3ADC Mux", wm8994_aif3adc_enum); |
1550 | 1554 | ||
1551 | static const struct soc_enum wm8958_aif3adc_enum = | 1555 | static SOC_ENUM_SINGLE_DECL(wm8958_aif3adc_enum, |
1552 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 3, 4, aif3adc_text); | 1556 | WM8994_POWER_MANAGEMENT_6, 3, aif3adc_text); |
1553 | 1557 | ||
1554 | static const struct snd_kcontrol_new wm8958_aif3adc_mux = | 1558 | static const struct snd_kcontrol_new wm8958_aif3adc_mux = |
1555 | SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum); | 1559 | SOC_DAPM_ENUM("AIF3ADC Mux", wm8958_aif3adc_enum); |
@@ -1558,8 +1562,8 @@ static const char *mono_pcm_out_text[] = { | |||
1558 | "None", "AIF2ADCL", "AIF2ADCR", | 1562 | "None", "AIF2ADCL", "AIF2ADCR", |
1559 | }; | 1563 | }; |
1560 | 1564 | ||
1561 | static const struct soc_enum mono_pcm_out_enum = | 1565 | static SOC_ENUM_SINGLE_DECL(mono_pcm_out_enum, |
1562 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 9, 3, mono_pcm_out_text); | 1566 | WM8994_POWER_MANAGEMENT_6, 9, mono_pcm_out_text); |
1563 | 1567 | ||
1564 | static const struct snd_kcontrol_new mono_pcm_out_mux = | 1568 | static const struct snd_kcontrol_new mono_pcm_out_mux = |
1565 | SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum); | 1569 | SOC_DAPM_ENUM("Mono PCM Out Mux", mono_pcm_out_enum); |
@@ -1569,14 +1573,14 @@ static const char *aif2dac_src_text[] = { | |||
1569 | }; | 1573 | }; |
1570 | 1574 | ||
1571 | /* Note that these two control shouldn't be simultaneously switched to AIF3 */ | 1575 | /* Note that these two control shouldn't be simultaneously switched to AIF3 */ |
1572 | static const struct soc_enum aif2dacl_src_enum = | 1576 | static SOC_ENUM_SINGLE_DECL(aif2dacl_src_enum, |
1573 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 7, 2, aif2dac_src_text); | 1577 | WM8994_POWER_MANAGEMENT_6, 7, aif2dac_src_text); |
1574 | 1578 | ||
1575 | static const struct snd_kcontrol_new aif2dacl_src_mux = | 1579 | static const struct snd_kcontrol_new aif2dacl_src_mux = |
1576 | SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum); | 1580 | SOC_DAPM_ENUM("AIF2DACL Mux", aif2dacl_src_enum); |
1577 | 1581 | ||
1578 | static const struct soc_enum aif2dacr_src_enum = | 1582 | static SOC_ENUM_SINGLE_DECL(aif2dacr_src_enum, |
1579 | SOC_ENUM_SINGLE(WM8994_POWER_MANAGEMENT_6, 8, 2, aif2dac_src_text); | 1583 | WM8994_POWER_MANAGEMENT_6, 8, aif2dac_src_text); |
1580 | 1584 | ||
1581 | static const struct snd_kcontrol_new aif2dacr_src_mux = | 1585 | static const struct snd_kcontrol_new aif2dacr_src_mux = |
1582 | SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); | 1586 | SOC_DAPM_ENUM("AIF2DACR Mux", aif2dacr_src_enum); |
@@ -2549,43 +2553,52 @@ static int wm8994_set_bias_level(struct snd_soc_codec *codec, | |||
2549 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) | 2553 | int wm8994_vmid_mode(struct snd_soc_codec *codec, enum wm8994_vmid_mode mode) |
2550 | { | 2554 | { |
2551 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); | 2555 | struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec); |
2556 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
2552 | 2557 | ||
2553 | switch (mode) { | 2558 | switch (mode) { |
2554 | case WM8994_VMID_NORMAL: | 2559 | case WM8994_VMID_NORMAL: |
2560 | snd_soc_dapm_mutex_lock(dapm); | ||
2561 | |||
2555 | if (wm8994->hubs.lineout1_se) { | 2562 | if (wm8994->hubs.lineout1_se) { |
2556 | snd_soc_dapm_disable_pin(&codec->dapm, | 2563 | snd_soc_dapm_disable_pin_unlocked(dapm, |
2557 | "LINEOUT1N Driver"); | 2564 | "LINEOUT1N Driver"); |
2558 | snd_soc_dapm_disable_pin(&codec->dapm, | 2565 | snd_soc_dapm_disable_pin_unlocked(dapm, |
2559 | "LINEOUT1P Driver"); | 2566 | "LINEOUT1P Driver"); |
2560 | } | 2567 | } |
2561 | if (wm8994->hubs.lineout2_se) { | 2568 | if (wm8994->hubs.lineout2_se) { |
2562 | snd_soc_dapm_disable_pin(&codec->dapm, | 2569 | snd_soc_dapm_disable_pin_unlocked(dapm, |
2563 | "LINEOUT2N Driver"); | 2570 | "LINEOUT2N Driver"); |
2564 | snd_soc_dapm_disable_pin(&codec->dapm, | 2571 | snd_soc_dapm_disable_pin_unlocked(dapm, |
2565 | "LINEOUT2P Driver"); | 2572 | "LINEOUT2P Driver"); |
2566 | } | 2573 | } |
2567 | 2574 | ||
2568 | /* Do the sync with the old mode to allow it to clean up */ | 2575 | /* Do the sync with the old mode to allow it to clean up */ |
2569 | snd_soc_dapm_sync(&codec->dapm); | 2576 | snd_soc_dapm_sync_unlocked(dapm); |
2570 | wm8994->vmid_mode = mode; | 2577 | wm8994->vmid_mode = mode; |
2578 | |||
2579 | snd_soc_dapm_mutex_unlock(dapm); | ||
2571 | break; | 2580 | break; |
2572 | 2581 | ||
2573 | case WM8994_VMID_FORCE: | 2582 | case WM8994_VMID_FORCE: |
2583 | snd_soc_dapm_mutex_lock(dapm); | ||
2584 | |||
2574 | if (wm8994->hubs.lineout1_se) { | 2585 | if (wm8994->hubs.lineout1_se) { |
2575 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2586 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
2576 | "LINEOUT1N Driver"); | 2587 | "LINEOUT1N Driver"); |
2577 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2588 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
2578 | "LINEOUT1P Driver"); | 2589 | "LINEOUT1P Driver"); |
2579 | } | 2590 | } |
2580 | if (wm8994->hubs.lineout2_se) { | 2591 | if (wm8994->hubs.lineout2_se) { |
2581 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2592 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
2582 | "LINEOUT2N Driver"); | 2593 | "LINEOUT2N Driver"); |
2583 | snd_soc_dapm_force_enable_pin(&codec->dapm, | 2594 | snd_soc_dapm_force_enable_pin_unlocked(dapm, |
2584 | "LINEOUT2P Driver"); | 2595 | "LINEOUT2P Driver"); |
2585 | } | 2596 | } |
2586 | 2597 | ||
2587 | wm8994->vmid_mode = mode; | 2598 | wm8994->vmid_mode = mode; |
2588 | snd_soc_dapm_sync(&codec->dapm); | 2599 | snd_soc_dapm_sync_unlocked(dapm); |
2600 | |||
2601 | snd_soc_dapm_mutex_unlock(dapm); | ||
2589 | break; | 2602 | break; |
2590 | 2603 | ||
2591 | default: | 2604 | default: |
@@ -3237,7 +3250,7 @@ static void wm8994_handle_retune_mobile_pdata(struct wm8994_priv *wm8994) | |||
3237 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | 3250 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", |
3238 | wm8994->num_retune_mobile_texts); | 3251 | wm8994->num_retune_mobile_texts); |
3239 | 3252 | ||
3240 | wm8994->retune_mobile_enum.max = wm8994->num_retune_mobile_texts; | 3253 | wm8994->retune_mobile_enum.items = wm8994->num_retune_mobile_texts; |
3241 | wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; | 3254 | wm8994->retune_mobile_enum.texts = wm8994->retune_mobile_texts; |
3242 | 3255 | ||
3243 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, | 3256 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, |
@@ -3293,7 +3306,7 @@ static void wm8994_handle_pdata(struct wm8994_priv *wm8994) | |||
3293 | for (i = 0; i < pdata->num_drc_cfgs; i++) | 3306 | for (i = 0; i < pdata->num_drc_cfgs; i++) |
3294 | wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; | 3307 | wm8994->drc_texts[i] = pdata->drc_cfgs[i].name; |
3295 | 3308 | ||
3296 | wm8994->drc_enum.max = pdata->num_drc_cfgs; | 3309 | wm8994->drc_enum.items = pdata->num_drc_cfgs; |
3297 | wm8994->drc_enum.texts = wm8994->drc_texts; | 3310 | wm8994->drc_enum.texts = wm8994->drc_texts; |
3298 | 3311 | ||
3299 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, | 3312 | ret = snd_soc_add_codec_controls(wm8994->hubs.codec, controls, |
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 4300caff1783..ddb197dc1d53 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c | |||
@@ -423,24 +423,24 @@ static const char *in1l_text[] = { | |||
423 | "Differential", "Single-ended IN1LN", "Single-ended IN1LP" | 423 | "Differential", "Single-ended IN1LN", "Single-ended IN1LP" |
424 | }; | 424 | }; |
425 | 425 | ||
426 | static const SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, | 426 | static SOC_ENUM_SINGLE_DECL(in1l_enum, WM8995_LEFT_LINE_INPUT_CONTROL, |
427 | 2, in1l_text); | 427 | 2, in1l_text); |
428 | 428 | ||
429 | static const char *in1r_text[] = { | 429 | static const char *in1r_text[] = { |
430 | "Differential", "Single-ended IN1RN", "Single-ended IN1RP" | 430 | "Differential", "Single-ended IN1RN", "Single-ended IN1RP" |
431 | }; | 431 | }; |
432 | 432 | ||
433 | static const SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, | 433 | static SOC_ENUM_SINGLE_DECL(in1r_enum, WM8995_LEFT_LINE_INPUT_CONTROL, |
434 | 0, in1r_text); | 434 | 0, in1r_text); |
435 | 435 | ||
436 | static const char *dmic_src_text[] = { | 436 | static const char *dmic_src_text[] = { |
437 | "DMICDAT1", "DMICDAT2", "DMICDAT3" | 437 | "DMICDAT1", "DMICDAT2", "DMICDAT3" |
438 | }; | 438 | }; |
439 | 439 | ||
440 | static const SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, | 440 | static SOC_ENUM_SINGLE_DECL(dmic_src1_enum, WM8995_POWER_MANAGEMENT_5, |
441 | 8, dmic_src_text); | 441 | 8, dmic_src_text); |
442 | static const SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, | 442 | static SOC_ENUM_SINGLE_DECL(dmic_src2_enum, WM8995_POWER_MANAGEMENT_5, |
443 | 6, dmic_src_text); | 443 | 6, dmic_src_text); |
444 | 444 | ||
445 | static const struct snd_kcontrol_new wm8995_snd_controls[] = { | 445 | static const struct snd_kcontrol_new wm8995_snd_controls[] = { |
446 | SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME, | 446 | SOC_DOUBLE_R_TLV("DAC1 Volume", WM8995_DAC1_LEFT_VOLUME, |
@@ -561,10 +561,8 @@ static int hp_supply_event(struct snd_soc_dapm_widget *w, | |||
561 | struct snd_kcontrol *kcontrol, int event) | 561 | struct snd_kcontrol *kcontrol, int event) |
562 | { | 562 | { |
563 | struct snd_soc_codec *codec; | 563 | struct snd_soc_codec *codec; |
564 | struct wm8995_priv *wm8995; | ||
565 | 564 | ||
566 | codec = w->codec; | 565 | codec = w->codec; |
567 | wm8995 = snd_soc_codec_get_drvdata(codec); | ||
568 | 566 | ||
569 | switch (event) { | 567 | switch (event) { |
570 | case SND_SOC_DAPM_PRE_PMU: | 568 | case SND_SOC_DAPM_PRE_PMU: |
@@ -783,14 +781,12 @@ static const char *sidetone_text[] = { | |||
783 | "ADC/DMIC1", "DMIC2", | 781 | "ADC/DMIC1", "DMIC2", |
784 | }; | 782 | }; |
785 | 783 | ||
786 | static const struct soc_enum sidetone1_enum = | 784 | static SOC_ENUM_SINGLE_DECL(sidetone1_enum, WM8995_SIDETONE, 0, sidetone_text); |
787 | SOC_ENUM_SINGLE(WM8995_SIDETONE, 0, 2, sidetone_text); | ||
788 | 785 | ||
789 | static const struct snd_kcontrol_new sidetone1_mux = | 786 | static const struct snd_kcontrol_new sidetone1_mux = |
790 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); | 787 | SOC_DAPM_ENUM("Left Sidetone Mux", sidetone1_enum); |
791 | 788 | ||
792 | static const struct soc_enum sidetone2_enum = | 789 | static SOC_ENUM_SINGLE_DECL(sidetone2_enum, WM8995_SIDETONE, 1, sidetone_text); |
793 | SOC_ENUM_SINGLE(WM8995_SIDETONE, 1, 2, sidetone_text); | ||
794 | 790 | ||
795 | static const struct snd_kcontrol_new sidetone2_mux = | 791 | static const struct snd_kcontrol_new sidetone2_mux = |
796 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); | 792 | SOC_DAPM_ENUM("Right Sidetone Mux", sidetone2_enum); |
@@ -886,8 +882,7 @@ static const char *adc_mux_text[] = { | |||
886 | "DMIC", | 882 | "DMIC", |
887 | }; | 883 | }; |
888 | 884 | ||
889 | static const struct soc_enum adc_enum = | 885 | static SOC_ENUM_SINGLE_VIRT_DECL(adc_enum, adc_mux_text); |
890 | SOC_ENUM_SINGLE(0, 0, 2, adc_mux_text); | ||
891 | 886 | ||
892 | static const struct snd_kcontrol_new adcl_mux = | 887 | static const struct snd_kcontrol_new adcl_mux = |
893 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); | 888 | SOC_DAPM_ENUM_VIRT("ADCL Mux", adc_enum); |
@@ -899,14 +894,14 @@ static const char *spk_src_text[] = { | |||
899 | "DAC1L", "DAC1R", "DAC2L", "DAC2R" | 894 | "DAC1L", "DAC1R", "DAC2L", "DAC2R" |
900 | }; | 895 | }; |
901 | 896 | ||
902 | static const SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, | 897 | static SOC_ENUM_SINGLE_DECL(spk1l_src_enum, WM8995_LEFT_PDM_SPEAKER_1, |
903 | 0, spk_src_text); | 898 | 0, spk_src_text); |
904 | static const SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, | 899 | static SOC_ENUM_SINGLE_DECL(spk1r_src_enum, WM8995_RIGHT_PDM_SPEAKER_1, |
905 | 0, spk_src_text); | 900 | 0, spk_src_text); |
906 | static const SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, | 901 | static SOC_ENUM_SINGLE_DECL(spk2l_src_enum, WM8995_LEFT_PDM_SPEAKER_2, |
907 | 0, spk_src_text); | 902 | 0, spk_src_text); |
908 | static const SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, | 903 | static SOC_ENUM_SINGLE_DECL(spk2r_src_enum, WM8995_RIGHT_PDM_SPEAKER_2, |
909 | 0, spk_src_text); | 904 | 0, spk_src_text); |
910 | 905 | ||
911 | static const struct snd_kcontrol_new spk1l_mux = | 906 | static const struct snd_kcontrol_new spk1l_mux = |
912 | SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum); | 907 | SOC_DAPM_ENUM("SPK1L SRC", spk1l_src_enum); |
diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 1a7655b0aa22..0330165079a4 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c | |||
@@ -2251,6 +2251,7 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
2251 | wm8996_polarity_fn polarity_cb) | 2251 | wm8996_polarity_fn polarity_cb) |
2252 | { | 2252 | { |
2253 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); | 2253 | struct wm8996_priv *wm8996 = snd_soc_codec_get_drvdata(codec); |
2254 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
2254 | 2255 | ||
2255 | wm8996->jack = jack; | 2256 | wm8996->jack = jack; |
2256 | wm8996->detecting = true; | 2257 | wm8996->detecting = true; |
@@ -2267,8 +2268,12 @@ int wm8996_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack, | |||
2267 | WM8996_MICB2_DISCH, 0); | 2268 | WM8996_MICB2_DISCH, 0); |
2268 | 2269 | ||
2269 | /* LDO2 powers the microphones, SYSCLK clocks detection */ | 2270 | /* LDO2 powers the microphones, SYSCLK clocks detection */ |
2270 | snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); | 2271 | snd_soc_dapm_mutex_lock(dapm); |
2271 | snd_soc_dapm_force_enable_pin(&codec->dapm, "SYSCLK"); | 2272 | |
2273 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); | ||
2274 | snd_soc_dapm_force_enable_pin_unlocked(dapm, "SYSCLK"); | ||
2275 | |||
2276 | snd_soc_dapm_mutex_unlock(dapm); | ||
2272 | 2277 | ||
2273 | /* We start off just enabling microphone detection - even a | 2278 | /* We start off just enabling microphone detection - even a |
2274 | * plain headphone will trigger detection. | 2279 | * plain headphone will trigger detection. |
@@ -2595,7 +2600,7 @@ static void wm8996_retune_mobile_pdata(struct snd_soc_codec *codec) | |||
2595 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", | 2600 | dev_dbg(codec->dev, "Allocated %d unique ReTune Mobile names\n", |
2596 | wm8996->num_retune_mobile_texts); | 2601 | wm8996->num_retune_mobile_texts); |
2597 | 2602 | ||
2598 | wm8996->retune_mobile_enum.max = wm8996->num_retune_mobile_texts; | 2603 | wm8996->retune_mobile_enum.items = wm8996->num_retune_mobile_texts; |
2599 | wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts; | 2604 | wm8996->retune_mobile_enum.texts = wm8996->retune_mobile_texts; |
2600 | 2605 | ||
2601 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); | 2606 | ret = snd_soc_add_codec_controls(codec, controls, ARRAY_SIZE(controls)); |
diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 555115ee2159..e10f44d7fdb7 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c | |||
@@ -86,7 +86,7 @@ static int wm8997_sysclk_ev(struct snd_soc_dapm_widget *w, | |||
86 | { | 86 | { |
87 | struct snd_soc_codec *codec = w->codec; | 87 | struct snd_soc_codec *codec = w->codec; |
88 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); | 88 | struct arizona *arizona = dev_get_drvdata(codec->dev->parent); |
89 | struct regmap *regmap = codec->control_data; | 89 | struct regmap *regmap = arizona->regmap; |
90 | const struct reg_default *patch = NULL; | 90 | const struct reg_default *patch = NULL; |
91 | int i, patch_size; | 91 | int i, patch_size; |
92 | 92 | ||
@@ -123,10 +123,12 @@ static const unsigned int wm8997_osr_val[] = { | |||
123 | 123 | ||
124 | static const struct soc_enum wm8997_hpout_osr[] = { | 124 | static const struct soc_enum wm8997_hpout_osr[] = { |
125 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, | 125 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_1L, |
126 | ARIZONA_OUT1_OSR_SHIFT, 0x7, 3, | 126 | ARIZONA_OUT1_OSR_SHIFT, 0x7, |
127 | ARRAY_SIZE(wm8997_osr_text), | ||
127 | wm8997_osr_text, wm8997_osr_val), | 128 | wm8997_osr_text, wm8997_osr_val), |
128 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, | 129 | SOC_VALUE_ENUM_SINGLE(ARIZONA_OUTPUT_PATH_CONFIG_3L, |
129 | ARIZONA_OUT3_OSR_SHIFT, 0x7, 3, | 130 | ARIZONA_OUT3_OSR_SHIFT, 0x7, |
131 | ARRAY_SIZE(wm8997_osr_text), | ||
130 | wm8997_osr_text, wm8997_osr_val), | 132 | wm8997_osr_text, wm8997_osr_val), |
131 | }; | 133 | }; |
132 | 134 | ||
@@ -170,15 +172,8 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), | |||
170 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), | 172 | ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), |
171 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), | 173 | ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), |
172 | 174 | ||
173 | SND_SOC_BYTES_MASK("EQ1 Coefficients", ARIZONA_EQ1_1, 21, | 175 | SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), |
174 | ARIZONA_EQ1_ENA_MASK), | 176 | SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), |
175 | SND_SOC_BYTES_MASK("EQ2 Coefficients", ARIZONA_EQ2_1, 21, | ||
176 | ARIZONA_EQ2_ENA_MASK), | ||
177 | SND_SOC_BYTES_MASK("EQ3 Coefficients", ARIZONA_EQ3_1, 21, | ||
178 | ARIZONA_EQ3_ENA_MASK), | ||
179 | SND_SOC_BYTES_MASK("EQ4 Coefficients", ARIZONA_EQ4_1, 21, | ||
180 | ARIZONA_EQ4_ENA_MASK), | ||
181 | |||
182 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, | 177 | SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, |
183 | 24, 0, eq_tlv), | 178 | 24, 0, eq_tlv), |
184 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, | 179 | SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, |
@@ -190,6 +185,8 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, | |||
190 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, | 185 | SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, |
191 | 24, 0, eq_tlv), | 186 | 24, 0, eq_tlv), |
192 | 187 | ||
188 | SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), | ||
189 | SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), | ||
193 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, | 190 | SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, |
194 | 24, 0, eq_tlv), | 191 | 24, 0, eq_tlv), |
195 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, | 192 | SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, |
@@ -201,6 +198,8 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, | |||
201 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, | 198 | SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, |
202 | 24, 0, eq_tlv), | 199 | 24, 0, eq_tlv), |
203 | 200 | ||
201 | SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), | ||
202 | SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), | ||
204 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, | 203 | SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, |
205 | 24, 0, eq_tlv), | 204 | 24, 0, eq_tlv), |
206 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, | 205 | SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, |
@@ -212,6 +211,8 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, | |||
212 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, | 211 | SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, |
213 | 24, 0, eq_tlv), | 212 | 24, 0, eq_tlv), |
214 | 213 | ||
214 | SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), | ||
215 | SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), | ||
215 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, | 216 | SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, |
216 | 24, 0, eq_tlv), | 217 | 24, 0, eq_tlv), |
217 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, | 218 | SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 444626fcab40..bb5f7b4e3ebb 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -684,24 +684,38 @@ static int wm_adsp_load(struct wm_adsp *dsp) | |||
684 | } | 684 | } |
685 | 685 | ||
686 | if (reg) { | 686 | if (reg) { |
687 | buf = wm_adsp_buf_alloc(region->data, | 687 | size_t to_write = PAGE_SIZE; |
688 | le32_to_cpu(region->len), | 688 | size_t remain = le32_to_cpu(region->len); |
689 | &buf_list); | 689 | const u8 *data = region->data; |
690 | if (!buf) { | 690 | |
691 | adsp_err(dsp, "Out of memory\n"); | 691 | while (remain > 0) { |
692 | ret = -ENOMEM; | 692 | if (remain < PAGE_SIZE) |
693 | goto out_fw; | 693 | to_write = remain; |
694 | } | 694 | |
695 | buf = wm_adsp_buf_alloc(data, | ||
696 | to_write, | ||
697 | &buf_list); | ||
698 | if (!buf) { | ||
699 | adsp_err(dsp, "Out of memory\n"); | ||
700 | ret = -ENOMEM; | ||
701 | goto out_fw; | ||
702 | } | ||
695 | 703 | ||
696 | ret = regmap_raw_write_async(regmap, reg, buf->buf, | 704 | ret = regmap_raw_write_async(regmap, reg, |
697 | le32_to_cpu(region->len)); | 705 | buf->buf, |
698 | if (ret != 0) { | 706 | to_write); |
699 | adsp_err(dsp, | 707 | if (ret != 0) { |
700 | "%s.%d: Failed to write %d bytes at %d in %s: %d\n", | 708 | adsp_err(dsp, |
701 | file, regions, | 709 | "%s.%d: Failed to write %zd bytes at %d in %s: %d\n", |
702 | le32_to_cpu(region->len), offset, | 710 | file, regions, |
703 | region_name, ret); | 711 | to_write, offset, |
704 | goto out_fw; | 712 | region_name, ret); |
713 | goto out_fw; | ||
714 | } | ||
715 | |||
716 | data += to_write; | ||
717 | reg += to_write / 2; | ||
718 | remain -= to_write; | ||
705 | } | 719 | } |
706 | } | 720 | } |
707 | 721 | ||
@@ -1679,6 +1693,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w, | |||
1679 | list_del(&alg_region->list); | 1693 | list_del(&alg_region->list); |
1680 | kfree(alg_region); | 1694 | kfree(alg_region); |
1681 | } | 1695 | } |
1696 | |||
1697 | adsp_dbg(dsp, "Shutdown complete\n"); | ||
1682 | break; | 1698 | break; |
1683 | 1699 | ||
1684 | default: | 1700 | default: |
diff --git a/sound/soc/davinci/davinci-evm.c b/sound/soc/davinci/davinci-evm.c index 70ff3772079f..621e9a997d4c 100644 --- a/sound/soc/davinci/davinci-evm.c +++ b/sound/soc/davinci/davinci-evm.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/platform_data/edma.h> | 17 | #include <linux/platform_data/edma.h> |
18 | #include <linux/i2c.h> | 18 | #include <linux/i2c.h> |
19 | #include <linux/of_platform.h> | 19 | #include <linux/of_platform.h> |
20 | #include <linux/clk.h> | ||
20 | #include <sound/core.h> | 21 | #include <sound/core.h> |
21 | #include <sound/pcm.h> | 22 | #include <sound/pcm.h> |
22 | #include <sound/soc.h> | 23 | #include <sound/soc.h> |
@@ -30,9 +31,34 @@ | |||
30 | #include "davinci-i2s.h" | 31 | #include "davinci-i2s.h" |
31 | 32 | ||
32 | struct snd_soc_card_drvdata_davinci { | 33 | struct snd_soc_card_drvdata_davinci { |
34 | struct clk *mclk; | ||
33 | unsigned sysclk; | 35 | unsigned sysclk; |
34 | }; | 36 | }; |
35 | 37 | ||
38 | static int evm_startup(struct snd_pcm_substream *substream) | ||
39 | { | ||
40 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
41 | struct snd_soc_card *soc_card = rtd->codec->card; | ||
42 | struct snd_soc_card_drvdata_davinci *drvdata = | ||
43 | snd_soc_card_get_drvdata(soc_card); | ||
44 | |||
45 | if (drvdata->mclk) | ||
46 | return clk_prepare_enable(drvdata->mclk); | ||
47 | |||
48 | return 0; | ||
49 | } | ||
50 | |||
51 | static void evm_shutdown(struct snd_pcm_substream *substream) | ||
52 | { | ||
53 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
54 | struct snd_soc_card *soc_card = rtd->codec->card; | ||
55 | struct snd_soc_card_drvdata_davinci *drvdata = | ||
56 | snd_soc_card_get_drvdata(soc_card); | ||
57 | |||
58 | if (drvdata->mclk) | ||
59 | clk_disable_unprepare(drvdata->mclk); | ||
60 | } | ||
61 | |||
36 | static int evm_hw_params(struct snd_pcm_substream *substream, | 62 | static int evm_hw_params(struct snd_pcm_substream *substream, |
37 | struct snd_pcm_hw_params *params) | 63 | struct snd_pcm_hw_params *params) |
38 | { | 64 | { |
@@ -59,6 +85,8 @@ static int evm_hw_params(struct snd_pcm_substream *substream, | |||
59 | } | 85 | } |
60 | 86 | ||
61 | static struct snd_soc_ops evm_ops = { | 87 | static struct snd_soc_ops evm_ops = { |
88 | .startup = evm_startup, | ||
89 | .shutdown = evm_shutdown, | ||
62 | .hw_params = evm_hw_params, | 90 | .hw_params = evm_hw_params, |
63 | }; | 91 | }; |
64 | 92 | ||
@@ -348,6 +376,7 @@ static int davinci_evm_probe(struct platform_device *pdev) | |||
348 | of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); | 376 | of_match_device(of_match_ptr(davinci_evm_dt_ids), &pdev->dev); |
349 | struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; | 377 | struct snd_soc_dai_link *dai = (struct snd_soc_dai_link *) match->data; |
350 | struct snd_soc_card_drvdata_davinci *drvdata = NULL; | 378 | struct snd_soc_card_drvdata_davinci *drvdata = NULL; |
379 | struct clk *mclk; | ||
351 | int ret = 0; | 380 | int ret = 0; |
352 | 381 | ||
353 | evm_soc_card.dai_link = dai; | 382 | evm_soc_card.dai_link = dai; |
@@ -367,13 +396,38 @@ static int davinci_evm_probe(struct platform_device *pdev) | |||
367 | if (ret) | 396 | if (ret) |
368 | return ret; | 397 | return ret; |
369 | 398 | ||
399 | mclk = devm_clk_get(&pdev->dev, "mclk"); | ||
400 | if (PTR_ERR(mclk) == -EPROBE_DEFER) { | ||
401 | return -EPROBE_DEFER; | ||
402 | } else if (IS_ERR(mclk)) { | ||
403 | dev_dbg(&pdev->dev, "mclk not found.\n"); | ||
404 | mclk = NULL; | ||
405 | } | ||
406 | |||
370 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); | 407 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); |
371 | if (!drvdata) | 408 | if (!drvdata) |
372 | return -ENOMEM; | 409 | return -ENOMEM; |
373 | 410 | ||
411 | drvdata->mclk = mclk; | ||
412 | |||
374 | ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); | 413 | ret = of_property_read_u32(np, "ti,codec-clock-rate", &drvdata->sysclk); |
375 | if (ret < 0) | 414 | |
376 | return -EINVAL; | 415 | if (ret < 0) { |
416 | if (!drvdata->mclk) { | ||
417 | dev_err(&pdev->dev, | ||
418 | "No clock or clock rate defined.\n"); | ||
419 | return -EINVAL; | ||
420 | } | ||
421 | drvdata->sysclk = clk_get_rate(drvdata->mclk); | ||
422 | } else if (drvdata->mclk) { | ||
423 | unsigned int requestd_rate = drvdata->sysclk; | ||
424 | clk_set_rate(drvdata->mclk, drvdata->sysclk); | ||
425 | drvdata->sysclk = clk_get_rate(drvdata->mclk); | ||
426 | if (drvdata->sysclk != requestd_rate) | ||
427 | dev_warn(&pdev->dev, | ||
428 | "Could not get requested rate %u using %u.\n", | ||
429 | requestd_rate, drvdata->sysclk); | ||
430 | } | ||
377 | 431 | ||
378 | snd_soc_card_set_drvdata(&evm_soc_card, drvdata); | 432 | snd_soc_card_set_drvdata(&evm_soc_card, drvdata); |
379 | ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); | 433 | ret = devm_snd_soc_register_card(&pdev->dev, &evm_soc_card); |
@@ -399,6 +453,7 @@ static struct platform_driver davinci_evm_driver = { | |||
399 | .driver = { | 453 | .driver = { |
400 | .name = "davinci_evm", | 454 | .name = "davinci_evm", |
401 | .owner = THIS_MODULE, | 455 | .owner = THIS_MODULE, |
456 | .pm = &snd_soc_pm_ops, | ||
402 | .of_match_table = of_match_ptr(davinci_evm_dt_ids), | 457 | .of_match_table = of_match_ptr(davinci_evm_dt_ids), |
403 | }, | 458 | }, |
404 | }; | 459 | }; |
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b7858bfa0295..b0ae0677f023 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c | |||
@@ -37,6 +37,16 @@ | |||
37 | #include "davinci-pcm.h" | 37 | #include "davinci-pcm.h" |
38 | #include "davinci-mcasp.h" | 38 | #include "davinci-mcasp.h" |
39 | 39 | ||
40 | struct davinci_mcasp_context { | ||
41 | u32 txfmtctl; | ||
42 | u32 rxfmtctl; | ||
43 | u32 txfmt; | ||
44 | u32 rxfmt; | ||
45 | u32 aclkxctl; | ||
46 | u32 aclkrctl; | ||
47 | u32 pdir; | ||
48 | }; | ||
49 | |||
40 | struct davinci_mcasp { | 50 | struct davinci_mcasp { |
41 | struct davinci_pcm_dma_params dma_params[2]; | 51 | struct davinci_pcm_dma_params dma_params[2]; |
42 | struct snd_dmaengine_dai_dma_data dma_data[2]; | 52 | struct snd_dmaengine_dai_dma_data dma_data[2]; |
@@ -53,6 +63,9 @@ struct davinci_mcasp { | |||
53 | u16 bclk_lrclk_ratio; | 63 | u16 bclk_lrclk_ratio; |
54 | int streams; | 64 | int streams; |
55 | 65 | ||
66 | int sysclk_freq; | ||
67 | bool bclk_master; | ||
68 | |||
56 | /* McASP FIFO related */ | 69 | /* McASP FIFO related */ |
57 | u8 txnumevt; | 70 | u8 txnumevt; |
58 | u8 rxnumevt; | 71 | u8 rxnumevt; |
@@ -60,15 +73,7 @@ struct davinci_mcasp { | |||
60 | bool dat_port; | 73 | bool dat_port; |
61 | 74 | ||
62 | #ifdef CONFIG_PM_SLEEP | 75 | #ifdef CONFIG_PM_SLEEP |
63 | struct { | 76 | struct davinci_mcasp_context context; |
64 | u32 txfmtctl; | ||
65 | u32 rxfmtctl; | ||
66 | u32 txfmt; | ||
67 | u32 rxfmt; | ||
68 | u32 aclkxctl; | ||
69 | u32 aclkrctl; | ||
70 | u32 pdir; | ||
71 | } context; | ||
72 | #endif | 77 | #endif |
73 | }; | 78 | }; |
74 | 79 | ||
@@ -263,7 +268,9 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
263 | unsigned int fmt) | 268 | unsigned int fmt) |
264 | { | 269 | { |
265 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); | 270 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai); |
271 | int ret = 0; | ||
266 | 272 | ||
273 | pm_runtime_get_sync(mcasp->dev); | ||
267 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 274 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
268 | case SND_SOC_DAIFMT_DSP_B: | 275 | case SND_SOC_DAIFMT_DSP_B: |
269 | case SND_SOC_DAIFMT_AC97: | 276 | case SND_SOC_DAIFMT_AC97: |
@@ -292,6 +299,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
292 | 299 | ||
293 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 300 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); |
294 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 301 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); |
302 | mcasp->bclk_master = 1; | ||
295 | break; | 303 | break; |
296 | case SND_SOC_DAIFMT_CBM_CFS: | 304 | case SND_SOC_DAIFMT_CBM_CFS: |
297 | /* codec is clock master and frame slave */ | 305 | /* codec is clock master and frame slave */ |
@@ -303,6 +311,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
303 | 311 | ||
304 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); | 312 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, ACLKX | ACLKR); |
305 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); | 313 | mcasp_set_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AFSX | AFSR); |
314 | mcasp->bclk_master = 0; | ||
306 | break; | 315 | break; |
307 | case SND_SOC_DAIFMT_CBM_CFM: | 316 | case SND_SOC_DAIFMT_CBM_CFM: |
308 | /* codec is clock and frame master */ | 317 | /* codec is clock and frame master */ |
@@ -314,10 +323,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
314 | 323 | ||
315 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, | 324 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, |
316 | ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); | 325 | ACLKX | AHCLKX | AFSX | ACLKR | AHCLKR | AFSR); |
326 | mcasp->bclk_master = 0; | ||
317 | break; | 327 | break; |
318 | 328 | ||
319 | default: | 329 | default: |
320 | return -EINVAL; | 330 | ret = -EINVAL; |
331 | goto out; | ||
321 | } | 332 | } |
322 | 333 | ||
323 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 334 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
@@ -354,10 +365,12 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai, | |||
354 | break; | 365 | break; |
355 | 366 | ||
356 | default: | 367 | default: |
357 | return -EINVAL; | 368 | ret = -EINVAL; |
369 | break; | ||
358 | } | 370 | } |
359 | 371 | out: | |
360 | return 0; | 372 | pm_runtime_put_sync(mcasp->dev); |
373 | return ret; | ||
361 | } | 374 | } |
362 | 375 | ||
363 | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) | 376 | static int davinci_mcasp_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) |
@@ -405,6 +418,8 @@ static int davinci_mcasp_set_sysclk(struct snd_soc_dai *dai, int clk_id, | |||
405 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); | 418 | mcasp_clr_bits(mcasp, DAVINCI_MCASP_PDIR_REG, AHCLKX); |
406 | } | 419 | } |
407 | 420 | ||
421 | mcasp->sysclk_freq = freq; | ||
422 | |||
408 | return 0; | 423 | return 0; |
409 | } | 424 | } |
410 | 425 | ||
@@ -448,7 +463,7 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp, | |||
448 | return 0; | 463 | return 0; |
449 | } | 464 | } |
450 | 465 | ||
451 | static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, | 466 | static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream, |
452 | int channels) | 467 | int channels) |
453 | { | 468 | { |
454 | int i; | 469 | int i; |
@@ -524,12 +539,18 @@ static int davinci_hw_common_param(struct davinci_mcasp *mcasp, int stream, | |||
524 | return 0; | 539 | return 0; |
525 | } | 540 | } |
526 | 541 | ||
527 | static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) | 542 | static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream) |
528 | { | 543 | { |
529 | int i, active_slots; | 544 | int i, active_slots; |
530 | u32 mask = 0; | 545 | u32 mask = 0; |
531 | u32 busel = 0; | 546 | u32 busel = 0; |
532 | 547 | ||
548 | if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) { | ||
549 | dev_err(mcasp->dev, "tdm slot %d not supported\n", | ||
550 | mcasp->tdm_slots); | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | |||
533 | active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; | 554 | active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots; |
534 | for (i = 0; i < active_slots; i++) | 555 | for (i = 0; i < active_slots; i++) |
535 | mask |= (1 << i); | 556 | mask |= (1 << i); |
@@ -539,35 +560,21 @@ static void davinci_hw_param(struct davinci_mcasp *mcasp, int stream) | |||
539 | if (!mcasp->dat_port) | 560 | if (!mcasp->dat_port) |
540 | busel = TXSEL; | 561 | busel = TXSEL; |
541 | 562 | ||
542 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | 563 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); |
543 | /* bit stream is MSB first with no delay */ | 564 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); |
544 | /* DSP_B mode */ | 565 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, |
545 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask); | 566 | FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); |
546 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD); | 567 | |
547 | 568 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); | |
548 | if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) | 569 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); |
549 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, | 570 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, |
550 | FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF)); | 571 | FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); |
551 | else | 572 | |
552 | printk(KERN_ERR "playback tdm slot %d not supported\n", | 573 | return 0; |
553 | mcasp->tdm_slots); | ||
554 | } else { | ||
555 | /* bit stream is MSB first with no delay */ | ||
556 | /* DSP_B mode */ | ||
557 | mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD); | ||
558 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask); | ||
559 | |||
560 | if ((mcasp->tdm_slots >= 2) && (mcasp->tdm_slots <= 32)) | ||
561 | mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, | ||
562 | FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF)); | ||
563 | else | ||
564 | printk(KERN_ERR "capture tdm slot %d not supported\n", | ||
565 | mcasp->tdm_slots); | ||
566 | } | ||
567 | } | 574 | } |
568 | 575 | ||
569 | /* S/PDIF */ | 576 | /* S/PDIF */ |
570 | static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) | 577 | static int mcasp_dit_hw_param(struct davinci_mcasp *mcasp) |
571 | { | 578 | { |
572 | /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 | 579 | /* Set the TX format : 24 bit right rotation, 32 bit slot, Pad 0 |
573 | and LSB first */ | 580 | and LSB first */ |
@@ -589,6 +596,8 @@ static void davinci_hw_dit_param(struct davinci_mcasp *mcasp) | |||
589 | 596 | ||
590 | /* Enable the DIT */ | 597 | /* Enable the DIT */ |
591 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); | 598 | mcasp_set_bits(mcasp, DAVINCI_MCASP_TXDITCTL_REG, DITEN); |
599 | |||
600 | return 0; | ||
592 | } | 601 | } |
593 | 602 | ||
594 | static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | 603 | static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, |
@@ -604,24 +613,31 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
604 | u8 fifo_level; | 613 | u8 fifo_level; |
605 | u8 slots = mcasp->tdm_slots; | 614 | u8 slots = mcasp->tdm_slots; |
606 | u8 active_serializers; | 615 | u8 active_serializers; |
607 | int channels; | 616 | int channels = params_channels(params); |
608 | struct snd_interval *pcm_channels = hw_param_interval(params, | 617 | int ret; |
609 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
610 | channels = pcm_channels->min; | ||
611 | 618 | ||
612 | active_serializers = (channels + slots - 1) / slots; | 619 | /* If mcasp is BCLK master we need to set BCLK divider */ |
620 | if (mcasp->bclk_master) { | ||
621 | unsigned int bclk_freq = snd_soc_params_to_bclk(params); | ||
622 | if (mcasp->sysclk_freq % bclk_freq != 0) { | ||
623 | dev_err(mcasp->dev, "Can't produce requred BCLK\n"); | ||
624 | return -EINVAL; | ||
625 | } | ||
626 | davinci_mcasp_set_clkdiv( | ||
627 | cpu_dai, 1, mcasp->sysclk_freq / bclk_freq); | ||
628 | } | ||
613 | 629 | ||
614 | if (davinci_hw_common_param(mcasp, substream->stream, channels) == -EINVAL) | 630 | ret = mcasp_common_hw_param(mcasp, substream->stream, channels); |
615 | return -EINVAL; | 631 | if (ret) |
616 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 632 | return ret; |
617 | fifo_level = mcasp->txnumevt * active_serializers; | ||
618 | else | ||
619 | fifo_level = mcasp->rxnumevt * active_serializers; | ||
620 | 633 | ||
621 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) | 634 | if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE) |
622 | davinci_hw_dit_param(mcasp); | 635 | ret = mcasp_dit_hw_param(mcasp); |
623 | else | 636 | else |
624 | davinci_hw_param(mcasp, substream->stream); | 637 | ret = mcasp_i2s_hw_param(mcasp, substream->stream); |
638 | |||
639 | if (ret) | ||
640 | return ret; | ||
625 | 641 | ||
626 | switch (params_format(params)) { | 642 | switch (params_format(params)) { |
627 | case SNDRV_PCM_FORMAT_U8: | 643 | case SNDRV_PCM_FORMAT_U8: |
@@ -655,6 +671,13 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream, | |||
655 | return -EINVAL; | 671 | return -EINVAL; |
656 | } | 672 | } |
657 | 673 | ||
674 | /* Calculate FIFO level */ | ||
675 | active_serializers = (channels + slots - 1) / slots; | ||
676 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
677 | fifo_level = mcasp->txnumevt * active_serializers; | ||
678 | else | ||
679 | fifo_level = mcasp->rxnumevt * active_serializers; | ||
680 | |||
658 | if (mcasp->version == MCASP_VERSION_2 && !fifo_level) | 681 | if (mcasp->version == MCASP_VERSION_2 && !fifo_level) |
659 | dma_params->acnt = 4; | 682 | dma_params->acnt = 4; |
660 | else | 683 | else |
@@ -678,19 +701,9 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream, | |||
678 | case SNDRV_PCM_TRIGGER_RESUME: | 701 | case SNDRV_PCM_TRIGGER_RESUME: |
679 | case SNDRV_PCM_TRIGGER_START: | 702 | case SNDRV_PCM_TRIGGER_START: |
680 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 703 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
681 | ret = pm_runtime_get_sync(mcasp->dev); | ||
682 | if (IS_ERR_VALUE(ret)) | ||
683 | dev_err(mcasp->dev, "pm_runtime_get_sync() failed\n"); | ||
684 | davinci_mcasp_start(mcasp, substream->stream); | 704 | davinci_mcasp_start(mcasp, substream->stream); |
685 | break; | 705 | break; |
686 | |||
687 | case SNDRV_PCM_TRIGGER_SUSPEND: | 706 | case SNDRV_PCM_TRIGGER_SUSPEND: |
688 | davinci_mcasp_stop(mcasp, substream->stream); | ||
689 | ret = pm_runtime_put_sync(mcasp->dev); | ||
690 | if (IS_ERR_VALUE(ret)) | ||
691 | dev_err(mcasp->dev, "pm_runtime_put_sync() failed\n"); | ||
692 | break; | ||
693 | |||
694 | case SNDRV_PCM_TRIGGER_STOP: | 707 | case SNDRV_PCM_TRIGGER_STOP: |
695 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 708 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
696 | davinci_mcasp_stop(mcasp, substream->stream); | 709 | davinci_mcasp_stop(mcasp, substream->stream); |
@@ -726,6 +739,43 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | |||
726 | .set_sysclk = davinci_mcasp_set_sysclk, | 739 | .set_sysclk = davinci_mcasp_set_sysclk, |
727 | }; | 740 | }; |
728 | 741 | ||
742 | #ifdef CONFIG_PM_SLEEP | ||
743 | static int davinci_mcasp_suspend(struct snd_soc_dai *dai) | ||
744 | { | ||
745 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | ||
746 | struct davinci_mcasp_context *context = &mcasp->context; | ||
747 | |||
748 | context->txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); | ||
749 | context->rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | ||
750 | context->txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); | ||
751 | context->rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); | ||
752 | context->aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | ||
753 | context->aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); | ||
754 | context->pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); | ||
755 | |||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | static int davinci_mcasp_resume(struct snd_soc_dai *dai) | ||
760 | { | ||
761 | struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(dai); | ||
762 | struct davinci_mcasp_context *context = &mcasp->context; | ||
763 | |||
764 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, context->txfmtctl); | ||
765 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, context->rxfmtctl); | ||
766 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, context->txfmt); | ||
767 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, context->rxfmt); | ||
768 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, context->aclkxctl); | ||
769 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, context->aclkrctl); | ||
770 | mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, context->pdir); | ||
771 | |||
772 | return 0; | ||
773 | } | ||
774 | #else | ||
775 | #define davinci_mcasp_suspend NULL | ||
776 | #define davinci_mcasp_resume NULL | ||
777 | #endif | ||
778 | |||
729 | #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 | 779 | #define DAVINCI_MCASP_RATES SNDRV_PCM_RATE_8000_192000 |
730 | 780 | ||
731 | #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ | 781 | #define DAVINCI_MCASP_PCM_FMTS (SNDRV_PCM_FMTBIT_S8 | \ |
@@ -742,6 +792,8 @@ static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = { | |||
742 | static struct snd_soc_dai_driver davinci_mcasp_dai[] = { | 792 | static struct snd_soc_dai_driver davinci_mcasp_dai[] = { |
743 | { | 793 | { |
744 | .name = "davinci-mcasp.0", | 794 | .name = "davinci-mcasp.0", |
795 | .suspend = davinci_mcasp_suspend, | ||
796 | .resume = davinci_mcasp_resume, | ||
745 | .playback = { | 797 | .playback = { |
746 | .channels_min = 2, | 798 | .channels_min = 2, |
747 | .channels_max = 32 * 16, | 799 | .channels_max = 32 * 16, |
@@ -775,28 +827,28 @@ static const struct snd_soc_component_driver davinci_mcasp_component = { | |||
775 | }; | 827 | }; |
776 | 828 | ||
777 | /* Some HW specific values and defaults. The rest is filled in from DT. */ | 829 | /* Some HW specific values and defaults. The rest is filled in from DT. */ |
778 | static struct snd_platform_data dm646x_mcasp_pdata = { | 830 | static struct davinci_mcasp_pdata dm646x_mcasp_pdata = { |
779 | .tx_dma_offset = 0x400, | 831 | .tx_dma_offset = 0x400, |
780 | .rx_dma_offset = 0x400, | 832 | .rx_dma_offset = 0x400, |
781 | .asp_chan_q = EVENTQ_0, | 833 | .asp_chan_q = EVENTQ_0, |
782 | .version = MCASP_VERSION_1, | 834 | .version = MCASP_VERSION_1, |
783 | }; | 835 | }; |
784 | 836 | ||
785 | static struct snd_platform_data da830_mcasp_pdata = { | 837 | static struct davinci_mcasp_pdata da830_mcasp_pdata = { |
786 | .tx_dma_offset = 0x2000, | 838 | .tx_dma_offset = 0x2000, |
787 | .rx_dma_offset = 0x2000, | 839 | .rx_dma_offset = 0x2000, |
788 | .asp_chan_q = EVENTQ_0, | 840 | .asp_chan_q = EVENTQ_0, |
789 | .version = MCASP_VERSION_2, | 841 | .version = MCASP_VERSION_2, |
790 | }; | 842 | }; |
791 | 843 | ||
792 | static struct snd_platform_data am33xx_mcasp_pdata = { | 844 | static struct davinci_mcasp_pdata am33xx_mcasp_pdata = { |
793 | .tx_dma_offset = 0, | 845 | .tx_dma_offset = 0, |
794 | .rx_dma_offset = 0, | 846 | .rx_dma_offset = 0, |
795 | .asp_chan_q = EVENTQ_0, | 847 | .asp_chan_q = EVENTQ_0, |
796 | .version = MCASP_VERSION_3, | 848 | .version = MCASP_VERSION_3, |
797 | }; | 849 | }; |
798 | 850 | ||
799 | static struct snd_platform_data dra7_mcasp_pdata = { | 851 | static struct davinci_mcasp_pdata dra7_mcasp_pdata = { |
800 | .tx_dma_offset = 0x200, | 852 | .tx_dma_offset = 0x200, |
801 | .rx_dma_offset = 0x284, | 853 | .rx_dma_offset = 0x284, |
802 | .asp_chan_q = EVENTQ_0, | 854 | .asp_chan_q = EVENTQ_0, |
@@ -864,11 +916,11 @@ err1: | |||
864 | return ret; | 916 | return ret; |
865 | } | 917 | } |
866 | 918 | ||
867 | static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( | 919 | static struct davinci_mcasp_pdata *davinci_mcasp_set_pdata_from_of( |
868 | struct platform_device *pdev) | 920 | struct platform_device *pdev) |
869 | { | 921 | { |
870 | struct device_node *np = pdev->dev.of_node; | 922 | struct device_node *np = pdev->dev.of_node; |
871 | struct snd_platform_data *pdata = NULL; | 923 | struct davinci_mcasp_pdata *pdata = NULL; |
872 | const struct of_device_id *match = | 924 | const struct of_device_id *match = |
873 | of_match_device(mcasp_dt_ids, &pdev->dev); | 925 | of_match_device(mcasp_dt_ids, &pdev->dev); |
874 | struct of_phandle_args dma_spec; | 926 | struct of_phandle_args dma_spec; |
@@ -881,7 +933,7 @@ static struct snd_platform_data *davinci_mcasp_set_pdata_from_of( | |||
881 | pdata = pdev->dev.platform_data; | 933 | pdata = pdev->dev.platform_data; |
882 | return pdata; | 934 | return pdata; |
883 | } else if (match) { | 935 | } else if (match) { |
884 | pdata = (struct snd_platform_data *) match->data; | 936 | pdata = (struct davinci_mcasp_pdata*) match->data; |
885 | } else { | 937 | } else { |
886 | /* control shouldn't reach here. something is wrong */ | 938 | /* control shouldn't reach here. something is wrong */ |
887 | ret = -EINVAL; | 939 | ret = -EINVAL; |
@@ -973,9 +1025,9 @@ nodata: | |||
973 | 1025 | ||
974 | static int davinci_mcasp_probe(struct platform_device *pdev) | 1026 | static int davinci_mcasp_probe(struct platform_device *pdev) |
975 | { | 1027 | { |
976 | struct davinci_pcm_dma_params *dma_data; | 1028 | struct davinci_pcm_dma_params *dma_params; |
977 | struct resource *mem, *ioarea, *res, *dat; | 1029 | struct resource *mem, *ioarea, *res, *dat; |
978 | struct snd_platform_data *pdata; | 1030 | struct davinci_mcasp_pdata *pdata; |
979 | struct davinci_mcasp *mcasp; | 1031 | struct davinci_mcasp *mcasp; |
980 | int ret; | 1032 | int ret; |
981 | 1033 | ||
@@ -1042,41 +1094,41 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1042 | if (dat) | 1094 | if (dat) |
1043 | mcasp->dat_port = true; | 1095 | mcasp->dat_port = true; |
1044 | 1096 | ||
1045 | dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; | 1097 | dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_PLAYBACK]; |
1046 | dma_data->asp_chan_q = pdata->asp_chan_q; | 1098 | dma_params->asp_chan_q = pdata->asp_chan_q; |
1047 | dma_data->ram_chan_q = pdata->ram_chan_q; | 1099 | dma_params->ram_chan_q = pdata->ram_chan_q; |
1048 | dma_data->sram_pool = pdata->sram_pool; | 1100 | dma_params->sram_pool = pdata->sram_pool; |
1049 | dma_data->sram_size = pdata->sram_size_playback; | 1101 | dma_params->sram_size = pdata->sram_size_playback; |
1050 | if (dat) | 1102 | if (dat) |
1051 | dma_data->dma_addr = dat->start; | 1103 | dma_params->dma_addr = dat->start; |
1052 | else | 1104 | else |
1053 | dma_data->dma_addr = mem->start + pdata->tx_dma_offset; | 1105 | dma_params->dma_addr = mem->start + pdata->tx_dma_offset; |
1054 | 1106 | ||
1055 | /* Unconditional dmaengine stuff */ | 1107 | /* Unconditional dmaengine stuff */ |
1056 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_data->dma_addr; | 1108 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = dma_params->dma_addr; |
1057 | 1109 | ||
1058 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | 1110 | res = platform_get_resource(pdev, IORESOURCE_DMA, 0); |
1059 | if (res) | 1111 | if (res) |
1060 | dma_data->channel = res->start; | 1112 | dma_params->channel = res->start; |
1061 | else | 1113 | else |
1062 | dma_data->channel = pdata->tx_dma_channel; | 1114 | dma_params->channel = pdata->tx_dma_channel; |
1063 | 1115 | ||
1064 | dma_data = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; | 1116 | dma_params = &mcasp->dma_params[SNDRV_PCM_STREAM_CAPTURE]; |
1065 | dma_data->asp_chan_q = pdata->asp_chan_q; | 1117 | dma_params->asp_chan_q = pdata->asp_chan_q; |
1066 | dma_data->ram_chan_q = pdata->ram_chan_q; | 1118 | dma_params->ram_chan_q = pdata->ram_chan_q; |
1067 | dma_data->sram_pool = pdata->sram_pool; | 1119 | dma_params->sram_pool = pdata->sram_pool; |
1068 | dma_data->sram_size = pdata->sram_size_capture; | 1120 | dma_params->sram_size = pdata->sram_size_capture; |
1069 | if (dat) | 1121 | if (dat) |
1070 | dma_data->dma_addr = dat->start; | 1122 | dma_params->dma_addr = dat->start; |
1071 | else | 1123 | else |
1072 | dma_data->dma_addr = mem->start + pdata->rx_dma_offset; | 1124 | dma_params->dma_addr = mem->start + pdata->rx_dma_offset; |
1073 | 1125 | ||
1074 | /* Unconditional dmaengine stuff */ | 1126 | /* Unconditional dmaengine stuff */ |
1075 | mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_data->dma_addr; | 1127 | mcasp->dma_data[SNDRV_PCM_STREAM_CAPTURE].addr = dma_params->dma_addr; |
1076 | 1128 | ||
1077 | if (mcasp->version < MCASP_VERSION_3) { | 1129 | if (mcasp->version < MCASP_VERSION_3) { |
1078 | mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; | 1130 | mcasp->fifo_base = DAVINCI_MCASP_V2_AFIFO_BASE; |
1079 | /* dma_data->dma_addr is pointing to the data port address */ | 1131 | /* dma_params->dma_addr is pointing to the data port address */ |
1080 | mcasp->dat_port = true; | 1132 | mcasp->dat_port = true; |
1081 | } else { | 1133 | } else { |
1082 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; | 1134 | mcasp->fifo_base = DAVINCI_MCASP_V3_AFIFO_BASE; |
@@ -1084,9 +1136,9 @@ static int davinci_mcasp_probe(struct platform_device *pdev) | |||
1084 | 1136 | ||
1085 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | 1137 | res = platform_get_resource(pdev, IORESOURCE_DMA, 1); |
1086 | if (res) | 1138 | if (res) |
1087 | dma_data->channel = res->start; | 1139 | dma_params->channel = res->start; |
1088 | else | 1140 | else |
1089 | dma_data->channel = pdata->rx_dma_channel; | 1141 | dma_params->channel = pdata->rx_dma_channel; |
1090 | 1142 | ||
1091 | /* Unconditional dmaengine stuff */ | 1143 | /* Unconditional dmaengine stuff */ |
1092 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; | 1144 | mcasp->dma_data[SNDRV_PCM_STREAM_PLAYBACK].filter_data = "tx"; |
@@ -1134,49 +1186,12 @@ static int davinci_mcasp_remove(struct platform_device *pdev) | |||
1134 | return 0; | 1186 | return 0; |
1135 | } | 1187 | } |
1136 | 1188 | ||
1137 | #ifdef CONFIG_PM_SLEEP | ||
1138 | static int davinci_mcasp_suspend(struct device *dev) | ||
1139 | { | ||
1140 | struct davinci_mcasp *mcasp = dev_get_drvdata(dev); | ||
1141 | |||
1142 | mcasp->context.txfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG); | ||
1143 | mcasp->context.rxfmtctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG); | ||
1144 | mcasp->context.txfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXFMT_REG); | ||
1145 | mcasp->context.rxfmt = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXFMT_REG); | ||
1146 | mcasp->context.aclkxctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG); | ||
1147 | mcasp->context.aclkrctl = mcasp_get_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG); | ||
1148 | mcasp->context.pdir = mcasp_get_reg(mcasp, DAVINCI_MCASP_PDIR_REG); | ||
1149 | |||
1150 | return 0; | ||
1151 | } | ||
1152 | |||
1153 | static int davinci_mcasp_resume(struct device *dev) | ||
1154 | { | ||
1155 | struct davinci_mcasp *mcasp = dev_get_drvdata(dev); | ||
1156 | |||
1157 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMCTL_REG, mcasp->context.txfmtctl); | ||
1158 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMCTL_REG, mcasp->context.rxfmtctl); | ||
1159 | mcasp_set_reg(mcasp, DAVINCI_MCASP_TXFMT_REG, mcasp->context.txfmt); | ||
1160 | mcasp_set_reg(mcasp, DAVINCI_MCASP_RXFMT_REG, mcasp->context.rxfmt); | ||
1161 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, mcasp->context.aclkxctl); | ||
1162 | mcasp_set_reg(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, mcasp->context.aclkrctl); | ||
1163 | mcasp_set_reg(mcasp, DAVINCI_MCASP_PDIR_REG, mcasp->context.pdir); | ||
1164 | |||
1165 | return 0; | ||
1166 | } | ||
1167 | #endif | ||
1168 | |||
1169 | SIMPLE_DEV_PM_OPS(davinci_mcasp_pm_ops, | ||
1170 | davinci_mcasp_suspend, | ||
1171 | davinci_mcasp_resume); | ||
1172 | |||
1173 | static struct platform_driver davinci_mcasp_driver = { | 1189 | static struct platform_driver davinci_mcasp_driver = { |
1174 | .probe = davinci_mcasp_probe, | 1190 | .probe = davinci_mcasp_probe, |
1175 | .remove = davinci_mcasp_remove, | 1191 | .remove = davinci_mcasp_remove, |
1176 | .driver = { | 1192 | .driver = { |
1177 | .name = "davinci-mcasp", | 1193 | .name = "davinci-mcasp", |
1178 | .owner = THIS_MODULE, | 1194 | .owner = THIS_MODULE, |
1179 | .pm = &davinci_mcasp_pm_ops, | ||
1180 | .of_match_table = mcasp_dt_ids, | 1195 | .of_match_table = mcasp_dt_ids, |
1181 | }, | 1196 | }, |
1182 | }; | 1197 | }; |
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 07f8f141727d..597962ec28fa 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig | |||
@@ -1,5 +1,6 @@ | |||
1 | config SND_SOC_FSL_SAI | 1 | config SND_SOC_FSL_SAI |
2 | tristate | 2 | tristate |
3 | select REGMAP_MMIO | ||
3 | select SND_SOC_GENERIC_DMAENGINE_PCM | 4 | select SND_SOC_GENERIC_DMAENGINE_PCM |
4 | 5 | ||
5 | config SND_SOC_FSL_SSI | 6 | config SND_SOC_FSL_SSI |
@@ -7,9 +8,11 @@ config SND_SOC_FSL_SSI | |||
7 | 8 | ||
8 | config SND_SOC_FSL_SPDIF | 9 | config SND_SOC_FSL_SPDIF |
9 | tristate | 10 | tristate |
11 | select REGMAP_MMIO | ||
10 | 12 | ||
11 | config SND_SOC_FSL_ESAI | 13 | config SND_SOC_FSL_ESAI |
12 | tristate | 14 | tristate |
15 | select REGMAP_MMIO | ||
13 | 16 | ||
14 | config SND_SOC_FSL_UTILS | 17 | config SND_SOC_FSL_UTILS |
15 | tristate | 18 | tristate |
@@ -168,12 +171,14 @@ config SND_SOC_EUKREA_TLV320 | |||
168 | depends on MACH_EUKREA_MBIMX27_BASEBOARD \ | 171 | depends on MACH_EUKREA_MBIMX27_BASEBOARD \ |
169 | || MACH_EUKREA_MBIMXSD25_BASEBOARD \ | 172 | || MACH_EUKREA_MBIMXSD25_BASEBOARD \ |
170 | || MACH_EUKREA_MBIMXSD35_BASEBOARD \ | 173 | || MACH_EUKREA_MBIMXSD35_BASEBOARD \ |
171 | || MACH_EUKREA_MBIMXSD51_BASEBOARD | 174 | || MACH_EUKREA_MBIMXSD51_BASEBOARD \ |
175 | || (OF && ARM) | ||
172 | depends on I2C | 176 | depends on I2C |
173 | select SND_SOC_TLV320AIC23 | 177 | select SND_SOC_TLV320AIC23_I2C |
174 | select SND_SOC_IMX_PCM_FIQ | ||
175 | select SND_SOC_IMX_AUDMUX | 178 | select SND_SOC_IMX_AUDMUX |
176 | select SND_SOC_IMX_SSI | 179 | select SND_SOC_IMX_SSI |
180 | select SND_SOC_FSL_SSI | ||
181 | select SND_SOC_IMX_PCM_DMA | ||
177 | help | 182 | help |
178 | Enable I2S based access to the TLV320AIC23B codec attached | 183 | Enable I2S based access to the TLV320AIC23B codec attached |
179 | to the SSI interface | 184 | to the SSI interface |
@@ -204,7 +209,6 @@ config SND_SOC_IMX_SPDIF | |||
204 | tristate "SoC Audio support for i.MX boards with S/PDIF" | 209 | tristate "SoC Audio support for i.MX boards with S/PDIF" |
205 | select SND_SOC_IMX_PCM_DMA | 210 | select SND_SOC_IMX_PCM_DMA |
206 | select SND_SOC_FSL_SPDIF | 211 | select SND_SOC_FSL_SPDIF |
207 | select REGMAP_MMIO | ||
208 | help | 212 | help |
209 | SoC Audio support for i.MX boards with S/PDIF | 213 | SoC Audio support for i.MX boards with S/PDIF |
210 | Say Y if you want to add support for SoC audio on an i.MX board with | 214 | Say Y if you want to add support for SoC audio on an i.MX board with |
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c index 5983740be123..eb093d5b85c4 100644 --- a/sound/soc/fsl/eukrea-tlv320.c +++ b/sound/soc/fsl/eukrea-tlv320.c | |||
@@ -15,8 +15,11 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/errno.h> | ||
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
19 | #include <linux/moduleparam.h> | 20 | #include <linux/moduleparam.h> |
21 | #include <linux/of.h> | ||
22 | #include <linux/of_platform.h> | ||
20 | #include <linux/device.h> | 23 | #include <linux/device.h> |
21 | #include <linux/i2c.h> | 24 | #include <linux/i2c.h> |
22 | #include <sound/core.h> | 25 | #include <sound/core.h> |
@@ -26,6 +29,7 @@ | |||
26 | 29 | ||
27 | #include "../codecs/tlv320aic23.h" | 30 | #include "../codecs/tlv320aic23.h" |
28 | #include "imx-ssi.h" | 31 | #include "imx-ssi.h" |
32 | #include "fsl_ssi.h" | ||
29 | #include "imx-audmux.h" | 33 | #include "imx-audmux.h" |
30 | 34 | ||
31 | #define CODEC_CLOCK 12000000 | 35 | #define CODEC_CLOCK 12000000 |
@@ -41,7 +45,8 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, | |||
41 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | | 45 | ret = snd_soc_dai_set_fmt(cpu_dai, SND_SOC_DAIFMT_I2S | |
42 | SND_SOC_DAIFMT_NB_NF | | 46 | SND_SOC_DAIFMT_NB_NF | |
43 | SND_SOC_DAIFMT_CBM_CFM); | 47 | SND_SOC_DAIFMT_CBM_CFM); |
44 | if (ret) { | 48 | /* fsl_ssi lacks the set_fmt ops. */ |
49 | if (ret && ret != -ENOTSUPP) { | ||
45 | dev_err(cpu_dai->dev, | 50 | dev_err(cpu_dai->dev, |
46 | "Failed to set the cpu dai format.\n"); | 51 | "Failed to set the cpu dai format.\n"); |
47 | return ret; | 52 | return ret; |
@@ -63,11 +68,13 @@ static int eukrea_tlv320_hw_params(struct snd_pcm_substream *substream, | |||
63 | "Failed to set the codec sysclk.\n"); | 68 | "Failed to set the codec sysclk.\n"); |
64 | return ret; | 69 | return ret; |
65 | } | 70 | } |
71 | |||
66 | snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); | 72 | snd_soc_dai_set_tdm_slot(cpu_dai, 0xffffffc, 0xffffffc, 2, 0); |
67 | 73 | ||
68 | ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, | 74 | ret = snd_soc_dai_set_sysclk(cpu_dai, IMX_SSP_SYS_CLK, 0, |
69 | SND_SOC_CLOCK_IN); | 75 | SND_SOC_CLOCK_IN); |
70 | if (ret) { | 76 | /* fsl_ssi lacks the set_sysclk ops */ |
77 | if (ret && ret != -EINVAL) { | ||
71 | dev_err(cpu_dai->dev, | 78 | dev_err(cpu_dai->dev, |
72 | "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n"); | 79 | "Can't set the IMX_SSP_SYS_CLK CPU system clock.\n"); |
73 | return ret; | 80 | return ret; |
@@ -84,14 +91,10 @@ static struct snd_soc_dai_link eukrea_tlv320_dai = { | |||
84 | .name = "tlv320aic23", | 91 | .name = "tlv320aic23", |
85 | .stream_name = "TLV320AIC23", | 92 | .stream_name = "TLV320AIC23", |
86 | .codec_dai_name = "tlv320aic23-hifi", | 93 | .codec_dai_name = "tlv320aic23-hifi", |
87 | .platform_name = "imx-ssi.0", | ||
88 | .codec_name = "tlv320aic23-codec.0-001a", | ||
89 | .cpu_dai_name = "imx-ssi.0", | ||
90 | .ops = &eukrea_tlv320_snd_ops, | 94 | .ops = &eukrea_tlv320_snd_ops, |
91 | }; | 95 | }; |
92 | 96 | ||
93 | static struct snd_soc_card eukrea_tlv320 = { | 97 | static struct snd_soc_card eukrea_tlv320 = { |
94 | .name = "cpuimx-audio", | ||
95 | .owner = THIS_MODULE, | 98 | .owner = THIS_MODULE, |
96 | .dai_link = &eukrea_tlv320_dai, | 99 | .dai_link = &eukrea_tlv320_dai, |
97 | .num_links = 1, | 100 | .num_links = 1, |
@@ -101,8 +104,65 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
101 | { | 104 | { |
102 | int ret; | 105 | int ret; |
103 | int int_port = 0, ext_port; | 106 | int int_port = 0, ext_port; |
107 | struct device_node *np = pdev->dev.of_node; | ||
108 | struct device_node *ssi_np, *codec_np; | ||
104 | 109 | ||
105 | if (machine_is_eukrea_cpuimx27()) { | 110 | eukrea_tlv320.dev = &pdev->dev; |
111 | if (np) { | ||
112 | ret = snd_soc_of_parse_card_name(&eukrea_tlv320, | ||
113 | "eukrea,model"); | ||
114 | if (ret) { | ||
115 | dev_err(&pdev->dev, | ||
116 | "eukrea,model node missing or invalid.\n"); | ||
117 | goto err; | ||
118 | } | ||
119 | |||
120 | ssi_np = of_parse_phandle(pdev->dev.of_node, | ||
121 | "ssi-controller", 0); | ||
122 | if (!ssi_np) { | ||
123 | dev_err(&pdev->dev, | ||
124 | "ssi-controller missing or invalid.\n"); | ||
125 | ret = -ENODEV; | ||
126 | goto err; | ||
127 | } | ||
128 | |||
129 | codec_np = of_parse_phandle(ssi_np, "codec-handle", 0); | ||
130 | if (codec_np) | ||
131 | eukrea_tlv320_dai.codec_of_node = codec_np; | ||
132 | else | ||
133 | dev_err(&pdev->dev, "codec-handle node missing or invalid.\n"); | ||
134 | |||
135 | ret = of_property_read_u32(np, "fsl,mux-int-port", &int_port); | ||
136 | if (ret) { | ||
137 | dev_err(&pdev->dev, | ||
138 | "fsl,mux-int-port node missing or invalid.\n"); | ||
139 | return ret; | ||
140 | } | ||
141 | ret = of_property_read_u32(np, "fsl,mux-ext-port", &ext_port); | ||
142 | if (ret) { | ||
143 | dev_err(&pdev->dev, | ||
144 | "fsl,mux-ext-port node missing or invalid.\n"); | ||
145 | return ret; | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * The port numbering in the hardware manual starts at 1, while | ||
150 | * the audmux API expects it starts at 0. | ||
151 | */ | ||
152 | int_port--; | ||
153 | ext_port--; | ||
154 | |||
155 | eukrea_tlv320_dai.cpu_of_node = ssi_np; | ||
156 | eukrea_tlv320_dai.platform_of_node = ssi_np; | ||
157 | } else { | ||
158 | eukrea_tlv320_dai.cpu_dai_name = "imx-ssi.0"; | ||
159 | eukrea_tlv320_dai.platform_name = "imx-ssi.0"; | ||
160 | eukrea_tlv320_dai.codec_name = "tlv320aic23-codec.0-001a"; | ||
161 | eukrea_tlv320.name = "cpuimx-audio"; | ||
162 | } | ||
163 | |||
164 | if (machine_is_eukrea_cpuimx27() || | ||
165 | of_find_compatible_node(NULL, NULL, "fsl,imx21-audmux")) { | ||
106 | imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, | 166 | imx_audmux_v1_configure_port(MX27_AUDMUX_HPCR1_SSI0, |
107 | IMX_AUDMUX_V1_PCR_SYN | | 167 | IMX_AUDMUX_V1_PCR_SYN | |
108 | IMX_AUDMUX_V1_PCR_TFSDIR | | 168 | IMX_AUDMUX_V1_PCR_TFSDIR | |
@@ -119,8 +179,12 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
119 | ); | 179 | ); |
120 | } else if (machine_is_eukrea_cpuimx25sd() || | 180 | } else if (machine_is_eukrea_cpuimx25sd() || |
121 | machine_is_eukrea_cpuimx35sd() || | 181 | machine_is_eukrea_cpuimx35sd() || |
122 | machine_is_eukrea_cpuimx51sd()) { | 182 | machine_is_eukrea_cpuimx51sd() || |
123 | ext_port = machine_is_eukrea_cpuimx25sd() ? 4 : 3; | 183 | of_find_compatible_node(NULL, NULL, "fsl,imx31-audmux")) { |
184 | if (!np) | ||
185 | ext_port = machine_is_eukrea_cpuimx25sd() ? | ||
186 | 4 : 3; | ||
187 | |||
124 | imx_audmux_v2_configure_port(int_port, | 188 | imx_audmux_v2_configure_port(int_port, |
125 | IMX_AUDMUX_V2_PTCR_SYN | | 189 | IMX_AUDMUX_V2_PTCR_SYN | |
126 | IMX_AUDMUX_V2_PTCR_TFSDIR | | 190 | IMX_AUDMUX_V2_PTCR_TFSDIR | |
@@ -134,14 +198,27 @@ static int eukrea_tlv320_probe(struct platform_device *pdev) | |||
134 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) | 198 | IMX_AUDMUX_V2_PDCR_RXDSEL(int_port) |
135 | ); | 199 | ); |
136 | } else { | 200 | } else { |
137 | /* return happy. We might run on a totally different machine */ | 201 | if (np) { |
138 | return 0; | 202 | /* The eukrea,asoc-tlv320 driver was explicitely |
203 | * requested (through the device tree). | ||
204 | */ | ||
205 | dev_err(&pdev->dev, | ||
206 | "Missing or invalid audmux DT node.\n"); | ||
207 | return -ENODEV; | ||
208 | } else { | ||
209 | /* Return happy. | ||
210 | * We might run on a totally different machine. | ||
211 | */ | ||
212 | return 0; | ||
213 | } | ||
139 | } | 214 | } |
140 | 215 | ||
141 | eukrea_tlv320.dev = &pdev->dev; | ||
142 | ret = snd_soc_register_card(&eukrea_tlv320); | 216 | ret = snd_soc_register_card(&eukrea_tlv320); |
217 | err: | ||
143 | if (ret) | 218 | if (ret) |
144 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | 219 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); |
220 | if (np) | ||
221 | of_node_put(ssi_np); | ||
145 | 222 | ||
146 | return ret; | 223 | return ret; |
147 | } | 224 | } |
@@ -153,10 +230,17 @@ static int eukrea_tlv320_remove(struct platform_device *pdev) | |||
153 | return 0; | 230 | return 0; |
154 | } | 231 | } |
155 | 232 | ||
233 | static const struct of_device_id imx_tlv320_dt_ids[] = { | ||
234 | { .compatible = "eukrea,asoc-tlv320"}, | ||
235 | { /* sentinel */ } | ||
236 | }; | ||
237 | MODULE_DEVICE_TABLE(of, imx_tlv320_dt_ids); | ||
238 | |||
156 | static struct platform_driver eukrea_tlv320_driver = { | 239 | static struct platform_driver eukrea_tlv320_driver = { |
157 | .driver = { | 240 | .driver = { |
158 | .name = "eukrea_tlv320", | 241 | .name = "eukrea_tlv320", |
159 | .owner = THIS_MODULE, | 242 | .owner = THIS_MODULE, |
243 | .of_match_table = imx_tlv320_dt_ids, | ||
160 | }, | 244 | }, |
161 | .probe = eukrea_tlv320_probe, | 245 | .probe = eukrea_tlv320_probe, |
162 | .remove = eukrea_tlv320_remove, | 246 | .remove = eukrea_tlv320_remove, |
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index d0c72ed261e7..0ba37005ab04 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c | |||
@@ -326,7 +326,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, | |||
326 | regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, | 326 | regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMA, |
327 | ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); | 327 | ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(tx_mask)); |
328 | regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, | 328 | regmap_update_bits(esai_priv->regmap, REG_ESAI_TSMB, |
329 | ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(tx_mask)); | 329 | ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(tx_mask)); |
330 | 330 | ||
331 | regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, | 331 | regmap_update_bits(esai_priv->regmap, REG_ESAI_RCCR, |
332 | ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); | 332 | ESAI_xCCR_xDC_MASK, ESAI_xCCR_xDC(slots)); |
@@ -334,7 +334,7 @@ static int fsl_esai_set_dai_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, | |||
334 | regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, | 334 | regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMA, |
335 | ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); | 335 | ESAI_xSMA_xS_MASK, ESAI_xSMA_xS(rx_mask)); |
336 | regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, | 336 | regmap_update_bits(esai_priv->regmap, REG_ESAI_RSMB, |
337 | ESAI_xSMA_xS_MASK, ESAI_xSMB_xS(rx_mask)); | 337 | ESAI_xSMB_xS_MASK, ESAI_xSMB_xS(rx_mask)); |
338 | 338 | ||
339 | esai_priv->slot_width = slot_width; | 339 | esai_priv->slot_width = slot_width; |
340 | 340 | ||
@@ -431,17 +431,26 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
431 | static int fsl_esai_startup(struct snd_pcm_substream *substream, | 431 | static int fsl_esai_startup(struct snd_pcm_substream *substream, |
432 | struct snd_soc_dai *dai) | 432 | struct snd_soc_dai *dai) |
433 | { | 433 | { |
434 | int ret; | ||
434 | struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); | 435 | struct fsl_esai *esai_priv = snd_soc_dai_get_drvdata(dai); |
435 | 436 | ||
436 | /* | 437 | /* |
437 | * Some platforms might use the same bit to gate all three or two of | 438 | * Some platforms might use the same bit to gate all three or two of |
438 | * clocks, so keep all clocks open/close at the same time for safety | 439 | * clocks, so keep all clocks open/close at the same time for safety |
439 | */ | 440 | */ |
440 | clk_prepare_enable(esai_priv->coreclk); | 441 | ret = clk_prepare_enable(esai_priv->coreclk); |
441 | if (!IS_ERR(esai_priv->extalclk)) | 442 | if (ret) |
442 | clk_prepare_enable(esai_priv->extalclk); | 443 | return ret; |
443 | if (!IS_ERR(esai_priv->fsysclk)) | 444 | if (!IS_ERR(esai_priv->extalclk)) { |
444 | clk_prepare_enable(esai_priv->fsysclk); | 445 | ret = clk_prepare_enable(esai_priv->extalclk); |
446 | if (ret) | ||
447 | goto err_extalck; | ||
448 | } | ||
449 | if (!IS_ERR(esai_priv->fsysclk)) { | ||
450 | ret = clk_prepare_enable(esai_priv->fsysclk); | ||
451 | if (ret) | ||
452 | goto err_fsysclk; | ||
453 | } | ||
445 | 454 | ||
446 | if (!dai->active) { | 455 | if (!dai->active) { |
447 | /* Reset Port C */ | 456 | /* Reset Port C */ |
@@ -463,6 +472,14 @@ static int fsl_esai_startup(struct snd_pcm_substream *substream, | |||
463 | } | 472 | } |
464 | 473 | ||
465 | return 0; | 474 | return 0; |
475 | |||
476 | err_fsysclk: | ||
477 | if (!IS_ERR(esai_priv->extalclk)) | ||
478 | clk_disable_unprepare(esai_priv->extalclk); | ||
479 | err_extalck: | ||
480 | clk_disable_unprepare(esai_priv->coreclk); | ||
481 | |||
482 | return ret; | ||
466 | } | 483 | } |
467 | 484 | ||
468 | static int fsl_esai_hw_params(struct snd_pcm_substream *substream, | 485 | static int fsl_esai_hw_params(struct snd_pcm_substream *substream, |
@@ -661,7 +678,7 @@ static bool fsl_esai_writeable_reg(struct device *dev, unsigned int reg) | |||
661 | } | 678 | } |
662 | } | 679 | } |
663 | 680 | ||
664 | static const struct regmap_config fsl_esai_regmap_config = { | 681 | static struct regmap_config fsl_esai_regmap_config = { |
665 | .reg_bits = 32, | 682 | .reg_bits = 32, |
666 | .reg_stride = 4, | 683 | .reg_stride = 4, |
667 | .val_bits = 32, | 684 | .val_bits = 32, |
@@ -687,6 +704,9 @@ static int fsl_esai_probe(struct platform_device *pdev) | |||
687 | esai_priv->pdev = pdev; | 704 | esai_priv->pdev = pdev; |
688 | strcpy(esai_priv->name, np->name); | 705 | strcpy(esai_priv->name, np->name); |
689 | 706 | ||
707 | if (of_property_read_bool(np, "big-endian")) | ||
708 | fsl_esai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
709 | |||
690 | /* Get the addresses and IRQ */ | 710 | /* Get the addresses and IRQ */ |
691 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 711 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
692 | regs = devm_ioremap_resource(&pdev->dev, res); | 712 | regs = devm_ioremap_resource(&pdev->dev, res); |
diff --git a/sound/soc/fsl/fsl_esai.h b/sound/soc/fsl/fsl_esai.h index 9c9f957fcae1..75e14033e8d8 100644 --- a/sound/soc/fsl/fsl_esai.h +++ b/sound/soc/fsl/fsl_esai.h | |||
@@ -322,7 +322,7 @@ | |||
322 | #define ESAI_xSMB_xS_SHIFT 0 | 322 | #define ESAI_xSMB_xS_SHIFT 0 |
323 | #define ESAI_xSMB_xS_WIDTH 16 | 323 | #define ESAI_xSMB_xS_WIDTH 16 |
324 | #define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT) | 324 | #define ESAI_xSMB_xS_MASK (((1 << ESAI_xSMB_xS_WIDTH) - 1) << ESAI_xSMB_xS_SHIFT) |
325 | #define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMA_xS_MASK) | 325 | #define ESAI_xSMB_xS(v) (((v) >> ESAI_xSMA_xS_WIDTH) & ESAI_xSMB_xS_MASK) |
326 | 326 | ||
327 | /* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */ | 327 | /* Port C Direction Register -- REG_ESAI_PRRC 0xF8 */ |
328 | #define ESAI_PRRC_PDC_SHIFT 0 | 328 | #define ESAI_PRRC_PDC_SHIFT 0 |
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index cdd3fa830704..c4a423111673 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/dmaengine.h> | 15 | #include <linux/dmaengine.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/of_address.h> | 17 | #include <linux/of_address.h> |
18 | #include <linux/regmap.h> | ||
18 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
19 | #include <sound/core.h> | 20 | #include <sound/core.h> |
20 | #include <sound/dmaengine_pcm.h> | 21 | #include <sound/dmaengine_pcm.h> |
@@ -22,34 +23,6 @@ | |||
22 | 23 | ||
23 | #include "fsl_sai.h" | 24 | #include "fsl_sai.h" |
24 | 25 | ||
25 | static inline u32 sai_readl(struct fsl_sai *sai, | ||
26 | const void __iomem *addr) | ||
27 | { | ||
28 | u32 val; | ||
29 | |||
30 | val = __raw_readl(addr); | ||
31 | |||
32 | if (likely(sai->big_endian_regs)) | ||
33 | val = be32_to_cpu(val); | ||
34 | else | ||
35 | val = le32_to_cpu(val); | ||
36 | rmb(); | ||
37 | |||
38 | return val; | ||
39 | } | ||
40 | |||
41 | static inline void sai_writel(struct fsl_sai *sai, | ||
42 | u32 val, void __iomem *addr) | ||
43 | { | ||
44 | wmb(); | ||
45 | if (likely(sai->big_endian_regs)) | ||
46 | val = cpu_to_be32(val); | ||
47 | else | ||
48 | val = cpu_to_le32(val); | ||
49 | |||
50 | __raw_writel(val, addr); | ||
51 | } | ||
52 | |||
53 | static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | 26 | static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, |
54 | int clk_id, unsigned int freq, int fsl_dir) | 27 | int clk_id, unsigned int freq, int fsl_dir) |
55 | { | 28 | { |
@@ -61,7 +34,8 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | |||
61 | else | 34 | else |
62 | reg_cr2 = FSL_SAI_RCR2; | 35 | reg_cr2 = FSL_SAI_RCR2; |
63 | 36 | ||
64 | val_cr2 = sai_readl(sai, sai->base + reg_cr2); | 37 | regmap_read(sai->regmap, reg_cr2, &val_cr2); |
38 | |||
65 | val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK; | 39 | val_cr2 &= ~FSL_SAI_CR2_MSEL_MASK; |
66 | 40 | ||
67 | switch (clk_id) { | 41 | switch (clk_id) { |
@@ -81,7 +55,7 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | |||
81 | return -EINVAL; | 55 | return -EINVAL; |
82 | } | 56 | } |
83 | 57 | ||
84 | sai_writel(sai, val_cr2, sai->base + reg_cr2); | 58 | regmap_write(sai->regmap, reg_cr2, val_cr2); |
85 | 59 | ||
86 | return 0; | 60 | return 0; |
87 | } | 61 | } |
@@ -89,32 +63,22 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, | |||
89 | static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, | 63 | static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, |
90 | int clk_id, unsigned int freq, int dir) | 64 | int clk_id, unsigned int freq, int dir) |
91 | { | 65 | { |
92 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | ||
93 | int ret; | 66 | int ret; |
94 | 67 | ||
95 | if (dir == SND_SOC_CLOCK_IN) | 68 | if (dir == SND_SOC_CLOCK_IN) |
96 | return 0; | 69 | return 0; |
97 | 70 | ||
98 | ret = clk_prepare_enable(sai->clk); | ||
99 | if (ret) | ||
100 | return ret; | ||
101 | |||
102 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, | 71 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, |
103 | FSL_FMT_TRANSMITTER); | 72 | FSL_FMT_TRANSMITTER); |
104 | if (ret) { | 73 | if (ret) { |
105 | dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); | 74 | dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); |
106 | goto err_clk; | 75 | return ret; |
107 | } | 76 | } |
108 | 77 | ||
109 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, | 78 | ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, |
110 | FSL_FMT_RECEIVER); | 79 | FSL_FMT_RECEIVER); |
111 | if (ret) { | 80 | if (ret) |
112 | dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret); | 81 | dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret); |
113 | goto err_clk; | ||
114 | } | ||
115 | |||
116 | err_clk: | ||
117 | clk_disable_unprepare(sai->clk); | ||
118 | 82 | ||
119 | return ret; | 83 | return ret; |
120 | } | 84 | } |
@@ -133,43 +97,84 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, | |||
133 | reg_cr4 = FSL_SAI_RCR4; | 97 | reg_cr4 = FSL_SAI_RCR4; |
134 | } | 98 | } |
135 | 99 | ||
136 | val_cr2 = sai_readl(sai, sai->base + reg_cr2); | 100 | regmap_read(sai->regmap, reg_cr2, &val_cr2); |
137 | val_cr4 = sai_readl(sai, sai->base + reg_cr4); | 101 | regmap_read(sai->regmap, reg_cr4, &val_cr4); |
138 | 102 | ||
139 | if (sai->big_endian_data) | 103 | if (sai->big_endian_data) |
140 | val_cr4 &= ~FSL_SAI_CR4_MF; | 104 | val_cr4 &= ~FSL_SAI_CR4_MF; |
141 | else | 105 | else |
142 | val_cr4 |= FSL_SAI_CR4_MF; | 106 | val_cr4 |= FSL_SAI_CR4_MF; |
143 | 107 | ||
108 | /* DAI mode */ | ||
144 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | 109 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { |
145 | case SND_SOC_DAIFMT_I2S: | 110 | case SND_SOC_DAIFMT_I2S: |
111 | /* | ||
112 | * Frame low, 1clk before data, one word length for frame sync, | ||
113 | * frame sync starts one serial clock cycle earlier, | ||
114 | * that is, together with the last bit of the previous | ||
115 | * data word. | ||
116 | */ | ||
117 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
118 | val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP; | ||
119 | break; | ||
120 | case SND_SOC_DAIFMT_LEFT_J: | ||
121 | /* | ||
122 | * Frame high, one word length for frame sync, | ||
123 | * frame sync asserts with the first bit of the frame. | ||
124 | */ | ||
125 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
126 | val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); | ||
127 | break; | ||
128 | case SND_SOC_DAIFMT_DSP_A: | ||
129 | /* | ||
130 | * Frame high, 1clk before data, one bit for frame sync, | ||
131 | * frame sync starts one serial clock cycle earlier, | ||
132 | * that is, together with the last bit of the previous | ||
133 | * data word. | ||
134 | */ | ||
135 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
136 | val_cr4 &= ~FSL_SAI_CR4_FSP; | ||
146 | val_cr4 |= FSL_SAI_CR4_FSE; | 137 | val_cr4 |= FSL_SAI_CR4_FSE; |
138 | sai->is_dsp_mode = true; | ||
139 | break; | ||
140 | case SND_SOC_DAIFMT_DSP_B: | ||
141 | /* | ||
142 | * Frame high, one bit for frame sync, | ||
143 | * frame sync asserts with the first bit of the frame. | ||
144 | */ | ||
145 | val_cr2 &= ~FSL_SAI_CR2_BCP; | ||
146 | val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP); | ||
147 | sai->is_dsp_mode = true; | ||
147 | break; | 148 | break; |
149 | case SND_SOC_DAIFMT_RIGHT_J: | ||
150 | /* To be done */ | ||
148 | default: | 151 | default: |
149 | return -EINVAL; | 152 | return -EINVAL; |
150 | } | 153 | } |
151 | 154 | ||
155 | /* DAI clock inversion */ | ||
152 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | 156 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { |
153 | case SND_SOC_DAIFMT_IB_IF: | 157 | case SND_SOC_DAIFMT_IB_IF: |
154 | val_cr4 |= FSL_SAI_CR4_FSP; | 158 | /* Invert both clocks */ |
155 | val_cr2 &= ~FSL_SAI_CR2_BCP; | 159 | val_cr2 ^= FSL_SAI_CR2_BCP; |
160 | val_cr4 ^= FSL_SAI_CR4_FSP; | ||
156 | break; | 161 | break; |
157 | case SND_SOC_DAIFMT_IB_NF: | 162 | case SND_SOC_DAIFMT_IB_NF: |
158 | val_cr4 &= ~FSL_SAI_CR4_FSP; | 163 | /* Invert bit clock */ |
159 | val_cr2 &= ~FSL_SAI_CR2_BCP; | 164 | val_cr2 ^= FSL_SAI_CR2_BCP; |
160 | break; | 165 | break; |
161 | case SND_SOC_DAIFMT_NB_IF: | 166 | case SND_SOC_DAIFMT_NB_IF: |
162 | val_cr4 |= FSL_SAI_CR4_FSP; | 167 | /* Invert frame clock */ |
163 | val_cr2 |= FSL_SAI_CR2_BCP; | 168 | val_cr4 ^= FSL_SAI_CR4_FSP; |
164 | break; | 169 | break; |
165 | case SND_SOC_DAIFMT_NB_NF: | 170 | case SND_SOC_DAIFMT_NB_NF: |
166 | val_cr4 &= ~FSL_SAI_CR4_FSP; | 171 | /* Nothing to do for both normal cases */ |
167 | val_cr2 |= FSL_SAI_CR2_BCP; | ||
168 | break; | 172 | break; |
169 | default: | 173 | default: |
170 | return -EINVAL; | 174 | return -EINVAL; |
171 | } | 175 | } |
172 | 176 | ||
177 | /* DAI clock master masks */ | ||
173 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | 178 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { |
174 | case SND_SOC_DAIFMT_CBS_CFS: | 179 | case SND_SOC_DAIFMT_CBS_CFS: |
175 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; | 180 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; |
@@ -179,39 +184,37 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, | |||
179 | val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; | 184 | val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; |
180 | val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; | 185 | val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; |
181 | break; | 186 | break; |
187 | case SND_SOC_DAIFMT_CBS_CFM: | ||
188 | val_cr2 |= FSL_SAI_CR2_BCD_MSTR; | ||
189 | val_cr4 &= ~FSL_SAI_CR4_FSD_MSTR; | ||
190 | break; | ||
191 | case SND_SOC_DAIFMT_CBM_CFS: | ||
192 | val_cr2 &= ~FSL_SAI_CR2_BCD_MSTR; | ||
193 | val_cr4 |= FSL_SAI_CR4_FSD_MSTR; | ||
194 | break; | ||
182 | default: | 195 | default: |
183 | return -EINVAL; | 196 | return -EINVAL; |
184 | } | 197 | } |
185 | 198 | ||
186 | sai_writel(sai, val_cr2, sai->base + reg_cr2); | 199 | regmap_write(sai->regmap, reg_cr2, val_cr2); |
187 | sai_writel(sai, val_cr4, sai->base + reg_cr4); | 200 | regmap_write(sai->regmap, reg_cr4, val_cr4); |
188 | 201 | ||
189 | return 0; | 202 | return 0; |
190 | } | 203 | } |
191 | 204 | ||
192 | static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) | 205 | static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) |
193 | { | 206 | { |
194 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | ||
195 | int ret; | 207 | int ret; |
196 | 208 | ||
197 | ret = clk_prepare_enable(sai->clk); | ||
198 | if (ret) | ||
199 | return ret; | ||
200 | |||
201 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER); | 209 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER); |
202 | if (ret) { | 210 | if (ret) { |
203 | dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); | 211 | dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); |
204 | goto err_clk; | 212 | return ret; |
205 | } | 213 | } |
206 | 214 | ||
207 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER); | 215 | ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER); |
208 | if (ret) { | 216 | if (ret) |
209 | dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret); | 217 | dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret); |
210 | goto err_clk; | ||
211 | } | ||
212 | |||
213 | err_clk: | ||
214 | clk_disable_unprepare(sai->clk); | ||
215 | 218 | ||
216 | return ret; | 219 | return ret; |
217 | } | 220 | } |
@@ -235,16 +238,19 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
235 | reg_mr = FSL_SAI_RMR; | 238 | reg_mr = FSL_SAI_RMR; |
236 | } | 239 | } |
237 | 240 | ||
238 | val_cr4 = sai_readl(sai, sai->base + reg_cr4); | 241 | regmap_read(sai->regmap, reg_cr4, &val_cr4); |
242 | regmap_read(sai->regmap, reg_cr4, &val_cr5); | ||
243 | |||
239 | val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK; | 244 | val_cr4 &= ~FSL_SAI_CR4_SYWD_MASK; |
240 | val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK; | 245 | val_cr4 &= ~FSL_SAI_CR4_FRSZ_MASK; |
241 | 246 | ||
242 | val_cr5 = sai_readl(sai, sai->base + reg_cr5); | ||
243 | val_cr5 &= ~FSL_SAI_CR5_WNW_MASK; | 247 | val_cr5 &= ~FSL_SAI_CR5_WNW_MASK; |
244 | val_cr5 &= ~FSL_SAI_CR5_W0W_MASK; | 248 | val_cr5 &= ~FSL_SAI_CR5_W0W_MASK; |
245 | val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; | 249 | val_cr5 &= ~FSL_SAI_CR5_FBT_MASK; |
246 | 250 | ||
247 | val_cr4 |= FSL_SAI_CR4_SYWD(word_width); | 251 | if (!sai->is_dsp_mode) |
252 | val_cr4 |= FSL_SAI_CR4_SYWD(word_width); | ||
253 | |||
248 | val_cr5 |= FSL_SAI_CR5_WNW(word_width); | 254 | val_cr5 |= FSL_SAI_CR5_WNW(word_width); |
249 | val_cr5 |= FSL_SAI_CR5_W0W(word_width); | 255 | val_cr5 |= FSL_SAI_CR5_W0W(word_width); |
250 | 256 | ||
@@ -257,9 +263,9 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, | |||
257 | val_cr4 |= FSL_SAI_CR4_FRSZ(channels); | 263 | val_cr4 |= FSL_SAI_CR4_FRSZ(channels); |
258 | val_mr = ~0UL - ((1 << channels) - 1); | 264 | val_mr = ~0UL - ((1 << channels) - 1); |
259 | 265 | ||
260 | sai_writel(sai, val_cr4, sai->base + reg_cr4); | 266 | regmap_write(sai->regmap, reg_cr4, val_cr4); |
261 | sai_writel(sai, val_cr5, sai->base + reg_cr5); | 267 | regmap_write(sai->regmap, reg_cr5, val_cr5); |
262 | sai_writel(sai, val_mr, sai->base + reg_mr); | 268 | regmap_write(sai->regmap, reg_mr, val_mr); |
263 | 269 | ||
264 | return 0; | 270 | return 0; |
265 | } | 271 | } |
@@ -268,44 +274,42 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
268 | struct snd_soc_dai *cpu_dai) | 274 | struct snd_soc_dai *cpu_dai) |
269 | { | 275 | { |
270 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 276 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
271 | u32 tcsr, rcsr, val_cr2, val_cr3, reg_cr3; | 277 | u32 tcsr, rcsr; |
272 | |||
273 | val_cr2 = sai_readl(sai, sai->base + FSL_SAI_TCR2); | ||
274 | val_cr2 &= ~FSL_SAI_CR2_SYNC; | ||
275 | sai_writel(sai, val_cr2, sai->base + FSL_SAI_TCR2); | ||
276 | 278 | ||
277 | val_cr2 = sai_readl(sai, sai->base + FSL_SAI_RCR2); | 279 | /* |
278 | val_cr2 |= FSL_SAI_CR2_SYNC; | 280 | * The transmitter bit clock and frame sync are to be |
279 | sai_writel(sai, val_cr2, sai->base + FSL_SAI_RCR2); | 281 | * used by both the transmitter and receiver. |
282 | */ | ||
283 | regmap_update_bits(sai->regmap, FSL_SAI_TCR2, FSL_SAI_CR2_SYNC, | ||
284 | ~FSL_SAI_CR2_SYNC); | ||
285 | regmap_update_bits(sai->regmap, FSL_SAI_RCR2, FSL_SAI_CR2_SYNC, | ||
286 | FSL_SAI_CR2_SYNC); | ||
280 | 287 | ||
281 | tcsr = sai_readl(sai, sai->base + FSL_SAI_TCSR); | 288 | regmap_read(sai->regmap, FSL_SAI_TCSR, &tcsr); |
282 | rcsr = sai_readl(sai, sai->base + FSL_SAI_RCSR); | 289 | regmap_read(sai->regmap, FSL_SAI_RCSR, &rcsr); |
283 | 290 | ||
284 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 291 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
285 | tcsr |= FSL_SAI_CSR_FRDE; | 292 | tcsr |= FSL_SAI_CSR_FRDE; |
286 | rcsr &= ~FSL_SAI_CSR_FRDE; | 293 | rcsr &= ~FSL_SAI_CSR_FRDE; |
287 | reg_cr3 = FSL_SAI_TCR3; | ||
288 | } else { | 294 | } else { |
289 | rcsr |= FSL_SAI_CSR_FRDE; | 295 | rcsr |= FSL_SAI_CSR_FRDE; |
290 | tcsr &= ~FSL_SAI_CSR_FRDE; | 296 | tcsr &= ~FSL_SAI_CSR_FRDE; |
291 | reg_cr3 = FSL_SAI_RCR3; | ||
292 | } | 297 | } |
293 | 298 | ||
294 | val_cr3 = sai_readl(sai, sai->base + reg_cr3); | 299 | /* |
295 | 300 | * It is recommended that the transmitter is the last enabled | |
301 | * and the first disabled. | ||
302 | */ | ||
296 | switch (cmd) { | 303 | switch (cmd) { |
297 | case SNDRV_PCM_TRIGGER_START: | 304 | case SNDRV_PCM_TRIGGER_START: |
298 | case SNDRV_PCM_TRIGGER_RESUME: | 305 | case SNDRV_PCM_TRIGGER_RESUME: |
299 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 306 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
300 | tcsr |= FSL_SAI_CSR_TERE; | 307 | tcsr |= FSL_SAI_CSR_TERE; |
301 | rcsr |= FSL_SAI_CSR_TERE; | 308 | rcsr |= FSL_SAI_CSR_TERE; |
302 | val_cr3 |= FSL_SAI_CR3_TRCE; | ||
303 | 309 | ||
304 | sai_writel(sai, val_cr3, sai->base + reg_cr3); | 310 | regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); |
305 | sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR); | 311 | regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); |
306 | sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR); | ||
307 | break; | 312 | break; |
308 | |||
309 | case SNDRV_PCM_TRIGGER_STOP: | 313 | case SNDRV_PCM_TRIGGER_STOP: |
310 | case SNDRV_PCM_TRIGGER_SUSPEND: | 314 | case SNDRV_PCM_TRIGGER_SUSPEND: |
311 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 315 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
@@ -314,11 +318,8 @@ static int fsl_sai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
314 | rcsr &= ~FSL_SAI_CSR_TERE; | 318 | rcsr &= ~FSL_SAI_CSR_TERE; |
315 | } | 319 | } |
316 | 320 | ||
317 | val_cr3 &= ~FSL_SAI_CR3_TRCE; | 321 | regmap_write(sai->regmap, FSL_SAI_TCSR, tcsr); |
318 | 322 | regmap_write(sai->regmap, FSL_SAI_RCSR, rcsr); | |
319 | sai_writel(sai, tcsr, sai->base + FSL_SAI_TCSR); | ||
320 | sai_writel(sai, rcsr, sai->base + FSL_SAI_RCSR); | ||
321 | sai_writel(sai, val_cr3, sai->base + reg_cr3); | ||
322 | break; | 323 | break; |
323 | default: | 324 | default: |
324 | return -EINVAL; | 325 | return -EINVAL; |
@@ -331,16 +332,32 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream, | |||
331 | struct snd_soc_dai *cpu_dai) | 332 | struct snd_soc_dai *cpu_dai) |
332 | { | 333 | { |
333 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 334 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
335 | u32 reg; | ||
336 | |||
337 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
338 | reg = FSL_SAI_TCR3; | ||
339 | else | ||
340 | reg = FSL_SAI_RCR3; | ||
341 | |||
342 | regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, | ||
343 | FSL_SAI_CR3_TRCE); | ||
334 | 344 | ||
335 | return clk_prepare_enable(sai->clk); | 345 | return 0; |
336 | } | 346 | } |
337 | 347 | ||
338 | static void fsl_sai_shutdown(struct snd_pcm_substream *substream, | 348 | static void fsl_sai_shutdown(struct snd_pcm_substream *substream, |
339 | struct snd_soc_dai *cpu_dai) | 349 | struct snd_soc_dai *cpu_dai) |
340 | { | 350 | { |
341 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); | 351 | struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); |
352 | u32 reg; | ||
353 | |||
354 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
355 | reg = FSL_SAI_TCR3; | ||
356 | else | ||
357 | reg = FSL_SAI_RCR3; | ||
342 | 358 | ||
343 | clk_disable_unprepare(sai->clk); | 359 | regmap_update_bits(sai->regmap, reg, FSL_SAI_CR3_TRCE, |
360 | ~FSL_SAI_CR3_TRCE); | ||
344 | } | 361 | } |
345 | 362 | ||
346 | static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { | 363 | static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { |
@@ -355,18 +372,13 @@ static const struct snd_soc_dai_ops fsl_sai_pcm_dai_ops = { | |||
355 | static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) | 372 | static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) |
356 | { | 373 | { |
357 | struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); | 374 | struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev); |
358 | int ret; | ||
359 | 375 | ||
360 | ret = clk_prepare_enable(sai->clk); | 376 | regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0); |
361 | if (ret) | 377 | regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0); |
362 | return ret; | 378 | regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK, |
363 | 379 | FSL_SAI_MAXBURST_TX * 2); | |
364 | sai_writel(sai, 0x0, sai->base + FSL_SAI_RCSR); | 380 | regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK, |
365 | sai_writel(sai, 0x0, sai->base + FSL_SAI_TCSR); | 381 | FSL_SAI_MAXBURST_RX - 1); |
366 | sai_writel(sai, FSL_SAI_MAXBURST_TX * 2, sai->base + FSL_SAI_TCR1); | ||
367 | sai_writel(sai, FSL_SAI_MAXBURST_RX - 1, sai->base + FSL_SAI_RCR1); | ||
368 | |||
369 | clk_disable_unprepare(sai->clk); | ||
370 | 382 | ||
371 | snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, | 383 | snd_soc_dai_init_dma_data(cpu_dai, &sai->dma_params_tx, |
372 | &sai->dma_params_rx); | 384 | &sai->dma_params_rx); |
@@ -397,26 +409,109 @@ static const struct snd_soc_component_driver fsl_component = { | |||
397 | .name = "fsl-sai", | 409 | .name = "fsl-sai", |
398 | }; | 410 | }; |
399 | 411 | ||
412 | static bool fsl_sai_readable_reg(struct device *dev, unsigned int reg) | ||
413 | { | ||
414 | switch (reg) { | ||
415 | case FSL_SAI_TCSR: | ||
416 | case FSL_SAI_TCR1: | ||
417 | case FSL_SAI_TCR2: | ||
418 | case FSL_SAI_TCR3: | ||
419 | case FSL_SAI_TCR4: | ||
420 | case FSL_SAI_TCR5: | ||
421 | case FSL_SAI_TFR: | ||
422 | case FSL_SAI_TMR: | ||
423 | case FSL_SAI_RCSR: | ||
424 | case FSL_SAI_RCR1: | ||
425 | case FSL_SAI_RCR2: | ||
426 | case FSL_SAI_RCR3: | ||
427 | case FSL_SAI_RCR4: | ||
428 | case FSL_SAI_RCR5: | ||
429 | case FSL_SAI_RDR: | ||
430 | case FSL_SAI_RFR: | ||
431 | case FSL_SAI_RMR: | ||
432 | return true; | ||
433 | default: | ||
434 | return false; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | static bool fsl_sai_volatile_reg(struct device *dev, unsigned int reg) | ||
439 | { | ||
440 | switch (reg) { | ||
441 | case FSL_SAI_TFR: | ||
442 | case FSL_SAI_RFR: | ||
443 | case FSL_SAI_TDR: | ||
444 | case FSL_SAI_RDR: | ||
445 | return true; | ||
446 | default: | ||
447 | return false; | ||
448 | } | ||
449 | |||
450 | } | ||
451 | |||
452 | static bool fsl_sai_writeable_reg(struct device *dev, unsigned int reg) | ||
453 | { | ||
454 | switch (reg) { | ||
455 | case FSL_SAI_TCSR: | ||
456 | case FSL_SAI_TCR1: | ||
457 | case FSL_SAI_TCR2: | ||
458 | case FSL_SAI_TCR3: | ||
459 | case FSL_SAI_TCR4: | ||
460 | case FSL_SAI_TCR5: | ||
461 | case FSL_SAI_TDR: | ||
462 | case FSL_SAI_TMR: | ||
463 | case FSL_SAI_RCSR: | ||
464 | case FSL_SAI_RCR1: | ||
465 | case FSL_SAI_RCR2: | ||
466 | case FSL_SAI_RCR3: | ||
467 | case FSL_SAI_RCR4: | ||
468 | case FSL_SAI_RCR5: | ||
469 | case FSL_SAI_RMR: | ||
470 | return true; | ||
471 | default: | ||
472 | return false; | ||
473 | } | ||
474 | } | ||
475 | |||
476 | static struct regmap_config fsl_sai_regmap_config = { | ||
477 | .reg_bits = 32, | ||
478 | .reg_stride = 4, | ||
479 | .val_bits = 32, | ||
480 | |||
481 | .max_register = FSL_SAI_RMR, | ||
482 | .readable_reg = fsl_sai_readable_reg, | ||
483 | .volatile_reg = fsl_sai_volatile_reg, | ||
484 | .writeable_reg = fsl_sai_writeable_reg, | ||
485 | }; | ||
486 | |||
400 | static int fsl_sai_probe(struct platform_device *pdev) | 487 | static int fsl_sai_probe(struct platform_device *pdev) |
401 | { | 488 | { |
402 | struct device_node *np = pdev->dev.of_node; | 489 | struct device_node *np = pdev->dev.of_node; |
403 | struct fsl_sai *sai; | 490 | struct fsl_sai *sai; |
404 | struct resource *res; | 491 | struct resource *res; |
492 | void __iomem *base; | ||
405 | int ret; | 493 | int ret; |
406 | 494 | ||
407 | sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); | 495 | sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); |
408 | if (!sai) | 496 | if (!sai) |
409 | return -ENOMEM; | 497 | return -ENOMEM; |
410 | 498 | ||
499 | sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); | ||
500 | if (sai->big_endian_regs) | ||
501 | fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
502 | |||
503 | sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); | ||
504 | |||
411 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 505 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
412 | sai->base = devm_ioremap_resource(&pdev->dev, res); | 506 | base = devm_ioremap_resource(&pdev->dev, res); |
413 | if (IS_ERR(sai->base)) | 507 | if (IS_ERR(base)) |
414 | return PTR_ERR(sai->base); | 508 | return PTR_ERR(base); |
415 | 509 | ||
416 | sai->clk = devm_clk_get(&pdev->dev, "sai"); | 510 | sai->regmap = devm_regmap_init_mmio_clk(&pdev->dev, |
417 | if (IS_ERR(sai->clk)) { | 511 | "sai", base, &fsl_sai_regmap_config); |
418 | dev_err(&pdev->dev, "Cannot get SAI's clock\n"); | 512 | if (IS_ERR(sai->regmap)) { |
419 | return PTR_ERR(sai->clk); | 513 | dev_err(&pdev->dev, "regmap init failed\n"); |
514 | return PTR_ERR(sai->regmap); | ||
420 | } | 515 | } |
421 | 516 | ||
422 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; | 517 | sai->dma_params_rx.addr = res->start + FSL_SAI_RDR; |
@@ -424,9 +519,6 @@ static int fsl_sai_probe(struct platform_device *pdev) | |||
424 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; | 519 | sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; |
425 | sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; | 520 | sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; |
426 | 521 | ||
427 | sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs"); | ||
428 | sai->big_endian_data = of_property_read_bool(np, "big-endian-data"); | ||
429 | |||
430 | platform_set_drvdata(pdev, sai); | 522 | platform_set_drvdata(pdev, sai); |
431 | 523 | ||
432 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, | 524 | ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, |
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 41bb62e69361..e432260be598 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h | |||
@@ -15,31 +15,36 @@ | |||
15 | SNDRV_PCM_FMTBIT_S20_3LE |\ | 15 | SNDRV_PCM_FMTBIT_S20_3LE |\ |
16 | SNDRV_PCM_FMTBIT_S24_LE) | 16 | SNDRV_PCM_FMTBIT_S24_LE) |
17 | 17 | ||
18 | /* SAI Register Map Register */ | ||
19 | #define FSL_SAI_TCSR 0x00 /* SAI Transmit Control */ | ||
20 | #define FSL_SAI_TCR1 0x04 /* SAI Transmit Configuration 1 */ | ||
21 | #define FSL_SAI_TCR2 0x08 /* SAI Transmit Configuration 2 */ | ||
22 | #define FSL_SAI_TCR3 0x0c /* SAI Transmit Configuration 3 */ | ||
23 | #define FSL_SAI_TCR4 0x10 /* SAI Transmit Configuration 4 */ | ||
24 | #define FSL_SAI_TCR5 0x14 /* SAI Transmit Configuration 5 */ | ||
25 | #define FSL_SAI_TDR 0x20 /* SAI Transmit Data */ | ||
26 | #define FSL_SAI_TFR 0x40 /* SAI Transmit FIFO */ | ||
27 | #define FSL_SAI_TMR 0x60 /* SAI Transmit Mask */ | ||
28 | #define FSL_SAI_RCSR 0x80 /* SAI Receive Control */ | ||
29 | #define FSL_SAI_RCR1 0x84 /* SAI Receive Configuration 1 */ | ||
30 | #define FSL_SAI_RCR2 0x88 /* SAI Receive Configuration 2 */ | ||
31 | #define FSL_SAI_RCR3 0x8c /* SAI Receive Configuration 3 */ | ||
32 | #define FSL_SAI_RCR4 0x90 /* SAI Receive Configuration 4 */ | ||
33 | #define FSL_SAI_RCR5 0x94 /* SAI Receive Configuration 5 */ | ||
34 | #define FSL_SAI_RDR 0xa0 /* SAI Receive Data */ | ||
35 | #define FSL_SAI_RFR 0xc0 /* SAI Receive FIFO */ | ||
36 | #define FSL_SAI_RMR 0xe0 /* SAI Receive Mask */ | ||
37 | |||
18 | /* SAI Transmit/Recieve Control Register */ | 38 | /* SAI Transmit/Recieve Control Register */ |
19 | #define FSL_SAI_TCSR 0x00 | ||
20 | #define FSL_SAI_RCSR 0x80 | ||
21 | #define FSL_SAI_CSR_TERE BIT(31) | 39 | #define FSL_SAI_CSR_TERE BIT(31) |
22 | #define FSL_SAI_CSR_FWF BIT(17) | 40 | #define FSL_SAI_CSR_FWF BIT(17) |
23 | #define FSL_SAI_CSR_FRIE BIT(8) | 41 | #define FSL_SAI_CSR_FRIE BIT(8) |
24 | #define FSL_SAI_CSR_FRDE BIT(0) | 42 | #define FSL_SAI_CSR_FRDE BIT(0) |
25 | 43 | ||
26 | /* SAI Transmit Data/FIFO/MASK Register */ | ||
27 | #define FSL_SAI_TDR 0x20 | ||
28 | #define FSL_SAI_TFR 0x40 | ||
29 | #define FSL_SAI_TMR 0x60 | ||
30 | |||
31 | /* SAI Recieve Data/FIFO/MASK Register */ | ||
32 | #define FSL_SAI_RDR 0xa0 | ||
33 | #define FSL_SAI_RFR 0xc0 | ||
34 | #define FSL_SAI_RMR 0xe0 | ||
35 | |||
36 | /* SAI Transmit and Recieve Configuration 1 Register */ | 44 | /* SAI Transmit and Recieve Configuration 1 Register */ |
37 | #define FSL_SAI_TCR1 0x04 | 45 | #define FSL_SAI_CR1_RFW_MASK 0x1f |
38 | #define FSL_SAI_RCR1 0x84 | ||
39 | 46 | ||
40 | /* SAI Transmit and Recieve Configuration 2 Register */ | 47 | /* SAI Transmit and Recieve Configuration 2 Register */ |
41 | #define FSL_SAI_TCR2 0x08 | ||
42 | #define FSL_SAI_RCR2 0x88 | ||
43 | #define FSL_SAI_CR2_SYNC BIT(30) | 48 | #define FSL_SAI_CR2_SYNC BIT(30) |
44 | #define FSL_SAI_CR2_MSEL_MASK (0xff << 26) | 49 | #define FSL_SAI_CR2_MSEL_MASK (0xff << 26) |
45 | #define FSL_SAI_CR2_MSEL_BUS 0 | 50 | #define FSL_SAI_CR2_MSEL_BUS 0 |
@@ -50,15 +55,11 @@ | |||
50 | #define FSL_SAI_CR2_BCD_MSTR BIT(24) | 55 | #define FSL_SAI_CR2_BCD_MSTR BIT(24) |
51 | 56 | ||
52 | /* SAI Transmit and Recieve Configuration 3 Register */ | 57 | /* SAI Transmit and Recieve Configuration 3 Register */ |
53 | #define FSL_SAI_TCR3 0x0c | ||
54 | #define FSL_SAI_RCR3 0x8c | ||
55 | #define FSL_SAI_CR3_TRCE BIT(16) | 58 | #define FSL_SAI_CR3_TRCE BIT(16) |
56 | #define FSL_SAI_CR3_WDFL(x) (x) | 59 | #define FSL_SAI_CR3_WDFL(x) (x) |
57 | #define FSL_SAI_CR3_WDFL_MASK 0x1f | 60 | #define FSL_SAI_CR3_WDFL_MASK 0x1f |
58 | 61 | ||
59 | /* SAI Transmit and Recieve Configuration 4 Register */ | 62 | /* SAI Transmit and Recieve Configuration 4 Register */ |
60 | #define FSL_SAI_TCR4 0x10 | ||
61 | #define FSL_SAI_RCR4 0x90 | ||
62 | #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) | 63 | #define FSL_SAI_CR4_FRSZ(x) (((x) - 1) << 16) |
63 | #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) | 64 | #define FSL_SAI_CR4_FRSZ_MASK (0x1f << 16) |
64 | #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) | 65 | #define FSL_SAI_CR4_SYWD(x) (((x) - 1) << 8) |
@@ -69,8 +70,6 @@ | |||
69 | #define FSL_SAI_CR4_FSD_MSTR BIT(0) | 70 | #define FSL_SAI_CR4_FSD_MSTR BIT(0) |
70 | 71 | ||
71 | /* SAI Transmit and Recieve Configuration 5 Register */ | 72 | /* SAI Transmit and Recieve Configuration 5 Register */ |
72 | #define FSL_SAI_TCR5 0x14 | ||
73 | #define FSL_SAI_RCR5 0x94 | ||
74 | #define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24) | 73 | #define FSL_SAI_CR5_WNW(x) (((x) - 1) << 24) |
75 | #define FSL_SAI_CR5_WNW_MASK (0x1f << 24) | 74 | #define FSL_SAI_CR5_WNW_MASK (0x1f << 24) |
76 | #define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16) | 75 | #define FSL_SAI_CR5_W0W(x) (((x) - 1) << 16) |
@@ -100,12 +99,11 @@ | |||
100 | #define FSL_SAI_MAXBURST_RX 6 | 99 | #define FSL_SAI_MAXBURST_RX 6 |
101 | 100 | ||
102 | struct fsl_sai { | 101 | struct fsl_sai { |
103 | struct clk *clk; | 102 | struct regmap *regmap; |
104 | |||
105 | void __iomem *base; | ||
106 | 103 | ||
107 | bool big_endian_regs; | 104 | bool big_endian_regs; |
108 | bool big_endian_data; | 105 | bool big_endian_data; |
106 | bool is_dsp_mode; | ||
109 | 107 | ||
110 | struct snd_dmaengine_dai_dma_data dma_params_rx; | 108 | struct snd_dmaengine_dai_dma_data dma_params_rx; |
111 | struct snd_dmaengine_dai_dma_data dma_params_tx; | 109 | struct snd_dmaengine_dai_dma_data dma_params_tx; |
diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 4d075f1abe78..6452ca83d889 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c | |||
@@ -911,8 +911,8 @@ static int fsl_spdif_dai_probe(struct snd_soc_dai *dai) | |||
911 | { | 911 | { |
912 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); | 912 | struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); |
913 | 913 | ||
914 | dai->playback_dma_data = &spdif_private->dma_params_tx; | 914 | snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx, |
915 | dai->capture_dma_data = &spdif_private->dma_params_rx; | 915 | &spdif_private->dma_params_rx); |
916 | 916 | ||
917 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); | 917 | snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); |
918 | 918 | ||
@@ -985,7 +985,7 @@ static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) | |||
985 | } | 985 | } |
986 | } | 986 | } |
987 | 987 | ||
988 | static const struct regmap_config fsl_spdif_regmap_config = { | 988 | static struct regmap_config fsl_spdif_regmap_config = { |
989 | .reg_bits = 32, | 989 | .reg_bits = 32, |
990 | .reg_stride = 4, | 990 | .reg_stride = 4, |
991 | .val_bits = 32, | 991 | .val_bits = 32, |
@@ -1105,6 +1105,9 @@ static int fsl_spdif_probe(struct platform_device *pdev) | |||
1105 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); | 1105 | memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); |
1106 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; | 1106 | spdif_priv->cpu_dai_drv.name = spdif_priv->name; |
1107 | 1107 | ||
1108 | if (of_property_read_bool(np, "big-endian")) | ||
1109 | fsl_spdif_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG; | ||
1110 | |||
1108 | /* Get the addresses and IRQ */ | 1111 | /* Get the addresses and IRQ */ |
1109 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1112 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1110 | regs = devm_ioremap_resource(&pdev->dev, res); | 1113 | regs = devm_ioremap_resource(&pdev->dev, res); |
diff --git a/sound/soc/fsl/imx-mc13783.c b/sound/soc/fsl/imx-mc13783.c index 79cee782dbbf..a2fd7321b5a9 100644 --- a/sound/soc/fsl/imx-mc13783.c +++ b/sound/soc/fsl/imx-mc13783.c | |||
@@ -160,7 +160,6 @@ static struct platform_driver imx_mc13783_audio_driver = { | |||
160 | .driver = { | 160 | .driver = { |
161 | .name = "imx_mc13783", | 161 | .name = "imx_mc13783", |
162 | .owner = THIS_MODULE, | 162 | .owner = THIS_MODULE, |
163 | .pm = &snd_soc_pm_ops, | ||
164 | }, | 163 | }, |
165 | .probe = imx_mc13783_probe, | 164 | .probe = imx_mc13783_probe, |
166 | .remove = imx_mc13783_remove | 165 | .remove = imx_mc13783_remove |
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 6553202dd48c..7abf6a079574 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c | |||
@@ -270,18 +270,17 @@ static int imx_pcm_new(struct snd_soc_pcm_runtime *rtd) | |||
270 | ret = imx_pcm_preallocate_dma_buffer(pcm, | 270 | ret = imx_pcm_preallocate_dma_buffer(pcm, |
271 | SNDRV_PCM_STREAM_PLAYBACK); | 271 | SNDRV_PCM_STREAM_PLAYBACK); |
272 | if (ret) | 272 | if (ret) |
273 | goto out; | 273 | return ret; |
274 | } | 274 | } |
275 | 275 | ||
276 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | 276 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { |
277 | ret = imx_pcm_preallocate_dma_buffer(pcm, | 277 | ret = imx_pcm_preallocate_dma_buffer(pcm, |
278 | SNDRV_PCM_STREAM_CAPTURE); | 278 | SNDRV_PCM_STREAM_CAPTURE); |
279 | if (ret) | 279 | if (ret) |
280 | goto out; | 280 | return ret; |
281 | } | 281 | } |
282 | 282 | ||
283 | out: | 283 | return 0; |
284 | return ret; | ||
285 | } | 284 | } |
286 | 285 | ||
287 | static int ssi_irq = 0; | 286 | static int ssi_irq = 0; |
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c index f2beae78969f..1cb22dd034eb 100644 --- a/sound/soc/fsl/imx-sgtl5000.c +++ b/sound/soc/fsl/imx-sgtl5000.c | |||
@@ -33,8 +33,7 @@ struct imx_sgtl5000_data { | |||
33 | 33 | ||
34 | static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd) | 34 | static int imx_sgtl5000_dai_init(struct snd_soc_pcm_runtime *rtd) |
35 | { | 35 | { |
36 | struct imx_sgtl5000_data *data = container_of(rtd->card, | 36 | struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(rtd->card); |
37 | struct imx_sgtl5000_data, card); | ||
38 | struct device *dev = rtd->card->dev; | 37 | struct device *dev = rtd->card->dev; |
39 | int ret; | 38 | int ret; |
40 | 39 | ||
@@ -159,13 +158,15 @@ static int imx_sgtl5000_probe(struct platform_device *pdev) | |||
159 | data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; | 158 | data->card.dapm_widgets = imx_sgtl5000_dapm_widgets; |
160 | data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); | 159 | data->card.num_dapm_widgets = ARRAY_SIZE(imx_sgtl5000_dapm_widgets); |
161 | 160 | ||
161 | platform_set_drvdata(pdev, &data->card); | ||
162 | snd_soc_card_set_drvdata(&data->card, data); | ||
163 | |||
162 | ret = devm_snd_soc_register_card(&pdev->dev, &data->card); | 164 | ret = devm_snd_soc_register_card(&pdev->dev, &data->card); |
163 | if (ret) { | 165 | if (ret) { |
164 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | 166 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); |
165 | goto fail; | 167 | goto fail; |
166 | } | 168 | } |
167 | 169 | ||
168 | platform_set_drvdata(pdev, data); | ||
169 | of_node_put(ssi_np); | 170 | of_node_put(ssi_np); |
170 | of_node_put(codec_np); | 171 | of_node_put(codec_np); |
171 | 172 | ||
@@ -184,7 +185,8 @@ fail: | |||
184 | 185 | ||
185 | static int imx_sgtl5000_remove(struct platform_device *pdev) | 186 | static int imx_sgtl5000_remove(struct platform_device *pdev) |
186 | { | 187 | { |
187 | struct imx_sgtl5000_data *data = platform_get_drvdata(pdev); | 188 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
189 | struct imx_sgtl5000_data *data = snd_soc_card_get_drvdata(card); | ||
188 | 190 | ||
189 | clk_put(data->codec_clk); | 191 | clk_put(data->codec_clk); |
190 | 192 | ||
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 3fd76bc391de..3a3d17ce6ba4 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c | |||
@@ -71,7 +71,7 @@ static int imx_wm8962_set_bias_level(struct snd_soc_card *card, | |||
71 | { | 71 | { |
72 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | 72 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; |
73 | struct imx_priv *priv = &card_priv; | 73 | struct imx_priv *priv = &card_priv; |
74 | struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); | 74 | struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); |
75 | struct device *dev = &priv->pdev->dev; | 75 | struct device *dev = &priv->pdev->dev; |
76 | unsigned int pll_out; | 76 | unsigned int pll_out; |
77 | int ret; | 77 | int ret; |
@@ -137,7 +137,7 @@ static int imx_wm8962_late_probe(struct snd_soc_card *card) | |||
137 | { | 137 | { |
138 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; | 138 | struct snd_soc_dai *codec_dai = card->rtd[0].codec_dai; |
139 | struct imx_priv *priv = &card_priv; | 139 | struct imx_priv *priv = &card_priv; |
140 | struct imx_wm8962_data *data = platform_get_drvdata(priv->pdev); | 140 | struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); |
141 | struct device *dev = &priv->pdev->dev; | 141 | struct device *dev = &priv->pdev->dev; |
142 | int ret; | 142 | int ret; |
143 | 143 | ||
@@ -264,13 +264,15 @@ static int imx_wm8962_probe(struct platform_device *pdev) | |||
264 | data->card.late_probe = imx_wm8962_late_probe; | 264 | data->card.late_probe = imx_wm8962_late_probe; |
265 | data->card.set_bias_level = imx_wm8962_set_bias_level; | 265 | data->card.set_bias_level = imx_wm8962_set_bias_level; |
266 | 266 | ||
267 | platform_set_drvdata(pdev, &data->card); | ||
268 | snd_soc_card_set_drvdata(&data->card, data); | ||
269 | |||
267 | ret = devm_snd_soc_register_card(&pdev->dev, &data->card); | 270 | ret = devm_snd_soc_register_card(&pdev->dev, &data->card); |
268 | if (ret) { | 271 | if (ret) { |
269 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); | 272 | dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret); |
270 | goto clk_fail; | 273 | goto clk_fail; |
271 | } | 274 | } |
272 | 275 | ||
273 | platform_set_drvdata(pdev, data); | ||
274 | of_node_put(ssi_np); | 276 | of_node_put(ssi_np); |
275 | of_node_put(codec_np); | 277 | of_node_put(codec_np); |
276 | 278 | ||
@@ -289,7 +291,8 @@ fail: | |||
289 | 291 | ||
290 | static int imx_wm8962_remove(struct platform_device *pdev) | 292 | static int imx_wm8962_remove(struct platform_device *pdev) |
291 | { | 293 | { |
292 | struct imx_wm8962_data *data = platform_get_drvdata(pdev); | 294 | struct snd_soc_card *card = platform_get_drvdata(pdev); |
295 | struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); | ||
293 | 296 | ||
294 | if (!IS_ERR(data->codec_clk)) | 297 | if (!IS_ERR(data->codec_clk)) |
295 | clk_disable_unprepare(data->codec_clk); | 298 | clk_disable_unprepare(data->codec_clk); |
diff --git a/sound/soc/fsl/wm1133-ev1.c b/sound/soc/fsl/wm1133-ev1.c index fce63252bdbb..804749a6c61e 100644 --- a/sound/soc/fsl/wm1133-ev1.c +++ b/sound/soc/fsl/wm1133-ev1.c | |||
@@ -214,12 +214,6 @@ static int wm1133_ev1_init(struct snd_soc_pcm_runtime *rtd) | |||
214 | struct snd_soc_codec *codec = rtd->codec; | 214 | struct snd_soc_codec *codec = rtd->codec; |
215 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 215 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
216 | 216 | ||
217 | snd_soc_dapm_new_controls(dapm, wm1133_ev1_widgets, | ||
218 | ARRAY_SIZE(wm1133_ev1_widgets)); | ||
219 | |||
220 | snd_soc_dapm_add_routes(dapm, wm1133_ev1_map, | ||
221 | ARRAY_SIZE(wm1133_ev1_map)); | ||
222 | |||
223 | /* Headphone jack detection */ | 217 | /* Headphone jack detection */ |
224 | snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); | 218 | snd_soc_jack_new(codec, "Headphone", SND_JACK_HEADPHONE, &hp_jack); |
225 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), | 219 | snd_soc_jack_add_pins(&hp_jack, ARRAY_SIZE(hp_jack_pins), |
@@ -257,6 +251,11 @@ static struct snd_soc_card wm1133_ev1 = { | |||
257 | .owner = THIS_MODULE, | 251 | .owner = THIS_MODULE, |
258 | .dai_link = &wm1133_ev1_dai, | 252 | .dai_link = &wm1133_ev1_dai, |
259 | .num_links = 1, | 253 | .num_links = 1, |
254 | |||
255 | .dapm_widgets = wm1133_ev1_widgets, | ||
256 | .num_dapm_widgets = ARRAY_SIZE(wm1133_ev1_widgets), | ||
257 | .dapm_routes = wm1133_ev1_map, | ||
258 | .num_dapm_routes = ARRAY_SIZE(wm1133_ev1_map), | ||
260 | }; | 259 | }; |
261 | 260 | ||
262 | static struct platform_device *wm1133_ev1_snd_device; | 261 | static struct platform_device *wm1133_ev1_snd_device; |
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 61c10bf503d2..4577b69fcf2c 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig | |||
@@ -2,12 +2,50 @@ config SND_MFLD_MACHINE | |||
2 | tristate "SOC Machine Audio driver for Intel Medfield MID platform" | 2 | tristate "SOC Machine Audio driver for Intel Medfield MID platform" |
3 | depends on INTEL_SCU_IPC | 3 | depends on INTEL_SCU_IPC |
4 | select SND_SOC_SN95031 | 4 | select SND_SOC_SN95031 |
5 | select SND_SST_PLATFORM | 5 | select SND_SST_MFLD_PLATFORM |
6 | help | 6 | help |
7 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform | 7 | This adds support for ASoC machine driver for Intel(R) MID Medfield platform |
8 | used as alsa device in audio substem in Intel(R) MID devices | 8 | used as alsa device in audio substem in Intel(R) MID devices |
9 | Say Y if you have such a device | 9 | Say Y if you have such a device |
10 | If unsure select "N". | 10 | If unsure select "N". |
11 | 11 | ||
12 | config SND_SST_PLATFORM | 12 | config SND_SST_MFLD_PLATFORM |
13 | tristate | 13 | tristate |
14 | |||
15 | config SND_SOC_INTEL_SST | ||
16 | tristate "ASoC support for Intel(R) Smart Sound Technology" | ||
17 | select SND_SOC_INTEL_SST_ACPI if ACPI | ||
18 | depends on (X86 || COMPILE_TEST) | ||
19 | help | ||
20 | This adds support for Intel(R) Smart Sound Technology (SST). | ||
21 | Say Y if you have such a device | ||
22 | If unsure select "N". | ||
23 | |||
24 | config SND_SOC_INTEL_SST_ACPI | ||
25 | tristate | ||
26 | |||
27 | config SND_SOC_INTEL_HASWELL | ||
28 | tristate | ||
29 | |||
30 | config SND_SOC_INTEL_BAYTRAIL | ||
31 | tristate | ||
32 | |||
33 | config SND_SOC_INTEL_HASWELL_MACH | ||
34 | tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" | ||
35 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS | ||
36 | select SND_SOC_INTEL_HASWELL | ||
37 | select SND_SOC_RT5640 | ||
38 | help | ||
39 | This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell | ||
40 | Ultrabook platforms. | ||
41 | Say Y if you have such a device | ||
42 | If unsure select "N". | ||
43 | |||
44 | config SND_SOC_INTEL_BYT_RT5640_MACH | ||
45 | tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" | ||
46 | depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS | ||
47 | select SND_SOC_INTEL_BAYTRAIL | ||
48 | select SND_SOC_RT5640 | ||
49 | help | ||
50 | This adds audio driver for Intel Baytrail platform based boards | ||
51 | with the RT5640 audio codec. | ||
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 639883339465..edeb79ae3dff 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile | |||
@@ -1,5 +1,28 @@ | |||
1 | snd-soc-sst-platform-objs := sst_platform.o | 1 | # Core support |
2 | snd-soc-sst-dsp-objs := sst-dsp.o sst-firmware.o | ||
3 | snd-soc-sst-acpi-objs := sst-acpi.o | ||
4 | |||
5 | snd-soc-sst-mfld-platform-objs := sst-mfld-platform.o | ||
2 | snd-soc-mfld-machine-objs := mfld_machine.o | 6 | snd-soc-mfld-machine-objs := mfld_machine.o |
3 | 7 | ||
4 | obj-$(CONFIG_SND_SST_PLATFORM) += snd-soc-sst-platform.o | 8 | obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += snd-soc-sst-mfld-platform.o |
5 | obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o | 9 | obj-$(CONFIG_SND_MFLD_MACHINE) += snd-soc-mfld-machine.o |
10 | |||
11 | obj-$(CONFIG_SND_SOC_INTEL_SST) += snd-soc-sst-dsp.o | ||
12 | obj-$(CONFIG_SND_SOC_INTEL_SST_ACPI) += snd-soc-sst-acpi.o | ||
13 | |||
14 | # Platform Support | ||
15 | snd-soc-sst-haswell-pcm-objs := \ | ||
16 | sst-haswell-ipc.o sst-haswell-pcm.o sst-haswell-dsp.o | ||
17 | snd-soc-sst-baytrail-pcm-objs := \ | ||
18 | sst-baytrail-ipc.o sst-baytrail-pcm.o sst-baytrail-dsp.o | ||
19 | |||
20 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += snd-soc-sst-haswell-pcm.o | ||
21 | obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += snd-soc-sst-baytrail-pcm.o | ||
22 | |||
23 | # Machine support | ||
24 | snd-soc-sst-haswell-objs := haswell.o | ||
25 | snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o | ||
26 | |||
27 | obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o | ||
28 | obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o | ||
diff --git a/sound/soc/intel/byt-rt5640.c b/sound/soc/intel/byt-rt5640.c new file mode 100644 index 000000000000..eff97c8e5218 --- /dev/null +++ b/sound/soc/intel/byt-rt5640.c | |||
@@ -0,0 +1,187 @@ | |||
1 | /* | ||
2 | * Intel Baytrail SST RT5640 machine driver | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/acpi.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <sound/pcm.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | #include <sound/soc.h> | ||
24 | #include <sound/jack.h> | ||
25 | #include "../codecs/rt5640.h" | ||
26 | |||
27 | #include "sst-dsp.h" | ||
28 | |||
29 | static const struct snd_soc_dapm_widget byt_rt5640_widgets[] = { | ||
30 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
31 | SND_SOC_DAPM_MIC("Headset Mic", NULL), | ||
32 | SND_SOC_DAPM_MIC("Internal Mic", NULL), | ||
33 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
34 | }; | ||
35 | |||
36 | static const struct snd_soc_dapm_route byt_rt5640_audio_map[] = { | ||
37 | {"IN2P", NULL, "Headset Mic"}, | ||
38 | {"IN2N", NULL, "Headset Mic"}, | ||
39 | {"DMIC1", NULL, "Internal Mic"}, | ||
40 | {"Headphone", NULL, "HPOL"}, | ||
41 | {"Headphone", NULL, "HPOR"}, | ||
42 | {"Speaker", NULL, "SPOLP"}, | ||
43 | {"Speaker", NULL, "SPOLN"}, | ||
44 | {"Speaker", NULL, "SPORP"}, | ||
45 | {"Speaker", NULL, "SPORN"}, | ||
46 | }; | ||
47 | |||
48 | static const struct snd_kcontrol_new byt_rt5640_controls[] = { | ||
49 | SOC_DAPM_PIN_SWITCH("Headphone"), | ||
50 | SOC_DAPM_PIN_SWITCH("Headset Mic"), | ||
51 | SOC_DAPM_PIN_SWITCH("Internal Mic"), | ||
52 | SOC_DAPM_PIN_SWITCH("Speaker"), | ||
53 | }; | ||
54 | |||
55 | static int byt_rt5640_hw_params(struct snd_pcm_substream *substream, | ||
56 | struct snd_pcm_hw_params *params) | ||
57 | { | ||
58 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
59 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
60 | int ret; | ||
61 | |||
62 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1, | ||
63 | params_rate(params) * 256, | ||
64 | SND_SOC_CLOCK_IN); | ||
65 | if (ret < 0) { | ||
66 | dev_err(codec_dai->dev, "can't set codec clock %d\n", ret); | ||
67 | return ret; | ||
68 | } | ||
69 | ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1, | ||
70 | params_rate(params) * 64, | ||
71 | params_rate(params) * 256); | ||
72 | if (ret < 0) { | ||
73 | dev_err(codec_dai->dev, "can't set codec pll: %d\n", ret); | ||
74 | return ret; | ||
75 | } | ||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int byt_rt5640_init(struct snd_soc_pcm_runtime *runtime) | ||
80 | { | ||
81 | int ret; | ||
82 | struct snd_soc_codec *codec = runtime->codec; | ||
83 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
84 | struct snd_soc_card *card = runtime->card; | ||
85 | |||
86 | card->dapm.idle_bias_off = true; | ||
87 | |||
88 | ret = snd_soc_add_card_controls(card, byt_rt5640_controls, | ||
89 | ARRAY_SIZE(byt_rt5640_controls)); | ||
90 | if (ret) { | ||
91 | dev_err(card->dev, "unable to add card controls\n"); | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | snd_soc_dapm_ignore_suspend(dapm, "HPOL"); | ||
96 | snd_soc_dapm_ignore_suspend(dapm, "HPOR"); | ||
97 | |||
98 | snd_soc_dapm_ignore_suspend(dapm, "SPOLP"); | ||
99 | snd_soc_dapm_ignore_suspend(dapm, "SPOLN"); | ||
100 | snd_soc_dapm_ignore_suspend(dapm, "SPORP"); | ||
101 | snd_soc_dapm_ignore_suspend(dapm, "SPORN"); | ||
102 | |||
103 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | ||
104 | snd_soc_dapm_enable_pin(dapm, "Headphone"); | ||
105 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | ||
106 | snd_soc_dapm_enable_pin(dapm, "Internal Mic"); | ||
107 | |||
108 | snd_soc_dapm_sync(dapm); | ||
109 | return ret; | ||
110 | } | ||
111 | |||
112 | static struct snd_soc_ops byt_rt5640_ops = { | ||
113 | .hw_params = byt_rt5640_hw_params, | ||
114 | }; | ||
115 | |||
116 | static struct snd_soc_dai_link byt_rt5640_dais[] = { | ||
117 | { | ||
118 | .name = "Baytrail Audio", | ||
119 | .stream_name = "Audio", | ||
120 | .cpu_dai_name = "Front-cpu-dai", | ||
121 | .codec_dai_name = "rt5640-aif1", | ||
122 | .codec_name = "i2c-10EC5640:00", | ||
123 | .platform_name = "baytrail-pcm-audio", | ||
124 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
125 | SND_SOC_DAIFMT_CBS_CFS, | ||
126 | .init = byt_rt5640_init, | ||
127 | .ignore_suspend = 1, | ||
128 | .ops = &byt_rt5640_ops, | ||
129 | }, | ||
130 | { | ||
131 | .name = "Baytrail Voice", | ||
132 | .stream_name = "Voice", | ||
133 | .cpu_dai_name = "Mic1-cpu-dai", | ||
134 | .codec_dai_name = "rt5640-aif1", | ||
135 | .codec_name = "i2c-10EC5640:00", | ||
136 | .platform_name = "baytrail-pcm-audio", | ||
137 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
138 | SND_SOC_DAIFMT_CBS_CFS, | ||
139 | .init = NULL, | ||
140 | .ignore_suspend = 1, | ||
141 | .ops = &byt_rt5640_ops, | ||
142 | }, | ||
143 | }; | ||
144 | |||
145 | static struct snd_soc_card byt_rt5640_card = { | ||
146 | .name = "byt-rt5640", | ||
147 | .dai_link = byt_rt5640_dais, | ||
148 | .num_links = ARRAY_SIZE(byt_rt5640_dais), | ||
149 | .dapm_widgets = byt_rt5640_widgets, | ||
150 | .num_dapm_widgets = ARRAY_SIZE(byt_rt5640_widgets), | ||
151 | .dapm_routes = byt_rt5640_audio_map, | ||
152 | .num_dapm_routes = ARRAY_SIZE(byt_rt5640_audio_map), | ||
153 | }; | ||
154 | |||
155 | static int byt_rt5640_probe(struct platform_device *pdev) | ||
156 | { | ||
157 | struct snd_soc_card *card = &byt_rt5640_card; | ||
158 | struct device *dev = &pdev->dev; | ||
159 | |||
160 | card->dev = &pdev->dev; | ||
161 | dev_set_drvdata(dev, card); | ||
162 | return snd_soc_register_card(card); | ||
163 | } | ||
164 | |||
165 | static int byt_rt5640_remove(struct platform_device *pdev) | ||
166 | { | ||
167 | struct snd_soc_card *card = platform_get_drvdata(pdev); | ||
168 | |||
169 | snd_soc_unregister_card(card); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static struct platform_driver byt_rt5640_audio = { | ||
175 | .probe = byt_rt5640_probe, | ||
176 | .remove = byt_rt5640_remove, | ||
177 | .driver = { | ||
178 | .name = "byt-rt5640", | ||
179 | .owner = THIS_MODULE, | ||
180 | }, | ||
181 | }; | ||
182 | module_platform_driver(byt_rt5640_audio) | ||
183 | |||
184 | MODULE_DESCRIPTION("ASoC Intel(R) Baytrail Machine driver"); | ||
185 | MODULE_AUTHOR("Omair Md Abdullah, Jarkko Nikula"); | ||
186 | MODULE_LICENSE("GPL v2"); | ||
187 | MODULE_ALIAS("platform:byt-rt5640"); | ||
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c new file mode 100644 index 000000000000..54345a2a7386 --- /dev/null +++ b/sound/soc/intel/haswell.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * Intel Haswell Lynxpoint SST Audio | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | #include <sound/core.h> | ||
20 | #include <sound/pcm.h> | ||
21 | #include <sound/soc.h> | ||
22 | #include <sound/pcm_params.h> | ||
23 | |||
24 | #include "sst-dsp.h" | ||
25 | #include "sst-haswell-ipc.h" | ||
26 | |||
27 | #include "../codecs/rt5640.h" | ||
28 | |||
29 | /* Haswell ULT platforms have a Headphone and Mic jack */ | ||
30 | static const struct snd_soc_dapm_widget haswell_widgets[] = { | ||
31 | SND_SOC_DAPM_HP("Headphones", NULL), | ||
32 | SND_SOC_DAPM_MIC("Mic", NULL), | ||
33 | }; | ||
34 | |||
35 | static const struct snd_soc_dapm_route haswell_rt5640_map[] = { | ||
36 | |||
37 | {"Headphones", NULL, "HPOR"}, | ||
38 | {"Headphones", NULL, "HPOL"}, | ||
39 | {"IN2P", NULL, "Mic"}, | ||
40 | |||
41 | /* CODEC BE connections */ | ||
42 | {"SSP0 CODEC IN", NULL, "AIF1 Capture"}, | ||
43 | {"AIF1 Playback", NULL, "SSP0 CODEC OUT"}, | ||
44 | }; | ||
45 | |||
46 | static int haswell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd, | ||
47 | struct snd_pcm_hw_params *params) | ||
48 | { | ||
49 | struct snd_interval *rate = hw_param_interval(params, | ||
50 | SNDRV_PCM_HW_PARAM_RATE); | ||
51 | struct snd_interval *channels = hw_param_interval(params, | ||
52 | SNDRV_PCM_HW_PARAM_CHANNELS); | ||
53 | |||
54 | /* The ADSP will covert the FE rate to 48k, stereo */ | ||
55 | rate->min = rate->max = 48000; | ||
56 | channels->min = channels->max = 2; | ||
57 | |||
58 | /* set SSP0 to 16 bit */ | ||
59 | snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - | ||
60 | SNDRV_PCM_HW_PARAM_FIRST_MASK], | ||
61 | SNDRV_PCM_FORMAT_S16_LE); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int haswell_rt5640_hw_params(struct snd_pcm_substream *substream, | ||
66 | struct snd_pcm_hw_params *params) | ||
67 | { | ||
68 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
69 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
70 | int ret; | ||
71 | |||
72 | ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_MCLK, 12288000, | ||
73 | SND_SOC_CLOCK_IN); | ||
74 | |||
75 | if (ret < 0) { | ||
76 | dev_err(rtd->dev, "can't set codec sysclk configuration\n"); | ||
77 | return ret; | ||
78 | } | ||
79 | |||
80 | /* set correct codec filter for DAI format and clock config */ | ||
81 | snd_soc_update_bits(rtd->codec, 0x83, 0xffff, 0x8000); | ||
82 | |||
83 | return ret; | ||
84 | } | ||
85 | |||
86 | static struct snd_soc_ops haswell_rt5640_ops = { | ||
87 | .hw_params = haswell_rt5640_hw_params, | ||
88 | }; | ||
89 | |||
90 | static int haswell_rtd_init(struct snd_soc_pcm_runtime *rtd) | ||
91 | { | ||
92 | struct snd_soc_codec *codec = rtd->codec; | ||
93 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
94 | struct sst_pdata *pdata = dev_get_platdata(rtd->platform->dev); | ||
95 | struct sst_hsw *haswell = pdata->dsp; | ||
96 | int ret; | ||
97 | |||
98 | /* Set ADSP SSP port settings */ | ||
99 | ret = sst_hsw_device_set_config(haswell, SST_HSW_DEVICE_SSP_0, | ||
100 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ, | ||
101 | SST_HSW_DEVICE_CLOCK_MASTER, 9); | ||
102 | if (ret < 0) { | ||
103 | dev_err(rtd->dev, "failed to set device config\n"); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | /* always connected */ | ||
108 | snd_soc_dapm_enable_pin(dapm, "Headphones"); | ||
109 | snd_soc_dapm_enable_pin(dapm, "Mic"); | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static struct snd_soc_dai_link haswell_rt5640_dais[] = { | ||
115 | /* Front End DAI links */ | ||
116 | { | ||
117 | .name = "System", | ||
118 | .stream_name = "System Playback", | ||
119 | .cpu_dai_name = "System Pin", | ||
120 | .platform_name = "haswell-pcm-audio", | ||
121 | .dynamic = 1, | ||
122 | .codec_name = "snd-soc-dummy", | ||
123 | .codec_dai_name = "snd-soc-dummy-dai", | ||
124 | .init = haswell_rtd_init, | ||
125 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
126 | .dpcm_playback = 1, | ||
127 | }, | ||
128 | { | ||
129 | .name = "Offload0", | ||
130 | .stream_name = "Offload0 Playback", | ||
131 | .cpu_dai_name = "Offload0 Pin", | ||
132 | .platform_name = "haswell-pcm-audio", | ||
133 | .dynamic = 1, | ||
134 | .codec_name = "snd-soc-dummy", | ||
135 | .codec_dai_name = "snd-soc-dummy-dai", | ||
136 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
137 | .dpcm_playback = 1, | ||
138 | }, | ||
139 | { | ||
140 | .name = "Offload1", | ||
141 | .stream_name = "Offload1 Playback", | ||
142 | .cpu_dai_name = "Offload1 Pin", | ||
143 | .platform_name = "haswell-pcm-audio", | ||
144 | .dynamic = 1, | ||
145 | .codec_name = "snd-soc-dummy", | ||
146 | .codec_dai_name = "snd-soc-dummy-dai", | ||
147 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
148 | .dpcm_playback = 1, | ||
149 | }, | ||
150 | { | ||
151 | .name = "Loopback", | ||
152 | .stream_name = "Loopback", | ||
153 | .cpu_dai_name = "Loopback Pin", | ||
154 | .platform_name = "haswell-pcm-audio", | ||
155 | .dynamic = 0, | ||
156 | .codec_name = "snd-soc-dummy", | ||
157 | .codec_dai_name = "snd-soc-dummy-dai", | ||
158 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
159 | .dpcm_capture = 1, | ||
160 | }, | ||
161 | { | ||
162 | .name = "Capture", | ||
163 | .stream_name = "Capture", | ||
164 | .cpu_dai_name = "Capture Pin", | ||
165 | .platform_name = "haswell-pcm-audio", | ||
166 | .dynamic = 1, | ||
167 | .codec_name = "snd-soc-dummy", | ||
168 | .codec_dai_name = "snd-soc-dummy-dai", | ||
169 | .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST}, | ||
170 | .dpcm_capture = 1, | ||
171 | }, | ||
172 | |||
173 | /* Back End DAI links */ | ||
174 | { | ||
175 | /* SSP0 - Codec */ | ||
176 | .name = "Codec", | ||
177 | .be_id = 0, | ||
178 | .cpu_dai_name = "snd-soc-dummy-dai", | ||
179 | .platform_name = "snd-soc-dummy", | ||
180 | .no_pcm = 1, | ||
181 | .codec_name = "i2c-INT33CA:00", | ||
182 | .codec_dai_name = "rt5640-aif1", | ||
183 | .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | | ||
184 | SND_SOC_DAIFMT_CBS_CFS, | ||
185 | .ignore_suspend = 1, | ||
186 | .ignore_pmdown_time = 1, | ||
187 | .be_hw_params_fixup = haswell_ssp0_fixup, | ||
188 | .ops = &haswell_rt5640_ops, | ||
189 | .dpcm_playback = 1, | ||
190 | .dpcm_capture = 1, | ||
191 | }, | ||
192 | }; | ||
193 | |||
194 | /* audio machine driver for Haswell Lynxpoint DSP + RT5640 */ | ||
195 | static struct snd_soc_card haswell_rt5640 = { | ||
196 | .name = "haswell-rt5640", | ||
197 | .owner = THIS_MODULE, | ||
198 | .dai_link = haswell_rt5640_dais, | ||
199 | .num_links = ARRAY_SIZE(haswell_rt5640_dais), | ||
200 | .dapm_widgets = haswell_widgets, | ||
201 | .num_dapm_widgets = ARRAY_SIZE(haswell_widgets), | ||
202 | .dapm_routes = haswell_rt5640_map, | ||
203 | .num_dapm_routes = ARRAY_SIZE(haswell_rt5640_map), | ||
204 | .fully_routed = true, | ||
205 | }; | ||
206 | |||
207 | static int haswell_audio_probe(struct platform_device *pdev) | ||
208 | { | ||
209 | haswell_rt5640.dev = &pdev->dev; | ||
210 | |||
211 | return snd_soc_register_card(&haswell_rt5640); | ||
212 | } | ||
213 | |||
214 | static int haswell_audio_remove(struct platform_device *pdev) | ||
215 | { | ||
216 | snd_soc_unregister_card(&haswell_rt5640); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static struct platform_driver haswell_audio = { | ||
221 | .probe = haswell_audio_probe, | ||
222 | .remove = haswell_audio_remove, | ||
223 | .driver = { | ||
224 | .name = "haswell-audio", | ||
225 | .owner = THIS_MODULE, | ||
226 | }, | ||
227 | }; | ||
228 | |||
229 | module_platform_driver(haswell_audio) | ||
230 | |||
231 | /* Module information */ | ||
232 | MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); | ||
233 | MODULE_DESCRIPTION("Intel SST Audio for Haswell Lynxpoint"); | ||
234 | MODULE_LICENSE("GPL v2"); | ||
235 | MODULE_ALIAS("platform:haswell-audio"); | ||
diff --git a/sound/soc/intel/mfld_machine.c b/sound/soc/intel/mfld_machine.c index d3d4c32434f7..0cef32e9d402 100644 --- a/sound/soc/intel/mfld_machine.c +++ b/sound/soc/intel/mfld_machine.c | |||
@@ -101,20 +101,27 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol, | |||
101 | struct snd_ctl_elem_value *ucontrol) | 101 | struct snd_ctl_elem_value *ucontrol) |
102 | { | 102 | { |
103 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 103 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
104 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
104 | 105 | ||
105 | if (ucontrol->value.integer.value[0] == hs_switch) | 106 | if (ucontrol->value.integer.value[0] == hs_switch) |
106 | return 0; | 107 | return 0; |
107 | 108 | ||
109 | snd_soc_dapm_mutex_lock(dapm); | ||
110 | |||
108 | if (ucontrol->value.integer.value[0]) { | 111 | if (ucontrol->value.integer.value[0]) { |
109 | pr_debug("hs_set HS path\n"); | 112 | pr_debug("hs_set HS path\n"); |
110 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | 113 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); |
111 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 114 | snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); |
112 | } else { | 115 | } else { |
113 | pr_debug("hs_set EP path\n"); | 116 | pr_debug("hs_set EP path\n"); |
114 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 117 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); |
115 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | 118 | snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); |
116 | } | 119 | } |
117 | snd_soc_dapm_sync(&codec->dapm); | 120 | |
121 | snd_soc_dapm_sync_unlocked(dapm); | ||
122 | |||
123 | snd_soc_dapm_mutex_unlock(dapm); | ||
124 | |||
118 | hs_switch = ucontrol->value.integer.value[0]; | 125 | hs_switch = ucontrol->value.integer.value[0]; |
119 | 126 | ||
120 | return 0; | 127 | return 0; |
@@ -122,18 +129,20 @@ static int headset_set_switch(struct snd_kcontrol *kcontrol, | |||
122 | 129 | ||
123 | static void lo_enable_out_pins(struct snd_soc_codec *codec) | 130 | static void lo_enable_out_pins(struct snd_soc_codec *codec) |
124 | { | 131 | { |
125 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTL"); | 132 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
126 | snd_soc_dapm_enable_pin(&codec->dapm, "IHFOUTR"); | 133 | |
127 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTL"); | 134 | snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTL"); |
128 | snd_soc_dapm_enable_pin(&codec->dapm, "LINEOUTR"); | 135 | snd_soc_dapm_enable_pin_unlocked(dapm, "IHFOUTR"); |
129 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB1OUT"); | 136 | snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTL"); |
130 | snd_soc_dapm_enable_pin(&codec->dapm, "VIB2OUT"); | 137 | snd_soc_dapm_enable_pin_unlocked(dapm, "LINEOUTR"); |
138 | snd_soc_dapm_enable_pin_unlocked(dapm, "VIB1OUT"); | ||
139 | snd_soc_dapm_enable_pin_unlocked(dapm, "VIB2OUT"); | ||
131 | if (hs_switch) { | 140 | if (hs_switch) { |
132 | snd_soc_dapm_enable_pin(&codec->dapm, "Headphones"); | 141 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphones"); |
133 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 142 | snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); |
134 | } else { | 143 | } else { |
135 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 144 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); |
136 | snd_soc_dapm_enable_pin(&codec->dapm, "EPOUT"); | 145 | snd_soc_dapm_enable_pin_unlocked(dapm, "EPOUT"); |
137 | } | 146 | } |
138 | } | 147 | } |
139 | 148 | ||
@@ -148,44 +157,52 @@ static int lo_set_switch(struct snd_kcontrol *kcontrol, | |||
148 | struct snd_ctl_elem_value *ucontrol) | 157 | struct snd_ctl_elem_value *ucontrol) |
149 | { | 158 | { |
150 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 159 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
160 | struct snd_soc_dapm_context *dapm = &codec->dapm; | ||
151 | 161 | ||
152 | if (ucontrol->value.integer.value[0] == lo_dac) | 162 | if (ucontrol->value.integer.value[0] == lo_dac) |
153 | return 0; | 163 | return 0; |
154 | 164 | ||
165 | snd_soc_dapm_mutex_lock(dapm); | ||
166 | |||
155 | /* we dont want to work with last state of lineout so just enable all | 167 | /* we dont want to work with last state of lineout so just enable all |
156 | * pins and then disable pins not required | 168 | * pins and then disable pins not required |
157 | */ | 169 | */ |
158 | lo_enable_out_pins(codec); | 170 | lo_enable_out_pins(codec); |
171 | |||
159 | switch (ucontrol->value.integer.value[0]) { | 172 | switch (ucontrol->value.integer.value[0]) { |
160 | case 0: | 173 | case 0: |
161 | pr_debug("set vibra path\n"); | 174 | pr_debug("set vibra path\n"); |
162 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB1OUT"); | 175 | snd_soc_dapm_disable_pin_unlocked(dapm, "VIB1OUT"); |
163 | snd_soc_dapm_disable_pin(&codec->dapm, "VIB2OUT"); | 176 | snd_soc_dapm_disable_pin_unlocked(dapm, "VIB2OUT"); |
164 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); | 177 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0); |
165 | break; | 178 | break; |
166 | 179 | ||
167 | case 1: | 180 | case 1: |
168 | pr_debug("set hs path\n"); | 181 | pr_debug("set hs path\n"); |
169 | snd_soc_dapm_disable_pin(&codec->dapm, "Headphones"); | 182 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphones"); |
170 | snd_soc_dapm_disable_pin(&codec->dapm, "EPOUT"); | 183 | snd_soc_dapm_disable_pin_unlocked(dapm, "EPOUT"); |
171 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); | 184 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x22); |
172 | break; | 185 | break; |
173 | 186 | ||
174 | case 2: | 187 | case 2: |
175 | pr_debug("set spkr path\n"); | 188 | pr_debug("set spkr path\n"); |
176 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTL"); | 189 | snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTL"); |
177 | snd_soc_dapm_disable_pin(&codec->dapm, "IHFOUTR"); | 190 | snd_soc_dapm_disable_pin_unlocked(dapm, "IHFOUTR"); |
178 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); | 191 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x44); |
179 | break; | 192 | break; |
180 | 193 | ||
181 | case 3: | 194 | case 3: |
182 | pr_debug("set null path\n"); | 195 | pr_debug("set null path\n"); |
183 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTL"); | 196 | snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTL"); |
184 | snd_soc_dapm_disable_pin(&codec->dapm, "LINEOUTR"); | 197 | snd_soc_dapm_disable_pin_unlocked(dapm, "LINEOUTR"); |
185 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); | 198 | snd_soc_update_bits(codec, SN95031_LOCTL, 0x66, 0x66); |
186 | break; | 199 | break; |
187 | } | 200 | } |
188 | snd_soc_dapm_sync(&codec->dapm); | 201 | |
202 | snd_soc_dapm_sync_unlocked(dapm); | ||
203 | |||
204 | snd_soc_dapm_mutex_unlock(dapm); | ||
205 | |||
189 | lo_dac = ucontrol->value.integer.value[0]; | 206 | lo_dac = ucontrol->value.integer.value[0]; |
190 | return 0; | 207 | return 0; |
191 | } | 208 | } |
diff --git a/sound/soc/intel/sst-acpi.c b/sound/soc/intel/sst-acpi.c new file mode 100644 index 000000000000..5d06eecb6198 --- /dev/null +++ b/sound/soc/intel/sst-acpi.c | |||
@@ -0,0 +1,284 @@ | |||
1 | /* | ||
2 | * Intel SST loader on ACPI systems | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/acpi.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/firmware.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | |||
23 | #include "sst-dsp.h" | ||
24 | |||
25 | #define SST_LPT_DSP_DMA_ADDR_OFFSET 0x0F0000 | ||
26 | #define SST_WPT_DSP_DMA_ADDR_OFFSET 0x0FE000 | ||
27 | #define SST_LPT_DSP_DMA_SIZE (1024 - 1) | ||
28 | |||
29 | /* Descriptor for SST ASoC machine driver */ | ||
30 | struct sst_acpi_mach { | ||
31 | /* ACPI ID for the matching machine driver. Audio codec for instance */ | ||
32 | const u8 id[ACPI_ID_LEN]; | ||
33 | /* machine driver name */ | ||
34 | const char *drv_name; | ||
35 | /* firmware file name */ | ||
36 | const char *fw_filename; | ||
37 | }; | ||
38 | |||
39 | /* Descriptor for setting up SST platform data */ | ||
40 | struct sst_acpi_desc { | ||
41 | const char *drv_name; | ||
42 | struct sst_acpi_mach *machines; | ||
43 | /* Platform resource indexes. Must set to -1 if not used */ | ||
44 | int resindex_lpe_base; | ||
45 | int resindex_pcicfg_base; | ||
46 | int resindex_fw_base; | ||
47 | int irqindex_host_ipc; | ||
48 | int resindex_dma_base; | ||
49 | /* Unique number identifying the SST core on platform */ | ||
50 | int sst_id; | ||
51 | /* DMA only valid when resindex_dma_base != -1*/ | ||
52 | int dma_engine; | ||
53 | int dma_size; | ||
54 | }; | ||
55 | |||
56 | struct sst_acpi_priv { | ||
57 | struct platform_device *pdev_mach; | ||
58 | struct platform_device *pdev_pcm; | ||
59 | struct sst_pdata sst_pdata; | ||
60 | struct sst_acpi_desc *desc; | ||
61 | struct sst_acpi_mach *mach; | ||
62 | }; | ||
63 | |||
64 | static void sst_acpi_fw_cb(const struct firmware *fw, void *context) | ||
65 | { | ||
66 | struct platform_device *pdev = context; | ||
67 | struct device *dev = &pdev->dev; | ||
68 | struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev); | ||
69 | struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata; | ||
70 | struct sst_acpi_desc *desc = sst_acpi->desc; | ||
71 | struct sst_acpi_mach *mach = sst_acpi->mach; | ||
72 | |||
73 | sst_pdata->fw = fw; | ||
74 | if (!fw) { | ||
75 | dev_err(dev, "Cannot load firmware %s\n", mach->fw_filename); | ||
76 | return; | ||
77 | } | ||
78 | |||
79 | /* register PCM and DAI driver */ | ||
80 | sst_acpi->pdev_pcm = | ||
81 | platform_device_register_data(dev, desc->drv_name, -1, | ||
82 | sst_pdata, sizeof(*sst_pdata)); | ||
83 | if (IS_ERR(sst_acpi->pdev_pcm)) { | ||
84 | dev_err(dev, "Cannot register device %s. Error %d\n", | ||
85 | desc->drv_name, (int)PTR_ERR(sst_acpi->pdev_pcm)); | ||
86 | } | ||
87 | |||
88 | return; | ||
89 | } | ||
90 | |||
91 | static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level, | ||
92 | void *context, void **ret) | ||
93 | { | ||
94 | *(bool *)context = true; | ||
95 | return AE_OK; | ||
96 | } | ||
97 | |||
98 | static struct sst_acpi_mach *sst_acpi_find_machine( | ||
99 | struct sst_acpi_mach *machines) | ||
100 | { | ||
101 | struct sst_acpi_mach *mach; | ||
102 | bool found = false; | ||
103 | |||
104 | for (mach = machines; mach->id[0]; mach++) | ||
105 | if (ACPI_SUCCESS(acpi_get_devices(mach->id, | ||
106 | sst_acpi_mach_match, | ||
107 | &found, NULL)) && found) | ||
108 | return mach; | ||
109 | |||
110 | return NULL; | ||
111 | } | ||
112 | |||
113 | static int sst_acpi_probe(struct platform_device *pdev) | ||
114 | { | ||
115 | const struct acpi_device_id *id; | ||
116 | struct device *dev = &pdev->dev; | ||
117 | struct sst_acpi_priv *sst_acpi; | ||
118 | struct sst_pdata *sst_pdata; | ||
119 | struct sst_acpi_mach *mach; | ||
120 | struct sst_acpi_desc *desc; | ||
121 | struct resource *mmio; | ||
122 | int ret = 0; | ||
123 | |||
124 | sst_acpi = devm_kzalloc(dev, sizeof(*sst_acpi), GFP_KERNEL); | ||
125 | if (sst_acpi == NULL) | ||
126 | return -ENOMEM; | ||
127 | |||
128 | id = acpi_match_device(dev->driver->acpi_match_table, dev); | ||
129 | if (!id) | ||
130 | return -ENODEV; | ||
131 | |||
132 | desc = (struct sst_acpi_desc *)id->driver_data; | ||
133 | mach = sst_acpi_find_machine(desc->machines); | ||
134 | if (mach == NULL) { | ||
135 | dev_err(dev, "No matching ASoC machine driver found\n"); | ||
136 | return -ENODEV; | ||
137 | } | ||
138 | |||
139 | sst_pdata = &sst_acpi->sst_pdata; | ||
140 | sst_pdata->id = desc->sst_id; | ||
141 | sst_acpi->desc = desc; | ||
142 | sst_acpi->mach = mach; | ||
143 | |||
144 | if (desc->resindex_dma_base >= 0) { | ||
145 | sst_pdata->dma_engine = desc->dma_engine; | ||
146 | sst_pdata->dma_base = desc->resindex_dma_base; | ||
147 | sst_pdata->dma_size = desc->dma_size; | ||
148 | } | ||
149 | |||
150 | if (desc->irqindex_host_ipc >= 0) | ||
151 | sst_pdata->irq = platform_get_irq(pdev, desc->irqindex_host_ipc); | ||
152 | |||
153 | if (desc->resindex_lpe_base >= 0) { | ||
154 | mmio = platform_get_resource(pdev, IORESOURCE_MEM, | ||
155 | desc->resindex_lpe_base); | ||
156 | if (mmio) { | ||
157 | sst_pdata->lpe_base = mmio->start; | ||
158 | sst_pdata->lpe_size = resource_size(mmio); | ||
159 | } | ||
160 | } | ||
161 | |||
162 | if (desc->resindex_pcicfg_base >= 0) { | ||
163 | mmio = platform_get_resource(pdev, IORESOURCE_MEM, | ||
164 | desc->resindex_pcicfg_base); | ||
165 | if (mmio) { | ||
166 | sst_pdata->pcicfg_base = mmio->start; | ||
167 | sst_pdata->pcicfg_size = resource_size(mmio); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | if (desc->resindex_fw_base >= 0) { | ||
172 | mmio = platform_get_resource(pdev, IORESOURCE_MEM, | ||
173 | desc->resindex_fw_base); | ||
174 | if (mmio) { | ||
175 | sst_pdata->fw_base = mmio->start; | ||
176 | sst_pdata->fw_size = resource_size(mmio); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | platform_set_drvdata(pdev, sst_acpi); | ||
181 | |||
182 | /* register machine driver */ | ||
183 | sst_acpi->pdev_mach = | ||
184 | platform_device_register_data(dev, mach->drv_name, -1, | ||
185 | sst_pdata, sizeof(*sst_pdata)); | ||
186 | if (IS_ERR(sst_acpi->pdev_mach)) | ||
187 | return PTR_ERR(sst_acpi->pdev_mach); | ||
188 | |||
189 | /* continue SST probing after firmware is loaded */ | ||
190 | ret = request_firmware_nowait(THIS_MODULE, true, mach->fw_filename, | ||
191 | dev, GFP_KERNEL, pdev, sst_acpi_fw_cb); | ||
192 | if (ret) | ||
193 | platform_device_unregister(sst_acpi->pdev_mach); | ||
194 | |||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | static int sst_acpi_remove(struct platform_device *pdev) | ||
199 | { | ||
200 | struct sst_acpi_priv *sst_acpi = platform_get_drvdata(pdev); | ||
201 | struct sst_pdata *sst_pdata = &sst_acpi->sst_pdata; | ||
202 | |||
203 | platform_device_unregister(sst_acpi->pdev_mach); | ||
204 | if (!IS_ERR_OR_NULL(sst_acpi->pdev_pcm)) | ||
205 | platform_device_unregister(sst_acpi->pdev_pcm); | ||
206 | release_firmware(sst_pdata->fw); | ||
207 | |||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static struct sst_acpi_mach haswell_machines[] = { | ||
212 | { "INT33CA", "haswell-audio", "intel/IntcSST1.bin" }, | ||
213 | {} | ||
214 | }; | ||
215 | |||
216 | static struct sst_acpi_desc sst_acpi_haswell_desc = { | ||
217 | .drv_name = "haswell-pcm-audio", | ||
218 | .machines = haswell_machines, | ||
219 | .resindex_lpe_base = 0, | ||
220 | .resindex_pcicfg_base = 1, | ||
221 | .resindex_fw_base = -1, | ||
222 | .irqindex_host_ipc = 0, | ||
223 | .sst_id = SST_DEV_ID_LYNX_POINT, | ||
224 | .dma_engine = SST_DMA_TYPE_DW, | ||
225 | .resindex_dma_base = SST_LPT_DSP_DMA_ADDR_OFFSET, | ||
226 | .dma_size = SST_LPT_DSP_DMA_SIZE, | ||
227 | }; | ||
228 | |||
229 | static struct sst_acpi_mach broadwell_machines[] = { | ||
230 | { "INT343A", "broadwell-audio", "intel/IntcSST2.bin" }, | ||
231 | {} | ||
232 | }; | ||
233 | |||
234 | static struct sst_acpi_desc sst_acpi_broadwell_desc = { | ||
235 | .drv_name = "haswell-pcm-audio", | ||
236 | .machines = broadwell_machines, | ||
237 | .resindex_lpe_base = 0, | ||
238 | .resindex_pcicfg_base = 1, | ||
239 | .resindex_fw_base = -1, | ||
240 | .irqindex_host_ipc = 0, | ||
241 | .sst_id = SST_DEV_ID_WILDCAT_POINT, | ||
242 | .dma_engine = SST_DMA_TYPE_DW, | ||
243 | .resindex_dma_base = SST_WPT_DSP_DMA_ADDR_OFFSET, | ||
244 | .dma_size = SST_LPT_DSP_DMA_SIZE, | ||
245 | }; | ||
246 | |||
247 | static struct sst_acpi_mach baytrail_machines[] = { | ||
248 | { "10EC5640", "byt-rt5640", "intel/fw_sst_0f28.bin-i2s_master" }, | ||
249 | {} | ||
250 | }; | ||
251 | |||
252 | static struct sst_acpi_desc sst_acpi_baytrail_desc = { | ||
253 | .drv_name = "baytrail-pcm-audio", | ||
254 | .machines = baytrail_machines, | ||
255 | .resindex_lpe_base = 0, | ||
256 | .resindex_pcicfg_base = 1, | ||
257 | .resindex_fw_base = 2, | ||
258 | .irqindex_host_ipc = 5, | ||
259 | .sst_id = SST_DEV_ID_BYT, | ||
260 | .resindex_dma_base = -1, | ||
261 | }; | ||
262 | |||
263 | static struct acpi_device_id sst_acpi_match[] = { | ||
264 | { "INT33C8", (unsigned long)&sst_acpi_haswell_desc }, | ||
265 | { "INT3438", (unsigned long)&sst_acpi_broadwell_desc }, | ||
266 | { "80860F28", (unsigned long)&sst_acpi_baytrail_desc }, | ||
267 | { } | ||
268 | }; | ||
269 | MODULE_DEVICE_TABLE(acpi, sst_acpi_match); | ||
270 | |||
271 | static struct platform_driver sst_acpi_driver = { | ||
272 | .probe = sst_acpi_probe, | ||
273 | .remove = sst_acpi_remove, | ||
274 | .driver = { | ||
275 | .name = "sst-acpi", | ||
276 | .owner = THIS_MODULE, | ||
277 | .acpi_match_table = ACPI_PTR(sst_acpi_match), | ||
278 | }, | ||
279 | }; | ||
280 | module_platform_driver(sst_acpi_driver); | ||
281 | |||
282 | MODULE_AUTHOR("Jarkko Nikula <jarkko.nikula@linux.intel.com>"); | ||
283 | MODULE_DESCRIPTION("Intel SST loader on ACPI systems"); | ||
284 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c new file mode 100644 index 000000000000..a50bf7fc0e3a --- /dev/null +++ b/sound/soc/intel/sst-baytrail-dsp.c | |||
@@ -0,0 +1,372 @@ | |||
1 | /* | ||
2 | * Intel Baytrail SST DSP driver | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/delay.h> | ||
16 | #include <linux/fs.h> | ||
17 | #include <linux/slab.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/dma-mapping.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/firmware.h> | ||
24 | |||
25 | #include "sst-dsp.h" | ||
26 | #include "sst-dsp-priv.h" | ||
27 | #include "sst-baytrail-ipc.h" | ||
28 | |||
29 | #define SST_BYT_FW_SIGNATURE_SIZE 4 | ||
30 | #define SST_BYT_FW_SIGN "$SST" | ||
31 | |||
32 | #define SST_BYT_IRAM_OFFSET 0xC0000 | ||
33 | #define SST_BYT_DRAM_OFFSET 0x100000 | ||
34 | #define SST_BYT_SHIM_OFFSET 0x140000 | ||
35 | |||
36 | enum sst_ram_type { | ||
37 | SST_BYT_IRAM = 1, | ||
38 | SST_BYT_DRAM = 2, | ||
39 | SST_BYT_CACHE = 3, | ||
40 | }; | ||
41 | |||
42 | struct dma_block_info { | ||
43 | enum sst_ram_type type; /* IRAM/DRAM */ | ||
44 | u32 size; /* Bytes */ | ||
45 | u32 ram_offset; /* Offset in I/DRAM */ | ||
46 | u32 rsvd; /* Reserved field */ | ||
47 | }; | ||
48 | |||
49 | struct fw_header { | ||
50 | unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE]; | ||
51 | u32 file_size; /* size of fw minus this header */ | ||
52 | u32 modules; /* # of modules */ | ||
53 | u32 file_format; /* version of header format */ | ||
54 | u32 reserved[4]; | ||
55 | }; | ||
56 | |||
57 | struct sst_byt_fw_module_header { | ||
58 | unsigned char signature[SST_BYT_FW_SIGNATURE_SIZE]; | ||
59 | u32 mod_size; /* size of module */ | ||
60 | u32 blocks; /* # of blocks */ | ||
61 | u32 type; /* codec type, pp lib */ | ||
62 | u32 entry_point; | ||
63 | }; | ||
64 | |||
65 | static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | ||
66 | struct sst_byt_fw_module_header *module) | ||
67 | { | ||
68 | struct dma_block_info *block; | ||
69 | struct sst_module *mod; | ||
70 | struct sst_module_data block_data; | ||
71 | struct sst_module_template template; | ||
72 | int count; | ||
73 | |||
74 | memset(&template, 0, sizeof(template)); | ||
75 | template.id = module->type; | ||
76 | template.entry = module->entry_point; | ||
77 | template.p.type = SST_MEM_DRAM; | ||
78 | template.p.data_type = SST_DATA_P; | ||
79 | template.s.type = SST_MEM_DRAM; | ||
80 | template.s.data_type = SST_DATA_S; | ||
81 | |||
82 | mod = sst_module_new(fw, &template, NULL); | ||
83 | if (mod == NULL) | ||
84 | return -ENOMEM; | ||
85 | |||
86 | block = (void *)module + sizeof(*module); | ||
87 | |||
88 | for (count = 0; count < module->blocks; count++) { | ||
89 | |||
90 | if (block->size <= 0) { | ||
91 | dev_err(dsp->dev, "block %d size invalid\n", count); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | switch (block->type) { | ||
96 | case SST_BYT_IRAM: | ||
97 | block_data.offset = block->ram_offset + | ||
98 | dsp->addr.iram_offset; | ||
99 | block_data.type = SST_MEM_IRAM; | ||
100 | break; | ||
101 | case SST_BYT_DRAM: | ||
102 | block_data.offset = block->ram_offset + | ||
103 | dsp->addr.dram_offset; | ||
104 | block_data.type = SST_MEM_DRAM; | ||
105 | break; | ||
106 | case SST_BYT_CACHE: | ||
107 | block_data.offset = block->ram_offset + | ||
108 | (dsp->addr.fw_ext - dsp->addr.lpe); | ||
109 | block_data.type = SST_MEM_CACHE; | ||
110 | break; | ||
111 | default: | ||
112 | dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n", | ||
113 | block->type, count); | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | |||
117 | block_data.size = block->size; | ||
118 | block_data.data_type = SST_DATA_M; | ||
119 | block_data.data = (void *)block + sizeof(*block); | ||
120 | |||
121 | sst_module_insert_fixed_block(mod, &block_data); | ||
122 | |||
123 | block = (void *)block + sizeof(*block) + block->size; | ||
124 | } | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int sst_byt_parse_fw_image(struct sst_fw *sst_fw) | ||
129 | { | ||
130 | struct fw_header *header; | ||
131 | struct sst_byt_fw_module_header *module; | ||
132 | struct sst_dsp *dsp = sst_fw->dsp; | ||
133 | int ret, count; | ||
134 | |||
135 | /* Read the header information from the data pointer */ | ||
136 | header = (struct fw_header *)sst_fw->dma_buf; | ||
137 | |||
138 | /* verify FW */ | ||
139 | if ((strncmp(header->signature, SST_BYT_FW_SIGN, 4) != 0) || | ||
140 | (sst_fw->size != header->file_size + sizeof(*header))) { | ||
141 | /* Invalid FW signature */ | ||
142 | dev_err(dsp->dev, "Invalid FW sign/filesize mismatch\n"); | ||
143 | return -EINVAL; | ||
144 | } | ||
145 | |||
146 | dev_dbg(dsp->dev, | ||
147 | "header sign=%4s size=0x%x modules=0x%x fmt=0x%x size=%zu\n", | ||
148 | header->signature, header->file_size, header->modules, | ||
149 | header->file_format, sizeof(*header)); | ||
150 | |||
151 | module = (void *)sst_fw->dma_buf + sizeof(*header); | ||
152 | for (count = 0; count < header->modules; count++) { | ||
153 | /* module */ | ||
154 | ret = sst_byt_parse_module(dsp, sst_fw, module); | ||
155 | if (ret < 0) { | ||
156 | dev_err(dsp->dev, "invalid module %d\n", count); | ||
157 | return ret; | ||
158 | } | ||
159 | module = (void *)module + sizeof(*module) + module->mod_size; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static void sst_byt_dump_shim(struct sst_dsp *sst) | ||
166 | { | ||
167 | int i; | ||
168 | u64 reg; | ||
169 | |||
170 | for (i = 0; i <= 0xF0; i += 8) { | ||
171 | reg = sst_dsp_shim_read64_unlocked(sst, i); | ||
172 | if (reg) | ||
173 | dev_dbg(sst->dev, "shim 0x%2.2x value 0x%16.16llx\n", | ||
174 | i, reg); | ||
175 | } | ||
176 | |||
177 | for (i = 0x00; i <= 0xff; i += 4) { | ||
178 | reg = readl(sst->addr.pci_cfg + i); | ||
179 | if (reg) | ||
180 | dev_dbg(sst->dev, "pci 0x%2.2x value 0x%8.8x\n", | ||
181 | i, (u32)reg); | ||
182 | } | ||
183 | } | ||
184 | |||
185 | static irqreturn_t sst_byt_irq(int irq, void *context) | ||
186 | { | ||
187 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
188 | u64 isrx; | ||
189 | irqreturn_t ret = IRQ_NONE; | ||
190 | |||
191 | spin_lock(&sst->spinlock); | ||
192 | |||
193 | isrx = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
194 | if (isrx & SST_ISRX_DONE) { | ||
195 | /* ADSP has processed the message request from IA */ | ||
196 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCX, | ||
197 | SST_BYT_IPCX_DONE, 0); | ||
198 | ret = IRQ_WAKE_THREAD; | ||
199 | } | ||
200 | if (isrx & SST_BYT_ISRX_REQUEST) { | ||
201 | /* mask message request from ADSP and do processing later */ | ||
202 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX, | ||
203 | SST_BYT_IMRX_REQUEST, | ||
204 | SST_BYT_IMRX_REQUEST); | ||
205 | ret = IRQ_WAKE_THREAD; | ||
206 | } | ||
207 | |||
208 | spin_unlock(&sst->spinlock); | ||
209 | |||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | static void sst_byt_boot(struct sst_dsp *sst) | ||
214 | { | ||
215 | int tries = 10; | ||
216 | |||
217 | /* release stall and wait to unstall */ | ||
218 | sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_STALL, 0x0); | ||
219 | while (tries--) { | ||
220 | if (!(sst_dsp_shim_read64(sst, SST_CSR) & | ||
221 | SST_BYT_CSR_PWAITMODE)) | ||
222 | break; | ||
223 | msleep(100); | ||
224 | } | ||
225 | if (tries < 0) { | ||
226 | dev_err(sst->dev, "unable to start DSP\n"); | ||
227 | sst_byt_dump_shim(sst); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static void sst_byt_reset(struct sst_dsp *sst) | ||
232 | { | ||
233 | /* put DSP into reset, set reset vector and stall */ | ||
234 | sst_dsp_shim_update_bits64(sst, SST_CSR, | ||
235 | SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL, | ||
236 | SST_BYT_CSR_RST | SST_BYT_CSR_VECTOR_SEL | SST_BYT_CSR_STALL); | ||
237 | |||
238 | udelay(10); | ||
239 | |||
240 | /* take DSP out of reset and keep stalled for FW loading */ | ||
241 | sst_dsp_shim_update_bits64(sst, SST_CSR, SST_BYT_CSR_RST, 0); | ||
242 | } | ||
243 | |||
244 | struct sst_adsp_memregion { | ||
245 | u32 start; | ||
246 | u32 end; | ||
247 | int blocks; | ||
248 | enum sst_mem_type type; | ||
249 | }; | ||
250 | |||
251 | /* BYT test stuff */ | ||
252 | static const struct sst_adsp_memregion byt_region[] = { | ||
253 | {0xC0000, 0x100000, 8, SST_MEM_IRAM}, /* I-SRAM - 8 * 32kB */ | ||
254 | {0x100000, 0x140000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | ||
255 | }; | ||
256 | |||
257 | static int sst_byt_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
258 | { | ||
259 | sst->addr.lpe_base = pdata->lpe_base; | ||
260 | sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size); | ||
261 | if (!sst->addr.lpe) | ||
262 | return -ENODEV; | ||
263 | |||
264 | /* ADSP PCI MMIO config space */ | ||
265 | sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size); | ||
266 | if (!sst->addr.pci_cfg) { | ||
267 | iounmap(sst->addr.lpe); | ||
268 | return -ENODEV; | ||
269 | } | ||
270 | |||
271 | /* SST Extended FW allocation */ | ||
272 | sst->addr.fw_ext = ioremap(pdata->fw_base, pdata->fw_size); | ||
273 | if (!sst->addr.fw_ext) { | ||
274 | iounmap(sst->addr.pci_cfg); | ||
275 | iounmap(sst->addr.lpe); | ||
276 | return -ENODEV; | ||
277 | } | ||
278 | |||
279 | /* SST Shim */ | ||
280 | sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset; | ||
281 | |||
282 | sst_dsp_mailbox_init(sst, SST_BYT_MAILBOX_OFFSET + 0x204, | ||
283 | SST_BYT_IPC_MAX_PAYLOAD_SIZE, | ||
284 | SST_BYT_MAILBOX_OFFSET, | ||
285 | SST_BYT_IPC_MAX_PAYLOAD_SIZE); | ||
286 | |||
287 | sst->irq = pdata->irq; | ||
288 | |||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int sst_byt_init(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
293 | { | ||
294 | const struct sst_adsp_memregion *region; | ||
295 | struct device *dev; | ||
296 | int ret = -ENODEV, i, j, region_count; | ||
297 | u32 offset, size; | ||
298 | |||
299 | dev = sst->dev; | ||
300 | |||
301 | switch (sst->id) { | ||
302 | case SST_DEV_ID_BYT: | ||
303 | region = byt_region; | ||
304 | region_count = ARRAY_SIZE(byt_region); | ||
305 | sst->addr.iram_offset = SST_BYT_IRAM_OFFSET; | ||
306 | sst->addr.dram_offset = SST_BYT_DRAM_OFFSET; | ||
307 | sst->addr.shim_offset = SST_BYT_SHIM_OFFSET; | ||
308 | break; | ||
309 | default: | ||
310 | dev_err(dev, "failed to get mem resources\n"); | ||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | ret = sst_byt_resource_map(sst, pdata); | ||
315 | if (ret < 0) { | ||
316 | dev_err(dev, "failed to map resources\n"); | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | /* | ||
321 | * save the physical address of extended firmware block in the first | ||
322 | * 4 bytes of the mailbox | ||
323 | */ | ||
324 | memcpy_toio(sst->addr.lpe + SST_BYT_MAILBOX_OFFSET, | ||
325 | &pdata->fw_base, sizeof(u32)); | ||
326 | |||
327 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | ||
328 | if (ret) | ||
329 | return ret; | ||
330 | |||
331 | /* enable Interrupt from both sides */ | ||
332 | sst_dsp_shim_update_bits64(sst, SST_IMRX, 0x3, 0x0); | ||
333 | sst_dsp_shim_update_bits64(sst, SST_IMRD, 0x3, 0x0); | ||
334 | |||
335 | /* register DSP memory blocks - ideally we should get this from ACPI */ | ||
336 | for (i = 0; i < region_count; i++) { | ||
337 | offset = region[i].start; | ||
338 | size = (region[i].end - region[i].start) / region[i].blocks; | ||
339 | |||
340 | /* register individual memory blocks */ | ||
341 | for (j = 0; j < region[i].blocks; j++) { | ||
342 | sst_mem_block_register(sst, offset, size, | ||
343 | region[i].type, NULL, j, sst); | ||
344 | offset += size; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static void sst_byt_free(struct sst_dsp *sst) | ||
352 | { | ||
353 | sst_mem_block_unregister_all(sst); | ||
354 | iounmap(sst->addr.lpe); | ||
355 | iounmap(sst->addr.pci_cfg); | ||
356 | iounmap(sst->addr.fw_ext); | ||
357 | } | ||
358 | |||
359 | struct sst_ops sst_byt_ops = { | ||
360 | .reset = sst_byt_reset, | ||
361 | .boot = sst_byt_boot, | ||
362 | .write = sst_shim32_write, | ||
363 | .read = sst_shim32_read, | ||
364 | .write64 = sst_shim32_write64, | ||
365 | .read64 = sst_shim32_read64, | ||
366 | .ram_read = sst_memcpy_fromio_32, | ||
367 | .ram_write = sst_memcpy_toio_32, | ||
368 | .irq_handler = sst_byt_irq, | ||
369 | .init = sst_byt_init, | ||
370 | .free = sst_byt_free, | ||
371 | .parse_fw = sst_byt_parse_fw_image, | ||
372 | }; | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.c b/sound/soc/intel/sst-baytrail-ipc.c new file mode 100644 index 000000000000..d0eaeee21be4 --- /dev/null +++ b/sound/soc/intel/sst-baytrail-ipc.c | |||
@@ -0,0 +1,867 @@ | |||
1 | /* | ||
2 | * Intel Baytrail SST IPC Support | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/list.h> | ||
18 | #include <linux/device.h> | ||
19 | #include <linux/wait.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/workqueue.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/list.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/kthread.h> | ||
28 | #include <linux/firmware.h> | ||
29 | #include <linux/io.h> | ||
30 | #include <asm/div64.h> | ||
31 | |||
32 | #include "sst-baytrail-ipc.h" | ||
33 | #include "sst-dsp.h" | ||
34 | #include "sst-dsp-priv.h" | ||
35 | |||
36 | /* IPC message timeout */ | ||
37 | #define IPC_TIMEOUT_MSECS 300 | ||
38 | #define IPC_BOOT_MSECS 200 | ||
39 | |||
40 | #define IPC_EMPTY_LIST_SIZE 8 | ||
41 | |||
42 | /* IPC header bits */ | ||
43 | #define IPC_HEADER_MSG_ID_MASK 0xff | ||
44 | #define IPC_HEADER_MSG_ID(x) ((x) & IPC_HEADER_MSG_ID_MASK) | ||
45 | #define IPC_HEADER_STR_ID_SHIFT 8 | ||
46 | #define IPC_HEADER_STR_ID_MASK 0x1f | ||
47 | #define IPC_HEADER_STR_ID(x) (((x) & 0x1f) << IPC_HEADER_STR_ID_SHIFT) | ||
48 | #define IPC_HEADER_LARGE_SHIFT 13 | ||
49 | #define IPC_HEADER_LARGE(x) (((x) & 0x1) << IPC_HEADER_LARGE_SHIFT) | ||
50 | #define IPC_HEADER_DATA_SHIFT 16 | ||
51 | #define IPC_HEADER_DATA_MASK 0x3fff | ||
52 | #define IPC_HEADER_DATA(x) (((x) & 0x3fff) << IPC_HEADER_DATA_SHIFT) | ||
53 | |||
54 | /* mask for differentiating between notification and reply message */ | ||
55 | #define IPC_NOTIFICATION (0x1 << 7) | ||
56 | |||
57 | /* I2L Stream config/control msgs */ | ||
58 | #define IPC_IA_ALLOC_STREAM 0x20 | ||
59 | #define IPC_IA_FREE_STREAM 0x21 | ||
60 | #define IPC_IA_PAUSE_STREAM 0x24 | ||
61 | #define IPC_IA_RESUME_STREAM 0x25 | ||
62 | #define IPC_IA_DROP_STREAM 0x26 | ||
63 | #define IPC_IA_START_STREAM 0x30 | ||
64 | |||
65 | /* notification messages */ | ||
66 | #define IPC_IA_FW_INIT_CMPLT 0x81 | ||
67 | #define IPC_SST_PERIOD_ELAPSED 0x97 | ||
68 | |||
69 | /* IPC messages between host and ADSP */ | ||
70 | struct sst_byt_address_info { | ||
71 | u32 addr; | ||
72 | u32 size; | ||
73 | } __packed; | ||
74 | |||
75 | struct sst_byt_str_type { | ||
76 | u8 codec_type; | ||
77 | u8 str_type; | ||
78 | u8 operation; | ||
79 | u8 protected_str; | ||
80 | u8 time_slots; | ||
81 | u8 reserved; | ||
82 | u16 result; | ||
83 | } __packed; | ||
84 | |||
85 | struct sst_byt_pcm_params { | ||
86 | u8 num_chan; | ||
87 | u8 pcm_wd_sz; | ||
88 | u8 use_offload_path; | ||
89 | u8 reserved; | ||
90 | u32 sfreq; | ||
91 | u8 channel_map[8]; | ||
92 | } __packed; | ||
93 | |||
94 | struct sst_byt_frames_info { | ||
95 | u16 num_entries; | ||
96 | u16 rsrvd; | ||
97 | u32 frag_size; | ||
98 | struct sst_byt_address_info ring_buf_info[8]; | ||
99 | } __packed; | ||
100 | |||
101 | struct sst_byt_alloc_params { | ||
102 | struct sst_byt_str_type str_type; | ||
103 | struct sst_byt_pcm_params pcm_params; | ||
104 | struct sst_byt_frames_info frame_info; | ||
105 | } __packed; | ||
106 | |||
107 | struct sst_byt_alloc_response { | ||
108 | struct sst_byt_str_type str_type; | ||
109 | u8 reserved[88]; | ||
110 | } __packed; | ||
111 | |||
112 | struct sst_byt_start_stream_params { | ||
113 | u32 byte_offset; | ||
114 | } __packed; | ||
115 | |||
116 | struct sst_byt_tstamp { | ||
117 | u64 ring_buffer_counter; | ||
118 | u64 hardware_counter; | ||
119 | u64 frames_decoded; | ||
120 | u64 bytes_decoded; | ||
121 | u64 bytes_copied; | ||
122 | u32 sampling_frequency; | ||
123 | u32 channel_peak[8]; | ||
124 | } __packed; | ||
125 | |||
126 | /* driver internal IPC message structure */ | ||
127 | struct ipc_message { | ||
128 | struct list_head list; | ||
129 | u64 header; | ||
130 | |||
131 | /* direction wrt host CPU */ | ||
132 | char tx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
133 | size_t tx_size; | ||
134 | char rx_data[SST_BYT_IPC_MAX_PAYLOAD_SIZE]; | ||
135 | size_t rx_size; | ||
136 | |||
137 | wait_queue_head_t waitq; | ||
138 | bool complete; | ||
139 | bool wait; | ||
140 | int errno; | ||
141 | }; | ||
142 | |||
143 | struct sst_byt_stream; | ||
144 | struct sst_byt; | ||
145 | |||
146 | /* stream infomation */ | ||
147 | struct sst_byt_stream { | ||
148 | struct list_head node; | ||
149 | |||
150 | /* configuration */ | ||
151 | struct sst_byt_alloc_params request; | ||
152 | struct sst_byt_alloc_response reply; | ||
153 | |||
154 | /* runtime info */ | ||
155 | struct sst_byt *byt; | ||
156 | int str_id; | ||
157 | bool commited; | ||
158 | bool running; | ||
159 | |||
160 | /* driver callback */ | ||
161 | u32 (*notify_position)(struct sst_byt_stream *stream, void *data); | ||
162 | void *pdata; | ||
163 | }; | ||
164 | |||
165 | /* SST Baytrail IPC data */ | ||
166 | struct sst_byt { | ||
167 | struct device *dev; | ||
168 | struct sst_dsp *dsp; | ||
169 | |||
170 | /* stream */ | ||
171 | struct list_head stream_list; | ||
172 | |||
173 | /* boot */ | ||
174 | wait_queue_head_t boot_wait; | ||
175 | bool boot_complete; | ||
176 | |||
177 | /* IPC messaging */ | ||
178 | struct list_head tx_list; | ||
179 | struct list_head rx_list; | ||
180 | struct list_head empty_list; | ||
181 | wait_queue_head_t wait_txq; | ||
182 | struct task_struct *tx_thread; | ||
183 | struct kthread_worker kworker; | ||
184 | struct kthread_work kwork; | ||
185 | struct ipc_message *msg; | ||
186 | }; | ||
187 | |||
188 | static inline u64 sst_byt_header(int msg_id, int data, bool large, int str_id) | ||
189 | { | ||
190 | u64 header; | ||
191 | |||
192 | header = IPC_HEADER_MSG_ID(msg_id) | | ||
193 | IPC_HEADER_STR_ID(str_id) | | ||
194 | IPC_HEADER_LARGE(large) | | ||
195 | IPC_HEADER_DATA(data) | | ||
196 | SST_BYT_IPCX_BUSY; | ||
197 | |||
198 | return header; | ||
199 | } | ||
200 | |||
201 | static inline u16 sst_byt_header_msg_id(u64 header) | ||
202 | { | ||
203 | return header & IPC_HEADER_MSG_ID_MASK; | ||
204 | } | ||
205 | |||
206 | static inline u8 sst_byt_header_str_id(u64 header) | ||
207 | { | ||
208 | return (header >> IPC_HEADER_STR_ID_SHIFT) & IPC_HEADER_STR_ID_MASK; | ||
209 | } | ||
210 | |||
211 | static inline u16 sst_byt_header_data(u64 header) | ||
212 | { | ||
213 | return (header >> IPC_HEADER_DATA_SHIFT) & IPC_HEADER_DATA_MASK; | ||
214 | } | ||
215 | |||
216 | static struct sst_byt_stream *sst_byt_get_stream(struct sst_byt *byt, | ||
217 | int stream_id) | ||
218 | { | ||
219 | struct sst_byt_stream *stream; | ||
220 | |||
221 | list_for_each_entry(stream, &byt->stream_list, node) { | ||
222 | if (stream->str_id == stream_id) | ||
223 | return stream; | ||
224 | } | ||
225 | |||
226 | return NULL; | ||
227 | } | ||
228 | |||
229 | static void sst_byt_ipc_shim_dbg(struct sst_byt *byt, const char *text) | ||
230 | { | ||
231 | struct sst_dsp *sst = byt->dsp; | ||
232 | u64 isr, ipcd, imrx, ipcx; | ||
233 | |||
234 | ipcx = sst_dsp_shim_read64_unlocked(sst, SST_IPCX); | ||
235 | isr = sst_dsp_shim_read64_unlocked(sst, SST_ISRX); | ||
236 | ipcd = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
237 | imrx = sst_dsp_shim_read64_unlocked(sst, SST_IMRX); | ||
238 | |||
239 | dev_err(byt->dev, | ||
240 | "ipc: --%s-- ipcx 0x%llx isr 0x%llx ipcd 0x%llx imrx 0x%llx\n", | ||
241 | text, ipcx, isr, ipcd, imrx); | ||
242 | } | ||
243 | |||
244 | /* locks held by caller */ | ||
245 | static struct ipc_message *sst_byt_msg_get_empty(struct sst_byt *byt) | ||
246 | { | ||
247 | struct ipc_message *msg = NULL; | ||
248 | |||
249 | if (!list_empty(&byt->empty_list)) { | ||
250 | msg = list_first_entry(&byt->empty_list, | ||
251 | struct ipc_message, list); | ||
252 | list_del(&msg->list); | ||
253 | } | ||
254 | |||
255 | return msg; | ||
256 | } | ||
257 | |||
258 | static void sst_byt_ipc_tx_msgs(struct kthread_work *work) | ||
259 | { | ||
260 | struct sst_byt *byt = | ||
261 | container_of(work, struct sst_byt, kwork); | ||
262 | struct ipc_message *msg; | ||
263 | u64 ipcx; | ||
264 | unsigned long flags; | ||
265 | |||
266 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
267 | if (list_empty(&byt->tx_list)) { | ||
268 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
269 | return; | ||
270 | } | ||
271 | |||
272 | /* if the DSP is busy we will TX messages after IRQ */ | ||
273 | ipcx = sst_dsp_shim_read64_unlocked(byt->dsp, SST_IPCX); | ||
274 | if (ipcx & SST_BYT_IPCX_BUSY) { | ||
275 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
276 | return; | ||
277 | } | ||
278 | |||
279 | msg = list_first_entry(&byt->tx_list, struct ipc_message, list); | ||
280 | |||
281 | list_move(&msg->list, &byt->rx_list); | ||
282 | |||
283 | /* send the message */ | ||
284 | if (msg->header & IPC_HEADER_LARGE(true)) | ||
285 | sst_dsp_outbox_write(byt->dsp, msg->tx_data, msg->tx_size); | ||
286 | sst_dsp_shim_write64_unlocked(byt->dsp, SST_IPCX, msg->header); | ||
287 | |||
288 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
289 | } | ||
290 | |||
291 | static inline void sst_byt_tx_msg_reply_complete(struct sst_byt *byt, | ||
292 | struct ipc_message *msg) | ||
293 | { | ||
294 | msg->complete = true; | ||
295 | |||
296 | if (!msg->wait) | ||
297 | list_add_tail(&msg->list, &byt->empty_list); | ||
298 | else | ||
299 | wake_up(&msg->waitq); | ||
300 | } | ||
301 | |||
302 | static int sst_byt_tx_wait_done(struct sst_byt *byt, struct ipc_message *msg, | ||
303 | void *rx_data) | ||
304 | { | ||
305 | unsigned long flags; | ||
306 | int ret; | ||
307 | |||
308 | /* wait for DSP completion */ | ||
309 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
310 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
311 | |||
312 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
313 | if (ret == 0) { | ||
314 | list_del(&msg->list); | ||
315 | sst_byt_ipc_shim_dbg(byt, "message timeout"); | ||
316 | |||
317 | ret = -ETIMEDOUT; | ||
318 | } else { | ||
319 | |||
320 | /* copy the data returned from DSP */ | ||
321 | if (msg->rx_size) | ||
322 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
323 | ret = msg->errno; | ||
324 | } | ||
325 | |||
326 | list_add_tail(&msg->list, &byt->empty_list); | ||
327 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | static int sst_byt_ipc_tx_message(struct sst_byt *byt, u64 header, | ||
332 | void *tx_data, size_t tx_bytes, | ||
333 | void *rx_data, size_t rx_bytes, int wait) | ||
334 | { | ||
335 | unsigned long flags; | ||
336 | struct ipc_message *msg; | ||
337 | |||
338 | spin_lock_irqsave(&byt->dsp->spinlock, flags); | ||
339 | |||
340 | msg = sst_byt_msg_get_empty(byt); | ||
341 | if (msg == NULL) { | ||
342 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
343 | return -EBUSY; | ||
344 | } | ||
345 | |||
346 | msg->header = header; | ||
347 | msg->tx_size = tx_bytes; | ||
348 | msg->rx_size = rx_bytes; | ||
349 | msg->wait = wait; | ||
350 | msg->errno = 0; | ||
351 | msg->complete = false; | ||
352 | |||
353 | if (tx_bytes) { | ||
354 | /* msg content = lower 32-bit of the header + data */ | ||
355 | *(u32 *)msg->tx_data = (u32)(header & (u32)-1); | ||
356 | memcpy(msg->tx_data + sizeof(u32), tx_data, tx_bytes); | ||
357 | msg->tx_size += sizeof(u32); | ||
358 | } | ||
359 | |||
360 | list_add_tail(&msg->list, &byt->tx_list); | ||
361 | spin_unlock_irqrestore(&byt->dsp->spinlock, flags); | ||
362 | |||
363 | queue_kthread_work(&byt->kworker, &byt->kwork); | ||
364 | |||
365 | if (wait) | ||
366 | return sst_byt_tx_wait_done(byt, msg, rx_data); | ||
367 | else | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static inline int sst_byt_ipc_tx_msg_wait(struct sst_byt *byt, u64 header, | ||
372 | void *tx_data, size_t tx_bytes, | ||
373 | void *rx_data, size_t rx_bytes) | ||
374 | { | ||
375 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
376 | rx_data, rx_bytes, 1); | ||
377 | } | ||
378 | |||
379 | static inline int sst_byt_ipc_tx_msg_nowait(struct sst_byt *byt, u64 header, | ||
380 | void *tx_data, size_t tx_bytes) | ||
381 | { | ||
382 | return sst_byt_ipc_tx_message(byt, header, tx_data, tx_bytes, | ||
383 | NULL, 0, 0); | ||
384 | } | ||
385 | |||
386 | static struct ipc_message *sst_byt_reply_find_msg(struct sst_byt *byt, | ||
387 | u64 header) | ||
388 | { | ||
389 | struct ipc_message *msg = NULL, *_msg; | ||
390 | u64 mask; | ||
391 | |||
392 | /* match reply to message sent based on msg and stream IDs */ | ||
393 | mask = IPC_HEADER_MSG_ID_MASK | | ||
394 | IPC_HEADER_STR_ID_MASK << IPC_HEADER_STR_ID_SHIFT; | ||
395 | header &= mask; | ||
396 | |||
397 | if (list_empty(&byt->rx_list)) { | ||
398 | dev_err(byt->dev, | ||
399 | "ipc: rx list is empty but received 0x%llx\n", header); | ||
400 | goto out; | ||
401 | } | ||
402 | |||
403 | list_for_each_entry(_msg, &byt->rx_list, list) { | ||
404 | if ((_msg->header & mask) == header) { | ||
405 | msg = _msg; | ||
406 | break; | ||
407 | } | ||
408 | } | ||
409 | |||
410 | out: | ||
411 | return msg; | ||
412 | } | ||
413 | |||
414 | static void sst_byt_stream_update(struct sst_byt *byt, struct ipc_message *msg) | ||
415 | { | ||
416 | struct sst_byt_stream *stream; | ||
417 | u64 header = msg->header; | ||
418 | u8 stream_id = sst_byt_header_str_id(header); | ||
419 | u8 stream_msg = sst_byt_header_msg_id(header); | ||
420 | |||
421 | stream = sst_byt_get_stream(byt, stream_id); | ||
422 | if (stream == NULL) | ||
423 | return; | ||
424 | |||
425 | switch (stream_msg) { | ||
426 | case IPC_IA_DROP_STREAM: | ||
427 | case IPC_IA_PAUSE_STREAM: | ||
428 | case IPC_IA_FREE_STREAM: | ||
429 | stream->running = false; | ||
430 | break; | ||
431 | case IPC_IA_START_STREAM: | ||
432 | case IPC_IA_RESUME_STREAM: | ||
433 | stream->running = true; | ||
434 | break; | ||
435 | } | ||
436 | } | ||
437 | |||
438 | static int sst_byt_process_reply(struct sst_byt *byt, u64 header) | ||
439 | { | ||
440 | struct ipc_message *msg; | ||
441 | |||
442 | msg = sst_byt_reply_find_msg(byt, header); | ||
443 | if (msg == NULL) | ||
444 | return 1; | ||
445 | |||
446 | if (header & IPC_HEADER_LARGE(true)) { | ||
447 | msg->rx_size = sst_byt_header_data(header); | ||
448 | sst_dsp_inbox_read(byt->dsp, msg->rx_data, msg->rx_size); | ||
449 | } | ||
450 | |||
451 | /* update any stream states */ | ||
452 | sst_byt_stream_update(byt, msg); | ||
453 | |||
454 | list_del(&msg->list); | ||
455 | /* wake up */ | ||
456 | sst_byt_tx_msg_reply_complete(byt, msg); | ||
457 | |||
458 | return 1; | ||
459 | } | ||
460 | |||
461 | static void sst_byt_fw_ready(struct sst_byt *byt, u64 header) | ||
462 | { | ||
463 | dev_dbg(byt->dev, "ipc: DSP is ready 0x%llX\n", header); | ||
464 | |||
465 | byt->boot_complete = true; | ||
466 | wake_up(&byt->boot_wait); | ||
467 | } | ||
468 | |||
469 | static int sst_byt_process_notification(struct sst_byt *byt, | ||
470 | unsigned long *flags) | ||
471 | { | ||
472 | struct sst_dsp *sst = byt->dsp; | ||
473 | struct sst_byt_stream *stream; | ||
474 | u64 header; | ||
475 | u8 msg_id, stream_id; | ||
476 | int handled = 1; | ||
477 | |||
478 | header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
479 | msg_id = sst_byt_header_msg_id(header); | ||
480 | |||
481 | switch (msg_id) { | ||
482 | case IPC_SST_PERIOD_ELAPSED: | ||
483 | stream_id = sst_byt_header_str_id(header); | ||
484 | stream = sst_byt_get_stream(byt, stream_id); | ||
485 | if (stream && stream->running && stream->notify_position) { | ||
486 | spin_unlock_irqrestore(&sst->spinlock, *flags); | ||
487 | stream->notify_position(stream, stream->pdata); | ||
488 | spin_lock_irqsave(&sst->spinlock, *flags); | ||
489 | } | ||
490 | break; | ||
491 | case IPC_IA_FW_INIT_CMPLT: | ||
492 | sst_byt_fw_ready(byt, header); | ||
493 | break; | ||
494 | } | ||
495 | |||
496 | return handled; | ||
497 | } | ||
498 | |||
499 | static irqreturn_t sst_byt_irq_thread(int irq, void *context) | ||
500 | { | ||
501 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
502 | struct sst_byt *byt = sst_dsp_get_thread_context(sst); | ||
503 | u64 header; | ||
504 | unsigned long flags; | ||
505 | |||
506 | spin_lock_irqsave(&sst->spinlock, flags); | ||
507 | |||
508 | header = sst_dsp_shim_read64_unlocked(sst, SST_IPCD); | ||
509 | if (header & SST_BYT_IPCD_BUSY) { | ||
510 | if (header & IPC_NOTIFICATION) { | ||
511 | /* message from ADSP */ | ||
512 | sst_byt_process_notification(byt, &flags); | ||
513 | } else { | ||
514 | /* reply from ADSP */ | ||
515 | sst_byt_process_reply(byt, header); | ||
516 | } | ||
517 | /* | ||
518 | * clear IPCD BUSY bit and set DONE bit. Tell DSP we have | ||
519 | * processed the message and can accept new. Clear data part | ||
520 | * of the header | ||
521 | */ | ||
522 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IPCD, | ||
523 | SST_BYT_IPCD_DONE | SST_BYT_IPCD_BUSY | | ||
524 | IPC_HEADER_DATA(IPC_HEADER_DATA_MASK), | ||
525 | SST_BYT_IPCD_DONE); | ||
526 | /* unmask message request interrupts */ | ||
527 | sst_dsp_shim_update_bits64_unlocked(sst, SST_IMRX, | ||
528 | SST_BYT_IMRX_REQUEST, 0); | ||
529 | } | ||
530 | |||
531 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
532 | |||
533 | /* continue to send any remaining messages... */ | ||
534 | queue_kthread_work(&byt->kworker, &byt->kwork); | ||
535 | |||
536 | return IRQ_HANDLED; | ||
537 | } | ||
538 | |||
539 | /* stream API */ | ||
540 | struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | ||
541 | u32 (*notify_position)(struct sst_byt_stream *stream, void *data), | ||
542 | void *data) | ||
543 | { | ||
544 | struct sst_byt_stream *stream; | ||
545 | |||
546 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
547 | if (stream == NULL) | ||
548 | return NULL; | ||
549 | |||
550 | list_add(&stream->node, &byt->stream_list); | ||
551 | stream->notify_position = notify_position; | ||
552 | stream->pdata = data; | ||
553 | stream->byt = byt; | ||
554 | stream->str_id = id; | ||
555 | |||
556 | return stream; | ||
557 | } | ||
558 | |||
559 | int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
560 | int bits) | ||
561 | { | ||
562 | stream->request.pcm_params.pcm_wd_sz = bits; | ||
563 | return 0; | ||
564 | } | ||
565 | |||
566 | int sst_byt_stream_set_channels(struct sst_byt *byt, | ||
567 | struct sst_byt_stream *stream, u8 channels) | ||
568 | { | ||
569 | stream->request.pcm_params.num_chan = channels; | ||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
574 | unsigned int rate) | ||
575 | { | ||
576 | stream->request.pcm_params.sfreq = rate; | ||
577 | return 0; | ||
578 | } | ||
579 | |||
580 | /* stream sonfiguration */ | ||
581 | int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
582 | int codec_type, int stream_type, int operation) | ||
583 | { | ||
584 | stream->request.str_type.codec_type = codec_type; | ||
585 | stream->request.str_type.str_type = stream_type; | ||
586 | stream->request.str_type.operation = operation; | ||
587 | stream->request.str_type.time_slots = 0xc; | ||
588 | |||
589 | return 0; | ||
590 | } | ||
591 | |||
592 | int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
593 | uint32_t buffer_addr, uint32_t buffer_size) | ||
594 | { | ||
595 | stream->request.frame_info.num_entries = 1; | ||
596 | stream->request.frame_info.ring_buf_info[0].addr = buffer_addr; | ||
597 | stream->request.frame_info.ring_buf_info[0].size = buffer_size; | ||
598 | /* calculate bytes per 4 ms fragment */ | ||
599 | stream->request.frame_info.frag_size = | ||
600 | stream->request.pcm_params.sfreq * | ||
601 | stream->request.pcm_params.num_chan * | ||
602 | stream->request.pcm_params.pcm_wd_sz / 8 * | ||
603 | 4 / 1000; | ||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
608 | { | ||
609 | struct sst_byt_alloc_params *str_req = &stream->request; | ||
610 | struct sst_byt_alloc_response *reply = &stream->reply; | ||
611 | u64 header; | ||
612 | int ret; | ||
613 | |||
614 | header = sst_byt_header(IPC_IA_ALLOC_STREAM, | ||
615 | sizeof(*str_req) + sizeof(u32), | ||
616 | true, stream->str_id); | ||
617 | ret = sst_byt_ipc_tx_msg_wait(byt, header, str_req, sizeof(*str_req), | ||
618 | reply, sizeof(*reply)); | ||
619 | if (ret < 0) { | ||
620 | dev_err(byt->dev, "ipc: error stream commit failed\n"); | ||
621 | return ret; | ||
622 | } | ||
623 | |||
624 | stream->commited = true; | ||
625 | |||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
630 | { | ||
631 | u64 header; | ||
632 | int ret = 0; | ||
633 | |||
634 | if (!stream->commited) | ||
635 | goto out; | ||
636 | |||
637 | header = sst_byt_header(IPC_IA_FREE_STREAM, 0, false, stream->str_id); | ||
638 | ret = sst_byt_ipc_tx_msg_wait(byt, header, NULL, 0, NULL, 0); | ||
639 | if (ret < 0) { | ||
640 | dev_err(byt->dev, "ipc: free stream %d failed\n", | ||
641 | stream->str_id); | ||
642 | return -EAGAIN; | ||
643 | } | ||
644 | |||
645 | stream->commited = false; | ||
646 | out: | ||
647 | list_del(&stream->node); | ||
648 | kfree(stream); | ||
649 | |||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | static int sst_byt_stream_operations(struct sst_byt *byt, int type, | ||
654 | int stream_id, int wait) | ||
655 | { | ||
656 | struct sst_byt_start_stream_params start_stream; | ||
657 | u64 header; | ||
658 | void *tx_msg = NULL; | ||
659 | size_t size = 0; | ||
660 | |||
661 | if (type != IPC_IA_START_STREAM) { | ||
662 | header = sst_byt_header(type, 0, false, stream_id); | ||
663 | } else { | ||
664 | start_stream.byte_offset = 0; | ||
665 | header = sst_byt_header(IPC_IA_START_STREAM, | ||
666 | sizeof(start_stream) + sizeof(u32), | ||
667 | true, stream_id); | ||
668 | tx_msg = &start_stream; | ||
669 | size = sizeof(start_stream); | ||
670 | } | ||
671 | |||
672 | if (wait) | ||
673 | return sst_byt_ipc_tx_msg_wait(byt, header, | ||
674 | tx_msg, size, NULL, 0); | ||
675 | else | ||
676 | return sst_byt_ipc_tx_msg_nowait(byt, header, tx_msg, size); | ||
677 | } | ||
678 | |||
679 | /* stream ALSA trigger operations */ | ||
680 | int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
681 | { | ||
682 | int ret; | ||
683 | |||
684 | ret = sst_byt_stream_operations(byt, IPC_IA_START_STREAM, | ||
685 | stream->str_id, 0); | ||
686 | if (ret < 0) | ||
687 | dev_err(byt->dev, "ipc: error failed to start stream %d\n", | ||
688 | stream->str_id); | ||
689 | |||
690 | return ret; | ||
691 | } | ||
692 | |||
693 | int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
694 | { | ||
695 | int ret; | ||
696 | |||
697 | /* don't stop streams that are not commited */ | ||
698 | if (!stream->commited) | ||
699 | return 0; | ||
700 | |||
701 | ret = sst_byt_stream_operations(byt, IPC_IA_DROP_STREAM, | ||
702 | stream->str_id, 0); | ||
703 | if (ret < 0) | ||
704 | dev_err(byt->dev, "ipc: error failed to stop stream %d\n", | ||
705 | stream->str_id); | ||
706 | return ret; | ||
707 | } | ||
708 | |||
709 | int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
710 | { | ||
711 | int ret; | ||
712 | |||
713 | ret = sst_byt_stream_operations(byt, IPC_IA_PAUSE_STREAM, | ||
714 | stream->str_id, 0); | ||
715 | if (ret < 0) | ||
716 | dev_err(byt->dev, "ipc: error failed to pause stream %d\n", | ||
717 | stream->str_id); | ||
718 | |||
719 | return ret; | ||
720 | } | ||
721 | |||
722 | int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream) | ||
723 | { | ||
724 | int ret; | ||
725 | |||
726 | ret = sst_byt_stream_operations(byt, IPC_IA_RESUME_STREAM, | ||
727 | stream->str_id, 0); | ||
728 | if (ret < 0) | ||
729 | dev_err(byt->dev, "ipc: error failed to resume stream %d\n", | ||
730 | stream->str_id); | ||
731 | |||
732 | return ret; | ||
733 | } | ||
734 | |||
735 | int sst_byt_get_dsp_position(struct sst_byt *byt, | ||
736 | struct sst_byt_stream *stream, int buffer_size) | ||
737 | { | ||
738 | struct sst_dsp *sst = byt->dsp; | ||
739 | struct sst_byt_tstamp fw_tstamp; | ||
740 | u8 str_id = stream->str_id; | ||
741 | u32 tstamp_offset; | ||
742 | |||
743 | tstamp_offset = SST_BYT_TIMESTAMP_OFFSET + str_id * sizeof(fw_tstamp); | ||
744 | memcpy_fromio(&fw_tstamp, | ||
745 | sst->addr.lpe + tstamp_offset, sizeof(fw_tstamp)); | ||
746 | |||
747 | return do_div(fw_tstamp.ring_buffer_counter, buffer_size); | ||
748 | } | ||
749 | |||
750 | static int msg_empty_list_init(struct sst_byt *byt) | ||
751 | { | ||
752 | struct ipc_message *msg; | ||
753 | int i; | ||
754 | |||
755 | byt->msg = kzalloc(sizeof(*msg) * IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
756 | if (byt->msg == NULL) | ||
757 | return -ENOMEM; | ||
758 | |||
759 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
760 | init_waitqueue_head(&byt->msg[i].waitq); | ||
761 | list_add(&byt->msg[i].list, &byt->empty_list); | ||
762 | } | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt) | ||
768 | { | ||
769 | return byt->dsp; | ||
770 | } | ||
771 | |||
772 | static struct sst_dsp_device byt_dev = { | ||
773 | .thread = sst_byt_irq_thread, | ||
774 | .ops = &sst_byt_ops, | ||
775 | }; | ||
776 | |||
777 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata) | ||
778 | { | ||
779 | struct sst_byt *byt; | ||
780 | struct sst_fw *byt_sst_fw; | ||
781 | int err; | ||
782 | |||
783 | dev_dbg(dev, "initialising Byt DSP IPC\n"); | ||
784 | |||
785 | byt = devm_kzalloc(dev, sizeof(*byt), GFP_KERNEL); | ||
786 | if (byt == NULL) | ||
787 | return -ENOMEM; | ||
788 | |||
789 | byt->dev = dev; | ||
790 | INIT_LIST_HEAD(&byt->stream_list); | ||
791 | INIT_LIST_HEAD(&byt->tx_list); | ||
792 | INIT_LIST_HEAD(&byt->rx_list); | ||
793 | INIT_LIST_HEAD(&byt->empty_list); | ||
794 | init_waitqueue_head(&byt->boot_wait); | ||
795 | init_waitqueue_head(&byt->wait_txq); | ||
796 | |||
797 | err = msg_empty_list_init(byt); | ||
798 | if (err < 0) | ||
799 | return -ENOMEM; | ||
800 | |||
801 | /* start the IPC message thread */ | ||
802 | init_kthread_worker(&byt->kworker); | ||
803 | byt->tx_thread = kthread_run(kthread_worker_fn, | ||
804 | &byt->kworker, | ||
805 | dev_name(byt->dev)); | ||
806 | if (IS_ERR(byt->tx_thread)) { | ||
807 | err = PTR_ERR(byt->tx_thread); | ||
808 | dev_err(byt->dev, "error failed to create message TX task\n"); | ||
809 | goto err_free_msg; | ||
810 | } | ||
811 | init_kthread_work(&byt->kwork, sst_byt_ipc_tx_msgs); | ||
812 | |||
813 | byt_dev.thread_context = byt; | ||
814 | |||
815 | /* init SST shim */ | ||
816 | byt->dsp = sst_dsp_new(dev, &byt_dev, pdata); | ||
817 | if (byt->dsp == NULL) { | ||
818 | err = -ENODEV; | ||
819 | goto err_free_msg; | ||
820 | } | ||
821 | |||
822 | /* keep the DSP in reset state for base FW loading */ | ||
823 | sst_dsp_reset(byt->dsp); | ||
824 | |||
825 | byt_sst_fw = sst_fw_new(byt->dsp, pdata->fw, byt); | ||
826 | if (byt_sst_fw == NULL) { | ||
827 | err = -ENODEV; | ||
828 | dev_err(dev, "error: failed to load firmware\n"); | ||
829 | goto fw_err; | ||
830 | } | ||
831 | |||
832 | /* wait for DSP boot completion */ | ||
833 | sst_dsp_boot(byt->dsp); | ||
834 | err = wait_event_timeout(byt->boot_wait, byt->boot_complete, | ||
835 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
836 | if (err == 0) { | ||
837 | err = -EIO; | ||
838 | dev_err(byt->dev, "ipc: error DSP boot timeout\n"); | ||
839 | goto boot_err; | ||
840 | } | ||
841 | |||
842 | pdata->dsp = byt; | ||
843 | |||
844 | return 0; | ||
845 | |||
846 | boot_err: | ||
847 | sst_dsp_reset(byt->dsp); | ||
848 | sst_fw_free(byt_sst_fw); | ||
849 | fw_err: | ||
850 | sst_dsp_free(byt->dsp); | ||
851 | err_free_msg: | ||
852 | kfree(byt->msg); | ||
853 | |||
854 | return err; | ||
855 | } | ||
856 | EXPORT_SYMBOL_GPL(sst_byt_dsp_init); | ||
857 | |||
858 | void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata) | ||
859 | { | ||
860 | struct sst_byt *byt = pdata->dsp; | ||
861 | |||
862 | sst_dsp_reset(byt->dsp); | ||
863 | sst_fw_free_all(byt->dsp); | ||
864 | sst_dsp_free(byt->dsp); | ||
865 | kfree(byt->msg); | ||
866 | } | ||
867 | EXPORT_SYMBOL_GPL(sst_byt_dsp_free); | ||
diff --git a/sound/soc/intel/sst-baytrail-ipc.h b/sound/soc/intel/sst-baytrail-ipc.h new file mode 100644 index 000000000000..f172b6440fa9 --- /dev/null +++ b/sound/soc/intel/sst-baytrail-ipc.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Intel Baytrail SST IPC Support | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef __SST_BYT_IPC_H | ||
16 | #define __SST_BYT_IPC_H | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | |||
20 | struct sst_byt; | ||
21 | struct sst_byt_stream; | ||
22 | struct sst_pdata; | ||
23 | extern struct sst_ops sst_byt_ops; | ||
24 | |||
25 | |||
26 | #define SST_BYT_MAILBOX_OFFSET 0x144000 | ||
27 | #define SST_BYT_TIMESTAMP_OFFSET (SST_BYT_MAILBOX_OFFSET + 0x800) | ||
28 | |||
29 | /** | ||
30 | * Upfront defined maximum message size that is | ||
31 | * expected by the in/out communication pipes in FW. | ||
32 | */ | ||
33 | #define SST_BYT_IPC_MAX_PAYLOAD_SIZE 200 | ||
34 | |||
35 | /* stream API */ | ||
36 | struct sst_byt_stream *sst_byt_stream_new(struct sst_byt *byt, int id, | ||
37 | uint32_t (*get_write_position)(struct sst_byt_stream *stream, | ||
38 | void *data), | ||
39 | void *data); | ||
40 | |||
41 | /* stream configuration */ | ||
42 | int sst_byt_stream_set_bits(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
43 | int bits); | ||
44 | int sst_byt_stream_set_channels(struct sst_byt *byt, | ||
45 | struct sst_byt_stream *stream, u8 channels); | ||
46 | int sst_byt_stream_set_rate(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
47 | unsigned int rate); | ||
48 | int sst_byt_stream_type(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
49 | int codec_type, int stream_type, int operation); | ||
50 | int sst_byt_stream_buffer(struct sst_byt *byt, struct sst_byt_stream *stream, | ||
51 | uint32_t buffer_addr, uint32_t buffer_size); | ||
52 | int sst_byt_stream_commit(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
53 | int sst_byt_stream_free(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
54 | |||
55 | /* stream ALSA trigger operations */ | ||
56 | int sst_byt_stream_start(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
57 | int sst_byt_stream_stop(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
58 | int sst_byt_stream_pause(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
59 | int sst_byt_stream_resume(struct sst_byt *byt, struct sst_byt_stream *stream); | ||
60 | |||
61 | int sst_byt_get_dsp_position(struct sst_byt *byt, | ||
62 | struct sst_byt_stream *stream, int buffer_size); | ||
63 | |||
64 | /* init */ | ||
65 | int sst_byt_dsp_init(struct device *dev, struct sst_pdata *pdata); | ||
66 | void sst_byt_dsp_free(struct device *dev, struct sst_pdata *pdata); | ||
67 | struct sst_dsp *sst_byt_get_dsp(struct sst_byt *byt); | ||
68 | |||
69 | #endif | ||
diff --git a/sound/soc/intel/sst-baytrail-pcm.c b/sound/soc/intel/sst-baytrail-pcm.c new file mode 100644 index 000000000000..6d101f3813b4 --- /dev/null +++ b/sound/soc/intel/sst-baytrail-pcm.c | |||
@@ -0,0 +1,422 @@ | |||
1 | /* | ||
2 | * Intel Baytrail SST PCM Support | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/dma-mapping.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 "sst-baytrail-ipc.h" | ||
23 | #include "sst-dsp-priv.h" | ||
24 | #include "sst-dsp.h" | ||
25 | |||
26 | #define BYT_PCM_COUNT 2 | ||
27 | |||
28 | static const struct snd_pcm_hardware sst_byt_pcm_hardware = { | ||
29 | .info = SNDRV_PCM_INFO_MMAP | | ||
30 | SNDRV_PCM_INFO_MMAP_VALID | | ||
31 | SNDRV_PCM_INFO_INTERLEAVED | | ||
32 | SNDRV_PCM_INFO_PAUSE | | ||
33 | SNDRV_PCM_INFO_RESUME, | ||
34 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
35 | SNDRV_PCM_FORMAT_S24_LE, | ||
36 | .period_bytes_min = 384, | ||
37 | .period_bytes_max = 48000, | ||
38 | .periods_min = 2, | ||
39 | .periods_max = 250, | ||
40 | .buffer_bytes_max = 96000, | ||
41 | }; | ||
42 | |||
43 | /* private data for each PCM DSP stream */ | ||
44 | struct sst_byt_pcm_data { | ||
45 | struct sst_byt_stream *stream; | ||
46 | struct snd_pcm_substream *substream; | ||
47 | struct mutex mutex; | ||
48 | }; | ||
49 | |||
50 | /* private data for the driver */ | ||
51 | struct sst_byt_priv_data { | ||
52 | /* runtime DSP */ | ||
53 | struct sst_byt *byt; | ||
54 | |||
55 | /* DAI data */ | ||
56 | struct sst_byt_pcm_data pcm[BYT_PCM_COUNT]; | ||
57 | }; | ||
58 | |||
59 | /* this may get called several times by oss emulation */ | ||
60 | static int sst_byt_pcm_hw_params(struct snd_pcm_substream *substream, | ||
61 | struct snd_pcm_hw_params *params) | ||
62 | { | ||
63 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
64 | struct sst_byt_priv_data *pdata = | ||
65 | snd_soc_platform_get_drvdata(rtd->platform); | ||
66 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
67 | struct sst_byt *byt = pdata->byt; | ||
68 | u32 rate, bits; | ||
69 | u8 channels; | ||
70 | int ret, playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK); | ||
71 | |||
72 | dev_dbg(rtd->dev, "PCM: hw_params, pcm_data %p\n", pcm_data); | ||
73 | |||
74 | ret = sst_byt_stream_type(byt, pcm_data->stream, | ||
75 | 1, 1, !playback); | ||
76 | if (ret < 0) { | ||
77 | dev_err(rtd->dev, "failed to set stream format %d\n", ret); | ||
78 | return ret; | ||
79 | } | ||
80 | |||
81 | rate = params_rate(params); | ||
82 | ret = sst_byt_stream_set_rate(byt, pcm_data->stream, rate); | ||
83 | if (ret < 0) { | ||
84 | dev_err(rtd->dev, "could not set rate %d\n", rate); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | bits = snd_pcm_format_width(params_format(params)); | ||
89 | ret = sst_byt_stream_set_bits(byt, pcm_data->stream, bits); | ||
90 | if (ret < 0) { | ||
91 | dev_err(rtd->dev, "could not set formats %d\n", | ||
92 | params_rate(params)); | ||
93 | return ret; | ||
94 | } | ||
95 | |||
96 | channels = (u8)(params_channels(params) & 0xF); | ||
97 | ret = sst_byt_stream_set_channels(byt, pcm_data->stream, channels); | ||
98 | if (ret < 0) { | ||
99 | dev_err(rtd->dev, "could not set channels %d\n", | ||
100 | params_rate(params)); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
105 | |||
106 | ret = sst_byt_stream_buffer(byt, pcm_data->stream, | ||
107 | substream->dma_buffer.addr, | ||
108 | params_buffer_bytes(params)); | ||
109 | if (ret < 0) { | ||
110 | dev_err(rtd->dev, "PCM: failed to set DMA buffer %d\n", ret); | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | ret = sst_byt_stream_commit(byt, pcm_data->stream); | ||
115 | if (ret < 0) { | ||
116 | dev_err(rtd->dev, "PCM: failed stream commit %d\n", ret); | ||
117 | return ret; | ||
118 | } | ||
119 | |||
120 | return 0; | ||
121 | } | ||
122 | |||
123 | static int sst_byt_pcm_hw_free(struct snd_pcm_substream *substream) | ||
124 | { | ||
125 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
126 | |||
127 | dev_dbg(rtd->dev, "PCM: hw_free\n"); | ||
128 | snd_pcm_lib_free_pages(substream); | ||
129 | |||
130 | return 0; | ||
131 | } | ||
132 | |||
133 | static int sst_byt_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
134 | { | ||
135 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
136 | struct sst_byt_priv_data *pdata = | ||
137 | snd_soc_platform_get_drvdata(rtd->platform); | ||
138 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
139 | struct sst_byt *byt = pdata->byt; | ||
140 | |||
141 | dev_dbg(rtd->dev, "PCM: trigger %d\n", cmd); | ||
142 | |||
143 | switch (cmd) { | ||
144 | case SNDRV_PCM_TRIGGER_START: | ||
145 | sst_byt_stream_start(byt, pcm_data->stream); | ||
146 | break; | ||
147 | case SNDRV_PCM_TRIGGER_RESUME: | ||
148 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
149 | sst_byt_stream_resume(byt, pcm_data->stream); | ||
150 | break; | ||
151 | case SNDRV_PCM_TRIGGER_STOP: | ||
152 | sst_byt_stream_stop(byt, pcm_data->stream); | ||
153 | break; | ||
154 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
155 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
156 | sst_byt_stream_pause(byt, pcm_data->stream); | ||
157 | break; | ||
158 | default: | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static u32 byt_notify_pointer(struct sst_byt_stream *stream, void *data) | ||
166 | { | ||
167 | struct sst_byt_pcm_data *pcm_data = data; | ||
168 | struct snd_pcm_substream *substream = pcm_data->substream; | ||
169 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
170 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
171 | u32 pos; | ||
172 | |||
173 | pos = frames_to_bytes(runtime, | ||
174 | (runtime->control->appl_ptr % | ||
175 | runtime->buffer_size)); | ||
176 | |||
177 | dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | ||
178 | |||
179 | snd_pcm_period_elapsed(substream); | ||
180 | return pos; | ||
181 | } | ||
182 | |||
183 | static snd_pcm_uframes_t sst_byt_pcm_pointer(struct snd_pcm_substream *substream) | ||
184 | { | ||
185 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
186 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
187 | struct sst_byt_priv_data *pdata = | ||
188 | snd_soc_platform_get_drvdata(rtd->platform); | ||
189 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
190 | struct sst_byt *byt = pdata->byt; | ||
191 | snd_pcm_uframes_t offset; | ||
192 | int pos; | ||
193 | |||
194 | pos = sst_byt_get_dsp_position(byt, pcm_data->stream, | ||
195 | snd_pcm_lib_buffer_bytes(substream)); | ||
196 | offset = bytes_to_frames(runtime, pos); | ||
197 | |||
198 | dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", | ||
199 | frames_to_bytes(runtime, (u32)offset)); | ||
200 | return offset; | ||
201 | } | ||
202 | |||
203 | static int sst_byt_pcm_open(struct snd_pcm_substream *substream) | ||
204 | { | ||
205 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
206 | struct sst_byt_priv_data *pdata = | ||
207 | snd_soc_platform_get_drvdata(rtd->platform); | ||
208 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
209 | struct sst_byt *byt = pdata->byt; | ||
210 | |||
211 | dev_dbg(rtd->dev, "PCM: open\n"); | ||
212 | |||
213 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | ||
214 | mutex_lock(&pcm_data->mutex); | ||
215 | |||
216 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | ||
217 | pcm_data->substream = substream; | ||
218 | |||
219 | snd_soc_set_runtime_hwparams(substream, &sst_byt_pcm_hardware); | ||
220 | |||
221 | pcm_data->stream = sst_byt_stream_new(byt, rtd->cpu_dai->id + 1, | ||
222 | byt_notify_pointer, pcm_data); | ||
223 | if (pcm_data->stream == NULL) { | ||
224 | dev_err(rtd->dev, "failed to create stream\n"); | ||
225 | mutex_unlock(&pcm_data->mutex); | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | |||
229 | mutex_unlock(&pcm_data->mutex); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int sst_byt_pcm_close(struct snd_pcm_substream *substream) | ||
234 | { | ||
235 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
236 | struct sst_byt_priv_data *pdata = | ||
237 | snd_soc_platform_get_drvdata(rtd->platform); | ||
238 | struct sst_byt_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
239 | struct sst_byt *byt = pdata->byt; | ||
240 | int ret; | ||
241 | |||
242 | dev_dbg(rtd->dev, "PCM: close\n"); | ||
243 | |||
244 | mutex_lock(&pcm_data->mutex); | ||
245 | ret = sst_byt_stream_free(byt, pcm_data->stream); | ||
246 | if (ret < 0) { | ||
247 | dev_dbg(rtd->dev, "Free stream fail\n"); | ||
248 | goto out; | ||
249 | } | ||
250 | pcm_data->stream = NULL; | ||
251 | |||
252 | out: | ||
253 | mutex_unlock(&pcm_data->mutex); | ||
254 | return ret; | ||
255 | } | ||
256 | |||
257 | static int sst_byt_pcm_mmap(struct snd_pcm_substream *substream, | ||
258 | struct vm_area_struct *vma) | ||
259 | { | ||
260 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
261 | |||
262 | dev_dbg(rtd->dev, "PCM: mmap\n"); | ||
263 | return snd_pcm_lib_default_mmap(substream, vma); | ||
264 | } | ||
265 | |||
266 | static struct snd_pcm_ops sst_byt_pcm_ops = { | ||
267 | .open = sst_byt_pcm_open, | ||
268 | .close = sst_byt_pcm_close, | ||
269 | .ioctl = snd_pcm_lib_ioctl, | ||
270 | .hw_params = sst_byt_pcm_hw_params, | ||
271 | .hw_free = sst_byt_pcm_hw_free, | ||
272 | .trigger = sst_byt_pcm_trigger, | ||
273 | .pointer = sst_byt_pcm_pointer, | ||
274 | .mmap = sst_byt_pcm_mmap, | ||
275 | }; | ||
276 | |||
277 | static void sst_byt_pcm_free(struct snd_pcm *pcm) | ||
278 | { | ||
279 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
280 | } | ||
281 | |||
282 | static int sst_byt_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
283 | { | ||
284 | struct snd_pcm *pcm = rtd->pcm; | ||
285 | size_t size; | ||
286 | int ret = 0; | ||
287 | |||
288 | ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); | ||
289 | if (ret) | ||
290 | return ret; | ||
291 | |||
292 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | ||
293 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
294 | size = sst_byt_pcm_hardware.buffer_bytes_max; | ||
295 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
296 | SNDRV_DMA_TYPE_DEV, | ||
297 | rtd->card->dev, | ||
298 | size, size); | ||
299 | if (ret) { | ||
300 | dev_err(rtd->dev, "dma buffer allocation failed %d\n", | ||
301 | ret); | ||
302 | return ret; | ||
303 | } | ||
304 | } | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | static struct snd_soc_dai_driver byt_dais[] = { | ||
310 | { | ||
311 | .name = "Front-cpu-dai", | ||
312 | .playback = { | ||
313 | .stream_name = "System Playback", | ||
314 | .channels_min = 2, | ||
315 | .channels_max = 2, | ||
316 | .rates = SNDRV_PCM_RATE_48000, | ||
317 | .formats = SNDRV_PCM_FMTBIT_S24_3LE | | ||
318 | SNDRV_PCM_FMTBIT_S16_LE, | ||
319 | }, | ||
320 | }, | ||
321 | { | ||
322 | .name = "Mic1-cpu-dai", | ||
323 | .capture = { | ||
324 | .stream_name = "Analog Capture", | ||
325 | .channels_min = 2, | ||
326 | .channels_max = 2, | ||
327 | .rates = SNDRV_PCM_RATE_48000, | ||
328 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
329 | }, | ||
330 | }, | ||
331 | }; | ||
332 | |||
333 | static int sst_byt_pcm_probe(struct snd_soc_platform *platform) | ||
334 | { | ||
335 | struct sst_pdata *plat_data = dev_get_platdata(platform->dev); | ||
336 | struct sst_byt_priv_data *priv_data; | ||
337 | int i; | ||
338 | |||
339 | if (!plat_data) | ||
340 | return -ENODEV; | ||
341 | |||
342 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), | ||
343 | GFP_KERNEL); | ||
344 | priv_data->byt = plat_data->dsp; | ||
345 | snd_soc_platform_set_drvdata(platform, priv_data); | ||
346 | |||
347 | for (i = 0; i < ARRAY_SIZE(byt_dais); i++) | ||
348 | mutex_init(&priv_data->pcm[i].mutex); | ||
349 | |||
350 | return 0; | ||
351 | } | ||
352 | |||
353 | static int sst_byt_pcm_remove(struct snd_soc_platform *platform) | ||
354 | { | ||
355 | return 0; | ||
356 | } | ||
357 | |||
358 | static struct snd_soc_platform_driver byt_soc_platform = { | ||
359 | .probe = sst_byt_pcm_probe, | ||
360 | .remove = sst_byt_pcm_remove, | ||
361 | .ops = &sst_byt_pcm_ops, | ||
362 | .pcm_new = sst_byt_pcm_new, | ||
363 | .pcm_free = sst_byt_pcm_free, | ||
364 | }; | ||
365 | |||
366 | static const struct snd_soc_component_driver byt_dai_component = { | ||
367 | .name = "byt-dai", | ||
368 | }; | ||
369 | |||
370 | static int sst_byt_pcm_dev_probe(struct platform_device *pdev) | ||
371 | { | ||
372 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
373 | int ret; | ||
374 | |||
375 | ret = sst_byt_dsp_init(&pdev->dev, sst_pdata); | ||
376 | if (ret < 0) | ||
377 | return -ENODEV; | ||
378 | |||
379 | ret = snd_soc_register_platform(&pdev->dev, &byt_soc_platform); | ||
380 | if (ret < 0) | ||
381 | goto err_plat; | ||
382 | |||
383 | ret = snd_soc_register_component(&pdev->dev, &byt_dai_component, | ||
384 | byt_dais, ARRAY_SIZE(byt_dais)); | ||
385 | if (ret < 0) | ||
386 | goto err_comp; | ||
387 | |||
388 | return 0; | ||
389 | |||
390 | err_comp: | ||
391 | snd_soc_unregister_platform(&pdev->dev); | ||
392 | err_plat: | ||
393 | sst_byt_dsp_free(&pdev->dev, sst_pdata); | ||
394 | return ret; | ||
395 | } | ||
396 | |||
397 | static int sst_byt_pcm_dev_remove(struct platform_device *pdev) | ||
398 | { | ||
399 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
400 | |||
401 | snd_soc_unregister_platform(&pdev->dev); | ||
402 | snd_soc_unregister_component(&pdev->dev); | ||
403 | sst_byt_dsp_free(&pdev->dev, sst_pdata); | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static struct platform_driver sst_byt_pcm_driver = { | ||
409 | .driver = { | ||
410 | .name = "baytrail-pcm-audio", | ||
411 | .owner = THIS_MODULE, | ||
412 | }, | ||
413 | |||
414 | .probe = sst_byt_pcm_dev_probe, | ||
415 | .remove = sst_byt_pcm_dev_remove, | ||
416 | }; | ||
417 | module_platform_driver(sst_byt_pcm_driver); | ||
418 | |||
419 | MODULE_AUTHOR("Jarkko Nikula"); | ||
420 | MODULE_DESCRIPTION("Baytrail PCM"); | ||
421 | MODULE_LICENSE("GPL v2"); | ||
422 | MODULE_ALIAS("platform:baytrail-pcm-audio"); | ||
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h new file mode 100644 index 000000000000..fe8e81aad646 --- /dev/null +++ b/sound/soc/intel/sst-dsp-priv.h | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * Intel Smart Sound Technology | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __SOUND_SOC_SST_DSP_PRIV_H | ||
18 | #define __SOUND_SOC_SST_DSP_PRIV_H | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/firmware.h> | ||
24 | |||
25 | struct sst_mem_block; | ||
26 | struct sst_module; | ||
27 | struct sst_fw; | ||
28 | |||
29 | /* | ||
30 | * DSP Operations exported by platform Audio DSP driver. | ||
31 | */ | ||
32 | struct sst_ops { | ||
33 | /* DSP core boot / reset */ | ||
34 | void (*boot)(struct sst_dsp *); | ||
35 | void (*reset)(struct sst_dsp *); | ||
36 | |||
37 | /* Shim IO */ | ||
38 | void (*write)(void __iomem *addr, u32 offset, u32 value); | ||
39 | u32 (*read)(void __iomem *addr, u32 offset); | ||
40 | void (*write64)(void __iomem *addr, u32 offset, u64 value); | ||
41 | u64 (*read64)(void __iomem *addr, u32 offset); | ||
42 | |||
43 | /* DSP I/DRAM IO */ | ||
44 | void (*ram_read)(struct sst_dsp *sst, void *dest, void __iomem *src, | ||
45 | size_t bytes); | ||
46 | void (*ram_write)(struct sst_dsp *sst, void __iomem *dest, void *src, | ||
47 | size_t bytes); | ||
48 | |||
49 | void (*dump)(struct sst_dsp *); | ||
50 | |||
51 | /* IRQ handlers */ | ||
52 | irqreturn_t (*irq_handler)(int irq, void *context); | ||
53 | |||
54 | /* SST init and free */ | ||
55 | int (*init)(struct sst_dsp *sst, struct sst_pdata *pdata); | ||
56 | void (*free)(struct sst_dsp *sst); | ||
57 | |||
58 | /* FW module parser/loader */ | ||
59 | int (*parse_fw)(struct sst_fw *sst_fw); | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * Audio DSP memory offsets and addresses. | ||
64 | */ | ||
65 | struct sst_addr { | ||
66 | u32 lpe_base; | ||
67 | u32 shim_offset; | ||
68 | u32 iram_offset; | ||
69 | u32 dram_offset; | ||
70 | void __iomem *lpe; | ||
71 | void __iomem *shim; | ||
72 | void __iomem *pci_cfg; | ||
73 | void __iomem *fw_ext; | ||
74 | }; | ||
75 | |||
76 | /* | ||
77 | * Audio DSP Mailbox configuration. | ||
78 | */ | ||
79 | struct sst_mailbox { | ||
80 | void __iomem *in_base; | ||
81 | void __iomem *out_base; | ||
82 | size_t in_size; | ||
83 | size_t out_size; | ||
84 | }; | ||
85 | |||
86 | /* | ||
87 | * Audio DSP Firmware data types. | ||
88 | */ | ||
89 | enum sst_data_type { | ||
90 | SST_DATA_M = 0, /* module block data */ | ||
91 | SST_DATA_P = 1, /* peristant data (text, data) */ | ||
92 | SST_DATA_S = 2, /* scratch data (usually buffers) */ | ||
93 | }; | ||
94 | |||
95 | /* | ||
96 | * Audio DSP memory block types. | ||
97 | */ | ||
98 | enum sst_mem_type { | ||
99 | SST_MEM_IRAM = 0, | ||
100 | SST_MEM_DRAM = 1, | ||
101 | SST_MEM_ANY = 2, | ||
102 | SST_MEM_CACHE= 3, | ||
103 | }; | ||
104 | |||
105 | /* | ||
106 | * Audio DSP Generic Firmware File. | ||
107 | * | ||
108 | * SST Firmware files can consist of 1..N modules. This generic structure is | ||
109 | * used to manage each firmware file and it's modules regardless of SST firmware | ||
110 | * type. A SST driver may load multiple FW files. | ||
111 | */ | ||
112 | struct sst_fw { | ||
113 | struct sst_dsp *dsp; | ||
114 | |||
115 | /* base addresses of FW file data */ | ||
116 | dma_addr_t dmable_fw_paddr; /* physical address of fw data */ | ||
117 | void *dma_buf; /* virtual address of fw data */ | ||
118 | u32 size; /* size of fw data */ | ||
119 | |||
120 | /* lists */ | ||
121 | struct list_head list; /* DSP list of FW */ | ||
122 | struct list_head module_list; /* FW list of modules */ | ||
123 | |||
124 | void *private; /* core doesn't touch this */ | ||
125 | }; | ||
126 | |||
127 | /* | ||
128 | * Audio DSP Generic Module data. | ||
129 | * | ||
130 | * This is used to dsecribe any sections of persistent (text and data) and | ||
131 | * scratch (buffers) of module data in ADSP memory space. | ||
132 | */ | ||
133 | struct sst_module_data { | ||
134 | |||
135 | enum sst_mem_type type; /* destination memory type */ | ||
136 | enum sst_data_type data_type; /* type of module data */ | ||
137 | |||
138 | u32 size; /* size in bytes */ | ||
139 | u32 offset; /* offset in FW file */ | ||
140 | u32 data_offset; /* offset in ADSP memory space */ | ||
141 | void *data; /* module data */ | ||
142 | }; | ||
143 | |||
144 | /* | ||
145 | * Audio DSP Generic Module Template. | ||
146 | * | ||
147 | * Used to define and register a new FW module. This data is extracted from | ||
148 | * FW module header information. | ||
149 | */ | ||
150 | struct sst_module_template { | ||
151 | u32 id; | ||
152 | u32 entry; /* entry point */ | ||
153 | struct sst_module_data s; /* scratch data */ | ||
154 | struct sst_module_data p; /* peristant data */ | ||
155 | }; | ||
156 | |||
157 | /* | ||
158 | * Audio DSP Generic Module. | ||
159 | * | ||
160 | * Each Firmware file can consist of 1..N modules. A module can span multiple | ||
161 | * ADSP memory blocks. The simplest FW will be a file with 1 module. | ||
162 | */ | ||
163 | struct sst_module { | ||
164 | struct sst_dsp *dsp; | ||
165 | struct sst_fw *sst_fw; /* parent FW we belong too */ | ||
166 | |||
167 | /* module configuration */ | ||
168 | u32 id; | ||
169 | u32 entry; /* module entry point */ | ||
170 | u32 offset; /* module offset in firmware file */ | ||
171 | u32 size; /* module size */ | ||
172 | struct sst_module_data s; /* scratch data */ | ||
173 | struct sst_module_data p; /* peristant data */ | ||
174 | |||
175 | /* runtime */ | ||
176 | u32 usage_count; /* can be unloaded if count == 0 */ | ||
177 | void *private; /* core doesn't touch this */ | ||
178 | |||
179 | /* lists */ | ||
180 | struct list_head block_list; /* Module list of blocks in use */ | ||
181 | struct list_head list; /* DSP list of modules */ | ||
182 | struct list_head list_fw; /* FW list of modules */ | ||
183 | }; | ||
184 | |||
185 | /* | ||
186 | * SST Memory Block operations. | ||
187 | */ | ||
188 | struct sst_block_ops { | ||
189 | int (*enable)(struct sst_mem_block *block); | ||
190 | int (*disable)(struct sst_mem_block *block); | ||
191 | }; | ||
192 | |||
193 | /* | ||
194 | * SST Generic Memory Block. | ||
195 | * | ||
196 | * SST ADP memory has multiple IRAM and DRAM blocks. Some ADSP blocks can be | ||
197 | * power gated. | ||
198 | */ | ||
199 | struct sst_mem_block { | ||
200 | struct sst_dsp *dsp; | ||
201 | struct sst_module *module; /* module that uses this block */ | ||
202 | |||
203 | /* block config */ | ||
204 | u32 offset; /* offset from base */ | ||
205 | u32 size; /* block size */ | ||
206 | u32 index; /* block index 0..N */ | ||
207 | enum sst_mem_type type; /* block memory type IRAM/DRAM */ | ||
208 | struct sst_block_ops *ops; /* block operations, if any */ | ||
209 | |||
210 | /* block status */ | ||
211 | enum sst_data_type data_type; /* data type held in this block */ | ||
212 | u32 bytes_used; /* bytes in use by modules */ | ||
213 | void *private; /* generic core does not touch this */ | ||
214 | int users; /* number of modules using this block */ | ||
215 | |||
216 | /* block lists */ | ||
217 | struct list_head module_list; /* Module list of blocks */ | ||
218 | struct list_head list; /* Map list of free/used blocks */ | ||
219 | }; | ||
220 | |||
221 | /* | ||
222 | * Generic SST Shim Interface. | ||
223 | */ | ||
224 | struct sst_dsp { | ||
225 | |||
226 | /* runtime */ | ||
227 | struct sst_dsp_device *sst_dev; | ||
228 | spinlock_t spinlock; /* IPC locking */ | ||
229 | struct mutex mutex; /* DSP FW lock */ | ||
230 | struct device *dev; | ||
231 | void *thread_context; | ||
232 | int irq; | ||
233 | u32 id; | ||
234 | |||
235 | /* list of free and used ADSP memory blocks */ | ||
236 | struct list_head used_block_list; | ||
237 | struct list_head free_block_list; | ||
238 | |||
239 | /* operations */ | ||
240 | struct sst_ops *ops; | ||
241 | |||
242 | /* debug FS */ | ||
243 | struct dentry *debugfs_root; | ||
244 | |||
245 | /* base addresses */ | ||
246 | struct sst_addr addr; | ||
247 | |||
248 | /* mailbox */ | ||
249 | struct sst_mailbox mailbox; | ||
250 | |||
251 | /* SST FW files loaded and their modules */ | ||
252 | struct list_head module_list; | ||
253 | struct list_head fw_list; | ||
254 | |||
255 | /* platform data */ | ||
256 | struct sst_pdata *pdata; | ||
257 | |||
258 | /* DMA FW loading */ | ||
259 | struct sst_dma *dma; | ||
260 | bool fw_use_dma; | ||
261 | }; | ||
262 | |||
263 | /* Size optimised DRAM/IRAM memcpy */ | ||
264 | static inline void sst_dsp_write(struct sst_dsp *sst, void *src, | ||
265 | u32 dest_offset, size_t bytes) | ||
266 | { | ||
267 | sst->ops->ram_write(sst, sst->addr.lpe + dest_offset, src, bytes); | ||
268 | } | ||
269 | |||
270 | static inline void sst_dsp_read(struct sst_dsp *sst, void *dest, | ||
271 | u32 src_offset, size_t bytes) | ||
272 | { | ||
273 | sst->ops->ram_read(sst, dest, sst->addr.lpe + src_offset, bytes); | ||
274 | } | ||
275 | |||
276 | static inline void *sst_dsp_get_thread_context(struct sst_dsp *sst) | ||
277 | { | ||
278 | return sst->thread_context; | ||
279 | } | ||
280 | |||
281 | /* Create/Free FW files - can contain multiple modules */ | ||
282 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | ||
283 | const struct firmware *fw, void *private); | ||
284 | void sst_fw_free(struct sst_fw *sst_fw); | ||
285 | void sst_fw_free_all(struct sst_dsp *dsp); | ||
286 | |||
287 | /* Create/Free firmware modules */ | ||
288 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, | ||
289 | struct sst_module_template *template, void *private); | ||
290 | void sst_module_free(struct sst_module *sst_module); | ||
291 | int sst_module_insert(struct sst_module *sst_module); | ||
292 | int sst_module_remove(struct sst_module *sst_module); | ||
293 | int sst_module_insert_fixed_block(struct sst_module *module, | ||
294 | struct sst_module_data *data); | ||
295 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id); | ||
296 | |||
297 | /* allocate/free pesistent/scratch memory regions managed by drv */ | ||
298 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp); | ||
299 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | ||
300 | struct sst_module *scratch); | ||
301 | int sst_block_module_remove(struct sst_module *module); | ||
302 | |||
303 | /* Register the DSPs memory blocks - would be nice to read from ACPI */ | ||
304 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | ||
305 | u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, | ||
306 | void *private); | ||
307 | void sst_mem_block_unregister_all(struct sst_dsp *dsp); | ||
308 | |||
309 | #endif | ||
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c new file mode 100644 index 000000000000..0c129fd85ecf --- /dev/null +++ b/sound/soc/intel/sst-dsp.c | |||
@@ -0,0 +1,385 @@ | |||
1 | /* | ||
2 | * Intel Smart Sound Technology (SST) DSP Core Driver | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/slab.h> | ||
18 | #include <linux/export.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/platform_device.h> | ||
22 | #include <linux/io.h> | ||
23 | |||
24 | #include "sst-dsp.h" | ||
25 | #include "sst-dsp-priv.h" | ||
26 | |||
27 | #define CREATE_TRACE_POINTS | ||
28 | #include <trace/events/intel-sst.h> | ||
29 | |||
30 | /* Internal generic low-level SST IO functions - can be overidden */ | ||
31 | void sst_shim32_write(void __iomem *addr, u32 offset, u32 value) | ||
32 | { | ||
33 | writel(value, addr + offset); | ||
34 | } | ||
35 | EXPORT_SYMBOL_GPL(sst_shim32_write); | ||
36 | |||
37 | u32 sst_shim32_read(void __iomem *addr, u32 offset) | ||
38 | { | ||
39 | return readl(addr + offset); | ||
40 | } | ||
41 | EXPORT_SYMBOL_GPL(sst_shim32_read); | ||
42 | |||
43 | void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value) | ||
44 | { | ||
45 | memcpy_toio(addr + offset, &value, sizeof(value)); | ||
46 | } | ||
47 | EXPORT_SYMBOL_GPL(sst_shim32_write64); | ||
48 | |||
49 | u64 sst_shim32_read64(void __iomem *addr, u32 offset) | ||
50 | { | ||
51 | u64 val; | ||
52 | |||
53 | memcpy_fromio(&val, addr + offset, sizeof(val)); | ||
54 | return val; | ||
55 | } | ||
56 | EXPORT_SYMBOL_GPL(sst_shim32_read64); | ||
57 | |||
58 | static inline void _sst_memcpy_toio_32(volatile u32 __iomem *dest, | ||
59 | u32 *src, size_t bytes) | ||
60 | { | ||
61 | int i, words = bytes >> 2; | ||
62 | |||
63 | for (i = 0; i < words; i++) | ||
64 | writel(src[i], dest + i); | ||
65 | } | ||
66 | |||
67 | static inline void _sst_memcpy_fromio_32(u32 *dest, | ||
68 | const volatile __iomem u32 *src, size_t bytes) | ||
69 | { | ||
70 | int i, words = bytes >> 2; | ||
71 | |||
72 | for (i = 0; i < words; i++) | ||
73 | dest[i] = readl(src + i); | ||
74 | } | ||
75 | |||
76 | void sst_memcpy_toio_32(struct sst_dsp *sst, | ||
77 | void __iomem *dest, void *src, size_t bytes) | ||
78 | { | ||
79 | _sst_memcpy_toio_32(dest, src, bytes); | ||
80 | } | ||
81 | EXPORT_SYMBOL_GPL(sst_memcpy_toio_32); | ||
82 | |||
83 | void sst_memcpy_fromio_32(struct sst_dsp *sst, void *dest, | ||
84 | void __iomem *src, size_t bytes) | ||
85 | { | ||
86 | _sst_memcpy_fromio_32(dest, src, bytes); | ||
87 | } | ||
88 | EXPORT_SYMBOL_GPL(sst_memcpy_fromio_32); | ||
89 | |||
90 | /* Public API */ | ||
91 | void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value) | ||
92 | { | ||
93 | unsigned long flags; | ||
94 | |||
95 | spin_lock_irqsave(&sst->spinlock, flags); | ||
96 | sst->ops->write(sst->addr.shim, offset, value); | ||
97 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
98 | } | ||
99 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write); | ||
100 | |||
101 | u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset) | ||
102 | { | ||
103 | unsigned long flags; | ||
104 | u32 val; | ||
105 | |||
106 | spin_lock_irqsave(&sst->spinlock, flags); | ||
107 | val = sst->ops->read(sst->addr.shim, offset); | ||
108 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
109 | |||
110 | return val; | ||
111 | } | ||
112 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read); | ||
113 | |||
114 | void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value) | ||
115 | { | ||
116 | unsigned long flags; | ||
117 | |||
118 | spin_lock_irqsave(&sst->spinlock, flags); | ||
119 | sst->ops->write64(sst->addr.shim, offset, value); | ||
120 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
121 | } | ||
122 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write64); | ||
123 | |||
124 | u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset) | ||
125 | { | ||
126 | unsigned long flags; | ||
127 | u64 val; | ||
128 | |||
129 | spin_lock_irqsave(&sst->spinlock, flags); | ||
130 | val = sst->ops->read64(sst->addr.shim, offset); | ||
131 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
132 | |||
133 | return val; | ||
134 | } | ||
135 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read64); | ||
136 | |||
137 | void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value) | ||
138 | { | ||
139 | sst->ops->write(sst->addr.shim, offset, value); | ||
140 | } | ||
141 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write_unlocked); | ||
142 | |||
143 | u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset) | ||
144 | { | ||
145 | return sst->ops->read(sst->addr.shim, offset); | ||
146 | } | ||
147 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read_unlocked); | ||
148 | |||
149 | void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value) | ||
150 | { | ||
151 | sst->ops->write64(sst->addr.shim, offset, value); | ||
152 | } | ||
153 | EXPORT_SYMBOL_GPL(sst_dsp_shim_write64_unlocked); | ||
154 | |||
155 | u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset) | ||
156 | { | ||
157 | return sst->ops->read64(sst->addr.shim, offset); | ||
158 | } | ||
159 | EXPORT_SYMBOL_GPL(sst_dsp_shim_read64_unlocked); | ||
160 | |||
161 | int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, | ||
162 | u32 mask, u32 value) | ||
163 | { | ||
164 | bool change; | ||
165 | unsigned int old, new; | ||
166 | u32 ret; | ||
167 | |||
168 | ret = sst_dsp_shim_read_unlocked(sst, offset); | ||
169 | |||
170 | old = ret; | ||
171 | new = (old & (~mask)) | (value & mask); | ||
172 | |||
173 | change = (old != new); | ||
174 | if (change) | ||
175 | sst_dsp_shim_write_unlocked(sst, offset, new); | ||
176 | |||
177 | return change; | ||
178 | } | ||
179 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_unlocked); | ||
180 | |||
181 | int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, | ||
182 | u64 mask, u64 value) | ||
183 | { | ||
184 | bool change; | ||
185 | u64 old, new; | ||
186 | |||
187 | old = sst_dsp_shim_read64_unlocked(sst, offset); | ||
188 | |||
189 | new = (old & (~mask)) | (value & mask); | ||
190 | |||
191 | change = (old != new); | ||
192 | if (change) | ||
193 | sst_dsp_shim_write64_unlocked(sst, offset, new); | ||
194 | |||
195 | return change; | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked); | ||
198 | |||
199 | int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, | ||
200 | u32 mask, u32 value) | ||
201 | { | ||
202 | unsigned long flags; | ||
203 | bool change; | ||
204 | |||
205 | spin_lock_irqsave(&sst->spinlock, flags); | ||
206 | change = sst_dsp_shim_update_bits_unlocked(sst, offset, mask, value); | ||
207 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
208 | return change; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits); | ||
211 | |||
212 | int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, | ||
213 | u64 mask, u64 value) | ||
214 | { | ||
215 | unsigned long flags; | ||
216 | bool change; | ||
217 | |||
218 | spin_lock_irqsave(&sst->spinlock, flags); | ||
219 | change = sst_dsp_shim_update_bits64_unlocked(sst, offset, mask, value); | ||
220 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
221 | return change; | ||
222 | } | ||
223 | EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); | ||
224 | |||
225 | void sst_dsp_dump(struct sst_dsp *sst) | ||
226 | { | ||
227 | sst->ops->dump(sst); | ||
228 | } | ||
229 | EXPORT_SYMBOL_GPL(sst_dsp_dump); | ||
230 | |||
231 | void sst_dsp_reset(struct sst_dsp *sst) | ||
232 | { | ||
233 | sst->ops->reset(sst); | ||
234 | } | ||
235 | EXPORT_SYMBOL_GPL(sst_dsp_reset); | ||
236 | |||
237 | int sst_dsp_boot(struct sst_dsp *sst) | ||
238 | { | ||
239 | sst->ops->boot(sst); | ||
240 | return 0; | ||
241 | } | ||
242 | EXPORT_SYMBOL_GPL(sst_dsp_boot); | ||
243 | |||
244 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg) | ||
245 | { | ||
246 | sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY); | ||
247 | trace_sst_ipc_msg_tx(msg); | ||
248 | } | ||
249 | EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_tx); | ||
250 | |||
251 | u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp) | ||
252 | { | ||
253 | u32 msg; | ||
254 | |||
255 | msg = sst_dsp_shim_read_unlocked(dsp, SST_IPCX); | ||
256 | trace_sst_ipc_msg_rx(msg); | ||
257 | |||
258 | return msg; | ||
259 | } | ||
260 | EXPORT_SYMBOL_GPL(sst_dsp_ipc_msg_rx); | ||
261 | |||
262 | int sst_dsp_mailbox_init(struct sst_dsp *sst, u32 inbox_offset, size_t inbox_size, | ||
263 | u32 outbox_offset, size_t outbox_size) | ||
264 | { | ||
265 | sst->mailbox.in_base = sst->addr.lpe + inbox_offset; | ||
266 | sst->mailbox.out_base = sst->addr.lpe + outbox_offset; | ||
267 | sst->mailbox.in_size = inbox_size; | ||
268 | sst->mailbox.out_size = outbox_size; | ||
269 | return 0; | ||
270 | } | ||
271 | EXPORT_SYMBOL_GPL(sst_dsp_mailbox_init); | ||
272 | |||
273 | void sst_dsp_outbox_write(struct sst_dsp *sst, void *message, size_t bytes) | ||
274 | { | ||
275 | u32 i; | ||
276 | |||
277 | trace_sst_ipc_outbox_write(bytes); | ||
278 | |||
279 | memcpy_toio(sst->mailbox.out_base, message, bytes); | ||
280 | |||
281 | for (i = 0; i < bytes; i += 4) | ||
282 | trace_sst_ipc_outbox_wdata(i, *(u32 *)(message + i)); | ||
283 | } | ||
284 | EXPORT_SYMBOL_GPL(sst_dsp_outbox_write); | ||
285 | |||
286 | void sst_dsp_outbox_read(struct sst_dsp *sst, void *message, size_t bytes) | ||
287 | { | ||
288 | u32 i; | ||
289 | |||
290 | trace_sst_ipc_outbox_read(bytes); | ||
291 | |||
292 | memcpy_fromio(message, sst->mailbox.out_base, bytes); | ||
293 | |||
294 | for (i = 0; i < bytes; i += 4) | ||
295 | trace_sst_ipc_outbox_rdata(i, *(u32 *)(message + i)); | ||
296 | } | ||
297 | EXPORT_SYMBOL_GPL(sst_dsp_outbox_read); | ||
298 | |||
299 | void sst_dsp_inbox_write(struct sst_dsp *sst, void *message, size_t bytes) | ||
300 | { | ||
301 | u32 i; | ||
302 | |||
303 | trace_sst_ipc_inbox_write(bytes); | ||
304 | |||
305 | memcpy_toio(sst->mailbox.in_base, message, bytes); | ||
306 | |||
307 | for (i = 0; i < bytes; i += 4) | ||
308 | trace_sst_ipc_inbox_wdata(i, *(u32 *)(message + i)); | ||
309 | } | ||
310 | EXPORT_SYMBOL_GPL(sst_dsp_inbox_write); | ||
311 | |||
312 | void sst_dsp_inbox_read(struct sst_dsp *sst, void *message, size_t bytes) | ||
313 | { | ||
314 | u32 i; | ||
315 | |||
316 | trace_sst_ipc_inbox_read(bytes); | ||
317 | |||
318 | memcpy_fromio(message, sst->mailbox.in_base, bytes); | ||
319 | |||
320 | for (i = 0; i < bytes; i += 4) | ||
321 | trace_sst_ipc_inbox_rdata(i, *(u32 *)(message + i)); | ||
322 | } | ||
323 | EXPORT_SYMBOL_GPL(sst_dsp_inbox_read); | ||
324 | |||
325 | struct sst_dsp *sst_dsp_new(struct device *dev, | ||
326 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata) | ||
327 | { | ||
328 | struct sst_dsp *sst; | ||
329 | int err; | ||
330 | |||
331 | dev_dbg(dev, "initialising audio DSP id 0x%x\n", pdata->id); | ||
332 | |||
333 | sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); | ||
334 | if (sst == NULL) | ||
335 | return NULL; | ||
336 | |||
337 | spin_lock_init(&sst->spinlock); | ||
338 | mutex_init(&sst->mutex); | ||
339 | sst->dev = dev; | ||
340 | sst->thread_context = sst_dev->thread_context; | ||
341 | sst->sst_dev = sst_dev; | ||
342 | sst->id = pdata->id; | ||
343 | sst->irq = pdata->irq; | ||
344 | sst->ops = sst_dev->ops; | ||
345 | sst->pdata = pdata; | ||
346 | INIT_LIST_HEAD(&sst->used_block_list); | ||
347 | INIT_LIST_HEAD(&sst->free_block_list); | ||
348 | INIT_LIST_HEAD(&sst->module_list); | ||
349 | INIT_LIST_HEAD(&sst->fw_list); | ||
350 | |||
351 | /* Initialise SST Audio DSP */ | ||
352 | if (sst->ops->init) { | ||
353 | err = sst->ops->init(sst, pdata); | ||
354 | if (err < 0) | ||
355 | return NULL; | ||
356 | } | ||
357 | |||
358 | /* Register the ISR */ | ||
359 | err = request_threaded_irq(sst->irq, sst->ops->irq_handler, | ||
360 | sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); | ||
361 | if (err) | ||
362 | goto irq_err; | ||
363 | |||
364 | return sst; | ||
365 | |||
366 | irq_err: | ||
367 | if (sst->ops->free) | ||
368 | sst->ops->free(sst); | ||
369 | |||
370 | return NULL; | ||
371 | } | ||
372 | EXPORT_SYMBOL_GPL(sst_dsp_new); | ||
373 | |||
374 | void sst_dsp_free(struct sst_dsp *sst) | ||
375 | { | ||
376 | free_irq(sst->irq, sst); | ||
377 | if (sst->ops->free) | ||
378 | sst->ops->free(sst); | ||
379 | } | ||
380 | EXPORT_SYMBOL_GPL(sst_dsp_free); | ||
381 | |||
382 | /* Module information */ | ||
383 | MODULE_AUTHOR("Liam Girdwood"); | ||
384 | MODULE_DESCRIPTION("Intel SST Core"); | ||
385 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h new file mode 100644 index 000000000000..74052b59485c --- /dev/null +++ b/sound/soc/intel/sst-dsp.h | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * Intel Smart Sound Technology (SST) Core | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __SOUND_SOC_SST_DSP_H | ||
18 | #define __SOUND_SOC_SST_DSP_H | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | |||
24 | /* SST Device IDs */ | ||
25 | #define SST_DEV_ID_LYNX_POINT 0x33C8 | ||
26 | #define SST_DEV_ID_WILDCAT_POINT 0x3438 | ||
27 | #define SST_DEV_ID_BYT 0x0F28 | ||
28 | |||
29 | /* Supported SST DMA Devices */ | ||
30 | #define SST_DMA_TYPE_DW 1 | ||
31 | #define SST_DMA_TYPE_MID 2 | ||
32 | |||
33 | /* SST Shim register map | ||
34 | * The register naming can differ between products. Some products also | ||
35 | * contain extra functionality. | ||
36 | */ | ||
37 | #define SST_CSR 0x00 | ||
38 | #define SST_PISR 0x08 | ||
39 | #define SST_PIMR 0x10 | ||
40 | #define SST_ISRX 0x18 | ||
41 | #define SST_ISRD 0x20 | ||
42 | #define SST_IMRX 0x28 | ||
43 | #define SST_IMRD 0x30 | ||
44 | #define SST_IPCX 0x38 /* IPC IA -> SST */ | ||
45 | #define SST_IPCD 0x40 /* IPC SST -> IA */ | ||
46 | #define SST_ISRSC 0x48 | ||
47 | #define SST_ISRLPESC 0x50 | ||
48 | #define SST_IMRSC 0x58 | ||
49 | #define SST_IMRLPESC 0x60 | ||
50 | #define SST_IPCSC 0x68 | ||
51 | #define SST_IPCLPESC 0x70 | ||
52 | #define SST_CLKCTL 0x78 | ||
53 | #define SST_CSR2 0x80 | ||
54 | #define SST_LTRC 0xE0 | ||
55 | #define SST_HDMC 0xE8 | ||
56 | #define SST_DBGO 0xF0 | ||
57 | |||
58 | #define SST_SHIM_SIZE 0x100 | ||
59 | #define SST_PWMCTRL 0x1000 | ||
60 | |||
61 | /* SST Shim Register bits | ||
62 | * The register bit naming can differ between products. Some products also | ||
63 | * contain extra functionality. | ||
64 | */ | ||
65 | |||
66 | /* CSR / CS */ | ||
67 | #define SST_CSR_RST (0x1 << 1) | ||
68 | #define SST_CSR_SBCS0 (0x1 << 2) | ||
69 | #define SST_CSR_SBCS1 (0x1 << 3) | ||
70 | #define SST_CSR_DCS(x) (x << 4) | ||
71 | #define SST_CSR_DCS_MASK (0x7 << 4) | ||
72 | #define SST_CSR_STALL (0x1 << 10) | ||
73 | #define SST_CSR_S0IOCS (0x1 << 21) | ||
74 | #define SST_CSR_S1IOCS (0x1 << 23) | ||
75 | #define SST_CSR_LPCS (0x1 << 31) | ||
76 | #define SST_BYT_CSR_RST (0x1 << 0) | ||
77 | #define SST_BYT_CSR_VECTOR_SEL (0x1 << 1) | ||
78 | #define SST_BYT_CSR_STALL (0x1 << 2) | ||
79 | #define SST_BYT_CSR_PWAITMODE (0x1 << 3) | ||
80 | |||
81 | /* ISRX / ISC */ | ||
82 | #define SST_ISRX_BUSY (0x1 << 1) | ||
83 | #define SST_ISRX_DONE (0x1 << 0) | ||
84 | #define SST_BYT_ISRX_REQUEST (0x1 << 1) | ||
85 | |||
86 | /* ISRD / ISD */ | ||
87 | #define SST_ISRD_BUSY (0x1 << 1) | ||
88 | #define SST_ISRD_DONE (0x1 << 0) | ||
89 | |||
90 | /* IMRX / IMC */ | ||
91 | #define SST_IMRX_BUSY (0x1 << 1) | ||
92 | #define SST_IMRX_DONE (0x1 << 0) | ||
93 | #define SST_BYT_IMRX_REQUEST (0x1 << 1) | ||
94 | |||
95 | /* IPCX / IPCC */ | ||
96 | #define SST_IPCX_DONE (0x1 << 30) | ||
97 | #define SST_IPCX_BUSY (0x1 << 31) | ||
98 | #define SST_BYT_IPCX_DONE ((u64)0x1 << 62) | ||
99 | #define SST_BYT_IPCX_BUSY ((u64)0x1 << 63) | ||
100 | |||
101 | /* IPCD */ | ||
102 | #define SST_IPCD_DONE (0x1 << 30) | ||
103 | #define SST_IPCD_BUSY (0x1 << 31) | ||
104 | #define SST_BYT_IPCD_DONE ((u64)0x1 << 62) | ||
105 | #define SST_BYT_IPCD_BUSY ((u64)0x1 << 63) | ||
106 | |||
107 | /* CLKCTL */ | ||
108 | #define SST_CLKCTL_SMOS(x) (x << 24) | ||
109 | #define SST_CLKCTL_MASK (3 << 24) | ||
110 | #define SST_CLKCTL_DCPLCG (1 << 18) | ||
111 | #define SST_CLKCTL_SCOE1 (1 << 17) | ||
112 | #define SST_CLKCTL_SCOE0 (1 << 16) | ||
113 | |||
114 | /* CSR2 / CS2 */ | ||
115 | #define SST_CSR2_SDFD_SSP0 (1 << 1) | ||
116 | #define SST_CSR2_SDFD_SSP1 (1 << 2) | ||
117 | |||
118 | /* LTRC */ | ||
119 | #define SST_LTRC_VAL(x) (x << 0) | ||
120 | |||
121 | /* HDMC */ | ||
122 | #define SST_HDMC_HDDA0(x) (x << 0) | ||
123 | #define SST_HDMC_HDDA1(x) (x << 7) | ||
124 | |||
125 | |||
126 | /* SST Vendor Defined Registers and bits */ | ||
127 | #define SST_VDRTCTL0 0xa0 | ||
128 | #define SST_VDRTCTL1 0xa4 | ||
129 | #define SST_VDRTCTL2 0xa8 | ||
130 | #define SST_VDRTCTL3 0xaC | ||
131 | |||
132 | /* VDRTCTL0 */ | ||
133 | #define SST_VDRTCL0_DSRAMPGE_SHIFT 16 | ||
134 | #define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT) | ||
135 | #define SST_VDRTCL0_ISRAMPGE_SHIFT 6 | ||
136 | #define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT) | ||
137 | |||
138 | struct sst_dsp; | ||
139 | |||
140 | /* | ||
141 | * SST Device. | ||
142 | * | ||
143 | * This structure is populated by the SST core driver. | ||
144 | */ | ||
145 | struct sst_dsp_device { | ||
146 | /* Mandatory fields */ | ||
147 | struct sst_ops *ops; | ||
148 | irqreturn_t (*thread)(int irq, void *context); | ||
149 | void *thread_context; | ||
150 | }; | ||
151 | |||
152 | /* | ||
153 | * SST Platform Data. | ||
154 | */ | ||
155 | struct sst_pdata { | ||
156 | /* ACPI data */ | ||
157 | u32 lpe_base; | ||
158 | u32 lpe_size; | ||
159 | u32 pcicfg_base; | ||
160 | u32 pcicfg_size; | ||
161 | u32 fw_base; | ||
162 | u32 fw_size; | ||
163 | int irq; | ||
164 | |||
165 | /* Firmware */ | ||
166 | const struct firmware *fw; | ||
167 | |||
168 | /* DMA */ | ||
169 | u32 dma_base; | ||
170 | u32 dma_size; | ||
171 | int dma_engine; | ||
172 | |||
173 | /* DSP */ | ||
174 | u32 id; | ||
175 | void *dsp; | ||
176 | }; | ||
177 | |||
178 | /* Initialization */ | ||
179 | struct sst_dsp *sst_dsp_new(struct device *dev, | ||
180 | struct sst_dsp_device *sst_dev, struct sst_pdata *pdata); | ||
181 | void sst_dsp_free(struct sst_dsp *sst); | ||
182 | |||
183 | /* SHIM Read / Write */ | ||
184 | void sst_dsp_shim_write(struct sst_dsp *sst, u32 offset, u32 value); | ||
185 | u32 sst_dsp_shim_read(struct sst_dsp *sst, u32 offset); | ||
186 | int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, | ||
187 | u32 mask, u32 value); | ||
188 | void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value); | ||
189 | u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset); | ||
190 | int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, | ||
191 | u64 mask, u64 value); | ||
192 | |||
193 | /* SHIM Read / Write Unlocked for callers already holding sst lock */ | ||
194 | void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); | ||
195 | u32 sst_dsp_shim_read_unlocked(struct sst_dsp *sst, u32 offset); | ||
196 | int sst_dsp_shim_update_bits_unlocked(struct sst_dsp *sst, u32 offset, | ||
197 | u32 mask, u32 value); | ||
198 | void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value); | ||
199 | u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset); | ||
200 | int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, | ||
201 | u64 mask, u64 value); | ||
202 | |||
203 | /* Internal generic low-level SST IO functions - can be overidden */ | ||
204 | void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); | ||
205 | u32 sst_shim32_read(void __iomem *addr, u32 offset); | ||
206 | void sst_shim32_write64(void __iomem *addr, u32 offset, u64 value); | ||
207 | u64 sst_shim32_read64(void __iomem *addr, u32 offset); | ||
208 | void sst_memcpy_toio_32(struct sst_dsp *sst, | ||
209 | void __iomem *dest, void *src, size_t bytes); | ||
210 | void sst_memcpy_fromio_32(struct sst_dsp *sst, | ||
211 | void *dest, void __iomem *src, size_t bytes); | ||
212 | |||
213 | /* DSP reset & boot */ | ||
214 | void sst_dsp_reset(struct sst_dsp *sst); | ||
215 | int sst_dsp_boot(struct sst_dsp *sst); | ||
216 | |||
217 | /* Msg IO */ | ||
218 | void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg); | ||
219 | u32 sst_dsp_ipc_msg_rx(struct sst_dsp *dsp); | ||
220 | |||
221 | /* Mailbox management */ | ||
222 | int sst_dsp_mailbox_init(struct sst_dsp *dsp, u32 inbox_offset, | ||
223 | size_t inbox_size, u32 outbox_offset, size_t outbox_size); | ||
224 | void sst_dsp_inbox_write(struct sst_dsp *dsp, void *message, size_t bytes); | ||
225 | void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes); | ||
226 | void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes); | ||
227 | void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes); | ||
228 | void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes); | ||
229 | |||
230 | /* Debug */ | ||
231 | void sst_dsp_dump(struct sst_dsp *sst); | ||
232 | |||
233 | #endif | ||
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c new file mode 100644 index 000000000000..f7687107cf7f --- /dev/null +++ b/sound/soc/intel/sst-firmware.c | |||
@@ -0,0 +1,587 @@ | |||
1 | /* | ||
2 | * Intel SST Firmware Loader | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/slab.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/firmware.h> | ||
21 | #include <linux/export.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/dma-mapping.h> | ||
24 | #include <linux/dmaengine.h> | ||
25 | #include <linux/pci.h> | ||
26 | |||
27 | #include <asm/page.h> | ||
28 | #include <asm/pgtable.h> | ||
29 | |||
30 | #include "sst-dsp.h" | ||
31 | #include "sst-dsp-priv.h" | ||
32 | |||
33 | static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes) | ||
34 | { | ||
35 | u32 i; | ||
36 | |||
37 | /* copy one 32 bit word at a time as 64 bit access is not supported */ | ||
38 | for (i = 0; i < bytes; i += 4) | ||
39 | memcpy_toio(dest + i, src + i, 4); | ||
40 | } | ||
41 | |||
42 | /* create new generic firmware object */ | ||
43 | struct sst_fw *sst_fw_new(struct sst_dsp *dsp, | ||
44 | const struct firmware *fw, void *private) | ||
45 | { | ||
46 | struct sst_fw *sst_fw; | ||
47 | int err; | ||
48 | |||
49 | if (!dsp->ops->parse_fw) | ||
50 | return NULL; | ||
51 | |||
52 | sst_fw = kzalloc(sizeof(*sst_fw), GFP_KERNEL); | ||
53 | if (sst_fw == NULL) | ||
54 | return NULL; | ||
55 | |||
56 | sst_fw->dsp = dsp; | ||
57 | sst_fw->private = private; | ||
58 | sst_fw->size = fw->size; | ||
59 | |||
60 | err = dma_coerce_mask_and_coherent(dsp->dev, DMA_BIT_MASK(32)); | ||
61 | if (err < 0) { | ||
62 | kfree(sst_fw); | ||
63 | return NULL; | ||
64 | } | ||
65 | |||
66 | /* allocate DMA buffer to store FW data */ | ||
67 | sst_fw->dma_buf = dma_alloc_coherent(dsp->dev, sst_fw->size, | ||
68 | &sst_fw->dmable_fw_paddr, GFP_DMA | GFP_KERNEL); | ||
69 | if (!sst_fw->dma_buf) { | ||
70 | dev_err(dsp->dev, "error: DMA alloc failed\n"); | ||
71 | kfree(sst_fw); | ||
72 | return NULL; | ||
73 | } | ||
74 | |||
75 | /* copy FW data to DMA-able memory */ | ||
76 | memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size); | ||
77 | |||
78 | /* call core specific FW paser to load FW data into DSP */ | ||
79 | err = dsp->ops->parse_fw(sst_fw); | ||
80 | if (err < 0) { | ||
81 | dev_err(dsp->dev, "error: parse fw failed %d\n", err); | ||
82 | goto parse_err; | ||
83 | } | ||
84 | |||
85 | mutex_lock(&dsp->mutex); | ||
86 | list_add(&sst_fw->list, &dsp->fw_list); | ||
87 | mutex_unlock(&dsp->mutex); | ||
88 | |||
89 | return sst_fw; | ||
90 | |||
91 | parse_err: | ||
92 | dma_free_coherent(dsp->dev, sst_fw->size, | ||
93 | sst_fw->dma_buf, | ||
94 | sst_fw->dmable_fw_paddr); | ||
95 | kfree(sst_fw); | ||
96 | return NULL; | ||
97 | } | ||
98 | EXPORT_SYMBOL_GPL(sst_fw_new); | ||
99 | |||
100 | /* free single firmware object */ | ||
101 | void sst_fw_free(struct sst_fw *sst_fw) | ||
102 | { | ||
103 | struct sst_dsp *dsp = sst_fw->dsp; | ||
104 | |||
105 | mutex_lock(&dsp->mutex); | ||
106 | list_del(&sst_fw->list); | ||
107 | mutex_unlock(&dsp->mutex); | ||
108 | |||
109 | dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, | ||
110 | sst_fw->dmable_fw_paddr); | ||
111 | kfree(sst_fw); | ||
112 | } | ||
113 | EXPORT_SYMBOL_GPL(sst_fw_free); | ||
114 | |||
115 | /* free all firmware objects */ | ||
116 | void sst_fw_free_all(struct sst_dsp *dsp) | ||
117 | { | ||
118 | struct sst_fw *sst_fw, *t; | ||
119 | |||
120 | mutex_lock(&dsp->mutex); | ||
121 | list_for_each_entry_safe(sst_fw, t, &dsp->fw_list, list) { | ||
122 | |||
123 | list_del(&sst_fw->list); | ||
124 | dma_free_coherent(dsp->dev, sst_fw->size, sst_fw->dma_buf, | ||
125 | sst_fw->dmable_fw_paddr); | ||
126 | kfree(sst_fw); | ||
127 | } | ||
128 | mutex_unlock(&dsp->mutex); | ||
129 | } | ||
130 | EXPORT_SYMBOL_GPL(sst_fw_free_all); | ||
131 | |||
132 | /* create a new SST generic module from FW template */ | ||
133 | struct sst_module *sst_module_new(struct sst_fw *sst_fw, | ||
134 | struct sst_module_template *template, void *private) | ||
135 | { | ||
136 | struct sst_dsp *dsp = sst_fw->dsp; | ||
137 | struct sst_module *sst_module; | ||
138 | |||
139 | sst_module = kzalloc(sizeof(*sst_module), GFP_KERNEL); | ||
140 | if (sst_module == NULL) | ||
141 | return NULL; | ||
142 | |||
143 | sst_module->id = template->id; | ||
144 | sst_module->dsp = dsp; | ||
145 | sst_module->sst_fw = sst_fw; | ||
146 | |||
147 | memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data)); | ||
148 | memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data)); | ||
149 | |||
150 | INIT_LIST_HEAD(&sst_module->block_list); | ||
151 | |||
152 | mutex_lock(&dsp->mutex); | ||
153 | list_add(&sst_module->list, &dsp->module_list); | ||
154 | mutex_unlock(&dsp->mutex); | ||
155 | |||
156 | return sst_module; | ||
157 | } | ||
158 | EXPORT_SYMBOL_GPL(sst_module_new); | ||
159 | |||
160 | /* free firmware module and remove from available list */ | ||
161 | void sst_module_free(struct sst_module *sst_module) | ||
162 | { | ||
163 | struct sst_dsp *dsp = sst_module->dsp; | ||
164 | |||
165 | mutex_lock(&dsp->mutex); | ||
166 | list_del(&sst_module->list); | ||
167 | mutex_unlock(&dsp->mutex); | ||
168 | |||
169 | kfree(sst_module); | ||
170 | } | ||
171 | EXPORT_SYMBOL_GPL(sst_module_free); | ||
172 | |||
173 | static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type, | ||
174 | u32 offset) | ||
175 | { | ||
176 | struct sst_mem_block *block; | ||
177 | |||
178 | list_for_each_entry(block, &dsp->free_block_list, list) { | ||
179 | if (block->type == type && block->offset == offset) | ||
180 | return block; | ||
181 | } | ||
182 | |||
183 | return NULL; | ||
184 | } | ||
185 | |||
186 | static int block_alloc_contiguous(struct sst_module *module, | ||
187 | struct sst_module_data *data, u32 offset, int size) | ||
188 | { | ||
189 | struct list_head tmp = LIST_HEAD_INIT(tmp); | ||
190 | struct sst_dsp *dsp = module->dsp; | ||
191 | struct sst_mem_block *block; | ||
192 | |||
193 | while (size > 0) { | ||
194 | block = find_block(dsp, data->type, offset); | ||
195 | if (!block) { | ||
196 | list_splice(&tmp, &dsp->free_block_list); | ||
197 | return -ENOMEM; | ||
198 | } | ||
199 | |||
200 | list_move_tail(&block->list, &tmp); | ||
201 | offset += block->size; | ||
202 | size -= block->size; | ||
203 | } | ||
204 | |||
205 | list_splice(&tmp, &dsp->used_block_list); | ||
206 | return 0; | ||
207 | } | ||
208 | |||
209 | /* allocate free DSP blocks for module data - callers hold locks */ | ||
210 | static int block_alloc(struct sst_module *module, | ||
211 | struct sst_module_data *data) | ||
212 | { | ||
213 | struct sst_dsp *dsp = module->dsp; | ||
214 | struct sst_mem_block *block, *tmp; | ||
215 | int ret = 0; | ||
216 | |||
217 | if (data->size == 0) | ||
218 | return 0; | ||
219 | |||
220 | /* find first free whole blocks that can hold module */ | ||
221 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
222 | |||
223 | /* ignore blocks with wrong type */ | ||
224 | if (block->type != data->type) | ||
225 | continue; | ||
226 | |||
227 | if (data->size > block->size) | ||
228 | continue; | ||
229 | |||
230 | data->offset = block->offset; | ||
231 | block->data_type = data->data_type; | ||
232 | block->bytes_used = data->size % block->size; | ||
233 | list_add(&block->module_list, &module->block_list); | ||
234 | list_move(&block->list, &dsp->used_block_list); | ||
235 | dev_dbg(dsp->dev, " *module %d added block %d:%d\n", | ||
236 | module->id, block->type, block->index); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | /* then find free multiple blocks that can hold module */ | ||
241 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
242 | |||
243 | /* ignore blocks with wrong type */ | ||
244 | if (block->type != data->type) | ||
245 | continue; | ||
246 | |||
247 | /* do we span > 1 blocks */ | ||
248 | if (data->size > block->size) { | ||
249 | ret = block_alloc_contiguous(module, data, | ||
250 | block->offset + block->size, | ||
251 | data->size - block->size); | ||
252 | if (ret == 0) | ||
253 | return ret; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | /* not enough free block space */ | ||
258 | return -ENOMEM; | ||
259 | } | ||
260 | |||
261 | /* remove module from memory - callers hold locks */ | ||
262 | static void block_module_remove(struct sst_module *module) | ||
263 | { | ||
264 | struct sst_mem_block *block, *tmp; | ||
265 | struct sst_dsp *dsp = module->dsp; | ||
266 | int err; | ||
267 | |||
268 | /* disable each block */ | ||
269 | list_for_each_entry(block, &module->block_list, module_list) { | ||
270 | |||
271 | if (block->ops && block->ops->disable) { | ||
272 | err = block->ops->disable(block); | ||
273 | if (err < 0) | ||
274 | dev_err(dsp->dev, | ||
275 | "error: cant disable block %d:%d\n", | ||
276 | block->type, block->index); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | /* mark each block as free */ | ||
281 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | ||
282 | list_del(&block->module_list); | ||
283 | list_move(&block->list, &dsp->free_block_list); | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* prepare the memory block to receive data from host - callers hold locks */ | ||
288 | static int block_module_prepare(struct sst_module *module) | ||
289 | { | ||
290 | struct sst_mem_block *block; | ||
291 | int ret = 0; | ||
292 | |||
293 | /* enable each block so that's it'e ready for module P/S data */ | ||
294 | list_for_each_entry(block, &module->block_list, module_list) { | ||
295 | |||
296 | if (block->ops && block->ops->enable) { | ||
297 | ret = block->ops->enable(block); | ||
298 | if (ret < 0) { | ||
299 | dev_err(module->dsp->dev, | ||
300 | "error: cant disable block %d:%d\n", | ||
301 | block->type, block->index); | ||
302 | goto err; | ||
303 | } | ||
304 | } | ||
305 | } | ||
306 | return ret; | ||
307 | |||
308 | err: | ||
309 | list_for_each_entry(block, &module->block_list, module_list) { | ||
310 | if (block->ops && block->ops->disable) | ||
311 | block->ops->disable(block); | ||
312 | } | ||
313 | return ret; | ||
314 | } | ||
315 | |||
316 | /* allocate memory blocks for static module addresses - callers hold locks */ | ||
317 | static int block_alloc_fixed(struct sst_module *module, | ||
318 | struct sst_module_data *data) | ||
319 | { | ||
320 | struct sst_dsp *dsp = module->dsp; | ||
321 | struct sst_mem_block *block, *tmp; | ||
322 | u32 end = data->offset + data->size, block_end; | ||
323 | int err; | ||
324 | |||
325 | /* only IRAM/DRAM blocks are managed */ | ||
326 | if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM) | ||
327 | return 0; | ||
328 | |||
329 | /* are blocks already attached to this module */ | ||
330 | list_for_each_entry_safe(block, tmp, &module->block_list, module_list) { | ||
331 | |||
332 | /* force compacting mem blocks of the same data_type */ | ||
333 | if (block->data_type != data->data_type) | ||
334 | continue; | ||
335 | |||
336 | block_end = block->offset + block->size; | ||
337 | |||
338 | /* find block that holds section */ | ||
339 | if (data->offset >= block->offset && end < block_end) | ||
340 | return 0; | ||
341 | |||
342 | /* does block span more than 1 section */ | ||
343 | if (data->offset >= block->offset && data->offset < block_end) { | ||
344 | |||
345 | err = block_alloc_contiguous(module, data, | ||
346 | block->offset + block->size, | ||
347 | data->size - block->size + data->offset - block->offset); | ||
348 | if (err < 0) | ||
349 | return -ENOMEM; | ||
350 | |||
351 | /* module already owns blocks */ | ||
352 | return 0; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | /* find first free blocks that can hold section in free list */ | ||
357 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
358 | block_end = block->offset + block->size; | ||
359 | |||
360 | /* find block that holds section */ | ||
361 | if (data->offset >= block->offset && end < block_end) { | ||
362 | |||
363 | /* add block */ | ||
364 | block->data_type = data->data_type; | ||
365 | list_move(&block->list, &dsp->used_block_list); | ||
366 | list_add(&block->module_list, &module->block_list); | ||
367 | return 0; | ||
368 | } | ||
369 | |||
370 | /* does block span more than 1 section */ | ||
371 | if (data->offset >= block->offset && data->offset < block_end) { | ||
372 | |||
373 | err = block_alloc_contiguous(module, data, | ||
374 | block->offset + block->size, | ||
375 | data->size - block->size); | ||
376 | if (err < 0) | ||
377 | return -ENOMEM; | ||
378 | |||
379 | /* add block */ | ||
380 | block->data_type = data->data_type; | ||
381 | list_move(&block->list, &dsp->used_block_list); | ||
382 | list_add(&block->module_list, &module->block_list); | ||
383 | return 0; | ||
384 | } | ||
385 | |||
386 | } | ||
387 | |||
388 | return -ENOMEM; | ||
389 | } | ||
390 | |||
391 | /* Load fixed module data into DSP memory blocks */ | ||
392 | int sst_module_insert_fixed_block(struct sst_module *module, | ||
393 | struct sst_module_data *data) | ||
394 | { | ||
395 | struct sst_dsp *dsp = module->dsp; | ||
396 | int ret; | ||
397 | |||
398 | mutex_lock(&dsp->mutex); | ||
399 | |||
400 | /* alloc blocks that includes this section */ | ||
401 | ret = block_alloc_fixed(module, data); | ||
402 | if (ret < 0) { | ||
403 | dev_err(dsp->dev, | ||
404 | "error: no free blocks for section at offset 0x%x size 0x%x\n", | ||
405 | data->offset, data->size); | ||
406 | mutex_unlock(&dsp->mutex); | ||
407 | return -ENOMEM; | ||
408 | } | ||
409 | |||
410 | /* prepare DSP blocks for module copy */ | ||
411 | ret = block_module_prepare(module); | ||
412 | if (ret < 0) { | ||
413 | dev_err(dsp->dev, "error: fw module prepare failed\n"); | ||
414 | goto err; | ||
415 | } | ||
416 | |||
417 | /* copy partial module data to blocks */ | ||
418 | sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size); | ||
419 | |||
420 | mutex_unlock(&dsp->mutex); | ||
421 | return ret; | ||
422 | |||
423 | err: | ||
424 | block_module_remove(module); | ||
425 | mutex_unlock(&dsp->mutex); | ||
426 | return ret; | ||
427 | } | ||
428 | EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block); | ||
429 | |||
430 | /* Unload entire module from DSP memory */ | ||
431 | int sst_block_module_remove(struct sst_module *module) | ||
432 | { | ||
433 | struct sst_dsp *dsp = module->dsp; | ||
434 | |||
435 | mutex_lock(&dsp->mutex); | ||
436 | block_module_remove(module); | ||
437 | mutex_unlock(&dsp->mutex); | ||
438 | return 0; | ||
439 | } | ||
440 | EXPORT_SYMBOL_GPL(sst_block_module_remove); | ||
441 | |||
442 | /* register a DSP memory block for use with FW based modules */ | ||
443 | struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset, | ||
444 | u32 size, enum sst_mem_type type, struct sst_block_ops *ops, u32 index, | ||
445 | void *private) | ||
446 | { | ||
447 | struct sst_mem_block *block; | ||
448 | |||
449 | block = kzalloc(sizeof(*block), GFP_KERNEL); | ||
450 | if (block == NULL) | ||
451 | return NULL; | ||
452 | |||
453 | block->offset = offset; | ||
454 | block->size = size; | ||
455 | block->index = index; | ||
456 | block->type = type; | ||
457 | block->dsp = dsp; | ||
458 | block->private = private; | ||
459 | block->ops = ops; | ||
460 | |||
461 | mutex_lock(&dsp->mutex); | ||
462 | list_add(&block->list, &dsp->free_block_list); | ||
463 | mutex_unlock(&dsp->mutex); | ||
464 | |||
465 | return block; | ||
466 | } | ||
467 | EXPORT_SYMBOL_GPL(sst_mem_block_register); | ||
468 | |||
469 | /* unregister all DSP memory blocks */ | ||
470 | void sst_mem_block_unregister_all(struct sst_dsp *dsp) | ||
471 | { | ||
472 | struct sst_mem_block *block, *tmp; | ||
473 | |||
474 | mutex_lock(&dsp->mutex); | ||
475 | |||
476 | /* unregister used blocks */ | ||
477 | list_for_each_entry_safe(block, tmp, &dsp->used_block_list, list) { | ||
478 | list_del(&block->list); | ||
479 | kfree(block); | ||
480 | } | ||
481 | |||
482 | /* unregister free blocks */ | ||
483 | list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) { | ||
484 | list_del(&block->list); | ||
485 | kfree(block); | ||
486 | } | ||
487 | |||
488 | mutex_unlock(&dsp->mutex); | ||
489 | } | ||
490 | EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all); | ||
491 | |||
492 | /* allocate scratch buffer blocks */ | ||
493 | struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp) | ||
494 | { | ||
495 | struct sst_module *sst_module, *scratch; | ||
496 | struct sst_mem_block *block, *tmp; | ||
497 | u32 block_size; | ||
498 | int ret = 0; | ||
499 | |||
500 | scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL); | ||
501 | if (scratch == NULL) | ||
502 | return NULL; | ||
503 | |||
504 | mutex_lock(&dsp->mutex); | ||
505 | |||
506 | /* calculate required scratch size */ | ||
507 | list_for_each_entry(sst_module, &dsp->module_list, list) { | ||
508 | if (scratch->s.size > sst_module->s.size) | ||
509 | scratch->s.size = scratch->s.size; | ||
510 | else | ||
511 | scratch->s.size = sst_module->s.size; | ||
512 | } | ||
513 | |||
514 | dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n", | ||
515 | scratch->s.size); | ||
516 | |||
517 | /* init scratch module */ | ||
518 | scratch->dsp = dsp; | ||
519 | scratch->s.type = SST_MEM_DRAM; | ||
520 | scratch->s.data_type = SST_DATA_S; | ||
521 | INIT_LIST_HEAD(&scratch->block_list); | ||
522 | |||
523 | /* check free blocks before looking at used blocks for space */ | ||
524 | if (!list_empty(&dsp->free_block_list)) | ||
525 | block = list_first_entry(&dsp->free_block_list, | ||
526 | struct sst_mem_block, list); | ||
527 | else | ||
528 | block = list_first_entry(&dsp->used_block_list, | ||
529 | struct sst_mem_block, list); | ||
530 | block_size = block->size; | ||
531 | |||
532 | /* allocate blocks for module scratch buffers */ | ||
533 | dev_dbg(dsp->dev, "allocating scratch blocks\n"); | ||
534 | ret = block_alloc(scratch, &scratch->s); | ||
535 | if (ret < 0) { | ||
536 | dev_err(dsp->dev, "error: can't alloc scratch blocks\n"); | ||
537 | goto err; | ||
538 | } | ||
539 | |||
540 | /* assign the same offset of scratch to each module */ | ||
541 | list_for_each_entry(sst_module, &dsp->module_list, list) | ||
542 | sst_module->s.offset = scratch->s.offset; | ||
543 | |||
544 | mutex_unlock(&dsp->mutex); | ||
545 | return scratch; | ||
546 | |||
547 | err: | ||
548 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | ||
549 | list_del(&block->module_list); | ||
550 | mutex_unlock(&dsp->mutex); | ||
551 | return NULL; | ||
552 | } | ||
553 | EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch); | ||
554 | |||
555 | /* free all scratch blocks */ | ||
556 | void sst_mem_block_free_scratch(struct sst_dsp *dsp, | ||
557 | struct sst_module *scratch) | ||
558 | { | ||
559 | struct sst_mem_block *block, *tmp; | ||
560 | |||
561 | mutex_lock(&dsp->mutex); | ||
562 | |||
563 | list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list) | ||
564 | list_del(&block->module_list); | ||
565 | |||
566 | mutex_unlock(&dsp->mutex); | ||
567 | } | ||
568 | EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch); | ||
569 | |||
570 | /* get a module from it's unique ID */ | ||
571 | struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id) | ||
572 | { | ||
573 | struct sst_module *module; | ||
574 | |||
575 | mutex_lock(&dsp->mutex); | ||
576 | |||
577 | list_for_each_entry(module, &dsp->module_list, list) { | ||
578 | if (module->id == id) { | ||
579 | mutex_unlock(&dsp->mutex); | ||
580 | return module; | ||
581 | } | ||
582 | } | ||
583 | |||
584 | mutex_unlock(&dsp->mutex); | ||
585 | return NULL; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(sst_module_get_from_id); | ||
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c new file mode 100644 index 000000000000..f5ebf36af889 --- /dev/null +++ b/sound/soc/intel/sst-haswell-dsp.c | |||
@@ -0,0 +1,517 @@ | |||
1 | /* | ||
2 | * Intel Haswell SST DSP driver | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/fs.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/sched.h> | ||
22 | #include <linux/export.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/dma-mapping.h> | ||
26 | #include <linux/platform_device.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/firmware.h> | ||
29 | #include <linux/pm_runtime.h> | ||
30 | |||
31 | #include <linux/acpi.h> | ||
32 | #include <acpi/acpi_bus.h> | ||
33 | |||
34 | #include "sst-dsp.h" | ||
35 | #include "sst-dsp-priv.h" | ||
36 | #include "sst-haswell-ipc.h" | ||
37 | |||
38 | #include <trace/events/hswadsp.h> | ||
39 | |||
40 | #define SST_HSW_FW_SIGNATURE_SIZE 4 | ||
41 | #define SST_HSW_FW_SIGN "$SST" | ||
42 | #define SST_HSW_FW_LIB_SIGN "$LIB" | ||
43 | |||
44 | #define SST_WPT_SHIM_OFFSET 0xFB000 | ||
45 | #define SST_LP_SHIM_OFFSET 0xE7000 | ||
46 | #define SST_WPT_IRAM_OFFSET 0xA0000 | ||
47 | #define SST_LP_IRAM_OFFSET 0x80000 | ||
48 | |||
49 | #define SST_SHIM_PM_REG 0x84 | ||
50 | |||
51 | #define SST_HSW_IRAM 1 | ||
52 | #define SST_HSW_DRAM 2 | ||
53 | #define SST_HSW_REGS 3 | ||
54 | |||
55 | struct dma_block_info { | ||
56 | __le32 type; /* IRAM/DRAM */ | ||
57 | __le32 size; /* Bytes */ | ||
58 | __le32 ram_offset; /* Offset in I/DRAM */ | ||
59 | __le32 rsvd; /* Reserved field */ | ||
60 | } __attribute__((packed)); | ||
61 | |||
62 | struct fw_module_info { | ||
63 | __le32 persistent_size; | ||
64 | __le32 scratch_size; | ||
65 | } __attribute__((packed)); | ||
66 | |||
67 | struct fw_header { | ||
68 | unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* FW signature */ | ||
69 | __le32 file_size; /* size of fw minus this header */ | ||
70 | __le32 modules; /* # of modules */ | ||
71 | __le32 file_format; /* version of header format */ | ||
72 | __le32 reserved[4]; | ||
73 | } __attribute__((packed)); | ||
74 | |||
75 | struct fw_module_header { | ||
76 | unsigned char signature[SST_HSW_FW_SIGNATURE_SIZE]; /* module signature */ | ||
77 | __le32 mod_size; /* size of module */ | ||
78 | __le32 blocks; /* # of blocks */ | ||
79 | __le16 padding; | ||
80 | __le16 type; /* codec type, pp lib */ | ||
81 | __le32 entry_point; | ||
82 | struct fw_module_info info; | ||
83 | } __attribute__((packed)); | ||
84 | |||
85 | static void hsw_free(struct sst_dsp *sst); | ||
86 | |||
87 | static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw, | ||
88 | struct fw_module_header *module) | ||
89 | { | ||
90 | struct dma_block_info *block; | ||
91 | struct sst_module *mod; | ||
92 | struct sst_module_data block_data; | ||
93 | struct sst_module_template template; | ||
94 | int count; | ||
95 | void __iomem *ram; | ||
96 | |||
97 | /* TODO: allowed module types need to be configurable */ | ||
98 | if (module->type != SST_HSW_MODULE_BASE_FW | ||
99 | && module->type != SST_HSW_MODULE_PCM_SYSTEM | ||
100 | && module->type != SST_HSW_MODULE_PCM | ||
101 | && module->type != SST_HSW_MODULE_PCM_REFERENCE | ||
102 | && module->type != SST_HSW_MODULE_PCM_CAPTURE | ||
103 | && module->type != SST_HSW_MODULE_LPAL) | ||
104 | return 0; | ||
105 | |||
106 | dev_dbg(dsp->dev, "new module sign 0x%s size 0x%x blocks 0x%x type 0x%x\n", | ||
107 | module->signature, module->mod_size, | ||
108 | module->blocks, module->type); | ||
109 | dev_dbg(dsp->dev, " entrypoint 0x%x\n", module->entry_point); | ||
110 | dev_dbg(dsp->dev, " persistent 0x%x scratch 0x%x\n", | ||
111 | module->info.persistent_size, module->info.scratch_size); | ||
112 | |||
113 | memset(&template, 0, sizeof(template)); | ||
114 | template.id = module->type; | ||
115 | template.entry = module->entry_point; | ||
116 | template.p.size = module->info.persistent_size; | ||
117 | template.p.type = SST_MEM_DRAM; | ||
118 | template.p.data_type = SST_DATA_P; | ||
119 | template.s.size = module->info.scratch_size; | ||
120 | template.s.type = SST_MEM_DRAM; | ||
121 | template.s.data_type = SST_DATA_S; | ||
122 | |||
123 | mod = sst_module_new(fw, &template, NULL); | ||
124 | if (mod == NULL) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | block = (void *)module + sizeof(*module); | ||
128 | |||
129 | for (count = 0; count < module->blocks; count++) { | ||
130 | |||
131 | if (block->size <= 0) { | ||
132 | dev_err(dsp->dev, | ||
133 | "error: block %d size invalid\n", count); | ||
134 | sst_module_free(mod); | ||
135 | return -EINVAL; | ||
136 | } | ||
137 | |||
138 | switch (block->type) { | ||
139 | case SST_HSW_IRAM: | ||
140 | ram = dsp->addr.lpe; | ||
141 | block_data.offset = | ||
142 | block->ram_offset + dsp->addr.iram_offset; | ||
143 | block_data.type = SST_MEM_IRAM; | ||
144 | break; | ||
145 | case SST_HSW_DRAM: | ||
146 | ram = dsp->addr.lpe; | ||
147 | block_data.offset = block->ram_offset; | ||
148 | block_data.type = SST_MEM_DRAM; | ||
149 | break; | ||
150 | default: | ||
151 | dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n", | ||
152 | block->type, count); | ||
153 | sst_module_free(mod); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | block_data.size = block->size; | ||
158 | block_data.data_type = SST_DATA_M; | ||
159 | block_data.data = (void *)block + sizeof(*block); | ||
160 | block_data.data_offset = block_data.data - fw->dma_buf; | ||
161 | |||
162 | dev_dbg(dsp->dev, "copy firmware block %d type 0x%x " | ||
163 | "size 0x%x ==> ram %p offset 0x%x\n", | ||
164 | count, block->type, block->size, ram, | ||
165 | block->ram_offset); | ||
166 | |||
167 | sst_module_insert_fixed_block(mod, &block_data); | ||
168 | |||
169 | block = (void *)block + sizeof(*block) + block->size; | ||
170 | } | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int hsw_parse_fw_image(struct sst_fw *sst_fw) | ||
175 | { | ||
176 | struct fw_header *header; | ||
177 | struct sst_module *scratch; | ||
178 | struct fw_module_header *module; | ||
179 | struct sst_dsp *dsp = sst_fw->dsp; | ||
180 | struct sst_hsw *hsw = sst_fw->private; | ||
181 | int ret, count; | ||
182 | |||
183 | /* Read the header information from the data pointer */ | ||
184 | header = (struct fw_header *)sst_fw->dma_buf; | ||
185 | |||
186 | /* verify FW */ | ||
187 | if ((strncmp(header->signature, SST_HSW_FW_SIGN, 4) != 0) || | ||
188 | (sst_fw->size != header->file_size + sizeof(*header))) { | ||
189 | dev_err(dsp->dev, "error: invalid fw sign/filesize mismatch\n"); | ||
190 | return -EINVAL; | ||
191 | } | ||
192 | |||
193 | dev_dbg(dsp->dev, "header size=0x%x modules=0x%x fmt=0x%x size=%zu\n", | ||
194 | header->file_size, header->modules, | ||
195 | header->file_format, sizeof(*header)); | ||
196 | |||
197 | /* parse each module */ | ||
198 | module = (void *)sst_fw->dma_buf + sizeof(*header); | ||
199 | for (count = 0; count < header->modules; count++) { | ||
200 | |||
201 | /* module */ | ||
202 | ret = hsw_parse_module(dsp, sst_fw, module); | ||
203 | if (ret < 0) { | ||
204 | dev_err(dsp->dev, "error: invalid module %d\n", count); | ||
205 | return ret; | ||
206 | } | ||
207 | module = (void *)module + sizeof(*module) + module->mod_size; | ||
208 | } | ||
209 | |||
210 | /* allocate persistent/scratch mem regions */ | ||
211 | scratch = sst_mem_block_alloc_scratch(dsp); | ||
212 | if (scratch == NULL) | ||
213 | return -ENOMEM; | ||
214 | |||
215 | sst_hsw_set_scratch_module(hsw, scratch); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static irqreturn_t hsw_irq(int irq, void *context) | ||
221 | { | ||
222 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
223 | u32 isr; | ||
224 | int ret = IRQ_NONE; | ||
225 | |||
226 | spin_lock(&sst->spinlock); | ||
227 | |||
228 | /* Interrupt arrived, check src */ | ||
229 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
230 | if (isr & SST_ISRX_DONE) { | ||
231 | trace_sst_irq_done(isr, | ||
232 | sst_dsp_shim_read_unlocked(sst, SST_IMRX)); | ||
233 | |||
234 | /* Mask Done interrupt before return */ | ||
235 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
236 | SST_IMRX_DONE, SST_IMRX_DONE); | ||
237 | ret = IRQ_WAKE_THREAD; | ||
238 | } | ||
239 | |||
240 | if (isr & SST_ISRX_BUSY) { | ||
241 | trace_sst_irq_busy(isr, | ||
242 | sst_dsp_shim_read_unlocked(sst, SST_IMRX)); | ||
243 | |||
244 | /* Mask Busy interrupt before return */ | ||
245 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
246 | SST_IMRX_BUSY, SST_IMRX_BUSY); | ||
247 | ret = IRQ_WAKE_THREAD; | ||
248 | } | ||
249 | |||
250 | spin_unlock(&sst->spinlock); | ||
251 | return ret; | ||
252 | } | ||
253 | |||
254 | static void hsw_boot(struct sst_dsp *sst) | ||
255 | { | ||
256 | /* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */ | ||
257 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
258 | SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0); | ||
259 | |||
260 | /* stall DSP core, set clk to 192/96Mhz */ | ||
261 | sst_dsp_shim_update_bits_unlocked(sst, | ||
262 | SST_CSR, SST_CSR_STALL | SST_CSR_DCS_MASK, | ||
263 | SST_CSR_STALL | SST_CSR_DCS(4)); | ||
264 | |||
265 | /* Set 24MHz MCLK, prevent local clock gating, enable SSP0 clock */ | ||
266 | sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL, | ||
267 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0, | ||
268 | SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0); | ||
269 | |||
270 | /* disable DMA finish function for SSP0 & SSP1 */ | ||
271 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1, | ||
272 | SST_CSR2_SDFD_SSP1); | ||
273 | |||
274 | /* enable DMA engine 0,1 all channels to access host memory */ | ||
275 | sst_dsp_shim_update_bits_unlocked(sst, SST_HDMC, | ||
276 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff), | ||
277 | SST_HDMC_HDDA1(0xff) | SST_HDMC_HDDA0(0xff)); | ||
278 | |||
279 | /* disable all clock gating */ | ||
280 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2); | ||
281 | |||
282 | /* set DSP to RUN */ | ||
283 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0); | ||
284 | } | ||
285 | |||
286 | static void hsw_reset(struct sst_dsp *sst) | ||
287 | { | ||
288 | /* put DSP into reset and stall */ | ||
289 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
290 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL); | ||
291 | |||
292 | /* keep in reset for 10ms */ | ||
293 | mdelay(10); | ||
294 | |||
295 | /* take DSP out of reset and keep stalled for FW loading */ | ||
296 | sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, | ||
297 | SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL); | ||
298 | } | ||
299 | |||
300 | struct sst_adsp_memregion { | ||
301 | u32 start; | ||
302 | u32 end; | ||
303 | int blocks; | ||
304 | enum sst_mem_type type; | ||
305 | }; | ||
306 | |||
307 | /* lynx point ADSP mem regions */ | ||
308 | static const struct sst_adsp_memregion lp_region[] = { | ||
309 | {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | ||
310 | {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */ | ||
311 | {0x80000, 0xE0000, 12, SST_MEM_IRAM}, /* I-SRAM - 12 * 32kB */ | ||
312 | }; | ||
313 | |||
314 | /* wild cat point ADSP mem regions */ | ||
315 | static const struct sst_adsp_memregion wpt_region[] = { | ||
316 | {0x00000, 0x40000, 8, SST_MEM_DRAM}, /* D-SRAM0 - 8 * 32kB */ | ||
317 | {0x40000, 0x80000, 8, SST_MEM_DRAM}, /* D-SRAM1 - 8 * 32kB */ | ||
318 | {0x80000, 0xA0000, 4, SST_MEM_DRAM}, /* D-SRAM2 - 4 * 32kB */ | ||
319 | {0xA0000, 0xF0000, 10, SST_MEM_IRAM}, /* I-SRAM - 10 * 32kB */ | ||
320 | }; | ||
321 | |||
322 | static int hsw_acpi_resource_map(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
323 | { | ||
324 | /* ADSP DRAM & IRAM */ | ||
325 | sst->addr.lpe_base = pdata->lpe_base; | ||
326 | sst->addr.lpe = ioremap(pdata->lpe_base, pdata->lpe_size); | ||
327 | if (!sst->addr.lpe) | ||
328 | return -ENODEV; | ||
329 | |||
330 | /* ADSP PCI MMIO config space */ | ||
331 | sst->addr.pci_cfg = ioremap(pdata->pcicfg_base, pdata->pcicfg_size); | ||
332 | if (!sst->addr.pci_cfg) { | ||
333 | iounmap(sst->addr.lpe); | ||
334 | return -ENODEV; | ||
335 | } | ||
336 | |||
337 | /* SST Shim */ | ||
338 | sst->addr.shim = sst->addr.lpe + sst->addr.shim_offset; | ||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static u32 hsw_block_get_bit(struct sst_mem_block *block) | ||
343 | { | ||
344 | u32 bit = 0, shift = 0; | ||
345 | |||
346 | switch (block->type) { | ||
347 | case SST_MEM_DRAM: | ||
348 | shift = 16; | ||
349 | break; | ||
350 | case SST_MEM_IRAM: | ||
351 | shift = 6; | ||
352 | break; | ||
353 | default: | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | bit = 1 << (block->index + shift); | ||
358 | |||
359 | return bit; | ||
360 | } | ||
361 | |||
362 | /* enable 32kB memory block - locks held by caller */ | ||
363 | static int hsw_block_enable(struct sst_mem_block *block) | ||
364 | { | ||
365 | struct sst_dsp *sst = block->dsp; | ||
366 | u32 bit, val; | ||
367 | |||
368 | if (block->users++ > 0) | ||
369 | return 0; | ||
370 | |||
371 | dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n", | ||
372 | block->type, block->index, block->offset); | ||
373 | |||
374 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
375 | bit = hsw_block_get_bit(block); | ||
376 | writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
377 | |||
378 | /* wait 18 DSP clock ticks */ | ||
379 | udelay(10); | ||
380 | |||
381 | return 0; | ||
382 | } | ||
383 | |||
384 | /* disable 32kB memory block - locks held by caller */ | ||
385 | static int hsw_block_disable(struct sst_mem_block *block) | ||
386 | { | ||
387 | struct sst_dsp *sst = block->dsp; | ||
388 | u32 bit, val; | ||
389 | |||
390 | if (--block->users > 0) | ||
391 | return 0; | ||
392 | |||
393 | dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n", | ||
394 | block->type, block->index, block->offset); | ||
395 | |||
396 | val = readl(sst->addr.pci_cfg + SST_VDRTCTL0); | ||
397 | bit = hsw_block_get_bit(block); | ||
398 | writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
403 | static struct sst_block_ops sst_hsw_ops = { | ||
404 | .enable = hsw_block_enable, | ||
405 | .disable = hsw_block_disable, | ||
406 | }; | ||
407 | |||
408 | static int hsw_enable_shim(struct sst_dsp *sst) | ||
409 | { | ||
410 | int tries = 10; | ||
411 | u32 reg; | ||
412 | |||
413 | /* enable shim */ | ||
414 | reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
415 | writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG); | ||
416 | |||
417 | /* check that ADSP shim is enabled */ | ||
418 | while (tries--) { | ||
419 | reg = sst_dsp_shim_read_unlocked(sst, SST_CSR); | ||
420 | if (reg != 0xffffffff) | ||
421 | return 0; | ||
422 | |||
423 | msleep(1); | ||
424 | } | ||
425 | |||
426 | return -ENODEV; | ||
427 | } | ||
428 | |||
429 | static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata) | ||
430 | { | ||
431 | const struct sst_adsp_memregion *region; | ||
432 | struct device *dev; | ||
433 | int ret = -ENODEV, i, j, region_count; | ||
434 | u32 offset, size; | ||
435 | |||
436 | dev = sst->dev; | ||
437 | |||
438 | switch (sst->id) { | ||
439 | case SST_DEV_ID_LYNX_POINT: | ||
440 | region = lp_region; | ||
441 | region_count = ARRAY_SIZE(lp_region); | ||
442 | sst->addr.iram_offset = SST_LP_IRAM_OFFSET; | ||
443 | sst->addr.shim_offset = SST_LP_SHIM_OFFSET; | ||
444 | break; | ||
445 | case SST_DEV_ID_WILDCAT_POINT: | ||
446 | region = wpt_region; | ||
447 | region_count = ARRAY_SIZE(wpt_region); | ||
448 | sst->addr.iram_offset = SST_WPT_IRAM_OFFSET; | ||
449 | sst->addr.shim_offset = SST_WPT_SHIM_OFFSET; | ||
450 | break; | ||
451 | default: | ||
452 | dev_err(dev, "error: failed to get mem resources\n"); | ||
453 | return ret; | ||
454 | } | ||
455 | |||
456 | ret = hsw_acpi_resource_map(sst, pdata); | ||
457 | if (ret < 0) { | ||
458 | dev_err(dev, "error: failed to map resources\n"); | ||
459 | return ret; | ||
460 | } | ||
461 | |||
462 | /* enable the DSP SHIM */ | ||
463 | ret = hsw_enable_shim(sst); | ||
464 | if (ret < 0) { | ||
465 | dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n"); | ||
466 | return ret; | ||
467 | } | ||
468 | |||
469 | ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); | ||
470 | if (ret) | ||
471 | return ret; | ||
472 | |||
473 | /* Enable Interrupt from both sides */ | ||
474 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0); | ||
475 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD, | ||
476 | (0x3 | 0x1 << 16 | 0x3 << 21), 0x0); | ||
477 | |||
478 | /* register DSP memory blocks - ideally we should get this from ACPI */ | ||
479 | for (i = 0; i < region_count; i++) { | ||
480 | offset = region[i].start; | ||
481 | size = (region[i].end - region[i].start) / region[i].blocks; | ||
482 | |||
483 | /* register individual memory blocks */ | ||
484 | for (j = 0; j < region[i].blocks; j++) { | ||
485 | sst_mem_block_register(sst, offset, size, | ||
486 | region[i].type, &sst_hsw_ops, j, sst); | ||
487 | offset += size; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | /* set default power gating mask */ | ||
492 | writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL0); | ||
493 | |||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static void hsw_free(struct sst_dsp *sst) | ||
498 | { | ||
499 | sst_mem_block_unregister_all(sst); | ||
500 | iounmap(sst->addr.lpe); | ||
501 | iounmap(sst->addr.pci_cfg); | ||
502 | } | ||
503 | |||
504 | struct sst_ops haswell_ops = { | ||
505 | .reset = hsw_reset, | ||
506 | .boot = hsw_boot, | ||
507 | .write = sst_shim32_write, | ||
508 | .read = sst_shim32_read, | ||
509 | .write64 = sst_shim32_write64, | ||
510 | .read64 = sst_shim32_read64, | ||
511 | .ram_read = sst_memcpy_fromio_32, | ||
512 | .ram_write = sst_memcpy_toio_32, | ||
513 | .irq_handler = hsw_irq, | ||
514 | .init = hsw_init, | ||
515 | .free = hsw_free, | ||
516 | .parse_fw = hsw_parse_fw_image, | ||
517 | }; | ||
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c new file mode 100644 index 000000000000..f46bb4ddde6f --- /dev/null +++ b/sound/soc/intel/sst-haswell-ipc.c | |||
@@ -0,0 +1,1785 @@ | |||
1 | /* | ||
2 | * Intel SST Haswell/Broadwell IPC Support | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/types.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/list.h> | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/wait.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <linux/export.h> | ||
25 | #include <linux/slab.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/sched.h> | ||
28 | #include <linux/list.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/kthread.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include <linux/dma-mapping.h> | ||
33 | #include <linux/debugfs.h> | ||
34 | |||
35 | #include "sst-haswell-ipc.h" | ||
36 | #include "sst-dsp.h" | ||
37 | #include "sst-dsp-priv.h" | ||
38 | |||
39 | /* Global Message - Generic */ | ||
40 | #define IPC_GLB_TYPE_SHIFT 24 | ||
41 | #define IPC_GLB_TYPE_MASK (0x1f << IPC_GLB_TYPE_SHIFT) | ||
42 | #define IPC_GLB_TYPE(x) (x << IPC_GLB_TYPE_SHIFT) | ||
43 | |||
44 | /* Global Message - Reply */ | ||
45 | #define IPC_GLB_REPLY_SHIFT 0 | ||
46 | #define IPC_GLB_REPLY_MASK (0x1f << IPC_GLB_REPLY_SHIFT) | ||
47 | #define IPC_GLB_REPLY_TYPE(x) (x << IPC_GLB_REPLY_TYPE_SHIFT) | ||
48 | |||
49 | /* Stream Message - Generic */ | ||
50 | #define IPC_STR_TYPE_SHIFT 20 | ||
51 | #define IPC_STR_TYPE_MASK (0xf << IPC_STR_TYPE_SHIFT) | ||
52 | #define IPC_STR_TYPE(x) (x << IPC_STR_TYPE_SHIFT) | ||
53 | #define IPC_STR_ID_SHIFT 16 | ||
54 | #define IPC_STR_ID_MASK (0xf << IPC_STR_ID_SHIFT) | ||
55 | #define IPC_STR_ID(x) (x << IPC_STR_ID_SHIFT) | ||
56 | |||
57 | /* Stream Message - Reply */ | ||
58 | #define IPC_STR_REPLY_SHIFT 0 | ||
59 | #define IPC_STR_REPLY_MASK (0x1f << IPC_STR_REPLY_SHIFT) | ||
60 | |||
61 | /* Stream Stage Message - Generic */ | ||
62 | #define IPC_STG_TYPE_SHIFT 12 | ||
63 | #define IPC_STG_TYPE_MASK (0xf << IPC_STG_TYPE_SHIFT) | ||
64 | #define IPC_STG_TYPE(x) (x << IPC_STG_TYPE_SHIFT) | ||
65 | #define IPC_STG_ID_SHIFT 10 | ||
66 | #define IPC_STG_ID_MASK (0x3 << IPC_STG_ID_SHIFT) | ||
67 | #define IPC_STG_ID(x) (x << IPC_STG_ID_SHIFT) | ||
68 | |||
69 | /* Stream Stage Message - Reply */ | ||
70 | #define IPC_STG_REPLY_SHIFT 0 | ||
71 | #define IPC_STG_REPLY_MASK (0x1f << IPC_STG_REPLY_SHIFT) | ||
72 | |||
73 | /* Debug Log Message - Generic */ | ||
74 | #define IPC_LOG_OP_SHIFT 20 | ||
75 | #define IPC_LOG_OP_MASK (0xf << IPC_LOG_OP_SHIFT) | ||
76 | #define IPC_LOG_OP_TYPE(x) (x << IPC_LOG_OP_SHIFT) | ||
77 | #define IPC_LOG_ID_SHIFT 16 | ||
78 | #define IPC_LOG_ID_MASK (0xf << IPC_LOG_ID_SHIFT) | ||
79 | #define IPC_LOG_ID(x) (x << IPC_LOG_ID_SHIFT) | ||
80 | |||
81 | /* IPC message timeout (msecs) */ | ||
82 | #define IPC_TIMEOUT_MSECS 300 | ||
83 | #define IPC_BOOT_MSECS 200 | ||
84 | #define IPC_MSG_WAIT 0 | ||
85 | #define IPC_MSG_NOWAIT 1 | ||
86 | |||
87 | /* Firmware Ready Message */ | ||
88 | #define IPC_FW_READY (0x1 << 29) | ||
89 | #define IPC_STATUS_MASK (0x3 << 30) | ||
90 | |||
91 | #define IPC_EMPTY_LIST_SIZE 8 | ||
92 | #define IPC_MAX_STREAMS 4 | ||
93 | |||
94 | /* Mailbox */ | ||
95 | #define IPC_MAX_MAILBOX_BYTES 256 | ||
96 | |||
97 | /* Global Message - Types and Replies */ | ||
98 | enum ipc_glb_type { | ||
99 | IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ | ||
100 | IPC_GLB_PERFORMANCE_MONITOR = 1, /* Performance monitoring actions */ | ||
101 | IPC_GLB_ALLOCATE_STREAM = 3, /* Request to allocate new stream */ | ||
102 | IPC_GLB_FREE_STREAM = 4, /* Request to free stream */ | ||
103 | IPC_GLB_GET_FW_CAPABILITIES = 5, /* Retrieves firmware capabilities */ | ||
104 | IPC_GLB_STREAM_MESSAGE = 6, /* Message directed to stream or its stages */ | ||
105 | /* Request to store firmware context during D0->D3 transition */ | ||
106 | IPC_GLB_REQUEST_DUMP = 7, | ||
107 | /* Request to restore firmware context during D3->D0 transition */ | ||
108 | IPC_GLB_RESTORE_CONTEXT = 8, | ||
109 | IPC_GLB_GET_DEVICE_FORMATS = 9, /* Set device format */ | ||
110 | IPC_GLB_SET_DEVICE_FORMATS = 10, /* Get device format */ | ||
111 | IPC_GLB_SHORT_REPLY = 11, | ||
112 | IPC_GLB_ENTER_DX_STATE = 12, | ||
113 | IPC_GLB_GET_MIXER_STREAM_INFO = 13, /* Request mixer stream params */ | ||
114 | IPC_GLB_DEBUG_LOG_MESSAGE = 14, /* Message to or from the debug logger. */ | ||
115 | IPC_GLB_REQUEST_TRANSFER = 16, /* < Request Transfer for host */ | ||
116 | IPC_GLB_MAX_IPC_MESSAGE_TYPE = 17, /* Maximum message number */ | ||
117 | }; | ||
118 | |||
119 | enum ipc_glb_reply { | ||
120 | IPC_GLB_REPLY_SUCCESS = 0, /* The operation was successful. */ | ||
121 | IPC_GLB_REPLY_ERROR_INVALID_PARAM = 1, /* Invalid parameter was passed. */ | ||
122 | IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE = 2, /* Uknown message type was resceived. */ | ||
123 | IPC_GLB_REPLY_OUT_OF_RESOURCES = 3, /* No resources to satisfy the request. */ | ||
124 | IPC_GLB_REPLY_BUSY = 4, /* The system or resource is busy. */ | ||
125 | IPC_GLB_REPLY_PENDING = 5, /* The action was scheduled for processing. */ | ||
126 | IPC_GLB_REPLY_FAILURE = 6, /* Critical error happened. */ | ||
127 | IPC_GLB_REPLY_INVALID_REQUEST = 7, /* Request can not be completed. */ | ||
128 | IPC_GLB_REPLY_STAGE_UNINITIALIZED = 8, /* Processing stage was uninitialized. */ | ||
129 | IPC_GLB_REPLY_NOT_FOUND = 9, /* Required resource can not be found. */ | ||
130 | IPC_GLB_REPLY_SOURCE_NOT_STARTED = 10, /* Source was not started. */ | ||
131 | }; | ||
132 | |||
133 | /* Stream Message - Types */ | ||
134 | enum ipc_str_operation { | ||
135 | IPC_STR_RESET = 0, | ||
136 | IPC_STR_PAUSE = 1, | ||
137 | IPC_STR_RESUME = 2, | ||
138 | IPC_STR_STAGE_MESSAGE = 3, | ||
139 | IPC_STR_NOTIFICATION = 4, | ||
140 | IPC_STR_MAX_MESSAGE | ||
141 | }; | ||
142 | |||
143 | /* Stream Stage Message Types */ | ||
144 | enum ipc_stg_operation { | ||
145 | IPC_STG_GET_VOLUME = 0, | ||
146 | IPC_STG_SET_VOLUME, | ||
147 | IPC_STG_SET_WRITE_POSITION, | ||
148 | IPC_STG_SET_FX_ENABLE, | ||
149 | IPC_STG_SET_FX_DISABLE, | ||
150 | IPC_STG_SET_FX_GET_PARAM, | ||
151 | IPC_STG_SET_FX_SET_PARAM, | ||
152 | IPC_STG_SET_FX_GET_INFO, | ||
153 | IPC_STG_MUTE_LOOPBACK, | ||
154 | IPC_STG_MAX_MESSAGE | ||
155 | }; | ||
156 | |||
157 | /* Stream Stage Message Types For Notification*/ | ||
158 | enum ipc_stg_operation_notify { | ||
159 | IPC_POSITION_CHANGED = 0, | ||
160 | IPC_STG_GLITCH, | ||
161 | IPC_STG_MAX_NOTIFY | ||
162 | }; | ||
163 | |||
164 | enum ipc_glitch_type { | ||
165 | IPC_GLITCH_UNDERRUN = 1, | ||
166 | IPC_GLITCH_DECODER_ERROR, | ||
167 | IPC_GLITCH_DOUBLED_WRITE_POS, | ||
168 | IPC_GLITCH_MAX | ||
169 | }; | ||
170 | |||
171 | /* Debug Control */ | ||
172 | enum ipc_debug_operation { | ||
173 | IPC_DEBUG_ENABLE_LOG = 0, | ||
174 | IPC_DEBUG_DISABLE_LOG = 1, | ||
175 | IPC_DEBUG_REQUEST_LOG_DUMP = 2, | ||
176 | IPC_DEBUG_NOTIFY_LOG_DUMP = 3, | ||
177 | IPC_DEBUG_MAX_DEBUG_LOG | ||
178 | }; | ||
179 | |||
180 | /* Firmware Ready */ | ||
181 | struct sst_hsw_ipc_fw_ready { | ||
182 | u32 inbox_offset; | ||
183 | u32 outbox_offset; | ||
184 | u32 inbox_size; | ||
185 | u32 outbox_size; | ||
186 | u32 fw_info_size; | ||
187 | u8 fw_info[1]; | ||
188 | } __attribute__((packed)); | ||
189 | |||
190 | struct ipc_message { | ||
191 | struct list_head list; | ||
192 | u32 header; | ||
193 | |||
194 | /* direction wrt host CPU */ | ||
195 | char tx_data[IPC_MAX_MAILBOX_BYTES]; | ||
196 | size_t tx_size; | ||
197 | char rx_data[IPC_MAX_MAILBOX_BYTES]; | ||
198 | size_t rx_size; | ||
199 | |||
200 | wait_queue_head_t waitq; | ||
201 | bool pending; | ||
202 | bool complete; | ||
203 | bool wait; | ||
204 | int errno; | ||
205 | }; | ||
206 | |||
207 | struct sst_hsw_stream; | ||
208 | struct sst_hsw; | ||
209 | |||
210 | /* Stream infomation */ | ||
211 | struct sst_hsw_stream { | ||
212 | /* configuration */ | ||
213 | struct sst_hsw_ipc_stream_alloc_req request; | ||
214 | struct sst_hsw_ipc_stream_alloc_reply reply; | ||
215 | struct sst_hsw_ipc_stream_free_req free_req; | ||
216 | |||
217 | /* Mixer info */ | ||
218 | u32 mute_volume[SST_HSW_NO_CHANNELS]; | ||
219 | u32 mute[SST_HSW_NO_CHANNELS]; | ||
220 | |||
221 | /* runtime info */ | ||
222 | struct sst_hsw *hsw; | ||
223 | int host_id; | ||
224 | bool commited; | ||
225 | bool running; | ||
226 | |||
227 | /* Notification work */ | ||
228 | struct work_struct notify_work; | ||
229 | u32 header; | ||
230 | |||
231 | /* Position info from DSP */ | ||
232 | struct sst_hsw_ipc_stream_set_position wpos; | ||
233 | struct sst_hsw_ipc_stream_get_position rpos; | ||
234 | struct sst_hsw_ipc_stream_glitch_position glitch; | ||
235 | |||
236 | /* Volume info */ | ||
237 | struct sst_hsw_ipc_volume_req vol_req; | ||
238 | |||
239 | /* driver callback */ | ||
240 | u32 (*notify_position)(struct sst_hsw_stream *stream, void *data); | ||
241 | void *pdata; | ||
242 | |||
243 | struct list_head node; | ||
244 | }; | ||
245 | |||
246 | /* FW log ring information */ | ||
247 | struct sst_hsw_log_stream { | ||
248 | dma_addr_t dma_addr; | ||
249 | unsigned char *dma_area; | ||
250 | unsigned char *ring_descr; | ||
251 | int pages; | ||
252 | int size; | ||
253 | |||
254 | /* Notification work */ | ||
255 | struct work_struct notify_work; | ||
256 | wait_queue_head_t readers_wait_q; | ||
257 | struct mutex rw_mutex; | ||
258 | |||
259 | u32 last_pos; | ||
260 | u32 curr_pos; | ||
261 | u32 reader_pos; | ||
262 | |||
263 | /* fw log config */ | ||
264 | u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS]; | ||
265 | |||
266 | struct sst_hsw *hsw; | ||
267 | }; | ||
268 | |||
269 | /* SST Haswell IPC data */ | ||
270 | struct sst_hsw { | ||
271 | struct device *dev; | ||
272 | struct sst_dsp *dsp; | ||
273 | struct platform_device *pdev_pcm; | ||
274 | |||
275 | /* FW config */ | ||
276 | struct sst_hsw_ipc_fw_ready fw_ready; | ||
277 | struct sst_hsw_ipc_fw_version version; | ||
278 | struct sst_module *scratch; | ||
279 | bool fw_done; | ||
280 | |||
281 | /* stream */ | ||
282 | struct list_head stream_list; | ||
283 | |||
284 | /* global mixer */ | ||
285 | struct sst_hsw_ipc_stream_info_reply mixer_info; | ||
286 | enum sst_hsw_volume_curve curve_type; | ||
287 | u32 curve_duration; | ||
288 | u32 mute[SST_HSW_NO_CHANNELS]; | ||
289 | u32 mute_volume[SST_HSW_NO_CHANNELS]; | ||
290 | |||
291 | /* DX */ | ||
292 | struct sst_hsw_ipc_dx_reply dx; | ||
293 | |||
294 | /* boot */ | ||
295 | wait_queue_head_t boot_wait; | ||
296 | bool boot_complete; | ||
297 | bool shutdown; | ||
298 | |||
299 | /* IPC messaging */ | ||
300 | struct list_head tx_list; | ||
301 | struct list_head rx_list; | ||
302 | struct list_head empty_list; | ||
303 | wait_queue_head_t wait_txq; | ||
304 | struct task_struct *tx_thread; | ||
305 | struct kthread_worker kworker; | ||
306 | struct kthread_work kwork; | ||
307 | bool pending; | ||
308 | struct ipc_message *msg; | ||
309 | |||
310 | /* FW log stream */ | ||
311 | struct sst_hsw_log_stream log_stream; | ||
312 | }; | ||
313 | |||
314 | #define CREATE_TRACE_POINTS | ||
315 | #include <trace/events/hswadsp.h> | ||
316 | |||
317 | static inline u32 msg_get_global_type(u32 msg) | ||
318 | { | ||
319 | return (msg & IPC_GLB_TYPE_MASK) >> IPC_GLB_TYPE_SHIFT; | ||
320 | } | ||
321 | |||
322 | static inline u32 msg_get_global_reply(u32 msg) | ||
323 | { | ||
324 | return (msg & IPC_GLB_REPLY_MASK) >> IPC_GLB_REPLY_SHIFT; | ||
325 | } | ||
326 | |||
327 | static inline u32 msg_get_stream_type(u32 msg) | ||
328 | { | ||
329 | return (msg & IPC_STR_TYPE_MASK) >> IPC_STR_TYPE_SHIFT; | ||
330 | } | ||
331 | |||
332 | static inline u32 msg_get_stage_type(u32 msg) | ||
333 | { | ||
334 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | ||
335 | } | ||
336 | |||
337 | static inline u32 msg_set_stage_type(u32 msg, u32 type) | ||
338 | { | ||
339 | return (msg & ~IPC_STG_TYPE_MASK) + | ||
340 | (type << IPC_STG_TYPE_SHIFT); | ||
341 | } | ||
342 | |||
343 | static inline u32 msg_get_stream_id(u32 msg) | ||
344 | { | ||
345 | return (msg & IPC_STR_ID_MASK) >> IPC_STR_ID_SHIFT; | ||
346 | } | ||
347 | |||
348 | static inline u32 msg_get_notify_reason(u32 msg) | ||
349 | { | ||
350 | return (msg & IPC_STG_TYPE_MASK) >> IPC_STG_TYPE_SHIFT; | ||
351 | } | ||
352 | |||
353 | u32 create_channel_map(enum sst_hsw_channel_config config) | ||
354 | { | ||
355 | switch (config) { | ||
356 | case SST_HSW_CHANNEL_CONFIG_MONO: | ||
357 | return (0xFFFFFFF0 | SST_HSW_CHANNEL_CENTER); | ||
358 | case SST_HSW_CHANNEL_CONFIG_STEREO: | ||
359 | return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT | ||
360 | | (SST_HSW_CHANNEL_RIGHT << 4)); | ||
361 | case SST_HSW_CHANNEL_CONFIG_2_POINT_1: | ||
362 | return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT | ||
363 | | (SST_HSW_CHANNEL_RIGHT << 4) | ||
364 | | (SST_HSW_CHANNEL_LFE << 8 )); | ||
365 | case SST_HSW_CHANNEL_CONFIG_3_POINT_0: | ||
366 | return (0xFFFFF000 | SST_HSW_CHANNEL_LEFT | ||
367 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
368 | | (SST_HSW_CHANNEL_RIGHT << 8)); | ||
369 | case SST_HSW_CHANNEL_CONFIG_3_POINT_1: | ||
370 | return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT | ||
371 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
372 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
373 | | (SST_HSW_CHANNEL_LFE << 12)); | ||
374 | case SST_HSW_CHANNEL_CONFIG_QUATRO: | ||
375 | return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT | ||
376 | | (SST_HSW_CHANNEL_RIGHT << 4) | ||
377 | | (SST_HSW_CHANNEL_LEFT_SURROUND << 8) | ||
378 | | (SST_HSW_CHANNEL_RIGHT_SURROUND << 12)); | ||
379 | case SST_HSW_CHANNEL_CONFIG_4_POINT_0: | ||
380 | return (0xFFFF0000 | SST_HSW_CHANNEL_LEFT | ||
381 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
382 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
383 | | (SST_HSW_CHANNEL_CENTER_SURROUND << 12)); | ||
384 | case SST_HSW_CHANNEL_CONFIG_5_POINT_0: | ||
385 | return (0xFFF00000 | SST_HSW_CHANNEL_LEFT | ||
386 | | (SST_HSW_CHANNEL_CENTER << 4) | ||
387 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
388 | | (SST_HSW_CHANNEL_LEFT_SURROUND << 12) | ||
389 | | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16)); | ||
390 | case SST_HSW_CHANNEL_CONFIG_5_POINT_1: | ||
391 | return (0xFF000000 | SST_HSW_CHANNEL_CENTER | ||
392 | | (SST_HSW_CHANNEL_LEFT << 4) | ||
393 | | (SST_HSW_CHANNEL_RIGHT << 8) | ||
394 | | (SST_HSW_CHANNEL_LEFT_SURROUND << 12) | ||
395 | | (SST_HSW_CHANNEL_RIGHT_SURROUND << 16) | ||
396 | | (SST_HSW_CHANNEL_LFE << 20)); | ||
397 | case SST_HSW_CHANNEL_CONFIG_DUAL_MONO: | ||
398 | return (0xFFFFFF00 | SST_HSW_CHANNEL_LEFT | ||
399 | | (SST_HSW_CHANNEL_LEFT << 4)); | ||
400 | default: | ||
401 | return 0xFFFFFFFF; | ||
402 | } | ||
403 | } | ||
404 | |||
405 | static struct sst_hsw_stream *get_stream_by_id(struct sst_hsw *hsw, | ||
406 | int stream_id) | ||
407 | { | ||
408 | struct sst_hsw_stream *stream; | ||
409 | |||
410 | list_for_each_entry(stream, &hsw->stream_list, node) { | ||
411 | if (stream->reply.stream_hw_id == stream_id) | ||
412 | return stream; | ||
413 | } | ||
414 | |||
415 | return NULL; | ||
416 | } | ||
417 | |||
418 | static void ipc_shim_dbg(struct sst_hsw *hsw, const char *text) | ||
419 | { | ||
420 | struct sst_dsp *sst = hsw->dsp; | ||
421 | u32 isr, ipcd, imrx, ipcx; | ||
422 | |||
423 | ipcx = sst_dsp_shim_read_unlocked(sst, SST_IPCX); | ||
424 | isr = sst_dsp_shim_read_unlocked(sst, SST_ISRX); | ||
425 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
426 | imrx = sst_dsp_shim_read_unlocked(sst, SST_IMRX); | ||
427 | |||
428 | dev_err(hsw->dev, "ipc: --%s-- ipcx 0x%8.8x isr 0x%8.8x ipcd 0x%8.8x imrx 0x%8.8x\n", | ||
429 | text, ipcx, isr, ipcd, imrx); | ||
430 | } | ||
431 | |||
432 | /* locks held by caller */ | ||
433 | static struct ipc_message *msg_get_empty(struct sst_hsw *hsw) | ||
434 | { | ||
435 | struct ipc_message *msg = NULL; | ||
436 | |||
437 | if (!list_empty(&hsw->empty_list)) { | ||
438 | msg = list_first_entry(&hsw->empty_list, struct ipc_message, | ||
439 | list); | ||
440 | list_del(&msg->list); | ||
441 | } | ||
442 | |||
443 | return msg; | ||
444 | } | ||
445 | |||
446 | static void ipc_tx_msgs(struct kthread_work *work) | ||
447 | { | ||
448 | struct sst_hsw *hsw = | ||
449 | container_of(work, struct sst_hsw, kwork); | ||
450 | struct ipc_message *msg; | ||
451 | unsigned long flags; | ||
452 | u32 ipcx; | ||
453 | |||
454 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
455 | |||
456 | if (list_empty(&hsw->tx_list) || hsw->pending) { | ||
457 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
458 | return; | ||
459 | } | ||
460 | |||
461 | /* if the DSP is busy we will TX messages after IRQ */ | ||
462 | ipcx = sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX); | ||
463 | if (ipcx & SST_IPCX_BUSY) { | ||
464 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
465 | return; | ||
466 | } | ||
467 | |||
468 | msg = list_first_entry(&hsw->tx_list, struct ipc_message, list); | ||
469 | |||
470 | list_move(&msg->list, &hsw->rx_list); | ||
471 | |||
472 | /* send the message */ | ||
473 | sst_dsp_outbox_write(hsw->dsp, msg->tx_data, msg->tx_size); | ||
474 | sst_dsp_ipc_msg_tx(hsw->dsp, msg->header | SST_IPCX_BUSY); | ||
475 | |||
476 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
477 | } | ||
478 | |||
479 | /* locks held by caller */ | ||
480 | static void tx_msg_reply_complete(struct sst_hsw *hsw, struct ipc_message *msg) | ||
481 | { | ||
482 | msg->complete = true; | ||
483 | trace_ipc_reply("completed", msg->header); | ||
484 | |||
485 | if (!msg->wait) | ||
486 | list_add_tail(&msg->list, &hsw->empty_list); | ||
487 | else | ||
488 | wake_up(&msg->waitq); | ||
489 | } | ||
490 | |||
491 | static int tx_wait_done(struct sst_hsw *hsw, struct ipc_message *msg, | ||
492 | void *rx_data) | ||
493 | { | ||
494 | unsigned long flags; | ||
495 | int ret; | ||
496 | |||
497 | /* wait for DSP completion (in all cases atm inc pending) */ | ||
498 | ret = wait_event_timeout(msg->waitq, msg->complete, | ||
499 | msecs_to_jiffies(IPC_TIMEOUT_MSECS)); | ||
500 | |||
501 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
502 | if (ret == 0) { | ||
503 | ipc_shim_dbg(hsw, "message timeout"); | ||
504 | |||
505 | trace_ipc_error("error message timeout for", msg->header); | ||
506 | ret = -ETIMEDOUT; | ||
507 | } else { | ||
508 | |||
509 | /* copy the data returned from DSP */ | ||
510 | if (msg->rx_size) | ||
511 | memcpy(rx_data, msg->rx_data, msg->rx_size); | ||
512 | ret = msg->errno; | ||
513 | } | ||
514 | |||
515 | list_add_tail(&msg->list, &hsw->empty_list); | ||
516 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
517 | return ret; | ||
518 | } | ||
519 | |||
520 | static int ipc_tx_message(struct sst_hsw *hsw, u32 header, void *tx_data, | ||
521 | size_t tx_bytes, void *rx_data, size_t rx_bytes, int wait) | ||
522 | { | ||
523 | struct ipc_message *msg; | ||
524 | unsigned long flags; | ||
525 | |||
526 | spin_lock_irqsave(&hsw->dsp->spinlock, flags); | ||
527 | |||
528 | msg = msg_get_empty(hsw); | ||
529 | if (msg == NULL) { | ||
530 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
531 | return -EBUSY; | ||
532 | } | ||
533 | |||
534 | if (tx_bytes) | ||
535 | memcpy(msg->tx_data, tx_data, tx_bytes); | ||
536 | |||
537 | msg->header = header; | ||
538 | msg->tx_size = tx_bytes; | ||
539 | msg->rx_size = rx_bytes; | ||
540 | msg->wait = wait; | ||
541 | msg->errno = 0; | ||
542 | msg->pending = false; | ||
543 | msg->complete = false; | ||
544 | |||
545 | list_add_tail(&msg->list, &hsw->tx_list); | ||
546 | spin_unlock_irqrestore(&hsw->dsp->spinlock, flags); | ||
547 | |||
548 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | ||
549 | |||
550 | if (wait) | ||
551 | return tx_wait_done(hsw, msg, rx_data); | ||
552 | else | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static inline int ipc_tx_message_wait(struct sst_hsw *hsw, u32 header, | ||
557 | void *tx_data, size_t tx_bytes, void *rx_data, size_t rx_bytes) | ||
558 | { | ||
559 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, rx_data, | ||
560 | rx_bytes, 1); | ||
561 | } | ||
562 | |||
563 | static inline int ipc_tx_message_nowait(struct sst_hsw *hsw, u32 header, | ||
564 | void *tx_data, size_t tx_bytes) | ||
565 | { | ||
566 | return ipc_tx_message(hsw, header, tx_data, tx_bytes, NULL, 0, 0); | ||
567 | } | ||
568 | |||
569 | static void hsw_fw_ready(struct sst_hsw *hsw, u32 header) | ||
570 | { | ||
571 | struct sst_hsw_ipc_fw_ready fw_ready; | ||
572 | u32 offset; | ||
573 | |||
574 | offset = (header & 0x1FFFFFFF) << 3; | ||
575 | |||
576 | dev_dbg(hsw->dev, "ipc: DSP is ready 0x%8.8x offset %d\n", | ||
577 | header, offset); | ||
578 | |||
579 | /* copy data from the DSP FW ready offset */ | ||
580 | sst_dsp_read(hsw->dsp, &fw_ready, offset, sizeof(fw_ready)); | ||
581 | |||
582 | sst_dsp_mailbox_init(hsw->dsp, fw_ready.inbox_offset, | ||
583 | fw_ready.inbox_size, fw_ready.outbox_offset, | ||
584 | fw_ready.outbox_size); | ||
585 | |||
586 | hsw->boot_complete = true; | ||
587 | wake_up(&hsw->boot_wait); | ||
588 | |||
589 | dev_dbg(hsw->dev, " mailbox upstream 0x%x - size 0x%x\n", | ||
590 | fw_ready.inbox_offset, fw_ready.inbox_size); | ||
591 | dev_dbg(hsw->dev, " mailbox downstream 0x%x - size 0x%x\n", | ||
592 | fw_ready.outbox_offset, fw_ready.outbox_size); | ||
593 | } | ||
594 | |||
595 | static void hsw_notification_work(struct work_struct *work) | ||
596 | { | ||
597 | struct sst_hsw_stream *stream = container_of(work, | ||
598 | struct sst_hsw_stream, notify_work); | ||
599 | struct sst_hsw_ipc_stream_glitch_position *glitch = &stream->glitch; | ||
600 | struct sst_hsw_ipc_stream_get_position *pos = &stream->rpos; | ||
601 | struct sst_hsw *hsw = stream->hsw; | ||
602 | u32 reason; | ||
603 | |||
604 | reason = msg_get_notify_reason(stream->header); | ||
605 | |||
606 | switch (reason) { | ||
607 | case IPC_STG_GLITCH: | ||
608 | trace_ipc_notification("DSP stream under/overrun", | ||
609 | stream->reply.stream_hw_id); | ||
610 | sst_dsp_inbox_read(hsw->dsp, glitch, sizeof(*glitch)); | ||
611 | |||
612 | dev_err(hsw->dev, "glitch %d pos 0x%x write pos 0x%x\n", | ||
613 | glitch->glitch_type, glitch->present_pos, | ||
614 | glitch->write_pos); | ||
615 | break; | ||
616 | |||
617 | case IPC_POSITION_CHANGED: | ||
618 | trace_ipc_notification("DSP stream position changed for", | ||
619 | stream->reply.stream_hw_id); | ||
620 | sst_dsp_inbox_read(hsw->dsp, pos, sizeof(pos)); | ||
621 | |||
622 | if (stream->notify_position) | ||
623 | stream->notify_position(stream, stream->pdata); | ||
624 | |||
625 | break; | ||
626 | default: | ||
627 | dev_err(hsw->dev, "error: unknown notification 0x%x\n", | ||
628 | stream->header); | ||
629 | break; | ||
630 | } | ||
631 | |||
632 | /* tell DSP that notification has been handled */ | ||
633 | sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IPCD, | ||
634 | SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); | ||
635 | |||
636 | /* unmask busy interrupt */ | ||
637 | sst_dsp_shim_update_bits_unlocked(hsw->dsp, SST_IMRX, SST_IMRX_BUSY, 0); | ||
638 | } | ||
639 | |||
640 | static struct ipc_message *reply_find_msg(struct sst_hsw *hsw, u32 header) | ||
641 | { | ||
642 | struct ipc_message *msg; | ||
643 | |||
644 | /* clear reply bits & status bits */ | ||
645 | header &= ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
646 | |||
647 | if (list_empty(&hsw->rx_list)) { | ||
648 | dev_err(hsw->dev, "error: rx list empty but received 0x%x\n", | ||
649 | header); | ||
650 | return NULL; | ||
651 | } | ||
652 | |||
653 | list_for_each_entry(msg, &hsw->rx_list, list) { | ||
654 | if (msg->header == header) | ||
655 | return msg; | ||
656 | } | ||
657 | |||
658 | return NULL; | ||
659 | } | ||
660 | |||
661 | static void hsw_stream_update(struct sst_hsw *hsw, struct ipc_message *msg) | ||
662 | { | ||
663 | struct sst_hsw_stream *stream; | ||
664 | u32 header = msg->header & ~(IPC_STATUS_MASK | IPC_GLB_REPLY_MASK); | ||
665 | u32 stream_id = msg_get_stream_id(header); | ||
666 | u32 stream_msg = msg_get_stream_type(header); | ||
667 | |||
668 | stream = get_stream_by_id(hsw, stream_id); | ||
669 | if (stream == NULL) | ||
670 | return; | ||
671 | |||
672 | switch (stream_msg) { | ||
673 | case IPC_STR_STAGE_MESSAGE: | ||
674 | case IPC_STR_NOTIFICATION: | ||
675 | case IPC_STR_RESET: | ||
676 | break; | ||
677 | case IPC_STR_PAUSE: | ||
678 | stream->running = false; | ||
679 | trace_ipc_notification("stream paused", | ||
680 | stream->reply.stream_hw_id); | ||
681 | break; | ||
682 | case IPC_STR_RESUME: | ||
683 | stream->running = true; | ||
684 | trace_ipc_notification("stream running", | ||
685 | stream->reply.stream_hw_id); | ||
686 | break; | ||
687 | } | ||
688 | } | ||
689 | |||
690 | static int hsw_process_reply(struct sst_hsw *hsw, u32 header) | ||
691 | { | ||
692 | struct ipc_message *msg; | ||
693 | u32 reply = msg_get_global_reply(header); | ||
694 | |||
695 | trace_ipc_reply("processing -->", header); | ||
696 | |||
697 | msg = reply_find_msg(hsw, header); | ||
698 | if (msg == NULL) { | ||
699 | trace_ipc_error("error: can't find message header", header); | ||
700 | return -EIO; | ||
701 | } | ||
702 | |||
703 | /* first process the header */ | ||
704 | switch (reply) { | ||
705 | case IPC_GLB_REPLY_PENDING: | ||
706 | trace_ipc_pending_reply("received", header); | ||
707 | msg->pending = true; | ||
708 | hsw->pending = true; | ||
709 | return 1; | ||
710 | case IPC_GLB_REPLY_SUCCESS: | ||
711 | if (msg->pending) { | ||
712 | trace_ipc_pending_reply("completed", header); | ||
713 | sst_dsp_inbox_read(hsw->dsp, msg->rx_data, | ||
714 | msg->rx_size); | ||
715 | hsw->pending = false; | ||
716 | } else { | ||
717 | /* copy data from the DSP */ | ||
718 | sst_dsp_outbox_read(hsw->dsp, msg->rx_data, | ||
719 | msg->rx_size); | ||
720 | } | ||
721 | break; | ||
722 | /* these will be rare - but useful for debug */ | ||
723 | case IPC_GLB_REPLY_UNKNOWN_MESSAGE_TYPE: | ||
724 | trace_ipc_error("error: unknown message type", header); | ||
725 | msg->errno = -EBADMSG; | ||
726 | break; | ||
727 | case IPC_GLB_REPLY_OUT_OF_RESOURCES: | ||
728 | trace_ipc_error("error: out of resources", header); | ||
729 | msg->errno = -ENOMEM; | ||
730 | break; | ||
731 | case IPC_GLB_REPLY_BUSY: | ||
732 | trace_ipc_error("error: reply busy", header); | ||
733 | msg->errno = -EBUSY; | ||
734 | break; | ||
735 | case IPC_GLB_REPLY_FAILURE: | ||
736 | trace_ipc_error("error: reply failure", header); | ||
737 | msg->errno = -EINVAL; | ||
738 | break; | ||
739 | case IPC_GLB_REPLY_STAGE_UNINITIALIZED: | ||
740 | trace_ipc_error("error: stage uninitialized", header); | ||
741 | msg->errno = -EINVAL; | ||
742 | break; | ||
743 | case IPC_GLB_REPLY_NOT_FOUND: | ||
744 | trace_ipc_error("error: reply not found", header); | ||
745 | msg->errno = -EINVAL; | ||
746 | break; | ||
747 | case IPC_GLB_REPLY_SOURCE_NOT_STARTED: | ||
748 | trace_ipc_error("error: source not started", header); | ||
749 | msg->errno = -EINVAL; | ||
750 | break; | ||
751 | case IPC_GLB_REPLY_INVALID_REQUEST: | ||
752 | trace_ipc_error("error: invalid request", header); | ||
753 | msg->errno = -EINVAL; | ||
754 | break; | ||
755 | case IPC_GLB_REPLY_ERROR_INVALID_PARAM: | ||
756 | trace_ipc_error("error: invalid parameter", header); | ||
757 | msg->errno = -EINVAL; | ||
758 | break; | ||
759 | default: | ||
760 | trace_ipc_error("error: unknown reply", header); | ||
761 | msg->errno = -EINVAL; | ||
762 | break; | ||
763 | } | ||
764 | |||
765 | /* update any stream states */ | ||
766 | hsw_stream_update(hsw, msg); | ||
767 | |||
768 | /* wake up and return the error if we have waiters on this message ? */ | ||
769 | list_del(&msg->list); | ||
770 | tx_msg_reply_complete(hsw, msg); | ||
771 | |||
772 | return 1; | ||
773 | } | ||
774 | |||
775 | static int hsw_stream_message(struct sst_hsw *hsw, u32 header) | ||
776 | { | ||
777 | u32 stream_msg, stream_id, stage_type; | ||
778 | struct sst_hsw_stream *stream; | ||
779 | int handled = 0; | ||
780 | |||
781 | stream_msg = msg_get_stream_type(header); | ||
782 | stream_id = msg_get_stream_id(header); | ||
783 | stage_type = msg_get_stage_type(header); | ||
784 | |||
785 | stream = get_stream_by_id(hsw, stream_id); | ||
786 | if (stream == NULL) | ||
787 | return handled; | ||
788 | |||
789 | stream->header = header; | ||
790 | |||
791 | switch (stream_msg) { | ||
792 | case IPC_STR_STAGE_MESSAGE: | ||
793 | dev_err(hsw->dev, "error: stage msg not implemented 0x%8.8x\n", | ||
794 | header); | ||
795 | break; | ||
796 | case IPC_STR_NOTIFICATION: | ||
797 | schedule_work(&stream->notify_work); | ||
798 | break; | ||
799 | default: | ||
800 | /* handle pending message complete request */ | ||
801 | handled = hsw_process_reply(hsw, header); | ||
802 | break; | ||
803 | } | ||
804 | |||
805 | return handled; | ||
806 | } | ||
807 | |||
808 | static int hsw_log_message(struct sst_hsw *hsw, u32 header) | ||
809 | { | ||
810 | u32 operation = (header & IPC_LOG_OP_MASK) >> IPC_LOG_OP_SHIFT; | ||
811 | struct sst_hsw_log_stream *stream = &hsw->log_stream; | ||
812 | int ret = 1; | ||
813 | |||
814 | if (operation != IPC_DEBUG_REQUEST_LOG_DUMP) { | ||
815 | dev_err(hsw->dev, | ||
816 | "error: log msg not implemented 0x%8.8x\n", header); | ||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | mutex_lock(&stream->rw_mutex); | ||
821 | stream->last_pos = stream->curr_pos; | ||
822 | sst_dsp_inbox_read( | ||
823 | hsw->dsp, &stream->curr_pos, sizeof(stream->curr_pos)); | ||
824 | mutex_unlock(&stream->rw_mutex); | ||
825 | |||
826 | schedule_work(&stream->notify_work); | ||
827 | |||
828 | return ret; | ||
829 | } | ||
830 | |||
831 | static int hsw_process_notification(struct sst_hsw *hsw) | ||
832 | { | ||
833 | struct sst_dsp *sst = hsw->dsp; | ||
834 | u32 type, header; | ||
835 | int handled = 1; | ||
836 | |||
837 | header = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
838 | type = msg_get_global_type(header); | ||
839 | |||
840 | trace_ipc_request("processing -->", header); | ||
841 | |||
842 | /* FW Ready is a special case */ | ||
843 | if (!hsw->boot_complete && header & IPC_FW_READY) { | ||
844 | hsw_fw_ready(hsw, header); | ||
845 | return handled; | ||
846 | } | ||
847 | |||
848 | switch (type) { | ||
849 | case IPC_GLB_GET_FW_VERSION: | ||
850 | case IPC_GLB_ALLOCATE_STREAM: | ||
851 | case IPC_GLB_FREE_STREAM: | ||
852 | case IPC_GLB_GET_FW_CAPABILITIES: | ||
853 | case IPC_GLB_REQUEST_DUMP: | ||
854 | case IPC_GLB_GET_DEVICE_FORMATS: | ||
855 | case IPC_GLB_SET_DEVICE_FORMATS: | ||
856 | case IPC_GLB_ENTER_DX_STATE: | ||
857 | case IPC_GLB_GET_MIXER_STREAM_INFO: | ||
858 | case IPC_GLB_MAX_IPC_MESSAGE_TYPE: | ||
859 | case IPC_GLB_RESTORE_CONTEXT: | ||
860 | case IPC_GLB_SHORT_REPLY: | ||
861 | dev_err(hsw->dev, "error: message type %d header 0x%x\n", | ||
862 | type, header); | ||
863 | break; | ||
864 | case IPC_GLB_STREAM_MESSAGE: | ||
865 | handled = hsw_stream_message(hsw, header); | ||
866 | break; | ||
867 | case IPC_GLB_DEBUG_LOG_MESSAGE: | ||
868 | handled = hsw_log_message(hsw, header); | ||
869 | break; | ||
870 | default: | ||
871 | dev_err(hsw->dev, "error: unexpected type %d hdr 0x%8.8x\n", | ||
872 | type, header); | ||
873 | break; | ||
874 | } | ||
875 | |||
876 | return handled; | ||
877 | } | ||
878 | |||
879 | static irqreturn_t hsw_irq_thread(int irq, void *context) | ||
880 | { | ||
881 | struct sst_dsp *sst = (struct sst_dsp *) context; | ||
882 | struct sst_hsw *hsw = sst_dsp_get_thread_context(sst); | ||
883 | u32 ipcx, ipcd; | ||
884 | int handled; | ||
885 | unsigned long flags; | ||
886 | |||
887 | spin_lock_irqsave(&sst->spinlock, flags); | ||
888 | |||
889 | ipcx = sst_dsp_ipc_msg_rx(hsw->dsp); | ||
890 | ipcd = sst_dsp_shim_read_unlocked(sst, SST_IPCD); | ||
891 | |||
892 | /* reply message from DSP */ | ||
893 | if (ipcx & SST_IPCX_DONE) { | ||
894 | |||
895 | /* Handle Immediate reply from DSP Core */ | ||
896 | handled = hsw_process_reply(hsw, ipcx); | ||
897 | |||
898 | if (handled > 0) { | ||
899 | /* clear DONE bit - tell DSP we have completed */ | ||
900 | sst_dsp_shim_update_bits_unlocked(sst, SST_IPCX, | ||
901 | SST_IPCX_DONE, 0); | ||
902 | |||
903 | /* unmask Done interrupt */ | ||
904 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
905 | SST_IMRX_DONE, 0); | ||
906 | } | ||
907 | } | ||
908 | |||
909 | /* new message from DSP */ | ||
910 | if (ipcd & SST_IPCD_BUSY) { | ||
911 | |||
912 | /* Handle Notification and Delayed reply from DSP Core */ | ||
913 | handled = hsw_process_notification(hsw); | ||
914 | |||
915 | /* clear BUSY bit and set DONE bit - accept new messages */ | ||
916 | if (handled > 0) { | ||
917 | sst_dsp_shim_update_bits_unlocked(sst, SST_IPCD, | ||
918 | SST_IPCD_BUSY | SST_IPCD_DONE, SST_IPCD_DONE); | ||
919 | |||
920 | /* unmask busy interrupt */ | ||
921 | sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, | ||
922 | SST_IMRX_BUSY, 0); | ||
923 | } | ||
924 | } | ||
925 | |||
926 | spin_unlock_irqrestore(&sst->spinlock, flags); | ||
927 | |||
928 | /* continue to send any remaining messages... */ | ||
929 | queue_kthread_work(&hsw->kworker, &hsw->kwork); | ||
930 | |||
931 | return IRQ_HANDLED; | ||
932 | } | ||
933 | |||
934 | int sst_hsw_fw_get_version(struct sst_hsw *hsw, | ||
935 | struct sst_hsw_ipc_fw_version *version) | ||
936 | { | ||
937 | int ret; | ||
938 | |||
939 | ret = ipc_tx_message_wait(hsw, IPC_GLB_TYPE(IPC_GLB_GET_FW_VERSION), | ||
940 | NULL, 0, version, sizeof(*version)); | ||
941 | if (ret < 0) | ||
942 | dev_err(hsw->dev, "error: get version failed\n"); | ||
943 | |||
944 | return ret; | ||
945 | } | ||
946 | |||
947 | /* Mixer Controls */ | ||
948 | int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
949 | u32 stage_id, u32 channel) | ||
950 | { | ||
951 | int ret; | ||
952 | |||
953 | ret = sst_hsw_stream_get_volume(hsw, stream, stage_id, channel, | ||
954 | &stream->mute_volume[channel]); | ||
955 | if (ret < 0) | ||
956 | return ret; | ||
957 | |||
958 | ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, 0); | ||
959 | if (ret < 0) { | ||
960 | dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", | ||
961 | stream->reply.stream_hw_id, channel); | ||
962 | return ret; | ||
963 | } | ||
964 | |||
965 | stream->mute[channel] = 1; | ||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
970 | u32 stage_id, u32 channel) | ||
971 | |||
972 | { | ||
973 | int ret; | ||
974 | |||
975 | stream->mute[channel] = 0; | ||
976 | ret = sst_hsw_stream_set_volume(hsw, stream, stage_id, channel, | ||
977 | stream->mute_volume[channel]); | ||
978 | if (ret < 0) { | ||
979 | dev_err(hsw->dev, "error: can't unmute stream %d channel %d\n", | ||
980 | stream->reply.stream_hw_id, channel); | ||
981 | return ret; | ||
982 | } | ||
983 | |||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
988 | u32 stage_id, u32 channel, u32 *volume) | ||
989 | { | ||
990 | if (channel > 1) | ||
991 | return -EINVAL; | ||
992 | |||
993 | sst_dsp_read(hsw->dsp, volume, | ||
994 | stream->reply.volume_register_address[channel], sizeof(volume)); | ||
995 | |||
996 | return 0; | ||
997 | } | ||
998 | |||
999 | int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, | ||
1000 | struct sst_hsw_stream *stream, u64 curve_duration, | ||
1001 | enum sst_hsw_volume_curve curve) | ||
1002 | { | ||
1003 | /* curve duration in steps of 100ns */ | ||
1004 | stream->vol_req.curve_duration = curve_duration; | ||
1005 | stream->vol_req.curve_type = curve; | ||
1006 | |||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | /* stream volume */ | ||
1011 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | ||
1012 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume) | ||
1013 | { | ||
1014 | struct sst_hsw_ipc_volume_req *req; | ||
1015 | u32 header; | ||
1016 | int ret; | ||
1017 | |||
1018 | trace_ipc_request("set stream volume", stream->reply.stream_hw_id); | ||
1019 | |||
1020 | if (channel > 1) | ||
1021 | return -EINVAL; | ||
1022 | |||
1023 | if (stream->mute[channel]) { | ||
1024 | stream->mute_volume[channel] = volume; | ||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
1029 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
1030 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | ||
1031 | header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); | ||
1032 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
1033 | |||
1034 | req = &stream->vol_req; | ||
1035 | req->channel = channel; | ||
1036 | req->target_volume = volume; | ||
1037 | |||
1038 | ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0); | ||
1039 | if (ret < 0) { | ||
1040 | dev_err(hsw->dev, "error: set stream volume failed\n"); | ||
1041 | return ret; | ||
1042 | } | ||
1043 | |||
1044 | return 0; | ||
1045 | } | ||
1046 | |||
1047 | int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel) | ||
1048 | { | ||
1049 | int ret; | ||
1050 | |||
1051 | ret = sst_hsw_mixer_get_volume(hsw, stage_id, channel, | ||
1052 | &hsw->mute_volume[channel]); | ||
1053 | if (ret < 0) | ||
1054 | return ret; | ||
1055 | |||
1056 | ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, 0); | ||
1057 | if (ret < 0) { | ||
1058 | dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", | ||
1059 | channel); | ||
1060 | return ret; | ||
1061 | } | ||
1062 | |||
1063 | hsw->mute[channel] = 1; | ||
1064 | return 0; | ||
1065 | } | ||
1066 | |||
1067 | int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel) | ||
1068 | { | ||
1069 | int ret; | ||
1070 | |||
1071 | ret = sst_hsw_mixer_set_volume(hsw, stage_id, channel, | ||
1072 | hsw->mixer_info.volume_register_address[channel]); | ||
1073 | if (ret < 0) { | ||
1074 | dev_err(hsw->dev, "error: failed to unmute mixer channel %d\n", | ||
1075 | channel); | ||
1076 | return ret; | ||
1077 | } | ||
1078 | |||
1079 | hsw->mute[channel] = 0; | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
1084 | u32 *volume) | ||
1085 | { | ||
1086 | if (channel > 1) | ||
1087 | return -EINVAL; | ||
1088 | |||
1089 | sst_dsp_read(hsw->dsp, volume, | ||
1090 | hsw->mixer_info.volume_register_address[channel], | ||
1091 | sizeof(*volume)); | ||
1092 | |||
1093 | return 0; | ||
1094 | } | ||
1095 | |||
1096 | int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, | ||
1097 | u64 curve_duration, enum sst_hsw_volume_curve curve) | ||
1098 | { | ||
1099 | /* curve duration in steps of 100ns */ | ||
1100 | hsw->curve_duration = curve_duration; | ||
1101 | hsw->curve_type = curve; | ||
1102 | |||
1103 | return 0; | ||
1104 | } | ||
1105 | |||
1106 | /* global mixer volume */ | ||
1107 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
1108 | u32 volume) | ||
1109 | { | ||
1110 | struct sst_hsw_ipc_volume_req req; | ||
1111 | u32 header; | ||
1112 | int ret; | ||
1113 | |||
1114 | trace_ipc_request("set mixer volume", volume); | ||
1115 | |||
1116 | /* set both at same time ? */ | ||
1117 | if (channel == 2) { | ||
1118 | if (hsw->mute[0] && hsw->mute[1]) { | ||
1119 | hsw->mute_volume[0] = hsw->mute_volume[1] = volume; | ||
1120 | return 0; | ||
1121 | } else if (hsw->mute[0]) | ||
1122 | req.channel = 1; | ||
1123 | else if (hsw->mute[1]) | ||
1124 | req.channel = 0; | ||
1125 | else | ||
1126 | req.channel = 0xffffffff; | ||
1127 | } else { | ||
1128 | /* set only 1 channel */ | ||
1129 | if (hsw->mute[channel]) { | ||
1130 | hsw->mute_volume[channel] = volume; | ||
1131 | return 0; | ||
1132 | } | ||
1133 | req.channel = channel; | ||
1134 | } | ||
1135 | |||
1136 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
1137 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
1138 | header |= (hsw->mixer_info.mixer_hw_id << IPC_STR_ID_SHIFT); | ||
1139 | header |= (IPC_STG_SET_VOLUME << IPC_STG_TYPE_SHIFT); | ||
1140 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
1141 | |||
1142 | req.curve_duration = hsw->curve_duration; | ||
1143 | req.curve_type = hsw->curve_type; | ||
1144 | req.target_volume = volume; | ||
1145 | |||
1146 | ret = ipc_tx_message_wait(hsw, header, &req, sizeof(req), NULL, 0); | ||
1147 | if (ret < 0) { | ||
1148 | dev_err(hsw->dev, "error: set mixer volume failed\n"); | ||
1149 | return ret; | ||
1150 | } | ||
1151 | |||
1152 | return 0; | ||
1153 | } | ||
1154 | |||
1155 | /* Stream API */ | ||
1156 | struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | ||
1157 | u32 (*notify_position)(struct sst_hsw_stream *stream, void *data), | ||
1158 | void *data) | ||
1159 | { | ||
1160 | struct sst_hsw_stream *stream; | ||
1161 | |||
1162 | stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
1163 | if (stream == NULL) | ||
1164 | return NULL; | ||
1165 | |||
1166 | list_add(&stream->node, &hsw->stream_list); | ||
1167 | stream->notify_position = notify_position; | ||
1168 | stream->pdata = data; | ||
1169 | stream->hsw = hsw; | ||
1170 | stream->host_id = id; | ||
1171 | |||
1172 | /* work to process notification messages */ | ||
1173 | INIT_WORK(&stream->notify_work, hsw_notification_work); | ||
1174 | |||
1175 | return stream; | ||
1176 | } | ||
1177 | |||
1178 | int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | ||
1179 | { | ||
1180 | u32 header; | ||
1181 | int ret = 0; | ||
1182 | |||
1183 | /* dont free DSP streams that are not commited */ | ||
1184 | if (!stream->commited) | ||
1185 | goto out; | ||
1186 | |||
1187 | trace_ipc_request("stream free", stream->host_id); | ||
1188 | |||
1189 | stream->free_req.stream_id = stream->reply.stream_hw_id; | ||
1190 | header = IPC_GLB_TYPE(IPC_GLB_FREE_STREAM); | ||
1191 | |||
1192 | ret = ipc_tx_message_wait(hsw, header, &stream->free_req, | ||
1193 | sizeof(stream->free_req), NULL, 0); | ||
1194 | if (ret < 0) { | ||
1195 | dev_err(hsw->dev, "error: free stream %d failed\n", | ||
1196 | stream->free_req.stream_id); | ||
1197 | return -EAGAIN; | ||
1198 | } | ||
1199 | |||
1200 | trace_hsw_stream_free_req(stream, &stream->free_req); | ||
1201 | |||
1202 | out: | ||
1203 | list_del(&stream->node); | ||
1204 | kfree(stream); | ||
1205 | |||
1206 | return ret; | ||
1207 | } | ||
1208 | |||
1209 | int sst_hsw_stream_set_bits(struct sst_hsw *hsw, | ||
1210 | struct sst_hsw_stream *stream, enum sst_hsw_bitdepth bits) | ||
1211 | { | ||
1212 | if (stream->commited) { | ||
1213 | dev_err(hsw->dev, "error: stream committed for set bits\n"); | ||
1214 | return -EINVAL; | ||
1215 | } | ||
1216 | |||
1217 | stream->request.format.bitdepth = bits; | ||
1218 | return 0; | ||
1219 | } | ||
1220 | |||
1221 | int sst_hsw_stream_set_channels(struct sst_hsw *hsw, | ||
1222 | struct sst_hsw_stream *stream, int channels) | ||
1223 | { | ||
1224 | if (stream->commited) { | ||
1225 | dev_err(hsw->dev, "error: stream committed for set channels\n"); | ||
1226 | return -EINVAL; | ||
1227 | } | ||
1228 | |||
1229 | /* stereo is only supported atm */ | ||
1230 | if (channels != 2) | ||
1231 | return -EINVAL; | ||
1232 | |||
1233 | stream->request.format.ch_num = channels; | ||
1234 | return 0; | ||
1235 | } | ||
1236 | |||
1237 | int sst_hsw_stream_set_rate(struct sst_hsw *hsw, | ||
1238 | struct sst_hsw_stream *stream, int rate) | ||
1239 | { | ||
1240 | if (stream->commited) { | ||
1241 | dev_err(hsw->dev, "error: stream committed for set rate\n"); | ||
1242 | return -EINVAL; | ||
1243 | } | ||
1244 | |||
1245 | stream->request.format.frequency = rate; | ||
1246 | return 0; | ||
1247 | } | ||
1248 | |||
1249 | int sst_hsw_stream_set_map_config(struct sst_hsw *hsw, | ||
1250 | struct sst_hsw_stream *stream, u32 map, | ||
1251 | enum sst_hsw_channel_config config) | ||
1252 | { | ||
1253 | if (stream->commited) { | ||
1254 | dev_err(hsw->dev, "error: stream committed for set map\n"); | ||
1255 | return -EINVAL; | ||
1256 | } | ||
1257 | |||
1258 | stream->request.format.map = map; | ||
1259 | stream->request.format.config = config; | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, | ||
1264 | struct sst_hsw_stream *stream, enum sst_hsw_interleaving style) | ||
1265 | { | ||
1266 | if (stream->commited) { | ||
1267 | dev_err(hsw->dev, "error: stream committed for set style\n"); | ||
1268 | return -EINVAL; | ||
1269 | } | ||
1270 | |||
1271 | stream->request.format.style = style; | ||
1272 | return 0; | ||
1273 | } | ||
1274 | |||
1275 | int sst_hsw_stream_set_valid(struct sst_hsw *hsw, | ||
1276 | struct sst_hsw_stream *stream, u32 bits) | ||
1277 | { | ||
1278 | if (stream->commited) { | ||
1279 | dev_err(hsw->dev, "error: stream committed for set valid bits\n"); | ||
1280 | return -EINVAL; | ||
1281 | } | ||
1282 | |||
1283 | stream->request.format.valid_bit = bits; | ||
1284 | return 0; | ||
1285 | } | ||
1286 | |||
1287 | /* Stream Configuration */ | ||
1288 | int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
1289 | enum sst_hsw_stream_path_id path_id, | ||
1290 | enum sst_hsw_stream_type stream_type, | ||
1291 | enum sst_hsw_stream_format format_id) | ||
1292 | { | ||
1293 | if (stream->commited) { | ||
1294 | dev_err(hsw->dev, "error: stream committed for set format\n"); | ||
1295 | return -EINVAL; | ||
1296 | } | ||
1297 | |||
1298 | stream->request.path_id = path_id; | ||
1299 | stream->request.stream_type = stream_type; | ||
1300 | stream->request.format_id = format_id; | ||
1301 | |||
1302 | trace_hsw_stream_alloc_request(stream, &stream->request); | ||
1303 | |||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
1308 | u32 ring_pt_address, u32 num_pages, | ||
1309 | u32 ring_size, u32 ring_offset, u32 ring_first_pfn) | ||
1310 | { | ||
1311 | if (stream->commited) { | ||
1312 | dev_err(hsw->dev, "error: stream committed for buffer\n"); | ||
1313 | return -EINVAL; | ||
1314 | } | ||
1315 | |||
1316 | stream->request.ringinfo.ring_pt_address = ring_pt_address; | ||
1317 | stream->request.ringinfo.num_pages = num_pages; | ||
1318 | stream->request.ringinfo.ring_size = ring_size; | ||
1319 | stream->request.ringinfo.ring_offset = ring_offset; | ||
1320 | stream->request.ringinfo.ring_first_pfn = ring_first_pfn; | ||
1321 | |||
1322 | trace_hsw_stream_buffer(stream); | ||
1323 | |||
1324 | return 0; | ||
1325 | } | ||
1326 | |||
1327 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | ||
1328 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | ||
1329 | u32 entry_point) | ||
1330 | { | ||
1331 | struct sst_hsw_module_map *map = &stream->request.map; | ||
1332 | |||
1333 | if (stream->commited) { | ||
1334 | dev_err(hsw->dev, "error: stream committed for set module\n"); | ||
1335 | return -EINVAL; | ||
1336 | } | ||
1337 | |||
1338 | /* only support initial module atm */ | ||
1339 | map->module_entries_count = 1; | ||
1340 | map->module_entries[0].module_id = module_id; | ||
1341 | map->module_entries[0].entry_point = entry_point; | ||
1342 | |||
1343 | return 0; | ||
1344 | } | ||
1345 | |||
1346 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | ||
1347 | struct sst_hsw_stream *stream, u32 offset, u32 size) | ||
1348 | { | ||
1349 | if (stream->commited) { | ||
1350 | dev_err(hsw->dev, "error: stream committed for set pmem\n"); | ||
1351 | return -EINVAL; | ||
1352 | } | ||
1353 | |||
1354 | stream->request.persistent_mem.offset = offset; | ||
1355 | stream->request.persistent_mem.size = size; | ||
1356 | |||
1357 | return 0; | ||
1358 | } | ||
1359 | |||
1360 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | ||
1361 | struct sst_hsw_stream *stream, u32 offset, u32 size) | ||
1362 | { | ||
1363 | if (stream->commited) { | ||
1364 | dev_err(hsw->dev, "error: stream committed for set smem\n"); | ||
1365 | return -EINVAL; | ||
1366 | } | ||
1367 | |||
1368 | stream->request.scratch_mem.offset = offset; | ||
1369 | stream->request.scratch_mem.size = size; | ||
1370 | |||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | ||
1375 | { | ||
1376 | struct sst_hsw_ipc_stream_alloc_req *str_req = &stream->request; | ||
1377 | struct sst_hsw_ipc_stream_alloc_reply *reply = &stream->reply; | ||
1378 | u32 header; | ||
1379 | int ret; | ||
1380 | |||
1381 | trace_ipc_request("stream alloc", stream->host_id); | ||
1382 | |||
1383 | header = IPC_GLB_TYPE(IPC_GLB_ALLOCATE_STREAM); | ||
1384 | |||
1385 | ret = ipc_tx_message_wait(hsw, header, str_req, sizeof(*str_req), | ||
1386 | reply, sizeof(*reply)); | ||
1387 | if (ret < 0) { | ||
1388 | dev_err(hsw->dev, "error: stream commit failed\n"); | ||
1389 | return ret; | ||
1390 | } | ||
1391 | |||
1392 | stream->commited = 1; | ||
1393 | trace_hsw_stream_alloc_reply(stream); | ||
1394 | |||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | /* Stream Information - these calls could be inline but we want the IPC | ||
1399 | ABI to be opaque to client PCM drivers to cope with any future ABI changes */ | ||
1400 | int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, | ||
1401 | struct sst_hsw_stream *stream) | ||
1402 | { | ||
1403 | return stream->reply.stream_hw_id; | ||
1404 | } | ||
1405 | |||
1406 | int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, | ||
1407 | struct sst_hsw_stream *stream) | ||
1408 | { | ||
1409 | return stream->reply.mixer_hw_id; | ||
1410 | } | ||
1411 | |||
1412 | u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, | ||
1413 | struct sst_hsw_stream *stream) | ||
1414 | { | ||
1415 | return stream->reply.read_position_register_address; | ||
1416 | } | ||
1417 | |||
1418 | u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, | ||
1419 | struct sst_hsw_stream *stream) | ||
1420 | { | ||
1421 | return stream->reply.presentation_position_register_address; | ||
1422 | } | ||
1423 | |||
1424 | u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, | ||
1425 | struct sst_hsw_stream *stream, u32 channel) | ||
1426 | { | ||
1427 | if (channel >= 2) | ||
1428 | return 0; | ||
1429 | |||
1430 | return stream->reply.peak_meter_register_address[channel]; | ||
1431 | } | ||
1432 | |||
1433 | u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, | ||
1434 | struct sst_hsw_stream *stream, u32 channel) | ||
1435 | { | ||
1436 | if (channel >= 2) | ||
1437 | return 0; | ||
1438 | |||
1439 | return stream->reply.volume_register_address[channel]; | ||
1440 | } | ||
1441 | |||
1442 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw) | ||
1443 | { | ||
1444 | struct sst_hsw_ipc_stream_info_reply *reply; | ||
1445 | u32 header; | ||
1446 | int ret; | ||
1447 | |||
1448 | reply = &hsw->mixer_info; | ||
1449 | header = IPC_GLB_TYPE(IPC_GLB_GET_MIXER_STREAM_INFO); | ||
1450 | |||
1451 | trace_ipc_request("get global mixer info", 0); | ||
1452 | |||
1453 | ret = ipc_tx_message_wait(hsw, header, NULL, 0, reply, sizeof(*reply)); | ||
1454 | if (ret < 0) { | ||
1455 | dev_err(hsw->dev, "error: get stream info failed\n"); | ||
1456 | return ret; | ||
1457 | } | ||
1458 | |||
1459 | trace_hsw_mixer_info_reply(reply); | ||
1460 | |||
1461 | return 0; | ||
1462 | } | ||
1463 | |||
1464 | /* Send stream command */ | ||
1465 | static int sst_hsw_stream_operations(struct sst_hsw *hsw, int type, | ||
1466 | int stream_id, int wait) | ||
1467 | { | ||
1468 | u32 header; | ||
1469 | |||
1470 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | IPC_STR_TYPE(type); | ||
1471 | header |= (stream_id << IPC_STR_ID_SHIFT); | ||
1472 | |||
1473 | if (wait) | ||
1474 | return ipc_tx_message_wait(hsw, header, NULL, 0, NULL, 0); | ||
1475 | else | ||
1476 | return ipc_tx_message_nowait(hsw, header, NULL, 0); | ||
1477 | } | ||
1478 | |||
1479 | /* Stream ALSA trigger operations */ | ||
1480 | int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
1481 | int wait) | ||
1482 | { | ||
1483 | int ret; | ||
1484 | |||
1485 | trace_ipc_request("stream pause", stream->reply.stream_hw_id); | ||
1486 | |||
1487 | ret = sst_hsw_stream_operations(hsw, IPC_STR_PAUSE, | ||
1488 | stream->reply.stream_hw_id, wait); | ||
1489 | if (ret < 0) | ||
1490 | dev_err(hsw->dev, "error: failed to pause stream %d\n", | ||
1491 | stream->reply.stream_hw_id); | ||
1492 | |||
1493 | return ret; | ||
1494 | } | ||
1495 | |||
1496 | int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
1497 | int wait) | ||
1498 | { | ||
1499 | int ret; | ||
1500 | |||
1501 | trace_ipc_request("stream resume", stream->reply.stream_hw_id); | ||
1502 | |||
1503 | ret = sst_hsw_stream_operations(hsw, IPC_STR_RESUME, | ||
1504 | stream->reply.stream_hw_id, wait); | ||
1505 | if (ret < 0) | ||
1506 | dev_err(hsw->dev, "error: failed to resume stream %d\n", | ||
1507 | stream->reply.stream_hw_id); | ||
1508 | |||
1509 | return ret; | ||
1510 | } | ||
1511 | |||
1512 | int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream) | ||
1513 | { | ||
1514 | int ret, tries = 10; | ||
1515 | |||
1516 | /* dont reset streams that are not commited */ | ||
1517 | if (!stream->commited) | ||
1518 | return 0; | ||
1519 | |||
1520 | /* wait for pause to complete before we reset the stream */ | ||
1521 | while (stream->running && tries--) | ||
1522 | msleep(1); | ||
1523 | if (!tries) { | ||
1524 | dev_err(hsw->dev, "error: reset stream %d still running\n", | ||
1525 | stream->reply.stream_hw_id); | ||
1526 | return -EINVAL; | ||
1527 | } | ||
1528 | |||
1529 | trace_ipc_request("stream reset", stream->reply.stream_hw_id); | ||
1530 | |||
1531 | ret = sst_hsw_stream_operations(hsw, IPC_STR_RESET, | ||
1532 | stream->reply.stream_hw_id, 1); | ||
1533 | if (ret < 0) | ||
1534 | dev_err(hsw->dev, "error: failed to reset stream %d\n", | ||
1535 | stream->reply.stream_hw_id); | ||
1536 | return ret; | ||
1537 | } | ||
1538 | |||
1539 | /* Stream pointer positions */ | ||
1540 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | ||
1541 | struct sst_hsw_stream *stream) | ||
1542 | { | ||
1543 | return stream->rpos.position; | ||
1544 | } | ||
1545 | |||
1546 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | ||
1547 | struct sst_hsw_stream *stream, u32 stage_id, u32 position) | ||
1548 | { | ||
1549 | u32 header; | ||
1550 | int ret; | ||
1551 | |||
1552 | trace_stream_write_position(stream->reply.stream_hw_id, position); | ||
1553 | |||
1554 | header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) | | ||
1555 | IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE); | ||
1556 | header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT); | ||
1557 | header |= (IPC_STG_SET_WRITE_POSITION << IPC_STG_TYPE_SHIFT); | ||
1558 | header |= (stage_id << IPC_STG_ID_SHIFT); | ||
1559 | stream->wpos.position = position; | ||
1560 | |||
1561 | ret = ipc_tx_message_nowait(hsw, header, &stream->wpos, | ||
1562 | sizeof(stream->wpos)); | ||
1563 | if (ret < 0) | ||
1564 | dev_err(hsw->dev, "error: stream %d set position %d failed\n", | ||
1565 | stream->reply.stream_hw_id, position); | ||
1566 | |||
1567 | return ret; | ||
1568 | } | ||
1569 | |||
1570 | /* physical BE config */ | ||
1571 | int sst_hsw_device_set_config(struct sst_hsw *hsw, | ||
1572 | enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, | ||
1573 | enum sst_hsw_device_mode mode, u32 clock_divider) | ||
1574 | { | ||
1575 | struct sst_hsw_ipc_device_config_req config; | ||
1576 | u32 header; | ||
1577 | int ret; | ||
1578 | |||
1579 | trace_ipc_request("set device config", dev); | ||
1580 | |||
1581 | config.ssp_interface = dev; | ||
1582 | config.clock_frequency = mclk; | ||
1583 | config.mode = mode; | ||
1584 | config.clock_divider = clock_divider; | ||
1585 | |||
1586 | trace_hsw_device_config_req(&config); | ||
1587 | |||
1588 | header = IPC_GLB_TYPE(IPC_GLB_SET_DEVICE_FORMATS); | ||
1589 | |||
1590 | ret = ipc_tx_message_wait(hsw, header, &config, sizeof(config), | ||
1591 | NULL, 0); | ||
1592 | if (ret < 0) | ||
1593 | dev_err(hsw->dev, "error: set device formats failed\n"); | ||
1594 | |||
1595 | return ret; | ||
1596 | } | ||
1597 | EXPORT_SYMBOL_GPL(sst_hsw_device_set_config); | ||
1598 | |||
1599 | /* DX Config */ | ||
1600 | int sst_hsw_dx_set_state(struct sst_hsw *hsw, | ||
1601 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx) | ||
1602 | { | ||
1603 | u32 header, state_; | ||
1604 | int ret; | ||
1605 | |||
1606 | header = IPC_GLB_TYPE(IPC_GLB_ENTER_DX_STATE); | ||
1607 | state_ = state; | ||
1608 | |||
1609 | trace_ipc_request("PM enter Dx state", state); | ||
1610 | |||
1611 | ret = ipc_tx_message_wait(hsw, header, &state_, sizeof(state_), | ||
1612 | dx, sizeof(dx)); | ||
1613 | if (ret < 0) { | ||
1614 | dev_err(hsw->dev, "ipc: error set dx state %d failed\n", state); | ||
1615 | return ret; | ||
1616 | } | ||
1617 | |||
1618 | dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n", | ||
1619 | dx->entries_no, state); | ||
1620 | |||
1621 | memcpy(&hsw->dx, dx, sizeof(*dx)); | ||
1622 | return 0; | ||
1623 | } | ||
1624 | |||
1625 | /* Used to save state into hsw->dx_reply */ | ||
1626 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | ||
1627 | u32 *offset, u32 *size, u32 *source) | ||
1628 | { | ||
1629 | struct sst_hsw_ipc_dx_memory_item *dx_mem; | ||
1630 | struct sst_hsw_ipc_dx_reply *dx_reply; | ||
1631 | int entry_no; | ||
1632 | |||
1633 | dx_reply = &hsw->dx; | ||
1634 | entry_no = dx_reply->entries_no; | ||
1635 | |||
1636 | trace_ipc_request("PM get Dx state", entry_no); | ||
1637 | |||
1638 | if (item >= entry_no) | ||
1639 | return -EINVAL; | ||
1640 | |||
1641 | dx_mem = &dx_reply->mem_info[item]; | ||
1642 | *offset = dx_mem->offset; | ||
1643 | *size = dx_mem->size; | ||
1644 | *source = dx_mem->source; | ||
1645 | |||
1646 | return 0; | ||
1647 | } | ||
1648 | |||
1649 | static int msg_empty_list_init(struct sst_hsw *hsw) | ||
1650 | { | ||
1651 | int i; | ||
1652 | |||
1653 | hsw->msg = kzalloc(sizeof(struct ipc_message) * | ||
1654 | IPC_EMPTY_LIST_SIZE, GFP_KERNEL); | ||
1655 | if (hsw->msg == NULL) | ||
1656 | return -ENOMEM; | ||
1657 | |||
1658 | for (i = 0; i < IPC_EMPTY_LIST_SIZE; i++) { | ||
1659 | init_waitqueue_head(&hsw->msg[i].waitq); | ||
1660 | list_add(&hsw->msg[i].list, &hsw->empty_list); | ||
1661 | } | ||
1662 | |||
1663 | return 0; | ||
1664 | } | ||
1665 | |||
1666 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | ||
1667 | struct sst_module *scratch) | ||
1668 | { | ||
1669 | hsw->scratch = scratch; | ||
1670 | } | ||
1671 | |||
1672 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw) | ||
1673 | { | ||
1674 | return hsw->dsp; | ||
1675 | } | ||
1676 | |||
1677 | static struct sst_dsp_device hsw_dev = { | ||
1678 | .thread = hsw_irq_thread, | ||
1679 | .ops = &haswell_ops, | ||
1680 | }; | ||
1681 | |||
1682 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata) | ||
1683 | { | ||
1684 | struct sst_hsw_ipc_fw_version version; | ||
1685 | struct sst_hsw *hsw; | ||
1686 | struct sst_fw *hsw_sst_fw; | ||
1687 | int ret; | ||
1688 | |||
1689 | dev_dbg(dev, "initialising Audio DSP IPC\n"); | ||
1690 | |||
1691 | hsw = devm_kzalloc(dev, sizeof(*hsw), GFP_KERNEL); | ||
1692 | if (hsw == NULL) | ||
1693 | return -ENOMEM; | ||
1694 | |||
1695 | hsw->dev = dev; | ||
1696 | INIT_LIST_HEAD(&hsw->stream_list); | ||
1697 | INIT_LIST_HEAD(&hsw->tx_list); | ||
1698 | INIT_LIST_HEAD(&hsw->rx_list); | ||
1699 | INIT_LIST_HEAD(&hsw->empty_list); | ||
1700 | init_waitqueue_head(&hsw->boot_wait); | ||
1701 | init_waitqueue_head(&hsw->wait_txq); | ||
1702 | |||
1703 | ret = msg_empty_list_init(hsw); | ||
1704 | if (ret < 0) | ||
1705 | goto list_err; | ||
1706 | |||
1707 | /* start the IPC message thread */ | ||
1708 | init_kthread_worker(&hsw->kworker); | ||
1709 | hsw->tx_thread = kthread_run(kthread_worker_fn, | ||
1710 | &hsw->kworker, | ||
1711 | dev_name(hsw->dev)); | ||
1712 | if (IS_ERR(hsw->tx_thread)) { | ||
1713 | ret = PTR_ERR(hsw->tx_thread); | ||
1714 | dev_err(hsw->dev, "error: failed to create message TX task\n"); | ||
1715 | goto list_err; | ||
1716 | } | ||
1717 | init_kthread_work(&hsw->kwork, ipc_tx_msgs); | ||
1718 | |||
1719 | hsw_dev.thread_context = hsw; | ||
1720 | |||
1721 | /* init SST shim */ | ||
1722 | hsw->dsp = sst_dsp_new(dev, &hsw_dev, pdata); | ||
1723 | if (hsw->dsp == NULL) { | ||
1724 | ret = -ENODEV; | ||
1725 | goto list_err; | ||
1726 | } | ||
1727 | |||
1728 | /* keep the DSP in reset state for base FW loading */ | ||
1729 | sst_dsp_reset(hsw->dsp); | ||
1730 | |||
1731 | hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw); | ||
1732 | |||
1733 | if (hsw_sst_fw == NULL) { | ||
1734 | ret = -ENODEV; | ||
1735 | dev_err(dev, "error: failed to load firmware\n"); | ||
1736 | goto fw_err; | ||
1737 | } | ||
1738 | |||
1739 | /* wait for DSP boot completion */ | ||
1740 | sst_dsp_boot(hsw->dsp); | ||
1741 | ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete, | ||
1742 | msecs_to_jiffies(IPC_BOOT_MSECS)); | ||
1743 | if (ret == 0) { | ||
1744 | ret = -EIO; | ||
1745 | dev_err(hsw->dev, "error: ADSP boot timeout\n"); | ||
1746 | goto boot_err; | ||
1747 | } | ||
1748 | |||
1749 | /* get the FW version */ | ||
1750 | sst_hsw_fw_get_version(hsw, &version); | ||
1751 | dev_info(hsw->dev, "FW loaded: type %d - version: %d.%d build %d\n", | ||
1752 | version.type, version.major, version.minor, version.build); | ||
1753 | |||
1754 | /* get the globalmixer */ | ||
1755 | ret = sst_hsw_mixer_get_info(hsw); | ||
1756 | if (ret < 0) { | ||
1757 | dev_err(hsw->dev, "error: failed to get stream info\n"); | ||
1758 | goto boot_err; | ||
1759 | } | ||
1760 | |||
1761 | pdata->dsp = hsw; | ||
1762 | return 0; | ||
1763 | |||
1764 | boot_err: | ||
1765 | sst_dsp_reset(hsw->dsp); | ||
1766 | sst_fw_free(hsw_sst_fw); | ||
1767 | fw_err: | ||
1768 | sst_dsp_free(hsw->dsp); | ||
1769 | kfree(hsw->msg); | ||
1770 | list_err: | ||
1771 | return ret; | ||
1772 | } | ||
1773 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_init); | ||
1774 | |||
1775 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata) | ||
1776 | { | ||
1777 | struct sst_hsw *hsw = pdata->dsp; | ||
1778 | |||
1779 | sst_dsp_reset(hsw->dsp); | ||
1780 | sst_fw_free_all(hsw->dsp); | ||
1781 | sst_dsp_free(hsw->dsp); | ||
1782 | kfree(hsw->scratch); | ||
1783 | kfree(hsw->msg); | ||
1784 | } | ||
1785 | EXPORT_SYMBOL_GPL(sst_hsw_dsp_free); | ||
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h new file mode 100644 index 000000000000..d517929ccc38 --- /dev/null +++ b/sound/soc/intel/sst-haswell-ipc.h | |||
@@ -0,0 +1,488 @@ | |||
1 | /* | ||
2 | * Intel SST Haswell/Broadwell IPC Support | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef __SST_HASWELL_IPC_H | ||
18 | #define __SST_HASWELL_IPC_H | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | |||
24 | #define SST_HSW_NO_CHANNELS 2 | ||
25 | #define SST_HSW_MAX_DX_REGIONS 14 | ||
26 | |||
27 | #define SST_HSW_FW_LOG_CONFIG_DWORDS 12 | ||
28 | #define SST_HSW_GLOBAL_LOG 15 | ||
29 | |||
30 | /** | ||
31 | * Upfront defined maximum message size that is | ||
32 | * expected by the in/out communication pipes in FW. | ||
33 | */ | ||
34 | #define SST_HSW_IPC_MAX_PAYLOAD_SIZE 400 | ||
35 | #define SST_HSW_MAX_INFO_SIZE 64 | ||
36 | #define SST_HSW_BUILD_HASH_LENGTH 40 | ||
37 | |||
38 | struct sst_hsw; | ||
39 | struct sst_hsw_stream; | ||
40 | struct sst_hsw_log_stream; | ||
41 | struct sst_pdata; | ||
42 | struct sst_module; | ||
43 | extern struct sst_ops haswell_ops; | ||
44 | |||
45 | /* Stream Allocate Path ID */ | ||
46 | enum sst_hsw_stream_path_id { | ||
47 | SST_HSW_STREAM_PATH_SSP0_OUT = 0, | ||
48 | SST_HSW_STREAM_PATH_SSP0_IN = 1, | ||
49 | SST_HSW_STREAM_PATH_MAX_PATH_ID = 2, | ||
50 | }; | ||
51 | |||
52 | /* Stream Allocate Stream Type */ | ||
53 | enum sst_hsw_stream_type { | ||
54 | SST_HSW_STREAM_TYPE_RENDER = 0, | ||
55 | SST_HSW_STREAM_TYPE_SYSTEM = 1, | ||
56 | SST_HSW_STREAM_TYPE_CAPTURE = 2, | ||
57 | SST_HSW_STREAM_TYPE_LOOPBACK = 3, | ||
58 | SST_HSW_STREAM_TYPE_MAX_STREAM_TYPE = 4, | ||
59 | }; | ||
60 | |||
61 | /* Stream Allocate Stream Format */ | ||
62 | enum sst_hsw_stream_format { | ||
63 | SST_HSW_STREAM_FORMAT_PCM_FORMAT = 0, | ||
64 | SST_HSW_STREAM_FORMAT_MP3_FORMAT = 1, | ||
65 | SST_HSW_STREAM_FORMAT_AAC_FORMAT = 2, | ||
66 | SST_HSW_STREAM_FORMAT_MAX_FORMAT_ID = 3, | ||
67 | }; | ||
68 | |||
69 | /* Device ID */ | ||
70 | enum sst_hsw_device_id { | ||
71 | SST_HSW_DEVICE_SSP_0 = 0, | ||
72 | SST_HSW_DEVICE_SSP_1 = 1, | ||
73 | }; | ||
74 | |||
75 | /* Device Master Clock Frequency */ | ||
76 | enum sst_hsw_device_mclk { | ||
77 | SST_HSW_DEVICE_MCLK_OFF = 0, | ||
78 | SST_HSW_DEVICE_MCLK_FREQ_6_MHZ = 1, | ||
79 | SST_HSW_DEVICE_MCLK_FREQ_12_MHZ = 2, | ||
80 | SST_HSW_DEVICE_MCLK_FREQ_24_MHZ = 3, | ||
81 | }; | ||
82 | |||
83 | /* Device Clock Master */ | ||
84 | enum sst_hsw_device_mode { | ||
85 | SST_HSW_DEVICE_CLOCK_SLAVE = 0, | ||
86 | SST_HSW_DEVICE_CLOCK_MASTER = 1, | ||
87 | }; | ||
88 | |||
89 | /* DX Power State */ | ||
90 | enum sst_hsw_dx_state { | ||
91 | SST_HSW_DX_STATE_D0 = 0, | ||
92 | SST_HSW_DX_STATE_D1 = 1, | ||
93 | SST_HSW_DX_STATE_D3 = 3, | ||
94 | SST_HSW_DX_STATE_MAX = 3, | ||
95 | }; | ||
96 | |||
97 | /* Audio stream stage IDs */ | ||
98 | enum sst_hsw_fx_stage_id { | ||
99 | SST_HSW_STAGE_ID_WAVES = 0, | ||
100 | SST_HSW_STAGE_ID_DTS = 1, | ||
101 | SST_HSW_STAGE_ID_DOLBY = 2, | ||
102 | SST_HSW_STAGE_ID_BOOST = 3, | ||
103 | SST_HSW_STAGE_ID_MAX_FX_ID | ||
104 | }; | ||
105 | |||
106 | /* DX State Type */ | ||
107 | enum sst_hsw_dx_type { | ||
108 | SST_HSW_DX_TYPE_FW_IMAGE = 0, | ||
109 | SST_HSW_DX_TYPE_MEMORY_DUMP = 1 | ||
110 | }; | ||
111 | |||
112 | /* Volume Curve Type*/ | ||
113 | enum sst_hsw_volume_curve { | ||
114 | SST_HSW_VOLUME_CURVE_NONE = 0, | ||
115 | SST_HSW_VOLUME_CURVE_FADE = 1 | ||
116 | }; | ||
117 | |||
118 | /* Sample ordering */ | ||
119 | enum sst_hsw_interleaving { | ||
120 | SST_HSW_INTERLEAVING_PER_CHANNEL = 0, | ||
121 | SST_HSW_INTERLEAVING_PER_SAMPLE = 1, | ||
122 | }; | ||
123 | |||
124 | /* Channel indices */ | ||
125 | enum sst_hsw_channel_index { | ||
126 | SST_HSW_CHANNEL_LEFT = 0, | ||
127 | SST_HSW_CHANNEL_CENTER = 1, | ||
128 | SST_HSW_CHANNEL_RIGHT = 2, | ||
129 | SST_HSW_CHANNEL_LEFT_SURROUND = 3, | ||
130 | SST_HSW_CHANNEL_CENTER_SURROUND = 3, | ||
131 | SST_HSW_CHANNEL_RIGHT_SURROUND = 4, | ||
132 | SST_HSW_CHANNEL_LFE = 7, | ||
133 | SST_HSW_CHANNEL_INVALID = 0xF, | ||
134 | }; | ||
135 | |||
136 | /* List of supported channel maps. */ | ||
137 | enum sst_hsw_channel_config { | ||
138 | SST_HSW_CHANNEL_CONFIG_MONO = 0, /* mono only. */ | ||
139 | SST_HSW_CHANNEL_CONFIG_STEREO = 1, /* L & R. */ | ||
140 | SST_HSW_CHANNEL_CONFIG_2_POINT_1 = 2, /* L, R & LFE; PCM only. */ | ||
141 | SST_HSW_CHANNEL_CONFIG_3_POINT_0 = 3, /* L, C & R; MP3 & AAC only. */ | ||
142 | SST_HSW_CHANNEL_CONFIG_3_POINT_1 = 4, /* L, C, R & LFE; PCM only. */ | ||
143 | SST_HSW_CHANNEL_CONFIG_QUATRO = 5, /* L, R, Ls & Rs; PCM only. */ | ||
144 | SST_HSW_CHANNEL_CONFIG_4_POINT_0 = 6, /* L, C, R & Cs; MP3 & AAC only. */ | ||
145 | SST_HSW_CHANNEL_CONFIG_5_POINT_0 = 7, /* L, C, R, Ls & Rs. */ | ||
146 | SST_HSW_CHANNEL_CONFIG_5_POINT_1 = 8, /* L, C, R, Ls, Rs & LFE. */ | ||
147 | SST_HSW_CHANNEL_CONFIG_DUAL_MONO = 9, /* One channel replicated in two. */ | ||
148 | SST_HSW_CHANNEL_CONFIG_INVALID, | ||
149 | }; | ||
150 | |||
151 | /* List of supported bit depths. */ | ||
152 | enum sst_hsw_bitdepth { | ||
153 | SST_HSW_DEPTH_8BIT = 8, | ||
154 | SST_HSW_DEPTH_16BIT = 16, | ||
155 | SST_HSW_DEPTH_24BIT = 24, /* Default. */ | ||
156 | SST_HSW_DEPTH_32BIT = 32, | ||
157 | SST_HSW_DEPTH_INVALID = 33, | ||
158 | }; | ||
159 | |||
160 | enum sst_hsw_module_id { | ||
161 | SST_HSW_MODULE_BASE_FW = 0x0, | ||
162 | SST_HSW_MODULE_MP3 = 0x1, | ||
163 | SST_HSW_MODULE_AAC_5_1 = 0x2, | ||
164 | SST_HSW_MODULE_AAC_2_0 = 0x3, | ||
165 | SST_HSW_MODULE_SRC = 0x4, | ||
166 | SST_HSW_MODULE_WAVES = 0x5, | ||
167 | SST_HSW_MODULE_DOLBY = 0x6, | ||
168 | SST_HSW_MODULE_BOOST = 0x7, | ||
169 | SST_HSW_MODULE_LPAL = 0x8, | ||
170 | SST_HSW_MODULE_DTS = 0x9, | ||
171 | SST_HSW_MODULE_PCM_CAPTURE = 0xA, | ||
172 | SST_HSW_MODULE_PCM_SYSTEM = 0xB, | ||
173 | SST_HSW_MODULE_PCM_REFERENCE = 0xC, | ||
174 | SST_HSW_MODULE_PCM = 0xD, | ||
175 | SST_HSW_MODULE_BLUETOOTH_RENDER_MODULE = 0xE, | ||
176 | SST_HSW_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF, | ||
177 | SST_HSW_MAX_MODULE_ID, | ||
178 | }; | ||
179 | |||
180 | enum sst_hsw_performance_action { | ||
181 | SST_HSW_PERF_START = 0, | ||
182 | SST_HSW_PERF_STOP = 1, | ||
183 | }; | ||
184 | |||
185 | /* SST firmware module info */ | ||
186 | struct sst_hsw_module_info { | ||
187 | u8 name[SST_HSW_MAX_INFO_SIZE]; | ||
188 | u8 version[SST_HSW_MAX_INFO_SIZE]; | ||
189 | } __attribute__((packed)); | ||
190 | |||
191 | /* Module entry point */ | ||
192 | struct sst_hsw_module_entry { | ||
193 | enum sst_hsw_module_id module_id; | ||
194 | u32 entry_point; | ||
195 | } __attribute__((packed)); | ||
196 | |||
197 | /* Module map - alignement matches DSP */ | ||
198 | struct sst_hsw_module_map { | ||
199 | u8 module_entries_count; | ||
200 | struct sst_hsw_module_entry module_entries[1]; | ||
201 | } __attribute__((packed)); | ||
202 | |||
203 | struct sst_hsw_memory_info { | ||
204 | u32 offset; | ||
205 | u32 size; | ||
206 | } __attribute__((packed)); | ||
207 | |||
208 | struct sst_hsw_fx_enable { | ||
209 | struct sst_hsw_module_map module_map; | ||
210 | struct sst_hsw_memory_info persistent_mem; | ||
211 | } __attribute__((packed)); | ||
212 | |||
213 | struct sst_hsw_get_fx_param { | ||
214 | u32 parameter_id; | ||
215 | u32 param_size; | ||
216 | } __attribute__((packed)); | ||
217 | |||
218 | struct sst_hsw_perf_action { | ||
219 | u32 action; | ||
220 | } __attribute__((packed)); | ||
221 | |||
222 | struct sst_hsw_perf_data { | ||
223 | u64 timestamp; | ||
224 | u64 cycles; | ||
225 | u64 datatime; | ||
226 | } __attribute__((packed)); | ||
227 | |||
228 | /* FW version */ | ||
229 | struct sst_hsw_ipc_fw_version { | ||
230 | u8 build; | ||
231 | u8 minor; | ||
232 | u8 major; | ||
233 | u8 type; | ||
234 | u8 fw_build_hash[SST_HSW_BUILD_HASH_LENGTH]; | ||
235 | u32 fw_log_providers_hash; | ||
236 | } __attribute__((packed)); | ||
237 | |||
238 | /* Stream ring info */ | ||
239 | struct sst_hsw_ipc_stream_ring { | ||
240 | u32 ring_pt_address; | ||
241 | u32 num_pages; | ||
242 | u32 ring_size; | ||
243 | u32 ring_offset; | ||
244 | u32 ring_first_pfn; | ||
245 | } __attribute__((packed)); | ||
246 | |||
247 | /* Debug Dump Log Enable Request */ | ||
248 | struct sst_hsw_ipc_debug_log_enable_req { | ||
249 | struct sst_hsw_ipc_stream_ring ringinfo; | ||
250 | u32 config[SST_HSW_FW_LOG_CONFIG_DWORDS]; | ||
251 | } __attribute__((packed)); | ||
252 | |||
253 | /* Debug Dump Log Reply */ | ||
254 | struct sst_hsw_ipc_debug_log_reply { | ||
255 | u32 log_buffer_begining; | ||
256 | u32 log_buffer_size; | ||
257 | } __attribute__((packed)); | ||
258 | |||
259 | /* Stream glitch position */ | ||
260 | struct sst_hsw_ipc_stream_glitch_position { | ||
261 | u32 glitch_type; | ||
262 | u32 present_pos; | ||
263 | u32 write_pos; | ||
264 | } __attribute__((packed)); | ||
265 | |||
266 | /* Stream get position */ | ||
267 | struct sst_hsw_ipc_stream_get_position { | ||
268 | u32 position; | ||
269 | u32 fw_cycle_count; | ||
270 | } __attribute__((packed)); | ||
271 | |||
272 | /* Stream set position */ | ||
273 | struct sst_hsw_ipc_stream_set_position { | ||
274 | u32 position; | ||
275 | u32 end_of_buffer; | ||
276 | } __attribute__((packed)); | ||
277 | |||
278 | /* Stream Free Request */ | ||
279 | struct sst_hsw_ipc_stream_free_req { | ||
280 | u8 stream_id; | ||
281 | u8 reserved[3]; | ||
282 | } __attribute__((packed)); | ||
283 | |||
284 | /* Set Volume Request */ | ||
285 | struct sst_hsw_ipc_volume_req { | ||
286 | u32 channel; | ||
287 | u32 target_volume; | ||
288 | u64 curve_duration; | ||
289 | u32 curve_type; | ||
290 | } __attribute__((packed)); | ||
291 | |||
292 | /* Device Configuration Request */ | ||
293 | struct sst_hsw_ipc_device_config_req { | ||
294 | u32 ssp_interface; | ||
295 | u32 clock_frequency; | ||
296 | u32 mode; | ||
297 | u16 clock_divider; | ||
298 | u16 reserved; | ||
299 | } __attribute__((packed)); | ||
300 | |||
301 | /* Audio Data formats */ | ||
302 | struct sst_hsw_audio_data_format_ipc { | ||
303 | u32 frequency; | ||
304 | u32 bitdepth; | ||
305 | u32 map; | ||
306 | u32 config; | ||
307 | u32 style; | ||
308 | u8 ch_num; | ||
309 | u8 valid_bit; | ||
310 | u8 reserved[2]; | ||
311 | } __attribute__((packed)); | ||
312 | |||
313 | /* Stream Allocate Request */ | ||
314 | struct sst_hsw_ipc_stream_alloc_req { | ||
315 | u8 path_id; | ||
316 | u8 stream_type; | ||
317 | u8 format_id; | ||
318 | u8 reserved; | ||
319 | struct sst_hsw_audio_data_format_ipc format; | ||
320 | struct sst_hsw_ipc_stream_ring ringinfo; | ||
321 | struct sst_hsw_module_map map; | ||
322 | struct sst_hsw_memory_info persistent_mem; | ||
323 | struct sst_hsw_memory_info scratch_mem; | ||
324 | u32 number_of_notifications; | ||
325 | } __attribute__((packed)); | ||
326 | |||
327 | /* Stream Allocate Reply */ | ||
328 | struct sst_hsw_ipc_stream_alloc_reply { | ||
329 | u32 stream_hw_id; | ||
330 | u32 mixer_hw_id; // returns rate ???? | ||
331 | u32 read_position_register_address; | ||
332 | u32 presentation_position_register_address; | ||
333 | u32 peak_meter_register_address[SST_HSW_NO_CHANNELS]; | ||
334 | u32 volume_register_address[SST_HSW_NO_CHANNELS]; | ||
335 | } __attribute__((packed)); | ||
336 | |||
337 | /* Get Mixer Stream Info */ | ||
338 | struct sst_hsw_ipc_stream_info_reply { | ||
339 | u32 mixer_hw_id; | ||
340 | u32 peak_meter_register_address[SST_HSW_NO_CHANNELS]; | ||
341 | u32 volume_register_address[SST_HSW_NO_CHANNELS]; | ||
342 | } __attribute__((packed)); | ||
343 | |||
344 | /* DX State Request */ | ||
345 | struct sst_hsw_ipc_dx_req { | ||
346 | u8 state; | ||
347 | u8 reserved[3]; | ||
348 | } __attribute__((packed)); | ||
349 | |||
350 | /* DX State Reply Memory Info Item */ | ||
351 | struct sst_hsw_ipc_dx_memory_item { | ||
352 | u32 offset; | ||
353 | u32 size; | ||
354 | u32 source; | ||
355 | } __attribute__((packed)); | ||
356 | |||
357 | /* DX State Reply */ | ||
358 | struct sst_hsw_ipc_dx_reply { | ||
359 | u32 entries_no; | ||
360 | struct sst_hsw_ipc_dx_memory_item mem_info[SST_HSW_MAX_DX_REGIONS]; | ||
361 | } __attribute__((packed)); | ||
362 | |||
363 | struct sst_hsw_ipc_fw_version; | ||
364 | |||
365 | /* SST Init & Free */ | ||
366 | struct sst_hsw *sst_hsw_new(struct device *dev, const u8 *fw, size_t fw_length, | ||
367 | u32 fw_offset); | ||
368 | void sst_hsw_free(struct sst_hsw *hsw); | ||
369 | int sst_hsw_fw_get_version(struct sst_hsw *hsw, | ||
370 | struct sst_hsw_ipc_fw_version *version); | ||
371 | u32 create_channel_map(enum sst_hsw_channel_config config); | ||
372 | |||
373 | /* Stream Mixer Controls - */ | ||
374 | int sst_hsw_stream_mute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
375 | u32 stage_id, u32 channel); | ||
376 | int sst_hsw_stream_unmute(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
377 | u32 stage_id, u32 channel); | ||
378 | |||
379 | int sst_hsw_stream_set_volume(struct sst_hsw *hsw, | ||
380 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 volume); | ||
381 | int sst_hsw_stream_get_volume(struct sst_hsw *hsw, | ||
382 | struct sst_hsw_stream *stream, u32 stage_id, u32 channel, u32 *volume); | ||
383 | |||
384 | int sst_hsw_stream_set_volume_curve(struct sst_hsw *hsw, | ||
385 | struct sst_hsw_stream *stream, u64 curve_duration, | ||
386 | enum sst_hsw_volume_curve curve); | ||
387 | |||
388 | /* Global Mixer Controls - */ | ||
389 | int sst_hsw_mixer_mute(struct sst_hsw *hsw, u32 stage_id, u32 channel); | ||
390 | int sst_hsw_mixer_unmute(struct sst_hsw *hsw, u32 stage_id, u32 channel); | ||
391 | |||
392 | int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
393 | u32 volume); | ||
394 | int sst_hsw_mixer_get_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel, | ||
395 | u32 *volume); | ||
396 | |||
397 | int sst_hsw_mixer_set_volume_curve(struct sst_hsw *hsw, | ||
398 | u64 curve_duration, enum sst_hsw_volume_curve curve); | ||
399 | |||
400 | /* Stream API */ | ||
401 | struct sst_hsw_stream *sst_hsw_stream_new(struct sst_hsw *hsw, int id, | ||
402 | u32 (*get_write_position)(struct sst_hsw_stream *stream, void *data), | ||
403 | void *data); | ||
404 | |||
405 | int sst_hsw_stream_free(struct sst_hsw *hsw, struct sst_hsw_stream *stream); | ||
406 | |||
407 | /* Stream Configuration */ | ||
408 | int sst_hsw_stream_format(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
409 | enum sst_hsw_stream_path_id path_id, | ||
410 | enum sst_hsw_stream_type stream_type, | ||
411 | enum sst_hsw_stream_format format_id); | ||
412 | |||
413 | int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
414 | u32 ring_pt_address, u32 num_pages, | ||
415 | u32 ring_size, u32 ring_offset, u32 ring_first_pfn); | ||
416 | |||
417 | int sst_hsw_stream_commit(struct sst_hsw *hsw, struct sst_hsw_stream *stream); | ||
418 | |||
419 | int sst_hsw_stream_set_valid(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
420 | u32 bits); | ||
421 | int sst_hsw_stream_set_rate(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
422 | int rate); | ||
423 | int sst_hsw_stream_set_bits(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
424 | enum sst_hsw_bitdepth bits); | ||
425 | int sst_hsw_stream_set_channels(struct sst_hsw *hsw, | ||
426 | struct sst_hsw_stream *stream, int channels); | ||
427 | int sst_hsw_stream_set_map_config(struct sst_hsw *hsw, | ||
428 | struct sst_hsw_stream *stream, u32 map, | ||
429 | enum sst_hsw_channel_config config); | ||
430 | int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
431 | enum sst_hsw_interleaving style); | ||
432 | int sst_hsw_stream_set_module_info(struct sst_hsw *hsw, | ||
433 | struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id, | ||
434 | u32 entry_point); | ||
435 | int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw, | ||
436 | struct sst_hsw_stream *stream, u32 offset, u32 size); | ||
437 | int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw, | ||
438 | struct sst_hsw_stream *stream, u32 offset, u32 size); | ||
439 | int sst_hsw_stream_get_hw_id(struct sst_hsw *hsw, | ||
440 | struct sst_hsw_stream *stream); | ||
441 | int sst_hsw_stream_get_mixer_id(struct sst_hsw *hsw, | ||
442 | struct sst_hsw_stream *stream); | ||
443 | u32 sst_hsw_stream_get_read_reg(struct sst_hsw *hsw, | ||
444 | struct sst_hsw_stream *stream); | ||
445 | u32 sst_hsw_stream_get_pointer_reg(struct sst_hsw *hsw, | ||
446 | struct sst_hsw_stream *stream); | ||
447 | u32 sst_hsw_stream_get_peak_reg(struct sst_hsw *hsw, | ||
448 | struct sst_hsw_stream *stream, u32 channel); | ||
449 | u32 sst_hsw_stream_get_vol_reg(struct sst_hsw *hsw, | ||
450 | struct sst_hsw_stream *stream, u32 channel); | ||
451 | int sst_hsw_mixer_get_info(struct sst_hsw *hsw); | ||
452 | |||
453 | /* Stream ALSA trigger operations */ | ||
454 | int sst_hsw_stream_pause(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
455 | int wait); | ||
456 | int sst_hsw_stream_resume(struct sst_hsw *hsw, struct sst_hsw_stream *stream, | ||
457 | int wait); | ||
458 | int sst_hsw_stream_reset(struct sst_hsw *hsw, struct sst_hsw_stream *stream); | ||
459 | |||
460 | /* Stream pointer positions */ | ||
461 | int sst_hsw_stream_get_read_pos(struct sst_hsw *hsw, | ||
462 | struct sst_hsw_stream *stream, u32 *position); | ||
463 | int sst_hsw_stream_get_write_pos(struct sst_hsw *hsw, | ||
464 | struct sst_hsw_stream *stream, u32 *position); | ||
465 | int sst_hsw_stream_set_write_position(struct sst_hsw *hsw, | ||
466 | struct sst_hsw_stream *stream, u32 stage_id, u32 position); | ||
467 | int sst_hsw_get_dsp_position(struct sst_hsw *hsw, | ||
468 | struct sst_hsw_stream *stream); | ||
469 | |||
470 | /* HW port config */ | ||
471 | int sst_hsw_device_set_config(struct sst_hsw *hsw, | ||
472 | enum sst_hsw_device_id dev, enum sst_hsw_device_mclk mclk, | ||
473 | enum sst_hsw_device_mode mode, u32 clock_divider); | ||
474 | |||
475 | /* DX Config */ | ||
476 | int sst_hsw_dx_set_state(struct sst_hsw *hsw, | ||
477 | enum sst_hsw_dx_state state, struct sst_hsw_ipc_dx_reply *dx); | ||
478 | int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item, | ||
479 | u32 *offset, u32 *size, u32 *source); | ||
480 | |||
481 | /* init */ | ||
482 | int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata); | ||
483 | void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata); | ||
484 | struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw); | ||
485 | void sst_hsw_set_scratch_module(struct sst_hsw *hsw, | ||
486 | struct sst_module *scratch); | ||
487 | |||
488 | #endif | ||
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c new file mode 100644 index 000000000000..0a32dd13a23d --- /dev/null +++ b/sound/soc/intel/sst-haswell-pcm.c | |||
@@ -0,0 +1,872 @@ | |||
1 | /* | ||
2 | * Intel SST Haswell/Broadwell PCM Support | ||
3 | * | ||
4 | * Copyright (C) 2013, Intel Corporation. All rights reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/dma-mapping.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <asm/page.h> | ||
23 | #include <asm/pgtable.h> | ||
24 | #include <sound/core.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/pcm_params.h> | ||
27 | #include <sound/dmaengine_pcm.h> | ||
28 | #include <sound/soc.h> | ||
29 | #include <sound/tlv.h> | ||
30 | #include <sound/compress_driver.h> | ||
31 | |||
32 | #include "sst-haswell-ipc.h" | ||
33 | #include "sst-dsp-priv.h" | ||
34 | #include "sst-dsp.h" | ||
35 | |||
36 | #define HSW_PCM_COUNT 6 | ||
37 | #define HSW_VOLUME_MAX 0x7FFFFFFF /* 0dB */ | ||
38 | |||
39 | /* simple volume table */ | ||
40 | static const u32 volume_map[] = { | ||
41 | HSW_VOLUME_MAX >> 30, | ||
42 | HSW_VOLUME_MAX >> 29, | ||
43 | HSW_VOLUME_MAX >> 28, | ||
44 | HSW_VOLUME_MAX >> 27, | ||
45 | HSW_VOLUME_MAX >> 26, | ||
46 | HSW_VOLUME_MAX >> 25, | ||
47 | HSW_VOLUME_MAX >> 24, | ||
48 | HSW_VOLUME_MAX >> 23, | ||
49 | HSW_VOLUME_MAX >> 22, | ||
50 | HSW_VOLUME_MAX >> 21, | ||
51 | HSW_VOLUME_MAX >> 20, | ||
52 | HSW_VOLUME_MAX >> 19, | ||
53 | HSW_VOLUME_MAX >> 18, | ||
54 | HSW_VOLUME_MAX >> 17, | ||
55 | HSW_VOLUME_MAX >> 16, | ||
56 | HSW_VOLUME_MAX >> 15, | ||
57 | HSW_VOLUME_MAX >> 14, | ||
58 | HSW_VOLUME_MAX >> 13, | ||
59 | HSW_VOLUME_MAX >> 12, | ||
60 | HSW_VOLUME_MAX >> 11, | ||
61 | HSW_VOLUME_MAX >> 10, | ||
62 | HSW_VOLUME_MAX >> 9, | ||
63 | HSW_VOLUME_MAX >> 8, | ||
64 | HSW_VOLUME_MAX >> 7, | ||
65 | HSW_VOLUME_MAX >> 6, | ||
66 | HSW_VOLUME_MAX >> 5, | ||
67 | HSW_VOLUME_MAX >> 4, | ||
68 | HSW_VOLUME_MAX >> 3, | ||
69 | HSW_VOLUME_MAX >> 2, | ||
70 | HSW_VOLUME_MAX >> 1, | ||
71 | HSW_VOLUME_MAX >> 0, | ||
72 | }; | ||
73 | |||
74 | #define HSW_PCM_PERIODS_MAX 64 | ||
75 | #define HSW_PCM_PERIODS_MIN 2 | ||
76 | |||
77 | static const struct snd_pcm_hardware hsw_pcm_hardware = { | ||
78 | .info = SNDRV_PCM_INFO_MMAP | | ||
79 | SNDRV_PCM_INFO_MMAP_VALID | | ||
80 | SNDRV_PCM_INFO_INTERLEAVED | | ||
81 | SNDRV_PCM_INFO_PAUSE | | ||
82 | SNDRV_PCM_INFO_RESUME | | ||
83 | SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, | ||
84 | .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FORMAT_S24_LE | | ||
85 | SNDRV_PCM_FMTBIT_S32_LE, | ||
86 | .period_bytes_min = PAGE_SIZE, | ||
87 | .period_bytes_max = (HSW_PCM_PERIODS_MAX / HSW_PCM_PERIODS_MIN) * PAGE_SIZE, | ||
88 | .periods_min = HSW_PCM_PERIODS_MIN, | ||
89 | .periods_max = HSW_PCM_PERIODS_MAX, | ||
90 | .buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE, | ||
91 | }; | ||
92 | |||
93 | /* private data for each PCM DSP stream */ | ||
94 | struct hsw_pcm_data { | ||
95 | int dai_id; | ||
96 | struct sst_hsw_stream *stream; | ||
97 | u32 volume[2]; | ||
98 | struct snd_pcm_substream *substream; | ||
99 | struct snd_compr_stream *cstream; | ||
100 | unsigned int wpos; | ||
101 | struct mutex mutex; | ||
102 | }; | ||
103 | |||
104 | /* private data for the driver */ | ||
105 | struct hsw_priv_data { | ||
106 | /* runtime DSP */ | ||
107 | struct sst_hsw *hsw; | ||
108 | |||
109 | /* page tables */ | ||
110 | unsigned char *pcm_pg[HSW_PCM_COUNT][2]; | ||
111 | |||
112 | /* DAI data */ | ||
113 | struct hsw_pcm_data pcm[HSW_PCM_COUNT]; | ||
114 | }; | ||
115 | |||
116 | static inline u32 hsw_mixer_to_ipc(unsigned int value) | ||
117 | { | ||
118 | if (value >= ARRAY_SIZE(volume_map)) | ||
119 | return volume_map[0]; | ||
120 | else | ||
121 | return volume_map[value]; | ||
122 | } | ||
123 | |||
124 | static inline unsigned int hsw_ipc_to_mixer(u32 value) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | for (i = 0; i < ARRAY_SIZE(volume_map); i++) { | ||
129 | if (volume_map[i] >= value) | ||
130 | return i; | ||
131 | } | ||
132 | |||
133 | return i - 1; | ||
134 | } | ||
135 | |||
136 | static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol, | ||
137 | struct snd_ctl_elem_value *ucontrol) | ||
138 | { | ||
139 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
140 | struct soc_mixer_control *mc = | ||
141 | (struct soc_mixer_control *)kcontrol->private_value; | ||
142 | struct hsw_priv_data *pdata = | ||
143 | snd_soc_platform_get_drvdata(platform); | ||
144 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | ||
145 | struct sst_hsw *hsw = pdata->hsw; | ||
146 | u32 volume; | ||
147 | |||
148 | mutex_lock(&pcm_data->mutex); | ||
149 | |||
150 | if (!pcm_data->stream) { | ||
151 | pcm_data->volume[0] = | ||
152 | hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
153 | pcm_data->volume[1] = | ||
154 | hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | ||
155 | mutex_unlock(&pcm_data->mutex); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | if (ucontrol->value.integer.value[0] == | ||
160 | ucontrol->value.integer.value[1]) { | ||
161 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
162 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume); | ||
163 | } else { | ||
164 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
165 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume); | ||
166 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | ||
167 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume); | ||
168 | } | ||
169 | |||
170 | mutex_unlock(&pcm_data->mutex); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol, | ||
175 | struct snd_ctl_elem_value *ucontrol) | ||
176 | { | ||
177 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
178 | struct soc_mixer_control *mc = | ||
179 | (struct soc_mixer_control *)kcontrol->private_value; | ||
180 | struct hsw_priv_data *pdata = | ||
181 | snd_soc_platform_get_drvdata(platform); | ||
182 | struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg]; | ||
183 | struct sst_hsw *hsw = pdata->hsw; | ||
184 | u32 volume; | ||
185 | |||
186 | mutex_lock(&pcm_data->mutex); | ||
187 | |||
188 | if (!pcm_data->stream) { | ||
189 | ucontrol->value.integer.value[0] = | ||
190 | hsw_ipc_to_mixer(pcm_data->volume[0]); | ||
191 | ucontrol->value.integer.value[1] = | ||
192 | hsw_ipc_to_mixer(pcm_data->volume[1]); | ||
193 | mutex_unlock(&pcm_data->mutex); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 0, &volume); | ||
198 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | ||
199 | sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume); | ||
200 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | ||
201 | mutex_unlock(&pcm_data->mutex); | ||
202 | |||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | static int hsw_volume_put(struct snd_kcontrol *kcontrol, | ||
207 | struct snd_ctl_elem_value *ucontrol) | ||
208 | { | ||
209 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
210 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
211 | struct sst_hsw *hsw = pdata->hsw; | ||
212 | u32 volume; | ||
213 | |||
214 | if (ucontrol->value.integer.value[0] == | ||
215 | ucontrol->value.integer.value[1]) { | ||
216 | |||
217 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
218 | sst_hsw_mixer_set_volume(hsw, 0, 2, volume); | ||
219 | |||
220 | } else { | ||
221 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]); | ||
222 | sst_hsw_mixer_set_volume(hsw, 0, 0, volume); | ||
223 | |||
224 | volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[1]); | ||
225 | sst_hsw_mixer_set_volume(hsw, 0, 1, volume); | ||
226 | } | ||
227 | |||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int hsw_volume_get(struct snd_kcontrol *kcontrol, | ||
232 | struct snd_ctl_elem_value *ucontrol) | ||
233 | { | ||
234 | struct snd_soc_platform *platform = snd_kcontrol_chip(kcontrol); | ||
235 | struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform); | ||
236 | struct sst_hsw *hsw = pdata->hsw; | ||
237 | unsigned int volume = 0; | ||
238 | |||
239 | sst_hsw_mixer_get_volume(hsw, 0, 0, &volume); | ||
240 | ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume); | ||
241 | |||
242 | sst_hsw_mixer_get_volume(hsw, 0, 1, &volume); | ||
243 | ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume); | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | /* TLV used by both global and stream volumes */ | ||
249 | static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1); | ||
250 | |||
251 | /* System Pin has no volume control */ | ||
252 | static const struct snd_kcontrol_new hsw_volume_controls[] = { | ||
253 | /* Global DSP volume */ | ||
254 | SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8, | ||
255 | ARRAY_SIZE(volume_map) -1, 0, | ||
256 | hsw_volume_get, hsw_volume_put, hsw_vol_tlv), | ||
257 | /* Offload 0 volume */ | ||
258 | SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8, | ||
259 | ARRAY_SIZE(volume_map), 0, | ||
260 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
261 | /* Offload 1 volume */ | ||
262 | SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8, | ||
263 | ARRAY_SIZE(volume_map), 0, | ||
264 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
265 | /* Loopback volume */ | ||
266 | SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8, | ||
267 | ARRAY_SIZE(volume_map), 0, | ||
268 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
269 | /* Mic Capture volume */ | ||
270 | SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8, | ||
271 | ARRAY_SIZE(volume_map), 0, | ||
272 | hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv), | ||
273 | }; | ||
274 | |||
275 | /* Create DMA buffer page table for DSP */ | ||
276 | static int create_adsp_page_table(struct hsw_priv_data *pdata, | ||
277 | struct snd_soc_pcm_runtime *rtd, | ||
278 | unsigned char *dma_area, size_t size, int pcm, int stream) | ||
279 | { | ||
280 | int i, pages; | ||
281 | |||
282 | if (size % PAGE_SIZE) | ||
283 | pages = (size / PAGE_SIZE) + 1; | ||
284 | else | ||
285 | pages = size / PAGE_SIZE; | ||
286 | |||
287 | dev_dbg(rtd->dev, "generating page table for %p size 0x%zu pages %d\n", | ||
288 | dma_area, size, pages); | ||
289 | |||
290 | for (i = 0; i < pages; i++) { | ||
291 | u32 idx = (((i << 2) + i)) >> 1; | ||
292 | u32 pfn = (virt_to_phys(dma_area + i * PAGE_SIZE)) >> PAGE_SHIFT; | ||
293 | u32 *pg_table; | ||
294 | |||
295 | dev_dbg(rtd->dev, "pfn i %i idx %d pfn %x\n", i, idx, pfn); | ||
296 | |||
297 | pg_table = (u32*)(pdata->pcm_pg[pcm][stream] + idx); | ||
298 | |||
299 | if (i & 1) | ||
300 | *pg_table |= (pfn << 4); | ||
301 | else | ||
302 | *pg_table |= pfn; | ||
303 | } | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | /* this may get called several times by oss emulation */ | ||
309 | static int hsw_pcm_hw_params(struct snd_pcm_substream *substream, | ||
310 | struct snd_pcm_hw_params *params) | ||
311 | { | ||
312 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
313 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
314 | struct hsw_priv_data *pdata = | ||
315 | snd_soc_platform_get_drvdata(rtd->platform); | ||
316 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
317 | struct sst_hsw *hsw = pdata->hsw; | ||
318 | struct sst_module *module_data; | ||
319 | struct sst_dsp *dsp; | ||
320 | enum sst_hsw_stream_type stream_type; | ||
321 | enum sst_hsw_stream_path_id path_id; | ||
322 | u32 rate, bits, map, pages, module_id; | ||
323 | u8 channels; | ||
324 | int ret; | ||
325 | |||
326 | /* stream direction */ | ||
327 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
328 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | ||
329 | else | ||
330 | path_id = SST_HSW_STREAM_PATH_SSP0_IN; | ||
331 | |||
332 | /* DSP stream type depends on DAI ID */ | ||
333 | switch (rtd->cpu_dai->id) { | ||
334 | case 0: | ||
335 | stream_type = SST_HSW_STREAM_TYPE_SYSTEM; | ||
336 | module_id = SST_HSW_MODULE_PCM_SYSTEM; | ||
337 | break; | ||
338 | case 1: | ||
339 | case 2: | ||
340 | stream_type = SST_HSW_STREAM_TYPE_RENDER; | ||
341 | module_id = SST_HSW_MODULE_PCM; | ||
342 | break; | ||
343 | case 3: | ||
344 | /* path ID needs to be OUT for loopback */ | ||
345 | stream_type = SST_HSW_STREAM_TYPE_LOOPBACK; | ||
346 | path_id = SST_HSW_STREAM_PATH_SSP0_OUT; | ||
347 | module_id = SST_HSW_MODULE_PCM_REFERENCE; | ||
348 | break; | ||
349 | case 4: | ||
350 | stream_type = SST_HSW_STREAM_TYPE_CAPTURE; | ||
351 | module_id = SST_HSW_MODULE_PCM_CAPTURE; | ||
352 | break; | ||
353 | default: | ||
354 | dev_err(rtd->dev, "error: invalid DAI ID %d\n", | ||
355 | rtd->cpu_dai->id); | ||
356 | return -EINVAL; | ||
357 | }; | ||
358 | |||
359 | ret = sst_hsw_stream_format(hsw, pcm_data->stream, | ||
360 | path_id, stream_type, SST_HSW_STREAM_FORMAT_PCM_FORMAT); | ||
361 | if (ret < 0) { | ||
362 | dev_err(rtd->dev, "error: failed to set format %d\n", ret); | ||
363 | return ret; | ||
364 | } | ||
365 | |||
366 | rate = params_rate(params); | ||
367 | ret = sst_hsw_stream_set_rate(hsw, pcm_data->stream, rate); | ||
368 | if (ret < 0) { | ||
369 | dev_err(rtd->dev, "error: could not set rate %d\n", rate); | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | switch (params_format(params)) { | ||
374 | case SNDRV_PCM_FORMAT_S16_LE: | ||
375 | bits = SST_HSW_DEPTH_16BIT; | ||
376 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 16); | ||
377 | break; | ||
378 | case SNDRV_PCM_FORMAT_S24_LE: | ||
379 | bits = SST_HSW_DEPTH_24BIT; | ||
380 | sst_hsw_stream_set_valid(hsw, pcm_data->stream, 32); | ||
381 | break; | ||
382 | default: | ||
383 | dev_err(rtd->dev, "error: invalid format %d\n", | ||
384 | params_format(params)); | ||
385 | return -EINVAL; | ||
386 | } | ||
387 | |||
388 | ret = sst_hsw_stream_set_bits(hsw, pcm_data->stream, bits); | ||
389 | if (ret < 0) { | ||
390 | dev_err(rtd->dev, "error: could not set bits %d\n", bits); | ||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | /* we only support stereo atm */ | ||
395 | channels = params_channels(params); | ||
396 | if (channels != 2) { | ||
397 | dev_err(rtd->dev, "error: invalid channels %d\n", channels); | ||
398 | return -EINVAL; | ||
399 | } | ||
400 | |||
401 | map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO); | ||
402 | sst_hsw_stream_set_map_config(hsw, pcm_data->stream, | ||
403 | map, SST_HSW_CHANNEL_CONFIG_STEREO); | ||
404 | |||
405 | ret = sst_hsw_stream_set_channels(hsw, pcm_data->stream, channels); | ||
406 | if (ret < 0) { | ||
407 | dev_err(rtd->dev, "error: could not set channels %d\n", | ||
408 | channels); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
413 | if (ret < 0) { | ||
414 | dev_err(rtd->dev, "error: could not allocate %d bytes for PCM %d\n", | ||
415 | params_buffer_bytes(params), ret); | ||
416 | return ret; | ||
417 | } | ||
418 | |||
419 | ret = create_adsp_page_table(pdata, rtd, runtime->dma_area, | ||
420 | runtime->dma_bytes, rtd->cpu_dai->id, substream->stream); | ||
421 | if (ret < 0) | ||
422 | return ret; | ||
423 | |||
424 | sst_hsw_stream_set_style(hsw, pcm_data->stream, | ||
425 | SST_HSW_INTERLEAVING_PER_CHANNEL); | ||
426 | |||
427 | if (runtime->dma_bytes % PAGE_SIZE) | ||
428 | pages = (runtime->dma_bytes / PAGE_SIZE) + 1; | ||
429 | else | ||
430 | pages = runtime->dma_bytes / PAGE_SIZE; | ||
431 | |||
432 | ret = sst_hsw_stream_buffer(hsw, pcm_data->stream, | ||
433 | virt_to_phys(pdata->pcm_pg[rtd->cpu_dai->id][substream->stream]), | ||
434 | pages, runtime->dma_bytes, 0, | ||
435 | (u32)(virt_to_phys(runtime->dma_area) >> PAGE_SHIFT)); | ||
436 | if (ret < 0) { | ||
437 | dev_err(rtd->dev, "error: failed to set DMA buffer %d\n", ret); | ||
438 | return ret; | ||
439 | } | ||
440 | |||
441 | dsp = sst_hsw_get_dsp(hsw); | ||
442 | |||
443 | module_data = sst_module_get_from_id(dsp, module_id); | ||
444 | if (module_data == NULL) { | ||
445 | dev_err(rtd->dev, "error: failed to get module config\n"); | ||
446 | return -EINVAL; | ||
447 | } | ||
448 | |||
449 | /* we use hardcoded memory offsets atm, will be updated for new FW */ | ||
450 | if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) { | ||
451 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
452 | SST_HSW_MODULE_PCM_CAPTURE, module_data->entry); | ||
453 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
454 | 0x449400, 0x4000); | ||
455 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
456 | 0x400000, 0); | ||
457 | } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */ | ||
458 | sst_hsw_stream_set_module_info(hsw, pcm_data->stream, | ||
459 | SST_HSW_MODULE_PCM_SYSTEM, module_data->entry); | ||
460 | |||
461 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
462 | module_data->offset, module_data->size); | ||
463 | sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream, | ||
464 | 0x44d400, 0x3800); | ||
465 | |||
466 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
467 | module_data->offset, module_data->size); | ||
468 | sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream, | ||
469 | 0x400000, 0); | ||
470 | } | ||
471 | |||
472 | ret = sst_hsw_stream_commit(hsw, pcm_data->stream); | ||
473 | if (ret < 0) { | ||
474 | dev_err(rtd->dev, "error: failed to commit stream %d\n", ret); | ||
475 | return ret; | ||
476 | } | ||
477 | |||
478 | ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1); | ||
479 | if (ret < 0) | ||
480 | dev_err(rtd->dev, "error: failed to pause %d\n", ret); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int hsw_pcm_hw_free(struct snd_pcm_substream *substream) | ||
486 | { | ||
487 | snd_pcm_lib_free_pages(substream); | ||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int hsw_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
492 | { | ||
493 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
494 | struct hsw_priv_data *pdata = | ||
495 | snd_soc_platform_get_drvdata(rtd->platform); | ||
496 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
497 | struct sst_hsw *hsw = pdata->hsw; | ||
498 | |||
499 | switch (cmd) { | ||
500 | case SNDRV_PCM_TRIGGER_START: | ||
501 | case SNDRV_PCM_TRIGGER_RESUME: | ||
502 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
503 | sst_hsw_stream_resume(hsw, pcm_data->stream, 0); | ||
504 | break; | ||
505 | case SNDRV_PCM_TRIGGER_STOP: | ||
506 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
507 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
508 | sst_hsw_stream_pause(hsw, pcm_data->stream, 0); | ||
509 | break; | ||
510 | default: | ||
511 | break; | ||
512 | } | ||
513 | |||
514 | return 0; | ||
515 | } | ||
516 | |||
517 | static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data) | ||
518 | { | ||
519 | struct hsw_pcm_data *pcm_data = data; | ||
520 | struct snd_pcm_substream *substream = pcm_data->substream; | ||
521 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
522 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
523 | u32 pos; | ||
524 | |||
525 | pos = frames_to_bytes(runtime, | ||
526 | (runtime->control->appl_ptr % runtime->buffer_size)); | ||
527 | |||
528 | dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos); | ||
529 | |||
530 | /* let alsa know we have play a period */ | ||
531 | snd_pcm_period_elapsed(substream); | ||
532 | return pos; | ||
533 | } | ||
534 | |||
535 | static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream) | ||
536 | { | ||
537 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
538 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
539 | struct hsw_priv_data *pdata = | ||
540 | snd_soc_platform_get_drvdata(rtd->platform); | ||
541 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
542 | struct sst_hsw *hsw = pdata->hsw; | ||
543 | snd_pcm_uframes_t offset; | ||
544 | |||
545 | offset = bytes_to_frames(runtime, | ||
546 | sst_hsw_get_dsp_position(hsw, pcm_data->stream)); | ||
547 | |||
548 | dev_dbg(rtd->dev, "PCM: DMA pointer %zu bytes\n", | ||
549 | frames_to_bytes(runtime, (u32)offset)); | ||
550 | return offset; | ||
551 | } | ||
552 | |||
553 | static int hsw_pcm_open(struct snd_pcm_substream *substream) | ||
554 | { | ||
555 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
556 | struct hsw_priv_data *pdata = | ||
557 | snd_soc_platform_get_drvdata(rtd->platform); | ||
558 | struct hsw_pcm_data *pcm_data; | ||
559 | struct sst_hsw *hsw = pdata->hsw; | ||
560 | |||
561 | pcm_data = &pdata->pcm[rtd->cpu_dai->id]; | ||
562 | |||
563 | mutex_lock(&pcm_data->mutex); | ||
564 | |||
565 | snd_soc_pcm_set_drvdata(rtd, pcm_data); | ||
566 | pcm_data->substream = substream; | ||
567 | |||
568 | snd_soc_set_runtime_hwparams(substream, &hsw_pcm_hardware); | ||
569 | |||
570 | pcm_data->stream = sst_hsw_stream_new(hsw, rtd->cpu_dai->id, | ||
571 | hsw_notify_pointer, pcm_data); | ||
572 | if (pcm_data->stream == NULL) { | ||
573 | dev_err(rtd->dev, "error: failed to create stream\n"); | ||
574 | mutex_unlock(&pcm_data->mutex); | ||
575 | return -EINVAL; | ||
576 | } | ||
577 | |||
578 | /* Set previous saved volume */ | ||
579 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
580 | 0, pcm_data->volume[0]); | ||
581 | sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, | ||
582 | 1, pcm_data->volume[1]); | ||
583 | |||
584 | mutex_unlock(&pcm_data->mutex); | ||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int hsw_pcm_close(struct snd_pcm_substream *substream) | ||
589 | { | ||
590 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | ||
591 | struct hsw_priv_data *pdata = | ||
592 | snd_soc_platform_get_drvdata(rtd->platform); | ||
593 | struct hsw_pcm_data *pcm_data = snd_soc_pcm_get_drvdata(rtd); | ||
594 | struct sst_hsw *hsw = pdata->hsw; | ||
595 | int ret; | ||
596 | |||
597 | mutex_lock(&pcm_data->mutex); | ||
598 | ret = sst_hsw_stream_reset(hsw, pcm_data->stream); | ||
599 | if (ret < 0) { | ||
600 | dev_dbg(rtd->dev, "error: reset stream failed %d\n", ret); | ||
601 | goto out; | ||
602 | } | ||
603 | |||
604 | ret = sst_hsw_stream_free(hsw, pcm_data->stream); | ||
605 | if (ret < 0) { | ||
606 | dev_dbg(rtd->dev, "error: free stream failed %d\n", ret); | ||
607 | goto out; | ||
608 | } | ||
609 | pcm_data->stream = NULL; | ||
610 | |||
611 | out: | ||
612 | mutex_unlock(&pcm_data->mutex); | ||
613 | return ret; | ||
614 | } | ||
615 | |||
616 | static struct snd_pcm_ops hsw_pcm_ops = { | ||
617 | .open = hsw_pcm_open, | ||
618 | .close = hsw_pcm_close, | ||
619 | .ioctl = snd_pcm_lib_ioctl, | ||
620 | .hw_params = hsw_pcm_hw_params, | ||
621 | .hw_free = hsw_pcm_hw_free, | ||
622 | .trigger = hsw_pcm_trigger, | ||
623 | .pointer = hsw_pcm_pointer, | ||
624 | .mmap = snd_pcm_lib_default_mmap, | ||
625 | }; | ||
626 | |||
627 | static void hsw_pcm_free(struct snd_pcm *pcm) | ||
628 | { | ||
629 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
630 | } | ||
631 | |||
632 | static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd) | ||
633 | { | ||
634 | struct snd_pcm *pcm = rtd->pcm; | ||
635 | int ret = 0; | ||
636 | |||
637 | ret = dma_coerce_mask_and_coherent(rtd->card->dev, DMA_BIT_MASK(32)); | ||
638 | if (ret) | ||
639 | return ret; | ||
640 | |||
641 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream || | ||
642 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) { | ||
643 | ret = snd_pcm_lib_preallocate_pages_for_all(pcm, | ||
644 | SNDRV_DMA_TYPE_DEV, | ||
645 | rtd->card->dev, | ||
646 | hsw_pcm_hardware.buffer_bytes_max, | ||
647 | hsw_pcm_hardware.buffer_bytes_max); | ||
648 | if (ret) { | ||
649 | dev_err(rtd->dev, "dma buffer allocation failed %d\n", | ||
650 | ret); | ||
651 | return ret; | ||
652 | } | ||
653 | } | ||
654 | |||
655 | return ret; | ||
656 | } | ||
657 | |||
658 | #define HSW_FORMATS \ | ||
659 | (SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S16_LE |\ | ||
660 | SNDRV_PCM_FMTBIT_S32_LE) | ||
661 | |||
662 | static struct snd_soc_dai_driver hsw_dais[] = { | ||
663 | { | ||
664 | .name = "System Pin", | ||
665 | .playback = { | ||
666 | .stream_name = "System Playback", | ||
667 | .channels_min = 2, | ||
668 | .channels_max = 2, | ||
669 | .rates = SNDRV_PCM_RATE_48000, | ||
670 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
671 | }, | ||
672 | }, | ||
673 | { | ||
674 | /* PCM */ | ||
675 | .name = "Offload0 Pin", | ||
676 | .playback = { | ||
677 | .stream_name = "Offload0 Playback", | ||
678 | .channels_min = 2, | ||
679 | .channels_max = 2, | ||
680 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
681 | .formats = HSW_FORMATS, | ||
682 | }, | ||
683 | }, | ||
684 | { | ||
685 | /* PCM */ | ||
686 | .name = "Offload1 Pin", | ||
687 | .playback = { | ||
688 | .stream_name = "Offload1 Playback", | ||
689 | .channels_min = 2, | ||
690 | .channels_max = 2, | ||
691 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
692 | .formats = HSW_FORMATS, | ||
693 | }, | ||
694 | }, | ||
695 | { | ||
696 | .name = "Loopback Pin", | ||
697 | .capture = { | ||
698 | .stream_name = "Loopback Capture", | ||
699 | .channels_min = 2, | ||
700 | .channels_max = 2, | ||
701 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
702 | .formats = HSW_FORMATS, | ||
703 | }, | ||
704 | }, | ||
705 | { | ||
706 | .name = "Capture Pin", | ||
707 | .capture = { | ||
708 | .stream_name = "Analog Capture", | ||
709 | .channels_min = 2, | ||
710 | .channels_max = 2, | ||
711 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
712 | .formats = HSW_FORMATS, | ||
713 | }, | ||
714 | }, | ||
715 | }; | ||
716 | |||
717 | static const struct snd_soc_dapm_widget widgets[] = { | ||
718 | |||
719 | /* Backend DAIs */ | ||
720 | SND_SOC_DAPM_AIF_IN("SSP0 CODEC IN", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
721 | SND_SOC_DAPM_AIF_OUT("SSP0 CODEC OUT", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
722 | SND_SOC_DAPM_AIF_IN("SSP1 BT IN", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
723 | SND_SOC_DAPM_AIF_OUT("SSP1 BT OUT", NULL, 0, SND_SOC_NOPM, 0, 0), | ||
724 | |||
725 | /* Global Playback Mixer */ | ||
726 | SND_SOC_DAPM_MIXER("Playback VMixer", SND_SOC_NOPM, 0, 0, NULL, 0), | ||
727 | }; | ||
728 | |||
729 | static const struct snd_soc_dapm_route graph[] = { | ||
730 | |||
731 | /* Playback Mixer */ | ||
732 | {"Playback VMixer", NULL, "System Playback"}, | ||
733 | {"Playback VMixer", NULL, "Offload0 Playback"}, | ||
734 | {"Playback VMixer", NULL, "Offload1 Playback"}, | ||
735 | |||
736 | {"SSP0 CODEC OUT", NULL, "Playback VMixer"}, | ||
737 | |||
738 | {"Analog Capture", NULL, "SSP0 CODEC IN"}, | ||
739 | }; | ||
740 | |||
741 | static int hsw_pcm_probe(struct snd_soc_platform *platform) | ||
742 | { | ||
743 | struct sst_pdata *pdata = dev_get_platdata(platform->dev); | ||
744 | struct hsw_priv_data *priv_data; | ||
745 | int i; | ||
746 | |||
747 | if (!pdata) | ||
748 | return -ENODEV; | ||
749 | |||
750 | priv_data = devm_kzalloc(platform->dev, sizeof(*priv_data), GFP_KERNEL); | ||
751 | priv_data->hsw = pdata->dsp; | ||
752 | snd_soc_platform_set_drvdata(platform, priv_data); | ||
753 | |||
754 | /* allocate DSP buffer page tables */ | ||
755 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | ||
756 | |||
757 | mutex_init(&priv_data->pcm[i].mutex); | ||
758 | |||
759 | /* playback */ | ||
760 | if (hsw_dais[i].playback.channels_min) { | ||
761 | priv_data->pcm_pg[i][0] = kzalloc(PAGE_SIZE, GFP_DMA); | ||
762 | if (priv_data->pcm_pg[i][0] == NULL) | ||
763 | goto err; | ||
764 | } | ||
765 | |||
766 | /* capture */ | ||
767 | if (hsw_dais[i].capture.channels_min) { | ||
768 | priv_data->pcm_pg[i][1] = kzalloc(PAGE_SIZE, GFP_DMA); | ||
769 | if (priv_data->pcm_pg[i][1] == NULL) | ||
770 | goto err; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | return 0; | ||
775 | |||
776 | err: | ||
777 | for (;i >= 0; i--) { | ||
778 | if (hsw_dais[i].playback.channels_min) | ||
779 | kfree(priv_data->pcm_pg[i][0]); | ||
780 | if (hsw_dais[i].capture.channels_min) | ||
781 | kfree(priv_data->pcm_pg[i][1]); | ||
782 | } | ||
783 | return -ENOMEM; | ||
784 | } | ||
785 | |||
786 | static int hsw_pcm_remove(struct snd_soc_platform *platform) | ||
787 | { | ||
788 | struct hsw_priv_data *priv_data = | ||
789 | snd_soc_platform_get_drvdata(platform); | ||
790 | int i; | ||
791 | |||
792 | for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) { | ||
793 | if (hsw_dais[i].playback.channels_min) | ||
794 | kfree(priv_data->pcm_pg[i][0]); | ||
795 | if (hsw_dais[i].capture.channels_min) | ||
796 | kfree(priv_data->pcm_pg[i][1]); | ||
797 | } | ||
798 | |||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | static struct snd_soc_platform_driver hsw_soc_platform = { | ||
803 | .probe = hsw_pcm_probe, | ||
804 | .remove = hsw_pcm_remove, | ||
805 | .ops = &hsw_pcm_ops, | ||
806 | .pcm_new = hsw_pcm_new, | ||
807 | .pcm_free = hsw_pcm_free, | ||
808 | .controls = hsw_volume_controls, | ||
809 | .num_controls = ARRAY_SIZE(hsw_volume_controls), | ||
810 | .dapm_widgets = widgets, | ||
811 | .num_dapm_widgets = ARRAY_SIZE(widgets), | ||
812 | .dapm_routes = graph, | ||
813 | .num_dapm_routes = ARRAY_SIZE(graph), | ||
814 | }; | ||
815 | |||
816 | static const struct snd_soc_component_driver hsw_dai_component = { | ||
817 | .name = "haswell-dai", | ||
818 | }; | ||
819 | |||
820 | static int hsw_pcm_dev_probe(struct platform_device *pdev) | ||
821 | { | ||
822 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
823 | int ret; | ||
824 | |||
825 | ret = sst_hsw_dsp_init(&pdev->dev, sst_pdata); | ||
826 | if (ret < 0) | ||
827 | return -ENODEV; | ||
828 | |||
829 | ret = snd_soc_register_platform(&pdev->dev, &hsw_soc_platform); | ||
830 | if (ret < 0) | ||
831 | goto err_plat; | ||
832 | |||
833 | ret = snd_soc_register_component(&pdev->dev, &hsw_dai_component, | ||
834 | hsw_dais, ARRAY_SIZE(hsw_dais)); | ||
835 | if (ret < 0) | ||
836 | goto err_comp; | ||
837 | |||
838 | return 0; | ||
839 | |||
840 | err_comp: | ||
841 | snd_soc_unregister_platform(&pdev->dev); | ||
842 | err_plat: | ||
843 | sst_hsw_dsp_free(&pdev->dev, sst_pdata); | ||
844 | return 0; | ||
845 | } | ||
846 | |||
847 | static int hsw_pcm_dev_remove(struct platform_device *pdev) | ||
848 | { | ||
849 | struct sst_pdata *sst_pdata = dev_get_platdata(&pdev->dev); | ||
850 | |||
851 | snd_soc_unregister_platform(&pdev->dev); | ||
852 | snd_soc_unregister_component(&pdev->dev); | ||
853 | sst_hsw_dsp_free(&pdev->dev, sst_pdata); | ||
854 | |||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static struct platform_driver hsw_pcm_driver = { | ||
859 | .driver = { | ||
860 | .name = "haswell-pcm-audio", | ||
861 | .owner = THIS_MODULE, | ||
862 | }, | ||
863 | |||
864 | .probe = hsw_pcm_dev_probe, | ||
865 | .remove = hsw_pcm_dev_remove, | ||
866 | }; | ||
867 | module_platform_driver(hsw_pcm_driver); | ||
868 | |||
869 | MODULE_AUTHOR("Liam Girdwood, Xingchao Wang"); | ||
870 | MODULE_DESCRIPTION("Haswell/Lynxpoint + Broadwell/Wildcatpoint PCM"); | ||
871 | MODULE_LICENSE("GPL v2"); | ||
872 | MODULE_ALIAS("platform:haswell-pcm-audio"); | ||
diff --git a/sound/soc/intel/sst_dsp.h b/sound/soc/intel/sst-mfld-dsp.h index 0fce1de284ff..3b63edc04b7f 100644 --- a/sound/soc/intel/sst_dsp.h +++ b/sound/soc/intel/sst-mfld-dsp.h | |||
@@ -1,7 +1,7 @@ | |||
1 | #ifndef __SST_DSP_H__ | 1 | #ifndef __SST_MFLD_DSP_H__ |
2 | #define __SST_DSP_H__ | 2 | #define __SST_MFLD_DSP_H__ |
3 | /* | 3 | /* |
4 | * sst_dsp.h - Intel SST Driver for audio engine | 4 | * sst_mfld_dsp.h - Intel SST Driver for audio engine |
5 | * | 5 | * |
6 | * Copyright (C) 2008-12 Intel Corporation | 6 | * Copyright (C) 2008-12 Intel Corporation |
7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> | 7 | * Authors: Vinod Koul <vinod.koul@linux.intel.com> |
@@ -131,4 +131,4 @@ struct snd_sst_params { | |||
131 | struct snd_sst_alloc_params_ext aparams; | 131 | struct snd_sst_alloc_params_ext aparams; |
132 | }; | 132 | }; |
133 | 133 | ||
134 | #endif /* __SST_DSP_H__ */ | 134 | #endif /* __SST_MFLD_DSP_H__ */ |
diff --git a/sound/soc/intel/sst_platform.c b/sound/soc/intel/sst-mfld-platform.c index f465a8180863..840306c2ef14 100644 --- a/sound/soc/intel/sst_platform.c +++ b/sound/soc/intel/sst-mfld-platform.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * sst_platform.c - Intel MID Platform driver | 2 | * sst_mfld_platform.c - Intel MID Platform driver |
3 | * | 3 | * |
4 | * Copyright (C) 2010-2013 Intel Corp | 4 | * Copyright (C) 2010-2013 Intel Corp |
5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
@@ -33,7 +33,7 @@ | |||
33 | #include <sound/pcm_params.h> | 33 | #include <sound/pcm_params.h> |
34 | #include <sound/soc.h> | 34 | #include <sound/soc.h> |
35 | #include <sound/compress_driver.h> | 35 | #include <sound/compress_driver.h> |
36 | #include "sst_platform.h" | 36 | #include "sst-mfld-platform.h" |
37 | 37 | ||
38 | static struct sst_device *sst; | 38 | static struct sst_device *sst; |
39 | static DEFINE_MUTEX(sst_lock); | 39 | static DEFINE_MUTEX(sst_lock); |
@@ -709,7 +709,7 @@ static int sst_platform_remove(struct platform_device *pdev) | |||
709 | 709 | ||
710 | static struct platform_driver sst_platform_driver = { | 710 | static struct platform_driver sst_platform_driver = { |
711 | .driver = { | 711 | .driver = { |
712 | .name = "sst-platform", | 712 | .name = "sst-mfld-platform", |
713 | .owner = THIS_MODULE, | 713 | .owner = THIS_MODULE, |
714 | }, | 714 | }, |
715 | .probe = sst_platform_probe, | 715 | .probe = sst_platform_probe, |
@@ -722,4 +722,4 @@ MODULE_DESCRIPTION("ASoC Intel(R) MID Platform driver"); | |||
722 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); | 722 | MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>"); |
723 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); | 723 | MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>"); |
724 | MODULE_LICENSE("GPL v2"); | 724 | MODULE_LICENSE("GPL v2"); |
725 | MODULE_ALIAS("platform:sst-platform"); | 725 | MODULE_ALIAS("platform:sst-mfld-platform"); |
diff --git a/sound/soc/intel/sst_platform.h b/sound/soc/intel/sst-mfld-platform.h index bee64fb7d2ef..0c4e2ddcecb1 100644 --- a/sound/soc/intel/sst_platform.h +++ b/sound/soc/intel/sst-mfld-platform.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * sst_platform.h - Intel MID Platform driver header file | 2 | * sst_mfld_platform.h - Intel MID Platform driver header file |
3 | * | 3 | * |
4 | * Copyright (C) 2010 Intel Corp | 4 | * Copyright (C) 2010 Intel Corp |
5 | * Author: Vinod Koul <vinod.koul@intel.com> | 5 | * Author: Vinod Koul <vinod.koul@intel.com> |
@@ -27,7 +27,7 @@ | |||
27 | #ifndef __SST_PLATFORMDRV_H__ | 27 | #ifndef __SST_PLATFORMDRV_H__ |
28 | #define __SST_PLATFORMDRV_H__ | 28 | #define __SST_PLATFORMDRV_H__ |
29 | 29 | ||
30 | #include "sst_dsp.h" | 30 | #include "sst-mfld-dsp.h" |
31 | 31 | ||
32 | #define SST_MONO 1 | 32 | #define SST_MONO 1 |
33 | #define SST_STEREO 2 | 33 | #define SST_STEREO 2 |
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig index 22ad9c5654b5..e00659351a4e 100644 --- a/sound/soc/omap/Kconfig +++ b/sound/soc/omap/Kconfig | |||
@@ -58,7 +58,7 @@ config SND_OMAP_SOC_OSK5912 | |||
58 | tristate "SoC Audio support for omap osk5912" | 58 | tristate "SoC Audio support for omap osk5912" |
59 | depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C | 59 | depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C |
60 | select SND_OMAP_SOC_MCBSP | 60 | select SND_OMAP_SOC_MCBSP |
61 | select SND_SOC_TLV320AIC23 | 61 | select SND_SOC_TLV320AIC23_I2C |
62 | help | 62 | help |
63 | Say Y if you want to add support for SoC audio on osk5912. | 63 | Say Y if you want to add support for SoC audio on osk5912. |
64 | 64 | ||
@@ -66,7 +66,7 @@ config SND_OMAP_SOC_AM3517EVM | |||
66 | tristate "SoC Audio support for OMAP3517 / AM3517 EVM" | 66 | tristate "SoC Audio support for OMAP3517 / AM3517 EVM" |
67 | depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C | 67 | depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C |
68 | select SND_OMAP_SOC_MCBSP | 68 | select SND_OMAP_SOC_MCBSP |
69 | select SND_SOC_TLV320AIC23 | 69 | select SND_SOC_TLV320AIC23_I2C |
70 | help | 70 | help |
71 | Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 | 71 | Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 |
72 | EVM. | 72 | EVM. |
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 629446482a91..f141435b0b4a 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c | |||
@@ -103,60 +103,62 @@ static int ams_delta_set_audio_mode(struct snd_kcontrol *kcontrol, | |||
103 | if (!codec->hw_write) | 103 | if (!codec->hw_write) |
104 | return -EUNATCH; | 104 | return -EUNATCH; |
105 | 105 | ||
106 | if (ucontrol->value.enumerated.item[0] >= control->max) | 106 | if (ucontrol->value.enumerated.item[0] >= control->items) |
107 | return -EINVAL; | 107 | return -EINVAL; |
108 | 108 | ||
109 | mutex_lock(&codec->mutex); | 109 | snd_soc_dapm_mutex_lock(dapm); |
110 | 110 | ||
111 | /* Translate selection to bitmap */ | 111 | /* Translate selection to bitmap */ |
112 | pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; | 112 | pins = ams_delta_audio_mode_pins[ucontrol->value.enumerated.item[0]]; |
113 | 113 | ||
114 | /* Setup pins after corresponding bits if changed */ | 114 | /* Setup pins after corresponding bits if changed */ |
115 | pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); | 115 | pin = !!(pins & (1 << AMS_DELTA_MOUTHPIECE)); |
116 | |||
116 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) { | 117 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Mouthpiece")) { |
117 | changed = 1; | 118 | changed = 1; |
118 | if (pin) | 119 | if (pin) |
119 | snd_soc_dapm_enable_pin(dapm, "Mouthpiece"); | 120 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mouthpiece"); |
120 | else | 121 | else |
121 | snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); | 122 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); |
122 | } | 123 | } |
123 | pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); | 124 | pin = !!(pins & (1 << AMS_DELTA_EARPIECE)); |
124 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) { | 125 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Earpiece")) { |
125 | changed = 1; | 126 | changed = 1; |
126 | if (pin) | 127 | if (pin) |
127 | snd_soc_dapm_enable_pin(dapm, "Earpiece"); | 128 | snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); |
128 | else | 129 | else |
129 | snd_soc_dapm_disable_pin(dapm, "Earpiece"); | 130 | snd_soc_dapm_disable_pin_unlocked(dapm, "Earpiece"); |
130 | } | 131 | } |
131 | pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); | 132 | pin = !!(pins & (1 << AMS_DELTA_MICROPHONE)); |
132 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) { | 133 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Microphone")) { |
133 | changed = 1; | 134 | changed = 1; |
134 | if (pin) | 135 | if (pin) |
135 | snd_soc_dapm_enable_pin(dapm, "Microphone"); | 136 | snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); |
136 | else | 137 | else |
137 | snd_soc_dapm_disable_pin(dapm, "Microphone"); | 138 | snd_soc_dapm_disable_pin_unlocked(dapm, "Microphone"); |
138 | } | 139 | } |
139 | pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); | 140 | pin = !!(pins & (1 << AMS_DELTA_SPEAKER)); |
140 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) { | 141 | if (pin != snd_soc_dapm_get_pin_status(dapm, "Speaker")) { |
141 | changed = 1; | 142 | changed = 1; |
142 | if (pin) | 143 | if (pin) |
143 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 144 | snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); |
144 | else | 145 | else |
145 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 146 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
146 | } | 147 | } |
147 | pin = !!(pins & (1 << AMS_DELTA_AGC)); | 148 | pin = !!(pins & (1 << AMS_DELTA_AGC)); |
148 | if (pin != ams_delta_audio_agc) { | 149 | if (pin != ams_delta_audio_agc) { |
149 | ams_delta_audio_agc = pin; | 150 | ams_delta_audio_agc = pin; |
150 | changed = 1; | 151 | changed = 1; |
151 | if (pin) | 152 | if (pin) |
152 | snd_soc_dapm_enable_pin(dapm, "AGCIN"); | 153 | snd_soc_dapm_enable_pin_unlocked(dapm, "AGCIN"); |
153 | else | 154 | else |
154 | snd_soc_dapm_disable_pin(dapm, "AGCIN"); | 155 | snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); |
155 | } | 156 | } |
157 | |||
156 | if (changed) | 158 | if (changed) |
157 | snd_soc_dapm_sync(dapm); | 159 | snd_soc_dapm_sync_unlocked(dapm); |
158 | 160 | ||
159 | mutex_unlock(&codec->mutex); | 161 | snd_soc_dapm_mutex_unlock(dapm); |
160 | 162 | ||
161 | return changed; | 163 | return changed; |
162 | } | 164 | } |
@@ -194,13 +196,11 @@ static int ams_delta_get_audio_mode(struct snd_kcontrol *kcontrol, | |||
194 | return 0; | 196 | return 0; |
195 | } | 197 | } |
196 | 198 | ||
197 | static const struct soc_enum ams_delta_audio_enum[] = { | 199 | static const SOC_ENUM_SINGLE_EXT_DECL(ams_delta_audio_enum, |
198 | SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ams_delta_audio_mode), | 200 | ams_delta_audio_mode); |
199 | ams_delta_audio_mode), | ||
200 | }; | ||
201 | 201 | ||
202 | static const struct snd_kcontrol_new ams_delta_audio_controls[] = { | 202 | static const struct snd_kcontrol_new ams_delta_audio_controls[] = { |
203 | SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum[0], | 203 | SOC_ENUM_EXT("Audio Mode", ams_delta_audio_enum, |
204 | ams_delta_get_audio_mode, ams_delta_set_audio_mode), | 204 | ams_delta_get_audio_mode, ams_delta_set_audio_mode), |
205 | }; | 205 | }; |
206 | 206 | ||
@@ -315,12 +315,17 @@ static void cx81801_close(struct tty_struct *tty) | |||
315 | v253_ops.close(tty); | 315 | v253_ops.close(tty); |
316 | 316 | ||
317 | /* Revert back to default audio input/output constellation */ | 317 | /* Revert back to default audio input/output constellation */ |
318 | snd_soc_dapm_disable_pin(dapm, "Mouthpiece"); | 318 | snd_soc_dapm_mutex_lock(dapm); |
319 | snd_soc_dapm_enable_pin(dapm, "Earpiece"); | 319 | |
320 | snd_soc_dapm_enable_pin(dapm, "Microphone"); | 320 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mouthpiece"); |
321 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 321 | snd_soc_dapm_enable_pin_unlocked(dapm, "Earpiece"); |
322 | snd_soc_dapm_disable_pin(dapm, "AGCIN"); | 322 | snd_soc_dapm_enable_pin_unlocked(dapm, "Microphone"); |
323 | snd_soc_dapm_sync(dapm); | 323 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
324 | snd_soc_dapm_disable_pin_unlocked(dapm, "AGCIN"); | ||
325 | |||
326 | snd_soc_dapm_sync_unlocked(dapm); | ||
327 | |||
328 | snd_soc_dapm_mutex_unlock(codec); | ||
324 | } | 329 | } |
325 | 330 | ||
326 | /* Line discipline .hangup() */ | 331 | /* Line discipline .hangup() */ |
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 3fde9e402710..fd4d9c809e50 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c | |||
@@ -68,26 +68,30 @@ static void n810_ext_control(struct snd_soc_dapm_context *dapm) | |||
68 | break; | 68 | break; |
69 | } | 69 | } |
70 | 70 | ||
71 | snd_soc_dapm_mutex_lock(dapm); | ||
72 | |||
71 | if (n810_spk_func) | 73 | if (n810_spk_func) |
72 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 74 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
73 | else | 75 | else |
74 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 76 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
75 | 77 | ||
76 | if (hp) | 78 | if (hp) |
77 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 79 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
78 | else | 80 | else |
79 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 81 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
80 | if (line1l) | 82 | if (line1l) |
81 | snd_soc_dapm_enable_pin(dapm, "LINE1L"); | 83 | snd_soc_dapm_enable_pin_unlocked(dapm, "LINE1L"); |
82 | else | 84 | else |
83 | snd_soc_dapm_disable_pin(dapm, "LINE1L"); | 85 | snd_soc_dapm_disable_pin_unlocked(dapm, "LINE1L"); |
84 | 86 | ||
85 | if (n810_dmic_func) | 87 | if (n810_dmic_func) |
86 | snd_soc_dapm_enable_pin(dapm, "DMic"); | 88 | snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); |
87 | else | 89 | else |
88 | snd_soc_dapm_disable_pin(dapm, "DMic"); | 90 | snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); |
91 | |||
92 | snd_soc_dapm_sync_unlocked(dapm); | ||
89 | 93 | ||
90 | snd_soc_dapm_sync(dapm); | 94 | snd_soc_dapm_mutex_unlock(dapm); |
91 | } | 95 | } |
92 | 96 | ||
93 | static int n810_startup(struct snd_pcm_substream *substream) | 97 | static int n810_startup(struct snd_pcm_substream *substream) |
@@ -305,7 +309,9 @@ static int __init n810_soc_init(void) | |||
305 | int err; | 309 | int err; |
306 | struct device *dev; | 310 | struct device *dev; |
307 | 311 | ||
308 | if (!(machine_is_nokia_n810() || machine_is_nokia_n810_wimax())) | 312 | if (!of_have_populated_dt() || |
313 | (!of_machine_is_compatible("nokia,n810") && | ||
314 | !of_machine_is_compatible("nokia,n810-wimax"))) | ||
309 | return -ENODEV; | 315 | return -ENODEV; |
310 | 316 | ||
311 | n810_snd_device = platform_device_alloc("soc-audio", -1); | 317 | n810_snd_device = platform_device_alloc("soc-audio", -1); |
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c index 611179c3bca4..7fb3d4b10370 100644 --- a/sound/soc/omap/rx51.c +++ b/sound/soc/omap/rx51.c | |||
@@ -74,26 +74,30 @@ static void rx51_ext_control(struct snd_soc_dapm_context *dapm) | |||
74 | break; | 74 | break; |
75 | } | 75 | } |
76 | 76 | ||
77 | snd_soc_dapm_mutex_lock(dapm); | ||
78 | |||
77 | if (rx51_spk_func) | 79 | if (rx51_spk_func) |
78 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 80 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
79 | else | 81 | else |
80 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 82 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
81 | if (rx51_dmic_func) | 83 | if (rx51_dmic_func) |
82 | snd_soc_dapm_enable_pin(dapm, "DMic"); | 84 | snd_soc_dapm_enable_pin_unlocked(dapm, "DMic"); |
83 | else | 85 | else |
84 | snd_soc_dapm_disable_pin(dapm, "DMic"); | 86 | snd_soc_dapm_disable_pin_unlocked(dapm, "DMic"); |
85 | if (hp) | 87 | if (hp) |
86 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 88 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
87 | else | 89 | else |
88 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 90 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
89 | if (hs) | 91 | if (hs) |
90 | snd_soc_dapm_enable_pin(dapm, "HS Mic"); | 92 | snd_soc_dapm_enable_pin_unlocked(dapm, "HS Mic"); |
91 | else | 93 | else |
92 | snd_soc_dapm_disable_pin(dapm, "HS Mic"); | 94 | snd_soc_dapm_disable_pin_unlocked(dapm, "HS Mic"); |
93 | 95 | ||
94 | gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); | 96 | gpio_set_value(RX51_TVOUT_SEL_GPIO, tvout); |
95 | 97 | ||
96 | snd_soc_dapm_sync(dapm); | 98 | snd_soc_dapm_sync_unlocked(dapm); |
99 | |||
100 | snd_soc_dapm_mutex_unlock(dapm); | ||
97 | } | 101 | } |
98 | 102 | ||
99 | static int rx51_startup(struct snd_pcm_substream *substream) | 103 | static int rx51_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/pxa/corgi.c b/sound/soc/pxa/corgi.c index 916ff63d85d0..5a88136aa800 100644 --- a/sound/soc/pxa/corgi.c +++ b/sound/soc/pxa/corgi.c | |||
@@ -47,51 +47,55 @@ static int corgi_spk_func; | |||
47 | 47 | ||
48 | static void corgi_ext_control(struct snd_soc_dapm_context *dapm) | 48 | static void corgi_ext_control(struct snd_soc_dapm_context *dapm) |
49 | { | 49 | { |
50 | snd_soc_dapm_mutex_lock(dapm); | ||
51 | |||
50 | /* set up jack connection */ | 52 | /* set up jack connection */ |
51 | switch (corgi_jack_func) { | 53 | switch (corgi_jack_func) { |
52 | case CORGI_HP: | 54 | case CORGI_HP: |
53 | /* set = unmute headphone */ | 55 | /* set = unmute headphone */ |
54 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); | 56 | gpio_set_value(CORGI_GPIO_MUTE_L, 1); |
55 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 57 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
56 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 58 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
57 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 59 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
58 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 60 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
59 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 61 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
60 | break; | 62 | break; |
61 | case CORGI_MIC: | 63 | case CORGI_MIC: |
62 | /* reset = mute headphone */ | 64 | /* reset = mute headphone */ |
63 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 65 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
64 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); | 66 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
65 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 67 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
66 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 68 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
67 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 69 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
68 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 70 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
69 | break; | 71 | break; |
70 | case CORGI_LINE: | 72 | case CORGI_LINE: |
71 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 73 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
72 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); | 74 | gpio_set_value(CORGI_GPIO_MUTE_R, 0); |
73 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 75 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
74 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 76 | snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); |
75 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 77 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
76 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 78 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
77 | break; | 79 | break; |
78 | case CORGI_HEADSET: | 80 | case CORGI_HEADSET: |
79 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); | 81 | gpio_set_value(CORGI_GPIO_MUTE_L, 0); |
80 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); | 82 | gpio_set_value(CORGI_GPIO_MUTE_R, 1); |
81 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 83 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
82 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 84 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
83 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 85 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
84 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 86 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); |
85 | break; | 87 | break; |
86 | } | 88 | } |
87 | 89 | ||
88 | if (corgi_spk_func == CORGI_SPK_ON) | 90 | if (corgi_spk_func == CORGI_SPK_ON) |
89 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 91 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
90 | else | 92 | else |
91 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 93 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
92 | 94 | ||
93 | /* signal a DAPM event */ | 95 | /* signal a DAPM event */ |
94 | snd_soc_dapm_sync(dapm); | 96 | snd_soc_dapm_sync_unlocked(dapm); |
97 | |||
98 | snd_soc_dapm_mutex_unlock(dapm); | ||
95 | } | 99 | } |
96 | 100 | ||
97 | static int corgi_startup(struct snd_pcm_substream *substream) | 101 | static int corgi_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/pxa/magician.c b/sound/soc/pxa/magician.c index aeb08f5f3e1c..41ab6678b65d 100644 --- a/sound/soc/pxa/magician.c +++ b/sound/soc/pxa/magician.c | |||
@@ -45,27 +45,31 @@ static void magician_ext_control(struct snd_soc_codec *codec) | |||
45 | { | 45 | { |
46 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 46 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
47 | 47 | ||
48 | snd_soc_dapm_mutex_lock(dapm); | ||
49 | |||
48 | if (magician_spk_switch) | 50 | if (magician_spk_switch) |
49 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 51 | snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); |
50 | else | 52 | else |
51 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 53 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
52 | if (magician_hp_switch) | 54 | if (magician_hp_switch) |
53 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 55 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
54 | else | 56 | else |
55 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 57 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
56 | 58 | ||
57 | switch (magician_in_sel) { | 59 | switch (magician_in_sel) { |
58 | case MAGICIAN_MIC: | 60 | case MAGICIAN_MIC: |
59 | snd_soc_dapm_disable_pin(dapm, "Headset Mic"); | 61 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Mic"); |
60 | snd_soc_dapm_enable_pin(dapm, "Call Mic"); | 62 | snd_soc_dapm_enable_pin_unlocked(dapm, "Call Mic"); |
61 | break; | 63 | break; |
62 | case MAGICIAN_MIC_EXT: | 64 | case MAGICIAN_MIC_EXT: |
63 | snd_soc_dapm_disable_pin(dapm, "Call Mic"); | 65 | snd_soc_dapm_disable_pin_unlocked(dapm, "Call Mic"); |
64 | snd_soc_dapm_enable_pin(dapm, "Headset Mic"); | 66 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Mic"); |
65 | break; | 67 | break; |
66 | } | 68 | } |
67 | 69 | ||
68 | snd_soc_dapm_sync(dapm); | 70 | snd_soc_dapm_sync_unlocked(dapm); |
71 | |||
72 | snd_soc_dapm_mutex_unlock(dapm); | ||
69 | } | 73 | } |
70 | 74 | ||
71 | static int magician_startup(struct snd_pcm_substream *substream) | 75 | static int magician_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index d1b6bf9c8583..1373b017a951 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c | |||
@@ -46,61 +46,66 @@ static int spitz_mic_gpio; | |||
46 | 46 | ||
47 | static void spitz_ext_control(struct snd_soc_dapm_context *dapm) | 47 | static void spitz_ext_control(struct snd_soc_dapm_context *dapm) |
48 | { | 48 | { |
49 | snd_soc_dapm_mutex_lock(dapm); | ||
50 | |||
49 | if (spitz_spk_func == SPITZ_SPK_ON) | 51 | if (spitz_spk_func == SPITZ_SPK_ON) |
50 | snd_soc_dapm_enable_pin(dapm, "Ext Spk"); | 52 | snd_soc_dapm_enable_pin_unlocked(dapm, "Ext Spk"); |
51 | else | 53 | else |
52 | snd_soc_dapm_disable_pin(dapm, "Ext Spk"); | 54 | snd_soc_dapm_disable_pin_unlocked(dapm, "Ext Spk"); |
53 | 55 | ||
54 | /* set up jack connection */ | 56 | /* set up jack connection */ |
55 | switch (spitz_jack_func) { | 57 | switch (spitz_jack_func) { |
56 | case SPITZ_HP: | 58 | case SPITZ_HP: |
57 | /* enable and unmute hp jack, disable mic bias */ | 59 | /* enable and unmute hp jack, disable mic bias */ |
58 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 60 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
59 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 61 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
60 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 62 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
61 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 63 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
62 | gpio_set_value(SPITZ_GPIO_MUTE_L, 1); | 64 | gpio_set_value(SPITZ_GPIO_MUTE_L, 1); |
63 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); | 65 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); |
64 | break; | 66 | break; |
65 | case SPITZ_MIC: | 67 | case SPITZ_MIC: |
66 | /* enable mic jack and bias, mute hp */ | 68 | /* enable mic jack and bias, mute hp */ |
67 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 69 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
68 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 70 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
69 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 71 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
70 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 72 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
71 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 73 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
72 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); | 74 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
73 | break; | 75 | break; |
74 | case SPITZ_LINE: | 76 | case SPITZ_LINE: |
75 | /* enable line jack, disable mic bias and mute hp */ | 77 | /* enable line jack, disable mic bias and mute hp */ |
76 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 78 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
77 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 79 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
78 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 80 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
79 | snd_soc_dapm_enable_pin(dapm, "Line Jack"); | 81 | snd_soc_dapm_enable_pin_unlocked(dapm, "Line Jack"); |
80 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 82 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
81 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); | 83 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
82 | break; | 84 | break; |
83 | case SPITZ_HEADSET: | 85 | case SPITZ_HEADSET: |
84 | /* enable and unmute headset jack enable mic bias, mute L hp */ | 86 | /* enable and unmute headset jack enable mic bias, mute L hp */ |
85 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 87 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
86 | snd_soc_dapm_enable_pin(dapm, "Mic Jack"); | 88 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic Jack"); |
87 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 89 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
88 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 90 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); |
89 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 91 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
90 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); | 92 | gpio_set_value(SPITZ_GPIO_MUTE_R, 1); |
91 | break; | 93 | break; |
92 | case SPITZ_HP_OFF: | 94 | case SPITZ_HP_OFF: |
93 | 95 | ||
94 | /* jack removed, everything off */ | 96 | /* jack removed, everything off */ |
95 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 97 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
96 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 98 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
97 | snd_soc_dapm_disable_pin(dapm, "Mic Jack"); | 99 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Jack"); |
98 | snd_soc_dapm_disable_pin(dapm, "Line Jack"); | 100 | snd_soc_dapm_disable_pin_unlocked(dapm, "Line Jack"); |
99 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); | 101 | gpio_set_value(SPITZ_GPIO_MUTE_L, 0); |
100 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); | 102 | gpio_set_value(SPITZ_GPIO_MUTE_R, 0); |
101 | break; | 103 | break; |
102 | } | 104 | } |
103 | snd_soc_dapm_sync(dapm); | 105 | |
106 | snd_soc_dapm_sync_unlocked(dapm); | ||
107 | |||
108 | snd_soc_dapm_mutex_unlock(dapm); | ||
104 | } | 109 | } |
105 | 110 | ||
106 | static int spitz_startup(struct snd_pcm_substream *substream) | 111 | static int spitz_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c index d6f38d7ecc1c..cead1658d10a 100644 --- a/sound/soc/pxa/tosa.c +++ b/sound/soc/pxa/tosa.c | |||
@@ -48,31 +48,35 @@ static void tosa_ext_control(struct snd_soc_codec *codec) | |||
48 | { | 48 | { |
49 | struct snd_soc_dapm_context *dapm = &codec->dapm; | 49 | struct snd_soc_dapm_context *dapm = &codec->dapm; |
50 | 50 | ||
51 | snd_soc_dapm_mutex_lock(dapm); | ||
52 | |||
51 | /* set up jack connection */ | 53 | /* set up jack connection */ |
52 | switch (tosa_jack_func) { | 54 | switch (tosa_jack_func) { |
53 | case TOSA_HP: | 55 | case TOSA_HP: |
54 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); | 56 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)"); |
55 | snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); | 57 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headphone Jack"); |
56 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 58 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
57 | break; | 59 | break; |
58 | case TOSA_MIC_INT: | 60 | case TOSA_MIC_INT: |
59 | snd_soc_dapm_enable_pin(dapm, "Mic (Internal)"); | 61 | snd_soc_dapm_enable_pin_unlocked(dapm, "Mic (Internal)"); |
60 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 62 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
61 | snd_soc_dapm_disable_pin(dapm, "Headset Jack"); | 63 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headset Jack"); |
62 | break; | 64 | break; |
63 | case TOSA_HEADSET: | 65 | case TOSA_HEADSET: |
64 | snd_soc_dapm_disable_pin(dapm, "Mic (Internal)"); | 66 | snd_soc_dapm_disable_pin_unlocked(dapm, "Mic (Internal)"); |
65 | snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); | 67 | snd_soc_dapm_disable_pin_unlocked(dapm, "Headphone Jack"); |
66 | snd_soc_dapm_enable_pin(dapm, "Headset Jack"); | 68 | snd_soc_dapm_enable_pin_unlocked(dapm, "Headset Jack"); |
67 | break; | 69 | break; |
68 | } | 70 | } |
69 | 71 | ||
70 | if (tosa_spk_func == TOSA_SPK_ON) | 72 | if (tosa_spk_func == TOSA_SPK_ON) |
71 | snd_soc_dapm_enable_pin(dapm, "Speaker"); | 73 | snd_soc_dapm_enable_pin_unlocked(dapm, "Speaker"); |
72 | else | 74 | else |
73 | snd_soc_dapm_disable_pin(dapm, "Speaker"); | 75 | snd_soc_dapm_disable_pin_unlocked(dapm, "Speaker"); |
76 | |||
77 | snd_soc_dapm_sync_unlocked(dapm); | ||
74 | 78 | ||
75 | snd_soc_dapm_sync(dapm); | 79 | snd_soc_dapm_mutex_unlock(dapm); |
76 | } | 80 | } |
77 | 81 | ||
78 | static int tosa_startup(struct snd_pcm_substream *substream) | 82 | static int tosa_startup(struct snd_pcm_substream *substream) |
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig index 454f41cfc828..f2e289180e46 100644 --- a/sound/soc/samsung/Kconfig +++ b/sound/soc/samsung/Kconfig | |||
@@ -59,7 +59,7 @@ config SND_SOC_SAMSUNG_JIVE_WM8750 | |||
59 | select SND_SOC_WM8750 | 59 | select SND_SOC_WM8750 |
60 | select SND_S3C2412_SOC_I2S | 60 | select SND_S3C2412_SOC_I2S |
61 | help | 61 | help |
62 | Sat Y if you want to add support for SoC audio on the Jive. | 62 | Say Y if you want to add support for SoC audio on the Jive. |
63 | 63 | ||
64 | config SND_SOC_SAMSUNG_SMDK_WM8580 | 64 | config SND_SOC_SAMSUNG_SMDK_WM8580 |
65 | tristate "SoC I2S Audio support for WM8580 on SMDK" | 65 | tristate "SoC I2S Audio support for WM8580 on SMDK" |
@@ -117,7 +117,7 @@ config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 | |||
117 | tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" | 117 | tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" |
118 | depends on SND_SOC_SAMSUNG && ARCH_S3C24XX | 118 | depends on SND_SOC_SAMSUNG && ARCH_S3C24XX |
119 | select SND_S3C24XX_I2S | 119 | select SND_S3C24XX_I2S |
120 | select SND_SOC_TLV320AIC23 | 120 | select SND_SOC_TLV320AIC23_I2C |
121 | select SND_SOC_SAMSUNG_SIMTEC | 121 | select SND_SOC_SAMSUNG_SIMTEC |
122 | 122 | ||
123 | config SND_SOC_SAMSUNG_SIMTEC_HERMES | 123 | config SND_SOC_SAMSUNG_SIMTEC_HERMES |
@@ -145,11 +145,11 @@ config SND_SOC_SAMSUNG_RX1950_UDA1380 | |||
145 | 145 | ||
146 | config SND_SOC_SAMSUNG_SMDK_WM9713 | 146 | config SND_SOC_SAMSUNG_SMDK_WM9713 |
147 | tristate "SoC AC97 Audio support for SMDK with WM9713" | 147 | tristate "SoC AC97 Audio support for SMDK with WM9713" |
148 | depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 || MACH_SMDKV310 || MACH_SMDKC210) | 148 | depends on SND_SOC_SAMSUNG && (MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110) |
149 | select SND_SOC_WM9713 | 149 | select SND_SOC_WM9713 |
150 | select SND_SAMSUNG_AC97 | 150 | select SND_SAMSUNG_AC97 |
151 | help | 151 | help |
152 | Sat Y if you want to add support for SoC audio on the SMDK. | 152 | Say Y if you want to add support for SoC audio on the SMDK. |
153 | 153 | ||
154 | config SND_SOC_SMARTQ | 154 | config SND_SOC_SMARTQ |
155 | tristate "SoC I2S Audio support for SmartQ board" | 155 | tristate "SoC I2S Audio support for SmartQ board" |
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 0ff492df7929..7d0051ced838 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | snd-soc-rcar-objs := core.o gen.o scu.o adg.o ssi.o | 1 | snd-soc-rcar-objs := core.o gen.o src.o adg.o ssi.o |
2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file | 2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o \ No newline at end of file |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index a53235c4d1b0..953f1cce982d 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
@@ -25,15 +25,165 @@ struct rsnd_adg { | |||
25 | }; | 25 | }; |
26 | 26 | ||
27 | #define for_each_rsnd_clk(pos, adg, i) \ | 27 | #define for_each_rsnd_clk(pos, adg, i) \ |
28 | for (i = 0, (pos) = adg->clk[i]; \ | 28 | for (i = 0; \ |
29 | i < CLKMAX; \ | 29 | (i < CLKMAX) && \ |
30 | i++, (pos) = adg->clk[i]) | 30 | ((pos) = adg->clk[i]); \ |
31 | i++) | ||
31 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) | 32 | #define rsnd_priv_to_adg(priv) ((struct rsnd_adg *)(priv)->adg) |
32 | 33 | ||
33 | static int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, | 34 | |
34 | struct rsnd_mod *mod, | 35 | static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) |
35 | unsigned int src_rate, | 36 | { |
36 | unsigned int dst_rate) | 37 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); |
38 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
39 | int id = rsnd_mod_id(mod); | ||
40 | int ws = id; | ||
41 | |||
42 | if (rsnd_ssi_is_pin_sharing(rsnd_ssi_mod_get(priv, id))) { | ||
43 | switch (id) { | ||
44 | case 1: | ||
45 | case 2: | ||
46 | ws = 0; | ||
47 | break; | ||
48 | case 4: | ||
49 | ws = 3; | ||
50 | break; | ||
51 | case 8: | ||
52 | ws = 7; | ||
53 | break; | ||
54 | } | ||
55 | } | ||
56 | |||
57 | return (0x6 + ws) << 8; | ||
58 | } | ||
59 | |||
60 | static int rsnd_adg_set_src_timsel_gen2(struct rsnd_dai *rdai, | ||
61 | struct rsnd_mod *mod, | ||
62 | struct rsnd_dai_stream *io, | ||
63 | u32 timsel) | ||
64 | { | ||
65 | int is_play = rsnd_dai_is_play(rdai, io); | ||
66 | int id = rsnd_mod_id(mod); | ||
67 | int shift = (id % 2) ? 16 : 0; | ||
68 | u32 mask, ws; | ||
69 | u32 in, out; | ||
70 | |||
71 | ws = rsnd_adg_ssi_ws_timing_gen2(io); | ||
72 | |||
73 | in = (is_play) ? timsel : ws; | ||
74 | out = (is_play) ? ws : timsel; | ||
75 | |||
76 | in = in << shift; | ||
77 | out = out << shift; | ||
78 | mask = 0xffff << shift; | ||
79 | |||
80 | switch (id / 2) { | ||
81 | case 0: | ||
82 | rsnd_mod_bset(mod, SRCIN_TIMSEL0, mask, in); | ||
83 | rsnd_mod_bset(mod, SRCOUT_TIMSEL0, mask, out); | ||
84 | break; | ||
85 | case 1: | ||
86 | rsnd_mod_bset(mod, SRCIN_TIMSEL1, mask, in); | ||
87 | rsnd_mod_bset(mod, SRCOUT_TIMSEL1, mask, out); | ||
88 | break; | ||
89 | case 2: | ||
90 | rsnd_mod_bset(mod, SRCIN_TIMSEL2, mask, in); | ||
91 | rsnd_mod_bset(mod, SRCOUT_TIMSEL2, mask, out); | ||
92 | break; | ||
93 | case 3: | ||
94 | rsnd_mod_bset(mod, SRCIN_TIMSEL3, mask, in); | ||
95 | rsnd_mod_bset(mod, SRCOUT_TIMSEL3, mask, out); | ||
96 | break; | ||
97 | case 4: | ||
98 | rsnd_mod_bset(mod, SRCIN_TIMSEL4, mask, in); | ||
99 | rsnd_mod_bset(mod, SRCOUT_TIMSEL4, mask, out); | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, | ||
107 | struct rsnd_dai *rdai, | ||
108 | struct rsnd_dai_stream *io, | ||
109 | unsigned int src_rate, | ||
110 | unsigned int dst_rate) | ||
111 | { | ||
112 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
113 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | ||
114 | struct device *dev = rsnd_priv_to_dev(priv); | ||
115 | int idx, sel, div, step, ret; | ||
116 | u32 val, en; | ||
117 | unsigned int min, diff; | ||
118 | unsigned int sel_rate [] = { | ||
119 | clk_get_rate(adg->clk[CLKA]), /* 0000: CLKA */ | ||
120 | clk_get_rate(adg->clk[CLKB]), /* 0001: CLKB */ | ||
121 | clk_get_rate(adg->clk[CLKC]), /* 0010: CLKC */ | ||
122 | adg->rbga_rate_for_441khz_div_6,/* 0011: RBGA */ | ||
123 | adg->rbgb_rate_for_48khz_div_6, /* 0100: RBGB */ | ||
124 | }; | ||
125 | |||
126 | min = ~0; | ||
127 | val = 0; | ||
128 | en = 0; | ||
129 | for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { | ||
130 | idx = 0; | ||
131 | step = 2; | ||
132 | |||
133 | if (!sel_rate[sel]) | ||
134 | continue; | ||
135 | |||
136 | for (div = 2; div <= 98304; div += step) { | ||
137 | diff = abs(src_rate - sel_rate[sel] / div); | ||
138 | if (min > diff) { | ||
139 | val = (sel << 8) | idx; | ||
140 | min = diff; | ||
141 | en = 1 << (sel + 1); /* fixme */ | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * step of 0_0000 / 0_0001 / 0_1101 | ||
146 | * are out of order | ||
147 | */ | ||
148 | if ((idx > 2) && (idx % 2)) | ||
149 | step *= 2; | ||
150 | if (idx == 0x1c) { | ||
151 | div += step; | ||
152 | step *= 2; | ||
153 | } | ||
154 | idx++; | ||
155 | } | ||
156 | } | ||
157 | |||
158 | if (min == ~0) { | ||
159 | dev_err(dev, "no Input clock\n"); | ||
160 | return -EIO; | ||
161 | } | ||
162 | |||
163 | ret = rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val); | ||
164 | if (ret < 0) { | ||
165 | dev_err(dev, "timsel error\n"); | ||
166 | return ret; | ||
167 | } | ||
168 | |||
169 | rsnd_mod_bset(mod, DIV_EN, en, en); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, | ||
175 | struct rsnd_dai *rdai, | ||
176 | struct rsnd_dai_stream *io) | ||
177 | { | ||
178 | u32 val = rsnd_adg_ssi_ws_timing_gen2(io); | ||
179 | |||
180 | return rsnd_adg_set_src_timsel_gen2(rdai, mod, io, val); | ||
181 | } | ||
182 | |||
183 | int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, | ||
184 | struct rsnd_mod *mod, | ||
185 | unsigned int src_rate, | ||
186 | unsigned int dst_rate) | ||
37 | { | 187 | { |
38 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | 188 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
39 | struct device *dev = rsnd_priv_to_dev(priv); | 189 | struct device *dev = rsnd_priv_to_dev(priv); |
@@ -91,18 +241,6 @@ find_rate: | |||
91 | return 0; | 241 | return 0; |
92 | } | 242 | } |
93 | 243 | ||
94 | int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, | ||
95 | struct rsnd_mod *mod, | ||
96 | unsigned int src_rate, | ||
97 | unsigned int dst_rate) | ||
98 | { | ||
99 | if (rsnd_is_gen1(priv)) | ||
100 | return rsnd_adg_set_convert_clk_gen1(priv, mod, | ||
101 | src_rate, dst_rate); | ||
102 | |||
103 | return -EINVAL; | ||
104 | } | ||
105 | |||
106 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) | 244 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *mod, u32 val) |
107 | { | 245 | { |
108 | int id = rsnd_mod_id(mod); | 246 | int id = rsnd_mod_id(mod); |
@@ -254,13 +392,13 @@ static void rsnd_adg_ssi_clk_init(struct rsnd_priv *priv, struct rsnd_adg *adg) | |||
254 | } | 392 | } |
255 | 393 | ||
256 | int rsnd_adg_probe(struct platform_device *pdev, | 394 | int rsnd_adg_probe(struct platform_device *pdev, |
257 | struct rcar_snd_info *info, | ||
258 | struct rsnd_priv *priv) | 395 | struct rsnd_priv *priv) |
259 | { | 396 | { |
260 | struct rsnd_adg *adg; | 397 | struct rsnd_adg *adg; |
261 | struct device *dev = rsnd_priv_to_dev(priv); | 398 | struct device *dev = rsnd_priv_to_dev(priv); |
262 | struct clk *clk; | 399 | struct clk *clk, *clk_orig; |
263 | int i; | 400 | int i; |
401 | bool use_old_style = false; | ||
264 | 402 | ||
265 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); | 403 | adg = devm_kzalloc(dev, sizeof(*adg), GFP_KERNEL); |
266 | if (!adg) { | 404 | if (!adg) { |
@@ -268,10 +406,39 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
268 | return -ENOMEM; | 406 | return -ENOMEM; |
269 | } | 407 | } |
270 | 408 | ||
271 | adg->clk[CLKA] = clk_get(NULL, "audio_clk_a"); | 409 | clk_orig = devm_clk_get(dev, NULL); |
272 | adg->clk[CLKB] = clk_get(NULL, "audio_clk_b"); | 410 | adg->clk[CLKA] = devm_clk_get(dev, "clk_a"); |
273 | adg->clk[CLKC] = clk_get(NULL, "audio_clk_c"); | 411 | adg->clk[CLKB] = devm_clk_get(dev, "clk_b"); |
274 | adg->clk[CLKI] = clk_get(NULL, "audio_clk_internal"); | 412 | adg->clk[CLKC] = devm_clk_get(dev, "clk_c"); |
413 | adg->clk[CLKI] = devm_clk_get(dev, "clk_i"); | ||
414 | |||
415 | /* | ||
416 | * It request device dependent audio clock. | ||
417 | * But above all clks will indicate rsnd module clock | ||
418 | * if platform doesn't it | ||
419 | */ | ||
420 | for_each_rsnd_clk(clk, adg, i) { | ||
421 | if (clk_orig == clk) { | ||
422 | dev_warn(dev, | ||
423 | "doesn't have device dependent clock, use independent clock\n"); | ||
424 | use_old_style = true; | ||
425 | break; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | /* | ||
430 | * note: | ||
431 | * these exist in order to keep compatible with | ||
432 | * platform which has device independent audio clock, | ||
433 | * but will be removed soon | ||
434 | */ | ||
435 | if (use_old_style) { | ||
436 | adg->clk[CLKA] = devm_clk_get(NULL, "audio_clk_a"); | ||
437 | adg->clk[CLKB] = devm_clk_get(NULL, "audio_clk_b"); | ||
438 | adg->clk[CLKC] = devm_clk_get(NULL, "audio_clk_c"); | ||
439 | adg->clk[CLKI] = devm_clk_get(NULL, "audio_clk_internal"); | ||
440 | } | ||
441 | |||
275 | for_each_rsnd_clk(clk, adg, i) { | 442 | for_each_rsnd_clk(clk, adg, i) { |
276 | if (IS_ERR(clk)) { | 443 | if (IS_ERR(clk)) { |
277 | dev_err(dev, "Audio clock failed\n"); | 444 | dev_err(dev, "Audio clock failed\n"); |
@@ -287,14 +454,3 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
287 | 454 | ||
288 | return 0; | 455 | return 0; |
289 | } | 456 | } |
290 | |||
291 | void rsnd_adg_remove(struct platform_device *pdev, | ||
292 | struct rsnd_priv *priv) | ||
293 | { | ||
294 | struct rsnd_adg *adg = priv->adg; | ||
295 | struct clk *clk; | ||
296 | int i; | ||
297 | |||
298 | for_each_rsnd_clk(clk, adg, i) | ||
299 | clk_put(clk); | ||
300 | } | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 743de5e3b1e1..6a1b45df8101 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
@@ -73,13 +73,13 @@ | |||
73 | * | +- ssi[2] | 73 | * | +- ssi[2] |
74 | * | ... | 74 | * | ... |
75 | * | | 75 | * | |
76 | * | ** these control scu | 76 | * | ** these control src |
77 | * | | 77 | * | |
78 | * +- scu | 78 | * +- src |
79 | * | | 79 | * | |
80 | * +- scu[0] | 80 | * +- src[0] |
81 | * +- scu[1] | 81 | * +- src[1] |
82 | * +- scu[2] | 82 | * +- src[2] |
83 | * ... | 83 | * ... |
84 | * | 84 | * |
85 | * | 85 | * |
@@ -107,6 +107,11 @@ | |||
107 | (!(priv->info->func) ? 0 : \ | 107 | (!(priv->info->func) ? 0 : \ |
108 | priv->info->func(param)) | 108 | priv->info->func(param)) |
109 | 109 | ||
110 | #define rsnd_is_enable_path(io, name) \ | ||
111 | ((io)->info ? (io)->info->name : NULL) | ||
112 | #define rsnd_info_id(priv, io, name) \ | ||
113 | ((io)->info->name - priv->info->name##_info) | ||
114 | |||
110 | /* | 115 | /* |
111 | * rsnd_mod functions | 116 | * rsnd_mod functions |
112 | */ | 117 | */ |
@@ -121,17 +126,19 @@ char *rsnd_mod_name(struct rsnd_mod *mod) | |||
121 | void rsnd_mod_init(struct rsnd_priv *priv, | 126 | void rsnd_mod_init(struct rsnd_priv *priv, |
122 | struct rsnd_mod *mod, | 127 | struct rsnd_mod *mod, |
123 | struct rsnd_mod_ops *ops, | 128 | struct rsnd_mod_ops *ops, |
129 | enum rsnd_mod_type type, | ||
124 | int id) | 130 | int id) |
125 | { | 131 | { |
126 | mod->priv = priv; | 132 | mod->priv = priv; |
127 | mod->id = id; | 133 | mod->id = id; |
128 | mod->ops = ops; | 134 | mod->ops = ops; |
129 | INIT_LIST_HEAD(&mod->list); | 135 | mod->type = type; |
130 | } | 136 | } |
131 | 137 | ||
132 | /* | 138 | /* |
133 | * rsnd_dma functions | 139 | * rsnd_dma functions |
134 | */ | 140 | */ |
141 | static void __rsnd_dma_start(struct rsnd_dma *dma); | ||
135 | static void rsnd_dma_continue(struct rsnd_dma *dma) | 142 | static void rsnd_dma_continue(struct rsnd_dma *dma) |
136 | { | 143 | { |
137 | /* push next A or B plane */ | 144 | /* push next A or B plane */ |
@@ -142,8 +149,9 @@ static void rsnd_dma_continue(struct rsnd_dma *dma) | |||
142 | void rsnd_dma_start(struct rsnd_dma *dma) | 149 | void rsnd_dma_start(struct rsnd_dma *dma) |
143 | { | 150 | { |
144 | /* push both A and B plane*/ | 151 | /* push both A and B plane*/ |
152 | dma->offset = 0; | ||
145 | dma->submit_loop = 2; | 153 | dma->submit_loop = 2; |
146 | schedule_work(&dma->work); | 154 | __rsnd_dma_start(dma); |
147 | } | 155 | } |
148 | 156 | ||
149 | void rsnd_dma_stop(struct rsnd_dma *dma) | 157 | void rsnd_dma_stop(struct rsnd_dma *dma) |
@@ -156,12 +164,26 @@ void rsnd_dma_stop(struct rsnd_dma *dma) | |||
156 | static void rsnd_dma_complete(void *data) | 164 | static void rsnd_dma_complete(void *data) |
157 | { | 165 | { |
158 | struct rsnd_dma *dma = (struct rsnd_dma *)data; | 166 | struct rsnd_dma *dma = (struct rsnd_dma *)data; |
159 | struct rsnd_priv *priv = dma->priv; | 167 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
168 | struct rsnd_priv *priv = rsnd_mod_to_priv(rsnd_dma_to_mod(dma)); | ||
169 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
160 | unsigned long flags; | 170 | unsigned long flags; |
161 | 171 | ||
162 | rsnd_lock(priv, flags); | 172 | rsnd_lock(priv, flags); |
163 | 173 | ||
164 | dma->complete(dma); | 174 | /* |
175 | * Renesas sound Gen1 needs 1 DMAC, | ||
176 | * Gen2 needs 2 DMAC. | ||
177 | * In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri. | ||
178 | * But, Audio-DMAC-peri-peri doesn't have interrupt, | ||
179 | * and this driver is assuming that here. | ||
180 | * | ||
181 | * If Audio-DMAC-peri-peri has interrpt, | ||
182 | * rsnd_dai_pointer_update() will be called twice, | ||
183 | * ant it will breaks io->byte_pos | ||
184 | */ | ||
185 | |||
186 | rsnd_dai_pointer_update(io, io->byte_per_period); | ||
165 | 187 | ||
166 | if (dma->submit_loop) | 188 | if (dma->submit_loop) |
167 | rsnd_dma_continue(dma); | 189 | rsnd_dma_continue(dma); |
@@ -169,20 +191,23 @@ static void rsnd_dma_complete(void *data) | |||
169 | rsnd_unlock(priv, flags); | 191 | rsnd_unlock(priv, flags); |
170 | } | 192 | } |
171 | 193 | ||
172 | static void rsnd_dma_do_work(struct work_struct *work) | 194 | static void __rsnd_dma_start(struct rsnd_dma *dma) |
173 | { | 195 | { |
174 | struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); | 196 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); |
175 | struct rsnd_priv *priv = dma->priv; | 197 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
198 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); | ||
199 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
176 | struct device *dev = rsnd_priv_to_dev(priv); | 200 | struct device *dev = rsnd_priv_to_dev(priv); |
177 | struct dma_async_tx_descriptor *desc; | 201 | struct dma_async_tx_descriptor *desc; |
178 | dma_addr_t buf; | 202 | dma_addr_t buf; |
179 | size_t len; | 203 | size_t len = io->byte_per_period; |
180 | int i; | 204 | int i; |
181 | 205 | ||
182 | for (i = 0; i < dma->submit_loop; i++) { | 206 | for (i = 0; i < dma->submit_loop; i++) { |
183 | 207 | ||
184 | if (dma->inquiry(dma, &buf, &len) < 0) | 208 | buf = runtime->dma_addr + |
185 | return; | 209 | rsnd_dai_pointer_offset(io, dma->offset + len); |
210 | dma->offset = len; | ||
186 | 211 | ||
187 | desc = dmaengine_prep_slave_single( | 212 | desc = dmaengine_prep_slave_single( |
188 | dma->chan, buf, len, dma->dir, | 213 | dma->chan, buf, len, dma->dir, |
@@ -204,16 +229,20 @@ static void rsnd_dma_do_work(struct work_struct *work) | |||
204 | } | 229 | } |
205 | } | 230 | } |
206 | 231 | ||
232 | static void rsnd_dma_do_work(struct work_struct *work) | ||
233 | { | ||
234 | struct rsnd_dma *dma = container_of(work, struct rsnd_dma, work); | ||
235 | |||
236 | __rsnd_dma_start(dma); | ||
237 | } | ||
238 | |||
207 | int rsnd_dma_available(struct rsnd_dma *dma) | 239 | int rsnd_dma_available(struct rsnd_dma *dma) |
208 | { | 240 | { |
209 | return !!dma->chan; | 241 | return !!dma->chan; |
210 | } | 242 | } |
211 | 243 | ||
212 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | 244 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, |
213 | int is_play, int id, | 245 | int is_play, int id) |
214 | int (*inquiry)(struct rsnd_dma *dma, | ||
215 | dma_addr_t *buf, int *len), | ||
216 | int (*complete)(struct rsnd_dma *dma)) | ||
217 | { | 246 | { |
218 | struct device *dev = rsnd_priv_to_dev(priv); | 247 | struct device *dev = rsnd_priv_to_dev(priv); |
219 | struct dma_slave_config cfg; | 248 | struct dma_slave_config cfg; |
@@ -246,9 +275,6 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | |||
246 | goto rsnd_dma_init_err; | 275 | goto rsnd_dma_init_err; |
247 | 276 | ||
248 | dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 277 | dma->dir = is_play ? DMA_TO_DEVICE : DMA_FROM_DEVICE; |
249 | dma->priv = priv; | ||
250 | dma->inquiry = inquiry; | ||
251 | dma->complete = complete; | ||
252 | INIT_WORK(&dma->work, rsnd_dma_do_work); | 278 | INIT_WORK(&dma->work, rsnd_dma_do_work); |
253 | 279 | ||
254 | return 0; | 280 | return 0; |
@@ -271,26 +297,42 @@ void rsnd_dma_quit(struct rsnd_priv *priv, | |||
271 | /* | 297 | /* |
272 | * rsnd_dai functions | 298 | * rsnd_dai functions |
273 | */ | 299 | */ |
274 | #define rsnd_dai_call(rdai, io, fn) \ | 300 | #define __rsnd_mod_call(mod, func, rdai, io) \ |
275 | ({ \ | 301 | ({ \ |
276 | struct rsnd_mod *mod, *n; \ | 302 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
277 | int ret = 0; \ | 303 | struct device *dev = rsnd_priv_to_dev(priv); \ |
278 | for_each_rsnd_mod(mod, n, io) { \ | 304 | dev_dbg(dev, "%s [%d] %s\n", \ |
279 | ret = rsnd_mod_call(mod, fn, rdai, io); \ | 305 | rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \ |
280 | if (ret < 0) \ | 306 | (mod)->ops->func(mod, rdai, io); \ |
281 | break; \ | 307 | }) |
282 | } \ | 308 | |
283 | ret; \ | 309 | #define rsnd_mod_call(mod, func, rdai, io) \ |
310 | (!(mod) ? -ENODEV : \ | ||
311 | !((mod)->ops->func) ? 0 : \ | ||
312 | __rsnd_mod_call(mod, func, (rdai), (io))) | ||
313 | |||
314 | #define rsnd_dai_call(rdai, io, fn) \ | ||
315 | ({ \ | ||
316 | struct rsnd_mod *mod; \ | ||
317 | int ret = 0, i; \ | ||
318 | for (i = 0; i < RSND_MOD_MAX; i++) { \ | ||
319 | mod = (io)->mod[i]; \ | ||
320 | if (!mod) \ | ||
321 | continue; \ | ||
322 | ret = rsnd_mod_call(mod, fn, (rdai), (io)); \ | ||
323 | if (ret < 0) \ | ||
324 | break; \ | ||
325 | } \ | ||
326 | ret; \ | ||
284 | }) | 327 | }) |
285 | 328 | ||
286 | int rsnd_dai_connect(struct rsnd_dai *rdai, | 329 | static int rsnd_dai_connect(struct rsnd_mod *mod, |
287 | struct rsnd_mod *mod, | 330 | struct rsnd_dai_stream *io) |
288 | struct rsnd_dai_stream *io) | ||
289 | { | 331 | { |
290 | if (!mod) | 332 | if (!mod) |
291 | return -EIO; | 333 | return -EIO; |
292 | 334 | ||
293 | if (!list_empty(&mod->list)) { | 335 | if (io->mod[mod->type]) { |
294 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 336 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
295 | struct device *dev = rsnd_priv_to_dev(priv); | 337 | struct device *dev = rsnd_priv_to_dev(priv); |
296 | 338 | ||
@@ -300,14 +342,8 @@ int rsnd_dai_connect(struct rsnd_dai *rdai, | |||
300 | return -EIO; | 342 | return -EIO; |
301 | } | 343 | } |
302 | 344 | ||
303 | list_add_tail(&mod->list, &io->head); | 345 | io->mod[mod->type] = mod; |
304 | 346 | mod->io = io; | |
305 | return 0; | ||
306 | } | ||
307 | |||
308 | int rsnd_dai_disconnect(struct rsnd_mod *mod) | ||
309 | { | ||
310 | list_del_init(&mod->list); | ||
311 | 347 | ||
312 | return 0; | 348 | return 0; |
313 | } | 349 | } |
@@ -316,7 +352,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | |||
316 | { | 352 | { |
317 | int id = rdai - priv->rdai; | 353 | int id = rdai - priv->rdai; |
318 | 354 | ||
319 | if ((id < 0) || (id >= rsnd_dai_nr(priv))) | 355 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) |
320 | return -EINVAL; | 356 | return -EINVAL; |
321 | 357 | ||
322 | return id; | 358 | return id; |
@@ -324,7 +360,7 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai) | |||
324 | 360 | ||
325 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) | 361 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id) |
326 | { | 362 | { |
327 | if ((id < 0) || (id >= rsnd_dai_nr(priv))) | 363 | if ((id < 0) || (id >= rsnd_rdai_nr(priv))) |
328 | return NULL; | 364 | return NULL; |
329 | 365 | ||
330 | return priv->rdai + id; | 366 | return priv->rdai + id; |
@@ -382,10 +418,6 @@ static int rsnd_dai_stream_init(struct rsnd_dai_stream *io, | |||
382 | { | 418 | { |
383 | struct snd_pcm_runtime *runtime = substream->runtime; | 419 | struct snd_pcm_runtime *runtime = substream->runtime; |
384 | 420 | ||
385 | if (!list_empty(&io->head)) | ||
386 | return -EIO; | ||
387 | |||
388 | INIT_LIST_HEAD(&io->head); | ||
389 | io->substream = substream; | 421 | io->substream = substream; |
390 | io->byte_pos = 0; | 422 | io->byte_pos = 0; |
391 | io->period_pos = 0; | 423 | io->period_pos = 0; |
@@ -440,10 +472,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
440 | if (ret < 0) | 472 | if (ret < 0) |
441 | goto dai_trigger_end; | 473 | goto dai_trigger_end; |
442 | 474 | ||
443 | ret = rsnd_gen_path_init(priv, rdai, io); | ||
444 | if (ret < 0) | ||
445 | goto dai_trigger_end; | ||
446 | |||
447 | ret = rsnd_dai_call(rdai, io, init); | 475 | ret = rsnd_dai_call(rdai, io, init); |
448 | if (ret < 0) | 476 | if (ret < 0) |
449 | goto dai_trigger_end; | 477 | goto dai_trigger_end; |
@@ -461,10 +489,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
461 | if (ret < 0) | 489 | if (ret < 0) |
462 | goto dai_trigger_end; | 490 | goto dai_trigger_end; |
463 | 491 | ||
464 | ret = rsnd_gen_path_exit(priv, rdai, io); | ||
465 | if (ret < 0) | ||
466 | goto dai_trigger_end; | ||
467 | |||
468 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); | 492 | ret = rsnd_platform_call(priv, dai, stop, ssi_id); |
469 | if (ret < 0) | 493 | if (ret < 0) |
470 | goto dai_trigger_end; | 494 | goto dai_trigger_end; |
@@ -540,24 +564,86 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | |||
540 | .set_fmt = rsnd_soc_dai_set_fmt, | 564 | .set_fmt = rsnd_soc_dai_set_fmt, |
541 | }; | 565 | }; |
542 | 566 | ||
567 | static int rsnd_path_init(struct rsnd_priv *priv, | ||
568 | struct rsnd_dai *rdai, | ||
569 | struct rsnd_dai_stream *io) | ||
570 | { | ||
571 | struct rsnd_mod *mod; | ||
572 | struct rsnd_dai_platform_info *dai_info = rdai->info; | ||
573 | int ret; | ||
574 | int ssi_id = -1; | ||
575 | int src_id = -1; | ||
576 | |||
577 | /* | ||
578 | * Gen1 is created by SRU/SSI, and this SRU is base module of | ||
579 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | ||
580 | * | ||
581 | * Easy image is.. | ||
582 | * Gen1 SRU = Gen2 SCU + SSIU + etc | ||
583 | * | ||
584 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | ||
585 | * using fixed path. | ||
586 | */ | ||
587 | if (dai_info) { | ||
588 | if (rsnd_is_enable_path(io, ssi)) | ||
589 | ssi_id = rsnd_info_id(priv, io, ssi); | ||
590 | if (rsnd_is_enable_path(io, src)) | ||
591 | src_id = rsnd_info_id(priv, io, src); | ||
592 | } else { | ||
593 | /* get SSI's ID */ | ||
594 | mod = rsnd_ssi_mod_get_frm_dai(priv, | ||
595 | rsnd_dai_id(priv, rdai), | ||
596 | rsnd_dai_is_play(rdai, io)); | ||
597 | if (!mod) | ||
598 | return 0; | ||
599 | ssi_id = src_id = rsnd_mod_id(mod); | ||
600 | } | ||
601 | |||
602 | ret = 0; | ||
603 | |||
604 | /* SRC */ | ||
605 | if (src_id >= 0) { | ||
606 | mod = rsnd_src_mod_get(priv, src_id); | ||
607 | ret = rsnd_dai_connect(mod, io); | ||
608 | if (ret < 0) | ||
609 | return ret; | ||
610 | } | ||
611 | |||
612 | /* SSI */ | ||
613 | if (ssi_id >= 0) { | ||
614 | mod = rsnd_ssi_mod_get(priv, ssi_id); | ||
615 | ret = rsnd_dai_connect(mod, io); | ||
616 | if (ret < 0) | ||
617 | return ret; | ||
618 | } | ||
619 | |||
620 | return ret; | ||
621 | } | ||
622 | |||
543 | static int rsnd_dai_probe(struct platform_device *pdev, | 623 | static int rsnd_dai_probe(struct platform_device *pdev, |
544 | struct rcar_snd_info *info, | ||
545 | struct rsnd_priv *priv) | 624 | struct rsnd_priv *priv) |
546 | { | 625 | { |
547 | struct snd_soc_dai_driver *drv; | 626 | struct snd_soc_dai_driver *drv; |
627 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
548 | struct rsnd_dai *rdai; | 628 | struct rsnd_dai *rdai; |
549 | struct rsnd_mod *pmod, *cmod; | 629 | struct rsnd_mod *pmod, *cmod; |
550 | struct device *dev = rsnd_priv_to_dev(priv); | 630 | struct device *dev = rsnd_priv_to_dev(priv); |
551 | int dai_nr; | 631 | int dai_nr = info->dai_info_nr; |
552 | int i; | 632 | int i; |
553 | 633 | ||
554 | /* get max dai nr */ | 634 | /* |
555 | for (dai_nr = 0; dai_nr < 32; dai_nr++) { | 635 | * dai_nr should be set via dai_info_nr, |
556 | pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); | 636 | * but allow it to keeping compatible |
557 | cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); | 637 | */ |
638 | if (!dai_nr) { | ||
639 | /* get max dai nr */ | ||
640 | for (dai_nr = 0; dai_nr < 32; dai_nr++) { | ||
641 | pmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 1); | ||
642 | cmod = rsnd_ssi_mod_get_frm_dai(priv, dai_nr, 0); | ||
558 | 643 | ||
559 | if (!pmod && !cmod) | 644 | if (!pmod && !cmod) |
560 | break; | 645 | break; |
646 | } | ||
561 | } | 647 | } |
562 | 648 | ||
563 | if (!dai_nr) { | 649 | if (!dai_nr) { |
@@ -572,7 +658,13 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
572 | return -ENOMEM; | 658 | return -ENOMEM; |
573 | } | 659 | } |
574 | 660 | ||
661 | priv->rdai_nr = dai_nr; | ||
662 | priv->daidrv = drv; | ||
663 | priv->rdai = rdai; | ||
664 | |||
575 | for (i = 0; i < dai_nr; i++) { | 665 | for (i = 0; i < dai_nr; i++) { |
666 | if (info->dai_info) | ||
667 | rdai[i].info = &info->dai_info[i]; | ||
576 | 668 | ||
577 | pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); | 669 | pmod = rsnd_ssi_mod_get_frm_dai(priv, i, 1); |
578 | cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); | 670 | cmod = rsnd_ssi_mod_get_frm_dai(priv, i, 0); |
@@ -580,9 +672,6 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
580 | /* | 672 | /* |
581 | * init rsnd_dai | 673 | * init rsnd_dai |
582 | */ | 674 | */ |
583 | INIT_LIST_HEAD(&rdai[i].playback.head); | ||
584 | INIT_LIST_HEAD(&rdai[i].capture.head); | ||
585 | |||
586 | snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); | 675 | snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); |
587 | 676 | ||
588 | /* | 677 | /* |
@@ -595,12 +684,20 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
595 | drv[i].playback.formats = RSND_FMTS; | 684 | drv[i].playback.formats = RSND_FMTS; |
596 | drv[i].playback.channels_min = 2; | 685 | drv[i].playback.channels_min = 2; |
597 | drv[i].playback.channels_max = 2; | 686 | drv[i].playback.channels_max = 2; |
687 | |||
688 | if (info->dai_info) | ||
689 | rdai[i].playback.info = &info->dai_info[i].playback; | ||
690 | rsnd_path_init(priv, &rdai[i], &rdai[i].playback); | ||
598 | } | 691 | } |
599 | if (cmod) { | 692 | if (cmod) { |
600 | drv[i].capture.rates = RSND_RATES; | 693 | drv[i].capture.rates = RSND_RATES; |
601 | drv[i].capture.formats = RSND_FMTS; | 694 | drv[i].capture.formats = RSND_FMTS; |
602 | drv[i].capture.channels_min = 2; | 695 | drv[i].capture.channels_min = 2; |
603 | drv[i].capture.channels_max = 2; | 696 | drv[i].capture.channels_max = 2; |
697 | |||
698 | if (info->dai_info) | ||
699 | rdai[i].capture.info = &info->dai_info[i].capture; | ||
700 | rsnd_path_init(priv, &rdai[i], &rdai[i].capture); | ||
604 | } | 701 | } |
605 | 702 | ||
606 | dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, | 703 | dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, |
@@ -608,18 +705,9 @@ static int rsnd_dai_probe(struct platform_device *pdev, | |||
608 | cmod ? "capture" : " -- "); | 705 | cmod ? "capture" : " -- "); |
609 | } | 706 | } |
610 | 707 | ||
611 | priv->dai_nr = dai_nr; | ||
612 | priv->daidrv = drv; | ||
613 | priv->rdai = rdai; | ||
614 | |||
615 | return 0; | 708 | return 0; |
616 | } | 709 | } |
617 | 710 | ||
618 | static void rsnd_dai_remove(struct platform_device *pdev, | ||
619 | struct rsnd_priv *priv) | ||
620 | { | ||
621 | } | ||
622 | |||
623 | /* | 711 | /* |
624 | * pcm ops | 712 | * pcm ops |
625 | */ | 713 | */ |
@@ -713,7 +801,16 @@ static int rsnd_probe(struct platform_device *pdev) | |||
713 | struct rcar_snd_info *info; | 801 | struct rcar_snd_info *info; |
714 | struct rsnd_priv *priv; | 802 | struct rsnd_priv *priv; |
715 | struct device *dev = &pdev->dev; | 803 | struct device *dev = &pdev->dev; |
716 | int ret; | 804 | struct rsnd_dai *rdai; |
805 | int (*probe_func[])(struct platform_device *pdev, | ||
806 | struct rsnd_priv *priv) = { | ||
807 | rsnd_gen_probe, | ||
808 | rsnd_ssi_probe, | ||
809 | rsnd_src_probe, | ||
810 | rsnd_adg_probe, | ||
811 | rsnd_dai_probe, | ||
812 | }; | ||
813 | int ret, i; | ||
717 | 814 | ||
718 | info = pdev->dev.platform_data; | 815 | info = pdev->dev.platform_data; |
719 | if (!info) { | 816 | if (!info) { |
@@ -737,25 +834,21 @@ static int rsnd_probe(struct platform_device *pdev) | |||
737 | /* | 834 | /* |
738 | * init each module | 835 | * init each module |
739 | */ | 836 | */ |
740 | ret = rsnd_gen_probe(pdev, info, priv); | 837 | for (i = 0; i < ARRAY_SIZE(probe_func); i++) { |
741 | if (ret < 0) | 838 | ret = probe_func[i](pdev, priv); |
742 | return ret; | 839 | if (ret) |
743 | 840 | return ret; | |
744 | ret = rsnd_scu_probe(pdev, info, priv); | 841 | } |
745 | if (ret < 0) | ||
746 | return ret; | ||
747 | 842 | ||
748 | ret = rsnd_adg_probe(pdev, info, priv); | 843 | for_each_rsnd_dai(rdai, priv, i) { |
749 | if (ret < 0) | 844 | ret = rsnd_dai_call(rdai, &rdai->playback, probe); |
750 | return ret; | 845 | if (ret) |
846 | return ret; | ||
751 | 847 | ||
752 | ret = rsnd_ssi_probe(pdev, info, priv); | 848 | ret = rsnd_dai_call(rdai, &rdai->capture, probe); |
753 | if (ret < 0) | 849 | if (ret) |
754 | return ret; | 850 | return ret; |
755 | 851 | } | |
756 | ret = rsnd_dai_probe(pdev, info, priv); | ||
757 | if (ret < 0) | ||
758 | return ret; | ||
759 | 852 | ||
760 | /* | 853 | /* |
761 | * asoc register | 854 | * asoc register |
@@ -767,7 +860,7 @@ static int rsnd_probe(struct platform_device *pdev) | |||
767 | } | 860 | } |
768 | 861 | ||
769 | ret = snd_soc_register_component(dev, &rsnd_soc_component, | 862 | ret = snd_soc_register_component(dev, &rsnd_soc_component, |
770 | priv->daidrv, rsnd_dai_nr(priv)); | 863 | priv->daidrv, rsnd_rdai_nr(priv)); |
771 | if (ret < 0) { | 864 | if (ret < 0) { |
772 | dev_err(dev, "cannot snd dai register\n"); | 865 | dev_err(dev, "cannot snd dai register\n"); |
773 | goto exit_snd_soc; | 866 | goto exit_snd_soc; |
@@ -789,17 +882,20 @@ exit_snd_soc: | |||
789 | static int rsnd_remove(struct platform_device *pdev) | 882 | static int rsnd_remove(struct platform_device *pdev) |
790 | { | 883 | { |
791 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | 884 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); |
885 | struct rsnd_dai *rdai; | ||
886 | int ret, i; | ||
792 | 887 | ||
793 | pm_runtime_disable(&pdev->dev); | 888 | pm_runtime_disable(&pdev->dev); |
794 | 889 | ||
795 | /* | 890 | for_each_rsnd_dai(rdai, priv, i) { |
796 | * remove each module | 891 | ret = rsnd_dai_call(rdai, &rdai->playback, remove); |
797 | */ | 892 | if (ret) |
798 | rsnd_ssi_remove(pdev, priv); | 893 | return ret; |
799 | rsnd_adg_remove(pdev, priv); | 894 | |
800 | rsnd_scu_remove(pdev, priv); | 895 | ret = rsnd_dai_call(rdai, &rdai->capture, remove); |
801 | rsnd_dai_remove(pdev, priv); | 896 | if (ret) |
802 | rsnd_gen_remove(pdev, priv); | 897 | return ret; |
898 | } | ||
803 | 899 | ||
804 | return 0; | 900 | return 0; |
805 | } | 901 | } |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index add088bd4b2a..9094970dbdfb 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
@@ -155,62 +155,6 @@ static int rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
155 | return 0; | 155 | return 0; |
156 | } | 156 | } |
157 | 157 | ||
158 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
159 | struct rsnd_dai *rdai, | ||
160 | struct rsnd_dai_stream *io) | ||
161 | { | ||
162 | struct rsnd_mod *mod; | ||
163 | int ret; | ||
164 | int id; | ||
165 | |||
166 | /* | ||
167 | * Gen1 is created by SRU/SSI, and this SRU is base module of | ||
168 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | ||
169 | * | ||
170 | * Easy image is.. | ||
171 | * Gen1 SRU = Gen2 SCU + SSIU + etc | ||
172 | * | ||
173 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | ||
174 | * using fixed path. | ||
175 | * | ||
176 | * Then, SSI id = SCU id here | ||
177 | */ | ||
178 | |||
179 | /* get SSI's ID */ | ||
180 | mod = rsnd_ssi_mod_get_frm_dai(priv, | ||
181 | rsnd_dai_id(priv, rdai), | ||
182 | rsnd_dai_is_play(rdai, io)); | ||
183 | id = rsnd_mod_id(mod); | ||
184 | |||
185 | /* SSI */ | ||
186 | mod = rsnd_ssi_mod_get(priv, id); | ||
187 | ret = rsnd_dai_connect(rdai, mod, io); | ||
188 | if (ret < 0) | ||
189 | return ret; | ||
190 | |||
191 | /* SCU */ | ||
192 | mod = rsnd_scu_mod_get(priv, id); | ||
193 | ret = rsnd_dai_connect(rdai, mod, io); | ||
194 | |||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
199 | struct rsnd_dai *rdai, | ||
200 | struct rsnd_dai_stream *io) | ||
201 | { | ||
202 | struct rsnd_mod *mod, *n; | ||
203 | int ret = 0; | ||
204 | |||
205 | /* | ||
206 | * remove all mod from rdai | ||
207 | */ | ||
208 | for_each_rsnd_mod(mod, n, io) | ||
209 | ret |= rsnd_dai_disconnect(mod); | ||
210 | |||
211 | return ret; | ||
212 | } | ||
213 | |||
214 | /* | 158 | /* |
215 | * Gen2 | 159 | * Gen2 |
216 | */ | 160 | */ |
@@ -229,14 +173,40 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
229 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), | 173 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE0, 0x800), |
230 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), | 174 | RSND_GEN2_S_REG(gen, SSIU, SSI_MODE1, 0x804), |
231 | /* FIXME: it needs SSI_MODE2/3 in the future */ | 175 | /* FIXME: it needs SSI_MODE2/3 in the future */ |
176 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_MODE, 0x0, 0x80), | ||
177 | RSND_GEN2_M_REG(gen, SSIU, SSI_BUSIF_ADINR,0x4, 0x80), | ||
178 | RSND_GEN2_M_REG(gen, SSIU, SSI_CTRL, 0x10, 0x80), | ||
232 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), | 179 | RSND_GEN2_M_REG(gen, SSIU, INT_ENABLE, 0x18, 0x80), |
233 | 180 | ||
181 | RSND_GEN2_M_REG(gen, SCU, SRC_BUSIF_MODE, 0x0, 0x20), | ||
182 | RSND_GEN2_M_REG(gen, SCU, SRC_ROUTE_MODE0,0xc, 0x20), | ||
183 | RSND_GEN2_M_REG(gen, SCU, SRC_CTRL, 0x10, 0x20), | ||
184 | RSND_GEN2_M_REG(gen, SCU, SRC_SWRSR, 0x200, 0x40), | ||
185 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCIR, 0x204, 0x40), | ||
186 | RSND_GEN2_M_REG(gen, SCU, SRC_ADINR, 0x214, 0x40), | ||
187 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSCR, 0x21c, 0x40), | ||
188 | RSND_GEN2_M_REG(gen, SCU, SRC_IFSVR, 0x220, 0x40), | ||
189 | RSND_GEN2_M_REG(gen, SCU, SRC_SRCCR, 0x224, 0x40), | ||
190 | RSND_GEN2_M_REG(gen, SCU, SRC_BSDSR, 0x22c, 0x40), | ||
191 | RSND_GEN2_M_REG(gen, SCU, SRC_BSISR, 0x238, 0x40), | ||
192 | |||
234 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), | 193 | RSND_GEN2_S_REG(gen, ADG, BRRA, 0x00), |
235 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), | 194 | RSND_GEN2_S_REG(gen, ADG, BRRB, 0x04), |
236 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), | 195 | RSND_GEN2_S_REG(gen, ADG, SSICKR, 0x08), |
237 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), | 196 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL0, 0x0c), |
238 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), | 197 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL1, 0x10), |
239 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), | 198 | RSND_GEN2_S_REG(gen, ADG, AUDIO_CLK_SEL2, 0x14), |
199 | RSND_GEN2_S_REG(gen, ADG, DIV_EN, 0x30), | ||
200 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL0, 0x34), | ||
201 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL1, 0x38), | ||
202 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL2, 0x3c), | ||
203 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL3, 0x40), | ||
204 | RSND_GEN2_S_REG(gen, ADG, SRCIN_TIMSEL4, 0x44), | ||
205 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL0, 0x48), | ||
206 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL1, 0x4c), | ||
207 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL2, 0x50), | ||
208 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL3, 0x54), | ||
209 | RSND_GEN2_S_REG(gen, ADG, SRCOUT_TIMSEL4, 0x58), | ||
240 | 210 | ||
241 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), | 211 | RSND_GEN2_M_REG(gen, SSI, SSICR, 0x00, 0x40), |
242 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), | 212 | RSND_GEN2_M_REG(gen, SSI, SSISR, 0x04, 0x40), |
@@ -249,7 +219,6 @@ static int rsnd_gen2_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
249 | } | 219 | } |
250 | 220 | ||
251 | static int rsnd_gen2_probe(struct platform_device *pdev, | 221 | static int rsnd_gen2_probe(struct platform_device *pdev, |
252 | struct rcar_snd_info *info, | ||
253 | struct rsnd_priv *priv) | 222 | struct rsnd_priv *priv) |
254 | { | 223 | { |
255 | struct device *dev = rsnd_priv_to_dev(priv); | 224 | struct device *dev = rsnd_priv_to_dev(priv); |
@@ -283,7 +252,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
283 | return ret; | 252 | return ret; |
284 | 253 | ||
285 | dev_dbg(dev, "Gen2 device probed\n"); | 254 | dev_dbg(dev, "Gen2 device probed\n"); |
286 | dev_dbg(dev, "SRU : %08x => %p\n", scu_res->start, | 255 | dev_dbg(dev, "SCU : %08x => %p\n", scu_res->start, |
287 | gen->base[RSND_GEN2_SCU]); | 256 | gen->base[RSND_GEN2_SCU]); |
288 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, | 257 | dev_dbg(dev, "ADG : %08x => %p\n", adg_res->start, |
289 | gen->base[RSND_GEN2_ADG]); | 258 | gen->base[RSND_GEN2_ADG]); |
@@ -317,7 +286,7 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
317 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), | 286 | RSND_GEN1_S_REG(gen, SRU, SRC_ROUTE_CTRL, 0xc0), |
318 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), | 287 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE0, 0xD0), |
319 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), | 288 | RSND_GEN1_S_REG(gen, SRU, SSI_MODE1, 0xD4), |
320 | RSND_GEN1_M_REG(gen, SRU, BUSIF_MODE, 0x20, 0x4), | 289 | RSND_GEN1_M_REG(gen, SRU, SRC_BUSIF_MODE, 0x20, 0x4), |
321 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), | 290 | RSND_GEN1_M_REG(gen, SRU, SRC_ROUTE_MODE0,0x50, 0x8), |
322 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), | 291 | RSND_GEN1_M_REG(gen, SRU, SRC_SWRSR, 0x200, 0x40), |
323 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), | 292 | RSND_GEN1_M_REG(gen, SRU, SRC_SRCIR, 0x204, 0x40), |
@@ -347,7 +316,6 @@ static int rsnd_gen1_regmap_init(struct rsnd_priv *priv, struct rsnd_gen *gen) | |||
347 | } | 316 | } |
348 | 317 | ||
349 | static int rsnd_gen1_probe(struct platform_device *pdev, | 318 | static int rsnd_gen1_probe(struct platform_device *pdev, |
350 | struct rcar_snd_info *info, | ||
351 | struct rsnd_priv *priv) | 319 | struct rsnd_priv *priv) |
352 | { | 320 | { |
353 | struct device *dev = rsnd_priv_to_dev(priv); | 321 | struct device *dev = rsnd_priv_to_dev(priv); |
@@ -392,7 +360,6 @@ static int rsnd_gen1_probe(struct platform_device *pdev, | |||
392 | * Gen | 360 | * Gen |
393 | */ | 361 | */ |
394 | int rsnd_gen_probe(struct platform_device *pdev, | 362 | int rsnd_gen_probe(struct platform_device *pdev, |
395 | struct rcar_snd_info *info, | ||
396 | struct rsnd_priv *priv) | 363 | struct rsnd_priv *priv) |
397 | { | 364 | { |
398 | struct device *dev = rsnd_priv_to_dev(priv); | 365 | struct device *dev = rsnd_priv_to_dev(priv); |
@@ -409,17 +376,12 @@ int rsnd_gen_probe(struct platform_device *pdev, | |||
409 | 376 | ||
410 | ret = -ENODEV; | 377 | ret = -ENODEV; |
411 | if (rsnd_is_gen1(priv)) | 378 | if (rsnd_is_gen1(priv)) |
412 | ret = rsnd_gen1_probe(pdev, info, priv); | 379 | ret = rsnd_gen1_probe(pdev, priv); |
413 | else if (rsnd_is_gen2(priv)) | 380 | else if (rsnd_is_gen2(priv)) |
414 | ret = rsnd_gen2_probe(pdev, info, priv); | 381 | ret = rsnd_gen2_probe(pdev, priv); |
415 | 382 | ||
416 | if (ret < 0) | 383 | if (ret < 0) |
417 | dev_err(dev, "unknown generation R-Car sound device\n"); | 384 | dev_err(dev, "unknown generation R-Car sound device\n"); |
418 | 385 | ||
419 | return ret; | 386 | return ret; |
420 | } | 387 | } |
421 | |||
422 | void rsnd_gen_remove(struct platform_device *pdev, | ||
423 | struct rsnd_priv *priv) | ||
424 | { | ||
425 | } | ||
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 4ca66cd899c8..c46e0afa54ae 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
@@ -32,15 +32,9 @@ | |||
32 | */ | 32 | */ |
33 | enum rsnd_reg { | 33 | enum rsnd_reg { |
34 | /* SRU/SCU/SSIU */ | 34 | /* SRU/SCU/SSIU */ |
35 | RSND_REG_SRC_ROUTE_SEL, /* for Gen1 */ | ||
36 | RSND_REG_SRC_TMG_SEL0, /* for Gen1 */ | ||
37 | RSND_REG_SRC_TMG_SEL1, /* for Gen1 */ | ||
38 | RSND_REG_SRC_TMG_SEL2, /* for Gen1 */ | ||
39 | RSND_REG_SRC_ROUTE_CTRL, /* for Gen1 */ | ||
40 | RSND_REG_SSI_MODE0, | 35 | RSND_REG_SSI_MODE0, |
41 | RSND_REG_SSI_MODE1, | 36 | RSND_REG_SSI_MODE1, |
42 | RSND_REG_BUSIF_MODE, | 37 | RSND_REG_SRC_BUSIF_MODE, |
43 | RSND_REG_INT_ENABLE, /* for Gen2 */ | ||
44 | RSND_REG_SRC_ROUTE_MODE0, | 38 | RSND_REG_SRC_ROUTE_MODE0, |
45 | RSND_REG_SRC_SWRSR, | 39 | RSND_REG_SRC_SWRSR, |
46 | RSND_REG_SRC_SRCIR, | 40 | RSND_REG_SRC_SRCIR, |
@@ -48,7 +42,6 @@ enum rsnd_reg { | |||
48 | RSND_REG_SRC_IFSCR, | 42 | RSND_REG_SRC_IFSCR, |
49 | RSND_REG_SRC_IFSVR, | 43 | RSND_REG_SRC_IFSVR, |
50 | RSND_REG_SRC_SRCCR, | 44 | RSND_REG_SRC_SRCCR, |
51 | RSND_REG_SRC_MNFSR, | ||
52 | 45 | ||
53 | /* ADG */ | 46 | /* ADG */ |
54 | RSND_REG_BRRA, | 47 | RSND_REG_BRRA, |
@@ -56,10 +49,6 @@ enum rsnd_reg { | |||
56 | RSND_REG_SSICKR, | 49 | RSND_REG_SSICKR, |
57 | RSND_REG_AUDIO_CLK_SEL0, | 50 | RSND_REG_AUDIO_CLK_SEL0, |
58 | RSND_REG_AUDIO_CLK_SEL1, | 51 | RSND_REG_AUDIO_CLK_SEL1, |
59 | RSND_REG_AUDIO_CLK_SEL2, | ||
60 | RSND_REG_AUDIO_CLK_SEL3, /* for Gen1 */ | ||
61 | RSND_REG_AUDIO_CLK_SEL4, /* for Gen1 */ | ||
62 | RSND_REG_AUDIO_CLK_SEL5, /* for Gen1 */ | ||
63 | 52 | ||
64 | /* SSI */ | 53 | /* SSI */ |
65 | RSND_REG_SSICR, | 54 | RSND_REG_SSICR, |
@@ -68,9 +57,62 @@ enum rsnd_reg { | |||
68 | RSND_REG_SSIRDR, | 57 | RSND_REG_SSIRDR, |
69 | RSND_REG_SSIWSR, | 58 | RSND_REG_SSIWSR, |
70 | 59 | ||
60 | /* SHARE see below */ | ||
61 | RSND_REG_SHARE01, | ||
62 | RSND_REG_SHARE02, | ||
63 | RSND_REG_SHARE03, | ||
64 | RSND_REG_SHARE04, | ||
65 | RSND_REG_SHARE05, | ||
66 | RSND_REG_SHARE06, | ||
67 | RSND_REG_SHARE07, | ||
68 | RSND_REG_SHARE08, | ||
69 | RSND_REG_SHARE09, | ||
70 | RSND_REG_SHARE10, | ||
71 | RSND_REG_SHARE11, | ||
72 | RSND_REG_SHARE12, | ||
73 | RSND_REG_SHARE13, | ||
74 | RSND_REG_SHARE14, | ||
75 | RSND_REG_SHARE15, | ||
76 | RSND_REG_SHARE16, | ||
77 | RSND_REG_SHARE17, | ||
78 | RSND_REG_SHARE18, | ||
79 | RSND_REG_SHARE19, | ||
80 | |||
71 | RSND_REG_MAX, | 81 | RSND_REG_MAX, |
72 | }; | 82 | }; |
73 | 83 | ||
84 | /* Gen1 only */ | ||
85 | #define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01 | ||
86 | #define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02 | ||
87 | #define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03 | ||
88 | #define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04 | ||
89 | #define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05 | ||
90 | #define RSND_REG_SRC_MNFSR RSND_REG_SHARE06 | ||
91 | #define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07 | ||
92 | #define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08 | ||
93 | #define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09 | ||
94 | |||
95 | /* Gen2 only */ | ||
96 | #define RSND_REG_SRC_CTRL RSND_REG_SHARE01 | ||
97 | #define RSND_REG_SSI_CTRL RSND_REG_SHARE02 | ||
98 | #define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 | ||
99 | #define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 | ||
100 | #define RSND_REG_INT_ENABLE RSND_REG_SHARE05 | ||
101 | #define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 | ||
102 | #define RSND_REG_SRC_BSISR RSND_REG_SHARE07 | ||
103 | #define RSND_REG_DIV_EN RSND_REG_SHARE08 | ||
104 | #define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09 | ||
105 | #define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10 | ||
106 | #define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11 | ||
107 | #define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12 | ||
108 | #define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13 | ||
109 | #define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14 | ||
110 | #define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15 | ||
111 | #define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16 | ||
112 | #define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17 | ||
113 | #define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18 | ||
114 | #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 | ||
115 | |||
74 | struct rsnd_priv; | 116 | struct rsnd_priv; |
75 | struct rsnd_mod; | 117 | struct rsnd_mod; |
76 | struct rsnd_dai; | 118 | struct rsnd_dai; |
@@ -96,24 +138,20 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | |||
96 | * R-Car DMA | 138 | * R-Car DMA |
97 | */ | 139 | */ |
98 | struct rsnd_dma { | 140 | struct rsnd_dma { |
99 | struct rsnd_priv *priv; | ||
100 | struct sh_dmae_slave slave; | 141 | struct sh_dmae_slave slave; |
101 | struct work_struct work; | 142 | struct work_struct work; |
102 | struct dma_chan *chan; | 143 | struct dma_chan *chan; |
103 | enum dma_data_direction dir; | 144 | enum dma_data_direction dir; |
104 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len); | ||
105 | int (*complete)(struct rsnd_dma *dma); | ||
106 | 145 | ||
107 | int submit_loop; | 146 | int submit_loop; |
147 | int offset; /* it cares A/B plane */ | ||
108 | }; | 148 | }; |
109 | 149 | ||
110 | void rsnd_dma_start(struct rsnd_dma *dma); | 150 | void rsnd_dma_start(struct rsnd_dma *dma); |
111 | void rsnd_dma_stop(struct rsnd_dma *dma); | 151 | void rsnd_dma_stop(struct rsnd_dma *dma); |
112 | int rsnd_dma_available(struct rsnd_dma *dma); | 152 | int rsnd_dma_available(struct rsnd_dma *dma); |
113 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, | 153 | int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma, |
114 | int is_play, int id, | 154 | int is_play, int id); |
115 | int (*inquiry)(struct rsnd_dma *dma, dma_addr_t *buf, int *len), | ||
116 | int (*complete)(struct rsnd_dma *dma)); | ||
117 | void rsnd_dma_quit(struct rsnd_priv *priv, | 155 | void rsnd_dma_quit(struct rsnd_priv *priv, |
118 | struct rsnd_dma *dma); | 156 | struct rsnd_dma *dma); |
119 | 157 | ||
@@ -121,9 +159,20 @@ void rsnd_dma_quit(struct rsnd_priv *priv, | |||
121 | /* | 159 | /* |
122 | * R-Car sound mod | 160 | * R-Car sound mod |
123 | */ | 161 | */ |
162 | enum rsnd_mod_type { | ||
163 | RSND_MOD_SRC = 0, | ||
164 | RSND_MOD_SSI, | ||
165 | RSND_MOD_MAX, | ||
166 | }; | ||
124 | 167 | ||
125 | struct rsnd_mod_ops { | 168 | struct rsnd_mod_ops { |
126 | char *name; | 169 | char *name; |
170 | int (*probe)(struct rsnd_mod *mod, | ||
171 | struct rsnd_dai *rdai, | ||
172 | struct rsnd_dai_stream *io); | ||
173 | int (*remove)(struct rsnd_mod *mod, | ||
174 | struct rsnd_dai *rdai, | ||
175 | struct rsnd_dai_stream *io); | ||
127 | int (*init)(struct rsnd_mod *mod, | 176 | int (*init)(struct rsnd_mod *mod, |
128 | struct rsnd_dai *rdai, | 177 | struct rsnd_dai *rdai, |
129 | struct rsnd_dai_stream *io); | 178 | struct rsnd_dai_stream *io); |
@@ -138,28 +187,26 @@ struct rsnd_mod_ops { | |||
138 | struct rsnd_dai_stream *io); | 187 | struct rsnd_dai_stream *io); |
139 | }; | 188 | }; |
140 | 189 | ||
190 | struct rsnd_dai_stream; | ||
141 | struct rsnd_mod { | 191 | struct rsnd_mod { |
142 | int id; | 192 | int id; |
193 | enum rsnd_mod_type type; | ||
143 | struct rsnd_priv *priv; | 194 | struct rsnd_priv *priv; |
144 | struct rsnd_mod_ops *ops; | 195 | struct rsnd_mod_ops *ops; |
145 | struct list_head list; /* connect to rsnd_dai playback/capture */ | ||
146 | struct rsnd_dma dma; | 196 | struct rsnd_dma dma; |
197 | struct rsnd_dai_stream *io; | ||
147 | }; | 198 | }; |
148 | 199 | ||
149 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 200 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
150 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | 201 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) |
151 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) | 202 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) |
203 | #define rsnd_mod_to_io(mod) ((mod)->io) | ||
152 | #define rsnd_mod_id(mod) ((mod)->id) | 204 | #define rsnd_mod_id(mod) ((mod)->id) |
153 | #define for_each_rsnd_mod(pos, n, io) \ | ||
154 | list_for_each_entry_safe(pos, n, &(io)->head, list) | ||
155 | #define rsnd_mod_call(mod, func, rdai, io) \ | ||
156 | (!(mod) ? -ENODEV : \ | ||
157 | !((mod)->ops->func) ? 0 : \ | ||
158 | (mod)->ops->func(mod, rdai, io)) | ||
159 | 205 | ||
160 | void rsnd_mod_init(struct rsnd_priv *priv, | 206 | void rsnd_mod_init(struct rsnd_priv *priv, |
161 | struct rsnd_mod *mod, | 207 | struct rsnd_mod *mod, |
162 | struct rsnd_mod_ops *ops, | 208 | struct rsnd_mod_ops *ops, |
209 | enum rsnd_mod_type type, | ||
163 | int id); | 210 | int id); |
164 | char *rsnd_mod_name(struct rsnd_mod *mod); | 211 | char *rsnd_mod_name(struct rsnd_mod *mod); |
165 | 212 | ||
@@ -168,13 +215,16 @@ char *rsnd_mod_name(struct rsnd_mod *mod); | |||
168 | */ | 215 | */ |
169 | #define RSND_DAI_NAME_SIZE 16 | 216 | #define RSND_DAI_NAME_SIZE 16 |
170 | struct rsnd_dai_stream { | 217 | struct rsnd_dai_stream { |
171 | struct list_head head; /* head of rsnd_mod list */ | ||
172 | struct snd_pcm_substream *substream; | 218 | struct snd_pcm_substream *substream; |
219 | struct rsnd_mod *mod[RSND_MOD_MAX]; | ||
220 | struct rsnd_dai_path_info *info; /* rcar_snd.h */ | ||
173 | int byte_pos; | 221 | int byte_pos; |
174 | int period_pos; | 222 | int period_pos; |
175 | int byte_per_period; | 223 | int byte_per_period; |
176 | int next_period_byte; | 224 | int next_period_byte; |
177 | }; | 225 | }; |
226 | #define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI]) | ||
227 | #define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC]) | ||
178 | 228 | ||
179 | struct rsnd_dai { | 229 | struct rsnd_dai { |
180 | char name[RSND_DAI_NAME_SIZE]; | 230 | char name[RSND_DAI_NAME_SIZE]; |
@@ -189,16 +239,14 @@ struct rsnd_dai { | |||
189 | unsigned int data_alignment:1; | 239 | unsigned int data_alignment:1; |
190 | }; | 240 | }; |
191 | 241 | ||
192 | #define rsnd_dai_nr(priv) ((priv)->dai_nr) | 242 | #define rsnd_rdai_nr(priv) ((priv)->rdai_nr) |
193 | #define for_each_rsnd_dai(rdai, priv, i) \ | 243 | #define for_each_rsnd_dai(rdai, priv, i) \ |
194 | for (i = 0, (rdai) = rsnd_dai_get(priv, i); \ | 244 | for (i = 0; \ |
195 | i < rsnd_dai_nr(priv); \ | 245 | (i < rsnd_rdai_nr(priv)) && \ |
196 | i++, (rdai) = rsnd_dai_get(priv, i)) | 246 | ((rdai) = rsnd_dai_get(priv, i)); \ |
247 | i++) | ||
197 | 248 | ||
198 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); | 249 | struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id); |
199 | int rsnd_dai_disconnect(struct rsnd_mod *mod); | ||
200 | int rsnd_dai_connect(struct rsnd_dai *rdai, struct rsnd_mod *mod, | ||
201 | struct rsnd_dai_stream *io); | ||
202 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); | 250 | int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io); |
203 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | 251 | int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); |
204 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) | 252 | #define rsnd_dai_get_platform_info(rdai) ((rdai)->info) |
@@ -206,21 +254,13 @@ int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai); | |||
206 | 254 | ||
207 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 255 | void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
208 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 256 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
257 | #define rsnd_dai_is_clk_master(rdai) ((rdai)->clk_master) | ||
209 | 258 | ||
210 | /* | 259 | /* |
211 | * R-Car Gen1/Gen2 | 260 | * R-Car Gen1/Gen2 |
212 | */ | 261 | */ |
213 | int rsnd_gen_probe(struct platform_device *pdev, | 262 | int rsnd_gen_probe(struct platform_device *pdev, |
214 | struct rcar_snd_info *info, | ||
215 | struct rsnd_priv *priv); | 263 | struct rsnd_priv *priv); |
216 | void rsnd_gen_remove(struct platform_device *pdev, | ||
217 | struct rsnd_priv *priv); | ||
218 | int rsnd_gen_path_init(struct rsnd_priv *priv, | ||
219 | struct rsnd_dai *rdai, | ||
220 | struct rsnd_dai_stream *io); | ||
221 | int rsnd_gen_path_exit(struct rsnd_priv *priv, | ||
222 | struct rsnd_dai *rdai, | ||
223 | struct rsnd_dai_stream *io); | ||
224 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | 264 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
225 | struct rsnd_mod *mod, | 265 | struct rsnd_mod *mod, |
226 | enum rsnd_reg reg); | 266 | enum rsnd_reg reg); |
@@ -233,14 +273,19 @@ void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | |||
233 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); | 273 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); |
234 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); | 274 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); |
235 | int rsnd_adg_probe(struct platform_device *pdev, | 275 | int rsnd_adg_probe(struct platform_device *pdev, |
236 | struct rcar_snd_info *info, | ||
237 | struct rsnd_priv *priv); | ||
238 | void rsnd_adg_remove(struct platform_device *pdev, | ||
239 | struct rsnd_priv *priv); | 276 | struct rsnd_priv *priv); |
240 | int rsnd_adg_set_convert_clk(struct rsnd_priv *priv, | 277 | int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, |
241 | struct rsnd_mod *mod, | 278 | struct rsnd_mod *mod, |
242 | unsigned int src_rate, | 279 | unsigned int src_rate, |
243 | unsigned int dst_rate); | 280 | unsigned int dst_rate); |
281 | int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, | ||
282 | struct rsnd_dai *rdai, | ||
283 | struct rsnd_dai_stream *io, | ||
284 | unsigned int src_rate, | ||
285 | unsigned int dst_rate); | ||
286 | int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *mod, | ||
287 | struct rsnd_dai *rdai, | ||
288 | struct rsnd_dai_stream *io); | ||
244 | 289 | ||
245 | /* | 290 | /* |
246 | * R-Car sound priv | 291 | * R-Car sound priv |
@@ -257,10 +302,10 @@ struct rsnd_priv { | |||
257 | void *gen; | 302 | void *gen; |
258 | 303 | ||
259 | /* | 304 | /* |
260 | * below value will be filled on rsnd_scu_probe() | 305 | * below value will be filled on rsnd_src_probe() |
261 | */ | 306 | */ |
262 | void *scu; | 307 | void *src; |
263 | int scu_nr; | 308 | int src_nr; |
264 | 309 | ||
265 | /* | 310 | /* |
266 | * below value will be filled on rsnd_adg_probe() | 311 | * below value will be filled on rsnd_adg_probe() |
@@ -270,46 +315,62 @@ struct rsnd_priv { | |||
270 | /* | 315 | /* |
271 | * below value will be filled on rsnd_ssi_probe() | 316 | * below value will be filled on rsnd_ssi_probe() |
272 | */ | 317 | */ |
273 | void *ssiu; | 318 | void *ssi; |
319 | int ssi_nr; | ||
274 | 320 | ||
275 | /* | 321 | /* |
276 | * below value will be filled on rsnd_dai_probe() | 322 | * below value will be filled on rsnd_dai_probe() |
277 | */ | 323 | */ |
278 | struct snd_soc_dai_driver *daidrv; | 324 | struct snd_soc_dai_driver *daidrv; |
279 | struct rsnd_dai *rdai; | 325 | struct rsnd_dai *rdai; |
280 | int dai_nr; | 326 | int rdai_nr; |
281 | }; | 327 | }; |
282 | 328 | ||
283 | #define rsnd_priv_to_dev(priv) ((priv)->dev) | 329 | #define rsnd_priv_to_dev(priv) ((priv)->dev) |
330 | #define rsnd_priv_to_info(priv) ((priv)->info) | ||
284 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) | 331 | #define rsnd_lock(priv, flags) spin_lock_irqsave(&priv->lock, flags) |
285 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) | 332 | #define rsnd_unlock(priv, flags) spin_unlock_irqrestore(&priv->lock, flags) |
286 | 333 | ||
334 | #define rsnd_info_is_playback(priv, type) \ | ||
335 | ({ \ | ||
336 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); \ | ||
337 | int i, is_play = 0; \ | ||
338 | for (i = 0; i < info->dai_info_nr; i++) { \ | ||
339 | if (info->dai_info[i].playback.type == (type)->info) { \ | ||
340 | is_play = 1; \ | ||
341 | break; \ | ||
342 | } \ | ||
343 | } \ | ||
344 | is_play; \ | ||
345 | }) | ||
346 | |||
287 | /* | 347 | /* |
288 | * R-Car SCU | 348 | * R-Car SRC |
289 | */ | 349 | */ |
290 | int rsnd_scu_probe(struct platform_device *pdev, | 350 | int rsnd_src_probe(struct platform_device *pdev, |
291 | struct rcar_snd_info *info, | ||
292 | struct rsnd_priv *priv); | 351 | struct rsnd_priv *priv); |
293 | void rsnd_scu_remove(struct platform_device *pdev, | 352 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); |
294 | struct rsnd_priv *priv); | 353 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
295 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id); | 354 | struct rsnd_dai_stream *io, |
296 | bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod); | ||
297 | unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, | ||
298 | struct rsnd_mod *ssi_mod, | ||
299 | struct snd_pcm_runtime *runtime); | 355 | struct snd_pcm_runtime *runtime); |
356 | int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | ||
357 | struct rsnd_dai *rdai, | ||
358 | struct rsnd_dai_stream *io); | ||
359 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | ||
360 | struct rsnd_dai *rdai, | ||
361 | struct rsnd_dai_stream *io); | ||
300 | 362 | ||
301 | #define rsnd_scu_nr(priv) ((priv)->scu_nr) | 363 | #define rsnd_src_nr(priv) ((priv)->src_nr) |
302 | 364 | ||
303 | /* | 365 | /* |
304 | * R-Car SSI | 366 | * R-Car SSI |
305 | */ | 367 | */ |
306 | int rsnd_ssi_probe(struct platform_device *pdev, | 368 | int rsnd_ssi_probe(struct platform_device *pdev, |
307 | struct rcar_snd_info *info, | ||
308 | struct rsnd_priv *priv); | ||
309 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
310 | struct rsnd_priv *priv); | 369 | struct rsnd_priv *priv); |
311 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 370 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
312 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 371 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
313 | int dai_id, int is_play); | 372 | int dai_id, int is_play); |
373 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | ||
374 | int rsnd_ssi_is_play(struct rsnd_mod *mod); | ||
314 | 375 | ||
315 | #endif | 376 | #endif |
diff --git a/sound/soc/sh/rcar/scu.c b/sound/soc/sh/rcar/scu.c deleted file mode 100644 index 9bb08bb1d455..000000000000 --- a/sound/soc/sh/rcar/scu.c +++ /dev/null | |||
@@ -1,384 +0,0 @@ | |||
1 | /* | ||
2 | * Renesas R-Car SCU support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include "rsnd.h" | ||
12 | |||
13 | struct rsnd_scu { | ||
14 | struct rsnd_scu_platform_info *info; /* rcar_snd.h */ | ||
15 | struct rsnd_mod mod; | ||
16 | struct clk *clk; | ||
17 | }; | ||
18 | |||
19 | #define rsnd_scu_mode_flags(p) ((p)->info->flags) | ||
20 | #define rsnd_scu_convert_rate(p) ((p)->info->convert_rate) | ||
21 | |||
22 | #define RSND_SCU_NAME_SIZE 16 | ||
23 | |||
24 | /* | ||
25 | * ADINR | ||
26 | */ | ||
27 | #define OTBL_24 (0 << 16) | ||
28 | #define OTBL_22 (2 << 16) | ||
29 | #define OTBL_20 (4 << 16) | ||
30 | #define OTBL_18 (6 << 16) | ||
31 | #define OTBL_16 (8 << 16) | ||
32 | |||
33 | /* | ||
34 | * image of SRC (Sampling Rate Converter) | ||
35 | * | ||
36 | * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ | ||
37 | * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | | ||
38 | * 44.1kHz <-> +-----+ +-----+ +-------+ | ||
39 | * ... | ||
40 | * | ||
41 | */ | ||
42 | |||
43 | #define rsnd_mod_to_scu(_mod) \ | ||
44 | container_of((_mod), struct rsnd_scu, mod) | ||
45 | |||
46 | #define for_each_rsnd_scu(pos, priv, i) \ | ||
47 | for ((i) = 0; \ | ||
48 | ((i) < rsnd_scu_nr(priv)) && \ | ||
49 | ((pos) = (struct rsnd_scu *)(priv)->scu + i); \ | ||
50 | i++) | ||
51 | |||
52 | /* Gen1 only */ | ||
53 | static int rsnd_src_set_route_if_gen1(struct rsnd_priv *priv, | ||
54 | struct rsnd_mod *mod, | ||
55 | struct rsnd_dai *rdai, | ||
56 | struct rsnd_dai_stream *io) | ||
57 | { | ||
58 | struct scu_route_config { | ||
59 | u32 mask; | ||
60 | int shift; | ||
61 | } routes[] = { | ||
62 | { 0xF, 0, }, /* 0 */ | ||
63 | { 0xF, 4, }, /* 1 */ | ||
64 | { 0xF, 8, }, /* 2 */ | ||
65 | { 0x7, 12, }, /* 3 */ | ||
66 | { 0x7, 16, }, /* 4 */ | ||
67 | { 0x7, 20, }, /* 5 */ | ||
68 | { 0x7, 24, }, /* 6 */ | ||
69 | { 0x3, 28, }, /* 7 */ | ||
70 | { 0x3, 30, }, /* 8 */ | ||
71 | }; | ||
72 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
73 | u32 mask; | ||
74 | u32 val; | ||
75 | int shift; | ||
76 | int id; | ||
77 | |||
78 | /* | ||
79 | * Gen1 only | ||
80 | */ | ||
81 | if (!rsnd_is_gen1(priv)) | ||
82 | return 0; | ||
83 | |||
84 | id = rsnd_mod_id(mod); | ||
85 | if (id < 0 || id >= ARRAY_SIZE(routes)) | ||
86 | return -EIO; | ||
87 | |||
88 | /* | ||
89 | * SRC_ROUTE_SELECT | ||
90 | */ | ||
91 | val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | ||
92 | val = val << routes[id].shift; | ||
93 | mask = routes[id].mask << routes[id].shift; | ||
94 | |||
95 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
96 | |||
97 | /* | ||
98 | * SRC_TIMING_SELECT | ||
99 | */ | ||
100 | shift = (id % 4) * 8; | ||
101 | mask = 0x1F << shift; | ||
102 | |||
103 | /* | ||
104 | * ADG is used as source clock if SRC was used, | ||
105 | * then, SSI WS is used as destination clock. | ||
106 | * SSI WS is used as source clock if SRC is not used | ||
107 | * (when playback, source/destination become reverse when capture) | ||
108 | */ | ||
109 | if (rsnd_scu_convert_rate(scu)) /* use ADG */ | ||
110 | val = 0; | ||
111 | else if (8 == id) /* use SSI WS, but SRU8 is special */ | ||
112 | val = id << shift; | ||
113 | else /* use SSI WS */ | ||
114 | val = (id + 1) << shift; | ||
115 | |||
116 | switch (id / 4) { | ||
117 | case 0: | ||
118 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | ||
119 | break; | ||
120 | case 1: | ||
121 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | ||
122 | break; | ||
123 | case 2: | ||
124 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | ||
125 | break; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | unsigned int rsnd_scu_get_ssi_rate(struct rsnd_priv *priv, | ||
132 | struct rsnd_mod *ssi_mod, | ||
133 | struct snd_pcm_runtime *runtime) | ||
134 | { | ||
135 | struct rsnd_scu *scu; | ||
136 | unsigned int rate; | ||
137 | |||
138 | /* this function is assuming SSI id = SCU id here */ | ||
139 | scu = rsnd_mod_to_scu(rsnd_scu_mod_get(priv, rsnd_mod_id(ssi_mod))); | ||
140 | |||
141 | /* | ||
142 | * return convert rate if SRC is used, | ||
143 | * otherwise, return runtime->rate as usual | ||
144 | */ | ||
145 | rate = rsnd_scu_convert_rate(scu); | ||
146 | if (!rate) | ||
147 | rate = runtime->rate; | ||
148 | |||
149 | return rate; | ||
150 | } | ||
151 | |||
152 | static int rsnd_scu_convert_rate_ctrl(struct rsnd_priv *priv, | ||
153 | struct rsnd_mod *mod, | ||
154 | struct rsnd_dai *rdai, | ||
155 | struct rsnd_dai_stream *io) | ||
156 | { | ||
157 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
158 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
159 | u32 convert_rate = rsnd_scu_convert_rate(scu); | ||
160 | u32 adinr = runtime->channels; | ||
161 | |||
162 | /* set/clear soft reset */ | ||
163 | rsnd_mod_write(mod, SRC_SWRSR, 0); | ||
164 | rsnd_mod_write(mod, SRC_SWRSR, 1); | ||
165 | |||
166 | /* Initialize the operation of the SRC internal circuits */ | ||
167 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
168 | |||
169 | /* Set channel number and output bit length */ | ||
170 | switch (runtime->sample_bits) { | ||
171 | case 16: | ||
172 | adinr |= OTBL_16; | ||
173 | break; | ||
174 | case 32: | ||
175 | adinr |= OTBL_24; | ||
176 | break; | ||
177 | default: | ||
178 | return -EIO; | ||
179 | } | ||
180 | rsnd_mod_write(mod, SRC_ADINR, adinr); | ||
181 | |||
182 | if (convert_rate) { | ||
183 | u32 fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
184 | int ret; | ||
185 | |||
186 | /* Enable the initial value of IFS */ | ||
187 | rsnd_mod_write(mod, SRC_IFSCR, 1); | ||
188 | |||
189 | /* Set initial value of IFS */ | ||
190 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
191 | |||
192 | /* Select SRC mode (fixed value) */ | ||
193 | rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); | ||
194 | |||
195 | /* Set the restriction value of the FS ratio (98%) */ | ||
196 | rsnd_mod_write(mod, SRC_MNFSR, fsrate / 100 * 98); | ||
197 | |||
198 | if (rsnd_is_gen1(priv)) { | ||
199 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | ||
200 | } | ||
201 | |||
202 | /* set convert clock */ | ||
203 | ret = rsnd_adg_set_convert_clk(priv, mod, | ||
204 | runtime->rate, | ||
205 | convert_rate); | ||
206 | if (ret < 0) | ||
207 | return ret; | ||
208 | } | ||
209 | |||
210 | /* Cancel the initialization and operate the SRC function */ | ||
211 | rsnd_mod_write(mod, SRC_SRCIR, 0); | ||
212 | |||
213 | /* use DMA transfer */ | ||
214 | rsnd_mod_write(mod, BUSIF_MODE, 1); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int rsnd_scu_transfer_start(struct rsnd_priv *priv, | ||
220 | struct rsnd_mod *mod, | ||
221 | struct rsnd_dai *rdai, | ||
222 | struct rsnd_dai_stream *io) | ||
223 | { | ||
224 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
225 | int id = rsnd_mod_id(mod); | ||
226 | u32 val; | ||
227 | |||
228 | if (rsnd_is_gen1(priv)) { | ||
229 | val = (1 << id); | ||
230 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, val, val); | ||
231 | } | ||
232 | |||
233 | if (rsnd_scu_convert_rate(scu)) | ||
234 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static int rsnd_scu_transfer_stop(struct rsnd_priv *priv, | ||
240 | struct rsnd_mod *mod, | ||
241 | struct rsnd_dai *rdai, | ||
242 | struct rsnd_dai_stream *io) | ||
243 | { | ||
244 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
245 | int id = rsnd_mod_id(mod); | ||
246 | u32 mask; | ||
247 | |||
248 | if (rsnd_is_gen1(priv)) { | ||
249 | mask = (1 << id); | ||
250 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, mask, 0); | ||
251 | } | ||
252 | |||
253 | if (rsnd_scu_convert_rate(scu)) | ||
254 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | bool rsnd_scu_hpbif_is_enable(struct rsnd_mod *mod) | ||
260 | { | ||
261 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
262 | u32 flags = rsnd_scu_mode_flags(scu); | ||
263 | |||
264 | return !!(flags & RSND_SCU_USE_HPBIF); | ||
265 | } | ||
266 | |||
267 | static int rsnd_scu_start(struct rsnd_mod *mod, | ||
268 | struct rsnd_dai *rdai, | ||
269 | struct rsnd_dai_stream *io) | ||
270 | { | ||
271 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
272 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
273 | struct device *dev = rsnd_priv_to_dev(priv); | ||
274 | int ret; | ||
275 | |||
276 | /* | ||
277 | * SCU will be used if it has RSND_SCU_USE_HPBIF flags | ||
278 | */ | ||
279 | if (!rsnd_scu_hpbif_is_enable(mod)) { | ||
280 | /* it use PIO transter */ | ||
281 | dev_dbg(dev, "%s%d is not used\n", | ||
282 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | |||
287 | clk_enable(scu->clk); | ||
288 | |||
289 | /* it use DMA transter */ | ||
290 | |||
291 | ret = rsnd_src_set_route_if_gen1(priv, mod, rdai, io); | ||
292 | if (ret < 0) | ||
293 | return ret; | ||
294 | |||
295 | ret = rsnd_scu_convert_rate_ctrl(priv, mod, rdai, io); | ||
296 | if (ret < 0) | ||
297 | return ret; | ||
298 | |||
299 | ret = rsnd_scu_transfer_start(priv, mod, rdai, io); | ||
300 | if (ret < 0) | ||
301 | return ret; | ||
302 | |||
303 | dev_dbg(dev, "%s%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
304 | |||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | static int rsnd_scu_stop(struct rsnd_mod *mod, | ||
309 | struct rsnd_dai *rdai, | ||
310 | struct rsnd_dai_stream *io) | ||
311 | { | ||
312 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
313 | struct rsnd_scu *scu = rsnd_mod_to_scu(mod); | ||
314 | |||
315 | if (!rsnd_scu_hpbif_is_enable(mod)) | ||
316 | return 0; | ||
317 | |||
318 | rsnd_scu_transfer_stop(priv, mod, rdai, io); | ||
319 | |||
320 | clk_disable(scu->clk); | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static struct rsnd_mod_ops rsnd_scu_ops = { | ||
326 | .name = "scu", | ||
327 | .start = rsnd_scu_start, | ||
328 | .stop = rsnd_scu_stop, | ||
329 | }; | ||
330 | |||
331 | struct rsnd_mod *rsnd_scu_mod_get(struct rsnd_priv *priv, int id) | ||
332 | { | ||
333 | if (WARN_ON(id < 0 || id >= rsnd_scu_nr(priv))) | ||
334 | id = 0; | ||
335 | |||
336 | return &((struct rsnd_scu *)(priv->scu) + id)->mod; | ||
337 | } | ||
338 | |||
339 | int rsnd_scu_probe(struct platform_device *pdev, | ||
340 | struct rcar_snd_info *info, | ||
341 | struct rsnd_priv *priv) | ||
342 | { | ||
343 | struct device *dev = rsnd_priv_to_dev(priv); | ||
344 | struct rsnd_scu *scu; | ||
345 | struct clk *clk; | ||
346 | char name[RSND_SCU_NAME_SIZE]; | ||
347 | int i, nr; | ||
348 | |||
349 | /* | ||
350 | * init SCU | ||
351 | */ | ||
352 | nr = info->scu_info_nr; | ||
353 | scu = devm_kzalloc(dev, sizeof(*scu) * nr, GFP_KERNEL); | ||
354 | if (!scu) { | ||
355 | dev_err(dev, "SCU allocate failed\n"); | ||
356 | return -ENOMEM; | ||
357 | } | ||
358 | |||
359 | priv->scu_nr = nr; | ||
360 | priv->scu = scu; | ||
361 | |||
362 | for_each_rsnd_scu(scu, priv, i) { | ||
363 | snprintf(name, RSND_SCU_NAME_SIZE, "scu.%d", i); | ||
364 | |||
365 | clk = devm_clk_get(dev, name); | ||
366 | if (IS_ERR(clk)) | ||
367 | return PTR_ERR(clk); | ||
368 | |||
369 | rsnd_mod_init(priv, &scu->mod, | ||
370 | &rsnd_scu_ops, i); | ||
371 | scu->info = &info->scu_info[i]; | ||
372 | scu->clk = clk; | ||
373 | |||
374 | dev_dbg(dev, "SCU%d probed\n", i); | ||
375 | } | ||
376 | dev_dbg(dev, "scu probed\n"); | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | void rsnd_scu_remove(struct platform_device *pdev, | ||
382 | struct rsnd_priv *priv) | ||
383 | { | ||
384 | } | ||
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c new file mode 100644 index 000000000000..ea6a214985d0 --- /dev/null +++ b/sound/soc/sh/rcar/src.c | |||
@@ -0,0 +1,687 @@ | |||
1 | /* | ||
2 | * Renesas R-Car SRC support | ||
3 | * | ||
4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * published by the Free Software Foundation. | ||
10 | */ | ||
11 | #include "rsnd.h" | ||
12 | |||
13 | struct rsnd_src { | ||
14 | struct rsnd_src_platform_info *info; /* rcar_snd.h */ | ||
15 | struct rsnd_mod mod; | ||
16 | struct clk *clk; | ||
17 | }; | ||
18 | |||
19 | #define RSND_SRC_NAME_SIZE 16 | ||
20 | |||
21 | /* | ||
22 | * ADINR | ||
23 | */ | ||
24 | #define OTBL_24 (0 << 16) | ||
25 | #define OTBL_22 (2 << 16) | ||
26 | #define OTBL_20 (4 << 16) | ||
27 | #define OTBL_18 (6 << 16) | ||
28 | #define OTBL_16 (8 << 16) | ||
29 | |||
30 | #define rsnd_src_mode_flags(p) ((p)->info->flags) | ||
31 | #define rsnd_src_convert_rate(p) ((p)->info->convert_rate) | ||
32 | #define rsnd_mod_to_src(_mod) \ | ||
33 | container_of((_mod), struct rsnd_src, mod) | ||
34 | #define rsnd_src_hpbif_is_enable(src) \ | ||
35 | (rsnd_src_mode_flags(src) & RSND_SCU_USE_HPBIF) | ||
36 | #define rsnd_src_dma_available(src) \ | ||
37 | rsnd_dma_available(rsnd_mod_to_dma(&(src)->mod)) | ||
38 | |||
39 | #define for_each_rsnd_src(pos, priv, i) \ | ||
40 | for ((i) = 0; \ | ||
41 | ((i) < rsnd_src_nr(priv)) && \ | ||
42 | ((pos) = (struct rsnd_src *)(priv)->src + i); \ | ||
43 | i++) | ||
44 | |||
45 | |||
46 | /* | ||
47 | * image of SRC (Sampling Rate Converter) | ||
48 | * | ||
49 | * 96kHz <-> +-----+ 48kHz +-----+ 48kHz +-------+ | ||
50 | * 48kHz <-> | SRC | <------> | SSI | <-----> | codec | | ||
51 | * 44.1kHz <-> +-----+ +-----+ +-------+ | ||
52 | * ... | ||
53 | * | ||
54 | */ | ||
55 | |||
56 | /* | ||
57 | * src.c is caring... | ||
58 | * | ||
59 | * Gen1 | ||
60 | * | ||
61 | * [mem] -> [SRU] -> [SSI] | ||
62 | * |--------| | ||
63 | * | ||
64 | * Gen2 | ||
65 | * | ||
66 | * [mem] -> [SRC] -> [SSIU] -> [SSI] | ||
67 | * |-----------------| | ||
68 | */ | ||
69 | |||
70 | /* | ||
71 | * How to use SRC bypass mode for debugging | ||
72 | * | ||
73 | * SRC has bypass mode, and it is useful for debugging. | ||
74 | * In Gen2 case, | ||
75 | * SRCm_MODE controls whether SRC is used or not | ||
76 | * SSI_MODE0 controls whether SSIU which receives SRC data | ||
77 | * is used or not. | ||
78 | * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC, | ||
79 | * but SRC bypass mode needs SSI_MODE0 only. | ||
80 | * | ||
81 | * This driver request | ||
82 | * struct rsnd_src_platform_info { | ||
83 | * u32 flags; | ||
84 | * u32 convert_rate; | ||
85 | * } | ||
86 | * | ||
87 | * rsnd_src_hpbif_is_enable() will be true | ||
88 | * if flags had RSND_SRC_USE_HPBIF, | ||
89 | * and it controls whether SSIU is used or not. | ||
90 | * | ||
91 | * rsnd_src_convert_rate() indicates | ||
92 | * above convert_rate, and it controls | ||
93 | * whether SRC is used or not. | ||
94 | * | ||
95 | * ex) doesn't use SRC | ||
96 | * struct rsnd_src_platform_info info = { | ||
97 | * .flags = 0, | ||
98 | * .convert_rate = 0, | ||
99 | * }; | ||
100 | * | ||
101 | * ex) uses SRC | ||
102 | * struct rsnd_src_platform_info info = { | ||
103 | * .flags = RSND_SRC_USE_HPBIF, | ||
104 | * .convert_rate = 48000, | ||
105 | * }; | ||
106 | * | ||
107 | * ex) uses SRC bypass mode | ||
108 | * struct rsnd_src_platform_info info = { | ||
109 | * .flags = RSND_SRC_USE_HPBIF, | ||
110 | * .convert_rate = 0, | ||
111 | * }; | ||
112 | * | ||
113 | */ | ||
114 | |||
115 | /* | ||
116 | * Gen1/Gen2 common functions | ||
117 | */ | ||
118 | int rsnd_src_ssi_mode_init(struct rsnd_mod *ssi_mod, | ||
119 | struct rsnd_dai *rdai, | ||
120 | struct rsnd_dai_stream *io) | ||
121 | { | ||
122 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
123 | struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); | ||
124 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
125 | int ssi_id = rsnd_mod_id(ssi_mod); | ||
126 | int has_src = 0; | ||
127 | |||
128 | /* | ||
129 | * SSI_MODE0 | ||
130 | */ | ||
131 | if (info->dai_info) { | ||
132 | has_src = !!src_mod; | ||
133 | } else { | ||
134 | struct rsnd_src *src = rsnd_mod_to_src(src_mod); | ||
135 | has_src = rsnd_src_hpbif_is_enable(src); | ||
136 | } | ||
137 | |||
138 | rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), | ||
139 | has_src ? 0 : (1 << ssi_id)); | ||
140 | |||
141 | /* | ||
142 | * SSI_MODE1 | ||
143 | */ | ||
144 | if (rsnd_ssi_is_pin_sharing(ssi_mod)) { | ||
145 | int shift = -1; | ||
146 | switch (ssi_id) { | ||
147 | case 1: | ||
148 | shift = 0; | ||
149 | break; | ||
150 | case 2: | ||
151 | shift = 2; | ||
152 | break; | ||
153 | case 4: | ||
154 | shift = 16; | ||
155 | break; | ||
156 | } | ||
157 | |||
158 | if (shift >= 0) | ||
159 | rsnd_mod_bset(ssi_mod, SSI_MODE1, | ||
160 | 0x3 << shift, | ||
161 | rsnd_dai_is_clk_master(rdai) ? | ||
162 | 0x2 << shift : 0x1 << shift); | ||
163 | } | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod, | ||
169 | struct rsnd_dai *rdai, | ||
170 | struct rsnd_dai_stream *io) | ||
171 | { | ||
172 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
173 | |||
174 | /* enable PIO interrupt if Gen2 */ | ||
175 | if (rsnd_is_gen2(priv)) | ||
176 | rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | ||
182 | struct rsnd_dai_stream *io, | ||
183 | struct snd_pcm_runtime *runtime) | ||
184 | { | ||
185 | struct rsnd_src *src; | ||
186 | unsigned int rate; | ||
187 | |||
188 | src = rsnd_mod_to_src(rsnd_io_to_mod_src(io)); | ||
189 | |||
190 | /* | ||
191 | * return convert rate if SRC is used, | ||
192 | * otherwise, return runtime->rate as usual | ||
193 | */ | ||
194 | rate = rsnd_src_convert_rate(src); | ||
195 | if (!rate) | ||
196 | rate = runtime->rate; | ||
197 | |||
198 | return rate; | ||
199 | } | ||
200 | |||
201 | static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, | ||
202 | struct rsnd_dai *rdai, | ||
203 | struct rsnd_dai_stream *io) | ||
204 | { | ||
205 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
206 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
207 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
208 | u32 adinr = runtime->channels; | ||
209 | u32 fsrate = 0; | ||
210 | |||
211 | if (convert_rate) | ||
212 | fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
213 | |||
214 | /* set/clear soft reset */ | ||
215 | rsnd_mod_write(mod, SRC_SWRSR, 0); | ||
216 | rsnd_mod_write(mod, SRC_SWRSR, 1); | ||
217 | |||
218 | /* | ||
219 | * Initialize the operation of the SRC internal circuits | ||
220 | * see rsnd_src_start() | ||
221 | */ | ||
222 | rsnd_mod_write(mod, SRC_SRCIR, 1); | ||
223 | |||
224 | /* Set channel number and output bit length */ | ||
225 | switch (runtime->sample_bits) { | ||
226 | case 16: | ||
227 | adinr |= OTBL_16; | ||
228 | break; | ||
229 | case 32: | ||
230 | adinr |= OTBL_24; | ||
231 | break; | ||
232 | default: | ||
233 | return -EIO; | ||
234 | } | ||
235 | rsnd_mod_write(mod, SRC_ADINR, adinr); | ||
236 | |||
237 | /* Enable the initial value of IFS */ | ||
238 | if (fsrate) { | ||
239 | rsnd_mod_write(mod, SRC_IFSCR, 1); | ||
240 | |||
241 | /* Set initial value of IFS */ | ||
242 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
243 | } | ||
244 | |||
245 | /* use DMA transfer */ | ||
246 | rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int rsnd_src_init(struct rsnd_mod *mod, | ||
252 | struct rsnd_dai *rdai, | ||
253 | struct rsnd_dai_stream *io) | ||
254 | { | ||
255 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
256 | |||
257 | clk_enable(src->clk); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | static int rsnd_src_quit(struct rsnd_mod *mod, | ||
263 | struct rsnd_dai *rdai, | ||
264 | struct rsnd_dai_stream *io) | ||
265 | { | ||
266 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
267 | |||
268 | clk_disable(src->clk); | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static int rsnd_src_start(struct rsnd_mod *mod, | ||
274 | struct rsnd_dai *rdai, | ||
275 | struct rsnd_dai_stream *io) | ||
276 | { | ||
277 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
278 | |||
279 | /* | ||
280 | * Cancel the initialization and operate the SRC function | ||
281 | * see rsnd_src_set_convert_rate() | ||
282 | */ | ||
283 | rsnd_mod_write(mod, SRC_SRCIR, 0); | ||
284 | |||
285 | if (rsnd_src_convert_rate(src)) | ||
286 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
287 | |||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | |||
292 | static int rsnd_src_stop(struct rsnd_mod *mod, | ||
293 | struct rsnd_dai *rdai, | ||
294 | struct rsnd_dai_stream *io) | ||
295 | { | ||
296 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
297 | |||
298 | if (rsnd_src_convert_rate(src)) | ||
299 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | static struct rsnd_mod_ops rsnd_src_non_ops = { | ||
305 | .name = "src (non)", | ||
306 | }; | ||
307 | |||
308 | /* | ||
309 | * Gen1 functions | ||
310 | */ | ||
311 | static int rsnd_src_set_route_gen1(struct rsnd_mod *mod, | ||
312 | struct rsnd_dai *rdai, | ||
313 | struct rsnd_dai_stream *io) | ||
314 | { | ||
315 | struct src_route_config { | ||
316 | u32 mask; | ||
317 | int shift; | ||
318 | } routes[] = { | ||
319 | { 0xF, 0, }, /* 0 */ | ||
320 | { 0xF, 4, }, /* 1 */ | ||
321 | { 0xF, 8, }, /* 2 */ | ||
322 | { 0x7, 12, }, /* 3 */ | ||
323 | { 0x7, 16, }, /* 4 */ | ||
324 | { 0x7, 20, }, /* 5 */ | ||
325 | { 0x7, 24, }, /* 6 */ | ||
326 | { 0x3, 28, }, /* 7 */ | ||
327 | { 0x3, 30, }, /* 8 */ | ||
328 | }; | ||
329 | u32 mask; | ||
330 | u32 val; | ||
331 | int id; | ||
332 | |||
333 | id = rsnd_mod_id(mod); | ||
334 | if (id < 0 || id >= ARRAY_SIZE(routes)) | ||
335 | return -EIO; | ||
336 | |||
337 | /* | ||
338 | * SRC_ROUTE_SELECT | ||
339 | */ | ||
340 | val = rsnd_dai_is_play(rdai, io) ? 0x1 : 0x2; | ||
341 | val = val << routes[id].shift; | ||
342 | mask = routes[id].mask << routes[id].shift; | ||
343 | |||
344 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
345 | |||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod, | ||
350 | struct rsnd_dai *rdai, | ||
351 | struct rsnd_dai_stream *io) | ||
352 | { | ||
353 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
354 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
355 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
356 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
357 | u32 mask; | ||
358 | u32 val; | ||
359 | int shift; | ||
360 | int id = rsnd_mod_id(mod); | ||
361 | int ret; | ||
362 | |||
363 | /* | ||
364 | * SRC_TIMING_SELECT | ||
365 | */ | ||
366 | shift = (id % 4) * 8; | ||
367 | mask = 0x1F << shift; | ||
368 | |||
369 | /* | ||
370 | * ADG is used as source clock if SRC was used, | ||
371 | * then, SSI WS is used as destination clock. | ||
372 | * SSI WS is used as source clock if SRC is not used | ||
373 | * (when playback, source/destination become reverse when capture) | ||
374 | */ | ||
375 | ret = 0; | ||
376 | if (convert_rate) { | ||
377 | /* use ADG */ | ||
378 | val = 0; | ||
379 | ret = rsnd_adg_set_convert_clk_gen1(priv, mod, | ||
380 | runtime->rate, | ||
381 | convert_rate); | ||
382 | } else if (8 == id) { | ||
383 | /* use SSI WS, but SRU8 is special */ | ||
384 | val = id << shift; | ||
385 | } else { | ||
386 | /* use SSI WS */ | ||
387 | val = (id + 1) << shift; | ||
388 | } | ||
389 | |||
390 | if (ret < 0) | ||
391 | return ret; | ||
392 | |||
393 | switch (id / 4) { | ||
394 | case 0: | ||
395 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | ||
396 | break; | ||
397 | case 1: | ||
398 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | ||
399 | break; | ||
400 | case 2: | ||
401 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | ||
402 | break; | ||
403 | } | ||
404 | |||
405 | return 0; | ||
406 | } | ||
407 | |||
408 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | ||
409 | struct rsnd_dai *rdai, | ||
410 | struct rsnd_dai_stream *io) | ||
411 | { | ||
412 | int ret; | ||
413 | |||
414 | ret = rsnd_src_set_convert_rate(mod, rdai, io); | ||
415 | if (ret < 0) | ||
416 | return ret; | ||
417 | |||
418 | /* Select SRC mode (fixed value) */ | ||
419 | rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); | ||
420 | |||
421 | /* Set the restriction value of the FS ratio (98%) */ | ||
422 | rsnd_mod_write(mod, SRC_MNFSR, | ||
423 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); | ||
424 | |||
425 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | ||
426 | |||
427 | return 0; | ||
428 | } | ||
429 | |||
430 | static int rsnd_src_init_gen1(struct rsnd_mod *mod, | ||
431 | struct rsnd_dai *rdai, | ||
432 | struct rsnd_dai_stream *io) | ||
433 | { | ||
434 | int ret; | ||
435 | |||
436 | ret = rsnd_src_init(mod, rdai, io); | ||
437 | if (ret < 0) | ||
438 | return ret; | ||
439 | |||
440 | ret = rsnd_src_set_route_gen1(mod, rdai, io); | ||
441 | if (ret < 0) | ||
442 | return ret; | ||
443 | |||
444 | ret = rsnd_src_set_convert_rate_gen1(mod, rdai, io); | ||
445 | if (ret < 0) | ||
446 | return ret; | ||
447 | |||
448 | ret = rsnd_src_set_convert_timing_gen1(mod, rdai, io); | ||
449 | if (ret < 0) | ||
450 | return ret; | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static int rsnd_src_start_gen1(struct rsnd_mod *mod, | ||
456 | struct rsnd_dai *rdai, | ||
457 | struct rsnd_dai_stream *io) | ||
458 | { | ||
459 | int id = rsnd_mod_id(mod); | ||
460 | |||
461 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); | ||
462 | |||
463 | return rsnd_src_start(mod, rdai, io); | ||
464 | } | ||
465 | |||
466 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | ||
467 | struct rsnd_dai *rdai, | ||
468 | struct rsnd_dai_stream *io) | ||
469 | { | ||
470 | int id = rsnd_mod_id(mod); | ||
471 | |||
472 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); | ||
473 | |||
474 | return rsnd_src_stop(mod, rdai, io); | ||
475 | } | ||
476 | |||
477 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { | ||
478 | .name = "sru (gen1)", | ||
479 | .init = rsnd_src_init_gen1, | ||
480 | .quit = rsnd_src_quit, | ||
481 | .start = rsnd_src_start_gen1, | ||
482 | .stop = rsnd_src_stop_gen1, | ||
483 | }; | ||
484 | |||
485 | /* | ||
486 | * Gen2 functions | ||
487 | */ | ||
488 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | ||
489 | struct rsnd_dai *rdai, | ||
490 | struct rsnd_dai_stream *io) | ||
491 | { | ||
492 | int ret; | ||
493 | |||
494 | ret = rsnd_src_set_convert_rate(mod, rdai, io); | ||
495 | if (ret < 0) | ||
496 | return ret; | ||
497 | |||
498 | rsnd_mod_write(mod, SSI_BUSIF_ADINR, rsnd_mod_read(mod, SRC_ADINR)); | ||
499 | rsnd_mod_write(mod, SSI_BUSIF_MODE, rsnd_mod_read(mod, SRC_BUSIF_MODE)); | ||
500 | |||
501 | rsnd_mod_write(mod, SRC_SRCCR, 0x00011110); | ||
502 | |||
503 | rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); | ||
504 | rsnd_mod_write(mod, SRC_BSISR, 0x00100060); | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static int rsnd_src_set_convert_timing_gen2(struct rsnd_mod *mod, | ||
510 | struct rsnd_dai *rdai, | ||
511 | struct rsnd_dai_stream *io) | ||
512 | { | ||
513 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
514 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
515 | u32 convert_rate = rsnd_src_convert_rate(src); | ||
516 | int ret; | ||
517 | |||
518 | if (convert_rate) | ||
519 | ret = rsnd_adg_set_convert_clk_gen2(mod, rdai, io, | ||
520 | runtime->rate, | ||
521 | convert_rate); | ||
522 | else | ||
523 | ret = rsnd_adg_set_convert_timing_gen2(mod, rdai, io); | ||
524 | |||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | ||
529 | struct rsnd_dai *rdai, | ||
530 | struct rsnd_dai_stream *io) | ||
531 | { | ||
532 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
533 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
534 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
535 | struct rsnd_mod *ssi = rsnd_ssi_mod_get(priv, rsnd_mod_id(mod)); | ||
536 | struct device *dev = rsnd_priv_to_dev(priv); | ||
537 | int ret; | ||
538 | int is_play; | ||
539 | |||
540 | if (info->dai_info) | ||
541 | is_play = rsnd_info_is_playback(priv, src); | ||
542 | else | ||
543 | is_play = rsnd_ssi_is_play(ssi); | ||
544 | |||
545 | ret = rsnd_dma_init(priv, | ||
546 | rsnd_mod_to_dma(mod), | ||
547 | is_play, | ||
548 | src->info->dma_id); | ||
549 | if (ret < 0) | ||
550 | dev_err(dev, "SRC DMA failed\n"); | ||
551 | |||
552 | return ret; | ||
553 | } | ||
554 | |||
555 | static int rsnd_src_remove_gen2(struct rsnd_mod *mod, | ||
556 | struct rsnd_dai *rdai, | ||
557 | struct rsnd_dai_stream *io) | ||
558 | { | ||
559 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | ||
560 | |||
561 | return 0; | ||
562 | } | ||
563 | |||
564 | static int rsnd_src_init_gen2(struct rsnd_mod *mod, | ||
565 | struct rsnd_dai *rdai, | ||
566 | struct rsnd_dai_stream *io) | ||
567 | { | ||
568 | int ret; | ||
569 | |||
570 | ret = rsnd_src_init(mod, rdai, io); | ||
571 | if (ret < 0) | ||
572 | return ret; | ||
573 | |||
574 | ret = rsnd_src_set_convert_rate_gen2(mod, rdai, io); | ||
575 | if (ret < 0) | ||
576 | return ret; | ||
577 | |||
578 | ret = rsnd_src_set_convert_timing_gen2(mod, rdai, io); | ||
579 | if (ret < 0) | ||
580 | return ret; | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static int rsnd_src_start_gen2(struct rsnd_mod *mod, | ||
586 | struct rsnd_dai *rdai, | ||
587 | struct rsnd_dai_stream *io) | ||
588 | { | ||
589 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
590 | |||
591 | rsnd_dma_start(rsnd_mod_to_dma(&src->mod)); | ||
592 | |||
593 | rsnd_mod_write(mod, SSI_CTRL, 0x1); | ||
594 | rsnd_mod_write(mod, SRC_CTRL, 0x11); | ||
595 | |||
596 | return rsnd_src_start(mod, rdai, io); | ||
597 | } | ||
598 | |||
599 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | ||
600 | struct rsnd_dai *rdai, | ||
601 | struct rsnd_dai_stream *io) | ||
602 | { | ||
603 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
604 | |||
605 | rsnd_mod_write(mod, SSI_CTRL, 0); | ||
606 | rsnd_mod_write(mod, SRC_CTRL, 0); | ||
607 | |||
608 | rsnd_dma_stop(rsnd_mod_to_dma(&src->mod)); | ||
609 | |||
610 | return rsnd_src_stop(mod, rdai, io); | ||
611 | } | ||
612 | |||
613 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { | ||
614 | .name = "src (gen2)", | ||
615 | .probe = rsnd_src_probe_gen2, | ||
616 | .remove = rsnd_src_remove_gen2, | ||
617 | .init = rsnd_src_init_gen2, | ||
618 | .quit = rsnd_src_quit, | ||
619 | .start = rsnd_src_start_gen2, | ||
620 | .stop = rsnd_src_stop_gen2, | ||
621 | }; | ||
622 | |||
623 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | ||
624 | { | ||
625 | if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) | ||
626 | id = 0; | ||
627 | |||
628 | return &((struct rsnd_src *)(priv->src) + id)->mod; | ||
629 | } | ||
630 | |||
631 | int rsnd_src_probe(struct platform_device *pdev, | ||
632 | struct rsnd_priv *priv) | ||
633 | { | ||
634 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
635 | struct device *dev = rsnd_priv_to_dev(priv); | ||
636 | struct rsnd_src *src; | ||
637 | struct rsnd_mod_ops *ops; | ||
638 | struct clk *clk; | ||
639 | char name[RSND_SRC_NAME_SIZE]; | ||
640 | int i, nr; | ||
641 | |||
642 | /* | ||
643 | * init SRC | ||
644 | */ | ||
645 | nr = info->src_info_nr; | ||
646 | if (!nr) | ||
647 | return 0; | ||
648 | |||
649 | src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); | ||
650 | if (!src) { | ||
651 | dev_err(dev, "SRC allocate failed\n"); | ||
652 | return -ENOMEM; | ||
653 | } | ||
654 | |||
655 | priv->src_nr = nr; | ||
656 | priv->src = src; | ||
657 | |||
658 | for_each_rsnd_src(src, priv, i) { | ||
659 | snprintf(name, RSND_SRC_NAME_SIZE, "src.%d", i); | ||
660 | |||
661 | clk = devm_clk_get(dev, name); | ||
662 | if (IS_ERR(clk)) { | ||
663 | snprintf(name, RSND_SRC_NAME_SIZE, "scu.%d", i); | ||
664 | clk = devm_clk_get(dev, name); | ||
665 | } | ||
666 | |||
667 | if (IS_ERR(clk)) | ||
668 | return PTR_ERR(clk); | ||
669 | |||
670 | src->info = &info->src_info[i]; | ||
671 | src->clk = clk; | ||
672 | |||
673 | ops = &rsnd_src_non_ops; | ||
674 | if (rsnd_src_hpbif_is_enable(src)) { | ||
675 | if (rsnd_is_gen1(priv)) | ||
676 | ops = &rsnd_src_gen1_ops; | ||
677 | if (rsnd_is_gen2(priv)) | ||
678 | ops = &rsnd_src_gen2_ops; | ||
679 | } | ||
680 | |||
681 | rsnd_mod_init(priv, &src->mod, ops, RSND_MOD_SRC, i); | ||
682 | |||
683 | dev_dbg(dev, "SRC%d probed\n", i); | ||
684 | } | ||
685 | |||
686 | return 0; | ||
687 | } | ||
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 4b8cf7ca9d19..633b23d209b9 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
@@ -64,108 +64,29 @@ struct rsnd_ssi { | |||
64 | struct rsnd_mod mod; | 64 | struct rsnd_mod mod; |
65 | 65 | ||
66 | struct rsnd_dai *rdai; | 66 | struct rsnd_dai *rdai; |
67 | struct rsnd_dai_stream *io; | ||
68 | u32 cr_own; | 67 | u32 cr_own; |
69 | u32 cr_clk; | 68 | u32 cr_clk; |
70 | u32 cr_etc; | 69 | u32 cr_etc; |
71 | int err; | 70 | int err; |
72 | int dma_offset; | ||
73 | unsigned int usrcnt; | 71 | unsigned int usrcnt; |
74 | unsigned int rate; | 72 | unsigned int rate; |
75 | }; | 73 | }; |
76 | 74 | ||
77 | struct rsnd_ssiu { | ||
78 | u32 ssi_mode0; | ||
79 | u32 ssi_mode1; | ||
80 | |||
81 | int ssi_nr; | ||
82 | struct rsnd_ssi *ssi; | ||
83 | }; | ||
84 | |||
85 | #define for_each_rsnd_ssi(pos, priv, i) \ | 75 | #define for_each_rsnd_ssi(pos, priv, i) \ |
86 | for (i = 0; \ | 76 | for (i = 0; \ |
87 | (i < rsnd_ssi_nr(priv)) && \ | 77 | (i < rsnd_ssi_nr(priv)) && \ |
88 | ((pos) = ((struct rsnd_ssiu *)((priv)->ssiu))->ssi + i); \ | 78 | ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ |
89 | i++) | 79 | i++) |
90 | 80 | ||
91 | #define rsnd_ssi_nr(priv) (((struct rsnd_ssiu *)((priv)->ssiu))->ssi_nr) | 81 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) |
92 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 82 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
93 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) | 83 | #define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma)) |
94 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) | 84 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0) |
95 | #define rsnd_ssi_dma_available(ssi) \ | 85 | #define rsnd_ssi_dma_available(ssi) \ |
96 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) | 86 | rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod)) |
97 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) | 87 | #define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent) |
98 | #define rsnd_rdai_is_clk_master(rdai) ((rdai)->clk_master) | ||
99 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 88 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) |
100 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | 89 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) |
101 | #define rsnd_ssi_to_ssiu(ssi)\ | ||
102 | (((struct rsnd_ssiu *)((ssi) - rsnd_mod_id(&(ssi)->mod))) - 1) | ||
103 | |||
104 | static void rsnd_ssi_mode_set(struct rsnd_priv *priv, | ||
105 | struct rsnd_dai *rdai, | ||
106 | struct rsnd_ssi *ssi) | ||
107 | { | ||
108 | struct device *dev = rsnd_priv_to_dev(priv); | ||
109 | struct rsnd_mod *scu; | ||
110 | struct rsnd_ssiu *ssiu = rsnd_ssi_to_ssiu(ssi); | ||
111 | int id = rsnd_mod_id(&ssi->mod); | ||
112 | u32 flags; | ||
113 | u32 val; | ||
114 | |||
115 | scu = rsnd_scu_mod_get(priv, rsnd_mod_id(&ssi->mod)); | ||
116 | |||
117 | /* | ||
118 | * SSI_MODE0 | ||
119 | */ | ||
120 | |||
121 | /* see also BUSIF_MODE */ | ||
122 | if (rsnd_scu_hpbif_is_enable(scu)) { | ||
123 | ssiu->ssi_mode0 &= ~(1 << id); | ||
124 | dev_dbg(dev, "SSI%d uses DEPENDENT mode\n", id); | ||
125 | } else { | ||
126 | ssiu->ssi_mode0 |= (1 << id); | ||
127 | dev_dbg(dev, "SSI%d uses INDEPENDENT mode\n", id); | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * SSI_MODE1 | ||
132 | */ | ||
133 | #define ssi_parent_set(p, sync, adg, ext) \ | ||
134 | do { \ | ||
135 | ssi->parent = ssiu->ssi + p; \ | ||
136 | if (rsnd_rdai_is_clk_master(rdai)) \ | ||
137 | val = adg; \ | ||
138 | else \ | ||
139 | val = ext; \ | ||
140 | if (flags & RSND_SSI_SYNC) \ | ||
141 | val |= sync; \ | ||
142 | } while (0) | ||
143 | |||
144 | flags = rsnd_ssi_mode_flags(ssi); | ||
145 | if (flags & RSND_SSI_CLK_PIN_SHARE) { | ||
146 | |||
147 | val = 0; | ||
148 | switch (id) { | ||
149 | case 1: | ||
150 | ssi_parent_set(0, (1 << 4), (0x2 << 0), (0x1 << 0)); | ||
151 | break; | ||
152 | case 2: | ||
153 | ssi_parent_set(0, (1 << 4), (0x2 << 2), (0x1 << 2)); | ||
154 | break; | ||
155 | case 4: | ||
156 | ssi_parent_set(3, (1 << 20), (0x2 << 16), (0x1 << 16)); | ||
157 | break; | ||
158 | case 8: | ||
159 | ssi_parent_set(7, 0, 0, 0); | ||
160 | break; | ||
161 | } | ||
162 | |||
163 | ssiu->ssi_mode1 |= val; | ||
164 | } | ||
165 | |||
166 | rsnd_mod_write(&ssi->mod, SSI_MODE0, ssiu->ssi_mode0); | ||
167 | rsnd_mod_write(&ssi->mod, SSI_MODE1, ssiu->ssi_mode1); | ||
168 | } | ||
169 | 90 | ||
170 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | 91 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, |
171 | u32 bit) | 92 | u32 bit) |
@@ -200,7 +121,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
200 | 1, 2, 4, 8, 16, 6, 12, | 121 | 1, 2, 4, 8, 16, 6, 12, |
201 | }; | 122 | }; |
202 | unsigned int main_rate; | 123 | unsigned int main_rate; |
203 | unsigned int rate = rsnd_scu_get_ssi_rate(priv, &ssi->mod, runtime); | 124 | unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); |
204 | 125 | ||
205 | /* | 126 | /* |
206 | * Find best clock, and try to start ADG | 127 | * Find best clock, and try to start ADG |
@@ -252,7 +173,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | |||
252 | if (0 == ssi->usrcnt) { | 173 | if (0 == ssi->usrcnt) { |
253 | clk_enable(ssi->clk); | 174 | clk_enable(ssi->clk); |
254 | 175 | ||
255 | if (rsnd_rdai_is_clk_master(rdai)) { | 176 | if (rsnd_dai_is_clk_master(rdai)) { |
256 | if (rsnd_ssi_clk_from_parent(ssi)) | 177 | if (rsnd_ssi_clk_from_parent(ssi)) |
257 | rsnd_ssi_hw_start(ssi->parent, rdai, io); | 178 | rsnd_ssi_hw_start(ssi->parent, rdai, io); |
258 | else | 179 | else |
@@ -302,7 +223,7 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi, | |||
302 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ | 223 | rsnd_mod_write(&ssi->mod, SSICR, cr); /* disabled all */ |
303 | rsnd_ssi_status_check(&ssi->mod, IIRQ); | 224 | rsnd_ssi_status_check(&ssi->mod, IIRQ); |
304 | 225 | ||
305 | if (rsnd_rdai_is_clk_master(rdai)) { | 226 | if (rsnd_dai_is_clk_master(rdai)) { |
306 | if (rsnd_ssi_clk_from_parent(ssi)) | 227 | if (rsnd_ssi_clk_from_parent(ssi)) |
307 | rsnd_ssi_hw_stop(ssi->parent, rdai); | 228 | rsnd_ssi_hw_stop(ssi->parent, rdai); |
308 | else | 229 | else |
@@ -323,8 +244,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
323 | struct rsnd_dai_stream *io) | 244 | struct rsnd_dai_stream *io) |
324 | { | 245 | { |
325 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 246 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
326 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
327 | struct device *dev = rsnd_priv_to_dev(priv); | ||
328 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 247 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
329 | u32 cr; | 248 | u32 cr; |
330 | 249 | ||
@@ -365,13 +284,10 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
365 | * set ssi parameter | 284 | * set ssi parameter |
366 | */ | 285 | */ |
367 | ssi->rdai = rdai; | 286 | ssi->rdai = rdai; |
368 | ssi->io = io; | ||
369 | ssi->cr_own = cr; | 287 | ssi->cr_own = cr; |
370 | ssi->err = -1; /* ignore 1st error */ | 288 | ssi->err = -1; /* ignore 1st error */ |
371 | 289 | ||
372 | rsnd_ssi_mode_set(priv, rdai, ssi); | 290 | rsnd_src_ssi_mode_init(mod, rdai, io); |
373 | |||
374 | dev_dbg(dev, "%s.%d init\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
375 | 291 | ||
376 | return 0; | 292 | return 0; |
377 | } | 293 | } |
@@ -384,13 +300,10 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
384 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 300 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
385 | struct device *dev = rsnd_priv_to_dev(priv); | 301 | struct device *dev = rsnd_priv_to_dev(priv); |
386 | 302 | ||
387 | dev_dbg(dev, "%s.%d quit\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
388 | |||
389 | if (ssi->err > 0) | 303 | if (ssi->err > 0) |
390 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); | 304 | dev_warn(dev, "ssi under/over flow err = %d\n", ssi->err); |
391 | 305 | ||
392 | ssi->rdai = NULL; | 306 | ssi->rdai = NULL; |
393 | ssi->io = NULL; | ||
394 | ssi->cr_own = 0; | 307 | ssi->cr_own = 0; |
395 | ssi->err = 0; | 308 | ssi->err = 0; |
396 | 309 | ||
@@ -414,8 +327,9 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | |||
414 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | 327 | static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) |
415 | { | 328 | { |
416 | struct rsnd_ssi *ssi = data; | 329 | struct rsnd_ssi *ssi = data; |
417 | struct rsnd_dai_stream *io = ssi->io; | 330 | struct rsnd_mod *mod = &ssi->mod; |
418 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | 331 | struct rsnd_dai_stream *io = rsnd_mod_to_io(mod); |
332 | u32 status = rsnd_mod_read(mod, SSISR); | ||
419 | irqreturn_t ret = IRQ_NONE; | 333 | irqreturn_t ret = IRQ_NONE; |
420 | 334 | ||
421 | if (io && (status & DIRQ)) { | 335 | if (io && (status & DIRQ)) { |
@@ -432,9 +346,9 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
432 | * see rsnd_ssi_init() | 346 | * see rsnd_ssi_init() |
433 | */ | 347 | */ |
434 | if (rsnd_dai_is_play(rdai, io)) | 348 | if (rsnd_dai_is_play(rdai, io)) |
435 | rsnd_mod_write(&ssi->mod, SSITDR, *buf); | 349 | rsnd_mod_write(mod, SSITDR, *buf); |
436 | else | 350 | else |
437 | *buf = rsnd_mod_read(&ssi->mod, SSIRDR); | 351 | *buf = rsnd_mod_read(mod, SSIRDR); |
438 | 352 | ||
439 | rsnd_dai_pointer_update(io, sizeof(*buf)); | 353 | rsnd_dai_pointer_update(io, sizeof(*buf)); |
440 | 354 | ||
@@ -444,25 +358,39 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data) | |||
444 | return ret; | 358 | return ret; |
445 | } | 359 | } |
446 | 360 | ||
447 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | 361 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, |
448 | struct rsnd_dai *rdai, | 362 | struct rsnd_dai *rdai, |
449 | struct rsnd_dai_stream *io) | 363 | struct rsnd_dai_stream *io) |
450 | { | 364 | { |
451 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 365 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
452 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
453 | struct device *dev = rsnd_priv_to_dev(priv); | 366 | struct device *dev = rsnd_priv_to_dev(priv); |
367 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
368 | int irq = ssi->info->pio_irq; | ||
369 | int ret; | ||
370 | |||
371 | ret = devm_request_irq(dev, irq, | ||
372 | rsnd_ssi_pio_interrupt, | ||
373 | IRQF_SHARED, | ||
374 | dev_name(dev), ssi); | ||
375 | if (ret) | ||
376 | dev_err(dev, "SSI request interrupt failed\n"); | ||
377 | |||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | static int rsnd_ssi_pio_start(struct rsnd_mod *mod, | ||
382 | struct rsnd_dai *rdai, | ||
383 | struct rsnd_dai_stream *io) | ||
384 | { | ||
385 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
454 | 386 | ||
455 | /* enable PIO IRQ */ | 387 | /* enable PIO IRQ */ |
456 | ssi->cr_etc = UIEN | OIEN | DIEN; | 388 | ssi->cr_etc = UIEN | OIEN | DIEN; |
457 | 389 | ||
458 | /* enable PIO interrupt if gen2 */ | 390 | rsnd_src_enable_ssi_irq(mod, rdai, io); |
459 | if (rsnd_is_gen2(priv)) | ||
460 | rsnd_mod_write(&ssi->mod, INT_ENABLE, 0x0f000000); | ||
461 | 391 | ||
462 | rsnd_ssi_hw_start(ssi, rdai, io); | 392 | rsnd_ssi_hw_start(ssi, rdai, io); |
463 | 393 | ||
464 | dev_dbg(dev, "%s.%d start\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
465 | |||
466 | return 0; | 394 | return 0; |
467 | } | 395 | } |
468 | 396 | ||
@@ -470,12 +398,8 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
470 | struct rsnd_dai *rdai, | 398 | struct rsnd_dai *rdai, |
471 | struct rsnd_dai_stream *io) | 399 | struct rsnd_dai_stream *io) |
472 | { | 400 | { |
473 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
474 | struct device *dev = rsnd_priv_to_dev(priv); | ||
475 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 401 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
476 | 402 | ||
477 | dev_dbg(dev, "%s.%d stop\n", rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
478 | |||
479 | ssi->cr_etc = 0; | 403 | ssi->cr_etc = 0; |
480 | 404 | ||
481 | rsnd_ssi_hw_stop(ssi, rdai); | 405 | rsnd_ssi_hw_stop(ssi, rdai); |
@@ -485,35 +409,46 @@ static int rsnd_ssi_pio_stop(struct rsnd_mod *mod, | |||
485 | 409 | ||
486 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 410 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
487 | .name = "ssi (pio)", | 411 | .name = "ssi (pio)", |
412 | .probe = rsnd_ssi_pio_probe, | ||
488 | .init = rsnd_ssi_init, | 413 | .init = rsnd_ssi_init, |
489 | .quit = rsnd_ssi_quit, | 414 | .quit = rsnd_ssi_quit, |
490 | .start = rsnd_ssi_pio_start, | 415 | .start = rsnd_ssi_pio_start, |
491 | .stop = rsnd_ssi_pio_stop, | 416 | .stop = rsnd_ssi_pio_stop, |
492 | }; | 417 | }; |
493 | 418 | ||
494 | static int rsnd_ssi_dma_inquiry(struct rsnd_dma *dma, dma_addr_t *buf, int *len) | 419 | static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, |
420 | struct rsnd_dai *rdai, | ||
421 | struct rsnd_dai_stream *io) | ||
495 | { | 422 | { |
496 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | 423 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
497 | struct rsnd_dai_stream *io = ssi->io; | 424 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
498 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 425 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); |
426 | struct device *dev = rsnd_priv_to_dev(priv); | ||
427 | int dma_id = ssi->info->dma_id; | ||
428 | int is_play; | ||
429 | int ret; | ||
499 | 430 | ||
500 | *len = io->byte_per_period; | 431 | if (info->dai_info) |
501 | *buf = runtime->dma_addr + | 432 | is_play = rsnd_info_is_playback(priv, ssi); |
502 | rsnd_dai_pointer_offset(io, ssi->dma_offset + *len); | 433 | else |
503 | ssi->dma_offset = *len; /* it cares A/B plane */ | 434 | is_play = rsnd_ssi_is_play(&ssi->mod); |
504 | 435 | ||
505 | return 0; | 436 | ret = rsnd_dma_init( |
506 | } | 437 | priv, rsnd_mod_to_dma(mod), |
438 | is_play, | ||
439 | dma_id); | ||
507 | 440 | ||
508 | static int rsnd_ssi_dma_complete(struct rsnd_dma *dma) | 441 | if (ret < 0) |
509 | { | 442 | dev_err(dev, "SSI DMA failed\n"); |
510 | struct rsnd_ssi *ssi = rsnd_dma_to_ssi(dma); | ||
511 | struct rsnd_dai_stream *io = ssi->io; | ||
512 | u32 status = rsnd_mod_read(&ssi->mod, SSISR); | ||
513 | 443 | ||
514 | rsnd_ssi_record_error(ssi, status); | 444 | return ret; |
445 | } | ||
515 | 446 | ||
516 | rsnd_dai_pointer_update(ssi->io, io->byte_per_period); | 447 | static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, |
448 | struct rsnd_dai *rdai, | ||
449 | struct rsnd_dai_stream *io) | ||
450 | { | ||
451 | rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod)); | ||
517 | 452 | ||
518 | return 0; | 453 | return 0; |
519 | } | 454 | } |
@@ -527,14 +462,13 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | |||
527 | 462 | ||
528 | /* enable DMA transfer */ | 463 | /* enable DMA transfer */ |
529 | ssi->cr_etc = DMEN; | 464 | ssi->cr_etc = DMEN; |
530 | ssi->dma_offset = 0; | ||
531 | 465 | ||
532 | rsnd_dma_start(dma); | 466 | rsnd_dma_start(dma); |
533 | 467 | ||
534 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); | 468 | rsnd_ssi_hw_start(ssi, ssi->rdai, io); |
535 | 469 | ||
536 | /* enable WS continue */ | 470 | /* enable WS continue */ |
537 | if (rsnd_rdai_is_clk_master(rdai)) | 471 | if (rsnd_dai_is_clk_master(rdai)) |
538 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); | 472 | rsnd_mod_write(&ssi->mod, SSIWSR, CONT); |
539 | 473 | ||
540 | return 0; | 474 | return 0; |
@@ -549,6 +483,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
549 | 483 | ||
550 | ssi->cr_etc = 0; | 484 | ssi->cr_etc = 0; |
551 | 485 | ||
486 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | ||
487 | |||
552 | rsnd_ssi_hw_stop(ssi, rdai); | 488 | rsnd_ssi_hw_stop(ssi, rdai); |
553 | 489 | ||
554 | rsnd_dma_stop(dma); | 490 | rsnd_dma_stop(dma); |
@@ -558,6 +494,8 @@ static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | |||
558 | 494 | ||
559 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | 495 | static struct rsnd_mod_ops rsnd_ssi_dma_ops = { |
560 | .name = "ssi (dma)", | 496 | .name = "ssi (dma)", |
497 | .probe = rsnd_ssi_dma_probe, | ||
498 | .remove = rsnd_ssi_dma_remove, | ||
561 | .init = rsnd_ssi_init, | 499 | .init = rsnd_ssi_init, |
562 | .quit = rsnd_ssi_quit, | 500 | .quit = rsnd_ssi_quit, |
563 | .start = rsnd_ssi_dma_start, | 501 | .start = rsnd_ssi_dma_start, |
@@ -567,24 +505,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
567 | /* | 505 | /* |
568 | * Non SSI | 506 | * Non SSI |
569 | */ | 507 | */ |
570 | static int rsnd_ssi_non(struct rsnd_mod *mod, | ||
571 | struct rsnd_dai *rdai, | ||
572 | struct rsnd_dai_stream *io) | ||
573 | { | ||
574 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
575 | struct device *dev = rsnd_priv_to_dev(priv); | ||
576 | |||
577 | dev_dbg(dev, "%s\n", __func__); | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { | 508 | static struct rsnd_mod_ops rsnd_ssi_non_ops = { |
583 | .name = "ssi (non)", | 509 | .name = "ssi (non)", |
584 | .init = rsnd_ssi_non, | ||
585 | .quit = rsnd_ssi_non, | ||
586 | .start = rsnd_ssi_non, | ||
587 | .stop = rsnd_ssi_non, | ||
588 | }; | 510 | }; |
589 | 511 | ||
590 | /* | 512 | /* |
@@ -593,16 +515,30 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = { | |||
593 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, | 515 | struct rsnd_mod *rsnd_ssi_mod_get_frm_dai(struct rsnd_priv *priv, |
594 | int dai_id, int is_play) | 516 | int dai_id, int is_play) |
595 | { | 517 | { |
518 | struct rsnd_dai_platform_info *dai_info = NULL; | ||
519 | struct rsnd_dai_path_info *path_info = NULL; | ||
520 | struct rsnd_ssi_platform_info *target_info = NULL; | ||
596 | struct rsnd_ssi *ssi; | 521 | struct rsnd_ssi *ssi; |
597 | int i, has_play; | 522 | int i, has_play; |
598 | 523 | ||
524 | if (priv->rdai) | ||
525 | dai_info = priv->rdai[dai_id].info; | ||
526 | if (dai_info) | ||
527 | path_info = (is_play) ? &dai_info->playback : &dai_info->capture; | ||
528 | if (path_info) | ||
529 | target_info = path_info->ssi; | ||
530 | |||
599 | is_play = !!is_play; | 531 | is_play = !!is_play; |
600 | 532 | ||
601 | for_each_rsnd_ssi(ssi, priv, i) { | 533 | for_each_rsnd_ssi(ssi, priv, i) { |
534 | if (target_info == ssi->info) | ||
535 | return &ssi->mod; | ||
536 | |||
537 | /* for compatible */ | ||
602 | if (rsnd_ssi_dai_id(ssi) != dai_id) | 538 | if (rsnd_ssi_dai_id(ssi) != dai_id) |
603 | continue; | 539 | continue; |
604 | 540 | ||
605 | has_play = !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | 541 | has_play = rsnd_ssi_is_play(&ssi->mod); |
606 | 542 | ||
607 | if (is_play == has_play) | 543 | if (is_play == has_play) |
608 | return &ssi->mod; | 544 | return &ssi->mod; |
@@ -616,36 +552,66 @@ struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | |||
616 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) | 552 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) |
617 | id = 0; | 553 | id = 0; |
618 | 554 | ||
619 | return &(((struct rsnd_ssiu *)(priv->ssiu))->ssi + id)->mod; | 555 | return &((struct rsnd_ssi *)(priv->ssi) + id)->mod; |
556 | } | ||
557 | |||
558 | int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | ||
559 | { | ||
560 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
561 | |||
562 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); | ||
563 | } | ||
564 | |||
565 | int rsnd_ssi_is_play(struct rsnd_mod *mod) | ||
566 | { | ||
567 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
568 | |||
569 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY); | ||
570 | } | ||
571 | |||
572 | static void rsnd_ssi_parent_clk_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) | ||
573 | { | ||
574 | if (!rsnd_ssi_is_pin_sharing(&ssi->mod)) | ||
575 | return; | ||
576 | |||
577 | switch (rsnd_mod_id(&ssi->mod)) { | ||
578 | case 1: | ||
579 | case 2: | ||
580 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); | ||
581 | break; | ||
582 | case 4: | ||
583 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); | ||
584 | break; | ||
585 | case 8: | ||
586 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); | ||
587 | break; | ||
588 | } | ||
620 | } | 589 | } |
621 | 590 | ||
622 | int rsnd_ssi_probe(struct platform_device *pdev, | 591 | int rsnd_ssi_probe(struct platform_device *pdev, |
623 | struct rcar_snd_info *info, | ||
624 | struct rsnd_priv *priv) | 592 | struct rsnd_priv *priv) |
625 | { | 593 | { |
594 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
626 | struct rsnd_ssi_platform_info *pinfo; | 595 | struct rsnd_ssi_platform_info *pinfo; |
627 | struct device *dev = rsnd_priv_to_dev(priv); | 596 | struct device *dev = rsnd_priv_to_dev(priv); |
628 | struct rsnd_mod_ops *ops; | 597 | struct rsnd_mod_ops *ops; |
629 | struct clk *clk; | 598 | struct clk *clk; |
630 | struct rsnd_ssiu *ssiu; | ||
631 | struct rsnd_ssi *ssi; | 599 | struct rsnd_ssi *ssi; |
632 | char name[RSND_SSI_NAME_SIZE]; | 600 | char name[RSND_SSI_NAME_SIZE]; |
633 | int i, nr, ret; | 601 | int i, nr; |
634 | 602 | ||
635 | /* | 603 | /* |
636 | * init SSI | 604 | * init SSI |
637 | */ | 605 | */ |
638 | nr = info->ssi_info_nr; | 606 | nr = info->ssi_info_nr; |
639 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) + (sizeof(*ssi) * nr), | 607 | ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); |
640 | GFP_KERNEL); | 608 | if (!ssi) { |
641 | if (!ssiu) { | ||
642 | dev_err(dev, "SSI allocate failed\n"); | 609 | dev_err(dev, "SSI allocate failed\n"); |
643 | return -ENOMEM; | 610 | return -ENOMEM; |
644 | } | 611 | } |
645 | 612 | ||
646 | priv->ssiu = ssiu; | 613 | priv->ssi = ssi; |
647 | ssiu->ssi = (struct rsnd_ssi *)(ssiu + 1); | 614 | priv->ssi_nr = nr; |
648 | ssiu->ssi_nr = nr; | ||
649 | 615 | ||
650 | for_each_rsnd_ssi(ssi, priv, i) { | 616 | for_each_rsnd_ssi(ssi, priv, i) { |
651 | pinfo = &info->ssi_info[i]; | 617 | pinfo = &info->ssi_info[i]; |
@@ -660,61 +626,15 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
660 | ssi->clk = clk; | 626 | ssi->clk = clk; |
661 | 627 | ||
662 | ops = &rsnd_ssi_non_ops; | 628 | ops = &rsnd_ssi_non_ops; |
629 | if (pinfo->dma_id > 0) | ||
630 | ops = &rsnd_ssi_dma_ops; | ||
631 | else if (rsnd_ssi_pio_available(ssi)) | ||
632 | ops = &rsnd_ssi_pio_ops; | ||
663 | 633 | ||
664 | /* | 634 | rsnd_mod_init(priv, &ssi->mod, ops, RSND_MOD_SSI, i); |
665 | * SSI DMA case | ||
666 | */ | ||
667 | if (pinfo->dma_id > 0) { | ||
668 | ret = rsnd_dma_init( | ||
669 | priv, rsnd_mod_to_dma(&ssi->mod), | ||
670 | (rsnd_ssi_mode_flags(ssi) & RSND_SSI_PLAY), | ||
671 | pinfo->dma_id, | ||
672 | rsnd_ssi_dma_inquiry, | ||
673 | rsnd_ssi_dma_complete); | ||
674 | if (ret < 0) | ||
675 | dev_info(dev, "SSI DMA failed. try PIO transter\n"); | ||
676 | else | ||
677 | ops = &rsnd_ssi_dma_ops; | ||
678 | |||
679 | dev_dbg(dev, "SSI%d use DMA transfer\n", i); | ||
680 | } | ||
681 | |||
682 | /* | ||
683 | * SSI PIO case | ||
684 | */ | ||
685 | if (!rsnd_ssi_dma_available(ssi) && | ||
686 | rsnd_ssi_pio_available(ssi)) { | ||
687 | ret = devm_request_irq(dev, pinfo->pio_irq, | ||
688 | &rsnd_ssi_pio_interrupt, | ||
689 | IRQF_SHARED, | ||
690 | dev_name(dev), ssi); | ||
691 | if (ret) { | ||
692 | dev_err(dev, "SSI request interrupt failed\n"); | ||
693 | return ret; | ||
694 | } | ||
695 | |||
696 | ops = &rsnd_ssi_pio_ops; | ||
697 | 635 | ||
698 | dev_dbg(dev, "SSI%d use PIO transfer\n", i); | 636 | rsnd_ssi_parent_clk_setup(priv, ssi); |
699 | } | ||
700 | |||
701 | rsnd_mod_init(priv, &ssi->mod, ops, i); | ||
702 | } | 637 | } |
703 | 638 | ||
704 | dev_dbg(dev, "ssi probed\n"); | ||
705 | |||
706 | return 0; | 639 | return 0; |
707 | } | 640 | } |
708 | |||
709 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
710 | struct rsnd_priv *priv) | ||
711 | { | ||
712 | struct rsnd_ssi *ssi; | ||
713 | int i; | ||
714 | |||
715 | for_each_rsnd_ssi(ssi, priv, i) { | ||
716 | if (rsnd_ssi_dma_available(ssi)) | ||
717 | rsnd_dma_quit(priv, rsnd_mod_to_dma(&ssi->mod)); | ||
718 | } | ||
719 | |||
720 | } | ||
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 375dc6dfba4e..bfed3e4c45ff 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
@@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) | |||
96 | { | 96 | { |
97 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", | 97 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", |
98 | codec->name); | 98 | codec->name); |
99 | if (!codec->reg_cache) | 99 | |
100 | return 0; | ||
101 | kfree(codec->reg_cache); | 100 | kfree(codec->reg_cache); |
102 | codec->reg_cache = NULL; | 101 | codec->reg_cache = NULL; |
103 | return 0; | 102 | return 0; |
@@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec, | |||
117 | return -EINVAL; | 116 | return -EINVAL; |
118 | 117 | ||
119 | mutex_lock(&codec->cache_rw_mutex); | 118 | mutex_lock(&codec->cache_rw_mutex); |
120 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | 119 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) |
121 | codec->driver->reg_word_size); | 120 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, |
121 | codec->driver->reg_word_size); | ||
122 | mutex_unlock(&codec->cache_rw_mutex); | 122 | mutex_unlock(&codec->cache_rw_mutex); |
123 | 123 | ||
124 | return 0; | 124 | return 0; |
@@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, | |||
136 | unsigned int reg, unsigned int value) | 136 | unsigned int reg, unsigned int value) |
137 | { | 137 | { |
138 | mutex_lock(&codec->cache_rw_mutex); | 138 | mutex_lock(&codec->cache_rw_mutex); |
139 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | 139 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) |
140 | codec->driver->reg_word_size); | 140 | snd_soc_set_cache_val(codec->reg_cache, reg, value, |
141 | codec->driver->reg_word_size); | ||
141 | mutex_unlock(&codec->cache_rw_mutex); | 142 | mutex_unlock(&codec->cache_rw_mutex); |
142 | 143 | ||
143 | return 0; | 144 | return 0; |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 5e9690c85d8f..91083e6a6b38 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
@@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
30 | { | 30 | { |
31 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 31 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
32 | struct snd_soc_platform *platform = rtd->platform; | 32 | struct snd_soc_platform *platform = rtd->platform; |
33 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
34 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
35 | int ret = 0; | 33 | int ret = 0; |
36 | 34 | ||
37 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 35 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
@@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
52 | } | 50 | } |
53 | } | 51 | } |
54 | 52 | ||
55 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 53 | snd_soc_runtime_activate(rtd, cstream->direction); |
56 | cpu_dai->playback_active++; | ||
57 | codec_dai->playback_active++; | ||
58 | } else { | ||
59 | cpu_dai->capture_active++; | ||
60 | codec_dai->capture_active++; | ||
61 | } | ||
62 | |||
63 | cpu_dai->active++; | ||
64 | codec_dai->active++; | ||
65 | rtd->codec->active++; | ||
66 | 54 | ||
67 | mutex_unlock(&rtd->pcm_mutex); | 55 | mutex_unlock(&rtd->pcm_mutex); |
68 | 56 | ||
@@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
81 | struct snd_soc_pcm_runtime *fe = cstream->private_data; | 69 | struct snd_soc_pcm_runtime *fe = cstream->private_data; |
82 | struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; | 70 | struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; |
83 | struct snd_soc_platform *platform = fe->platform; | 71 | struct snd_soc_platform *platform = fe->platform; |
84 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
85 | struct snd_soc_dai *codec_dai = fe->codec_dai; | ||
86 | struct snd_soc_dpcm *dpcm; | 72 | struct snd_soc_dpcm *dpcm; |
87 | struct snd_soc_dapm_widget_list *list; | 73 | struct snd_soc_dapm_widget_list *list; |
88 | int stream; | 74 | int stream; |
@@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
140 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | 126 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; |
141 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 127 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
142 | 128 | ||
143 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 129 | snd_soc_runtime_activate(fe, stream); |
144 | cpu_dai->playback_active++; | ||
145 | codec_dai->playback_active++; | ||
146 | } else { | ||
147 | cpu_dai->capture_active++; | ||
148 | codec_dai->capture_active++; | ||
149 | } | ||
150 | |||
151 | cpu_dai->active++; | ||
152 | codec_dai->active++; | ||
153 | fe->codec->active++; | ||
154 | 130 | ||
155 | mutex_unlock(&fe->card->mutex); | 131 | mutex_unlock(&fe->card->mutex); |
156 | 132 | ||
@@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
202 | struct snd_soc_platform *platform = rtd->platform; | 178 | struct snd_soc_platform *platform = rtd->platform; |
203 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 179 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
204 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 180 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
205 | struct snd_soc_codec *codec = rtd->codec; | 181 | int stream; |
206 | 182 | ||
207 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 183 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
208 | 184 | ||
209 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 185 | if (cstream->direction == SND_COMPRESS_PLAYBACK) |
210 | cpu_dai->playback_active--; | 186 | stream = SNDRV_PCM_STREAM_PLAYBACK; |
211 | codec_dai->playback_active--; | 187 | else |
212 | } else { | 188 | stream = SNDRV_PCM_STREAM_CAPTURE; |
213 | cpu_dai->capture_active--; | ||
214 | codec_dai->capture_active--; | ||
215 | } | ||
216 | 189 | ||
217 | snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); | 190 | snd_soc_runtime_deactivate(rtd, stream); |
218 | 191 | ||
219 | cpu_dai->active--; | 192 | snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); |
220 | codec_dai->active--; | ||
221 | codec->active--; | ||
222 | 193 | ||
223 | if (!cpu_dai->active) | 194 | if (!cpu_dai->active) |
224 | cpu_dai->rate = 0; | 195 | cpu_dai->rate = 0; |
@@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
235 | cpu_dai->runtime = NULL; | 206 | cpu_dai->runtime = NULL; |
236 | 207 | ||
237 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 208 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { |
238 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 209 | if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
239 | rtd->dai_link->ignore_pmdown_time) { | ||
240 | snd_soc_dapm_stream_event(rtd, | 210 | snd_soc_dapm_stream_event(rtd, |
241 | SNDRV_PCM_STREAM_PLAYBACK, | 211 | SNDRV_PCM_STREAM_PLAYBACK, |
242 | SND_SOC_DAPM_STREAM_STOP); | 212 | SND_SOC_DAPM_STREAM_STOP); |
@@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) | |||
261 | { | 231 | { |
262 | struct snd_soc_pcm_runtime *fe = cstream->private_data; | 232 | struct snd_soc_pcm_runtime *fe = cstream->private_data; |
263 | struct snd_soc_platform *platform = fe->platform; | 233 | struct snd_soc_platform *platform = fe->platform; |
264 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
265 | struct snd_soc_dai *codec_dai = fe->codec_dai; | ||
266 | struct snd_soc_dpcm *dpcm; | 234 | struct snd_soc_dpcm *dpcm; |
267 | int stream, ret; | 235 | int stream, ret; |
268 | 236 | ||
269 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 237 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
270 | 238 | ||
271 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 239 | if (cstream->direction == SND_COMPRESS_PLAYBACK) |
272 | stream = SNDRV_PCM_STREAM_PLAYBACK; | 240 | stream = SNDRV_PCM_STREAM_PLAYBACK; |
273 | cpu_dai->playback_active--; | 241 | else |
274 | codec_dai->playback_active--; | ||
275 | } else { | ||
276 | stream = SNDRV_PCM_STREAM_CAPTURE; | 242 | stream = SNDRV_PCM_STREAM_CAPTURE; |
277 | cpu_dai->capture_active--; | ||
278 | codec_dai->capture_active--; | ||
279 | } | ||
280 | 243 | ||
281 | cpu_dai->active--; | 244 | snd_soc_runtime_deactivate(fe, stream); |
282 | codec_dai->active--; | ||
283 | fe->codec->active--; | ||
284 | 245 | ||
285 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 246 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
286 | 247 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe1df50805a3..359c2849b364 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
@@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); | |||
56 | #endif | 56 | #endif |
57 | 57 | ||
58 | static DEFINE_MUTEX(client_mutex); | 58 | static DEFINE_MUTEX(client_mutex); |
59 | static LIST_HEAD(dai_list); | ||
60 | static LIST_HEAD(platform_list); | 59 | static LIST_HEAD(platform_list); |
61 | static LIST_HEAD(codec_list); | 60 | static LIST_HEAD(codec_list); |
62 | static LIST_HEAD(component_list); | 61 | static LIST_HEAD(component_list); |
@@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, | |||
370 | { | 369 | { |
371 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 370 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
372 | ssize_t len, ret = 0; | 371 | ssize_t len, ret = 0; |
372 | struct snd_soc_component *component; | ||
373 | struct snd_soc_dai *dai; | 373 | struct snd_soc_dai *dai; |
374 | 374 | ||
375 | if (!buf) | 375 | if (!buf) |
376 | return -ENOMEM; | 376 | return -ENOMEM; |
377 | 377 | ||
378 | list_for_each_entry(dai, &dai_list, list) { | 378 | list_for_each_entry(component, &component_list, list) { |
379 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); | 379 | list_for_each_entry(dai, &component->dai_list, list) { |
380 | if (len >= 0) | 380 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
381 | ret += len; | 381 | dai->name); |
382 | if (ret > PAGE_SIZE) { | 382 | if (len >= 0) |
383 | ret = PAGE_SIZE; | 383 | ret += len; |
384 | break; | 384 | if (ret > PAGE_SIZE) { |
385 | ret = PAGE_SIZE; | ||
386 | break; | ||
387 | } | ||
385 | } | 388 | } |
386 | } | 389 | } |
387 | 390 | ||
@@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
855 | { | 858 | { |
856 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 859 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
857 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 860 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
861 | struct snd_soc_component *component; | ||
858 | struct snd_soc_codec *codec; | 862 | struct snd_soc_codec *codec; |
859 | struct snd_soc_platform *platform; | 863 | struct snd_soc_platform *platform; |
860 | struct snd_soc_dai *codec_dai, *cpu_dai; | 864 | struct snd_soc_dai *codec_dai, *cpu_dai; |
@@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
863 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); | 867 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); |
864 | 868 | ||
865 | /* Find CPU DAI from registered DAIs*/ | 869 | /* Find CPU DAI from registered DAIs*/ |
866 | list_for_each_entry(cpu_dai, &dai_list, list) { | 870 | list_for_each_entry(component, &component_list, list) { |
867 | if (dai_link->cpu_of_node && | 871 | if (dai_link->cpu_of_node && |
868 | (cpu_dai->dev->of_node != dai_link->cpu_of_node)) | 872 | component->dev->of_node != dai_link->cpu_of_node) |
869 | continue; | 873 | continue; |
870 | if (dai_link->cpu_name && | 874 | if (dai_link->cpu_name && |
871 | strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) | 875 | strcmp(dev_name(component->dev), dai_link->cpu_name)) |
872 | continue; | ||
873 | if (dai_link->cpu_dai_name && | ||
874 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
875 | continue; | 876 | continue; |
877 | list_for_each_entry(cpu_dai, &component->dai_list, list) { | ||
878 | if (dai_link->cpu_dai_name && | ||
879 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
880 | continue; | ||
876 | 881 | ||
877 | rtd->cpu_dai = cpu_dai; | 882 | rtd->cpu_dai = cpu_dai; |
883 | } | ||
878 | } | 884 | } |
879 | 885 | ||
880 | if (!rtd->cpu_dai) { | 886 | if (!rtd->cpu_dai) { |
@@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
899 | * CODEC found, so find CODEC DAI from registered DAIs from | 905 | * CODEC found, so find CODEC DAI from registered DAIs from |
900 | * this CODEC | 906 | * this CODEC |
901 | */ | 907 | */ |
902 | list_for_each_entry(codec_dai, &dai_list, list) { | 908 | list_for_each_entry(codec_dai, &codec->component.dai_list, list) { |
903 | if (codec->dev == codec_dai->dev && | 909 | if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) { |
904 | !strcmp(codec_dai->name, | ||
905 | dai_link->codec_dai_name)) { | ||
906 | |||
907 | rtd->codec_dai = codec_dai; | 910 | rtd->codec_dai = codec_dai; |
911 | break; | ||
908 | } | 912 | } |
909 | } | 913 | } |
910 | 914 | ||
@@ -1128,12 +1132,8 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
1128 | driver->num_dapm_widgets); | 1132 | driver->num_dapm_widgets); |
1129 | 1133 | ||
1130 | /* Create DAPM widgets for each DAI stream */ | 1134 | /* Create DAPM widgets for each DAI stream */ |
1131 | list_for_each_entry(dai, &dai_list, list) { | 1135 | list_for_each_entry(dai, &codec->component.dai_list, list) |
1132 | if (dai->dev != codec->dev) | ||
1133 | continue; | ||
1134 | |||
1135 | snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); | 1136 | snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); |
1136 | } | ||
1137 | 1137 | ||
1138 | codec->dapm.idle_bias_off = driver->idle_bias_off; | 1138 | codec->dapm.idle_bias_off = driver->idle_bias_off; |
1139 | 1139 | ||
@@ -1180,6 +1180,7 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
1180 | { | 1180 | { |
1181 | int ret = 0; | 1181 | int ret = 0; |
1182 | const struct snd_soc_platform_driver *driver = platform->driver; | 1182 | const struct snd_soc_platform_driver *driver = platform->driver; |
1183 | struct snd_soc_component *component; | ||
1183 | struct snd_soc_dai *dai; | 1184 | struct snd_soc_dai *dai; |
1184 | 1185 | ||
1185 | platform->card = card; | 1186 | platform->card = card; |
@@ -1195,11 +1196,11 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
1195 | driver->dapm_widgets, driver->num_dapm_widgets); | 1196 | driver->dapm_widgets, driver->num_dapm_widgets); |
1196 | 1197 | ||
1197 | /* Create DAPM widgets for each DAI stream */ | 1198 | /* Create DAPM widgets for each DAI stream */ |
1198 | list_for_each_entry(dai, &dai_list, list) { | 1199 | list_for_each_entry(component, &component_list, list) { |
1199 | if (dai->dev != platform->dev) | 1200 | if (component->dev != platform->dev) |
1200 | continue; | 1201 | continue; |
1201 | 1202 | list_for_each_entry(dai, &component->dai_list, list) | |
1202 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); | 1203 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); |
1203 | } | 1204 | } |
1204 | 1205 | ||
1205 | platform->dapm.idle_bias_off = 1; | 1206 | platform->dapm.idle_bias_off = 1; |
@@ -2571,10 +2572,10 @@ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, | |||
2571 | 2572 | ||
2572 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 2573 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
2573 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; | 2574 | uinfo->count = e->shift_l == e->shift_r ? 1 : 2; |
2574 | uinfo->value.enumerated.items = e->max; | 2575 | uinfo->value.enumerated.items = e->items; |
2575 | 2576 | ||
2576 | if (uinfo->value.enumerated.item > e->max - 1) | 2577 | if (uinfo->value.enumerated.item >= e->items) |
2577 | uinfo->value.enumerated.item = e->max - 1; | 2578 | uinfo->value.enumerated.item = e->items - 1; |
2578 | strlcpy(uinfo->value.enumerated.name, | 2579 | strlcpy(uinfo->value.enumerated.name, |
2579 | e->texts[uinfo->value.enumerated.item], | 2580 | e->texts[uinfo->value.enumerated.item], |
2580 | sizeof(uinfo->value.enumerated.name)); | 2581 | sizeof(uinfo->value.enumerated.name)); |
@@ -2596,14 +2597,18 @@ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2596 | { | 2597 | { |
2597 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2598 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2598 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2599 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2599 | unsigned int val; | 2600 | unsigned int val, item; |
2601 | unsigned int reg_val; | ||
2600 | 2602 | ||
2601 | val = snd_soc_read(codec, e->reg); | 2603 | reg_val = snd_soc_read(codec, e->reg); |
2602 | ucontrol->value.enumerated.item[0] | 2604 | val = (reg_val >> e->shift_l) & e->mask; |
2603 | = (val >> e->shift_l) & e->mask; | 2605 | item = snd_soc_enum_val_to_item(e, val); |
2604 | if (e->shift_l != e->shift_r) | 2606 | ucontrol->value.enumerated.item[0] = item; |
2605 | ucontrol->value.enumerated.item[1] = | 2607 | if (e->shift_l != e->shift_r) { |
2606 | (val >> e->shift_r) & e->mask; | 2608 | val = (reg_val >> e->shift_l) & e->mask; |
2609 | item = snd_soc_enum_val_to_item(e, val); | ||
2610 | ucontrol->value.enumerated.item[1] = item; | ||
2611 | } | ||
2607 | 2612 | ||
2608 | return 0; | 2613 | return 0; |
2609 | } | 2614 | } |
@@ -2623,17 +2628,18 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2623 | { | 2628 | { |
2624 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2629 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
2625 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2630 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2631 | unsigned int *item = ucontrol->value.enumerated.item; | ||
2626 | unsigned int val; | 2632 | unsigned int val; |
2627 | unsigned int mask; | 2633 | unsigned int mask; |
2628 | 2634 | ||
2629 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2635 | if (item[0] >= e->items) |
2630 | return -EINVAL; | 2636 | return -EINVAL; |
2631 | val = ucontrol->value.enumerated.item[0] << e->shift_l; | 2637 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
2632 | mask = e->mask << e->shift_l; | 2638 | mask = e->mask << e->shift_l; |
2633 | if (e->shift_l != e->shift_r) { | 2639 | if (e->shift_l != e->shift_r) { |
2634 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2640 | if (item[1] >= e->items) |
2635 | return -EINVAL; | 2641 | return -EINVAL; |
2636 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | 2642 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r; |
2637 | mask |= e->mask << e->shift_r; | 2643 | mask |= e->mask << e->shift_r; |
2638 | } | 2644 | } |
2639 | 2645 | ||
@@ -2642,78 +2648,46 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, | |||
2642 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); | 2648 | EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); |
2643 | 2649 | ||
2644 | /** | 2650 | /** |
2645 | * snd_soc_get_value_enum_double - semi enumerated double mixer get callback | 2651 | * snd_soc_read_signed - Read a codec register and interprete as signed value |
2646 | * @kcontrol: mixer control | 2652 | * @codec: codec |
2647 | * @ucontrol: control element information | 2653 | * @reg: Register to read |
2648 | * | 2654 | * @mask: Mask to use after shifting the register value |
2649 | * Callback to get the value of a double semi enumerated mixer. | 2655 | * @shift: Right shift of register value |
2656 | * @sign_bit: Bit that describes if a number is negative or not. | ||
2650 | * | 2657 | * |
2651 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | 2658 | * This functions reads a codec register. The register value is shifted right |
2652 | * used for handling bitfield coded enumeration for example. | 2659 | * by 'shift' bits and masked with the given 'mask'. Afterwards it translates |
2660 | * the given registervalue into a signed integer if sign_bit is non-zero. | ||
2653 | * | 2661 | * |
2654 | * Returns 0 for success. | 2662 | * Returns the register value as signed int. |
2655 | */ | 2663 | */ |
2656 | int snd_soc_get_value_enum_double(struct snd_kcontrol *kcontrol, | 2664 | static int snd_soc_read_signed(struct snd_soc_codec *codec, unsigned int reg, |
2657 | struct snd_ctl_elem_value *ucontrol) | 2665 | unsigned int mask, unsigned int shift, unsigned int sign_bit) |
2658 | { | 2666 | { |
2659 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 2667 | int ret; |
2660 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2668 | unsigned int val; |
2661 | unsigned int reg_val, val, mux; | ||
2662 | 2669 | ||
2663 | reg_val = snd_soc_read(codec, e->reg); | 2670 | val = (snd_soc_read(codec, reg) >> shift) & mask; |
2664 | val = (reg_val >> e->shift_l) & e->mask; | ||
2665 | for (mux = 0; mux < e->max; mux++) { | ||
2666 | if (val == e->values[mux]) | ||
2667 | break; | ||
2668 | } | ||
2669 | ucontrol->value.enumerated.item[0] = mux; | ||
2670 | if (e->shift_l != e->shift_r) { | ||
2671 | val = (reg_val >> e->shift_r) & e->mask; | ||
2672 | for (mux = 0; mux < e->max; mux++) { | ||
2673 | if (val == e->values[mux]) | ||
2674 | break; | ||
2675 | } | ||
2676 | ucontrol->value.enumerated.item[1] = mux; | ||
2677 | } | ||
2678 | 2671 | ||
2679 | return 0; | 2672 | if (!sign_bit) |
2680 | } | 2673 | return val; |
2681 | EXPORT_SYMBOL_GPL(snd_soc_get_value_enum_double); | ||
2682 | 2674 | ||
2683 | /** | 2675 | /* non-negative number */ |
2684 | * snd_soc_put_value_enum_double - semi enumerated double mixer put callback | 2676 | if (!(val & BIT(sign_bit))) |
2685 | * @kcontrol: mixer control | 2677 | return val; |
2686 | * @ucontrol: control element information | ||
2687 | * | ||
2688 | * Callback to set the value of a double semi enumerated mixer. | ||
2689 | * | ||
2690 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
2691 | * used for handling bitfield coded enumeration for example. | ||
2692 | * | ||
2693 | * Returns 0 for success. | ||
2694 | */ | ||
2695 | int snd_soc_put_value_enum_double(struct snd_kcontrol *kcontrol, | ||
2696 | struct snd_ctl_elem_value *ucontrol) | ||
2697 | { | ||
2698 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2699 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2700 | unsigned int val; | ||
2701 | unsigned int mask; | ||
2702 | 2678 | ||
2703 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2679 | ret = val; |
2704 | return -EINVAL; | ||
2705 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | ||
2706 | mask = e->mask << e->shift_l; | ||
2707 | if (e->shift_l != e->shift_r) { | ||
2708 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
2709 | return -EINVAL; | ||
2710 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | ||
2711 | mask |= e->mask << e->shift_r; | ||
2712 | } | ||
2713 | 2680 | ||
2714 | return snd_soc_update_bits_locked(codec, e->reg, mask, val); | 2681 | /* |
2682 | * The register most probably does not contain a full-sized int. | ||
2683 | * Instead we have an arbitrary number of bits in a signed | ||
2684 | * representation which has to be translated into a full-sized int. | ||
2685 | * This is done by filling up all bits above the sign-bit. | ||
2686 | */ | ||
2687 | ret |= ~((int)(BIT(sign_bit) - 1)); | ||
2688 | |||
2689 | return ret; | ||
2715 | } | 2690 | } |
2716 | EXPORT_SYMBOL_GPL(snd_soc_put_value_enum_double); | ||
2717 | 2691 | ||
2718 | /** | 2692 | /** |
2719 | * snd_soc_info_volsw - single mixer info callback | 2693 | * snd_soc_info_volsw - single mixer info callback |
@@ -2743,7 +2717,7 @@ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, | |||
2743 | 2717 | ||
2744 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; | 2718 | uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; |
2745 | uinfo->value.integer.min = 0; | 2719 | uinfo->value.integer.min = 0; |
2746 | uinfo->value.integer.max = platform_max; | 2720 | uinfo->value.integer.max = platform_max - mc->min; |
2747 | return 0; | 2721 | return 0; |
2748 | } | 2722 | } |
2749 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); | 2723 | EXPORT_SYMBOL_GPL(snd_soc_info_volsw); |
@@ -2769,11 +2743,16 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
2769 | unsigned int shift = mc->shift; | 2743 | unsigned int shift = mc->shift; |
2770 | unsigned int rshift = mc->rshift; | 2744 | unsigned int rshift = mc->rshift; |
2771 | int max = mc->max; | 2745 | int max = mc->max; |
2746 | int min = mc->min; | ||
2747 | int sign_bit = mc->sign_bit; | ||
2772 | unsigned int mask = (1 << fls(max)) - 1; | 2748 | unsigned int mask = (1 << fls(max)) - 1; |
2773 | unsigned int invert = mc->invert; | 2749 | unsigned int invert = mc->invert; |
2774 | 2750 | ||
2775 | ucontrol->value.integer.value[0] = | 2751 | if (sign_bit) |
2776 | (snd_soc_read(codec, reg) >> shift) & mask; | 2752 | mask = BIT(sign_bit + 1) - 1; |
2753 | |||
2754 | ucontrol->value.integer.value[0] = snd_soc_read_signed(codec, reg, mask, | ||
2755 | shift, sign_bit) - min; | ||
2777 | if (invert) | 2756 | if (invert) |
2778 | ucontrol->value.integer.value[0] = | 2757 | ucontrol->value.integer.value[0] = |
2779 | max - ucontrol->value.integer.value[0]; | 2758 | max - ucontrol->value.integer.value[0]; |
@@ -2781,10 +2760,12 @@ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, | |||
2781 | if (snd_soc_volsw_is_stereo(mc)) { | 2760 | if (snd_soc_volsw_is_stereo(mc)) { |
2782 | if (reg == reg2) | 2761 | if (reg == reg2) |
2783 | ucontrol->value.integer.value[1] = | 2762 | ucontrol->value.integer.value[1] = |
2784 | (snd_soc_read(codec, reg) >> rshift) & mask; | 2763 | snd_soc_read_signed(codec, reg, mask, rshift, |
2764 | sign_bit) - min; | ||
2785 | else | 2765 | else |
2786 | ucontrol->value.integer.value[1] = | 2766 | ucontrol->value.integer.value[1] = |
2787 | (snd_soc_read(codec, reg2) >> shift) & mask; | 2767 | snd_soc_read_signed(codec, reg2, mask, shift, |
2768 | sign_bit) - min; | ||
2788 | if (invert) | 2769 | if (invert) |
2789 | ucontrol->value.integer.value[1] = | 2770 | ucontrol->value.integer.value[1] = |
2790 | max - ucontrol->value.integer.value[1]; | 2771 | max - ucontrol->value.integer.value[1]; |
@@ -2815,20 +2796,25 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
2815 | unsigned int shift = mc->shift; | 2796 | unsigned int shift = mc->shift; |
2816 | unsigned int rshift = mc->rshift; | 2797 | unsigned int rshift = mc->rshift; |
2817 | int max = mc->max; | 2798 | int max = mc->max; |
2799 | int min = mc->min; | ||
2800 | unsigned int sign_bit = mc->sign_bit; | ||
2818 | unsigned int mask = (1 << fls(max)) - 1; | 2801 | unsigned int mask = (1 << fls(max)) - 1; |
2819 | unsigned int invert = mc->invert; | 2802 | unsigned int invert = mc->invert; |
2820 | int err; | 2803 | int err; |
2821 | bool type_2r = 0; | 2804 | bool type_2r = false; |
2822 | unsigned int val2 = 0; | 2805 | unsigned int val2 = 0; |
2823 | unsigned int val, val_mask; | 2806 | unsigned int val, val_mask; |
2824 | 2807 | ||
2825 | val = (ucontrol->value.integer.value[0] & mask); | 2808 | if (sign_bit) |
2809 | mask = BIT(sign_bit + 1) - 1; | ||
2810 | |||
2811 | val = ((ucontrol->value.integer.value[0] + min) & mask); | ||
2826 | if (invert) | 2812 | if (invert) |
2827 | val = max - val; | 2813 | val = max - val; |
2828 | val_mask = mask << shift; | 2814 | val_mask = mask << shift; |
2829 | val = val << shift; | 2815 | val = val << shift; |
2830 | if (snd_soc_volsw_is_stereo(mc)) { | 2816 | if (snd_soc_volsw_is_stereo(mc)) { |
2831 | val2 = (ucontrol->value.integer.value[1] & mask); | 2817 | val2 = ((ucontrol->value.integer.value[1] + min) & mask); |
2832 | if (invert) | 2818 | if (invert) |
2833 | val2 = max - val2; | 2819 | val2 = max - val2; |
2834 | if (reg == reg2) { | 2820 | if (reg == reg2) { |
@@ -2836,7 +2822,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
2836 | val |= val2 << rshift; | 2822 | val |= val2 << rshift; |
2837 | } else { | 2823 | } else { |
2838 | val2 = val2 << shift; | 2824 | val2 = val2 << shift; |
2839 | type_2r = 1; | 2825 | type_2r = true; |
2840 | } | 2826 | } |
2841 | } | 2827 | } |
2842 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); | 2828 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); |
@@ -3234,7 +3220,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
3234 | struct soc_bytes *params = (void *)kcontrol->private_value; | 3220 | struct soc_bytes *params = (void *)kcontrol->private_value; |
3235 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 3221 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
3236 | int ret, len; | 3222 | int ret, len; |
3237 | unsigned int val; | 3223 | unsigned int val, mask; |
3238 | void *data; | 3224 | void *data; |
3239 | 3225 | ||
3240 | if (!codec->using_regmap) | 3226 | if (!codec->using_regmap) |
@@ -3264,12 +3250,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
3264 | ((u8 *)data)[0] |= val; | 3250 | ((u8 *)data)[0] |= val; |
3265 | break; | 3251 | break; |
3266 | case 2: | 3252 | case 2: |
3267 | ((u16 *)data)[0] &= cpu_to_be16(~params->mask); | 3253 | mask = ~params->mask; |
3268 | ((u16 *)data)[0] |= cpu_to_be16(val); | 3254 | ret = regmap_parse_val(codec->control_data, |
3255 | &mask, &mask); | ||
3256 | if (ret != 0) | ||
3257 | goto out; | ||
3258 | |||
3259 | ((u16 *)data)[0] &= mask; | ||
3260 | |||
3261 | ret = regmap_parse_val(codec->control_data, | ||
3262 | &val, &val); | ||
3263 | if (ret != 0) | ||
3264 | goto out; | ||
3265 | |||
3266 | ((u16 *)data)[0] |= val; | ||
3269 | break; | 3267 | break; |
3270 | case 4: | 3268 | case 4: |
3271 | ((u32 *)data)[0] &= cpu_to_be32(~params->mask); | 3269 | mask = ~params->mask; |
3272 | ((u32 *)data)[0] |= cpu_to_be32(val); | 3270 | ret = regmap_parse_val(codec->control_data, |
3271 | &mask, &mask); | ||
3272 | if (ret != 0) | ||
3273 | goto out; | ||
3274 | |||
3275 | ((u32 *)data)[0] &= mask; | ||
3276 | |||
3277 | ret = regmap_parse_val(codec->control_data, | ||
3278 | &val, &val); | ||
3279 | if (ret != 0) | ||
3280 | goto out; | ||
3281 | |||
3282 | ((u32 *)data)[0] |= val; | ||
3273 | break; | 3283 | break; |
3274 | default: | 3284 | default: |
3275 | ret = -EINVAL; | 3285 | ret = -EINVAL; |
@@ -3609,6 +3619,30 @@ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
3609 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | 3619 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); |
3610 | 3620 | ||
3611 | /** | 3621 | /** |
3622 | * snd_soc_of_xlate_tdm_slot - generate tx/rx slot mask. | ||
3623 | * @slots: Number of slots in use. | ||
3624 | * @tx_mask: bitmask representing active TX slots. | ||
3625 | * @rx_mask: bitmask representing active RX slots. | ||
3626 | * | ||
3627 | * Generates the TDM tx and rx slot default masks for DAI. | ||
3628 | */ | ||
3629 | static int snd_soc_of_xlate_tdm_slot_mask(unsigned int slots, | ||
3630 | unsigned int *tx_mask, | ||
3631 | unsigned int *rx_mask) | ||
3632 | { | ||
3633 | if (*tx_mask || *rx_mask) | ||
3634 | return 0; | ||
3635 | |||
3636 | if (!slots) | ||
3637 | return -EINVAL; | ||
3638 | |||
3639 | *tx_mask = (1 << slots) - 1; | ||
3640 | *rx_mask = (1 << slots) - 1; | ||
3641 | |||
3642 | return 0; | ||
3643 | } | ||
3644 | |||
3645 | /** | ||
3612 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. | 3646 | * snd_soc_dai_set_tdm_slot - configure DAI TDM. |
3613 | * @dai: DAI | 3647 | * @dai: DAI |
3614 | * @tx_mask: bitmask representing active TX slots. | 3648 | * @tx_mask: bitmask representing active TX slots. |
@@ -3622,11 +3656,17 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); | |||
3622 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | 3656 | int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, |
3623 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) | 3657 | unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) |
3624 | { | 3658 | { |
3659 | if (dai->driver && dai->driver->ops->of_xlate_tdm_slot_mask) | ||
3660 | dai->driver->ops->of_xlate_tdm_slot_mask(slots, | ||
3661 | &tx_mask, &rx_mask); | ||
3662 | else | ||
3663 | snd_soc_of_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); | ||
3664 | |||
3625 | if (dai->driver && dai->driver->ops->set_tdm_slot) | 3665 | if (dai->driver && dai->driver->ops->set_tdm_slot) |
3626 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, | 3666 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
3627 | slots, slot_width); | 3667 | slots, slot_width); |
3628 | else | 3668 | else |
3629 | return -EINVAL; | 3669 | return -ENOTSUPP; |
3630 | } | 3670 | } |
3631 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | 3671 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); |
3632 | 3672 | ||
@@ -3882,95 +3922,42 @@ static inline char *fmt_multiple_name(struct device *dev, | |||
3882 | } | 3922 | } |
3883 | 3923 | ||
3884 | /** | 3924 | /** |
3885 | * snd_soc_register_dai - Register a DAI with the ASoC core | 3925 | * snd_soc_unregister_dai - Unregister DAIs from the ASoC core |
3886 | * | 3926 | * |
3887 | * @dai: DAI to register | 3927 | * @component: The component for which the DAIs should be unregistered |
3888 | */ | 3928 | */ |
3889 | static int snd_soc_register_dai(struct device *dev, | 3929 | static void snd_soc_unregister_dais(struct snd_soc_component *component) |
3890 | struct snd_soc_dai_driver *dai_drv) | ||
3891 | { | 3930 | { |
3892 | struct snd_soc_codec *codec; | 3931 | struct snd_soc_dai *dai, *_dai; |
3893 | struct snd_soc_dai *dai; | ||
3894 | |||
3895 | dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); | ||
3896 | 3932 | ||
3897 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | 3933 | list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { |
3898 | if (dai == NULL) | 3934 | dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", |
3899 | return -ENOMEM; | 3935 | dai->name); |
3900 | 3936 | list_del(&dai->list); | |
3901 | /* create DAI component name */ | 3937 | kfree(dai->name); |
3902 | dai->name = fmt_single_name(dev, &dai->id); | ||
3903 | if (dai->name == NULL) { | ||
3904 | kfree(dai); | 3938 | kfree(dai); |
3905 | return -ENOMEM; | ||
3906 | } | ||
3907 | |||
3908 | dai->dev = dev; | ||
3909 | dai->driver = dai_drv; | ||
3910 | dai->dapm.dev = dev; | ||
3911 | if (!dai->driver->ops) | ||
3912 | dai->driver->ops = &null_dai_ops; | ||
3913 | |||
3914 | mutex_lock(&client_mutex); | ||
3915 | |||
3916 | list_for_each_entry(codec, &codec_list, list) { | ||
3917 | if (codec->dev == dev) { | ||
3918 | dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", | ||
3919 | dai->name, codec->name); | ||
3920 | dai->codec = codec; | ||
3921 | break; | ||
3922 | } | ||
3923 | } | 3939 | } |
3924 | |||
3925 | if (!dai->codec) | ||
3926 | dai->dapm.idle_bias_off = 1; | ||
3927 | |||
3928 | list_add(&dai->list, &dai_list); | ||
3929 | |||
3930 | mutex_unlock(&client_mutex); | ||
3931 | |||
3932 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); | ||
3933 | |||
3934 | return 0; | ||
3935 | } | 3940 | } |
3936 | 3941 | ||
3937 | /** | 3942 | /** |
3938 | * snd_soc_unregister_dai - Unregister a DAI from the ASoC core | 3943 | * snd_soc_register_dais - Register a DAI with the ASoC core |
3939 | * | 3944 | * |
3940 | * @dai: DAI to unregister | 3945 | * @component: The component the DAIs are registered for |
3941 | */ | 3946 | * @codec: The CODEC that the DAIs are registered for, NULL if the component is |
3942 | static void snd_soc_unregister_dai(struct device *dev) | 3947 | * not a CODEC. |
3943 | { | 3948 | * @dai_drv: DAI driver to use for the DAIs |
3944 | struct snd_soc_dai *dai; | ||
3945 | |||
3946 | list_for_each_entry(dai, &dai_list, list) { | ||
3947 | if (dev == dai->dev) | ||
3948 | goto found; | ||
3949 | } | ||
3950 | return; | ||
3951 | |||
3952 | found: | ||
3953 | mutex_lock(&client_mutex); | ||
3954 | list_del(&dai->list); | ||
3955 | mutex_unlock(&client_mutex); | ||
3956 | |||
3957 | dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); | ||
3958 | kfree(dai->name); | ||
3959 | kfree(dai); | ||
3960 | } | ||
3961 | |||
3962 | /** | ||
3963 | * snd_soc_register_dais - Register multiple DAIs with the ASoC core | ||
3964 | * | ||
3965 | * @dai: Array of DAIs to register | ||
3966 | * @count: Number of DAIs | 3949 | * @count: Number of DAIs |
3950 | * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the | ||
3951 | * parent's name. | ||
3967 | */ | 3952 | */ |
3968 | static int snd_soc_register_dais(struct device *dev, | 3953 | static int snd_soc_register_dais(struct snd_soc_component *component, |
3969 | struct snd_soc_dai_driver *dai_drv, size_t count) | 3954 | struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, |
3955 | size_t count, bool legacy_dai_naming) | ||
3970 | { | 3956 | { |
3971 | struct snd_soc_codec *codec; | 3957 | struct device *dev = component->dev; |
3972 | struct snd_soc_dai *dai; | 3958 | struct snd_soc_dai *dai; |
3973 | int i, ret = 0; | 3959 | unsigned int i; |
3960 | int ret; | ||
3974 | 3961 | ||
3975 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); | 3962 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); |
3976 | 3963 | ||
@@ -3982,70 +3969,54 @@ static int snd_soc_register_dais(struct device *dev, | |||
3982 | goto err; | 3969 | goto err; |
3983 | } | 3970 | } |
3984 | 3971 | ||
3985 | /* create DAI component name */ | 3972 | /* |
3986 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | 3973 | * Back in the old days when we still had component-less DAIs, |
3974 | * instead of having a static name, component-less DAIs would | ||
3975 | * inherit the name of the parent device so it is possible to | ||
3976 | * register multiple instances of the DAI. We still need to keep | ||
3977 | * the same naming style even though those DAIs are not | ||
3978 | * component-less anymore. | ||
3979 | */ | ||
3980 | if (count == 1 && legacy_dai_naming) { | ||
3981 | dai->name = fmt_single_name(dev, &dai->id); | ||
3982 | } else { | ||
3983 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | ||
3984 | if (dai_drv[i].id) | ||
3985 | dai->id = dai_drv[i].id; | ||
3986 | else | ||
3987 | dai->id = i; | ||
3988 | } | ||
3987 | if (dai->name == NULL) { | 3989 | if (dai->name == NULL) { |
3988 | kfree(dai); | 3990 | kfree(dai); |
3989 | ret = -EINVAL; | 3991 | ret = -ENOMEM; |
3990 | goto err; | 3992 | goto err; |
3991 | } | 3993 | } |
3992 | 3994 | ||
3995 | dai->component = component; | ||
3996 | dai->codec = codec; | ||
3993 | dai->dev = dev; | 3997 | dai->dev = dev; |
3994 | dai->driver = &dai_drv[i]; | 3998 | dai->driver = &dai_drv[i]; |
3995 | if (dai->driver->id) | ||
3996 | dai->id = dai->driver->id; | ||
3997 | else | ||
3998 | dai->id = i; | ||
3999 | dai->dapm.dev = dev; | 3999 | dai->dapm.dev = dev; |
4000 | if (!dai->driver->ops) | 4000 | if (!dai->driver->ops) |
4001 | dai->driver->ops = &null_dai_ops; | 4001 | dai->driver->ops = &null_dai_ops; |
4002 | 4002 | ||
4003 | mutex_lock(&client_mutex); | ||
4004 | |||
4005 | list_for_each_entry(codec, &codec_list, list) { | ||
4006 | if (codec->dev == dev) { | ||
4007 | dev_dbg(dev, | ||
4008 | "ASoC: Mapped DAI %s to CODEC %s\n", | ||
4009 | dai->name, codec->name); | ||
4010 | dai->codec = codec; | ||
4011 | break; | ||
4012 | } | ||
4013 | } | ||
4014 | |||
4015 | if (!dai->codec) | 4003 | if (!dai->codec) |
4016 | dai->dapm.idle_bias_off = 1; | 4004 | dai->dapm.idle_bias_off = 1; |
4017 | 4005 | ||
4018 | list_add(&dai->list, &dai_list); | 4006 | list_add(&dai->list, &component->dai_list); |
4019 | 4007 | ||
4020 | mutex_unlock(&client_mutex); | 4008 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); |
4021 | |||
4022 | dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); | ||
4023 | } | 4009 | } |
4024 | 4010 | ||
4025 | return 0; | 4011 | return 0; |
4026 | 4012 | ||
4027 | err: | 4013 | err: |
4028 | for (i--; i >= 0; i--) | 4014 | snd_soc_unregister_dais(component); |
4029 | snd_soc_unregister_dai(dev); | ||
4030 | 4015 | ||
4031 | return ret; | 4016 | return ret; |
4032 | } | 4017 | } |
4033 | 4018 | ||
4034 | /** | 4019 | /** |
4035 | * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core | ||
4036 | * | ||
4037 | * @dai: Array of DAIs to unregister | ||
4038 | * @count: Number of DAIs | ||
4039 | */ | ||
4040 | static void snd_soc_unregister_dais(struct device *dev, size_t count) | ||
4041 | { | ||
4042 | int i; | ||
4043 | |||
4044 | for (i = 0; i < count; i++) | ||
4045 | snd_soc_unregister_dai(dev); | ||
4046 | } | ||
4047 | |||
4048 | /** | ||
4049 | * snd_soc_register_component - Register a component with the ASoC core | 4020 | * snd_soc_register_component - Register a component with the ASoC core |
4050 | * | 4021 | * |
4051 | */ | 4022 | */ |
@@ -4053,6 +4024,7 @@ static int | |||
4053 | __snd_soc_register_component(struct device *dev, | 4024 | __snd_soc_register_component(struct device *dev, |
4054 | struct snd_soc_component *cmpnt, | 4025 | struct snd_soc_component *cmpnt, |
4055 | const struct snd_soc_component_driver *cmpnt_drv, | 4026 | const struct snd_soc_component_driver *cmpnt_drv, |
4027 | struct snd_soc_codec *codec, | ||
4056 | struct snd_soc_dai_driver *dai_drv, | 4028 | struct snd_soc_dai_driver *dai_drv, |
4057 | int num_dai, bool allow_single_dai) | 4029 | int num_dai, bool allow_single_dai) |
4058 | { | 4030 | { |
@@ -4075,20 +4047,10 @@ __snd_soc_register_component(struct device *dev, | |||
4075 | cmpnt->driver = cmpnt_drv; | 4047 | cmpnt->driver = cmpnt_drv; |
4076 | cmpnt->dai_drv = dai_drv; | 4048 | cmpnt->dai_drv = dai_drv; |
4077 | cmpnt->num_dai = num_dai; | 4049 | cmpnt->num_dai = num_dai; |
4050 | INIT_LIST_HEAD(&cmpnt->dai_list); | ||
4078 | 4051 | ||
4079 | /* | 4052 | ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, |
4080 | * snd_soc_register_dai() uses fmt_single_name(), and | 4053 | allow_single_dai); |
4081 | * snd_soc_register_dais() uses fmt_multiple_name() | ||
4082 | * for dai->name which is used for name based matching | ||
4083 | * | ||
4084 | * this function is used from cpu/codec. | ||
4085 | * allow_single_dai flag can ignore "codec" driver reworking | ||
4086 | * since it had been used snd_soc_register_dais(), | ||
4087 | */ | ||
4088 | if ((1 == num_dai) && allow_single_dai) | ||
4089 | ret = snd_soc_register_dai(dev, dai_drv); | ||
4090 | else | ||
4091 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | ||
4092 | if (ret < 0) { | 4054 | if (ret < 0) { |
4093 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); | 4055 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); |
4094 | goto error_component_name; | 4056 | goto error_component_name; |
@@ -4121,7 +4083,9 @@ int snd_soc_register_component(struct device *dev, | |||
4121 | return -ENOMEM; | 4083 | return -ENOMEM; |
4122 | } | 4084 | } |
4123 | 4085 | ||
4124 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, | 4086 | cmpnt->ignore_pmdown_time = true; |
4087 | |||
4088 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, | ||
4125 | dai_drv, num_dai, true); | 4089 | dai_drv, num_dai, true); |
4126 | } | 4090 | } |
4127 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | 4091 | EXPORT_SYMBOL_GPL(snd_soc_register_component); |
@@ -4141,7 +4105,7 @@ void snd_soc_unregister_component(struct device *dev) | |||
4141 | return; | 4105 | return; |
4142 | 4106 | ||
4143 | found: | 4107 | found: |
4144 | snd_soc_unregister_dais(dev, cmpnt->num_dai); | 4108 | snd_soc_unregister_dais(cmpnt); |
4145 | 4109 | ||
4146 | mutex_lock(&client_mutex); | 4110 | mutex_lock(&client_mutex); |
4147 | list_del(&cmpnt->list); | 4111 | list_del(&cmpnt->list); |
@@ -4319,7 +4283,7 @@ int snd_soc_register_codec(struct device *dev, | |||
4319 | codec->volatile_register = codec_drv->volatile_register; | 4283 | codec->volatile_register = codec_drv->volatile_register; |
4320 | codec->readable_register = codec_drv->readable_register; | 4284 | codec->readable_register = codec_drv->readable_register; |
4321 | codec->writable_register = codec_drv->writable_register; | 4285 | codec->writable_register = codec_drv->writable_register; |
4322 | codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; | 4286 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; |
4323 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 4287 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
4324 | codec->dapm.dev = dev; | 4288 | codec->dapm.dev = dev; |
4325 | codec->dapm.codec = codec; | 4289 | codec->dapm.codec = codec; |
@@ -4342,7 +4306,7 @@ int snd_soc_register_codec(struct device *dev, | |||
4342 | /* register component */ | 4306 | /* register component */ |
4343 | ret = __snd_soc_register_component(dev, &codec->component, | 4307 | ret = __snd_soc_register_component(dev, &codec->component, |
4344 | &codec_drv->component_driver, | 4308 | &codec_drv->component_driver, |
4345 | dai_drv, num_dai, false); | 4309 | codec, dai_drv, num_dai, false); |
4346 | if (ret < 0) { | 4310 | if (ret < 0) { |
4347 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); | 4311 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); |
4348 | goto fail_codec_name; | 4312 | goto fail_codec_name; |
@@ -4417,6 +4381,122 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, | |||
4417 | } | 4381 | } |
4418 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); | 4382 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_card_name); |
4419 | 4383 | ||
4384 | static const struct snd_soc_dapm_widget simple_widgets[] = { | ||
4385 | SND_SOC_DAPM_MIC("Microphone", NULL), | ||
4386 | SND_SOC_DAPM_LINE("Line", NULL), | ||
4387 | SND_SOC_DAPM_HP("Headphone", NULL), | ||
4388 | SND_SOC_DAPM_SPK("Speaker", NULL), | ||
4389 | }; | ||
4390 | |||
4391 | int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, | ||
4392 | const char *propname) | ||
4393 | { | ||
4394 | struct device_node *np = card->dev->of_node; | ||
4395 | struct snd_soc_dapm_widget *widgets; | ||
4396 | const char *template, *wname; | ||
4397 | int i, j, num_widgets, ret; | ||
4398 | |||
4399 | num_widgets = of_property_count_strings(np, propname); | ||
4400 | if (num_widgets < 0) { | ||
4401 | dev_err(card->dev, | ||
4402 | "ASoC: Property '%s' does not exist\n", propname); | ||
4403 | return -EINVAL; | ||
4404 | } | ||
4405 | if (num_widgets & 1) { | ||
4406 | dev_err(card->dev, | ||
4407 | "ASoC: Property '%s' length is not even\n", propname); | ||
4408 | return -EINVAL; | ||
4409 | } | ||
4410 | |||
4411 | num_widgets /= 2; | ||
4412 | if (!num_widgets) { | ||
4413 | dev_err(card->dev, "ASoC: Property '%s's length is zero\n", | ||
4414 | propname); | ||
4415 | return -EINVAL; | ||
4416 | } | ||
4417 | |||
4418 | widgets = devm_kcalloc(card->dev, num_widgets, sizeof(*widgets), | ||
4419 | GFP_KERNEL); | ||
4420 | if (!widgets) { | ||
4421 | dev_err(card->dev, | ||
4422 | "ASoC: Could not allocate memory for widgets\n"); | ||
4423 | return -ENOMEM; | ||
4424 | } | ||
4425 | |||
4426 | for (i = 0; i < num_widgets; i++) { | ||
4427 | ret = of_property_read_string_index(np, propname, | ||
4428 | 2 * i, &template); | ||
4429 | if (ret) { | ||
4430 | dev_err(card->dev, | ||
4431 | "ASoC: Property '%s' index %d read error:%d\n", | ||
4432 | propname, 2 * i, ret); | ||
4433 | return -EINVAL; | ||
4434 | } | ||
4435 | |||
4436 | for (j = 0; j < ARRAY_SIZE(simple_widgets); j++) { | ||
4437 | if (!strncmp(template, simple_widgets[j].name, | ||
4438 | strlen(simple_widgets[j].name))) { | ||
4439 | widgets[i] = simple_widgets[j]; | ||
4440 | break; | ||
4441 | } | ||
4442 | } | ||
4443 | |||
4444 | if (j >= ARRAY_SIZE(simple_widgets)) { | ||
4445 | dev_err(card->dev, | ||
4446 | "ASoC: DAPM widget '%s' is not supported\n", | ||
4447 | template); | ||
4448 | return -EINVAL; | ||
4449 | } | ||
4450 | |||
4451 | ret = of_property_read_string_index(np, propname, | ||
4452 | (2 * i) + 1, | ||
4453 | &wname); | ||
4454 | if (ret) { | ||
4455 | dev_err(card->dev, | ||
4456 | "ASoC: Property '%s' index %d read error:%d\n", | ||
4457 | propname, (2 * i) + 1, ret); | ||
4458 | return -EINVAL; | ||
4459 | } | ||
4460 | |||
4461 | widgets[i].name = wname; | ||
4462 | } | ||
4463 | |||
4464 | card->dapm_widgets = widgets; | ||
4465 | card->num_dapm_widgets = num_widgets; | ||
4466 | |||
4467 | return 0; | ||
4468 | } | ||
4469 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); | ||
4470 | |||
4471 | int snd_soc_of_parse_tdm_slot(struct device_node *np, | ||
4472 | unsigned int *slots, | ||
4473 | unsigned int *slot_width) | ||
4474 | { | ||
4475 | u32 val; | ||
4476 | int ret; | ||
4477 | |||
4478 | if (of_property_read_bool(np, "dai-tdm-slot-num")) { | ||
4479 | ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); | ||
4480 | if (ret) | ||
4481 | return ret; | ||
4482 | |||
4483 | if (slots) | ||
4484 | *slots = val; | ||
4485 | } | ||
4486 | |||
4487 | if (of_property_read_bool(np, "dai-tdm-slot-width")) { | ||
4488 | ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); | ||
4489 | if (ret) | ||
4490 | return ret; | ||
4491 | |||
4492 | if (slot_width) | ||
4493 | *slot_width = val; | ||
4494 | } | ||
4495 | |||
4496 | return 0; | ||
4497 | } | ||
4498 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); | ||
4499 | |||
4420 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | 4500 | int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, |
4421 | const char *propname) | 4501 | const char *propname) |
4422 | { | 4502 | { |
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index dc8ff13187f7..c8a780d0d057 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c | |||
@@ -70,8 +70,6 @@ static int dapm_up_seq[] = { | |||
70 | [snd_soc_dapm_aif_out] = 4, | 70 | [snd_soc_dapm_aif_out] = 4, |
71 | [snd_soc_dapm_mic] = 5, | 71 | [snd_soc_dapm_mic] = 5, |
72 | [snd_soc_dapm_mux] = 6, | 72 | [snd_soc_dapm_mux] = 6, |
73 | [snd_soc_dapm_virt_mux] = 6, | ||
74 | [snd_soc_dapm_value_mux] = 6, | ||
75 | [snd_soc_dapm_dac] = 7, | 73 | [snd_soc_dapm_dac] = 7, |
76 | [snd_soc_dapm_switch] = 8, | 74 | [snd_soc_dapm_switch] = 8, |
77 | [snd_soc_dapm_mixer] = 8, | 75 | [snd_soc_dapm_mixer] = 8, |
@@ -102,8 +100,6 @@ static int dapm_down_seq[] = { | |||
102 | [snd_soc_dapm_mic] = 7, | 100 | [snd_soc_dapm_mic] = 7, |
103 | [snd_soc_dapm_micbias] = 8, | 101 | [snd_soc_dapm_micbias] = 8, |
104 | [snd_soc_dapm_mux] = 9, | 102 | [snd_soc_dapm_mux] = 9, |
105 | [snd_soc_dapm_virt_mux] = 9, | ||
106 | [snd_soc_dapm_value_mux] = 9, | ||
107 | [snd_soc_dapm_aif_in] = 10, | 103 | [snd_soc_dapm_aif_in] = 10, |
108 | [snd_soc_dapm_aif_out] = 10, | 104 | [snd_soc_dapm_aif_out] = 10, |
109 | [snd_soc_dapm_dai_in] = 10, | 105 | [snd_soc_dapm_dai_in] = 10, |
@@ -115,6 +111,12 @@ static int dapm_down_seq[] = { | |||
115 | [snd_soc_dapm_post] = 14, | 111 | [snd_soc_dapm_post] = 14, |
116 | }; | 112 | }; |
117 | 113 | ||
114 | static void dapm_assert_locked(struct snd_soc_dapm_context *dapm) | ||
115 | { | ||
116 | if (dapm->card && dapm->card->instantiated) | ||
117 | lockdep_assert_held(&dapm->card->dapm_mutex); | ||
118 | } | ||
119 | |||
118 | static void pop_wait(u32 pop_time) | 120 | static void pop_wait(u32 pop_time) |
119 | { | 121 | { |
120 | if (pop_time) | 122 | if (pop_time) |
@@ -146,15 +148,16 @@ static bool dapm_dirty_widget(struct snd_soc_dapm_widget *w) | |||
146 | return !list_empty(&w->dirty); | 148 | return !list_empty(&w->dirty); |
147 | } | 149 | } |
148 | 150 | ||
149 | void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) | 151 | static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason) |
150 | { | 152 | { |
153 | dapm_assert_locked(w->dapm); | ||
154 | |||
151 | if (!dapm_dirty_widget(w)) { | 155 | if (!dapm_dirty_widget(w)) { |
152 | dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", | 156 | dev_vdbg(w->dapm->dev, "Marking %s dirty due to %s\n", |
153 | w->name, reason); | 157 | w->name, reason); |
154 | list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); | 158 | list_add_tail(&w->dirty, &w->dapm->card->dapm_dirty); |
155 | } | 159 | } |
156 | } | 160 | } |
157 | EXPORT_SYMBOL_GPL(dapm_mark_dirty); | ||
158 | 161 | ||
159 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) | 162 | void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm) |
160 | { | 163 | { |
@@ -361,6 +364,8 @@ static void dapm_reset(struct snd_soc_card *card) | |||
361 | { | 364 | { |
362 | struct snd_soc_dapm_widget *w; | 365 | struct snd_soc_dapm_widget *w; |
363 | 366 | ||
367 | lockdep_assert_held(&card->dapm_mutex); | ||
368 | |||
364 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); | 369 | memset(&card->dapm_stats, 0, sizeof(card->dapm_stats)); |
365 | 370 | ||
366 | list_for_each_entry(w, &card->widgets, list) { | 371 | list_for_each_entry(w, &card->widgets, list) { |
@@ -386,7 +391,8 @@ static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg, | |||
386 | return -1; | 391 | return -1; |
387 | } | 392 | } |
388 | 393 | ||
389 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, int val) | 394 | static int soc_widget_write(struct snd_soc_dapm_widget *w, int reg, |
395 | unsigned int val) | ||
390 | { | 396 | { |
391 | if (w->codec) | 397 | if (w->codec) |
392 | return snd_soc_write(w->codec, reg, val); | 398 | return snd_soc_write(w->codec, reg, val); |
@@ -498,131 +504,40 @@ out: | |||
498 | return ret; | 504 | return ret; |
499 | } | 505 | } |
500 | 506 | ||
501 | /* set up initial codec paths */ | 507 | /* connect mux widget to its interconnecting audio paths */ |
502 | static void dapm_set_path_status(struct snd_soc_dapm_widget *w, | 508 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, |
503 | struct snd_soc_dapm_path *p, int i) | 509 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
510 | struct snd_soc_dapm_path *path, const char *control_name, | ||
511 | const struct snd_kcontrol_new *kcontrol) | ||
504 | { | 512 | { |
505 | switch (w->id) { | 513 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
506 | case snd_soc_dapm_switch: | 514 | unsigned int val, item; |
507 | case snd_soc_dapm_mixer: | 515 | int i; |
508 | case snd_soc_dapm_mixer_named_ctl: { | ||
509 | int val; | ||
510 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | ||
511 | w->kcontrol_news[i].private_value; | ||
512 | int reg = mc->reg; | ||
513 | unsigned int shift = mc->shift; | ||
514 | int max = mc->max; | ||
515 | unsigned int mask = (1 << fls(max)) - 1; | ||
516 | unsigned int invert = mc->invert; | ||
517 | |||
518 | if (reg != SND_SOC_NOPM) { | ||
519 | soc_widget_read(w, reg, &val); | ||
520 | val = (val >> shift) & mask; | ||
521 | if (invert) | ||
522 | val = max - val; | ||
523 | p->connect = !!val; | ||
524 | } else { | ||
525 | p->connect = 0; | ||
526 | } | ||
527 | |||
528 | } | ||
529 | break; | ||
530 | case snd_soc_dapm_mux: { | ||
531 | struct soc_enum *e = (struct soc_enum *) | ||
532 | w->kcontrol_news[i].private_value; | ||
533 | int val, item; | ||
534 | |||
535 | soc_widget_read(w, e->reg, &val); | ||
536 | item = (val >> e->shift_l) & e->mask; | ||
537 | |||
538 | if (item < e->max && !strcmp(p->name, e->texts[item])) | ||
539 | p->connect = 1; | ||
540 | else | ||
541 | p->connect = 0; | ||
542 | } | ||
543 | break; | ||
544 | case snd_soc_dapm_virt_mux: { | ||
545 | struct soc_enum *e = (struct soc_enum *) | ||
546 | w->kcontrol_news[i].private_value; | ||
547 | 516 | ||
548 | p->connect = 0; | 517 | if (e->reg != SND_SOC_NOPM) { |
518 | soc_widget_read(dest, e->reg, &val); | ||
519 | val = (val >> e->shift_l) & e->mask; | ||
520 | item = snd_soc_enum_val_to_item(e, val); | ||
521 | } else { | ||
549 | /* since a virtual mux has no backing registers to | 522 | /* since a virtual mux has no backing registers to |
550 | * decide which path to connect, it will try to match | 523 | * decide which path to connect, it will try to match |
551 | * with the first enumeration. This is to ensure | 524 | * with the first enumeration. This is to ensure |
552 | * that the default mux choice (the first) will be | 525 | * that the default mux choice (the first) will be |
553 | * correctly powered up during initialization. | 526 | * correctly powered up during initialization. |
554 | */ | 527 | */ |
555 | if (!strcmp(p->name, e->texts[0])) | 528 | item = 0; |
556 | p->connect = 1; | ||
557 | } | ||
558 | break; | ||
559 | case snd_soc_dapm_value_mux: { | ||
560 | struct soc_enum *e = (struct soc_enum *) | ||
561 | w->kcontrol_news[i].private_value; | ||
562 | int val, item; | ||
563 | |||
564 | soc_widget_read(w, e->reg, &val); | ||
565 | val = (val >> e->shift_l) & e->mask; | ||
566 | for (item = 0; item < e->max; item++) { | ||
567 | if (val == e->values[item]) | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | if (item < e->max && !strcmp(p->name, e->texts[item])) | ||
572 | p->connect = 1; | ||
573 | else | ||
574 | p->connect = 0; | ||
575 | } | ||
576 | break; | ||
577 | /* does not affect routing - always connected */ | ||
578 | case snd_soc_dapm_pga: | ||
579 | case snd_soc_dapm_out_drv: | ||
580 | case snd_soc_dapm_output: | ||
581 | case snd_soc_dapm_adc: | ||
582 | case snd_soc_dapm_input: | ||
583 | case snd_soc_dapm_siggen: | ||
584 | case snd_soc_dapm_dac: | ||
585 | case snd_soc_dapm_micbias: | ||
586 | case snd_soc_dapm_vmid: | ||
587 | case snd_soc_dapm_supply: | ||
588 | case snd_soc_dapm_regulator_supply: | ||
589 | case snd_soc_dapm_clock_supply: | ||
590 | case snd_soc_dapm_aif_in: | ||
591 | case snd_soc_dapm_aif_out: | ||
592 | case snd_soc_dapm_dai_in: | ||
593 | case snd_soc_dapm_dai_out: | ||
594 | case snd_soc_dapm_hp: | ||
595 | case snd_soc_dapm_mic: | ||
596 | case snd_soc_dapm_spk: | ||
597 | case snd_soc_dapm_line: | ||
598 | case snd_soc_dapm_dai_link: | ||
599 | case snd_soc_dapm_kcontrol: | ||
600 | p->connect = 1; | ||
601 | break; | ||
602 | /* does affect routing - dynamically connected */ | ||
603 | case snd_soc_dapm_pre: | ||
604 | case snd_soc_dapm_post: | ||
605 | p->connect = 0; | ||
606 | break; | ||
607 | } | 529 | } |
608 | } | ||
609 | |||
610 | /* connect mux widget to its interconnecting audio paths */ | ||
611 | static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | ||
612 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | ||
613 | struct snd_soc_dapm_path *path, const char *control_name, | ||
614 | const struct snd_kcontrol_new *kcontrol) | ||
615 | { | ||
616 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
617 | int i; | ||
618 | 530 | ||
619 | for (i = 0; i < e->max; i++) { | 531 | for (i = 0; i < e->items; i++) { |
620 | if (!(strcmp(control_name, e->texts[i]))) { | 532 | if (!(strcmp(control_name, e->texts[i]))) { |
621 | list_add(&path->list, &dapm->card->paths); | 533 | list_add(&path->list, &dapm->card->paths); |
622 | list_add(&path->list_sink, &dest->sources); | 534 | list_add(&path->list_sink, &dest->sources); |
623 | list_add(&path->list_source, &src->sinks); | 535 | list_add(&path->list_source, &src->sinks); |
624 | path->name = (char*)e->texts[i]; | 536 | path->name = (char*)e->texts[i]; |
625 | dapm_set_path_status(dest, path, 0); | 537 | if (i == item) |
538 | path->connect = 1; | ||
539 | else | ||
540 | path->connect = 0; | ||
626 | return 0; | 541 | return 0; |
627 | } | 542 | } |
628 | } | 543 | } |
@@ -630,6 +545,30 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm, | |||
630 | return -ENODEV; | 545 | return -ENODEV; |
631 | } | 546 | } |
632 | 547 | ||
548 | /* set up initial codec paths */ | ||
549 | static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w, | ||
550 | struct snd_soc_dapm_path *p, int i) | ||
551 | { | ||
552 | struct soc_mixer_control *mc = (struct soc_mixer_control *) | ||
553 | w->kcontrol_news[i].private_value; | ||
554 | unsigned int reg = mc->reg; | ||
555 | unsigned int shift = mc->shift; | ||
556 | unsigned int max = mc->max; | ||
557 | unsigned int mask = (1 << fls(max)) - 1; | ||
558 | unsigned int invert = mc->invert; | ||
559 | unsigned int val; | ||
560 | |||
561 | if (reg != SND_SOC_NOPM) { | ||
562 | soc_widget_read(w, reg, &val); | ||
563 | val = (val >> shift) & mask; | ||
564 | if (invert) | ||
565 | val = max - val; | ||
566 | p->connect = !!val; | ||
567 | } else { | ||
568 | p->connect = 0; | ||
569 | } | ||
570 | } | ||
571 | |||
633 | /* connect mixer widget to its interconnecting audio paths */ | 572 | /* connect mixer widget to its interconnecting audio paths */ |
634 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | 573 | static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, |
635 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, | 574 | struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest, |
@@ -644,7 +583,7 @@ static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm, | |||
644 | list_add(&path->list_sink, &dest->sources); | 583 | list_add(&path->list_sink, &dest->sources); |
645 | list_add(&path->list_source, &src->sinks); | 584 | list_add(&path->list_source, &src->sinks); |
646 | path->name = dest->kcontrol_news[i].name; | 585 | path->name = dest->kcontrol_news[i].name; |
647 | dapm_set_path_status(dest, path, i); | 586 | dapm_set_mixer_path_status(dest, path, i); |
648 | return 0; | 587 | return 0; |
649 | } | 588 | } |
650 | } | 589 | } |
@@ -723,8 +662,6 @@ static int dapm_create_or_share_mixmux_kcontrol(struct snd_soc_dapm_widget *w, | |||
723 | kcname_in_long_name = true; | 662 | kcname_in_long_name = true; |
724 | break; | 663 | break; |
725 | case snd_soc_dapm_mux: | 664 | case snd_soc_dapm_mux: |
726 | case snd_soc_dapm_virt_mux: | ||
727 | case snd_soc_dapm_value_mux: | ||
728 | wname_in_long_name = true; | 665 | wname_in_long_name = true; |
729 | kcname_in_long_name = false; | 666 | kcname_in_long_name = false; |
730 | break; | 667 | break; |
@@ -1218,7 +1155,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1218 | ret = regulator_allow_bypass(w->regulator, false); | 1155 | ret = regulator_allow_bypass(w->regulator, false); |
1219 | if (ret != 0) | 1156 | if (ret != 0) |
1220 | dev_warn(w->dapm->dev, | 1157 | dev_warn(w->dapm->dev, |
1221 | "ASoC: Failed to bypass %s: %d\n", | 1158 | "ASoC: Failed to unbypass %s: %d\n", |
1222 | w->name, ret); | 1159 | w->name, ret); |
1223 | } | 1160 | } |
1224 | 1161 | ||
@@ -1228,7 +1165,7 @@ int dapm_regulator_event(struct snd_soc_dapm_widget *w, | |||
1228 | ret = regulator_allow_bypass(w->regulator, true); | 1165 | ret = regulator_allow_bypass(w->regulator, true); |
1229 | if (ret != 0) | 1166 | if (ret != 0) |
1230 | dev_warn(w->dapm->dev, | 1167 | dev_warn(w->dapm->dev, |
1231 | "ASoC: Failed to unbypass %s: %d\n", | 1168 | "ASoC: Failed to bypass %s: %d\n", |
1232 | w->name, ret); | 1169 | w->name, ret); |
1233 | } | 1170 | } |
1234 | 1171 | ||
@@ -1823,6 +1760,8 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1823 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); | 1760 | ASYNC_DOMAIN_EXCLUSIVE(async_domain); |
1824 | enum snd_soc_bias_level bias; | 1761 | enum snd_soc_bias_level bias; |
1825 | 1762 | ||
1763 | lockdep_assert_held(&card->dapm_mutex); | ||
1764 | |||
1826 | trace_snd_soc_dapm_start(card); | 1765 | trace_snd_soc_dapm_start(card); |
1827 | 1766 | ||
1828 | list_for_each_entry(d, &card->dapm_list, list) { | 1767 | list_for_each_entry(d, &card->dapm_list, list) { |
@@ -1897,10 +1836,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1897 | 1836 | ||
1898 | trace_snd_soc_dapm_walk_done(card); | 1837 | trace_snd_soc_dapm_walk_done(card); |
1899 | 1838 | ||
1900 | /* Run all the bias changes in parallel */ | 1839 | /* Run card bias changes at first */ |
1901 | list_for_each_entry(d, &card->dapm_list, list) | 1840 | dapm_pre_sequence_async(&card->dapm, 0); |
1902 | async_schedule_domain(dapm_pre_sequence_async, d, | 1841 | /* Run other bias changes in parallel */ |
1903 | &async_domain); | 1842 | list_for_each_entry(d, &card->dapm_list, list) { |
1843 | if (d != &card->dapm) | ||
1844 | async_schedule_domain(dapm_pre_sequence_async, d, | ||
1845 | &async_domain); | ||
1846 | } | ||
1904 | async_synchronize_full_domain(&async_domain); | 1847 | async_synchronize_full_domain(&async_domain); |
1905 | 1848 | ||
1906 | list_for_each_entry(w, &down_list, power_list) { | 1849 | list_for_each_entry(w, &down_list, power_list) { |
@@ -1920,10 +1863,14 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) | |||
1920 | dapm_seq_run(card, &up_list, event, true); | 1863 | dapm_seq_run(card, &up_list, event, true); |
1921 | 1864 | ||
1922 | /* Run all the bias changes in parallel */ | 1865 | /* Run all the bias changes in parallel */ |
1923 | list_for_each_entry(d, &card->dapm_list, list) | 1866 | list_for_each_entry(d, &card->dapm_list, list) { |
1924 | async_schedule_domain(dapm_post_sequence_async, d, | 1867 | if (d != &card->dapm) |
1925 | &async_domain); | 1868 | async_schedule_domain(dapm_post_sequence_async, d, |
1869 | &async_domain); | ||
1870 | } | ||
1926 | async_synchronize_full_domain(&async_domain); | 1871 | async_synchronize_full_domain(&async_domain); |
1872 | /* Run card bias changes at last */ | ||
1873 | dapm_post_sequence_async(&card->dapm, 0); | ||
1927 | 1874 | ||
1928 | /* do we need to notify any clients that DAPM event is complete */ | 1875 | /* do we need to notify any clients that DAPM event is complete */ |
1929 | list_for_each_entry(d, &card->dapm_list, list) { | 1876 | list_for_each_entry(d, &card->dapm_list, list) { |
@@ -2110,6 +2057,8 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, | |||
2110 | struct snd_soc_dapm_path *path; | 2057 | struct snd_soc_dapm_path *path; |
2111 | int found = 0; | 2058 | int found = 0; |
2112 | 2059 | ||
2060 | lockdep_assert_held(&card->dapm_mutex); | ||
2061 | |||
2113 | /* find dapm widget path assoc with kcontrol */ | 2062 | /* find dapm widget path assoc with kcontrol */ |
2114 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2063 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2115 | if (!path->name || !e->texts[mux]) | 2064 | if (!path->name || !e->texts[mux]) |
@@ -2160,6 +2109,8 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, | |||
2160 | struct snd_soc_dapm_path *path; | 2109 | struct snd_soc_dapm_path *path; |
2161 | int found = 0; | 2110 | int found = 0; |
2162 | 2111 | ||
2112 | lockdep_assert_held(&card->dapm_mutex); | ||
2113 | |||
2163 | /* find dapm widget path assoc with kcontrol */ | 2114 | /* find dapm widget path assoc with kcontrol */ |
2164 | dapm_kcontrol_for_each_path(path, kcontrol) { | 2115 | dapm_kcontrol_for_each_path(path, kcontrol) { |
2165 | found = 1; | 2116 | found = 1; |
@@ -2325,6 +2276,8 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2325 | { | 2276 | { |
2326 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); | 2277 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
2327 | 2278 | ||
2279 | dapm_assert_locked(dapm); | ||
2280 | |||
2328 | if (!w) { | 2281 | if (!w) { |
2329 | dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); | 2282 | dev_err(dapm->dev, "ASoC: DAPM unknown pin %s\n", pin); |
2330 | return -EINVAL; | 2283 | return -EINVAL; |
@@ -2341,18 +2294,18 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm, | |||
2341 | } | 2294 | } |
2342 | 2295 | ||
2343 | /** | 2296 | /** |
2344 | * snd_soc_dapm_sync - scan and power dapm paths | 2297 | * snd_soc_dapm_sync_unlocked - scan and power dapm paths |
2345 | * @dapm: DAPM context | 2298 | * @dapm: DAPM context |
2346 | * | 2299 | * |
2347 | * Walks all dapm audio paths and powers widgets according to their | 2300 | * Walks all dapm audio paths and powers widgets according to their |
2348 | * stream or path usage. | 2301 | * stream or path usage. |
2349 | * | 2302 | * |
2303 | * Requires external locking. | ||
2304 | * | ||
2350 | * Returns 0 for success. | 2305 | * Returns 0 for success. |
2351 | */ | 2306 | */ |
2352 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | 2307 | int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm) |
2353 | { | 2308 | { |
2354 | int ret; | ||
2355 | |||
2356 | /* | 2309 | /* |
2357 | * Suppress early reports (eg, jacks syncing their state) to avoid | 2310 | * Suppress early reports (eg, jacks syncing their state) to avoid |
2358 | * silly DAPM runs during card startup. | 2311 | * silly DAPM runs during card startup. |
@@ -2360,8 +2313,25 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | |||
2360 | if (!dapm->card || !dapm->card->instantiated) | 2313 | if (!dapm->card || !dapm->card->instantiated) |
2361 | return 0; | 2314 | return 0; |
2362 | 2315 | ||
2316 | return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); | ||
2317 | } | ||
2318 | EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked); | ||
2319 | |||
2320 | /** | ||
2321 | * snd_soc_dapm_sync - scan and power dapm paths | ||
2322 | * @dapm: DAPM context | ||
2323 | * | ||
2324 | * Walks all dapm audio paths and powers widgets according to their | ||
2325 | * stream or path usage. | ||
2326 | * | ||
2327 | * Returns 0 for success. | ||
2328 | */ | ||
2329 | int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm) | ||
2330 | { | ||
2331 | int ret; | ||
2332 | |||
2363 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2333 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
2364 | ret = dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); | 2334 | ret = snd_soc_dapm_sync_unlocked(dapm); |
2365 | mutex_unlock(&dapm->card->dapm_mutex); | 2335 | mutex_unlock(&dapm->card->dapm_mutex); |
2366 | return ret; | 2336 | return ret; |
2367 | } | 2337 | } |
@@ -2444,8 +2414,6 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm, | |||
2444 | path->connect = 1; | 2414 | path->connect = 1; |
2445 | return 0; | 2415 | return 0; |
2446 | case snd_soc_dapm_mux: | 2416 | case snd_soc_dapm_mux: |
2447 | case snd_soc_dapm_virt_mux: | ||
2448 | case snd_soc_dapm_value_mux: | ||
2449 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, | 2417 | ret = dapm_connect_mux(dapm, wsource, wsink, path, control, |
2450 | &wsink->kcontrol_news[0]); | 2418 | &wsink->kcontrol_news[0]); |
2451 | if (ret != 0) | 2419 | if (ret != 0) |
@@ -2772,8 +2740,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) | |||
2772 | dapm_new_mixer(w); | 2740 | dapm_new_mixer(w); |
2773 | break; | 2741 | break; |
2774 | case snd_soc_dapm_mux: | 2742 | case snd_soc_dapm_mux: |
2775 | case snd_soc_dapm_virt_mux: | ||
2776 | case snd_soc_dapm_value_mux: | ||
2777 | dapm_new_mux(w); | 2743 | dapm_new_mux(w); |
2778 | break; | 2744 | break; |
2779 | case snd_soc_dapm_pga: | 2745 | case snd_soc_dapm_pga: |
@@ -2935,213 +2901,75 @@ int snd_soc_dapm_get_enum_double(struct snd_kcontrol *kcontrol, | |||
2935 | { | 2901 | { |
2936 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2902 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
2937 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2903 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
2938 | unsigned int val; | 2904 | unsigned int reg_val, val; |
2939 | |||
2940 | val = snd_soc_read(codec, e->reg); | ||
2941 | ucontrol->value.enumerated.item[0] = (val >> e->shift_l) & e->mask; | ||
2942 | if (e->shift_l != e->shift_r) | ||
2943 | ucontrol->value.enumerated.item[1] = | ||
2944 | (val >> e->shift_r) & e->mask; | ||
2945 | |||
2946 | return 0; | ||
2947 | } | ||
2948 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); | ||
2949 | |||
2950 | /** | ||
2951 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback | ||
2952 | * @kcontrol: mixer control | ||
2953 | * @ucontrol: control element information | ||
2954 | * | ||
2955 | * Callback to set the value of a dapm enumerated double mixer control. | ||
2956 | * | ||
2957 | * Returns 0 for success. | ||
2958 | */ | ||
2959 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, | ||
2960 | struct snd_ctl_elem_value *ucontrol) | ||
2961 | { | ||
2962 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
2963 | struct snd_soc_card *card = codec->card; | ||
2964 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
2965 | unsigned int val, mux, change; | ||
2966 | unsigned int mask; | ||
2967 | struct snd_soc_dapm_update update; | ||
2968 | int ret = 0; | ||
2969 | |||
2970 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | ||
2971 | return -EINVAL; | ||
2972 | mux = ucontrol->value.enumerated.item[0]; | ||
2973 | val = mux << e->shift_l; | ||
2974 | mask = e->mask << e->shift_l; | ||
2975 | if (e->shift_l != e->shift_r) { | ||
2976 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | ||
2977 | return -EINVAL; | ||
2978 | val |= ucontrol->value.enumerated.item[1] << e->shift_r; | ||
2979 | mask |= e->mask << e->shift_r; | ||
2980 | } | ||
2981 | |||
2982 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
2983 | |||
2984 | change = snd_soc_test_bits(codec, e->reg, mask, val); | ||
2985 | if (change) { | ||
2986 | update.kcontrol = kcontrol; | ||
2987 | update.reg = e->reg; | ||
2988 | update.mask = mask; | ||
2989 | update.val = val; | ||
2990 | card->update = &update; | ||
2991 | |||
2992 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | ||
2993 | |||
2994 | card->update = NULL; | ||
2995 | } | ||
2996 | |||
2997 | mutex_unlock(&card->dapm_mutex); | ||
2998 | 2905 | ||
2999 | if (ret > 0) | 2906 | if (e->reg != SND_SOC_NOPM) |
3000 | soc_dpcm_runtime_update(card); | 2907 | reg_val = snd_soc_read(codec, e->reg); |
3001 | 2908 | else | |
3002 | return change; | 2909 | reg_val = dapm_kcontrol_get_value(kcontrol); |
3003 | } | ||
3004 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); | ||
3005 | |||
3006 | /** | ||
3007 | * snd_soc_dapm_get_enum_virt - Get virtual DAPM mux | ||
3008 | * @kcontrol: mixer control | ||
3009 | * @ucontrol: control element information | ||
3010 | * | ||
3011 | * Returns 0 for success. | ||
3012 | */ | ||
3013 | int snd_soc_dapm_get_enum_virt(struct snd_kcontrol *kcontrol, | ||
3014 | struct snd_ctl_elem_value *ucontrol) | ||
3015 | { | ||
3016 | ucontrol->value.enumerated.item[0] = dapm_kcontrol_get_value(kcontrol); | ||
3017 | return 0; | ||
3018 | } | ||
3019 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_virt); | ||
3020 | |||
3021 | /** | ||
3022 | * snd_soc_dapm_put_enum_virt - Set virtual DAPM mux | ||
3023 | * @kcontrol: mixer control | ||
3024 | * @ucontrol: control element information | ||
3025 | * | ||
3026 | * Returns 0 for success. | ||
3027 | */ | ||
3028 | int snd_soc_dapm_put_enum_virt(struct snd_kcontrol *kcontrol, | ||
3029 | struct snd_ctl_elem_value *ucontrol) | ||
3030 | { | ||
3031 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
3032 | struct snd_soc_card *card = codec->card; | ||
3033 | unsigned int value; | ||
3034 | struct soc_enum *e = | ||
3035 | (struct soc_enum *)kcontrol->private_value; | ||
3036 | int change; | ||
3037 | int ret = 0; | ||
3038 | |||
3039 | if (ucontrol->value.enumerated.item[0] >= e->max) | ||
3040 | return -EINVAL; | ||
3041 | |||
3042 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3043 | |||
3044 | value = ucontrol->value.enumerated.item[0]; | ||
3045 | change = dapm_kcontrol_set_value(kcontrol, value); | ||
3046 | if (change) | ||
3047 | ret = soc_dapm_mux_update_power(card, kcontrol, value, e); | ||
3048 | |||
3049 | mutex_unlock(&card->dapm_mutex); | ||
3050 | |||
3051 | if (ret > 0) | ||
3052 | soc_dpcm_runtime_update(card); | ||
3053 | |||
3054 | return change; | ||
3055 | } | ||
3056 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_virt); | ||
3057 | |||
3058 | /** | ||
3059 | * snd_soc_dapm_get_value_enum_double - dapm semi enumerated double mixer get | ||
3060 | * callback | ||
3061 | * @kcontrol: mixer control | ||
3062 | * @ucontrol: control element information | ||
3063 | * | ||
3064 | * Callback to get the value of a dapm semi enumerated double mixer control. | ||
3065 | * | ||
3066 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
3067 | * used for handling bitfield coded enumeration for example. | ||
3068 | * | ||
3069 | * Returns 0 for success. | ||
3070 | */ | ||
3071 | int snd_soc_dapm_get_value_enum_double(struct snd_kcontrol *kcontrol, | ||
3072 | struct snd_ctl_elem_value *ucontrol) | ||
3073 | { | ||
3074 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | ||
3075 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | ||
3076 | unsigned int reg_val, val, mux; | ||
3077 | 2910 | ||
3078 | reg_val = snd_soc_read(codec, e->reg); | ||
3079 | val = (reg_val >> e->shift_l) & e->mask; | 2911 | val = (reg_val >> e->shift_l) & e->mask; |
3080 | for (mux = 0; mux < e->max; mux++) { | 2912 | ucontrol->value.enumerated.item[0] = snd_soc_enum_val_to_item(e, val); |
3081 | if (val == e->values[mux]) | ||
3082 | break; | ||
3083 | } | ||
3084 | ucontrol->value.enumerated.item[0] = mux; | ||
3085 | if (e->shift_l != e->shift_r) { | 2913 | if (e->shift_l != e->shift_r) { |
3086 | val = (reg_val >> e->shift_r) & e->mask; | 2914 | val = (reg_val >> e->shift_r) & e->mask; |
3087 | for (mux = 0; mux < e->max; mux++) { | 2915 | val = snd_soc_enum_val_to_item(e, val); |
3088 | if (val == e->values[mux]) | 2916 | ucontrol->value.enumerated.item[1] = val; |
3089 | break; | ||
3090 | } | ||
3091 | ucontrol->value.enumerated.item[1] = mux; | ||
3092 | } | 2917 | } |
3093 | 2918 | ||
3094 | return 0; | 2919 | return 0; |
3095 | } | 2920 | } |
3096 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_value_enum_double); | 2921 | EXPORT_SYMBOL_GPL(snd_soc_dapm_get_enum_double); |
3097 | 2922 | ||
3098 | /** | 2923 | /** |
3099 | * snd_soc_dapm_put_value_enum_double - dapm semi enumerated double mixer set | 2924 | * snd_soc_dapm_put_enum_double - dapm enumerated double mixer set callback |
3100 | * callback | ||
3101 | * @kcontrol: mixer control | 2925 | * @kcontrol: mixer control |
3102 | * @ucontrol: control element information | 2926 | * @ucontrol: control element information |
3103 | * | 2927 | * |
3104 | * Callback to set the value of a dapm semi enumerated double mixer control. | 2928 | * Callback to set the value of a dapm enumerated double mixer control. |
3105 | * | ||
3106 | * Semi enumerated mixer: the enumerated items are referred as values. Can be | ||
3107 | * used for handling bitfield coded enumeration for example. | ||
3108 | * | 2929 | * |
3109 | * Returns 0 for success. | 2930 | * Returns 0 for success. |
3110 | */ | 2931 | */ |
3111 | int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | 2932 | int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, |
3112 | struct snd_ctl_elem_value *ucontrol) | 2933 | struct snd_ctl_elem_value *ucontrol) |
3113 | { | 2934 | { |
3114 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); | 2935 | struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); |
3115 | struct snd_soc_card *card = codec->card; | 2936 | struct snd_soc_card *card = codec->card; |
3116 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; | 2937 | struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; |
3117 | unsigned int val, mux, change; | 2938 | unsigned int *item = ucontrol->value.enumerated.item; |
2939 | unsigned int val, change; | ||
3118 | unsigned int mask; | 2940 | unsigned int mask; |
3119 | struct snd_soc_dapm_update update; | 2941 | struct snd_soc_dapm_update update; |
3120 | int ret = 0; | 2942 | int ret = 0; |
3121 | 2943 | ||
3122 | if (ucontrol->value.enumerated.item[0] > e->max - 1) | 2944 | if (item[0] >= e->items) |
3123 | return -EINVAL; | 2945 | return -EINVAL; |
3124 | mux = ucontrol->value.enumerated.item[0]; | 2946 | |
3125 | val = e->values[ucontrol->value.enumerated.item[0]] << e->shift_l; | 2947 | val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; |
3126 | mask = e->mask << e->shift_l; | 2948 | mask = e->mask << e->shift_l; |
3127 | if (e->shift_l != e->shift_r) { | 2949 | if (e->shift_l != e->shift_r) { |
3128 | if (ucontrol->value.enumerated.item[1] > e->max - 1) | 2950 | if (item[1] > e->items) |
3129 | return -EINVAL; | 2951 | return -EINVAL; |
3130 | val |= e->values[ucontrol->value.enumerated.item[1]] << e->shift_r; | 2952 | val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_l; |
3131 | mask |= e->mask << e->shift_r; | 2953 | mask |= e->mask << e->shift_r; |
3132 | } | 2954 | } |
3133 | 2955 | ||
3134 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | 2956 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); |
3135 | 2957 | ||
3136 | change = snd_soc_test_bits(codec, e->reg, mask, val); | 2958 | if (e->reg != SND_SOC_NOPM) |
2959 | change = snd_soc_test_bits(codec, e->reg, mask, val); | ||
2960 | else | ||
2961 | change = dapm_kcontrol_set_value(kcontrol, val); | ||
2962 | |||
3137 | if (change) { | 2963 | if (change) { |
3138 | update.kcontrol = kcontrol; | 2964 | if (e->reg != SND_SOC_NOPM) { |
3139 | update.reg = e->reg; | 2965 | update.kcontrol = kcontrol; |
3140 | update.mask = mask; | 2966 | update.reg = e->reg; |
3141 | update.val = val; | 2967 | update.mask = mask; |
3142 | card->update = &update; | 2968 | update.val = val; |
2969 | card->update = &update; | ||
2970 | } | ||
3143 | 2971 | ||
3144 | ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); | 2972 | ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); |
3145 | 2973 | ||
3146 | card->update = NULL; | 2974 | card->update = NULL; |
3147 | } | 2975 | } |
@@ -3153,7 +2981,7 @@ int snd_soc_dapm_put_value_enum_double(struct snd_kcontrol *kcontrol, | |||
3153 | 2981 | ||
3154 | return change; | 2982 | return change; |
3155 | } | 2983 | } |
3156 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_value_enum_double); | 2984 | EXPORT_SYMBOL_GPL(snd_soc_dapm_put_enum_double); |
3157 | 2985 | ||
3158 | /** | 2986 | /** |
3159 | * snd_soc_dapm_info_pin_switch - Info for a pin switch | 2987 | * snd_soc_dapm_info_pin_switch - Info for a pin switch |
@@ -3210,15 +3038,11 @@ int snd_soc_dapm_put_pin_switch(struct snd_kcontrol *kcontrol, | |||
3210 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); | 3038 | struct snd_soc_card *card = snd_kcontrol_chip(kcontrol); |
3211 | const char *pin = (const char *)kcontrol->private_value; | 3039 | const char *pin = (const char *)kcontrol->private_value; |
3212 | 3040 | ||
3213 | mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3214 | |||
3215 | if (ucontrol->value.integer.value[0]) | 3041 | if (ucontrol->value.integer.value[0]) |
3216 | snd_soc_dapm_enable_pin(&card->dapm, pin); | 3042 | snd_soc_dapm_enable_pin(&card->dapm, pin); |
3217 | else | 3043 | else |
3218 | snd_soc_dapm_disable_pin(&card->dapm, pin); | 3044 | snd_soc_dapm_disable_pin(&card->dapm, pin); |
3219 | 3045 | ||
3220 | mutex_unlock(&card->dapm_mutex); | ||
3221 | |||
3222 | snd_soc_dapm_sync(&card->dapm); | 3046 | snd_soc_dapm_sync(&card->dapm); |
3223 | return 0; | 3047 | return 0; |
3224 | } | 3048 | } |
@@ -3248,7 +3072,7 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3248 | ret = regulator_allow_bypass(w->regulator, true); | 3072 | ret = regulator_allow_bypass(w->regulator, true); |
3249 | if (ret != 0) | 3073 | if (ret != 0) |
3250 | dev_warn(w->dapm->dev, | 3074 | dev_warn(w->dapm->dev, |
3251 | "ASoC: Failed to unbypass %s: %d\n", | 3075 | "ASoC: Failed to bypass %s: %d\n", |
3252 | w->name, ret); | 3076 | w->name, ret); |
3253 | } | 3077 | } |
3254 | break; | 3078 | break; |
@@ -3287,8 +3111,6 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm, | |||
3287 | w->power_check = dapm_generic_check_power; | 3111 | w->power_check = dapm_generic_check_power; |
3288 | break; | 3112 | break; |
3289 | case snd_soc_dapm_mux: | 3113 | case snd_soc_dapm_mux: |
3290 | case snd_soc_dapm_virt_mux: | ||
3291 | case snd_soc_dapm_value_mux: | ||
3292 | w->power_check = dapm_generic_check_power; | 3114 | w->power_check = dapm_generic_check_power; |
3293 | break; | 3115 | break; |
3294 | case snd_soc_dapm_dai_out: | 3116 | case snd_soc_dapm_dai_out: |
@@ -3767,23 +3589,52 @@ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, | |||
3767 | } | 3589 | } |
3768 | 3590 | ||
3769 | /** | 3591 | /** |
3592 | * snd_soc_dapm_enable_pin_unlocked - enable pin. | ||
3593 | * @dapm: DAPM context | ||
3594 | * @pin: pin name | ||
3595 | * | ||
3596 | * Enables input/output pin and its parents or children widgets iff there is | ||
3597 | * a valid audio route and active audio stream. | ||
3598 | * | ||
3599 | * Requires external locking. | ||
3600 | * | ||
3601 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3602 | * do any widget power switching. | ||
3603 | */ | ||
3604 | int snd_soc_dapm_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, | ||
3605 | const char *pin) | ||
3606 | { | ||
3607 | return snd_soc_dapm_set_pin(dapm, pin, 1); | ||
3608 | } | ||
3609 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin_unlocked); | ||
3610 | |||
3611 | /** | ||
3770 | * snd_soc_dapm_enable_pin - enable pin. | 3612 | * snd_soc_dapm_enable_pin - enable pin. |
3771 | * @dapm: DAPM context | 3613 | * @dapm: DAPM context |
3772 | * @pin: pin name | 3614 | * @pin: pin name |
3773 | * | 3615 | * |
3774 | * Enables input/output pin and its parents or children widgets iff there is | 3616 | * Enables input/output pin and its parents or children widgets iff there is |
3775 | * a valid audio route and active audio stream. | 3617 | * a valid audio route and active audio stream. |
3618 | * | ||
3776 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 3619 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
3777 | * do any widget power switching. | 3620 | * do any widget power switching. |
3778 | */ | 3621 | */ |
3779 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) | 3622 | int snd_soc_dapm_enable_pin(struct snd_soc_dapm_context *dapm, const char *pin) |
3780 | { | 3623 | { |
3781 | return snd_soc_dapm_set_pin(dapm, pin, 1); | 3624 | int ret; |
3625 | |||
3626 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3627 | |||
3628 | ret = snd_soc_dapm_set_pin(dapm, pin, 1); | ||
3629 | |||
3630 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3631 | |||
3632 | return ret; | ||
3782 | } | 3633 | } |
3783 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | 3634 | EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); |
3784 | 3635 | ||
3785 | /** | 3636 | /** |
3786 | * snd_soc_dapm_force_enable_pin - force a pin to be enabled | 3637 | * snd_soc_dapm_force_enable_pin_unlocked - force a pin to be enabled |
3787 | * @dapm: DAPM context | 3638 | * @dapm: DAPM context |
3788 | * @pin: pin name | 3639 | * @pin: pin name |
3789 | * | 3640 | * |
@@ -3791,11 +3642,13 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_enable_pin); | |||
3791 | * intended for use with microphone bias supplies used in microphone | 3642 | * intended for use with microphone bias supplies used in microphone |
3792 | * jack detection. | 3643 | * jack detection. |
3793 | * | 3644 | * |
3645 | * Requires external locking. | ||
3646 | * | ||
3794 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 3647 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
3795 | * do any widget power switching. | 3648 | * do any widget power switching. |
3796 | */ | 3649 | */ |
3797 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | 3650 | int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm, |
3798 | const char *pin) | 3651 | const char *pin) |
3799 | { | 3652 | { |
3800 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); | 3653 | struct snd_soc_dapm_widget *w = dapm_find_widget(dapm, pin, true); |
3801 | 3654 | ||
@@ -3811,25 +3664,103 @@ int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | |||
3811 | 3664 | ||
3812 | return 0; | 3665 | return 0; |
3813 | } | 3666 | } |
3667 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin_unlocked); | ||
3668 | |||
3669 | /** | ||
3670 | * snd_soc_dapm_force_enable_pin - force a pin to be enabled | ||
3671 | * @dapm: DAPM context | ||
3672 | * @pin: pin name | ||
3673 | * | ||
3674 | * Enables input/output pin regardless of any other state. This is | ||
3675 | * intended for use with microphone bias supplies used in microphone | ||
3676 | * jack detection. | ||
3677 | * | ||
3678 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3679 | * do any widget power switching. | ||
3680 | */ | ||
3681 | int snd_soc_dapm_force_enable_pin(struct snd_soc_dapm_context *dapm, | ||
3682 | const char *pin) | ||
3683 | { | ||
3684 | int ret; | ||
3685 | |||
3686 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3687 | |||
3688 | ret = snd_soc_dapm_force_enable_pin_unlocked(dapm, pin); | ||
3689 | |||
3690 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3691 | |||
3692 | return ret; | ||
3693 | } | ||
3814 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); | 3694 | EXPORT_SYMBOL_GPL(snd_soc_dapm_force_enable_pin); |
3815 | 3695 | ||
3816 | /** | 3696 | /** |
3697 | * snd_soc_dapm_disable_pin_unlocked - disable pin. | ||
3698 | * @dapm: DAPM context | ||
3699 | * @pin: pin name | ||
3700 | * | ||
3701 | * Disables input/output pin and its parents or children widgets. | ||
3702 | * | ||
3703 | * Requires external locking. | ||
3704 | * | ||
3705 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3706 | * do any widget power switching. | ||
3707 | */ | ||
3708 | int snd_soc_dapm_disable_pin_unlocked(struct snd_soc_dapm_context *dapm, | ||
3709 | const char *pin) | ||
3710 | { | ||
3711 | return snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3712 | } | ||
3713 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin_unlocked); | ||
3714 | |||
3715 | /** | ||
3817 | * snd_soc_dapm_disable_pin - disable pin. | 3716 | * snd_soc_dapm_disable_pin - disable pin. |
3818 | * @dapm: DAPM context | 3717 | * @dapm: DAPM context |
3819 | * @pin: pin name | 3718 | * @pin: pin name |
3820 | * | 3719 | * |
3821 | * Disables input/output pin and its parents or children widgets. | 3720 | * Disables input/output pin and its parents or children widgets. |
3721 | * | ||
3822 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | 3722 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to |
3823 | * do any widget power switching. | 3723 | * do any widget power switching. |
3824 | */ | 3724 | */ |
3825 | int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, | 3725 | int snd_soc_dapm_disable_pin(struct snd_soc_dapm_context *dapm, |
3826 | const char *pin) | 3726 | const char *pin) |
3827 | { | 3727 | { |
3828 | return snd_soc_dapm_set_pin(dapm, pin, 0); | 3728 | int ret; |
3729 | |||
3730 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3731 | |||
3732 | ret = snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3733 | |||
3734 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3735 | |||
3736 | return ret; | ||
3829 | } | 3737 | } |
3830 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | 3738 | EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); |
3831 | 3739 | ||
3832 | /** | 3740 | /** |
3741 | * snd_soc_dapm_nc_pin_unlocked - permanently disable pin. | ||
3742 | * @dapm: DAPM context | ||
3743 | * @pin: pin name | ||
3744 | * | ||
3745 | * Marks the specified pin as being not connected, disabling it along | ||
3746 | * any parent or child widgets. At present this is identical to | ||
3747 | * snd_soc_dapm_disable_pin() but in future it will be extended to do | ||
3748 | * additional things such as disabling controls which only affect | ||
3749 | * paths through the pin. | ||
3750 | * | ||
3751 | * Requires external locking. | ||
3752 | * | ||
3753 | * NOTE: snd_soc_dapm_sync() needs to be called after this for DAPM to | ||
3754 | * do any widget power switching. | ||
3755 | */ | ||
3756 | int snd_soc_dapm_nc_pin_unlocked(struct snd_soc_dapm_context *dapm, | ||
3757 | const char *pin) | ||
3758 | { | ||
3759 | return snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3760 | } | ||
3761 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin_unlocked); | ||
3762 | |||
3763 | /** | ||
3833 | * snd_soc_dapm_nc_pin - permanently disable pin. | 3764 | * snd_soc_dapm_nc_pin - permanently disable pin. |
3834 | * @dapm: DAPM context | 3765 | * @dapm: DAPM context |
3835 | * @pin: pin name | 3766 | * @pin: pin name |
@@ -3845,7 +3776,15 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_disable_pin); | |||
3845 | */ | 3776 | */ |
3846 | int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) | 3777 | int snd_soc_dapm_nc_pin(struct snd_soc_dapm_context *dapm, const char *pin) |
3847 | { | 3778 | { |
3848 | return snd_soc_dapm_set_pin(dapm, pin, 0); | 3779 | int ret; |
3780 | |||
3781 | mutex_lock_nested(&dapm->card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); | ||
3782 | |||
3783 | ret = snd_soc_dapm_set_pin(dapm, pin, 0); | ||
3784 | |||
3785 | mutex_unlock(&dapm->card->dapm_mutex); | ||
3786 | |||
3787 | return ret; | ||
3849 | } | 3788 | } |
3850 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); | 3789 | EXPORT_SYMBOL_GPL(snd_soc_dapm_nc_pin); |
3851 | 3790 | ||
@@ -3985,7 +3924,7 @@ void snd_soc_dapm_free(struct snd_soc_dapm_context *dapm) | |||
3985 | } | 3924 | } |
3986 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); | 3925 | EXPORT_SYMBOL_GPL(snd_soc_dapm_free); |
3987 | 3926 | ||
3988 | static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | 3927 | static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) |
3989 | { | 3928 | { |
3990 | struct snd_soc_card *card = dapm->card; | 3929 | struct snd_soc_card *card = dapm->card; |
3991 | struct snd_soc_dapm_widget *w; | 3930 | struct snd_soc_dapm_widget *w; |
@@ -4025,14 +3964,21 @@ static void soc_dapm_shutdown_codec(struct snd_soc_dapm_context *dapm) | |||
4025 | */ | 3964 | */ |
4026 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) | 3965 | void snd_soc_dapm_shutdown(struct snd_soc_card *card) |
4027 | { | 3966 | { |
4028 | struct snd_soc_codec *codec; | 3967 | struct snd_soc_dapm_context *dapm; |
4029 | 3968 | ||
4030 | list_for_each_entry(codec, &card->codec_dev_list, card_list) { | 3969 | list_for_each_entry(dapm, &card->dapm_list, list) { |
4031 | soc_dapm_shutdown_codec(&codec->dapm); | 3970 | if (dapm != &card->dapm) { |
4032 | if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) | 3971 | soc_dapm_shutdown_dapm(dapm); |
4033 | snd_soc_dapm_set_bias_level(&codec->dapm, | 3972 | if (dapm->bias_level == SND_SOC_BIAS_STANDBY) |
4034 | SND_SOC_BIAS_OFF); | 3973 | snd_soc_dapm_set_bias_level(dapm, |
3974 | SND_SOC_BIAS_OFF); | ||
3975 | } | ||
4035 | } | 3976 | } |
3977 | |||
3978 | soc_dapm_shutdown_dapm(&card->dapm); | ||
3979 | if (card->dapm.bias_level == SND_SOC_BIAS_STANDBY) | ||
3980 | snd_soc_dapm_set_bias_level(&card->dapm, | ||
3981 | SND_SOC_BIAS_OFF); | ||
4036 | } | 3982 | } |
4037 | 3983 | ||
4038 | /* Module information */ | 3984 | /* Module information */ |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 47e1ce771e65..330eaf007d89 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
@@ -35,6 +35,86 @@ | |||
35 | #define DPCM_MAX_BE_USERS 8 | 35 | #define DPCM_MAX_BE_USERS 8 |
36 | 36 | ||
37 | /** | 37 | /** |
38 | * snd_soc_runtime_activate() - Increment active count for PCM runtime components | ||
39 | * @rtd: ASoC PCM runtime that is activated | ||
40 | * @stream: Direction of the PCM stream | ||
41 | * | ||
42 | * Increments the active count for all the DAIs and components attached to a PCM | ||
43 | * runtime. Should typically be called when a stream is opened. | ||
44 | * | ||
45 | * Must be called with the rtd->pcm_mutex being held | ||
46 | */ | ||
47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | ||
48 | { | ||
49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
50 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
51 | |||
52 | lockdep_assert_held(&rtd->pcm_mutex); | ||
53 | |||
54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
55 | cpu_dai->playback_active++; | ||
56 | codec_dai->playback_active++; | ||
57 | } else { | ||
58 | cpu_dai->capture_active++; | ||
59 | codec_dai->capture_active++; | ||
60 | } | ||
61 | |||
62 | cpu_dai->active++; | ||
63 | codec_dai->active++; | ||
64 | cpu_dai->component->active++; | ||
65 | codec_dai->component->active++; | ||
66 | } | ||
67 | |||
68 | /** | ||
69 | * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components | ||
70 | * @rtd: ASoC PCM runtime that is deactivated | ||
71 | * @stream: Direction of the PCM stream | ||
72 | * | ||
73 | * Decrements the active count for all the DAIs and components attached to a PCM | ||
74 | * runtime. Should typically be called when a stream is closed. | ||
75 | * | ||
76 | * Must be called with the rtd->pcm_mutex being held | ||
77 | */ | ||
78 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | ||
79 | { | ||
80 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
82 | |||
83 | lockdep_assert_held(&rtd->pcm_mutex); | ||
84 | |||
85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
86 | cpu_dai->playback_active--; | ||
87 | codec_dai->playback_active--; | ||
88 | } else { | ||
89 | cpu_dai->capture_active--; | ||
90 | codec_dai->capture_active--; | ||
91 | } | ||
92 | |||
93 | cpu_dai->active--; | ||
94 | codec_dai->active--; | ||
95 | cpu_dai->component->active--; | ||
96 | codec_dai->component->active--; | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay | ||
101 | * @rtd: The ASoC PCM runtime that should be checked. | ||
102 | * | ||
103 | * This function checks whether the power down delay should be ignored for a | ||
104 | * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has | ||
105 | * been configured to ignore the delay, or if none of the components benefits | ||
106 | * from having the delay. | ||
107 | */ | ||
108 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) | ||
109 | { | ||
110 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) | ||
111 | return true; | ||
112 | |||
113 | return rtd->cpu_dai->component->ignore_pmdown_time && | ||
114 | rtd->codec_dai->component->ignore_pmdown_time; | ||
115 | } | ||
116 | |||
117 | /** | ||
38 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters | 118 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters |
39 | * @substream: the pcm substream | 119 | * @substream: the pcm substream |
40 | * @hw: the hardware parameters | 120 | * @hw: the hardware parameters |
@@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
378 | runtime->hw.rate_max); | 458 | runtime->hw.rate_max); |
379 | 459 | ||
380 | dynamic: | 460 | dynamic: |
381 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 461 | |
382 | cpu_dai->playback_active++; | 462 | snd_soc_runtime_activate(rtd, substream->stream); |
383 | codec_dai->playback_active++; | 463 | |
384 | } else { | ||
385 | cpu_dai->capture_active++; | ||
386 | codec_dai->capture_active++; | ||
387 | } | ||
388 | cpu_dai->active++; | ||
389 | codec_dai->active++; | ||
390 | rtd->codec->active++; | ||
391 | mutex_unlock(&rtd->pcm_mutex); | 464 | mutex_unlock(&rtd->pcm_mutex); |
392 | return 0; | 465 | return 0; |
393 | 466 | ||
@@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
459 | struct snd_soc_platform *platform = rtd->platform; | 532 | struct snd_soc_platform *platform = rtd->platform; |
460 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 533 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
461 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 534 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
462 | struct snd_soc_codec *codec = rtd->codec; | ||
463 | 535 | ||
464 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 536 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
465 | 537 | ||
466 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 538 | snd_soc_runtime_deactivate(rtd, substream->stream); |
467 | cpu_dai->playback_active--; | ||
468 | codec_dai->playback_active--; | ||
469 | } else { | ||
470 | cpu_dai->capture_active--; | ||
471 | codec_dai->capture_active--; | ||
472 | } | ||
473 | |||
474 | cpu_dai->active--; | ||
475 | codec_dai->active--; | ||
476 | codec->active--; | ||
477 | 539 | ||
478 | /* clear the corresponding DAIs rate when inactive */ | 540 | /* clear the corresponding DAIs rate when inactive */ |
479 | if (!cpu_dai->active) | 541 | if (!cpu_dai->active) |
@@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
496 | cpu_dai->runtime = NULL; | 558 | cpu_dai->runtime = NULL; |
497 | 559 | ||
498 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 560 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
499 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 561 | if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
500 | rtd->dai_link->ignore_pmdown_time) { | ||
501 | /* powered down playback stream now */ | 562 | /* powered down playback stream now */ |
502 | snd_soc_dapm_stream_event(rtd, | 563 | snd_soc_dapm_stream_event(rtd, |
503 | SNDRV_PCM_STREAM_PLAYBACK, | 564 | SNDRV_PCM_STREAM_PLAYBACK, |
@@ -1989,6 +2050,7 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card) | |||
1989 | 2050 | ||
1990 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); | 2051 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list); |
1991 | if (paths < 0) { | 2052 | if (paths < 0) { |
2053 | dpcm_path_put(&list); | ||
1992 | dev_warn(fe->dev, "ASoC: %s no valid %s path\n", | 2054 | dev_warn(fe->dev, "ASoC: %s no valid %s path\n", |
1993 | fe->dai_link->name, "playback"); | 2055 | fe->dai_link->name, "playback"); |
1994 | mutex_unlock(&card->mutex); | 2056 | mutex_unlock(&card->mutex); |
@@ -2018,6 +2080,7 @@ capture: | |||
2018 | 2080 | ||
2019 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); | 2081 | paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list); |
2020 | if (paths < 0) { | 2082 | if (paths < 0) { |
2083 | dpcm_path_put(&list); | ||
2021 | dev_warn(fe->dev, "ASoC: %s no valid %s path\n", | 2084 | dev_warn(fe->dev, "ASoC: %s no valid %s path\n", |
2022 | fe->dai_link->name, "capture"); | 2085 | fe->dai_link->name, "capture"); |
2023 | mutex_unlock(&card->mutex); | 2086 | mutex_unlock(&card->mutex); |
@@ -2082,6 +2145,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) | |||
2082 | fe->dpcm[stream].runtime = fe_substream->runtime; | 2145 | fe->dpcm[stream].runtime = fe_substream->runtime; |
2083 | 2146 | ||
2084 | if (dpcm_path_get(fe, stream, &list) <= 0) { | 2147 | if (dpcm_path_get(fe, stream, &list) <= 0) { |
2148 | dpcm_path_put(&list); | ||
2085 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", | 2149 | dev_dbg(fe->dev, "ASoC: %s no valid %s route\n", |
2086 | fe->dai_link->name, stream ? "capture" : "playback"); | 2150 | fe->dai_link->name, stream ? "capture" : "playback"); |
2087 | } | 2151 | } |
diff --git a/sound/soc/spear/spdif_out.c b/sound/soc/spear/spdif_out.c index fe99f461aff0..19cca043e6e4 100644 --- a/sound/soc/spear/spdif_out.c +++ b/sound/soc/spear/spdif_out.c | |||
@@ -213,10 +213,7 @@ static int spdif_digital_mute(struct snd_soc_dai *dai, int mute) | |||
213 | static int spdif_mute_get(struct snd_kcontrol *kcontrol, | 213 | static int spdif_mute_get(struct snd_kcontrol *kcontrol, |
214 | struct snd_ctl_elem_value *ucontrol) | 214 | struct snd_ctl_elem_value *ucontrol) |
215 | { | 215 | { |
216 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 216 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
217 | struct snd_soc_card *card = codec->card; | ||
218 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
219 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
220 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); | 217 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); |
221 | 218 | ||
222 | ucontrol->value.integer.value[0] = host->saved_params.mute; | 219 | ucontrol->value.integer.value[0] = host->saved_params.mute; |
@@ -226,10 +223,7 @@ static int spdif_mute_get(struct snd_kcontrol *kcontrol, | |||
226 | static int spdif_mute_put(struct snd_kcontrol *kcontrol, | 223 | static int spdif_mute_put(struct snd_kcontrol *kcontrol, |
227 | struct snd_ctl_elem_value *ucontrol) | 224 | struct snd_ctl_elem_value *ucontrol) |
228 | { | 225 | { |
229 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 226 | struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); |
230 | struct snd_soc_card *card = codec->card; | ||
231 | struct snd_soc_pcm_runtime *rtd = card->rtd; | ||
232 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
233 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); | 227 | struct spdif_out_dev *host = snd_soc_dai_get_drvdata(cpu_dai); |
234 | 228 | ||
235 | if (host->saved_params.mute == ucontrol->value.integer.value[0]) | 229 | if (host->saved_params.mute == ucontrol->value.integer.value[0]) |
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig index 9f9c1856f822..31198cf7f88d 100644 --- a/sound/soc/tegra/Kconfig +++ b/sound/soc/tegra/Kconfig | |||
@@ -105,7 +105,7 @@ config SND_SOC_TEGRA_TRIMSLICE | |||
105 | tristate "SoC Audio support for TrimSlice board" | 105 | tristate "SoC Audio support for TrimSlice board" |
106 | depends on SND_SOC_TEGRA && I2C | 106 | depends on SND_SOC_TEGRA && I2C |
107 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC | 107 | select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC |
108 | select SND_SOC_TLV320AIC23 | 108 | select SND_SOC_TLV320AIC23_I2C |
109 | help | 109 | help |
110 | Say Y or M here if you want to add support for SoC audio on the | 110 | Say Y or M here if you want to add support for SoC audio on the |
111 | TrimSlice platform. | 111 | TrimSlice platform. |
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c index e0305a148568..9edd68db9f48 100644 --- a/sound/soc/txx9/txx9aclc-ac97.c +++ b/sound/soc/txx9/txx9aclc-ac97.c | |||
@@ -183,14 +183,16 @@ static int txx9aclc_ac97_dev_probe(struct platform_device *pdev) | |||
183 | irq = platform_get_irq(pdev, 0); | 183 | irq = platform_get_irq(pdev, 0); |
184 | if (irq < 0) | 184 | if (irq < 0) |
185 | return irq; | 185 | return irq; |
186 | |||
187 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); | ||
188 | if (!drvdata) | ||
189 | return -ENOMEM; | ||
190 | |||
186 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 191 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
187 | drvdata->base = devm_ioremap_resource(&pdev->dev, r); | 192 | drvdata->base = devm_ioremap_resource(&pdev->dev, r); |
188 | if (IS_ERR(drvdata->base)) | 193 | if (IS_ERR(drvdata->base)) |
189 | return PTR_ERR(drvdata->base); | 194 | return PTR_ERR(drvdata->base); |
190 | 195 | ||
191 | drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); | ||
192 | if (!drvdata) | ||
193 | return -ENOMEM; | ||
194 | platform_set_drvdata(pdev, drvdata); | 196 | platform_set_drvdata(pdev, drvdata); |
195 | drvdata->physbase = r->start; | 197 | drvdata->physbase = r->start; |
196 | if (sizeof(drvdata->physbase) > sizeof(r->start) && | 198 | if (sizeof(drvdata->physbase) > sizeof(r->start) && |
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index de9408b83f75..e05a86b7c0da 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
@@ -14,6 +14,7 @@ config SND_USB_AUDIO | |||
14 | select SND_HWDEP | 14 | select SND_HWDEP |
15 | select SND_RAWMIDI | 15 | select SND_RAWMIDI |
16 | select SND_PCM | 16 | select SND_PCM |
17 | select BITREVERSE | ||
17 | help | 18 | help |
18 | Say Y here to include support for USB audio and USB MIDI | 19 | Say Y here to include support for USB audio and USB MIDI |
19 | devices. | 20 | devices. |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 44b0ba4feab3..1bed780e21d9 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -883,6 +883,7 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, | |||
883 | } | 883 | } |
884 | break; | 884 | break; |
885 | 885 | ||
886 | case USB_ID(0x046d, 0x0807): /* Logitech Webcam C500 */ | ||
886 | case USB_ID(0x046d, 0x0808): | 887 | case USB_ID(0x046d, 0x0808): |
887 | case USB_ID(0x046d, 0x0809): | 888 | case USB_ID(0x046d, 0x0809): |
888 | case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ | 889 | case USB_ID(0x046d, 0x081b): /* HD Webcam c310 */ |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index 32af6b741ef5..d1d72ff50347 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -328,6 +328,11 @@ static struct usbmix_name_map gamecom780_map[] = { | |||
328 | {} | 328 | {} |
329 | }; | 329 | }; |
330 | 330 | ||
331 | static const struct usbmix_name_map kef_x300a_map[] = { | ||
332 | { 10, NULL }, /* firmware locks up (?) when we try to access this FU */ | ||
333 | { 0 } | ||
334 | }; | ||
335 | |||
331 | /* | 336 | /* |
332 | * Control map entries | 337 | * Control map entries |
333 | */ | 338 | */ |
@@ -419,6 +424,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
419 | .id = USB_ID(0x200c, 0x1018), | 424 | .id = USB_ID(0x200c, 0x1018), |
420 | .map = ebox44_map, | 425 | .map = ebox44_map, |
421 | }, | 426 | }, |
427 | { | ||
428 | .id = USB_ID(0x27ac, 0x1000), | ||
429 | .map = kef_x300a_map, | ||
430 | }, | ||
422 | { 0 } /* terminator */ | 431 | { 0 } /* terminator */ |
423 | }; | 432 | }; |
424 | 433 | ||