diff options
Diffstat (limited to 'sound')
553 files changed, 17129 insertions, 8142 deletions
diff --git a/sound/ac97/bus.c b/sound/ac97/bus.c index 8dfffdc101a2..47c6787158a7 100644 --- a/sound/ac97/bus.c +++ b/sound/ac97/bus.c @@ -387,7 +387,6 @@ void snd_ac97_controller_unregister(struct ac97_controller *ac97_ctrl) } EXPORT_SYMBOL_GPL(snd_ac97_controller_unregister); -#ifdef CONFIG_PM static int ac97_pm_runtime_suspend(struct device *dev) { struct ac97_codec_device *codec = to_ac97_device(dev); @@ -419,7 +418,6 @@ static int ac97_pm_runtime_resume(struct device *dev) return pm_generic_runtime_resume(dev); } -#endif /* CONFIG_PM */ static const struct dev_pm_ops ac97_pm = { .suspend = pm_generic_suspend, @@ -428,10 +426,7 @@ static const struct dev_pm_ops ac97_pm = { .thaw = pm_generic_thaw, .poweroff = pm_generic_poweroff, .restore = pm_generic_restore, - SET_RUNTIME_PM_OPS( - ac97_pm_runtime_suspend, - ac97_pm_runtime_resume, - NULL) + RUNTIME_PM_OPS(ac97_pm_runtime_suspend, ac97_pm_runtime_resume, NULL) }; static int ac97_get_enable_clk(struct ac97_codec_device *adev) @@ -535,7 +530,7 @@ const struct bus_type ac97_bus_type = { .name = "ac97bus", .dev_groups = ac97_dev_groups, .match = ac97_bus_match, - .pm = &ac97_pm, + .pm = pm_ptr(&ac97_pm), .probe = ac97_bus_probe, .remove = ac97_bus_remove, }; diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index c3340b8ff3da..243965615ef2 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -1061,7 +1061,7 @@ static void aaci_remove(struct amba_device *dev) } } -static struct amba_id aaci_ids[] = { +static const struct amba_id aaci_ids[] = { { .id = 0x00041041, .mask = 0x000fffff, diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index d8f8e08f1bb7..84e264f335ca 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c @@ -817,7 +817,6 @@ err_prepare_enable: return retval; } -#ifdef CONFIG_PM_SLEEP static int atmel_ac97c_suspend(struct device *pdev) { struct snd_card *card = dev_get_drvdata(pdev); @@ -836,11 +835,7 @@ static int atmel_ac97c_resume(struct device *pdev) return ret; } -static SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume); -#define ATMEL_AC97C_PM_OPS &atmel_ac97c_pm -#else -#define ATMEL_AC97C_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(atmel_ac97c_pm, atmel_ac97c_suspend, atmel_ac97c_resume); static void atmel_ac97c_remove(struct platform_device *pdev) { @@ -864,7 +859,7 @@ static struct platform_driver atmel_ac97c_driver = { .remove = atmel_ac97c_remove, .driver = { .name = "atmel_ac97c", - .pm = ATMEL_AC97C_PM_OPS, + .pm = pm_ptr(&atmel_ac97c_pm), .of_match_table = atmel_ac97c_dt_ids, }, }; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 290690fc2abc..283aac441fa0 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -592,7 +592,6 @@ static const struct attribute_group *pcm_dev_attr_groups[]; * PM callbacks: we need to deal only with suspend here, as the resume is * triggered either from user-space or the driver's resume callback */ -#ifdef CONFIG_PM_SLEEP static int do_pcm_suspend(struct device *dev) { struct snd_pcm_str *pstr = dev_get_drvdata(dev); @@ -601,10 +600,9 @@ static int do_pcm_suspend(struct device *dev) snd_pcm_suspend_all(pstr->pcm); return 0; } -#endif static const struct dev_pm_ops pcm_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL) + SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL) }; /* device type for PCM -- basically only for passing PM callbacks */ diff --git a/sound/core/pcm_drm_eld.c b/sound/core/pcm_drm_eld.c index 1cdca4d4fc9c..688eefce82fa 100644 --- a/sound/core/pcm_drm_eld.c +++ b/sound/core/pcm_drm_eld.c @@ -5,8 +5,10 @@ #include <linux/bitfield.h> #include <linux/export.h> #include <linux/hdmi.h> +#include <linux/unaligned.h> #include <drm/drm_edid.h> #include <drm/drm_eld.h> +#include <sound/info.h> #include <sound/pcm.h> #include <sound/pcm_drm_eld.h> @@ -162,3 +164,388 @@ int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld) return ret; } EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld); + +#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 +#define SND_PRINT_BITS_ADVISED_BUFSIZE 16 +#define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 + +static const char * const eld_connection_type_names[4] = { + "HDMI", + "DisplayPort", + "2-reserved", + "3-reserved" +}; + +static const char * const cea_audio_coding_type_names[] = { + /* 0 */ "undefined", + /* 1 */ "LPCM", + /* 2 */ "AC-3", + /* 3 */ "MPEG1", + /* 4 */ "MP3", + /* 5 */ "MPEG2", + /* 6 */ "AAC-LC", + /* 7 */ "DTS", + /* 8 */ "ATRAC", + /* 9 */ "DSD (One Bit Audio)", + /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", + /* 11 */ "DTS-HD", + /* 12 */ "MLP (Dolby TrueHD)", + /* 13 */ "DST", + /* 14 */ "WMAPro", + /* 15 */ "HE-AAC", + /* 16 */ "HE-AACv2", + /* 17 */ "MPEG Surround", +}; + +static const char * const cea_speaker_allocation_names[] = { + /* 0 */ "FL/FR", + /* 1 */ "LFE", + /* 2 */ "FC", + /* 3 */ "RL/RR", + /* 4 */ "RC", + /* 5 */ "FLC/FRC", + /* 6 */ "RLC/RRC", + /* 7 */ "FLW/FRW", + /* 8 */ "FLH/FRH", + /* 9 */ "TC", + /* 10 */ "FCH", +}; + +/* + * SS1:SS0 index => sample size + */ +static const int cea_sample_sizes[4] = { + 0, /* 0: Refer to Stream Header */ + ELD_PCM_BITS_16, /* 1: 16 bits */ + ELD_PCM_BITS_20, /* 2: 20 bits */ + ELD_PCM_BITS_24, /* 3: 24 bits */ +}; + +/* + * SF2:SF1:SF0 index => sampling frequency + */ +static const int cea_sampling_frequencies[8] = { + 0, /* 0: Refer to Stream Header */ + SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ + SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ + SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ + SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ + SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ + SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ + SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ +}; + +#define GRAB_BITS(buf, byte, lowbit, bits) \ +({ \ + BUILD_BUG_ON(lowbit > 7); \ + BUILD_BUG_ON(bits > 8); \ + BUILD_BUG_ON(bits <= 0); \ + \ + (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ +}) + +static void hdmi_update_short_audio_desc(struct device *dev, + struct snd_cea_sad *a, + const unsigned char *buf) +{ + int i; + int val; + + val = GRAB_BITS(buf, 1, 0, 7); + a->rates = 0; + for (i = 0; i < 7; i++) + if (val & (1 << i)) + a->rates |= cea_sampling_frequencies[i + 1]; + + a->channels = GRAB_BITS(buf, 0, 0, 3); + a->channels++; + + a->sample_bits = 0; + a->max_bitrate = 0; + + a->format = GRAB_BITS(buf, 0, 3, 4); + switch (a->format) { + case AUDIO_CODING_TYPE_REF_STREAM_HEADER: + dev_info(dev, "HDMI: audio coding type 0 not expected\n"); + break; + + case AUDIO_CODING_TYPE_LPCM: + val = GRAB_BITS(buf, 2, 0, 3); + for (i = 0; i < 3; i++) + if (val & (1 << i)) + a->sample_bits |= cea_sample_sizes[i + 1]; + break; + + case AUDIO_CODING_TYPE_AC3: + case AUDIO_CODING_TYPE_MPEG1: + case AUDIO_CODING_TYPE_MP3: + case AUDIO_CODING_TYPE_MPEG2: + case AUDIO_CODING_TYPE_AACLC: + case AUDIO_CODING_TYPE_DTS: + case AUDIO_CODING_TYPE_ATRAC: + a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); + a->max_bitrate *= 8000; + break; + + case AUDIO_CODING_TYPE_SACD: + break; + + case AUDIO_CODING_TYPE_EAC3: + break; + + case AUDIO_CODING_TYPE_DTS_HD: + break; + + case AUDIO_CODING_TYPE_MLP: + break; + + case AUDIO_CODING_TYPE_DST: + break; + + case AUDIO_CODING_TYPE_WMAPRO: + a->profile = GRAB_BITS(buf, 2, 0, 3); + break; + + case AUDIO_CODING_TYPE_REF_CXT: + a->format = GRAB_BITS(buf, 2, 3, 5); + if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || + a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { + dev_info(dev, + "HDMI: audio coding xtype %d not expected\n", + a->format); + a->format = 0; + } else + a->format += AUDIO_CODING_TYPE_HE_AAC - + AUDIO_CODING_XTYPE_HE_AAC; + break; + } +} + +/* + * Be careful, ELD buf could be totally rubbish! + */ +int snd_parse_eld(struct device *dev, struct snd_parsed_hdmi_eld *e, + const unsigned char *buf, int size) +{ + int mnl; + int i; + + memset(e, 0, sizeof(*e)); + e->eld_ver = GRAB_BITS(buf, 0, 3, 5); + if (e->eld_ver != ELD_VER_CEA_861D && + e->eld_ver != ELD_VER_PARTIAL) { + dev_info(dev, "HDMI: Unknown ELD version %d\n", e->eld_ver); + goto out_fail; + } + + e->baseline_len = GRAB_BITS(buf, 2, 0, 8); + mnl = GRAB_BITS(buf, 4, 0, 5); + e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); + + e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); + e->support_ai = GRAB_BITS(buf, 5, 1, 1); + e->conn_type = GRAB_BITS(buf, 5, 2, 2); + e->sad_count = GRAB_BITS(buf, 5, 4, 4); + + e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; + e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); + + e->port_id = get_unaligned_le64(buf + 8); + + /* not specified, but the spec's tendency is little endian */ + e->manufacture_id = get_unaligned_le16(buf + 16); + e->product_id = get_unaligned_le16(buf + 18); + + if (mnl > ELD_MAX_MNL) { + dev_info(dev, "HDMI: MNL is reserved value %d\n", mnl); + goto out_fail; + } else if (ELD_FIXED_BYTES + mnl > size) { + dev_info(dev, "HDMI: out of range MNL %d\n", mnl); + goto out_fail; + } else + strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); + + for (i = 0; i < e->sad_count; i++) { + if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { + dev_info(dev, "HDMI: out of range SAD %d\n", i); + goto out_fail; + } + hdmi_update_short_audio_desc(dev, e->sad + i, + buf + ELD_FIXED_BYTES + mnl + 3 * i); + } + + /* + * HDMI sink's ELD info cannot always be retrieved for now, e.g. + * in console or for audio devices. Assume the highest speakers + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!e->spk_alloc) + e->spk_alloc = 0xffff; + + return 0; + +out_fail: + return -EINVAL; +} +EXPORT_SYMBOL_GPL(snd_parse_eld); + +/* + * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with + * hdmi-specific routine. + */ +static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) +{ + static const unsigned int alsa_rates[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, + 88200, 96000, 176400, 192000, 384000 + }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) + if (pcm & (1 << i)) + j += scnprintf(buf + j, buflen - j, " %d", + alsa_rates[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void eld_print_pcm_bits(int pcm, char *buf, int buflen) +{ + static const unsigned int bits[] = { 8, 16, 20, 24, 32 }; + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(bits); i++) + if (pcm & (ELD_PCM_BITS_8 << i)) + j += scnprintf(buf + j, buflen - j, " %d", bits[i]); + + buf[j] = '\0'; /* necessary when j == 0 */ +} + +static void hdmi_show_short_audio_desc(struct device *dev, + struct snd_cea_sad *a) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; + + if (!a->format) + return; + + hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); + + if (a->format == AUDIO_CODING_TYPE_LPCM) + eld_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); + else if (a->max_bitrate) + snprintf(buf2, sizeof(buf2), + ", max bitrate = %d", a->max_bitrate); + else + buf2[0] = '\0'; + + dev_dbg(dev, + "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", + cea_audio_coding_type_names[a->format], + a->channels, buf, buf2); +} + +static void snd_eld_print_channel_allocation(int spk_alloc, char *buf, int buflen) +{ + int i, j; + + for (i = 0, j = 0; i < ARRAY_SIZE(cea_speaker_allocation_names); i++) { + if (spk_alloc & (1 << i)) + j += scnprintf(buf + j, buflen - j, " %s", + cea_speaker_allocation_names[i]); + } + buf[j] = '\0'; /* necessary when j == 0 */ +} + +void snd_show_eld(struct device *dev, struct snd_parsed_hdmi_eld *e) +{ + int i; + + dev_dbg(dev, "HDMI: detected monitor %s at connection type %s\n", + e->monitor_name, + eld_connection_type_names[e->conn_type]); + + if (e->spk_alloc) { + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + snd_eld_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + dev_dbg(dev, "HDMI: available speakers:%s\n", buf); + } + + for (i = 0; i < e->sad_count; i++) + hdmi_show_short_audio_desc(dev, e->sad + i); +} +EXPORT_SYMBOL_GPL(snd_show_eld); + +#ifdef CONFIG_SND_PROC_FS +static void hdmi_print_sad_info(int i, struct snd_cea_sad *a, + struct snd_info_buffer *buffer) +{ + char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; + + snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", + i, a->format, cea_audio_coding_type_names[a->format]); + snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); + + hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); + + if (a->format == AUDIO_CODING_TYPE_LPCM) { + eld_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); + snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", + i, a->sample_bits, buf); + } + + if (a->max_bitrate) + snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", + i, a->max_bitrate); + + if (a->profile) + snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); +} + +void snd_print_eld_info(struct snd_parsed_hdmi_eld *e, + struct snd_info_buffer *buffer) +{ + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + int i; + static const char * const eld_version_names[32] = { + "reserved", + "reserved", + "CEA-861D or below", + [3 ... 30] = "reserved", + [31] = "partial" + }; + static const char * const cea_edid_version_names[8] = { + "no CEA EDID Timing Extension block present", + "CEA-861", + "CEA-861-A", + "CEA-861-B, C or D", + [4 ... 7] = "reserved" + }; + + snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); + snd_iprintf(buffer, "connection_type\t\t%s\n", + eld_connection_type_names[e->conn_type]); + snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, + eld_version_names[e->eld_ver]); + snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, + cea_edid_version_names[e->cea_edid_ver]); + snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); + snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); + snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); + snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); + snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); + snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); + + snd_eld_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); + snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); + + snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); + + for (i = 0; i < e->sad_count; i++) + hdmi_print_sad_info(i, e->sad + i, buffer); +} +EXPORT_SYMBOL_GPL(snd_print_eld_info); +#endif /* CONFIG_SND_PROC_FS */ diff --git a/sound/core/pcm_misc.c b/sound/core/pcm_misc.c index 4f556211bb56..d3a08e292072 100644 --- a/sound/core/pcm_misc.c +++ b/sound/core/pcm_misc.c @@ -432,9 +432,9 @@ int snd_pcm_format_set_silence(snd_pcm_format_t format, void *data, unsigned int if (samples == 0) return 0; width = pcm_formats[(INT)format].phys; /* physical width */ - pat = pcm_formats[(INT)format].silence; - if (!width || !pat) + if (!width) return -EINVAL; + pat = pcm_formats[(INT)format].silence; /* signed or 1 byte data */ if (pcm_formats[(INT)format].signd == 1 || width <= 8) { unsigned int bytes = samples * width / 8; diff --git a/sound/core/seq/oss/seq_oss_event.c b/sound/core/seq/oss/seq_oss_event.c index 7b7c925dd3aa..76fb81077eef 100644 --- a/sound/core/seq/oss/seq_oss_event.c +++ b/sound/core/seq/oss/seq_oss_event.c @@ -290,16 +290,14 @@ note_on_event(struct seq_oss_devinfo *dp, int dev, int ch, int note, int vel, st if (note == 255 && info->ch[ch].note >= 0) { /* volume control */ int type; - //if (! vel) - /* set volume to zero -- note off */ - // type = SNDRV_SEQ_EVENT_NOTEOFF; - //else - if (info->ch[ch].vel) + + if (info->ch[ch].vel) /* sample already started -- volume change */ type = SNDRV_SEQ_EVENT_KEYPRESS; else /* sample not started -- start now */ type = SNDRV_SEQ_EVENT_NOTEON; + info->ch[ch].vel = vel; return set_note_event(dp, dev, type, ch, info->ch[ch].note, vel, ev); } else if (note >= 128) diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 706f53e39b53..198c598a5393 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c @@ -1150,8 +1150,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait) if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) { /* check if data is available in the pool */ - if (!snd_seq_write_pool_allocated(client) || - snd_seq_pool_poll_wait(client->pool, file, wait)) + if (snd_seq_pool_poll_wait(client->pool, file, wait)) mask |= EPOLLOUT | EPOLLWRNORM; } @@ -2586,8 +2585,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table if (client == NULL) return -ENXIO; - if (! snd_seq_write_pool_allocated(client)) - return 1; if (snd_seq_pool_poll_wait(client->pool, file, wait)) return 1; return 0; @@ -2729,6 +2726,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, continue; } + mutex_lock(&client->ioctl_mutex); snd_iprintf(buffer, "Client %3d : \"%s\" [%s %s]\n", c, client->name, client->type == USER_CLIENT ? "User" : "Kernel", @@ -2746,6 +2744,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry, snd_iprintf(buffer, " Input pool :\n"); snd_seq_info_pool(buffer, client->data.user.fifo->pool, " "); } + mutex_unlock(&client->ioctl_mutex); snd_seq_client_unlock(client); } } diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c index 20155e3e87c6..ccde0ca3d208 100644 --- a/sound/core/seq/seq_memory.c +++ b/sound/core/seq/seq_memory.c @@ -427,6 +427,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, poll_table *wait) { poll_wait(file, &pool->output_sleep, wait); + guard(spinlock_irq)(&pool->lock); return snd_seq_output_ok(pool); } diff --git a/sound/core/timer.c b/sound/core/timer.c index fbada79380f9..d774b9b71ce2 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1515,91 +1515,97 @@ static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *ti id->subdevice = timer->tmr_subdevice; } -static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) +static void get_next_device(struct snd_timer_id *id) { - struct snd_timer_id id; struct snd_timer *timer; struct list_head *p; - if (copy_from_user(&id, _tid, sizeof(id))) - return -EFAULT; - guard(mutex)(®ister_mutex); - if (id.dev_class < 0) { /* first item */ + if (id->dev_class < 0) { /* first item */ if (list_empty(&snd_timer_list)) - snd_timer_user_zero_id(&id); + snd_timer_user_zero_id(id); else { timer = list_entry(snd_timer_list.next, struct snd_timer, device_list); - snd_timer_user_copy_id(&id, timer); + snd_timer_user_copy_id(id, timer); } } else { - switch (id.dev_class) { + switch (id->dev_class) { case SNDRV_TIMER_CLASS_GLOBAL: - id.device = id.device < 0 ? 0 : id.device + 1; + id->device = id->device < 0 ? 0 : id->device + 1; list_for_each(p, &snd_timer_list) { timer = list_entry(p, struct snd_timer, device_list); if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) { - snd_timer_user_copy_id(&id, timer); + snd_timer_user_copy_id(id, timer); break; } - if (timer->tmr_device >= id.device) { - snd_timer_user_copy_id(&id, timer); + if (timer->tmr_device >= id->device) { + snd_timer_user_copy_id(id, timer); break; } } if (p == &snd_timer_list) - snd_timer_user_zero_id(&id); + snd_timer_user_zero_id(id); break; case SNDRV_TIMER_CLASS_CARD: case SNDRV_TIMER_CLASS_PCM: - if (id.card < 0) { - id.card = 0; + if (id->card < 0) { + id->card = 0; } else { - if (id.device < 0) { - id.device = 0; + if (id->device < 0) { + id->device = 0; } else { - if (id.subdevice < 0) - id.subdevice = 0; - else if (id.subdevice < INT_MAX) - id.subdevice++; + if (id->subdevice < 0) + id->subdevice = 0; + else if (id->subdevice < INT_MAX) + id->subdevice++; } } list_for_each(p, &snd_timer_list) { timer = list_entry(p, struct snd_timer, device_list); - if (timer->tmr_class > id.dev_class) { - snd_timer_user_copy_id(&id, timer); + if (timer->tmr_class > id->dev_class) { + snd_timer_user_copy_id(id, timer); break; } - if (timer->tmr_class < id.dev_class) + if (timer->tmr_class < id->dev_class) continue; - if (timer->card->number > id.card) { - snd_timer_user_copy_id(&id, timer); + if (timer->card->number > id->card) { + snd_timer_user_copy_id(id, timer); break; } - if (timer->card->number < id.card) + if (timer->card->number < id->card) continue; - if (timer->tmr_device > id.device) { - snd_timer_user_copy_id(&id, timer); + if (timer->tmr_device > id->device) { + snd_timer_user_copy_id(id, timer); break; } - if (timer->tmr_device < id.device) + if (timer->tmr_device < id->device) continue; - if (timer->tmr_subdevice > id.subdevice) { - snd_timer_user_copy_id(&id, timer); + if (timer->tmr_subdevice > id->subdevice) { + snd_timer_user_copy_id(id, timer); break; } - if (timer->tmr_subdevice < id.subdevice) + if (timer->tmr_subdevice < id->subdevice) continue; - snd_timer_user_copy_id(&id, timer); + snd_timer_user_copy_id(id, timer); break; } if (p == &snd_timer_list) - snd_timer_user_zero_id(&id); + snd_timer_user_zero_id(id); break; default: - snd_timer_user_zero_id(&id); + snd_timer_user_zero_id(id); } } +} + +static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) +{ + struct snd_timer_id id; + + if (copy_from_user(&id, _tid, sizeof(id))) + return -EFAULT; + scoped_guard(mutex, ®ister_mutex) + get_next_device(&id); if (copy_to_user(_tid, &id, sizeof(*_tid))) return -EFAULT; return 0; @@ -1620,23 +1626,24 @@ static int snd_timer_user_ginfo(struct file *file, tid = ginfo->tid; memset(ginfo, 0, sizeof(*ginfo)); ginfo->tid = tid; - guard(mutex)(®ister_mutex); - t = snd_timer_find(&tid); - if (!t) - return -ENODEV; - ginfo->card = t->card ? t->card->number : -1; - if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) - ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; - strscpy(ginfo->id, t->id, sizeof(ginfo->id)); - strscpy(ginfo->name, t->name, sizeof(ginfo->name)); - scoped_guard(spinlock_irq, &t->lock) - ginfo->resolution = snd_timer_hw_resolution(t); - if (t->hw.resolution_min > 0) { - ginfo->resolution_min = t->hw.resolution_min; - ginfo->resolution_max = t->hw.resolution_max; - } - list_for_each(p, &t->open_list_head) { - ginfo->clients++; + scoped_guard(mutex, ®ister_mutex) { + t = snd_timer_find(&tid); + if (!t) + return -ENODEV; + ginfo->card = t->card ? t->card->number : -1; + if (t->hw.flags & SNDRV_TIMER_HW_SLAVE) + ginfo->flags |= SNDRV_TIMER_FLG_SLAVE; + strscpy(ginfo->id, t->id, sizeof(ginfo->id)); + strscpy(ginfo->name, t->name, sizeof(ginfo->name)); + scoped_guard(spinlock_irq, &t->lock) + ginfo->resolution = snd_timer_hw_resolution(t); + if (t->hw.resolution_min > 0) { + ginfo->resolution_min = t->hw.resolution_min; + ginfo->resolution_max = t->hw.resolution_max; + } + list_for_each(p, &t->open_list_head) { + ginfo->clients++; + } } if (copy_to_user(_ginfo, ginfo, sizeof(*ginfo))) return -EFAULT; @@ -1674,31 +1681,31 @@ static int snd_timer_user_gstatus(struct file *file, struct snd_timer_gstatus gstatus; struct snd_timer_id tid; struct snd_timer *t; - int err = 0; if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus))) return -EFAULT; tid = gstatus.tid; memset(&gstatus, 0, sizeof(gstatus)); gstatus.tid = tid; - guard(mutex)(®ister_mutex); - t = snd_timer_find(&tid); - if (t != NULL) { - guard(spinlock_irq)(&t->lock); - gstatus.resolution = snd_timer_hw_resolution(t); - if (t->hw.precise_resolution) { - t->hw.precise_resolution(t, &gstatus.resolution_num, - &gstatus.resolution_den); + scoped_guard(mutex, ®ister_mutex) { + t = snd_timer_find(&tid); + if (t != NULL) { + guard(spinlock_irq)(&t->lock); + gstatus.resolution = snd_timer_hw_resolution(t); + if (t->hw.precise_resolution) { + t->hw.precise_resolution(t, &gstatus.resolution_num, + &gstatus.resolution_den); + } else { + gstatus.resolution_num = gstatus.resolution; + gstatus.resolution_den = 1000000000uL; + } } else { - gstatus.resolution_num = gstatus.resolution; - gstatus.resolution_den = 1000000000uL; + return -ENODEV; } - } else { - err = -ENODEV; } - if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) - err = -EFAULT; - return err; + if (copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) + return -EFAULT; + return 0; } static int snd_timer_user_tselect(struct file *file, diff --git a/sound/hda/intel-dsp-config.c b/sound/hda/intel-dsp-config.c index ce3ae2cba660..5103e37be428 100644 --- a/sound/hda/intel-dsp-config.c +++ b/sound/hda/intel-dsp-config.c @@ -108,6 +108,10 @@ static const struct config_entry config_table[] = { {} } }, + { + .flags = FLAG_SST, + .device = PCI_DEVICE_ID_INTEL_HDA_RPL_M, + }, #endif #if IS_ENABLED(CONFIG_SND_SOC_SOF_APOLLOLAKE) { diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 59c784a70ac1..e35c727a52fa 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1735,27 +1735,27 @@ static int snd_es18xx_new_device(struct snd_card *card, chip->active = 0; if (!devm_request_region(card->dev, port, 16, "ES18xx")) { - dev_err(card->dev, "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); + dev_err(card->dev, "unable to grab ports 0x%lx-0x%lx\n", port, port + 16 - 1); return -EBUSY; } if (devm_request_irq(card->dev, irq, snd_es18xx_interrupt, 0, "ES18xx", (void *) card)) { - dev_err(card->dev, "unable to grap IRQ %d\n", irq); + dev_err(card->dev, "unable to grab IRQ %d\n", irq); return -EBUSY; } chip->irq = irq; card->sync_irq = chip->irq; if (snd_devm_request_dma(card->dev, dma1, "ES18xx DMA 1")) { - dev_err(card->dev, "unable to grap DMA1 %d\n", dma1); + dev_err(card->dev, "unable to grab DMA1 %d\n", dma1); return -EBUSY; } chip->dma1 = dma1; if (dma2 != dma1 && snd_devm_request_dma(card->dev, dma2, "ES18xx DMA 2")) { - dev_err(card->dev, "unable to grap DMA2 %d\n", dma2); + dev_err(card->dev, "unable to grab DMA2 %d\n", dma2); return -EBUSY; } chip->dma2 = dma2; diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 220ea1952c1e..a07a665d93dc 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -486,7 +486,7 @@ __skip_base: #endif /* CS4231 || OPTi93X */ #ifndef OPTi93X - outb(irq_bits << 3 | dma_bits, chip->wss_base); + outb(irq_bits << 3 | dma_bits, chip->wss_base); #else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); #endif /* OPTi93X */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 9993b02d2968..806c4d754387 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -159,7 +159,7 @@ static int dao_set_left_input(struct dao *dao, struct rsc *input) struct daio *daio = &dao->daio; int i; - entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL); + entry = kcalloc(daio->rscl.msr, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; @@ -188,7 +188,7 @@ static int dao_set_right_input(struct dao *dao, struct rsc *input) struct daio *daio = &dao->daio; int i; - entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL); + entry = kcalloc(daio->rscr.msr, sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 7484de255a3e..4effcc0090ac 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -1966,7 +1966,6 @@ static int __snd_echo_probe(struct pci_dev *pci, struct snd_card *card; struct echoaudio *chip; char *dsp; - __maybe_unused int i; int err; if (dev >= SNDRV_CARDS) @@ -1976,7 +1975,6 @@ static int __snd_echo_probe(struct pci_dev *pci, return -ENOENT; } - i = 0; err = snd_devm_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, sizeof(*chip), &card); if (err < 0) @@ -2080,7 +2078,7 @@ static int __snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH /* Creates a list of available digital modes */ chip->num_digital_modes = 0; - for (i = 0; i < 6; i++) + for (int i = 0; i < 6; i++) if (chip->digital_modes & (1 << i)) chip->digital_mode_list[chip->num_digital_modes++] = i; @@ -2092,7 +2090,7 @@ static int __snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK /* Creates a list of available clock sources */ chip->num_clock_sources = 0; - for (i = 0; i < 10; i++) + for (int i = 0; i < 10; i++) if (chip->input_clock_types & (1 << i)) chip->clock_source_list[chip->num_clock_sources++] = i; diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index d29711777161..f6982bc6ff0d 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -441,7 +441,7 @@ snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *memblk) unmap_memblk(emu, blk); spin_unlock_irqrestore(&emu->memblk_lock, flags); synth_free_pages(emu, blk); - __snd_util_mem_free(hdr, memblk); + __snd_util_mem_free(hdr, memblk); mutex_unlock(&hdr->block_mutex); return 0; } diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 84ebf19f2883..fb955a205d50 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -267,6 +267,7 @@ comment "Set to Y if you want auto-loading the codec driver" config SND_HDA_CODEC_HDMI tristate "Build HDMI/DisplayPort HD-audio codec support" select SND_DYNAMIC_MINORS + select SND_PCM_ELD help Say Y or M here to include HDMI and DisplayPort HD-audio codec support in snd-hda-intel driver. This includes all AMD/ATI, diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c index 4ef7878e8fd4..235d22049aa9 100644 --- a/sound/pci/hda/cs35l56_hda.c +++ b/sound/pci/hda/cs35l56_hda.c @@ -546,12 +546,10 @@ static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmw const struct firmware *coeff_firmware, char *coeff_filename) { - if (wmfw_firmware) - release_firmware(wmfw_firmware); + release_firmware(wmfw_firmware); kfree(wmfw_filename); - if (coeff_firmware) - release_firmware(coeff_firmware); + release_firmware(coeff_firmware); kfree(coeff_filename); } diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index e51d47572557..13a7d92e8d8d 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -31,8 +31,9 @@ static void generate_tone(struct hda_beep *beep, int tone) beep->power_hook(beep, true); beep->playing = 1; } - snd_hda_codec_write(codec, beep->nid, 0, - AC_VERB_SET_BEEP_CONTROL, tone); + if (!codec->beep_just_power_on) + snd_hda_codec_write(codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, tone); if (!tone && beep->playing) { beep->playing = 0; if (beep->power_hook) @@ -212,10 +213,12 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) struct hda_beep *beep; int err; - if (!snd_hda_get_bool_hint(codec, "beep")) - return 0; /* disabled explicitly by hints */ - if (codec->beep_mode == HDA_BEEP_MODE_OFF) - return 0; /* disabled by module option */ + if (!codec->beep_just_power_on) { + if (!snd_hda_get_bool_hint(codec, "beep")) + return 0; /* disabled explicitly by hints */ + if (codec->beep_mode == HDA_BEEP_MODE_OFF) + return 0; /* disabled by module option */ + } beep = kzalloc(sizeof(*beep), GFP_KERNEL); if (beep == NULL) diff --git a/sound/pci/hda/hda_bind.c b/sound/pci/hda/hda_bind.c index b7ca2a83fbb0..9521e5e0e6e6 100644 --- a/sound/pci/hda/hda_bind.c +++ b/sound/pci/hda/hda_bind.c @@ -185,7 +185,7 @@ int __hda_codec_driver_register(struct hda_codec_driver *drv, const char *name, drv->core.driver.probe = hda_codec_driver_probe; drv->core.driver.remove = hda_codec_driver_remove; drv->core.driver.shutdown = hda_codec_driver_shutdown; - drv->core.driver.pm = &hda_codec_driver_pm; + drv->core.driver.pm = pm_ptr(&hda_codec_driver_pm); drv->core.type = HDA_DEV_LEGACY; drv->core.match = hda_codec_match; drv->core.unsol_event = hda_codec_unsol_event; diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 46a220404999..b436d436831b 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3039,8 +3039,7 @@ const struct dev_pm_ops hda_codec_driver_pm = { .thaw = pm_sleep_ptr(hda_codec_pm_thaw), .poweroff = pm_sleep_ptr(hda_codec_pm_suspend), .restore = pm_sleep_ptr(hda_codec_pm_restore), - .runtime_suspend = pm_ptr(hda_codec_runtime_suspend), - .runtime_resume = pm_ptr(hda_codec_runtime_resume), + RUNTIME_PM_OPS(hda_codec_runtime_suspend, hda_codec_runtime_resume, NULL) }; /* suspend the codec at shutdown; called from driver's shutdown callback */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 301730432375..d3e87b9c1a4f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -17,11 +17,6 @@ #include <sound/hda_codec.h> #include "hda_local.h" -enum eld_versions { - ELD_VER_CEA_861D = 2, - ELD_VER_PARTIAL = 31, -}; - enum cea_edid_versions { CEA_EDID_VER_NONE = 0, CEA_EDID_VER_CEA861 = 1, @@ -30,95 +25,12 @@ enum cea_edid_versions { CEA_EDID_VER_RESERVED = 4, }; -static const char * const eld_connection_type_names[4] = { - "HDMI", - "DisplayPort", - "2-reserved", - "3-reserved" -}; - -enum cea_audio_coding_types { - AUDIO_CODING_TYPE_REF_STREAM_HEADER = 0, - AUDIO_CODING_TYPE_LPCM = 1, - AUDIO_CODING_TYPE_AC3 = 2, - AUDIO_CODING_TYPE_MPEG1 = 3, - AUDIO_CODING_TYPE_MP3 = 4, - AUDIO_CODING_TYPE_MPEG2 = 5, - AUDIO_CODING_TYPE_AACLC = 6, - AUDIO_CODING_TYPE_DTS = 7, - AUDIO_CODING_TYPE_ATRAC = 8, - AUDIO_CODING_TYPE_SACD = 9, - AUDIO_CODING_TYPE_EAC3 = 10, - AUDIO_CODING_TYPE_DTS_HD = 11, - AUDIO_CODING_TYPE_MLP = 12, - AUDIO_CODING_TYPE_DST = 13, - AUDIO_CODING_TYPE_WMAPRO = 14, - AUDIO_CODING_TYPE_REF_CXT = 15, - /* also include valid xtypes below */ - AUDIO_CODING_TYPE_HE_AAC = 15, - AUDIO_CODING_TYPE_HE_AAC2 = 16, - AUDIO_CODING_TYPE_MPEG_SURROUND = 17, -}; - -enum cea_audio_coding_xtypes { - AUDIO_CODING_XTYPE_HE_REF_CT = 0, - AUDIO_CODING_XTYPE_HE_AAC = 1, - AUDIO_CODING_XTYPE_HE_AAC2 = 2, - AUDIO_CODING_XTYPE_MPEG_SURROUND = 3, - AUDIO_CODING_XTYPE_FIRST_RESERVED = 4, -}; - -static const char * const cea_audio_coding_type_names[] = { - /* 0 */ "undefined", - /* 1 */ "LPCM", - /* 2 */ "AC-3", - /* 3 */ "MPEG1", - /* 4 */ "MP3", - /* 5 */ "MPEG2", - /* 6 */ "AAC-LC", - /* 7 */ "DTS", - /* 8 */ "ATRAC", - /* 9 */ "DSD (One Bit Audio)", - /* 10 */ "E-AC-3/DD+ (Dolby Digital Plus)", - /* 11 */ "DTS-HD", - /* 12 */ "MLP (Dolby TrueHD)", - /* 13 */ "DST", - /* 14 */ "WMAPro", - /* 15 */ "HE-AAC", - /* 16 */ "HE-AACv2", - /* 17 */ "MPEG Surround", -}; - /* * The following two lists are shared between * - HDMI audio InfoFrame (source to sink) * - CEA E-EDID Extension (sink to source) */ -/* - * SS1:SS0 index => sample size - */ -static const int cea_sample_sizes[4] = { - 0, /* 0: Refer to Stream Header */ - AC_SUPPCM_BITS_16, /* 1: 16 bits */ - AC_SUPPCM_BITS_20, /* 2: 20 bits */ - AC_SUPPCM_BITS_24, /* 3: 24 bits */ -}; - -/* - * SF2:SF1:SF0 index => sampling frequency - */ -static const int cea_sampling_frequencies[8] = { - 0, /* 0: Refer to Stream Header */ - SNDRV_PCM_RATE_32000, /* 1: 32000Hz */ - SNDRV_PCM_RATE_44100, /* 2: 44100Hz */ - SNDRV_PCM_RATE_48000, /* 3: 48000Hz */ - SNDRV_PCM_RATE_88200, /* 4: 88200Hz */ - SNDRV_PCM_RATE_96000, /* 5: 96000Hz */ - SNDRV_PCM_RATE_176400, /* 6: 176400Hz */ - SNDRV_PCM_RATE_192000, /* 7: 192000Hz */ -}; - static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, int byte_index) { @@ -132,159 +44,6 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, return val; } -#define GRAB_BITS(buf, byte, lowbit, bits) \ -({ \ - BUILD_BUG_ON(lowbit > 7); \ - BUILD_BUG_ON(bits > 8); \ - BUILD_BUG_ON(bits <= 0); \ - \ - (buf[byte] >> (lowbit)) & ((1 << (bits)) - 1); \ -}) - -static void hdmi_update_short_audio_desc(struct hda_codec *codec, - struct cea_sad *a, - const unsigned char *buf) -{ - int i; - int val; - - val = GRAB_BITS(buf, 1, 0, 7); - a->rates = 0; - for (i = 0; i < 7; i++) - if (val & (1 << i)) - a->rates |= cea_sampling_frequencies[i + 1]; - - a->channels = GRAB_BITS(buf, 0, 0, 3); - a->channels++; - - a->sample_bits = 0; - a->max_bitrate = 0; - - a->format = GRAB_BITS(buf, 0, 3, 4); - switch (a->format) { - case AUDIO_CODING_TYPE_REF_STREAM_HEADER: - codec_info(codec, "HDMI: audio coding type 0 not expected\n"); - break; - - case AUDIO_CODING_TYPE_LPCM: - val = GRAB_BITS(buf, 2, 0, 3); - for (i = 0; i < 3; i++) - if (val & (1 << i)) - a->sample_bits |= cea_sample_sizes[i + 1]; - break; - - case AUDIO_CODING_TYPE_AC3: - case AUDIO_CODING_TYPE_MPEG1: - case AUDIO_CODING_TYPE_MP3: - case AUDIO_CODING_TYPE_MPEG2: - case AUDIO_CODING_TYPE_AACLC: - case AUDIO_CODING_TYPE_DTS: - case AUDIO_CODING_TYPE_ATRAC: - a->max_bitrate = GRAB_BITS(buf, 2, 0, 8); - a->max_bitrate *= 8000; - break; - - case AUDIO_CODING_TYPE_SACD: - break; - - case AUDIO_CODING_TYPE_EAC3: - break; - - case AUDIO_CODING_TYPE_DTS_HD: - break; - - case AUDIO_CODING_TYPE_MLP: - break; - - case AUDIO_CODING_TYPE_DST: - break; - - case AUDIO_CODING_TYPE_WMAPRO: - a->profile = GRAB_BITS(buf, 2, 0, 3); - break; - - case AUDIO_CODING_TYPE_REF_CXT: - a->format = GRAB_BITS(buf, 2, 3, 5); - if (a->format == AUDIO_CODING_XTYPE_HE_REF_CT || - a->format >= AUDIO_CODING_XTYPE_FIRST_RESERVED) { - codec_info(codec, - "HDMI: audio coding xtype %d not expected\n", - a->format); - a->format = 0; - } else - a->format += AUDIO_CODING_TYPE_HE_AAC - - AUDIO_CODING_XTYPE_HE_AAC; - break; - } -} - -/* - * Be careful, ELD buf could be totally rubbish! - */ -int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, - const unsigned char *buf, int size) -{ - int mnl; - int i; - - memset(e, 0, sizeof(*e)); - e->eld_ver = GRAB_BITS(buf, 0, 3, 5); - if (e->eld_ver != ELD_VER_CEA_861D && - e->eld_ver != ELD_VER_PARTIAL) { - codec_info(codec, "HDMI: Unknown ELD version %d\n", e->eld_ver); - goto out_fail; - } - - e->baseline_len = GRAB_BITS(buf, 2, 0, 8); - mnl = GRAB_BITS(buf, 4, 0, 5); - e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); - - e->support_hdcp = GRAB_BITS(buf, 5, 0, 1); - e->support_ai = GRAB_BITS(buf, 5, 1, 1); - e->conn_type = GRAB_BITS(buf, 5, 2, 2); - e->sad_count = GRAB_BITS(buf, 5, 4, 4); - - e->aud_synch_delay = GRAB_BITS(buf, 6, 0, 8) * 2; - e->spk_alloc = GRAB_BITS(buf, 7, 0, 7); - - e->port_id = get_unaligned_le64(buf + 8); - - /* not specified, but the spec's tendency is little endian */ - e->manufacture_id = get_unaligned_le16(buf + 16); - e->product_id = get_unaligned_le16(buf + 18); - - if (mnl > ELD_MAX_MNL) { - codec_info(codec, "HDMI: MNL is reserved value %d\n", mnl); - goto out_fail; - } else if (ELD_FIXED_BYTES + mnl > size) { - codec_info(codec, "HDMI: out of range MNL %d\n", mnl); - goto out_fail; - } else - strscpy(e->monitor_name, buf + ELD_FIXED_BYTES, mnl + 1); - - for (i = 0; i < e->sad_count; i++) { - if (ELD_FIXED_BYTES + mnl + 3 * (i + 1) > size) { - codec_info(codec, "HDMI: out of range SAD %d\n", i); - goto out_fail; - } - hdmi_update_short_audio_desc(codec, e->sad + i, - buf + ELD_FIXED_BYTES + mnl + 3 * i); - } - - /* - * HDMI sink's ELD info cannot always be retrieved for now, e.g. - * in console or for audio devices. Assume the highest speakers - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!e->spk_alloc) - e->spk_alloc = 0xffff; - - return 0; - -out_fail: - return -EINVAL; -} - int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, @@ -346,155 +105,27 @@ error: return ret; } -/* - * SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with - * hdmi-specific routine. - */ -static void hdmi_print_pcm_rates(int pcm, char *buf, int buflen) -{ - static const unsigned int alsa_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, 64000, - 88200, 96000, 176400, 192000, 384000 - }; - int i, j; - - for (i = 0, j = 0; i < ARRAY_SIZE(alsa_rates); i++) - if (pcm & (1 << i)) - j += scnprintf(buf + j, buflen - j, " %d", - alsa_rates[i]); - - buf[j] = '\0'; /* necessary when j == 0 */ -} - -#define SND_PRINT_RATES_ADVISED_BUFSIZE 80 - -static void hdmi_show_short_audio_desc(struct hda_codec *codec, - struct cea_sad *a) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - char buf2[8 + SND_PRINT_BITS_ADVISED_BUFSIZE] = ", bits ="; - - if (!a->format) - return; - - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); - - if (a->format == AUDIO_CODING_TYPE_LPCM) - snd_print_pcm_bits(a->sample_bits, buf2 + 8, sizeof(buf2) - 8); - else if (a->max_bitrate) - snprintf(buf2, sizeof(buf2), - ", max bitrate = %d", a->max_bitrate); - else - buf2[0] = '\0'; - - codec_dbg(codec, - "HDMI: supports coding type %s: channels = %d, rates =%s%s\n", - cea_audio_coding_type_names[a->format], - a->channels, buf, buf2); -} - -void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e) -{ - int i; - - codec_dbg(codec, "HDMI: detected monitor %s at connection type %s\n", - e->monitor_name, - eld_connection_type_names[e->conn_type]); - - if (e->spk_alloc) { - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - codec_dbg(codec, "HDMI: available speakers:%s\n", buf); - } - - for (i = 0; i < e->sad_count; i++) - hdmi_show_short_audio_desc(codec, e->sad + i); -} - #ifdef CONFIG_SND_PROC_FS - -static void hdmi_print_sad_info(int i, struct cea_sad *a, - struct snd_info_buffer *buffer) -{ - char buf[SND_PRINT_RATES_ADVISED_BUFSIZE]; - - snd_iprintf(buffer, "sad%d_coding_type\t[0x%x] %s\n", - i, a->format, cea_audio_coding_type_names[a->format]); - snd_iprintf(buffer, "sad%d_channels\t\t%d\n", i, a->channels); - - hdmi_print_pcm_rates(a->rates, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_rates\t\t[0x%x]%s\n", i, a->rates, buf); - - if (a->format == AUDIO_CODING_TYPE_LPCM) { - snd_print_pcm_bits(a->sample_bits, buf, sizeof(buf)); - snd_iprintf(buffer, "sad%d_bits\t\t[0x%x]%s\n", - i, a->sample_bits, buf); - } - - if (a->max_bitrate) - snd_iprintf(buffer, "sad%d_max_bitrate\t%d\n", - i, a->max_bitrate); - - if (a->profile) - snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); -} - void snd_hdmi_print_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer, hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid) { - struct parsed_hdmi_eld *e = &eld->info; - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - int i; - static const char * const eld_version_names[32] = { - "reserved", - "reserved", - "CEA-861D or below", - [3 ... 30] = "reserved", - [31] = "partial" - }; - static const char * const cea_edid_version_names[8] = { - "no CEA EDID Timing Extension block present", - "CEA-861", - "CEA-861-A", - "CEA-861-B, C or D", - [4 ... 7] = "reserved" - }; - snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid); snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id); snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid); + if (!eld->eld_valid) return; - snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); - snd_iprintf(buffer, "connection_type\t\t%s\n", - eld_connection_type_names[e->conn_type]); - snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, - eld_version_names[e->eld_ver]); - snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, - cea_edid_version_names[e->cea_edid_ver]); - snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); - snd_iprintf(buffer, "product_id\t\t0x%x\n", e->product_id); - snd_iprintf(buffer, "port_id\t\t\t0x%llx\n", (long long)e->port_id); - snd_iprintf(buffer, "support_hdcp\t\t%d\n", e->support_hdcp); - snd_iprintf(buffer, "support_ai\t\t%d\n", e->support_ai); - snd_iprintf(buffer, "audio_sync_delay\t%d\n", e->aud_synch_delay); - - snd_hdac_print_channel_allocation(e->spk_alloc, buf, sizeof(buf)); - snd_iprintf(buffer, "speakers\t\t[0x%x]%s\n", e->spk_alloc, buf); - - snd_iprintf(buffer, "sad_count\t\t%d\n", e->sad_count); - - for (i = 0; i < e->sad_count; i++) - hdmi_print_sad_info(i, e->sad + i, buffer); + + snd_print_eld_info(&eld->info, buffer); } void snd_hdmi_write_eld_info(struct hdmi_eld *eld, struct snd_info_buffer *buffer) { - struct parsed_hdmi_eld *e = &eld->info; + struct snd_parsed_hdmi_eld *e = &eld->info; char line[64]; char name[64]; char *sname; @@ -556,7 +187,7 @@ void snd_hdmi_write_eld_info(struct hdmi_eld *eld, #endif /* CONFIG_SND_PROC_FS */ /* update PCM info based on ELD */ -void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, +void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo) { u32 rates; @@ -574,17 +205,17 @@ void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, maxbps = 16; channels_max = 2; for (i = 0; i < e->sad_count; i++) { - struct cea_sad *a = &e->sad[i]; + struct snd_cea_sad *a = &e->sad[i]; rates |= a->rates; if (a->channels > channels_max) channels_max = a->channels; if (a->format == AUDIO_CODING_TYPE_LPCM) { - if (a->sample_bits & AC_SUPPCM_BITS_20) { + if (a->sample_bits & ELD_PCM_BITS_20) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 20) maxbps = 20; } - if (a->sample_bits & AC_SUPPCM_BITS_24) { + if (a->sample_bits & ELD_PCM_BITS_24) { formats |= SNDRV_PCM_FMTBIT_S32_LE; if (maxbps < 24) maxbps = 24; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e67c22c59f02..512fb22f5e5e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -37,6 +37,7 @@ #include <linux/completion.h> #include <linux/acpi.h> #include <linux/pgtable.h> +#include <linux/dmi.h> #ifdef CONFIG_X86 /* for snoop control */ @@ -1050,7 +1051,7 @@ static int azx_suspend(struct device *dev) return 0; } -static int __maybe_unused azx_resume(struct device *dev) +static int azx_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1097,7 +1098,7 @@ static int azx_thaw_noirq(struct device *dev) return 0; } -static int __maybe_unused azx_runtime_suspend(struct device *dev) +static int azx_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1114,7 +1115,7 @@ static int __maybe_unused azx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused azx_runtime_resume(struct device *dev) +static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1131,7 +1132,7 @@ static int __maybe_unused azx_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused azx_runtime_idle(struct device *dev) +static int azx_runtime_idle(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip; @@ -1162,7 +1163,7 @@ static const struct dev_pm_ops azx_pm = { .complete = pm_sleep_ptr(azx_complete), .freeze_noirq = pm_sleep_ptr(azx_freeze_noirq), .thaw_noirq = pm_sleep_ptr(azx_thaw_noirq), - SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) + RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; @@ -1352,8 +1353,21 @@ static void azx_free(struct azx *chip) if (use_vga_switcheroo(hda)) { if (chip->disabled && hda->probe_continued) snd_hda_unlock_devices(&chip->bus); - if (hda->vga_switcheroo_registered) + if (hda->vga_switcheroo_registered) { vga_switcheroo_unregister_client(chip->pci); + + /* Some GPUs don't have sound, and azx_first_init fails, + * leaving the device probed but non-functional. As long + * as it's probed, the PCI subsystem keeps its runtime + * PM status as active. Force it to suspended (as we + * actually stop the chip) to allow GPU to suspend via + * vga_switcheroo, and print a warning. + */ + dev_warn(&pci->dev, "GPU sound probed, but not operational: please add a quirk to driver_denylist\n"); + pm_runtime_disable(&pci->dev); + pm_runtime_set_suspended(&pci->dev); + pm_runtime_enable(&pci->dev); + } } if (bus->chip_init) { @@ -2061,6 +2075,27 @@ static const struct pci_device_id driver_denylist[] = { {} }; +static struct pci_device_id driver_denylist_ideapad_z570[] = { + { PCI_DEVICE_SUB(0x10de, 0x0bea, 0x0000, 0x0000) }, /* NVIDIA GF108 HDA */ + {} +}; + +/* DMI-based denylist, to be used when: + * - PCI subsystem IDs are zero, impossible to distinguish from valid sound cards. + * - Different modifications of the same laptop use different GPU models. + */ +static const struct dmi_system_id driver_denylist_dmi[] = { + { + /* No HDA in NVIDIA DGPU. BIOS disables it, but quirk_nvidia_hda() reenables. */ + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Ideapad Z570"), + }, + .driver_data = &driver_denylist_ideapad_z570, + }, + {} +}; + static const struct hda_controller_ops pci_hda_ops = { .disable_msi_reset_irq = disable_msi_reset_irq, .position_check = azx_position_check, @@ -2071,6 +2106,7 @@ static DECLARE_BITMAP(probed_devs, SNDRV_CARDS); static int azx_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { + const struct dmi_system_id *dmi; struct snd_card *card; struct hda_intel *hda; struct azx *chip; @@ -2083,6 +2119,12 @@ static int azx_probe(struct pci_dev *pci, return -ENODEV; } + dmi = dmi_first_match(driver_denylist_dmi); + if (dmi && pci_match_id(dmi->driver_data, pci)) { + dev_info(&pci->dev, "Skipping the device on the DMI denylist\n"); + return -ENODEV; + } + dev = find_first_zero_bit(probed_devs, SNDRV_CARDS); if (dev >= SNDRV_CARDS) return -ENODEV; @@ -2757,7 +2799,7 @@ static struct pci_driver azx_driver = { .remove = azx_remove, .shutdown = azx_shutdown, .driver = { - .pm = &azx_pm, + .pm = pm_ptr(&azx_pm), }, }; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 763f79f6f32e..4714057dba85 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -10,6 +10,8 @@ #ifndef __SOUND_HDA_LOCAL_H #define __SOUND_HDA_LOCAL_H +#include <sound/pcm_drm_eld.h> + /* We abuse kcontrol_new.subdev field to pass the NID corresponding to * the given new control. If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG, * snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID. @@ -675,61 +677,18 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, #define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) -/* - * CEA Short Audio Descriptor data - */ -struct cea_sad { - int channels; - int format; /* (format == 0) indicates invalid SAD */ - int rates; - int sample_bits; /* for LPCM */ - int max_bitrate; /* for AC3...ATRAC */ - int profile; /* for WMAPRO */ -}; - -#define ELD_FIXED_BYTES 20 -#define ELD_MAX_SIZE 256 -#define ELD_MAX_MNL 16 -#define ELD_MAX_SAD 16 - -/* - * ELD: EDID Like Data - */ -struct parsed_hdmi_eld { - /* - * all fields will be cleared before updating ELD - */ - int baseline_len; - int eld_ver; - int cea_edid_ver; - char monitor_name[ELD_MAX_MNL + 1]; - int manufacture_id; - int product_id; - u64 port_id; - int support_hdcp; - int support_ai; - int conn_type; - int aud_synch_delay; - int spk_alloc; - int sad_count; - struct cea_sad sad[ELD_MAX_SAD]; -}; - struct hdmi_eld { bool monitor_present; bool eld_valid; int eld_size; char eld_buffer[ELD_MAX_SIZE]; - struct parsed_hdmi_eld info; + struct snd_parsed_hdmi_eld info; }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, unsigned char *buf, int *eld_size); -int snd_hdmi_parse_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e, - const unsigned char *buf, int size); -void snd_hdmi_show_eld(struct hda_codec *codec, struct parsed_hdmi_eld *e); -void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, +void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c index b1e30a83dfb0..a590d431c5ff 100644 --- a/sound/pci/hda/hda_tegra.c +++ b/sound/pci/hda/hda_tegra.c @@ -125,7 +125,7 @@ static void hda_tegra_init(struct hda_tegra *hda) /* * power management */ -static int __maybe_unused hda_tegra_suspend(struct device *dev) +static int hda_tegra_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); int rc; @@ -138,7 +138,7 @@ static int __maybe_unused hda_tegra_suspend(struct device *dev) return 0; } -static int __maybe_unused hda_tegra_resume(struct device *dev) +static int hda_tegra_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); int rc; @@ -151,7 +151,7 @@ static int __maybe_unused hda_tegra_resume(struct device *dev) return 0; } -static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev) +static int hda_tegra_runtime_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; @@ -170,7 +170,7 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) +static int hda_tegra_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; @@ -204,10 +204,8 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) } static const struct dev_pm_ops hda_tegra_pm = { - SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) - SET_RUNTIME_PM_OPS(hda_tegra_runtime_suspend, - hda_tegra_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) + RUNTIME_PM_OPS(hda_tegra_runtime_suspend, hda_tegra_runtime_resume, NULL) }; static int hda_tegra_dev_disconnect(struct snd_device *device) @@ -602,7 +600,7 @@ static void hda_tegra_shutdown(struct platform_device *pdev) static struct platform_driver tegra_platform_hda = { .driver = { .name = "tegra-hda", - .pm = &hda_tegra_pm, + .pm = pm_ptr(&hda_tegra_pm), .of_match_table = hda_tegra_match, }, .probe = hda_tegra_probe, diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 643e0496b093..7167989a8d86 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -1511,8 +1511,8 @@ static void update_eld(struct hda_codec *codec, if (eld->eld_valid) { if (eld->eld_size <= 0 || - snd_hdmi_parse_eld(codec, &eld->info, eld->eld_buffer, - eld->eld_size) < 0) { + snd_parse_eld(hda_codec_dev(codec), &eld->info, + eld->eld_buffer, eld->eld_size) < 0) { eld->eld_valid = false; if (repoll) { schedule_delayed_work(&per_pin->work, @@ -1555,7 +1555,7 @@ static void update_eld(struct hda_codec *codec, pcm_jack = pin_idx_to_pcm_jack(codec, per_pin); if (eld->eld_valid) - snd_hdmi_show_eld(codec, &eld->info); + snd_show_eld(hda_codec_dev(codec), &eld->info); eld_changed = (pin_eld->eld_valid != eld->eld_valid); eld_changed |= (pin_eld->monitor_present != eld->monitor_present); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a84857a3c2bf..b4fe681ec3cb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -28,6 +28,7 @@ #include <sound/hda_codec.h> #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_beep.h" #include "hda_jack.h" #include "hda_generic.h" #include "hda_component.h" @@ -586,6 +587,9 @@ static void alc_shutup_pins(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + if (spec->no_shutup_pins) + return; + switch (codec->core.vendor_id) { case 0x10ec0236: case 0x10ec0256: @@ -601,8 +605,7 @@ static void alc_shutup_pins(struct hda_codec *codec) alc_headset_mic_no_shutup(codec); break; default: - if (!spec->no_shutup_pins) - snd_hda_shutup_pins(codec); + snd_hda_shutup_pins(codec); break; } } @@ -7016,6 +7019,30 @@ static void alc285_fixup_hp_envy_x360(struct hda_codec *codec, } } +static void alc285_fixup_hp_beep(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + codec->beep_just_power_on = true; + } else if (action == HDA_FIXUP_ACT_INIT) { +#ifdef CONFIG_SND_HDA_INPUT_BEEP + /* + * Just enable loopback to internal speaker and headphone jack. + * Disable amplification to get about the same beep volume as + * was on pure BIOS setup before loading the driver. + */ + alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13)); + + snd_hda_enable_beep_device(codec, 1); + +#if !IS_ENABLED(CONFIG_INPUT_PCSPKR) + dev_warn_once(hda_codec_dev(codec), + "enable CONFIG_INPUT_PCSPKR to get PC beeps\n"); +#endif +#endif + } +} + /* for hda_fixup_thinkpad_acpi() */ #include "thinkpad_helper.c" @@ -7801,6 +7828,7 @@ enum { ALC285_FIXUP_HP_GPIO_LED, ALC285_FIXUP_HP_MUTE_LED, ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED, + ALC285_FIXUP_HP_BEEP_MICMUTE_LED, ALC236_FIXUP_HP_MUTE_LED_COEFBIT2, ALC236_FIXUP_HP_GPIO_LED, ALC236_FIXUP_HP_MUTE_LED, @@ -9395,6 +9423,12 @@ static const struct hda_fixup alc269_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = alc285_fixup_hp_spectre_x360_mute_led, }, + [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc285_fixup_hp_beep, + .chained = true, + .chain_id = ALC285_FIXUP_HP_MUTE_LED, + }, [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = { .type = HDA_FIXUP_FUNC, .v.func = alc236_fixup_hp_mute_led_coefbit2, @@ -10489,7 +10523,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF), SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT), - SND_PCI_QUIRK(0x103c, 0x8760, "HP", ALC285_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED), SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS), SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED), SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED), @@ -10519,6 +10553,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x8812, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1), SND_PCI_QUIRK(0x103c, 0x881d, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), + SND_PCI_QUIRK(0x103c, 0x881e, "HP Laptop 15s-du3xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2), SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED), @@ -10688,17 +10723,54 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite X360 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 13 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite X360 13 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da0, "HP 16 Clipper OmniBook 7(X360)", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da1, "HP 16 Clipper OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da7, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2), SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2), + SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8dee, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8df0, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e11, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e12, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e13, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e14, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), + SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1043, 0x1074, "ASUS G614PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2), SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK), SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C), @@ -10783,6 +10855,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE), SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15), + SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15), SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2), SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502), SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2), diff --git a/sound/pci/hda/tas2781-spi.h b/sound/pci/hda/tas2781-spi.h index ecfc3c8bb821..7a0faceeb675 100644 --- a/sound/pci/hda/tas2781-spi.h +++ b/sound/pci/hda/tas2781-spi.h @@ -88,7 +88,6 @@ struct tasdevice_priv { struct mutex codec_lock; struct regmap *regmap; struct device *dev; - struct tm tm; unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE]; unsigned char coef_binaryname[64]; diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index 0e42b87dadb8..9ed49b0dbe6b 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -45,7 +45,7 @@ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ SNDRV_CTL_ELEM_ACCESS_READWRITE,\ .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_range, \ + .info = snd_soc_info_volsw, \ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&(struct soc_mixer_control) \ {.reg = xreg, .rreg = xreg, .shift = xshift, \ @@ -594,7 +594,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) efi_guid_t efi_guid = EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a, 0xa3, 0x5d, 0xb3); static efi_char16_t efi_name[] = L"CALI_DATA"; - struct tm *tm = &tas_priv->tm; unsigned int attr, crc; unsigned int *tmp_val; efi_status_t status; @@ -629,10 +628,9 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) crc, tmp_val[21]); if (crc == tmp_val[21]) { - time64_to_tm(tmp_val[20], 0, tm); - dev_dbg(tas_priv->dev, "%4ld-%2d-%2d, %2d:%2d:%2d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + time64_t seconds = tmp_val[20]; + + dev_dbg(tas_priv->dev, "%ptTsr\n", &seconds); tasdevice_apply_calibration(tas_priv); } else tas_priv->cali_data.total_sz = 0; @@ -755,8 +753,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) out: mutex_unlock(&tas_hda->priv->codec_lock); - if (fmw) - release_firmware(fmw); + release_firmware(fmw); pm_runtime_mark_last_busy(tas_hda->dev); pm_runtime_put_autosuspend(tas_hda->dev); } diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c index 04db80af53c0..399f2e4c3b62 100644 --- a/sound/pci/hda/tas2781_hda_spi.c +++ b/sound/pci/hda/tas2781_hda_spi.c @@ -52,7 +52,7 @@ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ SNDRV_CTL_ELEM_ACCESS_READWRITE, \ .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw_range, \ + .info = snd_soc_info_volsw, \ .get = xhandler_get, .put = xhandler_put, \ .private_value = (unsigned long)&(struct soc_mixer_control) { \ .reg = xreg, .rreg = xreg, \ @@ -802,7 +802,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME; unsigned char data[TASDEVICE_CALIBRATION_DATA_SIZE], *buf; unsigned int attr, crc, offset, *tmp_val; - struct tm *tm = &tas_priv->tm; unsigned long total_sz = 0; efi_status_t status; @@ -849,7 +848,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) if (crc != tmp_val[3 + tmp_val[1] * 6]) return 0; - time64_to_tm(tmp_val[2], 0, tm); for (int j = 0; j < tmp_val[1]; j++) { offset = j * 6 + 3; if (tmp_val[offset] == tas_priv->index) { @@ -882,7 +880,6 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv) */ crc = crc32(~0, data, 84) ^ ~0; if (crc == tmp_val[21]) { - time64_to_tm(tmp_val[20], 0, tm); for (int i = 0; i < CALIB_MAX; i++) tas_priv->cali_data[i] = tmp_val[tas_priv->index * 5 + i]; diff --git a/sound/pci/hda/tas2781_spi_fwlib.c b/sound/pci/hda/tas2781_spi_fwlib.c index 131d9a77d140..d90d022d8449 100644 --- a/sound/pci/hda/tas2781_spi_fwlib.c +++ b/sound/pci/hda/tas2781_spi_fwlib.c @@ -2,7 +2,7 @@ // // TAS2781 HDA SPI driver // -// Copyright 2024-2025 Texas Instruments, Inc. +// Copyright 2024 - 2025 Texas Instruments, Inc. // // Author: Baojun Xu <baojun.xu@ti.com> @@ -370,10 +370,10 @@ static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw, int i, n = ARRAY_SIZE(non_ppc3_mapping_table); unsigned char dev_idx = 0; - if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) { + if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) { p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table; n = ARRAY_SIZE(ppc3_tas2781_mapping_table); - } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) { + } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) { p = (struct blktyp_devidx_map *)ppc3_mapping_table; n = ARRAY_SIZE(ppc3_mapping_table); } @@ -1605,7 +1605,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv, int rc = 0; if (drv_ver == 0x100) { - if (ppcver >= PPC3_VERSION) { + if (ppcver >= PPC3_VERSION_BASE) { tas_priv->fw_parse_variable_header = fw_parse_variable_header_kernel; tas_priv->fw_parse_program_data = diff --git a/sound/pci/lola/lola.h b/sound/pci/lola/lola.h index 0ff772cf66e6..25f72f9e3f9b 100644 --- a/sound/pci/lola/lola.h +++ b/sound/pci/lola/lola.h @@ -499,8 +499,6 @@ int lola_init_mixer_widget(struct lola *chip, int nid); void lola_free_mixer(struct lola *chip); int lola_create_mixer(struct lola *chip); int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute); -void lola_save_mixer(struct lola *chip); -void lola_restore_mixer(struct lola *chip); int lola_set_src_config(struct lola *chip, unsigned int src_mask, bool update); /* proc */ diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index 6b162489cb5f..9cb26a8a4e1a 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -336,49 +336,6 @@ int lola_setup_all_analog_gains(struct lola *chip, int dir, bool mute) return lola_codec_flush(chip); } -void lola_save_mixer(struct lola *chip) -{ - /* mute analog output */ - if (chip->mixer.array_saved) { - /* store contents of mixer array */ - memcpy_fromio(chip->mixer.array_saved, chip->mixer.array, - sizeof(*chip->mixer.array)); - } - lola_setup_all_analog_gains(chip, PLAY, true); /* output mute */ -} - -void lola_restore_mixer(struct lola *chip) -{ - int i; - - /*lola_reset_setups(chip);*/ - if (chip->mixer.array_saved) { - /* restore contents of mixer array */ - memcpy_toio(chip->mixer.array, chip->mixer.array_saved, - sizeof(*chip->mixer.array)); - /* inform micro-controller about all restored values - * and ignore return values - */ - for (i = 0; i < chip->mixer.src_phys_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_SOURCE_GAIN, - i, 0); - for (i = 0; i < chip->mixer.src_stream_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_SOURCE_GAIN, - chip->mixer.src_stream_out_ofs + i, 0); - for (i = 0; i < chip->mixer.dest_stream_ins; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - i, 0); - for (i = 0; i < chip->mixer.dest_phys_outs; i++) - lola_codec_write(chip, chip->mixer.nid, - LOLA_VERB_SET_DESTINATION_GAIN, - chip->mixer.dest_phys_out_ofs + i, 0); - lola_codec_flush(chip); - } -} - /* */ diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index c346f42befc2..ff7439634d76 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -854,11 +854,9 @@ static struct pci_driver oxygen_driver = { .name = KBUILD_MODNAME, .id_table = oxygen_ids, .probe = generic_oxygen_probe, -#ifdef CONFIG_PM_SLEEP .driver = { - .pm = &oxygen_pci_pm, + .pm = pm_sleep_ptr(&oxygen_pci_pm), }, -#endif }; module_pci_driver(oxygen_driver); diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 0cae640708f3..820026daf838 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -161,9 +161,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, const struct pci_device_id *id ) ); -#ifdef CONFIG_PM_SLEEP extern const struct dev_pm_ops oxygen_pci_pm; -#endif void oxygen_pci_shutdown(struct pci_dev *pci); /* oxygen_mixer.c */ diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 92ffe9dc20c5..9340d3c9ffd6 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -713,7 +713,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, } EXPORT_SYMBOL(oxygen_pci_probe); -#ifdef CONFIG_PM_SLEEP static int oxygen_pci_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -789,9 +788,7 @@ static int oxygen_pci_resume(struct device *dev) return 0; } -SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume); -EXPORT_SYMBOL(oxygen_pci_pm); -#endif /* CONFIG_PM_SLEEP */ +EXPORT_SIMPLE_DEV_PM_OPS(oxygen_pci_pm, oxygen_pci_suspend, oxygen_pci_resume); void oxygen_pci_shutdown(struct pci_dev *pci) { diff --git a/sound/pci/oxygen/se6x.c b/sound/pci/oxygen/se6x.c index 17650a5b1bfa..9d009015d97e 100644 --- a/sound/pci/oxygen/se6x.c +++ b/sound/pci/oxygen/se6x.c @@ -137,11 +137,9 @@ static struct pci_driver se6x_driver = { .name = KBUILD_MODNAME, .id_table = se6x_ids, .probe = se6x_probe, -#ifdef CONFIG_PM_SLEEP .driver = { - .pm = &oxygen_pci_pm, + .pm = pm_sleep_ptr(&oxygen_pci_pm), }, -#endif .shutdown = oxygen_pci_shutdown, }; diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 2e405133371f..ded62199da7f 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -82,11 +82,9 @@ static struct pci_driver xonar_driver = { .name = KBUILD_MODNAME, .id_table = xonar_ids, .probe = xonar_probe, -#ifdef CONFIG_PM_SLEEP .driver = { - .pm = &oxygen_pci_pm, + .pm = pm_sleep_ptr(&oxygen_pci_pm), }, -#endif .shutdown = oxygen_pci_shutdown, }; diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index 468a6a20dc1e..fdb039896205 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -204,7 +204,6 @@ static int snd_vx222_probe(struct pci_dev *pci, return 0; } -#ifdef CONFIG_PM_SLEEP static int snd_vx222_suspend(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); @@ -221,18 +220,14 @@ static int snd_vx222_resume(struct device *dev) return snd_vx_resume(&vx->core); } -static SIMPLE_DEV_PM_OPS(snd_vx222_pm, snd_vx222_suspend, snd_vx222_resume); -#define SND_VX222_PM_OPS &snd_vx222_pm -#else -#define SND_VX222_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(snd_vx222_pm, snd_vx222_suspend, snd_vx222_resume); static struct pci_driver vx222_driver = { .name = KBUILD_MODNAME, .id_table = snd_vx222_ids, .probe = snd_vx222_probe, .driver = { - .pm = SND_VX222_PM_OPS, + .pm = pm_ptr(&snd_vx222_pm), }, }; diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 5efba76abb31..8b7d51266f81 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -81,6 +81,13 @@ config SND_SOC_UTILS_KUNIT_TEST help If you want to perform tests on ALSA SoC utils library say Y here. +config SND_SOC_OPS_KUNIT_TEST + tristate "KUnit tests for SoC ops" + depends on KUNIT + default KUNIT_ALL_TESTS + help + If you want to perform tests on ALSA SoC ops library say Y here. + config SND_SOC_ACPI tristate diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 08baaa11d813..358e227c5ab6 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -21,6 +21,10 @@ ifneq ($(CONFIG_SND_SOC_UTILS_KUNIT_TEST),) obj-$(CONFIG_SND_SOC_UTILS_KUNIT_TEST) += soc-utils-test.o endif +ifneq ($(CONFIG_SND_SOC_OPS_KUNIT_TEST),) +obj-$(CONFIG_SND_SOC_OPS_KUNIT_TEST) += soc-ops-test.o +endif + ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),) snd-soc-core-y += soc-generic-dmaengine-pcm.o endif diff --git a/sound/soc/amd/Kconfig b/sound/soc/amd/Kconfig index 803521178279..c7daae392d74 100644 --- a/sound/soc/amd/Kconfig +++ b/sound/soc/amd/Kconfig @@ -161,15 +161,15 @@ config SND_SOC_AMD_SOUNDWIRE If unsure select "N". config SND_SOC_AMD_PS - tristate "AMD Audio Coprocessor-v6.3 Pink Sardine support" + tristate "AMD Audio Coprocessor-v6.3/v7.0/v7.1 support" select SND_SOC_AMD_SOUNDWIRE_LINK_BASELINE select SND_SOC_ACPI_AMD_MATCH depends on X86 && PCI && ACPI help - This option enables Audio Coprocessor i.e ACP v6.3 support on - AMD Pink sardine platform. By enabling this flag build will be - triggered for ACP PCI driver, ACP PDM DMA driver, ACP SoundWire - DMA driver. + This option enables Audio Coprocessor i.e ACP6.3/ACP7.0/ACP7.1 + variants support. By enabling this flag build will be triggered + for ACP PCI driver, ACP PDM DMA driver, ACP SoundWire DMA + driver. Say m if you have such a device. If unsure select "N". diff --git a/sound/soc/amd/acp/Kconfig b/sound/soc/amd/acp/Kconfig index 03f3fcbba5af..b9432052c638 100644 --- a/sound/soc/amd/acp/Kconfig +++ b/sound/soc/amd/acp/Kconfig @@ -28,6 +28,9 @@ config SND_SOC_AMD_ACP_LEGACY_COMMON config SND_SOC_AMD_ACP_I2S tristate +config SND_SOC_AMD_ACPI_MACH + tristate + config SND_SOC_AMD_ACP_PCM tristate select SND_SOC_ACPI if ACPI @@ -37,6 +40,7 @@ config SND_SOC_AMD_ACP_PCI depends on X86 && PCI depends on ACPI select SND_SOC_AMD_ACP_LEGACY_COMMON + select SND_SOC_AMD_ACPI_MACH help This options enables generic PCI driver for ACP device. @@ -47,6 +51,7 @@ config SND_AMD_ASOC_RENOIR select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM select SND_SOC_AMD_ACP_LEGACY_COMMON + select SND_SOC_AMD_ACPI_MACH depends on X86 && PCI help This option enables Renoir I2S support on AMD platform. @@ -58,6 +63,8 @@ config SND_AMD_ASOC_REMBRANDT select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM select SND_SOC_AMD_ACP_LEGACY_COMMON + select SND_SOC_AMD_ACPI_MACH + depends on AMD_NODE depends on X86 && PCI help This option enables Rembrandt I2S support on AMD platform. @@ -68,10 +75,12 @@ config SND_AMD_ASOC_ACP63 tristate "AMD ACP ASOC ACP6.3 Support" depends on X86 && PCI depends on ACPI + depends on AMD_NODE select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM select SND_SOC_AMD_ACP_LEGACY_COMMON + select SND_SOC_AMD_ACPI_MACH help This option enables Acp6.3 I2S support on AMD platform. Say Y if you want to enable AUDIO on ACP6.3 @@ -81,10 +90,12 @@ config SND_AMD_ASOC_ACP70 tristate "AMD ACP ASOC Acp7.0 Support" depends on X86 && PCI depends on ACPI + depends on AMD_NODE select SND_SOC_AMD_ACP_PCM select SND_SOC_AMD_ACP_I2S select SND_SOC_AMD_ACP_PDM select SND_SOC_AMD_ACP_LEGACY_COMMON + select SND_SOC_AMD_ACPI_MACH help This option enables Acp7.0 PDM support on AMD platform. Say Y if you want to enable AUDIO on ACP7.0 @@ -156,6 +167,7 @@ config SND_SOC_AMD_LEGACY_SDW_MACH select SND_SOC_RT712_SDCA_SDW select SND_SOC_RT712_SDCA_DMIC_SDW select SND_SOC_RT1316_SDW + select SND_SOC_RT1320_SDW select SND_SOC_RT715_SDW select SND_SOC_RT715_SDCA_SDW select SND_SOC_RT722_SDCA_SDW diff --git a/sound/soc/amd/acp/Makefile b/sound/soc/amd/acp/Makefile index bb2702036338..08220b9a3802 100644 --- a/sound/soc/amd/acp/Makefile +++ b/sound/soc/amd/acp/Makefile @@ -11,6 +11,7 @@ snd-acp-pdm-y := acp-pdm.o snd-acp-legacy-common-y := acp-legacy-common.o snd-acp-pci-y := acp-pci.o snd-amd-sdw-acpi-y := amd-sdw-acpi.o +snd-amd-acpi-mach-y := amd-acpi-mach.o #platform specific driver snd-acp-renoir-y := acp-renoir.o @@ -22,7 +23,7 @@ snd-acp70-y := acp70.o snd-acp-mach-y := acp-mach-common.o snd-acp-legacy-mach-y := acp-legacy-mach.o acp3x-es83xx/acp3x-es83xx.o snd-acp-sof-mach-y := acp-sof-mach.o -snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o +snd-soc-acpi-amd-match-y := amd-acp63-acpi-match.o amd-acp70-acpi-match.o snd-acp-sdw-mach-y := acp-sdw-mach-common.o snd-acp-sdw-sof-mach-y += acp-sdw-sof-mach.o snd-acp-sdw-legacy-mach-y += acp-sdw-legacy-mach.o @@ -32,6 +33,7 @@ obj-$(CONFIG_SND_SOC_AMD_ACP_I2S) += snd-acp-i2s.o obj-$(CONFIG_SND_SOC_AMD_ACP_PDM) += snd-acp-pdm.o obj-$(CONFIG_SND_SOC_AMD_ACP_LEGACY_COMMON) += snd-acp-legacy-common.o obj-$(CONFIG_SND_SOC_AMD_ACP_PCI) += snd-acp-pci.o +obj-$(CONFIG_SND_SOC_AMD_ACPI_MACH) += snd-amd-acpi-mach.o obj-$(CONFIG_SND_AMD_ASOC_RENOIR) += snd-acp-renoir.o obj-$(CONFIG_SND_AMD_ASOC_REMBRANDT) += snd-acp-rembrandt.o diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c index 89e99ed4275a..a38409dd1d34 100644 --- a/sound/soc/amd/acp/acp-i2s.c +++ b/sound/soc/amd/acp/acp-i2s.c @@ -31,14 +31,10 @@ #define ACP63_LRCLK_DIV_FIELD GENMASK(12, 2) #define ACP63_BCLK_DIV_FIELD GENMASK(23, 13) -static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) +static inline void acp_set_i2s_clk(struct acp_chip_info *chip, int dai_id) { u32 i2s_clk_reg, val; - struct acp_chip_info *chip; - struct device *dev; - dev = adata->dev; - chip = dev_get_platdata(dev); switch (dai_id) { case I2S_SP_INSTANCE: i2s_clk_reg = ACP_I2STDM0_MSTRCLKGEN; @@ -55,36 +51,37 @@ static inline void acp_set_i2s_clk(struct acp_dev_data *adata, int dai_id) } val = I2S_MASTER_MODE_ENABLE; - if (adata->tdm_mode) + if (chip->tdm_mode) val |= BIT(1); switch (chip->acp_rev) { case ACP63_PCI_ID: case ACP70_PCI_ID: case ACP71_PCI_ID: - val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, adata->lrclk_div); - val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, adata->bclk_div); + val |= FIELD_PREP(ACP63_LRCLK_DIV_FIELD, chip->lrclk_div); + val |= FIELD_PREP(ACP63_BCLK_DIV_FIELD, chip->bclk_div); break; default: - val |= FIELD_PREP(LRCLK_DIV_FIELD, adata->lrclk_div); - val |= FIELD_PREP(BCLK_DIV_FIELD, adata->bclk_div); + val |= FIELD_PREP(LRCLK_DIV_FIELD, chip->lrclk_div); + val |= FIELD_PREP(BCLK_DIV_FIELD, chip->bclk_div); } - writel(val, adata->acp_base + i2s_clk_reg); + writel(val, chip->base + i2s_clk_reg); } static int acp_i2s_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { - struct acp_dev_data *adata = snd_soc_dai_get_drvdata(cpu_dai); + struct device *dev = cpu_dai->component->dev; + struct acp_chip_info *chip = dev_get_platdata(dev); int mode; mode = fmt & SND_SOC_DAIFMT_FORMAT_MASK; switch (mode) { case SND_SOC_DAIFMT_I2S: - adata->tdm_mode = TDM_DISABLE; + chip->tdm_mode = TDM_DISABLE; break; case SND_SOC_DAIFMT_DSP_A: - adata->tdm_mode = TDM_ENABLE; + chip->tdm_mode = TDM_ENABLE; break; default: return -EINVAL; @@ -96,7 +93,6 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas int slots, int slot_width) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = snd_soc_dai_get_drvdata(dai); struct acp_chip_info *chip; struct acp_stream *stream; int slot_len, no_of_slots; @@ -157,35 +153,35 @@ static int acp_i2s_set_tdm_slot(struct snd_soc_dai *dai, u32 tx_mask, u32 rx_mas slots = no_of_slots; - spin_lock_irq(&adata->acp_lock); - list_for_each_entry(stream, &adata->stream_list, list) { + spin_lock_irq(&chip->acp_lock); + list_for_each_entry(stream, &chip->stream_list, list) { switch (chip->acp_rev) { case ACP_RN_PCI_ID: case ACP_RMB_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) - adata->tdm_tx_fmt[stream->dai_id - 1] = + chip->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) - adata->tdm_rx_fmt[stream->dai_id - 1] = + chip->tdm_rx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 15) | (slot_len << 18); break; case ACP63_PCI_ID: case ACP70_PCI_ID: case ACP71_PCI_ID: if (tx_mask && stream->dir == SNDRV_PCM_STREAM_PLAYBACK) - adata->tdm_tx_fmt[stream->dai_id - 1] = + chip->tdm_tx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 13) | (slot_len << 18); else if (rx_mask && stream->dir == SNDRV_PCM_STREAM_CAPTURE) - adata->tdm_rx_fmt[stream->dai_id - 1] = + chip->tdm_rx_fmt[stream->dai_id - 1] = FRM_LEN | (slots << 13) | (slot_len << 18); break; default: dev_err(dev, "Unknown chip revision %d\n", chip->acp_rev); - spin_unlock_irq(&adata->acp_lock); + spin_unlock_irq(&chip->acp_lock); return -EINVAL; } } - spin_unlock_irq(&adata->acp_lock); + spin_unlock_irq(&chip->acp_lock); return 0; } @@ -193,15 +189,15 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata; + struct acp_chip_info *chip; struct acp_resource *rsrc; u32 val; u32 xfer_resolution; u32 reg_val, fmt_reg, tdm_fmt; u32 lrclk_div_val, bclk_div_val; - adata = snd_soc_dai_get_drvdata(dai); - rsrc = adata->rsrc; + chip = dev_get_platdata(dev); + rsrc = chip->rsrc; /* These values are as per Hardware Spec */ switch (params_format(params)) { @@ -240,7 +236,7 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; } - adata->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution; + chip->xfer_tx_resolution[dai->driver->id - 1] = xfer_resolution; } else { switch (dai->driver->id) { case I2S_BT_INSTANCE: @@ -259,22 +255,22 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ dev_err(dev, "Invalid dai id %x\n", dai->driver->id); return -EINVAL; } - adata->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution; + chip->xfer_rx_resolution[dai->driver->id - 1] = xfer_resolution; } - val = readl(adata->acp_base + reg_val); + val = readl(chip->base + reg_val); val &= ~ACP3x_ITER_IRER_SAMP_LEN_MASK; val = val | (xfer_resolution << 3); - writel(val, adata->acp_base + reg_val); + writel(val, chip->base + reg_val); - if (adata->tdm_mode) { - val = readl(adata->acp_base + reg_val); - writel(val | BIT(1), adata->acp_base + reg_val); + if (chip->tdm_mode) { + val = readl(chip->base + reg_val); + writel(val | BIT(1), chip->base + reg_val); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - tdm_fmt = adata->tdm_tx_fmt[dai->driver->id - 1]; + tdm_fmt = chip->tdm_tx_fmt[dai->driver->id - 1]; else - tdm_fmt = adata->tdm_rx_fmt[dai->driver->id - 1]; - writel(tdm_fmt, adata->acp_base + fmt_reg); + tdm_fmt = chip->tdm_rx_fmt[dai->driver->id - 1]; + writel(tdm_fmt, chip->base + fmt_reg); } if (rsrc->soc_mclk) { @@ -377,8 +373,8 @@ static int acp_i2s_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_ default: break; } - adata->lrclk_div = lrclk_div_val; - adata->bclk_div = bclk_div_val; + chip->lrclk_div = lrclk_div_val; + chip->bclk_div = bclk_div_val; } return 0; } @@ -387,8 +383,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct { struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_resource *rsrc = adata->rsrc; + struct acp_chip_info *chip = dev_get_platdata(dev); + struct acp_resource *rsrc = chip->rsrc; u32 val, period_bytes, reg_val, ier_val, water_val, buf_size, buf_reg; period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size); @@ -398,20 +394,20 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - stream->bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream); + stream->bytescount = acp_get_byte_count(chip, stream->dai_id, substream->stream); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { switch (dai->driver->id) { case I2S_BT_INSTANCE: - water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(adata); + water_val = ACP_BT_TX_INTR_WATERMARK_SIZE(chip); reg_val = ACP_BTTDM_ITER; ier_val = ACP_BTTDM_IER; - buf_reg = ACP_BT_TX_RINGBUFSIZE(adata); + buf_reg = ACP_BT_TX_RINGBUFSIZE(chip); break; case I2S_SP_INSTANCE: - water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(adata); + water_val = ACP_I2S_TX_INTR_WATERMARK_SIZE(chip); reg_val = ACP_I2STDM_ITER; ier_val = ACP_I2STDM_IER; - buf_reg = ACP_I2S_TX_RINGBUFSIZE(adata); + buf_reg = ACP_I2S_TX_RINGBUFSIZE(chip); break; case I2S_HS_INSTANCE: water_val = ACP_HS_TX_INTR_WATERMARK_SIZE; @@ -426,16 +422,16 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct } else { switch (dai->driver->id) { case I2S_BT_INSTANCE: - water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(adata); + water_val = ACP_BT_RX_INTR_WATERMARK_SIZE(chip); reg_val = ACP_BTTDM_IRER; ier_val = ACP_BTTDM_IER; - buf_reg = ACP_BT_RX_RINGBUFSIZE(adata); + buf_reg = ACP_BT_RX_RINGBUFSIZE(chip); break; case I2S_SP_INSTANCE: - water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(adata); + water_val = ACP_I2S_RX_INTR_WATERMARK_SIZE(chip); reg_val = ACP_I2STDM_IRER; ier_val = ACP_I2STDM_IER; - buf_reg = ACP_I2S_RX_RINGBUFSIZE(adata); + buf_reg = ACP_I2S_RX_RINGBUFSIZE(chip); break; case I2S_HS_INSTANCE: water_val = ACP_HS_RX_INTR_WATERMARK_SIZE; @@ -449,14 +445,14 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct } } - writel(period_bytes, adata->acp_base + water_val); - writel(buf_size, adata->acp_base + buf_reg); + writel(period_bytes, chip->base + water_val); + writel(buf_size, chip->base + buf_reg); if (rsrc->soc_mclk) - acp_set_i2s_clk(adata, dai->driver->id); - val = readl(adata->acp_base + reg_val); + acp_set_i2s_clk(chip, dai->driver->id); + val = readl(chip->base + reg_val); val = val | BIT(0); - writel(val, adata->acp_base + reg_val); - writel(1, adata->acp_base + ier_val); + writel(val, chip->base + reg_val); + writel(1, chip->base + ier_val); return 0; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: @@ -493,19 +489,19 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct return -EINVAL; } } - val = readl(adata->acp_base + reg_val); + val = readl(chip->base + reg_val); val = val & ~BIT(0); - writel(val, adata->acp_base + reg_val); - - if (!(readl(adata->acp_base + ACP_BTTDM_ITER) & BIT(0)) && - !(readl(adata->acp_base + ACP_BTTDM_IRER) & BIT(0))) - writel(0, adata->acp_base + ACP_BTTDM_IER); - if (!(readl(adata->acp_base + ACP_I2STDM_ITER) & BIT(0)) && - !(readl(adata->acp_base + ACP_I2STDM_IRER) & BIT(0))) - writel(0, adata->acp_base + ACP_I2STDM_IER); - if (!(readl(adata->acp_base + ACP_HSTDM_ITER) & BIT(0)) && - !(readl(adata->acp_base + ACP_HSTDM_IRER) & BIT(0))) - writel(0, adata->acp_base + ACP_HSTDM_IER); + writel(val, chip->base + reg_val); + + if (!(readl(chip->base + ACP_BTTDM_ITER) & BIT(0)) && + !(readl(chip->base + ACP_BTTDM_IRER) & BIT(0))) + writel(0, chip->base + ACP_BTTDM_IER); + if (!(readl(chip->base + ACP_I2STDM_ITER) & BIT(0)) && + !(readl(chip->base + ACP_I2STDM_IRER) & BIT(0))) + writel(0, chip->base + ACP_I2STDM_IER); + if (!(readl(chip->base + ACP_HSTDM_ITER) & BIT(0)) && + !(readl(chip->base + ACP_HSTDM_IRER) & BIT(0))) + writel(0, chip->base + ACP_HSTDM_IER); return 0; default: return -EINVAL; @@ -517,9 +513,8 @@ static int acp_i2s_trigger(struct snd_pcm_substream *substream, int cmd, struct static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_chip_info *chip; - struct acp_resource *rsrc = adata->rsrc; + struct acp_chip_info *chip = dev_get_platdata(dev); + struct acp_resource *rsrc = chip->rsrc; struct acp_stream *stream = substream->runtime->private_data; u32 reg_dma_size = 0, reg_fifo_size = 0, reg_fifo_addr = 0; u32 phy_addr = 0, acp_fifo_addr = 0, ext_int_ctrl; @@ -529,56 +524,56 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d switch (dai->driver->id) { case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata); + reg_dma_size = ACP_I2S_TX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + SP_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata); - reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata); + reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip); + reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip); if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_SP_TX_MEM_WINDOW_START; else phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip)); } else { - reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata); + reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + SP_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata); - reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata); + reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip); + reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip); if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_SP_RX_MEM_WINDOW_START; else phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip)); } break; case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_BT_TX_DMA_SIZE(adata); + reg_dma_size = ACP_BT_TX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + BT_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata); - reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata); + reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip); + reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip); if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_BT_TX_MEM_WINDOW_START; else phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip)); } else { - reg_dma_size = ACP_BT_RX_DMA_SIZE(adata); + reg_dma_size = ACP_BT_RX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + BT_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata); - reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata); + reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip); + reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip); if (chip->acp_rev >= ACP70_PCI_ID) phy_addr = ACP7x_I2S_BT_RX_MEM_WINDOW_START; else phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip)); } break; case I2S_HS_INSTANCE: @@ -593,7 +588,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d phy_addr = ACP7x_I2S_HS_TX_MEM_WINDOW_START; else phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); + writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR); } else { reg_dma_size = ACP_HS_RX_DMA_SIZE; acp_fifo_addr = rsrc->sram_pte_offset + @@ -605,7 +600,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d phy_addr = ACP7x_I2S_HS_RX_MEM_WINDOW_START; else phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); + writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR); } break; default: @@ -613,11 +608,11 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d return -EINVAL; } - writel(DMA_SIZE, adata->acp_base + reg_dma_size); - writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); - writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); + writel(DMA_SIZE, chip->base + reg_dma_size); + writel(acp_fifo_addr, chip->base + reg_fifo_addr); + writel(FIFO_SIZE, chip->base + reg_fifo_size); - ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used)); ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | BIT(BT_RX_THRESHOLD(rsrc->offset)) | BIT(I2S_TX_THRESHOLD(rsrc->offset)) | @@ -625,7 +620,7 @@ static int acp_i2s_prepare(struct snd_pcm_substream *substream, struct snd_soc_d BIT(HS_RX_THRESHOLD(rsrc->offset)) | BIT(HS_TX_THRESHOLD(rsrc->offset)); - writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used)); return 0; } @@ -634,8 +629,8 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d { struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_resource *rsrc = adata->rsrc; + struct acp_chip_info *chip = dev_get_platdata(dev); + struct acp_resource *rsrc = chip->rsrc; unsigned int dir = substream->stream; unsigned int irq_bit = 0; diff --git a/sound/soc/amd/acp/acp-legacy-common.c b/sound/soc/amd/acp/acp-legacy-common.c index 7acc7ed2e8cc..b4d68484e06d 100644 --- a/sound/soc/amd/acp/acp-legacy-common.c +++ b/sound/soc/amd/acp/acp-legacy-common.c @@ -13,32 +13,132 @@ */ #include "amd.h" +#include <linux/acpi.h> #include <linux/pci.h> #include <linux/export.h> +#include "../mach-config.h" + #define ACP_RENOIR_PDM_ADDR 0x02 #define ACP_REMBRANDT_PDM_ADDR 0x03 #define ACP63_PDM_ADDR 0x02 #define ACP70_PDM_ADDR 0x02 -void acp_enable_interrupts(struct acp_dev_data *adata) +struct acp_resource rn_rsrc = { + .offset = 20, + .no_of_ctrls = 1, + .irqp_used = 0, + .irq_reg_offset = 0x1800, + .scratch_reg_offset = 0x12800, + .sram_pte_offset = 0x02052800, +}; +EXPORT_SYMBOL_NS_GPL(rn_rsrc, "SND_SOC_ACP_COMMON"); + +struct acp_resource rmb_rsrc = { + .offset = 0, + .no_of_ctrls = 2, + .irqp_used = 1, + .soc_mclk = true, + .irq_reg_offset = 0x1a00, + .scratch_reg_offset = 0x12800, + .sram_pte_offset = 0x03802800, +}; +EXPORT_SYMBOL_NS_GPL(rmb_rsrc, "SND_SOC_ACP_COMMON"); + +struct acp_resource acp63_rsrc = { + .offset = 0, + .no_of_ctrls = 2, + .irqp_used = 1, + .soc_mclk = true, + .irq_reg_offset = 0x1a00, + .scratch_reg_offset = 0x12800, + .sram_pte_offset = 0x03802800, +}; +EXPORT_SYMBOL_NS_GPL(acp63_rsrc, "SND_SOC_ACP_COMMON"); + +struct acp_resource acp70_rsrc = { + .offset = 0, + .no_of_ctrls = 2, + .irqp_used = 1, + .soc_mclk = true, + .irq_reg_offset = 0x1a00, + .scratch_reg_offset = 0x10000, + .sram_pte_offset = 0x03800000, +}; +EXPORT_SYMBOL_NS_GPL(acp70_rsrc, "SND_SOC_ACP_COMMON"); + +static const struct snd_acp_hw_ops acp_common_hw_ops = { + /* ACP hardware initilizations */ + .acp_init = acp_init, + .acp_deinit = acp_deinit, + + /* ACP Interrupts*/ + .irq = acp_irq_handler, + .en_interrupts = acp_enable_interrupts, + .dis_interrupts = acp_disable_interrupts, +}; + +irqreturn_t acp_irq_handler(int irq, void *data) { - struct acp_resource *rsrc = adata->rsrc; + struct acp_chip_info *chip = data; + struct acp_resource *rsrc = chip->rsrc; + struct acp_stream *stream; + u16 i2s_flag = 0; + u32 ext_intr_stat, ext_intr_stat1; + + if (rsrc->no_of_ctrls == 2) + ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(chip, (rsrc->irqp_used - 1))); + + ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used)); + + spin_lock(&chip->acp_lock); + list_for_each_entry(stream, &chip->stream_list, list) { + if (ext_intr_stat & stream->irq_bit) { + writel(stream->irq_bit, + ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used)); + snd_pcm_period_elapsed(stream->substream); + i2s_flag = 1; + } + if (chip->rsrc->no_of_ctrls == 2) { + if (ext_intr_stat1 & stream->irq_bit) { + writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(chip, + (rsrc->irqp_used - 1))); + snd_pcm_period_elapsed(stream->substream); + i2s_flag = 1; + } + } + } + spin_unlock(&chip->acp_lock); + if (i2s_flag) + return IRQ_HANDLED; + + return IRQ_NONE; +} + +int acp_enable_interrupts(struct acp_chip_info *chip) +{ + struct acp_resource *rsrc; u32 ext_intr_ctrl; - writel(0x01, ACP_EXTERNAL_INTR_ENB(adata)); - ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + rsrc = chip->rsrc; + writel(0x01, ACP_EXTERNAL_INTR_ENB(chip)); + ext_intr_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used)); ext_intr_ctrl |= ACP_ERROR_MASK; - writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + writel(ext_intr_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used)); + + return 0; } EXPORT_SYMBOL_NS_GPL(acp_enable_interrupts, "SND_SOC_ACP_COMMON"); -void acp_disable_interrupts(struct acp_dev_data *adata) +int acp_disable_interrupts(struct acp_chip_info *chip) { - struct acp_resource *rsrc = adata->rsrc; + struct acp_resource *rsrc; + + rsrc = chip->rsrc; + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(chip, rsrc->irqp_used)); + writel(0x00, ACP_EXTERNAL_INTR_ENB(chip)); - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - writel(0x00, ACP_EXTERNAL_INTR_ENB(adata)); + return 0; } EXPORT_SYMBOL_NS_GPL(acp_disable_interrupts, "SND_SOC_ACP_COMMON"); @@ -48,7 +148,7 @@ static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct acp_stream *stream = runtime->private_data; struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); u32 physical_addr, pdm_size, period_bytes; @@ -57,29 +157,29 @@ static void set_acp_pdm_ring_buffer(struct snd_pcm_substream *substream, physical_addr = stream->reg_offset + MEM_WINDOW_START; /* Init ACP PDM Ring buffer */ - writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR); - writel(pdm_size, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE); - writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); - writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); + writel(physical_addr, chip->base + ACP_WOV_RX_RINGBUFADDR); + writel(pdm_size, chip->base + ACP_WOV_RX_RINGBUFSIZE); + writel(period_bytes, chip->base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL); } static void set_acp_pdm_clk(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); unsigned int pdm_ctrl; /* Enable default ACP PDM clk */ - writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL); - pdm_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL); + writel(PDM_CLK_FREQ_MASK, chip->base + ACP_WOV_CLK_CTRL); + pdm_ctrl = readl(chip->base + ACP_WOV_MISC_CTRL); pdm_ctrl |= PDM_MISC_CTRL_MASK; - writel(pdm_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL); + writel(pdm_ctrl, chip->base + ACP_WOV_MISC_CTRL); set_acp_pdm_ring_buffer(substream, dai); } void restore_acp_pdm_params(struct snd_pcm_substream *substream, - struct acp_dev_data *adata) + struct acp_chip_info *chip) { struct snd_soc_dai *dai; struct snd_soc_pcm_runtime *soc_runtime; @@ -87,14 +187,15 @@ void restore_acp_pdm_params(struct snd_pcm_substream *substream, soc_runtime = snd_soc_substream_to_rtd(substream); dai = snd_soc_rtd_to_cpu(soc_runtime, 0); + /* Programming channel mask and sampling rate */ - writel(adata->ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS); - writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR); + writel(chip->ch_mask, chip->base + ACP_WOV_PDM_NO_OF_CHANNELS); + writel(PDM_DEC_64, chip->base + ACP_WOV_PDM_DECIMATION_FACTOR); /* Enabling ACP Pdm interuppts */ - ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0)); ext_int_ctrl |= PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0)); set_acp_pdm_clk(substream, dai); } EXPORT_SYMBOL_NS_GPL(restore_acp_pdm_params, "SND_SOC_ACP_COMMON"); @@ -103,8 +204,8 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); - struct acp_resource *rsrc = adata->rsrc; + struct acp_chip_info *chip = dev_get_platdata(dev); + struct acp_resource *rsrc = chip->rsrc; struct acp_stream *stream = substream->runtime->private_data; u32 reg_dma_size, reg_fifo_size, reg_fifo_addr; u32 phy_addr, acp_fifo_addr, ext_int_ctrl; @@ -113,40 +214,40 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, switch (dai->driver->id) { case I2S_SP_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_I2S_TX_DMA_SIZE(adata); + reg_dma_size = ACP_I2S_TX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + SP_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_TX_FIFOADDR(adata); - reg_fifo_size = ACP_I2S_TX_FIFOSIZE(adata); + reg_fifo_addr = ACP_I2S_TX_FIFOADDR(chip); + reg_fifo_size = ACP_I2S_TX_FIFOSIZE(chip); phy_addr = I2S_SP_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_TX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_I2S_TX_RINGBUFADDR(chip)); } else { - reg_dma_size = ACP_I2S_RX_DMA_SIZE(adata); + reg_dma_size = ACP_I2S_RX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + SP_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_I2S_RX_FIFOADDR(adata); - reg_fifo_size = ACP_I2S_RX_FIFOSIZE(adata); + reg_fifo_addr = ACP_I2S_RX_FIFOADDR(chip); + reg_fifo_size = ACP_I2S_RX_FIFOSIZE(chip); phy_addr = I2S_SP_RX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_I2S_RX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_I2S_RX_RINGBUFADDR(chip)); } break; case I2S_BT_INSTANCE: if (dir == SNDRV_PCM_STREAM_PLAYBACK) { - reg_dma_size = ACP_BT_TX_DMA_SIZE(adata); + reg_dma_size = ACP_BT_TX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + BT_PB_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_TX_FIFOADDR(adata); - reg_fifo_size = ACP_BT_TX_FIFOSIZE(adata); + reg_fifo_addr = ACP_BT_TX_FIFOADDR(chip); + reg_fifo_size = ACP_BT_TX_FIFOSIZE(chip); phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_TX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_BT_TX_RINGBUFADDR(chip)); } else { - reg_dma_size = ACP_BT_RX_DMA_SIZE(adata); + reg_dma_size = ACP_BT_RX_DMA_SIZE(chip); acp_fifo_addr = rsrc->sram_pte_offset + BT_CAPT_FIFO_ADDR_OFFSET; - reg_fifo_addr = ACP_BT_RX_FIFOADDR(adata); - reg_fifo_size = ACP_BT_RX_FIFOSIZE(adata); + reg_fifo_addr = ACP_BT_RX_FIFOADDR(chip); + reg_fifo_size = ACP_BT_RX_FIFOSIZE(chip); phy_addr = I2S_BT_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_BT_RX_RINGBUFADDR(adata)); + writel(phy_addr, chip->base + ACP_BT_RX_RINGBUFADDR(chip)); } break; case I2S_HS_INSTANCE: @@ -157,7 +258,7 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, reg_fifo_addr = ACP_HS_TX_FIFOADDR; reg_fifo_size = ACP_HS_TX_FIFOSIZE; phy_addr = I2S_HS_TX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_HS_TX_RINGBUFADDR); + writel(phy_addr, chip->base + ACP_HS_TX_RINGBUFADDR); } else { reg_dma_size = ACP_HS_RX_DMA_SIZE; acp_fifo_addr = rsrc->sram_pte_offset + @@ -165,7 +266,7 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, reg_fifo_addr = ACP_HS_RX_FIFOADDR; reg_fifo_size = ACP_HS_RX_FIFOSIZE; phy_addr = I2S_HS_RX_MEM_WINDOW_START + stream->reg_offset; - writel(phy_addr, adata->acp_base + ACP_HS_RX_RINGBUFADDR); + writel(phy_addr, chip->base + ACP_HS_RX_RINGBUFADDR); } break; default: @@ -173,11 +274,11 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, return -EINVAL; } - writel(DMA_SIZE, adata->acp_base + reg_dma_size); - writel(acp_fifo_addr, adata->acp_base + reg_fifo_addr); - writel(FIFO_SIZE, adata->acp_base + reg_fifo_size); + writel(DMA_SIZE, chip->base + reg_dma_size); + writel(acp_fifo_addr, chip->base + reg_fifo_addr); + writel(FIFO_SIZE, chip->base + reg_fifo_size); - ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used)); ext_int_ctrl |= BIT(I2S_RX_THRESHOLD(rsrc->offset)) | BIT(BT_RX_THRESHOLD(rsrc->offset)) | BIT(I2S_TX_THRESHOLD(rsrc->offset)) | @@ -185,12 +286,12 @@ static int set_acp_i2s_dma_fifo(struct snd_pcm_substream *substream, BIT(HS_RX_THRESHOLD(rsrc->offset)) | BIT(HS_TX_THRESHOLD(rsrc->offset)); - writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, rsrc->irqp_used)); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, rsrc->irqp_used)); return 0; } int restore_acp_i2s_params(struct snd_pcm_substream *substream, - struct acp_dev_data *adata, + struct acp_chip_info *chip, struct acp_stream *stream) { struct snd_soc_dai *dai; @@ -200,7 +301,7 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream, soc_runtime = snd_soc_substream_to_rtd(substream); dai = snd_soc_rtd_to_cpu(soc_runtime, 0); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - tdm_fmt = adata->tdm_tx_fmt[stream->dai_id - 1]; + tdm_fmt = chip->tdm_tx_fmt[stream->dai_id - 1]; switch (stream->dai_id) { case I2S_BT_INSTANCE: reg_val = ACP_BTTDM_ITER; @@ -218,9 +319,9 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream, pr_err("Invalid dai id %x\n", stream->dai_id); return -EINVAL; } - val = adata->xfer_tx_resolution[stream->dai_id - 1] << 3; + val = chip->xfer_tx_resolution[stream->dai_id - 1] << 3; } else { - tdm_fmt = adata->tdm_rx_fmt[stream->dai_id - 1]; + tdm_fmt = chip->tdm_rx_fmt[stream->dai_id - 1]; switch (stream->dai_id) { case I2S_BT_INSTANCE: reg_val = ACP_BTTDM_IRER; @@ -238,13 +339,13 @@ int restore_acp_i2s_params(struct snd_pcm_substream *substream, pr_err("Invalid dai id %x\n", stream->dai_id); return -EINVAL; } - val = adata->xfer_rx_resolution[stream->dai_id - 1] << 3; + val = chip->xfer_rx_resolution[stream->dai_id - 1] << 3; } - writel(val, adata->acp_base + reg_val); - if (adata->tdm_mode == TDM_ENABLE) { - writel(tdm_fmt, adata->acp_base + fmt_reg); - val = readl(adata->acp_base + reg_val); - writel(val | 0x2, adata->acp_base + reg_val); + writel(val, chip->base + reg_val); + if (chip->tdm_mode == TDM_ENABLE) { + writel(tdm_fmt, chip->base + fmt_reg); + val = readl(chip->base + reg_val); + writel(val | 0x2, chip->base + reg_val); } return set_acp_i2s_dma_fifo(substream, dai); } @@ -344,24 +445,32 @@ int acp_deinit(struct acp_chip_info *chip) return 0; } EXPORT_SYMBOL_NS_GPL(acp_deinit, "SND_SOC_ACP_COMMON"); - -int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) +int acp_machine_select(struct acp_chip_info *chip) { - pci_write_config_dword(dev, 0x60, smn_addr); - pci_write_config_dword(dev, 0x64, data); + struct snd_soc_acpi_mach *mach; + int size, platform; + + if (chip->flag == FLAG_AMD_LEGACY_ONLY_DMIC) { + platform = chip->acp_rev; + chip->mach_dev = platform_device_register_data(chip->dev, "acp-pdm-mach", + PLATFORM_DEVID_NONE, &platform, + sizeof(platform)); + } else { + size = sizeof(*chip->machines); + mach = snd_soc_acpi_find_machine(chip->machines); + if (!mach) { + dev_err(chip->dev, "warning: No matching ASoC machine driver found\n"); + return -EINVAL; + } + mach->mach_params.subsystem_rev = chip->acp_rev; + chip->mach_dev = platform_device_register_data(chip->dev, mach->drv_name, + PLATFORM_DEVID_NONE, mach, size); + } + if (IS_ERR(chip->mach_dev)) + dev_warn(chip->dev, "Unable to register Machine device\n"); return 0; } -EXPORT_SYMBOL_NS_GPL(smn_write, "SND_SOC_ACP_COMMON"); - -int smn_read(struct pci_dev *dev, u32 smn_addr) -{ - u32 data; - - pci_write_config_dword(dev, 0x60, smn_addr); - pci_read_config_dword(dev, 0x64, &data); - return data; -} -EXPORT_SYMBOL_NS_GPL(smn_read, "SND_SOC_ACP_COMMON"); +EXPORT_SYMBOL_NS_GPL(acp_machine_select, "SND_SOC_ACP_COMMON"); static void check_acp3x_config(struct acp_chip_info *chip) { @@ -445,7 +554,9 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) { struct acpi_device *pdm_dev; const union acpi_object *obj; - u32 pdm_addr; + acpi_handle handle; + acpi_integer dmic_status; + u32 pdm_addr, ret; switch (chip->acp_rev) { case ACP_RN_PCI_ID: @@ -477,9 +588,58 @@ void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip) obj->integer.value == pdm_addr) chip->is_pdm_dev = true; } + + handle = ACPI_HANDLE(&pci->dev); + ret = acpi_evaluate_integer(handle, "_WOV", NULL, &dmic_status); + if (!ACPI_FAILURE(ret)) + chip->is_pdm_dev = dmic_status; } } EXPORT_SYMBOL_NS_GPL(check_acp_config, "SND_SOC_ACP_COMMON"); +struct snd_acp_hw_ops acp31_common_hw_ops; +EXPORT_SYMBOL_NS_GPL(acp31_common_hw_ops, "SND_SOC_ACP_COMMON"); +int acp31_hw_ops_init(struct acp_chip_info *chip) +{ + memcpy(&acp31_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops)); + chip->acp_hw_ops = &acp31_common_hw_ops; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp31_hw_ops_init, "SND_SOC_ACP_COMMON"); + +struct snd_acp_hw_ops acp6x_common_hw_ops; +EXPORT_SYMBOL_NS_GPL(acp6x_common_hw_ops, "SND_SOC_ACP_COMMON"); +int acp6x_hw_ops_init(struct acp_chip_info *chip) +{ + memcpy(&acp6x_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops)); + chip->acp_hw_ops = &acp6x_common_hw_ops; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp6x_hw_ops_init, "SND_SOC_ACP_COMMON"); + +struct snd_acp_hw_ops acp63_common_hw_ops; +EXPORT_SYMBOL_NS_GPL(acp63_common_hw_ops, "SND_SOC_ACP_COMMON"); +int acp63_hw_ops_init(struct acp_chip_info *chip) +{ + memcpy(&acp63_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops)); + chip->acp_hw_ops = &acp63_common_hw_ops; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp63_hw_ops_init, "SND_SOC_ACP_COMMON"); + +struct snd_acp_hw_ops acp70_common_hw_ops; +EXPORT_SYMBOL_NS_GPL(acp70_common_hw_ops, "SND_SOC_ACP_COMMON"); +int acp70_hw_ops_init(struct acp_chip_info *chip) +{ + memcpy(&acp70_common_hw_ops, &acp_common_hw_ops, sizeof(acp_common_hw_ops)); + chip->acp_hw_ops = &acp70_common_hw_ops; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(acp70_hw_ops_init, "SND_SOC_ACP_COMMON"); + MODULE_DESCRIPTION("AMD ACP legacy common features"); MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/amd/acp/acp-mach-common.c b/sound/soc/amd/acp/acp-mach-common.c index f7602c1769bf..a0dab85088ec 100644 --- a/sound/soc/amd/acp/acp-mach-common.c +++ b/sound/soc/amd/acp/acp-mach-common.c @@ -919,7 +919,7 @@ static int acp_max98388_hw_params(struct snd_pcm_substream *substream, int ret; ret = snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_CBS_CFS | SND_SOC_DAIFMT_I2S | + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF); if (ret < 0) return ret; diff --git a/sound/soc/amd/acp/acp-pci.c b/sound/soc/amd/acp/acp-pci.c index e0fc42d939d3..0b2aa33cc426 100644 --- a/sound/soc/amd/acp/acp-pci.c +++ b/sound/soc/amd/acp/acp-pci.c @@ -26,32 +26,88 @@ #define ACP3x_REG_START 0x1240000 #define ACP3x_REG_END 0x125C000 -static struct platform_device *dmic_dev; -static struct platform_device *pdev; - -static const struct resource acp_res[] = { - { - .start = 0, - .end = ACP3x_REG_END - ACP3x_REG_START, - .name = "acp_mem", - .flags = IORESOURCE_MEM, - }, - { - .start = 0, - .end = 0, - .name = "acp_dai_irq", - .flags = IORESOURCE_IRQ, - }, -}; +static irqreturn_t irq_handler(int irq, void *data) +{ + struct acp_chip_info *chip = data; -static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) + if (chip && chip->acp_hw_ops && chip->acp_hw_ops->irq) + return chip->acp_hw_ops->irq(irq, chip); + + return IRQ_NONE; +} +static void acp_fill_platform_dev_info(struct platform_device_info *pdevinfo, + struct device *parent, + struct fwnode_handle *fw_node, + char *name, unsigned int id, + const struct resource *res, + unsigned int num_res, + const void *data, + size_t size_data) +{ + pdevinfo->name = name; + pdevinfo->id = id; + pdevinfo->parent = parent; + pdevinfo->num_res = num_res; + pdevinfo->res = res; + pdevinfo->data = data; + pdevinfo->size_data = size_data; + pdevinfo->fwnode = fw_node; +} + +static int create_acp_platform_devs(struct pci_dev *pci, struct acp_chip_info *chip, u32 addr) { struct platform_device_info pdevinfo; + struct device *parent; + int ret; + + parent = &pci->dev; + + if (chip->is_i2s_config || chip->is_pdm_dev) { + chip->res = devm_kzalloc(&pci->dev, sizeof(struct resource), GFP_KERNEL); + if (!chip->res) { + ret = -ENOMEM; + goto err; + } + chip->res->flags = IORESOURCE_MEM; + chip->res->start = addr; + chip->res->end = addr + (ACP3x_REG_END - ACP3x_REG_START); + memset(&pdevinfo, 0, sizeof(pdevinfo)); + } + + memset(&pdevinfo, 0, sizeof(pdevinfo)); + acp_fill_platform_dev_info(&pdevinfo, parent, NULL, chip->name, + 0, chip->res, 1, chip, sizeof(*chip)); + + chip->acp_plat_dev = platform_device_register_full(&pdevinfo); + if (IS_ERR(chip->acp_plat_dev)) { + dev_err(&pci->dev, + "cannot register %s device\n", pdevinfo.name); + ret = PTR_ERR(chip->acp_plat_dev); + goto err; + } + if (chip->is_pdm_dev && chip->is_pdm_config) { + chip->dmic_codec_dev = platform_device_register_data(&pci->dev, + "dmic-codec", + PLATFORM_DEVID_NONE, + NULL, 0); + if (IS_ERR(chip->dmic_codec_dev)) { + dev_err(&pci->dev, "failed to create DMIC device\n"); + ret = PTR_ERR(chip->dmic_codec_dev); + goto unregister_acp_plat_dev; + } + } + return 0; +unregister_acp_plat_dev: + platform_device_unregister(chip->acp_plat_dev); +err: + return ret; +} + +static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) +{ struct device *dev = &pci->dev; - const struct resource *res_acp; struct acp_chip_info *chip; - struct resource *res; - unsigned int flag, addr, num_res, i; + unsigned int flag, addr; int ret; flag = snd_amd_acp_find_config(pci); @@ -75,24 +131,32 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id pci_set_master(pci); - res_acp = acp_res; - num_res = ARRAY_SIZE(acp_res); chip->acp_rev = pci->revision; switch (pci->revision) { case 0x01: chip->name = "acp_asoc_renoir"; + chip->rsrc = &rn_rsrc; + chip->acp_hw_ops_init = acp31_hw_ops_init; + chip->machines = &snd_soc_acpi_amd_acp_machines; break; case 0x6f: chip->name = "acp_asoc_rembrandt"; + chip->rsrc = &rmb_rsrc; + chip->acp_hw_ops_init = acp6x_hw_ops_init; + chip->machines = &snd_soc_acpi_amd_rmb_acp_machines; break; case 0x63: chip->name = "acp_asoc_acp63"; + chip->rsrc = &acp63_rsrc; + chip->acp_hw_ops_init = acp63_hw_ops_init; + chip->machines = &snd_soc_acpi_amd_acp63_acp_machines; break; case 0x70: - chip->name = "acp_asoc_acp70"; - break; case 0x71: chip->name = "acp_asoc_acp70"; + chip->rsrc = &acp70_rsrc; + chip->acp_hw_ops_init = acp70_hw_ops_init; + chip->machines = &snd_soc_acpi_amd_acp70_acp_machines; break; default: dev_err(dev, "Unsupported device revision:0x%x\n", pci->revision); @@ -100,64 +164,46 @@ static int acp_pci_probe(struct pci_dev *pci, const struct pci_device_id *pci_id goto release_regions; } chip->flag = flag; - dmic_dev = platform_device_register_data(dev, "dmic-codec", PLATFORM_DEVID_NONE, NULL, 0); - if (IS_ERR(dmic_dev)) { - dev_err(dev, "failed to create DMIC device\n"); - ret = PTR_ERR(dmic_dev); - goto release_regions; - } addr = pci_resource_start(pci, 0); chip->base = devm_ioremap(&pci->dev, addr, pci_resource_len(pci, 0)); if (!chip->base) { ret = -ENOMEM; - goto unregister_dmic_dev; + goto release_regions; } - ret = acp_init(chip); + chip->addr = addr; + + chip->acp_hw_ops_init(chip); + ret = acp_hw_init(chip); if (ret) - goto unregister_dmic_dev; + goto release_regions; + + ret = devm_request_irq(dev, pci->irq, irq_handler, + IRQF_SHARED, "ACP_I2S_IRQ", chip); + if (ret) { + dev_err(&pci->dev, "ACP I2S IRQ request failed %d\n", ret); + goto de_init; + } check_acp_config(pci, chip); if (!chip->is_pdm_dev && !chip->is_i2s_config) goto skip_pdev_creation; - res = devm_kcalloc(&pci->dev, num_res, sizeof(struct resource), GFP_KERNEL); - if (!res) { - ret = -ENOMEM; - goto unregister_dmic_dev; + ret = create_acp_platform_devs(pci, chip, addr); + if (ret < 0) { + dev_err(&pci->dev, "ACP platform devices creation failed\n"); + goto de_init; } - for (i = 0; i < num_res; i++, res_acp++) { - res[i].name = res_acp->name; - res[i].flags = res_acp->flags; - res[i].start = addr + res_acp->start; - res[i].end = addr + res_acp->end; - if (res_acp->flags == IORESOURCE_IRQ) { - res[i].start = pci->irq; - res[i].end = res[i].start; - } - } + chip->chip_pdev = chip->acp_plat_dev; + chip->dev = &chip->acp_plat_dev->dev; - memset(&pdevinfo, 0, sizeof(pdevinfo)); - - pdevinfo.name = chip->name; - pdevinfo.id = 0; - pdevinfo.parent = &pci->dev; - pdevinfo.num_res = num_res; - pdevinfo.res = &res[0]; - pdevinfo.data = chip; - pdevinfo.size_data = sizeof(*chip); - - pdev = platform_device_register_full(&pdevinfo); - if (IS_ERR(pdev)) { - dev_err(&pci->dev, "cannot register %s device\n", pdevinfo.name); - ret = PTR_ERR(pdev); - goto unregister_dmic_dev; - } + acp_machine_select(chip); + INIT_LIST_HEAD(&chip->stream_list); + spin_lock_init(&chip->acp_lock); skip_pdev_creation: - chip->chip_pdev = pdev; dev_set_drvdata(&pci->dev, chip); pm_runtime_set_autosuspend_delay(&pci->dev, 2000); pm_runtime_use_autosuspend(&pci->dev); @@ -165,8 +211,8 @@ skip_pdev_creation: pm_runtime_allow(&pci->dev); return ret; -unregister_dmic_dev: - platform_device_unregister(dmic_dev); +de_init: + acp_hw_deinit(chip); release_regions: pci_release_regions(pci); disable_pci: @@ -175,41 +221,38 @@ disable_pci: return ret; }; -static int __maybe_unused snd_acp_suspend(struct device *dev) +static int snd_acp_suspend(struct device *dev) { struct acp_chip_info *chip; int ret; chip = dev_get_drvdata(dev); - ret = acp_deinit(chip); + ret = acp_hw_deinit(chip); if (ret) dev_err(dev, "ACP de-init failed\n"); return ret; } -static int __maybe_unused snd_acp_resume(struct device *dev) +static int snd_acp_resume(struct device *dev) { struct acp_chip_info *chip; - struct acp_dev_data *adata; - struct device child; int ret; chip = dev_get_drvdata(dev); - ret = acp_init(chip); + ret = acp_hw_init(chip); if (ret) dev_err(dev, "ACP init failed\n"); - if (chip->chip_pdev) { - child = chip->chip_pdev->dev; - adata = dev_get_drvdata(&child); - if (adata) - acp_enable_interrupts(adata); - } + + ret = acp_hw_en_interrupts(chip); + if (ret) + dev_err(dev, "ACP en-interrupts failed\n"); + return ret; } static const struct dev_pm_ops acp_pm_ops = { - SET_RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume) + RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_resume, NULL) + SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume) }; static void acp_pci_remove(struct pci_dev *pci) @@ -220,11 +263,14 @@ static void acp_pci_remove(struct pci_dev *pci) chip = pci_get_drvdata(pci); pm_runtime_forbid(&pci->dev); pm_runtime_get_noresume(&pci->dev); - if (dmic_dev) - platform_device_unregister(dmic_dev); - if (pdev) - platform_device_unregister(pdev); - ret = acp_deinit(chip); + if (chip->dmic_codec_dev) + platform_device_unregister(chip->dmic_codec_dev); + if (chip->acp_plat_dev) + platform_device_unregister(chip->acp_plat_dev); + if (chip->mach_dev) + platform_device_unregister(chip->mach_dev); + + ret = acp_hw_deinit(chip); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); } @@ -243,7 +289,7 @@ static struct pci_driver snd_amd_acp_pci_driver = { .probe = acp_pci_probe, .remove = acp_pci_remove, .driver = { - .pm = &acp_pm_ops, + .pm = pm_ptr(&acp_pm_ops), }, }; module_pci_driver(snd_amd_acp_pci_driver); diff --git a/sound/soc/amd/acp/acp-pdm.c b/sound/soc/amd/acp/acp-pdm.c index d4855da05b6a..1bfc34c2aa53 100644 --- a/sound/soc/amd/acp/acp-pdm.c +++ b/sound/soc/amd/acp/acp-pdm.c @@ -30,17 +30,16 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, { struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); struct acp_chip_info *chip; u32 physical_addr, size_dmic, period_bytes; unsigned int dmic_ctrl; chip = dev_get_platdata(dev); /* Enable default DMIC clk */ - writel(PDM_CLK_FREQ_MASK, adata->acp_base + ACP_WOV_CLK_CTRL); - dmic_ctrl = readl(adata->acp_base + ACP_WOV_MISC_CTRL); + writel(PDM_CLK_FREQ_MASK, chip->base + ACP_WOV_CLK_CTRL); + dmic_ctrl = readl(chip->base + ACP_WOV_MISC_CTRL); dmic_ctrl |= PDM_MISC_CTRL_MASK; - writel(dmic_ctrl, adata->acp_base + ACP_WOV_MISC_CTRL); + writel(dmic_ctrl, chip->base + ACP_WOV_MISC_CTRL); period_bytes = frames_to_bytes(substream->runtime, substream->runtime->period_size); @@ -53,10 +52,10 @@ static int acp_dmic_prepare(struct snd_pcm_substream *substream, physical_addr = stream->reg_offset + MEM_WINDOW_START; /* Init DMIC Ring buffer */ - writel(physical_addr, adata->acp_base + ACP_WOV_RX_RINGBUFADDR); - writel(size_dmic, adata->acp_base + ACP_WOV_RX_RINGBUFSIZE); - writel(period_bytes, adata->acp_base + ACP_WOV_RX_INTR_WATERMARK_SIZE); - writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); + writel(physical_addr, chip->base + ACP_WOV_RX_RINGBUFADDR); + writel(size_dmic, chip->base + ACP_WOV_RX_RINGBUFSIZE); + writel(period_bytes, chip->base + ACP_WOV_RX_INTR_WATERMARK_SIZE); + writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL); return 0; } @@ -65,7 +64,7 @@ static int acp_dmic_dai_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); unsigned int dma_enable; int ret = 0; @@ -73,27 +72,27 @@ static int acp_dmic_dai_trigger(struct snd_pcm_substream *substream, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - dma_enable = readl(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE); + dma_enable = readl(chip->base + ACP_WOV_PDM_DMA_ENABLE); if (!(dma_enable & DMA_EN_MASK)) { - writel(PDM_ENABLE, adata->acp_base + ACP_WOV_PDM_ENABLE); - writel(PDM_ENABLE, adata->acp_base + ACP_WOV_PDM_DMA_ENABLE); + writel(PDM_ENABLE, chip->base + ACP_WOV_PDM_ENABLE); + writel(PDM_ENABLE, chip->base + ACP_WOV_PDM_DMA_ENABLE); } - ret = readl_poll_timeout_atomic(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE, + ret = readl_poll_timeout_atomic(chip->base + ACP_WOV_PDM_DMA_ENABLE, dma_enable, (dma_enable & DMA_EN_MASK), DELAY_US, PDM_TIMEOUT); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dma_enable = readl(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE); + dma_enable = readl(chip->base + ACP_WOV_PDM_DMA_ENABLE); if ((dma_enable & DMA_EN_MASK)) { - writel(PDM_DISABLE, adata->acp_base + ACP_WOV_PDM_ENABLE); - writel(PDM_DISABLE, adata->acp_base + ACP_WOV_PDM_DMA_ENABLE); + writel(PDM_DISABLE, chip->base + ACP_WOV_PDM_ENABLE); + writel(PDM_DISABLE, chip->base + ACP_WOV_PDM_DMA_ENABLE); } - ret = readl_poll_timeout_atomic(adata->acp_base + ACP_WOV_PDM_DMA_ENABLE, + ret = readl_poll_timeout_atomic(chip->base + ACP_WOV_PDM_DMA_ENABLE, dma_enable, !(dma_enable & DMA_EN_MASK), DELAY_US, PDM_TIMEOUT); break; @@ -109,7 +108,7 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hwparams, struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); unsigned int channels, ch_mask; channels = params_channels(hwparams); @@ -128,14 +127,14 @@ static int acp_dmic_hwparams(struct snd_pcm_substream *substream, return -EINVAL; } - adata->ch_mask = ch_mask; + chip->ch_mask = ch_mask; if (params_format(hwparams) != SNDRV_PCM_FORMAT_S32_LE) { dev_err(dai->dev, "Invalid format:%d\n", params_format(hwparams)); return -EINVAL; } - writel(ch_mask, adata->acp_base + ACP_WOV_PDM_NO_OF_CHANNELS); - writel(PDM_DEC_64, adata->acp_base + ACP_WOV_PDM_DECIMATION_FACTOR); + writel(ch_mask, chip->base + ACP_WOV_PDM_NO_OF_CHANNELS); + writel(PDM_DEC_64, chip->base + ACP_WOV_PDM_DECIMATION_FACTOR); return 0; } @@ -145,7 +144,7 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream, { struct acp_stream *stream = substream->runtime->private_data; struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); u32 ext_int_ctrl; stream->dai_id = DMIC_INSTANCE; @@ -154,9 +153,9 @@ static int acp_dmic_dai_startup(struct snd_pcm_substream *substream, stream->reg_offset = ACP_REGION2_OFFSET; /* Enable DMIC Interrupts */ - ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0)); ext_int_ctrl |= PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0)); return 0; } @@ -165,13 +164,13 @@ static void acp_dmic_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct device *dev = dai->component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); u32 ext_int_ctrl; /* Disable DMIC interrupts */ - ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(adata, 0)); + ext_int_ctrl = readl(ACP_EXTERNAL_INTR_CNTL(chip, 0)); ext_int_ctrl &= ~PDM_DMA_INTR_MASK; - writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(adata, 0)); + writel(ext_int_ctrl, ACP_EXTERNAL_INTR_CNTL(chip, 0)); } const struct snd_soc_dai_ops acp_dmic_dai_ops = { diff --git a/sound/soc/amd/acp/acp-platform.c b/sound/soc/amd/acp/acp-platform.c index aa330aeeb301..b3eddf76aaa4 100644 --- a/sound/soc/amd/acp/acp-platform.c +++ b/sound/soc/amd/acp/acp-platform.c @@ -21,7 +21,6 @@ #include <linux/dma-mapping.h> #include "amd.h" -#include "../mach-config.h" #include "acp-mach.h" #define DRV_NAME "acp_i2s_dma" @@ -108,101 +107,37 @@ static const struct snd_pcm_hardware acp6x_pcm_hardware_capture = { .periods_max = CAPTURE_MAX_NUM_PERIODS, }; -int acp_machine_select(struct acp_dev_data *adata) +void config_pte_for_stream(struct acp_chip_info *chip, struct acp_stream *stream) { - struct snd_soc_acpi_mach *mach; - int size, platform; - - if (adata->flag == FLAG_AMD_LEGACY_ONLY_DMIC) { - platform = adata->acp_rev; - adata->mach_dev = platform_device_register_data(adata->dev, "acp-pdm-mach", - PLATFORM_DEVID_NONE, &platform, - sizeof(platform)); - } else { - size = sizeof(*adata->machines); - mach = snd_soc_acpi_find_machine(adata->machines); - if (!mach) { - dev_err(adata->dev, "warning: No matching ASoC machine driver found\n"); - return -EINVAL; - } - mach->mach_params.subsystem_rev = adata->acp_rev; - adata->mach_dev = platform_device_register_data(adata->dev, mach->drv_name, - PLATFORM_DEVID_NONE, mach, size); - } - if (IS_ERR(adata->mach_dev)) - dev_warn(adata->dev, "Unable to register Machine device\n"); - return 0; -} -EXPORT_SYMBOL_NS_GPL(acp_machine_select, "SND_SOC_ACP_COMMON"); - -static irqreturn_t i2s_irq_handler(int irq, void *data) -{ - struct acp_dev_data *adata = data; - struct acp_resource *rsrc = adata->rsrc; - struct acp_stream *stream; - u16 i2s_flag = 0; - u32 ext_intr_stat, ext_intr_stat1; - - if (adata->rsrc->no_of_ctrls == 2) - ext_intr_stat1 = readl(ACP_EXTERNAL_INTR_STAT(adata, (rsrc->irqp_used - 1))); - - ext_intr_stat = readl(ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - - spin_lock(&adata->acp_lock); - list_for_each_entry(stream, &adata->stream_list, list) { - if (ext_intr_stat & stream->irq_bit) { - writel(stream->irq_bit, - ACP_EXTERNAL_INTR_STAT(adata, rsrc->irqp_used)); - snd_pcm_period_elapsed(stream->substream); - i2s_flag = 1; - } - if (adata->rsrc->no_of_ctrls == 2) { - if (ext_intr_stat1 & stream->irq_bit) { - writel(stream->irq_bit, ACP_EXTERNAL_INTR_STAT(adata, - (rsrc->irqp_used - 1))); - snd_pcm_period_elapsed(stream->substream); - i2s_flag = 1; - } - } - } - spin_unlock(&adata->acp_lock); - if (i2s_flag) - return IRQ_HANDLED; - - return IRQ_NONE; -} - -void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream) -{ - struct acp_resource *rsrc = adata->rsrc; + struct acp_resource *rsrc = chip->rsrc; u32 reg_val; reg_val = rsrc->sram_pte_offset; stream->reg_offset = 0x02000000; - writel((reg_val + GRP1_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); - writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); + writel((reg_val + GRP1_OFFSET) | BIT(31), chip->base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_1); + writel(PAGE_SIZE_4K_ENABLE, chip->base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_1); - writel((reg_val + GRP2_OFFSET) | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2); - writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2); + writel((reg_val + GRP2_OFFSET) | BIT(31), chip->base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_2); + writel(PAGE_SIZE_4K_ENABLE, chip->base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_2); - writel(reg_val | BIT(31), adata->acp_base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5); - writel(PAGE_SIZE_4K_ENABLE, adata->acp_base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5); + writel(reg_val | BIT(31), chip->base + ACPAXI2AXI_ATU_BASE_ADDR_GRP_5); + writel(PAGE_SIZE_4K_ENABLE, chip->base + ACPAXI2AXI_ATU_PAGE_SIZE_GRP_5); - writel(0x01, adata->acp_base + ACPAXI2AXI_ATU_CTRL); + writel(0x01, chip->base + ACPAXI2AXI_ATU_CTRL); } EXPORT_SYMBOL_NS_GPL(config_pte_for_stream, "SND_SOC_ACP_COMMON"); -void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size) +void config_acp_dma(struct acp_chip_info *chip, struct acp_stream *stream, int size) { struct snd_pcm_substream *substream = stream->substream; - struct acp_resource *rsrc = adata->rsrc; + struct acp_resource *rsrc = chip->rsrc; dma_addr_t addr = substream->dma_buffer.addr; int num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); u32 low, high, val; u16 page_idx; - switch (adata->acp_rev) { + switch (chip->acp_rev) { case ACP70_PCI_ID: case ACP71_PCI_ID: switch (stream->dai_id) { @@ -228,7 +163,7 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s val = 0x6000; break; default: - dev_err(adata->dev, "Invalid dai id %x\n", stream->dai_id); + dev_err(chip->dev, "Invalid dai id %x\n", stream->dai_id); return; } break; @@ -241,9 +176,9 @@ void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int s /* Load the low address of page int ACP SRAM through SRBM */ low = lower_32_bits(addr); high = upper_32_bits(addr); - writel(low, adata->acp_base + rsrc->scratch_reg_offset + val); + writel(low, chip->base + rsrc->scratch_reg_offset + val); high |= BIT(31); - writel(high, adata->acp_base + rsrc->scratch_reg_offset + val + 4); + writel(high, chip->base + rsrc->scratch_reg_offset + val + 4); /* Move to next physically contiguous page */ val += 8; @@ -256,7 +191,6 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs { struct snd_pcm_runtime *runtime = substream->runtime; struct device *dev = component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); struct acp_chip_info *chip; struct acp_stream *stream; int ret; @@ -266,7 +200,7 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs return -ENOMEM; stream->substream = substream; - chip = dev_get_platdata(dev); + chip = dev_get_drvdata(dev->parent); switch (chip->acp_rev) { case ACP63_PCI_ID: case ACP70_PCI_ID: @@ -306,11 +240,11 @@ static int acp_dma_open(struct snd_soc_component *component, struct snd_pcm_subs } runtime->private_data = stream; - writel(1, ACP_EXTERNAL_INTR_ENB(adata)); + writel(1, ACP_EXTERNAL_INTR_ENB(chip)); - spin_lock_irq(&adata->acp_lock); - list_add_tail(&stream->list, &adata->stream_list); - spin_unlock_irq(&adata->acp_lock); + spin_lock_irq(&chip->acp_lock); + list_add_tail(&stream->list, &chip->stream_list); + spin_unlock_irq(&chip->acp_lock); return ret; } @@ -319,13 +253,14 @@ static int acp_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { - struct acp_dev_data *adata = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + struct acp_chip_info *chip = dev_get_drvdata(dev->parent); struct acp_stream *stream = substream->runtime->private_data; u64 size = params_buffer_bytes(params); /* Configure ACP DMA block with params */ - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, size); + config_pte_for_stream(chip, stream); + config_acp_dma(chip, stream, size); return 0; } @@ -334,7 +269,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct device *dev = component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_drvdata(dev->parent); struct acp_stream *stream = substream->runtime->private_data; u32 pos, buffersize; u64 bytescount; @@ -342,7 +277,7 @@ static snd_pcm_uframes_t acp_dma_pointer(struct snd_soc_component *component, buffersize = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); - bytescount = acp_get_byte_count(adata, stream->dai_id, substream->stream); + bytescount = acp_get_byte_count(chip, stream->dai_id, substream->stream); if (bytescount > stream->bytescount) bytescount -= stream->bytescount; @@ -366,13 +301,13 @@ static int acp_dma_close(struct snd_soc_component *component, struct snd_pcm_substream *substream) { struct device *dev = component->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_drvdata(dev->parent); struct acp_stream *stream = substream->runtime->private_data; /* Remove entry from list */ - spin_lock_irq(&adata->acp_lock); + spin_lock_irq(&chip->acp_lock); list_del(&stream->list); - spin_unlock_irq(&adata->acp_lock); + spin_unlock_irq(&chip->acp_lock); kfree(stream); return 0; @@ -390,38 +325,30 @@ static const struct snd_soc_component_driver acp_pcm_component = { int acp_platform_register(struct device *dev) { - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip; struct snd_soc_dai_driver; unsigned int status; - status = devm_request_irq(dev, adata->i2s_irq, i2s_irq_handler, - IRQF_SHARED, "ACP_I2S_IRQ", adata); - if (status) { - dev_err(dev, "ACP I2S IRQ request failed\n"); - return status; + chip = dev_get_platdata(dev); + if (!chip || !chip->base) { + dev_err(dev, "ACP chip data is NULL\n"); + return -ENODEV; } status = devm_snd_soc_register_component(dev, &acp_pcm_component, - adata->dai_driver, - adata->num_dai); + chip->dai_driver, + chip->num_dai); if (status) { dev_err(dev, "Fail to register acp i2s component\n"); return status; } - INIT_LIST_HEAD(&adata->stream_list); - spin_lock_init(&adata->acp_lock); - return 0; } EXPORT_SYMBOL_NS_GPL(acp_platform_register, "SND_SOC_ACP_COMMON"); int acp_platform_unregister(struct device *dev) { - struct acp_dev_data *adata = dev_get_drvdata(dev); - - if (adata->mach_dev) - platform_device_unregister(adata->mach_dev); return 0; } EXPORT_SYMBOL_NS_GPL(acp_platform_unregister, "SND_SOC_ACP_COMMON"); diff --git a/sound/soc/amd/acp/acp-rembrandt.c b/sound/soc/amd/acp/acp-rembrandt.c index 2648256fa129..746b6ed72029 100644 --- a/sound/soc/amd/acp/acp-rembrandt.c +++ b/sound/soc/amd/acp/acp-rembrandt.c @@ -22,6 +22,8 @@ #include <linux/pci.h> #include <linux/pm_runtime.h> +#include <asm/amd_node.h> + #include "amd.h" #include "../mach-config.h" #include "acp-mach.h" @@ -31,47 +33,6 @@ #define MP1_C2PMSG_69 0x3B10A14 #define MP1_C2PMSG_85 0x3B10A54 #define MP1_C2PMSG_93 0x3B10A74 -#define HOST_BRIDGE_ID 0x14B5 - -static struct acp_resource rsrc = { - .offset = 0, - .no_of_ctrls = 2, - .irqp_used = 1, - .soc_mclk = true, - .irq_reg_offset = 0x1a00, - .scratch_reg_offset = 0x12800, - .sram_pte_offset = 0x03802800, -}; - -static struct snd_soc_acpi_codecs amp_rt1019 = { - .num_codecs = 1, - .codecs = {"10EC1019"} -}; - -static struct snd_soc_acpi_codecs amp_max = { - .num_codecs = 1, - .codecs = {"MX98360A"} -}; - -static struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = { - { - .id = "10508825", - .drv_name = "rmb-nau8825-max", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &_max, - }, - { - .id = "AMDI0007", - .drv_name = "rembrandt-acp", - }, - { - .id = "RTL5682", - .drv_name = "rmb-rt5682s-rt1019", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &_rt1019, - }, - {}, -}; static struct snd_soc_dai_driver acp_rmb_dai[] = { { @@ -166,29 +127,26 @@ static struct snd_soc_dai_driver acp_rmb_dai[] = { static int acp6x_master_clock_generate(struct device *dev) { - int data = 0; - struct pci_dev *smn_dev; - - smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, HOST_BRIDGE_ID, NULL); - if (!smn_dev) { - dev_err(dev, "Failed to get host bridge device\n"); - return -ENODEV; - } - - smn_write(smn_dev, MP1_C2PMSG_93, 0); - smn_write(smn_dev, MP1_C2PMSG_85, 0xC4); - smn_write(smn_dev, MP1_C2PMSG_69, 0x4); - read_poll_timeout(smn_read, data, data, DELAY_US, - ACP_TIMEOUT, false, smn_dev, MP1_C2PMSG_93); - return 0; + int data, rc; + + rc = amd_smn_write(0, MP1_C2PMSG_93, 0); + if (rc) + return rc; + rc = amd_smn_write(0, MP1_C2PMSG_85, 0xC4); + if (rc) + return rc; + rc = amd_smn_write(0, MP1_C2PMSG_69, 0x4); + if (rc) + return rc; + + return read_poll_timeout(smn_read_register, data, data > 0, DELAY_US, + ACP_TIMEOUT, false, MP1_C2PMSG_93); } static int rembrandt_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; - struct acp_dev_data *adata; - struct resource *res; u32 ret; chip = dev_get_platdata(&pdev->dev); @@ -202,45 +160,20 @@ static int rembrandt_audio_probe(struct platform_device *pdev) return -ENODEV; } - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); - if (!adata) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); - return -ENODEV; - } - - adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!adata->acp_base) - return -ENOMEM; + chip->dev = dev; + chip->dai_driver = acp_rmb_dai; + chip->num_dai = ARRAY_SIZE(acp_rmb_dai); - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); - return -ENODEV; - } - - adata->i2s_irq = res->start; - adata->dev = dev; - adata->dai_driver = acp_rmb_dai; - adata->num_dai = ARRAY_SIZE(acp_rmb_dai); - adata->rsrc = &rsrc; - adata->acp_rev = chip->acp_rev; - adata->flag = chip->flag; - adata->is_i2s_config = chip->is_i2s_config; - adata->machines = snd_soc_acpi_amd_rmb_acp_machines; - acp_machine_select(adata); - - dev_set_drvdata(dev, adata); - - if (chip->is_i2s_config && rsrc.soc_mclk) { + if (chip->is_i2s_config && chip->rsrc->soc_mclk) { ret = acp6x_master_clock_generate(dev); if (ret) return ret; } - acp_enable_interrupts(adata); + ret = acp_hw_en_interrupts(chip); + if (ret) { + dev_err(dev, "ACP en-interrupts failed\n"); + return ret; + } acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); @@ -253,44 +186,48 @@ static int rembrandt_audio_probe(struct platform_device *pdev) static void rembrandt_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); + int ret; + + ret = acp_hw_dis_interrupts(chip); + if (ret) + dev_err(dev, "ACP dis-interrupts failed\n"); - acp_disable_interrupts(adata); acp_platform_unregister(dev); pm_runtime_disable(&pdev->dev); } -static int __maybe_unused rmb_pcm_resume(struct device *dev) +static int rmb_pcm_resume(struct device *dev) { - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); struct acp_stream *stream; struct snd_pcm_substream *substream; snd_pcm_uframes_t buf_in_frames; u64 buf_size; - if (adata->is_i2s_config && adata->rsrc->soc_mclk) + if (chip->is_i2s_config && chip->rsrc->soc_mclk) acp6x_master_clock_generate(dev); - spin_lock(&adata->acp_lock); - list_for_each_entry(stream, &adata->stream_list, list) { + spin_lock(&chip->acp_lock); + list_for_each_entry(stream, &chip->stream_list, list) { substream = stream->substream; if (substream && substream->runtime) { buf_in_frames = (substream->runtime->buffer_size); buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); + config_pte_for_stream(chip, stream); + config_acp_dma(chip, stream, buf_size); if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); + restore_acp_i2s_params(substream, chip, stream); else - restore_acp_pdm_params(substream, adata); + restore_acp_pdm_params(substream, chip); } } - spin_unlock(&adata->acp_lock); + spin_unlock(&chip->acp_lock); return 0; } static const struct dev_pm_ops rmb_dma_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume) + SYSTEM_SLEEP_PM_OPS(NULL, rmb_pcm_resume) }; static struct platform_driver rembrandt_driver = { @@ -298,7 +235,7 @@ static struct platform_driver rembrandt_driver = { .remove = rembrandt_audio_remove, .driver = { .name = "acp_asoc_rembrandt", - .pm = &rmb_dma_pm_ops, + .pm = pm_ptr(&rmb_dma_pm_ops), }, }; diff --git a/sound/soc/amd/acp/acp-renoir.c b/sound/soc/amd/acp/acp-renoir.c index ca2b74283d8f..ebf0106fc737 100644 --- a/sound/soc/amd/acp/acp-renoir.c +++ b/sound/soc/amd/acp/acp-renoir.c @@ -27,55 +27,6 @@ #define DRV_NAME "acp_asoc_renoir" -static struct acp_resource rsrc = { - .offset = 20, - .no_of_ctrls = 1, - .irqp_used = 0, - .irq_reg_offset = 0x1800, - .scratch_reg_offset = 0x12800, - .sram_pte_offset = 0x02052800, -}; - -static struct snd_soc_acpi_codecs amp_rt1019 = { - .num_codecs = 1, - .codecs = {"10EC1019"} -}; - -static struct snd_soc_acpi_codecs amp_max = { - .num_codecs = 1, - .codecs = {"MX98360A"} -}; - -static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { - { - .id = "10EC5682", - .drv_name = "acp3xalc56821019", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &_rt1019, - }, - { - .id = "RTL5682", - .drv_name = "acp3xalc5682sm98360", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &_max, - }, - { - .id = "RTL5682", - .drv_name = "acp3xalc5682s1019", - .machine_quirk = snd_soc_acpi_codec_list, - .quirk_data = &_rt1019, - }, - { - .id = "AMDI1019", - .drv_name = "renoir-acp", - }, - { - .id = "ESSX8336", - .drv_name = "acp3x-es83xx", - }, - {}, -}; - static struct snd_soc_dai_driver acp_renoir_dai[] = { { .name = "acp-i2s-sp", @@ -147,8 +98,6 @@ static int renoir_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; - struct acp_dev_data *adata; - struct resource *res; int ret; chip = dev_get_platdata(&pdev->dev); @@ -162,37 +111,16 @@ static int renoir_audio_probe(struct platform_device *pdev) return -ENODEV; } - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); - if (!adata) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); - return -ENODEV; - } - - adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!adata->acp_base) - return -ENOMEM; + chip->dev = dev; + chip->dai_driver = acp_renoir_dai; + chip->num_dai = ARRAY_SIZE(acp_renoir_dai); - ret = platform_get_irq_byname(pdev, "acp_dai_irq"); - if (ret < 0) + ret = acp_hw_en_interrupts(chip); + if (ret) { + dev_err(dev, "ACP en-interrupts failed\n"); return ret; - adata->i2s_irq = ret; - - adata->dev = dev; - adata->dai_driver = acp_renoir_dai; - adata->num_dai = ARRAY_SIZE(acp_renoir_dai); - adata->rsrc = &rsrc; - adata->acp_rev = chip->acp_rev; - adata->flag = chip->flag; - - adata->machines = snd_soc_acpi_amd_acp_machines; - acp_machine_select(adata); + } - dev_set_drvdata(dev, adata); - acp_enable_interrupts(adata); acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); @@ -206,40 +134,44 @@ static int renoir_audio_probe(struct platform_device *pdev) static void renoir_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); + int ret; + + ret = acp_hw_dis_interrupts(chip); + if (ret) + dev_err(dev, "ACP dis-interrupts failed\n"); - acp_disable_interrupts(adata); acp_platform_unregister(dev); } -static int __maybe_unused rn_pcm_resume(struct device *dev) +static int rn_pcm_resume(struct device *dev) { - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); struct acp_stream *stream; struct snd_pcm_substream *substream; snd_pcm_uframes_t buf_in_frames; u64 buf_size; - spin_lock(&adata->acp_lock); - list_for_each_entry(stream, &adata->stream_list, list) { + spin_lock(&chip->acp_lock); + list_for_each_entry(stream, &chip->stream_list, list) { substream = stream->substream; if (substream && substream->runtime) { buf_in_frames = (substream->runtime->buffer_size); buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); + config_pte_for_stream(chip, stream); + config_acp_dma(chip, stream, buf_size); if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); + restore_acp_i2s_params(substream, chip, stream); else - restore_acp_pdm_params(substream, adata); + restore_acp_pdm_params(substream, chip); } } - spin_unlock(&adata->acp_lock); + spin_unlock(&chip->acp_lock); return 0; } static const struct dev_pm_ops rn_dma_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, rn_pcm_resume) + SYSTEM_SLEEP_PM_OPS(NULL, rn_pcm_resume) }; static struct platform_driver renoir_driver = { @@ -247,7 +179,7 @@ static struct platform_driver renoir_driver = { .remove = renoir_audio_remove, .driver = { .name = "acp_asoc_renoir", - .pm = &rn_dma_pm_ops, + .pm = pm_ptr(&rn_dma_pm_ops), }, }; diff --git a/sound/soc/amd/acp/acp-sdw-legacy-mach.c b/sound/soc/amd/acp/acp-sdw-legacy-mach.c index 9280cd30d19c..2020c5cfb3d5 100644 --- a/sound/soc/amd/acp/acp-sdw-legacy-mach.c +++ b/sound/soc/amd/acp/acp-sdw-legacy-mach.c @@ -28,6 +28,8 @@ static void log_quirks(struct device *dev) SOC_JACK_JDSRC(soc_sdw_quirk)); if (soc_sdw_quirk & ASOC_SDW_ACP_DMIC) dev_dbg(dev, "quirk SOC_SDW_ACP_DMIC enabled\n"); + if (soc_sdw_quirk & ASOC_SDW_CODEC_SPKR) + dev_dbg(dev, "quirk ASOC_SDW_CODEC_SPKR enabled\n"); } static int soc_sdw_quirk_cb(const struct dmi_system_id *id) @@ -45,6 +47,38 @@ static const struct dmi_system_id soc_sdw_quirk_table[] = { }, .driver_data = (void *)RT711_JD2, }, + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D80"), + }, + .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), + }, + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D81"), + }, + .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), + }, + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D82"), + }, + .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), + }, + { + .callback = soc_sdw_quirk_cb, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"), + DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0D83"), + }, + .driver_data = (void *)(ASOC_SDW_CODEC_SPKR), + }, {} }; @@ -122,6 +156,13 @@ static int create_sdw_dailink(struct snd_soc_card *card, if (ret) return ret; break; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + ret = get_acp70_cpu_pin_id(ffs(soc_end->link_mask - 1), + *be_id, &cpu_pin_id, dev); + if (ret) + return ret; + break; default: return -EINVAL; } @@ -221,6 +262,8 @@ static int create_sdw_dailinks(struct snd_soc_card *card, switch (amd_ctx->acp_rev) { case ACP63_PCI_REV: + case ACP70_PCI_REV: + case ACP71_PCI_REV: sdw_platform_component->name = "amd_ps_sdw_dma.0"; break; default: @@ -266,6 +309,8 @@ static int create_dmic_dailinks(struct snd_soc_card *card, switch (amd_ctx->acp_rev) { case ACP63_PCI_REV: + case ACP70_PCI_REV: + case ACP71_PCI_REV: pdm_cpu->name = "acp_ps_pdm_dma.0"; pdm_platform->name = "acp_ps_pdm_dma.0"; break; diff --git a/sound/soc/amd/acp/acp-sdw-mach-common.c b/sound/soc/amd/acp/acp-sdw-mach-common.c index 6f5c39ed1a18..e5f394dc2f4c 100644 --- a/sound/soc/amd/acp/acp-sdw-mach-common.c +++ b/sound/soc/amd/acp/acp-sdw-mach-common.c @@ -59,6 +59,40 @@ int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct dev } EXPORT_SYMBOL_NS_GPL(get_acp63_cpu_pin_id, "SND_SOC_AMD_SDW_MACH"); +int get_acp70_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev) +{ + switch (sdw_link_id) { + case AMD_SDW0: + case AMD_SDW1: + switch (be_id) { + case SOC_SDW_JACK_OUT_DAI_ID: + *cpu_pin_id = ACP70_SW_AUDIO0_TX; + break; + case SOC_SDW_JACK_IN_DAI_ID: + *cpu_pin_id = ACP70_SW_AUDIO0_RX; + break; + case SOC_SDW_AMP_OUT_DAI_ID: + *cpu_pin_id = ACP70_SW_AUDIO1_TX; + break; + case SOC_SDW_AMP_IN_DAI_ID: + *cpu_pin_id = ACP70_SW_AUDIO1_RX; + break; + case SOC_SDW_DMIC_DAI_ID: + *cpu_pin_id = ACP70_SW_AUDIO2_RX; + break; + default: + dev_err(dev, "Invalid be id:%d\n", be_id); + return -EINVAL; + } + break; + default: + return -EINVAL; + } + dev_dbg(dev, "sdw_link_id:%d, be_id:%d, cpu_pin_id:%d\n", sdw_link_id, be_id, *cpu_pin_id); + return 0; +} +EXPORT_SYMBOL_NS_GPL(get_acp70_cpu_pin_id, "SND_SOC_AMD_SDW_MACH"); + MODULE_DESCRIPTION("AMD SoundWire Common Machine driver"); MODULE_AUTHOR("Vijendar Mukunda <Vijendar.Mukunda@amd.com>"); MODULE_LICENSE("GPL"); diff --git a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c index 2b0aa270a3e9..eb5d4a5baef2 100644 --- a/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c +++ b/sound/soc/amd/acp/acp3x-es83xx/acp3x-es83xx.c @@ -19,6 +19,7 @@ #include <linux/io.h> #include <linux/acpi.h> #include <linux/dmi.h> +#include <linux/string_choices.h> #include "../acp-mach.h" #include "acp3x-es83xx.h" @@ -241,9 +242,9 @@ static int acp3x_es83xx_configure_gpios(struct acp3x_es83xx_private *priv) dev_info(priv->codec_dev, "speaker gpio %d active %s, headphone gpio %d active %s\n", priv->enable_spk_gpio.crs_entry_index, - priv->enable_spk_gpio.active_low ? "low" : "high", + str_low_high(priv->enable_spk_gpio.active_low), priv->enable_hp_gpio.crs_entry_index, - priv->enable_hp_gpio.active_low ? "low" : "high"); + str_low_high(priv->enable_hp_gpio.active_low)); return 0; } diff --git a/sound/soc/amd/acp/acp63.c b/sound/soc/amd/acp/acp63.c index 81496e713440..52d895e624c7 100644 --- a/sound/soc/amd/acp/acp63.c +++ b/sound/soc/amd/acp/acp63.c @@ -20,6 +20,9 @@ #include <linux/dma-mapping.h> #include <linux/pm_runtime.h> #include <linux/pci.h> + +#include <asm/amd_node.h> + #include "amd.h" #include "acp-mach.h" #include "../mach-config.h" @@ -49,24 +52,6 @@ union clk_pll_req_no { u32 clk_pll_req_no_reg; }; -static struct acp_resource rsrc = { - .offset = 0, - .no_of_ctrls = 2, - .irqp_used = 1, - .soc_mclk = true, - .irq_reg_offset = 0x1a00, - .scratch_reg_offset = 0x12800, - .sram_pte_offset = 0x03802800, -}; - -static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[] = { - { - .id = "AMDI0052", - .drv_name = "acp63-acp", - }, - {}, -}; - static struct snd_soc_dai_driver acp63_dai[] = { { .name = "acp-i2s-sp", @@ -158,47 +143,61 @@ static struct snd_soc_dai_driver acp63_dai[] = { }, }; -static int acp63_i2s_master_clock_generate(struct acp_dev_data *adata) +static int acp63_i2s_master_clock_generate(struct acp_chip_info *chip) { + int rc; u32 data; union clk_pll_req_no clk_pll; - struct pci_dev *smn_dev; - - smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, 0x14E8, NULL); - if (!smn_dev) - return -ENODEV; /* Clk5 pll register values to get mclk as 196.6MHz*/ clk_pll.bits.fb_mult_int = 0x31; clk_pll.bits.pll_spine_div = 0; clk_pll.bits.gb_mult_frac = 0x26E9; - data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0); - smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ); - - data = smn_read(smn_dev, CLK_SPLL_FIELD_2_N0); - if (data & PLL_FRANCE_EN) - smn_write(smn_dev, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN); - - smn_write(smn_dev, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg); - - data = smn_read(smn_dev, CLK_PLL_PWR_REQ_N0); - smn_write(smn_dev, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ); - - data = smn_read(smn_dev, CLK_DFSBYPASS_CONTR); - smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0); - smn_write(smn_dev, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1); + rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data); + if (rc) + return rc; + rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_STOP_REQ); + if (rc) + return rc; + + rc = amd_smn_read(0, CLK_SPLL_FIELD_2_N0, &data); + if (rc) + return rc; + if (data & PLL_FRANCE_EN) { + rc = amd_smn_write(0, CLK_SPLL_FIELD_2_N0, data | PLL_FRANCE_EN); + if (rc) + return rc; + } - smn_write(smn_dev, CLK_DFS_CNTL_N0, CLK0_DIVIDER); - return 0; + rc = amd_smn_write(0, CLK_PLL_REQ_N0, clk_pll.clk_pll_req_no_reg); + if (rc) + return rc; + + rc = amd_smn_read(0, CLK_PLL_PWR_REQ_N0, &data); + if (rc) + return rc; + rc = amd_smn_write(0, CLK_PLL_PWR_REQ_N0, data | PLL_AUTO_START_REQ); + if (rc) + return rc; + + rc = amd_smn_read(0, CLK_DFSBYPASS_CONTR, &data); + if (rc) + return rc; + rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_0); + if (rc) + return rc; + rc = amd_smn_write(0, CLK_DFSBYPASS_CONTR, data | EXIT_DPF_BYPASS_1); + if (rc) + return rc; + + return amd_smn_write(0, CLK_DFS_CNTL_N0, CLK0_DIVIDER); } static int acp63_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; - struct acp_dev_data *adata; - struct resource *res; int ret; chip = dev_get_platdata(&pdev->dev); @@ -212,44 +211,20 @@ static int acp63_audio_probe(struct platform_device *pdev) return -ENODEV; } - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); - if (!adata) - return -ENOMEM; + chip->dev = dev; + chip->dai_driver = acp63_dai; + chip->num_dai = ARRAY_SIZE(acp63_dai); - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); - return -ENODEV; - } - - adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!adata->acp_base) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); - return -ENODEV; - } - - adata->i2s_irq = res->start; - adata->dev = dev; - adata->dai_driver = acp63_dai; - adata->num_dai = ARRAY_SIZE(acp63_dai); - adata->rsrc = &rsrc; - adata->acp_rev = chip->acp_rev; - adata->flag = chip->flag; - adata->is_i2s_config = chip->is_i2s_config; - adata->machines = snd_soc_acpi_amd_acp63_acp_machines; - acp_machine_select(adata); - dev_set_drvdata(dev, adata); - - if (chip->is_i2s_config && rsrc.soc_mclk) { - ret = acp63_i2s_master_clock_generate(adata); + if (chip->is_i2s_config && chip->rsrc->soc_mclk) { + ret = acp63_i2s_master_clock_generate(chip); if (ret) return ret; } - acp_enable_interrupts(adata); + ret = acp_hw_en_interrupts(chip); + if (ret) { + dev_err(dev, "ACP en-interrupts failed\n"); + return ret; + } acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); @@ -262,44 +237,48 @@ static int acp63_audio_probe(struct platform_device *pdev) static void acp63_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); + int ret; + + ret = acp_hw_dis_interrupts(chip); + if (ret) + dev_err(dev, "ACP dis-interrupts failed\n"); - acp_disable_interrupts(adata); acp_platform_unregister(dev); pm_runtime_disable(&pdev->dev); } -static int __maybe_unused acp63_pcm_resume(struct device *dev) +static int acp63_pcm_resume(struct device *dev) { - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); struct acp_stream *stream; struct snd_pcm_substream *substream; snd_pcm_uframes_t buf_in_frames; u64 buf_size; - if (adata->is_i2s_config && adata->rsrc->soc_mclk) - acp63_i2s_master_clock_generate(adata); + if (chip->is_i2s_config && chip->rsrc->soc_mclk) + acp63_i2s_master_clock_generate(chip); - spin_lock(&adata->acp_lock); - list_for_each_entry(stream, &adata->stream_list, list) { + spin_lock(&chip->acp_lock); + list_for_each_entry(stream, &chip->stream_list, list) { substream = stream->substream; if (substream && substream->runtime) { buf_in_frames = (substream->runtime->buffer_size); buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); + config_pte_for_stream(chip, stream); + config_acp_dma(chip, stream, buf_size); if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); + restore_acp_i2s_params(substream, chip, stream); else - restore_acp_pdm_params(substream, adata); + restore_acp_pdm_params(substream, chip); } } - spin_unlock(&adata->acp_lock); + spin_unlock(&chip->acp_lock); return 0; } static const struct dev_pm_ops acp63_dma_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume) + SYSTEM_SLEEP_PM_OPS(NULL, acp63_pcm_resume) }; static struct platform_driver acp63_driver = { @@ -307,7 +286,7 @@ static struct platform_driver acp63_driver = { .remove = acp63_audio_remove, .driver = { .name = "acp_asoc_acp63", - .pm = &acp63_dma_pm_ops, + .pm = pm_ptr(&acp63_dma_pm_ops), }, }; diff --git a/sound/soc/amd/acp/acp70.c b/sound/soc/amd/acp/acp70.c index 9e23729fd1a7..6d5f5ade075c 100644 --- a/sound/soc/amd/acp/acp70.c +++ b/sound/soc/amd/acp/acp70.c @@ -23,29 +23,13 @@ #include "amd.h" #include "acp-mach.h" +#include <asm/amd_node.h> + #define DRV_NAME "acp_asoc_acp70" #define CLK7_CLK0_DFS_CNTL_N1 0X0006C1A4 #define CLK0_DIVIDER 0X19 -static struct acp_resource rsrc = { - .offset = 0, - .no_of_ctrls = 2, - .irqp_used = 1, - .soc_mclk = true, - .irq_reg_offset = 0x1a00, - .scratch_reg_offset = 0x10000, - .sram_pte_offset = 0x03800000, -}; - -static struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[] = { - { - .id = "AMDI0029", - .drv_name = "acp70-acp", - }, - {}, -}; - static struct snd_soc_dai_driver acp70_dai[] = { { .name = "acp-i2s-sp", @@ -137,35 +121,10 @@ static struct snd_soc_dai_driver acp70_dai[] = { }, }; -static int acp70_i2s_master_clock_generate(struct acp_dev_data *adata) -{ - struct pci_dev *smn_dev; - u32 device_id; - - if (adata->acp_rev == ACP70_PCI_ID) - device_id = 0x1507; - else if (adata->acp_rev == ACP71_PCI_ID) - device_id = 0x1122; - else - return -ENODEV; - - smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, device_id, NULL); - - if (!smn_dev) - return -ENODEV; - - /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/ - smn_write(smn_dev, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER); - - return 0; -} - static int acp_acp70_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct acp_chip_info *chip; - struct acp_dev_data *adata; - struct resource *res; int ret; chip = dev_get_platdata(&pdev->dev); @@ -183,44 +142,21 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) return -ENODEV; } - adata = devm_kzalloc(dev, sizeof(struct acp_dev_data), GFP_KERNEL); - if (!adata) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acp_mem"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_MEM FAILED\n"); - return -ENODEV; - } - - adata->acp_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!adata->acp_base) - return -ENOMEM; - - res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "acp_dai_irq"); - if (!res) { - dev_err(&pdev->dev, "IORESOURCE_IRQ FAILED\n"); - return -ENODEV; - } - - adata->i2s_irq = res->start; - adata->dev = dev; - adata->dai_driver = acp70_dai; - adata->num_dai = ARRAY_SIZE(acp70_dai); - adata->rsrc = &rsrc; - adata->machines = snd_soc_acpi_amd_acp70_acp_machines; - adata->acp_rev = chip->acp_rev; - adata->flag = chip->flag; - acp_machine_select(adata); - - dev_set_drvdata(dev, adata); + chip->dev = dev; + chip->dai_driver = acp70_dai; + chip->num_dai = ARRAY_SIZE(acp70_dai); - ret = acp70_i2s_master_clock_generate(adata); + /* Set clk7 DFS clock divider register value to get mclk as 196.608MHz*/ + ret = amd_smn_write(0, CLK7_CLK0_DFS_CNTL_N1, CLK0_DIVIDER); if (ret) { dev_err(&pdev->dev, "Failed to set I2S master clock as 196.608MHz\n"); return ret; } - acp_enable_interrupts(adata); + ret = acp_hw_en_interrupts(chip); + if (ret) { + dev_err(dev, "ACP en-interrupts failed\n"); + return ret; + } acp_platform_register(dev); pm_runtime_set_autosuspend_delay(&pdev->dev, ACP_SUSPEND_DELAY_MS); pm_runtime_use_autosuspend(&pdev->dev); @@ -233,43 +169,45 @@ static int acp_acp70_audio_probe(struct platform_device *pdev) static void acp_acp70_audio_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); + int ret; + + ret = acp_hw_dis_interrupts(chip); + if (ret) + dev_err(dev, "ACP dis-interrupts failed\n"); - acp_disable_interrupts(adata); acp_platform_unregister(dev); pm_runtime_disable(&pdev->dev); } -static int __maybe_unused acp70_pcm_resume(struct device *dev) +static int acp70_pcm_resume(struct device *dev) { - struct acp_dev_data *adata = dev_get_drvdata(dev); + struct acp_chip_info *chip = dev_get_platdata(dev); struct acp_stream *stream; struct snd_pcm_substream *substream; snd_pcm_uframes_t buf_in_frames; u64 buf_size; - spin_lock(&adata->acp_lock); - list_for_each_entry(stream, &adata->stream_list, list) { - if (stream) { - substream = stream->substream; - if (substream && substream->runtime) { - buf_in_frames = (substream->runtime->buffer_size); - buf_size = frames_to_bytes(substream->runtime, buf_in_frames); - config_pte_for_stream(adata, stream); - config_acp_dma(adata, stream, buf_size); - if (stream->dai_id) - restore_acp_i2s_params(substream, adata, stream); - else - restore_acp_pdm_params(substream, adata); - } + spin_lock(&chip->acp_lock); + list_for_each_entry(stream, &chip->stream_list, list) { + substream = stream->substream; + if (substream && substream->runtime) { + buf_in_frames = (substream->runtime->buffer_size); + buf_size = frames_to_bytes(substream->runtime, buf_in_frames); + config_pte_for_stream(chip, stream); + config_acp_dma(chip, stream, buf_size); + if (stream->dai_id) + restore_acp_i2s_params(substream, chip, stream); + else + restore_acp_pdm_params(substream, chip); } } - spin_unlock(&adata->acp_lock); + spin_unlock(&chip->acp_lock); return 0; } static const struct dev_pm_ops acp70_dma_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, acp70_pcm_resume) + SYSTEM_SLEEP_PM_OPS(NULL, acp70_pcm_resume) }; static struct platform_driver acp70_driver = { @@ -277,7 +215,7 @@ static struct platform_driver acp70_driver = { .remove = acp_acp70_audio_remove, .driver = { .name = "acp_asoc_acp70", - .pm = &acp70_dma_pm_ops, + .pm = pm_ptr(&acp70_dma_pm_ops), }, }; diff --git a/sound/soc/amd/acp/amd-acp70-acpi-match.c b/sound/soc/amd/acp/amd-acp70-acpi-match.c new file mode 100644 index 000000000000..e87ccfeee5bd --- /dev/null +++ b/sound/soc/amd/acp/amd-acp70-acpi-match.c @@ -0,0 +1,160 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * amd-acp70-acpi-match.c - tables and support for ACP 7.0 & ACP7.1 + * ACPI enumeration. + * + * Copyright 2025 Advanced Micro Devices, Inc. + */ + +#include <sound/soc-acpi.h> +#include "../mach-config.h" + +static const struct snd_soc_acpi_endpoint single_endpoint = { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0 +}; + +static const struct snd_soc_acpi_endpoint spk_l_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 0, + .group_id = 1 +}; + +static const struct snd_soc_acpi_endpoint spk_r_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1 +}; + +static const struct snd_soc_acpi_adr_device rt711_rt1316_group_adr[] = { + { + .adr = 0x000030025D071101ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt711" + }, + { + .adr = 0x000030025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_l_endpoint, + .name_prefix = "rt1316-1" + }, + { + .adr = 0x000032025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + }, +}; + +static const struct snd_soc_acpi_adr_device rt714_adr[] = { + { + .adr = 0x130025d071401ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt714" + } +}; + +static const struct snd_soc_acpi_link_adr acp70_4_in_1_sdca[] = { + { .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt711_rt1316_group_adr), + .adr_d = rt711_rt1316_group_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt714_adr), + .adr_d = rt714_adr, + }, + {} +}; + +static const struct snd_soc_acpi_endpoint rt722_endpoints[] = { + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device rt722_0_single_adr[] = { + { + .adr = 0x000030025d072201ull, + .num_endpoints = ARRAY_SIZE(rt722_endpoints), + .endpoints = rt722_endpoints, + .name_prefix = "rt722" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_1_single_adr[] = { + { + .adr = 0x000130025D132001ull, + .num_endpoints = 1, + .endpoints = &single_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_link_adr acp70_rt722_only[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr acp70_rt722_l0_rt1320_l1[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt722_0_single_adr), + .adr_d = rt722_0_single_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_single_adr), + .adr_d = rt1320_1_single_adr, + }, + {} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[] = { + { + .link_mask = BIT(0) | BIT(1), + .links = acp70_rt722_l0_rt1320_l1, + .drv_name = "amd_sdw", + }, + { + .link_mask = BIT(0), + .links = acp70_rt722_only, + .drv_name = "amd_sdw", + }, + { + .link_mask = BIT(0) | BIT(1), + .links = acp70_4_in_1_sdca, + .drv_name = "amd_sdw", + }, + {}, +}; +EXPORT_SYMBOL(snd_soc_acpi_amd_acp70_sdw_machines); + +MODULE_DESCRIPTION("AMD ACP7.0 & ACP7.1 tables and support for ACPI enumeration"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); diff --git a/sound/soc/amd/acp/amd-acpi-mach.c b/sound/soc/amd/acp/amd-acpi-mach.c new file mode 100644 index 000000000000..d95047d2ee94 --- /dev/null +++ b/sound/soc/amd/acp/amd-acpi-mach.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * amd-acpi-match.c - tables and support for ACP platforms + * ACPI enumeration. + * + * Copyright 2025 Advanced Micro Devices, Inc. + */ + +#include <sound/soc-acpi.h> + +struct snd_soc_acpi_codecs amp_rt1019 = { + .num_codecs = 1, + .codecs = {"10EC1019"} +}; + +struct snd_soc_acpi_codecs amp_max = { + .num_codecs = 1, + .codecs = {"MX98360A"} +}; + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines[] = { + { + .id = "10EC5682", + .drv_name = "acp3xalc56821019", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + }, + { + .id = "RTL5682", + .drv_name = "acp3xalc5682sm98360", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + }, + { + .id = "RTL5682", + .drv_name = "acp3xalc5682s1019", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + }, + { + .id = "AMDI1019", + .drv_name = "renoir-acp", + }, + { + .id = "ESSX8336", + .drv_name = "acp3x-es83xx", + }, + {}, +}; +EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_acp_machines, "SND_SOC_ACP_COMMON"); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines[] = { + { + .id = "10508825", + .drv_name = "rmb-nau8825-max", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_max, + }, + { + .id = "AMDI0007", + .drv_name = "rembrandt-acp", + }, + { + .id = "RTL5682", + .drv_name = "rmb-rt5682s-rt1019", + .machine_quirk = snd_soc_acpi_codec_list, + .quirk_data = &_rt1019, + }, + {}, +}; +EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_rmb_acp_machines, "SND_SOC_ACP_COMMON"); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines[] = { + { + .id = "AMDI0052", + .drv_name = "acp63-acp", + }, + {}, +}; +EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_acp63_acp_machines, "SND_SOC_ACP_COMMON"); + +struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines[] = { + { + .id = "AMDI0029", + .drv_name = "acp70-acp", + }, + {}, +}; +EXPORT_SYMBOL_NS_GPL(snd_soc_acpi_amd_acp70_acp_machines, "SND_SOC_ACP_COMMON"); + +MODULE_DESCRIPTION("AMD ACP tables and support for ACPI enumeration"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Venkataprasad.potturu@amd.com"); diff --git a/sound/soc/amd/acp/amd.h b/sound/soc/amd/acp/amd.h index ee69dfb10cb8..863e74fcee43 100644 --- a/sound/soc/amd/acp/amd.h +++ b/sound/soc/amd/acp/amd.h @@ -140,13 +140,36 @@ struct acp_chip_info { char *name; /* Platform name */ + struct resource *res; + struct device *dev; + struct snd_soc_dai_driver *dai_driver; + unsigned int acp_rev; /* ACP Revision id */ void __iomem *base; /* ACP memory PCI base */ + struct snd_acp_hw_ops *acp_hw_ops; + int (*acp_hw_ops_init)(struct acp_chip_info *chip); struct platform_device *chip_pdev; + struct acp_resource *rsrc; /* Platform specific resources*/ + struct list_head stream_list; + spinlock_t acp_lock; /* Used to protect stream_list */ + struct platform_device *dmic_codec_dev; + struct platform_device *acp_plat_dev; + struct platform_device *mach_dev; + struct snd_soc_acpi_mach *machines; + int num_dai; + u32 addr; + u32 bclk_div; + u32 lrclk_div; + u32 ch_mask; + u32 tdm_tx_fmt[3]; + u32 tdm_rx_fmt[3]; + u32 xfer_tx_resolution[3]; + u32 xfer_rx_resolution[3]; unsigned int flag; /* Distinguish b/w Legacy or Only PDM */ bool is_pdm_dev; /* flag set to true when ACP PDM controller exists */ bool is_pdm_config; /* flag set to true when PDM configuration is selected from BIOS */ bool is_i2s_config; /* flag set to true when I2S configuration is selected from BIOS */ + bool tdm_mode; }; struct acp_stream { @@ -172,35 +195,23 @@ struct acp_resource { u64 sram_pte_offset; }; -struct acp_dev_data { - char *name; - struct device *dev; - void __iomem *acp_base; - unsigned int i2s_irq; - unsigned int acp_rev; /* ACP Revision id */ - - bool tdm_mode; - bool is_i2s_config; - /* SOC specific dais */ - struct snd_soc_dai_driver *dai_driver; - int num_dai; - - struct list_head stream_list; - spinlock_t acp_lock; - - struct snd_soc_acpi_mach *machines; - struct platform_device *mach_dev; - - u32 bclk_div; - u32 lrclk_div; - - struct acp_resource *rsrc; - u32 ch_mask; - u32 tdm_tx_fmt[3]; - u32 tdm_rx_fmt[3]; - u32 xfer_tx_resolution[3]; - u32 xfer_rx_resolution[3]; - unsigned int flag; +/** + * struct snd_acp_hw_ops - ACP PCI driver platform specific ops + * @acp_init: ACP initialization + * @acp_deinit: ACP de-initialization + * @irq: ACP irq handler + * @en_interrupts: ACP enable interrupts + * @dis_interrupts: ACP disable interrupts + */ +struct snd_acp_hw_ops { + /* ACP hardware initilizations */ + int (*acp_init)(struct acp_chip_info *chip); + int (*acp_deinit)(struct acp_chip_info *chip); + + /* ACP Interrupts*/ + irqreturn_t (*irq)(int irq, void *data); + int (*en_interrupts)(struct acp_chip_info *chip); + int (*dis_interrupts)(struct acp_chip_info *chip); }; enum acp_config { @@ -227,76 +238,121 @@ enum acp_config { ACP_CONFIG_20, }; +extern struct acp_resource rn_rsrc; +extern struct acp_resource rmb_rsrc; +extern struct acp_resource acp63_rsrc; +extern struct acp_resource acp70_rsrc; + +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp_machines; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_rmb_acp_machines; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_acp_machines; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_acp_machines; + extern const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops; extern const struct snd_soc_dai_ops acp_dmic_dai_ops; int acp_platform_register(struct device *dev); int acp_platform_unregister(struct device *dev); -int acp_machine_select(struct acp_dev_data *adata); - -int smn_read(struct pci_dev *dev, u32 smn_addr); -int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data); +int acp_machine_select(struct acp_chip_info *chip); int acp_init(struct acp_chip_info *chip); int acp_deinit(struct acp_chip_info *chip); -void acp_enable_interrupts(struct acp_dev_data *adata); -void acp_disable_interrupts(struct acp_dev_data *adata); +int acp_enable_interrupts(struct acp_chip_info *chip); +int acp_disable_interrupts(struct acp_chip_info *chip); +irqreturn_t acp_irq_handler(int irq, void *data); + +extern struct snd_acp_hw_ops acp31_common_hw_ops; +extern struct snd_acp_hw_ops acp6x_common_hw_ops; +extern struct snd_acp_hw_ops acp63_common_hw_ops; +extern struct snd_acp_hw_ops acp70_common_hw_ops; +extern int acp31_hw_ops_init(struct acp_chip_info *chip); +extern int acp6x_hw_ops_init(struct acp_chip_info *chip); +extern int acp63_hw_ops_init(struct acp_chip_info *chip); +extern int acp70_hw_ops_init(struct acp_chip_info *chip); /* Machine configuration */ int snd_amd_acp_find_config(struct pci_dev *pci); -void config_pte_for_stream(struct acp_dev_data *adata, struct acp_stream *stream); -void config_acp_dma(struct acp_dev_data *adata, struct acp_stream *stream, int size); +void config_pte_for_stream(struct acp_chip_info *chip, struct acp_stream *stream); +void config_acp_dma(struct acp_chip_info *chip, struct acp_stream *stream, int size); void restore_acp_pdm_params(struct snd_pcm_substream *substream, - struct acp_dev_data *adata); + struct acp_chip_info *chip); int restore_acp_i2s_params(struct snd_pcm_substream *substream, - struct acp_dev_data *adata, struct acp_stream *stream); + struct acp_chip_info *chip, struct acp_stream *stream); void check_acp_config(struct pci_dev *pci, struct acp_chip_info *chip); -static inline u64 acp_get_byte_count(struct acp_dev_data *adata, int dai_id, int direction) +static inline int acp_hw_init(struct acp_chip_info *chip) +{ + if (chip && chip->acp_hw_ops && chip->acp_hw_ops->acp_init) + return chip->acp_hw_ops->acp_init(chip); + return -EOPNOTSUPP; +} + +static inline int acp_hw_deinit(struct acp_chip_info *chip) +{ + if (chip && chip->acp_hw_ops && chip->acp_hw_ops->acp_deinit) + return chip->acp_hw_ops->acp_deinit(chip); + return -EOPNOTSUPP; +} + +static inline int acp_hw_en_interrupts(struct acp_chip_info *chip) +{ + if (chip && chip->acp_hw_ops && chip->acp_hw_ops->en_interrupts) + return chip->acp_hw_ops->en_interrupts(chip); + return -EOPNOTSUPP; +} + +static inline int acp_hw_dis_interrupts(struct acp_chip_info *chip) +{ + if (chip && chip->acp_hw_ops && chip->acp_hw_ops->dis_interrupts) + chip->acp_hw_ops->dis_interrupts(chip); + return -EOPNOTSUPP; +} + +static inline u64 acp_get_byte_count(struct acp_chip_info *chip, int dai_id, int direction) { u64 byte_count = 0, low = 0, high = 0; if (direction == SNDRV_PCM_STREAM_PLAYBACK) { switch (dai_id) { case I2S_BT_INSTANCE: - high = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(adata)); - low = readl(adata->acp_base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW(adata)); + high = readl(chip->base + ACP_BT_TX_LINEARPOSITIONCNTR_HIGH(chip)); + low = readl(chip->base + ACP_BT_TX_LINEARPOSITIONCNTR_LOW(chip)); break; case I2S_SP_INSTANCE: - high = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(adata)); - low = readl(adata->acp_base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(adata)); + high = readl(chip->base + ACP_I2S_TX_LINEARPOSITIONCNTR_HIGH(chip)); + low = readl(chip->base + ACP_I2S_TX_LINEARPOSITIONCNTR_LOW(chip)); break; case I2S_HS_INSTANCE: - high = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW); + high = readl(chip->base + ACP_HS_TX_LINEARPOSITIONCNTR_HIGH); + low = readl(chip->base + ACP_HS_TX_LINEARPOSITIONCNTR_LOW); break; default: - dev_err(adata->dev, "Invalid dai id %x\n", dai_id); + dev_err(chip->dev, "Invalid dai id %x\n", dai_id); goto POINTER_RETURN_BYTES; } } else { switch (dai_id) { case I2S_BT_INSTANCE: - high = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(adata)); - low = readl(adata->acp_base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW(adata)); + high = readl(chip->base + ACP_BT_RX_LINEARPOSITIONCNTR_HIGH(chip)); + low = readl(chip->base + ACP_BT_RX_LINEARPOSITIONCNTR_LOW(chip)); break; case I2S_SP_INSTANCE: - high = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(adata)); - low = readl(adata->acp_base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(adata)); + high = readl(chip->base + ACP_I2S_RX_LINEARPOSITIONCNTR_HIGH(chip)); + low = readl(chip->base + ACP_I2S_RX_LINEARPOSITIONCNTR_LOW(chip)); break; case I2S_HS_INSTANCE: - high = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW); + high = readl(chip->base + ACP_HS_RX_LINEARPOSITIONCNTR_HIGH); + low = readl(chip->base + ACP_HS_RX_LINEARPOSITIONCNTR_LOW); break; case DMIC_INSTANCE: - high = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); - low = readl(adata->acp_base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); + high = readl(chip->base + ACP_WOV_RX_LINEARPOSITIONCNTR_HIGH); + low = readl(chip->base + ACP_WOV_RX_LINEARPOSITIONCNTR_LOW); break; default: - dev_err(adata->dev, "Invalid dai id %x\n", dai_id); + dev_err(chip->dev, "Invalid dai id %x\n", dai_id); goto POINTER_RETURN_BYTES; } } diff --git a/sound/soc/amd/acp/chip_offset_byte.h b/sound/soc/amd/acp/chip_offset_byte.h index 117ea63e85c6..82275c9de53a 100644 --- a/sound/soc/amd/acp/chip_offset_byte.h +++ b/sound/soc/amd/acp/chip_offset_byte.h @@ -29,13 +29,13 @@ #define ACP_PIN_CONFIG 0x1440 #define ACP3X_PIN_CONFIG 0x1400 -#define ACP_EXTERNAL_INTR_REG_ADDR(adata, offset, ctrl) \ - (adata->acp_base + adata->rsrc->irq_reg_offset + offset + (ctrl * 0x04)) +#define ACP_EXTERNAL_INTR_REG_ADDR(chip, offset, ctrl) \ + (chip->base + chip->rsrc->irq_reg_offset + offset + (ctrl * 0x04)) -#define ACP_EXTERNAL_INTR_ENB(adata) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x0, 0x0) -#define ACP_EXTERNAL_INTR_CNTL(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, 0x4, ctrl) -#define ACP_EXTERNAL_INTR_STAT(adata, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(adata, \ - (0x4 + (adata->rsrc->no_of_ctrls * 0x04)), ctrl) +#define ACP_EXTERNAL_INTR_ENB(chip) ACP_EXTERNAL_INTR_REG_ADDR(chip, 0x0, 0x0) +#define ACP_EXTERNAL_INTR_CNTL(chip, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(chip, 0x4, ctrl) +#define ACP_EXTERNAL_INTR_STAT(chip, ctrl) ACP_EXTERNAL_INTR_REG_ADDR(chip, \ + (0x4 + (chip->rsrc->no_of_ctrls * 0x04)), ctrl) /* Registers from ACP_AUDIO_BUFFERS block */ diff --git a/sound/soc/amd/acp/soc_amd_sdw_common.h b/sound/soc/amd/acp/soc_amd_sdw_common.h index b7bae107c13e..1f24e0e06487 100644 --- a/sound/soc/amd/acp/soc_amd_sdw_common.h +++ b/sound/soc/amd/acp/soc_amd_sdw_common.h @@ -19,9 +19,12 @@ #define AMD_SDW_MAX_GROUPS 9 #define ACP63_PCI_REV 0x63 +#define ACP70_PCI_REV 0x70 +#define ACP71_PCI_REV 0x71 #define SOC_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0)) #define ASOC_SDW_FOUR_SPK BIT(4) #define ASOC_SDW_ACP_DMIC BIT(5) +#define ASOC_SDW_CODEC_SPKR BIT(15) #define AMD_SDW0 0 #define AMD_SDW1 1 @@ -38,11 +41,20 @@ #define ACP_DMIC_BE_ID 4 +#define ACP70_SW_AUDIO0_TX 0 +#define ACP70_SW_AUDIO1_TX 1 +#define ACP70_SW_AUDIO2_TX 2 + +#define ACP70_SW_AUDIO0_RX 3 +#define ACP70_SW_AUDIO1_RX 4 +#define ACP70_SW_AUDIO2_RX 5 + struct amd_mc_ctx { unsigned int acp_rev; unsigned int max_sdw_links; }; int get_acp63_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev); +int get_acp70_cpu_pin_id(u32 sdw_link_id, int be_id, int *cpu_pin_id, struct device *dev); #endif diff --git a/sound/soc/amd/mach-config.h b/sound/soc/amd/mach-config.h index a86c76f781f9..fdf016a64bbf 100644 --- a/sound/soc/amd/mach-config.h +++ b/sound/soc/amd/mach-config.h @@ -26,6 +26,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp63_sof_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sof_machines[]; +extern struct snd_soc_acpi_mach snd_soc_acpi_amd_acp70_sdw_machines[]; struct config_entry { u32 flags; diff --git a/sound/soc/amd/ps/Makefile b/sound/soc/amd/ps/Makefile index b5efb1c5382c..778ee4726389 100644 --- a/sound/soc/amd/ps/Makefile +++ b/sound/soc/amd/ps/Makefile @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only # Pink Sardine platform Support -snd-pci-ps-y := pci-ps.o +snd-pci-ps-y := pci-ps.o ps-common.o snd-ps-pdm-dma-y := ps-pdm-dma.o snd-soc-ps-mach-y := ps-mach.o snd-ps-sdw-dma-y := ps-sdw-dma.o diff --git a/sound/soc/amd/ps/acp63.h b/sound/soc/amd/ps/acp63.h index e54eabaa4d3e..85feae45c44c 100644 --- a/sound/soc/amd/ps/acp63.h +++ b/sound/soc/amd/ps/acp63.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0+ */ /* - * AMD ALSA SoC PDM Driver + * AMD Common ACP header file for ACP6.3, ACP7.0 & ACP7.1 platforms * - * Copyright (C) 2022, 2023 Advanced Micro Devices, Inc. All rights reserved. + * Copyright (C) 2022, 2023, 2025 Advanced Micro Devices, Inc. All rights reserved. */ #include <linux/soundwire/sdw_amd.h> @@ -11,15 +11,18 @@ #define ACP_DEVICE_ID 0x15E2 #define ACP63_REG_START 0x1240000 #define ACP63_REG_END 0x125C000 +#define ACP63_PCI_REV 0x63 +#define ACP70_PCI_REV 0x70 +#define ACP71_PCI_REV 0x71 #define ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK 0x00010001 -#define ACP_PGFSM_CNTL_POWER_ON_MASK 1 -#define ACP_PGFSM_CNTL_POWER_OFF_MASK 0 -#define ACP_PGFSM_STATUS_MASK 3 -#define ACP_POWERED_ON 0 -#define ACP_POWER_ON_IN_PROGRESS 1 -#define ACP_POWERED_OFF 2 -#define ACP_POWER_OFF_IN_PROGRESS 3 +#define ACP63_PGFSM_CNTL_POWER_ON_MASK 1 +#define ACP63_PGFSM_CNTL_POWER_OFF_MASK 0 +#define ACP63_PGFSM_STATUS_MASK 3 +#define ACP63_POWERED_ON 0 +#define ACP63_POWER_ON_IN_PROGRESS 1 +#define ACP63_POWERED_OFF 2 +#define ACP63_POWER_OFF_IN_PROGRESS 3 #define ACP_ERROR_MASK 0x20000000 #define ACP_EXT_INTR_STAT_CLEAR_MASK 0xFFFFFFFF @@ -60,7 +63,7 @@ #define AMD_SDW_MAX_MANAGERS 2 /* time in ms for acp timeout */ -#define ACP_TIMEOUT 500 +#define ACP63_TIMEOUT 500 #define ACP_SDW0_STAT BIT(21) #define ACP_SDW1_STAT BIT(2) @@ -72,13 +75,13 @@ #define ACP_AUDIO0_RX_THRESHOLD 0x1b #define ACP_AUDIO1_RX_THRESHOLD 0x19 #define ACP_AUDIO2_RX_THRESHOLD 0x17 -#define ACP_P1_AUDIO1_TX_THRESHOLD BIT(6) -#define ACP_P1_AUDIO1_RX_THRESHOLD BIT(5) -#define ACP_SDW_DMA_IRQ_MASK 0x1F800000 -#define ACP_P1_SDW_DMA_IRQ_MASK 0x60 +#define ACP63_P1_AUDIO1_TX_THRESHOLD BIT(6) +#define ACP63_P1_AUDIO1_RX_THRESHOLD BIT(5) +#define ACP63_SDW_DMA_IRQ_MASK 0x1F800000 +#define ACP63_P1_SDW_DMA_IRQ_MASK 0x60 #define ACP63_SDW0_DMA_MAX_STREAMS 6 #define ACP63_SDW1_DMA_MAX_STREAMS 2 -#define ACP_P1_AUDIO_TX_THRESHOLD 6 +#define ACP63_P1_AUDIO_TX_THRESHOLD 6 /* * Below entries describes SDW0 instance DMA stream id and DMA irq bit mapping @@ -91,8 +94,8 @@ * 4 (SDW0_AUDIO1_RX) 25 * 5 (SDW0_AUDIO2_RX) 23 */ -#define SDW0_DMA_TX_IRQ_MASK(i) (ACP_AUDIO0_TX_THRESHOLD - (2 * (i))) -#define SDW0_DMA_RX_IRQ_MASK(i) (ACP_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3))) +#define ACP63_SDW0_DMA_TX_IRQ_MASK(i) (ACP_AUDIO0_TX_THRESHOLD - (2 * (i))) +#define ACP63_SDW0_DMA_RX_IRQ_MASK(i) (ACP_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3))) /* * Below entries describes SDW1 instance DMA stream id and DMA irq bit mapping @@ -101,7 +104,7 @@ * 0 (SDW1_AUDIO1_TX) 6 * 1 (SDW1_AUDIO1_RX) 5 */ -#define SDW1_DMA_IRQ_MASK(i) (ACP_P1_AUDIO_TX_THRESHOLD - (i)) +#define ACP63_SDW1_DMA_IRQ_MASK(i) (ACP63_P1_AUDIO_TX_THRESHOLD - (i)) #define ACP_DELAY_US 5 #define ACP_SDW_RING_BUFF_ADDR_OFFSET (128 * 1024) @@ -129,6 +132,61 @@ #define SDW_MAX_BUFFER (SDW_PLAYBACK_MAX_PERIOD_SIZE * SDW_PLAYBACK_MAX_NUM_PERIODS) #define SDW_MIN_BUFFER SDW_MAX_BUFFER +#define ACP_HW_OPS(acp_data, cb) ((acp_data)->hw_ops->cb) + +#define ACP70_PGFSM_CNTL_POWER_ON_MASK 0x1F +#define ACP70_PGFSM_CNTL_POWER_OFF_MASK 0 +#define ACP70_PGFSM_STATUS_MASK 0xFF +#define ACP70_TIMEOUT 2000 +#define ACP70_SDW_HOST_WAKE_MASK 0x0C00000 +#define ACP70_SDW0_HOST_WAKE_STAT BIT(24) +#define ACP70_SDW1_HOST_WAKE_STAT BIT(25) +#define ACP70_SDW0_PME_STAT BIT(26) +#define ACP70_SDW1_PME_STAT BIT(27) + +#define ACP70_SDW0_DMA_MAX_STREAMS 6 +#define ACP70_SDW1_DMA_MAX_STREAMS ACP70_SDW0_DMA_MAX_STREAMS +#define ACP70_SDW_DMA_IRQ_MASK 0x1F800000 +#define ACP70_P1_SDW_DMA_IRQ_MASK 0x1F8 + +#define ACP70_P1_AUDIO0_TX_THRESHOLD 0x8 +#define ACP70_P1_AUDIO1_TX_THRESHOLD 0x6 +#define ACP70_P1_AUDIO2_TX_THRESHOLD 0x4 +#define ACP70_P1_AUDIO0_RX_THRESHOLD 0x7 +#define ACP70_P1_AUDIO1_RX_THRESHOLD 0x5 +#define ACP70_P1_AUDIO2_RX_THRESHOLD 0x3 + +#define ACP70_SDW0_DMA_TX_IRQ_MASK(i) (ACP_AUDIO0_TX_THRESHOLD - (2 * (i))) +#define ACP70_SDW0_DMA_RX_IRQ_MASK(i) (ACP_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3))) + +/* + * Below entries describes SDW1 instance DMA stream id and DMA irq bit mapping + * in ACP_EXTENAL_INTR_CNTL1 register for ACP70/ACP71 platforms + * Stream id IRQ Bit + * 0 (SDW1_AUDIO0_TX) 8 + * 1 (SDW1_AUDIO1_TX) 6 + * 2 (SDW1_AUDIO2_TX) 4 + * 3 (SDW1_AUDIO0_RX) 7 + * 4 (SDW1_AUDIO1_RX) 5 + * 5 (SDW1_AUDIO2_RX) 3 + */ +#define ACP70_SDW1_DMA_TX_IRQ_MASK(i) (ACP70_P1_AUDIO0_TX_THRESHOLD - (2 * (i))) +#define ACP70_SDW1_DMA_RX_IRQ_MASK(i) (ACP70_P1_AUDIO0_RX_THRESHOLD - (2 * ((i) - 3))) + +#define ACP70_SW0_AUDIO0_TX_EN ACP_SW0_AUDIO0_TX_EN +#define ACP70_SW0_AUDIO1_TX_EN ACP_SW0_AUDIO1_TX_EN +#define ACP70_SW0_AUDIO2_TX_EN ACP_SW0_AUDIO2_TX_EN +#define ACP70_SW0_AUDIO0_RX_EN ACP_SW0_AUDIO0_RX_EN +#define ACP70_SW0_AUDIO1_RX_EN ACP_SW0_AUDIO1_RX_EN +#define ACP70_SW0_AUDIO2_RX_EN ACP_SW0_AUDIO2_RX_EN + +#define ACP70_SW1_AUDIO0_TX_EN 0x0003C10 +#define ACP70_SW1_AUDIO1_TX_EN 0x0003C50 +#define ACP70_SW1_AUDIO2_TX_EN 0x0003C6C +#define ACP70_SW1_AUDIO0_RX_EN 0x0003C88 +#define ACP70_SW1_AUDIO1_RX_EN 0x0003D28 +#define ACP70_SW1_AUDIO2_RX_EN 0x0003D44 + enum acp_config { ACP_CONFIG_0 = 0, ACP_CONFIG_1, @@ -146,20 +204,34 @@ enum acp_config { ACP_CONFIG_13, ACP_CONFIG_14, ACP_CONFIG_15, + ACP_CONFIG_16, + ACP_CONFIG_17, + ACP_CONFIG_18, + ACP_CONFIG_19, + ACP_CONFIG_20, +}; + +enum amd_acp63_sdw0_channel { + ACP63_SDW0_AUDIO0_TX = 0, + ACP63_SDW0_AUDIO1_TX, + ACP63_SDW0_AUDIO2_TX, + ACP63_SDW0_AUDIO0_RX, + ACP63_SDW0_AUDIO1_RX, + ACP63_SDW0_AUDIO2_RX, }; -enum amd_sdw0_channel { - ACP_SDW0_AUDIO0_TX = 0, - ACP_SDW0_AUDIO1_TX, - ACP_SDW0_AUDIO2_TX, - ACP_SDW0_AUDIO0_RX, - ACP_SDW0_AUDIO1_RX, - ACP_SDW0_AUDIO2_RX, +enum amd_acp63_sdw1_channel { + ACP63_SDW1_AUDIO1_TX, + ACP63_SDW1_AUDIO1_RX, }; -enum amd_sdw1_channel { - ACP_SDW1_AUDIO1_TX, - ACP_SDW1_AUDIO1_RX, +enum amd_acp70_sdw_channel { + ACP70_SDW_AUDIO0_TX = 0, + ACP70_SDW_AUDIO1_TX, + ACP70_SDW_AUDIO2_TX, + ACP70_SDW_AUDIO0_RX, + ACP70_SDW_AUDIO1_RX, + ACP70_SDW_AUDIO2_RX, }; struct pdm_stream_instance { @@ -180,8 +252,11 @@ struct pdm_dev_data { struct sdw_dma_dev_data { void __iomem *acp_base; struct mutex *acp_lock; /* used to protect acp common register access */ - struct snd_pcm_substream *sdw0_dma_stream[ACP63_SDW0_DMA_MAX_STREAMS]; - struct snd_pcm_substream *sdw1_dma_stream[ACP63_SDW1_DMA_MAX_STREAMS]; + u32 acp_rev; + struct snd_pcm_substream *acp63_sdw0_dma_stream[ACP63_SDW0_DMA_MAX_STREAMS]; + struct snd_pcm_substream *acp63_sdw1_dma_stream[ACP63_SDW1_DMA_MAX_STREAMS]; + struct snd_pcm_substream *acp70_sdw0_dma_stream[ACP70_SDW0_DMA_MAX_STREAMS]; + struct snd_pcm_substream *acp70_sdw1_dma_stream[ACP70_SDW1_DMA_MAX_STREAMS]; }; struct acp_sdw_dma_stream { @@ -212,10 +287,35 @@ struct sdw_dma_ring_buf_reg { u32 pos_high_reg; }; +struct acp63_dev_data; + +/** + * struct acp_hw_ops - ACP PCI driver platform specific ops + * @acp_init: ACP initialization + * @acp_deinit: ACP de-initialization + * @acp_get_config: function to read the acp pin configuration + * @acp_sdw_dma_irq_thread: ACP SoundWire DMA interrupt thread + * acp_suspend: ACP system level suspend callback + * acp_resume: ACP system level resume callback + * acp_suspend_runtime: ACP runtime suspend callback + * acp_resume_runtime: ACP runtime resume callback + */ +struct acp_hw_ops { + int (*acp_init)(void __iomem *acp_base, struct device *dev); + int (*acp_deinit)(void __iomem *acp_base, struct device *dev); + void (*acp_get_config)(struct pci_dev *pci, struct acp63_dev_data *acp_data); + void (*acp_sdw_dma_irq_thread)(struct acp63_dev_data *acp_data); + int (*acp_suspend)(struct device *dev); + int (*acp_resume)(struct device *dev); + int (*acp_suspend_runtime)(struct device *dev); + int (*acp_resume_runtime)(struct device *dev); +}; + /** * struct acp63_dev_data - acp pci driver context * @acp63_base: acp mmio base * @res: resource + * @hw_ops: ACP pci driver platform-specific ops * @pdm_dev: ACP PDM controller platform device * @dmic_codec: platform device for DMIC Codec * sdw_dma_dev: platform device for SoundWire DMA controller @@ -229,16 +329,25 @@ struct sdw_dma_ring_buf_reg { * @is_pdm_config: flat set to true when PDM configuration is selected from BIOS * @is_sdw_config: flag set to true when SDW configuration is selected from BIOS * @sdw_en_stat: flag set to true when any one of the SoundWire manager instance is enabled + * @acp70_sdw0_wake_event: flag set to true when wake irq asserted for SW0 instance + * @acp70_sdw1_wake_event: flag set to true when wake irq asserted for SW1 instance * @addr: pci ioremap address * @reg_range: ACP reigister range * @acp_rev: ACP PCI revision id - * @sdw0-dma_intr_stat: DMA interrupt status array for SoundWire manager-SW0 instance - * @sdw_dma_intr_stat: DMA interrupt status array for SoundWire manager-SW1 instance + * @acp63_sdw0-dma_intr_stat: DMA interrupt status array for ACP6.3 platform SoundWire + * manager-SW0 instance + * @acp63_sdw_dma_intr_stat: DMA interrupt status array for ACP6.3 platform SoundWire + * manager-SW1 instance + * @acp70_sdw0-dma_intr_stat: DMA interrupt status array for ACP7.0 platform SoundWire + * manager-SW0 instance + * @acp70_sdw_dma_intr_stat: DMA interrupt status array for ACP7.0 platform SoundWire + * manager-SW1 instance */ struct acp63_dev_data { void __iomem *acp63_base; struct resource *res; + struct acp_hw_ops *hw_ops; struct platform_device *pdm_dev; struct platform_device *dmic_codec_dev; struct platform_device *sdw_dma_dev; @@ -253,11 +362,80 @@ struct acp63_dev_data { bool is_pdm_config; bool is_sdw_config; bool sdw_en_stat; + bool acp70_sdw0_wake_event; + bool acp70_sdw1_wake_event; u32 addr; u32 reg_range; u32 acp_rev; - u16 sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS]; - u16 sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS]; + u16 acp63_sdw0_dma_intr_stat[ACP63_SDW0_DMA_MAX_STREAMS]; + u16 acp63_sdw1_dma_intr_stat[ACP63_SDW1_DMA_MAX_STREAMS]; + u16 acp70_sdw0_dma_intr_stat[ACP70_SDW0_DMA_MAX_STREAMS]; + u16 acp70_sdw1_dma_intr_stat[ACP70_SDW1_DMA_MAX_STREAMS]; }; +void acp63_hw_init_ops(struct acp_hw_ops *hw_ops); +void acp70_hw_init_ops(struct acp_hw_ops *hw_ops); + +static inline int acp_hw_init(struct acp63_dev_data *adata, struct device *dev) +{ + if (adata && adata->hw_ops && adata->hw_ops->acp_init) + return ACP_HW_OPS(adata, acp_init)(adata->acp63_base, dev); + return -EOPNOTSUPP; +} + +static inline int acp_hw_deinit(struct acp63_dev_data *adata, struct device *dev) +{ + if (adata && adata->hw_ops && adata->hw_ops->acp_deinit) + return ACP_HW_OPS(adata, acp_deinit)(adata->acp63_base, dev); + return -EOPNOTSUPP; +} + +static inline void acp_hw_get_config(struct pci_dev *pci, struct acp63_dev_data *adata) +{ + if (adata && adata->hw_ops && adata->hw_ops->acp_get_config) + ACP_HW_OPS(adata, acp_get_config)(pci, adata); +} + +static inline void acp_hw_sdw_dma_irq_thread(struct acp63_dev_data *adata) +{ + if (adata && adata->hw_ops && adata->hw_ops->acp_sdw_dma_irq_thread) + ACP_HW_OPS(adata, acp_sdw_dma_irq_thread)(adata); +} + +static inline int acp_hw_suspend(struct device *dev) +{ + struct acp63_dev_data *adata = dev_get_drvdata(dev); + + if (adata && adata->hw_ops && adata->hw_ops->acp_suspend) + return ACP_HW_OPS(adata, acp_suspend)(dev); + return -EOPNOTSUPP; +} + +static inline int acp_hw_resume(struct device *dev) +{ + struct acp63_dev_data *adata = dev_get_drvdata(dev); + + if (adata && adata->hw_ops && adata->hw_ops->acp_resume) + return ACP_HW_OPS(adata, acp_resume)(dev); + return -EOPNOTSUPP; +} + +static inline int acp_hw_suspend_runtime(struct device *dev) +{ + struct acp63_dev_data *adata = dev_get_drvdata(dev); + + if (adata && adata->hw_ops && adata->hw_ops->acp_suspend_runtime) + return ACP_HW_OPS(adata, acp_suspend_runtime)(dev); + return -EOPNOTSUPP; +} + +static inline int acp_hw_runtime_resume(struct device *dev) +{ + struct acp63_dev_data *adata = dev_get_drvdata(dev); + + if (adata && adata->hw_ops && adata->hw_ops->acp_resume_runtime) + return ACP_HW_OPS(adata, acp_resume_runtime)(dev); + return -EOPNOTSUPP; +} + int snd_amd_acp_find_config(struct pci_dev *pci); diff --git a/sound/soc/amd/ps/pci-ps.c b/sound/soc/amd/ps/pci-ps.c index 8b556950b855..8e57f31ef7f7 100644 --- a/sound/soc/amd/ps/pci-ps.c +++ b/sound/soc/amd/ps/pci-ps.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * AMD Pink Sardine ACP PCI Driver + * AMD common ACP PCI driver for ACP6.3, ACP7.0 & ACP7.1 platforms. * - * Copyright 2022 Advanced Micro Devices, Inc. + * Copyright 2022, 2025 Advanced Micro Devices, Inc. */ #include <linux/pci.h> @@ -21,109 +21,168 @@ #include "acp63.h" -static int acp63_power_on(void __iomem *acp_base) +static void handle_acp70_sdw_wake_event(struct acp63_dev_data *adata) { - u32 val; - - val = readl(acp_base + ACP_PGFSM_STATUS); - - if (!val) - return val; + struct amd_sdw_manager *amd_manager; - if ((val & ACP_PGFSM_STATUS_MASK) != ACP_POWER_ON_IN_PROGRESS) - writel(ACP_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + if (adata->acp70_sdw0_wake_event) { + amd_manager = dev_get_drvdata(&adata->sdw->pdev[0]->dev); + if (amd_manager) + pm_request_resume(amd_manager->dev); + adata->acp70_sdw0_wake_event = 0; + } - return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP_TIMEOUT); + if (adata->acp70_sdw1_wake_event) { + amd_manager = dev_get_drvdata(&adata->sdw->pdev[1]->dev); + if (amd_manager) + pm_request_resume(amd_manager->dev); + adata->acp70_sdw1_wake_event = 0; + } } -static int acp63_reset(void __iomem *acp_base) +static short int check_and_handle_acp70_sdw_wake_irq(struct acp63_dev_data *adata) { - u32 val; - int ret; + u32 ext_intr_stat1; + int irq_flag = 0; + bool sdw_wake_irq = false; - writel(1, acp_base + ACP_SOFT_RESET); - - ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, - val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, - DELAY_US, ACP_TIMEOUT); - if (ret) - return ret; - - writel(0, acp_base + ACP_SOFT_RESET); - - return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP_TIMEOUT); -} - -static void acp63_enable_interrupts(void __iomem *acp_base) -{ - writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); - writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL); -} + ext_intr_stat1 = readl(adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + if (ext_intr_stat1 & ACP70_SDW0_HOST_WAKE_STAT) { + writel(ACP70_SDW0_HOST_WAKE_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + adata->acp70_sdw0_wake_event = true; + sdw_wake_irq = true; + } -static void acp63_disable_interrupts(void __iomem *acp_base) -{ - writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT); - writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); - writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); -} + if (ext_intr_stat1 & ACP70_SDW1_HOST_WAKE_STAT) { + writel(ACP70_SDW1_HOST_WAKE_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + adata->acp70_sdw1_wake_event = true; + sdw_wake_irq = true; + } -static int acp63_init(void __iomem *acp_base, struct device *dev) -{ - int ret; + if (ext_intr_stat1 & ACP70_SDW0_PME_STAT) { + writel(0, adata->acp63_base + ACP_SW0_WAKE_EN); + writel(ACP70_SDW0_PME_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + adata->acp70_sdw0_wake_event = true; + sdw_wake_irq = true; + } - ret = acp63_power_on(acp_base); - if (ret) { - dev_err(dev, "ACP power on failed\n"); - return ret; + if (ext_intr_stat1 & ACP70_SDW1_PME_STAT) { + writel(0, adata->acp63_base + ACP_SW1_WAKE_EN); + writel(ACP70_SDW1_PME_STAT, adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + adata->acp70_sdw1_wake_event = true; + sdw_wake_irq = true; } - writel(0x01, acp_base + ACP_CONTROL); - ret = acp63_reset(acp_base); - if (ret) { - dev_err(dev, "ACP reset failed\n"); - return ret; + + if (sdw_wake_irq) { + handle_acp70_sdw_wake_event(adata); + irq_flag = 1; } - acp63_enable_interrupts(acp_base); - writel(0, acp_base + ACP_ZSC_DSP_CTRL); - return 0; + return irq_flag; } -static int acp63_deinit(void __iomem *acp_base, struct device *dev) +static short int check_and_handle_sdw_dma_irq(struct acp63_dev_data *adata, u32 ext_intr_stat, + u32 ext_intr_stat1) { - int ret; + u32 stream_id = 0; + u16 sdw_dma_irq_flag = 0; + u16 index; - acp63_disable_interrupts(acp_base); - ret = acp63_reset(acp_base); - if (ret) { - dev_err(dev, "ACP reset failed\n"); - return ret; + if (ext_intr_stat & ACP63_SDW_DMA_IRQ_MASK) { + for (index = ACP_AUDIO2_RX_THRESHOLD; index <= ACP_AUDIO0_TX_THRESHOLD; index++) { + if (ext_intr_stat & BIT(index)) { + writel(BIT(index), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); + switch (index) { + case ACP_AUDIO0_TX_THRESHOLD: + stream_id = ACP63_SDW0_AUDIO0_TX; + break; + case ACP_AUDIO1_TX_THRESHOLD: + stream_id = ACP63_SDW0_AUDIO1_TX; + break; + case ACP_AUDIO2_TX_THRESHOLD: + stream_id = ACP63_SDW0_AUDIO2_TX; + break; + case ACP_AUDIO0_RX_THRESHOLD: + stream_id = ACP63_SDW0_AUDIO0_RX; + break; + case ACP_AUDIO1_RX_THRESHOLD: + stream_id = ACP63_SDW0_AUDIO1_RX; + break; + case ACP_AUDIO2_RX_THRESHOLD: + stream_id = ACP63_SDW0_AUDIO2_RX; + break; + } + switch (adata->acp_rev) { + case ACP63_PCI_REV: + adata->acp63_sdw0_dma_intr_stat[stream_id] = 1; + break; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + adata->acp70_sdw0_dma_intr_stat[stream_id] = 1; + break; + } + sdw_dma_irq_flag = 1; + } + } } - writel(0, acp_base + ACP_CONTROL); - writel(1, acp_base + ACP_ZSC_DSP_CTRL); - return 0; + switch (adata->acp_rev) { + case ACP63_PCI_REV: + if (ext_intr_stat1 & ACP63_P1_AUDIO1_RX_THRESHOLD) { + writel(ACP63_P1_AUDIO1_RX_THRESHOLD, + adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + adata->acp63_sdw1_dma_intr_stat[ACP63_SDW1_AUDIO1_RX] = 1; + sdw_dma_irq_flag = 1; + } + if (ext_intr_stat1 & ACP63_P1_AUDIO1_TX_THRESHOLD) { + writel(ACP63_P1_AUDIO1_TX_THRESHOLD, + adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + adata->acp63_sdw1_dma_intr_stat[ACP63_SDW1_AUDIO1_TX] = 1; + sdw_dma_irq_flag = 1; + } + break; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + if (ext_intr_stat1 & ACP70_P1_SDW_DMA_IRQ_MASK) { + for (index = ACP70_P1_AUDIO2_RX_THRESHOLD; + index <= ACP70_P1_AUDIO0_TX_THRESHOLD; index++) { + if (ext_intr_stat1 & BIT(index)) { + writel(BIT(index), + adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); + switch (index) { + case ACP70_P1_AUDIO0_TX_THRESHOLD: + stream_id = ACP70_SDW_AUDIO0_TX; + break; + case ACP70_P1_AUDIO1_TX_THRESHOLD: + stream_id = ACP70_SDW_AUDIO1_TX; + break; + case ACP70_P1_AUDIO2_TX_THRESHOLD: + stream_id = ACP70_SDW_AUDIO2_TX; + break; + case ACP70_P1_AUDIO0_RX_THRESHOLD: + stream_id = ACP70_SDW_AUDIO0_RX; + break; + case ACP70_P1_AUDIO1_RX_THRESHOLD: + stream_id = ACP70_SDW_AUDIO1_RX; + break; + case ACP70_P1_AUDIO2_RX_THRESHOLD: + stream_id = ACP70_SDW_AUDIO2_RX; + break; + } + + adata->acp70_sdw1_dma_intr_stat[stream_id] = 1; + sdw_dma_irq_flag = 1; + } + } + } + break; + } + return sdw_dma_irq_flag; } static irqreturn_t acp63_irq_thread(int irq, void *context) { - struct sdw_dma_dev_data *sdw_dma_data; struct acp63_dev_data *adata = context; - u32 stream_index; - - sdw_dma_data = dev_get_drvdata(&adata->sdw_dma_dev->dev); - for (stream_index = 0; stream_index < ACP63_SDW0_DMA_MAX_STREAMS; stream_index++) { - if (adata->sdw0_dma_intr_stat[stream_index]) { - if (sdw_dma_data->sdw0_dma_stream[stream_index]) - snd_pcm_period_elapsed(sdw_dma_data->sdw0_dma_stream[stream_index]); - adata->sdw0_dma_intr_stat[stream_index] = 0; - } - } - for (stream_index = 0; stream_index < ACP63_SDW1_DMA_MAX_STREAMS; stream_index++) { - if (adata->sdw1_dma_intr_stat[stream_index]) { - if (sdw_dma_data->sdw1_dma_stream[stream_index]) - snd_pcm_period_elapsed(sdw_dma_data->sdw1_dma_stream[stream_index]); - adata->sdw1_dma_intr_stat[stream_index] = 0; - } - } + acp_hw_sdw_dma_irq_thread(adata); return IRQ_HANDLED; } @@ -133,10 +192,8 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) struct pdm_dev_data *ps_pdm_data; struct amd_sdw_manager *amd_manager; u32 ext_intr_stat, ext_intr_stat1; - u32 stream_id = 0; u16 irq_flag = 0; u16 sdw_dma_irq_flag = 0; - u16 index; adata = dev_id; if (!adata) @@ -173,6 +230,9 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) irq_flag = 1; } + if (adata->acp_rev >= ACP70_PCI_REV) + irq_flag = check_and_handle_acp70_sdw_wake_irq(adata); + if (ext_intr_stat & BIT(PDM_DMA_STAT)) { ps_pdm_data = dev_get_drvdata(&adata->pdm_dev->dev); writel(BIT(PDM_DMA_STAT), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); @@ -180,51 +240,8 @@ static irqreturn_t acp63_irq_handler(int irq, void *dev_id) snd_pcm_period_elapsed(ps_pdm_data->capture_stream); irq_flag = 1; } - if (ext_intr_stat & ACP_SDW_DMA_IRQ_MASK) { - for (index = ACP_AUDIO2_RX_THRESHOLD; index <= ACP_AUDIO0_TX_THRESHOLD; index++) { - if (ext_intr_stat & BIT(index)) { - writel(BIT(index), adata->acp63_base + ACP_EXTERNAL_INTR_STAT); - switch (index) { - case ACP_AUDIO0_TX_THRESHOLD: - stream_id = ACP_SDW0_AUDIO0_TX; - break; - case ACP_AUDIO1_TX_THRESHOLD: - stream_id = ACP_SDW0_AUDIO1_TX; - break; - case ACP_AUDIO2_TX_THRESHOLD: - stream_id = ACP_SDW0_AUDIO2_TX; - break; - case ACP_AUDIO0_RX_THRESHOLD: - stream_id = ACP_SDW0_AUDIO0_RX; - break; - case ACP_AUDIO1_RX_THRESHOLD: - stream_id = ACP_SDW0_AUDIO1_RX; - break; - case ACP_AUDIO2_RX_THRESHOLD: - stream_id = ACP_SDW0_AUDIO2_RX; - break; - } - - adata->sdw0_dma_intr_stat[stream_id] = 1; - sdw_dma_irq_flag = 1; - } - } - } - - if (ext_intr_stat1 & ACP_P1_AUDIO1_RX_THRESHOLD) { - writel(ACP_P1_AUDIO1_RX_THRESHOLD, - adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); - adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_RX] = 1; - sdw_dma_irq_flag = 1; - } - - if (ext_intr_stat1 & ACP_P1_AUDIO1_TX_THRESHOLD) { - writel(ACP_P1_AUDIO1_TX_THRESHOLD, - adata->acp63_base + ACP_EXTERNAL_INTR_STAT1); - adata->sdw1_dma_intr_stat[ACP_SDW1_AUDIO1_TX] = 1; - sdw_dma_irq_flag = 1; - } + sdw_dma_irq_flag = check_and_handle_sdw_dma_irq(adata, ext_intr_stat, ext_intr_stat1); if (sdw_dma_irq_flag) return IRQ_WAKE_THREAD; @@ -380,7 +397,6 @@ static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *a const union acpi_object *obj; acpi_handle handle; acpi_integer dmic_status; - u32 config; bool is_dmic_dev = false; bool is_sdw_dev = false; bool wov_en, dmic_en; @@ -390,30 +406,7 @@ static int get_acp63_device_config(struct pci_dev *pci, struct acp63_dev_data *a wov_en = true; dmic_en = false; - config = readl(acp_data->acp63_base + ACP_PIN_CONFIG); - switch (config) { - case ACP_CONFIG_4: - case ACP_CONFIG_5: - case ACP_CONFIG_10: - case ACP_CONFIG_11: - acp_data->is_pdm_config = true; - break; - case ACP_CONFIG_2: - case ACP_CONFIG_3: - acp_data->is_sdw_config = true; - break; - case ACP_CONFIG_6: - case ACP_CONFIG_7: - case ACP_CONFIG_12: - case ACP_CONFIG_8: - case ACP_CONFIG_13: - case ACP_CONFIG_14: - acp_data->is_pdm_config = true; - acp_data->is_sdw_config = true; - break; - default: - break; - } + acp_hw_get_config(pci, acp_data); if (acp_data->is_pdm_config) { pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP63_DMIC_ADDR, 0); @@ -540,11 +533,33 @@ unregister_dmic_codec_dev: unregister_pdm_dev: platform_device_unregister(adata->pdm_dev); de_init: - if (acp63_deinit(adata->acp63_base, &pci->dev)) + if (acp_hw_deinit(adata, &pci->dev)) dev_err(&pci->dev, "ACP de-init failed\n"); return ret; } +static int acp_hw_init_ops(struct acp63_dev_data *adata, struct pci_dev *pci) +{ + adata->hw_ops = devm_kzalloc(&pci->dev, sizeof(struct acp_hw_ops), + GFP_KERNEL); + if (!adata->hw_ops) + return -ENOMEM; + + switch (adata->acp_rev) { + case ACP63_PCI_REV: + acp63_hw_init_ops(adata->hw_ops); + break; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + acp70_hw_init_ops(adata->hw_ops); + break; + default: + dev_err(&pci->dev, "ACP device not found\n"); + return -ENODEV; + } + return 0; +} + static int snd_acp63_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -560,12 +575,14 @@ static int snd_acp63_probe(struct pci_dev *pci, if (flag) return -ENODEV; - /* Pink Sardine device check */ + /* ACP PCI revision id check for ACP6.3, ACP7.0 & ACP7.1 platforms */ switch (pci->revision) { - case 0x63: + case ACP63_PCI_REV: + case ACP70_PCI_REV: + case ACP71_PCI_REV: break; default: - dev_dbg(&pci->dev, "acp63 pci device not found\n"); + dev_dbg(&pci->dev, "acp63/acp70/acp71 pci device not found\n"); return -ENODEV; } if (pci_enable_device(pci)) { @@ -598,7 +615,12 @@ static int snd_acp63_probe(struct pci_dev *pci, pci_set_master(pci); pci_set_drvdata(pci, adata); mutex_init(&adata->acp_lock); - ret = acp63_init(adata->acp63_base, &pci->dev); + ret = acp_hw_init_ops(adata, pci); + if (ret) { + dev_err(&pci->dev, "ACP hw ops init failed\n"); + goto release_regions; + } + ret = acp_hw_init(adata, &pci->dev); if (ret) goto release_regions; ret = devm_request_threaded_irq(&pci->dev, pci->irq, acp63_irq_handler, @@ -618,7 +640,11 @@ static int snd_acp63_probe(struct pci_dev *pci, dev_err(&pci->dev, "ACP platform devices creation failed\n"); goto de_init; } - adata->machines = snd_soc_acpi_amd_acp63_sdw_machines; + if (adata->acp_rev >= ACP70_PCI_REV) + adata->machines = snd_soc_acpi_amd_acp70_sdw_machines; + else + adata->machines = snd_soc_acpi_amd_acp63_sdw_machines; + ret = acp63_machine_register(&pci->dev); if (ret) { dev_err(&pci->dev, "ACP machine register failed\n"); @@ -632,7 +658,7 @@ skip_pdev_creation: pm_runtime_allow(&pci->dev); return 0; de_init: - if (acp63_deinit(adata->acp63_base, &pci->dev)) + if (acp_hw_deinit(adata, &pci->dev)) dev_err(&pci->dev, "ACP de-init failed\n"); release_regions: pci_release_regions(pci); @@ -642,90 +668,24 @@ disable_pci: return ret; } -static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata) +static int snd_acp_suspend(struct device *dev) { - u32 sdw0_en, sdw1_en; - - sdw0_en = readl(adata->acp63_base + ACP_SW0_EN); - sdw1_en = readl(adata->acp63_base + ACP_SW1_EN); - return (sdw0_en || sdw1_en); -} - -static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata) -{ - u32 val; - - val = readl(adata->acp63_base + ACP_SW0_WAKE_EN); - if (val && adata->sdw->pdev[0]) - pm_request_resume(&adata->sdw->pdev[0]->dev); - - val = readl(adata->acp63_base + ACP_SW1_WAKE_EN); - if (val && adata->sdw->pdev[1]) - pm_request_resume(&adata->sdw->pdev[1]->dev); -} - -static int __maybe_unused snd_acp63_suspend(struct device *dev) -{ - struct acp63_dev_data *adata; - int ret; - - adata = dev_get_drvdata(dev); - if (adata->is_sdw_dev) { - adata->sdw_en_stat = check_acp_sdw_enable_status(adata); - if (adata->sdw_en_stat) { - writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL); - return 0; - } - } - ret = acp63_deinit(adata->acp63_base, dev); - if (ret) - dev_err(dev, "ACP de-init failed\n"); - - return ret; + return acp_hw_suspend(dev); } -static int __maybe_unused snd_acp63_runtime_resume(struct device *dev) +static int snd_acp_runtime_resume(struct device *dev) { - struct acp63_dev_data *adata; - int ret; - - adata = dev_get_drvdata(dev); - if (adata->sdw_en_stat) { - writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL); - return 0; - } - ret = acp63_init(adata->acp63_base, dev); - if (ret) { - dev_err(dev, "ACP init failed\n"); - return ret; - } - - if (!adata->sdw_en_stat) - handle_acp63_sdw_pme_event(adata); - return 0; + return acp_hw_runtime_resume(dev); } -static int __maybe_unused snd_acp63_resume(struct device *dev) +static int snd_acp_resume(struct device *dev) { - struct acp63_dev_data *adata; - int ret; - - adata = dev_get_drvdata(dev); - if (adata->sdw_en_stat) { - writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL); - return 0; - } - - ret = acp63_init(adata->acp63_base, dev); - if (ret) - dev_err(dev, "ACP init failed\n"); - - return ret; + return acp_hw_resume(dev); } static const struct dev_pm_ops acp63_pm_ops = { - SET_RUNTIME_PM_OPS(snd_acp63_suspend, snd_acp63_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(snd_acp63_suspend, snd_acp63_resume) + RUNTIME_PM_OPS(snd_acp_suspend, snd_acp_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(snd_acp_suspend, snd_acp_resume) }; static void snd_acp63_remove(struct pci_dev *pci) @@ -744,7 +704,7 @@ static void snd_acp63_remove(struct pci_dev *pci) } if (adata->mach_dev) platform_device_unregister(adata->mach_dev); - ret = acp63_deinit(adata->acp63_base, &pci->dev); + ret = acp_hw_deinit(adata, &pci->dev); if (ret) dev_err(&pci->dev, "ACP de-init failed\n"); pm_runtime_forbid(&pci->dev); @@ -767,7 +727,7 @@ static struct pci_driver ps_acp63_driver = { .probe = snd_acp63_probe, .remove = snd_acp63_remove, .driver = { - .pm = &acp63_pm_ops, + .pm = pm_ptr(&acp63_pm_ops), } }; @@ -775,7 +735,7 @@ module_pci_driver(ps_acp63_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); MODULE_AUTHOR("Syed.SabaKareem@amd.com"); -MODULE_DESCRIPTION("AMD ACP Pink Sardine PCI driver"); +MODULE_DESCRIPTION("AMD common ACP PCI driver for ACP6.3, ACP7.0 & ACP7.1 platforms"); MODULE_IMPORT_NS("SOUNDWIRE_AMD_INIT"); MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/amd/ps/ps-common.c b/sound/soc/amd/ps/ps-common.c new file mode 100644 index 000000000000..1c89fb5fe1da --- /dev/null +++ b/sound/soc/amd/ps/ps-common.c @@ -0,0 +1,475 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * AMD ACP PCI driver callback routines for ACP6.3, ACP7.0 & ACP7.1 + * platforms. + * + * Copyright 2025 Advanced Micro Devices, Inc. + * Authors: Vijendar Mukunda <Vijendar.Mukunda@amd.com> + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/export.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/pci.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <sound/pcm_params.h> + +#include "acp63.h" + +static int acp63_power_on(void __iomem *acp_base) +{ + u32 val; + + val = readl(acp_base + ACP_PGFSM_STATUS); + + if (!val) + return val; + + if ((val & ACP63_PGFSM_STATUS_MASK) != ACP63_POWER_ON_IN_PROGRESS) + writel(ACP63_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + + return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP63_TIMEOUT); +} + +static int acp63_reset(void __iomem *acp_base) +{ + u32 val; + int ret; + + writel(1, acp_base + ACP_SOFT_RESET); + + ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, + val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, + DELAY_US, ACP63_TIMEOUT); + if (ret) + return ret; + + writel(0, acp_base + ACP_SOFT_RESET); + + return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP63_TIMEOUT); +} + +static void acp63_enable_interrupts(void __iomem *acp_base) +{ + writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); + writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL); +} + +static void acp63_disable_interrupts(void __iomem *acp_base) +{ + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT); + writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); +} + +static int acp63_init(void __iomem *acp_base, struct device *dev) +{ + int ret; + + ret = acp63_power_on(acp_base); + if (ret) { + dev_err(dev, "ACP power on failed\n"); + return ret; + } + writel(0x01, acp_base + ACP_CONTROL); + ret = acp63_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + acp63_enable_interrupts(acp_base); + writel(0, acp_base + ACP_ZSC_DSP_CTRL); + return 0; +} + +static int acp63_deinit(void __iomem *acp_base, struct device *dev) +{ + int ret; + + acp63_disable_interrupts(acp_base); + ret = acp63_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + writel(0, acp_base + ACP_CONTROL); + writel(1, acp_base + ACP_ZSC_DSP_CTRL); + return 0; +} + +static void acp63_get_config(struct pci_dev *pci, struct acp63_dev_data *acp_data) +{ + u32 config; + + config = readl(acp_data->acp63_base + ACP_PIN_CONFIG); + dev_dbg(&pci->dev, "ACP config value: %d\n", config); + switch (config) { + case ACP_CONFIG_4: + case ACP_CONFIG_5: + case ACP_CONFIG_10: + case ACP_CONFIG_11: + acp_data->is_pdm_config = true; + break; + case ACP_CONFIG_2: + case ACP_CONFIG_3: + acp_data->is_sdw_config = true; + break; + case ACP_CONFIG_6: + case ACP_CONFIG_7: + case ACP_CONFIG_12: + case ACP_CONFIG_8: + case ACP_CONFIG_13: + case ACP_CONFIG_14: + acp_data->is_pdm_config = true; + acp_data->is_sdw_config = true; + break; + default: + break; + } +} + +static bool check_acp_sdw_enable_status(struct acp63_dev_data *adata) +{ + u32 sdw0_en, sdw1_en; + + sdw0_en = readl(adata->acp63_base + ACP_SW0_EN); + sdw1_en = readl(adata->acp63_base + ACP_SW1_EN); + return (sdw0_en || sdw1_en); +} + +static void handle_acp63_sdw_pme_event(struct acp63_dev_data *adata) +{ + u32 val; + + val = readl(adata->acp63_base + ACP_SW0_WAKE_EN); + if (val && adata->sdw->pdev[0]) + pm_request_resume(&adata->sdw->pdev[0]->dev); + + val = readl(adata->acp63_base + ACP_SW1_WAKE_EN); + if (val && adata->sdw->pdev[1]) + pm_request_resume(&adata->sdw->pdev[1]->dev); +} + +static int __maybe_unused snd_acp63_suspend(struct device *dev) +{ + struct acp63_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + if (adata->is_sdw_dev) { + adata->sdw_en_stat = check_acp_sdw_enable_status(adata); + if (adata->sdw_en_stat) { + writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL); + return 0; + } + } + ret = acp_hw_deinit(adata, dev); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + + return ret; +} + +static int __maybe_unused snd_acp63_runtime_resume(struct device *dev) +{ + struct acp63_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + if (adata->sdw_en_stat) { + writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL); + return 0; + } + ret = acp_hw_init(adata, dev); + if (ret) { + dev_err(dev, "ACP init failed\n"); + return ret; + } + + if (!adata->sdw_en_stat) + handle_acp63_sdw_pme_event(adata); + return 0; +} + +static int __maybe_unused snd_acp63_resume(struct device *dev) +{ + struct acp63_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + if (adata->sdw_en_stat) { + writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL); + return 0; + } + + ret = acp_hw_init(adata, dev); + if (ret) + dev_err(dev, "ACP init failed\n"); + + return ret; +} + +static void acp63_sdw_dma_irq_thread(struct acp63_dev_data *adata) +{ + struct sdw_dma_dev_data *sdw_data; + u32 stream_id; + + sdw_data = dev_get_drvdata(&adata->sdw_dma_dev->dev); + + for (stream_id = 0; stream_id < ACP63_SDW0_DMA_MAX_STREAMS; stream_id++) { + if (adata->acp63_sdw0_dma_intr_stat[stream_id]) { + if (sdw_data->acp63_sdw0_dma_stream[stream_id]) + snd_pcm_period_elapsed(sdw_data->acp63_sdw0_dma_stream[stream_id]); + adata->acp63_sdw0_dma_intr_stat[stream_id] = 0; + } + } + for (stream_id = 0; stream_id < ACP63_SDW1_DMA_MAX_STREAMS; stream_id++) { + if (adata->acp63_sdw1_dma_intr_stat[stream_id]) { + if (sdw_data->acp63_sdw1_dma_stream[stream_id]) + snd_pcm_period_elapsed(sdw_data->acp63_sdw1_dma_stream[stream_id]); + adata->acp63_sdw1_dma_intr_stat[stream_id] = 0; + } + } +} + +void acp63_hw_init_ops(struct acp_hw_ops *hw_ops) +{ + hw_ops->acp_init = acp63_init; + hw_ops->acp_deinit = acp63_deinit; + hw_ops->acp_get_config = acp63_get_config; + hw_ops->acp_sdw_dma_irq_thread = acp63_sdw_dma_irq_thread; + hw_ops->acp_suspend = snd_acp63_suspend; + hw_ops->acp_resume = snd_acp63_resume; + hw_ops->acp_suspend_runtime = snd_acp63_suspend; + hw_ops->acp_resume_runtime = snd_acp63_runtime_resume; +} + +static int acp70_power_on(void __iomem *acp_base) +{ + u32 val = 0; + + val = readl(acp_base + ACP_PGFSM_STATUS); + + if (!val) + return 0; + if (val & ACP70_PGFSM_STATUS_MASK) + writel(ACP70_PGFSM_CNTL_POWER_ON_MASK, acp_base + ACP_PGFSM_CONTROL); + + return readl_poll_timeout(acp_base + ACP_PGFSM_STATUS, val, !val, DELAY_US, ACP70_TIMEOUT); +} + +static int acp70_reset(void __iomem *acp_base) +{ + u32 val; + int ret; + + writel(1, acp_base + ACP_SOFT_RESET); + + ret = readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, + val & ACP_SOFT_RESET_SOFTRESET_AUDDONE_MASK, + DELAY_US, ACP70_TIMEOUT); + if (ret) + return ret; + + writel(0, acp_base + ACP_SOFT_RESET); + + return readl_poll_timeout(acp_base + ACP_SOFT_RESET, val, !val, DELAY_US, ACP70_TIMEOUT); +} + +static void acp70_enable_sdw_host_wake_interrupts(void __iomem *acp_base) +{ + u32 ext_intr_cntl1; + + ext_intr_cntl1 = readl(acp_base + ACP_EXTERNAL_INTR_CNTL1); + ext_intr_cntl1 |= ACP70_SDW_HOST_WAKE_MASK; + writel(ext_intr_cntl1, acp_base + ACP_EXTERNAL_INTR_CNTL1); +} + +static void acp70_enable_interrupts(void __iomem *acp_base) +{ + u32 sdw0_wake_en, sdw1_wake_en; + + writel(1, acp_base + ACP_EXTERNAL_INTR_ENB); + writel(ACP_ERROR_IRQ, acp_base + ACP_EXTERNAL_INTR_CNTL); + sdw0_wake_en = readl(acp_base + ACP_SW0_WAKE_EN); + sdw1_wake_en = readl(acp_base + ACP_SW1_WAKE_EN); + if (sdw0_wake_en || sdw1_wake_en) + acp70_enable_sdw_host_wake_interrupts(acp_base); +} + +static void acp70_disable_interrupts(void __iomem *acp_base) +{ + writel(ACP_EXT_INTR_STAT_CLEAR_MASK, acp_base + ACP_EXTERNAL_INTR_STAT); + writel(0, acp_base + ACP_EXTERNAL_INTR_CNTL); + writel(0, acp_base + ACP_EXTERNAL_INTR_ENB); +} + +static int acp70_init(void __iomem *acp_base, struct device *dev) +{ + int ret; + + ret = acp70_power_on(acp_base); + if (ret) { + dev_err(dev, "ACP power on failed\n"); + return ret; + } + writel(0x01, acp_base + ACP_CONTROL); + ret = acp70_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + writel(0, acp_base + ACP_ZSC_DSP_CTRL); + acp70_enable_interrupts(acp_base); + writel(0x1, acp_base + ACP_PME_EN); + return 0; +} + +static int acp70_deinit(void __iomem *acp_base, struct device *dev) +{ + int ret; + + acp70_disable_interrupts(acp_base); + ret = acp70_reset(acp_base); + if (ret) { + dev_err(dev, "ACP reset failed\n"); + return ret; + } + writel(0x01, acp_base + ACP_ZSC_DSP_CTRL); + return 0; +} + +static void acp70_get_config(struct pci_dev *pci, struct acp63_dev_data *acp_data) +{ + u32 config; + + config = readl(acp_data->acp63_base + ACP_PIN_CONFIG); + dev_dbg(&pci->dev, "ACP config value: %d\n", config); + switch (config) { + case ACP_CONFIG_4: + case ACP_CONFIG_5: + case ACP_CONFIG_10: + case ACP_CONFIG_11: + case ACP_CONFIG_20: + acp_data->is_pdm_config = true; + break; + case ACP_CONFIG_2: + case ACP_CONFIG_3: + case ACP_CONFIG_16: + acp_data->is_sdw_config = true; + break; + case ACP_CONFIG_6: + case ACP_CONFIG_7: + case ACP_CONFIG_12: + case ACP_CONFIG_8: + case ACP_CONFIG_13: + case ACP_CONFIG_14: + case ACP_CONFIG_17: + case ACP_CONFIG_18: + case ACP_CONFIG_19: + acp_data->is_pdm_config = true; + acp_data->is_sdw_config = true; + break; + default: + break; + } +} + +static void acp70_sdw_dma_irq_thread(struct acp63_dev_data *adata) +{ + struct sdw_dma_dev_data *sdw_data; + u32 stream_id; + + sdw_data = dev_get_drvdata(&adata->sdw_dma_dev->dev); + + for (stream_id = 0; stream_id < ACP70_SDW0_DMA_MAX_STREAMS; stream_id++) { + if (adata->acp70_sdw0_dma_intr_stat[stream_id]) { + if (sdw_data->acp70_sdw0_dma_stream[stream_id]) + snd_pcm_period_elapsed(sdw_data->acp70_sdw0_dma_stream[stream_id]); + adata->acp70_sdw0_dma_intr_stat[stream_id] = 0; + } + } + for (stream_id = 0; stream_id < ACP70_SDW1_DMA_MAX_STREAMS; stream_id++) { + if (adata->acp70_sdw1_dma_intr_stat[stream_id]) { + if (sdw_data->acp70_sdw1_dma_stream[stream_id]) + snd_pcm_period_elapsed(sdw_data->acp70_sdw1_dma_stream[stream_id]); + adata->acp70_sdw1_dma_intr_stat[stream_id] = 0; + } + } +} + +static int __maybe_unused snd_acp70_suspend(struct device *dev) +{ + struct acp63_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + if (adata->is_sdw_dev) { + adata->sdw_en_stat = check_acp_sdw_enable_status(adata); + if (adata->sdw_en_stat) { + writel(1, adata->acp63_base + ACP_ZSC_DSP_CTRL); + return 0; + } + } + ret = acp_hw_deinit(adata, dev); + if (ret) + dev_err(dev, "ACP de-init failed\n"); + + return ret; +} + +static int __maybe_unused snd_acp70_runtime_resume(struct device *dev) +{ + struct acp63_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + + if (adata->sdw_en_stat) { + writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL); + writel(1, adata->acp63_base + ACP_PME_EN); + return 0; + } + + ret = acp_hw_init(adata, dev); + if (ret) { + dev_err(dev, "ACP init failed\n"); + return ret; + } + return 0; +} + +static int __maybe_unused snd_acp70_resume(struct device *dev) +{ + struct acp63_dev_data *adata; + int ret; + + adata = dev_get_drvdata(dev); + + if (adata->sdw_en_stat) { + writel(0, adata->acp63_base + ACP_ZSC_DSP_CTRL); + writel(1, adata->acp63_base + ACP_PME_EN); + return 0; + } + + ret = acp_hw_init(adata, dev); + if (ret) + dev_err(dev, "ACP init failed\n"); + + return ret; +} + +void acp70_hw_init_ops(struct acp_hw_ops *hw_ops) +{ + hw_ops->acp_init = acp70_init; + hw_ops->acp_deinit = acp70_deinit; + hw_ops->acp_get_config = acp70_get_config; + hw_ops->acp_sdw_dma_irq_thread = acp70_sdw_dma_irq_thread; + hw_ops->acp_suspend = snd_acp70_suspend; + hw_ops->acp_resume = snd_acp70_resume; + hw_ops->acp_suspend_runtime = snd_acp70_suspend; + hw_ops->acp_resume_runtime = snd_acp70_runtime_resume; +} diff --git a/sound/soc/amd/ps/ps-pdm-dma.c b/sound/soc/amd/ps/ps-pdm-dma.c index 318fc260f293..9cfbe05ad996 100644 --- a/sound/soc/amd/ps/ps-pdm-dma.c +++ b/sound/soc/amd/ps/ps-pdm-dma.c @@ -1,8 +1,8 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * AMD ALSA SoC Pink Sardine PDM Driver + * AMD ALSA SoC common PDM Driver for ACP6.3, ACP7.0 & ACP7.1 platforms. * - * Copyright 2022 Advanced Micro Devices, Inc. + * Copyright 2022, 2025 Advanced Micro Devices, Inc. */ #include <linux/platform_device.h> @@ -402,7 +402,7 @@ static void acp63_pdm_audio_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused acp63_pdm_resume(struct device *dev) +static int acp63_pdm_resume(struct device *dev) { struct pdm_dev_data *adata; struct snd_pcm_runtime *runtime; @@ -423,7 +423,7 @@ static int __maybe_unused acp63_pdm_resume(struct device *dev) return 0; } -static int __maybe_unused acp63_pdm_suspend(struct device *dev) +static int acp63_pdm_suspend(struct device *dev) { struct pdm_dev_data *adata; @@ -432,7 +432,7 @@ static int __maybe_unused acp63_pdm_suspend(struct device *dev) return 0; } -static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev) +static int acp63_pdm_runtime_resume(struct device *dev) { struct pdm_dev_data *adata; @@ -442,8 +442,8 @@ static int __maybe_unused acp63_pdm_runtime_resume(struct device *dev) } static const struct dev_pm_ops acp63_pdm_pm_ops = { - SET_RUNTIME_PM_OPS(acp63_pdm_suspend, acp63_pdm_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(acp63_pdm_suspend, acp63_pdm_resume) + RUNTIME_PM_OPS(acp63_pdm_suspend, acp63_pdm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(acp63_pdm_suspend, acp63_pdm_resume) }; static struct platform_driver acp63_pdm_dma_driver = { @@ -451,13 +451,13 @@ static struct platform_driver acp63_pdm_dma_driver = { .remove = acp63_pdm_audio_remove, .driver = { .name = "acp_ps_pdm_dma", - .pm = &acp63_pdm_pm_ops, + .pm = pm_ptr(&acp63_pdm_pm_ops), }, }; module_platform_driver(acp63_pdm_dma_driver); MODULE_AUTHOR("Syed.SabaKareem@amd.com"); -MODULE_DESCRIPTION("AMD PINK SARDINE PDM Driver"); +MODULE_DESCRIPTION("AMD common PDM Driver for ACP6.3, ACP7,0 & ACP7.1 platforms"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/ps/ps-sdw-dma.c b/sound/soc/amd/ps/ps-sdw-dma.c index b602cca92b8b..1b933a017c06 100644 --- a/sound/soc/amd/ps/ps-sdw-dma.c +++ b/sound/soc/amd/ps/ps-sdw-dma.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * AMD ALSA SoC Pink Sardine SoundWire DMA Driver + * AMD ALSA SoC common SoundWire DMA Driver for ACP6.3, ACP7.0 and ACP7.1 + * platforms. * - * Copyright 2023 Advanced Micro Devices, Inc. + * Copyright 2023, 2025 Advanced Micro Devices, Inc. */ #include <linux/err.h> @@ -18,7 +19,7 @@ #define DRV_NAME "amd_ps_sdw_dma" -static struct sdw_dma_ring_buf_reg sdw0_dma_ring_buf_reg[ACP63_SDW0_DMA_MAX_STREAMS] = { +static struct sdw_dma_ring_buf_reg acp63_sdw0_dma_reg[ACP63_SDW0_DMA_MAX_STREAMS] = { {ACP_AUDIO0_TX_DMA_SIZE, ACP_AUDIO0_TX_FIFOADDR, ACP_AUDIO0_TX_FIFOSIZE, ACP_AUDIO0_TX_RINGBUFSIZE, ACP_AUDIO0_TX_RINGBUFADDR, ACP_AUDIO0_TX_INTR_WATERMARK_SIZE, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH}, @@ -44,7 +45,7 @@ static struct sdw_dma_ring_buf_reg sdw0_dma_ring_buf_reg[ACP63_SDW0_DMA_MAX_STRE * For TX/RX streams DMA registers programming for SDW1 instance, it uses ACP_P1_AUDIO1 register * set as per hardware register documentation */ -static struct sdw_dma_ring_buf_reg sdw1_dma_ring_buf_reg[ACP63_SDW1_DMA_MAX_STREAMS] = { +static struct sdw_dma_ring_buf_reg acp63_sdw1_dma_reg[ACP63_SDW1_DMA_MAX_STREAMS] = { {ACP_P1_AUDIO1_TX_DMA_SIZE, ACP_P1_AUDIO1_TX_FIFOADDR, ACP_P1_AUDIO1_TX_FIFOSIZE, ACP_P1_AUDIO1_TX_RINGBUFSIZE, ACP_P1_AUDIO1_TX_RINGBUFADDR, ACP_P1_AUDIO1_TX_INTR_WATERMARK_SIZE, @@ -55,7 +56,7 @@ static struct sdw_dma_ring_buf_reg sdw1_dma_ring_buf_reg[ACP63_SDW1_DMA_MAX_STRE ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH}, }; -static u32 sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = { +static u32 acp63_sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = { ACP_SW0_AUDIO0_TX_EN, ACP_SW0_AUDIO1_TX_EN, ACP_SW0_AUDIO2_TX_EN, @@ -70,11 +71,77 @@ static u32 sdw0_dma_enable_reg[ACP63_SDW0_DMA_MAX_STREAMS] = { * it uses ACP_SW1_AUDIO1_TX_EN and ACP_SW1_AUDIO1_RX_EN registers * as per hardware register documentation. */ -static u32 sdw1_dma_enable_reg[ACP63_SDW1_DMA_MAX_STREAMS] = { +static u32 acp63_sdw1_dma_enable_reg[ACP63_SDW1_DMA_MAX_STREAMS] = { ACP_SW1_AUDIO1_TX_EN, ACP_SW1_AUDIO1_RX_EN, }; +static struct sdw_dma_ring_buf_reg acp70_sdw0_dma_reg[ACP70_SDW0_DMA_MAX_STREAMS] = { + {ACP_AUDIO0_TX_DMA_SIZE, ACP_AUDIO0_TX_FIFOADDR, ACP_AUDIO0_TX_FIFOSIZE, + ACP_AUDIO0_TX_RINGBUFSIZE, ACP_AUDIO0_TX_RINGBUFADDR, ACP_AUDIO0_TX_INTR_WATERMARK_SIZE, + ACP_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH}, + {ACP_AUDIO1_TX_DMA_SIZE, ACP_AUDIO1_TX_FIFOADDR, ACP_AUDIO1_TX_FIFOSIZE, + ACP_AUDIO1_TX_RINGBUFSIZE, ACP_AUDIO1_TX_RINGBUFADDR, ACP_AUDIO1_TX_INTR_WATERMARK_SIZE, + ACP_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH}, + {ACP_AUDIO2_TX_DMA_SIZE, ACP_AUDIO2_TX_FIFOADDR, ACP_AUDIO2_TX_FIFOSIZE, + ACP_AUDIO2_TX_RINGBUFSIZE, ACP_AUDIO2_TX_RINGBUFADDR, ACP_AUDIO2_TX_INTR_WATERMARK_SIZE, + ACP_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH}, + {ACP_AUDIO0_RX_DMA_SIZE, ACP_AUDIO0_RX_FIFOADDR, ACP_AUDIO0_RX_FIFOSIZE, + ACP_AUDIO0_RX_RINGBUFSIZE, ACP_AUDIO0_RX_RINGBUFADDR, ACP_AUDIO0_RX_INTR_WATERMARK_SIZE, + ACP_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH}, + {ACP_AUDIO1_RX_DMA_SIZE, ACP_AUDIO1_RX_FIFOADDR, ACP_AUDIO1_RX_FIFOSIZE, + ACP_AUDIO1_RX_RINGBUFSIZE, ACP_AUDIO1_RX_RINGBUFADDR, ACP_AUDIO1_RX_INTR_WATERMARK_SIZE, + ACP_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH}, + {ACP_AUDIO2_RX_DMA_SIZE, ACP_AUDIO2_RX_FIFOADDR, ACP_AUDIO2_RX_FIFOSIZE, + ACP_AUDIO2_RX_RINGBUFSIZE, ACP_AUDIO2_RX_RINGBUFADDR, ACP_AUDIO2_RX_INTR_WATERMARK_SIZE, + ACP_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH} +}; + +static struct sdw_dma_ring_buf_reg acp70_sdw1_dma_reg[ACP70_SDW1_DMA_MAX_STREAMS] = { + {ACP_P1_AUDIO0_TX_DMA_SIZE, ACP_P1_AUDIO0_TX_FIFOADDR, ACP_P1_AUDIO0_TX_FIFOSIZE, + ACP_P1_AUDIO0_TX_RINGBUFSIZE, ACP_P1_AUDIO0_TX_RINGBUFADDR, + ACP_P1_AUDIO0_TX_INTR_WATERMARK_SIZE, + ACP_P1_AUDIO0_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO0_TX_LINEARPOSITIONCNTR_HIGH}, + {ACP_P1_AUDIO1_TX_DMA_SIZE, ACP_P1_AUDIO1_TX_FIFOADDR, ACP_P1_AUDIO1_TX_FIFOSIZE, + ACP_P1_AUDIO1_TX_RINGBUFSIZE, ACP_P1_AUDIO1_TX_RINGBUFADDR, + ACP_P1_AUDIO1_TX_INTR_WATERMARK_SIZE, + ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_TX_LINEARPOSITIONCNTR_HIGH}, + {ACP_P1_AUDIO2_TX_DMA_SIZE, ACP_P1_AUDIO2_TX_FIFOADDR, ACP_P1_AUDIO2_TX_FIFOSIZE, + ACP_P1_AUDIO2_TX_RINGBUFSIZE, ACP_P1_AUDIO2_TX_RINGBUFADDR, + ACP_P1_AUDIO2_TX_INTR_WATERMARK_SIZE, + ACP_P1_AUDIO2_TX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO2_TX_LINEARPOSITIONCNTR_HIGH}, + {ACP_P1_AUDIO0_RX_DMA_SIZE, ACP_P1_AUDIO0_RX_FIFOADDR, ACP_P1_AUDIO0_RX_FIFOSIZE, + ACP_P1_AUDIO0_RX_RINGBUFSIZE, ACP_P1_AUDIO0_RX_RINGBUFADDR, + ACP_P1_AUDIO0_RX_INTR_WATERMARK_SIZE, + ACP_P1_AUDIO0_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO0_RX_LINEARPOSITIONCNTR_HIGH}, + {ACP_P1_AUDIO1_RX_DMA_SIZE, ACP_P1_AUDIO1_RX_FIFOADDR, ACP_P1_AUDIO1_RX_FIFOSIZE, + ACP_P1_AUDIO1_RX_RINGBUFSIZE, ACP_P1_AUDIO1_RX_RINGBUFADDR, + ACP_P1_AUDIO1_RX_INTR_WATERMARK_SIZE, + ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO1_RX_LINEARPOSITIONCNTR_HIGH}, + {ACP_P1_AUDIO2_RX_DMA_SIZE, ACP_P1_AUDIO2_RX_FIFOADDR, ACP_P1_AUDIO2_RX_FIFOSIZE, + ACP_P1_AUDIO2_RX_RINGBUFSIZE, ACP_P1_AUDIO2_RX_RINGBUFADDR, + ACP_P1_AUDIO2_RX_INTR_WATERMARK_SIZE, + ACP_P1_AUDIO2_RX_LINEARPOSITIONCNTR_LOW, ACP_P1_AUDIO2_RX_LINEARPOSITIONCNTR_HIGH} +}; + +static u32 acp70_sdw0_dma_enable_reg[ACP70_SDW0_DMA_MAX_STREAMS] = { + ACP70_SW0_AUDIO0_TX_EN, + ACP70_SW0_AUDIO1_TX_EN, + ACP70_SW0_AUDIO2_TX_EN, + ACP70_SW0_AUDIO0_RX_EN, + ACP70_SW0_AUDIO1_RX_EN, + ACP70_SW0_AUDIO2_RX_EN, +}; + +static u32 acp70_sdw1_dma_enable_reg[ACP70_SDW1_DMA_MAX_STREAMS] = { + ACP70_SW1_AUDIO0_TX_EN, + ACP70_SW1_AUDIO1_TX_EN, + ACP70_SW1_AUDIO2_TX_EN, + ACP70_SW1_AUDIO0_RX_EN, + ACP70_SW1_AUDIO1_RX_EN, + ACP70_SW1_AUDIO2_RX_EN, +}; + static const struct snd_pcm_hardware acp63_sdw_hardware_playback = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | @@ -114,11 +181,10 @@ static const struct snd_pcm_hardware acp63_sdw_hardware_capture = { .periods_max = SDW_CAPTURE_MAX_NUM_PERIODS, }; -static void acp63_enable_disable_sdw_dma_interrupts(void __iomem *acp_base, bool enable) +static void acp63_enable_disable_sdw_dma_interrupts(void __iomem *acp_base, u32 irq_mask, + u32 irq_mask1, bool enable) { u32 ext_intr_cntl, ext_intr_cntl1; - u32 irq_mask = ACP_SDW_DMA_IRQ_MASK; - u32 irq_mask1 = ACP_P1_SDW_DMA_IRQ_MASK; if (enable) { ext_intr_cntl = readl(acp_base + ACP_EXTERNAL_INTR_CNTL); @@ -167,7 +233,7 @@ static void acp63_config_dma(struct acp_sdw_dma_stream *stream, void __iomem *ac } static int acp63_configure_sdw_ringbuffer(void __iomem *acp_base, u32 stream_id, u32 size, - u32 manager_instance) + u32 manager_instance, u32 acp_rev) { u32 reg_dma_size; u32 reg_fifo_addr; @@ -180,20 +246,47 @@ static int acp63_configure_sdw_ringbuffer(void __iomem *acp_base, u32 stream_id, u32 sdw_ring_buf_size; u32 sdw_mem_window_offset; - switch (manager_instance) { - case ACP_SDW0: - reg_dma_size = sdw0_dma_ring_buf_reg[stream_id].reg_dma_size; - reg_fifo_addr = sdw0_dma_ring_buf_reg[stream_id].reg_fifo_addr; - reg_fifo_size = sdw0_dma_ring_buf_reg[stream_id].reg_fifo_size; - reg_ring_buf_size = sdw0_dma_ring_buf_reg[stream_id].reg_ring_buf_size; - reg_ring_buf_addr = sdw0_dma_ring_buf_reg[stream_id].reg_ring_buf_addr; + switch (acp_rev) { + case ACP63_PCI_REV: + switch (manager_instance) { + case ACP_SDW0: + reg_dma_size = acp63_sdw0_dma_reg[stream_id].reg_dma_size; + reg_fifo_addr = acp63_sdw0_dma_reg[stream_id].reg_fifo_addr; + reg_fifo_size = acp63_sdw0_dma_reg[stream_id].reg_fifo_size; + reg_ring_buf_size = acp63_sdw0_dma_reg[stream_id].reg_ring_buf_size; + reg_ring_buf_addr = acp63_sdw0_dma_reg[stream_id].reg_ring_buf_addr; + break; + case ACP_SDW1: + reg_dma_size = acp63_sdw1_dma_reg[stream_id].reg_dma_size; + reg_fifo_addr = acp63_sdw1_dma_reg[stream_id].reg_fifo_addr; + reg_fifo_size = acp63_sdw1_dma_reg[stream_id].reg_fifo_size; + reg_ring_buf_size = acp63_sdw1_dma_reg[stream_id].reg_ring_buf_size; + reg_ring_buf_addr = acp63_sdw1_dma_reg[stream_id].reg_ring_buf_addr; + break; + default: + return -EINVAL; + } break; - case ACP_SDW1: - reg_dma_size = sdw1_dma_ring_buf_reg[stream_id].reg_dma_size; - reg_fifo_addr = sdw1_dma_ring_buf_reg[stream_id].reg_fifo_addr; - reg_fifo_size = sdw1_dma_ring_buf_reg[stream_id].reg_fifo_size; - reg_ring_buf_size = sdw1_dma_ring_buf_reg[stream_id].reg_ring_buf_size; - reg_ring_buf_addr = sdw1_dma_ring_buf_reg[stream_id].reg_ring_buf_addr; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + switch (manager_instance) { + case ACP_SDW0: + reg_dma_size = acp70_sdw0_dma_reg[stream_id].reg_dma_size; + reg_fifo_addr = acp70_sdw0_dma_reg[stream_id].reg_fifo_addr; + reg_fifo_size = acp70_sdw0_dma_reg[stream_id].reg_fifo_size; + reg_ring_buf_size = acp70_sdw0_dma_reg[stream_id].reg_ring_buf_size; + reg_ring_buf_addr = acp70_sdw0_dma_reg[stream_id].reg_ring_buf_addr; + break; + case ACP_SDW1: + reg_dma_size = acp70_sdw1_dma_reg[stream_id].reg_dma_size; + reg_fifo_addr = acp70_sdw1_dma_reg[stream_id].reg_fifo_addr; + reg_fifo_size = acp70_sdw1_dma_reg[stream_id].reg_fifo_size; + reg_ring_buf_size = acp70_sdw1_dma_reg[stream_id].reg_ring_buf_size; + reg_ring_buf_addr = acp70_sdw1_dma_reg[stream_id].reg_ring_buf_addr; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -265,21 +358,53 @@ static int acp63_sdw_dma_hw_params(struct snd_soc_component *component, if (!stream) return -EINVAL; stream_id = stream->stream_id; - switch (stream->instance) { - case ACP_SDW0: - sdw_data->sdw0_dma_stream[stream_id] = substream; - water_mark_size_reg = sdw0_dma_ring_buf_reg[stream_id].water_mark_size_reg; - acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - irq_mask = BIT(SDW0_DMA_TX_IRQ_MASK(stream_id)); - else - irq_mask = BIT(SDW0_DMA_RX_IRQ_MASK(stream_id)); + switch (sdw_data->acp_rev) { + case ACP63_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + sdw_data->acp63_sdw0_dma_stream[stream_id] = substream; + water_mark_size_reg = acp63_sdw0_dma_reg[stream_id].water_mark_size_reg; + acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + irq_mask = BIT(ACP63_SDW0_DMA_TX_IRQ_MASK(stream_id)); + else + irq_mask = BIT(ACP63_SDW0_DMA_RX_IRQ_MASK(stream_id)); + break; + case ACP_SDW1: + sdw_data->acp63_sdw1_dma_stream[stream_id] = substream; + acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1; + water_mark_size_reg = acp63_sdw1_dma_reg[stream_id].water_mark_size_reg; + irq_mask = BIT(ACP63_SDW1_DMA_IRQ_MASK(stream_id)); + break; + default: + return -EINVAL; + } break; - case ACP_SDW1: - sdw_data->sdw1_dma_stream[stream_id] = substream; - acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1; - water_mark_size_reg = sdw1_dma_ring_buf_reg[stream_id].water_mark_size_reg; - irq_mask = BIT(SDW1_DMA_IRQ_MASK(stream_id)); + case ACP70_PCI_REV: + case ACP71_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + sdw_data->acp70_sdw0_dma_stream[stream_id] = substream; + water_mark_size_reg = acp70_sdw0_dma_reg[stream_id].water_mark_size_reg; + acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + irq_mask = BIT(ACP70_SDW0_DMA_TX_IRQ_MASK(stream_id)); + else + irq_mask = BIT(ACP70_SDW0_DMA_RX_IRQ_MASK(stream_id)); + break; + case ACP_SDW1: + sdw_data->acp70_sdw1_dma_stream[stream_id] = substream; + acp_ext_intr_cntl_reg = ACP_EXTERNAL_INTR_CNTL1; + water_mark_size_reg = acp70_sdw1_dma_reg[stream_id].water_mark_size_reg; + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + irq_mask = BIT(ACP70_SDW1_DMA_TX_IRQ_MASK(stream_id)); + else + irq_mask = BIT(ACP70_SDW1_DMA_RX_IRQ_MASK(stream_id)); + + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -290,7 +415,7 @@ static int acp63_sdw_dma_hw_params(struct snd_soc_component *component, stream->num_pages = (PAGE_ALIGN(size) >> PAGE_SHIFT); acp63_config_dma(stream, sdw_data->acp_base, stream_id); ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, stream_id, size, - stream->instance); + stream->instance, sdw_data->acp_rev); if (ret) { dev_err(component->dev, "Invalid DMA channel\n"); return -EINVAL; @@ -302,20 +427,42 @@ static int acp63_sdw_dma_hw_params(struct snd_soc_component *component, return 0; } -static u64 acp63_sdw_get_byte_count(struct acp_sdw_dma_stream *stream, void __iomem *acp_base) +static u64 acp63_sdw_get_byte_count(struct acp_sdw_dma_stream *stream, void __iomem *acp_base, + u32 acp_rev) { union acp_sdw_dma_count byte_count; u32 pos_low_reg, pos_high_reg; byte_count.bytescount = 0; - switch (stream->instance) { - case ACP_SDW0: - pos_low_reg = sdw0_dma_ring_buf_reg[stream->stream_id].pos_low_reg; - pos_high_reg = sdw0_dma_ring_buf_reg[stream->stream_id].pos_high_reg; + switch (acp_rev) { + case ACP63_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + pos_low_reg = acp63_sdw0_dma_reg[stream->stream_id].pos_low_reg; + pos_high_reg = acp63_sdw0_dma_reg[stream->stream_id].pos_high_reg; + break; + case ACP_SDW1: + pos_low_reg = acp63_sdw1_dma_reg[stream->stream_id].pos_low_reg; + pos_high_reg = acp63_sdw1_dma_reg[stream->stream_id].pos_high_reg; + break; + default: + goto POINTER_RETURN_BYTES; + } break; - case ACP_SDW1: - pos_low_reg = sdw1_dma_ring_buf_reg[stream->stream_id].pos_low_reg; - pos_high_reg = sdw1_dma_ring_buf_reg[stream->stream_id].pos_high_reg; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + pos_low_reg = acp70_sdw0_dma_reg[stream->stream_id].pos_low_reg; + pos_high_reg = acp70_sdw0_dma_reg[stream->stream_id].pos_high_reg; + break; + case ACP_SDW1: + pos_low_reg = acp70_sdw1_dma_reg[stream->stream_id].pos_low_reg; + pos_high_reg = acp70_sdw1_dma_reg[stream->stream_id].pos_high_reg; + break; + default: + goto POINTER_RETURN_BYTES; + } break; default: goto POINTER_RETURN_BYTES; @@ -340,7 +487,7 @@ static snd_pcm_uframes_t acp63_sdw_dma_pointer(struct snd_soc_component *comp, stream = substream->runtime->private_data; buffersize = frames_to_bytes(substream->runtime, substream->runtime->buffer_size); - bytescount = acp63_sdw_get_byte_count(stream, sdw_data->acp_base); + bytescount = acp63_sdw_get_byte_count(stream, sdw_data->acp_base, sdw_data->acp_rev); if (bytescount > stream->bytescount) bytescount -= stream->bytescount; pos = do_div(bytescount, buffersize); @@ -367,12 +514,31 @@ static int acp63_sdw_dma_close(struct snd_soc_component *component, stream = substream->runtime->private_data; if (!stream) return -EINVAL; - switch (stream->instance) { - case ACP_SDW0: - sdw_data->sdw0_dma_stream[stream->stream_id] = NULL; + switch (sdw_data->acp_rev) { + case ACP63_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + sdw_data->acp63_sdw0_dma_stream[stream->stream_id] = NULL; + break; + case ACP_SDW1: + sdw_data->acp63_sdw1_dma_stream[stream->stream_id] = NULL; + break; + default: + return -EINVAL; + } break; - case ACP_SDW1: - sdw_data->sdw1_dma_stream[stream->stream_id] = NULL; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + sdw_data->acp70_sdw0_dma_stream[stream->stream_id] = NULL; + break; + case ACP_SDW1: + sdw_data->acp70_sdw1_dma_stream[stream->stream_id] = NULL; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -382,7 +548,7 @@ static int acp63_sdw_dma_close(struct snd_soc_component *component, } static int acp63_sdw_dma_enable(struct snd_pcm_substream *substream, - void __iomem *acp_base, bool sdw_dma_enable) + void __iomem *acp_base, u32 acp_rev, bool sdw_dma_enable) { struct acp_sdw_dma_stream *stream; u32 stream_id; @@ -393,12 +559,31 @@ static int acp63_sdw_dma_enable(struct snd_pcm_substream *substream, stream = substream->runtime->private_data; stream_id = stream->stream_id; - switch (stream->instance) { - case ACP_SDW0: - sdw_dma_en_reg = sdw0_dma_enable_reg[stream_id]; + switch (acp_rev) { + case ACP63_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + sdw_dma_en_reg = acp63_sdw0_dma_enable_reg[stream_id]; + break; + case ACP_SDW1: + sdw_dma_en_reg = acp63_sdw1_dma_enable_reg[stream_id]; + break; + default: + return -EINVAL; + } break; - case ACP_SDW1: - sdw_dma_en_reg = sdw1_dma_enable_reg[stream_id]; + case ACP70_PCI_REV: + case ACP71_PCI_REV: + switch (stream->instance) { + case ACP_SDW0: + sdw_dma_en_reg = acp70_sdw0_dma_enable_reg[stream_id]; + break; + case ACP_SDW1: + sdw_dma_en_reg = acp70_sdw1_dma_enable_reg[stream_id]; + break; + default: + return -EINVAL; + } break; default: return -EINVAL; @@ -422,12 +607,12 @@ static int acp63_sdw_dma_trigger(struct snd_soc_component *comp, case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_RESUME: - ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, true); + ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, sdw_data->acp_rev, true); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: - ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, false); + ret = acp63_sdw_dma_enable(substream, sdw_data->acp_base, sdw_data->acp_rev, false); break; default: ret = -EINVAL; @@ -474,6 +659,7 @@ static int acp63_sdw_platform_probe(struct platform_device *pdev) return -ENOMEM; sdw_data->acp_lock = &acp_data->acp_lock; + sdw_data->acp_rev = acp_data->acp_rev; dev_set_drvdata(&pdev->dev, sdw_data); status = devm_snd_soc_register_component(&pdev->dev, &acp63_sdw_component, @@ -495,15 +681,17 @@ static void acp63_sdw_platform_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) +static int acp63_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) { struct acp_sdw_dma_stream *stream; struct snd_pcm_substream *substream; struct snd_pcm_runtime *runtime; u32 period_bytes, buf_size, water_mark_size_reg; - u32 stream_count; + u32 stream_count, irq_mask, irq_mask1; int index, instance, ret; + irq_mask = ACP63_SDW_DMA_IRQ_MASK; + irq_mask1 = ACP63_P1_SDW_DMA_IRQ_MASK; for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) { if (instance == ACP_SDW0) stream_count = ACP63_SDW0_DMA_MAX_STREAMS; @@ -512,13 +700,11 @@ static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) for (index = 0; index < stream_count; index++) { if (instance == ACP_SDW0) { - substream = sdw_data->sdw0_dma_stream[index]; - water_mark_size_reg = - sdw0_dma_ring_buf_reg[index].water_mark_size_reg; + substream = sdw_data->acp63_sdw0_dma_stream[index]; + water_mark_size_reg = acp63_sdw0_dma_reg[index].water_mark_size_reg; } else { - substream = sdw_data->sdw1_dma_stream[index]; - water_mark_size_reg = - sdw1_dma_ring_buf_reg[index].water_mark_size_reg; + substream = sdw_data->acp63_sdw1_dma_stream[index]; + water_mark_size_reg = acp63_sdw1_dma_reg[index].water_mark_size_reg; } if (substream && substream->runtime) { @@ -528,27 +714,72 @@ static int acp_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) buf_size = frames_to_bytes(runtime, runtime->buffer_size); acp63_config_dma(stream, sdw_data->acp_base, index); ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index, - buf_size, instance); + buf_size, instance, + ACP63_PCI_REV); if (ret) return ret; writel(period_bytes, sdw_data->acp_base + water_mark_size_reg); } } } - acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, true); + acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, irq_mask, irq_mask1, true); return 0; } -static int __maybe_unused acp63_sdw_pcm_resume(struct device *dev) +static int acp70_restore_sdw_dma_config(struct sdw_dma_dev_data *sdw_data) +{ + struct acp_sdw_dma_stream *stream; + struct snd_pcm_substream *substream; + struct snd_pcm_runtime *runtime; + u32 period_bytes, buf_size, water_mark_size_reg; + u32 stream_count, irq_mask, irq_mask1; + int index, instance, ret; + + irq_mask = ACP70_SDW_DMA_IRQ_MASK; + irq_mask1 = ACP70_P1_SDW_DMA_IRQ_MASK; + stream_count = ACP70_SDW0_DMA_MAX_STREAMS; + for (instance = 0; instance < AMD_SDW_MAX_MANAGERS; instance++) { + for (index = 0; index < stream_count; index++) { + if (instance == ACP_SDW0) { + substream = sdw_data->acp70_sdw0_dma_stream[index]; + water_mark_size_reg = acp70_sdw0_dma_reg[index].water_mark_size_reg; + } else { + substream = sdw_data->acp70_sdw1_dma_stream[index]; + water_mark_size_reg = acp70_sdw1_dma_reg[index].water_mark_size_reg; + } + + if (substream && substream->runtime) { + runtime = substream->runtime; + stream = runtime->private_data; + period_bytes = frames_to_bytes(runtime, runtime->period_size); + buf_size = frames_to_bytes(runtime, runtime->buffer_size); + acp63_config_dma(stream, sdw_data->acp_base, index); + ret = acp63_configure_sdw_ringbuffer(sdw_data->acp_base, index, + buf_size, instance, + sdw_data->acp_rev); + if (ret) + return ret; + writel(period_bytes, sdw_data->acp_base + water_mark_size_reg); + } + } + } + acp63_enable_disable_sdw_dma_interrupts(sdw_data->acp_base, irq_mask, irq_mask1, true); + return 0; +} + +static int acp63_sdw_pcm_resume(struct device *dev) { struct sdw_dma_dev_data *sdw_data; sdw_data = dev_get_drvdata(dev); - return acp_restore_sdw_dma_config(sdw_data); + if (sdw_data->acp_rev == ACP63_PCI_REV) + return acp63_restore_sdw_dma_config(sdw_data); + else + return acp70_restore_sdw_dma_config(sdw_data); } static const struct dev_pm_ops acp63_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume) + SYSTEM_SLEEP_PM_OPS(NULL, acp63_sdw_pcm_resume) }; static struct platform_driver acp63_sdw_dma_driver = { @@ -556,13 +787,13 @@ static struct platform_driver acp63_sdw_dma_driver = { .remove = acp63_sdw_platform_remove, .driver = { .name = "amd_ps_sdw_dma", - .pm = &acp63_pm_ops, + .pm = pm_ptr(&acp63_pm_ops), }, }; module_platform_driver(acp63_sdw_dma_driver); MODULE_AUTHOR("Vijendar.Mukunda@amd.com"); -MODULE_DESCRIPTION("AMD ACP6.3 PS SDW DMA Driver"); +MODULE_DESCRIPTION("AMD common SDW DMA Driver for ACP6.3, ACP7.0 & ACP7.1 platforms"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/sound/soc/amd/rpl/rpl-pci-acp6x.c b/sound/soc/amd/rpl/rpl-pci-acp6x.c index a8e548ed991b..e3afe9172bdf 100644 --- a/sound/soc/amd/rpl/rpl-pci-acp6x.c +++ b/sound/soc/amd/rpl/rpl-pci-acp6x.c @@ -159,7 +159,7 @@ disable_pci: return ret; } -static int __maybe_unused snd_rpl_suspend(struct device *dev) +static int snd_rpl_suspend(struct device *dev) { struct rpl_dev_data *adata; int ret; @@ -171,7 +171,7 @@ static int __maybe_unused snd_rpl_suspend(struct device *dev) return ret; } -static int __maybe_unused snd_rpl_resume(struct device *dev) +static int snd_rpl_resume(struct device *dev) { struct rpl_dev_data *adata; int ret; @@ -184,8 +184,8 @@ static int __maybe_unused snd_rpl_resume(struct device *dev) } static const struct dev_pm_ops rpl_pm = { - SET_RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume) + RUNTIME_PM_OPS(snd_rpl_suspend, snd_rpl_resume, NULL) + SYSTEM_SLEEP_PM_OPS(snd_rpl_suspend, snd_rpl_resume) }; static void snd_rpl_remove(struct pci_dev *pci) @@ -217,7 +217,7 @@ static struct pci_driver rpl_acp6x_driver = { .probe = snd_rpl_probe, .remove = snd_rpl_remove, .driver = { - .pm = &rpl_pm, + .pm = pm_ptr(&rpl_pm), } }; diff --git a/sound/soc/amd/vangogh/acp5x-pcm-dma.c b/sound/soc/amd/vangogh/acp5x-pcm-dma.c index d5965f2b09bc..aa4726899434 100644 --- a/sound/soc/amd/vangogh/acp5x-pcm-dma.c +++ b/sound/soc/amd/vangogh/acp5x-pcm-dma.c @@ -420,7 +420,7 @@ static void acp5x_audio_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused acp5x_pcm_resume(struct device *dev) +static int acp5x_pcm_resume(struct device *dev) { struct i2s_dev_data *adata; struct i2s_stream_instance *rtd; @@ -473,7 +473,7 @@ static int __maybe_unused acp5x_pcm_resume(struct device *dev) return 0; } -static int __maybe_unused acp5x_pcm_suspend(struct device *dev) +static int acp5x_pcm_suspend(struct device *dev) { struct i2s_dev_data *adata; @@ -482,7 +482,7 @@ static int __maybe_unused acp5x_pcm_suspend(struct device *dev) return 0; } -static int __maybe_unused acp5x_pcm_runtime_resume(struct device *dev) +static int acp5x_pcm_runtime_resume(struct device *dev) { struct i2s_dev_data *adata; @@ -492,9 +492,8 @@ static int __maybe_unused acp5x_pcm_runtime_resume(struct device *dev) } static const struct dev_pm_ops acp5x_pm_ops = { - SET_RUNTIME_PM_OPS(acp5x_pcm_suspend, - acp5x_pcm_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(acp5x_pcm_suspend, acp5x_pcm_resume) + RUNTIME_PM_OPS(acp5x_pcm_suspend, acp5x_pcm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(acp5x_pcm_suspend, acp5x_pcm_resume) }; static struct platform_driver acp5x_dma_driver = { diff --git a/sound/soc/amd/yc/acp6x-mach.c b/sound/soc/amd/yc/acp6x-mach.c index a7637056972a..e632f16c9102 100644 --- a/sound/soc/amd/yc/acp6x-mach.c +++ b/sound/soc/amd/yc/acp6x-mach.c @@ -342,6 +342,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { { .driver_data = &acp6x_card, .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_NAME, "83J2"), + } + }, + { + .driver_data = &acp6x_card, + .matches = { DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK COMPUTER INC."), DMI_MATCH(DMI_PRODUCT_NAME, "UM5302TA"), } @@ -584,6 +591,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "pang13"), } }, + { + .driver_data = &acp6x_card, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Micro-Star International Co., Ltd."), + DMI_MATCH(DMI_PRODUCT_NAME, "Bravo 15 C7UCX"), + } + }, {} }; diff --git a/sound/soc/amd/yc/acp6x-pdm-dma.c b/sound/soc/amd/yc/acp6x-pdm-dma.c index 3eb3e82efb10..ac758b90f441 100644 --- a/sound/soc/amd/yc/acp6x-pdm-dma.c +++ b/sound/soc/amd/yc/acp6x-pdm-dma.c @@ -394,7 +394,7 @@ static void acp6x_pdm_audio_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused acp6x_pdm_resume(struct device *dev) +static int acp6x_pdm_resume(struct device *dev) { struct pdm_dev_data *adata; struct snd_pcm_runtime *runtime; @@ -415,7 +415,7 @@ static int __maybe_unused acp6x_pdm_resume(struct device *dev) return 0; } -static int __maybe_unused acp6x_pdm_suspend(struct device *dev) +static int acp6x_pdm_suspend(struct device *dev) { struct pdm_dev_data *adata; @@ -424,7 +424,7 @@ static int __maybe_unused acp6x_pdm_suspend(struct device *dev) return 0; } -static int __maybe_unused acp6x_pdm_runtime_resume(struct device *dev) +static int acp6x_pdm_runtime_resume(struct device *dev) { struct pdm_dev_data *adata; @@ -434,8 +434,8 @@ static int __maybe_unused acp6x_pdm_runtime_resume(struct device *dev) } static const struct dev_pm_ops acp6x_pdm_pm_ops = { - SET_RUNTIME_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_resume) + RUNTIME_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(acp6x_pdm_suspend, acp6x_pdm_resume) }; static struct platform_driver acp6x_pdm_dma_driver = { @@ -443,7 +443,7 @@ static struct platform_driver acp6x_pdm_dma_driver = { .remove = acp6x_pdm_audio_remove, .driver = { .name = "acp_yc_pdm_dma", - .pm = &acp6x_pdm_pm_ops, + .pm = pm_ptr(&acp6x_pdm_pm_ops), }, }; diff --git a/sound/soc/amd/yc/pci-acp6x.c b/sound/soc/amd/yc/pci-acp6x.c index 7af6a349b1d4..1140ed1cbb3d 100644 --- a/sound/soc/amd/yc/pci-acp6x.c +++ b/sound/soc/amd/yc/pci-acp6x.c @@ -277,7 +277,7 @@ disable_pci: return ret; } -static int __maybe_unused snd_acp6x_suspend(struct device *dev) +static int snd_acp6x_suspend(struct device *dev) { struct acp6x_dev_data *adata; int ret; @@ -289,7 +289,7 @@ static int __maybe_unused snd_acp6x_suspend(struct device *dev) return ret; } -static int __maybe_unused snd_acp6x_resume(struct device *dev) +static int snd_acp6x_resume(struct device *dev) { struct acp6x_dev_data *adata; int ret; @@ -302,8 +302,8 @@ static int __maybe_unused snd_acp6x_resume(struct device *dev) } static const struct dev_pm_ops acp6x_pm = { - SET_RUNTIME_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume) + RUNTIME_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume, NULL) + SYSTEM_SLEEP_PM_OPS(snd_acp6x_suspend, snd_acp6x_resume) }; static void snd_acp6x_remove(struct pci_dev *pci) @@ -339,7 +339,7 @@ static struct pci_driver yc_acp6x_driver = { .probe = snd_acp6x_probe, .remove = snd_acp6x_remove, .driver = { - .pm = &acp6x_pm, + .pm = pm_ptr(&acp6x_pm), } }; diff --git a/sound/soc/atmel/atmel-classd.c b/sound/soc/atmel/atmel-classd.c index ba314b279919..1f8c60d2de82 100644 --- a/sound/soc/atmel/atmel-classd.c +++ b/sound/soc/atmel/atmel-classd.c @@ -11,6 +11,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> +#include <linux/string_choices.h> #include <sound/core.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm_params.h> @@ -275,7 +276,7 @@ static int atmel_classd_component_probe(struct snd_soc_component *component) dev_info(component->dev, "PWM modulation type is %s, non-overlapping is %s\n", pwm_type[pdata->pwm_type], - pdata->non_overlap_enable?"enabled":"disabled"); + str_enabled_disabled(pdata->non_overlap_enable)); return 0; } diff --git a/sound/soc/atmel/tse850-pcm5142.c b/sound/soc/atmel/tse850-pcm5142.c index 0a9efd5f2861..2a1d0408a4cf 100644 --- a/sound/soc/atmel/tse850-pcm5142.c +++ b/sound/soc/atmel/tse850-pcm5142.c @@ -227,16 +227,9 @@ static const struct snd_kcontrol_new mux1 = static const struct snd_kcontrol_new mux2 = SOC_DAPM_ENUM_EXT("MUX2", mux_enum, tse850_get_mux2, tse850_put_mux2); -#define TSE850_DAPM_SINGLE_EXT(xname, reg, shift, max, invert, xget, xput) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_soc_info_volsw, \ - .get = xget, \ - .put = xput, \ - .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } - static const struct snd_kcontrol_new mix[] = { - TSE850_DAPM_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0, - tse850_get_mix, tse850_put_mix), + SOC_SINGLE_EXT("IN Switch", SND_SOC_NOPM, 0, 1, 0, + tse850_get_mix, tse850_put_mix), }; static const char * const ana_text[] = { diff --git a/sound/soc/au1x/i2sc.c b/sound/soc/au1x/i2sc.c index 7d296f29dade..57735004f416 100644 --- a/sound/soc/au1x/i2sc.c +++ b/sound/soc/au1x/i2sc.c @@ -279,7 +279,6 @@ static void au1xi2s_drvremove(struct platform_device *pdev) WR(ctx, I2S_ENABLE, EN_D); /* clock off, disable */ } -#ifdef CONFIG_PM static int au1xi2s_drvsuspend(struct device *dev) { struct au1xpsc_audio_data *ctx = dev_get_drvdata(dev); @@ -294,23 +293,13 @@ static int au1xi2s_drvresume(struct device *dev) return 0; } -static const struct dev_pm_ops au1xi2sc_pmops = { - .suspend = au1xi2s_drvsuspend, - .resume = au1xi2s_drvresume, -}; - -#define AU1XI2SC_PMOPS (&au1xi2sc_pmops) - -#else - -#define AU1XI2SC_PMOPS NULL - -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(au1xi2sc_pmops, au1xi2s_drvsuspend, + au1xi2s_drvresume); static struct platform_driver au1xi2s_driver = { .driver = { .name = "alchemy-i2sc", - .pm = AU1XI2SC_PMOPS, + .pm = pm_ptr(&au1xi2sc_pmops), }, .probe = au1xi2s_drvprobe, .remove = au1xi2s_drvremove, diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c index 8a59a50978b9..94698e08a513 100644 --- a/sound/soc/au1x/psc-ac97.c +++ b/sound/soc/au1x/psc-ac97.c @@ -436,7 +436,6 @@ static void au1xpsc_ac97_drvremove(struct platform_device *pdev) au1xpsc_ac97_workdata = NULL; /* MDEV */ } -#ifdef CONFIG_PM static int au1xpsc_ac97_drvsuspend(struct device *dev) { struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); @@ -467,23 +466,13 @@ static int au1xpsc_ac97_drvresume(struct device *dev) return 0; } -static const struct dev_pm_ops au1xpscac97_pmops = { - .suspend = au1xpsc_ac97_drvsuspend, - .resume = au1xpsc_ac97_drvresume, -}; - -#define AU1XPSCAC97_PMOPS &au1xpscac97_pmops - -#else - -#define AU1XPSCAC97_PMOPS NULL - -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(au1xpscac97_pmops, au1xpsc_ac97_drvsuspend, + au1xpsc_ac97_drvresume); static struct platform_driver au1xpsc_ac97_driver = { .driver = { .name = "au1xpsc_ac97", - .pm = AU1XPSCAC97_PMOPS, + .pm = pm_ptr(&au1xpscac97_pmops), }, .probe = au1xpsc_ac97_drvprobe, .remove = au1xpsc_ac97_drvremove, diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index bee013555e7a..bf59105fcb7a 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -354,7 +354,6 @@ static void au1xpsc_i2s_drvremove(struct platform_device *pdev) wmb(); /* drain writebuffer */ } -#ifdef CONFIG_PM static int au1xpsc_i2s_drvsuspend(struct device *dev) { struct au1xpsc_audio_data *wd = dev_get_drvdata(dev); @@ -385,23 +384,13 @@ static int au1xpsc_i2s_drvresume(struct device *dev) return 0; } -static const struct dev_pm_ops au1xpsci2s_pmops = { - .suspend = au1xpsc_i2s_drvsuspend, - .resume = au1xpsc_i2s_drvresume, -}; - -#define AU1XPSCI2S_PMOPS &au1xpsci2s_pmops - -#else - -#define AU1XPSCI2S_PMOPS NULL - -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(au1xpsci2s_pmops, au1xpsc_i2s_drvsuspend, + au1xpsc_i2s_drvresume); static struct platform_driver au1xpsc_i2s_driver = { .driver = { .name = "au1xpsc_i2s", - .pm = AU1XPSCI2S_PMOPS, + .pm = pm_ptr(&au1xpsci2s_pmops), }, .probe = au1xpsc_i2s_drvprobe, .remove = au1xpsc_i2s_drvremove, diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index ee35f3aa5521..40bb7a1d44bc 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -58,6 +58,7 @@ config SND_SOC_ALL_CODECS imply SND_SOC_AW87390 imply SND_SOC_AW88395 imply SND_SOC_AW88081 + imply SND_SOC_AW88166 imply SND_SOC_AW88261 imply SND_SOC_AW88399 imply SND_SOC_BT_SCO @@ -678,6 +679,18 @@ config SND_SOC_AW88395 digital Smart K audio amplifier with an integrated 10V smart boost convert. +config SND_SOC_AW88166 + tristate "Soc Audio for awinic aw88166" + depends on I2C + select REGMAP_I2C + select GPIOLIB + select SND_SOC_AW88395_LIB + help + This option enables support for aw88166 Smart PA. + The awinic AW88166 is an I2S/TDM input, high efficiency + digital Smart K audio amplifier with sound quality + enhancement algorithms and speaker protection. + config SND_SOC_AW88261 tristate "Soc Audio for awinic aw88261" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index d7ad795603c1..10f726066b6c 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -53,6 +53,7 @@ snd-soc-aw88081-y := aw88081.o snd-soc-aw88395-lib-y := aw88395/aw88395_lib.o snd-soc-aw88395-y := aw88395/aw88395.o \ aw88395/aw88395_device.o +snd-soc-aw88166-y := aw88166.o snd-soc-aw88261-y := aw88261.o snd-soc-aw88399-y := aw88399.o snd-soc-bd28623-y := bd28623.o @@ -470,6 +471,7 @@ obj-$(CONFIG_SND_SOC_AW87390) += snd-soc-aw87390.o obj-$(CONFIG_SND_SOC_AW88081) += snd-soc-aw88081.o obj-$(CONFIG_SND_SOC_AW88395_LIB) += snd-soc-aw88395-lib.o obj-$(CONFIG_SND_SOC_AW88395) +=snd-soc-aw88395.o +obj-$(CONFIG_SND_SOC_AW88166) +=snd-soc-aw88166.o obj-$(CONFIG_SND_SOC_AW88261) +=snd-soc-aw88261.o obj-$(CONFIG_SND_SOC_AW88399) += snd-soc-aw88399.o obj-$(CONFIG_SND_SOC_BD28623) += snd-soc-bd28623.o diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index 291249e0a2a3..6876462d8bdb 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -325,9 +325,7 @@ static int adau1701_reset(struct snd_soc_component *component, unsigned int clkd __assign_bit(1, values, 1); break; } - gpiod_set_array_value_cansleep(adau1701->gpio_pll_mode->ndescs, - adau1701->gpio_pll_mode->desc, adau1701->gpio_pll_mode->info, - values); + gpiod_multi_set_value_cansleep(adau1701->gpio_pll_mode, values); } adau1701->pll_clkdiv = clkdiv; diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c index 4dcc984761e0..0b6b0d2115eb 100644 --- a/sound/soc/codecs/adau17x1.c +++ b/sound/soc/codecs/adau17x1.c @@ -255,7 +255,7 @@ static int adau17x1_dsp_mux_enum_get(struct snd_kcontrol *kcontrol, #define DECLARE_ADAU17X1_DSP_MUX_CTRL(_name, _label, _stream, _text) \ const struct snd_kcontrol_new _name = \ - SOC_DAPM_ENUM_EXT(_label, (const struct soc_enum)\ + SOC_ENUM_EXT(_label, (const struct soc_enum)\ SOC_ENUM_SINGLE(SND_SOC_NOPM, _stream, \ ARRAY_SIZE(_text), _text), \ adau17x1_dsp_mux_enum_get, adau17x1_dsp_mux_enum_put) diff --git a/sound/soc/codecs/ak4375.c b/sound/soc/codecs/ak4375.c index 3ee5a5c3c5fe..452559d8c97b 100644 --- a/sound/soc/codecs/ak4375.c +++ b/sound/soc/codecs/ak4375.c @@ -438,7 +438,7 @@ static int ak4375_power_on(struct ak4375_priv *ak4375) return 0; } -static int __maybe_unused ak4375_runtime_suspend(struct device *dev) +static int ak4375_runtime_suspend(struct device *dev) { struct ak4375_priv *ak4375 = dev_get_drvdata(dev); @@ -448,7 +448,7 @@ static int __maybe_unused ak4375_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused ak4375_runtime_resume(struct device *dev) +static int ak4375_runtime_resume(struct device *dev) { struct ak4375_priv *ak4375 = dev_get_drvdata(dev); int ret; @@ -490,9 +490,8 @@ static const struct ak4375_drvdata ak4375_drvdata = { }; static const struct dev_pm_ops ak4375_pm = { - SET_RUNTIME_PM_OPS(ak4375_runtime_suspend, ak4375_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(ak4375_runtime_suspend, ak4375_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static int ak4375_i2c_probe(struct i2c_client *i2c) @@ -594,7 +593,7 @@ MODULE_DEVICE_TABLE(of, ak4375_of_match); static struct i2c_driver ak4375_i2c_driver = { .driver = { .name = "ak4375", - .pm = &ak4375_pm, + .pm = pm_ptr(&ak4375_pm), .of_match_table = ak4375_of_match, }, .probe = ak4375_i2c_probe, diff --git a/sound/soc/codecs/ak4458.c b/sound/soc/codecs/ak4458.c index d472d9952628..5f3a68dfe7bd 100644 --- a/sound/soc/codecs/ak4458.c +++ b/sound/soc/codecs/ak4458.c @@ -639,8 +639,7 @@ static void ak4458_reset(struct ak4458_priv *ak4458, bool active) } } -#ifdef CONFIG_PM -static int __maybe_unused ak4458_runtime_suspend(struct device *dev) +static int ak4458_runtime_suspend(struct device *dev) { struct ak4458_priv *ak4458 = dev_get_drvdata(dev); @@ -656,7 +655,7 @@ static int __maybe_unused ak4458_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused ak4458_runtime_resume(struct device *dev) +static int ak4458_runtime_resume(struct device *dev) { struct ak4458_priv *ak4458 = dev_get_drvdata(dev); int ret; @@ -678,7 +677,6 @@ static int __maybe_unused ak4458_runtime_resume(struct device *dev) return regcache_sync(ak4458->regmap); } -#endif /* CONFIG_PM */ static const struct snd_soc_component_driver soc_codec_dev_ak4458 = { .controls = ak4458_snd_controls, @@ -727,9 +725,8 @@ static const struct ak4458_drvdata ak4497_drvdata = { }; static const struct dev_pm_ops ak4458_pm = { - SET_RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(ak4458_runtime_suspend, ak4458_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static int ak4458_i2c_probe(struct i2c_client *i2c) @@ -805,7 +802,7 @@ MODULE_DEVICE_TABLE(of, ak4458_of_match); static struct i2c_driver ak4458_i2c_driver = { .driver = { .name = "ak4458", - .pm = &ak4458_pm, + .pm = pm_ptr(&ak4458_pm), .of_match_table = ak4458_of_match, }, .probe = ak4458_i2c_probe, diff --git a/sound/soc/codecs/ak5558.c b/sound/soc/codecs/ak5558.c index 6c767609f95d..683f3e472f50 100644 --- a/sound/soc/codecs/ak5558.c +++ b/sound/soc/codecs/ak5558.c @@ -342,7 +342,7 @@ static void ak5558_remove(struct snd_soc_component *component) ak5558_reset(ak5558, true); } -static int __maybe_unused ak5558_runtime_suspend(struct device *dev) +static int ak5558_runtime_suspend(struct device *dev) { struct ak5558_priv *ak5558 = dev_get_drvdata(dev); @@ -354,7 +354,7 @@ static int __maybe_unused ak5558_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused ak5558_runtime_resume(struct device *dev) +static int ak5558_runtime_resume(struct device *dev) { struct ak5558_priv *ak5558 = dev_get_drvdata(dev); int ret; @@ -376,9 +376,8 @@ static int __maybe_unused ak5558_runtime_resume(struct device *dev) } static const struct dev_pm_ops ak5558_pm = { - SET_RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(ak5558_runtime_suspend, ak5558_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct snd_soc_component_driver soc_codec_dev_ak5558 = { @@ -495,7 +494,7 @@ static struct i2c_driver ak5558_i2c_driver = { .driver = { .name = "ak5558", .of_match_table = of_match_ptr(ak5558_i2c_dt_ids), - .pm = &ak5558_pm, + .pm = pm_ptr(&ak5558_pm), }, .probe = ak5558_i2c_probe, .remove = ak5558_i2c_remove, diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 68cdb1027d0c..f2f47f1c1ac8 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1457,7 +1457,7 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; case SND_SOC_DAIFMT_DSP_B: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) - != SND_SOC_DAIFMT_CBM_CFM) { + != SND_SOC_DAIFMT_CBP_CFP) { arizona_aif_err(dai, "DSP_B not valid in slave mode\n"); return -EINVAL; } @@ -1468,7 +1468,7 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; case SND_SOC_DAIFMT_LEFT_J: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) - != SND_SOC_DAIFMT_CBM_CFM) { + != SND_SOC_DAIFMT_CBP_CFP) { arizona_aif_err(dai, "LEFT_J not valid in slave mode\n"); return -EINVAL; } @@ -1481,15 +1481,15 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: bclk |= ARIZONA_AIF1_BCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: bclk |= ARIZONA_AIF1_BCLK_MSTR; lrclk |= ARIZONA_AIF1TX_LRCLK_MSTR; break; diff --git a/sound/soc/codecs/aw88166.c b/sound/soc/codecs/aw88166.c new file mode 100644 index 000000000000..6c50c4a18b6a --- /dev/null +++ b/sound/soc/codecs/aw88166.c @@ -0,0 +1,1933 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88166.c -- ALSA SoC AW88166 codec support +// +// Copyright (c) 2025 AWINIC Technology CO., LTD +// +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#include <linux/crc32.h> +#include <linux/firmware.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/regmap.h> +#include <sound/soc.h> +#include "aw88166.h" +#include "aw88395/aw88395_device.h" + +struct aw88166 { + struct aw_device *aw_pa; + struct mutex lock; + struct gpio_desc *reset_gpio; + struct delayed_work start_work; + struct regmap *regmap; + struct aw_container *aw_cfg; + + unsigned int check_val; + unsigned int crc_init_val; + unsigned int vcalb_init_val; + unsigned int re_init_val; + unsigned int dither_st; + bool phase_sync; +}; + +static const struct regmap_config aw88166_remap_config = { + .val_bits = 16, + .reg_bits = 8, + .max_register = AW88166_REG_MAX, + .reg_format_endian = REGMAP_ENDIAN_LITTLE, + .val_format_endian = REGMAP_ENDIAN_BIG, +}; + +static int aw_dev_dsp_write_16bit(struct aw_device *aw_dev, + unsigned short dsp_addr, unsigned int dsp_data) +{ + int ret; + + ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr); + if (ret) { + dev_err(aw_dev->dev, "%s write addr error, ret=%d", __func__, ret); + return ret; + } + + ret = regmap_write(aw_dev->regmap, AW88166_DSPMDAT_REG, (u16)dsp_data); + if (ret) { + dev_err(aw_dev->dev, "%s write data error, ret=%d", __func__, ret); + return ret; + } + + return 0; +} + +static int aw_dev_dsp_read_16bit(struct aw_device *aw_dev, + unsigned short dsp_addr, unsigned int *dsp_data) +{ + unsigned int temp_data; + int ret; + + ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr); + if (ret) { + dev_err(aw_dev->dev, "%s write error, ret=%d", __func__, ret); + return ret; + } + + ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data); + if (ret) { + dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret); + return ret; + } + *dsp_data = temp_data; + + return 0; +} + +static int aw_dev_dsp_read_32bit(struct aw_device *aw_dev, + unsigned short dsp_addr, unsigned int *dsp_data) +{ + unsigned int temp_data; + int ret; + + ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, dsp_addr); + if (ret) { + dev_err(aw_dev->dev, "%s write error, ret=%d", __func__, ret); + return ret; + } + + ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data); + if (ret) { + dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret); + return ret; + } + *dsp_data = temp_data; + + ret = regmap_read(aw_dev->regmap, AW88166_DSPMDAT_REG, &temp_data); + if (ret) { + dev_err(aw_dev->dev, "%s read error, ret=%d", __func__, ret); + return ret; + } + *dsp_data |= (temp_data << 16); + + return 0; +} + +static int aw_dev_dsp_read(struct aw_device *aw_dev, + unsigned short dsp_addr, unsigned int *dsp_data, unsigned char data_type) +{ + u32 reg_value; + int ret; + + mutex_lock(&aw_dev->dsp_lock); + switch (data_type) { + case AW88166_DSP_16_DATA: + ret = aw_dev_dsp_read_16bit(aw_dev, dsp_addr, dsp_data); + if (ret) + dev_err(aw_dev->dev, "read dsp_addr[0x%x] 16-bit failed", (u32)dsp_addr); + break; + case AW88166_DSP_32_DATA: + ret = aw_dev_dsp_read_32bit(aw_dev, dsp_addr, dsp_data); + if (ret) + dev_err(aw_dev->dev, "read dsp_addr[0x%x] 32-bit failed", (u32)dsp_addr); + break; + default: + dev_err(aw_dev->dev, "data type[%d] unsupported", data_type); + ret = -EINVAL; + break; + } + + /* clear dsp chip select state */ + if (regmap_read(aw_dev->regmap, AW88166_ID_REG, ®_value)) + dev_err(aw_dev->dev, "%s fail to clear chip state. ret=%d\n", __func__, ret); + mutex_unlock(&aw_dev->dsp_lock); + + return ret; +} + +static void aw_dev_pwd(struct aw_device *aw_dev, bool pwd) +{ + int ret; + + if (pwd) + ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_PWDN_MASK, AW88166_PWDN_POWER_DOWN_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_PWDN_MASK, AW88166_PWDN_WORKING_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +static void aw_dev_get_int_status(struct aw_device *aw_dev, unsigned short *int_status) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88166_SYSINT_REG, ®_val); + if (ret) + dev_err(aw_dev->dev, "read interrupt reg fail, ret=%d", ret); + else + *int_status = reg_val; + + dev_dbg(aw_dev->dev, "read interrupt reg=0x%04x", *int_status); +} + +static void aw_dev_clear_int_status(struct aw_device *aw_dev) +{ + u16 int_status; + + /* read int status and clear */ + aw_dev_get_int_status(aw_dev, &int_status); + /* make sure int status is clear */ + aw_dev_get_int_status(aw_dev, &int_status); + if (int_status) + dev_dbg(aw_dev->dev, "int status(%d) is not cleaned.\n", int_status); +} + +static int aw_dev_get_iis_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88166_SYSST_REG, ®_val); + if (ret) + return ret; + if ((reg_val & AW88166_BIT_PLL_CHECK) != AW88166_BIT_PLL_CHECK) { + dev_err(aw_dev->dev, "check pll lock fail, reg_val:0x%04x", reg_val); + return -EINVAL; + } + + return 0; +} + +static int aw_dev_check_mode1_pll(struct aw_device *aw_dev) +{ + int ret, i; + + for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode1 iis signal check error"); + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static int aw_dev_check_mode2_pll(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88166_PLLCTRL2_REG, ®_val); + if (ret) + return ret; + + reg_val &= (~AW88166_CCO_MUX_MASK); + if (reg_val == AW88166_CCO_MUX_DIVIDED_VALUE) { + dev_dbg(aw_dev->dev, "CCO_MUX is already divider"); + return -EPERM; + } + + /* change mode2 */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_PLLCTRL2_REG, + ~AW88166_CCO_MUX_MASK, AW88166_CCO_MUX_DIVIDED_VALUE); + if (ret) + return ret; + + for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 iis signal check error"); + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + } else { + break; + } + } + + /* change mode1 */ + regmap_update_bits(aw_dev->regmap, AW88166_PLLCTRL2_REG, + ~AW88166_CCO_MUX_MASK, AW88166_CCO_MUX_BYPASS_VALUE); + if (ret == 0) { + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) { + ret = aw_dev_get_iis_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 switch to mode1, iis signal check error"); + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + } else { + break; + } + } + } + + return ret; +} + +static int aw_dev_check_syspll(struct aw_device *aw_dev) +{ + int ret; + + ret = aw_dev_check_mode1_pll(aw_dev); + if (ret) { + dev_dbg(aw_dev->dev, "mode1 check iis failed try switch to mode2 check"); + ret = aw_dev_check_mode2_pll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "mode2 check iis failed"); + return ret; + } + } + + return 0; +} + +static int aw_dev_check_sysst(struct aw_device *aw_dev) +{ + unsigned int check_val; + unsigned int reg_val; + int ret, i; + + ret = regmap_read(aw_dev->regmap, AW88166_PWMCTRL3_REG, ®_val); + if (ret) + return ret; + + if (reg_val & (~AW88166_NOISE_GATE_EN_MASK)) + check_val = AW88166_BIT_SYSST_NOSWS_CHECK; + else + check_val = AW88166_BIT_SYSST_SWS_CHECK; + + for (i = 0; i < AW88166_DEV_SYSST_CHECK_MAX; i++) { + ret = regmap_read(aw_dev->regmap, AW88166_SYSST_REG, ®_val); + if (ret) + return ret; + + if ((reg_val & (~AW88166_BIT_SYSST_CHECK_MASK) & check_val) != check_val) { + dev_err(aw_dev->dev, "check sysst fail, cnt=%d, reg_val=0x%04x, check:0x%x", + i, reg_val, AW88166_BIT_SYSST_NOSWS_CHECK); + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + } else { + return 0; + } + } + + return -EPERM; +} + +static void aw_dev_amppd(struct aw_device *aw_dev, bool amppd) +{ + int ret; + + if (amppd) + ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_AMPPD_MASK, AW88166_AMPPD_POWER_DOWN_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_AMPPD_MASK, AW88166_AMPPD_WORKING_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +static void aw_dev_dsp_enable(struct aw_device *aw_dev, bool is_enable) +{ + int ret; + + if (is_enable) + ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_DSPBY_MASK, AW88166_DSPBY_WORKING_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_DSPBY_MASK, AW88166_DSPBY_BYPASS_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed\n", __func__); +} + +static int aw88166_dev_get_icalk(struct aw88166 *aw88166, int16_t *icalk) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + unsigned int efrm_reg_val, efrl_reg_val; + uint16_t ef_isn_geslp, ef_isn_h5bits; + uint16_t icalk_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88166_EFRM2_REG, &efrm_reg_val); + if (ret) + return ret; + + ef_isn_geslp = (efrm_reg_val & (~AW88166_EF_ISN_GESLP_MASK)) >> + AW88166_EF_ISN_GESLP_SHIFT; + + ret = regmap_read(aw_dev->regmap, AW88166_EFRL_REG, &efrl_reg_val); + if (ret) + return ret; + + ef_isn_h5bits = (efrl_reg_val & (~AW88166_EF_ISN_H5BITS_MASK)) >> + AW88166_EF_ISN_H5BITS_SHIFT; + + if (aw88166->check_val == AW_EF_AND_CHECK) + icalk_val = ef_isn_geslp & (ef_isn_h5bits | AW88166_EF_ISN_H5BITS_SIGN_MASK); + else + icalk_val = ef_isn_geslp | (ef_isn_h5bits & (~AW88166_EF_ISN_H5BITS_SIGN_MASK)); + + if (icalk_val & (~AW88166_ICALK_SIGN_MASK)) + icalk_val = icalk_val | AW88166_ICALK_NEG_MASK; + *icalk = (int16_t)icalk_val; + + return 0; +} + +static int aw88166_dev_get_vcalk(struct aw88166 *aw88166, int16_t *vcalk) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + unsigned int efrm_reg_val, efrl_reg_val; + uint16_t ef_vsn_geslp, ef_vsn_h3bits; + uint16_t vcalk_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88166_EFRM2_REG, &efrm_reg_val); + if (ret) + return ret; + + ef_vsn_geslp = (efrm_reg_val & (~AW88166_EF_VSN_GESLP_MASK)) >> + AW88166_EF_VSN_GESLP_SHIFT; + + ret = regmap_read(aw_dev->regmap, AW88166_EFRL_REG, &efrl_reg_val); + if (ret) + return ret; + + ef_vsn_h3bits = (efrl_reg_val & (~AW88166_EF_VSN_H3BITS_MASK)) >> + AW88166_EF_VSN_H3BITS_SHIFT; + + if (aw88166->check_val == AW_EF_AND_CHECK) + vcalk_val = ef_vsn_geslp & (ef_vsn_h3bits | AW88166_EF_VSN_H3BITS_SIGN_MASK); + else + vcalk_val = ef_vsn_geslp | (ef_vsn_h3bits & (~AW88166_EF_VSN_H3BITS_SIGN_MASK)); + + if (vcalk_val & (~AW88166_VCALK_SIGN_MASK)) + vcalk_val = vcalk_val | AW88166_VCALK_NEG_MASK; + *vcalk = (int16_t)vcalk_val; + + return 0; +} + +static int aw88166_dev_set_vcalb(struct aw88166 *aw88166) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + int32_t ical_k, vcal_k, vcalb; + int16_t icalk, vcalk; + unsigned int reg_val; + int ret; + + ret = aw88166_dev_get_icalk(aw88166, &icalk); + if (ret) { + dev_err(aw_dev->dev, "get icalk failed\n"); + return ret; + } + ical_k = icalk * AW88166_ICABLK_FACTOR + AW88166_CABL_BASE_VALUE; + + ret = aw88166_dev_get_vcalk(aw88166, &vcalk); + if (ret) { + dev_err(aw_dev->dev, "get vbcalk failed\n"); + return ret; + } + vcal_k = vcalk * AW88166_VCABLK_FACTOR + AW88166_CABL_BASE_VALUE; + + vcalb = AW88166_VCALB_ACCURACY * AW88166_VSCAL_FACTOR / + AW88166_ISCAL_FACTOR * ical_k / vcal_k * aw88166->vcalb_init_val; + + vcalb = vcalb >> AW88166_VCALB_ADJ_FACTOR; + reg_val = (uint32_t)vcalb; + + regmap_write(aw_dev->regmap, AW88166_DSPVCALB_REG, reg_val); + + return 0; +} + +static int aw_dev_init_vcalb_update(struct aw88166 *aw88166, int flag) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + int ret; + + switch (flag) { + case AW88166_RECOVERY_SEC_DATA: + ret = regmap_write(aw_dev->regmap, AW88166_DSPVCALB_REG, aw88166->vcalb_init_val); + break; + case AW88166_RECORD_SEC_DATA: + ret = regmap_read(aw_dev->regmap, AW88166_DSPVCALB_REG, &aw88166->vcalb_init_val); + break; + default: + dev_err(aw_dev->dev, "unsupported type:%d\n", flag); + ret = -EINVAL; + break; + } + + return ret; +} + +static int aw_dev_init_re_update(struct aw88166 *aw88166, int flag) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + unsigned int re_temp_h, re_temp_l; + int ret; + + switch (flag) { + case AW88166_RECOVERY_SEC_DATA: + ret = regmap_write(aw_dev->regmap, AW88166_ACR1_REG, aw88166->re_init_val >> 16); + if (ret) + return ret; + ret = regmap_write(aw_dev->regmap, AW88166_ACR2_REG, + (uint16_t)aw88166->re_init_val); + if (ret) + return ret; + break; + case AW88166_RECORD_SEC_DATA: + ret = regmap_read(aw_dev->regmap, AW88166_ACR1_REG, &re_temp_h); + if (ret) + return ret; + ret = regmap_read(aw_dev->regmap, AW88166_ACR2_REG, &re_temp_l); + if (ret) + return ret; + aw88166->re_init_val = (re_temp_h << 16) + re_temp_l; + break; + default: + dev_err(aw_dev->dev, "unsupported type:%d\n", flag); + ret = -EINVAL; + break; + } + + return ret; +} + +static void aw_dev_backup_sec_record(struct aw88166 *aw88166) +{ + aw_dev_init_vcalb_update(aw88166, AW88166_RECORD_SEC_DATA); + aw_dev_init_re_update(aw88166, AW88166_RECOVERY_SEC_DATA); +} + +static void aw_dev_backup_sec_recovery(struct aw88166 *aw88166) +{ + aw_dev_init_vcalb_update(aw88166, AW88166_RECOVERY_SEC_DATA); + aw_dev_init_re_update(aw88166, AW88166_RECOVERY_SEC_DATA); +} + +static int aw_dev_update_cali_re(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + uint16_t re_lbits, re_hbits; + u32 cali_re; + int ret; + + if ((aw_dev->cali_desc.cali_re >= AW88166_CALI_RE_MAX) || + (aw_dev->cali_desc.cali_re <= AW88166_CALI_RE_MIN)) + return -EINVAL; + + cali_re = AW88166_SHOW_RE_TO_DSP_RE((aw_dev->cali_desc.cali_re + + aw_dev->cali_desc.ra), AW88166_DSP_RE_SHIFT); + + re_hbits = (cali_re & (~AW88166_CALI_RE_HBITS_MASK)) >> AW88166_CALI_RE_HBITS_SHIFT; + re_lbits = (cali_re & (~AW88166_CALI_RE_LBITS_MASK)) >> AW88166_CALI_RE_LBITS_SHIFT; + + ret = regmap_write(aw_dev->regmap, AW88166_ACR1_REG, re_hbits); + if (ret) { + dev_err(aw_dev->dev, "set cali re error"); + return ret; + } + + ret = regmap_write(aw_dev->regmap, AW88166_ACR2_REG, re_lbits); + if (ret) + dev_err(aw_dev->dev, "set cali re error"); + + return ret; +} + +static int aw_dev_fw_crc_check(struct aw_device *aw_dev) +{ + uint16_t check_val, fw_len_val; + unsigned int reg_val; + int ret; + + /* calculate fw_end_addr */ + fw_len_val = ((aw_dev->dsp_fw_len / AW_FW_ADDR_LEN) - 1) + AW88166_CRC_FW_BASE_ADDR; + + /* write fw_end_addr to crc_end_addr */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG, + ~AW88166_CRC_END_ADDR_MASK, fw_len_val); + if (ret) + return ret; + /* enable fw crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG, + ~AW88166_CRC_CODE_EN_MASK, AW88166_CRC_CODE_EN_ENABLE_VALUE); + + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + + /* read crc check result */ + regmap_read(aw_dev->regmap, AW88166_HAGCST_REG, ®_val); + if (ret) + return ret; + + check_val = (reg_val & (~AW88166_CRC_CHECK_BITS_MASK)) >> AW88166_CRC_CHECK_START_BIT; + + /* disable fw crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG, + ~AW88166_CRC_CODE_EN_MASK, AW88166_CRC_CODE_EN_DISABLE_VALUE); + if (ret) + return ret; + + if (check_val != AW88166_CRC_CHECK_PASS_VAL) { + dev_err(aw_dev->dev, "%s failed, check_val 0x%x != 0x%x\n", + __func__, check_val, AW88166_CRC_CHECK_PASS_VAL); + ret = -EINVAL; + } + + return ret; +} + +static int aw_dev_cfg_crc_check(struct aw_device *aw_dev) +{ + uint16_t check_val, cfg_len_val; + unsigned int reg_val; + int ret; + + /* calculate cfg end addr */ + cfg_len_val = ((aw_dev->dsp_cfg_len / AW_FW_ADDR_LEN) - 1) + AW88166_CRC_CFG_BASE_ADDR; + + /* write cfg_end_addr to crc_end_addr */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG, + ~AW88166_CRC_END_ADDR_MASK, cfg_len_val); + if (ret) + return ret; + + /* enable cfg crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG, + ~AW88166_CRC_CFG_EN_MASK, AW88166_CRC_CFG_EN_ENABLE_VALUE); + if (ret) + return ret; + + usleep_range(AW88166_1000_US, AW88166_1000_US + 10); + + /* read crc check result */ + ret = regmap_read(aw_dev->regmap, AW88166_HAGCST_REG, ®_val); + if (ret) + return ret; + + check_val = (reg_val & (~AW88166_CRC_CHECK_BITS_MASK)) >> AW88166_CRC_CHECK_START_BIT; + + /* disable cfg crc check */ + ret = regmap_update_bits(aw_dev->regmap, AW88166_CRCCTRL_REG, + ~AW88166_CRC_CFG_EN_MASK, AW88166_CRC_CFG_EN_DISABLE_VALUE); + if (ret) + return ret; + + if (check_val != AW88166_CRC_CHECK_PASS_VAL) { + dev_err(aw_dev->dev, "crc_check failed, check val 0x%x != 0x%x\n", + check_val, AW88166_CRC_CHECK_PASS_VAL); + ret = -EINVAL; + } + + return ret; +} + +static int aw_dev_hw_crc_check(struct aw88166 *aw88166) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + int ret; + + ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG, + ~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_BYPASS_VALUE); + if (ret) + return ret; + + ret = aw_dev_fw_crc_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "fw_crc_check failed\n"); + goto crc_check_failed; + } + + ret = aw_dev_cfg_crc_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "cfg_crc_check failed\n"); + goto crc_check_failed; + } + + ret = regmap_write(aw_dev->regmap, AW88166_CRCCTRL_REG, aw88166->crc_init_val); + if (ret) + return ret; + + ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG, + ~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_WORK_VALUE); + + return ret; + +crc_check_failed: + regmap_update_bits(aw_dev->regmap, AW88166_I2SCFG1_REG, + ~AW88166_RAM_CG_BYP_MASK, AW88166_RAM_CG_BYP_WORK_VALUE); + return ret; +} + +static void aw_dev_i2s_tx_enable(struct aw_device *aw_dev, bool flag) +{ + int ret; + + if (flag) + ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCTRL3_REG, + ~AW88166_I2STXEN_MASK, AW88166_I2STXEN_ENABLE_VALUE); + else + ret = regmap_update_bits(aw_dev->regmap, AW88166_I2SCTRL3_REG, + ~AW88166_I2STXEN_MASK, AW88166_I2STXEN_DISABLE_VALUE); + + if (ret) + dev_dbg(aw_dev->dev, "%s failed", __func__); +} + +static int aw_dev_get_dsp_status(struct aw_device *aw_dev) +{ + unsigned int reg_val; + int ret; + + ret = regmap_read(aw_dev->regmap, AW88166_WDT_REG, ®_val); + if (ret) + return ret; + if (!(reg_val & (~AW88166_WDT_CNT_MASK))) + return -EPERM; + + return 0; +} + +static int aw_dev_dsp_check(struct aw_device *aw_dev) +{ + int ret, i; + + switch (aw_dev->dsp_cfg) { + case AW88166_DEV_DSP_BYPASS: + dev_dbg(aw_dev->dev, "dsp bypass"); + ret = 0; + break; + case AW88166_DEV_DSP_WORK: + aw_dev_dsp_enable(aw_dev, false); + aw_dev_dsp_enable(aw_dev, true); + usleep_range(AW88166_1000_US, AW88166_1000_US + 10); + for (i = 0; i < AW88166_DEV_DSP_CHECK_MAX; i++) { + ret = aw_dev_get_dsp_status(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp wdt status error=%d", ret); + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + } + } + break; + default: + dev_err(aw_dev->dev, "unknown dsp cfg=%d", aw_dev->dsp_cfg); + ret = -EINVAL; + break; + } + + return ret; +} + +static int aw_dev_set_volume(struct aw_device *aw_dev, unsigned int value) +{ + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + unsigned int reg_value; + u16 real_value; + int ret; + + real_value = min((value + vol_desc->init_volume), (unsigned int)AW88166_MUTE_VOL); + + ret = regmap_read(aw_dev->regmap, AW88166_SYSCTRL2_REG, ®_value); + if (ret) + return ret; + + dev_dbg(aw_dev->dev, "value 0x%x , reg:0x%x", value, real_value); + + real_value = (real_value << AW88166_VOL_START_BIT) | (reg_value & AW88166_VOL_MASK); + + ret = regmap_write(aw_dev->regmap, AW88166_SYSCTRL2_REG, real_value); + + return ret; +} + +static void aw_dev_fade_in(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + u16 fade_in_vol = desc->ctl_volume; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_in_time == 0) { + aw_dev_set_volume(aw_dev, fade_in_vol); + return; + } + + for (i = AW88166_MUTE_VOL; i >= fade_in_vol; i -= fade_step) { + aw_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_in_time, aw_dev->fade_in_time + 10); + } + + if (i != fade_in_vol) + aw_dev_set_volume(aw_dev, fade_in_vol); +} + +static void aw_dev_fade_out(struct aw_device *aw_dev) +{ + struct aw_volume_desc *desc = &aw_dev->volume_desc; + int fade_step = aw_dev->fade_step; + int i; + + if (fade_step == 0 || aw_dev->fade_out_time == 0) { + aw_dev_set_volume(aw_dev, AW88166_MUTE_VOL); + return; + } + + for (i = desc->ctl_volume; i <= AW88166_MUTE_VOL; i += fade_step) { + aw_dev_set_volume(aw_dev, i); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } + + if (i != AW88166_MUTE_VOL) { + aw_dev_set_volume(aw_dev, AW88166_MUTE_VOL); + usleep_range(aw_dev->fade_out_time, aw_dev->fade_out_time + 10); + } +} + +static void aw88166_dev_mute(struct aw_device *aw_dev, bool is_mute) +{ + if (is_mute) { + aw_dev_fade_out(aw_dev); + regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_HMUTE_MASK, AW88166_HMUTE_ENABLE_VALUE); + } else { + regmap_update_bits(aw_dev->regmap, AW88166_SYSCTRL_REG, + ~AW88166_HMUTE_MASK, AW88166_HMUTE_DISABLE_VALUE); + aw_dev_fade_in(aw_dev); + } +} + +static void aw88166_dev_set_dither(struct aw88166 *aw88166, bool dither) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + + if (dither) + regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG, + ~AW88166_DITHER_EN_MASK, AW88166_DITHER_EN_ENABLE_VALUE); + else + regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG, + ~AW88166_DITHER_EN_MASK, AW88166_DITHER_EN_DISABLE_VALUE); +} + +static int aw88166_dev_start(struct aw88166 *aw88166) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + int ret; + + if (aw_dev->status == AW88166_DEV_PW_ON) { + dev_dbg(aw_dev->dev, "already power on"); + return 0; + } + + aw88166_dev_set_dither(aw88166, false); + + /* power on */ + aw_dev_pwd(aw_dev, false); + usleep_range(AW88166_2000_US, AW88166_2000_US + 10); + + ret = aw_dev_check_syspll(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "pll check failed cannot start\n"); + goto pll_check_fail; + } + + /* amppd on */ + aw_dev_amppd(aw_dev, false); + usleep_range(AW88166_1000_US, AW88166_1000_US + 50); + + /* check i2s status */ + ret = aw_dev_check_sysst(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "sysst check failed\n"); + goto sysst_check_fail; + } + + if (aw_dev->dsp_cfg == AW88166_DEV_DSP_WORK) { + aw_dev_backup_sec_recovery(aw88166); + ret = aw_dev_hw_crc_check(aw88166); + if (ret) { + dev_err(aw_dev->dev, "dsp crc check failed\n"); + goto crc_check_fail; + } + aw_dev_dsp_enable(aw_dev, false); + aw88166_dev_set_vcalb(aw88166); + aw_dev_update_cali_re(&aw_dev->cali_desc); + ret = aw_dev_dsp_check(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "dsp status check failed\n"); + goto dsp_check_fail; + } + } else { + dev_dbg(aw_dev->dev, "start pa with dsp bypass"); + } + + /* enable tx feedback */ + aw_dev_i2s_tx_enable(aw_dev, true); + + if (aw88166->dither_st == AW88166_DITHER_EN_ENABLE_VALUE) + aw88166_dev_set_dither(aw88166, true); + + /* close mute */ + aw88166_dev_mute(aw_dev, false); + /* clear inturrupt */ + aw_dev_clear_int_status(aw_dev); + aw_dev->status = AW88166_DEV_PW_ON; + + return 0; + +dsp_check_fail: +crc_check_fail: + aw_dev_dsp_enable(aw_dev, false); +sysst_check_fail: + aw_dev_clear_int_status(aw_dev); + aw_dev_amppd(aw_dev, true); +pll_check_fail: + aw_dev_pwd(aw_dev, true); + aw_dev->status = AW88166_DEV_PW_OFF; + + return ret; +} + +static int aw_dev_dsp_update_container(struct aw_device *aw_dev, + unsigned char *data, unsigned int len, unsigned short base) +{ + u32 tmp_len; + int i, ret; + + mutex_lock(&aw_dev->dsp_lock); + ret = regmap_write(aw_dev->regmap, AW88166_DSPMADD_REG, base); + if (ret) + goto error_operation; + + for (i = 0; i < len; i += AW88166_MAX_RAM_WRITE_BYTE_SIZE) { + if ((len - i) < AW88166_MAX_RAM_WRITE_BYTE_SIZE) + tmp_len = len - i; + else + tmp_len = AW88166_MAX_RAM_WRITE_BYTE_SIZE; + + ret = regmap_raw_write(aw_dev->regmap, AW88166_DSPMDAT_REG, + &data[i], tmp_len); + if (ret) + goto error_operation; + } + mutex_unlock(&aw_dev->dsp_lock); + + return 0; + +error_operation: + mutex_unlock(&aw_dev->dsp_lock); + return ret; +} + +static int aw_dev_get_ra(struct aw_cali_desc *cali_desc) +{ + struct aw_device *aw_dev = + container_of(cali_desc, struct aw_device, cali_desc); + u32 dsp_ra; + int ret; + + ret = aw_dev_dsp_read(aw_dev, AW88166_DSP_REG_CFG_ADPZ_RA, + &dsp_ra, AW88166_DSP_32_DATA); + if (ret) { + dev_err(aw_dev->dev, "read ra error\n"); + return ret; + } + + cali_desc->ra = AW88166_DSP_RE_TO_SHOW_RE(dsp_ra, + AW88166_DSP_RE_SHIFT); + + return 0; +} + +static int aw_dev_dsp_update_cfg(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int ret; + + dev_dbg(aw_dev->dev, "dsp config len:%d", len); + + if (!len || !data) { + dev_err(aw_dev->dev, "dsp config data is null or len is 0\n"); + return -EINVAL; + } + + ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88166_DSP_CFG_ADDR); + if (ret) + return ret; + + aw_dev->dsp_cfg_len = len; + + ret = aw_dev_get_ra(&aw_dev->cali_desc); + + return ret; +} + +static int aw_dev_dsp_update_fw(struct aw_device *aw_dev, + unsigned char *data, unsigned int len) +{ + int ret; + + dev_dbg(aw_dev->dev, "dsp firmware len:%d", len); + + if (!len || !data) { + dev_err(aw_dev->dev, "dsp firmware data is null or len is 0\n"); + return -EINVAL; + } + + aw_dev->dsp_fw_len = len; + ret = aw_dev_dsp_update_container(aw_dev, data, len, AW88166_DSP_FW_ADDR); + + return ret; +} + +static int aw_dev_check_sram(struct aw_device *aw_dev) +{ + unsigned int reg_val; + + mutex_lock(&aw_dev->dsp_lock); + /* read dsp_rom_check_reg */ + aw_dev_dsp_read_16bit(aw_dev, AW88166_DSP_ROM_CHECK_ADDR, ®_val); + if (reg_val != AW88166_DSP_ROM_CHECK_DATA) { + dev_err(aw_dev->dev, "check dsp rom failed, read[0x%x] != check[0x%x]\n", + reg_val, AW88166_DSP_ROM_CHECK_DATA); + goto error; + } + + /* check dsp_cfg_base_addr */ + aw_dev_dsp_write_16bit(aw_dev, AW88166_DSP_CFG_ADDR, AW88166_DSP_ODD_NUM_BIT_TEST); + aw_dev_dsp_read_16bit(aw_dev, AW88166_DSP_CFG_ADDR, ®_val); + if (reg_val != AW88166_DSP_ODD_NUM_BIT_TEST) { + dev_err(aw_dev->dev, "check dsp cfg failed, read[0x%x] != write[0x%x]\n", + reg_val, AW88166_DSP_ODD_NUM_BIT_TEST); + goto error; + } + mutex_unlock(&aw_dev->dsp_lock); + + return 0; +error: + mutex_unlock(&aw_dev->dsp_lock); + return -EPERM; +} + +static void aw_dev_select_memclk(struct aw_device *aw_dev, unsigned char flag) +{ + int ret; + + switch (flag) { + case AW88166_DEV_MEMCLK_PLL: + ret = regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG, + ~AW88166_MEM_CLKSEL_MASK, + AW88166_MEM_CLKSEL_DAPHCLK_VALUE); + if (ret) + dev_err(aw_dev->dev, "memclk select pll failed\n"); + break; + case AW88166_DEV_MEMCLK_OSC: + ret = regmap_update_bits(aw_dev->regmap, AW88166_DBGCTRL_REG, + ~AW88166_MEM_CLKSEL_MASK, + AW88166_MEM_CLKSEL_OSCCLK_VALUE); + if (ret) + dev_err(aw_dev->dev, "memclk select OSC failed\n"); + break; + default: + dev_err(aw_dev->dev, "unknown memclk config, flag=0x%x\n", flag); + break; + } +} + +static int aw_dev_update_reg_container(struct aw88166 *aw88166, + unsigned char *data, unsigned int len) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + struct aw_volume_desc *vol_desc = &aw_dev->volume_desc; + u16 read_vol, reg_val; + int data_len, i, ret; + int16_t *reg_data; + u8 reg_addr; + + reg_data = (int16_t *)data; + data_len = len >> 1; + + if (data_len & 0x1) { + dev_err(aw_dev->dev, "data len:%d unsupported\n", data_len); + return -EINVAL; + } + + for (i = 0; i < data_len; i += 2) { + reg_addr = reg_data[i]; + reg_val = reg_data[i + 1]; + + if (reg_addr == AW88166_DSPVCALB_REG) { + aw88166->vcalb_init_val = reg_val; + continue; + } + + if (reg_addr == AW88166_SYSCTRL_REG) { + if (reg_val & (~AW88166_DSPBY_MASK)) + aw_dev->dsp_cfg = AW88166_DEV_DSP_BYPASS; + else + aw_dev->dsp_cfg = AW88166_DEV_DSP_WORK; + + reg_val &= (AW88166_HMUTE_MASK | AW88166_PWDN_MASK | + AW88166_DSPBY_MASK); + reg_val |= (AW88166_HMUTE_ENABLE_VALUE | AW88166_PWDN_POWER_DOWN_VALUE | + AW88166_DSPBY_BYPASS_VALUE); + } + + if (reg_addr == AW88166_I2SCTRL3_REG) { + reg_val &= AW88166_I2STXEN_MASK; + reg_val |= AW88166_I2STXEN_DISABLE_VALUE; + } + + if (reg_addr == AW88166_SYSCTRL2_REG) { + read_vol = (reg_val & (~AW88166_VOL_MASK)) >> + AW88166_VOL_START_BIT; + aw_dev->volume_desc.init_volume = read_vol; + } + + if (reg_addr == AW88166_DBGCTRL_REG) { + if ((reg_val & (~AW88166_EF_DBMD_MASK)) == AW88166_EF_DBMD_OR_VALUE) + aw88166->check_val = AW_EF_OR_CHECK; + else + aw88166->check_val = AW_EF_AND_CHECK; + + aw88166->dither_st = reg_val & (~AW88166_DITHER_EN_MASK); + } + + if (reg_addr == AW88166_ACR1_REG) { + aw88166->re_init_val |= (uint32_t)reg_val << 16; + continue; + } + + if (reg_addr == AW88166_ACR2_REG) { + aw88166->re_init_val |= (uint32_t)reg_val; + continue; + } + + if (reg_addr == AW88166_CRCCTRL_REG) + aw88166->crc_init_val = reg_val; + + ret = regmap_write(aw_dev->regmap, reg_addr, reg_val); + if (ret) + return ret; + } + + aw_dev_pwd(aw_dev, false); + usleep_range(AW88166_1000_US, AW88166_1000_US + 10); + + if (aw_dev->prof_cur != aw_dev->prof_index) + vol_desc->ctl_volume = 0; + else + aw_dev_set_volume(aw_dev, vol_desc->ctl_volume); + + return 0; +} + +static int aw_dev_reg_update(struct aw88166 *aw88166, + unsigned char *data, unsigned int len) +{ + int ret; + + if (!len || !data) { + dev_err(aw88166->aw_pa->dev, "reg data is null or len is 0\n"); + return -EINVAL; + } + + ret = aw_dev_update_reg_container(aw88166, data, len); + if (ret) + dev_err(aw88166->aw_pa->dev, "reg update failed\n"); + + return ret; +} + +static int aw88166_dev_get_prof_name(struct aw_device *aw_dev, int index, char **prof_name) +{ + struct aw_prof_info *prof_info = &aw_dev->prof_info; + struct aw_prof_desc *prof_desc; + + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "index[%d] overflow count[%d]\n", + index, aw_dev->prof_info.count); + return -EINVAL; + } + + prof_desc = &aw_dev->prof_info.prof_desc[index]; + + *prof_name = prof_info->prof_name_list[prof_desc->id]; + + return 0; +} + +static int aw88166_dev_get_prof_data(struct aw_device *aw_dev, int index, + struct aw_prof_desc **prof_desc) +{ + if ((index >= aw_dev->prof_info.count) || (index < 0)) { + dev_err(aw_dev->dev, "%s: index[%d] overflow count[%d]\n", + __func__, index, aw_dev->prof_info.count); + return -EINVAL; + } + + *prof_desc = &aw_dev->prof_info.prof_desc[index]; + + return 0; +} + +static int aw88166_dev_fw_update(struct aw88166 *aw88166, bool up_dsp_fw_en, bool force_up_en) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + struct aw_prof_desc *prof_index_desc; + struct aw_sec_data_desc *sec_desc; + char *prof_name; + int ret; + + if ((aw_dev->prof_cur == aw_dev->prof_index) && + (force_up_en == AW88166_FORCE_UPDATE_OFF)) { + dev_dbg(aw_dev->dev, "scene no change, not update"); + return 0; + } + + if (aw_dev->fw_status == AW88166_DEV_FW_FAILED) { + dev_err(aw_dev->dev, "fw status[%d] error\n", aw_dev->fw_status); + return -EPERM; + } + + ret = aw88166_dev_get_prof_name(aw_dev, aw_dev->prof_index, &prof_name); + if (ret) + return ret; + + dev_dbg(aw_dev->dev, "start update %s", prof_name); + + ret = aw88166_dev_get_prof_data(aw_dev, aw_dev->prof_index, &prof_index_desc); + if (ret) + return ret; + + /* update reg */ + sec_desc = prof_index_desc->sec_desc; + ret = aw_dev_reg_update(aw88166, sec_desc[AW88395_DATA_TYPE_REG].data, + sec_desc[AW88395_DATA_TYPE_REG].len); + if (ret) { + dev_err(aw_dev->dev, "update reg failed\n"); + return ret; + } + + aw88166_dev_mute(aw_dev, true); + + if (aw_dev->dsp_cfg == AW88166_DEV_DSP_WORK) + aw_dev_dsp_enable(aw_dev, false); + + aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_OSC); + + ret = aw_dev_check_sram(aw_dev); + if (ret) { + dev_err(aw_dev->dev, "check sram failed\n"); + goto error; + } + + aw_dev_backup_sec_recovery(aw88166); + + if (up_dsp_fw_en) { + dev_dbg(aw_dev->dev, "fw_ver: [%x]", prof_index_desc->fw_ver); + ret = aw_dev_dsp_update_fw(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_FW].data, + sec_desc[AW88395_DATA_TYPE_DSP_FW].len); + if (ret) { + dev_err(aw_dev->dev, "update dsp fw failed\n"); + goto error; + } + } + + /* update dsp config */ + ret = aw_dev_dsp_update_cfg(aw_dev, sec_desc[AW88395_DATA_TYPE_DSP_CFG].data, + sec_desc[AW88395_DATA_TYPE_DSP_CFG].len); + if (ret) { + dev_err(aw_dev->dev, "update dsp cfg failed\n"); + goto error; + } + + aw_dev_backup_sec_record(aw88166); + + aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL); + + aw_dev->prof_cur = aw_dev->prof_index; + + return 0; + +error: + aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL); + return ret; +} + +static void aw88166_start_pa(struct aw88166 *aw88166) +{ + int ret, i; + + for (i = 0; i < AW88166_START_RETRIES; i++) { + ret = aw88166_dev_start(aw88166); + if (ret) { + dev_err(aw88166->aw_pa->dev, "aw88166 device start failed. retry = %d", i); + ret = aw88166_dev_fw_update(aw88166, AW88166_DSP_FW_UPDATE_ON, true); + if (ret) { + dev_err(aw88166->aw_pa->dev, "fw update failed"); + continue; + } + } else { + dev_dbg(aw88166->aw_pa->dev, "start success\n"); + break; + } + } +} + +static void aw88166_startup_work(struct work_struct *work) +{ + struct aw88166 *aw88166 = + container_of(work, struct aw88166, start_work.work); + + mutex_lock(&aw88166->lock); + aw88166_start_pa(aw88166); + mutex_unlock(&aw88166->lock); +} + +static void aw88166_start(struct aw88166 *aw88166, bool sync_start) +{ + int ret; + + if (aw88166->aw_pa->fw_status != AW88166_DEV_FW_OK) + return; + + if (aw88166->aw_pa->status == AW88166_DEV_PW_ON) + return; + + ret = aw88166_dev_fw_update(aw88166, AW88166_DSP_FW_UPDATE_OFF, aw88166->phase_sync); + if (ret) { + dev_err(aw88166->aw_pa->dev, "fw update failed\n"); + return; + } + + if (sync_start == AW88166_SYNC_START) + aw88166_start_pa(aw88166); + else + queue_delayed_work(system_wq, + &aw88166->start_work, + AW88166_START_WORK_DELAY_MS); +} + +static int aw_dev_check_sysint(struct aw_device *aw_dev) +{ + u16 reg_val; + + aw_dev_get_int_status(aw_dev, ®_val); + if (reg_val & AW88166_BIT_SYSINT_CHECK) { + dev_err(aw_dev->dev, "pa stop check fail:0x%04x\n", reg_val); + return -EINVAL; + } + + return 0; +} + +static int aw88166_stop(struct aw_device *aw_dev) +{ + struct aw_sec_data_desc *dsp_cfg = + &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_CFG]; + struct aw_sec_data_desc *dsp_fw = + &aw_dev->prof_info.prof_desc[aw_dev->prof_cur].sec_desc[AW88395_DATA_TYPE_DSP_FW]; + int int_st; + + if (aw_dev->status == AW88166_DEV_PW_OFF) { + dev_dbg(aw_dev->dev, "already power off"); + return 0; + } + + aw_dev->status = AW88166_DEV_PW_OFF; + + aw88166_dev_mute(aw_dev, true); + usleep_range(AW88166_4000_US, AW88166_4000_US + 100); + + aw_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88166_1000_US, AW88166_1000_US + 100); + + int_st = aw_dev_check_sysint(aw_dev); + + aw_dev_dsp_enable(aw_dev, false); + + aw_dev_amppd(aw_dev, true); + + if (int_st) { + aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_OSC); + aw_dev_dsp_update_fw(aw_dev, dsp_fw->data, dsp_fw->len); + aw_dev_dsp_update_cfg(aw_dev, dsp_cfg->data, dsp_cfg->len); + aw_dev_select_memclk(aw_dev, AW88166_DEV_MEMCLK_PLL); + } + + aw_dev_pwd(aw_dev, true); + + return 0; +} + +static struct snd_soc_dai_driver aw88166_dai[] = { + { + .name = "aw88166-aif", + .id = 1, + .playback = { + .stream_name = "Speaker_Playback", + .channels_min = 1, + .channels_max = 2, + .rates = AW88166_RATES, + .formats = AW88166_FORMATS, + }, + .capture = { + .stream_name = "Speaker_Capture", + .channels_min = 1, + .channels_max = 2, + .rates = AW88166_RATES, + .formats = AW88166_FORMATS, + }, + }, +}; + +static int aw88166_get_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88166->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_in_time; + + return 0; +} + +static int aw88166_set_fade_in_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88166->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_in_time) { + aw_dev->fade_in_time = time; + return 1; + } + + return 0; +} + +static int aw88166_get_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); + struct aw_device *aw_dev = aw88166->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->fade_out_time; + + return 0; +} + +static int aw88166_set_fade_out_time(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88166->aw_pa; + int time; + + time = ucontrol->value.integer.value[0]; + if (time < mc->min || time > mc->max) + return -EINVAL; + + if (time != aw_dev->fade_out_time) { + aw_dev->fade_out_time = time; + return 1; + } + + return 0; +} + +static int aw88166_dev_set_profile_index(struct aw_device *aw_dev, int index) +{ + /* check the index whether is valid */ + if ((index >= aw_dev->prof_info.count) || (index < 0)) + return -EINVAL; + /* check the index whether change */ + if (aw_dev->prof_index == index) + return -EINVAL; + + aw_dev->prof_index = index; + dev_dbg(aw_dev->dev, "set prof[%s]", + aw_dev->prof_info.prof_name_list[aw_dev->prof_info.prof_desc[index].id]); + + return 0; +} + +static int aw88166_profile_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + char *prof_name, *name; + int count, ret; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + + count = aw88166->aw_pa->prof_info.count; + if (count <= 0) { + uinfo->value.enumerated.items = 0; + return 0; + } + + uinfo->value.enumerated.items = count; + + if (uinfo->value.enumerated.item >= count) + uinfo->value.enumerated.item = count - 1; + + name = uinfo->value.enumerated.name; + count = uinfo->value.enumerated.item; + + ret = aw88166_dev_get_prof_name(aw88166->aw_pa, count, &prof_name); + if (ret) { + strscpy(uinfo->value.enumerated.name, "null", + strlen("null") + 1); + return 0; + } + + strscpy(name, prof_name, sizeof(uinfo->value.enumerated.name)); + + return 0; +} + +static int aw88166_profile_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88166->aw_pa->prof_index; + + return 0; +} + +static int aw88166_profile_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + int ret; + + mutex_lock(&aw88166->lock); + ret = aw88166_dev_set_profile_index(aw88166->aw_pa, ucontrol->value.integer.value[0]); + if (ret) { + dev_dbg(codec->dev, "profile index does not change"); + mutex_unlock(&aw88166->lock); + return 0; + } + + if (aw88166->aw_pa->status) { + aw88166_stop(aw88166->aw_pa); + aw88166_start(aw88166, AW88166_SYNC_START); + } + + mutex_unlock(&aw88166->lock); + + return 1; +} + +static int aw88166_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc; + + ucontrol->value.integer.value[0] = vol_desc->ctl_volume; + + return 0; +} + +static int aw88166_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + struct aw_volume_desc *vol_desc = &aw88166->aw_pa->volume_desc; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (vol_desc->ctl_volume != value) { + vol_desc->ctl_volume = value; + aw_dev_set_volume(aw88166->aw_pa, vol_desc->ctl_volume); + + return 1; + } + + return 0; +} + +static int aw88166_get_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + + ucontrol->value.integer.value[0] = aw88166->aw_pa->fade_step; + + return 0; +} + +static int aw88166_set_fade_step(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw88166->aw_pa->fade_step != value) { + aw88166->aw_pa->fade_step = value; + return 1; + } + + return 0; +} + +static int aw88166_re_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + struct aw_device *aw_dev = aw88166->aw_pa; + + ucontrol->value.integer.value[0] = aw_dev->cali_desc.cali_re; + + return 0; +} + +static int aw88166_re_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *codec = snd_soc_kcontrol_component(kcontrol); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct aw_device *aw_dev = aw88166->aw_pa; + int value; + + value = ucontrol->value.integer.value[0]; + if (value < mc->min || value > mc->max) + return -EINVAL; + + if (aw_dev->cali_desc.cali_re != value) { + aw_dev->cali_desc.cali_re = value; + return 1; + } + + return 0; +} + +static int aw88166_dev_init(struct aw88166 *aw88166, struct aw_container *aw_cfg) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + int ret; + + ret = aw88395_dev_cfg_load(aw_dev, aw_cfg); + if (ret) { + dev_err(aw_dev->dev, "aw_dev acf parse failed\n"); + return -EINVAL; + } + aw_dev->fade_in_time = AW88166_1000_US / 10; + aw_dev->fade_out_time = AW88166_1000_US >> 1; + aw_dev->prof_cur = aw_dev->prof_info.prof_desc[0].id; + aw_dev->prof_index = aw_dev->prof_info.prof_desc[0].id; + + ret = aw88166_dev_fw_update(aw88166, AW88166_FORCE_UPDATE_ON, AW88166_DSP_FW_UPDATE_ON); + if (ret) { + dev_err(aw_dev->dev, "fw update failed ret = %d\n", ret); + return ret; + } + + aw88166_dev_mute(aw_dev, true); + + /* close tx feedback */ + aw_dev_i2s_tx_enable(aw_dev, false); + usleep_range(AW88166_1000_US, AW88166_1000_US + 100); + + /* enable amppd */ + aw_dev_amppd(aw_dev, true); + + /* close dsp */ + aw_dev_dsp_enable(aw_dev, false); + /* set power down */ + aw_dev_pwd(aw_dev, true); + + return 0; +} + +static int aw88166_request_firmware_file(struct aw88166 *aw88166) +{ + const struct firmware *cont = NULL; + int ret; + + aw88166->aw_pa->fw_status = AW88166_DEV_FW_FAILED; + + ret = request_firmware(&cont, AW88166_ACF_FILE, aw88166->aw_pa->dev); + if (ret) { + dev_err(aw88166->aw_pa->dev, "request [%s] failed!\n", AW88166_ACF_FILE); + return ret; + } + + dev_dbg(aw88166->aw_pa->dev, "loaded %s - size: %zu\n", + AW88166_ACF_FILE, cont ? cont->size : 0); + + aw88166->aw_cfg = devm_kzalloc(aw88166->aw_pa->dev, + struct_size(aw88166->aw_cfg, data, cont->size), GFP_KERNEL); + if (!aw88166->aw_cfg) { + release_firmware(cont); + return -ENOMEM; + } + aw88166->aw_cfg->len = (int)cont->size; + memcpy(aw88166->aw_cfg->data, cont->data, cont->size); + release_firmware(cont); + + ret = aw88395_dev_load_acf_check(aw88166->aw_pa, aw88166->aw_cfg); + if (ret) { + dev_err(aw88166->aw_pa->dev, "load [%s] failed!\n", AW88166_ACF_FILE); + return ret; + } + + mutex_lock(&aw88166->lock); + /* aw device init */ + ret = aw88166_dev_init(aw88166, aw88166->aw_cfg); + if (ret) + dev_err(aw88166->aw_pa->dev, "dev init failed\n"); + mutex_unlock(&aw88166->lock); + + return ret; +} + +static const struct snd_kcontrol_new aw88166_controls[] = { + SOC_SINGLE_EXT("PCM Playback Volume", AW88166_SYSCTRL2_REG, + 6, AW88166_MUTE_VOL, 0, aw88166_volume_get, + aw88166_volume_set), + SOC_SINGLE_EXT("Fade Step", 0, 0, AW88166_MUTE_VOL, 0, + aw88166_get_fade_step, aw88166_set_fade_step), + SOC_SINGLE_EXT("Volume Ramp Up Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88166_get_fade_in_time, aw88166_set_fade_in_time), + SOC_SINGLE_EXT("Volume Ramp Down Step", 0, 0, FADE_TIME_MAX, FADE_TIME_MIN, + aw88166_get_fade_out_time, aw88166_set_fade_out_time), + SOC_SINGLE_EXT("Calib", 0, 0, AW88166_CALI_RE_MAX, 0, + aw88166_re_get, aw88166_re_set), + AW88166_PROFILE_EXT("AW88166 Profile Set", aw88166_profile_info, + aw88166_profile_get, aw88166_profile_set), +}; + +static int aw88166_playback_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); + + mutex_lock(&aw88166->lock); + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + aw88166_start(aw88166, AW88166_ASYNC_START); + break; + case SND_SOC_DAPM_POST_PMD: + aw88166_stop(aw88166->aw_pa); + break; + default: + break; + } + mutex_unlock(&aw88166->lock); + + return 0; +} + +static const struct snd_soc_dapm_widget aw88166_dapm_widgets[] = { + /* playback */ + SND_SOC_DAPM_AIF_IN_E("AIF_RX", "Speaker_Playback", 0, SND_SOC_NOPM, 0, 0, + aw88166_playback_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_OUTPUT("DAC Output"), + + /* capture */ + SND_SOC_DAPM_AIF_OUT("AIF_TX", "Speaker_Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_INPUT("ADC Input"), +}; + +static const struct snd_soc_dapm_route aw88166_audio_map[] = { + {"DAC Output", NULL, "AIF_RX"}, + {"AIF_TX", NULL, "ADC Input"}, +}; + +static int aw88166_codec_probe(struct snd_soc_component *component) +{ + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(component); + int ret; + + INIT_DELAYED_WORK(&aw88166->start_work, aw88166_startup_work); + + ret = aw88166_request_firmware_file(aw88166); + if (ret) + dev_err(aw88166->aw_pa->dev, "%s failed\n", __func__); + + return ret; +} + +static void aw88166_codec_remove(struct snd_soc_component *aw_codec) +{ + struct aw88166 *aw88166 = snd_soc_component_get_drvdata(aw_codec); + + cancel_delayed_work_sync(&aw88166->start_work); +} + +static const struct snd_soc_component_driver soc_codec_dev_aw88166 = { + .probe = aw88166_codec_probe, + .remove = aw88166_codec_remove, + .dapm_widgets = aw88166_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(aw88166_dapm_widgets), + .dapm_routes = aw88166_audio_map, + .num_dapm_routes = ARRAY_SIZE(aw88166_audio_map), + .controls = aw88166_controls, + .num_controls = ARRAY_SIZE(aw88166_controls), +}; + +static void aw88166_hw_reset(struct aw88166 *aw88166) +{ + if (aw88166->reset_gpio) { + gpiod_set_value_cansleep(aw88166->reset_gpio, 1); + usleep_range(AW88166_1000_US, AW88166_1000_US + 10); + gpiod_set_value_cansleep(aw88166->reset_gpio, 0); + usleep_range(AW88166_1000_US, AW88166_1000_US + 10); + } +} + +static void aw88166_parse_channel_dt(struct aw88166 *aw88166) +{ + struct aw_device *aw_dev = aw88166->aw_pa; + struct device_node *np = aw_dev->dev->of_node; + u32 channel_value; + + of_property_read_u32(np, "awinic,audio-channel", &channel_value); + aw_dev->channel = channel_value; + aw88166->phase_sync = of_property_read_bool(np, "awinic,sync-flag"); +} + +static int aw88166_init(struct aw88166 *aw88166, struct i2c_client *i2c, struct regmap *regmap) +{ + struct aw_device *aw_dev; + unsigned int chip_id; + int ret; + + ret = regmap_read(regmap, AW88166_ID_REG, &chip_id); + if (ret) { + dev_err(&i2c->dev, "%s read chipid error. ret = %d\n", __func__, ret); + return ret; + } + + aw_dev = devm_kzalloc(&i2c->dev, sizeof(*aw_dev), GFP_KERNEL); + if (!aw_dev) + return -ENOMEM; + aw88166->aw_pa = aw_dev; + + aw_dev->i2c = i2c; + aw_dev->dev = &i2c->dev; + aw_dev->regmap = regmap; + mutex_init(&aw_dev->dsp_lock); + + aw_dev->chip_id = chip_id; + aw_dev->acf = NULL; + aw_dev->prof_info.prof_desc = NULL; + aw_dev->prof_info.count = 0; + aw_dev->prof_info.prof_type = AW88395_DEV_NONE_TYPE_ID; + aw_dev->channel = AW88166_DEV_DEFAULT_CH; + aw_dev->fw_status = AW88166_DEV_FW_FAILED; + + aw_dev->fade_step = AW88166_VOLUME_STEP_DB; + aw_dev->volume_desc.ctl_volume = AW88166_VOL_DEFAULT_VALUE; + + aw88166_parse_channel_dt(aw88166); + + return 0; +} + +static int aw88166_i2c_probe(struct i2c_client *i2c) +{ + struct aw88166 *aw88166; + int ret; + + if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) + return dev_err_probe(&i2c->dev, -ENXIO, "check_functionality failed\n"); + + aw88166 = devm_kzalloc(&i2c->dev, sizeof(*aw88166), GFP_KERNEL); + if (!aw88166) + return -ENOMEM; + + mutex_init(&aw88166->lock); + + i2c_set_clientdata(i2c, aw88166); + + aw88166->reset_gpio = devm_gpiod_get_optional(&i2c->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(aw88166->reset_gpio)) + return dev_err_probe(&i2c->dev, PTR_ERR(aw88166->reset_gpio), + "reset gpio not defined\n"); + aw88166_hw_reset(aw88166); + + aw88166->regmap = devm_regmap_init_i2c(i2c, &aw88166_remap_config); + if (IS_ERR(aw88166->regmap)) + return dev_err_probe(&i2c->dev, PTR_ERR(aw88166->regmap), + "failed to init regmap\n"); + + /* aw pa init */ + ret = aw88166_init(aw88166, i2c, aw88166->regmap); + if (ret) + return ret; + + return devm_snd_soc_register_component(&i2c->dev, + &soc_codec_dev_aw88166, + aw88166_dai, ARRAY_SIZE(aw88166_dai)); +} + +static const struct i2c_device_id aw88166_i2c_id[] = { + { AW88166_I2C_NAME }, + { } +}; +MODULE_DEVICE_TABLE(i2c, aw88166_i2c_id); + +static struct i2c_driver aw88166_i2c_driver = { + .driver = { + .name = AW88166_I2C_NAME, + }, + .probe = aw88166_i2c_probe, + .id_table = aw88166_i2c_id, +}; +module_i2c_driver(aw88166_i2c_driver); + +MODULE_DESCRIPTION("ASoC AW88166 Smart PA Driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/codecs/aw88166.h b/sound/soc/codecs/aw88166.h new file mode 100644 index 000000000000..3a53ba0ac625 --- /dev/null +++ b/sound/soc/codecs/aw88166.h @@ -0,0 +1,534 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// aw88166.h -- ALSA SoC AW88166 codec support +// +// Copyright (c) 2025 AWINIC Technology CO., LTD +// +// Author: Weidong Wang <wangweidong.a@awinic.com> +// + +#ifndef __AW88166_H__ +#define __AW88166_H__ + +/* registers list */ +#define AW88166_ID_REG (0x00) +#define AW88166_SYSST_REG (0x01) +#define AW88166_SYSINT_REG (0x02) +#define AW88166_SYSINTM_REG (0x03) +#define AW88166_SYSCTRL_REG (0x04) +#define AW88166_SYSCTRL2_REG (0x05) +#define AW88166_I2SCTRL1_REG (0x06) +#define AW88166_I2SCTRL2_REG (0x07) +#define AW88166_I2SCTRL3_REG (0x08) +#define AW88166_DACCFG1_REG (0x09) +#define AW88166_DACCFG2_REG (0x0A) +#define AW88166_DACCFG3_REG (0x0B) +#define AW88166_DACCFG4_REG (0x0C) +#define AW88166_DACCFG5_REG (0x0D) +#define AW88166_DACCFG6_REG (0x0E) +#define AW88166_DACCFG7_REG (0x0F) +#define AW88166_MPDCFG1_REG (0x10) +#define AW88166_MPDCFG2_REG (0x11) +#define AW88166_MPDCFG3_REG (0x12) +#define AW88166_MPDCFG4_REG (0x13) +#define AW88166_PWMCTRL1_REG (0x14) +#define AW88166_PWMCTRL2_REG (0x15) +#define AW88166_PWMCTRL3_REG (0x16) +#define AW88166_I2SCFG1_REG (0x17) +#define AW88166_DBGCTRL_REG (0x18) +#define AW88166_HAGCST_REG (0x20) +#define AW88166_VBAT_REG (0x21) +#define AW88166_TEMP_REG (0x22) +#define AW88166_PVDD_REG (0x23) +#define AW88166_ISNDAT_REG (0x24) +#define AW88166_I2SINT_REG (0x25) +#define AW88166_I2SCAPCNT_REG (0x26) +#define AW88166_ANASTA1_REG (0x27) +#define AW88166_ANASTA2_REG (0x28) +#define AW88166_ANASTA3_REG (0x29) +#define AW88166_TESTDET_REG (0x2A) +#define AW88166_TESTIN_REG (0x38) +#define AW88166_TESTOUT_REG (0x39) +#define AW88166_MEMTEST_REG (0x3A) +#define AW88166_DSPMADD_REG (0x40) +#define AW88166_DSPMDAT_REG (0x41) +#define AW88166_WDT_REG (0x42) +#define AW88166_ACR1_REG (0x43) +#define AW88166_ACR2_REG (0x44) +#define AW88166_ASR1_REG (0x45) +#define AW88166_ASR2_REG (0x46) +#define AW88166_DSPCFG_REG (0x47) +#define AW88166_ASR3_REG (0x48) +#define AW88166_ASR4_REG (0x49) +#define AW88166_DSPVCALB_REG (0x4A) +#define AW88166_CRCCTRL_REG (0x4B) +#define AW88166_DSPDBG1_REG (0x4C) +#define AW88166_DSPDBG2_REG (0x4D) +#define AW88166_DSPDBG3_REG (0x4E) +#define AW88166_ISNCTRL1_REG (0x50) +#define AW88166_PLLCTRL1_REG (0x51) +#define AW88166_PLLCTRL2_REG (0x52) +#define AW88166_PLLCTRL3_REG (0x53) +#define AW88166_CDACTRL1_REG (0x54) +#define AW88166_CDACTRL2_REG (0x55) +#define AW88166_CDACTRL3_REG (0x56) +#define AW88166_SADCCTRL1_REG (0x57) +#define AW88166_SADCCTRL2_REG (0x58) +#define AW88166_BOPCTRL1_REG (0x59) +#define AW88166_BOPCTRL2_REG (0x5A) +#define AW88166_BOPCTRL3_REG (0x5B) +#define AW88166_BOPCTRL4_REG (0x5C) +#define AW88166_BOPCTRL5_REG (0x5D) +#define AW88166_BOPCTRL6_REG (0x5E) +#define AW88166_BOPCTRL7_REG (0x5F) +#define AW88166_BSTCTRL1_REG (0x60) +#define AW88166_BSTCTRL2_REG (0x61) +#define AW88166_BSTCTRL3_REG (0x62) +#define AW88166_BSTCTRL4_REG (0x63) +#define AW88166_BSTCTRL5_REG (0x64) +#define AW88166_BSTCTRL6_REG (0x65) +#define AW88166_DSMCFG1_REG (0x66) +#define AW88166_DSMCFG2_REG (0x67) +#define AW88166_DSMCFG3_REG (0x68) +#define AW88166_DSMCFG4_REG (0x69) +#define AW88166_DSMCFG5_REG (0x6A) +#define AW88166_DSMCFG6_REG (0x6B) +#define AW88166_DSMCFG7_REG (0x6C) +#define AW88166_DSMCFG8_REG (0x6D) +#define AW88166_TESTCTRL1_REG (0x70) +#define AW88166_TESTCTRL2_REG (0x71) +#define AW88166_EFCTRL1_REG (0x72) +#define AW88166_EFCTRL2_REG (0x73) +#define AW88166_EFWH_REG (0x74) +#define AW88166_EFWM2_REG (0x75) +#define AW88166_EFWM1_REG (0x76) +#define AW88166_EFRH_REG (0x77) +#define AW88166_EFRM2_REG (0x78) +#define AW88166_EFRM1_REG (0x79) +#define AW88166_EFRL_REG (0x7A) +#define AW88166_TM_REG (0x7C) +#define AW88166_TM2_REG (0x7D) + +#define AW88166_REG_MAX (0x7E) +#define AW88166_MUTE_VOL (1023) + +#define AW88166_DSP_CFG_ADDR (0x9B00) +#define AW88166_DSP_REG_CFG_ADPZ_RA (0x9B68) +#define AW88166_DSP_FW_ADDR (0x8980) +#define AW88166_DSP_ROM_CHECK_ADDR (0x1F40) + +#define AW88166_CALI_RE_HBITS_MASK (~(0xFFFF0000)) +#define AW88166_CALI_RE_HBITS_SHIFT (16) + +#define AW88166_CALI_RE_LBITS_MASK (~(0xFFFF)) +#define AW88166_CALI_RE_LBITS_SHIFT (0) + +#define AW88166_I2STXEN_START_BIT (9) +#define AW88166_I2STXEN_BITS_LEN (1) +#define AW88166_I2STXEN_MASK \ + (~(((1<<AW88166_I2STXEN_BITS_LEN)-1) << AW88166_I2STXEN_START_BIT)) + +#define AW88166_I2STXEN_DISABLE (0) +#define AW88166_I2STXEN_DISABLE_VALUE \ + (AW88166_I2STXEN_DISABLE << AW88166_I2STXEN_START_BIT) + +#define AW88166_I2STXEN_ENABLE (1) +#define AW88166_I2STXEN_ENABLE_VALUE \ + (AW88166_I2STXEN_ENABLE << AW88166_I2STXEN_START_BIT) + +#define AW88166_VOL_START_BIT (0) +#define AW88166_VOL_BITS_LEN (10) +#define AW88166_VOL_MASK \ + (~(((1<<AW88166_VOL_BITS_LEN)-1) << AW88166_VOL_START_BIT)) + +#define AW88166_PWDN_START_BIT (0) +#define AW88166_PWDN_BITS_LEN (1) +#define AW88166_PWDN_MASK \ + (~(((1<<AW88166_PWDN_BITS_LEN)-1) << AW88166_PWDN_START_BIT)) + +#define AW88166_PWDN_POWER_DOWN (1) +#define AW88166_PWDN_POWER_DOWN_VALUE \ + (AW88166_PWDN_POWER_DOWN << AW88166_PWDN_START_BIT) + +#define AW88166_PWDN_WORKING (0) +#define AW88166_PWDN_WORKING_VALUE \ + (AW88166_PWDN_WORKING << AW88166_PWDN_START_BIT) + +#define AW88166_DSPBY_START_BIT (2) +#define AW88166_DSPBY_BITS_LEN (1) +#define AW88166_DSPBY_MASK \ + (~(((1<<AW88166_DSPBY_BITS_LEN)-1) << AW88166_DSPBY_START_BIT)) + +#define AW88166_DSPBY_WORKING (0) +#define AW88166_DSPBY_WORKING_VALUE \ + (AW88166_DSPBY_WORKING << AW88166_DSPBY_START_BIT) + +#define AW88166_DSPBY_BYPASS (1) +#define AW88166_DSPBY_BYPASS_VALUE \ + (AW88166_DSPBY_BYPASS << AW88166_DSPBY_START_BIT) + +#define AW88166_MEM_CLKSEL_START_BIT (3) +#define AW88166_MEM_CLKSEL_BITS_LEN (1) +#define AW88166_MEM_CLKSEL_MASK \ + (~(((1<<AW88166_MEM_CLKSEL_BITS_LEN)-1) << AW88166_MEM_CLKSEL_START_BIT)) + +#define AW88166_MEM_CLKSEL_OSCCLK (0) +#define AW88166_MEM_CLKSEL_OSCCLK_VALUE \ + (AW88166_MEM_CLKSEL_OSCCLK << AW88166_MEM_CLKSEL_START_BIT) + +#define AW88166_MEM_CLKSEL_DAPHCLK (1) +#define AW88166_MEM_CLKSEL_DAPHCLK_VALUE \ + (AW88166_MEM_CLKSEL_DAPHCLK << AW88166_MEM_CLKSEL_START_BIT) + +#define AW88166_DITHER_EN_START_BIT (15) +#define AW88166_DITHER_EN_BITS_LEN (1) +#define AW88166_DITHER_EN_MASK \ + (~(((1<<AW88166_DITHER_EN_BITS_LEN)-1) << AW88166_DITHER_EN_START_BIT)) + +#define AW88166_DITHER_EN_DISABLE (0) +#define AW88166_DITHER_EN_DISABLE_VALUE \ + (AW88166_DITHER_EN_DISABLE << AW88166_DITHER_EN_START_BIT) + +#define AW88166_DITHER_EN_ENABLE (1) +#define AW88166_DITHER_EN_ENABLE_VALUE \ + (AW88166_DITHER_EN_ENABLE << AW88166_DITHER_EN_START_BIT) + +#define AW88166_HMUTE_START_BIT (8) +#define AW88166_HMUTE_BITS_LEN (1) +#define AW88166_HMUTE_MASK \ + (~(((1<<AW88166_HMUTE_BITS_LEN)-1) << AW88166_HMUTE_START_BIT)) + +#define AW88166_HMUTE_DISABLE (0) +#define AW88166_HMUTE_DISABLE_VALUE \ + (AW88166_HMUTE_DISABLE << AW88166_HMUTE_START_BIT) + +#define AW88166_HMUTE_ENABLE (1) +#define AW88166_HMUTE_ENABLE_VALUE \ + (AW88166_HMUTE_ENABLE << AW88166_HMUTE_START_BIT) + +#define AW88166_EF_DBMD_START_BIT (2) +#define AW88166_EF_DBMD_BITS_LEN (1) +#define AW88166_EF_DBMD_MASK \ + (~(((1<<AW88166_EF_DBMD_BITS_LEN)-1) << AW88166_EF_DBMD_START_BIT)) + +#define AW88166_EF_DBMD_OR (1) +#define AW88166_EF_DBMD_OR_VALUE \ + (AW88166_EF_DBMD_OR << AW88166_EF_DBMD_START_BIT) + +#define AW88166_CLKI_START_BIT (4) +#define AW88166_NOCLKI_START_BIT (5) +#define AW88166_PLLI_START_BIT (0) +#define AW88166_PLLI_INT_VALUE (1) +#define AW88166_PLLI_INT_INTERRUPT \ + (AW88166_PLLI_INT_VALUE << AW88166_PLLI_START_BIT) + +#define AW88166_CLKI_INT_VALUE (1) +#define AW88166_CLKI_INT_INTERRUPT \ + (AW88166_CLKI_INT_VALUE << AW88166_CLKI_START_BIT) + +#define AW88166_NOCLKI_INT_VALUE (1) +#define AW88166_NOCLKI_INT_INTERRUPT \ + (AW88166_NOCLKI_INT_VALUE << AW88166_NOCLKI_START_BIT) + +#define AW88166_BIT_SYSINT_CHECK \ + (AW88166_PLLI_INT_INTERRUPT | \ + AW88166_CLKI_INT_INTERRUPT | \ + AW88166_NOCLKI_INT_INTERRUPT) + +#define AW88166_CRC_CHECK_START_BIT (12) +#define AW88166_CRC_CHECK_BITS_LEN (3) +#define AW88166_CRC_CHECK_BITS_MASK \ + (~(((1<<AW88166_CRC_CHECK_BITS_LEN)-1) << AW88166_CRC_CHECK_START_BIT)) + +#define AW88166_RCV_MODE_RECEIVER (1) +#define AW88166_RCV_MODE_RECEIVER_VALUE \ + (AW88166_RCV_MODE_RECEIVER << AW88166_RCV_MODE_START_BIT) + +#define AW88166_AMPPD_START_BIT (1) +#define AW88166_AMPPD_BITS_LEN (1) +#define AW88166_AMPPD_MASK \ + (~(((1<<AW88166_AMPPD_BITS_LEN)-1) << AW88166_AMPPD_START_BIT)) + +#define AW88166_AMPPD_WORKING (0) +#define AW88166_AMPPD_WORKING_VALUE \ + (AW88166_AMPPD_WORKING << AW88166_AMPPD_START_BIT) + +#define AW88166_AMPPD_POWER_DOWN (1) +#define AW88166_AMPPD_POWER_DOWN_VALUE \ + (AW88166_AMPPD_POWER_DOWN << AW88166_AMPPD_START_BIT) + +#define AW88166_RAM_CG_BYP_START_BIT (0) +#define AW88166_RAM_CG_BYP_BITS_LEN (1) +#define AW88166_RAM_CG_BYP_MASK \ + (~(((1<<AW88166_RAM_CG_BYP_BITS_LEN)-1) << AW88166_RAM_CG_BYP_START_BIT)) + +#define AW88166_RAM_CG_BYP_WORK (0) +#define AW88166_RAM_CG_BYP_WORK_VALUE \ + (AW88166_RAM_CG_BYP_WORK << AW88166_RAM_CG_BYP_START_BIT) + +#define AW88166_RAM_CG_BYP_BYPASS (1) +#define AW88166_RAM_CG_BYP_BYPASS_VALUE \ + (AW88166_RAM_CG_BYP_BYPASS << AW88166_RAM_CG_BYP_START_BIT) + +#define AW88166_CRC_END_ADDR_START_BIT (0) +#define AW88166_CRC_END_ADDR_BITS_LEN (12) +#define AW88166_CRC_END_ADDR_MASK \ + (~(((1<<AW88166_CRC_END_ADDR_BITS_LEN)-1) << AW88166_CRC_END_ADDR_START_BIT)) + +#define AW88166_CRC_CODE_EN_START_BIT (13) +#define AW88166_CRC_CODE_EN_BITS_LEN (1) +#define AW88166_CRC_CODE_EN_MASK \ + (~(((1<<AW88166_CRC_CODE_EN_BITS_LEN)-1) << AW88166_CRC_CODE_EN_START_BIT)) + +#define AW88166_CRC_CODE_EN_DISABLE (0) +#define AW88166_CRC_CODE_EN_DISABLE_VALUE \ + (AW88166_CRC_CODE_EN_DISABLE << AW88166_CRC_CODE_EN_START_BIT) + +#define AW88166_CRC_CODE_EN_ENABLE (1) +#define AW88166_CRC_CODE_EN_ENABLE_VALUE \ + (AW88166_CRC_CODE_EN_ENABLE << AW88166_CRC_CODE_EN_START_BIT) + +#define AW88166_CRC_CFG_EN_START_BIT (12) +#define AW88166_CRC_CFG_EN_BITS_LEN (1) +#define AW88166_CRC_CFG_EN_MASK \ + (~(((1<<AW88166_CRC_CFG_EN_BITS_LEN)-1) << AW88166_CRC_CFG_EN_START_BIT)) + +#define AW88166_CRC_CFG_EN_DISABLE (0) +#define AW88166_CRC_CFG_EN_DISABLE_VALUE \ + (AW88166_CRC_CFG_EN_DISABLE << AW88166_CRC_CFG_EN_START_BIT) + +#define AW88166_CRC_CFG_EN_ENABLE (1) +#define AW88166_CRC_CFG_EN_ENABLE_VALUE \ + (AW88166_CRC_CFG_EN_ENABLE << AW88166_CRC_CFG_EN_START_BIT) + +#define AW88166_OCDS_START_BIT (3) +#define AW88166_OCDS_OC (1) +#define AW88166_OCDS_OC_VALUE \ + (AW88166_OCDS_OC << AW88166_OCDS_START_BIT) + +#define AW88166_NOCLKS_START_BIT (5) +#define AW88166_NOCLKS_NO_CLOCK (1) +#define AW88166_NOCLKS_NO_CLOCK_VALUE \ + (AW88166_NOCLKS_NO_CLOCK << AW88166_NOCLKS_START_BIT) + +#define AW88166_SWS_START_BIT (8) +#define AW88166_SWS_SWITCHING (1) +#define AW88166_SWS_SWITCHING_VALUE \ + (AW88166_SWS_SWITCHING << AW88166_SWS_START_BIT) + +#define AW88166_BSTS_START_BIT (9) +#define AW88166_BSTS_FINISHED (1) +#define AW88166_BSTS_FINISHED_VALUE \ + (AW88166_BSTS_FINISHED << AW88166_BSTS_START_BIT) + +#define AW88166_UVLS_START_BIT (14) +#define AW88166_UVLS_NORMAL (0) +#define AW88166_UVLS_NORMAL_VALUE \ + (AW88166_UVLS_NORMAL << AW88166_UVLS_START_BIT) + +#define AW88166_BSTOCS_START_BIT (11) +#define AW88166_BSTOCS_OVER_CURRENT (1) +#define AW88166_BSTOCS_OVER_CURRENT_VALUE \ + (AW88166_BSTOCS_OVER_CURRENT << AW88166_BSTOCS_START_BIT) + +#define AW88166_OTHS_START_BIT (1) +#define AW88166_OTHS_OT (1) +#define AW88166_OTHS_OT_VALUE \ + (AW88166_OTHS_OT << AW88166_OTHS_START_BIT) + +#define AW88166_PLLS_START_BIT (0) +#define AW88166_PLLS_LOCKED (1) +#define AW88166_PLLS_LOCKED_VALUE \ + (AW88166_PLLS_LOCKED << AW88166_PLLS_START_BIT) + +#define AW88166_CLKS_START_BIT (4) +#define AW88166_CLKS_STABLE (1) +#define AW88166_CLKS_STABLE_VALUE \ + (AW88166_CLKS_STABLE << AW88166_CLKS_START_BIT) + +#define AW88166_BIT_PLL_CHECK \ + (AW88166_CLKS_STABLE_VALUE | \ + AW88166_PLLS_LOCKED_VALUE) + +#define AW88166_BIT_SYSST_CHECK_MASK \ + (~(AW88166_UVLS_NORMAL_VALUE | \ + AW88166_BSTOCS_OVER_CURRENT_VALUE | \ + AW88166_BSTS_FINISHED_VALUE | \ + AW88166_SWS_SWITCHING_VALUE | \ + AW88166_NOCLKS_NO_CLOCK_VALUE | \ + AW88166_CLKS_STABLE_VALUE | \ + AW88166_OCDS_OC_VALUE | \ + AW88166_OTHS_OT_VALUE | \ + AW88166_PLLS_LOCKED_VALUE)) + +#define AW88166_BIT_SYSST_NOSWS_CHECK \ + (AW88166_BSTS_FINISHED_VALUE | \ + AW88166_CLKS_STABLE_VALUE | \ + AW88166_PLLS_LOCKED_VALUE) + +#define AW88166_BIT_SYSST_SWS_CHECK \ + (AW88166_BSTS_FINISHED_VALUE | \ + AW88166_CLKS_STABLE_VALUE | \ + AW88166_PLLS_LOCKED_VALUE | \ + AW88166_SWS_SWITCHING_VALUE) + +#define AW88166_CCO_MUX_START_BIT (14) +#define AW88166_CCO_MUX_BITS_LEN (1) +#define AW88166_CCO_MUX_MASK \ + (~(((1<<AW88166_CCO_MUX_BITS_LEN)-1) << AW88166_CCO_MUX_START_BIT)) + +#define AW88166_CCO_MUX_DIVIDED (0) +#define AW88166_CCO_MUX_DIVIDED_VALUE \ + (AW88166_CCO_MUX_DIVIDED << AW88166_CCO_MUX_START_BIT) + +#define AW88166_CCO_MUX_BYPASS (1) +#define AW88166_CCO_MUX_BYPASS_VALUE \ + (AW88166_CCO_MUX_BYPASS << AW88166_CCO_MUX_START_BIT) + +#define AW88166_NOISE_GATE_EN_START_BIT (13) +#define AW88166_NOISE_GATE_EN_BITS_LEN (1) +#define AW88166_NOISE_GATE_EN_MASK \ + (~(((1<<AW88166_NOISE_GATE_EN_BITS_LEN)-1) << AW88166_NOISE_GATE_EN_START_BIT)) + +#define AW88166_WDT_CNT_START_BIT (0) +#define AW88166_WDT_CNT_BITS_LEN (8) +#define AW88166_WDT_CNT_MASK \ + (~(((1<<AW88166_WDT_CNT_BITS_LEN)-1) << AW88166_WDT_CNT_START_BIT)) + +#define AW88166_EF_ISN_GESLP_START_BIT (0) +#define AW88166_EF_ISN_GESLP_BITS_LEN (10) +#define AW88166_EF_ISN_GESLP_MASK \ + (~(((1<<AW88166_EF_ISN_GESLP_BITS_LEN)-1) << AW88166_EF_ISN_GESLP_START_BIT)) +#define AW88166_EF_ISN_GESLP_SHIFT (0) + +#define AW88166_EF_VSN_GESLP_START_BIT (10) +#define AW88166_EF_VSN_GESLP_BITS_LEN (6) +#define AW88166_EF_VSN_GESLP_MASK \ + (~(((1<<AW88166_EF_VSN_GESLP_BITS_LEN)-1) << AW88166_EF_VSN_GESLP_START_BIT)) +#define AW88166_EF_VSN_GESLP_SHIFT (10) + +#define AW88166_EF_VSN_H3BITS_START_BIT (13) +#define AW88166_EF_VSN_H3BITS_BITS_LEN (3) +#define AW88166_EF_VSN_H3BITS_MASK \ + (~(((1<<AW88166_EF_VSN_H3BITS_BITS_LEN)-1) << AW88166_EF_VSN_H3BITS_START_BIT)) +#define AW88166_EF_VSN_H3BITS_SHIFT (10) +#define AW88166_EF_VSN_H3BITS_SIGN_MASK (0x7) + +#define AW88166_EF_ISN_H5BITS_START_BIT (8) +#define AW88166_EF_ISN_H5BITS_BITS_LEN (5) +#define AW88166_EF_ISN_H5BITS_MASK \ + (~(((1<<AW88166_EF_ISN_H5BITS_BITS_LEN)-1) << AW88166_EF_ISN_H5BITS_START_BIT)) +#define AW88166_EF_ISN_H5BITS_SIGN_MASK (0x1F) +#define AW88166_EF_ISN_H5BITS_SHIFT (3) + +#define AW88166_VSCAL_FACTOR (65300) +#define AW88166_ISCAL_FACTOR (34667) +#define AW88166_CABL_BASE_VALUE (1000) +#define AW88166_VCALK_SIGN_MASK (~(1 << 5)) +#define AW88166_VCALK_NEG_MASK (0xFFE0) +#define AW88166_ICALK_SIGN_MASK (~(1 << 9)) +#define AW88166_ICALK_NEG_MASK (0xFE00) +#define AW88166_ICABLK_FACTOR (1) +#define AW88166_VCABLK_FACTOR (2) +#define AW88166_VCALB_ADJ_FACTOR (12) +#define AW88166_VCALB_ACCURACY (1 << 12) +#define AW88166_DSP_RE_SHIFT (12) +#define AW88166_CALI_RE_MAX (15000) +#define AW88166_CALI_RE_MIN (4000) +#define AW88166_VOLUME_STEP_DB (64) +#define AW88166_VOL_DEFAULT_VALUE (0) +#define AW88166_DSP_RE_TO_SHOW_RE(re, shift) (((re) * (1000)) >> (shift)) +#define AW88166_SHOW_RE_TO_DSP_RE(re, shift) (((re) << shift) / (1000)) + +#define AW88166_DSP_ODD_NUM_BIT_TEST (0x5555) +#define AW88166_DSP_ROM_CHECK_DATA (0xFF99) + +#define AW88166_DEV_DEFAULT_CH (0) +#define AW88166_DEV_DSP_CHECK_MAX (5) +#define AW88166_MAX_RAM_WRITE_BYTE_SIZE (128) +#define AW_FW_ADDR_LEN (4) +#define AW88166_CRC_CHECK_PASS_VAL (0x4) +#define AW88166_CRC_CFG_BASE_ADDR (0xD80) +#define AW88166_CRC_FW_BASE_ADDR (0x4C0) +#define AW88166_DEV_SYSST_CHECK_MAX (10) +#define AW88166_START_RETRIES (5) +#define AW88166_START_WORK_DELAY_MS (0) +#define FADE_TIME_MAX 100000 +#define FADE_TIME_MIN 0 +#define AW88166_CHIP_ID (0x2066) +#define AW88166_I2C_NAME "aw88166" +#define AW88166_ACF_FILE "aw88166_acf.bin" + +#define AW88166_RATES (SNDRV_PCM_RATE_8000_48000 | \ + SNDRV_PCM_RATE_96000) +#define AW88166_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define AW88166_PROFILE_EXT(xname, profile_info, profile_get, profile_set) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .info = profile_info, \ + .get = profile_get, \ + .put = profile_set, \ +} + +enum { + AW_EF_AND_CHECK = 0, + AW_EF_OR_CHECK, +}; + +enum { + AW88166_DSP_FW_UPDATE_OFF = 0, + AW88166_DSP_FW_UPDATE_ON = 1, +}; + +enum { + AW88166_FORCE_UPDATE_OFF = 0, + AW88166_FORCE_UPDATE_ON = 1, +}; + +enum { + AW88166_1000_US = 1000, + AW88166_2000_US = 2000, + AW88166_3000_US = 3000, + AW88166_4000_US = 4000, +}; + +enum AW88166_DEV_STATUS { + AW88166_DEV_PW_OFF = 0, + AW88166_DEV_PW_ON, +}; + +enum AW88166_DEV_FW_STATUS { + AW88166_DEV_FW_FAILED = 0, + AW88166_DEV_FW_OK, +}; + +enum AW88166_DEV_MEMCLK { + AW88166_DEV_MEMCLK_OSC = 0, + AW88166_DEV_MEMCLK_PLL = 1, +}; + +enum AW88166_DEV_DSP_CFG { + AW88166_DEV_DSP_WORK = 0, + AW88166_DEV_DSP_BYPASS = 1, +}; + +enum { + AW88166_DSP_16_DATA = 0, + AW88166_DSP_32_DATA = 1, +}; + +enum { + AW88166_SYNC_START = 0, + AW88166_ASYNC_START, +}; + +enum { + AW88166_RECORD_SEC_DATA = 0, + AW88166_RECOVERY_SEC_DATA = 1, +}; + +#endif diff --git a/sound/soc/codecs/aw88395/aw88395_device.c b/sound/soc/codecs/aw88395/aw88395_device.c index 6b333d1c6e94..b7ea8be0d0cb 100644 --- a/sound/soc/codecs/aw88395/aw88395_device.c +++ b/sound/soc/codecs/aw88395/aw88395_device.c @@ -424,7 +424,7 @@ static int aw_dev_dsp_set_crc32(struct aw_device *aw_dev) return -EINVAL; } - crc_value = __crc32c_le(0xFFFFFFFF, crc_dsp_cfg->data, crc_data_len) ^ 0xFFFFFFFF; + crc_value = crc32c(0xFFFFFFFF, crc_dsp_cfg->data, crc_data_len) ^ 0xFFFFFFFF; return aw_dev_dsp_write(aw_dev, AW88395_DSP_REG_CRC_ADDR, crc_value, AW88395_DSP_32_DATA); diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c index 04304a7ad915..3eb862643b53 100644 --- a/sound/soc/codecs/cpcap.c +++ b/sound/soc/codecs/cpcap.c @@ -11,11 +11,21 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/mfd/motorola-cpcap.h> #include <sound/core.h> +#include <linux/input.h> +#include <sound/jack.h> #include <sound/soc.h> #include <sound/tlv.h> +/* Register 8 - CPCAP_REG_INTS1 --- Interrupt Sense 1 */ +#define CPCAP_BIT_HS_S 9 /* Headset */ +#define CPCAP_BIT_MB2_S 10 /* Mic Bias2 */ + +/* Register 9 - CPCAP_REG_INTS2 --- Interrupt Sense 2 */ +#define CPCAP_BIT_PTT_S 11 /* Push To Talk */ + /* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */ #define CPCAP_BIT_AUDIO_LOW_PWR 6 #define CPCAP_BIT_AUD_LOWPWR_SPEED 5 @@ -260,6 +270,10 @@ struct cpcap_audio { int codec_clk_id; int codec_freq; int codec_format; + struct regulator *vaudio; + int hsirq; + int mb2irq; + struct snd_soc_jack jack; }; static int cpcap_st_workaround(struct snd_soc_dapm_widget *w, @@ -1626,17 +1640,123 @@ static int cpcap_audio_reset(struct snd_soc_component *component, return 0; } +static irqreturn_t cpcap_hs_irq_thread(int irq, void *data) +{ + struct snd_soc_component *component = data; + struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cpcap->regmap; + int status = 0; + int mask = SND_JACK_HEADSET; + int val; + + if (!regmap_test_bits(regmap, CPCAP_REG_INTS1, BIT(CPCAP_BIT_HS_S))) { + val = BIT(CPCAP_BIT_MB_ON2) | BIT(CPCAP_BIT_PTT_CMP_EN); + regmap_update_bits(regmap, CPCAP_REG_TXI, val, val); + + val = BIT(CPCAP_BIT_ST_HS_CP_EN); + regmap_update_bits(regmap, CPCAP_REG_RXOA, val, val); + + regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_NORMAL); + + /* Give PTTS time to settle */ + msleep(20); + + if (!regmap_test_bits(regmap, CPCAP_REG_INTS2, + BIT(CPCAP_BIT_PTT_S))) { + /* Headphones detected. (May also be a headset with the + * MFB pressed.) + */ + status = SND_JACK_HEADPHONE; + dev_info(component->dev, "HP plugged in\n"); + } else if (regmap_test_bits(regmap, CPCAP_REG_INTS1, + BIT(CPCAP_BIT_MB2_S)) == 1) { + status = SND_JACK_HEADSET; + dev_info(component->dev, "HS plugged in\n"); + } else + dev_info(component->dev, "Unsupported HS plugged in\n"); + } else { + bool mic = cpcap->jack.status & SND_JACK_MICROPHONE; + + dev_info(component->dev, "H%s disconnect\n", mic ? "S" : "P"); + val = BIT(CPCAP_BIT_MB_ON2) | BIT(CPCAP_BIT_PTT_CMP_EN); + regmap_update_bits(cpcap->regmap, CPCAP_REG_TXI, val, 0); + + val = BIT(CPCAP_BIT_ST_HS_CP_EN); + regmap_update_bits(cpcap->regmap, CPCAP_REG_RXOA, val, 0); + + regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_STANDBY); + + mask |= SND_JACK_BTN_0; + } + + snd_soc_jack_report(&cpcap->jack, status, mask); + + return IRQ_HANDLED; +} + +static irqreturn_t cpcap_mb2_irq_thread(int irq, void *data) +{ + struct snd_soc_component *component = data; + struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); + struct regmap *regmap = cpcap->regmap; + int status = 0; + int mb2; + int ptt; + + if (regmap_test_bits(regmap, CPCAP_REG_INTS1, BIT(CPCAP_BIT_HS_S)) == 1) + return IRQ_HANDLED; + + mb2 = regmap_test_bits(regmap, CPCAP_REG_INTS1, BIT(CPCAP_BIT_MB2_S)); + ptt = regmap_test_bits(regmap, CPCAP_REG_INTS2, BIT(CPCAP_BIT_PTT_S)); + + /* Initial detection might have been with MFB pressed */ + if (!(cpcap->jack.status & SND_JACK_MICROPHONE)) { + if (ptt == 1 && mb2 == 1) { + dev_info(component->dev, "MIC plugged in\n"); + snd_soc_jack_report(&cpcap->jack, SND_JACK_MICROPHONE, + SND_JACK_MICROPHONE); + } + + return IRQ_HANDLED; + } + + if (!mb2 || !ptt) + status = SND_JACK_BTN_0; + + snd_soc_jack_report(&cpcap->jack, status, SND_JACK_BTN_0); + + return IRQ_HANDLED; +} + static int cpcap_soc_probe(struct snd_soc_component *component) { + struct platform_device *pdev = to_platform_device(component->dev); + struct snd_soc_card *card = component->card; struct cpcap_audio *cpcap; int err; cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL); if (!cpcap) return -ENOMEM; + snd_soc_component_set_drvdata(component, cpcap); cpcap->component = component; + cpcap->vaudio = devm_regulator_get(component->dev, "VAUDIO"); + if (IS_ERR(cpcap->vaudio)) + return dev_err_probe(component->dev, PTR_ERR(cpcap->vaudio), + "Cannot get VAUDIO regulator\n"); + + err = snd_soc_card_jack_new(card, "Headphones", + SND_JACK_HEADSET | SND_JACK_BTN_0, + &cpcap->jack); + if (err < 0) { + dev_err(component->dev, "Cannot create HS jack: %i\n", err); + return err; + } + + snd_jack_set_key(cpcap->jack.jack, SND_JACK_BTN_0, KEY_MEDIA); + cpcap->regmap = dev_get_regmap(component->dev->parent, NULL); if (!cpcap->regmap) return -ENODEV; @@ -1646,17 +1766,95 @@ static int cpcap_soc_probe(struct snd_soc_component *component) if (err) return err; - return cpcap_audio_reset(component, false); + cpcap->hsirq = platform_get_irq_byname(pdev, "hs"); + if (cpcap->hsirq < 0) + return cpcap->hsirq; + + err = devm_request_threaded_irq(component->dev, cpcap->hsirq, NULL, + cpcap_hs_irq_thread, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "cpcap-codec-hs", + component); + if (err) { + dev_warn(component->dev, "no HS irq%i: %i\n", + cpcap->hsirq, err); + return err; + } + + cpcap->mb2irq = platform_get_irq_byname(pdev, "mb2"); + if (cpcap->mb2irq < 0) + return cpcap->mb2irq; + + err = devm_request_threaded_irq(component->dev, cpcap->mb2irq, NULL, + cpcap_mb2_irq_thread, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_ONESHOT, + "cpcap-codec-mb2", + component); + if (err) { + dev_warn(component->dev, "no MB2 irq%i: %i\n", + cpcap->mb2irq, err); + return err; + } + + err = cpcap_audio_reset(component, false); + if (err) + return err; + + cpcap_hs_irq_thread(cpcap->hsirq, component); + + enable_irq_wake(cpcap->hsirq); + enable_irq_wake(cpcap->mb2irq); + + return 0; +} + +static void cpcap_soc_remove(struct snd_soc_component *component) +{ + struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); + + disable_irq_wake(cpcap->hsirq); + disable_irq_wake(cpcap->mb2irq); +} + +static int cpcap_set_bias_level(struct snd_soc_component *component, + enum snd_soc_bias_level level) +{ + struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component); + + /* VAIDIO should be kept in normal mode in order MIC/PTT to work */ + if (cpcap->jack.status & SND_JACK_MICROPHONE) + return 0; + + switch (level) { + case SND_SOC_BIAS_OFF: + break; + case SND_SOC_BIAS_PREPARE: + regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_NORMAL); + break; + case SND_SOC_BIAS_STANDBY: + regulator_set_mode(cpcap->vaudio, REGULATOR_MODE_STANDBY); + break; + case SND_SOC_BIAS_ON: + break; + } + + return 0; } static const struct snd_soc_component_driver soc_codec_dev_cpcap = { .probe = cpcap_soc_probe, + .remove = cpcap_soc_remove, .controls = cpcap_snd_controls, .num_controls = ARRAY_SIZE(cpcap_snd_controls), .dapm_widgets = cpcap_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(cpcap_dapm_widgets), .dapm_routes = intercon, .num_dapm_routes = ARRAY_SIZE(intercon), + .set_bias_level = cpcap_set_bias_level, .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, diff --git a/sound/soc/codecs/cros_ec_codec.c b/sound/soc/codecs/cros_ec_codec.c index 11e7b3f6d410..571222ec520c 100644 --- a/sound/soc/codecs/cros_ec_codec.c +++ b/sound/soc/codecs/cros_ec_codec.c @@ -21,6 +21,7 @@ #include <linux/platform_data/cros_ec_commands.h> #include <linux/platform_data/cros_ec_proto.h> #include <linux/platform_device.h> +#include <linux/string_choices.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -657,7 +658,7 @@ static int wov_enable_put(struct snd_kcontrol *kcontrol, (uint8_t *)&p, sizeof(p), NULL, 0); if (ret) { dev_err(priv->dev, "failed to %s wov\n", - enabled ? "enable" : "disable"); + str_enable_disable(enabled)); return ret; } diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 96555263e10b..0bb4bdb3deec 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -153,12 +153,12 @@ static int cs35l32_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct snd_soc_component *component = codec_dai->component; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: snd_soc_component_update_bits(component, CS35L32_ADSP_CTL, CS35L32_ADSP_MASTER_MASK, CS35L32_ADSP_MASTER_MASK); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: snd_soc_component_update_bits(component, CS35L32_ADSP_CTL, CS35L32_ADSP_MASTER_MASK, 0); break; @@ -504,7 +504,6 @@ static void cs35l32_i2c_remove(struct i2c_client *i2c_client) gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); } -#ifdef CONFIG_PM static int cs35l32_runtime_suspend(struct device *dev) { struct cs35l32_private *cs35l32 = dev_get_drvdata(dev); @@ -543,11 +542,9 @@ static int cs35l32_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops cs35l32_runtime_pm = { - SET_RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, - NULL) + RUNTIME_PM_OPS(cs35l32_runtime_suspend, cs35l32_runtime_resume, NULL) }; static const struct of_device_id cs35l32_of_match[] = { @@ -567,7 +564,7 @@ MODULE_DEVICE_TABLE(i2c, cs35l32_id); static struct i2c_driver cs35l32_i2c_driver = { .driver = { .name = "cs35l32", - .pm = &cs35l32_runtime_pm, + .pm = pm_ptr(&cs35l32_runtime_pm), .of_match_table = cs35l32_of_match, }, .id_table = cs35l32_id, diff --git a/sound/soc/codecs/cs35l33.c b/sound/soc/codecs/cs35l33.c index b03aab147530..c927592f90c9 100644 --- a/sound/soc/codecs/cs35l33.c +++ b/sound/soc/codecs/cs35l33.c @@ -438,12 +438,12 @@ static int cs35l33_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct cs35l33_private *priv = snd_soc_component_get_drvdata(component); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL, CS35L33_MS_MASK, CS35L33_MS_MASK); dev_dbg(component->dev, "Audio port in master mode\n"); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: regmap_update_bits(priv->regmap, CS35L33_ADSP_CTL, CS35L33_MS_MASK, 0); dev_dbg(component->dev, "Audio port in slave mode\n"); @@ -853,7 +853,7 @@ static const struct regmap_config cs35l33_regmap = { .use_single_write = true, }; -static int __maybe_unused cs35l33_runtime_resume(struct device *dev) +static int cs35l33_runtime_resume(struct device *dev) { struct cs35l33_private *cs35l33 = dev_get_drvdata(dev); int ret; @@ -891,7 +891,7 @@ err: return ret; } -static int __maybe_unused cs35l33_runtime_suspend(struct device *dev) +static int cs35l33_runtime_suspend(struct device *dev) { struct cs35l33_private *cs35l33 = dev_get_drvdata(dev); @@ -909,9 +909,7 @@ static int __maybe_unused cs35l33_runtime_suspend(struct device *dev) } static const struct dev_pm_ops cs35l33_pm_ops = { - SET_RUNTIME_PM_OPS(cs35l33_runtime_suspend, - cs35l33_runtime_resume, - NULL) + RUNTIME_PM_OPS(cs35l33_runtime_suspend, cs35l33_runtime_resume, NULL) }; static int cs35l33_get_hg_data(const struct device_node *np, @@ -1273,7 +1271,7 @@ MODULE_DEVICE_TABLE(i2c, cs35l33_id); static struct i2c_driver cs35l33_i2c_driver = { .driver = { .name = "cs35l33", - .pm = &cs35l33_pm_ops, + .pm = pm_ptr(&cs35l33_pm_ops), .of_match_table = cs35l33_of_match, }, diff --git a/sound/soc/codecs/cs35l34.c b/sound/soc/codecs/cs35l34.c index 287b27476a10..a5a8075598ff 100644 --- a/sound/soc/codecs/cs35l34.c +++ b/sound/soc/codecs/cs35l34.c @@ -523,11 +523,11 @@ static int cs35l34_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct cs35l34_private *priv = snd_soc_component_get_drvdata(component); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, 0x80, 0x80); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: regmap_update_bits(priv->regmap, CS35L34_ADSP_CLK_CTL, 0x80, 0x00); break; @@ -1116,7 +1116,7 @@ static void cs35l34_i2c_remove(struct i2c_client *client) cs35l34->core_supplies); } -static int __maybe_unused cs35l34_runtime_resume(struct device *dev) +static int cs35l34_runtime_resume(struct device *dev) { struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); int ret; @@ -1149,7 +1149,7 @@ err: return ret; } -static int __maybe_unused cs35l34_runtime_suspend(struct device *dev) +static int cs35l34_runtime_suspend(struct device *dev) { struct cs35l34_private *cs35l34 = dev_get_drvdata(dev); @@ -1165,9 +1165,7 @@ static int __maybe_unused cs35l34_runtime_suspend(struct device *dev) } static const struct dev_pm_ops cs35l34_pm_ops = { - SET_RUNTIME_PM_OPS(cs35l34_runtime_suspend, - cs35l34_runtime_resume, - NULL) + RUNTIME_PM_OPS(cs35l34_runtime_suspend, cs35l34_runtime_resume, NULL) }; static const struct of_device_id cs35l34_of_match[] = { @@ -1185,7 +1183,7 @@ MODULE_DEVICE_TABLE(i2c, cs35l34_id); static struct i2c_driver cs35l34_i2c_driver = { .driver = { .name = "cs35l34", - .pm = &cs35l34_pm_ops, + .pm = pm_ptr(&cs35l34_pm_ops), .of_match_table = cs35l34_of_match, }, diff --git a/sound/soc/codecs/cs35l41-spi.c b/sound/soc/codecs/cs35l41-spi.c index a6db44520c06..f9b6bf7bea9c 100644 --- a/sound/soc/codecs/cs35l41-spi.c +++ b/sound/soc/codecs/cs35l41-spi.c @@ -32,13 +32,16 @@ static int cs35l41_spi_probe(struct spi_device *spi) const struct regmap_config *regmap_config = &cs35l41_regmap_spi; struct cs35l41_hw_cfg *hw_cfg = dev_get_platdata(&spi->dev); struct cs35l41_private *cs35l41; + int ret; cs35l41 = devm_kzalloc(&spi->dev, sizeof(struct cs35l41_private), GFP_KERNEL); if (!cs35l41) return -ENOMEM; spi->max_speed_hz = CS35L41_SPI_MAX_FREQ; - spi_setup(spi); + ret = spi_setup(spi); + if (ret < 0) + return ret; spi_set_drvdata(spi, cs35l41); cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config); diff --git a/sound/soc/codecs/cs35l56.c b/sound/soc/codecs/cs35l56.c index 735a1e487c6f..b3158a84b87a 100644 --- a/sound/soc/codecs/cs35l56.c +++ b/sound/soc/codecs/cs35l56.c @@ -1441,7 +1441,6 @@ void cs35l56_remove(struct cs35l56_private *cs35l56) if (cs35l56->base.irq) devm_free_irq(cs35l56->base.dev, cs35l56->base.irq, &cs35l56->base); - flush_workqueue(cs35l56->dsp_wq); destroy_workqueue(cs35l56->dsp_wq); pm_runtime_dont_use_autosuspend(cs35l56->base.dev); diff --git a/sound/soc/codecs/cs4234.c b/sound/soc/codecs/cs4234.c index 69287ba7e955..dda7f5b4f2fb 100644 --- a/sound/soc/codecs/cs4234.c +++ b/sound/soc/codecs/cs4234.c @@ -307,9 +307,9 @@ static int cs4234_dai_set_fmt(struct snd_soc_dai *codec_dai, unsigned int format } switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: if (cs4234->format == SND_SOC_DAIFMT_DSP_A) { dev_err(component->dev, "Unsupported DSP A format in master mode\n"); return -EINVAL; @@ -860,7 +860,7 @@ static void cs4234_i2c_remove(struct i2c_client *i2c_client) cs4234_shutdown(cs4234); } -static int __maybe_unused cs4234_runtime_resume(struct device *dev) +static int cs4234_runtime_resume(struct device *dev) { struct cs4234 *cs4234 = dev_get_drvdata(dev); int ret; @@ -881,7 +881,7 @@ static int __maybe_unused cs4234_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused cs4234_runtime_suspend(struct device *dev) +static int cs4234_runtime_suspend(struct device *dev) { struct cs4234 *cs4234 = dev_get_drvdata(dev); @@ -891,7 +891,7 @@ static int __maybe_unused cs4234_runtime_suspend(struct device *dev) } static const struct dev_pm_ops cs4234_pm = { - SET_RUNTIME_PM_OPS(cs4234_runtime_suspend, cs4234_runtime_resume, NULL) + RUNTIME_PM_OPS(cs4234_runtime_suspend, cs4234_runtime_resume, NULL) }; static const struct of_device_id cs4234_of_match[] = { @@ -903,7 +903,7 @@ MODULE_DEVICE_TABLE(of, cs4234_of_match); static struct i2c_driver cs4234_i2c_driver = { .driver = { .name = "cs4234", - .pm = &cs4234_pm, + .pm = pm_ptr(&cs4234_pm), .of_match_table = cs4234_of_match, }, .probe = cs4234_i2c_probe, diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index 78ffb7fa7fc5..3f759c13d6d1 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -344,12 +344,12 @@ static int cs4265_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u8 iface = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_MASTER, CS4265_ADC_MASTER); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: snd_soc_component_update_bits(component, CS4265_ADC_CTL, CS4265_ADC_MASTER, 0); diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index 67e92bfecb56..9f9dc8b017a3 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -287,10 +287,10 @@ static int cs4270_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: cs4270->slave_mode = 1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: cs4270->slave_mode = 0; break; default: diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c index e864188ae5eb..6a3cca3d26c7 100644 --- a/sound/soc/codecs/cs4271.c +++ b/sound/soc/codecs/cs4271.c @@ -209,10 +209,10 @@ static int cs4271_set_dai_fmt(struct snd_soc_dai *codec_dai, int ret; switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: cs4271->master = false; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: cs4271->master = true; val |= CS4271_MODE1_MASTER; break; diff --git a/sound/soc/codecs/cs42l42-i2c.c b/sound/soc/codecs/cs42l42-i2c.c index 8a1d5c7a61d7..98b6718ccabf 100644 --- a/sound/soc/codecs/cs42l42-i2c.c +++ b/sound/soc/codecs/cs42l42-i2c.c @@ -48,7 +48,7 @@ static void cs42l42_i2c_remove(struct i2c_client *i2c_client) cs42l42_common_remove(cs42l42); } -static int __maybe_unused cs42l42_i2c_resume(struct device *dev) +static int cs42l42_i2c_resume(struct device *dev) { int ret; @@ -62,7 +62,7 @@ static int __maybe_unused cs42l42_i2c_resume(struct device *dev) } static const struct dev_pm_ops cs42l42_i2c_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume) + SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_i2c_resume) }; static const struct of_device_id __maybe_unused cs42l42_of_match[] = { @@ -87,7 +87,7 @@ MODULE_DEVICE_TABLE(i2c, cs42l42_id); static struct i2c_driver cs42l42_i2c_driver = { .driver = { .name = "cs42l42", - .pm = &cs42l42_i2c_pm_ops, + .pm = pm_ptr(&cs42l42_i2c_pm_ops), .of_match_table = of_match_ptr(cs42l42_of_match), .acpi_match_table = ACPI_PTR(cs42l42_acpi_match), }, diff --git a/sound/soc/codecs/cs42l42-sdw.c b/sound/soc/codecs/cs42l42-sdw.c index ae1401b250a3..f837c7eff10b 100644 --- a/sound/soc/codecs/cs42l42-sdw.c +++ b/sound/soc/codecs/cs42l42-sdw.c @@ -411,7 +411,7 @@ static const struct sdw_slave_ops cs42l42_sdw_ops = { .port_prep = cs42l42_sdw_port_prep, }; -static int __maybe_unused cs42l42_sdw_runtime_suspend(struct device *dev) +static int cs42l42_sdw_runtime_suspend(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); @@ -426,11 +426,11 @@ static int __maybe_unused cs42l42_sdw_runtime_suspend(struct device *dev) return 0; } -static const struct reg_sequence __maybe_unused cs42l42_soft_reboot_seq[] = { +static const struct reg_sequence cs42l42_soft_reboot_seq[] = { REG_SEQ0(CS42L42_SOFT_RESET_REBOOT, 0x1e), }; -static int __maybe_unused cs42l42_sdw_handle_unattach(struct cs42l42_private *cs42l42) +static int cs42l42_sdw_handle_unattach(struct cs42l42_private *cs42l42) { struct sdw_slave *peripheral = cs42l42->sdw_peripheral; @@ -460,7 +460,7 @@ static int __maybe_unused cs42l42_sdw_handle_unattach(struct cs42l42_private *cs return 0; } -static int __maybe_unused cs42l42_sdw_runtime_resume(struct device *dev) +static int cs42l42_sdw_runtime_resume(struct device *dev) { static const unsigned int ts_dbnce_ms[] = { 0, 125, 250, 500, 750, 1000, 1250, 1500}; struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); @@ -491,7 +491,7 @@ static int __maybe_unused cs42l42_sdw_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused cs42l42_sdw_resume(struct device *dev) +static int cs42l42_sdw_resume(struct device *dev) { struct cs42l42_private *cs42l42 = dev_get_drvdata(dev); int ret; @@ -596,8 +596,8 @@ static int cs42l42_sdw_remove(struct sdw_slave *peripheral) } static const struct dev_pm_ops cs42l42_sdw_pm = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_sdw_resume) - SET_RUNTIME_PM_OPS(cs42l42_sdw_runtime_suspend, cs42l42_sdw_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l42_sdw_resume) + RUNTIME_PM_OPS(cs42l42_sdw_runtime_suspend, cs42l42_sdw_runtime_resume, NULL) }; static const struct sdw_device_id cs42l42_sdw_id[] = { @@ -609,7 +609,7 @@ MODULE_DEVICE_TABLE(sdw, cs42l42_sdw_id); static struct sdw_driver cs42l42_sdw_driver = { .driver = { .name = "cs42l42-sdw", - .pm = &cs42l42_sdw_pm, + .pm = pm_ptr(&cs42l42_sdw_pm), }, .probe = cs42l42_sdw_probe, .remove = cs42l42_sdw_remove, diff --git a/sound/soc/codecs/cs42l42.c b/sound/soc/codecs/cs42l42.c index 501c951cc327..56668c392063 100644 --- a/sound/soc/codecs/cs42l42.c +++ b/sound/soc/codecs/cs42l42.c @@ -830,11 +830,11 @@ static int cs42l42_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u32 asp_cfg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: asp_cfg_val |= CS42L42_ASP_MASTER_MODE << CS42L42_ASP_MODE_SHIFT; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: asp_cfg_val |= CS42L42_ASP_SLAVE_MODE << CS42L42_ASP_MODE_SHIFT; break; diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index f171bd66fcac..ba7e237619f2 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -40,7 +40,7 @@ static void cs42l51_i2c_remove(struct i2c_client *i2c) } static const struct dev_pm_ops cs42l51_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume) + SYSTEM_SLEEP_PM_OPS(cs42l51_suspend, cs42l51_resume) }; static struct i2c_driver cs42l51_i2c_driver = { diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c index 6e51954bdb1e..8083a339dc7b 100644 --- a/sound/soc/codecs/cs42l51.c +++ b/sound/soc/codecs/cs42l51.c @@ -322,10 +322,10 @@ static int cs42l51_set_dai_fmt(struct snd_soc_dai *codec_dai, } switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: cs42l51->func = MODE_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: cs42l51->func = MODE_SLAVE_AUTO; break; default: @@ -805,7 +805,7 @@ void cs42l51_remove(struct device *dev) } EXPORT_SYMBOL_GPL(cs42l51_remove); -int __maybe_unused cs42l51_suspend(struct device *dev) +int cs42l51_suspend(struct device *dev) { struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); @@ -816,7 +816,7 @@ int __maybe_unused cs42l51_suspend(struct device *dev) } EXPORT_SYMBOL_GPL(cs42l51_suspend); -int __maybe_unused cs42l51_resume(struct device *dev) +int cs42l51_resume(struct device *dev) { struct cs42l51_private *cs42l51 = dev_get_drvdata(dev); diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 7128d4c62f50..cd3f92c19045 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -733,10 +733,10 @@ static int cs42l52_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u8 iface = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: iface = CS42L52_IFACE_CTL1_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface = CS42L52_IFACE_CTL1_SLAVE; break; default: diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index aaa10c459b52..aaf90c8b7339 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -757,10 +757,10 @@ static int cs42l56_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct cs42l56_private *cs42l56 = snd_soc_component_get_drvdata(component); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: cs42l56->iface = CS42L56_MASTER_MODE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: cs42l56->iface = CS42L56_SLAVE_MODE; break; default: diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index 21ba796a5cd9..ddf36001100e 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -943,11 +943,11 @@ static int cs42l73_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) mmcc = snd_soc_component_read(component, CS42L73_MMCC(id)); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: mmcc |= CS42L73_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: mmcc &= ~CS42L73_MS_MASTER; break; diff --git a/sound/soc/codecs/cs42l83-i2c.c b/sound/soc/codecs/cs42l83-i2c.c index 42c3e1efdc08..53a7fe1ab3dd 100644 --- a/sound/soc/codecs/cs42l83-i2c.c +++ b/sound/soc/codecs/cs42l83-i2c.c @@ -199,7 +199,7 @@ static void cs42l83_i2c_remove(struct i2c_client *i2c_client) cs42l42_common_remove(cs42l83); } -static int __maybe_unused cs42l83_i2c_resume(struct device *dev) +static int cs42l83_i2c_resume(struct device *dev) { int ret; @@ -213,7 +213,7 @@ static int __maybe_unused cs42l83_i2c_resume(struct device *dev) } static const struct dev_pm_ops cs42l83_i2c_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume) + SYSTEM_SLEEP_PM_OPS(cs42l42_suspend, cs42l83_i2c_resume) }; static const struct of_device_id __maybe_unused cs42l83_of_match[] = { @@ -225,7 +225,7 @@ MODULE_DEVICE_TABLE(of, cs42l83_of_match); static struct i2c_driver cs42l83_i2c_driver = { .driver = { .name = "cs42l83", - .pm = &cs42l83_i2c_pm_ops, + .pm = pm_ptr(&cs42l83_i2c_pm_ops), .of_match_table = of_match_ptr(cs42l83_of_match), }, .probe = cs42l83_i2c_probe, diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index ecaebf8e1c8f..039b3ecb3b9b 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -61,7 +61,7 @@ MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id); static struct i2c_driver cs42xx8_i2c_driver = { .driver = { .name = "cs42xx8", - .pm = &cs42xx8_pm, + .pm = pm_ptr(&cs42xx8_pm), .of_match_table = cs42xx8_of_match, }, .probe = cs42xx8_i2c_probe, diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index 9c44b6283b8f..6a925f3f7137 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -242,10 +242,10 @@ static int cs42xx8_set_dai_fmt(struct snd_soc_dai *codec_dai, /* Set master/slave audio interface */ switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: cs42xx8->slave_mode = true; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: cs42xx8->slave_mode = false; break; default: @@ -606,7 +606,6 @@ err_enable: } EXPORT_SYMBOL_GPL(cs42xx8_probe); -#ifdef CONFIG_PM static int cs42xx8_runtime_resume(struct device *dev) { struct cs42xx8_priv *cs42xx8 = dev_get_drvdata(dev); @@ -665,14 +664,11 @@ static int cs42xx8_runtime_suspend(struct device *dev) return 0; } -#endif -const struct dev_pm_ops cs42xx8_pm = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) +EXPORT_GPL_DEV_PM_OPS(cs42xx8_pm) = { + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(cs42xx8_runtime_suspend, cs42xx8_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(cs42xx8_pm); MODULE_DESCRIPTION("Cirrus Logic CS42448/CS42888 ALSA SoC Codec Driver"); MODULE_AUTHOR("Freescale Semiconductor, Inc."); diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index f8e2fb69ada2..d9b3d73c8388 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c @@ -640,10 +640,10 @@ static int cs43130_set_sp_fmt(int dai_id, unsigned int bitwidth_sclk, } switch (cs43130->dais[dai_id].dai_mode) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: dai_mode_val = 0; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: dai_mode_val = 1; break; default: @@ -851,7 +851,7 @@ static int cs43130_dsd_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM) + if (cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBP_CFP) regmap_update_bits(cs43130->regmap, CS43130_DSD_INT_CFG, CS43130_DSD_MASTER, CS43130_DSD_MASTER); else @@ -951,7 +951,7 @@ static int cs43130_hw_params(struct snd_pcm_substream *substream, break; } - if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBM_CFM) + if (!sclk && cs43130->dais[dai->id].dai_mode == SND_SOC_DAIFMT_CBP_CFP) /* Calculate SCLK in master mode if unassigned */ sclk = params_rate(params) * bitwidth_dai * params_channels(params); @@ -1516,11 +1516,11 @@ static int cs43130_pcm_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS; + case SND_SOC_DAIFMT_CBC_CFC: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBC_CFC; break; - case SND_SOC_DAIFMT_CBM_CFM: - cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; + case SND_SOC_DAIFMT_CBP_CFP: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBP_CFP; break; default: dev_err(cs43130->dev, "unsupported mode\n"); @@ -1579,11 +1579,11 @@ static int cs43130_dsd_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) struct cs43130_private *cs43130 = snd_soc_component_get_drvdata(component); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: - cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBS_CFS; + case SND_SOC_DAIFMT_CBC_CFC: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBC_CFC; break; - case SND_SOC_DAIFMT_CBM_CFM: - cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBM_CFM; + case SND_SOC_DAIFMT_CBP_CFP: + cs43130->dais[codec_dai->id].dai_mode = SND_SOC_DAIFMT_CBP_CFP; break; default: dev_err(cs43130->dev, "Unsupported DAI format.\n"); @@ -2672,7 +2672,7 @@ static void cs43130_i2c_remove(struct i2c_client *client) regulator_bulk_disable(CS43130_NUM_SUPPLIES, cs43130->supplies); } -static int __maybe_unused cs43130_runtime_suspend(struct device *dev) +static int cs43130_runtime_suspend(struct device *dev) { struct cs43130_private *cs43130 = dev_get_drvdata(dev); @@ -2691,7 +2691,7 @@ static int __maybe_unused cs43130_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused cs43130_runtime_resume(struct device *dev) +static int cs43130_runtime_resume(struct device *dev) { struct cs43130_private *cs43130 = dev_get_drvdata(dev); int ret; @@ -2727,8 +2727,7 @@ err: } static const struct dev_pm_ops cs43130_runtime_pm = { - SET_RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume, - NULL) + RUNTIME_PM_OPS(cs43130_runtime_suspend, cs43130_runtime_resume, NULL) }; #if IS_ENABLED(CONFIG_OF) @@ -2768,7 +2767,7 @@ static struct i2c_driver cs43130_i2c_driver = { .name = "cs43130", .of_match_table = of_match_ptr(cs43130_of_match), .acpi_match_table = ACPI_PTR(cs43130_acpi_match), - .pm = &cs43130_runtime_pm, + .pm = pm_ptr(&cs43130_runtime_pm), }, .id_table = cs43130_i2c_id, .probe = cs43130_i2c_probe, diff --git a/sound/soc/codecs/cs4341.c b/sound/soc/codecs/cs4341.c index d87aae31c516..b726e22ef57d 100644 --- a/sound/soc/codecs/cs4341.c +++ b/sound/soc/codecs/cs4341.c @@ -49,7 +49,7 @@ static int cs4341_set_fmt(struct snd_soc_dai *dai, unsigned int format) struct cs4341_priv *cs4341 = snd_soc_component_get_drvdata(component); switch (format & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a134ca722892..d9a9c34fffe3 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -312,7 +312,6 @@ static void cs4349_i2c_remove(struct i2c_client *client) gpiod_set_value_cansleep(cs4349->reset_gpio, 0); } -#ifdef CONFIG_PM static int cs4349_runtime_suspend(struct device *dev) { struct cs4349_private *cs4349 = dev_get_drvdata(dev); @@ -346,11 +345,9 @@ static int cs4349_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops cs4349_runtime_pm = { - SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume, - NULL) + RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume, NULL) }; static const struct of_device_id cs4349_of_match[] = { @@ -371,7 +368,7 @@ static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", .of_match_table = cs4349_of_match, - .pm = &cs4349_runtime_pm, + .pm = pm_ptr(&cs4349_runtime_pm), }, .id_table = cs4349_i2c_id, .probe = cs4349_i2c_probe, diff --git a/sound/soc/codecs/cs530x.c b/sound/soc/codecs/cs530x.c index 252e66c8449e..b9eff240b929 100644 --- a/sound/soc/codecs/cs530x.c +++ b/sound/soc/codecs/cs530x.c @@ -557,9 +557,9 @@ static int cs530x_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int asp_fmt, asp_cfg = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: asp_cfg = CS530X_ASP_PRIMARY; break; default: diff --git a/sound/soc/codecs/cs53l30.c b/sound/soc/codecs/cs53l30.c index 28f4be37dec1..61bf72681674 100644 --- a/sound/soc/codecs/cs53l30.c +++ b/sound/soc/codecs/cs53l30.c @@ -572,10 +572,10 @@ static int cs53l30_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) u8 aspcfg = 0, aspctl1 = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aspcfg |= CS53L30_ASP_MS; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -1031,7 +1031,6 @@ static void cs53l30_i2c_remove(struct i2c_client *client) cs53l30->supplies); } -#ifdef CONFIG_PM static int cs53l30_runtime_suspend(struct device *dev) { struct cs53l30_private *cs53l30 = dev_get_drvdata(dev); @@ -1070,11 +1069,9 @@ static int cs53l30_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops cs53l30_runtime_pm = { - SET_RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume, - NULL) + RUNTIME_PM_OPS(cs53l30_runtime_suspend, cs53l30_runtime_resume, NULL) }; static const struct of_device_id cs53l30_of_match[] = { @@ -1095,7 +1092,7 @@ static struct i2c_driver cs53l30_i2c_driver = { .driver = { .name = "cs53l30", .of_match_table = cs53l30_of_match, - .pm = &cs53l30_runtime_pm, + .pm = pm_ptr(&cs53l30_runtime_pm), }, .id_table = cs53l30_id, .probe = cs53l30_i2c_probe, diff --git a/sound/soc/codecs/cx2072x.c b/sound/soc/codecs/cx2072x.c index 8cfec8dcf839..934526f8f292 100644 --- a/sound/soc/codecs/cx2072x.c +++ b/sound/soc/codecs/cx2072x.c @@ -1611,7 +1611,7 @@ static const struct regmap_config cx2072x_regmap = { .reg_write = cx2072x_reg_write, }; -static int __maybe_unused cx2072x_runtime_suspend(struct device *dev) +static int cx2072x_runtime_suspend(struct device *dev) { struct cx2072x_priv *cx2072x = dev_get_drvdata(dev); @@ -1619,7 +1619,7 @@ static int __maybe_unused cx2072x_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused cx2072x_runtime_resume(struct device *dev) +static int cx2072x_runtime_resume(struct device *dev) { struct cx2072x_priv *cx2072x = dev_get_drvdata(dev); @@ -1696,17 +1696,15 @@ MODULE_DEVICE_TABLE(acpi, cx2072x_acpi_match); #endif static const struct dev_pm_ops cx2072x_runtime_pm = { - SET_RUNTIME_PM_OPS(cx2072x_runtime_suspend, cx2072x_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(cx2072x_runtime_suspend, cx2072x_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct i2c_driver cx2072x_i2c_driver = { .driver = { .name = "cx2072x", .acpi_match_table = ACPI_PTR(cx2072x_acpi_match), - .pm = &cx2072x_runtime_pm, + .pm = pm_ptr(&cx2072x_runtime_pm), }, .probe = cx2072x_i2c_probe, .remove = cx2072x_i2c_remove, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index da2d0242019e..a889f05119f8 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -882,11 +882,11 @@ static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) return -EINVAL; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: da7210->master = 1; dai_cfg1 |= DA7210_DAI_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: da7210->master = 0; dai_cfg1 |= DA7210_DAI_MODE_SLAVE; break; diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index eb97ac73ec06..a4496cc26902 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -2224,7 +2224,7 @@ static void da7213_i2c_remove(struct i2c_client *i2c) pm_runtime_disable(&i2c->dev); } -static int __maybe_unused da7213_runtime_suspend(struct device *dev) +static int da7213_runtime_suspend(struct device *dev) { struct da7213_priv *da7213 = dev_get_drvdata(dev); @@ -2235,7 +2235,7 @@ static int __maybe_unused da7213_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused da7213_runtime_resume(struct device *dev) +static int da7213_runtime_resume(struct device *dev) { struct da7213_priv *da7213 = dev_get_drvdata(dev); int ret; @@ -2248,8 +2248,8 @@ static int __maybe_unused da7213_runtime_resume(struct device *dev) } static const struct dev_pm_ops da7213_pm = { - SET_RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(da7213_runtime_suspend, da7213_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct i2c_device_id da7213_i2c_id[] = { @@ -2264,7 +2264,7 @@ static struct i2c_driver da7213_i2c_driver = { .name = "da7213", .of_match_table = of_match_ptr(da7213_of_match), .acpi_match_table = ACPI_PTR(da7213_acpi_match), - .pm = &da7213_pm, + .pm = pm_ptr(&da7213_pm), }, .probe = da7213_i2c_probe, .remove = da7213_i2c_remove, diff --git a/sound/soc/codecs/da7218.c b/sound/soc/codecs/da7218.c index 8aacd7350798..5f2f67e3bd29 100644 --- a/sound/soc/codecs/da7218.c +++ b/sound/soc/codecs/da7218.c @@ -1935,10 +1935,10 @@ static int da7218_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u8 dai_clk_mode = 0, dai_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: da7218->master = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: da7218->master = false; break; default: diff --git a/sound/soc/codecs/da7219.c b/sound/soc/codecs/da7219.c index e2da3e317b5a..3958e88a2445 100644 --- a/sound/soc/codecs/da7219.c +++ b/sound/soc/codecs/da7219.c @@ -1312,10 +1312,10 @@ static int da7219_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u8 dai_clk_mode = 0, dai_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: da7219->master = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: da7219->master = false; break; default: diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index b747f6fa12e4..016c9be3ebda 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1034,11 +1034,11 @@ static int da732x_set_dai_fmt(struct snd_soc_dai *dai, u32 fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: aif1 = DA732X_AIF_SLAVE; aif_mclk = DA732X_AIFM_FRAME_64 | DA732X_AIFM_SRC_SEL_AIFA; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif1 = DA732X_AIF_CLK_FROM_SRC; aif_mclk = DA732X_CLK_GENERATION_AIF_A; break; diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 8bb8fef2a1d1..eb795abe9acd 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1160,12 +1160,12 @@ static int da9055_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) u8 aif_clk_mode, aif_ctrl, mode; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: /* DA9055 in I2S Master Mode */ mode = 1; aif_clk_mode = DA9055_AIF_CLK_EN_MASTER_MODE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: /* DA9055 in I2S Slave Mode */ mode = 0; aif_clk_mode = DA9055_AIF_CLK_EN_SLAVE_MODE; diff --git a/sound/soc/codecs/dmic.c b/sound/soc/codecs/dmic.c index 4fd6f97e5a49..61e1bf1b3c9e 100644 --- a/sound/soc/codecs/dmic.c +++ b/sound/soc/codecs/dmic.c @@ -9,6 +9,7 @@ #include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/platform_device.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> #include <linux/module.h> #include <sound/core.h> @@ -25,6 +26,7 @@ module_param(wakeup_delay, uint, 0644); struct dmic { struct gpio_desc *gpio_en; + struct regulator *vref; int wakeup_delay; /* Delay after DMIC mode switch */ int modeswitch_delay; @@ -55,22 +57,33 @@ static int dmic_aif_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct dmic *dmic = snd_soc_component_get_drvdata(component); + int ret = 0; switch (event) { case SND_SOC_DAPM_POST_PMU: if (dmic->gpio_en) gpiod_set_value_cansleep(dmic->gpio_en, 1); + if (dmic->vref) { + ret = regulator_enable(dmic->vref); + if (ret) + return ret; + } + if (dmic->wakeup_delay) msleep(dmic->wakeup_delay); break; case SND_SOC_DAPM_POST_PMD: if (dmic->gpio_en) gpiod_set_value_cansleep(dmic->gpio_en, 0); + + if (dmic->vref) + ret = regulator_disable(dmic->vref); + break; } - return 0; + return ret; } static struct snd_soc_dai_driver dmic_dai = { @@ -85,7 +98,9 @@ static struct snd_soc_dai_driver dmic_dai = { | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_DSD_U8 | SNDRV_PCM_FMTBIT_DSD_U16_LE - | SNDRV_PCM_FMTBIT_DSD_U32_LE, + | SNDRV_PCM_FMTBIT_DSD_U32_LE + | SNDRV_PCM_FMTBIT_DSD_U16_BE + | SNDRV_PCM_FMTBIT_DSD_U32_BE, }, .ops = &dmic_dai_ops, }; @@ -98,6 +113,14 @@ static int dmic_component_probe(struct snd_soc_component *component) if (!dmic) return -ENOMEM; + dmic->vref = devm_regulator_get_optional(component->dev, "vref"); + if (IS_ERR(dmic->vref)) { + if (PTR_ERR(dmic->vref) != -ENODEV) + return dev_err_probe(component->dev, PTR_ERR(dmic->vref), + "Failed to get vref\n"); + dmic->vref = NULL; + } + dmic->gpio_en = devm_gpiod_get_optional(component->dev, "dmicen", GPIOD_OUT_LOW); if (IS_ERR(dmic->gpio_en)) diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c index e1a7f0b0c0f3..1139a2754ca3 100644 --- a/sound/soc/codecs/hdac_hdmi.c +++ b/sound/soc/codecs/hdac_hdmi.c @@ -1017,8 +1017,7 @@ static int hdac_hdmi_create_pin_port_muxs(struct hdac_device *hdev, return -ENOMEM; } - se->texts = devm_kmemdup(&hdev->dev, items, - (num_items * sizeof(char *)), GFP_KERNEL); + se->texts = devm_kmemdup_array(&hdev->dev, items, num_items, sizeof(items[0]), GFP_KERNEL); if (!se->texts) return -ENOMEM; @@ -2033,7 +2032,6 @@ static void hdmi_codec_remove(struct snd_soc_component *component) pm_runtime_disable(&hdev->dev); } -#ifdef CONFIG_PM_SLEEP static int hdmi_codec_resume(struct device *dev) { struct hdac_device *hdev = dev_to_hdac_dev(dev); @@ -2056,9 +2054,6 @@ static int hdmi_codec_resume(struct device *dev) hdac_hdmi_present_sense_all_pins(hdev, hdmi, false); return 0; } -#else -#define hdmi_codec_resume NULL -#endif static const struct snd_soc_component_driver hdmi_hda_codec = { .probe = hdmi_codec_probe, @@ -2228,7 +2223,6 @@ static int hdac_hdmi_dev_remove(struct hdac_device *hdev) return 0; } -#ifdef CONFIG_PM static int hdac_hdmi_runtime_suspend(struct device *dev) { struct hdac_device *hdev = dev_to_hdac_dev(dev); @@ -2297,14 +2291,10 @@ static int hdac_hdmi_runtime_resume(struct device *dev) return 0; } -#else -#define hdac_hdmi_runtime_suspend NULL -#define hdac_hdmi_runtime_resume NULL -#endif static const struct dev_pm_ops hdac_hdmi_pm = { - SET_RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, hdmi_codec_resume) + RUNTIME_PM_OPS(hdac_hdmi_runtime_suspend, hdac_hdmi_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, hdmi_codec_resume) }; static const struct hda_device_id hdmi_list[] = { @@ -2323,7 +2313,7 @@ MODULE_DEVICE_TABLE(hdaudio, hdmi_list); static struct hdac_driver hdmi_driver = { .driver = { .name = "HDMI HDA Codec", - .pm = &hdac_hdmi_pm, + .pm = pm_ptr(&hdac_hdmi_pm), }, .id_table = hdmi_list, .probe = hdac_hdmi_dev_probe, diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 69f98975e14a..497376bcd3ff 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -281,6 +281,7 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; uint8_t eld[MAX_ELD_BYTES]; + struct snd_parsed_hdmi_eld eld_parsed; struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; struct mutex lock; @@ -288,6 +289,7 @@ struct hdmi_codec_priv { struct snd_soc_jack *jack; unsigned int jack_status; u8 iec_status[AES_IEC958_STATUS_SIZE]; + struct snd_info_entry *proc_entry; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -469,6 +471,9 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (ret) goto err; + snd_parse_eld(dai->dev, &hcp->eld_parsed, + hcp->eld, sizeof(hcp->eld)); + ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); if (ret) goto err; @@ -825,8 +830,54 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +#ifdef CONFIG_SND_PROC_FS +static void print_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_codec_priv *hcp = entry->private_data; + + snd_print_eld_info(&hcp->eld_parsed, buffer); +} + +static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp, + struct snd_soc_dai *dai) +{ + struct snd_info_entry *entry; + char name[32]; + int err; + + snprintf(name, sizeof(name), "eld#%d", dai->id); + err = snd_card_proc_new(dai->component->card->snd_card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, hcp, print_eld_info); + hcp->proc_entry = entry; + + return 0; +} + +static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp) +{ + snd_info_free_entry(hcp->proc_entry); + hcp->proc_entry = NULL; +} +#else +static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp) +{ +} +#endif + static int hdmi_dai_probe(struct snd_soc_dai *dai) { + struct hdmi_codec_priv *hcp = + snd_soc_component_get_drvdata(dai->component); struct snd_soc_dapm_context *dapm; struct hdmi_codec_daifmt *daifmt; struct snd_soc_dapm_route route[] = { @@ -859,6 +910,15 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) snd_soc_dai_dma_data_set_playback(dai, daifmt); + return hdmi_dai_proc_new(hcp, dai); +} + +static int hdmi_dai_remove(struct snd_soc_dai *dai) +{ + struct hdmi_codec_priv *hcp = + snd_soc_component_get_drvdata(dai->component); + + hdmi_dai_proc_free(hcp); return 0; } @@ -875,11 +935,18 @@ static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, static void plugged_cb(struct device *dev, bool plugged) { struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); + int ret; if (plugged) { if (hcp->hcd.ops->get_eld) { hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); + ret = snd_parse_eld(dev, &hcp->eld_parsed, + hcp->eld, sizeof(hcp->eld)); + if (ret < 0) + dev_dbg(dev, "Failed to parse ELD: %d\n", ret); + else + snd_show_eld(dev, &hcp->eld_parsed); } hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); } else { @@ -926,6 +993,7 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { .probe = hdmi_dai_probe, + .remove = hdmi_dai_remove, .startup = hdmi_codec_startup, .shutdown = hdmi_codec_shutdown, .hw_params = hdmi_codec_hw_params, diff --git a/sound/soc/codecs/jz4760.c b/sound/soc/codecs/jz4760.c index 6217e611259f..e04af1b9ace8 100644 --- a/sound/soc/codecs/jz4760.c +++ b/sound/soc/codecs/jz4760.c @@ -314,37 +314,13 @@ static const struct snd_kcontrol_new jz4760_codec_snd_controls[] = { }; static const struct snd_kcontrol_new jz4760_codec_pcm_playback_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Volume", - .info = snd_soc_info_volsw, - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ - | SNDRV_CTL_ELEM_ACCESS_READWRITE, - .tlv.p = dac_tlv, - .get = snd_soc_dapm_get_volsw, - .put = snd_soc_dapm_put_volsw, - .private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR6, - JZ4760_CODEC_REG_GCR5, - REG_GCR_GAIN_OFFSET, - REG_GCR_GAIN_MAX, 1), - }, + SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4760_CODEC_REG_GCR6, JZ4760_CODEC_REG_GCR5, + REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, dac_tlv), }; static const struct snd_kcontrol_new jz4760_codec_hp_playback_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Volume", - .info = snd_soc_info_volsw, - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ - | SNDRV_CTL_ELEM_ACCESS_READWRITE, - .tlv.p = out_tlv, - .get = snd_soc_dapm_get_volsw, - .put = snd_soc_dapm_put_volsw, - .private_value = SOC_DOUBLE_R_VALUE(JZ4760_CODEC_REG_GCR2, - JZ4760_CODEC_REG_GCR1, - REG_GCR_GAIN_OFFSET, - REG_GCR_GAIN_MAX, 1), - }, + SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4760_CODEC_REG_GCR2, JZ4760_CODEC_REG_GCR1, + REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, out_tlv), }; static int hpout_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/jz4770.c b/sound/soc/codecs/jz4770.c index acb9eaa7ea1c..312202ab5cea 100644 --- a/sound/soc/codecs/jz4770.c +++ b/sound/soc/codecs/jz4770.c @@ -331,43 +331,15 @@ static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = { }; static const struct snd_kcontrol_new jz4770_codec_pcm_playback_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Volume", - .info = snd_soc_info_volsw, - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ - | SNDRV_CTL_ELEM_ACCESS_READWRITE, - .tlv.p = dac_tlv, - .get = snd_soc_dapm_get_volsw, - .put = snd_soc_dapm_put_volsw, - /* - * NOTE: DACR/DACL are inversed; the gain value written to DACR - * seems to affect the left channel, and the gain value written - * to DACL seems to affect the right channel. - */ - .private_value = SOC_DOUBLE_R_VALUE(JZ4770_CODEC_REG_GCR_DACR, - JZ4770_CODEC_REG_GCR_DACL, - REG_GCR_GAIN_OFFSET, - REG_GCR_GAIN_MAX, 1), - }, + SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4770_CODEC_REG_GCR_DACR, + JZ4770_CODEC_REG_GCR_DACL, REG_GCR_GAIN_OFFSET, + REG_GCR_GAIN_MAX, 1, dac_tlv), }; static const struct snd_kcontrol_new jz4770_codec_hp_playback_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Volume", - .info = snd_soc_info_volsw, - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ - | SNDRV_CTL_ELEM_ACCESS_READWRITE, - .tlv.p = out_tlv, - .get = snd_soc_dapm_get_volsw, - .put = snd_soc_dapm_put_volsw, - /* HPR/HPL inversed for the same reason as above */ - .private_value = SOC_DOUBLE_R_VALUE(JZ4770_CODEC_REG_GCR_HPR, - JZ4770_CODEC_REG_GCR_HPL, - REG_GCR_GAIN_OFFSET, - REG_GCR_GAIN_MAX, 1), - }, + SOC_DAPM_DOUBLE_R_TLV("Volume", JZ4770_CODEC_REG_GCR_HPR, + JZ4770_CODEC_REG_GCR_HPL, REG_GCR_GAIN_OFFSET, + REG_GCR_GAIN_MAX, 1, out_tlv), }; static int hpout_event(struct snd_soc_dapm_widget *w, diff --git a/sound/soc/codecs/lochnagar-sc.c b/sound/soc/codecs/lochnagar-sc.c index 5e0bd0d24ed3..a3d6318c9050 100644 --- a/sound/soc/codecs/lochnagar-sc.c +++ b/sound/soc/codecs/lochnagar-sc.c @@ -129,12 +129,12 @@ static int lochnagar_sc_check_fmt(struct snd_soc_dai *dai, unsigned int fmt, static int lochnagar_sc_set_line_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBS_CFS); + return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBC_CFC); } static int lochnagar_sc_set_usb_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBM_CFM); + return lochnagar_sc_check_fmt(dai, fmt, SND_SOC_DAIFMT_CBP_CFP); } static const struct snd_soc_dai_ops lochnagar_sc_line_ops = { diff --git a/sound/soc/codecs/lpass-rx-macro.c b/sound/soc/codecs/lpass-rx-macro.c index febbbe073962..45a6b83808b2 100644 --- a/sound/soc/codecs/lpass-rx-macro.c +++ b/sound/soc/codecs/lpass-rx-macro.c @@ -3963,7 +3963,7 @@ static const struct of_device_id rx_macro_dt_match[] = { }; MODULE_DEVICE_TABLE(of, rx_macro_dt_match); -static int __maybe_unused rx_macro_runtime_suspend(struct device *dev) +static int rx_macro_runtime_suspend(struct device *dev) { struct rx_macro *rx = dev_get_drvdata(dev); @@ -3977,7 +3977,7 @@ static int __maybe_unused rx_macro_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused rx_macro_runtime_resume(struct device *dev) +static int rx_macro_runtime_resume(struct device *dev) { struct rx_macro *rx = dev_get_drvdata(dev); int ret; @@ -4012,7 +4012,7 @@ err_npl: } static const struct dev_pm_ops rx_macro_pm_ops = { - SET_RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL) + RUNTIME_PM_OPS(rx_macro_runtime_suspend, rx_macro_runtime_resume, NULL) }; static struct platform_driver rx_macro_driver = { @@ -4020,7 +4020,7 @@ static struct platform_driver rx_macro_driver = { .name = "rx_macro", .of_match_table = rx_macro_dt_match, .suppress_bind_attrs = true, - .pm = &rx_macro_pm_ops, + .pm = pm_ptr(&rx_macro_pm_ops), }, .probe = rx_macro_probe, .remove = rx_macro_remove, diff --git a/sound/soc/codecs/lpass-tx-macro.c b/sound/soc/codecs/lpass-tx-macro.c index a134584acf90..27bae58f4072 100644 --- a/sound/soc/codecs/lpass-tx-macro.c +++ b/sound/soc/codecs/lpass-tx-macro.c @@ -2400,7 +2400,7 @@ static void tx_macro_remove(struct platform_device *pdev) lpass_macro_pds_exit(tx->pds); } -static int __maybe_unused tx_macro_runtime_suspend(struct device *dev) +static int tx_macro_runtime_suspend(struct device *dev) { struct tx_macro *tx = dev_get_drvdata(dev); @@ -2414,7 +2414,7 @@ static int __maybe_unused tx_macro_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tx_macro_runtime_resume(struct device *dev) +static int tx_macro_runtime_resume(struct device *dev) { struct tx_macro *tx = dev_get_drvdata(dev); int ret; @@ -2450,7 +2450,7 @@ err_npl: } static const struct dev_pm_ops tx_macro_pm_ops = { - SET_RUNTIME_PM_OPS(tx_macro_runtime_suspend, tx_macro_runtime_resume, NULL) + RUNTIME_PM_OPS(tx_macro_runtime_suspend, tx_macro_runtime_resume, NULL) }; static const struct tx_macro_data lpass_ver_9 = { @@ -2531,7 +2531,7 @@ static struct platform_driver tx_macro_driver = { .name = "tx_macro", .of_match_table = tx_macro_dt_match, .suppress_bind_attrs = true, - .pm = &tx_macro_pm_ops, + .pm = pm_ptr(&tx_macro_pm_ops), }, .probe = tx_macro_probe, .remove = tx_macro_remove, diff --git a/sound/soc/codecs/lpass-va-macro.c b/sound/soc/codecs/lpass-va-macro.c index c781da476240..74ada6e77526 100644 --- a/sound/soc/codecs/lpass-va-macro.c +++ b/sound/soc/codecs/lpass-va-macro.c @@ -1674,7 +1674,7 @@ static void va_macro_remove(struct platform_device *pdev) lpass_macro_pds_exit(va->pds); } -static int __maybe_unused va_macro_runtime_suspend(struct device *dev) +static int va_macro_runtime_suspend(struct device *dev) { struct va_macro *va = dev_get_drvdata(dev); @@ -1689,7 +1689,7 @@ static int __maybe_unused va_macro_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused va_macro_runtime_resume(struct device *dev) +static int va_macro_runtime_resume(struct device *dev) { struct va_macro *va = dev_get_drvdata(dev); int ret; @@ -1717,7 +1717,7 @@ static int __maybe_unused va_macro_runtime_resume(struct device *dev) static const struct dev_pm_ops va_macro_pm_ops = { - SET_RUNTIME_PM_OPS(va_macro_runtime_suspend, va_macro_runtime_resume, NULL) + RUNTIME_PM_OPS(va_macro_runtime_suspend, va_macro_runtime_resume, NULL) }; static const struct of_device_id va_macro_dt_match[] = { @@ -1735,7 +1735,7 @@ static struct platform_driver va_macro_driver = { .name = "va_macro", .of_match_table = va_macro_dt_match, .suppress_bind_attrs = true, - .pm = &va_macro_pm_ops, + .pm = pm_ptr(&va_macro_pm_ops), }, .probe = va_macro_probe, .remove = va_macro_remove, diff --git a/sound/soc/codecs/lpass-wsa-macro.c b/sound/soc/codecs/lpass-wsa-macro.c index c989d82d1d3c..b261fa373e65 100644 --- a/sound/soc/codecs/lpass-wsa-macro.c +++ b/sound/soc/codecs/lpass-wsa-macro.c @@ -2900,7 +2900,7 @@ static void wsa_macro_remove(struct platform_device *pdev) clk_disable_unprepare(wsa->fsgen); } -static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev) +static int wsa_macro_runtime_suspend(struct device *dev) { struct wsa_macro *wsa = dev_get_drvdata(dev); @@ -2914,7 +2914,7 @@ static int __maybe_unused wsa_macro_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wsa_macro_runtime_resume(struct device *dev) +static int wsa_macro_runtime_resume(struct device *dev) { struct wsa_macro *wsa = dev_get_drvdata(dev); int ret; @@ -2950,7 +2950,7 @@ err_npl: } static const struct dev_pm_ops wsa_macro_pm_ops = { - SET_RUNTIME_PM_OPS(wsa_macro_runtime_suspend, wsa_macro_runtime_resume, NULL) + RUNTIME_PM_OPS(wsa_macro_runtime_suspend, wsa_macro_runtime_resume, NULL) }; static const struct of_device_id wsa_macro_dt_match[] = { @@ -2977,7 +2977,7 @@ static struct platform_driver wsa_macro_driver = { .driver = { .name = "wsa_macro", .of_match_table = wsa_macro_dt_match, - .pm = &wsa_macro_pm_ops, + .pm = pm_ptr(&wsa_macro_pm_ops), }, .probe = wsa_macro_probe, .remove = wsa_macro_remove, diff --git a/sound/soc/codecs/madera.c b/sound/soc/codecs/madera.c index af109761f359..bc3470cf2c54 100644 --- a/sound/soc/codecs/madera.c +++ b/sound/soc/codecs/madera.c @@ -2776,7 +2776,7 @@ static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; case SND_SOC_DAIFMT_DSP_B: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != - SND_SOC_DAIFMT_CBM_CFM) { + SND_SOC_DAIFMT_CBP_CFP) { madera_aif_err(dai, "DSP_B not valid in slave mode\n"); return -EINVAL; } @@ -2787,7 +2787,7 @@ static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) break; case SND_SOC_DAIFMT_LEFT_J: if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != - SND_SOC_DAIFMT_CBM_CFM) { + SND_SOC_DAIFMT_CBP_CFP) { madera_aif_err(dai, "LEFT_J not valid in slave mode\n"); return -EINVAL; } @@ -2800,15 +2800,15 @@ static int madera_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: lrclk |= MADERA_AIF1TX_LRCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: bclk |= MADERA_AIF1_BCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: bclk |= MADERA_AIF1_BCLK_MSTR; lrclk |= MADERA_AIF1TX_LRCLK_MSTR; break; diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 790e2ae6dc18..22177c1ce160 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2604,7 +2604,6 @@ static void max98090_i2c_remove(struct i2c_client *client) max98090_i2c_shutdown(client); } -#ifdef CONFIG_PM static int max98090_runtime_resume(struct device *dev) { struct max98090_priv *max98090 = dev_get_drvdata(dev); @@ -2626,9 +2625,7 @@ static int max98090_runtime_suspend(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int max98090_resume(struct device *dev) { struct max98090_priv *max98090 = dev_get_drvdata(dev); @@ -2645,12 +2642,10 @@ static int max98090_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops max98090_pm = { - SET_RUNTIME_PM_OPS(max98090_runtime_suspend, - max98090_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume) + RUNTIME_PM_OPS(max98090_runtime_suspend, max98090_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(NULL, max98090_resume) }; #ifdef CONFIG_OF @@ -2673,7 +2668,7 @@ MODULE_DEVICE_TABLE(acpi, max98090_acpi_match); static struct i2c_driver max98090_i2c_driver = { .driver = { .name = "max98090", - .pm = &max98090_pm, + .pm = pm_ptr(&max98090_pm), .of_match_table = of_match_ptr(max98090_of_match), .acpi_match_table = ACPI_PTR(max98090_acpi_match), }, diff --git a/sound/soc/codecs/max98373-i2c.c b/sound/soc/codecs/max98373-i2c.c index 1f7ff3dbcbbe..56c4ba1f3782 100644 --- a/sound/soc/codecs/max98373-i2c.c +++ b/sound/soc/codecs/max98373-i2c.c @@ -472,7 +472,6 @@ static struct snd_soc_dai_driver max98373_dai[] = { } }; -#ifdef CONFIG_PM_SLEEP static int max98373_suspend(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); @@ -496,10 +495,9 @@ static int max98373_resume(struct device *dev) regcache_sync(max98373->regmap); return 0; } -#endif static const struct dev_pm_ops max98373_pm = { - SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume) + SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume) }; static const struct regmap_config max98373_regmap = { @@ -605,7 +603,7 @@ static struct i2c_driver max98373_i2c_driver = { .name = "max98373", .of_match_table = of_match_ptr(max98373_of_match), .acpi_match_table = ACPI_PTR(max98373_acpi_match), - .pm = &max98373_pm, + .pm = pm_ptr(&max98373_pm), }, .probe = max98373_i2c_probe, .id_table = max98373_i2c_id, diff --git a/sound/soc/codecs/max98373-sdw.c b/sound/soc/codecs/max98373-sdw.c index 26860882fd91..6088278e6503 100644 --- a/sound/soc/codecs/max98373-sdw.c +++ b/sound/soc/codecs/max98373-sdw.c @@ -246,7 +246,7 @@ static const struct regmap_config max98373_sdw_regmap = { }; /* Power management functions and structure */ -static __maybe_unused int max98373_suspend(struct device *dev) +static int max98373_suspend(struct device *dev) { struct max98373_priv *max98373 = dev_get_drvdata(dev); int i; @@ -262,7 +262,7 @@ static __maybe_unused int max98373_suspend(struct device *dev) #define MAX98373_PROBE_TIMEOUT 5000 -static __maybe_unused int max98373_resume(struct device *dev) +static int max98373_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct max98373_priv *max98373 = dev_get_drvdata(dev); @@ -292,8 +292,8 @@ regmap_sync: } static const struct dev_pm_ops max98373_pm = { - SET_SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume) - SET_RUNTIME_PM_OPS(max98373_suspend, max98373_resume, NULL) + SYSTEM_SLEEP_PM_OPS(max98373_suspend, max98373_resume) + RUNTIME_PM_OPS(max98373_suspend, max98373_resume, NULL) }; static int max98373_read_prop(struct sdw_slave *slave) @@ -874,7 +874,7 @@ static struct sdw_driver max98373_sdw_driver = { .name = "max98373", .of_match_table = of_match_ptr(max98373_of_match), .acpi_match_table = ACPI_PTR(max98373_acpi_match), - .pm = &max98373_pm, + .pm = pm_ptr(&max98373_pm), }, .probe = max98373_sdw_probe, .remove = max98373_sdw_remove, diff --git a/sound/soc/codecs/max98390.c b/sound/soc/codecs/max98390.c index 1bae253618fd..76296176f948 100644 --- a/sound/soc/codecs/max98390.c +++ b/sound/soc/codecs/max98390.c @@ -943,7 +943,6 @@ static int max98390_probe(struct snd_soc_component *component) return 0; } -#ifdef CONFIG_PM_SLEEP static int max98390_suspend(struct device *dev) { struct max98390_priv *max98390 = dev_get_drvdata(dev); @@ -967,10 +966,9 @@ static int max98390_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops max98390_pm = { - SET_SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume) + SYSTEM_SLEEP_PM_OPS(max98390_suspend, max98390_resume) }; static const struct snd_soc_component_driver soc_codec_dev_max98390 = { @@ -1130,7 +1128,7 @@ static struct i2c_driver max98390_i2c_driver = { .name = "max98390", .of_match_table = of_match_ptr(max98390_of_match), .acpi_match_table = ACPI_PTR(max98390_acpi_match), - .pm = &max98390_pm, + .pm = pm_ptr(&max98390_pm), }, .probe = max98390_i2c_probe, .id_table = max98390_i2c_id, diff --git a/sound/soc/codecs/max98396.c b/sound/soc/codecs/max98396.c index e52bb2266fa1..c1888cd83dbc 100644 --- a/sound/soc/codecs/max98396.c +++ b/sound/soc/codecs/max98396.c @@ -1571,7 +1571,6 @@ static int max98396_probe(struct snd_soc_component *component) return 0; } -#ifdef CONFIG_PM_SLEEP static int max98396_suspend(struct device *dev) { struct max98396_priv *max98396 = dev_get_drvdata(dev); @@ -1616,10 +1615,9 @@ static int max98396_resume(struct device *dev) regcache_sync(max98396->regmap); return 0; } -#endif static const struct dev_pm_ops max98396_pm = { - SET_SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume) + SYSTEM_SLEEP_PM_OPS(max98396_suspend, max98396_resume) }; static const struct snd_soc_component_driver soc_codec_dev_max98396 = { @@ -1904,7 +1902,7 @@ static struct i2c_driver max98396_i2c_driver = { .name = "max98396", .of_match_table = of_match_ptr(max98396_of_match), .acpi_match_table = ACPI_PTR(max98396_acpi_match), - .pm = &max98396_pm, + .pm = pm_ptr(&max98396_pm), }, .probe = max98396_i2c_probe, .id_table = max98396_i2c_id, diff --git a/sound/soc/codecs/max98520.c b/sound/soc/codecs/max98520.c index 479ded22672e..adf5a898c6df 100644 --- a/sound/soc/codecs/max98520.c +++ b/sound/soc/codecs/max98520.c @@ -621,7 +621,7 @@ static int max98520_probe(struct snd_soc_component *component) return 0; } -static int __maybe_unused max98520_suspend(struct device *dev) +static int max98520_suspend(struct device *dev) { struct max98520_priv *max98520 = dev_get_drvdata(dev); @@ -630,7 +630,7 @@ static int __maybe_unused max98520_suspend(struct device *dev) return 0; } -static int __maybe_unused max98520_resume(struct device *dev) +static int max98520_resume(struct device *dev) { struct max98520_priv *max98520 = dev_get_drvdata(dev); @@ -641,7 +641,7 @@ static int __maybe_unused max98520_resume(struct device *dev) } static const struct dev_pm_ops max98520_pm = { - SET_SYSTEM_SLEEP_PM_OPS(max98520_suspend, max98520_resume) + SYSTEM_SLEEP_PM_OPS(max98520_suspend, max98520_resume) }; static const struct snd_soc_component_driver soc_codec_dev_max98520 = { @@ -752,7 +752,7 @@ static struct i2c_driver max98520_i2c_driver = { .driver = { .name = "max98520", .of_match_table = of_match_ptr(max98520_of_match), - .pm = &max98520_pm, + .pm = pm_ptr(&max98520_pm), }, .probe = max98520_i2c_probe, .id_table = max98520_i2c_id, diff --git a/sound/soc/codecs/max9860.c b/sound/soc/codecs/max9860.c index 4015ed2c47ec..716d16daf7d7 100644 --- a/sound/soc/codecs/max9860.c +++ b/sound/soc/codecs/max9860.c @@ -539,7 +539,6 @@ static const struct snd_soc_component_driver max9860_component_driver = { .endianness = 1, }; -#ifdef CONFIG_PM static int max9860_suspend(struct device *dev) { struct max9860_priv *max9860 = dev_get_drvdata(dev); @@ -584,10 +583,9 @@ static int max9860_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops max9860_pm_ops = { - SET_RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL) + RUNTIME_PM_OPS(max9860_suspend, max9860_resume, NULL) }; static int max9860_probe(struct i2c_client *i2c) @@ -729,7 +727,7 @@ static struct i2c_driver max9860_i2c_driver = { .driver = { .name = "max9860", .of_match_table = max9860_of_match, - .pm = &max9860_pm_ops, + .pm = pm_ptr(&max9860_pm_ops), }, }; diff --git a/sound/soc/codecs/max98927.c b/sound/soc/codecs/max98927.c index 747aa6f1d54f..55cc18451a2d 100644 --- a/sound/soc/codecs/max98927.c +++ b/sound/soc/codecs/max98927.c @@ -731,7 +731,6 @@ static int max98927_probe(struct snd_soc_component *component) return 0; } -#ifdef CONFIG_PM_SLEEP static int max98927_suspend(struct device *dev) { struct max98927_priv *max98927 = dev_get_drvdata(dev); @@ -750,10 +749,9 @@ static int max98927_resume(struct device *dev) regcache_sync(max98927->regmap); return 0; } -#endif static const struct dev_pm_ops max98927_pm = { - SET_SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume) + SYSTEM_SLEEP_PM_OPS(max98927_suspend, max98927_resume) }; static const struct snd_soc_component_driver soc_component_dev_max98927 = { @@ -902,7 +900,7 @@ static struct i2c_driver max98927_i2c_driver = { .name = "max98927", .of_match_table = of_match_ptr(max98927_of_match), .acpi_match_table = ACPI_PTR(max98927_acpi_match), - .pm = &max98927_pm, + .pm = pm_ptr(&max98927_pm), }, .probe = max98927_i2c_probe, .remove = max98927_i2c_remove, diff --git a/sound/soc/codecs/mt6358.c b/sound/soc/codecs/mt6358.c index 9247b90d1b99..e033027fd4c7 100644 --- a/sound/soc/codecs/mt6358.c +++ b/sound/soc/codecs/mt6358.c @@ -162,47 +162,6 @@ static void capture_gpio_reset(struct mt6358_priv *priv) 0xf << 12, 0x0); } -/* use only when not govern by DAPM */ -static int mt6358_set_dcxo(struct mt6358_priv *priv, bool enable) -{ - regmap_update_bits(priv->regmap, MT6358_DCXO_CW14, - 0x1 << RG_XO_AUDIO_EN_M_SFT, - (enable ? 1 : 0) << RG_XO_AUDIO_EN_M_SFT); - return 0; -} - -/* use only when not govern by DAPM */ -static int mt6358_set_clksq(struct mt6358_priv *priv, bool enable) -{ - /* audio clk source from internal dcxo */ - regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, - RG_CLKSQ_IN_SEL_TEST_MASK_SFT, - 0x0); - - /* Enable/disable CLKSQ 26MHz */ - regmap_update_bits(priv->regmap, MT6358_AUDENC_ANA_CON6, - RG_CLKSQ_EN_MASK_SFT, - (enable ? 1 : 0) << RG_CLKSQ_EN_SFT); - return 0; -} - -/* use only when not govern by DAPM */ -static int mt6358_set_aud_global_bias(struct mt6358_priv *priv, bool enable) -{ - regmap_update_bits(priv->regmap, MT6358_AUDDEC_ANA_CON13, - RG_AUDGLB_PWRDN_VA28_MASK_SFT, - (enable ? 0 : 1) << RG_AUDGLB_PWRDN_VA28_SFT); - return 0; -} - -/* use only when not govern by DAPM */ -static int mt6358_set_topck(struct mt6358_priv *priv, bool enable) -{ - regmap_update_bits(priv->regmap, MT6358_AUD_TOP_CKPDN_CON0, - 0x0066, enable ? 0x0 : 0x66); - return 0; -} - static int mt6358_mtkaif_tx_enable(struct mt6358_priv *priv) { switch (priv->mtkaif_protocol) { @@ -252,69 +211,6 @@ static int mt6358_mtkaif_tx_disable(struct mt6358_priv *priv) return 0; } -int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt) -{ - struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); - - playback_gpio_set(priv); - capture_gpio_set(priv); - mt6358_mtkaif_tx_enable(priv); - - mt6358_set_dcxo(priv, true); - mt6358_set_aud_global_bias(priv, true); - mt6358_set_clksq(priv, true); - mt6358_set_topck(priv, true); - - /* set dat_miso_loopback on */ - regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, - RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, - 1 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); - regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, - RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, - 1 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); - return 0; -} -EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_enable); - -int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt) -{ - struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); - - /* set dat_miso_loopback off */ - regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, - RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_MASK_SFT, - 0 << RG_AUD_PAD_TOP_DAT_MISO2_LOOPBACK_SFT); - regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, - RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_MASK_SFT, - 0 << RG_AUD_PAD_TOP_DAT_MISO_LOOPBACK_SFT); - - mt6358_set_topck(priv, false); - mt6358_set_clksq(priv, false); - mt6358_set_aud_global_bias(priv, false); - mt6358_set_dcxo(priv, false); - - mt6358_mtkaif_tx_disable(priv); - playback_gpio_reset(priv); - capture_gpio_reset(priv); - return 0; -} -EXPORT_SYMBOL_GPL(mt6358_mtkaif_calibration_disable); - -int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, - int phase_1, int phase_2) -{ - struct mt6358_priv *priv = snd_soc_component_get_drvdata(cmpnt); - - regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, - RG_AUD_PAD_TOP_PHASE_MODE_MASK_SFT, - phase_1 << RG_AUD_PAD_TOP_PHASE_MODE_SFT); - regmap_update_bits(priv->regmap, MT6358_AUDIO_DIG_CFG, - RG_AUD_PAD_TOP_PHASE_MODE2_MASK_SFT, - phase_2 << RG_AUD_PAD_TOP_PHASE_MODE2_SFT); - return 0; -} -EXPORT_SYMBOL_GPL(mt6358_set_mtkaif_calibration_phase); - /* dl pga gain */ enum { DL_GAIN_8DB = 0, diff --git a/sound/soc/codecs/mt6358.h b/sound/soc/codecs/mt6358.h index a5953315eaa2..b729c3899b7e 100644 --- a/sound/soc/codecs/mt6358.h +++ b/sound/soc/codecs/mt6358.h @@ -2307,8 +2307,4 @@ enum { /* set only during init */ int mt6358_set_mtkaif_protocol(struct snd_soc_component *cmpnt, int mtkaif_protocol); -int mt6358_mtkaif_calibration_enable(struct snd_soc_component *cmpnt); -int mt6358_mtkaif_calibration_disable(struct snd_soc_component *cmpnt); -int mt6358_set_mtkaif_calibration_phase(struct snd_soc_component *cmpnt, - int phase_1, int phase_2); #endif /* __MT6358_H__ */ diff --git a/sound/soc/codecs/mt6359-accdet.h b/sound/soc/codecs/mt6359-accdet.h index c234f2f4276a..78ada3a5bfae 100644 --- a/sound/soc/codecs/mt6359-accdet.h +++ b/sound/soc/codecs/mt6359-accdet.h @@ -123,6 +123,15 @@ struct mt6359_accdet { struct workqueue_struct *jd_workqueue; }; +#if IS_ENABLED(CONFIG_SND_SOC_MT6359_ACCDET) int mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, struct snd_soc_jack *jack); +#else +static inline int +mt6359_accdet_enable_jack_detect(struct snd_soc_component *component, + struct snd_soc_jack *jack) +{ + return -EOPNOTSUPP; +} +#endif #endif diff --git a/sound/soc/codecs/mt6359.c b/sound/soc/codecs/mt6359.c index 0b76a55664b0..f73120c6a6ce 100644 --- a/sound/soc/codecs/mt6359.c +++ b/sound/soc/codecs/mt6359.c @@ -2867,9 +2867,12 @@ static int mt6359_parse_dt(struct mt6359_priv *priv) struct device *dev = priv->dev; struct device_node *np; - np = of_get_child_by_name(dev->parent->of_node, "mt6359codec"); - if (!np) - return -EINVAL; + np = of_get_child_by_name(dev->parent->of_node, "audio-codec"); + if (!np) { + np = of_get_child_by_name(dev->parent->of_node, "mt6359codec"); + if (!np) + return -EINVAL; + } ret = of_property_read_u32(np, "mediatek,dmic-mode", &priv->dmic_one_wire_mode); diff --git a/sound/soc/codecs/mt6660.c b/sound/soc/codecs/mt6660.c index 39a57f643d81..d16bccebae52 100644 --- a/sound/soc/codecs/mt6660.c +++ b/sound/soc/codecs/mt6660.c @@ -529,7 +529,7 @@ static void mt6660_i2c_remove(struct i2c_client *client) mutex_destroy(&chip->io_lock); } -static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev) +static int mt6660_i2c_runtime_suspend(struct device *dev) { struct mt6660_chip *chip = dev_get_drvdata(dev); @@ -538,7 +538,7 @@ static int __maybe_unused mt6660_i2c_runtime_suspend(struct device *dev) MT6660_REG_SYSTEM_CTRL, 0x01, 0x01); } -static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev) +static int mt6660_i2c_runtime_resume(struct device *dev) { struct mt6660_chip *chip = dev_get_drvdata(dev); @@ -548,8 +548,7 @@ static int __maybe_unused mt6660_i2c_runtime_resume(struct device *dev) } static const struct dev_pm_ops mt6660_dev_pm_ops = { - SET_RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend, - mt6660_i2c_runtime_resume, NULL) + RUNTIME_PM_OPS(mt6660_i2c_runtime_suspend, mt6660_i2c_runtime_resume, NULL) }; static const struct of_device_id __maybe_unused mt6660_of_id[] = { @@ -568,7 +567,7 @@ static struct i2c_driver mt6660_i2c_driver = { .driver = { .name = "mt6660", .of_match_table = of_match_ptr(mt6660_of_id), - .pm = &mt6660_dev_pm_ops, + .pm = pm_ptr(&mt6660_dev_pm_ops), }, .probe = mt6660_i2c_probe, .remove = mt6660_i2c_remove, diff --git a/sound/soc/codecs/nau8540.c b/sound/soc/codecs/nau8540.c index 7e59448e7ac6..caf2edb23088 100644 --- a/sound/soc/codecs/nau8540.c +++ b/sound/soc/codecs/nau8540.c @@ -482,10 +482,10 @@ static int nau8540_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int ctrl1_val = 0, ctrl2_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl2_val |= NAU8540_I2S_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/nau8810.c b/sound/soc/codecs/nau8810.c index dc3aaca89919..6f432b992941 100644 --- a/sound/soc/codecs/nau8810.c +++ b/sound/soc/codecs/nau8810.c @@ -613,10 +613,10 @@ static int nau8810_set_dai_fmt(struct snd_soc_dai *codec_dai, u16 ctrl1_val = 0, ctrl2_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl2_val |= NAU8810_CLKIO_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/nau8822.c b/sound/soc/codecs/nau8822.c index fd4a96a12060..15d6f8d01f78 100644 --- a/sound/soc/codecs/nau8822.c +++ b/sound/soc/codecs/nau8822.c @@ -806,10 +806,10 @@ static int nau8822_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) dev_dbg(component->dev, "%s\n", __func__); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl2_val |= 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: ctrl2_val &= ~1; break; default: diff --git a/sound/soc/codecs/nau8824.c b/sound/soc/codecs/nau8824.c index 5aaf8c496300..542bd22e6180 100644 --- a/sound/soc/codecs/nau8824.c +++ b/sound/soc/codecs/nau8824.c @@ -1159,10 +1159,10 @@ static int nau8824_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int ctrl1_val = 0, ctrl2_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl2_val |= NAU8824_I2S_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/nau8825.c b/sound/soc/codecs/nau8825.c index bde25bc6909d..25b8b19e27ec 100644 --- a/sound/soc/codecs/nau8825.c +++ b/sound/soc/codecs/nau8825.c @@ -1356,10 +1356,10 @@ static int nau8825_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) unsigned int ctrl1_val = 0, ctrl2_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl2_val |= NAU8825_I2S_MS_MASTER; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/ntp8918.c b/sound/soc/codecs/ntp8918.c index a332893fc51d..5593d48ef696 100644 --- a/sound/soc/codecs/ntp8918.c +++ b/sound/soc/codecs/ntp8918.c @@ -8,7 +8,6 @@ */ #include <linux/kernel.h> -#include <linux/clk.h> #include <linux/reset.h> #include <linux/i2c.h> #include <linux/regmap.h> diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index fc152496d5dc..a1ec881d7084 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -9,7 +9,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/delay.h> -#include <linux/gpio.h> #include <linux/i2c.h> #include <linux/regmap.h> #include <linux/of.h> diff --git a/sound/soc/codecs/pcm3008.c b/sound/soc/codecs/pcm3008.c index 09c6c1326833..d3d2e7f40170 100644 --- a/sound/soc/codecs/pcm3008.c +++ b/sound/soc/codecs/pcm3008.c @@ -14,7 +14,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/device.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/slab.h> #include <linux/module.h> #include <sound/core.h> @@ -22,17 +22,22 @@ #include <sound/initval.h> #include <sound/soc.h> -#include "pcm3008.h" +struct pcm3008 { + struct gpio_desc *dem0_pin; + struct gpio_desc *dem1_pin; + struct gpio_desc *pdad_pin; + struct gpio_desc *pdda_pin; +}; static int pcm3008_dac_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct pcm3008_setup_data *setup = component->dev->platform_data; + struct pcm3008 *pcm = component->dev->platform_data; - gpio_set_value_cansleep(setup->pdda_pin, - SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value_cansleep(pcm->pdda_pin, + SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -42,10 +47,10 @@ static int pcm3008_adc_ev(struct snd_soc_dapm_widget *w, int event) { struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct pcm3008_setup_data *setup = component->dev->platform_data; + struct pcm3008 *pcm = component->dev->platform_data; - gpio_set_value_cansleep(setup->pdad_pin, - SND_SOC_DAPM_EVENT_ON(event)); + gpiod_set_value_cansleep(pcm->pdad_pin, + SND_SOC_DAPM_EVENT_ON(event)); return 0; } @@ -106,11 +111,13 @@ static const struct snd_soc_component_driver soc_component_dev_pcm3008 = { static int pcm3008_codec_probe(struct platform_device *pdev) { - struct pcm3008_setup_data *setup = pdev->dev.platform_data; - int ret; + struct device *dev = &pdev->dev; + struct pcm3008 *pcm; - if (!setup) - return -EINVAL; + pcm = devm_kzalloc(dev, sizeof(*pcm), GFP_KERNEL); + if (!pcm) + return -ENOMEM; + platform_set_drvdata(pdev, pcm); /* DEM1 DEM0 DE-EMPHASIS_MODE * Low Low De-emphasis 44.1 kHz ON @@ -120,30 +127,26 @@ static int pcm3008_codec_probe(struct platform_device *pdev) */ /* Configure DEM0 GPIO (turning OFF DAC De-emphasis). */ - ret = devm_gpio_request_one(&pdev->dev, setup->dem0_pin, - GPIOF_OUT_INIT_HIGH, "codec_dem0"); - if (ret != 0) - return ret; + pcm->dem0_pin = devm_gpiod_get(dev, "dem0", GPIOD_OUT_HIGH); + if (IS_ERR(pcm->dem0_pin)) + return PTR_ERR(pcm->dem0_pin); /* Configure DEM1 GPIO (turning OFF DAC De-emphasis). */ - ret = devm_gpio_request_one(&pdev->dev, setup->dem1_pin, - GPIOF_OUT_INIT_LOW, "codec_dem1"); - if (ret != 0) - return ret; + pcm->dem1_pin = devm_gpiod_get(dev, "dem1", GPIOD_OUT_LOW); + if (IS_ERR(pcm->dem1_pin)) + return PTR_ERR(pcm->dem1_pin); /* Configure PDAD GPIO. */ - ret = devm_gpio_request_one(&pdev->dev, setup->pdad_pin, - GPIOF_OUT_INIT_LOW, "codec_pdad"); - if (ret != 0) - return ret; + pcm->pdad_pin = devm_gpiod_get(dev, "pdad", GPIOD_OUT_LOW); + if (IS_ERR(pcm->pdad_pin)) + return PTR_ERR(pcm->pdad_pin); /* Configure PDDA GPIO. */ - ret = devm_gpio_request_one(&pdev->dev, setup->pdda_pin, - GPIOF_OUT_INIT_LOW, "codec_pdda"); - if (ret != 0) - return ret; + pcm->pdda_pin = devm_gpiod_get(dev, "pdda", GPIOD_OUT_LOW); + if (IS_ERR(pcm->pdda_pin)) + return PTR_ERR(pcm->pdda_pin); - return devm_snd_soc_register_component(&pdev->dev, + return devm_snd_soc_register_component(dev, &soc_component_dev_pcm3008, &pcm3008_dai, 1); } diff --git a/sound/soc/codecs/pcm3008.h b/sound/soc/codecs/pcm3008.h deleted file mode 100644 index f7f4fbbd89db..000000000000 --- a/sound/soc/codecs/pcm3008.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * PCM3008 ALSA SoC Layer - * - * Author: Hugo Villeneuve - * Copyright (C) 2008 Lyrtech inc - */ - -#ifndef __LINUX_SND_SOC_PCM3008_H -#define __LINUX_SND_SOC_PCM3008_H - -struct pcm3008_setup_data { - unsigned dem0_pin; - unsigned dem1_pin; - unsigned pdad_pin; - unsigned pdda_pin; -}; - -#endif diff --git a/sound/soc/codecs/pcm3168a-i2c.c b/sound/soc/codecs/pcm3168a-i2c.c index 7052cc0c97d1..ff18c74b616c 100644 --- a/sound/soc/codecs/pcm3168a-i2c.c +++ b/sound/soc/codecs/pcm3168a-i2c.c @@ -10,6 +10,7 @@ #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <sound/soc.h> @@ -37,6 +38,13 @@ static const struct i2c_device_id pcm3168a_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, pcm3168a_i2c_id); +static const struct acpi_device_id pcm3168a_acpi_match[] = { + { "PCM3168A" }, + { "104C3168" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, pcm3168a_acpi_match); + static const struct of_device_id pcm3168a_of_match[] = { { .compatible = "ti,pcm3168a", }, { } @@ -49,8 +57,9 @@ static struct i2c_driver pcm3168a_i2c_driver = { .id_table = pcm3168a_i2c_id, .driver = { .name = "pcm3168a", + .acpi_match_table = pcm3168a_acpi_match, .of_match_table = pcm3168a_of_match, - .pm = &pcm3168a_pm_ops, + .pm = pm_ptr(&pcm3168a_pm_ops), }, }; module_i2c_driver(pcm3168a_i2c_driver); diff --git a/sound/soc/codecs/pcm3168a-spi.c b/sound/soc/codecs/pcm3168a-spi.c index b5b08046f545..0871338eacba 100644 --- a/sound/soc/codecs/pcm3168a-spi.c +++ b/sound/soc/codecs/pcm3168a-spi.c @@ -50,7 +50,7 @@ static struct spi_driver pcm3168a_spi_driver = { .driver = { .name = "pcm3168a", .of_match_table = pcm3168a_of_match, - .pm = &pcm3168a_pm_ops, + .pm = pm_ptr(&pcm3168a_pm_ops), }, }; module_spi_driver(pcm3168a_spi_driver); diff --git a/sound/soc/codecs/pcm3168a.c b/sound/soc/codecs/pcm3168a.c index fac0617ab95b..c8617a488b11 100644 --- a/sound/soc/codecs/pcm3168a.c +++ b/sound/soc/codecs/pcm3168a.c @@ -493,9 +493,9 @@ static int pcm3168a_hw_params(struct snd_pcm_substream *substream, } break; case 24: - if (provider_mode || (format == SND_SOC_DAIFMT_DSP_A) || - (format == SND_SOC_DAIFMT_DSP_B)) { - dev_err(component->dev, "24-bit slots not supported in provider mode, or consumer mode using DSP\n"); + if (!provider_mode && ((format == SND_SOC_DAIFMT_DSP_A) || + (format == SND_SOC_DAIFMT_DSP_B))) { + dev_err(component->dev, "24-bit slots not supported in consumer mode using DSP\n"); return -EINVAL; } break; @@ -743,7 +743,7 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) return dev_err_probe(dev, PTR_ERR(pcm3168a->gpio_rst), "failed to acquire RST gpio\n"); - pcm3168a->scki = devm_clk_get(dev, "scki"); + pcm3168a->scki = devm_clk_get_optional(dev, "scki"); if (IS_ERR(pcm3168a->scki)) return dev_err_probe(dev, PTR_ERR(pcm3168a->scki), "failed to acquire clock 'scki'\n"); @@ -755,6 +755,9 @@ int pcm3168a_probe(struct device *dev, struct regmap *regmap) } pcm3168a->sysclk = clk_get_rate(pcm3168a->scki); + /* Fallback to the default if no clk entry available. */ + if (!pcm3168a->sysclk) + pcm3168a->sysclk = 24576000; for (i = 0; i < ARRAY_SIZE(pcm3168a->supplies); i++) pcm3168a->supplies[i].supply = pcm3168a_supply_names[i]; @@ -846,7 +849,6 @@ void pcm3168a_remove(struct device *dev) } EXPORT_SYMBOL_GPL(pcm3168a_remove); -#ifdef CONFIG_PM static int pcm3168a_rt_resume(struct device *dev) { struct pcm3168a_priv *pcm3168a = dev_get_drvdata(dev); @@ -902,12 +904,10 @@ static int pcm3168a_rt_suspend(struct device *dev) return 0; } -#endif -const struct dev_pm_ops pcm3168a_pm_ops = { - SET_RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL) +EXPORT_GPL_DEV_PM_OPS(pcm3168a_pm_ops) = { + RUNTIME_PM_OPS(pcm3168a_rt_suspend, pcm3168a_rt_resume, NULL) }; -EXPORT_SYMBOL_GPL(pcm3168a_pm_ops); MODULE_DESCRIPTION("PCM3168A codec driver"); MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index 92bcf5179779..a1d849b0c50f 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -79,7 +79,7 @@ static struct i2c_driver pcm512x_i2c_driver = { .name = "pcm512x", .of_match_table = of_match_ptr(pcm512x_of_match), .acpi_match_table = ACPI_PTR(pcm512x_acpi_match), - .pm = &pcm512x_pm_ops, + .pm = pm_ptr(&pcm512x_pm_ops), }, }; diff --git a/sound/soc/codecs/pcm512x-spi.c b/sound/soc/codecs/pcm512x-spi.c index 6629b862f47d..92f7f78a4e20 100644 --- a/sound/soc/codecs/pcm512x-spi.c +++ b/sound/soc/codecs/pcm512x-spi.c @@ -58,7 +58,7 @@ static struct spi_driver pcm512x_spi_driver = { .driver = { .name = "pcm512x", .of_match_table = pcm512x_of_match, - .pm = &pcm512x_pm_ops, + .pm = pm_ptr(&pcm512x_pm_ops), }, }; diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index aa8edf87b743..007dfc0fa224 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1725,7 +1725,6 @@ void pcm512x_remove(struct device *dev) } EXPORT_SYMBOL_GPL(pcm512x_remove); -#ifdef CONFIG_PM static int pcm512x_suspend(struct device *dev) { struct pcm512x_priv *pcm512x = dev_get_drvdata(dev); @@ -1787,12 +1786,10 @@ static int pcm512x_resume(struct device *dev) return 0; } -#endif -const struct dev_pm_ops pcm512x_pm_ops = { - SET_RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) +EXPORT_GPL_DEV_PM_OPS(pcm512x_pm_ops) = { + RUNTIME_PM_OPS(pcm512x_suspend, pcm512x_resume, NULL) }; -EXPORT_SYMBOL_GPL(pcm512x_pm_ops); MODULE_DESCRIPTION("ASoC PCM512x codec driver"); MODULE_AUTHOR("Mark Brown <broonie@kernel.org>"); diff --git a/sound/soc/codecs/pcm6240.c b/sound/soc/codecs/pcm6240.c index 4ff39e0b95b2..b2bd2f172ae7 100644 --- a/sound/soc/codecs/pcm6240.c +++ b/sound/soc/codecs/pcm6240.c @@ -14,7 +14,7 @@ #include <linux/unaligned.h> #include <linux/firmware.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/module.h> #include <linux/of_irq.h> @@ -2035,10 +2035,8 @@ static const struct regmap_config pcmdevice_i2c_regmap = { static void pcmdevice_remove(struct pcmdevice_priv *pcm_dev) { - if (gpio_is_valid(pcm_dev->irq_info.gpio)) { - gpio_free(pcm_dev->irq_info.gpio); - free_irq(pcm_dev->irq_info.nmb, pcm_dev); - } + if (pcm_dev->irq) + free_irq(pcm_dev->irq, pcm_dev); mutex_destroy(&pcm_dev->codec_lock); } @@ -2109,7 +2107,7 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) ndev = 1; dev_addrs[0] = i2c->addr; } - pcm_dev->irq_info.gpio = of_irq_get(np, 0); + pcm_dev->irq = of_irq_get(np, 0); for (i = 0; i < ndev; i++) pcm_dev->addr[i] = dev_addrs[i]; @@ -2132,22 +2130,10 @@ static int pcmdevice_i2c_probe(struct i2c_client *i2c) if (pcm_dev->chip_id == PCM1690) goto skip_interrupt; - if (gpio_is_valid(pcm_dev->irq_info.gpio)) { - dev_dbg(pcm_dev->dev, "irq-gpio = %d", pcm_dev->irq_info.gpio); - - ret = gpio_request(pcm_dev->irq_info.gpio, "PCMDEV-IRQ"); - if (!ret) { - int gpio = pcm_dev->irq_info.gpio; - - gpio_direction_input(gpio); - pcm_dev->irq_info.nmb = gpio_to_irq(gpio); - - } else - dev_err(pcm_dev->dev, "%s: GPIO %d request error\n", - __func__, pcm_dev->irq_info.gpio); + if (pcm_dev->irq) { + dev_dbg(pcm_dev->dev, "irq = %d", pcm_dev->irq); } else - dev_err(pcm_dev->dev, "Looking up irq-gpio failed %d\n", - pcm_dev->irq_info.gpio); + dev_err(pcm_dev->dev, "No irq provided\n"); skip_interrupt: ret = devm_snd_soc_register_component(&i2c->dev, diff --git a/sound/soc/codecs/pcm6240.h b/sound/soc/codecs/pcm6240.h index 1e125bb97286..2d8f9e798139 100644 --- a/sound/soc/codecs/pcm6240.h +++ b/sound/soc/codecs/pcm6240.h @@ -208,11 +208,6 @@ struct pcmdevice_regbin { struct pcmdevice_config_info **cfg_info; }; -struct pcmdevice_irqinfo { - int gpio; - int nmb; -}; - struct pcmdevice_priv { struct snd_soc_component *component; struct i2c_client *client; @@ -221,7 +216,7 @@ struct pcmdevice_priv { struct gpio_desc *hw_rst; struct regmap *regmap; struct pcmdevice_regbin regbin; - struct pcmdevice_irqinfo irq_info; + int irq; unsigned int addr[PCMDEVICE_MAX_I2C_DEVICES]; unsigned int chip_id; int cur_conf; diff --git a/sound/soc/codecs/rk817_codec.c b/sound/soc/codecs/rk817_codec.c index 3c5b66357661..3c9957b00881 100644 --- a/sound/soc/codecs/rk817_codec.c +++ b/sound/soc/codecs/rk817_codec.c @@ -303,10 +303,10 @@ static int rk817_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int i2s_mst = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: i2s_mst |= RK817_I2S_MODE_SLV; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: i2s_mst |= RK817_I2S_MODE_MST; break; default: diff --git a/sound/soc/codecs/rt1011.c b/sound/soc/codecs/rt1011.c index a0e75b03e9dc..b84dd18ddde9 100644 --- a/sound/soc/codecs/rt1011.c +++ b/sound/soc/codecs/rt1011.c @@ -1671,7 +1671,7 @@ static int rt1011_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) snd_soc_dapm_mutex_lock(dapm); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT1011_I2S_TDM_MS_S; break; default: @@ -2192,15 +2192,15 @@ static const struct regmap_config rt1011_regmap = { #if defined(CONFIG_OF) static const struct of_device_id rt1011_of_match[] = { { .compatible = "realtek,rt1011", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt1011_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt1011_acpi_match[] = { - {"10EC1011", 0,}, - {}, + { "10EC1011" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1011_acpi_match); #endif diff --git a/sound/soc/codecs/rt1015.c b/sound/soc/codecs/rt1015.c index 0f806dde9c39..818b45226b72 100644 --- a/sound/soc/codecs/rt1015.c +++ b/sound/soc/codecs/rt1015.c @@ -753,10 +753,10 @@ static int rt1015_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0, reg_val2 = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: reg_val |= RT1015_TCON_TDM_MS_M; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT1015_TCON_TDM_MS_S; break; default: @@ -1105,15 +1105,15 @@ MODULE_DEVICE_TABLE(i2c, rt1015_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt1015_of_match[] = { { .compatible = "realtek,rt1015", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt1015_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt1015_acpi_match[] = { - {"10EC1015", 0,}, - {}, + { "10EC1015" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1015_acpi_match); #endif diff --git a/sound/soc/codecs/rt1016.c b/sound/soc/codecs/rt1016.c index fed4da23cba2..9f86f071fca8 100644 --- a/sound/soc/codecs/rt1016.c +++ b/sound/soc/codecs/rt1016.c @@ -367,11 +367,11 @@ static int rt1016_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: reg_val |= RT1016_I2S_MS_M; rt1016->master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT1016_I2S_MS_S; break; default: @@ -616,15 +616,15 @@ MODULE_DEVICE_TABLE(i2c, rt1016_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt1016_of_match[] = { { .compatible = "realtek,rt1016", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt1016_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt1016_acpi_match[] = { - {"10EC1016", 0,}, - {}, + { "10EC1016" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1016_acpi_match); #endif diff --git a/sound/soc/codecs/rt1017-sdca-sdw.c b/sound/soc/codecs/rt1017-sdca-sdw.c index 7c8103a0d562..88fc23a4999f 100644 --- a/sound/soc/codecs/rt1017-sdca-sdw.c +++ b/sound/soc/codecs/rt1017-sdca-sdw.c @@ -758,7 +758,7 @@ static const struct sdw_device_id rt1017_sdca_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt1017_sdca_id); -static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev) +static int rt1017_sdca_dev_suspend(struct device *dev) { struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); @@ -772,7 +772,7 @@ static int __maybe_unused rt1017_sdca_dev_suspend(struct device *dev) #define RT1017_PROBE_TIMEOUT 5000 -static int __maybe_unused rt1017_sdca_dev_resume(struct device *dev) +static int rt1017_sdca_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt1017_sdca_priv *rt1017 = dev_get_drvdata(dev); @@ -802,14 +802,14 @@ regmap_sync: } static const struct dev_pm_ops rt1017_sdca_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume) - SET_RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume) + RUNTIME_PM_OPS(rt1017_sdca_dev_suspend, rt1017_sdca_dev_resume, NULL) }; static struct sdw_driver rt1017_sdca_sdw_driver = { .driver = { .name = "rt1017-sdca", - .pm = &rt1017_sdca_pm, + .pm = pm_ptr(&rt1017_sdca_pm), }, .probe = rt1017_sdca_sdw_probe, .remove = rt1017_sdca_sdw_remove, diff --git a/sound/soc/codecs/rt1019.c b/sound/soc/codecs/rt1019.c index d989d06a2614..86539c6f6cc1 100644 --- a/sound/soc/codecs/rt1019.c +++ b/sound/soc/codecs/rt1019.c @@ -547,14 +547,14 @@ MODULE_DEVICE_TABLE(i2c, rt1019_i2c_id); static const struct of_device_id rt1019_of_match[] __maybe_unused = { { .compatible = "realtek,rt1019", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt1019_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt1019_acpi_match[] = { - { "10EC1019", 0}, - { }, + { "10EC1019" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1019_acpi_match); #endif diff --git a/sound/soc/codecs/rt1305.c b/sound/soc/codecs/rt1305.c index c2b55be8d165..26b7382f97ef 100644 --- a/sound/soc/codecs/rt1305.c +++ b/sound/soc/codecs/rt1305.c @@ -697,11 +697,11 @@ static int rt1305_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0, reg1_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: reg_val |= RT1305_SEL_I2S_OUT_MODE_M; rt1305->master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT1305_SEL_I2S_OUT_MODE_S; rt1305->master = 0; break; @@ -966,16 +966,16 @@ static const struct regmap_config rt1305_regmap = { static const struct of_device_id rt1305_of_match[] = { { .compatible = "realtek,rt1305", }, { .compatible = "realtek,rt1306", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt1305_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt1305_acpi_match[] = { - {"10EC1305", 0,}, - {"10EC1306", 0,}, - {}, + { "10EC1305" }, + { "10EC1306" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1305_acpi_match); #endif diff --git a/sound/soc/codecs/rt1308-sdw.c b/sound/soc/codecs/rt1308-sdw.c index 563df483a466..ea708068f0e8 100644 --- a/sound/soc/codecs/rt1308-sdw.c +++ b/sound/soc/codecs/rt1308-sdw.c @@ -753,7 +753,7 @@ static const struct sdw_device_id rt1308_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt1308_id); -static int __maybe_unused rt1308_dev_suspend(struct device *dev) +static int rt1308_dev_suspend(struct device *dev) { struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); @@ -767,7 +767,7 @@ static int __maybe_unused rt1308_dev_suspend(struct device *dev) #define RT1308_PROBE_TIMEOUT 5000 -static int __maybe_unused rt1308_dev_resume(struct device *dev) +static int rt1308_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt1308_sdw_priv *rt1308 = dev_get_drvdata(dev); @@ -797,14 +797,14 @@ regmap_sync: } static const struct dev_pm_ops rt1308_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume) - SET_RUNTIME_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume) + RUNTIME_PM_OPS(rt1308_dev_suspend, rt1308_dev_resume, NULL) }; static struct sdw_driver rt1308_sdw_driver = { .driver = { .name = "rt1308", - .pm = &rt1308_pm, + .pm = pm_ptr(&rt1308_pm), }, .probe = rt1308_sdw_probe, .remove = rt1308_sdw_remove, diff --git a/sound/soc/codecs/rt1308.c b/sound/soc/codecs/rt1308.c index b366338cea71..df50b38c24b9 100644 --- a/sound/soc/codecs/rt1308.c +++ b/sound/soc/codecs/rt1308.c @@ -523,7 +523,7 @@ static int rt1308_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0, reg1_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: rt1308->master = 0; break; default: @@ -781,15 +781,15 @@ static const struct regmap_config rt1308_regmap = { #ifdef CONFIG_OF static const struct of_device_id rt1308_of_match[] = { { .compatible = "realtek,rt1308", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, rt1308_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt1308_acpi_match[] = { - { "10EC1308", 0, }, - { }, + { "10EC1308" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1308_acpi_match); #endif diff --git a/sound/soc/codecs/rt1316-sdw.c b/sound/soc/codecs/rt1316-sdw.c index 22f1ed4e03f1..960b6c4f5a66 100644 --- a/sound/soc/codecs/rt1316-sdw.c +++ b/sound/soc/codecs/rt1316-sdw.c @@ -730,7 +730,7 @@ static const struct sdw_device_id rt1316_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt1316_id); -static int __maybe_unused rt1316_dev_suspend(struct device *dev) +static int rt1316_dev_suspend(struct device *dev) { struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); @@ -744,7 +744,7 @@ static int __maybe_unused rt1316_dev_suspend(struct device *dev) #define RT1316_PROBE_TIMEOUT 5000 -static int __maybe_unused rt1316_dev_resume(struct device *dev) +static int rt1316_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt1316_sdw_priv *rt1316 = dev_get_drvdata(dev); @@ -774,14 +774,14 @@ regmap_sync: } static const struct dev_pm_ops rt1316_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume) - SET_RUNTIME_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume) + RUNTIME_PM_OPS(rt1316_dev_suspend, rt1316_dev_resume, NULL) }; static struct sdw_driver rt1316_sdw_driver = { .driver = { .name = "rt1316-sdca", - .pm = &rt1316_pm, + .pm = pm_ptr(&rt1316_pm), }, .probe = rt1316_sdw_probe, .remove = rt1316_sdw_remove, diff --git a/sound/soc/codecs/rt1318-sdw.c b/sound/soc/codecs/rt1318-sdw.c index 319f71f5e60d..4eb636e0c9ed 100644 --- a/sound/soc/codecs/rt1318-sdw.c +++ b/sound/soc/codecs/rt1318-sdw.c @@ -807,7 +807,7 @@ static const struct sdw_device_id rt1318_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt1318_id); -static int __maybe_unused rt1318_dev_suspend(struct device *dev) +static int rt1318_dev_suspend(struct device *dev) { struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev); @@ -820,7 +820,7 @@ static int __maybe_unused rt1318_dev_suspend(struct device *dev) #define RT1318_PROBE_TIMEOUT 5000 -static int __maybe_unused rt1318_dev_resume(struct device *dev) +static int rt1318_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt1318_sdw_priv *rt1318 = dev_get_drvdata(dev); @@ -848,14 +848,14 @@ regmap_sync: } static const struct dev_pm_ops rt1318_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume) - SET_RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume) + RUNTIME_PM_OPS(rt1318_dev_suspend, rt1318_dev_resume, NULL) }; static struct sdw_driver rt1318_sdw_driver = { .driver = { .name = "rt1318-sdca", - .pm = &rt1318_pm, + .pm = pm_ptr(&rt1318_pm), }, .probe = rt1318_sdw_probe, .remove = rt1318_sdw_remove, diff --git a/sound/soc/codecs/rt1318.c b/sound/soc/codecs/rt1318.c index e12b1e96a53a..ae01b2ce630b 100644 --- a/sound/soc/codecs/rt1318.c +++ b/sound/soc/codecs/rt1318.c @@ -1147,14 +1147,14 @@ MODULE_DEVICE_TABLE(i2c, rt1318_i2c_id); static const struct of_device_id rt1318_of_match[] = { { .compatible = "realtek,rt1318", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt1318_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt1318_acpi_match[] = { - { "10EC1318", 0}, - { }, + { "10EC1318" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt1318_acpi_match); #endif diff --git a/sound/soc/codecs/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c index d83b236a0450..f51ba345a16e 100644 --- a/sound/soc/codecs/rt1320-sdw.c +++ b/sound/soc/codecs/rt1320-sdw.c @@ -1458,7 +1458,7 @@ static const struct sdw_device_id rt1320_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt1320_id); -static int __maybe_unused rt1320_dev_suspend(struct device *dev) +static int rt1320_dev_suspend(struct device *dev) { struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); @@ -1472,7 +1472,7 @@ static int __maybe_unused rt1320_dev_suspend(struct device *dev) #define RT1320_PROBE_TIMEOUT 5000 -static int __maybe_unused rt1320_dev_resume(struct device *dev) +static int rt1320_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt1320_sdw_priv *rt1320 = dev_get_drvdata(dev); @@ -1501,14 +1501,14 @@ regmap_sync: } static const struct dev_pm_ops rt1320_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume) - SET_RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume) + RUNTIME_PM_OPS(rt1320_dev_suspend, rt1320_dev_resume, NULL) }; static struct sdw_driver rt1320_sdw_driver = { .driver = { .name = "rt1320-sdca", - .pm = &rt1320_pm, + .pm = pm_ptr(&rt1320_pm), }, .probe = rt1320_sdw_probe, .remove = rt1320_sdw_remove, diff --git a/sound/soc/codecs/rt274.c b/sound/soc/codecs/rt274.c index bd61a257d7b5..2c055c45111f 100644 --- a/sound/soc/codecs/rt274.c +++ b/sound/soc/codecs/rt274.c @@ -706,12 +706,12 @@ static int rt274_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct rt274_priv *rt274 = snd_soc_component_get_drvdata(component); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: snd_soc_component_update_bits(component, RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_M); rt274->master = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: snd_soc_component_update_bits(component, RT274_I2S_CTRL1, RT274_I2S_MODE_MASK, RT274_I2S_MODE_S); rt274->master = false; @@ -1091,7 +1091,7 @@ static const struct regmap_config rt274_regmap = { #ifdef CONFIG_OF static const struct of_device_id rt274_of_match[] = { {.compatible = "realtek,rt274"}, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt274_of_match); #endif @@ -1104,9 +1104,9 @@ MODULE_DEVICE_TABLE(i2c, rt274_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt274_acpi_match[] = { - { "10EC0274", 0 }, - { "INT34C2", 0 }, - {}, + { "10EC0274" }, + { "INT34C2" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt274_acpi_match); #endif diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index d0f533120c33..fd8de8b49793 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -765,11 +765,11 @@ static int rt286_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: snd_soc_component_update_bits(component, RT286_I2S_CTRL1, 0x800, 0x800); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: snd_soc_component_update_bits(component, RT286_I2S_CTRL1, 0x800, 0x0); break; @@ -1083,8 +1083,9 @@ MODULE_DEVICE_TABLE(i2c, rt286_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt286_acpi_match[] = { - { "INT343A", 0 }, - {}, + { "10EC0286" }, + { "INT343A" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); #endif diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 13aef6c5e91c..ee3d9291eea6 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -829,11 +829,11 @@ static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) struct snd_soc_component *component = dai->component; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: snd_soc_component_update_bits(component, RT298_I2S_CTRL1, 0x800, 0x800); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: snd_soc_component_update_bits(component, RT298_I2S_CTRL1, 0x800, 0x0); break; @@ -1144,8 +1144,9 @@ MODULE_DEVICE_TABLE(i2c, rt298_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt298_acpi_match[] = { - { "INT343A", 0 }, - {}, + { "10EC0298" }, + { "INT343A" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt298_acpi_match); #endif diff --git a/sound/soc/codecs/rt5514-spi.c b/sound/soc/codecs/rt5514-spi.c index f475c8cfadae..54d84581ec47 100644 --- a/sound/soc/codecs/rt5514-spi.c +++ b/sound/soc/codecs/rt5514-spi.c @@ -458,7 +458,7 @@ static int rt5514_spi_probe(struct spi_device *spi) return 0; } -static int __maybe_unused rt5514_suspend(struct device *dev) +static int rt5514_suspend(struct device *dev) { int irq = to_spi_device(dev)->irq; @@ -468,7 +468,7 @@ static int __maybe_unused rt5514_suspend(struct device *dev) return 0; } -static int __maybe_unused rt5514_resume(struct device *dev) +static int rt5514_resume(struct device *dev) { struct rt5514_dsp *rt5514_dsp = dev_get_drvdata(dev); int irq = to_spi_device(dev)->irq; @@ -490,7 +490,7 @@ static int __maybe_unused rt5514_resume(struct device *dev) } static const struct dev_pm_ops rt5514_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rt5514_suspend, rt5514_resume) + SYSTEM_SLEEP_PM_OPS(rt5514_suspend, rt5514_resume) }; static const struct of_device_id rt5514_of_match[] = { @@ -502,7 +502,7 @@ MODULE_DEVICE_TABLE(of, rt5514_of_match); static struct spi_driver rt5514_spi_driver = { .driver = { .name = "rt5514", - .pm = &rt5514_pm_ops, + .pm = pm_ptr(&rt5514_pm_ops), .of_match_table = of_match_ptr(rt5514_of_match), }, .probe = rt5514_spi_probe, diff --git a/sound/soc/codecs/rt5514.c b/sound/soc/codecs/rt5514.c index 9cb74962161a..ab9d81c32be8 100644 --- a/sound/soc/codecs/rt5514.c +++ b/sound/soc/codecs/rt5514.c @@ -1206,15 +1206,15 @@ MODULE_DEVICE_TABLE(i2c, rt5514_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt5514_of_match[] = { { .compatible = "realtek,rt5514", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5514_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5514_acpi_match[] = { - { "10EC5514", 0}, - {}, + { "10EC5514" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5514_acpi_match); #endif @@ -1231,7 +1231,7 @@ static int rt5514_parse_dp(struct rt5514_priv *rt5514, struct device *dev) return 0; } -static __maybe_unused int rt5514_i2c_resume(struct device *dev) +static int rt5514_i2c_resume(struct device *dev) { struct rt5514_priv *rt5514 = dev_get_drvdata(dev); unsigned int val; @@ -1313,7 +1313,7 @@ static int rt5514_i2c_probe(struct i2c_client *i2c) } static const struct dev_pm_ops rt5514_i2_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume) + SYSTEM_SLEEP_PM_OPS(NULL, rt5514_i2c_resume) }; static struct i2c_driver rt5514_i2c_driver = { @@ -1321,7 +1321,7 @@ static struct i2c_driver rt5514_i2c_driver = { .name = "rt5514", .acpi_match_table = ACPI_PTR(rt5514_acpi_match), .of_match_table = of_match_ptr(rt5514_of_match), - .pm = &rt5514_i2_pm_ops, + .pm = pm_ptr(&rt5514_i2_pm_ops), }, .probe = rt5514_i2c_probe, .id_table = rt5514_i2c_id, diff --git a/sound/soc/codecs/rt5616.c b/sound/soc/codecs/rt5616.c index 34461c462009..1ec486707ff9 100644 --- a/sound/soc/codecs/rt5616.c +++ b/sound/soc/codecs/rt5616.c @@ -1015,10 +1015,10 @@ static int rt5616_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5616->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5616_I2S_MS_S; rt5616->master[dai->id] = 0; break; diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 12df0c4f2097..d523477c5102 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1411,10 +1411,10 @@ static int rt5631_hifi_codec_set_dai_fmt(struct snd_soc_dai *codec_dai, dev_dbg(component->dev, "enter %s\n", __func__); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5631->master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: iface |= RT5631_SDP_MODE_SEL_SLAVE; rt5631->master = 0; break; diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 855139348edb..21a18012b4c0 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -1773,10 +1773,10 @@ static int rt5640_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) int dai_sel; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5640->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5640_I2S_MS_S; rt5640->master[dai->id] = 0; break; @@ -2963,19 +2963,19 @@ MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id); static const struct of_device_id rt5640_of_match[] = { { .compatible = "realtek,rt5639", }, { .compatible = "realtek,rt5640", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5640_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5640_acpi_match[] = { - { "INT33CA", 0 }, - { "10EC3276", 0 }, - { "10EC5640", 0 }, - { "10EC5642", 0 }, - { "INTCCFFD", 0 }, - { }, + { "10EC3276" }, + { "10EC5640" }, + { "10EC5642" }, + { "INT33CA" }, + { "INTCCFFD" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5640_acpi_match); #endif diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 51187b1e0ed2..343e3bcef0ca 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2841,10 +2841,10 @@ static int rt5645_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5645->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5645_I2S_MS_S; rt5645->master[dai->id] = 0; break; @@ -3660,12 +3660,12 @@ MODULE_DEVICE_TABLE(of, rt5645_of_match); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5645_acpi_match[] = { - { "10EC5645", 0 }, - { "10EC5648", 0 }, - { "10EC5650", 0 }, - { "10EC5640", 0 }, - { "10EC3270", 0 }, - {}, + { "10EC3270" }, + { "10EC5640" }, + { "10EC5645" }, + { "10EC5648" }, + { "10EC5650" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5645_acpi_match); #endif @@ -4314,7 +4314,7 @@ static void rt5645_i2c_shutdown(struct i2c_client *i2c) gpiod_set_value(rt5645->gpiod_cbj_sleeve, 0); } -static int __maybe_unused rt5645_sys_suspend(struct device *dev) +static int rt5645_sys_suspend(struct device *dev) { struct rt5645_priv *rt5645 = dev_get_drvdata(dev); @@ -4327,7 +4327,7 @@ static int __maybe_unused rt5645_sys_suspend(struct device *dev) return 0; } -static int __maybe_unused rt5645_sys_resume(struct device *dev) +static int rt5645_sys_resume(struct device *dev) { struct rt5645_priv *rt5645 = dev_get_drvdata(dev); @@ -4342,7 +4342,7 @@ static int __maybe_unused rt5645_sys_resume(struct device *dev) } static const struct dev_pm_ops rt5645_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume) + SYSTEM_SLEEP_PM_OPS(rt5645_sys_suspend, rt5645_sys_resume) }; static struct i2c_driver rt5645_i2c_driver = { @@ -4350,7 +4350,7 @@ static struct i2c_driver rt5645_i2c_driver = { .name = "rt5645", .of_match_table = of_match_ptr(rt5645_of_match), .acpi_match_table = ACPI_PTR(rt5645_acpi_match), - .pm = &rt5645_pm, + .pm = pm_ptr(&rt5645_pm), }, .probe = rt5645_i2c_probe, .remove = rt5645_i2c_remove, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index 00421a1f54bf..9eeeba8cd6ff 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1352,10 +1352,10 @@ static int rt5651_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5651->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5651_I2S_MS_S; rt5651->master[dai->id] = 0; break; @@ -2184,16 +2184,16 @@ static const struct regmap_config rt5651_regmap = { #if defined(CONFIG_OF) static const struct of_device_id rt5651_of_match[] = { { .compatible = "realtek,rt5651", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5651_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5651_acpi_match[] = { - { "10EC5651", 0 }, - { "10EC5640", 0 }, - { }, + { "10EC5640" }, + { "10EC5651" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5651_acpi_match); #endif diff --git a/sound/soc/codecs/rt5659.c b/sound/soc/codecs/rt5659.c index a2652fa6e1d7..31b47db7b4f7 100644 --- a/sound/soc/codecs/rt5659.c +++ b/sound/soc/codecs/rt5659.c @@ -3363,10 +3363,10 @@ static int rt5659_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5659->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5659_I2S_MS_S; rt5659->master[dai->id] = 0; break; @@ -4315,16 +4315,16 @@ static void rt5659_i2c_shutdown(struct i2c_client *client) static const struct of_device_id rt5659_of_match[] = { { .compatible = "realtek,rt5658", }, { .compatible = "realtek,rt5659", }, - { }, + { } }; MODULE_DEVICE_TABLE(of, rt5659_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5659_acpi_match[] = { - { "10EC5658", 0, }, - { "10EC5659", 0, }, - { }, + { "10EC5658" }, + { "10EC5659" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5659_acpi_match); #endif diff --git a/sound/soc/codecs/rt5660.c b/sound/soc/codecs/rt5660.c index 3ac41d2c279b..82b92e83be4c 100644 --- a/sound/soc/codecs/rt5660.c +++ b/sound/soc/codecs/rt5660.c @@ -905,11 +905,11 @@ static int rt5660_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5660->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5660_I2S_MS_S; rt5660->master[dai->id] = 0; break; @@ -1232,16 +1232,16 @@ MODULE_DEVICE_TABLE(i2c, rt5660_i2c_id); #ifdef CONFIG_OF static const struct of_device_id rt5660_of_match[] = { { .compatible = "realtek,rt5660", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5660_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5660_acpi_match[] = { - { "10EC5660", 0 }, - { "10EC3277", 0 }, - { }, + { "10EC3277" }, + { "10EC5660" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5660_acpi_match); #endif diff --git a/sound/soc/codecs/rt5663.c b/sound/soc/codecs/rt5663.c index 9d32debd3689..45057562c0c8 100644 --- a/sound/soc/codecs/rt5663.c +++ b/sound/soc/codecs/rt5663.c @@ -2814,9 +2814,9 @@ static int rt5663_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5663_I2S_MS_S; break; default: @@ -3315,15 +3315,15 @@ MODULE_DEVICE_TABLE(i2c, rt5663_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id rt5663_of_match[] = { { .compatible = "realtek,rt5663", }, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5663_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5663_acpi_match[] = { - { "10EC5663", 0}, - {}, + { "10EC5663" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5663_acpi_match); #endif diff --git a/sound/soc/codecs/rt5665.c b/sound/soc/codecs/rt5665.c index 47df14ba5278..e0d1991cffdb 100644 --- a/sound/soc/codecs/rt5665.c +++ b/sound/soc/codecs/rt5665.c @@ -4219,10 +4219,10 @@ static int rt5665_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5665->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5665_I2S_MS_S; rt5665->master[dai->id] = 0; break; @@ -4949,16 +4949,16 @@ static void rt5665_i2c_shutdown(struct i2c_client *client) static const struct of_device_id rt5665_of_match[] = { {.compatible = "realtek,rt5665"}, {.compatible = "realtek,rt5666"}, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5665_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5665_acpi_match[] = { - {"10EC5665", 0,}, - {"10EC5666", 0,}, - {}, + { "10EC5665" }, + { "10EC5666" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5665_acpi_match); #endif diff --git a/sound/soc/codecs/rt5668.c b/sound/soc/codecs/rt5668.c index 494ca3ce9b96..f626453f332b 100644 --- a/sound/soc/codecs/rt5668.c +++ b/sound/soc/codecs/rt5668.c @@ -2010,10 +2010,10 @@ static int rt5668_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0, tdm_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5668->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: rt5668->master[dai->id] = 0; break; default: @@ -2598,15 +2598,15 @@ static void rt5668_i2c_shutdown(struct i2c_client *client) #ifdef CONFIG_OF static const struct of_device_id rt5668_of_match[] = { {.compatible = "realtek,rt5668b"}, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5668_of_match); #endif #ifdef CONFIG_ACPI static const struct acpi_device_id rt5668_acpi_match[] = { - {"10EC5668", 0,}, - {}, + { "10EC5668" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5668_acpi_match); #endif diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index 30bf96c35b58..efd26082f19a 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2439,10 +2439,10 @@ static int rt5670_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5670->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5670_I2S_MS_S; rt5670->master[dai->id] = 0; break; @@ -2880,10 +2880,10 @@ MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id); #ifdef CONFIG_ACPI static const struct acpi_device_id rt5670_acpi_match[] = { - { "10EC5670", 0}, - { "10EC5672", 0}, - { "10EC5640", 0}, /* quirk */ - { }, + { "10EC5640" }, /* quirk */ + { "10EC5670" }, + { "10EC5672" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match); #endif diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index d91a2184f67c..abe0a5a95770 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -617,7 +617,8 @@ static int rt5677_spi_probe(struct spi_device *spi) #ifdef CONFIG_ACPI static const struct acpi_device_id rt5677_spi_acpi_id[] = { - { "RT5677AA", 0 }, + { "10EC5677" }, + { "RT5677AA" }, { } }; MODULE_DEVICE_TABLE(acpi, rt5677_spi_acpi_id); diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 0e70a3ab42b5..6e4774148566 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4377,10 +4377,10 @@ static int rt5677_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5677->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg_val |= RT5677_I2S_MS_S; rt5677->master[dai->id] = 0; break; @@ -5201,6 +5201,7 @@ static const struct of_device_id rt5677_of_match[] = { MODULE_DEVICE_TABLE(of, rt5677_of_match); static const struct acpi_device_id rt5677_acpi_match[] = { + { "10EC5677", RT5677 }, { "RT5677CE", RT5677 }, { } }; diff --git a/sound/soc/codecs/rt5682-i2c.c b/sound/soc/codecs/rt5682-i2c.c index a8820435d1e0..bba987308e15 100644 --- a/sound/soc/codecs/rt5682-i2c.c +++ b/sound/soc/codecs/rt5682-i2c.c @@ -313,13 +313,13 @@ static void rt5682_i2c_remove(struct i2c_client *client) static const struct of_device_id rt5682_of_match[] = { {.compatible = "realtek,rt5682i"}, - {}, + { } }; MODULE_DEVICE_TABLE(of, rt5682_of_match); static const struct acpi_device_id rt5682_acpi_match[] = { - {"10EC5682", 0,}, - {}, + { "10EC5682" }, + { } }; MODULE_DEVICE_TABLE(acpi, rt5682_acpi_match); diff --git a/sound/soc/codecs/rt5682-sdw.c b/sound/soc/codecs/rt5682-sdw.c index 5edf11e136b4..aa229894129b 100644 --- a/sound/soc/codecs/rt5682-sdw.c +++ b/sound/soc/codecs/rt5682-sdw.c @@ -709,7 +709,7 @@ static const struct sdw_device_id rt5682_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt5682_id); -static int __maybe_unused rt5682_dev_suspend(struct device *dev) +static int rt5682_dev_suspend(struct device *dev) { struct rt5682_priv *rt5682 = dev_get_drvdata(dev); @@ -725,7 +725,7 @@ static int __maybe_unused rt5682_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt5682_dev_system_suspend(struct device *dev) +static int rt5682_dev_system_suspend(struct device *dev) { struct rt5682_priv *rt5682 = dev_get_drvdata(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev); @@ -753,7 +753,7 @@ static int __maybe_unused rt5682_dev_system_suspend(struct device *dev) return rt5682_dev_suspend(dev); } -static int __maybe_unused rt5682_dev_resume(struct device *dev) +static int rt5682_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt5682_priv *rt5682 = dev_get_drvdata(dev); @@ -791,14 +791,14 @@ regmap_sync: } static const struct dev_pm_ops rt5682_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume) - SET_RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt5682_dev_system_suspend, rt5682_dev_resume) + RUNTIME_PM_OPS(rt5682_dev_suspend, rt5682_dev_resume, NULL) }; static struct sdw_driver rt5682_sdw_driver = { .driver = { .name = "rt5682", - .pm = &rt5682_pm, + .pm = pm_ptr(&rt5682_pm), }, .probe = rt5682_sdw_probe, .remove = rt5682_sdw_remove, diff --git a/sound/soc/codecs/rt5682.c b/sound/soc/codecs/rt5682.c index b4d72fc4a44d..7c88370e2dee 100644 --- a/sound/soc/codecs/rt5682.c +++ b/sound/soc/codecs/rt5682.c @@ -2225,10 +2225,10 @@ static int rt5682_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0, tdm_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5682->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: rt5682->master[dai->id] = 0; break; default: diff --git a/sound/soc/codecs/rt5682s.c b/sound/soc/codecs/rt5682s.c index ce2e88e066f3..73c4b3c31f8c 100644 --- a/sound/soc/codecs/rt5682s.c +++ b/sound/soc/codecs/rt5682s.c @@ -2132,10 +2132,10 @@ static int rt5682s_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int reg_val = 0, tdm_ctrl = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: rt5682s->master[dai->id] = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: rt5682s->master[dai->id] = 0; break; default: diff --git a/sound/soc/codecs/rt700-sdw.c b/sound/soc/codecs/rt700-sdw.c index 24cb895b759f..44543c0da177 100644 --- a/sound/soc/codecs/rt700-sdw.c +++ b/sound/soc/codecs/rt700-sdw.c @@ -475,7 +475,7 @@ static const struct sdw_device_id rt700_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt700_id); -static int __maybe_unused rt700_dev_suspend(struct device *dev) +static int rt700_dev_suspend(struct device *dev) { struct rt700_priv *rt700 = dev_get_drvdata(dev); @@ -490,7 +490,7 @@ static int __maybe_unused rt700_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt700_dev_system_suspend(struct device *dev) +static int rt700_dev_system_suspend(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt700_priv *rt700 = dev_get_drvdata(dev); @@ -520,7 +520,7 @@ static int __maybe_unused rt700_dev_system_suspend(struct device *dev) #define RT700_PROBE_TIMEOUT 5000 -static int __maybe_unused rt700_dev_resume(struct device *dev) +static int rt700_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt700_priv *rt700 = dev_get_drvdata(dev); @@ -551,14 +551,14 @@ regmap_sync: } static const struct dev_pm_ops rt700_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume) - SET_RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt700_dev_system_suspend, rt700_dev_resume) + RUNTIME_PM_OPS(rt700_dev_suspend, rt700_dev_resume, NULL) }; static struct sdw_driver rt700_sdw_driver = { .driver = { .name = "rt700", - .pm = &rt700_pm, + .pm = pm_ptr(&rt700_pm), }, .probe = rt700_sdw_probe, .remove = rt700_sdw_remove, diff --git a/sound/soc/codecs/rt711-sdca-sdw.c b/sound/soc/codecs/rt711-sdca-sdw.c index f5933d2e085e..adf05f64259b 100644 --- a/sound/soc/codecs/rt711-sdca-sdw.c +++ b/sound/soc/codecs/rt711-sdca-sdw.c @@ -380,7 +380,7 @@ static const struct sdw_device_id rt711_sdca_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt711_sdca_id); -static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev) +static int rt711_sdca_dev_suspend(struct device *dev) { struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); @@ -396,7 +396,7 @@ static int __maybe_unused rt711_sdca_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev) +static int rt711_sdca_dev_system_suspend(struct device *dev) { struct rt711_sdca_priv *rt711_sdca = dev_get_drvdata(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev); @@ -428,7 +428,7 @@ static int __maybe_unused rt711_sdca_dev_system_suspend(struct device *dev) #define RT711_PROBE_TIMEOUT 5000 -static int __maybe_unused rt711_sdca_dev_resume(struct device *dev) +static int rt711_sdca_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt711_sdca_priv *rt711 = dev_get_drvdata(dev); @@ -467,14 +467,14 @@ regmap_sync: } static const struct dev_pm_ops rt711_sdca_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume) - SET_RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt711_sdca_dev_system_suspend, rt711_sdca_dev_resume) + RUNTIME_PM_OPS(rt711_sdca_dev_suspend, rt711_sdca_dev_resume, NULL) }; static struct sdw_driver rt711_sdca_sdw_driver = { .driver = { .name = "rt711-sdca", - .pm = &rt711_sdca_pm, + .pm = pm_ptr(&rt711_sdca_pm), }, .probe = rt711_sdca_sdw_probe, .remove = rt711_sdca_sdw_remove, diff --git a/sound/soc/codecs/rt711-sdw.c b/sound/soc/codecs/rt711-sdw.c index dfda6bb5c6f8..93a5a89a96b1 100644 --- a/sound/soc/codecs/rt711-sdw.c +++ b/sound/soc/codecs/rt711-sdw.c @@ -482,7 +482,7 @@ static const struct sdw_device_id rt711_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt711_id); -static int __maybe_unused rt711_dev_suspend(struct device *dev) +static int rt711_dev_suspend(struct device *dev) { struct rt711_priv *rt711 = dev_get_drvdata(dev); @@ -498,7 +498,7 @@ static int __maybe_unused rt711_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt711_dev_system_suspend(struct device *dev) +static int rt711_dev_system_suspend(struct device *dev) { struct rt711_priv *rt711 = dev_get_drvdata(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev); @@ -528,7 +528,7 @@ static int __maybe_unused rt711_dev_system_suspend(struct device *dev) #define RT711_PROBE_TIMEOUT 5000 -static int __maybe_unused rt711_dev_resume(struct device *dev) +static int rt711_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt711_priv *rt711 = dev_get_drvdata(dev); @@ -564,14 +564,14 @@ regmap_sync: } static const struct dev_pm_ops rt711_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume) - SET_RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume) + RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL) }; static struct sdw_driver rt711_sdw_driver = { .driver = { .name = "rt711", - .pm = &rt711_pm, + .pm = pm_ptr(&rt711_pm), }, .probe = rt711_sdw_probe, .remove = rt711_sdw_remove, diff --git a/sound/soc/codecs/rt712-sdca-dmic.c b/sound/soc/codecs/rt712-sdca-dmic.c index ee5435f3a80a..db011da63bd9 100644 --- a/sound/soc/codecs/rt712-sdca-dmic.c +++ b/sound/soc/codecs/rt712-sdca-dmic.c @@ -884,7 +884,7 @@ static const struct sdw_device_id rt712_sdca_dmic_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt712_sdca_dmic_id); -static int __maybe_unused rt712_sdca_dmic_dev_suspend(struct device *dev) +static int rt712_sdca_dmic_dev_suspend(struct device *dev) { struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(dev); @@ -897,7 +897,7 @@ static int __maybe_unused rt712_sdca_dmic_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt712_sdca_dmic_dev_system_suspend(struct device *dev) +static int rt712_sdca_dmic_dev_system_suspend(struct device *dev) { struct rt712_sdca_dmic_priv *rt712_sdca = dev_get_drvdata(dev); @@ -909,7 +909,7 @@ static int __maybe_unused rt712_sdca_dmic_dev_system_suspend(struct device *dev) #define RT712_PROBE_TIMEOUT 5000 -static int __maybe_unused rt712_sdca_dmic_dev_resume(struct device *dev) +static int rt712_sdca_dmic_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt712_sdca_dmic_priv *rt712 = dev_get_drvdata(dev); @@ -941,8 +941,8 @@ regmap_sync: } static const struct dev_pm_ops rt712_sdca_dmic_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt712_sdca_dmic_dev_system_suspend, rt712_sdca_dmic_dev_resume) - SET_RUNTIME_PM_OPS(rt712_sdca_dmic_dev_suspend, rt712_sdca_dmic_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt712_sdca_dmic_dev_system_suspend, rt712_sdca_dmic_dev_resume) + RUNTIME_PM_OPS(rt712_sdca_dmic_dev_suspend, rt712_sdca_dmic_dev_resume, NULL) }; @@ -978,7 +978,7 @@ static int rt712_sdca_dmic_sdw_remove(struct sdw_slave *slave) static struct sdw_driver rt712_sdca_dmic_sdw_driver = { .driver = { .name = "rt712-sdca-dmic", - .pm = &rt712_sdca_dmic_pm, + .pm = pm_ptr(&rt712_sdca_dmic_pm), }, .probe = rt712_sdca_dmic_sdw_probe, .remove = rt712_sdca_dmic_sdw_remove, diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c index b584a3f854b8..ea07131edfa2 100644 --- a/sound/soc/codecs/rt712-sdca-sdw.c +++ b/sound/soc/codecs/rt712-sdca-sdw.c @@ -400,7 +400,7 @@ static const struct sdw_device_id rt712_sdca_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt712_sdca_id); -static int __maybe_unused rt712_sdca_dev_suspend(struct device *dev) +static int rt712_sdca_dev_suspend(struct device *dev) { struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); @@ -416,7 +416,7 @@ static int __maybe_unused rt712_sdca_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt712_sdca_dev_system_suspend(struct device *dev) +static int rt712_sdca_dev_system_suspend(struct device *dev) { struct rt712_sdca_priv *rt712_sdca = dev_get_drvdata(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev); @@ -448,7 +448,7 @@ static int __maybe_unused rt712_sdca_dev_system_suspend(struct device *dev) #define RT712_PROBE_TIMEOUT 5000 -static int __maybe_unused rt712_sdca_dev_resume(struct device *dev) +static int rt712_sdca_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev); @@ -488,14 +488,14 @@ regmap_sync: } static const struct dev_pm_ops rt712_sdca_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt712_sdca_dev_system_suspend, rt712_sdca_dev_resume) - SET_RUNTIME_PM_OPS(rt712_sdca_dev_suspend, rt712_sdca_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt712_sdca_dev_system_suspend, rt712_sdca_dev_resume) + RUNTIME_PM_OPS(rt712_sdca_dev_suspend, rt712_sdca_dev_resume, NULL) }; static struct sdw_driver rt712_sdca_sdw_driver = { .driver = { .name = "rt712-sdca", - .pm = &rt712_sdca_pm, + .pm = pm_ptr(&rt712_sdca_pm), }, .probe = rt712_sdca_sdw_probe, .remove = rt712_sdca_sdw_remove, diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c index 78dbf9eed494..19d99b9d4ab2 100644 --- a/sound/soc/codecs/rt712-sdca.c +++ b/sound/soc/codecs/rt712-sdca.c @@ -652,6 +652,61 @@ static int rt712_sdca_fu0f_capture_put(struct snd_kcontrol *kcontrol, return 1; } +static int rt712_sdca_set_fu05_playback_ctl(struct rt712_sdca_priv *rt712) +{ + int err; + unsigned int ch_01, ch_02; + + ch_01 = (rt712->fu05_dapm_mute || rt712->fu05_mixer_l_mute) ? 0x01 : 0x00; + ch_02 = (rt712->fu05_dapm_mute || rt712->fu05_mixer_r_mute) ? 0x01 : 0x00; + + err = regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, + RT712_SDCA_CTL_FU_MUTE, CH_01), ch_01); + if (err < 0) + return err; + + err = regmap_write(rt712->regmap, + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, + RT712_SDCA_CTL_FU_MUTE, CH_02), ch_02); + if (err < 0) + return err; + + return 0; +} + +static int rt712_sdca_fu05_playback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + + ucontrol->value.integer.value[0] = !rt712->fu05_mixer_l_mute; + ucontrol->value.integer.value[1] = !rt712->fu05_mixer_r_mute; + return 0; +} + +static int rt712_sdca_fu05_playback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); + int err; + + if (rt712->fu05_mixer_l_mute == !ucontrol->value.integer.value[0] && + rt712->fu05_mixer_r_mute == !ucontrol->value.integer.value[1]) + return 0; + + rt712->fu05_mixer_l_mute = !ucontrol->value.integer.value[0]; + rt712->fu05_mixer_r_mute = !ucontrol->value.integer.value[1]; + + err = rt712_sdca_set_fu05_playback_ctl(rt712); + if (err < 0) + return err; + + return 1; +} + static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0); static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -1725, 75, 0); static const DECLARE_TLV_DB_SCALE(boost_vol_tlv, 0, 1000, 0); @@ -674,6 +729,8 @@ static const struct snd_kcontrol_new rt712_sdca_controls[] = { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 8, 3, 0, rt712_sdca_set_gain_get, rt712_sdca_set_gain_put, boost_vol_tlv), + SOC_DOUBLE_EXT("FU05 Playback Switch", SND_SOC_NOPM, 0, 1, 1, 0, + rt712_sdca_fu05_playback_get, rt712_sdca_fu05_playback_put), }; static const struct snd_kcontrol_new rt712_sdca_spk_controls[] = { @@ -766,28 +823,15 @@ static int rt712_sdca_fu05_event(struct snd_soc_dapm_widget *w, struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component); - unsigned char unmute = 0x0, mute = 0x1; switch (event) { case SND_SOC_DAPM_POST_PMU: - regmap_write(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_01), - unmute); - regmap_write(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_02), - unmute); + rt712->fu05_dapm_mute = false; + rt712_sdca_set_fu05_playback_ctl(rt712); break; case SND_SOC_DAPM_PRE_PMD: - regmap_write(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_01), - mute); - regmap_write(rt712->regmap, - SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, - RT712_SDCA_CTL_FU_MUTE, CH_02), - mute); + rt712->fu05_dapm_mute = true; + rt712_sdca_set_fu05_playback_ctl(rt712); break; } return 0; @@ -1640,6 +1684,8 @@ int rt712_sdca_init(struct device *dev, struct regmap *regmap, rt712->fu1e_dapm_mute = true; rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] = rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true; + rt712->fu05_dapm_mute = true; + rt712->fu05_mixer_l_mute = rt712->fu05_mixer_r_mute = false; /* JD source uses JD1 in default */ rt712->jd_src = RT712_JD1; diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h index a08491496d90..7ab7d5feb50a 100644 --- a/sound/soc/codecs/rt712-sdca.h +++ b/sound/soc/codecs/rt712-sdca.h @@ -42,6 +42,9 @@ struct rt712_sdca_priv { bool fu0f_mixer_r_mute; bool fu1e_dapm_mute; bool fu1e_mixer_mute[4]; + bool fu05_dapm_mute; + bool fu05_mixer_l_mute; + bool fu05_mixer_r_mute; }; struct rt712_dmic_kctrl_priv { diff --git a/sound/soc/codecs/rt715-sdca-sdw.c b/sound/soc/codecs/rt715-sdca-sdw.c index c8dabb9b16b5..ce7d8955efc3 100644 --- a/sound/soc/codecs/rt715-sdca-sdw.c +++ b/sound/soc/codecs/rt715-sdca-sdw.c @@ -205,7 +205,7 @@ static const struct sdw_device_id rt715_sdca_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt715_sdca_id); -static int __maybe_unused rt715_dev_suspend(struct device *dev) +static int rt715_dev_suspend(struct device *dev) { struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); @@ -222,7 +222,7 @@ static int __maybe_unused rt715_dev_suspend(struct device *dev) #define RT715_PROBE_TIMEOUT 5000 -static int __maybe_unused rt715_dev_resume(struct device *dev) +static int rt715_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt715_sdca_priv *rt715 = dev_get_drvdata(dev); @@ -263,14 +263,14 @@ regmap_sync: } static const struct dev_pm_ops rt715_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) - SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) + RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) }; static struct sdw_driver rt715_sdw_driver = { .driver = { .name = "rt715-sdca", - .pm = &rt715_pm, + .pm = pm_ptr(&rt715_pm), }, .probe = rt715_sdca_sdw_probe, .remove = rt715_sdca_sdw_remove, diff --git a/sound/soc/codecs/rt715-sdca.c b/sound/soc/codecs/rt715-sdca.c index 7e10fd913812..7fb02654c16b 100644 --- a/sound/soc/codecs/rt715-sdca.c +++ b/sound/soc/codecs/rt715-sdca.c @@ -427,14 +427,6 @@ static int rt715_sdca_fu_info(struct snd_kcontrol *kcontrol, .private_value = RT715_SDCA_PR_VALUE(reg_base, xcount, xmax, \ xshift, xinvert)} -#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ - xhandler_get, xhandler_put) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .info = snd_soc_info_volsw, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ - xmax, xinvert) } - #define RT715_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\ xhandler_put, tlv_array, xcount, xmax) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ diff --git a/sound/soc/codecs/rt715-sdw.c b/sound/soc/codecs/rt715-sdw.c index cd702574c84b..a3df4bbedf86 100644 --- a/sound/soc/codecs/rt715-sdw.c +++ b/sound/soc/codecs/rt715-sdw.c @@ -485,7 +485,7 @@ static const struct sdw_device_id rt715_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt715_id); -static int __maybe_unused rt715_dev_suspend(struct device *dev) +static int rt715_dev_suspend(struct device *dev) { struct rt715_priv *rt715 = dev_get_drvdata(dev); @@ -499,7 +499,7 @@ static int __maybe_unused rt715_dev_suspend(struct device *dev) #define RT715_PROBE_TIMEOUT 5000 -static int __maybe_unused rt715_dev_resume(struct device *dev) +static int rt715_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt715_priv *rt715 = dev_get_drvdata(dev); @@ -530,14 +530,14 @@ regmap_sync: } static const struct dev_pm_ops rt715_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) - SET_RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt715_dev_suspend, rt715_dev_resume) + RUNTIME_PM_OPS(rt715_dev_suspend, rt715_dev_resume, NULL) }; static struct sdw_driver rt715_sdw_driver = { .driver = { .name = "rt715", - .pm = &rt715_pm, + .pm = pm_ptr(&rt715_pm), }, .probe = rt715_sdw_probe, .remove = rt715_sdw_remove, diff --git a/sound/soc/codecs/rt715.c b/sound/soc/codecs/rt715.c index 299c9b12377c..2cf461852091 100644 --- a/sound/soc/codecs/rt715.c +++ b/sound/soc/codecs/rt715.c @@ -486,14 +486,6 @@ static int rt715_vol_info(struct snd_kcontrol *kcontrol, return 0; } -#define SOC_DOUBLE_R_EXT(xname, reg_left, reg_right, xshift, xmax, xinvert,\ - xhandler_get, xhandler_put) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ - .info = snd_soc_info_volsw, \ - .get = xhandler_get, .put = xhandler_put, \ - .private_value = SOC_DOUBLE_R_VALUE(reg_left, reg_right, xshift, \ - xmax, xinvert) } - #define RT715_MAIN_SWITCH_EXT(xname, xhandler_get, xhandler_put) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \ .info = rt715_switch_info, \ diff --git a/sound/soc/codecs/rt721-sdca-sdw.c b/sound/soc/codecs/rt721-sdca-sdw.c index c71453da088a..582b47d69278 100644 --- a/sound/soc/codecs/rt721-sdca-sdw.c +++ b/sound/soc/codecs/rt721-sdca-sdw.c @@ -437,7 +437,7 @@ static const struct sdw_device_id rt721_sdca_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt721_sdca_id); -static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev) +static int rt721_sdca_dev_suspend(struct device *dev) { struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); @@ -453,7 +453,7 @@ static int __maybe_unused rt721_sdca_dev_suspend(struct device *dev) return 0; } -static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev) +static int rt721_sdca_dev_system_suspend(struct device *dev) { struct rt721_sdca_priv *rt721_sdca = dev_get_drvdata(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev); @@ -485,7 +485,7 @@ static int __maybe_unused rt721_sdca_dev_system_suspend(struct device *dev) #define RT721_PROBE_TIMEOUT 5000 -static int __maybe_unused rt721_sdca_dev_resume(struct device *dev) +static int rt721_sdca_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt721_sdca_priv *rt721 = dev_get_drvdata(dev); @@ -524,15 +524,15 @@ regmap_sync: } static const struct dev_pm_ops rt721_sdca_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume) - SET_RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt721_sdca_dev_system_suspend, rt721_sdca_dev_resume) + RUNTIME_PM_OPS(rt721_sdca_dev_suspend, rt721_sdca_dev_resume, NULL) }; static struct sdw_driver rt721_sdca_sdw_driver = { .driver = { .name = "rt721-sdca", .owner = THIS_MODULE, - .pm = &rt721_sdca_pm, + .pm = pm_ptr(&rt721_sdca_pm), }, .probe = rt721_sdca_sdw_probe, .remove = rt721_sdca_sdw_remove, diff --git a/sound/soc/codecs/rt722-sdca-sdw.c b/sound/soc/codecs/rt722-sdca-sdw.c index 4d3043627bd0..11e2e8f68a98 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.c +++ b/sound/soc/codecs/rt722-sdca-sdw.c @@ -16,7 +16,7 @@ #include "rt722-sdca.h" #include "rt722-sdca-sdw.h" -static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) +static int rt722_sdca_mbq_size(struct device *dev, unsigned int reg) { switch (reg) { case 0x2f01 ... 0x2f0a: @@ -28,36 +28,52 @@ static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) 0): case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, 0): - case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, - 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, - RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): - case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: - return true; - default: - return false; - } -} - -static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg) -{ - switch (reg) { - case 0x2f01: - case 0x2f54: - case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU03, RT722_SDCA_CTL_SELECTED_MODE, 0): - case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, - 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, - RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_L) ... + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, + RT722_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_XU0D, + RT722_SDCA_CTL_SELECTED_MODE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_MUTE, CH_L) ... + SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, + RT722_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_MUTE, CH_01) ... + SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, + RT722_SDCA_CTL_FU_MUTE, CH_04): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, + RT722_SDCA_CTL_VENDOR_DEF, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ... + SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_L) ... + SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, + RT722_SDCA_CTL_FU_MUTE, CH_R): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, + RT722_SDCA_CTL_VENDOR_DEF, CH_08): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, + RT722_SDCA_CTL_REQ_POWER_STATE, 0): + case SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, + RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0): case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: - return true; - default: - return false; - } -} - -static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int reg) -{ - switch (reg) { + return 1; case 0x2000000 ... 0x2000024: case 0x2000029 ... 0x200004a: case 0x2000051 ... 0x2000052: @@ -74,6 +90,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5600000 ... 0x5600007: case 0x5700000 ... 0x5700004: case 0x5800000 ... 0x5800004: + case 0x5810000: case 0x5b00003: case 0x5c00011: case 0x5d00006: @@ -81,6 +98,7 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re case 0x5f00030: case 0x6100000 ... 0x6100051: case 0x6100055 ... 0x6100057: + case 0x6100060: case 0x6100062: case 0x6100064 ... 0x6100065: case 0x6100067: @@ -112,15 +130,32 @@ static bool rt722_sdca_mbq_readable_register(struct device *dev, unsigned int re RT722_SDCA_CTL_FU_CH_GAIN, CH_L): case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN, CH_R): - return true; + return 2; default: - return false; + return 0; } } -static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int reg) +static struct regmap_sdw_mbq_cfg rt722_mbq_config = { + .mbq_size = rt722_sdca_mbq_size, +}; + +static bool rt722_sdca_readable_register(struct device *dev, unsigned int reg) +{ + return rt722_sdca_mbq_size(dev, reg) > 0; +} + +static bool rt722_sdca_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case 0x2f01: + case 0x2f54: + case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_GE49, RT722_SDCA_CTL_DETECTED_MODE, + 0): + case SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, RT722_SDCA_CTL_HIDTX_CURRENT_OWNER, + 0) ... SDW_SDCA_CTL(FUNC_NUM_HID, RT722_SDCA_ENT_HID01, + RT722_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0): + case RT722_BUF_ADDR_HID1 ... RT722_BUF_ADDR_HID2: case 0x2000000: case 0x200000d: case 0x2000019: @@ -139,7 +174,7 @@ static bool rt722_sdca_mbq_volatile_register(struct device *dev, unsigned int re static const struct regmap_config rt722_sdca_regmap = { .reg_bits = 32, - .val_bits = 8, + .val_bits = 16, .readable_reg = rt722_sdca_readable_register, .volatile_reg = rt722_sdca_volatile_register, .max_register = 0x44ffffff, @@ -150,20 +185,6 @@ static const struct regmap_config rt722_sdca_regmap = { .use_single_write = true, }; -static const struct regmap_config rt722_sdca_mbq_regmap = { - .name = "sdw-mbq", - .reg_bits = 32, - .val_bits = 16, - .readable_reg = rt722_sdca_mbq_readable_register, - .volatile_reg = rt722_sdca_mbq_volatile_register, - .max_register = 0x41000312, - .reg_defaults = rt722_sdca_mbq_defaults, - .num_reg_defaults = ARRAY_SIZE(rt722_sdca_mbq_defaults), - .cache_type = REGCACHE_MAPLE, - .use_single_read = true, - .use_single_write = true, -}; - static int rt722_sdca_update_status(struct sdw_slave *slave, enum sdw_slave_status status) { @@ -207,6 +228,8 @@ static int rt722_sdca_read_prop(struct sdw_slave *slave) unsigned long addr; struct sdw_dpn_prop *dpn; + sdw_slave_read_lane_mapping(slave); + prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY; prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; @@ -373,18 +396,14 @@ static const struct sdw_slave_ops rt722_sdca_slave_ops = { static int rt722_sdca_sdw_probe(struct sdw_slave *slave, const struct sdw_device_id *id) { - struct regmap *regmap, *mbq_regmap; + struct regmap *regmap; /* Regmap Initialization */ - mbq_regmap = devm_regmap_init_sdw_mbq(slave, &rt722_sdca_mbq_regmap); - if (IS_ERR(mbq_regmap)) - return PTR_ERR(mbq_regmap); - - regmap = devm_regmap_init_sdw(slave, &rt722_sdca_regmap); + regmap = devm_regmap_init_sdw_mbq_cfg(slave, &rt722_sdca_regmap, &rt722_mbq_config); if (IS_ERR(regmap)) return PTR_ERR(regmap); - return rt722_sdca_init(&slave->dev, regmap, mbq_regmap, slave); + return rt722_sdca_init(&slave->dev, regmap, slave); } static int rt722_sdca_sdw_remove(struct sdw_slave *slave) @@ -411,7 +430,7 @@ static const struct sdw_device_id rt722_sdca_id[] = { }; MODULE_DEVICE_TABLE(sdw, rt722_sdca_id); -static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev) +static int rt722_sdca_dev_suspend(struct device *dev) { struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); @@ -422,12 +441,11 @@ static int __maybe_unused rt722_sdca_dev_suspend(struct device *dev) cancel_delayed_work_sync(&rt722->jack_btn_check_work); regcache_cache_only(rt722->regmap, true); - regcache_cache_only(rt722->mbq_regmap, true); return 0; } -static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev) +static int rt722_sdca_dev_system_suspend(struct device *dev) { struct rt722_sdca_priv *rt722_sdca = dev_get_drvdata(dev); struct sdw_slave *slave = dev_to_sdw_dev(dev); @@ -459,7 +477,7 @@ static int __maybe_unused rt722_sdca_dev_system_suspend(struct device *dev) #define RT722_PROBE_TIMEOUT 5000 -static int __maybe_unused rt722_sdca_dev_resume(struct device *dev) +static int rt722_sdca_dev_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct rt722_sdca_priv *rt722 = dev_get_drvdata(dev); @@ -492,20 +510,18 @@ regmap_sync: slave->unattach_request = 0; regcache_cache_only(rt722->regmap, false); regcache_sync(rt722->regmap); - regcache_cache_only(rt722->mbq_regmap, false); - regcache_sync(rt722->mbq_regmap); return 0; } static const struct dev_pm_ops rt722_sdca_pm = { - SET_SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume) - SET_RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rt722_sdca_dev_system_suspend, rt722_sdca_dev_resume) + RUNTIME_PM_OPS(rt722_sdca_dev_suspend, rt722_sdca_dev_resume, NULL) }; static struct sdw_driver rt722_sdca_sdw_driver = { .driver = { .name = "rt722-sdca", - .pm = &rt722_sdca_pm, + .pm = pm_ptr(&rt722_sdca_pm), }, .probe = rt722_sdca_sdw_probe, .remove = rt722_sdca_sdw_remove, diff --git a/sound/soc/codecs/rt722-sdca-sdw.h b/sound/soc/codecs/rt722-sdca-sdw.h index 5b43e86f75d1..80b014456940 100644 --- a/sound/soc/codecs/rt722-sdca-sdw.h +++ b/sound/soc/codecs/rt722-sdca-sdw.h @@ -31,50 +31,9 @@ static const struct reg_default rt722_sdca_reg_defaults[] = { { 0x2f5b, 0x07 }, { 0x2f5c, 0x27 }, { 0x2f5d, 0x07 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, - 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, - 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE, - 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE, - 0), 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, - 0), 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0), - 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0), - 0x00 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), - 0x09 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R), - 0x01 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0), - 0x03 }, - { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, -}; - -static const struct reg_default rt722_sdca_mbq_defaults[] = { { 0x200003c, 0xc214 }, { 0x2000046, 0x8004 }, + { 0x5810000, 0x702d }, { 0x6100006, 0x0005 }, { 0x6100010, 0x2630 }, { 0x6100011, 0x152f }, @@ -86,27 +45,34 @@ static const struct reg_default rt722_sdca_mbq_defaults[] = { { 0x6100028, 0x2a2a }, { 0x6100029, 0x4141 }, { 0x6100055, 0x0000 }, - { 0x5810000, 0x702d }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_L), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_MUTE, CH_R), + 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU05, RT722_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_L), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_MUTE, CH_R), + 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_USER_FU0F, RT722_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE12, RT722_SDCA_CTL_REQ_POWER_STATE, + 0), 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS01, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, + 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_CS11, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, + 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PDE40, RT722_SDCA_CTL_REQ_POWER_STATE, + 0), 0x03 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN, CH_L), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT722_SDCA_ENT_PLATFORM_FU44, RT722_SDCA_CTL_FU_CH_GAIN, CH_R), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, - CH_01), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, - CH_02), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, - CH_03), 0x0000 }, - { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, - CH_04), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_02), @@ -115,10 +81,41 @@ static const struct reg_default rt722_sdca_mbq_defaults[] = { 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_FU15, RT722_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_01), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_02), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_03), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_MUTE, CH_04), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_01), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_02), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_03), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_USER_FU1E, RT722_SDCA_CTL_FU_VOLUME, + CH_04), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_PDE2A, RT722_SDCA_CTL_REQ_POWER_STATE, 0), + 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_CS1F, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, + 0), 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT722_SDCA_ENT_IT26, RT722_SDCA_CTL_VENDOR_DEF, 0), + 0x00 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_L), + 0x01 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_MUTE, CH_R), + 0x01 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_L), 0x0000 }, { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_USER_FU06, RT722_SDCA_CTL_FU_VOLUME, CH_R), 0x0000 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_PDE23, RT722_SDCA_CTL_REQ_POWER_STATE, 0), + 0x03 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_CS31, RT722_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), + 0x09 }, + { SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT_OT23, RT722_SDCA_CTL_VENDOR_DEF, 0), 0x00 }, }; #endif /* __RT722_SDW_H__ */ diff --git a/sound/soc/codecs/rt722-sdca.c b/sound/soc/codecs/rt722-sdca.c index e17a142d03b9..f093ce841b3f 100644 --- a/sound/soc/codecs/rt722-sdca.c +++ b/sound/soc/codecs/rt722-sdca.c @@ -25,11 +25,13 @@ #include "rt722-sdca.h" +#define RT722_NID_ADDR(nid, reg) ((nid) << 20 | (reg)) + int rt722_sdca_index_write(struct rt722_sdca_priv *rt722, unsigned int nid, unsigned int reg, unsigned int value) { - struct regmap *regmap = rt722->mbq_regmap; - unsigned int addr = (nid << 20) | reg; + struct regmap *regmap = rt722->regmap; + unsigned int addr = RT722_NID_ADDR(nid, reg); int ret; ret = regmap_write(regmap, addr, value); @@ -45,8 +47,8 @@ int rt722_sdca_index_read(struct rt722_sdca_priv *rt722, unsigned int nid, unsigned int reg, unsigned int *value) { int ret; - struct regmap *regmap = rt722->mbq_regmap; - unsigned int addr = (nid << 20) | reg; + struct regmap *regmap = rt722->regmap; + unsigned int addr = RT722_NID_ADDR(nid, reg); ret = regmap_read(regmap, addr, value); if (ret < 0) @@ -361,8 +363,8 @@ static int rt722_sdca_set_gain_put(struct snd_kcontrol *kcontrol, strstr(ucontrol->id.name, "FU0F Capture Volume")) adc_vol_flag = 1; - regmap_read(rt722->mbq_regmap, mc->reg, &lvalue); - regmap_read(rt722->mbq_regmap, mc->rreg, &rvalue); + regmap_read(rt722->regmap, mc->reg, &lvalue); + regmap_read(rt722->regmap, mc->rreg, &rvalue); /* L Channel */ gain_l_val = ucontrol->value.integer.value[0]; @@ -402,13 +404,13 @@ static int rt722_sdca_set_gain_put(struct snd_kcontrol *kcontrol, return 0; /* Lch*/ - regmap_write(rt722->mbq_regmap, mc->reg, gain_l_val); + regmap_write(rt722->regmap, mc->reg, gain_l_val); /* Rch */ - regmap_write(rt722->mbq_regmap, mc->rreg, gain_r_val); + regmap_write(rt722->regmap, mc->rreg, gain_r_val); - regmap_read(rt722->mbq_regmap, mc->reg, &read_l); - regmap_read(rt722->mbq_regmap, mc->rreg, &read_r); + regmap_read(rt722->regmap, mc->reg, &read_l); + regmap_read(rt722->regmap, mc->rreg, &read_r); if (read_r == gain_r_val && read_l == gain_l_val) return changed; @@ -431,8 +433,8 @@ static int rt722_sdca_set_gain_get(struct snd_kcontrol *kcontrol, strstr(ucontrol->id.name, "FU0F Capture Volume")) adc_vol_flag = 1; - regmap_read(rt722->mbq_regmap, mc->reg, &read_l); - regmap_read(rt722->mbq_regmap, mc->rreg, &read_r); + regmap_read(rt722->regmap, mc->reg, &read_l); + regmap_read(rt722->regmap, mc->rreg, &read_r); if (mc->shift == 8) /* boost gain */ ctl_l = read_l / tendB; @@ -604,7 +606,7 @@ static int rt722_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol, /* check all channels */ for (i = 0; i < p->count; i++) { - regmap_read(rt722->mbq_regmap, p->reg_base + i, ®value); + regmap_read(rt722->regmap, p->reg_base + i, ®value); if (!adc_vol_flag) /* boost gain */ ctl = regvalue / boost_step; @@ -637,7 +639,7 @@ static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, /* check all channels */ for (i = 0; i < p->count; i++) { - regmap_read(rt722->mbq_regmap, p->reg_base + i, ®value[i]); + regmap_read(rt722->regmap, p->reg_base + i, ®value[i]); gain_val[i] = ucontrol->value.integer.value[i]; if (gain_val[i] > p->max) @@ -658,7 +660,7 @@ static int rt722_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol, return 0; for (i = 0; i < p->count; i++) { - err = regmap_write(rt722->mbq_regmap, p->reg_base + i, gain_val[i]); + err = regmap_write(rt722->regmap, p->reg_base + i, gain_val[i]); if (err < 0) dev_err(&rt722->slave->dev, "%s: %#08x can't be set\n", __func__, p->reg_base + i); @@ -739,77 +741,6 @@ static const struct snd_kcontrol_new rt722_sdca_controls[] = { 4, 3, boost_vol_tlv), }; -static int rt722_sdca_adc_mux_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); - struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); - unsigned int val = 0, mask_sft; - - if (strstr(ucontrol->id.name, "ADC 22 Mux")) - mask_sft = 12; - else if (strstr(ucontrol->id.name, "ADC 24 Mux")) - mask_sft = 4; - else if (strstr(ucontrol->id.name, "ADC 25 Mux")) - mask_sft = 0; - else - return -EINVAL; - - rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL, - RT722_HDA_LEGACY_MUX_CTL0, &val); - - ucontrol->value.enumerated.item[0] = (val >> mask_sft) & 0x7; - - return 0; -} - -static int rt722_sdca_adc_mux_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = - snd_soc_dapm_kcontrol_component(kcontrol); - struct snd_soc_dapm_context *dapm = - snd_soc_dapm_kcontrol_dapm(kcontrol); - struct rt722_sdca_priv *rt722 = snd_soc_component_get_drvdata(component); - struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; - unsigned int *item = ucontrol->value.enumerated.item; - unsigned int val, val2 = 0, change, mask_sft; - - if (item[0] >= e->items) - return -EINVAL; - - if (strstr(ucontrol->id.name, "ADC 22 Mux")) - mask_sft = 12; - else if (strstr(ucontrol->id.name, "ADC 24 Mux")) - mask_sft = 4; - else if (strstr(ucontrol->id.name, "ADC 25 Mux")) - mask_sft = 0; - else - return -EINVAL; - - val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l; - - rt722_sdca_index_read(rt722, RT722_VENDOR_HDA_CTL, - RT722_HDA_LEGACY_MUX_CTL0, &val2); - val2 = (0x7 << mask_sft) & val2; - - if (val == val2) - change = 0; - else - change = 1; - - if (change) - rt722_sdca_index_update_bits(rt722, RT722_VENDOR_HDA_CTL, - RT722_HDA_LEGACY_MUX_CTL0, 0x7 << mask_sft, - val << mask_sft); - - snd_soc_dapm_mux_update_power(dapm, kcontrol, - item[0], e, NULL); - - return change; -} - static const char * const adc22_mux_text[] = { "MIC2", "LINE1", @@ -821,26 +752,26 @@ static const char * const adc07_10_mux_text[] = { "DMIC2", }; -static SOC_ENUM_SINGLE_DECL( - rt722_adc22_enum, SND_SOC_NOPM, 0, adc22_mux_text); +static SOC_ENUM_SINGLE_DECL(rt722_adc22_enum, + RT722_NID_ADDR(RT722_VENDOR_HDA_CTL, RT722_HDA_LEGACY_MUX_CTL0), + 12, adc22_mux_text); -static SOC_ENUM_SINGLE_DECL( - rt722_adc24_enum, SND_SOC_NOPM, 0, adc07_10_mux_text); +static SOC_ENUM_SINGLE_DECL(rt722_adc24_enum, + RT722_NID_ADDR(RT722_VENDOR_HDA_CTL, RT722_HDA_LEGACY_MUX_CTL0), + 4, adc07_10_mux_text); -static SOC_ENUM_SINGLE_DECL( - rt722_adc25_enum, SND_SOC_NOPM, 0, adc07_10_mux_text); +static SOC_ENUM_SINGLE_DECL(rt722_adc25_enum, + RT722_NID_ADDR(RT722_VENDOR_HDA_CTL, RT722_HDA_LEGACY_MUX_CTL0), + 0, adc07_10_mux_text); static const struct snd_kcontrol_new rt722_sdca_adc22_mux = - SOC_DAPM_ENUM_EXT("ADC 22 Mux", rt722_adc22_enum, - rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put); + SOC_DAPM_ENUM("ADC 22 Mux", rt722_adc22_enum); static const struct snd_kcontrol_new rt722_sdca_adc24_mux = - SOC_DAPM_ENUM_EXT("ADC 24 Mux", rt722_adc24_enum, - rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put); + SOC_DAPM_ENUM("ADC 24 Mux", rt722_adc24_enum); static const struct snd_kcontrol_new rt722_sdca_adc25_mux = - SOC_DAPM_ENUM_EXT("ADC 25 Mux", rt722_adc25_enum, - rt722_sdca_adc_mux_get, rt722_sdca_adc_mux_put); + SOC_DAPM_ENUM("ADC 25 Mux", rt722_adc25_enum); static int rt722_sdca_fu42_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) @@ -1335,8 +1266,7 @@ static struct snd_soc_dai_driver rt722_sdca_dai[] = { } }; -int rt722_sdca_init(struct device *dev, struct regmap *regmap, - struct regmap *mbq_regmap, struct sdw_slave *slave) +int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave) { struct rt722_sdca_priv *rt722; @@ -1347,7 +1277,6 @@ int rt722_sdca_init(struct device *dev, struct regmap *regmap, dev_set_drvdata(dev, rt722); rt722->slave = slave; rt722->regmap = regmap; - rt722->mbq_regmap = mbq_regmap; mutex_init(&rt722->calibrate_mutex); mutex_init(&rt722->disable_irq_lock); @@ -1521,8 +1450,6 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt722->first_hw_init) { regcache_cache_only(rt722->regmap, false); regcache_cache_bypass(rt722->regmap, true); - regcache_cache_only(rt722->mbq_regmap, false); - regcache_cache_bypass(rt722->mbq_regmap, true); } else { /* * PM runtime is only enabled when a Slave reports as Attached @@ -1550,8 +1477,6 @@ int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave) if (rt722->first_hw_init) { regcache_cache_bypass(rt722->regmap, false); regcache_mark_dirty(rt722->regmap); - regcache_cache_bypass(rt722->mbq_regmap, false); - regcache_mark_dirty(rt722->mbq_regmap); } else rt722->first_hw_init = true; diff --git a/sound/soc/codecs/rt722-sdca.h b/sound/soc/codecs/rt722-sdca.h index 2464361a7958..04c3b4232ef3 100644 --- a/sound/soc/codecs/rt722-sdca.h +++ b/sound/soc/codecs/rt722-sdca.h @@ -17,7 +17,6 @@ struct rt722_sdca_priv { struct regmap *regmap; - struct regmap *mbq_regmap; struct snd_soc_component *component; struct sdw_slave *slave; struct sdw_bus_params params; @@ -229,8 +228,7 @@ enum rt722_sdca_jd_src { }; int rt722_sdca_io_init(struct device *dev, struct sdw_slave *slave); -int rt722_sdca_init(struct device *dev, struct regmap *regmap, - struct regmap *mbq_regmap, struct sdw_slave *slave); +int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave *slave); int rt722_sdca_index_write(struct rt722_sdca_priv *rt722, unsigned int nid, unsigned int reg, unsigned int value); int rt722_sdca_index_read(struct rt722_sdca_priv *rt722, diff --git a/sound/soc/codecs/rt9120.c b/sound/soc/codecs/rt9120.c index 733a7d130a95..97f56af25577 100644 --- a/sound/soc/codecs/rt9120.c +++ b/sound/soc/codecs/rt9120.c @@ -590,7 +590,7 @@ static void rt9120_remove(struct i2c_client *i2c) pm_runtime_set_suspended(&i2c->dev); } -static int __maybe_unused rt9120_runtime_suspend(struct device *dev) +static int rt9120_runtime_suspend(struct device *dev) { struct rt9120_data *data = dev_get_drvdata(dev); @@ -603,7 +603,7 @@ static int __maybe_unused rt9120_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused rt9120_runtime_resume(struct device *dev) +static int rt9120_runtime_resume(struct device *dev) { struct rt9120_data *data = dev_get_drvdata(dev); @@ -618,7 +618,7 @@ static int __maybe_unused rt9120_runtime_resume(struct device *dev) } static const struct dev_pm_ops rt9120_pm_ops = { - SET_RUNTIME_PM_OPS(rt9120_runtime_suspend, rt9120_runtime_resume, NULL) + RUNTIME_PM_OPS(rt9120_runtime_suspend, rt9120_runtime_resume, NULL) }; static const struct of_device_id __maybe_unused rt9120_device_table[] = { @@ -631,7 +631,7 @@ static struct i2c_driver rt9120_driver = { .driver = { .name = "rt9120", .of_match_table = rt9120_device_table, - .pm = &rt9120_pm_ops, + .pm = pm_ptr(&rt9120_pm_ops), }, .probe = rt9120_probe, .remove = rt9120_remove, diff --git a/sound/soc/codecs/rtq9128.c b/sound/soc/codecs/rtq9128.c index aa3eadecd974..391cc03d687f 100644 --- a/sound/soc/codecs/rtq9128.c +++ b/sound/soc/codecs/rtq9128.c @@ -729,7 +729,7 @@ static int rtq9128_probe(struct i2c_client *i2c) return devm_snd_soc_register_component(dev, &rtq9128_comp_driver, &rtq9128_dai, 1); } -static int __maybe_unused rtq9128_pm_runtime_suspend(struct device *dev) +static int rtq9128_pm_runtime_suspend(struct device *dev) { struct rtq9128_data *data = dev_get_drvdata(dev); struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -746,7 +746,7 @@ static int __maybe_unused rtq9128_pm_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused rtq9128_pm_runtime_resume(struct device *dev) +static int rtq9128_pm_runtime_resume(struct device *dev) { struct rtq9128_data *data = dev_get_drvdata(dev); struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -764,8 +764,8 @@ static int __maybe_unused rtq9128_pm_runtime_resume(struct device *dev) return regcache_sync(regmap); } -static const struct dev_pm_ops __maybe_unused rtq9128_pm_ops = { - SET_RUNTIME_PM_OPS(rtq9128_pm_runtime_suspend, rtq9128_pm_runtime_resume, NULL) +static const struct dev_pm_ops rtq9128_pm_ops = { + RUNTIME_PM_OPS(rtq9128_pm_runtime_suspend, rtq9128_pm_runtime_resume, NULL) }; static const struct of_device_id rtq9128_device_table[] = { diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index 7aa89e34657e..2cc8efe3d896 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -806,9 +806,9 @@ static int sgtl5000_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) * - clock and frame master */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: i2sctl |= SGTL5000_I2S_MASTER; sgtl5000->master = 1; break; diff --git a/sound/soc/codecs/sma1307.c b/sound/soc/codecs/sma1307.c index 480bcea48541..f5c303d4bb62 100644 --- a/sound/soc/codecs/sma1307.c +++ b/sound/soc/codecs/sma1307.c @@ -1019,14 +1019,9 @@ static const struct snd_kcontrol_new sma1307_aif_out1_source_control = { .private_value = (unsigned long)&sma1307_aif_out_source_enum }; -static const struct snd_kcontrol_new sma1307_sdo_control = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Switch", - .info = snd_soc_info_volsw, - .get = sma1307_dapm_sdo_enable_get, - .put = sma1307_dapm_sdo_enable_put, - .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, 0, 1, 0, 0) -}; +static const struct snd_kcontrol_new sma1307_sdo_control = + SOC_SINGLE_EXT("Switch", SND_SOC_NOPM, 0, 1, 0, + sma1307_dapm_sdo_enable_get, sma1307_dapm_sdo_enable_put); static const struct snd_kcontrol_new sma1307_enable_control = SOC_DAPM_SINGLE("Switch", SMA1307_00_SYSTEM_CTRL, 0, 1, 0); @@ -1728,6 +1723,11 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil } data = kzalloc(fw->size, GFP_KERNEL); + if (!data) { + release_firmware(fw); + sma1307->set.status = false; + return; + } size = fw->size >> 2; memcpy(data, fw->data, fw->size); @@ -1741,6 +1741,12 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil sma1307->set.header = devm_kzalloc(sma1307->dev, sma1307->set.header_size, GFP_KERNEL); + if (!sma1307->set.header) { + kfree(data); + sma1307->set.status = false; + return; + } + memcpy(sma1307->set.header, data, sma1307->set.header_size * sizeof(int)); @@ -1756,6 +1762,13 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil sma1307->set.def = devm_kzalloc(sma1307->dev, sma1307->set.def_size * sizeof(int), GFP_KERNEL); + if (!sma1307->set.def) { + kfree(data); + kfree(sma1307->set.header); + sma1307->set.status = false; + return; + } + memcpy(sma1307->set.def, &data[sma1307->set.header_size], sma1307->set.def_size * sizeof(int)); @@ -1768,6 +1781,16 @@ static void sma1307_setting_loaded(struct sma1307_priv *sma1307, const char *fil = devm_kzalloc(sma1307->dev, sma1307->set.mode_size * 2 * sizeof(int), GFP_KERNEL); + if (!sma1307->set.mode_set[i]) { + kfree(data); + kfree(sma1307->set.header); + kfree(sma1307->set.def); + for (int j = 0; j < i; j++) + kfree(sma1307->set.mode_set[j]); + sma1307->set.status = false; + return; + } + for (int j = 0; j < sma1307->set.mode_size; j++) { sma1307->set.mode_set[i][2 * j] = data[offset + ((num_mode + 1) * j)]; diff --git a/sound/soc/codecs/src4xxx.c b/sound/soc/codecs/src4xxx.c index db4e280dd055..5a3489475225 100644 --- a/sound/soc/codecs/src4xxx.c +++ b/sound/soc/codecs/src4xxx.c @@ -158,11 +158,11 @@ static int src4xxx_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int ctrl; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ctrl = SRC4XXX_BUS_MASTER; src4xxx->master[dai->id] = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: ctrl = 0; src4xxx->master[dai->id] = false; break; diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 684d52ec6600..b56dd279d90a 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -138,7 +138,6 @@ static const struct snd_soc_dapm_route tas2552_audio_map[] = { {"ASI OUT", NULL, "DMIC"} }; -#ifdef CONFIG_PM static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown) { u8 cfg1_reg = 0; @@ -152,7 +151,6 @@ static void tas2552_sw_shutdown(struct tas2552_data *tas2552, int sw_shutdown) snd_soc_component_update_bits(tas2552->component, TAS2552_CFG_1, TAS2552_SWS, cfg1_reg); } -#endif static int tas2552_setup_pll(struct snd_soc_component *component, struct snd_pcm_hw_params *params) @@ -480,7 +478,6 @@ static int tas2552_mute(struct snd_soc_dai *dai, int mute, int direction) return 0; } -#ifdef CONFIG_PM static int tas2552_runtime_suspend(struct device *dev) { struct tas2552_data *tas2552 = dev_get_drvdata(dev); @@ -508,11 +505,9 @@ static int tas2552_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops tas2552_pm = { - SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume, - NULL) + RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume, NULL) }; static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = { @@ -768,7 +763,7 @@ static struct i2c_driver tas2552_i2c_driver = { .driver = { .name = "tas2552", .of_match_table = of_match_ptr(tas2552_of_match), - .pm = &tas2552_pm, + .pm = pm_ptr(&tas2552_pm), }, .probe = tas2552_probe, .remove = tas2552_i2c_remove, diff --git a/sound/soc/codecs/tas2562.c b/sound/soc/codecs/tas2562.c index fef7ce39f664..8e00dcc09d0c 100644 --- a/sound/soc/codecs/tas2562.c +++ b/sound/soc/codecs/tas2562.c @@ -513,17 +513,9 @@ static const struct snd_kcontrol_new vsense_switch = static const struct snd_kcontrol_new tas2562_snd_controls[] = { SOC_SINGLE_TLV("Amp Gain Volume", TAS2562_PB_CFG1, 1, 0x1c, 0, tas2562_dac_tlv), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Volume Control", - .index = 0, - .tlv.p = dvc_tlv, - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_soc_info_volsw, - .get = tas2562_volume_control_get, - .put = tas2562_volume_control_put, - .private_value = SOC_SINGLE_VALUE(TAS2562_DVC_CFG1, 0, 110, 0, 0), - }, + SOC_SINGLE_EXT_TLV("Digital Volume Control", TAS2562_DVC_CFG1, 0, 110, 0, + tas2562_volume_control_get, tas2562_volume_control_put, + dvc_tlv), }; static const struct snd_soc_dapm_widget tas2110_dapm_widgets[] = { diff --git a/sound/soc/codecs/tas2764.c b/sound/soc/codecs/tas2764.c index 58315eab492a..08aa7ee34256 100644 --- a/sound/soc/codecs/tas2764.c +++ b/sound/soc/codecs/tas2764.c @@ -14,6 +14,7 @@ #include <linux/regulator/consumer.h> #include <linux/regmap.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/slab.h> #include <sound/soc.h> #include <sound/pcm.h> @@ -23,6 +24,11 @@ #include "tas2764.h" +enum tas2764_devid { + DEVID_TAS2764 = 0, + DEVID_SN012776 = 1 +}; + struct tas2764_priv { struct snd_soc_component *component; struct gpio_desc *reset_gpio; @@ -30,7 +36,8 @@ struct tas2764_priv { struct regmap *regmap; struct device *dev; int irq; - + enum tas2764_devid devid; + int v_sense_slot; int i_sense_slot; @@ -142,6 +149,8 @@ static int tas2764_codec_suspend(struct snd_soc_component *component) regcache_cache_only(tas2764->regmap, true); regcache_mark_dirty(tas2764->regmap); + usleep_range(6000, 7000); + return 0; } @@ -180,33 +189,6 @@ static SOC_ENUM_SINGLE_DECL( static const struct snd_kcontrol_new tas2764_asi1_mux = SOC_DAPM_ENUM("ASI1 Source", tas2764_ASI1_src_enum); -static int tas2764_dac_event(struct snd_soc_dapm_widget *w, - struct snd_kcontrol *kcontrol, int event) -{ - struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); - struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - int ret; - - switch (event) { - case SND_SOC_DAPM_POST_PMU: - tas2764->dac_powered = true; - ret = tas2764_update_pwr_ctrl(tas2764); - break; - case SND_SOC_DAPM_PRE_PMD: - tas2764->dac_powered = false; - ret = tas2764_update_pwr_ctrl(tas2764); - break; - default: - dev_err(tas2764->dev, "Unsupported event\n"); - return -EINVAL; - } - - if (ret < 0) - return ret; - - return 0; -} - static const struct snd_kcontrol_new isense_switch = SOC_DAPM_SINGLE("Switch", TAS2764_PWR_CTRL, TAS2764_ISENSE_POWER_EN, 1, 1); static const struct snd_kcontrol_new vsense_switch = @@ -219,8 +201,7 @@ static const struct snd_soc_dapm_widget tas2764_dapm_widgets[] = { 1, &isense_switch), SND_SOC_DAPM_SWITCH("VSENSE", TAS2764_PWR_CTRL, TAS2764_VSENSE_POWER_EN, 1, &vsense_switch), - SND_SOC_DAPM_DAC_E("DAC", NULL, SND_SOC_NOPM, 0, 0, tas2764_dac_event, - SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_OUTPUT("OUT"), SND_SOC_DAPM_SIGGEN("VMON"), SND_SOC_DAPM_SIGGEN("IMON") @@ -241,9 +222,34 @@ static int tas2764_mute(struct snd_soc_dai *dai, int mute, int direction) { struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(dai->component); + int ret; + + if (!mute) { + tas2764->dac_powered = true; + ret = tas2764_update_pwr_ctrl(tas2764); + if (ret) + return ret; + } tas2764->unmuted = !mute; - return tas2764_update_pwr_ctrl(tas2764); + ret = tas2764_update_pwr_ctrl(tas2764); + if (ret) + return ret; + + if (mute) { + /* Wait for ramp-down */ + usleep_range(6000, 7000); + + tas2764->dac_powered = false; + ret = tas2764_update_pwr_ctrl(tas2764); + if (ret) + return ret; + + /* Wait a bit after shutdown */ + usleep_range(2000, 3000); + } + + return 0; } static int tas2764_set_bitwidth(struct tas2764_priv *tas2764, int bitwidth) @@ -534,10 +540,16 @@ static struct snd_soc_dai_driver tas2764_dai_driver[] = { }, }; +static uint8_t sn012776_bop_presets[] = { + 0x01, 0x32, 0x02, 0x22, 0x83, 0x2d, 0x80, 0x02, 0x06, + 0x32, 0x46, 0x30, 0x02, 0x06, 0x38, 0x40, 0x30, 0x02, + 0x06, 0x3e, 0x37, 0x30, 0xff, 0xe6 +}; + static int tas2764_codec_probe(struct snd_soc_component *component) { struct tas2764_priv *tas2764 = snd_soc_component_get_drvdata(component); - int ret; + int ret, i; tas2764->component = component; @@ -586,6 +598,27 @@ static int tas2764_codec_probe(struct snd_soc_component *component) if (ret < 0) return ret; + switch (tas2764->devid) { + case DEVID_SN012776: + ret = snd_soc_component_update_bits(component, TAS2764_PWR_CTRL, + TAS2764_PWR_CTRL_BOP_SRC, + TAS2764_PWR_CTRL_BOP_SRC); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(sn012776_bop_presets); i++) { + ret = snd_soc_component_write(component, + TAS2764_BOP_CFG0 + i, + sn012776_bop_presets[i]); + + if (ret < 0) + return ret; + } + break; + default: + break; + } + return 0; } @@ -601,12 +634,21 @@ static SOC_ENUM_SINGLE_DECL( tas2764_hpf_enum, TAS2764_DC_BLK0, TAS2764_DC_BLK0_HPF_FREQ_PB_SHIFT, tas2764_hpf_texts); +static const char * const tas2764_oce_texts[] = { + "Disable", "Retry", +}; + +static SOC_ENUM_SINGLE_DECL( + tas2764_oce_enum, TAS2764_MISC_CFG1, + TAS2764_MISC_CFG1_OCE_RETRY_SHIFT, tas2764_oce_texts); + static const struct snd_kcontrol_new tas2764_snd_controls[] = { SOC_SINGLE_TLV("Speaker Volume", TAS2764_DVC, 0, TAS2764_DVC_MAX, 1, tas2764_playback_volume), SOC_SINGLE_TLV("Amp Gain Volume", TAS2764_CHNL_0, 1, 0x14, 0, tas2764_digital_tlv), SOC_ENUM("HPF Corner Frequency", tas2764_hpf_enum), + SOC_ENUM("OCE Handling", tas2764_oce_enum), }; static const struct snd_soc_component_driver soc_component_driver_tas2764 = { @@ -634,6 +676,7 @@ static const struct reg_default tas2764_reg_defaults[] = { { TAS2764_TDM_CFG2, 0x0a }, { TAS2764_TDM_CFG3, 0x10 }, { TAS2764_TDM_CFG5, 0x42 }, + { TAS2764_INT_CLK_CFG, 0x19 }, }; static const struct regmap_range_cfg tas2764_regmap_ranges[] = { @@ -651,6 +694,7 @@ static const struct regmap_range_cfg tas2764_regmap_ranges[] = { static bool tas2764_volatile_register(struct device *dev, unsigned int reg) { switch (reg) { + case TAS2764_SW_RST: case TAS2764_INT_LTCH0 ... TAS2764_INT_LTCH4: case TAS2764_INT_CLK_CFG: return true; @@ -715,6 +759,8 @@ static int tas2764_i2c_probe(struct i2c_client *client) if (!tas2764) return -ENOMEM; + tas2764->devid = (enum tas2764_devid)of_device_get_match_data(&client->dev); + tas2764->dev = &client->dev; tas2764->irq = client->irq; i2c_set_clientdata(client, tas2764); @@ -751,7 +797,8 @@ MODULE_DEVICE_TABLE(i2c, tas2764_i2c_id); #if defined(CONFIG_OF) static const struct of_device_id tas2764_of_match[] = { - { .compatible = "ti,tas2764" }, + { .compatible = "ti,tas2764", .data = (void *)DEVID_TAS2764 }, + { .compatible = "ti,sn012776", .data = (void *)DEVID_SN012776 }, {}, }; MODULE_DEVICE_TABLE(of, tas2764_of_match); diff --git a/sound/soc/codecs/tas2764.h b/sound/soc/codecs/tas2764.h index 9490f2686e38..3251dc0106e0 100644 --- a/sound/soc/codecs/tas2764.h +++ b/sound/soc/codecs/tas2764.h @@ -29,6 +29,7 @@ #define TAS2764_PWR_CTRL_ACTIVE 0x0 #define TAS2764_PWR_CTRL_MUTE BIT(0) #define TAS2764_PWR_CTRL_SHUTDOWN BIT(1) +#define TAS2764_PWR_CTRL_BOP_SRC BIT(7) #define TAS2764_VSENSE_POWER_EN 3 #define TAS2764_ISENSE_POWER_EN 4 @@ -43,6 +44,10 @@ #define TAS2764_CHNL_0 TAS2764_REG(0X0, 0x03) +/* Miscellaneous */ +#define TAS2764_MISC_CFG1 TAS2764_REG(0x0, 0x06) +#define TAS2764_MISC_CFG1_OCE_RETRY_SHIFT 5 + /* TDM Configuration Reg0 */ #define TAS2764_TDM_CFG0 TAS2764_REG(0X0, 0x08) #define TAS2764_TDM_CFG0_SMP_MASK BIT(5) @@ -116,4 +121,6 @@ #define TAS2764_INT_CLK_CFG TAS2764_REG(0x0, 0x5c) #define TAS2764_INT_CLK_CFG_IRQZ_CLR BIT(2) +#define TAS2764_BOP_CFG0 TAS2764_REG(0X0, 0x1d) + #endif /* __TAS2764__ */ diff --git a/sound/soc/codecs/tas2770.c b/sound/soc/codecs/tas2770.c index 863c3f672ba9..7f219df8be70 100644 --- a/sound/soc/codecs/tas2770.c +++ b/sound/soc/codecs/tas2770.c @@ -189,6 +189,31 @@ static int tas2770_mute(struct snd_soc_dai *dai, int mute, int direction) return tas2770_update_pwr_ctrl(tas2770); } +static int tas2770_set_ivsense_transmit(struct tas2770_priv *tas2770, + int i_slot, int v_slot) +{ + struct snd_soc_component *component = tas2770->component; + int ret; + + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG5, + TAS2770_TDM_CFG_REG5_VSNS_MASK | + TAS2770_TDM_CFG_REG5_50_MASK, + TAS2770_TDM_CFG_REG5_VSNS_ENABLE | + v_slot); + if (ret < 0) + return ret; + + ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG6, + TAS2770_TDM_CFG_REG6_ISNS_MASK | + TAS2770_TDM_CFG_REG6_50_MASK, + TAS2770_TDM_CFG_REG6_ISNS_ENABLE | + i_slot); + if (ret < 0) + return ret; + + return 0; +} + static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) { int ret; @@ -199,19 +224,16 @@ static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, TAS2770_TDM_CFG_REG2_RXW_MASK, TAS2770_TDM_CFG_REG2_RXW_16BITS); - tas2770->v_sense_slot = tas2770->i_sense_slot + 2; break; case SNDRV_PCM_FORMAT_S24_LE: ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, TAS2770_TDM_CFG_REG2_RXW_MASK, TAS2770_TDM_CFG_REG2_RXW_24BITS); - tas2770->v_sense_slot = tas2770->i_sense_slot + 4; break; case SNDRV_PCM_FORMAT_S32_LE: ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG2, TAS2770_TDM_CFG_REG2_RXW_MASK, TAS2770_TDM_CFG_REG2_RXW_32BITS); - tas2770->v_sense_slot = tas2770->i_sense_slot + 4; break; default: @@ -221,22 +243,6 @@ static int tas2770_set_bitwidth(struct tas2770_priv *tas2770, int bitwidth) if (ret < 0) return ret; - ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG5, - TAS2770_TDM_CFG_REG5_VSNS_MASK | - TAS2770_TDM_CFG_REG5_50_MASK, - TAS2770_TDM_CFG_REG5_VSNS_ENABLE | - tas2770->v_sense_slot); - if (ret < 0) - return ret; - - ret = snd_soc_component_update_bits(component, TAS2770_TDM_CFG_REG6, - TAS2770_TDM_CFG_REG6_ISNS_MASK | - TAS2770_TDM_CFG_REG6_50_MASK, - TAS2770_TDM_CFG_REG6_ISNS_ENABLE | - tas2770->i_sense_slot); - if (ret < 0) - return ret; - return 0; } @@ -491,6 +497,7 @@ static int tas2770_codec_probe(struct snd_soc_component *component) { struct tas2770_priv *tas2770 = snd_soc_component_get_drvdata(component); + int ret; tas2770->component = component; @@ -502,6 +509,14 @@ static int tas2770_codec_probe(struct snd_soc_component *component) tas2770_reset(tas2770); regmap_reinit_cache(tas2770->regmap, &tas2770_i2c_regmap); + if (tas2770->i_sense_slot != -1 && tas2770->v_sense_slot != -1) { + ret = tas2770_set_ivsense_transmit(tas2770, tas2770->i_sense_slot, + tas2770->v_sense_slot); + + if (ret < 0) + return ret; + } + return 0; } @@ -629,7 +644,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770) dev_info(tas2770->dev, "Property %s is missing setting default slot\n", "ti,imon-slot-no"); - tas2770->i_sense_slot = 0; + tas2770->i_sense_slot = -1; } rc = fwnode_property_read_u32(dev->fwnode, "ti,vmon-slot-no", @@ -638,7 +653,7 @@ static int tas2770_parse_dt(struct device *dev, struct tas2770_priv *tas2770) dev_info(tas2770->dev, "Property %s is missing setting default slot\n", "ti,vmon-slot-no"); - tas2770->v_sense_slot = 2; + tas2770->v_sense_slot = -1; } tas2770->sdz_gpio = devm_gpiod_get_optional(dev, "shutdown", GPIOD_OUT_HIGH); diff --git a/sound/soc/codecs/tas2781-fmwlib.c b/sound/soc/codecs/tas2781-fmwlib.c index 61d9c220b6a4..13a197468193 100644 --- a/sound/soc/codecs/tas2781-fmwlib.c +++ b/sound/soc/codecs/tas2781-fmwlib.c @@ -2,9 +2,10 @@ // // tas2781-fmwlib.c -- TASDEVICE firmware support // -// Copyright 2023 - 2024 Texas Instruments, Inc. +// Copyright 2023 - 2025 Texas Instruments, Inc. // // Author: Shenghao Ding <shenghao-ding@ti.com> +// Author: Baojun Xu <baojun.xu@ti.com> #include <linux/crc8.h> #include <linux/firmware.h> @@ -389,10 +390,10 @@ static unsigned char map_dev_idx(struct tasdevice_fw *tas_fmw, int i, n = ARRAY_SIZE(non_ppc3_mapping_table); unsigned char dev_idx = 0; - if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781) { + if (fw_fixed_hdr->ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) { p = (struct blktyp_devidx_map *)ppc3_tas2781_mapping_table; n = ARRAY_SIZE(ppc3_tas2781_mapping_table); - } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION) { + } else if (fw_fixed_hdr->ppcver >= PPC3_VERSION_BASE) { p = (struct blktyp_devidx_map *)ppc3_mapping_table; n = ARRAY_SIZE(ppc3_mapping_table); } @@ -559,6 +560,124 @@ out: return offset; } +static void fct_param_address_parser(struct cali_reg *r, + struct tasdevice_fw *tas_fmw, const unsigned char *data) +{ + struct fct_param_address *p = &tas_fmw->fct_par_addr; + unsigned int i; + + /* + * Calibration parameters locations and data schema in dsp firmware. + * The number of items are flexible, but not more than 20. The dsp tool + * will reseve 20*24-byte space for fct params. In some cases, the + * number of fct param is less than 20, the data will be saved from the + * beginning, the rest part will be stuffed with zero. + * + * fct_param_num (not more than 20) + * for (i = 0; i < fct_param_num; i++) { + * Alias of fct param (20 bytes) + * Book (1 byte) + * Page (1 byte) + * Offset (1 byte) + * CoeffLength (1 byte) = 0x1 + * } + * if (20 - fct_param_num) + * 24*(20 - fct_param_num) pieces of '0' as stuffing + * + * As follow: + * umg_SsmKEGCye = Book, Page, Offset, CoeffLength + * iks_E0 = Book, Page, Offset, CoeffLength + * yep_LsqM0 = Book, Page, Offset, CoeffLength + * oyz_U0_ujx = Book, Page, Offset, CoeffLength + * iks_GC_GMgq = Book, Page, Offset, CoeffLength + * gou_Yao = Book, Page, Offset, CoeffLength + * kgd_Wsc_Qsbp = Book, Page, Offset, CoeffLength + * yec_CqseSsqs = Book, Page, Offset, CoeffLength + * iks_SogkGgog2 = Book, Page, Offset, CoeffLength + * yec_Sae_Y = Book, Page, Offset, CoeffLength + * Re_Int = Book, Page, Offset, CoeffLength + * SigFlag = Book, Page, Offset, CoeffLength + * a1_Int = Book, Page, Offset, CoeffLength + * a2_Int = Book, Page, Offset, CoeffLength + */ + for (i = 0; i < 20; i++) { + const unsigned char *dat = &data[24 * i]; + + /* + * check whether current fct param is empty. + */ + if (dat[23] != 1) + break; + + if (!strncmp(dat, "umg_SsmKEGCye", 20)) + r->pow_reg = TASDEVICE_REG(dat[20], dat[21], dat[22]); + /* high 32-bit of real-time spk impedance */ + else if (!strncmp(dat, "iks_E0", 20)) + r->r0_reg = TASDEVICE_REG(dat[20], dat[21], dat[22]); + /* inverse of real-time spk impedance */ + else if (!strncmp(dat, "yep_LsqM0", 20)) + r->invr0_reg = + TASDEVICE_REG(dat[20], dat[21], dat[22]); + /* low 32-bit of real-time spk impedance */ + else if (!strncmp(dat, "oyz_U0_ujx", 20)) + r->r0_low_reg = + TASDEVICE_REG(dat[20], dat[21], dat[22]); + /* Delta Thermal Limit */ + else if (!strncmp(dat, "iks_GC_GMgq", 20)) + r->tlimit_reg = + TASDEVICE_REG(dat[20], dat[21], dat[22]); + /* Thermal data for PG 1.0 device */ + else if (!strncmp(dat, "gou_Yao", 20)) + memcpy(p->thr, &dat[20], 3); + /* Pilot tone enable flag, usually the sine wave */ + else if (!strncmp(dat, "kgd_Wsc_Qsbp", 20)) + memcpy(p->plt_flg, &dat[20], 3); + /* Pilot tone gain for calibration */ + else if (!strncmp(dat, "yec_CqseSsqs", 20)) + memcpy(p->sin_gn, &dat[20], 3); + /* Pilot tone gain for calibration, useless in PG 2.0 */ + else if (!strncmp(dat, "iks_SogkGgog2", 20)) + memcpy(p->sin_gn2, &dat[20], 3); + /* Thermal data for PG 2.0 device */ + else if (!strncmp(dat, "yec_Sae_Y", 20)) + memcpy(p->thr2, &dat[20], 3); + /* Spk Equivalent Resistance in fixed-point format */ + else if (!strncmp(dat, "Re_Int", 20)) + memcpy(p->r0_reg, &dat[20], 3); + /* Check whether the spk connection is open */ + else if (!strncmp(dat, "SigFlag", 20)) + memcpy(p->tf_reg, &dat[20], 3); + /* check spk resonant frequency */ + else if (!strncmp(dat, "a1_Int", 20)) + memcpy(p->a1_reg, &dat[20], 3); + /* check spk resonant frequency */ + else if (!strncmp(dat, "a2_Int", 20)) + memcpy(p->a2_reg, &dat[20], 3); + } +} + +static int fw_parse_fct_param_address(struct tasdevice_priv *tas_priv, + struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) +{ + struct calidata *cali_data = &tas_priv->cali_data; + struct cali_reg *r = &cali_data->cali_reg_array; + const unsigned char *data = fmw->data; + + if (offset + 520 > fmw->size) { + dev_err(tas_priv->dev, "%s: File Size error\n", __func__); + return -EINVAL; + } + + /* skip reserved part */ + offset += 40; + + fct_param_address_parser(r, tas_fmw, &data[offset]); + + offset += 480; + + return offset; +} + static int fw_parse_variable_header_kernel( struct tasdevice_priv *tas_priv, const struct firmware *fmw, int offset) @@ -1496,7 +1615,7 @@ static int tasdev_block_chksum(struct tasdevice_priv *tas_priv, unsigned int nr_value; int ret; - ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_I2CChecksum, + ret = tasdevice_dev_read(tas_priv, chn, TASDEVICE_CHECKSUM_REG, &nr_value); if (ret < 0) { dev_err(tas_priv->dev, "%s: Chn %d\n", __func__, chn); @@ -1540,7 +1659,7 @@ static int tasdev_load_blk(struct tasdevice_priv *tas_priv, while (block->nr_retry > 0) { if (block->is_pchksum_present) { ret = tasdevice_dev_write(tas_priv, chn, - TASDEVICE_I2CChecksum, 0); + TASDEVICE_CHECKSUM_REG, 0); if (ret < 0) break; } @@ -1686,13 +1805,29 @@ static int tasdevice_load_block(struct tasdevice_priv *tas_priv, return rc; } +static void dspbin_type_check(struct tasdevice_priv *tas_priv, + unsigned int ppcver) +{ + if (ppcver >= PPC3_VERSION_TAS2781_ALPHA_MIN) { + if (ppcver >= PPC3_VERSION_TAS2781_BETA_MIN) + tas_priv->dspbin_typ = TASDEV_BETA; + else if (ppcver >= PPC3_VERSION_TAS2781_BASIC_MIN) + tas_priv->dspbin_typ = TASDEV_BASIC; + else + tas_priv->dspbin_typ = TASDEV_ALPHA; + } + if (tas_priv->dspbin_typ != TASDEV_BASIC) + tas_priv->fw_parse_fct_param_address = + fw_parse_fct_param_address; +} + static int dspfw_default_callback(struct tasdevice_priv *tas_priv, unsigned int drv_ver, unsigned int ppcver) { int rc = 0; if (drv_ver == 0x100) { - if (ppcver >= PPC3_VERSION) { + if (ppcver >= PPC3_VERSION_BASE) { tas_priv->fw_parse_variable_header = fw_parse_variable_header_kernel; tas_priv->fw_parse_program_data = @@ -1701,6 +1836,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv, fw_parse_configuration_data_kernel; tas_priv->tasdevice_load_block = tasdevice_load_block_kernel; + dspbin_type_check(tas_priv, ppcver); } else { switch (ppcver) { case 0x00: @@ -1716,7 +1852,7 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv, default: dev_err(tas_priv->dev, "%s: PPCVer must be 0x0 or 0x%02x", - __func__, PPC3_VERSION); + __func__, PPC3_VERSION_BASE); dev_err(tas_priv->dev, " Current:0x%02x\n", ppcver); rc = -EINVAL; @@ -1952,28 +2088,25 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw, struct tasdevice_fw_fixed_hdr *fw_fixed_hdr; struct tasdevice_fw *tas_fmw; int offset = 0; - int ret = 0; + int ret; if (!fmw || !fmw->data) { dev_err(tas_priv->dev, "%s: Failed to read firmware %s\n", __func__, tas_priv->coef_binaryname); - ret = -EINVAL; - goto out; + return -EINVAL; } tas_priv->fmw = kzalloc(sizeof(struct tasdevice_fw), GFP_KERNEL); - if (!tas_priv->fmw) { - ret = -ENOMEM; - goto out; - } + if (!tas_priv->fmw) + return -ENOMEM; + tas_fmw = tas_priv->fmw; tas_fmw->dev = tas_priv->dev; offset = fw_parse_header(tas_priv, tas_fmw, fmw, offset); - if (offset == -EINVAL) { - ret = -EINVAL; - goto out; - } + if (offset == -EINVAL) + return -EINVAL; + fw_fixed_hdr = &(tas_fmw->fw_hdr.fixed_hdr); /* Support different versions of firmware */ switch (fw_fixed_hdr->drv_ver) { @@ -2006,28 +2139,32 @@ static int tasdevice_dspfw_ready(const struct firmware *fmw, ret = dspfw_default_callback(tas_priv, fw_fixed_hdr->drv_ver, fw_fixed_hdr->ppcver); if (ret) - goto out; + return ret; break; } offset = tas_priv->fw_parse_variable_header(tas_priv, fmw, offset); - if (offset < 0) { - ret = offset; - goto out; - } + if (offset < 0) + return offset; + offset = tas_priv->fw_parse_program_data(tas_priv, tas_fmw, fmw, offset); - if (offset < 0) { - ret = offset; - goto out; - } + if (offset < 0) + return offset; + offset = tas_priv->fw_parse_configuration_data(tas_priv, tas_fmw, fmw, offset); if (offset < 0) - ret = offset; + return offset; -out: - return ret; + if (tas_priv->fw_parse_fct_param_address) { + offset = tas_priv->fw_parse_fct_param_address(tas_priv, + tas_fmw, fmw, offset); + if (offset < 0) + return offset; + } + + return 0; } int tasdevice_dsp_parser(void *context) diff --git a/sound/soc/codecs/tas2781-i2c.c b/sound/soc/codecs/tas2781-i2c.c index 90c5b2e74d12..b950914b7d48 100644 --- a/sound/soc/codecs/tas2781-i2c.c +++ b/sound/soc/codecs/tas2781-i2c.c @@ -349,13 +349,31 @@ static int calib_data_get(struct tasdevice_priv *tas_priv, int reg, return rc; } +static int partial_cali_data_update(int *reg, int j) +{ + switch (tas2781_cali_start_reg[j].reg) { + case 0: + return reg[0]; + case TAS2781_PRM_PLT_FLAG_REG: + return reg[1]; + case TAS2781_PRM_SINEGAIN_REG: + return reg[2]; + case TAS2781_PRM_SINEGAIN2_REG: + return reg[3]; + default: + return 0; + } +} + static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i, int *reg, unsigned char *dat) { struct tasdevice *tasdev = tas_priv->tasdevice; struct bulk_reg_val *p = tasdev[i].cali_data_backup; + struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp; const int sum = ARRAY_SIZE(tas2781_cali_start_reg); - int j; + unsigned char val[4]; + int j, r; if (p == NULL) return; @@ -370,30 +388,23 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i, tasdevice_dev_read(tas_priv, i, p[j].reg, (int *)&p[j].val[0]); } else { - switch (tas2781_cali_start_reg[j].reg) { - case 0: { - if (!reg[0]) - continue; - p[j].reg = reg[0]; + if (!tas_priv->dspbin_typ) { + r = partial_cali_data_update(reg, j); + if (r) + p[j].reg = r; } - break; - case TAS2781_PRM_PLT_FLAG_REG: - p[j].reg = reg[1]; - break; - case TAS2781_PRM_SINEGAIN_REG: - p[j].reg = reg[2]; - break; - case TAS2781_PRM_SINEGAIN2_REG: - p[j].reg = reg[3]; - break; - } - tasdevice_dev_bulk_read(tas_priv, i, p[j].reg, - p[j].val, 4); + + if (p[j].reg) + tasdevice_dev_bulk_read(tas_priv, i, p[j].reg, + p[j].val, 4); } } + if (tas_priv->dspbin_typ == TASDEV_ALPHA) + tasdevice_dev_bulk_read(tas_priv, i, t->reg, t->val, 4); + /* Update the setting for calibration */ - for (j = 0; j < sum - 2; j++) { + for (j = 0; j < sum - 4; j++) { if (p[j].val_len == 1) { if (p[j].is_locked) tasdevice_dev_write(tas_priv, i, @@ -401,17 +412,33 @@ static void sngl_calib_start(struct tasdevice_priv *tas_priv, int i, TAS2781_TEST_PAGE_UNLOCK); tasdevice_dev_write(tas_priv, i, p[j].reg, tas2781_cali_start_reg[j].val[0]); - } else { - if (!p[j].reg) - continue; - tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, - (unsigned char *) - tas2781_cali_start_reg[j].val, 4); } } - tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, &dat[1], 4); - tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg, &dat[5], 4); + if (tas_priv->dspbin_typ == TASDEV_ALPHA) { + val[0] = 0x00; + val[1] = 0x00; + val[2] = 0x21; + val[3] = 0x8e; + } else { + val[0] = tas2781_cali_start_reg[j].val[0]; + val[1] = tas2781_cali_start_reg[j].val[1]; + val[2] = tas2781_cali_start_reg[j].val[2]; + val[3] = tas2781_cali_start_reg[j].val[3]; + } + tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, val, 4); + tasdevice_dev_bulk_write(tas_priv, i, p[j + 1].reg, + (unsigned char *)tas2781_cali_start_reg[j + 1].val, 4); + tasdevice_dev_bulk_write(tas_priv, i, p[j + 2].reg, &dat[1], 4); + tasdevice_dev_bulk_write(tas_priv, i, p[j + 3].reg, &dat[5], 4); + if (tas_priv->dspbin_typ == TASDEV_ALPHA) { + val[0] = 0x00; + val[1] = 0x00; + val[2] = 0x2a; + val[3] = 0x0b; + + tasdevice_dev_bulk_read(tas_priv, i, t->reg, val, 4); + } } static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol, @@ -452,14 +479,15 @@ static int tas2781_calib_start_put(struct snd_kcontrol *kcontrol, return 1; } -static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv) +static void tas2781_calib_stop_put(struct tasdevice_priv *priv) { const int sum = ARRAY_SIZE(tas2781_cali_start_reg); int i, j; - for (i = 0; i < tas_priv->ndev; i++) { - struct tasdevice *tasdev = tas_priv->tasdevice; + for (i = 0; i < priv->ndev; i++) { + struct tasdevice *tasdev = priv->tasdevice; struct bulk_reg_val *p = tasdev[i].cali_data_backup; + struct bulk_reg_val *t = &tasdev[i].alp_cali_bckp; if (p == NULL) continue; @@ -467,18 +495,21 @@ static void tas2781_calib_stop_put(struct tasdevice_priv *tas_priv) for (j = 0; j < sum; j++) { if (p[j].val_len == 1) { if (p[j].is_locked) - tasdevice_dev_write(tas_priv, i, + tasdevice_dev_write(priv, i, TAS2781_TEST_UNLOCK_REG, TAS2781_TEST_PAGE_UNLOCK); - tasdevice_dev_write(tas_priv, i, p[j].reg, + tasdevice_dev_write(priv, i, p[j].reg, p[j].val[0]); } else { if (!p[j].reg) continue; - tasdevice_dev_bulk_write(tas_priv, i, p[j].reg, + tasdevice_dev_bulk_write(priv, i, p[j].reg, p[j].val, 4); } } + + if (priv->dspbin_typ == TASDEV_ALPHA) + tasdevice_dev_bulk_write(priv, i, t->reg, t->val, 4); } } @@ -590,16 +621,20 @@ static int tasdev_cali_data_put(struct snd_kcontrol *kcontrol, i += 2; priv->is_user_space_calidata = true; - p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); - i += 3; - p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); - i += 3; - p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); - i += 3; - p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); - i += 3; - p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); - i += 3; + if (priv->dspbin_typ == TASDEV_BASIC) { + p->r0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->r0_low_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->invr0_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->pow_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + p->tlimit_reg = TASDEVICE_REG(src[i], src[i + 1], src[i + 2]); + i += 3; + } else { + i += 15; + } memcpy(dst, &src[i], cali_data->total_sz); return 1; @@ -646,12 +681,19 @@ static int tasdev_tf_data_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; - unsigned int reg; + unsigned int reg = TAS2781_RUNTIME_RE_REG_TF; + + if (tas_priv->chip_id == TAS2781) { + struct tasdevice_fw *tas_fmw = tas_priv->fmw; + struct fct_param_address *p = &(tas_fmw->fct_par_addr); - if (tas_priv->chip_id == TAS2781) reg = TAS2781_RUNTIME_RE_REG_TF; - else + if (tas_priv->dspbin_typ) + reg = TASDEVICE_REG(p->tf_reg[0], p->tf_reg[1], + p->tf_reg[2]); + } else { reg = TAS2563_RUNTIME_RE_REG_TF; + } guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; @@ -666,12 +708,19 @@ static int tasdev_re_data_get(struct snd_kcontrol *kcontrol, struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; - unsigned int reg; + unsigned int reg = TAS2781_RUNTIME_RE_REG; - if (tas_priv->chip_id == TAS2781) - reg = TAS2781_RUNTIME_RE_REG; - else + if (tas_priv->chip_id == TAS2781) { + struct tasdevice_fw *tas_fmw = tas_priv->fmw; + struct fct_param_address *p = &(tas_fmw->fct_par_addr); + + if (tas_priv->dspbin_typ) + reg = TASDEVICE_REG(p->r0_reg[0], p->r0_reg[1], + p->r0_reg[2]); + } else { reg = TAS2563_RUNTIME_RE_REG; + } + guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; return calib_data_get(tas_priv, reg, &dst[1]); @@ -705,11 +754,16 @@ static int tasdev_XMA1_data_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct tasdevice_fw *tas_fmw = tas_priv->fmw; + struct fct_param_address *p = &(tas_fmw->fct_par_addr); struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg = TASDEVICE_XM_A1_REG; + if (tas_priv->dspbin_typ) + reg = TASDEVICE_REG(p->a1_reg[0], p->a1_reg[1], p->a1_reg[2]); + guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; return calib_data_get(tas_priv, reg, &dst[1]); @@ -720,11 +774,16 @@ static int tasdev_XMA2_data_get(struct snd_kcontrol *kcontrol, { struct snd_soc_component *comp = snd_soc_kcontrol_component(kcontrol); struct tasdevice_priv *tas_priv = snd_soc_component_get_drvdata(comp); + struct tasdevice_fw *tas_fmw = tas_priv->fmw; + struct fct_param_address *p = &(tas_fmw->fct_par_addr); struct soc_bytes_ext *bytes_ext = (struct soc_bytes_ext *) kcontrol->private_value; unsigned char *dst = ucontrol->value.bytes.data; unsigned int reg = TASDEVICE_XM_A2_REG; + if (tas_priv->dspbin_typ) + reg = TASDEVICE_REG(p->a2_reg[0], p->a2_reg[1], p->a2_reg[2]); + guard(mutex)(&tas_priv->codec_lock); dst[0] = bytes_ext->max; return calib_data_get(tas_priv, reg, &dst[1]); @@ -1172,10 +1231,51 @@ static int tasdevice_dsp_create_ctrls(struct tasdevice_priv *tas_priv) nr_controls < mix_index ? nr_controls : mix_index); } +static void cali_reg_update(struct bulk_reg_val *p, + struct fct_param_address *t) +{ + const int sum = ARRAY_SIZE(tas2781_cali_start_reg); + int reg, j; + + for (j = 0; j < sum; j++) { + switch (tas2781_cali_start_reg[j].reg) { + case 0: + reg = TASDEVICE_REG(t->thr[0], t->thr[1], t->thr[2]); + break; + case TAS2781_PRM_PLT_FLAG_REG: + reg = TASDEVICE_REG(t->plt_flg[0], t->plt_flg[1], + t->plt_flg[2]); + break; + case TAS2781_PRM_SINEGAIN_REG: + reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1], + t->sin_gn[2]); + break; + case TAS2781_PRM_SINEGAIN2_REG: + reg = TASDEVICE_REG(t->sin_gn[0], t->sin_gn[1], + t->sin_gn[2]); + break; + default: + reg = 0; + break; + } + if (reg) + p[j].reg = reg; + } +} + +static void alpa_cali_update(struct bulk_reg_val *p, + struct fct_param_address *t) +{ + p->is_locked = false; + p->reg = TASDEVICE_REG(t->thr2[0], t->thr2[1], t->thr2[2]); + p->val_len = 4; +} + static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) { struct calidata *cali_data = &priv->cali_data; struct tasdevice *tasdev = priv->tasdevice; + struct tasdevice_fw *fmw = priv->fmw; struct soc_bytes_ext *ext_cali_data; struct snd_kcontrol_new *cali_ctrls; unsigned int nctrls; @@ -1191,14 +1291,25 @@ static int tasdevice_create_cali_ctrls(struct tasdevice_priv *priv) } if (priv->chip_id == TAS2781) { + struct fct_param_address *t = &(fmw->fct_par_addr); + cali_ctrls = (struct snd_kcontrol_new *)tas2781_cali_controls; nctrls = ARRAY_SIZE(tas2781_cali_controls); for (i = 0; i < priv->ndev; i++) { - tasdev[i].cali_data_backup = + struct bulk_reg_val *p; + + p = tasdev[i].cali_data_backup = kmemdup(tas2781_cali_start_reg, sizeof(tas2781_cali_start_reg), GFP_KERNEL); if (!tasdev[i].cali_data_backup) return -ENOMEM; + if (priv->dspbin_typ) { + cali_reg_update(p, t); + if (priv->dspbin_typ == TASDEV_ALPHA) { + p = &tasdev[i].alp_cali_bckp; + alpa_cali_update(p, t); + } + } } } else { cali_ctrls = (struct snd_kcontrol_new *)tas2563_cali_controls; diff --git a/sound/soc/codecs/tlv320adc3xxx.c b/sound/soc/codecs/tlv320adc3xxx.c index 1a50ff675244..191e067ed1c9 100644 --- a/sound/soc/codecs/tlv320adc3xxx.c +++ b/sound/soc/codecs/tlv320adc3xxx.c @@ -1493,8 +1493,7 @@ static void adc3xxx_i2c_remove(struct i2c_client *client) { struct adc3xxx *adc3xxx = i2c_get_clientdata(client); - if (adc3xxx->mclk) - clk_disable_unprepare(adc3xxx->mclk); + clk_disable_unprepare(adc3xxx->mclk); adc3xxx_free_gpio(adc3xxx); snd_soc_unregister_component(&client->dev); } diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index fa46f51d4341..423b9264a205 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1477,10 +1477,8 @@ static int dac33_i2c_probe(struct i2c_client *client) if (dac33 == NULL) return -ENOMEM; - dac33->reg_cache = devm_kmemdup(&client->dev, - dac33_reg, - ARRAY_SIZE(dac33_reg) * sizeof(u8), - GFP_KERNEL); + dac33->reg_cache = devm_kmemdup_array(&client->dev, dac33_reg, ARRAY_SIZE(dac33_reg), + sizeof(dac33_reg[0]), GFP_KERNEL); if (!dac33->reg_cache) return -ENOMEM; diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index b9eb59e3bfa0..5ce0db9326fd 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -399,7 +399,6 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c) return 0; } -#ifdef CONFIG_PM_SLEEP static int ts3a227e_suspend(struct device *dev) { struct ts3a227e *ts3a227e = dev_get_drvdata(dev); @@ -419,10 +418,9 @@ static int ts3a227e_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops ts3a227e_pm = { - SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume) + SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume) }; static const struct i2c_device_id ts3a227e_i2c_ids[] = { @@ -450,7 +448,7 @@ MODULE_DEVICE_TABLE(acpi, ts3a227e_acpi_match); static struct i2c_driver ts3a227e_driver = { .driver = { .name = "ts3a227e", - .pm = &ts3a227e_pm, + .pm = pm_ptr(&ts3a227e_pm), .of_match_table = of_match_ptr(ts3a227e_of_match), .acpi_match_table = ACPI_PTR(ts3a227e_acpi_match), }, diff --git a/sound/soc/codecs/tscs454.c b/sound/soc/codecs/tscs454.c index 850e5de9271e..da2f3cb1cd13 100644 --- a/sound/soc/codecs/tscs454.c +++ b/sound/soc/codecs/tscs454.c @@ -10,6 +10,7 @@ #include <linux/i2c.h> #include <linux/err.h> #include <linux/string.h> +#include <linux/string_choices.h> #include <linux/module.h> #include <linux/delay.h> #include <linux/mutex.h> @@ -737,9 +738,7 @@ static int pll_power_event(struct snd_soc_dapm_widget *w, ret = snd_soc_component_update_bits(component, R_PLLCTL, msk, val); if (ret < 0) { dev_err(component->dev, "Failed to %s PLL %d (%d)\n", - enable ? "enable" : "disable", - pll1 ? 1 : 2, - ret); + str_enable_disable(enable), pll1 ? 1 : 2, ret); return ret; } diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index e3782762139f..609886461805 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -2049,7 +2049,7 @@ static int twl4030_voice_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_CBP_CFP: format &= ~(TWL4030_VIF_SLAVE_EN); break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: format |= TWL4030_VIF_SLAVE_EN; break; default: diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 4f8fdd574585..c179d865b938 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -766,10 +766,8 @@ static int uda1380_i2c_probe(struct i2c_client *i2c) return ret; } - uda1380->reg_cache = devm_kmemdup(&i2c->dev, - uda1380_reg, - ARRAY_SIZE(uda1380_reg) * sizeof(u16), - GFP_KERNEL); + uda1380->reg_cache = devm_kmemdup_array(&i2c->dev, uda1380_reg, ARRAY_SIZE(uda1380_reg), + sizeof(uda1380_reg[0]), GFP_KERNEL); if (!uda1380->reg_cache) return -ENOMEM; diff --git a/sound/soc/codecs/wcd934x.c b/sound/soc/codecs/wcd934x.c index 910852eb9698..dd0cda394bf1 100644 --- a/sound/soc/codecs/wcd934x.c +++ b/sound/soc/codecs/wcd934x.c @@ -23,6 +23,8 @@ #include "wcd-clsh-v2.h" #include "wcd-mbhc-v2.h" +#include <dt-bindings/sound/qcom,wcd934x.h> + #define WCD934X_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000) @@ -307,6 +309,7 @@ {"SLIM TX" #id, NULL, "CDC_IF TX" #id " MUX"} #define WCD934X_MAX_MICBIAS MIC_BIAS_4 +#define NUM_CODEC_DAIS 9 enum { SIDO_SOURCE_INTERNAL, @@ -435,19 +438,6 @@ enum { }; enum { - AIF1_PB = 0, - AIF1_CAP, - AIF2_PB, - AIF2_CAP, - AIF3_PB, - AIF3_CAP, - AIF4_PB, - AIF4_VIFEED, - AIF4_MAD_TX, - NUM_CODEC_DAIS, -}; - -enum { INTn_1_INP_SEL_ZERO = 0, INTn_1_INP_SEL_DEC0, INTn_1_INP_SEL_DEC1, diff --git a/sound/soc/codecs/wcd937x-sdw.c b/sound/soc/codecs/wcd937x-sdw.c index 0c33f7f3dc25..1bfe7383b311 100644 --- a/sound/soc/codecs/wcd937x-sdw.c +++ b/sound/soc/codecs/wcd937x-sdw.c @@ -19,7 +19,7 @@ #include <sound/soc.h> #include "wcd937x.h" -static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { +static struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD937X_HPH_L, WCD937X_HPH_PORT, BIT(0)), WCD_SDW_CH(WCD937X_HPH_R, WCD937X_HPH_PORT, BIT(1)), WCD_SDW_CH(WCD937X_CLSH, WCD937X_CLSH_PORT, BIT(0)), @@ -30,7 +30,7 @@ static const struct wcd937x_sdw_ch_info wcd937x_sdw_rx_ch_info[] = { WCD_SDW_CH(WCD937X_DSD_R, WCD937X_DSD_PORT, BIT(1)), }; -static const struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { +static struct wcd937x_sdw_ch_info wcd937x_sdw_tx_ch_info[] = { WCD_SDW_CH(WCD937X_ADC1, WCD937X_ADC_1_PORT, BIT(0)), WCD_SDW_CH(WCD937X_ADC2, WCD937X_ADC_2_3_PORT, BIT(0)), WCD_SDW_CH(WCD937X_ADC3, WCD937X_ADC_2_3_PORT, BIT(0)), @@ -1019,14 +1019,16 @@ static int wcd9370_probe(struct sdw_slave *pdev, { struct device *dev = &pdev->dev; struct wcd937x_sdw_priv *wcd; - int ret; + u8 master_ch_mask[WCD937X_MAX_SWR_CH_IDS]; + int master_ch_mask_size = 0; + int ret, i; wcd = devm_kzalloc(dev, sizeof(*wcd), GFP_KERNEL); if (!wcd) return -ENOMEM; /* Port map index starts at 0, however the data port for this codec start at index 1 */ - if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) { wcd->is_tx = true; ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", &pdev->m_port_map[1], @@ -1048,10 +1050,36 @@ static int wcd9370_probe(struct sdw_slave *pdev, SDW_SCP_INT1_PARITY; pdev->prop.lane_control_support = true; pdev->prop.simple_clk_stop_capable = true; + + memset(master_ch_mask, 0, WCD937X_MAX_SWR_CH_IDS); + if (wcd->is_tx) { - pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS - 1, 0); + master_ch_mask_size = of_property_count_u8_elems(dev->of_node, + "qcom,tx-channel-mapping"); + + if (master_ch_mask_size) + ret = of_property_read_u8_array(dev->of_node, "qcom,tx-channel-mapping", + master_ch_mask, master_ch_mask_size); + } else { + master_ch_mask_size = of_property_count_u8_elems(dev->of_node, + "qcom,rx-channel-mapping"); + + if (master_ch_mask_size) + ret = of_property_read_u8_array(dev->of_node, "qcom,rx-channel-mapping", + master_ch_mask, master_ch_mask_size); + } + + if (ret < 0) + dev_info(dev, "Static channel mapping not specified using device channel maps\n"); + + if (wcd->is_tx) { + pdev->prop.source_ports = GENMASK(WCD937X_MAX_TX_SWR_PORTS, 0); pdev->prop.src_dpn_prop = wcd937x_dpn_prop; wcd->ch_info = &wcd937x_sdw_tx_ch_info[0]; + + for (i = 0; i < master_ch_mask_size; i++) + wcd->ch_info[i].master_ch_mask = WCD937X_SWRM_CH_MASK(master_ch_mask[i]); + pdev->prop.wake_capable = true; wcd->regmap = devm_regmap_init_sdw(pdev, &wcd937x_regmap_config); @@ -1065,6 +1093,9 @@ static int wcd9370_probe(struct sdw_slave *pdev, pdev->prop.sink_ports = GENMASK(WCD937X_MAX_SWR_PORTS - 1, 0); pdev->prop.sink_dpn_prop = wcd937x_dpn_prop; wcd->ch_info = &wcd937x_sdw_rx_ch_info[0]; + + for (i = 0; i < master_ch_mask_size; i++) + wcd->ch_info[i].master_ch_mask = WCD937X_SWRM_CH_MASK(master_ch_mask[i]); } @@ -1093,7 +1124,7 @@ static const struct sdw_device_id wcd9370_slave_id[] = { }; MODULE_DEVICE_TABLE(sdw, wcd9370_slave_id); -static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev) +static int wcd937x_sdw_runtime_suspend(struct device *dev) { struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); @@ -1105,7 +1136,7 @@ static int __maybe_unused wcd937x_sdw_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev) +static int wcd937x_sdw_runtime_resume(struct device *dev) { struct wcd937x_sdw_priv *wcd = dev_get_drvdata(dev); @@ -1118,7 +1149,7 @@ static int __maybe_unused wcd937x_sdw_runtime_resume(struct device *dev) } static const struct dev_pm_ops wcd937x_sdw_pm_ops = { - SET_RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL) + RUNTIME_PM_OPS(wcd937x_sdw_runtime_suspend, wcd937x_sdw_runtime_resume, NULL) }; static struct sdw_driver wcd9370_codec_driver = { @@ -1128,7 +1159,7 @@ static struct sdw_driver wcd9370_codec_driver = { .id_table = wcd9370_slave_id, .driver = { .name = "wcd9370-codec", - .pm = &wcd937x_sdw_pm_ops, + .pm = pm_ptr(&wcd937x_sdw_pm_ops), } }; module_sdw_driver(wcd9370_codec_driver); diff --git a/sound/soc/codecs/wcd937x.c b/sound/soc/codecs/wcd937x.c index c9d5e67bf66e..dd2045a5d26d 100644 --- a/sound/soc/codecs/wcd937x.c +++ b/sound/soc/codecs/wcd937x.c @@ -1197,13 +1197,21 @@ static int wcd937x_connect_port(struct wcd937x_sdw_priv *wcd, u8 port_idx, u8 ch const struct wcd937x_sdw_ch_info *ch_info = &wcd->ch_info[ch_id]; u8 port_num = ch_info->port_num; u8 ch_mask = ch_info->ch_mask; + u8 mstr_port_num, mstr_ch_mask; + struct sdw_slave *sdev = wcd->sdev; port_config->num = port_num; - if (enable) + mstr_port_num = sdev->m_port_map[port_num]; + mstr_ch_mask = ch_info->master_ch_mask; + + if (enable) { port_config->ch_mask |= ch_mask; - else + wcd->master_channel_map[mstr_port_num] |= mstr_ch_mask; + } else { port_config->ch_mask &= ~ch_mask; + wcd->master_channel_map[mstr_port_num] &= ~mstr_ch_mask; + } return 0; } @@ -2472,7 +2480,7 @@ static const struct irq_domain_ops wcd_domain_ops = { static int wcd937x_irq_init(struct wcd937x_priv *wcd, struct device *dev) { - wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + wcd->virq = irq_domain_create_linear(NULL, 1, &wcd_domain_ops, NULL); if (!(wcd->virq)) { dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); return -EINVAL; @@ -2563,6 +2571,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) ARRAY_SIZE(wcd9375_dapm_widgets)); if (ret < 0) { dev_err(component->dev, "Failed to add snd_ctls\n"); + wcd_clsh_ctrl_free(wcd937x->clsh_info); return ret; } @@ -2570,6 +2579,7 @@ static int wcd937x_soc_codec_probe(struct snd_soc_component *component) ARRAY_SIZE(wcd9375_audio_map)); if (ret < 0) { dev_err(component->dev, "Failed to add routes\n"); + wcd_clsh_ctrl_free(wcd937x->clsh_info); return ret; } } @@ -2689,10 +2699,51 @@ static int wcd937x_codec_set_sdw_stream(struct snd_soc_dai *dai, return 0; } +static int wcd937x_get_channel_map(const struct snd_soc_dai *dai, + unsigned int *tx_num, unsigned int *tx_slot, + unsigned int *rx_num, unsigned int *rx_slot) +{ + struct wcd937x_priv *wcd937x = dev_get_drvdata(dai->dev); + struct wcd937x_sdw_priv *wcd = wcd937x->sdw_priv[dai->id]; + int i; + + switch (dai->id) { + case AIF1_PB: + if (!rx_slot || !rx_num) { + dev_err(dai->dev, "Invalid rx_slot %p or rx_num %p\n", + rx_slot, rx_num); + return -EINVAL; + } + + for (i = 0; i < SDW_MAX_PORTS; i++) + rx_slot[i] = wcd->master_channel_map[i]; + + *rx_num = i; + break; + case AIF1_CAP: + if (!tx_slot || !tx_num) { + dev_err(dai->dev, "Invalid tx_slot %p or tx_num %p\n", + tx_slot, tx_num); + return -EINVAL; + } + + for (i = 0; i < SDW_MAX_PORTS; i++) + tx_slot[i] = wcd->master_channel_map[i]; + + *tx_num = i; + break; + default: + break; + } + + return 0; +} + static const struct snd_soc_dai_ops wcd937x_sdw_dai_ops = { .hw_params = wcd937x_codec_hw_params, .hw_free = wcd937x_codec_free, .set_stream = wcd937x_codec_set_sdw_stream, + .get_channel_map = wcd937x_get_channel_map, }; static struct snd_soc_dai_driver wcd937x_dais[] = { diff --git a/sound/soc/codecs/wcd937x.h b/sound/soc/codecs/wcd937x.h index 4afa48dcaf74..4ef57c496c37 100644 --- a/sound/soc/codecs/wcd937x.h +++ b/sound/soc/codecs/wcd937x.h @@ -489,6 +489,7 @@ #define WCD937X_MAX_MICBIAS 3 #define WCD937X_MAX_BULK_SUPPLY 4 #define WCD937X_MAX_SWR_CH_IDS 15 +#define WCD937X_SWRM_CH_MASK(ch_idx) BIT(ch_idx - 1) enum wcd937x_tx_sdw_ports { WCD937X_ADC_1_PORT = 1, @@ -510,12 +511,14 @@ enum wcd937x_rx_sdw_ports { struct wcd937x_sdw_ch_info { int port_num; unsigned int ch_mask; + unsigned int master_ch_mask; }; #define WCD_SDW_CH(id, pn, cmask) \ [id] = { \ .port_num = pn, \ .ch_mask = cmask, \ + .master_ch_mask = cmask, \ } struct wcd937x_priv; @@ -524,9 +527,11 @@ struct wcd937x_sdw_priv { struct sdw_stream_config sconfig; struct sdw_stream_runtime *sruntime; struct sdw_port_config port_config[WCD937X_MAX_SWR_PORTS]; - const struct wcd937x_sdw_ch_info *ch_info; + struct wcd937x_sdw_ch_info *ch_info; bool port_enable[WCD937X_MAX_SWR_CH_IDS]; + unsigned int master_channel_map[SDW_MAX_PORTS]; int active_ports; + int num_ports; bool is_tx; struct wcd937x_priv *wcd937x; struct irq_domain *slave_irq; diff --git a/sound/soc/codecs/wcd938x-sdw.c b/sound/soc/codecs/wcd938x-sdw.c index 7da8a10bd0a9..cabddadc90ef 100644 --- a/sound/soc/codecs/wcd938x-sdw.c +++ b/sound/soc/codecs/wcd938x-sdw.c @@ -1229,7 +1229,7 @@ static int wcd9380_probe(struct sdw_slave *pdev, * Port map index starts with 0, however the data port for this codec * are from index 1 */ - if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) { wcd->is_tx = true; ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", &pdev->m_port_map[1], @@ -1311,7 +1311,7 @@ static const struct sdw_device_id wcd9380_slave_id[] = { }; MODULE_DEVICE_TABLE(sdw, wcd9380_slave_id); -static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev) +static int wcd938x_sdw_runtime_suspend(struct device *dev) { struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev); @@ -1323,7 +1323,7 @@ static int __maybe_unused wcd938x_sdw_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev) +static int wcd938x_sdw_runtime_resume(struct device *dev) { struct wcd938x_sdw_priv *wcd = dev_get_drvdata(dev); @@ -1338,7 +1338,7 @@ static int __maybe_unused wcd938x_sdw_runtime_resume(struct device *dev) } static const struct dev_pm_ops wcd938x_sdw_pm_ops = { - SET_RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL) + RUNTIME_PM_OPS(wcd938x_sdw_runtime_suspend, wcd938x_sdw_runtime_resume, NULL) }; @@ -1349,7 +1349,7 @@ static struct sdw_driver wcd9380_codec_driver = { .id_table = wcd9380_slave_id, .driver = { .name = "wcd9380-codec", - .pm = &wcd938x_sdw_pm_ops, + .pm = pm_ptr(&wcd938x_sdw_pm_ops), } }; module_sdw_driver(wcd9380_codec_driver); diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index f2a4f3262bdb..1ae498c32391 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -70,13 +70,8 @@ #define WCD_MBHC_HS_V_MAX 1600 #define WCD938X_EAR_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ - .put = wcd938x_ear_pa_put_gain, \ - .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, snd_soc_get_volsw, \ + wcd938x_ear_pa_put_gain, tlv_array) enum { WCD9380 = 0, @@ -3030,7 +3025,7 @@ static const struct irq_domain_ops wcd_domain_ops = { static int wcd938x_irq_init(struct wcd938x_priv *wcd, struct device *dev) { - wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + wcd->virq = irq_domain_create_linear(NULL, 1, &wcd_domain_ops, NULL); if (!(wcd->virq)) { dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); return -EINVAL; diff --git a/sound/soc/codecs/wcd939x-sdw.c b/sound/soc/codecs/wcd939x-sdw.c index fca95777a75a..f7a9323a9fea 100644 --- a/sound/soc/codecs/wcd939x-sdw.c +++ b/sound/soc/codecs/wcd939x-sdw.c @@ -1429,7 +1429,7 @@ static int wcd9390_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) * Port map index starts with 0, however the data port for this codec * are from index 1 */ - if (of_property_read_bool(dev->of_node, "qcom,tx-port-mapping")) { + if (of_property_present(dev->of_node, "qcom,tx-port-mapping")) { wcd->is_tx = true; ret = of_property_read_u32_array(dev->of_node, "qcom,tx-port-mapping", @@ -1507,7 +1507,7 @@ static const struct sdw_device_id wcd9390_slave_id[] = { }; MODULE_DEVICE_TABLE(sdw, wcd9390_slave_id); -static int __maybe_unused wcd939x_sdw_runtime_suspend(struct device *dev) +static int wcd939x_sdw_runtime_suspend(struct device *dev) { struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); @@ -1519,7 +1519,7 @@ static int __maybe_unused wcd939x_sdw_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wcd939x_sdw_runtime_resume(struct device *dev) +static int wcd939x_sdw_runtime_resume(struct device *dev) { struct wcd939x_sdw_priv *wcd = dev_get_drvdata(dev); @@ -1532,7 +1532,7 @@ static int __maybe_unused wcd939x_sdw_runtime_resume(struct device *dev) } static const struct dev_pm_ops wcd939x_sdw_pm_ops = { - SET_RUNTIME_PM_OPS(wcd939x_sdw_runtime_suspend, wcd939x_sdw_runtime_resume, NULL) + RUNTIME_PM_OPS(wcd939x_sdw_runtime_suspend, wcd939x_sdw_runtime_resume, NULL) }; static struct sdw_driver wcd9390_codec_driver = { @@ -1542,7 +1542,7 @@ static struct sdw_driver wcd9390_codec_driver = { .id_table = wcd9390_slave_id, .driver = { .name = "wcd9390-codec", - .pm = &wcd939x_sdw_pm_ops, + .pm = pm_ptr(&wcd939x_sdw_pm_ops), } }; module_sdw_driver(wcd9390_codec_driver); diff --git a/sound/soc/codecs/wcd939x.c b/sound/soc/codecs/wcd939x.c index 4a417a92514d..0a87a79772da 100644 --- a/sound/soc/codecs/wcd939x.c +++ b/sound/soc/codecs/wcd939x.c @@ -2975,7 +2975,7 @@ static const struct irq_domain_ops wcd_domain_ops = { static int wcd939x_irq_init(struct wcd939x_priv *wcd, struct device *dev) { - wcd->virq = irq_domain_add_linear(NULL, 1, &wcd_domain_ops, NULL); + wcd->virq = irq_domain_create_linear(NULL, 1, &wcd_domain_ops, NULL); if (!(wcd->virq)) { dev_err(dev, "%s: Failed to add IRQ domain\n", __func__); return -EINVAL; diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index 841247173d98..87418c838ca0 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1576,15 +1576,15 @@ static int wm2200_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: lrclk |= WM2200_AIF1TX_LRCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: bclk |= WM2200_AIF1_BCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: lrclk |= WM2200_AIF1TX_LRCLK_MSTR; bclk |= WM2200_AIF1_BCLK_MSTR; break; @@ -2429,7 +2429,6 @@ static void wm2200_i2c_remove(struct i2c_client *i2c) wm2200->core_supplies); } -#ifdef CONFIG_PM static int wm2200_runtime_suspend(struct device *dev) { struct wm2200_priv *wm2200 = dev_get_drvdata(dev); @@ -2466,11 +2465,9 @@ static int wm2200_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops wm2200_pm = { - SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume, - NULL) + RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume, NULL) }; static const struct i2c_device_id wm2200_i2c_id[] = { @@ -2482,7 +2479,7 @@ MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id); static struct i2c_driver wm2200_i2c_driver = { .driver = { .name = "wm2200", - .pm = &wm2200_pm, + .pm = pm_ptr(&wm2200_pm), }, .probe = wm2200_i2c_probe, .remove = wm2200_i2c_remove, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 11bbc94a282c..d9e5762324df 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1303,15 +1303,15 @@ static int wm5100_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: lrclk |= WM5100_AIF1TX_LRCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: bclk |= WM5100_AIF1_BCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: lrclk |= WM5100_AIF1TX_LRCLK_MSTR; bclk |= WM5100_AIF1_BCLK_MSTR; break; @@ -2625,7 +2625,6 @@ static void wm5100_i2c_remove(struct i2c_client *i2c) gpiod_set_value_cansleep(wm5100->ldo_ena, 0); } -#ifdef CONFIG_PM static int wm5100_runtime_suspend(struct device *dev) { struct wm5100_priv *wm5100 = dev_get_drvdata(dev); @@ -2662,11 +2661,9 @@ static int wm5100_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops wm5100_pm = { - SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume, - NULL) + RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume, NULL) }; static const struct i2c_device_id wm5100_i2c_id[] = { @@ -2678,7 +2675,7 @@ MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id); static struct i2c_driver wm5100_i2c_driver = { .driver = { .name = "wm5100", - .pm = &wm5100_pm, + .pm = pm_ptr(&wm5100_pm), }, .probe = wm5100_i2c_probe, .remove = wm5100_i2c_remove, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 64eee0d2347d..212eca675f27 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -477,7 +477,7 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol, */ snd_soc_dapm_mutex_lock(dapm); - ret = snd_soc_get_volsw_range(kcontrol, ucontrol); + ret = snd_soc_get_volsw(kcontrol, ucontrol); snd_soc_dapm_mutex_unlock(dapm); @@ -497,7 +497,7 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol, */ snd_soc_dapm_mutex_lock(dapm); - ret = snd_soc_put_volsw_range(kcontrol, ucontrol); + ret = snd_soc_put_volsw(kcontrol, ucontrol); snd_soc_dapm_mutex_unlock(dapm); diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 66bd281095e1..b1fe6f4e0c10 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -846,12 +846,12 @@ static int wm8350_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master |= WM8350_BCLK_MSTR; dac_lrc |= WM8350_DACLRC_ENA; adc_lrc |= WM8350_ADCLRC_ENA; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c index 19ce839f6ef7..5ad6d5b63ffc 100644 --- a/sound/soc/codecs/wm8400.c +++ b/sound/soc/codecs/wm8400.c @@ -986,10 +986,10 @@ static int wm8400_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: audio3 &= ~WM8400_AIF_MSTR1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: audio3 |= WM8400_AIF_MSTR1; break; default: diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index 4a31d6f89502..79adbcc90d4a 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -389,10 +389,10 @@ static int wm8510_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: clk |= 0x0001; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 138eba7e577a..6671e13c320c 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -264,10 +264,10 @@ static int wm8523_set_dai_fmt(struct snd_soc_dai *codec_dai, WM8523_FMT_MASK | WM8523_AIF_MSTR_MASK); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aifctrl1 |= WM8523_AIF_MSTR; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8524.c b/sound/soc/codecs/wm8524.c index fa9942a08927..403e513f3fa8 100644 --- a/sound/soc/codecs/wm8524.c +++ b/sound/soc/codecs/wm8524.c @@ -139,7 +139,7 @@ static int wm8524_set_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) SND_SOC_DAIFMT_MASTER_MASK); if (fmt != (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS)) { + SND_SOC_DAIFMT_CBC_CFC)) { dev_err(codec_dai->dev, "Invalid DAI format\n"); return -EINVAL; } diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 73a8edc797fb..ba4a08456e78 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -614,10 +614,10 @@ static int wm8580_set_paif_dai_fmt(struct snd_soc_dai *codec_dai, aifb &= ~(WM8580_AIF_FMT_MASK | WM8580_AIF_LRP | WM8580_AIF_BCP); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: aifa &= ~WM8580_AIF_MS; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aifa |= WM8580_AIF_MS; break; default: diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index a1c99bbf5aa1..481088987742 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -243,10 +243,10 @@ static int wm8711_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index 2cbd6b189416..ea0a588da40f 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -128,7 +128,7 @@ static int wm8728_set_dai_fmt(struct snd_soc_dai *codec_dai, /* The hardware only support full slave mode */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index efdc242c2ede..f7e48f27649d 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -404,10 +404,10 @@ static int wm8737_set_dai_fmt(struct snd_soc_dai *codec_dai, u16 af = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: af |= WM8737_MS; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index 4863d6ac461b..4dfbb33edb09 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -308,7 +308,7 @@ static int wm8741_set_dai_fmt(struct snd_soc_dai *codec_dai, /* check master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index cae97fa3bcb0..312be0721b5d 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -522,10 +522,10 @@ static int wm8750_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: iface = 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index 38b76b7275e5..43cc368cf3f3 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -963,12 +963,12 @@ static int wm8753_pcm_set_dai_fmt(struct snd_soc_component *component, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ioctl |= 0x2; fallthrough; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: voice |= 0x0040; break; default: @@ -1089,12 +1089,12 @@ static int wm8753_i2s_set_dai_fmt(struct snd_soc_component *component, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ioctl |= 0x1; fallthrough; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: hifi |= 0x0040; break; default: diff --git a/sound/soc/codecs/wm8770.c b/sound/soc/codecs/wm8770.c index 38376b605201..5685c3bb5555 100644 --- a/sound/soc/codecs/wm8770.c +++ b/sound/soc/codecs/wm8770.c @@ -349,10 +349,10 @@ static int wm8770_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) component = dai->component; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master = 0x100; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: master = 0; break; default: diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index 166e00fcd11d..7b73c825aed4 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -182,9 +182,9 @@ static int wm8776_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) iface = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: master = 0; break; default: diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index e80dad87219b..3380d7301b17 100644 --- a/sound/soc/codecs/wm8804-i2c.c +++ b/sound/soc/codecs/wm8804-i2c.c @@ -56,7 +56,7 @@ MODULE_DEVICE_TABLE(acpi, wm8804_acpi_match); static struct i2c_driver wm8804_i2c_driver = { .driver = { .name = "wm8804", - .pm = &wm8804_pm, + .pm = pm_ptr(&wm8804_pm), .of_match_table = of_match_ptr(wm8804_of_match), .acpi_match_table = ACPI_PTR(wm8804_acpi_match), }, diff --git a/sound/soc/codecs/wm8804-spi.c b/sound/soc/codecs/wm8804-spi.c index 628568724c20..cf74abfb1a2c 100644 --- a/sound/soc/codecs/wm8804-spi.c +++ b/sound/soc/codecs/wm8804-spi.c @@ -38,7 +38,7 @@ MODULE_DEVICE_TABLE(of, wm8804_of_match); static struct spi_driver wm8804_spi_driver = { .driver = { .name = "wm8804", - .pm = &wm8804_pm, + .pm = pm_ptr(&wm8804_pm), .of_match_table = wm8804_of_match, }, .probe = wm8804_spi_probe, diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c index cfa78e4d8b73..48700cc25cb0 100644 --- a/sound/soc/codecs/wm8804.c +++ b/sound/soc/codecs/wm8804.c @@ -243,10 +243,10 @@ static int wm8804_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) snd_soc_component_update_bits(component, WM8804_AIFRX, 0x3, format); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: master = 0; break; default: @@ -680,7 +680,6 @@ void wm8804_remove(struct device *dev) } EXPORT_SYMBOL_GPL(wm8804_remove); -#if IS_ENABLED(CONFIG_PM) static int wm8804_runtime_resume(struct device *dev) { struct wm8804_priv *wm8804 = dev_get_drvdata(dev); @@ -713,12 +712,10 @@ static int wm8804_runtime_suspend(struct device *dev) return 0; } -#endif -const struct dev_pm_ops wm8804_pm = { - SET_RUNTIME_PM_OPS(wm8804_runtime_suspend, wm8804_runtime_resume, NULL) +EXPORT_GPL_DEV_PM_OPS(wm8804_pm) = { + RUNTIME_PM_OPS(wm8804_runtime_suspend, wm8804_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(wm8804_pm); MODULE_DESCRIPTION("ASoC WM8804 driver"); MODULE_AUTHOR("Dimitris Papastamos <dp@opensource.wolfsonmicro.com>"); diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index e44fdf97796f..6fb25588ca81 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -867,22 +867,22 @@ static int wm8900_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: clocking1 &= ~WM8900_REG_CLOCKING1_BCLK_DIR; aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; aif3 |= WM8900_REG_AUDIO3_ADCLRC_DIR; aif4 |= WM8900_REG_AUDIO4_DACLRC_DIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: clocking1 |= WM8900_REG_CLOCKING1_BCLK_DIR; aif3 &= ~WM8900_REG_AUDIO3_ADCLRC_DIR; aif4 &= ~WM8900_REG_AUDIO4_DACLRC_DIR; diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index c643b5377d3a..03902909f27e 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -1229,15 +1229,15 @@ static int wm8903_set_dai_fmt(struct snd_soc_dai *codec_dai, WM8903_AIF_LRCLK_INV | WM8903_AIF_BCLK_INV); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aif1 |= WM8903_LRCLK_DIR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif1 |= WM8903_LRCLK_DIR | WM8903_BCLK_DIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aif1 |= WM8903_BCLK_DIR; break; default: diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index aef82532f8cf..1de09ea646cf 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -844,6 +844,26 @@ static int out_pga_event(struct snd_soc_dapm_widget *w, return 0; } +static const char * const dmic_text[] = { + "DMIC1", "DMIC2" +}; + +static SOC_ENUM_SINGLE_DECL(dmic_enum, WM8904_DIGITAL_MICROPHONE_0, + WM8904_DMIC_SRC_SHIFT, dmic_text); + +static const struct snd_kcontrol_new dmic_mux = + SOC_DAPM_ENUM("DMIC Mux", dmic_enum); + +static const char * const cin_text[] = { + "ADC", "DMIC" +}; + +static SOC_ENUM_SINGLE_DECL(cin_enum, WM8904_DIGITAL_MICROPHONE_0, + WM8904_DMIC_ENA_SHIFT, cin_text); + +static const struct snd_kcontrol_new cin_mux = + SOC_DAPM_ENUM("Capture Input", cin_enum); + static const char *input_mode_text[] = { "Single-Ended", "Differential Line", "Differential Mic" }; @@ -963,6 +983,15 @@ SND_SOC_DAPM_AIF_OUT("AIFOUTL", "Capture", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_OUT("AIFOUTR", "Capture", 1, SND_SOC_NOPM, 0, 0), }; +static const struct snd_soc_dapm_widget wm8904_dmic_dapm_widgets[] = { +SND_SOC_DAPM_MUX("DMIC Mux", SND_SOC_NOPM, 0, 0, &dmic_mux), +}; + +static const struct snd_soc_dapm_widget wm8904_cin_dapm_widgets[] = { +SND_SOC_DAPM_MUX("Left Capture Input", SND_SOC_NOPM, 0, 0, &cin_mux), +SND_SOC_DAPM_MUX("Right Capture Input", SND_SOC_NOPM, 0, 0, &cin_mux), +}; + static const struct snd_soc_dapm_widget wm8904_dac_dapm_widgets[] = { SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0), @@ -1101,12 +1130,45 @@ static const struct snd_soc_dapm_route adc_intercon[] = { { "AIFOUTR", NULL, "AIFOUTR Mux" }, { "ADCL", NULL, "CLK_DSP" }, - { "ADCL", NULL, "Left Capture PGA" }, - { "ADCR", NULL, "CLK_DSP" }, +}; + +/* No DMICs, always connect PGAs */ +static const struct snd_soc_dapm_route cin_nodmic_con[] = { + { "ADCL", NULL, "Left Capture PGA" }, { "ADCR", NULL, "Right Capture PGA" }, }; +/* DMIC system in use: mux between ADC and DMICDAT1, 2 or both */ +static const struct snd_soc_dapm_route cin_adc_dmic_con[] = { + { "Left Capture Input", "ADC", "Left Capture PGA" }, + { "Right Capture Input", "ADC", "Right Capture PGA" }, + + { "ADCL", NULL, "Left Capture Input" }, + { "ADCR", NULL, "Right Capture Input" }, +}; + +/* IN1L as DMICDAT1 */ +static const struct snd_soc_dapm_route cin_dmic1_con[] = { + { "Left Capture Input", "DMIC", "IN1L" }, + { "Right Capture Input", "DMIC", "IN1L" }, +}; + +/* IN1R as DMICDAT2 */ +static const struct snd_soc_dapm_route cin_dmic2_con[] = { + { "Left Capture Input", "DMIC", "IN1R" }, + { "Right Capture Input", "DMIC", "IN1R" }, +}; + +/* DMICDAT1 and DMICDAT2: mux between them, ADC still used for IN2 and IN3 */ +static const struct snd_soc_dapm_route cin_2dmics_con[] = { + { "DMIC Mux", "DMIC1", "IN1L" }, + { "DMIC Mux", "DMIC2", "IN1R" }, + + { "Left Capture Input", "DMIC", "DMIC Mux" }, + { "Right Capture Input", "DMIC", "DMIC Mux" }, +}; + static const struct snd_soc_dapm_route dac_intercon[] = { { "DACL Mux", "Left", "AIFINL" }, { "DACL Mux", "Right", "AIFINR" }, @@ -1424,15 +1486,15 @@ static int wm8904_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int aif3 = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aif3 |= WM8904_LRCLK_DIR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aif1 |= WM8904_BCLK_DIR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif1 |= WM8904_BCLK_DIR; aif3 |= WM8904_LRCLK_DIR; break; @@ -2050,18 +2112,70 @@ static void wm8904_handle_retune_mobile_pdata(struct snd_soc_component *componen "Failed to add ReTune Mobile control: %d\n", ret); } +static void wm8904_handle_dmic_pdata(struct snd_soc_component *component) +{ + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); + struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component); + struct wm8904_pdata *pdata = wm8904->pdata; + unsigned int dmic_src; + + if (!pdata->in1l_as_dmicdat1 && !pdata->in1r_as_dmicdat2) { + snd_soc_dapm_add_routes(dapm, cin_nodmic_con, + ARRAY_SIZE(cin_nodmic_con)); + snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0, + WM8904_DMIC_ENA_MASK, 0); + return; + } + + /* Need a control and routing to switch between DMIC and ADC */ + snd_soc_dapm_new_controls(dapm, wm8904_cin_dapm_widgets, + ARRAY_SIZE(wm8904_cin_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, cin_adc_dmic_con, + ARRAY_SIZE(cin_adc_dmic_con)); + + if (pdata->in1l_as_dmicdat1 && pdata->in1r_as_dmicdat2) { + /* Need a control and routing to mux between DMICDAT1 and 2 */ + dev_dbg(component->dev, "DMICDAT1 and DMICDAT2 in use\n"); + snd_soc_dapm_new_controls(dapm, wm8904_dmic_dapm_widgets, + ARRAY_SIZE(wm8904_dmic_dapm_widgets)); + snd_soc_dapm_add_routes(dapm, cin_2dmics_con, + ARRAY_SIZE(cin_2dmics_con)); + return; + } + + /* Either DMICDAT1 or DMICDAT2 is in use, not both */ + if (pdata->in1l_as_dmicdat1) { + dmic_src = 0; + snd_soc_dapm_add_routes(dapm, cin_dmic1_con, + ARRAY_SIZE(cin_dmic1_con)); + } else { + dmic_src = 1; + snd_soc_dapm_add_routes(dapm, cin_dmic2_con, + ARRAY_SIZE(cin_dmic2_con)); + } + dev_dbg(component->dev, "DMIC_SRC (0 or 1): %d\n", dmic_src); + snd_soc_component_update_bits(component, WM8904_DIGITAL_MICROPHONE_0, + WM8904_DMIC_SRC_MASK, + dmic_src << WM8904_DMIC_SRC_SHIFT); +} + static void wm8904_handle_pdata(struct snd_soc_component *component) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(component); struct wm8904_priv *wm8904 = snd_soc_component_get_drvdata(component); struct wm8904_pdata *pdata = wm8904->pdata; int ret, i; if (!pdata) { + snd_soc_dapm_add_routes(dapm, cin_nodmic_con, + ARRAY_SIZE(cin_nodmic_con)); snd_soc_add_component_controls(component, wm8904_eq_controls, - ARRAY_SIZE(wm8904_eq_controls)); + ARRAY_SIZE(wm8904_eq_controls)); return; } + wm8904_handle_dmic_pdata(component); + dev_dbg(component->dev, "%d DRC configurations\n", pdata->num_drc_cfgs); if (pdata->num_drc_cfgs) { @@ -2117,10 +2231,11 @@ static int wm8904_probe(struct snd_soc_component *component) return -EINVAL; } - wm8904_handle_pdata(component); - wm8904_add_widgets(component); + /* This can add dependent widgets, so it is done after add_widgets */ + wm8904_handle_pdata(component); + return 0; } @@ -2168,6 +2283,184 @@ static const struct of_device_id wm8904_of_match[] = { MODULE_DEVICE_TABLE(of, wm8904_of_match); #endif +/** + * wm8904_read_cfg_reg_arr() - Reads a subarray from a DT u16 array + * + * @np: pointer to the device_node struct + * @regs_property: DT property of interest + * @size: size of subarrays within the array + * @idx: index of the subarray of interest + * @out: output + * + * Helper to read a subarray from a DT uint16-array, + * divided into equally sized arrays of size `size` + * + * Subset starts at `idx * size` and is of size `size` + * + * Return: 0 on success, negative error code otherwise + */ +static int wm8904_read_cfg_reg_arr(const struct device_node *np, + const char * const regs_property, + int size, int idx, + u16 * const out) +{ + int i, offset, ret; + + offset = idx * size; + + for (i = 0; i < size; i++) { + ret = of_property_read_u16_index(np, regs_property, i + offset, &out[i]); + if (ret) + return ret; + } + return 0; +} + +static int wm8904_parse_retune_cfg_regs(const struct device_node *np, + struct wm8904_pdata *pdata, int cfg_idx) +{ + return wm8904_read_cfg_reg_arr(np, "wlf,retune-mobile-cfg-regs", + WM8904_EQ_REGS, cfg_idx, + &pdata->retune_mobile_cfgs[cfg_idx].regs[0]); +} + +static int wm8904_parse_drc_cfg_regs(const struct device_node *np, + struct wm8904_pdata *pdata, int cfg_idx) +{ + return wm8904_read_cfg_reg_arr(np, "wlf,drc-cfg-regs", + WM8904_DRC_REGS, cfg_idx, + &pdata->drc_cfgs[cfg_idx].regs[0]); +} + +static int wm8904_parse_drc_cfg_from_of(struct i2c_client *i2c, + struct wm8904_pdata *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + int i, n_cfgs; + + n_cfgs = of_property_count_strings(np, "wlf,drc-cfg-names"); + if (n_cfgs == -EINVAL) + return 0; + + if (n_cfgs <= 0) { + dev_err(&i2c->dev, "Could not get wlf,drc-cfg-names length: %d", + n_cfgs); + return n_cfgs; + } + + pdata->drc_cfgs = devm_kzalloc(&i2c->dev, + n_cfgs * sizeof(struct wm8904_drc_cfg), + GFP_KERNEL); + if (!pdata->drc_cfgs) + return -ENOMEM; + + for (i = 0; i < n_cfgs; i++) { + if (wm8904_parse_drc_cfg_regs(np, pdata, i)) { + dev_err(&i2c->dev, + "Invalid 'wlf,drc-cfg-regs[%i,:]'\n", i); + return -EINVAL; + } + + if (of_property_read_string_index(np, "wlf,drc-cfg-names", i, + &pdata->drc_cfgs[i].name)) { + dev_err(&i2c->dev, + "Invalid 'wlf,drc-cfg-names[%i]'\n", i); + return -EINVAL; + } + } + + pdata->num_drc_cfgs = n_cfgs; + return 0; +} + +static int wm8904_parse_retune_cfg_from_of(struct i2c_client *i2c, + struct wm8904_pdata *pdata) +{ + const struct device_node *np = i2c->dev.of_node; + int i, n_cfgs; + + n_cfgs = of_property_count_strings(np, "wlf,retune-mobile-cfg-names"); + if (n_cfgs == -EINVAL) + return 0; + + if (n_cfgs <= 0) { + dev_err(&i2c->dev, + "Could not get wlf,retune-mobile-cfg-names length: %d", + n_cfgs); + return n_cfgs; + } + + pdata->retune_mobile_cfgs = devm_kzalloc(&i2c->dev, + n_cfgs * sizeof(struct wm8904_retune_mobile_cfg), + GFP_KERNEL); + if (!pdata->retune_mobile_cfgs) + return -ENOMEM; + + for (i = 0; i < n_cfgs; i++) { + if (wm8904_parse_retune_cfg_regs(np, pdata, i)) { + dev_err(&i2c->dev, + "Invalid 'wlf,retune-mobile-cfg-regs[%i,:]'\n", i); + return -EINVAL; + } + + if (of_property_read_u32_index(np, "wlf,retune-mobile-cfg-hz", i, + &pdata->retune_mobile_cfgs[i].rate)) { + dev_err(&i2c->dev, + "Invalid 'wlf,retune-mobile-cfg-hz[%i]'\n", i); + return -EINVAL; + } + + if (of_property_read_string_index(np, "wlf,retune-mobile-cfg-names", i, + &pdata->retune_mobile_cfgs[i].name)) { + dev_err(&i2c->dev, + "Invalid 'wlf,retune-mobile-cfg-names[%i]'\n", i); + return -EINVAL; + } + } + + pdata->num_retune_mobile_cfgs = n_cfgs; + return 0; +} + +static int wm8904_set_pdata_from_of(struct i2c_client *i2c, + struct wm8904_priv *wm8904) +{ + const struct device_node *np = i2c->dev.of_node; + struct wm8904_pdata *pdata; + int ret, i; + + pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->in1l_as_dmicdat1 = + of_property_read_bool(np, "wlf,in1l-as-dmicdat1"); + + pdata->in1r_as_dmicdat2 = + of_property_read_bool(np, "wlf,in1r-as-dmicdat2"); + + /* If absent, default to 0xFFFF for GPIO config (i.e.: don't set) */ + for (i = 0; i < WM8904_GPIO_REGS; i++) + pdata->gpio_cfg[i] = 0xFFFF; + + of_property_read_u32_array(np, "wlf,gpio-cfg", pdata->gpio_cfg, + ARRAY_SIZE(pdata->gpio_cfg)); + + of_property_read_u32_array(np, "wlf,micbias-cfg", pdata->mic_cfg, + ARRAY_SIZE(pdata->mic_cfg)); + + ret = wm8904_parse_drc_cfg_from_of(i2c, pdata); + if (ret) + return ret; + + ret = wm8904_parse_retune_cfg_from_of(i2c, pdata); + if (ret) + return ret; + + wm8904->pdata = pdata; + return 0; +} + static const struct i2c_device_id wm8904_i2c_id[]; static int wm8904_i2c_probe(struct i2c_client *i2c) @@ -2199,7 +2492,16 @@ static int wm8904_i2c_probe(struct i2c_client *i2c) wm8904->devtype = (uintptr_t)i2c_get_match_data(i2c); i2c_set_clientdata(i2c, wm8904); - wm8904->pdata = i2c->dev.platform_data; + + if (i2c->dev.of_node) { + ret = wm8904_set_pdata_from_of(i2c, wm8904); + if (ret) { + dev_err(&i2c->dev, "Failed to set platform data from of: %d\n", ret); + return ret; + } + } else { + wm8904->pdata = i2c->dev.platform_data; + } for (i = 0; i < ARRAY_SIZE(wm8904->supplies); i++) wm8904->supplies[i].supply = wm8904_supply_names[i]; @@ -2270,7 +2572,8 @@ static int wm8904_i2c_probe(struct i2c_client *i2c) /* Apply configuration from the platform data. */ if (wm8904->pdata) { for (i = 0; i < WM8904_GPIO_REGS; i++) { - if (!wm8904->pdata->gpio_cfg[i]) + /* 0xFFFF in this config means "don't touch" */ + if (wm8904->pdata->gpio_cfg[i] == 0xffff) continue; regmap_update_bits(wm8904->regmap, diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 8a532f7d750c..401ee20897b1 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -343,10 +343,10 @@ static int wm8940_set_dai_fmt(struct snd_soc_dai *codec_dai, u16 clk = snd_soc_component_read(component, WM8940_CLOCK) & 0x1fe; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: clk |= 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index bae52a8a2e11..bca83410b432 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -671,9 +671,9 @@ static int wm8955_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) u16 aif = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif |= WM8955_MS; break; default: diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 00858b9c9568..e6525b4cedfb 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -540,10 +540,10 @@ static int wm8960_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: iface |= 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index d1c731e25777..1ec7c5e8fd69 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -627,10 +627,10 @@ static int wm8961_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) WM8961_MS | WM8961_FORMAT_MASK); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif |= WM8961_MS; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index 08d164ce3e49..68f746626c33 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -2762,10 +2762,10 @@ static int wm8962_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif0 |= WM8962_MSTR; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -3850,7 +3850,6 @@ static void wm8962_i2c_remove(struct i2c_client *client) pm_runtime_disable(&client->dev); } -#ifdef CONFIG_PM static int wm8962_runtime_resume(struct device *dev) { struct wm8962_priv *wm8962 = dev_get_drvdata(dev); @@ -3930,11 +3929,10 @@ static int wm8962_runtime_suspend(struct device *dev) return 0; } -#endif static const struct dev_pm_ops wm8962_pm = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) + RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) }; static const struct i2c_device_id wm8962_i2c_id[] = { @@ -3953,7 +3951,7 @@ static struct i2c_driver wm8962_i2c_driver = { .driver = { .name = "wm8962", .of_match_table = wm8962_of_match, - .pm = &wm8962_pm, + .pm = pm_ptr(&wm8962_pm), }, .probe = wm8962_i2c_probe, .remove = wm8962_i2c_remove, diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b97c7d5bd4e7..62dcddeb78b3 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -452,10 +452,10 @@ static int wm8971_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: iface = 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 0ee3655cad01..bdf437a5403f 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -454,10 +454,10 @@ static int wm8974_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: clk |= 0x0001; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index 40d22b36b7a9..8c45ba6fc4c3 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -660,10 +660,10 @@ static int wm8978_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: clk |= 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: clk &= ~1; break; default: diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 252b4a6cac04..6a83afe6400b 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -594,10 +594,10 @@ static int wm8983_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) WM8983_FMT_MASK, format << WM8983_FMT_SHIFT); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: master = 0; break; default: diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index da00db5b0172..2e2d07193c41 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -688,10 +688,10 @@ static int wm8985_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) WM8985_FMT_MASK, format << WM8985_FMT_SHIFT); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: master = 0; break; default: diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index f0e9d6e38dc0..cf6d642b7bfe 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -589,10 +589,10 @@ static int wm8988_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: iface = 0x0040; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 573bd3d487ba..89df406bf552 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -897,10 +897,10 @@ static int wm8990_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: audio3 &= ~WM8990_AIF_MSTR1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: audio3 |= WM8990_AIF_MSTR1; break; default: diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 3bd9b362051b..c3dd44c1dd0c 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -958,10 +958,10 @@ static int wm8991_set_dai_fmt(struct snd_soc_dai *codec_dai, /* set master/slave audio interface */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: audio3 &= ~WM8991_AIF_MSTR1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: audio3 |= WM8991_AIF_MSTR1; break; default: diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index f257980f9b56..9be4f6cadba3 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1098,18 +1098,18 @@ static int wm8993_set_dai_fmt(struct snd_soc_dai *dai, aif4 &= ~WM8993_LRCLK_DIR; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: wm8993->master = 0; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aif4 |= WM8993_LRCLK_DIR; wm8993->master = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aif1 |= WM8993_BCLK_DIR; wm8993->master = 1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif1 |= WM8993_BCLK_DIR; aif4 |= WM8993_LRCLK_DIR; wm8993->master = 1; diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c index a4abe6e53bfc..240ec1bed234 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -2783,9 +2783,9 @@ static int wm8994_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: ms = WM8994_AIF1_MSTR; break; default: @@ -4662,7 +4662,6 @@ static void wm8994_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int wm8994_suspend(struct device *dev) { struct wm8994_priv *wm8994 = dev_get_drvdata(dev); @@ -4687,16 +4686,15 @@ static int wm8994_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops wm8994_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume) + SYSTEM_SLEEP_PM_OPS(wm8994_suspend, wm8994_resume) }; static struct platform_driver wm8994_codec_driver = { .driver = { .name = "wm8994-codec", - .pm = &wm8994_pm_ops, + .pm = pm_ptr(&wm8994_pm_ops), }, .probe = wm8994_probe, .remove = wm8994_remove, diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 1f9a9b636935..a88170a3ed91 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -1448,9 +1448,9 @@ static int wm8995_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) master = 0; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: master = WM8995_AIF1_MSTR; break; default: diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 5c06cea09bd1..c2af8d7ecdd8 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -1672,16 +1672,16 @@ static int wm8996_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR; lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: bclk |= WM8996_AIF1_BCLK_MSTR; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: bclk |= WM8996_AIF1_BCLK_MSTR; lrclk_tx |= WM8996_AIF1TX_LRCLK_MSTR; lrclk_rx |= WM8996_AIF1RX_LRCLK_MSTR; diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index cb9d040b34d6..94d8571360c4 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -907,18 +907,18 @@ static int wm9081_set_dai_fmt(struct snd_soc_dai *dai, WM9081_BCLK_DIR | WM9081_LRCLK_DIR | WM9081_AIF_FMT_MASK); switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: wm9081->master = 0; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: aif2 |= WM9081_LRCLK_DIR; wm9081->master = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: aif2 |= WM9081_BCLK_DIR; wm9081->master = 1; break; - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: aif2 |= WM9081_LRCLK_DIR | WM9081_BCLK_DIR; wm9081->master = 1; break; diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index e63921de0c37..8ff4b5f13b3a 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -275,13 +275,9 @@ static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol, return 0; } -#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_soc_info_volsw, \ - .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \ - .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \ - (xmixer << 8) | xshift, 1, 0, 0) \ -} +#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) \ + SOC_SINGLE_EXT(xname, SND_SOC_NOPM, ((xmixer) << 8) | (xshift), \ + 1, 0, wm9712_hp_mixer_get, wm9712_hp_mixer_put) /* Left Headphone Mixers */ static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = { diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 64b69316e4c7..5f1b0f5c1a58 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -284,13 +284,9 @@ static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol, return 0; } -#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_soc_info_volsw, \ - .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \ - .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \ - xshift, xmixer, 1, 0, 0) \ -} +#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) \ + SOC_DOUBLE_EXT(xname, SND_SOC_NOPM, xshift, xmixer, 1, 0, \ + wm9713_hp_mixer_get, wm9713_hp_mixer_put) /* Left Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { @@ -944,19 +940,19 @@ static int wm9713_set_dai_fmt(struct snd_soc_dai *codec_dai, /* clock masters */ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: reg |= 0x4000; gpio |= 0x0010; break; - case SND_SOC_DAIFMT_CBM_CFS: + case SND_SOC_DAIFMT_CBP_CFC: reg |= 0x6000; gpio |= 0x0018; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: reg |= 0x2000; gpio |= 0x001a; break; - case SND_SOC_DAIFMT_CBS_CFM: + case SND_SOC_DAIFMT_CBC_CFP: gpio |= 0x0012; break; } diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 0c881846f485..196ddb224e6d 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -14,6 +14,7 @@ #include <linux/pm.h> #include <linux/i2c.h> #include <linux/mfd/wm8994/registers.h> +#include <linux/string_choices.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -674,7 +675,7 @@ void wm_hubs_update_class_w(struct snd_soc_component *component) if (hubs->check_class_w_digital && !hubs->check_class_w_digital(component)) enable = false; - dev_vdbg(component->dev, "Class W %s\n", enable ? "enabled" : "disabled"); + dev_vdbg(component->dev, "Class W %s\n", str_enabled_disabled(enable)); snd_soc_component_update_bits(component, WM8993_CLASS_W_0, WM8993_CP_DYN_V | WM8993_CP_DYN_FREQ, enable); diff --git a/sound/soc/codecs/wsa881x.c b/sound/soc/codecs/wsa881x.c index dd2d6661adc7..6627d2da3722 100644 --- a/sound/soc/codecs/wsa881x.c +++ b/sound/soc/codecs/wsa881x.c @@ -199,13 +199,8 @@ #define WSA881X_PROBE_TIMEOUT 1000 #define WSA881X_PA_GAIN_TLV(xname, reg, shift, max, invert, tlv_array) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |\ - SNDRV_CTL_ELEM_ACCESS_READWRITE,\ - .tlv.p = (tlv_array), \ - .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\ - .put = wsa881x_put_pa_gain, \ - .private_value = SOC_SINGLE_VALUE(reg, shift, max, invert, 0) } + SOC_SINGLE_EXT_TLV(xname, reg, shift, max, invert, \ + snd_soc_get_volsw, wsa881x_put_pa_gain, tlv_array) static struct reg_default wsa881x_defaults[] = { { WSA881X_CHIP_ID0, 0x00 }, @@ -1174,7 +1169,7 @@ static int wsa881x_probe(struct sdw_slave *pdev, ARRAY_SIZE(wsa881x_dais)); } -static int __maybe_unused wsa881x_runtime_suspend(struct device *dev) +static int wsa881x_runtime_suspend(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); struct wsa881x_priv *wsa881x = dev_get_drvdata(dev); @@ -1187,7 +1182,7 @@ static int __maybe_unused wsa881x_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wsa881x_runtime_resume(struct device *dev) +static int wsa881x_runtime_resume(struct device *dev) { struct sdw_slave *slave = dev_to_sdw_dev(dev); struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -1211,7 +1206,7 @@ static int __maybe_unused wsa881x_runtime_resume(struct device *dev) } static const struct dev_pm_ops wsa881x_pm_ops = { - SET_RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL) + RUNTIME_PM_OPS(wsa881x_runtime_suspend, wsa881x_runtime_resume, NULL) }; static const struct sdw_device_id wsa881x_slave_id[] = { @@ -1227,7 +1222,7 @@ static struct sdw_driver wsa881x_codec_driver = { .id_table = wsa881x_slave_id, .driver = { .name = "wsa881x-codec", - .pm = &wsa881x_pm_ops, + .pm = pm_ptr(&wsa881x_pm_ops), } }; module_sdw_driver(wsa881x_codec_driver); diff --git a/sound/soc/codecs/wsa883x.c b/sound/soc/codecs/wsa883x.c index 47da5674d7c9..d259e1d4d83d 100644 --- a/sound/soc/codecs/wsa883x.c +++ b/sound/soc/codecs/wsa883x.c @@ -6,6 +6,7 @@ #include <linux/bitops.h> #include <linux/device.h> #include <linux/gpio/consumer.h> +#include <linux/hwmon.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> @@ -156,8 +157,28 @@ #define WSA883X_PA_FSM_ERR_COND (WSA883X_DIG_CTRL_BASE + 0x0014) #define WSA883X_PA_FSM_MSK (WSA883X_DIG_CTRL_BASE + 0x0015) #define WSA883X_PA_FSM_BYP (WSA883X_DIG_CTRL_BASE + 0x0016) +#define WSA883X_PA_FSM_BYP_DC_CAL_EN_MASK 0x01 +#define WSA883X_PA_FSM_BYP_DC_CAL_EN_SHIFT 0 +#define WSA883X_PA_FSM_BYP_CLK_WD_EN_MASK 0x02 +#define WSA883X_PA_FSM_BYP_CLK_WD_EN_SHIFT 1 +#define WSA883X_PA_FSM_BYP_BG_EN_MASK 0x04 +#define WSA883X_PA_FSM_BYP_BG_EN_SHIFT 2 +#define WSA883X_PA_FSM_BYP_BOOST_EN_MASK 0x08 +#define WSA883X_PA_FSM_BYP_BOOST_EN_SHIFT 3 +#define WSA883X_PA_FSM_BYP_PA_EN_MASK 0x10 +#define WSA883X_PA_FSM_BYP_PA_EN_SHIFT 4 +#define WSA883X_PA_FSM_BYP_D_UNMUTE_MASK 0x20 +#define WSA883X_PA_FSM_BYP_D_UNMUTE_SHIFT 5 +#define WSA883X_PA_FSM_BYP_SPKR_PROT_EN_MASK 0x40 +#define WSA883X_PA_FSM_BYP_SPKR_PROT_EN_SHIFT 6 +#define WSA883X_PA_FSM_BYP_TSADC_EN_MASK 0x80 +#define WSA883X_PA_FSM_BYP_TSADC_EN_SHIFT 7 #define WSA883X_PA_FSM_DBG (WSA883X_DIG_CTRL_BASE + 0x0017) #define WSA883X_TADC_VALUE_CTL (WSA883X_DIG_CTRL_BASE + 0x0020) +#define WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK 0x01 +#define WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_SHIFT 0 +#define WSA883X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_MASK 0x02 +#define WSA883X_TADC_VALUE_CTL_VBAT_VALUE_RD_EN_SHIFT 1 #define WSA883X_TEMP_DETECT_CTL (WSA883X_DIG_CTRL_BASE + 0x0021) #define WSA883X_TEMP_MSB (WSA883X_DIG_CTRL_BASE + 0x0022) #define WSA883X_TEMP_LSB (WSA883X_DIG_CTRL_BASE + 0x0023) @@ -427,6 +448,17 @@ SNDRV_PCM_FMTBIT_S24_LE |\ SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE) +/* Two-point trimming for temperature calibration */ +#define WSA883X_T1_TEMP -10L +#define WSA883X_T2_TEMP 150L + +/* + * Device will report senseless data in many cases, so discard any measurements + * outside of valid range. + */ +#define WSA883X_LOW_TEMP_THRESHOLD 5 +#define WSA883X_HIGH_TEMP_THRESHOLD 45 + struct wsa883x_priv { struct regmap *regmap; struct device *dev; @@ -441,6 +473,13 @@ struct wsa883x_priv { int active_ports; int dev_mode; int comp_offset; + /* + * Protects temperature reading code (related to speaker protection) and + * fields: temperature and pa_on. + */ + struct mutex sp_lock; + unsigned int temperature; + bool pa_on; }; enum { @@ -1186,6 +1225,10 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, switch (event) { case SND_SOC_DAPM_POST_PMU: + mutex_lock(&wsa883x->sp_lock); + wsa883x->pa_on = true; + mutex_unlock(&wsa883x->sp_lock); + switch (wsa883x->dev_mode) { case RECEIVER: snd_soc_component_write_field(component, WSA883X_CDC_PATH_MODE, @@ -1235,6 +1278,9 @@ static int wsa883x_spkr_event(struct snd_soc_dapm_widget *w, WSA883X_GLOBAL_PA_EN_MASK, 0); snd_soc_component_write_field(component, WSA883X_PDM_WD_CTL, WSA883X_PDM_EN_MASK, 0); + mutex_lock(&wsa883x->sp_lock); + wsa883x->pa_on = false; + mutex_unlock(&wsa883x->sp_lock); break; } return 0; @@ -1367,6 +1413,140 @@ static struct snd_soc_dai_driver wsa883x_dais[] = { }, }; +static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp) +{ + unsigned int d1_msb = 0, d1_lsb = 0, d2_msb = 0, d2_lsb = 0; + unsigned int dmeas_msb = 0, dmeas_lsb = 0; + int d1, d2, dmeas; + unsigned int mask; + int ret, range; + long val; + + guard(mutex)(&wsa883x->sp_lock); + + if (wsa883x->pa_on) { + /* + * Reading temperature is possible only when Power Amplifier is + * off. Report last cached data. + */ + *temp = wsa883x->temperature * 1000; + return 0; + } + + ret = pm_runtime_resume_and_get(wsa883x->dev); + if (ret < 0) + return ret; + + mask = WSA883X_PA_FSM_BYP_DC_CAL_EN_MASK | + WSA883X_PA_FSM_BYP_CLK_WD_EN_MASK | + WSA883X_PA_FSM_BYP_BG_EN_MASK | + WSA883X_PA_FSM_BYP_D_UNMUTE_MASK | + WSA883X_PA_FSM_BYP_SPKR_PROT_EN_MASK | + WSA883X_PA_FSM_BYP_TSADC_EN_MASK; + + /* + * Here and further do not care about read or update failures. + * For example, before turning the amplifier on for the first + * time, reading WSA883X_TEMP_DIN_MSB will always return 0. + * Instead, check if returned value is within reasonable + * thresholds. + */ + regmap_update_bits(wsa883x->regmap, WSA883X_PA_FSM_BYP, mask, mask); + + regmap_update_bits(wsa883x->regmap, WSA883X_TADC_VALUE_CTL, + WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, + FIELD_PREP(WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x0)); + + regmap_read(wsa883x->regmap, WSA883X_TEMP_MSB, &dmeas_msb); + regmap_read(wsa883x->regmap, WSA883X_TEMP_LSB, &dmeas_lsb); + + regmap_update_bits(wsa883x->regmap, WSA883X_TADC_VALUE_CTL, + WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, + FIELD_PREP(WSA883X_TADC_VALUE_CTL_TEMP_VALUE_RD_EN_MASK, 0x1)); + + regmap_read(wsa883x->regmap, WSA883X_OTP_REG_1, &d1_msb); + regmap_read(wsa883x->regmap, WSA883X_OTP_REG_2, &d1_lsb); + regmap_read(wsa883x->regmap, WSA883X_OTP_REG_3, &d2_msb); + regmap_read(wsa883x->regmap, WSA883X_OTP_REG_4, &d2_lsb); + + regmap_update_bits(wsa883x->regmap, WSA883X_PA_FSM_BYP, mask, 0x0); + + dmeas = (((dmeas_msb & 0xff) << 0x8) | (dmeas_lsb & 0xff)) >> 0x6; + d1 = (((d1_msb & 0xff) << 0x8) | (d1_lsb & 0xff)) >> 0x6; + d2 = (((d2_msb & 0xff) << 0x8) | (d2_lsb & 0xff)) >> 0x6; + + if (d1 == d2) { + /* Incorrect data in OTP? */ + ret = -EINVAL; + goto out; + } + + val = WSA883X_T1_TEMP + (((dmeas - d1) * (WSA883X_T2_TEMP - WSA883X_T1_TEMP)) / (d2 - d1)); + range = WSA883X_HIGH_TEMP_THRESHOLD - WSA883X_LOW_TEMP_THRESHOLD; + if (in_range(val, WSA883X_LOW_TEMP_THRESHOLD, range)) { + wsa883x->temperature = val; + *temp = val * 1000; + ret = 0; + } else { + ret = -EAGAIN; + } +out: + pm_runtime_mark_last_busy(wsa883x->dev); + pm_runtime_put_autosuspend(wsa883x->dev); + + return ret; +} + +static umode_t wsa883x_hwmon_is_visible(const void *data, + enum hwmon_sensor_types type, u32 attr, + int channel) +{ + if (type != hwmon_temp) + return 0; + + switch (attr) { + case hwmon_temp_input: + return 0444; + default: + break; + } + + return 0; +} + +static int wsa883x_hwmon_read(struct device *dev, + enum hwmon_sensor_types type, + u32 attr, int channel, long *temp) +{ + int ret; + + switch (attr) { + case hwmon_temp_input: + ret = wsa883x_get_temp(dev_get_drvdata(dev), temp); + break; + default: + ret = -EOPNOTSUPP; + break; + } + + return ret; +} + +static const struct hwmon_channel_info *const wsa883x_hwmon_info[] = { + HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT), + NULL +}; + +static const struct hwmon_ops wsa883x_hwmon_ops = { + .is_visible = wsa883x_hwmon_is_visible, + .read = wsa883x_hwmon_read, +}; + +static const struct hwmon_chip_info wsa883x_hwmon_chip_info = { + .ops = &wsa883x_hwmon_ops, + .info = wsa883x_hwmon_info, +}; + static int wsa883x_probe(struct sdw_slave *pdev, const struct sdw_device_id *id) { @@ -1402,6 +1582,7 @@ static int wsa883x_probe(struct sdw_slave *pdev, wsa883x->sconfig.bps = 1; wsa883x->sconfig.direction = SDW_DATA_DIR_RX; wsa883x->sconfig.type = SDW_STREAM_PDM; + mutex_init(&wsa883x->sp_lock); /** * Port map index starts with 0, however the data port for this codec @@ -1424,6 +1605,19 @@ static int wsa883x_probe(struct sdw_slave *pdev, "regmap_init failed\n"); goto err; } + + if (IS_REACHABLE(CONFIG_HWMON)) { + struct device *hwmon; + + hwmon = devm_hwmon_device_register_with_info(dev, "wsa883x", + wsa883x, + &wsa883x_hwmon_chip_info, + NULL); + if (IS_ERR(hwmon)) + return dev_err_probe(dev, PTR_ERR(hwmon), + "Failed to register hwmon sensor\n"); + } + pm_runtime_set_autosuspend_delay(dev, 3000); pm_runtime_use_autosuspend(dev); pm_runtime_mark_last_busy(dev); @@ -1442,7 +1636,7 @@ err: } -static int __maybe_unused wsa883x_runtime_suspend(struct device *dev) +static int wsa883x_runtime_suspend(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -1452,7 +1646,7 @@ static int __maybe_unused wsa883x_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wsa883x_runtime_resume(struct device *dev) +static int wsa883x_runtime_resume(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -1463,7 +1657,7 @@ static int __maybe_unused wsa883x_runtime_resume(struct device *dev) } static const struct dev_pm_ops wsa883x_pm_ops = { - SET_RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL) + RUNTIME_PM_OPS(wsa883x_runtime_suspend, wsa883x_runtime_resume, NULL) }; static const struct sdw_device_id wsa883x_swr_id[] = { @@ -1476,7 +1670,7 @@ MODULE_DEVICE_TABLE(sdw, wsa883x_swr_id); static struct sdw_driver wsa883x_codec_driver = { .driver = { .name = "wsa883x-codec", - .pm = &wsa883x_pm_ops, + .pm = pm_ptr(&wsa883x_pm_ops), .suppress_bind_attrs = true, }, .probe = wsa883x_probe, diff --git a/sound/soc/codecs/wsa884x.c b/sound/soc/codecs/wsa884x.c index 560a2c04b695..8051483aa1ac 100644 --- a/sound/soc/codecs/wsa884x.c +++ b/sound/soc/codecs/wsa884x.c @@ -2136,7 +2136,7 @@ static int wsa884x_probe(struct sdw_slave *pdev, ARRAY_SIZE(wsa884x_dais)); } -static int __maybe_unused wsa884x_runtime_suspend(struct device *dev) +static int wsa884x_runtime_suspend(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -2146,7 +2146,7 @@ static int __maybe_unused wsa884x_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused wsa884x_runtime_resume(struct device *dev) +static int wsa884x_runtime_resume(struct device *dev) { struct regmap *regmap = dev_get_regmap(dev, NULL); @@ -2157,7 +2157,7 @@ static int __maybe_unused wsa884x_runtime_resume(struct device *dev) } static const struct dev_pm_ops wsa884x_pm_ops = { - SET_RUNTIME_PM_OPS(wsa884x_runtime_suspend, wsa884x_runtime_resume, NULL) + RUNTIME_PM_OPS(wsa884x_runtime_suspend, wsa884x_runtime_resume, NULL) }; static const struct sdw_device_id wsa884x_swr_id[] = { @@ -2169,7 +2169,7 @@ MODULE_DEVICE_TABLE(sdw, wsa884x_swr_id); static struct sdw_driver wsa884x_codec_driver = { .driver = { .name = "wsa884x-codec", - .pm = &wsa884x_pm_ops, + .pm = pm_ptr(&wsa884x_pm_ops), }, .probe = wsa884x_probe, .ops = &wsa884x_slave_ops, diff --git a/sound/soc/dwc/dwc-i2s.c b/sound/soc/dwc/dwc-i2s.c index 57b789d7fbed..4c4171bb3fbb 100644 --- a/sound/soc/dwc/dwc-i2s.c +++ b/sound/soc/dwc/dwc-i2s.c @@ -478,7 +478,6 @@ static const struct snd_soc_dai_ops dw_i2s_dai_ops = { .set_tdm_slot = dw_i2s_set_tdm_slot, }; -#ifdef CONFIG_PM static int dw_i2s_runtime_suspend(struct device *dev) { struct dw_i2s_dev *dw_dev = dev_get_drvdata(dev); @@ -501,6 +500,7 @@ static int dw_i2s_runtime_resume(struct device *dev) return 0; } +#ifdef CONFIG_PM static int dw_i2s_suspend(struct snd_soc_component *component) { struct dw_i2s_dev *dev = snd_soc_component_get_drvdata(component); @@ -1084,7 +1084,7 @@ MODULE_DEVICE_TABLE(of, dw_i2s_of_match); #endif static const struct dev_pm_ops dwc_pm_ops = { - SET_RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL) + RUNTIME_PM_OPS(dw_i2s_runtime_suspend, dw_i2s_runtime_resume, NULL) }; static struct platform_driver dw_i2s_driver = { @@ -1093,7 +1093,7 @@ static struct platform_driver dw_i2s_driver = { .driver = { .name = "designware-i2s", .of_match_table = of_match_ptr(dw_i2s_of_match), - .pm = &dwc_pm_ops, + .pm = pm_ptr(&dwc_pm_ops), }, }; diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index 2bad9cb1daaf..ab583b432c60 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -759,7 +759,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; } else if (of_device_is_compatible(np, "fsl,imx-audio-tlv320aic31xx")) { codec_dai_name[0] = "tlv320dac31xx-hifi"; - priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; + priv->dai_fmt |= SND_SOC_DAIFMT_CBC_CFC; priv->dai_link[1].playback_only = 1; priv->dai_link[2].playback_only = 1; priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT; @@ -818,7 +818,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) priv->codec_priv[0].mclk_id = NAU8822_CLK_MCLK; priv->codec_priv[0].fll_id = NAU8822_CLK_PLL; priv->codec_priv[0].pll_id = NAU8822_CLK_PLL; - priv->dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + priv->dai_fmt |= SND_SOC_DAIFMT_CBP_CFP; if (codec_dev[0]) priv->codec_priv[0].mclk = devm_clk_get(codec_dev[0], NULL); } else if (of_device_is_compatible(np, "fsl,imx-audio-wm8904")) { diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index bde642318835..da401561e2de 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -290,8 +290,7 @@ static int fsl_aud2htx_runtime_resume(struct device *dev) static const struct dev_pm_ops fsl_aud2htx_pm_ops = { RUNTIME_PM_OPS(fsl_aud2htx_runtime_suspend, fsl_aud2htx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver fsl_aud2htx_driver = { diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 3cd9a66b70a1..7981d598ba13 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -488,11 +488,17 @@ static int fsl_audmix_probe(struct platform_device *pdev) goto err_disable_pm; } - priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0); - if (IS_ERR(priv->pdev)) { - ret = PTR_ERR(priv->pdev); - dev_err(dev, "failed to register platform: %d\n", ret); - goto err_disable_pm; + /* + * If dais property exist, then register the imx-audmix card driver. + * otherwise, it should be linked by audio graph card. + */ + if (of_find_property(pdev->dev.of_node, "dais", NULL)) { + priv->pdev = platform_device_register_data(dev, "imx-audmix", 0, NULL, 0); + if (IS_ERR(priv->pdev)) { + ret = PTR_ERR(priv->pdev); + dev_err(dev, "failed to register platform: %d\n", ret); + goto err_disable_pm; + } } return 0; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 0b247f16a163..cde0b0c6c1ef 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -1189,11 +1189,8 @@ static int fsl_esai_runtime_suspend(struct device *dev) } static const struct dev_pm_ops fsl_esai_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_esai_runtime_suspend, - fsl_esai_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_esai_runtime_suspend, fsl_esai_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver fsl_esai_driver = { @@ -1201,7 +1198,7 @@ static struct platform_driver fsl_esai_driver = { .remove = fsl_esai_remove, .driver = { .name = "fsl-esai-dai", - .pm = &fsl_esai_pm_ops, + .pm = pm_ptr(&fsl_esai_pm_ops), .of_match_table = fsl_esai_dt_ids, }, }; diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index fa4136683392..aabd90a8b3ec 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -19,6 +19,7 @@ #include <linux/dma/imx-dma.h> #include <sound/dmaengine_pcm.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <sound/soc.h> #include <sound/tlv.h> #include <sound/core.h> @@ -78,6 +79,7 @@ struct fsl_micfil { struct fsl_micfil_verid verid; struct fsl_micfil_param param; bool mclk_flag; /* mclk enable flag */ + bool dec_bypass; }; struct fsl_micfil_soc_data { @@ -129,7 +131,7 @@ static struct fsl_micfil_soc_data fsl_micfil_imx943 = { .fifos = 8, .fifo_depth = 32, .dataline = 0xf, - .formats = SNDRV_PCM_FMTBIT_S32_LE, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_DSD_U32_BE, .use_edma = true, .use_verid = true, .volume_sx = false, @@ -724,14 +726,14 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, if (ret) return ret; - if (micfil->vad_enabled) + if (micfil->vad_enabled && !micfil->dec_bypass) fsl_micfil_hwvad_enable(micfil); break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (micfil->vad_enabled) + if (micfil->vad_enabled && !micfil->dec_bypass) fsl_micfil_hwvad_disable(micfil); /* Disable the module */ @@ -778,8 +780,9 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, { struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai); unsigned int channels = params_channels(params); + snd_pcm_format_t format = params_format(params); unsigned int rate = params_rate(params); - int clk_div = 8; + int clk_div = 8, mclk_rate, div_multiply_k; int osr = MICFIL_OSR_DEFAULT; int ret; @@ -801,7 +804,39 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, micfil->mclk_flag = true; - ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); + /* floor(K * CLKDIV) */ + switch (micfil->quality) { + case QUALITY_HIGH: + div_multiply_k = clk_div >> 1; + break; + case QUALITY_LOW: + case QUALITY_VLOW1: + div_multiply_k = clk_div << 1; + break; + case QUALITY_VLOW2: + div_multiply_k = clk_div << 2; + break; + case QUALITY_MEDIUM: + case QUALITY_VLOW0: + default: + div_multiply_k = clk_div; + break; + } + + if (format == SNDRV_PCM_FORMAT_DSD_U32_BE) { + micfil->dec_bypass = true; + /* + * According to equation 29 in RM: + * MCLK_CLK_ROOT = PDM CLK rate * 2 * floor(K * CLKDIV) + * PDM CLK rate = rate * physical bit width (32) + */ + mclk_rate = rate * div_multiply_k * 32 * 2; + } else { + micfil->dec_bypass = false; + mclk_rate = rate * clk_div * osr * 8; + } + + ret = clk_set_rate(micfil->mclk, mclk_rate); if (ret) return ret; @@ -809,6 +844,10 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; + regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, + MICFIL_CTRL2_DEC_BYPASS, + micfil->dec_bypass ? MICFIL_CTRL2_DEC_BYPASS : 0); + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_CTRL2, MICFIL_CTRL2_CLKDIV | MICFIL_CTRL2_CICOSR, FIELD_PREP(MICFIL_CTRL2_CLKDIV, clk_div) | @@ -1473,11 +1512,8 @@ static int fsl_micfil_runtime_resume(struct device *dev) } static const struct dev_pm_ops fsl_micfil_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, - fsl_micfil_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_micfil_runtime_suspend, fsl_micfil_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver fsl_micfil_driver = { @@ -1485,7 +1521,7 @@ static struct platform_driver fsl_micfil_driver = { .remove = fsl_micfil_remove, .driver = { .name = "fsl-micfil-dai", - .pm = &fsl_micfil_pm_ops, + .pm = pm_ptr(&fsl_micfil_pm_ops), .of_match_table = fsl_micfil_dt_ids, }, }; diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index aa3661ea4ffc..fdfe4e7125bc 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -53,6 +53,7 @@ #define MICFIL_CTRL1_CHEN(ch) BIT(ch) /* MICFIL Control Register 2 -- REG_MICFILL_CTRL2 0x04 */ +#define MICFIL_CTRL2_DEC_BYPASS BIT(31) #define MICFIL_CTRL2_QSEL_SHIFT 25 #define MICFIL_CTRL2_QSEL GENMASK(27, 25) #define MICFIL_QSEL_MEDIUM_QUALITY 0 diff --git a/sound/soc/fsl/fsl_qmc_audio.c b/sound/soc/fsl/fsl_qmc_audio.c index e257b8adafe0..b2979290c973 100644 --- a/sound/soc/fsl/fsl_qmc_audio.c +++ b/sound/soc/fsl/fsl_qmc_audio.c @@ -892,7 +892,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_soc_dai_driver->playback.channels_max = count > 1 ? count : nb_tx_ts; } qmc_soc_dai_driver->playback.formats = qmc_audio_formats(nb_tx_ts, - count > 1 ? true : false); + count > 1); qmc_soc_dai_driver->capture.channels_min = 0; qmc_soc_dai_driver->capture.channels_max = 0; @@ -901,7 +901,7 @@ static int qmc_audio_dai_parse(struct qmc_audio *qmc_audio, struct device_node * qmc_soc_dai_driver->capture.channels_max = count > 1 ? count : nb_rx_ts; } qmc_soc_dai_driver->capture.formats = qmc_audio_formats(nb_rx_ts, - count > 1 ? true : false); + count > 1); qmc_soc_dai_driver->playback.rates = snd_pcm_rate_to_rate_bit(tx_fs_rate); qmc_soc_dai_driver->playback.rate_min = tx_fs_rate; diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 9f33dd11d47f..ed2b4780c470 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -1817,10 +1817,8 @@ disable_bus_clk: } static const struct dev_pm_ops fsl_sai_pm_ops = { - SET_RUNTIME_PM_OPS(fsl_sai_runtime_suspend, - fsl_sai_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(fsl_sai_runtime_suspend, fsl_sai_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver fsl_sai_driver = { @@ -1828,7 +1826,7 @@ static struct platform_driver fsl_sai_driver = { .remove = fsl_sai_remove, .driver = { .name = "fsl-sai", - .pm = &fsl_sai_pm_ops, + .pm = pm_ptr(&fsl_sai_pm_ops), .of_match_table = fsl_sai_ids, }, }; diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index c59c1af5a98a..83aea341c1b6 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -1821,8 +1821,7 @@ stop_ipg_clk: static const struct dev_pm_ops fsl_xcvr_pm_ops = { RUNTIME_PM_OPS(fsl_xcvr_runtime_suspend, fsl_xcvr_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver fsl_xcvr_driver = { diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index ac043ad367ac..905294682996 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -518,6 +518,7 @@ static int imx_card_parse_of(struct imx_card_data *data) struct snd_soc_dai_link *link; struct dai_link_data *link_data; struct of_phandle_args args; + bool playback_only, capture_only; int ret, num_links; u32 asrc_fmt = 0; u32 width; @@ -679,6 +680,10 @@ static int imx_card_parse_of(struct imx_card_data *data) link->ops = &imx_aif_ops; } + graph_util_parse_link_direction(np, &playback_only, &capture_only); + link->playback_only = playback_only; + link->capture_only = capture_only; + /* Get dai fmt */ ret = simple_util_parse_daifmt(dev, np, codec, NULL, &link->dai_fmt); diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c index 3391430e4253..83de3ae33691 100644 --- a/sound/soc/fsl/imx-pcm-fiq.c +++ b/sound/soc/fsl/imx-pcm-fiq.c @@ -185,8 +185,7 @@ static int snd_imx_open(struct snd_soc_component *component, atomic_set(&iprtd->playing, 0); atomic_set(&iprtd->capturing, 0); - hrtimer_init(&iprtd->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - iprtd->hrt.function = snd_hrtimer_callback; + hrtimer_setup(&iprtd->hrt, snd_hrtimer_callback, CLOCK_MONOTONIC, HRTIMER_MODE_REL); ret = snd_pcm_hw_constraint_integer(substream->runtime, SNDRV_PCM_HW_PARAM_PERIODS); diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c index 7c422535b01a..a8a3bad3df00 100644 --- a/sound/soc/generic/audio-graph-card.c +++ b/sound/soc/generic/audio-graph-card.c @@ -20,6 +20,13 @@ #define DPCM_SELECTABLE 1 +#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret) +static inline int _graph_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + #define ep_to_port(ep) of_get_parent(ep) static struct device_node *port_to_ports(struct device_node *port) { @@ -111,19 +118,17 @@ static int graph_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, 0); } - ret = graph_util_parse_dai(dev, ep, dlc, cpu); + ret = graph_util_parse_dai(priv, ep, dlc, cpu); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_tdm(ep, dai); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_clk(dev, ep, dai, dlc); - if (ret < 0) - return ret; - - return 0; +end: + return graph_ret(priv, ret); } static int graph_link_init(struct simple_util_priv *priv, @@ -148,7 +153,7 @@ static int graph_link_init(struct simple_util_priv *priv, ret = simple_util_parse_daifmt(dev, ep_cpu, ep_codec, NULL, &dai_link->dai_fmt); if (ret < 0) - return ret; + goto end; graph_util_parse_link_direction(top, &playback_only, &capture_only); graph_util_parse_link_direction(port_cpu, &playback_only, &capture_only); @@ -183,7 +188,9 @@ static int graph_link_init(struct simple_util_priv *priv, if (priv->ops) dai_link->ops = priv->ops; - return simple_util_set_dailink_name(dev, dai_link, name); + ret = simple_util_set_dailink_name(priv, dai_link, name); +end: + return graph_ret(priv, ret); } static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, @@ -215,7 +222,7 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, &is_single_links); if (ret) - return ret; + goto end; snprintf(dai_name, sizeof(dai_name), "fe.%pOFP.%s", cpus->of_node, cpus->dai_name); @@ -248,7 +255,7 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) - return ret; + goto end; snprintf(dai_name, sizeof(dai_name), "be.%pOFP.%s", codecs->of_node, codecs->dai_name); @@ -267,8 +274,8 @@ static int graph_dai_link_of_dpcm(struct simple_util_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); li->link++; - - return ret; +end: + return graph_ret(priv, ret); } static int graph_dai_link_of(struct simple_util_priv *priv, @@ -288,11 +295,11 @@ static int graph_dai_link_of(struct simple_util_priv *priv, ret = graph_parse_node(priv, cpu_ep, li, &is_single_links); if (ret < 0) - return ret; + goto end; ret = graph_parse_node(priv, codec_ep, li, NULL); if (ret < 0) - return ret; + goto end; snprintf(dai_name, sizeof(dai_name), "%s-%s", cpus->dai_name, codecs->dai_name); @@ -302,11 +309,11 @@ static int graph_dai_link_of(struct simple_util_priv *priv, ret = graph_link_init(priv, cpu_ep, codec_ep, li, dai_name); if (ret < 0) - return ret; + goto end; li->link++; - - return 0; +end: + return graph_ret(priv, ret); } static inline bool parse_as_dpcm_link(struct simple_util_priv *priv, @@ -383,13 +390,13 @@ static int __graph_for_each_link(struct simple_util_priv *priv, } if (ret < 0) - return ret; + goto end; codec_port_old = codec_port; } } - - return 0; +end: + return graph_ret(priv, ret); } static int graph_for_each_link(struct simple_util_priv *priv, @@ -422,7 +429,7 @@ static int graph_for_each_link(struct simple_util_priv *priv, break; } - return ret; + return graph_ret(priv, ret); } static int graph_count_noml(struct simple_util_priv *priv, @@ -431,11 +438,10 @@ static int graph_count_noml(struct simple_util_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - if (li->link >= SNDRV_MAX_LINKS) { - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; /* * DON'T REMOVE platforms @@ -450,8 +456,9 @@ static int graph_count_noml(struct simple_util_priv *priv, li->link += 1; /* 1xCPU-Codec */ dev_dbg(dev, "Count As Normal\n"); - - return 0; + ret = 0; +end: + return graph_ret(priv, ret); } static int graph_count_dpcm(struct simple_util_priv *priv, @@ -460,11 +467,10 @@ static int graph_count_dpcm(struct simple_util_priv *priv, struct link_info *li) { struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - if (li->link >= SNDRV_MAX_LINKS) { - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; if (li->cpu) { /* @@ -483,8 +489,9 @@ static int graph_count_dpcm(struct simple_util_priv *priv, } dev_dbg(dev, "Count As DPCM\n"); - - return 0; + ret = 0; +end: + return graph_ret(priv, ret); } static int graph_get_dais_count(struct simple_util_priv *priv, @@ -544,40 +551,41 @@ static int graph_get_dais_count(struct simple_util_priv *priv, int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) { struct snd_soc_card *card = simple_priv_to_card(priv); - int ret; + int ret = -ENOMEM; struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) - return -ENOMEM; + goto end; card->owner = THIS_MODULE; card->dev = dev; ret = graph_get_dais_count(priv, li); if (ret < 0) - return ret; + goto end; + ret = -EINVAL; if (!li->link) - return -EINVAL; + goto end; ret = simple_util_init_priv(priv, li); if (ret < 0) - return ret; + goto end; priv->pa_gpio = devm_gpiod_get_optional(dev, "pa", GPIOD_OUT_LOW); if (IS_ERR(priv->pa_gpio)) { ret = PTR_ERR(priv->pa_gpio); dev_err(dev, "failed to get amplifier gpio: %d\n", ret); - return ret; + goto end; } ret = simple_util_parse_widgets(card, NULL); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_routing(card, NULL); if (ret < 0) - return ret; + goto end; memset(li, 0, sizeof(*li)); ret = graph_for_each_link(priv, li, @@ -586,7 +594,7 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) if (ret < 0) goto err; - ret = simple_util_parse_card_name(card, NULL); + ret = simple_util_parse_card_name(priv, NULL); if (ret < 0) goto err; @@ -599,10 +607,9 @@ int audio_graph_parse_of(struct simple_util_priv *priv, struct device *dev) goto err; return 0; - err: simple_util_clean_reference(card); - +end: return dev_err_probe(dev, ret, "parse error\n"); } EXPORT_SYMBOL_GPL(audio_graph_parse_of); diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample.dtsi deleted file mode 100644 index 9efd31206c9b..000000000000 --- a/sound/soc/generic/audio-graph-card2-custom-sample.dtsi +++ /dev/null @@ -1,702 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * audio-graph-card2-custom-sample.dtsi - * - * Copyright (C) 2020 Renesas Electronics Corp. - * Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> - * - * This sample indicates how to use audio-graph-card2 and its - * custom driver. "audio-graph-card2-custom-sample" is the custome driver - * which is using audio-graph-card2. - * - * You can easily use this sample by adding below line on your DT file, - * and add new CONFIG to your .config. - * - * #include "../../../../../sound/soc/generic/audio-graph-card2-custom-sample.dtsi" - * - * CONFIG_SND_AUDIO_GRAPH_CARD2 - * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE - * CONFIG_SND_TEST_COMPONENT - * - * - * You can indicate more detail each device behavior as debug if you modify - * "compatible" on each test-component. see below - * - * test_cpu { - * - compatible = "test-cpu"; - * + compatible = "test-cpu-verbose"; - * ... - * }; - * - * test_codec { - * - compatible = "test-codec"; - * + compatible = "test-codec-verbose"; - * ... - * }; - * - * - * Below sample doesn't use "format" property, - * because test-component driver (test-cpu/test-codec) is supporting - * snd_soc_dai_ops :: .auto_selectable_formats. - * see - * snd_soc_runtime_get_dai_fmt() - * linux/sound/soc/generic/test-component.c :: test_dai_formats - */ -/ { - /* - * @ : used at links - * - * [Normal] - * cpu0 <-@-----------------> codec0 - * - * [Semi-Multi] - * - * CPU:Codec = 1:N - * - * +-+ - * cpu7 <-@------->| |-> codec12 - * | |-> codec13 - * +-+ - * - * [Multi-CPU/Codec-0] - * +-+ +-+ - * cpu1 <--| |<-@--------->| |-> codec1 - * cpu2 <--| | | |-> codec2 - * +-+ +-+ - * - * [Multi-CPU/Codec-1] - * - * +-+ +-+ - * | |<-@--------->| | - * | | | | - * cpu8 <--| |<----------->| |-> codec14 - * cpu9 <--| |<---+------->| |-> codec15 - * +-+ \------>| |-> codec16 - * +-+ - * - * [Multi-CPU/Codec-2] - * - * +-+ +-+ - * | |<-@--------->| | - * | | | | - * cpu10 <-| |<----------->| |-> codec17 - * cpu11 <-| |<-----+----->| |-> codec18 - * cpu12 <-| |<----/ +-+ - * +-+ - * - * [DPCM] - * - * CPU3/CPU4 are converting rate to 44100 - * - * FE BE - * **** - * cpu3 <-@--* *--@-> codec3 - * cpu4 <-@--* * (44.1kHz) - * **** - * - * [DPCM-Multi] - * - * --NOTE-- - * Multi-FE is not supported by ASoC. - * - * FE BE - * **** +-+ - * cpu5 <-@--* *--@-> | | -> codec4 - * cpu6 <-@--* * | | -> codec5 - * **** +-+ - * - * [Codec2Codec] - * +-@-> codec6 - * | - * +---> codec7 - * - * [Codec2Codec-Multi] - * - * --NOTE-- - * Multi connect N:M is not supported by ASoC. - * - * +-+ - * +-@->| |-> codec8 - * | | |-> codec9 - * | +-+ - * | +-+ - * +--->| |-> codec10 - * | |-> codec11 - * +-+ - */ - audio-graph-card2-custom-sample { - /* - * You can use audio-graph-card2 directly by using - * - * compatible = "audio-graph-card2"; - */ - compatible = "audio-graph-card2-custom-sample"; - - /* for [DPCM] */ - /* BE FE */ - routing = "TC DAI3 Playback", "DAI3 Playback", - "TC DAI3 Playback", "DAI4 Playback", - "DAI3 Capture", "TC DAI3 Capture", - "DAI4 Capture", "TC DAI3 Capture", - /* for [DPCM-Multi] */ - /* BE FE */ - "TC DAI4 Playback", "DAI5 Playback", - "TC DAI5 Playback", "DAI5 Playback", - "TC DAI4 Playback", "DAI6 Playback", - "TC DAI5 Playback", "DAI6 Playback", - "DAI5 Capture", "TC DAI4 Capture", - "DAI5 Capture", "TC DAI5 Capture", - "DAI6 Capture", "TC DAI4 Capture", - "DAI6 Capture", "TC DAI5 Capture", - /* for [Codec2Codec] */ - "TC OUT", "TC DAI7 Playback", - "TC DAI6 Capture", "TC IN", - /* for [Codec2Codec-Multi] */ - "TC OUT", "TC DAI10 Playback", - "TC DAI8 Capture", "TC IN", - "TC OUT", "TC DAI11 Playback", - "TC DAI9 Capture", "TC IN"; - - links = < - /* - * [Normal]: cpu side only - * cpu0/codec0 - */ - &cpu0 - - /* - * [Semi-Multi] - * cpu7/codec12/codec13 - */ - &sm0 - - /* - * [Multi-CPU/Codec-0]: cpu side only - * cpu1/cpu2/codec1/codec2 - */ - &mcpu0 - - /* - * [Multi-CPU/Codec-1]: cpu side only - * cpu8/cpu9/codec14/codec15/codec16 - * - * Because it will reach to the maximum of sound minor number, - * disable it so far. - * If you want to try it, please disable some other one instead. - */ - //&mcpu1 - - /* - * [Multi-CPU/Codec-2]: cpu side only - * cpu10/cpu11/cpu12/codec17/codec18 - * - * Because it will reach to the maximum of sound minor number, - * disable it so far. - * If you want to try it, please disable some other one instead. - */ - //&mcpu2 - - /* - * [DPCM]: both FE / BE - * cpu3/cpu4/codec3 - */ - &fe00 &fe01 &be0 - - /* - * [DPCM-Multi]: both FE / BE - * cpu5/cpu6/codec4/codec5 - */ - &fe10 &fe11 &be1 - - /* - * [Codec2Codec]: cpu side only - * codec6/codec7 - */ - &c2c - - /* - * [Codec2Codec-Multi]: cpu side only - * codec8/codec9/codec10/codec11 - */ - &c2c_m - >; - - multi { - #address-cells = <1>; - #size-cells = <0>; - - /* - * [Multi-CPU-0] - * - * +---+ +---+ - * cpu1 <--|A X|<-@------->|x a|-> codec1 - * cpu2 <--|B | | b|-> codec2 - * +---+ +---+ - */ - ports@0 { - reg = <0>; - #address-cells = <1>; - #size-cells = <0>; - mcpu0: port@0 { reg = <0>; mcpu00_ep: endpoint { remote-endpoint = <&mcodec00_ep>; };};/* (X) to pair */ - port@1 { reg = <1>; mcpu01_ep: endpoint { remote-endpoint = <&cpu1_ep>; };};/* (A) Multi Element */ - port@2 { reg = <2>; mcpu02_ep: endpoint { remote-endpoint = <&cpu2_ep>; };};/* (B) Multi Element */ - }; - - /* - * [Multi-Codec-0] - * - * +---+ +---+ - * cpu1 <--|A X|<-@------->|x a|-> codec1 - * cpu2 <--|B | | b|-> codec2 - * +---+ +---+ - */ - ports@1 { - reg = <1>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; mcodec00_ep: endpoint { remote-endpoint = <&mcpu00_ep>; };};/* (x) to pair */ - port@1 { reg = <1>; mcodec01_ep: endpoint { remote-endpoint = <&codec1_ep>; };};/* (a) Multi Element */ - port@2 { reg = <2>; mcodec02_ep: endpoint { remote-endpoint = <&codec2_ep>; };};/* (b) Multi Element */ - }; - - /* - * [DPCM-Multi]::BE - * - * FE BE - * **** +---+ - * cpu5 <-@--* *-----@--->|x a|-> codec4 - * cpu6 <-@--* * | b|-> codec5 - * **** +---+ - */ - ports@2 { - reg = <2>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; mbe_ep: endpoint { remote-endpoint = <&be10_ep>; };};/* (x) to pair */ - port@1 { reg = <1>; mbe1_ep: endpoint { remote-endpoint = <&codec4_ep>; };};/* (a) Multi Element */ - port@2 { reg = <2>; mbe2_ep: endpoint { remote-endpoint = <&codec5_ep>; };};/* (b) Multi Element */ - }; - - /* - * [Codec2Codec-Multi]::CPU - * - * +---+ - * +-@->|X A|-> codec8 - * | | B|-> codec9 - * | +---+ - * | +---+ - * +--->|x a|-> codec10 - * | b|-> codec11 - * +---+ - */ - ports@3 { - reg = <3>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; mc2c0_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */ - port@1 { reg = <1>; mc2c00_ep: endpoint { remote-endpoint = <&codec8_ep>; };};/* (A) Multi Element */ - port@2 { reg = <2>; mc2c01_ep: endpoint { remote-endpoint = <&codec9_ep>; };};/* (B) Multi Element */ - }; - - /* - * [Codec2Codec-Multi]::Codec - * - * +---+ - * +-@->|X A|-> codec8 - * | | B|-> codec9 - * | +---+ - * | +---+ - * +--->|x a|-> codec10 - * | b|-> codec11 - * +---+ - */ - ports@4 { - reg = <4>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; mc2c1_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */ - port@1 { reg = <1>; mc2c10_ep: endpoint { remote-endpoint = <&codec10_ep>; };};/* (a) Multi Element */ - port@2 { reg = <2>; mc2c11_ep: endpoint { remote-endpoint = <&codec11_ep>; };};/* (b) Multi Element */ - }; - - /* - * [Semi-Multi] - * - * +---+ - * cpu7 <-@------->|X A|-> codec12 - * | B|-> codec13 - * +---+ - */ - ports@5 { - reg = <5>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; smcodec0_ep: endpoint { remote-endpoint = <&cpu7_ep>; };};/* (X) to pair */ - port@1 { reg = <1>; smcodec1_ep: endpoint { remote-endpoint = <&codec12_ep>; };};/* (A) Multi Element */ - port@2 { reg = <2>; smcodec2_ep: endpoint { remote-endpoint = <&codec13_ep>; };};/* (B) Multi Element */ - }; - - /* - * [Multi-CPU-1] - * - * +---+ +---+ - * | X|<-@------->|x | - * | | | | - * cpu8 <--|A 1|<--------->|3 a|-> codec14 - * cpu9 <--|B 2|<---+----->|4 b|-> codec15 - * +---+ \---->|5 c|-> codec16 - * +---+ - */ - ports@6 { - reg = <6>; - #address-cells = <1>; - #size-cells = <0>; - mcpu1: port@0 { reg = <0>; mcpu10_ep: endpoint { remote-endpoint = <&mcodec10_ep>; };}; /* (X) to pair */ - port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - mcpu11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu8_ep>; }; /* (A) Multi Element */ - mcpu11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec11_ep_0>; }; /* (1) connected Codec */ - }; - port@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - mcpu12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu9_ep>; }; /* (B) Multi Element */ - mcpu12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec12_ep_0>; }; /* (2) connected Codec */ - mcpu12_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec13_ep_0>; }; /* (2) connected Codec */ - }; - }; - - /* - * [Multi-Codec-1] - * - * +---+ +---+ - * | X|<-@------->|x | - * | | | | - * cpu8 <--|A 1|<--------->|3 a|-> codec14 - * cpu9 <--|B 2|<---+----->|4 b|-> codec15 - * +---+ \---->|5 c|-> codec16 - * +---+ - */ - ports@7 { - reg = <7>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; mcodec10_ep: endpoint { remote-endpoint = <&mcpu10_ep>; };}; /* (x) to pair */ - port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - mcodec11_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec14_ep>; }; /* (a) Multi Element */ - mcodec11_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu11_ep_0>; }; /* (3) connected CPU */ - }; - port@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - mcodec12_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec15_ep>; }; /* (b) Multi Element */ - mcodec12_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_0>; }; /* (4) connected CPU */ - }; - port@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - mcodec13_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec16_ep>; }; /* (c) Multi Element */ - mcodec13_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu12_ep_1>; }; /* (5) connected CPU */ - }; - }; - - /* - * [Multi-CPU-2] - * - * +---+ +---+ - * | X|<-@------->|x | - * | | | | - * cpu10 <-|A 1|<--------->|4 a|-> codec17 - * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 - * cpu12 <-|C 3|<----/ +---+ - * +---+ - */ - ports@8 { - reg = <8>; - #address-cells = <1>; - #size-cells = <0>; - mcpu2: port@0 { reg = <0>; mcpu20_ep: endpoint { remote-endpoint = <&mcodec20_ep>; };}; /* (X) to pair */ - port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - mcpu21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu10_ep>; }; /* (A) Multi Element */ - mcpu21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec21_ep_0>; }; /* (1) connected Codec */ - }; - port@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - mcpu22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu11_ep>; }; /* (B) Multi Element */ - mcpu22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_0>; }; /* (2) connected Codec */ - }; - port@3 { - #address-cells = <1>; - #size-cells = <0>; - reg = <3>; - mcpu23_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu12_ep>; }; /* (C) Multi Element */ - mcpu23_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec22_ep_1>; }; /* (3) connected Codec */ - }; - }; - - /* - * [Multi-Codec-2] - * - * +---+ +---+ - * | X|<-@------->|x | - * | | | | - * cpu10 <-|A 1|<--------->|4 a|-> codec17 - * cpu11 <-|B 2|<-----+--->|5 b|-> codec18 - * cpu12 <-|C 3|<----/ +---+ - * +---+ - */ - ports@9 { - reg = <9>; - #address-cells = <1>; - #size-cells = <0>; - port@0 { reg = <0>; mcodec20_ep: endpoint { remote-endpoint = <&mcpu20_ep>; };}; /* (x) to pair */ - port@1 { - #address-cells = <1>; - #size-cells = <0>; - reg = <1>; - mcodec21_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec17_ep>; }; /* (a) Multi Element */ - mcodec21_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu21_ep_0>; }; /* (4) connected CPU */ - }; - port@2 { - #address-cells = <1>; - #size-cells = <0>; - reg = <2>; - mcodec22_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec18_ep>; }; /* (b) Multi Element */ - mcodec22_ep_0: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu22_ep_0>; }; /* (5) connected CPU */ - mcodec22_ep_1: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu23_ep_0>; }; /* (5) connected CPU */ - }; - }; - }; - - dpcm { - #address-cells = <1>; - #size-cells = <0>; - - ports@0 { - reg = <0>; - - #address-cells = <1>; - #size-cells = <0>; - /* - * [DPCM]::FE - * - * FE BE - * **** - * cpu3 <-@(fe00)--* *--(be0)@--> codec3 - * cpu4 <-@(fe01)--* * (44.1kHz) - * **** - */ - fe00: port@0 { reg = <0>; fe00_ep: endpoint { remote-endpoint = <&cpu3_ep>; }; }; - fe01: port@1 { reg = <1>; fe01_ep: endpoint { remote-endpoint = <&cpu4_ep>; }; }; - - /* - * [DPCM-Multi]::FE - * - * FE BE - * **** +-+ - * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 - * cpu6 <-@(fe11)--* * | |-> codec5 - * **** +-+ - */ - fe10: port@2 { reg = <2>; fe10_ep: endpoint { remote-endpoint = <&cpu5_ep>; }; }; - fe11: port@3 { reg = <3>; fe11_ep: endpoint { remote-endpoint = <&cpu6_ep>; }; }; - }; - - ports@1 { - reg = <1>; - - #address-cells = <1>; - #size-cells = <0>; - /* - * [DPCM]::BE - * - * FE BE - * **** - * cpu3 <-@(fe00)--* *--(be0)@--> codec3 - * cpu4 <-@(fe01)--* * (44.1kHz) - * **** - */ - be0: port@0 { reg = <0>; be00_ep: endpoint { remote-endpoint = <&codec3_ep>; }; }; - - /* - * [DPCM-Multi]::BE - * - * FE BE - * **** +-+ - * cpu5 <-@(fe10)--* *---(be1)@-->| |-> codec4 - * cpu6 <-@(fe11)--* * | |-> codec5 - * **** +-+ - */ - be1: port@1 { reg = <1>; be10_ep: endpoint { remote-endpoint = <&mbe_ep>; }; }; - }; - }; - - codec2codec { - #address-cells = <1>; - #size-cells = <0>; - /* - * [Codec2Codec] - * - * +-@(c2c)-> codec6 - * | - * +--------> codec7 - */ - ports@0 { - reg = <0>; - - #address-cells = <1>; - #size-cells = <0>; - - /* use default settings */ - c2c: port@0 { reg = <0>; c2cf_ep: endpoint { remote-endpoint = <&codec6_ep>; }; }; - port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec7_ep>; }; }; - }; - - /* - * [Codec2Codec-Multi] - * - * +-+ - * +-@(c2c_m)-->| |-> codec8 - * | | |-> codec9 - * | +-+ - * | +-+ - * +----------->| |-> codec10 - * | |-> codec11 - * +-+ - */ - ports@1 { - reg = <1>; - - #address-cells = <1>; - #size-cells = <0>; - - /* use original settings */ - rate = <48000>; - c2c_m: port@0 { reg = <0>; c2cmf_ep: endpoint { remote-endpoint = <&mc2c0_ep>; }; }; - port@1 { reg = <1>; c2cmb_ep: endpoint { remote-endpoint = <&mc2c1_ep>; }; }; - }; - }; - }; - - test_cpu { - /* - * update compatible to indicate more detail behaviour - * if you want. see test-compatible for more detail. - * - * ex) - * - compatible = "test-cpu"; - * + compatible = "test-cpu-verbose"; - */ - compatible = "test-cpu"; - ports { - #address-cells = <1>; - #size-cells = <0>; - - bitclock-master; - frame-master; - /* [Normal] */ - cpu0: port@0 { reg = <0>; cpu0_ep: endpoint { remote-endpoint = <&codec0_ep>; }; }; - - /* [Multi-CPU-0] */ - port@1 { reg = <1>; cpu1_ep: endpoint { remote-endpoint = <&mcpu01_ep>; }; }; - port@2 { reg = <2>; cpu2_ep: endpoint { remote-endpoint = <&mcpu02_ep>; }; }; - - /* [DPCM]::FE */ - port@3 { reg = <3>; cpu3_ep: endpoint { remote-endpoint = <&fe00_ep>; }; }; - port@4 { reg = <4>; cpu4_ep: endpoint { remote-endpoint = <&fe01_ep>; }; }; - - /* [DPCM-Multi]::FE */ - port@5 { reg = <5>; cpu5_ep: endpoint { remote-endpoint = <&fe10_ep>; }; }; - port@6 { reg = <6>; cpu6_ep: endpoint { remote-endpoint = <&fe11_ep>; }; }; - - /* [Semi-Multi] */ - sm0: port@7 { reg = <7>; cpu7_ep: endpoint { remote-endpoint = <&smcodec0_ep>; }; }; - - /* [Multi-CPU-1] */ - port@8 { reg = <8>; cpu8_ep: endpoint { remote-endpoint = <&mcpu11_ep>; }; }; - port@9 { reg = <9>; cpu9_ep: endpoint { remote-endpoint = <&mcpu12_ep>; }; }; - /* [Multi-CPU-2] */ - port@a { reg = <10>; cpu10_ep: endpoint { remote-endpoint = <&mcpu21_ep>; }; }; - port@b { reg = <11>; cpu11_ep: endpoint { remote-endpoint = <&mcpu22_ep>; }; }; - port@c { reg = <12>; cpu12_ep: endpoint { remote-endpoint = <&mcpu23_ep>; }; }; - }; - }; - - test_codec { - /* - * update compatible to indicate more detail behaviour - * if you want. see test-compatible for more detail. - * - * ex) - * - compatible = "test-codec"; - * + compatible = "test-codec-verbose"; - */ - compatible = "test-codec"; - ports { - #address-cells = <1>; - #size-cells = <0>; - - /* - * prefix can be added to *component*, - * see audio-graph-card2::routing - */ - prefix = "TC"; - - /* [Normal] */ - port@0 { reg = <0>; codec0_ep: endpoint { remote-endpoint = <&cpu0_ep>; }; }; - - /* [Multi-Codec-0] */ - port@1 { reg = <1>; codec1_ep: endpoint { remote-endpoint = <&mcodec01_ep>; }; }; - port@2 { reg = <2>; codec2_ep: endpoint { remote-endpoint = <&mcodec02_ep>; }; }; - - /* [DPCM]::BE */ - port@3 { - convert-rate = <44100>; - reg = <3>; codec3_ep: endpoint { remote-endpoint = <&be00_ep>; }; - }; - - /* [DPCM-Multi]::BE */ - port@4 { reg = <4>; codec4_ep: endpoint { remote-endpoint = <&mbe1_ep>; }; }; - port@5 { reg = <5>; codec5_ep: endpoint { remote-endpoint = <&mbe2_ep>; }; }; - - /* [Codec2Codec] */ - port@6 { bitclock-master; - frame-master; - reg = <6>; codec6_ep: endpoint { remote-endpoint = <&c2cf_ep>; }; }; - port@7 { reg = <7>; codec7_ep: endpoint { remote-endpoint = <&c2cb_ep>; }; }; - - /* [Codec2Codec-Multi] */ - port@8 { bitclock-master; - frame-master; - reg = <8>; codec8_ep: endpoint { remote-endpoint = <&mc2c00_ep>; }; }; - port@9 { reg = <9>; codec9_ep: endpoint { remote-endpoint = <&mc2c01_ep>; }; }; - port@a { reg = <10>; codec10_ep: endpoint { remote-endpoint = <&mc2c10_ep>; }; }; - port@b { reg = <11>; codec11_ep: endpoint { remote-endpoint = <&mc2c11_ep>; }; }; - - /* [Semi-Multi] */ - port@c { reg = <12>; codec12_ep: endpoint { remote-endpoint = <&smcodec1_ep>; }; }; - port@d { reg = <13>; codec13_ep: endpoint { remote-endpoint = <&smcodec2_ep>; }; }; - - /* [Multi-Codec-1] */ - port@e { reg = <14>; codec14_ep: endpoint { remote-endpoint = <&mcodec11_ep>; }; }; - port@f { reg = <15>; codec15_ep: endpoint { remote-endpoint = <&mcodec12_ep>; }; }; - port@10 { reg = <16>; codec16_ep: endpoint { remote-endpoint = <&mcodec13_ep>; }; }; - /* [Multi-Codec-2] */ - port@11 { reg = <17>; codec17_ep: endpoint { remote-endpoint = <&mcodec21_ep>; }; }; - port@12 { reg = <18>; codec18_ep: endpoint { remote-endpoint = <&mcodec22_ep>; }; }; - }; - }; -}; diff --git a/sound/soc/generic/audio-graph-card2-custom-sample1.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample1.dtsi new file mode 100644 index 000000000000..12d40e05de46 --- /dev/null +++ b/sound/soc/generic/audio-graph-card2-custom-sample1.dtsi @@ -0,0 +1,396 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * audio-graph-card2-custom-sample1.dtsi + * + * Copyright (C) 2020 Renesas Electronics Corp. + * Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This sample indicates how to use audio-graph-card2 and its + * custom driver. "audio-graph-card2-custom-sample" is the custome driver + * which is using audio-graph-card2. + * + * You can easily use this sample by adding below line on your DT file, + * and add new CONFIG to your .config. + * + * #include "../../../../../sound/soc/generic/audio-graph-card2-custom-sample1.dtsi" + * + * CONFIG_SND_AUDIO_GRAPH_CARD2 + * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE + * CONFIG_SND_TEST_COMPONENT + * + * + * You can indicate more detail each device behavior as debug if you modify + * "compatible" on each test-component. see below + * + * test_cpu { + * - compatible = "test-cpu"; + * + compatible = "test-cpu-verbose"; + * ... + * }; + * + * test_codec { + * - compatible = "test-codec"; + * + compatible = "test-codec-verbose"; + * ... + * }; + * + * + * Below sample doesn't use "format" property, + * because test-component driver (test-cpu/test-codec) is supporting + * snd_soc_dai_ops :: .auto_selectable_formats. + * see + * snd_soc_runtime_get_dai_fmt() + * linux/sound/soc/generic/test-component.c :: test_dai_formats + */ +/ { + audio-graph-card2-custom-sample-1 { + /* + * You can use audio-graph-card2 directly by using + * + * compatible = "audio-graph-card2"; + */ + compatible = "audio-graph-card2-custom-sample"; + label = "card2-custom-sample-1"; + + /* + * @ : used at links + */ + links = < + /* + * + * [Normal] + * + * <cpu1_0> + * cpu1_0 <-@-----> codec1_0 + */ + &cpu1_0 /* CPU side only */ + + /* + * [Semi-Multi] + * + * CPU:Codec = 1:N + * + * <sm> +-+ + * cpu1_1 <--@---->| |-> codec1_1 + * | |-> codec1_2 + * +-+ + */ + &sm /* CPU side only */ + + /* + * [Multi-CPU/Codec-A] + * + * +-+ <mcpuA> +-+ + * cpu1_2 <-| |<---@------>| |-> codec1_3 + * cpu1_3 <-| | | |-> codec1_4 + * +-+ +-+ + */ + &mcpuA /* CPU side only */ + + /* + * [Multi-CPU/Codec-B] + * + * +-+ <mcpuB> +-+ + * | |<---@------>| | + * | | | | + * cpu1_4 <-| |<---------->| |-> codec1_5 + * cpu1_5 <-| |<---+------>| |-> codec1_6 + * +-+ \----->| |-> codec1_7 + * +-+ + */ + &mcpuB /* CPU side only */ + + /* + * [Multi-CPU/Codec-C] + * + * +-+ <mcpuC> +-+ + * | |<---@------>| | + * | | | | + * cpu1_6 <-| |<---------->| |-> codec1_8 + * cpu1_7 <-| |<-----+---->| |-> codec1_9 + * cpu1_8 <-| |<----/ +-+ + * +-+ + */ + &mcpuC /* CPU side only */ + >; + + multi { + #address-cells = <1>; + #size-cells = <0>; + + /* + * [Semi-Multi] + * + * <sm> +---+ + * cpu1_1 <---@--->|X A|-> codec1_1 + * | B|-> codec1_2 + * +---+ + */ + ports@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; smcodec_ep: endpoint { remote-endpoint = <&cpu1_1_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; smcodec_A_ep: endpoint { remote-endpoint = <&codec1_1_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; smcodec_B_ep: endpoint { remote-endpoint = <&codec1_2_ep>; };};/* (B) Multi Element */ + }; + + /* + * [Multi-CPU-A] + * + * +---+ <mcpuA> +---+ + * cpu1_2 <-|A X|<---@---->|x a|-> codec1_3 + * cpu1_3 <-|B | | b|-> codec1_4 + * +---+ +---+ + */ + ports@1 { + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + mcpuA: port@0 { reg = <0>; mcpu_A_ep: endpoint { remote-endpoint = <&mcodec_A_ep>; };}; /* (X) to pair */ + port@1 { reg = <1>; mcpu_AA_ep: endpoint { remote-endpoint = <&cpu1_2_ep>; };}; /* (A) Multi Element */ + port@2 { reg = <2>; mcpu_AB_ep: endpoint { remote-endpoint = <&cpu1_3_ep>; };}; /* (B) Multi Element */ + }; + + /* + * [Multi-Codec-A] + * + * +---+ <mcpuA> +---+ + * cpu1_2 <-|A X|<-@------>|x a|-> codec1_3 + * cpu1_3 <-|B | | b|-> codec1_4 + * +---+ +---+ + */ + ports@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mcodec_A_ep: endpoint { remote-endpoint = <&mcpu_A_ep>; };}; /* (x) to pair */ + port@1 { reg = <1>; mcodec_Aa_ep: endpoint { remote-endpoint = <&codec1_3_ep>; };}; /* (a) Multi Element */ + port@2 { reg = <2>; mcodec_Ab_ep: endpoint { remote-endpoint = <&codec1_4_ep>; };}; /* (b) Multi Element */ + }; + + /* + * [Multi-CPU-B] + * + * +---+ <mcpuB> +---+ + * | X|<---@---->|x | + * | | | | + * cpu1_4 <-|A 1|<-------->|3 a|-> codec1_5 + * cpu1_5 <-|B 2|<---+---->|4 b|-> codec1_6 + * +---+ \--->|5 c|-> codec1_7 + * +---+ + */ + ports@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + mcpuB: port@0 { + reg = <0>; + mcpu_BX_ep: endpoint { remote-endpoint = <&mcodec_Bx_ep>; }; /* (X) to pair */ + }; + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu_BA_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_4_ep>; }; /* (A) Multi Element */ + mcpu_B1_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_B3_ep>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu_BB_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_5_ep>; }; /* (B) Multi Element */ + mcpu_B2_0_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_B4_ep>; }; /* (2) connected Codec */ + mcpu_B2_1_ep: endpoint@2 { reg = <2>; remote-endpoint = <&mcodec_B5_ep>; }; /* (2) connected Codec */ + }; + }; + + /* + * [Multi-Codec-B] + * + * +---+ <mcpuB> +---+ + * | X|<-@------>|x | + * | | | | + * cpu1_4 <-|A 1|<-------->|3 a|-> codec1_5 + * cpu1_5 <-|B 2|<---+---->|4 b|-> codec1_6 + * +---+ \--->|5 c|-> codec1_7 + * +---+ + */ + ports@4 { + reg = <4>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + mcodec_Bx_ep: endpoint { remote-endpoint = <&mcpu_BX_ep>; }; /* (x) to pair */ + }; + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec_Ba_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_5_ep>;}; /* (a) Multi Element */ + mcodec_B3_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_B1_ep>; }; /* (3) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec_Bb_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_6_ep>; }; /* (b) Multi Element */ + mcodec_B4_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_B2_0_ep>;}; /* (4) connected CPU */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcodec_Bc_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_7_ep>; }; /* (c) Multi Element */ + mcodec_B5_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_B2_1_ep>;}; /* (5) connected CPU */ + }; + }; + + /* + * [Multi-CPU-C] + * + * +---+ <mcpuC> +---+ + * | X|<-@------>|x | + * | | | | + * cpu1_6 <-|A 1|<-------->|4 a|-> codec1_8 + * cpu1_7 <-|B 2|<-----+-->|5 b|-> codec1_9 + * cpu1_8 <-|C 3|<----/ +---+ + * +---+ + */ + ports@5 { + reg = <5>; + #address-cells = <1>; + #size-cells = <0>; + mcpuC: port@0 { + reg = <0>; + mcpu_CX_ep: endpoint { remote-endpoint = <&mcodec_Cx_ep>; }; /* (X) to pair */ + }; + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcpu_CA_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_6_ep>; }; /* (A) Multi Element */ + mcpu_C1_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_C4_ep>; }; /* (1) connected Codec */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcpu_CB_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_7_ep>; }; /* (B) Multi Element */ + mcpu_C2_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_C5_0_ep>; }; /* (2) connected Codec */ + }; + port@3 { + #address-cells = <1>; + #size-cells = <0>; + reg = <3>; + mcpu_CC_ep: endpoint@0 { reg = <0>; remote-endpoint = <&cpu1_8_ep>; }; /* (C) Multi Element */ + mcpu_C3_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcodec_C5_1_ep>; }; /* (3) connected Codec */ + }; + }; + + /* + * [Multi-Codec-C] + * + * +---+ <mcpuC> +---+ + * | X|<-@------>|x | + * | | | | + * cpu1_6 <-|A 1|<-------->|4 a|-> codec1_8 + * cpu1_7 <-|B 2|<-----+-->|5 b|-> codec1_9 + * cpu1_8 <-|C 3|<----/ +---+ + * +---+ + */ + ports@6 { + reg = <6>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + mcodec_Cx_ep: endpoint { remote-endpoint = <&mcpu_CX_ep>; }; /* (x) to pair */ + }; + port@1 { + #address-cells = <1>; + #size-cells = <0>; + reg = <1>; + mcodec_Ca_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_8_ep>;}; /* (a) Multi Element */ + mcodec_C4_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_C1_ep>; }; /* (4) connected CPU */ + }; + port@2 { + #address-cells = <1>; + #size-cells = <0>; + reg = <2>; + mcodec_Cb_ep: endpoint@0 { reg = <0>; remote-endpoint = <&codec1_9_ep>;}; /* (b) Multi Element */ + mcodec_C5_0_ep: endpoint@1 { reg = <1>; remote-endpoint = <&mcpu_C2_ep>; }; /* (5) connected CPU */ + mcodec_C5_1_ep: endpoint@2 { reg = <2>; remote-endpoint = <&mcpu_C3_ep>; }; /* (5) connected CPU */ + }; + }; + }; + }; + + test_cpu_1 { + /* + * update compatible to indicate more detail behaviour + * if you want. see test-compatible for more detail. + * + * ex) + * - compatible = "test-cpu"; + * + compatible = "test-cpu-verbose"; + */ + compatible = "test-cpu"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + bitclock-master; + frame-master; + + /* [Normal] */ + cpu1_0: port@0 { reg = <0>; cpu1_0_ep: endpoint { remote-endpoint = <&codec1_0_ep>;}; }; + /* [Semi-Multi] */ + sm: port@1 { reg = <1>; cpu1_1_ep: endpoint { remote-endpoint = <&smcodec_ep>; }; }; + /* [Multi-CPU-A] */ + port@2 { reg = <2>; cpu1_2_ep: endpoint { remote-endpoint = <&mcpu_AA_ep>; }; }; + port@3 { reg = <3>; cpu1_3_ep: endpoint { remote-endpoint = <&mcpu_AB_ep>; }; }; + /* [Multi-CPU-B] */ + port@4 { reg = <4>; cpu1_4_ep: endpoint { remote-endpoint = <&mcpu_BA_ep>; }; }; + port@5 { reg = <5>; cpu1_5_ep: endpoint { remote-endpoint = <&mcpu_BB_ep>; }; }; + /* [Multi-CPU-C] */ + port@6 { reg = <6>; cpu1_6_ep: endpoint { remote-endpoint = <&mcpu_CA_ep>; }; }; + port@7 { reg = <7>; cpu1_7_ep: endpoint { remote-endpoint = <&mcpu_CB_ep>; }; }; + port@8 { reg = <8>; cpu1_8_ep: endpoint { remote-endpoint = <&mcpu_CC_ep>; }; }; + }; + }; + + test_codec_1 { + /* + * update compatible to indicate more detail behaviour + * if you want. see test-compatible for more detail. + * + * ex) + * - compatible = "test-codec"; + * + compatible = "test-codec-verbose"; + */ + compatible = "test-codec"; + + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* [Normal] */ + port@0 { reg = <0>; codec1_0_ep: endpoint { remote-endpoint = <&cpu1_0_ep>; }; }; + /* [Semi-Multi] */ + port@1 { reg = <1>; codec1_1_ep: endpoint { remote-endpoint = <&smcodec_A_ep>; }; }; + port@2 { reg = <2>; codec1_2_ep: endpoint { remote-endpoint = <&smcodec_B_ep>; }; }; + /* [Multi-Codec-0] */ + port@3 { reg = <3>; codec1_3_ep: endpoint { remote-endpoint = <&mcodec_Aa_ep>; }; }; + port@4 { reg = <4>; codec1_4_ep: endpoint { remote-endpoint = <&mcodec_Ab_ep>; }; }; + /* [Multi-Codec-1] */ + port@5 { reg = <5>; codec1_5_ep: endpoint { remote-endpoint = <&mcodec_Ba_ep>; }; }; + port@6 { reg = <6>; codec1_6_ep: endpoint { remote-endpoint = <&mcodec_Bb_ep>; }; }; + port@7 { reg = <7>; codec1_7_ep: endpoint { remote-endpoint = <&mcodec_Bc_ep>; }; }; + /* [Multi-Codec-2] */ + port@8 { reg = <8>; codec1_8_ep: endpoint { remote-endpoint = <&mcodec_Ca_ep>; }; }; + port@9 { reg = <9>; codec1_9_ep: endpoint { remote-endpoint = <&mcodec_Cb_ep>; }; }; + }; + }; +}; diff --git a/sound/soc/generic/audio-graph-card2-custom-sample2.dtsi b/sound/soc/generic/audio-graph-card2-custom-sample2.dtsi new file mode 100644 index 000000000000..1fb061a10ab1 --- /dev/null +++ b/sound/soc/generic/audio-graph-card2-custom-sample2.dtsi @@ -0,0 +1,382 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * audio-graph-card2-custom-sample2.dtsi + * + * Copyright (C) 2020 Renesas Electronics Corp. + * Copyright (C) 2020 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> + * + * This sample indicates how to use audio-graph-card2 and its + * custom driver. "audio-graph-card2-custom-sample" is the custome driver + * which is using audio-graph-card2. + * + * You can easily use this sample by adding below line on your DT file, + * and add new CONFIG to your .config. + * + * #include "../../../../../sound/soc/generic/audio-graph-card2-custom-sample2.dtsi" + * + * CONFIG_SND_AUDIO_GRAPH_CARD2 + * CONFIG_SND_AUDIO_GRAPH_CARD2_CUSTOM_SAMPLE + * CONFIG_SND_TEST_COMPONENT + * + * + * You can indicate more detail each device behavior as debug if you modify + * "compatible" on each test-component. see below + * + * test_cpu { + * - compatible = "test-cpu"; + * + compatible = "test-cpu-verbose"; + * ... + * }; + * + * test_codec { + * - compatible = "test-codec"; + * + compatible = "test-codec-verbose"; + * ... + * }; + * + * + * Below sample doesn't use "format" property, + * because test-component driver (test-cpu/test-codec) is supporting + * snd_soc_dai_ops :: .auto_selectable_formats. + * see + * snd_soc_runtime_get_dai_fmt() + * linux/sound/soc/generic/test-component.c :: test_dai_formats + */ +/ { + audio-graph-card2-custom-sample-2 { + /* + * You can use audio-graph-card2 directly by using + * + * compatible = "audio-graph-card2"; + */ + compatible = "audio-graph-card2-custom-sample"; + label = "card2-custom-sample-2"; + + /* for [DPCM] */ + /* BE FE */ + routing = "TC DAI0 Playback", "DAI0 Playback", + "TC DAI0 Playback", "DAI1 Playback", + "DAI0 Capture", "TC DAI0 Capture", + "DAI1 Capture", "TC DAI0 Capture", + /* for [DPCM-Multi] */ + /* BE FE */ + "TC DAI1 Playback", "DAI2 Playback", + "TC DAI2 Playback", "DAI2 Playback", + "TC DAI1 Playback", "DAI3 Playback", + "TC DAI2 Playback", "DAI3 Playback", + "DAI2 Capture", "TC DAI1 Capture", + "DAI2 Capture", "TC DAI2 Capture", + "DAI3 Capture", "TC DAI1 Capture", + "DAI3 Capture", "TC DAI2 Capture", + /* for [Codec2Codec] */ + "TC OUT", "TC DAI4 Playback", + "TC DAI3 Capture", "TC IN", + /* for [Codec2Codec-Multi] */ + "TC OUT", "TC DAI7 Playback", + "TC DAI5 Capture", "TC IN", + "TC OUT", "TC DAI8 Playback", + "TC DAI6 Capture", "TC IN"; + + /* + * @ : used at links + */ + links = < + /* + * [DPCM] + * + * cpu20/cpu21 are converting rate to 44.1kHz + * + * FE BE + * <feA> **** <beA> + * cpu2_0 <----@---* *------@---> codec2_0 (44.1kHz) + * cpu2_1 <----@---* * + * <feB> **** + */ + &feA &feB &beA /* both FE / BE */ + + /* + * [DPCM-Multi] + * + * FE BE + * <feC> **** <beB> +-+ + * cpu2_2 <----@---* *------@---> | | -> codec2_1 + * cpu2_3 <----@---* * | | -> codec2_2 + * <feD> **** +-+ + */ + &feC &feD &beB /* both FE / BE*/ + + /* + * [Codec2Codec] + * + * <c2c> + * +-@-> codec2_3 + * | + * +---> codec2_4 + */ + &c2c /* CPU side only */ + + /* + * [Codec2Codec-Multi] + * + * --NOTE-- + * Multi connect N:M is not supported by ASoC. + * + * <c2c_m> +-+ + * +---@-->| |-> codec2_5 + * | | |-> codec2_6 + * | +-+ + * | +-+ + * +------>| |-> codec2_7 + * | |-> codec2_8 + * +-+ + */ + &c2c_m /* CPU side only */ + >; + + multi { + #address-cells = <1>; + #size-cells = <0>; + + /* + * [DPCM-Multi]::BE + * + * FE BE + * <feC> **** <beB> +---+ + * cpu2_2 <----@---* *------@---> |x a| -> codec2_1 + * cpu2_3 <----@---* * | b| -> codec2_2 + * <feD> **** +---+ + */ + ports@2 { + reg = <2>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mbe_x_ep: endpoint { remote-endpoint = <&beB_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mbe_a_ep: endpoint { remote-endpoint = <&codec2_1_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mbe_b_ep: endpoint { remote-endpoint = <&codec2_2_ep>; };};/* (b) Multi Element */ + }; + + /* + * [Codec2Codec-Multi]::CPU + * + * <c2c_m> c2cmf +---+ + * +---@---------->|X A|-> codec2_5 + * | | B|-> codec2_6 + * | +---+ + * | c2cmb +---+ + * +-------------->|x a|-> codec2_7 + * | b|-> codec2_8 + * +---+ + */ + ports@3 { + reg = <3>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mc2c0X_ep: endpoint { remote-endpoint = <&c2cmf_ep>; };};/* (X) to pair */ + port@1 { reg = <1>; mc2c0A_ep: endpoint { remote-endpoint = <&codec2_5_ep>; };};/* (A) Multi Element */ + port@2 { reg = <2>; mc2c0B_ep: endpoint { remote-endpoint = <&codec2_6_ep>; };};/* (B) Multi Element */ + }; + + /* + * [Codec2Codec-Multi]::Codec + * + * <c2c_m> c2cmf +---+ + * +---@---------->|X A|-> codec2_5 + * | | B|-> codec2_6 + * | +---+ + * | c2cmb +---+ + * +-------------->|x a|-> codec2_7 + * | b|-> codec2_8 + * +---+ + */ + ports@4 { + reg = <4>; + #address-cells = <1>; + #size-cells = <0>; + port@0 { reg = <0>; mc2c1x_ep: endpoint { remote-endpoint = <&c2cmb_ep>; };};/* (x) to pair */ + port@1 { reg = <1>; mc2c1a_ep: endpoint { remote-endpoint = <&codec2_7_ep>; };};/* (a) Multi Element */ + port@2 { reg = <2>; mc2c1b_ep: endpoint { remote-endpoint = <&codec2_8_ep>; };};/* (b) Multi Element */ + }; + }; + + dpcm { + #address-cells = <1>; + #size-cells = <0>; + + /* FE part */ + ports@0 { + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + /* + * [DPCM]::FE + * + * FE BE + * <feA> **** <beA> + * cpu2_0 <----@---* *------@---> codec2_0 (44.1kHz) + * cpu2_1 <----@---* * + * <feB> **** + */ + feA: port@0 { reg = <0>; feA_ep: endpoint { remote-endpoint = <&cpu2_0_ep>; }; }; + feB: port@1 { reg = <1>; feB_ep: endpoint { remote-endpoint = <&cpu2_1_ep>; }; }; + + /* + * [DPCM-Multi]::FE + * + * FE BE + * <feC> **** <beB> +-+ + * cpu2_2 <----@---* *------@---> | | -> codec2_1 + * cpu2_3 <----@---* * | | -> codec2_2 + * <feD> **** +-+ + */ + feC: port@2 { reg = <2>; feC_ep: endpoint { remote-endpoint = <&cpu2_2_ep>; }; }; + feD: port@3 { reg = <3>; feD_ep: endpoint { remote-endpoint = <&cpu2_3_ep>; }; }; + }; + + /* BE part */ + ports@1 { + reg = <1>; + + #address-cells = <1>; + #size-cells = <0>; + /* + * [DPCM]::BE + * + * FE BE + * <feA> **** <beA> + * cpu2_0 <----@---* *------@---> codec2_0 (44.1kHz) + * cpu2_1 <----@---* * + * <feB> **** + */ + beA: port@0 { reg = <0>; beA_ep: endpoint { remote-endpoint = <&codec2_0_ep>; }; }; + + /* + * [DPCM-Multi]::BE + * + * FE BE + * <feC> **** <beB> +-------+ + * cpu2_2 <----@---* *------@---> |mbe_x | -> codec2_1 + * cpu2_3 <----@---* * | | -> codec2_2 + * <feD> **** +-------+ + */ + beB: port@1 { reg = <1>; beB_ep: endpoint { remote-endpoint = <&mbe_x_ep>; }; }; + }; + }; + + codec2codec { + #address-cells = <1>; + #size-cells = <0>; + /* + * [Codec2Codec] + * + * <c2c> + * +-@--> codec2_3 + * | + * +----> codec2_4 + */ + ports@0 { + reg = <0>; + + #address-cells = <1>; + #size-cells = <0>; + + /* use default settings */ + c2c: port@0 { reg = <0>; c2cf_ep: endpoint { remote-endpoint = <&codec2_3_ep>; }; }; + port@1 { reg = <1>; c2cb_ep: endpoint { remote-endpoint = <&codec2_4_ep>; }; }; + }; + + /* + * [Codec2Codec-Multi] + * + * <c2c_m> c2cmf +--------+ + * +---@---------->|mc2c0X |-> codec2_5 + * | | |-> codec2_6 + * | +--------+ + * | c2cmb +--------+ + * +-------------->|mc2c1x |-> codec2_7 + * | |-> codec2_8 + * +--------+ + */ + ports@1 { + reg = <1>; + + #address-cells = <1>; + #size-cells = <0>; + + /* use original settings */ + rate = <48000>; + c2c_m: port@0 { reg = <0>; c2cmf_ep: endpoint { remote-endpoint = <&mc2c0X_ep>; }; }; + port@1 { reg = <1>; c2cmb_ep: endpoint { remote-endpoint = <&mc2c1x_ep>; }; }; + }; + }; + }; + + test_cpu_2 { + /* + * update compatible to indicate more detail behaviour + * if you want. see test-compatible for more detail. + * + * ex) + * - compatible = "test-cpu"; + * + compatible = "test-cpu-verbose"; + */ + compatible = "test-cpu"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + bitclock-master; + frame-master; + + /* [DPCM]::FE */ + port@0 { reg = <0>; cpu2_0_ep: endpoint { remote-endpoint = <&feA_ep>; };}; + port@1 { reg = <1>; cpu2_1_ep: endpoint { remote-endpoint = <&feB_ep>; };}; + /* [DPCM-Multi]::FE */ + port@2 { reg = <2>; cpu2_2_ep: endpoint { remote-endpoint = <&feC_ep>; };}; + port@3 { reg = <3>; cpu2_3_ep: endpoint { remote-endpoint = <&feD_ep>; };}; + }; + }; + + test_codec_2 { + /* + * update compatible to indicate more detail behaviour + * if you want. see test-compatible for more detail. + * + * ex) + * - compatible = "test-codec"; + * + compatible = "test-codec-verbose"; + */ + compatible = "test-codec"; + ports { + #address-cells = <1>; + #size-cells = <0>; + + /* + * prefix can be added to *component*, + * see audio-graph-card2::routing + */ + prefix = "TC"; + + /* [DPCM]::BE */ + port@0 { + convert-rate = <44100>; + reg = <0>; codec2_0_ep: endpoint { remote-endpoint = <&beA_ep>; }; + }; + /* [DPCM-Multi]::BE */ + port@1 { reg = <1>; codec2_1_ep: endpoint { remote-endpoint = <&mbe_a_ep>; };}; + port@2 { reg = <2>; codec2_2_ep: endpoint { remote-endpoint = <&mbe_b_ep>; };}; + /* [Codec2Codec] */ + port@3 { bitclock-master; + frame-master; + reg = <3>; codec2_3_ep: endpoint { remote-endpoint = <&c2cf_ep>; };}; + port@4 { reg = <4>; codec2_4_ep: endpoint { remote-endpoint = <&c2cb_ep>; };}; + /* [Codec2Codec-Multi] */ + port@5 { bitclock-master; + frame-master; + reg = <5>; codec2_5_ep: endpoint { remote-endpoint = <&mc2c0A_ep>; };}; + port@6 { reg = <6>; codec2_6_ep: endpoint { remote-endpoint = <&mc2c0B_ep>; };}; + port@7 { reg = <7>; codec2_7_ep: endpoint { remote-endpoint = <&mc2c1a_ep>; };}; + port@8 { reg = <8>; codec2_8_ep: endpoint { remote-endpoint = <&mc2c1b_ep>; };}; + }; + }; +}; diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c index ee94b256b770..5dcc78c551a2 100644 --- a/sound/soc/generic/audio-graph-card2.c +++ b/sound/soc/generic/audio-graph-card2.c @@ -234,6 +234,13 @@ enum graph_type { #define GRAPH_NODENAME_DPCM "dpcm" #define GRAPH_NODENAME_C2C "codec2codec" +#define graph_ret(priv, ret) _graph_ret(priv, __func__, ret) +static inline int _graph_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + #define ep_to_port(ep) of_get_parent(ep) static struct device_node *port_to_ports(struct device_node *port) { @@ -409,21 +416,21 @@ static int __graph_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, idx); } - ret = graph_util_parse_dai(dev, ep, dlc, &is_single_links); + ret = graph_util_parse_dai(priv, ep, dlc, &is_single_links); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_tdm(ep, dai); if (ret < 0) - return ret; + goto end; - ret = simple_util_parse_tdm_width_map(dev, ep, dai); + ret = simple_util_parse_tdm_width_map(priv, ep, dai); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_clk(dev, ep, dai, dlc); if (ret < 0) - return ret; + goto end; /* * set DAI Name @@ -443,22 +450,22 @@ static int __graph_parse_node(struct simple_util_priv *priv, case GRAPH_NORMAL: /* run is_cpu only. see audio_graph2_link_normal() */ if (is_cpu) - simple_util_set_dailink_name(dev, dai_link, "%s%s-%s%s", + simple_util_set_dailink_name(priv, dai_link, "%s%s-%s%s", cpus->dai_name, cpu_multi, codecs->dai_name, codec_multi); break; case GRAPH_DPCM: if (is_cpu) - simple_util_set_dailink_name(dev, dai_link, "fe.%pOFP.%s%s", + simple_util_set_dailink_name(priv, dai_link, "fe.%pOFP.%s%s", cpus->of_node, cpus->dai_name, cpu_multi); else - simple_util_set_dailink_name(dev, dai_link, "be.%pOFP.%s%s", + simple_util_set_dailink_name(priv, dai_link, "be.%pOFP.%s%s", codecs->of_node, codecs->dai_name, codec_multi); break; case GRAPH_C2C: /* run is_cpu only. see audio_graph2_link_c2c() */ if (is_cpu) - simple_util_set_dailink_name(dev, dai_link, "c2c.%s%s-%s%s", + simple_util_set_dailink_name(priv, dai_link, "c2c.%s%s-%s%s", cpus->dai_name, cpu_multi, codecs->dai_name, codec_multi); break; @@ -488,11 +495,12 @@ static int __graph_parse_node(struct simple_util_priv *priv, simple_util_canonicalize_cpu(cpus, is_single_links); simple_util_canonicalize_platform(platforms, cpus); } - - return 0; +end: + return graph_ret(priv, ret); } -static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, +static int graph_parse_node_multi_nm(struct simple_util_priv *priv, + struct snd_soc_dai_link *dai_link, int *nm_idx, int cpu_idx, struct device_node *mcpu_port) { @@ -534,10 +542,10 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, struct device_node *mcodec_port_top __free(device_node) = ep_to_port(mcodec_ep_top); struct device_node *mcodec_ports __free(device_node) = port_to_ports(mcodec_port_top); int nm_max = max(dai_link->num_cpus, dai_link->num_codecs); - int ret = 0; + int ret = -EINVAL; if (cpu_idx > dai_link->num_cpus) - return -EINVAL; + goto end; for_each_of_graph_port_endpoint(mcpu_port, mcpu_ep_n) { int codec_idx = 0; @@ -578,8 +586,8 @@ static int graph_parse_node_multi_nm(struct snd_soc_dai_link *dai_link, if (ret < 0) break; } - - return ret; +end: + return graph_ret(priv, ret); } static int graph_parse_node_multi(struct simple_util_priv *priv, @@ -633,7 +641,7 @@ static int graph_parse_node_multi(struct simple_util_priv *priv, /* CPU:Codec = N:M */ if (is_cpu && dai_link->ch_maps) { - ret = graph_parse_node_multi_nm(dai_link, &nm_idx, idx, port); + ret = graph_parse_node_multi_nm(priv, dai_link, &nm_idx, idx, port); if (ret < 0) goto multi_err; } @@ -643,7 +651,7 @@ static int graph_parse_node_multi(struct simple_util_priv *priv, ret = -EINVAL; multi_err: - return ret; + return graph_ret(priv, ret); } static int graph_parse_node_single(struct simple_util_priv *priv, @@ -651,7 +659,7 @@ static int graph_parse_node_single(struct simple_util_priv *priv, struct device_node *ep, struct link_info *li, int is_cpu) { - return __graph_parse_node(priv, gtype, ep, li, is_cpu, 0); + return graph_ret(priv, __graph_parse_node(priv, gtype, ep, li, is_cpu, 0)); } static int graph_parse_node(struct simple_util_priv *priv, @@ -660,11 +668,14 @@ static int graph_parse_node(struct simple_util_priv *priv, struct link_info *li, int is_cpu) { struct device_node *port __free(device_node) = ep_to_port(ep); + int ret; if (graph_lnk_is_multi(port)) - return graph_parse_node_multi(priv, gtype, port, li, is_cpu); + ret = graph_parse_node_multi(priv, gtype, port, li, is_cpu); else - return graph_parse_node_single(priv, gtype, ep, li, is_cpu); + ret = graph_parse_node_single(priv, gtype, ep, li, is_cpu); + + return graph_ret(priv, ret); } static void graph_parse_daifmt(struct device_node *node, unsigned int *daifmt) @@ -842,18 +853,19 @@ int audio_graph2_link_normal(struct simple_util_priv *priv, */ ret = graph_parse_node(priv, GRAPH_NORMAL, codec_ep, li, 0); if (ret < 0) - return ret; + goto end; /* * call CPU, and set DAI Name */ ret = graph_parse_node(priv, GRAPH_NORMAL, cpu_ep, li, 1); if (ret < 0) - return ret; + goto end; graph_link_init(priv, lnk, cpu_ep, codec_ep, li, 1); - return ret; +end: + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_link_normal); @@ -946,7 +958,7 @@ int audio_graph2_link_dpcm(struct simple_util_priv *priv, graph_link_init(priv, lnk, cpu_ep, codec_ep, li, is_cpu); - return ret; + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_link_dpcm); @@ -992,8 +1004,13 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, struct snd_soc_pcm_stream *c2c_conf; c2c_conf = devm_kzalloc(dev, sizeof(*c2c_conf), GFP_KERNEL); - if (!c2c_conf) - return ret; + if (!c2c_conf) { + /* + * Clang doesn't allow to use "goto end" before calling __free(), + * because it bypasses the initialization. Use graph_ret() directly. + */ + return graph_ret(priv, -ENOMEM); + } c2c_conf->formats = SNDRV_PCM_FMTBIT_S32_LE; /* update ME */ c2c_conf->rates = SNDRV_PCM_RATE_8000_384000; @@ -1019,18 +1036,18 @@ int audio_graph2_link_c2c(struct simple_util_priv *priv, */ ret = graph_parse_node(priv, GRAPH_C2C, codec1_ep, li, 0); if (ret < 0) - return ret; + goto end; /* * call CPU, and set DAI Name */ ret = graph_parse_node(priv, GRAPH_C2C, codec0_ep, li, 1); if (ret < 0) - return ret; + goto end; graph_link_init(priv, lnk, codec0_ep, codec1_ep, li, 1); - - return ret; +end: + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_link_c2c); @@ -1078,7 +1095,7 @@ static int graph_link(struct simple_util_priv *priv, li->link++; err: - return ret; + return graph_ret(priv, ret); } static int graph_counter(struct device_node *lnk) @@ -1249,7 +1266,7 @@ static int graph_count(struct simple_util_priv *priv, li->link++; err: - return ret; + return graph_ret(priv, ret); } static int graph_for_each_link(struct simple_util_priv *priv, @@ -1266,7 +1283,7 @@ static int graph_for_each_link(struct simple_util_priv *priv, struct device_node *node = dev->of_node; struct device_node *lnk; enum graph_type gtype; - int rc, ret; + int rc, ret = 0; /* loop for all listed CPU port */ of_for_each_phandle(&it, rc, node, "links", NULL, 0) { @@ -1276,10 +1293,10 @@ static int graph_for_each_link(struct simple_util_priv *priv, ret = func(priv, hooks, gtype, lnk, li); if (ret < 0) - return ret; + break; } - return 0; + return graph_ret(priv, ret); } int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, @@ -1332,7 +1349,7 @@ int audio_graph2_parse_of(struct simple_util_priv *priv, struct device *dev, if (ret < 0) goto err; - ret = simple_util_parse_card_name(card, NULL); + ret = simple_util_parse_card_name(priv, NULL); if (ret < 0) goto err; @@ -1355,7 +1372,7 @@ err: if (ret < 0) dev_err_probe(dev, ret, "parse error\n"); - return ret; + return graph_ret(priv, ret); } EXPORT_SYMBOL_GPL(audio_graph2_parse_of); diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index c2445c5ccd84..a1ccc300e68c 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -15,6 +15,13 @@ #include <sound/pcm_params.h> #include <sound/simple_card_utils.h> +#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret) +static inline int _simple_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + int simple_util_get_sample_fmt(struct simple_util_data *data) { int i; @@ -133,33 +140,42 @@ int simple_util_parse_daifmt(struct device *dev, } EXPORT_SYMBOL_GPL(simple_util_parse_daifmt); -int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, +int simple_util_parse_tdm_width_map(struct simple_util_priv *priv, struct device_node *np, struct simple_util_dai *dai) { + struct device *dev = simple_priv_to_dev(priv); int n, i, ret; u32 *p; + /* + * NOTE + * + * Clang doesn't allow to use "goto end" before calling __free(), + * because it bypasses the initialization. Use simple_ret() directly. + */ + n = of_property_count_elems_of_size(np, "dai-tdm-slot-width-map", sizeof(u32)); if (n <= 0) return 0; + if (n % 3) { dev_err(dev, "Invalid number of cells for dai-tdm-slot-width-map\n"); - return -EINVAL; + return simple_ret(priv, -EINVAL); /* see NOTE */ } + ret = -ENOMEM; dai->tdm_width_map = devm_kcalloc(dev, n, sizeof(*dai->tdm_width_map), GFP_KERNEL); if (!dai->tdm_width_map) - return -ENOMEM; + return simple_ret(priv, ret); /* see NOTE */ - u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), - GFP_KERNEL); + u32 *array_values __free(kfree) = kcalloc(n, sizeof(*array_values), GFP_KERNEL); if (!array_values) - return -ENOMEM; + goto end; ret = of_property_read_u32_array(np, "dai-tdm-slot-width-map", array_values, n); if (ret < 0) { dev_err(dev, "Could not read dai-tdm-slot-width-map: %d\n", ret); - return ret; + goto end; } p = array_values; @@ -170,15 +186,17 @@ int simple_util_parse_tdm_width_map(struct device *dev, struct device_node *np, } dai->n_tdm_widths = i; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_parse_tdm_width_map); -int simple_util_set_dailink_name(struct device *dev, +int simple_util_set_dailink_name(struct simple_util_priv *priv, struct snd_soc_dai_link *dai_link, const char *fmt, ...) { + struct device *dev = simple_priv_to_dev(priv); va_list ap; char *name = NULL; int ret = -ENOMEM; @@ -194,13 +212,14 @@ int simple_util_set_dailink_name(struct device *dev, dai_link->stream_name = name; } - return ret; + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_set_dailink_name); -int simple_util_parse_card_name(struct snd_soc_card *card, +int simple_util_parse_card_name(struct simple_util_priv *priv, char *prefix) { + struct snd_soc_card *card = simple_priv_to_card(priv); int ret; if (!prefix) @@ -214,13 +233,13 @@ int simple_util_parse_card_name(struct snd_soc_card *card, snprintf(prop, sizeof(prop), "%sname", prefix); ret = snd_soc_of_parse_card_name(card, prop); if (ret < 0) - return ret; + goto end; } if (!card->name && card->dai_link) card->name = card->dai_link->name; - - return 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_parse_card_name); @@ -348,7 +367,8 @@ cpu_err: break; simple_clk_disable(dai); } - return ret; + + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_startup); @@ -379,16 +399,19 @@ void simple_util_shutdown(struct snd_pcm_substream *substream) } EXPORT_SYMBOL_GPL(simple_util_shutdown); -static int simple_set_clk_rate(struct device *dev, - struct simple_util_dai *simple_dai, - unsigned long rate) +static int simple_set_clk_rate(struct simple_util_priv *priv, + struct simple_util_dai *simple_dai, + unsigned long rate) { + struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; + if (!simple_dai) return 0; if (simple_dai->clk_fixed && rate != simple_dai->sysclk) { dev_err(dev, "dai %s invalid clock rate %lu\n", simple_dai->name, rate); - return -EINVAL; + goto end; } if (!simple_dai->clk) @@ -397,12 +420,15 @@ static int simple_set_clk_rate(struct device *dev, if (clk_get_rate(simple_dai->clk) == rate) return 0; - return clk_set_rate(simple_dai->clk, rate); + ret = clk_set_rate(simple_dai->clk, rate); +end: + return simple_ret(priv, ret); } -static int simple_set_tdm(struct snd_soc_dai *dai, - struct simple_util_dai *simple_dai, - struct snd_pcm_hw_params *params) +static int simple_set_tdm(struct simple_util_priv *priv, + struct snd_soc_dai *dai, + struct simple_util_dai *simple_dai, + struct snd_pcm_hw_params *params) { int sample_bits = params_width(params); int slot_width, slot_count; @@ -430,12 +456,8 @@ static int simple_set_tdm(struct snd_soc_dai *dai, simple_dai->rx_slot_mask, slot_count, slot_width); - if (ret && ret != -ENOTSUPP) { - dev_err(dai->dev, "simple-card: set_tdm_slot error: %d\n", ret); - return ret; - } - return 0; + return simple_ret(priv, ret); } int simple_util_hw_params(struct snd_pcm_substream *substream, @@ -457,15 +479,15 @@ int simple_util_hw_params(struct snd_pcm_substream *substream, mclk = params_rate(params) * mclk_fs; for_each_prop_dai_codec(props, i, pdai) { - ret = simple_set_clk_rate(rtd->dev, pdai, mclk); + ret = simple_set_clk_rate(priv, pdai, mclk); if (ret < 0) - return ret; + goto end; } for_each_prop_dai_cpu(props, i, pdai) { - ret = simple_set_clk_rate(rtd->dev, pdai, mclk); + ret = simple_set_clk_rate(priv, pdai, mclk); if (ret < 0) - return ret; + goto end; } /* Ensure sysclk is set on all components in case any @@ -476,39 +498,40 @@ int simple_util_hw_params(struct snd_pcm_substream *substream, ret = snd_soc_component_set_sysclk(component, 0, 0, mclk, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) - return ret; + goto end; } for_each_rtd_codec_dais(rtd, i, sdai) { pdai = simple_props_to_dai_codec(props, i); ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction); if (ret && ret != -ENOTSUPP) - return ret; + goto end; } for_each_rtd_cpu_dais(rtd, i, sdai) { pdai = simple_props_to_dai_cpu(props, i); ret = snd_soc_dai_set_sysclk(sdai, 0, mclk, pdai->clk_direction); if (ret && ret != -ENOTSUPP) - return ret; + goto end; } } for_each_prop_dai_codec(props, i, pdai) { sdai = snd_soc_rtd_to_codec(rtd, i); - ret = simple_set_tdm(sdai, pdai, params); + ret = simple_set_tdm(priv, sdai, pdai, params); if (ret < 0) - return ret; + goto end; } for_each_prop_dai_cpu(props, i, pdai) { sdai = snd_soc_rtd_to_cpu(rtd, i); - ret = simple_set_tdm(sdai, pdai, params); + ret = simple_set_tdm(priv, sdai, pdai, params); if (ret < 0) - return ret; + goto end; } - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_hw_params); @@ -536,7 +559,8 @@ int simple_util_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, } EXPORT_SYMBOL_GPL(simple_util_be_hw_params_fixup); -static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simple_dai) +static int simple_init_dai(struct simple_util_priv *priv, + struct snd_soc_dai *dai, struct simple_util_dai *simple_dai) { int ret; @@ -548,7 +572,7 @@ static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simp simple_dai->clk_direction); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "simple-card: set_sysclk error\n"); - return ret; + goto end; } } @@ -560,11 +584,12 @@ static int simple_init_dai(struct snd_soc_dai *dai, struct simple_util_dai *simp simple_dai->slot_width); if (ret && ret != -ENOTSUPP) { dev_err(dai->dev, "simple-card: set_tdm_slot error\n"); - return ret; + goto end; } } - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static inline int simple_component_is_codec(struct snd_soc_component *component) @@ -572,7 +597,8 @@ static inline int simple_component_is_codec(struct snd_soc_component *component) return component->driver->endianness; } -static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, +static int simple_init_for_codec2codec(struct simple_util_priv *priv, + struct snd_soc_pcm_runtime *rtd, struct simple_dai_props *dai_props) { struct snd_soc_dai_link *dai_link = rtd->dai_link; @@ -604,12 +630,13 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, if (ret < 0) { dev_err(rtd->dev, "simple-card: no valid dai_link params\n"); - return ret; + goto end; } + ret = -ENOMEM; c2c_params = devm_kzalloc(rtd->dev, sizeof(*c2c_params), GFP_KERNEL); if (!c2c_params) - return -ENOMEM; + goto end; c2c_params->formats = hw.formats; c2c_params->rates = hw.rates; @@ -621,7 +648,9 @@ static int simple_init_for_codec2codec(struct snd_soc_pcm_runtime *rtd, dai_link->c2c_params = c2c_params; dai_link->num_c2c_params = 1; - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd) @@ -632,21 +661,19 @@ int simple_util_dai_init(struct snd_soc_pcm_runtime *rtd) int i, ret; for_each_prop_dai_codec(props, i, dai) { - ret = simple_init_dai(snd_soc_rtd_to_codec(rtd, i), dai); + ret = simple_init_dai(priv, snd_soc_rtd_to_codec(rtd, i), dai); if (ret < 0) - return ret; + goto end; } for_each_prop_dai_cpu(props, i, dai) { - ret = simple_init_dai(snd_soc_rtd_to_cpu(rtd, i), dai); + ret = simple_init_dai(priv, snd_soc_rtd_to_cpu(rtd, i), dai); if (ret < 0) - return ret; + goto end; } - ret = simple_init_for_codec2codec(rtd, props); - if (ret < 0) - return ret; - - return 0; + ret = simple_init_for_codec2codec(priv, rtd, props); +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(simple_util_dai_init); @@ -831,7 +858,7 @@ int simple_util_init_aux_jacks(struct simple_util_priv *priv, char *prefix) priv->aux_jacks = devm_kcalloc(card->dev, num, sizeof(struct snd_soc_jack), GFP_KERNEL); if (!priv->aux_jacks) - return -ENOMEM; + return simple_ret(priv, -ENOMEM); for_each_card_auxs(card, component) { char id[128]; @@ -992,13 +1019,11 @@ int graph_util_card_probe(struct snd_soc_card *card) ret = simple_util_init_hp(card, &priv->hp_jack, NULL); if (ret < 0) - return ret; + goto end; ret = simple_util_init_mic(card, &priv->mic_jack, NULL); - if (ret < 0) - return ret; - - return 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(graph_util_card_probe); @@ -1074,9 +1099,11 @@ static int graph_get_dai_id(struct device_node *ep) return id; } -int graph_util_parse_dai(struct device *dev, struct device_node *ep, +int graph_util_parse_dai(struct simple_util_priv *priv, struct device_node *ep, struct snd_soc_dai_link_component *dlc, int *is_single_link) { + struct device *dev = simple_priv_to_dev(priv); + struct device_node *node; struct of_phandle_args args = {}; struct snd_soc_dai *dai; int ret; @@ -1084,7 +1111,7 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, if (!ep) return 0; - struct device_node *node __free(device_node) = of_graph_get_port_parent(ep); + node = of_graph_get_port_parent(ep); /* * Try to find from DAI node @@ -1092,11 +1119,12 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, args.np = ep; dai = snd_soc_get_dai_via_args(&args); if (dai) { + ret = -ENOMEM; dlc->of_node = node; dlc->dai_name = snd_soc_dai_name_get(dai); dlc->dai_args = snd_soc_copy_dai_args(dev, &args); if (!dlc->dai_args) - return -ENOMEM; + goto end; goto parse_dai_end; } @@ -1126,14 +1154,17 @@ int graph_util_parse_dai(struct device *dev, struct device_node *ep, * if he unbinded CPU or Codec. */ ret = snd_soc_get_dlc(&args, dlc); - if (ret < 0) - return ret; + if (ret < 0) { + of_node_put(node); + goto end; + } parse_dai_end: if (is_single_link) *is_single_link = of_graph_get_endpoint_count(node) == 1; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } EXPORT_SYMBOL_GPL(graph_util_parse_dai); diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index afe7e79ffdbd..5af6d1b308f2 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -29,7 +29,16 @@ static const struct snd_soc_ops simple_ops = { .hw_params = simple_util_hw_params, }; -static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_link_component *dlc) +#define simple_ret(priv, ret) _simple_ret(priv, __func__, ret) +static inline int _simple_ret(struct simple_util_priv *priv, + const char *func, int ret) +{ + return snd_soc_ret(simple_priv_to_dev(priv), ret, "at %s()\n", func); +} + +static int simple_parse_platform(struct simple_util_priv *priv, + struct device_node *node, + struct snd_soc_dai_link_component *dlc) { struct of_phandle_args args; int ret; @@ -43,7 +52,7 @@ static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_li */ ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); if (ret) - return ret; + return simple_ret(priv, ret); /* dai_name is not required and may not exist for plat component */ @@ -52,11 +61,12 @@ static int simple_parse_platform(struct device_node *node, struct snd_soc_dai_li return 0; } -static int simple_parse_dai(struct device *dev, +static int simple_parse_dai(struct simple_util_priv *priv, struct device_node *node, struct snd_soc_dai_link_component *dlc, int *is_single_link) { + struct device *dev = simple_priv_to_dev(priv); struct of_phandle_args args; struct snd_soc_dai *dai; int ret; @@ -70,17 +80,18 @@ static int simple_parse_dai(struct device *dev, */ ret = of_parse_phandle_with_args(node, DAI, CELL, 0, &args); if (ret) - return ret; + goto end; /* * Try to find from DAI args */ dai = snd_soc_get_dai_via_args(&args); if (dai) { + ret = -ENOMEM; dlc->dai_name = snd_soc_dai_name_get(dai); dlc->dai_args = snd_soc_copy_dai_args(dev, &args); if (!dlc->dai_args) - return -ENOMEM; + goto end; goto parse_dai_end; } @@ -106,13 +117,14 @@ static int simple_parse_dai(struct device *dev, */ ret = snd_soc_get_dlc(&args, dlc); if (ret < 0) - return ret; + goto end; parse_dai_end: if (is_single_link) *is_single_link = !args.args_count; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static void simple_parse_convert(struct device *dev, @@ -149,19 +161,17 @@ static int simple_parse_node(struct simple_util_priv *priv, dai = simple_props_to_dai_codec(dai_props, 0); } - ret = simple_parse_dai(dev, np, dlc, cpu); + ret = simple_parse_dai(priv, np, dlc, cpu); if (ret) - return ret; + goto end; ret = simple_util_parse_clk(dev, np, dai, dlc); if (ret) - return ret; + goto end; ret = simple_util_parse_tdm(np, dai); - if (ret) - return ret; - - return 0; +end: + return simple_ret(priv, ret); } static int simple_link_init(struct simple_util_priv *priv, @@ -183,7 +193,7 @@ static int simple_link_init(struct simple_util_priv *priv, ret = simple_util_parse_daifmt(dev, node, codec, prefix, &dai_link->dai_fmt); if (ret < 0) - return ret; + goto end; graph_util_parse_link_direction(top, &playback_only, &capture_only); graph_util_parse_link_direction(node, &playback_only, &capture_only); @@ -213,7 +223,9 @@ static int simple_link_init(struct simple_util_priv *priv, dai_link->init = simple_util_dai_init; dai_link->ops = &simple_ops; - return simple_util_set_dailink_name(dev, dai_link, name); + ret = simple_util_set_dailink_name(priv, dai_link, name); +end: + return simple_ret(priv, ret); } static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, @@ -290,7 +302,7 @@ static int simple_dai_link_of_dpcm(struct simple_util_priv *priv, out_put_node: li->link++; - return ret; + return simple_ret(priv, ret); } static int simple_dai_link_of(struct simple_util_priv *priv, @@ -330,7 +342,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv, if (ret < 0) goto dai_link_of_err; - ret = simple_parse_platform(plat, platforms); + ret = simple_parse_platform(priv, plat, platforms); if (ret < 0) goto dai_link_of_err; @@ -345,7 +357,7 @@ static int simple_dai_link_of(struct simple_util_priv *priv, dai_link_of_err: li->link++; - return ret; + return simple_ret(priv, ret); } static int __simple_for_each_link(struct simple_util_priv *priv, @@ -443,10 +455,10 @@ static int __simple_for_each_link(struct simple_util_priv *priv, node = of_get_next_child(top, node); } while (!is_top && node); - error: +error: of_node_put(node); - return ret; + return simple_ret(priv, ret); } static int simple_for_each_link(struct simple_util_priv *priv, @@ -479,7 +491,7 @@ static int simple_for_each_link(struct simple_util_priv *priv, break; } - return ret; + return simple_ret(priv, ret); } static void simple_depopulate_aux(void *data) @@ -500,9 +512,11 @@ static int simple_populate_aux(struct simple_util_priv *priv) ret = of_platform_populate(node, NULL, NULL, dev); if (ret) - return ret; + goto end; - return devm_add_action_or_reset(dev, simple_depopulate_aux, priv); + ret = devm_add_action_or_reset(dev, simple_depopulate_aux, priv); +end: + return simple_ret(priv, ret); } static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) @@ -512,15 +526,15 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) ret = simple_util_parse_widgets(card, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_routing(card, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_parse_pin_switches(card, PREFIX); if (ret < 0) - return ret; + goto end; /* Single/Muti DAI link(s) & New style of DT node */ memset(li, 0, sizeof(*li)); @@ -528,19 +542,19 @@ static int simple_parse_of(struct simple_util_priv *priv, struct link_info *li) simple_dai_link_of, simple_dai_link_of_dpcm); if (ret < 0) - return ret; + goto end; - ret = simple_util_parse_card_name(card, PREFIX); + ret = simple_util_parse_card_name(priv, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_populate_aux(priv); if (ret < 0) - return ret; + goto end; ret = snd_soc_of_parse_aux_devs(card, PREFIX "aux-devs"); - - return ret; +end: + return simple_ret(priv, ret); } static int simple_count_noml(struct simple_util_priv *priv, @@ -548,12 +562,10 @@ static int simple_count_noml(struct simple_util_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - if (li->link >= SNDRV_MAX_LINKS) { - struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; /* * DON'T REMOVE platforms @@ -575,8 +587,9 @@ static int simple_count_noml(struct simple_util_priv *priv, li->num[li->link].codecs = 1; li->link += 1; - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static int simple_count_dpcm(struct simple_util_priv *priv, @@ -584,12 +597,10 @@ static int simple_count_dpcm(struct simple_util_priv *priv, struct device_node *codec, struct link_info *li, bool is_top) { - if (li->link >= SNDRV_MAX_LINKS) { - struct device *dev = simple_priv_to_dev(priv); + int ret = -EINVAL; - dev_err(dev, "too many links\n"); - return -EINVAL; - } + if (li->link >= SNDRV_MAX_LINKS) + goto end; if (li->cpu) { /* @@ -606,8 +617,9 @@ static int simple_count_dpcm(struct simple_util_priv *priv, li->link++; /* dummy-Codec */ } - - return 0; + ret = 0; +end: + return simple_ret(priv, ret); } static int simple_get_dais_count(struct simple_util_priv *priv, @@ -683,17 +695,15 @@ static int simple_soc_probe(struct snd_soc_card *card) ret = simple_util_init_hp(card, &priv->hp_jack, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_init_mic(card, &priv->mic_jack, PREFIX); if (ret < 0) - return ret; + goto end; ret = simple_util_init_aux_jacks(priv, PREFIX); - if (ret < 0) - return ret; - - return 0; +end: + return simple_ret(priv, ret); } static int simple_probe(struct platform_device *pdev) @@ -715,20 +725,22 @@ static int simple_probe(struct platform_device *pdev) card->probe = simple_soc_probe; card->driver_name = "simple-card"; + ret = -ENOMEM; struct link_info *li __free(kfree) = kzalloc(sizeof(*li), GFP_KERNEL); if (!li) - return -ENOMEM; + goto end; ret = simple_get_dais_count(priv, li); if (ret < 0) - return ret; + goto end; + ret = -EINVAL; if (!li->link) - return -EINVAL; + goto end; ret = simple_util_init_priv(priv, li); if (ret < 0) - return ret; + goto end; if (np && of_device_is_available(np)) { @@ -795,8 +807,8 @@ static int simple_probe(struct platform_device *pdev) return 0; err: simple_util_clean_reference(card); - - return ret; +end: + return dev_err_probe(dev, ret, "parse error\n"); } static const struct of_device_id simple_of_match[] = { diff --git a/sound/soc/img/img-i2s-in.c b/sound/soc/img/img-i2s-in.c index 6a988976fb0d..98d2ab68883a 100644 --- a/sound/soc/img/img-i2s-in.c +++ b/sound/soc/img/img-i2s-in.c @@ -539,7 +539,6 @@ static void img_i2s_in_dev_remove(struct platform_device *pdev) img_i2s_in_runtime_suspend(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int img_i2s_in_suspend(struct device *dev) { struct img_i2s_in *i2s = dev_get_drvdata(dev); @@ -586,7 +585,6 @@ static int img_i2s_in_resume(struct device *dev) return 0; } -#endif static const struct of_device_id img_i2s_in_of_match[] = { { .compatible = "img,i2s-in" }, @@ -595,16 +593,15 @@ static const struct of_device_id img_i2s_in_of_match[] = { MODULE_DEVICE_TABLE(of, img_i2s_in_of_match); static const struct dev_pm_ops img_i2s_in_pm_ops = { - SET_RUNTIME_PM_OPS(img_i2s_in_runtime_suspend, - img_i2s_in_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume) + RUNTIME_PM_OPS(img_i2s_in_runtime_suspend, img_i2s_in_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(img_i2s_in_suspend, img_i2s_in_resume) }; static struct platform_driver img_i2s_in_driver = { .driver = { .name = "img-i2s-in", .of_match_table = img_i2s_in_of_match, - .pm = &img_i2s_in_pm_ops + .pm = pm_ptr(&img_i2s_in_pm_ops) }, .probe = img_i2s_in_probe, .remove = img_i2s_in_dev_remove diff --git a/sound/soc/img/img-i2s-out.c b/sound/soc/img/img-i2s-out.c index 1211e6184d97..aedcf56a5359 100644 --- a/sound/soc/img/img-i2s-out.c +++ b/sound/soc/img/img-i2s-out.c @@ -539,7 +539,6 @@ static void img_i2s_out_dev_remove(struct platform_device *pdev) img_i2s_out_runtime_suspend(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int img_i2s_out_suspend(struct device *dev) { struct img_i2s_out *i2s = dev_get_drvdata(dev); @@ -586,7 +585,6 @@ static int img_i2s_out_resume(struct device *dev) return 0; } -#endif static const struct of_device_id img_i2s_out_of_match[] = { { .compatible = "img,i2s-out" }, @@ -595,16 +593,15 @@ static const struct of_device_id img_i2s_out_of_match[] = { MODULE_DEVICE_TABLE(of, img_i2s_out_of_match); static const struct dev_pm_ops img_i2s_out_pm_ops = { - SET_RUNTIME_PM_OPS(img_i2s_out_runtime_suspend, - img_i2s_out_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume) + RUNTIME_PM_OPS(img_i2s_out_runtime_suspend, img_i2s_out_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(img_i2s_out_suspend, img_i2s_out_resume) }; static struct platform_driver img_i2s_out_driver = { .driver = { .name = "img-i2s-out", .of_match_table = img_i2s_out_of_match, - .pm = &img_i2s_out_pm_ops + .pm = pm_ptr(&img_i2s_out_pm_ops) }, .probe = img_i2s_out_probe, .remove = img_i2s_out_dev_remove diff --git a/sound/soc/img/img-parallel-out.c b/sound/soc/img/img-parallel-out.c index 4ec63119d67c..86b60e6dab38 100644 --- a/sound/soc/img/img-parallel-out.c +++ b/sound/soc/img/img-parallel-out.c @@ -300,15 +300,14 @@ static const struct of_device_id img_prl_out_of_match[] = { MODULE_DEVICE_TABLE(of, img_prl_out_of_match); static const struct dev_pm_ops img_prl_out_pm_ops = { - SET_RUNTIME_PM_OPS(img_prl_out_suspend, - img_prl_out_resume, NULL) + RUNTIME_PM_OPS(img_prl_out_suspend, img_prl_out_resume, NULL) }; static struct platform_driver img_prl_out_driver = { .driver = { .name = "img-parallel-out", .of_match_table = img_prl_out_of_match, - .pm = &img_prl_out_pm_ops + .pm = pm_ptr(&img_prl_out_pm_ops) }, .probe = img_prl_out_probe, .remove = img_prl_out_dev_remove diff --git a/sound/soc/img/img-spdif-in.c b/sound/soc/img/img-spdif-in.c index 3c513f5b8c54..82295e2508fa 100644 --- a/sound/soc/img/img-spdif-in.c +++ b/sound/soc/img/img-spdif-in.c @@ -817,7 +817,6 @@ static void img_spdif_in_dev_remove(struct platform_device *pdev) img_spdif_in_runtime_suspend(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int img_spdif_in_suspend(struct device *dev) { struct img_spdif_in *spdif = dev_get_drvdata(dev); @@ -857,7 +856,6 @@ static int img_spdif_in_resume(struct device *dev) return 0; } -#endif static const struct of_device_id img_spdif_in_of_match[] = { { .compatible = "img,spdif-in" }, @@ -866,16 +864,15 @@ static const struct of_device_id img_spdif_in_of_match[] = { MODULE_DEVICE_TABLE(of, img_spdif_in_of_match); static const struct dev_pm_ops img_spdif_in_pm_ops = { - SET_RUNTIME_PM_OPS(img_spdif_in_runtime_suspend, - img_spdif_in_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume) + RUNTIME_PM_OPS(img_spdif_in_runtime_suspend, img_spdif_in_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(img_spdif_in_suspend, img_spdif_in_resume) }; static struct platform_driver img_spdif_in_driver = { .driver = { .name = "img-spdif-in", .of_match_table = img_spdif_in_of_match, - .pm = &img_spdif_in_pm_ops + .pm = pm_ptr(&img_spdif_in_pm_ops) }, .probe = img_spdif_in_probe, .remove = img_spdif_in_dev_remove diff --git a/sound/soc/img/img-spdif-out.c b/sound/soc/img/img-spdif-out.c index 402695b5fc41..52f696219ef4 100644 --- a/sound/soc/img/img-spdif-out.c +++ b/sound/soc/img/img-spdif-out.c @@ -409,7 +409,6 @@ static void img_spdif_out_dev_remove(struct platform_device *pdev) img_spdif_out_runtime_suspend(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int img_spdif_out_suspend(struct device *dev) { struct img_spdif_out *spdif = dev_get_drvdata(dev); @@ -448,7 +447,7 @@ static int img_spdif_out_resume(struct device *dev) return 0; } -#endif + static const struct of_device_id img_spdif_out_of_match[] = { { .compatible = "img,spdif-out" }, {} @@ -456,16 +455,15 @@ static const struct of_device_id img_spdif_out_of_match[] = { MODULE_DEVICE_TABLE(of, img_spdif_out_of_match); static const struct dev_pm_ops img_spdif_out_pm_ops = { - SET_RUNTIME_PM_OPS(img_spdif_out_runtime_suspend, - img_spdif_out_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(img_spdif_out_suspend, img_spdif_out_resume) + RUNTIME_PM_OPS(img_spdif_out_runtime_suspend, img_spdif_out_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(img_spdif_out_suspend, img_spdif_out_resume) }; static struct platform_driver img_spdif_out_driver = { .driver = { .name = "img-spdif-out", .of_match_table = img_spdif_out_of_match, - .pm = &img_spdif_out_pm_ops + .pm = pm_ptr(&img_spdif_out_pm_ops) }, .probe = img_spdif_out_probe, .remove = img_spdif_out_dev_remove diff --git a/sound/soc/img/pistachio-internal-dac.c b/sound/soc/img/pistachio-internal-dac.c index fdeceb271e7f..ec4f891295c9 100644 --- a/sound/soc/img/pistachio-internal-dac.c +++ b/sound/soc/img/pistachio-internal-dac.c @@ -224,7 +224,6 @@ static void pistachio_internal_dac_remove(struct platform_device *pdev) regulator_disable(dac->supply); } -#ifdef CONFIG_PM static int pistachio_internal_dac_rt_resume(struct device *dev) { struct pistachio_internal_dac *dac = dev_get_drvdata(dev); @@ -251,11 +250,10 @@ static int pistachio_internal_dac_rt_suspend(struct device *dev) return 0; } -#endif static const struct dev_pm_ops pistachio_internal_dac_pm_ops = { - SET_RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend, - pistachio_internal_dac_rt_resume, NULL) + RUNTIME_PM_OPS(pistachio_internal_dac_rt_suspend, + pistachio_internal_dac_rt_resume, NULL) }; static const struct of_device_id pistachio_internal_dac_of_match[] = { @@ -268,7 +266,7 @@ static struct platform_driver pistachio_internal_dac_plat_driver = { .driver = { .name = "img-pistachio-internal-dac", .of_match_table = pistachio_internal_dac_of_match, - .pm = &pistachio_internal_dac_pm_ops + .pm = pm_ptr(&pistachio_internal_dac_pm_ops) }, .probe = pistachio_internal_dac_probe, .remove = pistachio_internal_dac_remove diff --git a/sound/soc/intel/avs/avs.h b/sound/soc/intel/avs/avs.h index eca6ec0428bb..585543f872fc 100644 --- a/sound/soc/intel/avs/avs.h +++ b/sound/soc/intel/avs/avs.h @@ -51,6 +51,7 @@ struct avs_dsp_ops { int (* const load_basefw)(struct avs_dev *, struct firmware *); int (* const load_lib)(struct avs_dev *, struct firmware *, u32); int (* const transfer_mods)(struct avs_dev *, bool, struct avs_module_entry *, u32); + int (* const config_basefw)(struct avs_dev *); int (* const enable_logs)(struct avs_dev *, enum avs_log_enable, u32, u32, unsigned long, u32 *); int (* const log_buffer_offset)(struct avs_dev *, u32); diff --git a/sound/soc/intel/avs/board_selection.c b/sound/soc/intel/avs/board_selection.c index 0266edeafc19..2d706edcbf92 100644 --- a/sound/soc/intel/avs/board_selection.c +++ b/sound/soc/intel/avs/board_selection.c @@ -312,6 +312,18 @@ static struct snd_soc_acpi_mach avs_tgl_i2s_machines[] = { {}, }; +static struct snd_soc_acpi_mach avs_mbl_i2s_machines[] = { + { + .id = "PCM3168A", + .drv_name = "avs_pcm3168a", + .mach_params = { + .i2s_link_mask = AVS_SSP(0) | AVS_SSP(2), + }, + .tplg_filename = "pcm3168a-tplg.bin", + }, + {} +}; + static struct snd_soc_acpi_mach avs_test_i2s_machines[] = { { .drv_name = "avs_i2s_test", @@ -378,10 +390,11 @@ static const struct avs_acpi_boards i2s_boards[] = { AVS_MACH_ENTRY(HDA_ICL_LP, avs_icl_i2s_machines), AVS_MACH_ENTRY(HDA_TGL_LP, avs_tgl_i2s_machines), AVS_MACH_ENTRY(HDA_EHL_0, avs_tgl_i2s_machines), + AVS_MACH_ENTRY(HDA_ADL_N, avs_mbl_i2s_machines), AVS_MACH_ENTRY(HDA_ADL_P, avs_tgl_i2s_machines), AVS_MACH_ENTRY(HDA_RPL_P_0, avs_tgl_i2s_machines), - AVS_MACH_ENTRY(HDA_RPL_M, avs_tgl_i2s_machines), - {}, + AVS_MACH_ENTRY(HDA_RPL_M, avs_mbl_i2s_machines), + {} }; static const struct avs_acpi_boards *avs_get_i2s_boards(struct avs_dev *adev) diff --git a/sound/soc/intel/avs/boards/Kconfig b/sound/soc/intel/avs/boards/Kconfig index 00b0f6c176d6..ba4bee42124c 100644 --- a/sound/soc/intel/avs/boards/Kconfig +++ b/sound/soc/intel/avs/boards/Kconfig @@ -87,6 +87,16 @@ config SND_SOC_INTEL_AVS_MACH_NAU8825 Say Y or m if you have such a device. This is a recommended option. If unsure select "N". +config SND_SOC_INTEL_AVS_MACH_PCM3168A + tristate "pcm3168a I2S board" + depends on I2C + depends on MFD_INTEL_LPSS || COMPILE_TEST + select SND_SOC_PCM3168A_I2C + help + This adds support for AVS with PCM3168A I2C codec configuration. + Say Y or m if you have such a device. This is a recommended option. + If unsure select "N". + config SND_SOC_INTEL_AVS_MACH_PROBE tristate "Probing (data) board" depends on DEBUG_FS diff --git a/sound/soc/intel/avs/boards/Makefile b/sound/soc/intel/avs/boards/Makefile index 4fbd936ffb3e..a95256b94dc8 100644 --- a/sound/soc/intel/avs/boards/Makefile +++ b/sound/soc/intel/avs/boards/Makefile @@ -9,6 +9,7 @@ snd-soc-avs-max98927-y := max98927.o snd-soc-avs-max98357a-y := max98357a.o snd-soc-avs-max98373-y := max98373.o snd-soc-avs-nau8825-y := nau8825.o +snd-soc-avs-pcm3168a-y := pcm3168a.o snd-soc-avs-probe-y := probe.o snd-soc-avs-rt274-y := rt274.o snd-soc-avs-rt286-y := rt286.o @@ -27,6 +28,7 @@ obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98927) += snd-soc-avs-max98927.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98357A) += snd-soc-avs-max98357a.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_MAX98373) += snd-soc-avs-max98373.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_NAU8825) += snd-soc-avs-nau8825.o +obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PCM3168A) += snd-soc-avs-pcm3168a.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_PROBE) += snd-soc-avs-probe.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT274) += snd-soc-avs-rt274.o obj-$(CONFIG_SND_SOC_INTEL_AVS_MACH_RT286) += snd-soc-avs-rt286.o diff --git a/sound/soc/intel/avs/boards/da7219.c b/sound/soc/intel/avs/boards/da7219.c index 76078a7005b0..7217ae51e89c 100644 --- a/sound/soc/intel/avs/boards/da7219.c +++ b/sound/soc/intel/avs/boards/da7219.c @@ -113,7 +113,8 @@ static int avs_da7219_codec_init(struct snd_soc_pcm_runtime *runtime) } num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -197,7 +198,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->be_hw_params_fixup = avs_da7219_be_fixup; dl->init = avs_da7219_codec_init; dl->exit = avs_da7219_codec_exit; diff --git a/sound/soc/intel/avs/boards/es8336.c b/sound/soc/intel/avs/boards/es8336.c index 426ce37105ae..6f3c4f6c9302 100644 --- a/sound/soc/intel/avs/boards/es8336.c +++ b/sound/soc/intel/avs/boards/es8336.c @@ -109,7 +109,8 @@ static int avs_es8336_codec_init(struct snd_soc_pcm_runtime *runtime) data = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; diff --git a/sound/soc/intel/avs/boards/max98357a.c b/sound/soc/intel/avs/boards/max98357a.c index 6570209c1a63..c55c1d60b777 100644 --- a/sound/soc/intel/avs/boards/max98357a.c +++ b/sound/soc/intel/avs/boards/max98357a.c @@ -78,7 +78,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->be_hw_params_fixup = avs_max98357a_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; diff --git a/sound/soc/intel/avs/boards/max98373.c b/sound/soc/intel/avs/boards/max98373.c index 6f25e66344b7..970f82bf4ce8 100644 --- a/sound/soc/intel/avs/boards/max98373.c +++ b/sound/soc/intel/avs/boards/max98373.c @@ -111,7 +111,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL); if (!dl->name || !dl->cpus || !dl->codecs) return -ENOMEM; diff --git a/sound/soc/intel/avs/boards/max98927.c b/sound/soc/intel/avs/boards/max98927.c index ad18c4e9a670..e4ce553bf1d6 100644 --- a/sound/soc/intel/avs/boards/max98927.c +++ b/sound/soc/intel/avs/boards/max98927.c @@ -108,7 +108,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL); if (!dl->name || !dl->cpus || !dl->codecs) return -ENOMEM; @@ -127,7 +127,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->be_hw_params_fixup = avs_max98927_be_fixup; dl->nonatomic = 1; dl->no_pcm = 1; diff --git a/sound/soc/intel/avs/boards/nau8825.c b/sound/soc/intel/avs/boards/nau8825.c index bf902540744c..e203ceb83b87 100644 --- a/sound/soc/intel/avs/boards/nau8825.c +++ b/sound/soc/intel/avs/boards/nau8825.c @@ -88,7 +88,8 @@ static int avs_nau8825_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -203,7 +204,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_nau8825_codec_init; dl->exit = avs_nau8825_codec_exit; dl->be_hw_params_fixup = avs_nau8825_be_fixup; diff --git a/sound/soc/intel/avs/boards/pcm3168a.c b/sound/soc/intel/avs/boards/pcm3168a.c new file mode 100644 index 000000000000..5d0e7a5bdc74 --- /dev/null +++ b/sound/soc/intel/avs/boards/pcm3168a.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0-only +// +// Copyright(c) 2024-2025 Intel Corporation +// +// Author: Cezary Rojewski <cezary.rojewski@intel.com> +// + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> + +static const struct snd_soc_dapm_widget card_widgets[] = { + SND_SOC_DAPM_HP("CPB Stereo HP 1", NULL), + SND_SOC_DAPM_HP("CPB Stereo HP 2", NULL), + SND_SOC_DAPM_HP("CPB Stereo HP 3", NULL), + SND_SOC_DAPM_LINE("CPB Line Out", NULL), + SND_SOC_DAPM_MIC("CPB Stereo Mic 1", NULL), + SND_SOC_DAPM_MIC("CPB Stereo Mic 2", NULL), + SND_SOC_DAPM_LINE("CPB Line In", NULL), +}; + +static const struct snd_soc_dapm_route card_routes[] = { + { "CPB Stereo HP 1", NULL, "AOUT1L" }, + { "CPB Stereo HP 1", NULL, "AOUT1R" }, + { "CPB Stereo HP 2", NULL, "AOUT2L" }, + { "CPB Stereo HP 2", NULL, "AOUT2R" }, + { "CPB Stereo HP 3", NULL, "AOUT3L" }, + { "CPB Stereo HP 3", NULL, "AOUT3R" }, + { "CPB Line Out", NULL, "AOUT4L" }, + { "CPB Line Out", NULL, "AOUT4R" }, + + { "AIN1L", NULL, "CPB Stereo Mic 1" }, + { "AIN1R", NULL, "CPB Stereo Mic 1" }, + { "AIN2L", NULL, "CPB Stereo Mic 2" }, + { "AIN2R", NULL, "CPB Stereo Mic 2" }, + { "AIN3L", NULL, "CPB Line In" }, + { "AIN3R", NULL, "CPB Line In" }, +}; + +static int avs_pcm3168a_be_fixup(struct snd_soc_pcm_runtime *runtime, + struct snd_pcm_hw_params *params) +{ + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + + /* Set SSP to 24 bit. */ + snd_mask_none(fmt); + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S24_LE); + + return 0; +} + +SND_SOC_DAILINK_DEF(pcm3168a_dac, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-dac"))); +SND_SOC_DAILINK_DEF(pcm3168a_adc, + DAILINK_COMP_ARRAY(COMP_CODEC("i2c-PCM3168A:00", "pcm3168a-adc"))); +SND_SOC_DAILINK_DEF(cpu_ssp0, DAILINK_COMP_ARRAY(COMP_CPU("SSP0 Pin"))); +SND_SOC_DAILINK_DEF(cpu_ssp2, DAILINK_COMP_ARRAY(COMP_CPU("SSP2 Pin"))); + +static int avs_create_dai_links(struct device *dev, struct snd_soc_dai_link **links, int *num_links) +{ + struct snd_soc_dai_link_component *platform; + struct snd_soc_dai_link *dl; + const int num_dl = 2; + + dl = devm_kcalloc(dev, num_dl, sizeof(*dl), GFP_KERNEL); + platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL); + if (!dl || !platform) + return -ENOMEM; + + platform->name = dev_name(dev); + dl[0].num_cpus = 1; + dl[0].num_codecs = 1; + dl[0].platforms = platform; + dl[0].num_platforms = 1; + dl[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBP_CFP; + dl[0].be_hw_params_fixup = avs_pcm3168a_be_fixup; + dl[0].nonatomic = 1; + dl[0].no_pcm = 1; + memcpy(&dl[1], &dl[0], sizeof(*dl)); + + dl[0].name = "SSP0-Codec-dac"; + dl[0].cpus = cpu_ssp0; + dl[0].codecs = pcm3168a_dac; + dl[1].name = "SSP2-Codec-adc"; + dl[1].cpus = cpu_ssp2; + dl[1].codecs = pcm3168a_adc; + + *links = dl; + *num_links = num_dl; + return 0; +} + +static int avs_pcm3168a_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct snd_soc_card *card; + int ret; + + card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + ret = avs_create_dai_links(dev, &card->dai_link, &card->num_links); + if (ret) + return ret; + + card->name = "avs_pcm3168a"; + card->dev = dev; + card->owner = THIS_MODULE; + card->dapm_widgets = card_widgets; + card->num_dapm_widgets = ARRAY_SIZE(card_widgets); + card->dapm_routes = card_routes; + card->num_dapm_routes = ARRAY_SIZE(card_routes); + card->fully_routed = true; + + return devm_snd_soc_register_card(dev, card); +} + +static const struct platform_device_id avs_pcm3168a_driver_ids[] = { + { + .name = "avs_pcm3168a", + }, + {}, +}; +MODULE_DEVICE_TABLE(platform, avs_pcm3168a_driver_ids); + +static struct platform_driver avs_pcm3168a_driver = { + .probe = avs_pcm3168a_probe, + .driver = { + .name = "avs_pcm3168a", + .pm = &snd_soc_pm_ops, + }, + .id_table = avs_pcm3168a_driver_ids, +}; + +module_platform_driver(avs_pcm3168a_driver); + +MODULE_DESCRIPTION("Intel pcm3168a machine driver"); +MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/intel/avs/boards/rt274.c b/sound/soc/intel/avs/boards/rt274.c index 4b6c02a40204..29977aee2153 100644 --- a/sound/soc/intel/avs/boards/rt274.c +++ b/sound/soc/intel/avs/boards/rt274.c @@ -98,7 +98,8 @@ static int avs_rt274_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -178,7 +179,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt274_codec_init; dl->exit = avs_rt274_codec_exit; dl->be_hw_params_fixup = avs_rt274_be_fixup; diff --git a/sound/soc/intel/avs/boards/rt286.c b/sound/soc/intel/avs/boards/rt286.c index e40563ca99fd..6a27c6a9f394 100644 --- a/sound/soc/intel/avs/boards/rt286.c +++ b/sound/soc/intel/avs/boards/rt286.c @@ -59,7 +59,8 @@ static int avs_rt286_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -146,7 +147,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt286_codec_init; dl->exit = avs_rt286_codec_exit; dl->be_hw_params_fixup = avs_rt286_be_fixup; diff --git a/sound/soc/intel/avs/boards/rt298.c b/sound/soc/intel/avs/boards/rt298.c index 94fce07c83f9..a7a463d6f852 100644 --- a/sound/soc/intel/avs/boards/rt298.c +++ b/sound/soc/intel/avs/boards/rt298.c @@ -70,7 +70,8 @@ static int avs_rt298_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; @@ -164,9 +165,9 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->num_platforms = 1; dl->id = 0; if (dmi_first_match(kblr_dmi_table)) - dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; else - dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt298_codec_init; dl->exit = avs_rt298_codec_exit; dl->be_hw_params_fixup = avs_rt298_be_fixup; diff --git a/sound/soc/intel/avs/boards/rt5514.c b/sound/soc/intel/avs/boards/rt5514.c index 30588d9e9ba3..d1c3e29a28ff 100644 --- a/sound/soc/intel/avs/boards/rt5514.c +++ b/sound/soc/intel/avs/boards/rt5514.c @@ -116,7 +116,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_rt5514_codec_init; dl->be_hw_params_fixup = avs_rt5514_be_fixup; dl->nonatomic = 1; diff --git a/sound/soc/intel/avs/boards/rt5663.c b/sound/soc/intel/avs/boards/rt5663.c index b456b9d14665..e3310b3268ba 100644 --- a/sound/soc/intel/avs/boards/rt5663.c +++ b/sound/soc/intel/avs/boards/rt5663.c @@ -65,7 +65,8 @@ static int avs_rt5663_codec_init(struct snd_soc_pcm_runtime *runtime) jack = &priv->jack; num_pins = ARRAY_SIZE(card_headset_pins); - pins = devm_kmemdup(card->dev, card_headset_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_headset_pins, num_pins, + sizeof(card_headset_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; diff --git a/sound/soc/intel/avs/boards/rt5682.c b/sound/soc/intel/avs/boards/rt5682.c index 335960cfd7ba..339df0b944c1 100644 --- a/sound/soc/intel/avs/boards/rt5682.c +++ b/sound/soc/intel/avs/boards/rt5682.c @@ -102,7 +102,8 @@ static int avs_rt5682_codec_init(struct snd_soc_pcm_runtime *runtime) jack = snd_soc_card_get_drvdata(card); num_pins = ARRAY_SIZE(card_jack_pins); - pins = devm_kmemdup(card->dev, card_jack_pins, sizeof(*pins) * num_pins, GFP_KERNEL); + pins = devm_kmemdup_array(card->dev, card_jack_pins, num_pins, + sizeof(card_jack_pins[0]), GFP_KERNEL); if (!pins) return -ENOMEM; diff --git a/sound/soc/intel/avs/boards/ssm4567.c b/sound/soc/intel/avs/boards/ssm4567.c index cfef00462f66..7667790d5273 100644 --- a/sound/soc/intel/avs/boards/ssm4567.c +++ b/sound/soc/intel/avs/boards/ssm4567.c @@ -97,7 +97,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->name = devm_kasprintf(dev, GFP_KERNEL, AVS_STRING_FMT("SSP", "-Codec", ssp_port, tdm_slot)); dl->cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL); - dl->codecs = devm_kzalloc(dev, sizeof(*dl->codecs) * 2, GFP_KERNEL); + dl->codecs = devm_kcalloc(dev, 2, sizeof(*dl->codecs), GFP_KERNEL); if (!dl->name || !dl->cpus || !dl->codecs) return -ENOMEM; @@ -116,7 +116,7 @@ static int avs_create_dai_link(struct device *dev, const char *platform_name, in dl->platforms = platform; dl->num_platforms = 1; dl->id = 0; - dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBS_CFS; + dl->dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | SND_SOC_DAIFMT_CBC_CFC; dl->init = avs_ssm4567_codec_init; dl->be_hw_params_fixup = avs_ssm4567_be_fixup; dl->nonatomic = 1; diff --git a/sound/soc/intel/avs/control.c b/sound/soc/intel/avs/control.c index dc7dc45e0a0a..2e01dc75a15a 100644 --- a/sound/soc/intel/avs/control.c +++ b/sound/soc/intel/avs/control.c @@ -6,6 +6,7 @@ // Cezary Rojewski <cezary.rojewski@intel.com> // +#include <linux/cleanup.h> #include <sound/soc.h> #include "avs.h" #include "control.h" @@ -31,8 +32,11 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i list_for_each_entry(path, &adev->path_list, node) { list_for_each_entry(ppl, &path->ppl_list, node) { list_for_each_entry(mod, &ppl->mod_list, node) { - if (guid_equal(&mod->template->cfg_ext->type, &AVS_PEAKVOL_MOD_UUID) - && mod->template->ctl_id == id) { + guid_t *type = &mod->template->cfg_ext->type; + + if ((guid_equal(type, &AVS_PEAKVOL_MOD_UUID) || + guid_equal(type, &AVS_GAIN_MOD_UUID)) && + mod->template->ctl_id == id) { spin_unlock(&adev->path_list_lock); return mod; } @@ -44,70 +48,168 @@ static struct avs_path_module *avs_get_volume_module(struct avs_dev *adev, u32 i return NULL; } -int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { - struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; - struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); - struct avs_volume_cfg *dspvols = NULL; + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct avs_control_data *ctl_data = mc->dobj.private; struct avs_path_module *active_module; + struct avs_volume_cfg *dspvols; + struct avs_dev *adev; size_t num_dspvols; - int ret = 0; + int ret, i; + + adev = avs_get_kcontrol_adev(kctl); - /* prevent access to modules while path is being constructed */ - mutex_lock(&adev->path_mutex); + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); active_module = avs_get_volume_module(adev, ctl_data->id); if (active_module) { ret = avs_ipc_peakvol_get_volume(adev, active_module->module_id, active_module->instance_id, &dspvols, &num_dspvols); - if (!ret) - ucontrol->value.integer.value[0] = dspvols[0].target_volume; + if (ret) + return AVS_IPC_RET(ret); - ret = AVS_IPC_RET(ret); + /* Do not copy more than the control can store. */ + num_dspvols = min_t(u32, num_dspvols, SND_SOC_TPLG_MAX_CHAN); + for (i = 0; i < num_dspvols; i++) + ctl_data->values[i] = dspvols[i].target_volume; kfree(dspvols); - } else { - ucontrol->value.integer.value[0] = ctl_data->volume; } - mutex_unlock(&adev->path_mutex); - return ret; + memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values)); + return 0; } -int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) { - struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - struct avs_control_data *ctl_data = (struct avs_control_data *)mc->dobj.private; - struct avs_dev *adev = avs_get_kcontrol_adev(kcontrol); - long *volume = &ctl_data->volume; struct avs_path_module *active_module; - struct avs_volume_cfg dspvol = {0}; - long ctlvol = ucontrol->value.integer.value[0]; - int ret = 0, changed = 0; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + struct avs_dev *adev; + long *input; + int ret, i; + + mc = (struct soc_mixer_control *)kctl->private_value; + ctl_data = mc->dobj.private; + adev = avs_get_kcontrol_adev(kctl); + input = uctl->value.integer.value; + i = 0; + + /* mc->num_channels can be 0. */ + do { + if (input[i] < mc->min || input[i] > mc->max) + return -EINVAL; + } while (++i < mc->num_channels); + + if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values))) + return 0; + + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); - if (ctlvol < 0 || ctlvol > mc->max) - return -EINVAL; + active_module = avs_get_volume_module(adev, ctl_data->id); + if (active_module) { + ret = avs_peakvol_set_volume(adev, active_module, mc, input); + if (ret) + return ret; + } - /* prevent access to modules while path is being constructed */ - mutex_lock(&adev->path_mutex); + memcpy(ctl_data->values, input, sizeof(ctl_data->values)); + return 1; +} - if (*volume != ctlvol) { - *volume = ctlvol; - changed = 1; - } +int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = max_t(u32, 1, mc->num_channels); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mc->max; + return 0; +} + +int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct avs_control_data *ctl_data = mc->dobj.private; + struct avs_path_module *active_module; + struct avs_mute_cfg *dspmutes; + struct avs_dev *adev; + size_t num_dspmutes; + int ret, i; + + adev = avs_get_kcontrol_adev(kctl); + + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); active_module = avs_get_volume_module(adev, ctl_data->id); if (active_module) { - dspvol.channel_id = AVS_ALL_CHANNELS_MASK; - dspvol.target_volume = *volume; + ret = avs_ipc_peakvol_get_mute(adev, active_module->module_id, + active_module->instance_id, &dspmutes, + &num_dspmutes); + if (ret) + return AVS_IPC_RET(ret); + + /* Do not copy more than the control can store. */ + num_dspmutes = min_t(u32, num_dspmutes, SND_SOC_TPLG_MAX_CHAN); + for (i = 0; i < num_dspmutes; i++) + ctl_data->values[i] = !dspmutes[i].mute; + kfree(dspmutes); + } - ret = avs_ipc_peakvol_set_volume(adev, active_module->module_id, - active_module->instance_id, &dspvol); - ret = AVS_IPC_RET(ret); + memcpy(uctl->value.integer.value, ctl_data->values, sizeof(ctl_data->values)); + return 0; +} + +int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl) +{ + struct avs_path_module *active_module; + struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; + struct avs_dev *adev; + long *input; + int ret, i; + + mc = (struct soc_mixer_control *)kctl->private_value; + ctl_data = mc->dobj.private; + adev = avs_get_kcontrol_adev(kctl); + input = uctl->value.integer.value; + i = 0; + + /* mc->num_channels can be 0. */ + do { + if (input[i] < mc->min || input[i] > mc->max) + return -EINVAL; + } while (++i < mc->num_channels); + + if (!memcmp(ctl_data->values, input, sizeof(ctl_data->values))) + return 0; + + /* Prevent access to modules while path is being constructed. */ + guard(mutex)(&adev->path_mutex); + + active_module = avs_get_volume_module(adev, ctl_data->id); + if (active_module) { + ret = avs_peakvol_set_mute(adev, active_module, mc, input); + if (ret) + return ret; } - mutex_unlock(&adev->path_mutex); + memcpy(ctl_data->values, input, sizeof(ctl_data->values)); + return 1; +} + +int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; - return ret ? ret : changed; + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = max_t(u32, 1, mc->num_channels); + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mc->max; + return 0; } diff --git a/sound/soc/intel/avs/control.h b/sound/soc/intel/avs/control.h index d9fac3569e8d..08b2919e4629 100644 --- a/sound/soc/intel/avs/control.h +++ b/sound/soc/intel/avs/control.h @@ -10,14 +10,18 @@ #define __SOUND_SOC_INTEL_AVS_CTRL_H #include <sound/control.h> +#include <uapi/sound/asoc.h> struct avs_control_data { u32 id; - - long volume; + long values[SND_SOC_TPLG_MAX_CHAN]; }; -int avs_control_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); -int avs_control_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int avs_control_volume_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_volume_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_volume_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo); +int avs_control_mute_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_mute_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *uctl); +int avs_control_mute_info(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *uinfo); #endif diff --git a/sound/soc/intel/avs/core.c b/sound/soc/intel/avs/core.c index 0e750e9e01d9..8fbf33e30dfc 100644 --- a/sound/soc/intel/avs/core.c +++ b/sound/soc/intel/avs/core.c @@ -612,7 +612,7 @@ static int avs_suspend_standby(struct avs_dev *adev) return 0; } -static int __maybe_unused avs_suspend_common(struct avs_dev *adev, bool low_power) +static int avs_suspend_common(struct avs_dev *adev, bool low_power) { struct hdac_bus *bus = &adev->base.core; int ret; @@ -673,7 +673,7 @@ static int avs_resume_standby(struct avs_dev *adev) return 0; } -static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power, bool purge) +static int avs_resume_common(struct avs_dev *adev, bool low_power, bool purge) { struct hdac_bus *bus = &adev->base.core; int ret; @@ -696,41 +696,41 @@ static int __maybe_unused avs_resume_common(struct avs_dev *adev, bool low_power return 0; } -static int __maybe_unused avs_suspend(struct device *dev) +static int avs_suspend(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), true); } -static int __maybe_unused avs_resume(struct device *dev) +static int avs_resume(struct device *dev) { return avs_resume_common(to_avs_dev(dev), true, true); } -static int __maybe_unused avs_runtime_suspend(struct device *dev) +static int avs_runtime_suspend(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), true); } -static int __maybe_unused avs_runtime_resume(struct device *dev) +static int avs_runtime_resume(struct device *dev) { return avs_resume_common(to_avs_dev(dev), true, false); } -static int __maybe_unused avs_freeze(struct device *dev) +static int avs_freeze(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), false); } -static int __maybe_unused avs_thaw(struct device *dev) +static int avs_thaw(struct device *dev) { return avs_resume_common(to_avs_dev(dev), false, true); } -static int __maybe_unused avs_poweroff(struct device *dev) +static int avs_poweroff(struct device *dev) { return avs_suspend_common(to_avs_dev(dev), false); } -static int __maybe_unused avs_restore(struct device *dev) +static int avs_restore(struct device *dev) { return avs_resume_common(to_avs_dev(dev), false, true); } @@ -742,7 +742,7 @@ static const struct dev_pm_ops avs_dev_pm = { .thaw = avs_thaw, .poweroff = avs_poweroff, .restore = avs_restore, - SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) + RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL) }; static const struct avs_sram_spec skl_sram_spec = { @@ -893,7 +893,7 @@ static struct pci_driver avs_pci_driver = { .shutdown = avs_pci_shutdown, .dev_groups = avs_attr_groups, .driver = { - .pm = &avs_dev_pm, + .pm = pm_ptr(&avs_dev_pm), }, }; module_pci_driver(avs_pci_driver); diff --git a/sound/soc/intel/avs/dsp.c b/sound/soc/intel/avs/dsp.c index 7b47e52c2b39..b9de691e9b9b 100644 --- a/sound/soc/intel/avs/dsp.c +++ b/sound/soc/intel/avs/dsp.c @@ -6,6 +6,7 @@ // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // +#include <linux/string_choices.h> #include <sound/hdaudio_ext.h> #include "avs.h" #include "registers.h" @@ -39,7 +40,7 @@ int avs_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) AVS_ADSPCS_TIMEOUT_US); if (ret) dev_err(adev->dev, "core_mask %d power %s failed: %d\n", - core_mask, power ? "on" : "off", ret); + core_mask, str_on_off(power), ret); return ret; } diff --git a/sound/soc/intel/avs/loader.c b/sound/soc/intel/avs/loader.c index 9ff7818395cd..0b29941feb0e 100644 --- a/sound/soc/intel/avs/loader.c +++ b/sound/soc/intel/avs/loader.c @@ -603,7 +603,7 @@ release_fw: return ret; } -int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) +static int avs_load_firmware(struct avs_dev *adev, bool purge) { struct avs_soc_component *acomp; int ret, i; @@ -657,28 +657,33 @@ reenable_gating: return 0; } -int avs_dsp_first_boot_firmware(struct avs_dev *adev) +static int avs_config_basefw(struct avs_dev *adev) { - int ret, i; + int ret; - if (avs_platattr_test(adev, CLDMA)) { - ret = hda_cldma_init(&code_loader, &adev->base.core, - adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE); - if (ret < 0) { - dev_err(adev->dev, "cldma init failed: %d\n", ret); + if (adev->spec->dsp_ops->config_basefw) { + ret = avs_dsp_op(adev, config_basefw); + if (ret) return ret; - } } - ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); - if (ret < 0) - return ret; + return 0; +} - ret = avs_dsp_boot_firmware(adev, true); - if (ret < 0) { - dev_err(adev->dev, "firmware boot failed: %d\n", ret); +int avs_dsp_boot_firmware(struct avs_dev *adev, bool purge) +{ + int ret; + + ret = avs_load_firmware(adev, purge); + if (ret) return ret; - } + + return avs_config_basefw(adev); +} + +static int avs_dsp_alloc_resources(struct avs_dev *adev) +{ + int ret, i; ret = avs_ipc_get_hw_config(adev, &adev->hw_cfg); if (ret) @@ -705,6 +710,31 @@ int avs_dsp_first_boot_firmware(struct avs_dev *adev) strscpy(adev->lib_names[0], "BASEFW", AVS_LIB_NAME_SIZE); ida_init(&adev->ppl_ida); - return 0; } + +int avs_dsp_first_boot_firmware(struct avs_dev *adev) +{ + int ret; + + if (avs_platattr_test(adev, CLDMA)) { + ret = hda_cldma_init(&code_loader, &adev->base.core, + adev->dsp_ba, AVS_CL_DEFAULT_BUFFER_SIZE); + if (ret < 0) { + dev_err(adev->dev, "cldma init failed: %d\n", ret); + return ret; + } + } + + ret = avs_dsp_core_disable(adev, AVS_MAIN_CORE_MASK); + if (ret < 0) + return ret; + + ret = avs_dsp_boot_firmware(adev, true); + if (ret < 0) { + dev_err(adev->dev, "firmware boot failed: %d\n", ret); + return ret; + } + + return avs_dsp_alloc_resources(adev); +} diff --git a/sound/soc/intel/avs/messages.c b/sound/soc/intel/avs/messages.c index 30b666f8909b..a5ba27983091 100644 --- a/sound/soc/intel/avs/messages.c +++ b/sound/soc/intel/avs/messages.c @@ -510,6 +510,44 @@ err: return ret; } +int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...) +{ + struct avs_tlv *tlv; + void *payload; + size_t offset; + va_list args; + int ret, i; + + payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + va_start(args, num_tlvs); + for (offset = i = 0; i < num_tlvs && offset < AVS_MAILBOX_SIZE - sizeof(*tlv); i++) { + tlv = (struct avs_tlv *)(payload + offset); + tlv->type = va_arg(args, u32); + tlv->length = va_arg(args, u32); + + offset += sizeof(*tlv) + tlv->length; + if (offset > AVS_MAILBOX_SIZE) + break; + + memcpy(tlv->value, va_arg(args, u8*), tlv->length); + } + + if (i == num_tlvs) + ret = avs_ipc_set_large_config(adev, AVS_BASEFW_MOD_ID, AVS_BASEFW_INST_ID, + AVS_BASEFW_FIRMWARE_CONFIG, payload, offset); + else + ret = -ERANGE; + + va_end(args); + kfree(payload); + if (ret) + dev_err(adev->dev, "set fw cfg failed: %d\n", ret); + return ret; +} + int avs_ipc_get_hw_config(struct avs_dev *adev, struct avs_hw_cfg *cfg) { struct avs_tlv *tlv; @@ -639,13 +677,6 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, (u8 *)&cpr_fmt, sizeof(cpr_fmt)); } -int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, - struct avs_volume_cfg *vol) -{ - return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, (u8 *)vol, - sizeof(*vol)); -} - int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, struct avs_volume_cfg **vols, size_t *num_vols) { @@ -668,6 +699,110 @@ int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_ return 0; } +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol) +{ + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_VOLUME, + (u8 *)vol, sizeof(*vol)); +} + +int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vols, size_t num_vols) +{ + struct avs_tlv *tlv; + size_t offset; + size_t size; + u8 *payload; + int ret, i; + + size = num_vols * sizeof(*vols); + size += num_vols * sizeof(*tlv); + if (size > AVS_MAILBOX_SIZE) + return -EINVAL; + + payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + for (offset = i = 0; i < num_vols; i++) { + tlv = (struct avs_tlv *)(payload + offset); + + tlv->type = AVS_PEAKVOL_VOLUME; + tlv->length = sizeof(*vols); + memcpy(tlv->value, &vols[i], tlv->length); + + offset += sizeof(*tlv) + tlv->length; + } + + ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload, + size); + kfree(payload); + return ret; +} + +int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg **mutes, size_t *num_mutes) +{ + size_t payload_size; + u8 *payload; + int ret; + + ret = avs_ipc_get_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE, NULL, 0, + &payload, &payload_size); + if (ret) + return ret; + + /* Non-zero payload expected for PEAKVOL_MUTE. */ + if (!payload_size) + return -EREMOTEIO; + + *mutes = (struct avs_mute_cfg *)payload; + *num_mutes = payload_size / sizeof(**mutes); + + return 0; +} + +int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mute) +{ + return avs_ipc_set_large_config(adev, module_id, instance_id, AVS_PEAKVOL_MUTE, + (u8 *)mute, sizeof(*mute)); +} + +int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mutes, size_t num_mutes) +{ + struct avs_tlv *tlv; + size_t offset; + size_t size; + u8 *payload; + int ret, i; + + size = num_mutes * sizeof(*mutes); + size += num_mutes * sizeof(*tlv); + if (size > AVS_MAILBOX_SIZE) + return -EINVAL; + + payload = kzalloc(AVS_MAILBOX_SIZE, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + for (offset = i = 0; i < num_mutes; i++) { + tlv = (struct avs_tlv *)(payload + offset); + + tlv->type = AVS_PEAKVOL_MUTE; + tlv->length = sizeof(*mutes); + memcpy(tlv->value, &mutes[i], tlv->length); + + offset += sizeof(*tlv) + tlv->length; + } + + ret = avs_ipc_set_large_config(adev, module_id, instance_id, AVS_VENDOR_CONFIG, payload, + size); + kfree(payload); + return ret; +} + #ifdef CONFIG_DEBUG_FS int avs_ipc_set_enable_logs(struct avs_dev *adev, u8 *log_info, size_t size) { diff --git a/sound/soc/intel/avs/messages.h b/sound/soc/intel/avs/messages.h index 0378633c7f96..2f243802ccc2 100644 --- a/sound/soc/intel/avs/messages.h +++ b/sound/soc/intel/avs/messages.h @@ -451,6 +451,8 @@ enum avs_fw_cfg_params { AVS_FW_CFG_RESERVED, AVS_FW_CFG_POWER_GATING_POLICY, AVS_FW_CFG_ASSERT_MODE, + AVS_FW_CFG_RESERVED2, + AVS_FW_CFG_BUS_HARDWARE_ID, }; struct avs_fw_cfg { @@ -475,7 +477,14 @@ struct avs_fw_cfg { u32 power_gating_policy; }; +struct avs_bus_hwid { + u32 device; + u32 subsystem; + u8 revision; +}; + int avs_ipc_get_fw_config(struct avs_dev *adev, struct avs_fw_cfg *cfg); +int avs_ipc_set_fw_config(struct avs_dev *adev, size_t num_tlvs, ...); enum avs_hw_cfg_params { AVS_HW_CFG_AVS_VER, @@ -643,6 +652,9 @@ int avs_ipc_set_system_time(struct avs_dev *adev); #define AVS_INTELWOV_MOD_UUID \ GUID_INIT(0xEC774FA9, 0x28D3, 0x424A, 0x90, 0xE4, 0x69, 0xF9, 0x84, 0xF1, 0xEE, 0xB7) +#define AVS_WOVHOSTM_MOD_UUID \ + GUID_INIT(0xF9ED62B7, 0x092E, 0x4A90, 0x8F, 0x4D, 0x82, 0xDA, 0xA8, 0xB3, 0x8F, 0x3B) + /* channel map */ enum avs_channel_index { AVS_CHANNEL_LEFT = 0, @@ -802,6 +814,15 @@ struct avs_volume_cfg { } __packed; static_assert(sizeof(struct avs_volume_cfg) == 24); +struct avs_mute_cfg { + u32 channel_id; + u32 mute; + u32 curve_type; + u32 reserved; /* alignment */ + u64 curve_duration; +} __packed; +static_assert(sizeof(struct avs_mute_cfg) == 24); + struct avs_peakvol_cfg { struct avs_modcfg_base base; struct avs_volume_cfg vols[]; @@ -872,8 +893,20 @@ struct avs_wov_cfg { } __packed; static_assert(sizeof(struct avs_wov_cfg) == 44); +struct avs_whm_cfg { + struct avs_modcfg_base base; + /* Audio format for output pin 0 */ + struct avs_audio_format ref_fmt; + struct avs_audio_format out_fmt; + u32 wake_tick_period; + struct avs_copier_gtw_cfg gtw_cfg; +} __packed; +static_assert(sizeof(struct avs_whm_cfg) == 108); + /* Module runtime parameters */ +#define AVS_VENDOR_CONFIG 0xFF + enum avs_copier_runtime_param { AVS_COPIER_SET_SINK_FORMAT = 2, }; @@ -892,6 +925,7 @@ int avs_ipc_copier_set_sink_format(struct avs_dev *adev, u16 module_id, enum avs_peakvol_runtime_param { AVS_PEAKVOL_VOLUME = 0, + AVS_PEAKVOL_MUTE = 3, }; enum avs_audio_curve_type { @@ -899,10 +933,18 @@ enum avs_audio_curve_type { AVS_AUDIO_CURVE_WINDOWS_FADE = 1, }; -int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, - struct avs_volume_cfg *vol); int avs_ipc_peakvol_get_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, struct avs_volume_cfg **vols, size_t *num_vols); +int avs_ipc_peakvol_set_volume(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vol); +int avs_ipc_peakvol_set_volumes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_volume_cfg *vols, size_t num_vols); +int avs_ipc_peakvol_get_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg **mutes, size_t *num_mutes); +int avs_ipc_peakvol_set_mute(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mute); +int avs_ipc_peakvol_set_mutes(struct avs_dev *adev, u16 module_id, u8 instance_id, + struct avs_mute_cfg *mutes, size_t num_mutes); #define AVS_PROBE_INST_ID 0 diff --git a/sound/soc/intel/avs/path.c b/sound/soc/intel/avs/path.c index f31d5e2caa7b..ef0c1d125d66 100644 --- a/sound/soc/intel/avs/path.c +++ b/sound/soc/intel/avs/path.c @@ -115,154 +115,193 @@ avs_path_find_variant(struct avs_dev *adev, return NULL; } -__maybe_unused -static bool avs_dma_type_is_host(u32 dma_type) +static void avs_init_node_id(union avs_connector_node_id *node_id, + struct avs_tplg_modcfg_ext *te, u32 dma_id) { - return dma_type == AVS_DMA_HDA_HOST_OUTPUT || - dma_type == AVS_DMA_HDA_HOST_INPUT; -} + node_id->val = 0; + node_id->dma_type = te->copier.dma_type; -__maybe_unused -static bool avs_dma_type_is_link(u32 dma_type) -{ - return !avs_dma_type_is_host(dma_type); -} + switch (node_id->dma_type) { + case AVS_DMA_DMIC_LINK_INPUT: + case AVS_DMA_I2S_LINK_OUTPUT: + case AVS_DMA_I2S_LINK_INPUT: + /* Gateway's virtual index is statically assigned in the topology. */ + node_id->vindex = te->copier.vindex.val; + break; -__maybe_unused -static bool avs_dma_type_is_output(u32 dma_type) -{ - return dma_type == AVS_DMA_HDA_HOST_OUTPUT || - dma_type == AVS_DMA_HDA_LINK_OUTPUT || - dma_type == AVS_DMA_I2S_LINK_OUTPUT; -} + case AVS_DMA_HDA_HOST_OUTPUT: + case AVS_DMA_HDA_HOST_INPUT: + /* Gateway's virtual index is dynamically assigned with DMA ID */ + node_id->vindex = dma_id; + break; -__maybe_unused -static bool avs_dma_type_is_input(u32 dma_type) -{ - return !avs_dma_type_is_output(dma_type); + case AVS_DMA_HDA_LINK_OUTPUT: + case AVS_DMA_HDA_LINK_INPUT: + node_id->vindex = te->copier.vindex.val | dma_id; + break; + + default: + *node_id = INVALID_NODE_ID; + break; + } } -static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) -{ - struct avs_tplg_module *t = mod->template; - struct avs_copier_cfg *cfg; - struct acpi_nhlt_format_config *ep_blob; - struct acpi_nhlt_endpoint *ep; - union avs_connector_node_id node_id = {0}; - size_t cfg_size, data_size; - void *data = NULL; - u32 dma_type; - int ret; +/* Every BLOB contains at least gateway attributes. */ +static struct acpi_nhlt_config *default_blob = (struct acpi_nhlt_config *)&(u32[2]) {4}; - data_size = sizeof(cfg->gtw_cfg.config); - dma_type = t->cfg_ext->copier.dma_type; - node_id.dma_type = dma_type; +static struct acpi_nhlt_config * +avs_nhlt_config_or_default(struct avs_dev *adev, struct avs_tplg_module *t) +{ + struct acpi_nhlt_format_config *fmtcfg; + struct avs_tplg_modcfg_ext *te; + struct avs_audio_format *fmt; + int link_type, dev_type; + int bus_id, dir; - switch (dma_type) { - struct avs_audio_format *fmt; - int direction; + te = t->cfg_ext; + switch (te->copier.dma_type) { case AVS_DMA_I2S_LINK_OUTPUT: - case AVS_DMA_I2S_LINK_INPUT: - if (avs_dma_type_is_input(dma_type)) - direction = SNDRV_PCM_STREAM_CAPTURE; - else - direction = SNDRV_PCM_STREAM_PLAYBACK; - - if (t->cfg_ext->copier.blob_fmt) - fmt = t->cfg_ext->copier.blob_fmt; - else if (direction == SNDRV_PCM_STREAM_CAPTURE) - fmt = t->in_fmt; - else - fmt = t->cfg_ext->copier.out_fmt; - - ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_SSP, - ACPI_NHLT_DEVICETYPE_CODEC, direction, - t->cfg_ext->copier.vindex.i2s.instance); - ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq, - fmt->valid_bit_depth, fmt->bit_depth); - if (!ep_blob) { - dev_err(adev->dev, "no I2S ep_blob found\n"); - return -ENOENT; - } - - data = ep_blob->config.capabilities; - data_size = ep_blob->config.capabilities_size; - /* I2S gateway's vindex is statically assigned in topology */ - node_id.vindex = t->cfg_ext->copier.vindex.val; + link_type = ACPI_NHLT_LINKTYPE_SSP; + dev_type = ACPI_NHLT_DEVICETYPE_CODEC; + bus_id = te->copier.vindex.i2s.instance; + dir = SNDRV_PCM_STREAM_PLAYBACK; + fmt = te->copier.out_fmt; + break; + case AVS_DMA_I2S_LINK_INPUT: + link_type = ACPI_NHLT_LINKTYPE_SSP; + dev_type = ACPI_NHLT_DEVICETYPE_CODEC; + bus_id = te->copier.vindex.i2s.instance; + dir = SNDRV_PCM_STREAM_CAPTURE; + fmt = t->in_fmt; break; case AVS_DMA_DMIC_LINK_INPUT: - direction = SNDRV_PCM_STREAM_CAPTURE; - - if (t->cfg_ext->copier.blob_fmt) - fmt = t->cfg_ext->copier.blob_fmt; - else - fmt = t->in_fmt; - - ep = acpi_nhlt_find_endpoint(ACPI_NHLT_LINKTYPE_PDM, -1, direction, 0); - ep_blob = acpi_nhlt_endpoint_find_fmtcfg(ep, fmt->num_channels, fmt->sampling_freq, - fmt->valid_bit_depth, fmt->bit_depth); - if (!ep_blob) { - dev_err(adev->dev, "no DMIC ep_blob found\n"); - return -ENOENT; - } - - data = ep_blob->config.capabilities; - data_size = ep_blob->config.capabilities_size; - /* DMIC gateway's vindex is statically assigned in topology */ - node_id.vindex = t->cfg_ext->copier.vindex.val; - + link_type = ACPI_NHLT_LINKTYPE_PDM; + dev_type = -1; /* ignored */ + bus_id = 0; + dir = SNDRV_PCM_STREAM_CAPTURE; + fmt = t->in_fmt; break; - case AVS_DMA_HDA_HOST_OUTPUT: - case AVS_DMA_HDA_HOST_INPUT: - /* HOST gateway's vindex is dynamically assigned with DMA id */ - node_id.vindex = mod->owner->owner->dma_id; - break; + default: + return default_blob; + } - case AVS_DMA_HDA_LINK_OUTPUT: - case AVS_DMA_HDA_LINK_INPUT: - node_id.vindex = t->cfg_ext->copier.vindex.val | - mod->owner->owner->dma_id; - break; + /* Override format selection if necessary. */ + if (te->copier.blob_fmt) + fmt = te->copier.blob_fmt; - case INVALID_OBJECT_ID: - default: - node_id = INVALID_NODE_ID; - break; + fmtcfg = acpi_nhlt_find_fmtcfg(link_type, dev_type, dir, bus_id, + fmt->num_channels, fmt->sampling_freq, fmt->valid_bit_depth, + fmt->bit_depth); + if (!fmtcfg) { + dev_warn(adev->dev, "Endpoint format configuration not found.\n"); + return ERR_PTR(-ENOENT); } - cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config) + data_size; - if (cfg_size > AVS_MAILBOX_SIZE) - return -EINVAL; + if (fmtcfg->config.capabilities_size < default_blob->capabilities_size) + return ERR_PTR(-ETOOSMALL); + /* The firmware expects the payload to be DWORD-aligned. */ + if (fmtcfg->config.capabilities_size % sizeof(u32)) + return ERR_PTR(-EINVAL); + return &fmtcfg->config; +} + +static int avs_fill_gtw_config(struct avs_dev *adev, struct avs_copier_gtw_cfg *gtw, + struct avs_tplg_module *t, size_t *cfg_size) +{ + struct acpi_nhlt_config *blob; + size_t gtw_size; + + blob = avs_nhlt_config_or_default(adev, t); + if (IS_ERR(blob)) + return PTR_ERR(blob); + + gtw_size = blob->capabilities_size; + if (*cfg_size + gtw_size > AVS_MAILBOX_SIZE) + return -E2BIG; + + gtw->config_length = gtw_size / sizeof(u32); + memcpy(gtw->config.blob, blob->capabilities, blob->capabilities_size); + *cfg_size += gtw_size; + + return 0; +} + +static int avs_copier_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_tplg_modcfg_ext *te; + struct avs_copier_cfg *cfg; + size_t cfg_size; + u32 dma_id; + int ret; + + te = t->cfg_ext; cfg = adev->modcfg_buf; - memset(cfg, 0, cfg_size); + dma_id = mod->owner->owner->dma_id; + cfg_size = offsetof(struct avs_copier_cfg, gtw_cfg.config); + + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size); + if (ret) + return ret; + cfg->base.cpc = t->cfg_base->cpc; cfg->base.ibs = t->cfg_base->ibs; cfg->base.obs = t->cfg_base->obs; cfg->base.is_pages = t->cfg_base->is_pages; cfg->base.audio_fmt = *t->in_fmt; - cfg->out_fmt = *t->cfg_ext->copier.out_fmt; - cfg->feature_mask = t->cfg_ext->copier.feature_mask; - cfg->gtw_cfg.node_id = node_id; - cfg->gtw_cfg.dma_buffer_size = t->cfg_ext->copier.dma_buffer_size; - /* config_length in DWORDs */ - cfg->gtw_cfg.config_length = DIV_ROUND_UP(data_size, 4); - if (data) - memcpy(&cfg->gtw_cfg.config.blob, data, data_size); + cfg->out_fmt = *te->copier.out_fmt; + cfg->feature_mask = te->copier.feature_mask; + avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id); + cfg->gtw_cfg.dma_buffer_size = te->copier.dma_buffer_size; + mod->gtw_attrs = cfg->gtw_cfg.config.attrs; + + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, + t->domain, cfg, cfg_size, &mod->instance_id); + return ret; +} + +static int avs_whm_create(struct avs_dev *adev, struct avs_path_module *mod) +{ + struct avs_tplg_module *t = mod->template; + struct avs_tplg_modcfg_ext *te; + struct avs_whm_cfg *cfg; + size_t cfg_size; + u32 dma_id; + int ret; + te = t->cfg_ext; + cfg = adev->modcfg_buf; + dma_id = mod->owner->owner->dma_id; + cfg_size = offsetof(struct avs_whm_cfg, gtw_cfg.config); + + ret = avs_fill_gtw_config(adev, &cfg->gtw_cfg, t, &cfg_size); + if (ret) + return ret; + + cfg->base.cpc = t->cfg_base->cpc; + cfg->base.ibs = t->cfg_base->ibs; + cfg->base.obs = t->cfg_base->obs; + cfg->base.is_pages = t->cfg_base->is_pages; + cfg->base.audio_fmt = *t->in_fmt; + cfg->ref_fmt = *te->whm.ref_fmt; + cfg->out_fmt = *te->whm.out_fmt; + cfg->wake_tick_period = te->whm.wake_tick_period; + avs_init_node_id(&cfg->gtw_cfg.node_id, te, dma_id); + cfg->gtw_cfg.dma_buffer_size = te->whm.dma_buffer_size; mod->gtw_attrs = cfg->gtw_cfg.config.attrs; - ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, - t->core_id, t->domain, cfg, cfg_size, - &mod->instance_id); + ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, + t->domain, cfg, cfg_size, &mod->instance_id); return ret; } -static struct avs_control_data *avs_get_module_control(struct avs_path_module *mod) +static struct soc_mixer_control *avs_get_module_control(struct avs_path_module *mod, + const char *name) { struct avs_tplg_module *t = mod->template; struct avs_tplg_path_template *path_tmpl; @@ -278,27 +317,93 @@ static struct avs_control_data *avs_get_module_control(struct avs_path_module *m mc = (struct soc_mixer_control *)w->kcontrols[i]->private_value; ctl_data = (struct avs_control_data *)mc->dobj.private; - if (ctl_data->id == t->ctl_id) - return ctl_data; + if (ctl_data->id == t->ctl_id && strstr(w->kcontrols[i]->id.name, name)) + return mc; } return NULL; } +int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input) +{ + struct avs_volume_cfg vols[SND_SOC_TPLG_MAX_CHAN] = {{0}}; + struct avs_control_data *ctl_data; + struct avs_tplg_module *t; + int ret, i; + + ctl_data = mc->dobj.private; + t = mod->template; + if (!input) + input = ctl_data->values; + + if (mc->num_channels) { + for (i = 0; i < mc->num_channels; i++) { + vols[i].channel_id = i; + vols[i].target_volume = input[i]; + vols[i].curve_type = t->cfg_ext->peakvol.curve_type; + vols[i].curve_duration = t->cfg_ext->peakvol.curve_duration; + } + + ret = avs_ipc_peakvol_set_volumes(adev, mod->module_id, mod->instance_id, vols, + mc->num_channels); + return AVS_IPC_RET(ret); + } + + /* Target all channels if no individual selected. */ + vols[0].channel_id = AVS_ALL_CHANNELS_MASK; + vols[0].target_volume = input[0]; + vols[0].curve_type = t->cfg_ext->peakvol.curve_type; + vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration; + + ret = avs_ipc_peakvol_set_volume(adev, mod->module_id, mod->instance_id, &vols[0]); + return AVS_IPC_RET(ret); +} + +int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input) +{ + struct avs_mute_cfg mutes[SND_SOC_TPLG_MAX_CHAN] = {{0}}; + struct avs_control_data *ctl_data; + struct avs_tplg_module *t; + int ret, i; + + ctl_data = mc->dobj.private; + t = mod->template; + if (!input) + input = ctl_data->values; + + if (mc->num_channels) { + for (i = 0; i < mc->num_channels; i++) { + mutes[i].channel_id = i; + mutes[i].mute = !input[i]; + mutes[i].curve_type = t->cfg_ext->peakvol.curve_type; + mutes[i].curve_duration = t->cfg_ext->peakvol.curve_duration; + } + + ret = avs_ipc_peakvol_set_mutes(adev, mod->module_id, mod->instance_id, mutes, + mc->num_channels); + return AVS_IPC_RET(ret); + } + + /* Target all channels if no individual selected. */ + mutes[0].channel_id = AVS_ALL_CHANNELS_MASK; + mutes[0].mute = !input[0]; + mutes[0].curve_type = t->cfg_ext->peakvol.curve_type; + mutes[0].curve_duration = t->cfg_ext->peakvol.curve_duration; + + ret = avs_ipc_peakvol_set_mute(adev, mod->module_id, mod->instance_id, &mutes[0]); + return AVS_IPC_RET(ret); +} + static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) { struct avs_tplg_module *t = mod->template; - struct avs_control_data *ctl_data; + struct soc_mixer_control *mc; struct avs_peakvol_cfg *cfg; - int volume = S32_MAX; size_t cfg_size; int ret; - ctl_data = avs_get_module_control(mod); - if (ctl_data) - volume = ctl_data->volume; - - /* As 2+ channels controls are unsupported, have a single block for all channels. */ cfg_size = struct_size(cfg, vols, 1); if (cfg_size > AVS_MAILBOX_SIZE) return -EINVAL; @@ -310,15 +415,28 @@ static int avs_peakvol_create(struct avs_dev *adev, struct avs_path_module *mod) cfg->base.obs = t->cfg_base->obs; cfg->base.is_pages = t->cfg_base->is_pages; cfg->base.audio_fmt = *t->in_fmt; - cfg->vols[0].target_volume = volume; cfg->vols[0].channel_id = AVS_ALL_CHANNELS_MASK; - cfg->vols[0].curve_type = AVS_AUDIO_CURVE_NONE; - cfg->vols[0].curve_duration = 0; + cfg->vols[0].target_volume = S32_MAX; + cfg->vols[0].curve_type = t->cfg_ext->peakvol.curve_type; + cfg->vols[0].curve_duration = t->cfg_ext->peakvol.curve_duration; ret = avs_dsp_init_module(adev, mod->module_id, mod->owner->instance_id, t->core_id, t->domain, cfg, cfg_size, &mod->instance_id); + if (ret) + return ret; - return ret; + /* Now configure both VOLUME and MUTE parameters. */ + mc = avs_get_module_control(mod, "Volume"); + if (mc) { + ret = avs_peakvol_set_volume(adev, mod, mc, NULL); + if (ret) + return ret; + } + + mc = avs_get_module_control(mod, "Switch"); + if (mc) + return avs_peakvol_set_mute(adev, mod, mc, NULL); + return 0; } static int avs_updown_mix_create(struct avs_dev *adev, struct avs_path_module *mod) @@ -533,6 +651,7 @@ static struct avs_module_create avs_module_create[] = { { &AVS_ASRC_MOD_UUID, avs_asrc_create }, { &AVS_INTELWOV_MOD_UUID, avs_wov_create }, { &AVS_PROBE_MOD_UUID, avs_probe_create }, + { &AVS_WOVHOSTM_MOD_UUID, avs_whm_create }, }; static int avs_path_module_type_create(struct avs_dev *adev, struct avs_path_module *mod) diff --git a/sound/soc/intel/avs/path.h b/sound/soc/intel/avs/path.h index bfd253c9fa95..7ed7e94e0a56 100644 --- a/sound/soc/intel/avs/path.h +++ b/sound/soc/intel/avs/path.h @@ -69,4 +69,9 @@ int avs_path_reset(struct avs_path *path); int avs_path_pause(struct avs_path *path); int avs_path_run(struct avs_path *path, int trigger); +int avs_peakvol_set_volume(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input); +int avs_peakvol_set_mute(struct avs_dev *adev, struct avs_path_module *mod, + struct soc_mixer_control *mc, long *input); + #endif diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index 4bfbcb5a5ae8..dac463390da1 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -1380,7 +1380,7 @@ int avs_i2s_platform_register(struct avs_dev *adev, const char *name, unsigned l for_each_set_bit(i, &port_mask, ssp_count) cpu_count += hweight_long(tdms[i]); - cpus = devm_kzalloc(adev->dev, sizeof(*cpus) * cpu_count, GFP_KERNEL); + cpus = devm_kcalloc(adev->dev, cpu_count, sizeof(*cpus), GFP_KERNEL); if (!cpus) return -ENOMEM; diff --git a/sound/soc/intel/avs/tgl.c b/sound/soc/intel/avs/tgl.c index a9019ff5e3af..56905f2b9eb2 100644 --- a/sound/soc/intel/avs/tgl.c +++ b/sound/soc/intel/avs/tgl.c @@ -6,7 +6,11 @@ // Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com> // +#include <linux/pci.h> #include "avs.h" +#include "messages.h" + +#define CPUID_TSC_LEAF 0x15 static int avs_tgl_dsp_core_power(struct avs_dev *adev, u32 core_mask, bool power) { @@ -35,6 +39,34 @@ static int avs_tgl_dsp_core_stall(struct avs_dev *adev, u32 core_mask, bool stal return avs_dsp_core_stall(adev, core_mask, stall); } +static int avs_tgl_config_basefw(struct avs_dev *adev) +{ + struct pci_dev *pci = adev->base.pci; + struct avs_bus_hwid hwid; + int ret; +#ifdef CONFIG_X86 + unsigned int ecx; + +#include <asm/cpuid.h> + ecx = cpuid_ecx(CPUID_TSC_LEAF); + if (ecx) { + ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_XTAL_FREQ_HZ, sizeof(ecx), &ecx); + if (ret) + return AVS_IPC_RET(ret); + } +#endif + + hwid.device = pci->device; + hwid.subsystem = pci->subsystem_vendor | (pci->subsystem_device << 16); + hwid.revision = pci->revision; + + ret = avs_ipc_set_fw_config(adev, 1, AVS_FW_CFG_BUS_HARDWARE_ID, sizeof(hwid), &hwid); + if (ret) + return AVS_IPC_RET(ret); + + return 0; +} + const struct avs_dsp_ops avs_tgl_dsp_ops = { .power = avs_tgl_dsp_core_power, .reset = avs_tgl_dsp_core_reset, @@ -44,6 +76,7 @@ const struct avs_dsp_ops avs_tgl_dsp_ops = { .load_basefw = avs_icl_load_basefw, .load_lib = avs_hda_load_library, .transfer_mods = avs_hda_transfer_modules, + .config_basefw = avs_tgl_config_basefw, .log_buffer_offset = avs_icl_log_buffer_offset, .log_buffer_status = avs_apl_log_buffer_status, .coredump = avs_apl_coredump, diff --git a/sound/soc/intel/avs/topology.c b/sound/soc/intel/avs/topology.c index d612f20ed989..3c222c352701 100644 --- a/sound/soc/intel/avs/topology.c +++ b/sound/soc/intel/avs/topology.c @@ -815,6 +815,66 @@ static const struct avs_tplg_token_parser modcfg_ext_parsers[] = { .offset = offsetof(struct avs_tplg_modcfg_ext, generic.num_output_pins), .parse = avs_parse_short_token, }, + { + .token = AVS_TKN_MODCFG_WHM_REF_AFMT_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.ref_fmt), + .parse = avs_parse_audio_format_ptr, + }, + { + .token = AVS_TKN_MODCFG_WHM_OUT_AFMT_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.out_fmt), + .parse = avs_parse_audio_format_ptr, + }, + { + .token = AVS_TKN_MODCFG_WHM_WAKE_TICK_PERIOD_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.wake_tick_period), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_VINDEX_U8, + .type = SND_SOC_TPLG_TUPLE_TYPE_BYTE, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.vindex), + .parse = avs_parse_byte_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_DMA_TYPE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_type), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_DMABUFF_SIZE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.dma_buffer_size), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_WHM_BLOB_AFMT_ID_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, whm.blob_fmt), + .parse = avs_parse_audio_format_ptr, + }, + { + .token = AVS_TKN_MODCFG_PEAKVOL_VOLUME_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.target_volume), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_TYPE_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_type), + .parse = avs_parse_word_token, + }, + { + .token = AVS_TKN_MODCFG_PEAKVOL_CURVE_DURATION_U32, + .type = SND_SOC_TPLG_TUPLE_TYPE_WORD, + .offset = offsetof(struct avs_tplg_modcfg_ext, peakvol.curve_duration), + .parse = avs_parse_word_token, + }, }; static const struct avs_tplg_token_parser pin_format_parsers[] = { @@ -1845,13 +1905,23 @@ static int avs_manifest(struct snd_soc_component *comp, int index, return 0; } -#define AVS_CONTROL_OPS_VOLUME 257 +enum { + AVS_CONTROL_OPS_VOLUME = 257, + AVS_CONTROL_OPS_MUTE, +}; static const struct snd_soc_tplg_kcontrol_ops avs_control_ops[] = { { .id = AVS_CONTROL_OPS_VOLUME, .get = avs_control_volume_get, .put = avs_control_volume_put, + .info = avs_control_volume_info, + }, + { + .id = AVS_CONTROL_OPS_MUTE, + .get = avs_control_mute_get, + .put = avs_control_mute_put, + .info = avs_control_mute_info, }, }; @@ -1873,18 +1943,20 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_ struct avs_control_data *ctl_data; struct soc_mixer_control *mc; size_t block_size; - int ret; + int ret, i; switch (le32_to_cpu(hdr->type)) { case SND_SOC_TPLG_TYPE_MIXER: - tmc = container_of(hdr, typeof(*tmc), hdr); - tuples = tmc->priv.array; - block_size = le32_to_cpu(tmc->priv.size); break; default: return -EINVAL; } + mc = (struct soc_mixer_control *)ctmpl->private_value; + tmc = container_of(hdr, typeof(*tmc), hdr); + tuples = tmc->priv.array; + block_size = le32_to_cpu(tmc->priv.size); + ctl_data = devm_kzalloc(comp->card->dev, sizeof(*ctl_data), GFP_KERNEL); if (!ctl_data) return -ENOMEM; @@ -1895,8 +1967,13 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_ if (ret) return ret; - mc = (struct soc_mixer_control *)ctmpl->private_value; mc->dobj.private = ctl_data; + if (tmc->invert) { + ctl_data->values[0] = mc->max; + for (i = 1; i < mc->num_channels; i++) + ctl_data->values[i] = mc->max; + } + return 0; } diff --git a/sound/soc/intel/avs/topology.h b/sound/soc/intel/avs/topology.h index 7892e3797f63..304880997717 100644 --- a/sound/soc/intel/avs/topology.h +++ b/sound/soc/intel/avs/topology.h @@ -74,10 +74,17 @@ struct avs_tplg_modcfg_ext { union avs_virtual_index vindex; u32 dma_type; u32 dma_buffer_size; - u32 config_length; - /* config_data part of priv data */ } copier; struct { + struct avs_audio_format *ref_fmt; + struct avs_audio_format *out_fmt; + u32 wake_tick_period; + union avs_virtual_index vindex; + u32 dma_type; + u32 dma_buffer_size; + struct avs_audio_format *blob_fmt; /* optional override */ + } whm; + struct { u32 out_channel_config; u32 coefficients_select; s32 coefficients[AVS_CHANNELS_MAX]; @@ -106,6 +113,11 @@ struct avs_tplg_modcfg_ext { struct { struct avs_audio_format *out_fmt; } micsel; + struct { + u32 target_volume; + u32 curve_type; + u32 curve_duration; + } peakvol; }; }; diff --git a/sound/soc/intel/catpt/device.c b/sound/soc/intel/catpt/device.c index 2aa637124bec..faa916f40069 100644 --- a/sound/soc/intel/catpt/device.c +++ b/sound/soc/intel/catpt/device.c @@ -28,7 +28,7 @@ #define CREATE_TRACE_POINTS #include "trace.h" -static int __maybe_unused catpt_suspend(struct device *dev) +static int catpt_suspend(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); struct dma_chan *chan; @@ -72,7 +72,7 @@ release_dma_chan: return catpt_dsp_power_down(cdev); } -static int __maybe_unused catpt_resume(struct device *dev) +static int catpt_resume(struct device *dev) { struct catpt_dev *cdev = dev_get_drvdata(dev); int ret, i; @@ -106,7 +106,7 @@ static int __maybe_unused catpt_resume(struct device *dev) return 0; } -static int __maybe_unused catpt_runtime_suspend(struct device *dev) +static int catpt_runtime_suspend(struct device *dev) { if (!try_module_get(dev->driver->owner)) { dev_info(dev, "module unloading, skipping suspend\n"); @@ -117,14 +117,14 @@ static int __maybe_unused catpt_runtime_suspend(struct device *dev) return catpt_suspend(dev); } -static int __maybe_unused catpt_runtime_resume(struct device *dev) +static int catpt_runtime_resume(struct device *dev) { return catpt_resume(dev); } static const struct dev_pm_ops catpt_dev_pm = { - SET_SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume) - SET_RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(catpt_suspend, catpt_resume) + RUNTIME_PM_OPS(catpt_runtime_suspend, catpt_runtime_resume, NULL) }; /* machine board owned by CATPT is removed with this hook */ @@ -378,7 +378,7 @@ static struct platform_driver catpt_acpi_driver = { .driver = { .name = "intel_catpt", .acpi_match_table = catpt_ids, - .pm = &catpt_dev_pm, + .pm = pm_ptr(&catpt_dev_pm), .dev_groups = catpt_attr_groups, }, }; diff --git a/sound/soc/intel/common/soc-acpi-intel-adl-match.c b/sound/soc/intel/common/soc-acpi-intel-adl-match.c index bb1324fb588e..a68efbe98948 100644 --- a/sound/soc/intel/common/soc-acpi-intel-adl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-adl-match.c @@ -214,6 +214,15 @@ static const struct snd_soc_acpi_adr_device rt1316_1_group2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1316_2_group2_adr[] = { + { + .adr = 0x000232025D131601ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1316-2" + } +}; + static const struct snd_soc_acpi_adr_device rt1316_1_single_adr[] = { { .adr = 0x000130025D131601ull, @@ -547,6 +556,20 @@ static const struct snd_soc_acpi_link_adr adl_chromebook_base[] = { {} }; +static const struct snd_soc_acpi_link_adr adl_sdw_rt1316_link02[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(rt1316_0_group2_adr), + .adr_d = rt1316_0_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1316_2_group2_adr), + .adr_d = rt1316_2_group2_adr, + }, + {} +}; + static const struct snd_soc_acpi_codecs adl_max98357a_amp = { .num_codecs = 1, .codecs = {"MX98357A"} @@ -749,6 +772,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_adl_sdw_machines[] = { .drv_name = "sof_sdw", .sof_tplg_filename = "sof-adl-sdw-max98373-rt5682.tplg", }, + { + .link_mask = BIT(0) | BIT(2), + .links = adl_sdw_rt1316_link02, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-adl-rt1316-l02.tplg", + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_adl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c index 0b4a9c27c47e..e04f6de746eb 100644 --- a/sound/soc/intel/common/soc-acpi-intel-lnl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-lnl-match.c @@ -37,6 +37,13 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_1_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + static const struct snd_soc_acpi_endpoint spk_2_endpoint = { .num = 0, .aggregated = 1, @@ -51,6 +58,27 @@ static const struct snd_soc_acpi_endpoint spk_3_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_4_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 4, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_5_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 5, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_6_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 6, + .group_id = 1, +}; + static const struct snd_soc_acpi_endpoint rt712_endpoints[] = { { .num = 0, @@ -159,6 +187,33 @@ static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { }, }; +static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, +}; + static const struct snd_soc_acpi_adr_device cs35l56_2_l_adr[] = { { .adr = 0x00023001FA355601ull, @@ -204,6 +259,48 @@ static const struct snd_soc_acpi_adr_device cs35l56_3_lr_adr[] = { } }; +static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = { + { + .adr = 0x00013001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_1_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00013101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + }, + { + .adr = 0x00013201fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP3" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = { + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_4_endpoint, + .name_prefix = "AMP4" + }, + { + .adr = 0x00033401fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_5_endpoint, + .name_prefix = "AMP5" + }, + { + .adr = 0x00033501fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_6_endpoint, + .name_prefix = "AMP6" + } +}; + static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { { .adr = 0x00003001FA424301ull, @@ -213,6 +310,15 @@ static const struct snd_soc_acpi_adr_device cs42l43_0_adr[] = { } }; +static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { + { + .adr = 0x00023001fa424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints), + .endpoints = cs42l43_amp_spkagg_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { .adr = 0x000030025D071101ull, @@ -408,6 +514,25 @@ static const struct snd_soc_acpi_link_adr lnl_cs42l43_l0_cs35l56_l23[] = { {} }; +static const struct snd_soc_acpi_link_adr lnl_cs42l43_l2_cs35l56x6_l13[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr), + .adr_d = cs35l56_1_3amp_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr), + .adr_d = cs35l56_3_3amp_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr lnl_rvp[] = { { .mask = BIT(0), @@ -553,6 +678,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .sof_tplg_filename = "sof-lnl-rt715-rt711-rt1308-mono.tplg", }, { + .link_mask = BIT(0), + .links = sdw_mockup_multi_func, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-rt722-l0.tplg", /* Reuse the existing tplg file */ + }, + { .link_mask = GENMASK(3, 0), .links = lnl_3_in_1_sdca, .drv_name = "sof_sdw", @@ -565,6 +696,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[] = { .sof_tplg_filename = "sof-lnl-cs42l43-l0-cs35l56-l23.tplg", }, { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = lnl_cs42l43_l2_cs35l56x6_l13, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-lnl-cs42l43-l2-cs35l56x6-l13.tplg", + }, + { .link_mask = BIT(0) | BIT(3), .links = lnl_cs42l43_l0_cs35l56_l3, .drv_name = "sof_sdw", diff --git a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c index dd7993b76dee..6603d8de501c 100644 --- a/sound/soc/intel/common/soc-acpi-intel-ptl-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-ptl-match.c @@ -50,6 +50,48 @@ static const struct snd_soc_acpi_endpoint spk_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint spk_1_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 1, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_2_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 2, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_3_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 3, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_4_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 4, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_5_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 5, + .group_id = 1, +}; + +static const struct snd_soc_acpi_endpoint spk_6_endpoint = { + .num = 0, + .aggregated = 1, + .group_position = 6, + .group_id = 1, +}; + /* * Multi-function codecs with three endpoints created for * headset, amp and dmic functions. @@ -116,6 +158,120 @@ static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints_endpoints[] }, }; +static const struct snd_soc_acpi_endpoint cs42l43_amp_spkagg_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, +}; + +static const struct snd_soc_acpi_endpoint cs42l43_endpoints[] = { + { /* Jack Playback Endpoint */ + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* DMIC Capture Endpoint */ + .num = 1, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Jack Capture Endpoint */ + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + { /* Speaker Playback Endpoint */ + .num = 3, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + +static const struct snd_soc_acpi_adr_device cs42l43_2_adr[] = { + { + .adr = 0x00023001fa424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_amp_spkagg_endpoints), + .endpoints = cs42l43_amp_spkagg_endpoints, + .name_prefix = "cs42l43" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_1_3amp_adr[] = { + { + .adr = 0x00013001fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_1_endpoint, + .name_prefix = "AMP1" + }, + { + .adr = 0x00013101fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_2_endpoint, + .name_prefix = "AMP2" + }, + { + .adr = 0x00013201fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_3_endpoint, + .name_prefix = "AMP3" + } +}; + +static const struct snd_soc_acpi_adr_device cs35l56_3_3amp_adr[] = { + { + .adr = 0x00033301fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_4_endpoint, + .name_prefix = "AMP4" + }, + { + .adr = 0x00033401fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_5_endpoint, + .name_prefix = "AMP5" + }, + { + .adr = 0x00033501fa355601ull, + .num_endpoints = 1, + .endpoints = &spk_6_endpoint, + .name_prefix = "AMP6" + } +}; + +static const struct snd_soc_acpi_adr_device cs42l43_3_adr[] = { + { + .adr = 0x00033001FA424301ull, + .num_endpoints = ARRAY_SIZE(cs42l43_endpoints), + .endpoints = cs42l43_endpoints, + .name_prefix = "cs42l43" + } +}; + static const struct snd_soc_acpi_adr_device rt711_sdca_0_adr[] = { { .adr = 0x000030025D071101ull, @@ -134,6 +290,15 @@ static const struct snd_soc_acpi_adr_device rt712_vb_2_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt712_vb_3_group1_adr[] = { + { + .adr = 0x000330025D071201ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints_endpoints, + .name_prefix = "rt712" + } +}; + static const struct snd_soc_acpi_adr_device rt713_vb_2_adr[] = { { .adr = 0x000230025d071301ull, @@ -143,6 +308,15 @@ static const struct snd_soc_acpi_adr_device rt713_vb_2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt713_vb_3_adr[] = { + { + .adr = 0x000330025D071301ull, + .num_endpoints = ARRAY_SIZE(jack_dmic_endpoints), + .endpoints = jack_dmic_endpoints, + .name_prefix = "rt713" + } +}; + static const struct snd_soc_acpi_adr_device rt721_3_single_adr[] = { { .adr = 0x000330025d072101ull, @@ -206,6 +380,24 @@ static const struct snd_soc_acpi_adr_device rt1320_1_group2_adr[] = { } }; +static const struct snd_soc_acpi_adr_device rt1320_2_group1_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + +static const struct snd_soc_acpi_adr_device rt1320_2_group2_adr[] = { + { + .adr = 0x000230025D132001ull, + .num_endpoints = 1, + .endpoints = &spk_r_endpoint, + .name_prefix = "rt1320-1" + } +}; + static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = { { .adr = 0x000330025D132001ull, @@ -215,6 +407,33 @@ static const struct snd_soc_acpi_adr_device rt1320_3_group2_adr[] = { } }; +static const struct snd_soc_acpi_link_adr ptl_cs42l43_l2_cs35l56x6_l13[] = { + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(cs42l43_2_adr), + .adr_d = cs42l43_2_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(cs35l56_1_3amp_adr), + .adr_d = cs35l56_1_3amp_adr, + }, + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs35l56_3_3amp_adr), + .adr_d = cs35l56_3_3amp_adr, + }, + {} +}; + +static const struct snd_soc_acpi_link_adr ptl_cs42l43_l3[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(cs42l43_3_adr), + .adr_d = cs42l43_3_adr, + } +}; + static const struct snd_soc_acpi_link_adr ptl_rt722_only[] = { { .mask = BIT(0), @@ -270,6 +489,25 @@ static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l2_rt1320_l13[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_sdw_rt713_vb_l3_rt1320_l12[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt713_vb_3_adr), + .adr_d = rt713_vb_3_adr, + }, + { + .mask = BIT(1), + .num_adr = ARRAY_SIZE(rt1320_1_group2_adr), + .adr_d = rt1320_1_group2_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group2_adr), + .adr_d = rt1320_2_group2_adr, + }, + {} +}; + static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l2_rt1320_l1[] = { { .mask = BIT(2), @@ -284,6 +522,20 @@ static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l2_rt1320_l1[] = { {} }; +static const struct snd_soc_acpi_link_adr ptl_sdw_rt712_vb_l3_rt1320_l2[] = { + { + .mask = BIT(3), + .num_adr = ARRAY_SIZE(rt712_vb_3_group1_adr), + .adr_d = rt712_vb_3_group1_adr, + }, + { + .mask = BIT(2), + .num_adr = ARRAY_SIZE(rt1320_2_group1_adr), + .adr_d = rt1320_2_group1_adr, + }, + {} +}; + /* this table is used when there is no I2S codec present */ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { /* mockup tests need to be first */ @@ -306,6 +558,18 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .sof_tplg_filename = "sof-ptl-rt715-rt711-rt1308-mono.tplg", }, { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_cs42l43_l2_cs35l56x6_l13, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-cs42l43-l2-cs35l56x6-l13.tplg", + }, + { + .link_mask = BIT(0), + .links = sdw_mockup_multi_func, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-rt722.tplg", /* Reuse the existing tplg file */ + }, + { .link_mask = BIT(0), .links = ptl_rvp, .drv_name = "sof_sdw", @@ -313,6 +577,12 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { }, { .link_mask = BIT(3), + .links = ptl_cs42l43_l3, + .drv_name = "sof_sdw", + .sof_tplg_filename = "sof-ptl-cs42l43-l3.tplg", + }, + { + .link_mask = BIT(3), .links = ptl_rt721_l3, .drv_name = "sof_sdw", .sof_tplg_filename = "sof-ptl-rt721.tplg", @@ -343,12 +613,26 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[] = { .sof_tplg_filename = "sof-ptl-rt712-l2-rt1320-l1.tplg" }, { + .link_mask = BIT(2) | BIT(3), + .links = ptl_sdw_rt712_vb_l3_rt1320_l2, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt712-l3-rt1320-l2.tplg" + }, + { .link_mask = BIT(1) | BIT(2) | BIT(3), .links = ptl_sdw_rt713_vb_l2_rt1320_l13, .drv_name = "sof_sdw", .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, .sof_tplg_filename = "sof-ptl-rt713-l2-rt1320-l13.tplg" }, + { + .link_mask = BIT(1) | BIT(2) | BIT(3), + .links = ptl_sdw_rt713_vb_l3_rt1320_l12, + .drv_name = "sof_sdw", + .machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb, + .sof_tplg_filename = "sof-ptl-rt713-l3-rt1320-l12.tplg" + }, {}, }; EXPORT_SYMBOL_GPL(snd_soc_acpi_intel_ptl_sdw_machines); diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c index a3d33997736a..d122ce69fa4f 100644 --- a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c +++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.c @@ -31,6 +31,30 @@ static const struct snd_soc_acpi_endpoint sdw_mockup_r_endpoint = { .group_id = 1, }; +static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = { + /* Jack Endpoint */ + { + .num = 0, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, + /* Amp Endpoint, work as spk_l_endpoint */ + { + .num = 1, + .aggregated = 1, + .group_position = 0, + .group_id = 1, + }, + /* DMIC Endpoint */ + { + .num = 2, + .aggregated = 0, + .group_position = 0, + .group_id = 0, + }, +}; + static const struct snd_soc_acpi_adr_device sdw_mockup_headset_0_adr[] = { { .adr = 0x0000000105AA5500ull, @@ -103,6 +127,15 @@ static const struct snd_soc_acpi_adr_device sdw_mockup_amp_2_group1_adr[] = { } }; +static const struct snd_soc_acpi_adr_device sdw_mockup_multi_function_adr[] = { + { + .adr = 0x0000000105AAAA01ull, + .num_endpoints = ARRAY_SIZE(jack_amp_g1_dmic_endpoints), + .endpoints = jack_amp_g1_dmic_endpoints, + .name_prefix = "sdw_mockup_mmulti-function" + } +}; + const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[] = { { .mask = BIT(0), @@ -164,3 +197,12 @@ const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[] = { }, {} }; + +const struct snd_soc_acpi_link_adr sdw_mockup_multi_func[] = { + { + .mask = BIT(0), + .num_adr = ARRAY_SIZE(sdw_mockup_multi_function_adr), + .adr_d = sdw_mockup_multi_function_adr, + }, + {} +}; diff --git a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h index c99eecd19e03..f7ed5beaca96 100644 --- a/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h +++ b/sound/soc/intel/common/soc-acpi-intel-sdw-mockup-match.h @@ -13,5 +13,6 @@ extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_1amp_mic[]; extern const struct snd_soc_acpi_link_adr sdw_mockup_headset_2amps_mic[]; extern const struct snd_soc_acpi_link_adr sdw_mockup_mic_headset_1amp[]; +extern const struct snd_soc_acpi_link_adr sdw_mockup_multi_func[]; #endif diff --git a/sound/soc/kirkwood/armada-370-db.c b/sound/soc/kirkwood/armada-370-db.c index 79ee7599f06a..77a5f440364e 100644 --- a/sound/soc/kirkwood/armada-370-db.c +++ b/sound/soc/kirkwood/armada-370-db.c @@ -73,20 +73,20 @@ static struct snd_soc_dai_link a370db_dai[] = { { .name = "CS42L51", .stream_name = "analog", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC, .ops = &a370db_ops, SND_SOC_DAILINK_REG(analog), }, { .name = "S/PDIF out", .stream_name = "spdif-out", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(spdif_out), }, { .name = "S/PDIF in", .stream_name = "spdif-in", - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS, + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(spdif_in), }, }; diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.c b/sound/soc/mediatek/common/mtk-afe-fe-dai.c index 3044d9ab3d4d..3809068f5620 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.c +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.c @@ -500,26 +500,6 @@ static int mtk_memif_set_rate_fs(struct mtk_base_afe *afe, return 0; } -int mtk_memif_set_rate(struct mtk_base_afe *afe, - int id, unsigned int rate) -{ - int fs = 0; - - if (!afe->get_dai_fs) { - dev_err(afe->dev, "%s(), error, afe->get_dai_fs == NULL\n", - __func__); - return -EINVAL; - } - - fs = afe->get_dai_fs(afe, id, rate); - - if (fs < 0) - return -EINVAL; - - return mtk_memif_set_rate_fs(afe, id, fs); -} -EXPORT_SYMBOL_GPL(mtk_memif_set_rate); - int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, int id, unsigned int rate) { diff --git a/sound/soc/mediatek/common/mtk-afe-fe-dai.h b/sound/soc/mediatek/common/mtk-afe-fe-dai.h index 8cec90671827..b6d0f2b27e86 100644 --- a/sound/soc/mediatek/common/mtk-afe-fe-dai.h +++ b/sound/soc/mediatek/common/mtk-afe-fe-dai.h @@ -42,8 +42,6 @@ int mtk_memif_set_addr(struct mtk_base_afe *afe, int id, size_t dma_bytes); int mtk_memif_set_channel(struct mtk_base_afe *afe, int id, unsigned int channel); -int mtk_memif_set_rate(struct mtk_base_afe *afe, - int id, unsigned int rate); int mtk_memif_set_rate_substream(struct snd_pcm_substream *substream, int id, unsigned int rate); int mtk_memif_set_format(struct mtk_base_afe *afe, diff --git a/sound/soc/mediatek/common/mtk-soc-card.h b/sound/soc/mediatek/common/mtk-soc-card.h index 3f6e24dd22df..a1d2794ac1f7 100644 --- a/sound/soc/mediatek/common/mtk-soc-card.h +++ b/sound/soc/mediatek/common/mtk-soc-card.h @@ -16,6 +16,7 @@ struct mtk_soc_card_data { const struct mtk_sof_priv *sof_priv; struct list_head sof_dai_link_list; struct mtk_platform_card_data *card_data; + struct snd_soc_component *accdet; void *mach_priv; }; diff --git a/sound/soc/mediatek/common/mtk-soundcard-driver.c b/sound/soc/mediatek/common/mtk-soundcard-driver.c index f4314dddc460..713a368f79cf 100644 --- a/sound/soc/mediatek/common/mtk-soundcard-driver.c +++ b/sound/soc/mediatek/common/mtk-soundcard-driver.c @@ -8,6 +8,7 @@ #include <linux/module.h> #include <linux/of.h> +#include <linux/of_platform.h> #include <sound/soc.h> #include "mtk-dsp-sof-common.h" @@ -192,7 +193,9 @@ EXPORT_SYMBOL_GPL(mtk_soundcard_common_capture_ops); int mtk_soundcard_common_probe(struct platform_device *pdev) { - struct device_node *platform_node, *adsp_node; + struct device_node *platform_node, *adsp_node, *accdet_node; + struct snd_soc_component *accdet_comp; + struct platform_device *accdet_pdev; const struct mtk_soundcard_pdata *pdata; struct mtk_soc_card_data *soc_card_data; struct snd_soc_dai_link *orig_dai_link, *dai_link; @@ -250,6 +253,20 @@ int mtk_soundcard_common_probe(struct platform_device *pdev) soc_card_data->card_data->jacks = jacks; + accdet_node = of_parse_phandle(pdev->dev.of_node, "mediatek,accdet", 0); + if (accdet_node) { + accdet_pdev = of_find_device_by_node(accdet_node); + if (accdet_pdev) { + accdet_comp = snd_soc_lookup_component(&accdet_pdev->dev, NULL); + if (accdet_comp) + soc_card_data->accdet = accdet_comp; + else + dev_err(&pdev->dev, "No sound component found from mediatek,accdet property\n"); + } else { + dev_err(&pdev->dev, "No device found from mediatek,accdet property\n"); + } + } + platform_node = of_parse_phandle(pdev->dev.of_node, "mediatek,platform", 0); if (!platform_node) return dev_err_probe(&pdev->dev, -EINVAL, diff --git a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c index 5f11bc5438bd..fcae38135d93 100644 --- a/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c +++ b/sound/soc/mediatek/mt2701/mt2701-afe-pcm.c @@ -1462,15 +1462,15 @@ static const struct of_device_id mt2701_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt2701_afe_pcm_dt_match); static const struct dev_pm_ops mt2701_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt2701_afe_runtime_suspend, - mt2701_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt2701_afe_runtime_suspend, + mt2701_afe_runtime_resume, NULL) }; static struct platform_driver mt2701_afe_pcm_driver = { .driver = { .name = "mt2701-audio", .of_match_table = mt2701_afe_pcm_dt_match, - .pm = &mt2701_afe_pm_ops, + .pm = pm_ptr(&mt2701_afe_pm_ops), }, .probe = mt2701_afe_pcm_dev_probe, .remove = mt2701_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt2701/mt2701-cs42448.c b/sound/soc/mediatek/mt2701/mt2701-cs42448.c index 00a79867235d..778a9dccfcaa 100644 --- a/sound/soc/mediatek/mt2701/mt2701-cs42448.c +++ b/sound/soc/mediatek/mt2701/mt2701-cs42448.c @@ -266,7 +266,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { [DAI_LINK_BE_I2S0] = { .name = "mt2701-cs42448-I2S0", .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, SND_SOC_DAILINK_REG(be_i2s0), @@ -274,7 +274,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { [DAI_LINK_BE_I2S1] = { .name = "mt2701-cs42448-I2S1", .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, SND_SOC_DAILINK_REG(be_i2s1), @@ -282,7 +282,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { [DAI_LINK_BE_I2S2] = { .name = "mt2701-cs42448-I2S2", .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, SND_SOC_DAILINK_REG(be_i2s2), @@ -290,7 +290,7 @@ static struct snd_soc_dai_link mt2701_cs42448_dai_links[] = { [DAI_LINK_BE_I2S3] = { .name = "mt2701-cs42448-I2S3", .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_GATED, .ops = &mt2701_cs42448_be_ops, SND_SOC_DAILINK_REG(be_i2s3), diff --git a/sound/soc/mediatek/mt2701/mt2701-wm8960.c b/sound/soc/mediatek/mt2701/mt2701-wm8960.c index 2814f0570928..84b3d6cd77a5 100644 --- a/sound/soc/mediatek/mt2701/mt2701-wm8960.c +++ b/sound/soc/mediatek/mt2701/mt2701-wm8960.c @@ -83,7 +83,7 @@ static struct snd_soc_dai_link mt2701_wm8960_dai_links[] = { { .name = "wm8960-codec", .no_pcm = 1, - .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBS_CFS + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_GATED, .ops = &mt2701_wm8960_be_ops, SND_SOC_DAILINK_REG(codec), diff --git a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c index 9159b42adf6a..f62a32f2f2b6 100644 --- a/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c +++ b/sound/soc/mediatek/mt6797/mt6797-afe-pcm.c @@ -879,15 +879,15 @@ static const struct of_device_id mt6797_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt6797_afe_pcm_dt_match); static const struct dev_pm_ops mt6797_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt6797_afe_runtime_suspend, - mt6797_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt6797_afe_runtime_suspend, + mt6797_afe_runtime_resume, NULL) }; static struct platform_driver mt6797_afe_pcm_driver = { .driver = { .name = "mt6797-audio", .of_match_table = mt6797_afe_pcm_dt_match, - .pm = &mt6797_afe_pm_ops, + .pm = pm_ptr(&mt6797_afe_pm_ops), }, .probe = mt6797_afe_pcm_dev_probe, .remove = mt6797_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c index 7db090414d59..7a6ad9116e55 100644 --- a/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c +++ b/sound/soc/mediatek/mt7986/mt7986-afe-pcm.c @@ -589,15 +589,15 @@ static const struct of_device_id mt7986_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt7986_afe_pcm_dt_match); static const struct dev_pm_ops mt7986_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt7986_afe_runtime_suspend, - mt7986_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt7986_afe_runtime_suspend, + mt7986_afe_runtime_resume, NULL) }; static struct platform_driver mt7986_afe_pcm_driver = { .driver = { .name = "mt7986-audio", .of_match_table = mt7986_afe_pcm_dt_match, - .pm = &mt7986_afe_pm_ops, + .pm = pm_ptr(&mt7986_afe_pm_ops), }, .probe = mt7986_afe_pcm_dev_probe, .remove = mt7986_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c index d57971413a04..fc55ff47b7bc 100644 --- a/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c +++ b/sound/soc/mediatek/mt7986/mt7986-dai-etdm.c @@ -348,10 +348,10 @@ static int mtk_dai_etdm_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: etdm_data->slave_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: etdm_data->slave_mode = false; break; default: diff --git a/sound/soc/mediatek/mt7986/mt7986-wm8960.c b/sound/soc/mediatek/mt7986/mt7986-wm8960.c index c3d1e2eeb0e5..f1dc18222be7 100644 --- a/sound/soc/mediatek/mt7986/mt7986-wm8960.c +++ b/sound/soc/mediatek/mt7986/mt7986-wm8960.c @@ -63,7 +63,7 @@ static struct snd_soc_dai_link mt7986_wm8960_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_GATED, SND_SOC_DAILINK_REG(codec), }, diff --git a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c index 03250273ea9c..04ed0cfec174 100644 --- a/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c +++ b/sound/soc/mediatek/mt8173/mt8173-afe-pcm.c @@ -1212,15 +1212,15 @@ static const struct of_device_id mt8173_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8173_afe_pcm_dt_match); static const struct dev_pm_ops mt8173_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8173_afe_runtime_suspend, - mt8173_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt8173_afe_runtime_suspend, + mt8173_afe_runtime_resume, NULL) }; static struct platform_driver mt8173_afe_pcm_driver = { .driver = { .name = "mt8173-afe-pcm", .of_match_table = mt8173_afe_pcm_dt_match, - .pm = &mt8173_afe_pm_ops, + .pm = pm_ptr(&mt8173_afe_pm_ops), }, .probe = mt8173_afe_pcm_dev_probe, .remove = mt8173_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8173/mt8173-max98090.c b/sound/soc/mediatek/mt8173/mt8173-max98090.c index 0724564cee6a..49ebb67c818a 100644 --- a/sound/soc/mediatek/mt8173/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173/mt8173-max98090.c @@ -122,7 +122,7 @@ static struct snd_soc_dai_link mt8173_max98090_dais[] = { .init = mt8173_max98090_init, .ops = &mt8173_max98090_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(hifi), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c index d8e4e70d834c..dc063d85e62f 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5514.c @@ -156,7 +156,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5514_dais[] = { .no_pcm = 1, .init = mt8173_rt5650_rt5514_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &mt8173_rt5650_rt5514_ops, .ignore_pmdown_time = 1, SND_SOC_DAILINK_REG(codec), diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c index 488f2314dbf7..a1ba5df87e1e 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650-rt5676.c @@ -197,7 +197,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .no_pcm = 1, .init = mt8173_rt5650_rt5676_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &mt8173_rt5650_rt5676_ops, .ignore_pmdown_time = 1, SND_SOC_DAILINK_REG(codec), @@ -214,7 +214,7 @@ static struct snd_soc_dai_link mt8173_rt5650_rt5676_dais[] = { .stream_name = "rt5650_rt5676 intercodec", .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(intercodec), }, }; diff --git a/sound/soc/mediatek/mt8173/mt8173-rt5650.c b/sound/soc/mediatek/mt8173/mt8173-rt5650.c index 59c19fdd8675..7d6a3586cdd5 100644 --- a/sound/soc/mediatek/mt8173/mt8173-rt5650.c +++ b/sound/soc/mediatek/mt8173/mt8173-rt5650.c @@ -235,7 +235,7 @@ static struct snd_soc_dai_link mt8173_rt5650_dais[] = { .no_pcm = 1, .init = mt8173_rt5650_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &mt8173_rt5650_ops, .ignore_pmdown_time = 1, SND_SOC_DAILINK_REG(codec), diff --git a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c index 3f377ba4ad53..d083b4bf0f95 100644 --- a/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c +++ b/sound/soc/mediatek/mt8183/mt8183-afe-pcm.c @@ -1257,15 +1257,15 @@ static const struct of_device_id mt8183_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8183_afe_pcm_dt_match); static const struct dev_pm_ops mt8183_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8183_afe_runtime_suspend, - mt8183_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt8183_afe_runtime_suspend, + mt8183_afe_runtime_resume, NULL) }; static struct platform_driver mt8183_afe_pcm_driver = { .driver = { .name = "mt8183-audio", .of_match_table = mt8183_afe_pcm_dt_match, - .pm = &mt8183_afe_pm_ops, + .pm = pm_ptr(&mt8183_afe_pm_ops), }, .probe = mt8183_afe_pcm_dev_probe, .remove = mt8183_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c index 1d8881e0a361..3388e076ccc9 100644 --- a/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-da7219-max98357.c @@ -563,7 +563,7 @@ static struct snd_soc_dai_link mt8183_da7219_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, diff --git a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c index 6267c8554c15..497a9043be7b 100644 --- a/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c +++ b/sound/soc/mediatek/mt8183/mt8183-mt6358-ts3a227-max98357.c @@ -575,7 +575,7 @@ static struct snd_soc_dai_link mt8183_mt6358_ts3a227_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8183_i2s_hw_params_fixup, @@ -783,7 +783,7 @@ mt8183_mt6358_ts3a227_max98357_dev_probe(struct platform_device *pdev) strcmp(dai_link->name, "I2S3") == 0) dai_link->dai_fmt = SND_SOC_DAIFMT_LEFT_J | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; } if (hdmi_codec && strcmp(dai_link->name, "TDM") == 0) { diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c index 70ec101890d3..daaca36a2d08 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.c @@ -329,61 +329,6 @@ void mt8186_afe_disable_clock(struct mtk_base_afe *afe) clk_disable_unprepare(afe_priv->clk[CLK_INFRA_SYS_AUDIO]); } -int mt8186_afe_suspend_clock(struct mtk_base_afe *afe) -{ - struct mt8186_afe_private *afe_priv = afe->platform_priv; - int ret; - - /* set audio int bus to 26M */ - ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); - if (ret) { - dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); - goto clk_mux_audio_intbus_err; - } - ret = mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); - if (ret) - goto clk_mux_audio_intbus_parent_err; - - clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); - - return 0; - -clk_mux_audio_intbus_parent_err: - mt8186_set_audio_int_bus_parent(afe, CLK_TOP_MAINPLL_D2_D4); -clk_mux_audio_intbus_err: - clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); - return ret; -} - -int mt8186_afe_resume_clock(struct mtk_base_afe *afe) -{ - struct mt8186_afe_private *afe_priv = afe->platform_priv; - int ret; - - /* set audio int bus to normal working clock */ - ret = clk_prepare_enable(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); - if (ret) { - dev_info(afe->dev, "%s clk_prepare_enable %s fail %d\n", - __func__, aud_clks[CLK_MUX_AUDIOINTBUS], ret); - goto clk_mux_audio_intbus_err; - } - ret = mt8186_set_audio_int_bus_parent(afe, - CLK_TOP_MAINPLL_D2_D4); - if (ret) - goto clk_mux_audio_intbus_parent_err; - - clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); - - return 0; - -clk_mux_audio_intbus_parent_err: - mt8186_set_audio_int_bus_parent(afe, CLK_CLK26M); -clk_mux_audio_intbus_err: - clk_disable_unprepare(afe_priv->clk[CLK_MUX_AUDIOINTBUS]); - return ret; -} - int mt8186_apll1_enable(struct mtk_base_afe *afe) { struct mt8186_afe_private *afe_priv = afe->platform_priv; diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h index a9d59e506d9a..e524833ce780 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-clk.h +++ b/sound/soc/mediatek/mt8186/mt8186-afe-clk.h @@ -85,8 +85,6 @@ int mt8186_afe_enable_cgs(struct mtk_base_afe *afe); void mt8186_afe_disable_cgs(struct mtk_base_afe *afe); int mt8186_afe_enable_clock(struct mtk_base_afe *afe); void mt8186_afe_disable_clock(struct mtk_base_afe *afe); -int mt8186_afe_suspend_clock(struct mtk_base_afe *afe); -int mt8186_afe_resume_clock(struct mtk_base_afe *afe); int mt8186_apll1_enable(struct mtk_base_afe *afe); void mt8186_apll1_disable(struct mtk_base_afe *afe); diff --git a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c index bafbef96a42d..db7c93401bee 100644 --- a/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c +++ b/sound/soc/mediatek/mt8186/mt8186-afe-pcm.c @@ -2978,15 +2978,15 @@ static const struct of_device_id mt8186_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8186_afe_pcm_dt_match); static const struct dev_pm_ops mt8186_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8186_afe_runtime_suspend, - mt8186_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt8186_afe_runtime_suspend, + mt8186_afe_runtime_resume, NULL) }; static struct platform_driver mt8186_afe_pcm_driver = { .driver = { .name = "mt8186-audio", .of_match_table = mt8186_afe_pcm_dt_match, - .pm = &mt8186_afe_pm_ops, + .pm = pm_ptr(&mt8186_afe_pm_ops), }, .probe = mt8186_afe_pcm_dev_probe, }; diff --git a/sound/soc/mediatek/mt8186/mt8186-mt6366.c b/sound/soc/mediatek/mt8186/mt8186-mt6366.c index a5ef913743d4..43546012cf61 100644 --- a/sound/soc/mediatek/mt8186/mt8186-mt6366.c +++ b/sound/soc/mediatek/mt8186/mt8186-mt6366.c @@ -875,7 +875,7 @@ static struct snd_soc_dai_link mt8186_mt6366_rt1019_rt5682s_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_IF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .playback_only = 1, .ignore_suspend = 1, .init = mt8186_mt6366_rt1019_rt5682s_hdmi_init, diff --git a/sound/soc/mediatek/mt8188/Makefile b/sound/soc/mediatek/mt8188/Makefile index 1178bce45c50..b9f3e4ad7b07 100644 --- a/sound/soc/mediatek/mt8188/Makefile +++ b/sound/soc/mediatek/mt8188/Makefile @@ -6,6 +6,7 @@ snd-soc-mt8188-afe-y := \ mt8188-afe-pcm.o \ mt8188-audsys-clk.o \ mt8188-dai-adda.o \ + mt8188-dai-dmic.o \ mt8188-dai-etdm.o \ mt8188-dai-pcm.o diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c index e69c1bb2cb23..7f411b857782 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.c @@ -58,7 +58,15 @@ static const char *aud_clks[MT8188_CLK_NUM] = { [MT8188_CLK_AUD_ADC] = "aud_adc", [MT8188_CLK_AUD_DAC_HIRES] = "aud_dac_hires", [MT8188_CLK_AUD_A1SYS_HP] = "aud_a1sys_hp", + [MT8188_CLK_AUD_AFE_DMIC1] = "aud_afe_dmic1", + [MT8188_CLK_AUD_AFE_DMIC2] = "aud_afe_dmic2", + [MT8188_CLK_AUD_AFE_DMIC3] = "aud_afe_dmic3", + [MT8188_CLK_AUD_AFE_DMIC4] = "aud_afe_dmic4", [MT8188_CLK_AUD_ADC_HIRES] = "aud_adc_hires", + [MT8188_CLK_AUD_DMIC_HIRES1] = "aud_dmic_hires1", + [MT8188_CLK_AUD_DMIC_HIRES2] = "aud_dmic_hires2", + [MT8188_CLK_AUD_DMIC_HIRES3] = "aud_dmic_hires3", + [MT8188_CLK_AUD_DMIC_HIRES4] = "aud_dmic_hires4", [MT8188_CLK_AUD_I2SIN] = "aud_i2sin", [MT8188_CLK_AUD_TDM_IN] = "aud_tdm_in", [MT8188_CLK_AUD_I2S_OUT] = "aud_i2s_out", diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h index ec53c171c170..c6c78d684f3e 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-clk.h +++ b/sound/soc/mediatek/mt8188/mt8188-afe-clk.h @@ -54,7 +54,15 @@ enum { MT8188_CLK_AUD_ADC, MT8188_CLK_AUD_DAC_HIRES, MT8188_CLK_AUD_A1SYS_HP, + MT8188_CLK_AUD_AFE_DMIC1, + MT8188_CLK_AUD_AFE_DMIC2, + MT8188_CLK_AUD_AFE_DMIC3, + MT8188_CLK_AUD_AFE_DMIC4, MT8188_CLK_AUD_ADC_HIRES, + MT8188_CLK_AUD_DMIC_HIRES1, + MT8188_CLK_AUD_DMIC_HIRES2, + MT8188_CLK_AUD_DMIC_HIRES3, + MT8188_CLK_AUD_DMIC_HIRES4, MT8188_CLK_AUD_I2SIN, MT8188_CLK_AUD_TDM_IN, MT8188_CLK_AUD_I2S_OUT, diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-common.h b/sound/soc/mediatek/mt8188/mt8188-afe-common.h index 1304d685a306..01aa11242e29 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-common.h +++ b/sound/soc/mediatek/mt8188/mt8188-afe-common.h @@ -137,6 +137,7 @@ struct mt8188_afe_private { int mt8188_afe_fs_timing(unsigned int rate); /* dai register */ int mt8188_dai_adda_register(struct mtk_base_afe *afe); +int mt8188_dai_dmic_register(struct mtk_base_afe *afe); int mt8188_dai_etdm_register(struct mtk_base_afe *afe); int mt8188_dai_pcm_register(struct mtk_base_afe *afe); diff --git a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c index 73e5c63aeec8..ac4fdf8ba78f 100644 --- a/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c +++ b/sound/soc/mediatek/mt8188/mt8188-afe-pcm.c @@ -652,6 +652,7 @@ static struct snd_soc_dai_driver mt8188_memif_dai_driver[] = { static const struct snd_kcontrol_new o002_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN2, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I004 Switch", AFE_CONN2, 4, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I012 Switch", AFE_CONN2, 12, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I020 Switch", AFE_CONN2, 20, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I022 Switch", AFE_CONN2, 22, 1, 0), @@ -662,6 +663,8 @@ static const struct snd_kcontrol_new o002_mix[] = { static const struct snd_kcontrol_new o003_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN3, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I005 Switch", AFE_CONN3, 5, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I006 Switch", AFE_CONN3, 6, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I013 Switch", AFE_CONN3, 13, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I021 Switch", AFE_CONN3, 21, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I023 Switch", AFE_CONN3, 23, 1, 0), @@ -672,6 +675,8 @@ static const struct snd_kcontrol_new o003_mix[] = { static const struct snd_kcontrol_new o004_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN4, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I006 Switch", AFE_CONN4, 6, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I008 Switch", AFE_CONN4, 8, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I014 Switch", AFE_CONN4, 14, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I024 Switch", AFE_CONN4, 24, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I074 Switch", AFE_CONN4_2, 10, 1, 0), @@ -679,6 +684,8 @@ static const struct snd_kcontrol_new o004_mix[] = { static const struct snd_kcontrol_new o005_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN5, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I007 Switch", AFE_CONN5, 7, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I010 Switch", AFE_CONN5, 10, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I015 Switch", AFE_CONN5, 15, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I025 Switch", AFE_CONN5, 25, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I075 Switch", AFE_CONN5_2, 11, 1, 0), @@ -686,6 +693,7 @@ static const struct snd_kcontrol_new o005_mix[] = { static const struct snd_kcontrol_new o006_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I000 Switch", AFE_CONN6, 0, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I008 Switch", AFE_CONN6, 8, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I016 Switch", AFE_CONN6, 16, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I026 Switch", AFE_CONN6, 26, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I076 Switch", AFE_CONN6_2, 12, 1, 0), @@ -693,18 +701,21 @@ static const struct snd_kcontrol_new o006_mix[] = { static const struct snd_kcontrol_new o007_mix[] = { SOC_DAPM_SINGLE_AUTODISABLE("I001 Switch", AFE_CONN7, 1, 1, 0), + SOC_DAPM_SINGLE_AUTODISABLE("I009 Switch", AFE_CONN7, 9, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I017 Switch", AFE_CONN7, 17, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I027 Switch", AFE_CONN7, 27, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I077 Switch", AFE_CONN7_2, 13, 1, 0), }; static const struct snd_kcontrol_new o008_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I010 Switch", AFE_CONN8, 10, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I018 Switch", AFE_CONN8, 18, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I028 Switch", AFE_CONN8, 28, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I078 Switch", AFE_CONN8_2, 14, 1, 0), }; static const struct snd_kcontrol_new o009_mix[] = { + SOC_DAPM_SINGLE_AUTODISABLE("I011 Switch", AFE_CONN9, 11, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I019 Switch", AFE_CONN9, 19, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I029 Switch", AFE_CONN9, 29, 1, 0), SOC_DAPM_SINGLE_AUTODISABLE("I079 Switch", AFE_CONN9_2, 15, 1, 0), @@ -1275,6 +1286,18 @@ static const struct snd_soc_dapm_route mt8188_memif_routes[] = { {"O002", "I070 Switch", "I070"}, {"O003", "I071 Switch", "I071"}, + {"O002", "I004 Switch", "I004"}, + {"O003", "I005 Switch", "I005"}, + {"O003", "I006 Switch", "I006"}, + {"O004", "I006 Switch", "I006"}, + {"O004", "I008 Switch", "I008"}, + {"O005", "I007 Switch", "I007"}, + {"O005", "I010 Switch", "I010"}, + {"O006", "I008 Switch", "I008"}, + {"O007", "I009 Switch", "I009"}, + {"O008", "I010 Switch", "I010"}, + {"O009", "I011 Switch", "I011"}, + {"O034", "I000 Switch", "I000"}, {"O035", "I001 Switch", "I001"}, {"O034", "I002 Switch", "I002"}, @@ -2855,10 +2878,6 @@ static bool mt8188_is_volatile_reg(struct device *dev, unsigned int reg) case AFE_DMIC3_SRC_DEBUG_MON0: case AFE_DMIC3_UL_SRC_MON0: case AFE_DMIC3_UL_SRC_MON1: - case DMIC_GAIN1_CUR: - case DMIC_GAIN2_CUR: - case DMIC_GAIN3_CUR: - case DMIC_GAIN4_CUR: case ETDM_IN1_MONITOR: case ETDM_IN2_MONITOR: case ETDM_OUT1_MONITOR: @@ -3076,6 +3095,7 @@ static int mt8188_dai_memif_register(struct mtk_base_afe *afe) typedef int (*dai_register_cb)(struct mtk_base_afe *); static const dai_register_cb dai_register_cbs[] = { mt8188_dai_adda_register, + mt8188_dai_dmic_register, mt8188_dai_etdm_register, mt8188_dai_pcm_register, mt8188_dai_memif_register, @@ -3361,15 +3381,15 @@ static const struct of_device_id mt8188_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8188_afe_pcm_dt_match); static const struct dev_pm_ops mt8188_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8188_afe_runtime_suspend, - mt8188_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt8188_afe_runtime_suspend, + mt8188_afe_runtime_resume, NULL) }; static struct platform_driver mt8188_afe_pcm_driver = { .driver = { .name = "mt8188-audio", .of_match_table = mt8188_afe_pcm_dt_match, - .pm = &mt8188_afe_pm_ops, + .pm = pm_ptr(&mt8188_afe_pm_ops), }, .probe = mt8188_afe_pcm_dev_probe, }; diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c index c796ad8b62ee..40d2ab0a7677 100644 --- a/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clk.c @@ -84,6 +84,10 @@ static const struct afe_gate aud_clks[CLK_AUD_NR_CLK] = { GATE_AUD1(CLK_AUD_AFE_26M_DMIC_TM, "aud_afe_26m_dmic_tm", "top_a1sys_hp", 14), GATE_AUD1(CLK_AUD_UL_TML_HIRES, "aud_ul_tml_hires", "top_audio_h", 16), GATE_AUD1(CLK_AUD_ADC_HIRES, "aud_adc_hires", "top_audio_h", 17), + GATE_AUD1(CLK_AUD_DMIC_HIRES1, "aud_dmic_hires1", "top_audio_h", 20), + GATE_AUD1(CLK_AUD_DMIC_HIRES2, "aud_dmic_hires2", "top_audio_h", 21), + GATE_AUD1(CLK_AUD_DMIC_HIRES3, "aud_dmic_hires3", "top_audio_h", 22), + GATE_AUD1(CLK_AUD_DMIC_HIRES4, "aud_dmic_hires4", "top_audio_h", 23), /* AUD3 */ GATE_AUD3(CLK_AUD_LINEIN_TUNER, "aud_linein_tuner", "top_apll5", 5), diff --git a/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h index 6f34ffc760e0..9cb732863c10 100644 --- a/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h +++ b/sound/soc/mediatek/mt8188/mt8188-audsys-clkid.h @@ -33,6 +33,10 @@ enum{ CLK_AUD_AFE_26M_DMIC_TM, CLK_AUD_UL_TML_HIRES, CLK_AUD_ADC_HIRES, + CLK_AUD_DMIC_HIRES1, + CLK_AUD_DMIC_HIRES2, + CLK_AUD_DMIC_HIRES3, + CLK_AUD_DMIC_HIRES4, CLK_AUD_LINEIN_TUNER, CLK_AUD_EARC_TUNER, CLK_AUD_I2SIN, diff --git a/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c b/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c new file mode 100644 index 000000000000..adcea7818be2 --- /dev/null +++ b/sound/soc/mediatek/mt8188/mt8188-dai-dmic.c @@ -0,0 +1,683 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * MediaTek ALSA SoC Audio DAI DMIC I/F Control + * + * Copyright (c) 2020 MediaTek Inc. + * Author: Bicycle Tsai <bicycle.tsai@mediatek.com> + * Trevor Wu <trevor.wu@mediatek.com> + * Parker Yang <parker.yang@mediatek.com> + */ + +#include <linux/delay.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <sound/pcm_params.h> +#include "mt8188-afe-clk.h" +#include "mt8188-afe-common.h" +#include "mt8188-reg.h" + +/* DMIC HW Gain configuration maximum value. */ +#define DMIC_GAIN_MAX_STEP GENMASK(19, 0) +#define DMIC_GAIN_MAX_PER_STEP GENMASK(7, 0) +#define DMIC_GAIN_MAX_TARGET GENMASK(27, 0) +#define DMIC_GAIN_MAX_CURRENT GENMASK(27, 0) + +#define CLK_PHASE_SEL_CH1 0 +#define CLK_PHASE_SEL_CH2 ((CLK_PHASE_SEL_CH1) + 4) + +#define DMIC1_SRC_SEL 0 +#define DMIC2_SRC_SEL 0 +#define DMIC3_SRC_SEL 2 +#define DMIC4_SRC_SEL 0 +#define DMIC5_SRC_SEL 4 +#define DMIC6_SRC_SEL 0 +#define DMIC7_SRC_SEL 6 +#define DMIC8_SRC_SEL 0 + +enum { + SUPPLY_SEQ_DMIC_GAIN, + SUPPLY_SEQ_DMIC_CK, +}; + +enum { + DMIC0, + DMIC1, + DMIC2, + DMIC3, + DMIC_NUM, +}; + +struct mtk_dai_dmic_ctrl_reg { + unsigned int con0; +}; + +struct mtk_dai_dmic_hw_gain_ctrl_reg { + unsigned int bypass; + unsigned int con0; +}; + +struct mtk_dai_dmic_priv { + unsigned int gain_on[DMIC_NUM]; + unsigned int channels; + bool hires_required; +}; + +static const struct mtk_dai_dmic_ctrl_reg dmic_ctrl_regs[DMIC_NUM] = { + [DMIC0] = { + .con0 = AFE_DMIC0_UL_SRC_CON0, + }, + [DMIC1] = { + .con0 = AFE_DMIC1_UL_SRC_CON0, + }, + [DMIC2] = { + .con0 = AFE_DMIC2_UL_SRC_CON0, + }, + [DMIC3] = { + .con0 = AFE_DMIC3_UL_SRC_CON0, + }, +}; + +static const struct mtk_dai_dmic_ctrl_reg *get_dmic_ctrl_reg(int id) +{ + if (id < 0 || id >= DMIC_NUM) + return NULL; + + return &dmic_ctrl_regs[id]; +} + +static const struct mtk_dai_dmic_hw_gain_ctrl_reg + dmic_hw_gain_ctrl_regs[DMIC_NUM] = { + [DMIC0] = { + .bypass = DMIC_BYPASS_HW_GAIN, + .con0 = DMIC_GAIN1_CON0, + }, + [DMIC1] = { + .bypass = DMIC_BYPASS_HW_GAIN, + .con0 = DMIC_GAIN2_CON0, + }, + [DMIC2] = { + .bypass = DMIC_BYPASS_HW_GAIN, + .con0 = DMIC_GAIN3_CON0, + }, + [DMIC3] = { + .bypass = DMIC_BYPASS_HW_GAIN, + .con0 = DMIC_GAIN4_CON0, + }, +}; + +static const struct mtk_dai_dmic_hw_gain_ctrl_reg + *get_dmic_hw_gain_ctrl_reg(struct mtk_base_afe *afe, int id) +{ + if ((id < 0) || (id >= DMIC_NUM)) { + dev_dbg(afe->dev, "%s invalid id\n", __func__); + return NULL; + } + + return &dmic_hw_gain_ctrl_regs[id]; +} + +static void mtk_dai_dmic_hw_gain_bypass(struct mtk_base_afe *afe, + unsigned int id, bool bypass) +{ + const struct mtk_dai_dmic_hw_gain_ctrl_reg *reg; + unsigned int msk; + + reg = get_dmic_hw_gain_ctrl_reg(afe, id); + if (!reg) + return; + + switch (id) { + case DMIC0: + msk = DMIC_BYPASS_HW_GAIN_DMIC1_BYPASS; + break; + case DMIC1: + msk = DMIC_BYPASS_HW_GAIN_DMIC2_BYPASS; + break; + case DMIC2: + msk = DMIC_BYPASS_HW_GAIN_DMIC3_BYPASS; + break; + case DMIC3: + msk = DMIC_BYPASS_HW_GAIN_DMIC4_BYPASS; + break; + default: + return; + } + + if (bypass) + regmap_set_bits(afe->regmap, reg->bypass, msk); + else + regmap_clear_bits(afe->regmap, reg->bypass, msk); +} + +static void mtk_dai_dmic_hw_gain_on(struct mtk_base_afe *afe, unsigned int id, + bool on) +{ + const struct mtk_dai_dmic_hw_gain_ctrl_reg *reg = get_dmic_hw_gain_ctrl_reg(afe, id); + + if (!reg) + return; + + if (on) + regmap_set_bits(afe->regmap, reg->con0, DMIC_GAIN_CON0_GAIN_ON); + else + regmap_clear_bits(afe->regmap, reg->con0, DMIC_GAIN_CON0_GAIN_ON); +} + +static const struct reg_sequence mtk_dai_dmic_iir_coeff_reg_defaults[] = { + { AFE_DMIC0_IIR_COEF_02_01, 0x00000000 }, + { AFE_DMIC0_IIR_COEF_04_03, 0x00003FB8 }, + { AFE_DMIC0_IIR_COEF_06_05, 0x3FB80000 }, + { AFE_DMIC0_IIR_COEF_08_07, 0x3FB80000 }, + { AFE_DMIC0_IIR_COEF_10_09, 0x0000C048 }, + { AFE_DMIC1_IIR_COEF_02_01, 0x00000000 }, + { AFE_DMIC1_IIR_COEF_04_03, 0x00003FB8 }, + { AFE_DMIC1_IIR_COEF_06_05, 0x3FB80000 }, + { AFE_DMIC1_IIR_COEF_08_07, 0x3FB80000 }, + { AFE_DMIC1_IIR_COEF_10_09, 0x0000C048 }, + { AFE_DMIC2_IIR_COEF_02_01, 0x00000000 }, + { AFE_DMIC2_IIR_COEF_04_03, 0x00003FB8 }, + { AFE_DMIC2_IIR_COEF_06_05, 0x3FB80000 }, + { AFE_DMIC2_IIR_COEF_08_07, 0x3FB80000 }, + { AFE_DMIC2_IIR_COEF_10_09, 0x0000C048 }, + { AFE_DMIC3_IIR_COEF_02_01, 0x00000000 }, + { AFE_DMIC3_IIR_COEF_04_03, 0x00003FB8 }, + { AFE_DMIC3_IIR_COEF_06_05, 0x3FB80000 }, + { AFE_DMIC3_IIR_COEF_08_07, 0x3FB80000 }, + { AFE_DMIC3_IIR_COEF_10_09, 0x0000C048 }, +}; + +static int mtk_dai_dmic_load_iir_coeff_table(struct mtk_base_afe *afe) +{ + return regmap_multi_reg_write(afe->regmap, + mtk_dai_dmic_iir_coeff_reg_defaults, + ARRAY_SIZE(mtk_dai_dmic_iir_coeff_reg_defaults)); +} + +static int mtk_dai_dmic_configure_array(struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + const u32 mask = PWR2_TOP_CON_DMIC8_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC7_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC6_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC5_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC4_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC3_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC2_SRC_SEL_MASK | + PWR2_TOP_CON_DMIC1_SRC_SEL_MASK; + const u32 val = PWR2_TOP_CON_DMIC8_SRC_SEL_VAL(DMIC8_SRC_SEL) | + PWR2_TOP_CON_DMIC7_SRC_SEL_VAL(DMIC7_SRC_SEL) | + PWR2_TOP_CON_DMIC6_SRC_SEL_VAL(DMIC6_SRC_SEL) | + PWR2_TOP_CON_DMIC5_SRC_SEL_VAL(DMIC5_SRC_SEL) | + PWR2_TOP_CON_DMIC4_SRC_SEL_VAL(DMIC4_SRC_SEL) | + PWR2_TOP_CON_DMIC3_SRC_SEL_VAL(DMIC3_SRC_SEL) | + PWR2_TOP_CON_DMIC2_SRC_SEL_VAL(DMIC2_SRC_SEL) | + PWR2_TOP_CON_DMIC1_SRC_SEL_VAL(DMIC1_SRC_SEL); + + return regmap_update_bits(afe->regmap, PWR2_TOP_CON0, mask, val); +} + +/* This function assumes that the caller checked that channels is valid */ +static u8 mtk_dmic_channels_to_dmic_number(unsigned int channels) +{ + switch (channels) { + case 1: + return DMIC0; + case 2: + return DMIC1; + case 3: + return DMIC2; + case 4: + default: + return DMIC3; + } +} + +static void mtk_dai_dmic_hw_gain_enable(struct mtk_base_afe *afe, + unsigned int channels, bool enable) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN]; + u8 dmic_num; + int i; + + dmic_num = mtk_dmic_channels_to_dmic_number(channels); + for (i = dmic_num; i >= DMIC0; i--) { + if (enable && dmic_priv->gain_on[i]) { + mtk_dai_dmic_hw_gain_bypass(afe, i, false); + mtk_dai_dmic_hw_gain_on(afe, i, true); + } else { + mtk_dai_dmic_hw_gain_on(afe, i, false); + mtk_dai_dmic_hw_gain_bypass(afe, i, true); + } + } +} + +static int mtk_dmic_gain_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN]; + unsigned int channels = dmic_priv->channels; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + if (!channels) + return -EINVAL; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + mtk_dai_dmic_hw_gain_enable(afe, channels, true); + break; + case SND_SOC_DAPM_POST_PMD: + mtk_dai_dmic_hw_gain_enable(afe, channels, false); + break; + default: + break; + } + + return 0; +} + +static int mtk_dmic_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(cmpnt); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN]; + const struct mtk_dai_dmic_ctrl_reg *reg = NULL; + unsigned int channels = dmic_priv->channels; + unsigned int msk; + u8 dmic_num; + int i; + + dev_dbg(afe->dev, "%s(), name %s, event 0x%x\n", + __func__, w->name, event); + + if (!channels) + return -EINVAL; + + dmic_num = mtk_dmic_channels_to_dmic_number(channels); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + /* request fifo soft rst */ + msk = 0; + for (i = dmic_num; i >= DMIC0; i--) + msk |= PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(i); + + regmap_set_bits(afe->regmap, PWR2_TOP_CON1, msk); + + msk = AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL | + AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL | + AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL | + AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL; + + for (i = dmic_num; i >= DMIC0; i--) { + reg = get_dmic_ctrl_reg(i); + if (reg) + regmap_set_bits(afe->regmap, reg->con0, msk); + } + break; + case SND_SOC_DAPM_POST_PMU: + msk = AFE_DMIC_UL_SRC_CON0_UL_SRC_ON_TMP_CTL; + + for (i = dmic_num; i >= DMIC0; i--) { + reg = get_dmic_ctrl_reg(i); + if (reg) + regmap_set_bits(afe->regmap, reg->con0, msk); + } + + if (dmic_priv->hires_required) { + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES1]); + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES2]); + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES3]); + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES4]); + } + + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC1]); + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC2]); + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC3]); + mt8188_afe_enable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC4]); + + /* release fifo soft rst */ + msk = 0; + for (i = dmic_num; i >= DMIC0; i--) + msk |= PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(i); + + regmap_clear_bits(afe->regmap, PWR2_TOP_CON1, msk); + break; + case SND_SOC_DAPM_PRE_PMD: + msk = AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL | + AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL | + AFE_DMIC_UL_SRC_CON0_UL_SRC_ON_TMP_CTL | + AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL | + AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL; + + for (i = dmic_num; i >= DMIC0; i--) { + reg = get_dmic_ctrl_reg(i); + if (reg) + regmap_set_bits(afe->regmap, reg->con0, msk); + } + break; + case SND_SOC_DAPM_POST_PMD: + /* should delayed 1/fs(smallest is 8k) = 125us before afe off */ + usleep_range(125, 126); + + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC1]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC2]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC3]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_AFE_DMIC4]); + + if (dmic_priv->hires_required) { + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES1]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES2]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES3]); + mt8188_afe_disable_clk(afe, afe_priv->clk[MT8188_CLK_AUD_DMIC_HIRES4]); + } + break; + default: + break; + } + + return 0; +} + +static int mtk_dai_dmic_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct mtk_base_afe *afe = snd_soc_dai_get_drvdata(dai); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN]; + unsigned int rate = params_rate(params); + unsigned int channels = params_channels(params); + const struct mtk_dai_dmic_ctrl_reg *reg = NULL; + u32 val = AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_CH1(CLK_PHASE_SEL_CH1) | + AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_CH2(CLK_PHASE_SEL_CH2) | + AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL(0); + const u32 msk = AFE_DMIC_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL | + AFE_DMIC_UL_SRC_CON0_UL_PHASE_SEL_MASK | + AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL_MASK | + AFE_DMIC_UL_VOICE_MODE_MASK; + u8 dmic_num; + int ret; + int i; + + if (!channels || channels > 8) + return -EINVAL; + + ret = mtk_dai_dmic_configure_array(dai); + if (ret < 0) + return ret; + + ret = mtk_dai_dmic_load_iir_coeff_table(afe); + if (ret < 0) + return ret; + + switch (rate) { + case 96000: + val |= AFE_DMIC_UL_CON0_VOCIE_MODE_96K; + dmic_priv->hires_required = 1; + break; + case 48000: + val |= AFE_DMIC_UL_CON0_VOCIE_MODE_48K; + dmic_priv->hires_required = 0; + break; + case 32000: + val |= AFE_DMIC_UL_CON0_VOCIE_MODE_32K; + dmic_priv->hires_required = 0; + break; + case 16000: + val |= AFE_DMIC_UL_CON0_VOCIE_MODE_16K; + dmic_priv->hires_required = 0; + break; + case 8000: + val |= AFE_DMIC_UL_CON0_VOCIE_MODE_8K; + dmic_priv->hires_required = 0; + break; + default: + dev_dbg(afe->dev, "%s invalid rate %u, use 48000Hz\n", __func__, rate); + val |= AFE_DMIC_UL_CON0_VOCIE_MODE_48K; + dmic_priv->hires_required = 0; + break; + } + + dmic_num = mtk_dmic_channels_to_dmic_number(channels); + for (i = dmic_num; i >= DMIC0; i--) { + reg = get_dmic_ctrl_reg(i); + if (reg) { + ret = regmap_update_bits(afe->regmap, reg->con0, msk, val); + if (ret < 0) + return ret; + } + } + + dmic_priv->channels = channels; + + return 0; +} + +static const struct snd_soc_dai_ops mtk_dai_dmic_ops = { + .hw_params = mtk_dai_dmic_hw_params, +}; + +#define MTK_DMIC_RATES (SNDRV_PCM_RATE_8000 |\ + SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 |\ + SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_96000) + +#define MTK_DMIC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ + SNDRV_PCM_FMTBIT_S32_LE) + +static struct snd_soc_dai_driver mtk_dai_dmic_driver[] = { + { + .name = "DMIC", + .id = MT8188_AFE_IO_DMIC_IN, + .capture = { + .stream_name = "DMIC Capture", + .channels_min = 1, + .channels_max = 8, + .rates = MTK_DMIC_RATES, + .formats = MTK_DMIC_FORMATS, + }, + .ops = &mtk_dai_dmic_ops, + }, +}; + +static const struct snd_soc_dapm_widget mtk_dai_dmic_widgets[] = { + SND_SOC_DAPM_MIXER("I004", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I005", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I006", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I007", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I008", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I009", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I010", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_MIXER("I011", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY_S("DMIC_GAIN_ON", SUPPLY_SEQ_DMIC_GAIN, + SND_SOC_NOPM, 0, 0, + mtk_dmic_gain_event, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD), + SND_SOC_DAPM_SUPPLY_S("DMIC_CK_ON", SUPPLY_SEQ_DMIC_CK, + PWR2_TOP_CON1, + PWR2_TOP_CON1_DMIC_CKDIV_ON_SHIFT, 0, + mtk_dmic_event, + SND_SOC_DAPM_PRE_POST_PMU | + SND_SOC_DAPM_PRE_POST_PMD), + SND_SOC_DAPM_INPUT("DMIC_INPUT"), +}; + +static const struct snd_soc_dapm_route mtk_dai_dmic_routes[] = { + {"I004", NULL, "DMIC Capture"}, + {"I005", NULL, "DMIC Capture"}, + {"I006", NULL, "DMIC Capture"}, + {"I007", NULL, "DMIC Capture"}, + {"I008", NULL, "DMIC Capture"}, + {"I009", NULL, "DMIC Capture"}, + {"I010", NULL, "DMIC Capture"}, + {"I011", NULL, "DMIC Capture"}, + {"DMIC Capture", NULL, "DMIC_CK_ON"}, + {"DMIC Capture", NULL, "DMIC_GAIN_ON"}, + {"DMIC Capture", NULL, "DMIC_INPUT"}, +}; + +static const char * const mt8188_dmic_gain_enable_text[] = { + "Bypass", "Connect", +}; + +static SOC_ENUM_SINGLE_EXT_DECL(dmic_gain_on_enum, + mt8188_dmic_gain_enable_text); + +static int mtk_dai_dmic_hw_gain_ctrl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN]; + unsigned int source = ucontrol->value.enumerated.item[0]; + unsigned int *cached; + + if (source >= e->items) + return -EINVAL; + + if (!strcmp(kcontrol->id.name, "DMIC1_HW_GAIN_EN")) + cached = &dmic_priv->gain_on[0]; + else if (!strcmp(kcontrol->id.name, "DMIC2_HW_GAIN_EN")) + cached = &dmic_priv->gain_on[1]; + else if (!strcmp(kcontrol->id.name, "DMIC3_HW_GAIN_EN")) + cached = &dmic_priv->gain_on[2]; + else if (!strcmp(kcontrol->id.name, "DMIC4_HW_GAIN_EN")) + cached = &dmic_priv->gain_on[3]; + else + return -EINVAL; + + if (source == *cached) + return 0; + + *cached = source; + return 1; +} + +static int mtk_dai_dmic_hw_gain_ctrl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + struct mtk_base_afe *afe = snd_soc_component_get_drvdata(component); + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv = afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN]; + unsigned int val; + + if (!strcmp(kcontrol->id.name, "DMIC1_HW_GAIN_EN")) + val = dmic_priv->gain_on[0]; + else if (!strcmp(kcontrol->id.name, "DMIC2_HW_GAIN_EN")) + val = dmic_priv->gain_on[1]; + else if (!strcmp(kcontrol->id.name, "DMIC3_HW_GAIN_EN")) + val = dmic_priv->gain_on[2]; + else if (!strcmp(kcontrol->id.name, "DMIC4_HW_GAIN_EN")) + val = dmic_priv->gain_on[3]; + else + return -EINVAL; + + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static const struct snd_kcontrol_new mtk_dai_dmic_controls[] = { + SOC_ENUM_EXT("DMIC1_HW_GAIN_EN", dmic_gain_on_enum, + mtk_dai_dmic_hw_gain_ctrl_get, + mtk_dai_dmic_hw_gain_ctrl_put), + SOC_ENUM_EXT("DMIC2_HW_GAIN_EN", dmic_gain_on_enum, + mtk_dai_dmic_hw_gain_ctrl_get, + mtk_dai_dmic_hw_gain_ctrl_put), + SOC_ENUM_EXT("DMIC3_HW_GAIN_EN", dmic_gain_on_enum, + mtk_dai_dmic_hw_gain_ctrl_get, + mtk_dai_dmic_hw_gain_ctrl_put), + SOC_ENUM_EXT("DMIC4_HW_GAIN_EN", dmic_gain_on_enum, + mtk_dai_dmic_hw_gain_ctrl_get, + mtk_dai_dmic_hw_gain_ctrl_put), + SOC_SINGLE("DMIC1_HW_GAIN_TARGET", DMIC_GAIN1_CON1, + 0, DMIC_GAIN_MAX_TARGET, 0), + SOC_SINGLE("DMIC2_HW_GAIN_TARGET", DMIC_GAIN2_CON1, + 0, DMIC_GAIN_MAX_TARGET, 0), + SOC_SINGLE("DMIC3_HW_GAIN_TARGET", DMIC_GAIN3_CON1, + 0, DMIC_GAIN_MAX_TARGET, 0), + SOC_SINGLE("DMIC4_HW_GAIN_TARGET", DMIC_GAIN4_CON1, + 0, DMIC_GAIN_MAX_TARGET, 0), + SOC_SINGLE("DMIC1_HW_GAIN_CURRENT", DMIC_GAIN1_CUR, + 0, DMIC_GAIN_MAX_CURRENT, 0), + SOC_SINGLE("DMIC2_HW_GAIN_CURRENT", DMIC_GAIN2_CUR, + 0, DMIC_GAIN_MAX_CURRENT, 0), + SOC_SINGLE("DMIC3_HW_GAIN_CURRENT", DMIC_GAIN3_CUR, + 0, DMIC_GAIN_MAX_CURRENT, 0), + SOC_SINGLE("DMIC4_HW_GAIN_CURRENT", DMIC_GAIN4_CUR, + 0, DMIC_GAIN_MAX_CURRENT, 0), + SOC_SINGLE("DMIC1_HW_GAIN_UP_STEP", DMIC_GAIN1_CON3, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC2_HW_GAIN_UP_STEP", DMIC_GAIN2_CON3, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC3_HW_GAIN_UP_STEP", DMIC_GAIN3_CON3, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC4_HW_GAIN_UP_STEP", DMIC_GAIN4_CON3, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC1_HW_GAIN_DOWN_STEP", DMIC_GAIN1_CON2, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC2_HW_GAIN_DOWN_STEP", DMIC_GAIN2_CON2, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC3_HW_GAIN_DOWN_STEP", DMIC_GAIN3_CON2, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC4_HW_GAIN_DOWN_STEP", DMIC_GAIN4_CON2, + 0, DMIC_GAIN_MAX_STEP, 0), + SOC_SINGLE("DMIC1_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN1_CON0, + DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0), + SOC_SINGLE("DMIC2_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN2_CON0, + DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0), + SOC_SINGLE("DMIC3_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN3_CON0, + DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0), + SOC_SINGLE("DMIC4_HW_GAIN_SAMPLE_PER_STEP", DMIC_GAIN4_CON0, + DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT, DMIC_GAIN_MAX_PER_STEP, 0), +}; + +static int init_dmic_priv_data(struct mtk_base_afe *afe) +{ + struct mt8188_afe_private *afe_priv = afe->platform_priv; + struct mtk_dai_dmic_priv *dmic_priv; + + dmic_priv = devm_kzalloc(afe->dev, sizeof(struct mtk_dai_dmic_priv), + GFP_KERNEL); + if (!dmic_priv) + return -ENOMEM; + + afe_priv->dai_priv[MT8188_AFE_IO_DMIC_IN] = dmic_priv; + return 0; +} + +int mt8188_dai_dmic_register(struct mtk_base_afe *afe) +{ + struct mtk_base_afe_dai *dai; + + dai = devm_kzalloc(afe->dev, sizeof(*dai), GFP_KERNEL); + if (!dai) + return -ENOMEM; + + list_add(&dai->list, &afe->sub_dais); + + dai->dai_drivers = mtk_dai_dmic_driver; + dai->num_dai_drivers = ARRAY_SIZE(mtk_dai_dmic_driver); + dai->dapm_widgets = mtk_dai_dmic_widgets; + dai->num_dapm_widgets = ARRAY_SIZE(mtk_dai_dmic_widgets); + dai->dapm_routes = mtk_dai_dmic_routes; + dai->num_dapm_routes = ARRAY_SIZE(mtk_dai_dmic_routes); + dai->controls = mtk_dai_dmic_controls; + dai->num_controls = ARRAY_SIZE(mtk_dai_dmic_controls); + + return init_dmic_priv_data(afe); +} diff --git a/sound/soc/mediatek/mt8188/mt8188-mt6359.c b/sound/soc/mediatek/mt8188/mt8188-mt6359.c index 2d0d04e0232d..20dc9470ba76 100644 --- a/sound/soc/mediatek/mt8188/mt8188-mt6359.c +++ b/sound/soc/mediatek/mt8188/mt8188-mt6359.c @@ -17,6 +17,7 @@ #include "mt8188-afe-common.h" #include "../../codecs/nau8825.h" #include "../../codecs/mt6359.h" +#include "../../codecs/mt6359-accdet.h" #include "../../codecs/rt5682.h" #include "../common/mtk-afe-platform-driver.h" #include "../common/mtk-soundcard-driver.h" @@ -150,6 +151,11 @@ SND_SOC_DAILINK_DEFS(dl_src, "mt6359-snd-codec-aif1")), DAILINK_COMP_ARRAY(COMP_EMPTY())); +SND_SOC_DAILINK_DEFS(DMIC_BE, + DAILINK_COMP_ARRAY(COMP_CPU("DMIC")), + DAILINK_COMP_ARRAY(COMP_DUMMY()), + DAILINK_COMP_ARRAY(COMP_EMPTY())); + SND_SOC_DAILINK_DEFS(dptx, DAILINK_COMP_ARRAY(COMP_CPU("DPTX")), DAILINK_COMP_ARRAY(COMP_DUMMY()), @@ -266,6 +272,17 @@ static struct snd_soc_jack_pin nau8825_jack_pins[] = { }, }; +static struct snd_soc_jack_pin mt8188_headset_jack_pins[] = { + { + .pin = "Headphone", + .mask = SND_JACK_HEADPHONE, + }, + { + .pin = "Headset Mic", + .mask = SND_JACK_MICROPHONE, + }, +}; + static const struct snd_kcontrol_new mt8188_dumb_spk_controls[] = { SOC_DAPM_PIN_SWITCH("Ext Spk"), }; @@ -297,6 +314,7 @@ static const struct snd_soc_dapm_widget mt8188_rear_spk_widgets[] = { static const struct snd_soc_dapm_widget mt8188_mt6359_widgets[] = { SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("AP DMIC", NULL), SND_SOC_DAPM_SINK("HDMI"), SND_SOC_DAPM_SINK("DP"), SND_SOC_DAPM_MIXER(SOF_DMA_DL2, SND_SOC_NOPM, 0, 0, NULL, 0), @@ -500,6 +518,35 @@ static int mt8188_mt6359_mtkaif_calibration(struct snd_soc_pcm_runtime *rtd) return 0; } +static int mt8188_mt6359_accdet_init(struct snd_soc_pcm_runtime *rtd) +{ + struct mtk_soc_card_data *soc_card_data = snd_soc_card_get_drvdata(rtd->card); + struct snd_soc_jack *jack = &soc_card_data->card_data->jacks[MT8188_JACK_HEADSET]; + int ret; + + if (!soc_card_data->accdet) + return 0; + + ret = snd_soc_card_jack_new_pins(rtd->card, "Headset Jack", + SND_JACK_HEADSET | SND_JACK_BTN_0 | + SND_JACK_BTN_1 | SND_JACK_BTN_2 | + SND_JACK_BTN_3, + jack, mt8188_headset_jack_pins, + ARRAY_SIZE(mt8188_headset_jack_pins)); + if (ret) { + dev_err(rtd->dev, "Headset Jack create failed: %d\n", ret); + return ret; + } + + ret = mt6359_accdet_enable_jack_detect(soc_card_data->accdet, jack); + if (ret) { + dev_err(rtd->dev, "Headset Jack enable failed: %d\n", ret); + return ret; + } + + return 0; +} + static int mt8188_mt6359_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_component *cmpnt_codec = @@ -512,6 +559,8 @@ static int mt8188_mt6359_init(struct snd_soc_pcm_runtime *rtd) /* mtkaif calibration */ mt8188_mt6359_mtkaif_calibration(rtd); + mt8188_mt6359_accdet_init(rtd); + return 0; } @@ -533,6 +582,7 @@ enum { DAI_LINK_UL9_FE, DAI_LINK_UL10_FE, DAI_LINK_DL_SRC_BE, + DAI_LINK_DMIC_BE, DAI_LINK_DPTX_BE, DAI_LINK_ETDM1_IN_BE, DAI_LINK_ETDM2_IN_BE, @@ -1120,6 +1170,13 @@ static struct snd_soc_dai_link mt8188_mt6359_dai_links[] = { .playback_only = 1, SND_SOC_DAILINK_REG(dl_src), }, + [DAI_LINK_DMIC_BE] = { + .name = "DMIC_BE", + .no_pcm = 1, + .capture_only = 1, + .ignore_suspend = 1, + SND_SOC_DAILINK_REG(DMIC_BE), + }, [DAI_LINK_DPTX_BE] = { .name = "DPTX_BE", .ops = &mt8188_dptx_ops, diff --git a/sound/soc/mediatek/mt8188/mt8188-reg.h b/sound/soc/mediatek/mt8188/mt8188-reg.h index bdd885419ff3..2e9c65de249d 100644 --- a/sound/soc/mediatek/mt8188/mt8188-reg.h +++ b/sound/soc/mediatek/mt8188/mt8188-reg.h @@ -2837,9 +2837,20 @@ #define PWR2_TOP_CON_DMIC3_SRC_SEL_MASK GENMASK(16, 14) #define PWR2_TOP_CON_DMIC2_SRC_SEL_MASK GENMASK(13, 11) #define PWR2_TOP_CON_DMIC1_SRC_SEL_MASK GENMASK(10, 8) +#define PWR2_TOP_CON_DMIC8_SRC_SEL_VAL(x) ((x) << 29) +#define PWR2_TOP_CON_DMIC7_SRC_SEL_VAL(x) ((x) << 26) +#define PWR2_TOP_CON_DMIC6_SRC_SEL_VAL(x) ((x) << 23) +#define PWR2_TOP_CON_DMIC5_SRC_SEL_VAL(x) ((x) << 20) +#define PWR2_TOP_CON_DMIC4_SRC_SEL_VAL(x) ((x) << 17) +#define PWR2_TOP_CON_DMIC3_SRC_SEL_VAL(x) ((x) << 14) +#define PWR2_TOP_CON_DMIC2_SRC_SEL_VAL(x) ((x) << 11) +#define PWR2_TOP_CON_DMIC1_SRC_SEL_VAL(x) ((x) << 8) /* PWR2_TOP_CON1 */ -#define PWR2_TOP_CON1_DMIC_CKDIV_ON BIT(1) +#define PWR2_TOP_CON1_DMIC_FIFO_SOFT_RST_EN(x) BIT(5 + 6 * (x)) +#define PWR2_TOP_CON1_DMIC_CKDIV_ON BIT(1) +#define PWR2_TOP_CON1_DMIC_CKDIV_ON_SHIFT 1 + /* PCM_INTF_CON1 */ #define PCM_INTF_CON1_SYNC_OUT_INV BIT(23) @@ -2921,13 +2932,14 @@ #define AFE_DMIC_UL_SRC_CON0_UL_TWO_WIRE_MODE_CTL BIT(23) #define AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH2_CTL BIT(22) #define AFE_DMIC_UL_SRC_CON0_UL_MODE_3P25M_CH1_CTL BIT(21) - +#define AFE_DMIC_UL_VOICE_MODE(x) (((x) & GENMASK(2, 0)) << 17) #define AFE_DMIC_UL_VOICE_MODE_MASK GENMASK(19, 17) #define AFE_DMIC_UL_CON0_VOCIE_MODE_8K AFE_DMIC_UL_VOICE_MODE(0) #define AFE_DMIC_UL_CON0_VOCIE_MODE_16K AFE_DMIC_UL_VOICE_MODE(1) #define AFE_DMIC_UL_CON0_VOCIE_MODE_32K AFE_DMIC_UL_VOICE_MODE(2) #define AFE_DMIC_UL_CON0_VOCIE_MODE_48K AFE_DMIC_UL_VOICE_MODE(3) #define AFE_DMIC_UL_CON0_VOCIE_MODE_96K AFE_DMIC_UL_VOICE_MODE(4) +#define AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL(x) (((x) & GENMASK(2, 0)) << 7) #define AFE_DMIC_UL_SRC_CON0_UL_IIR_MODE_CTL_MASK GENMASK(9, 7) #define AFE_DMIC_UL_SRC_CON0_UL_IIR_ON_TMP_CTL BIT(10) #define AFE_DMIC_UL_SRC_CON0_UL_SDM_3_LEVEL_CTL BIT(1) @@ -2944,6 +2956,7 @@ /* DMIC_GAINx_CON0 */ #define DMIC_GAIN_CON0_GAIN_ON BIT(0) +#define DMIC_GAIN_CON0_SAMPLE_PER_STEP_SHIFT 8 #define DMIC_GAIN_CON0_SAMPLE_PER_STEP_MASK GENMASK(15, 8) /* DMIC_GAINx_CON1 */ diff --git a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c index 80cda7bf5ccc..fd6af74d7995 100644 --- a/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c +++ b/sound/soc/mediatek/mt8192/mt8192-afe-pcm.c @@ -2313,15 +2313,15 @@ static const struct of_device_id mt8192_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8192_afe_pcm_dt_match); static const struct dev_pm_ops mt8192_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8192_afe_runtime_suspend, - mt8192_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt8192_afe_runtime_suspend, + mt8192_afe_runtime_resume, NULL) }; static struct platform_driver mt8192_afe_pcm_driver = { .driver = { .name = "mt8192-audio", .of_match_table = mt8192_afe_pcm_dt_match, - .pm = &mt8192_afe_pm_ops, + .pm = pm_ptr(&mt8192_afe_pm_ops), }, .probe = mt8192_afe_pcm_dev_probe, .remove = mt8192_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c index b1598cc5587e..bf483a8fb34a 100644 --- a/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c +++ b/sound/soc/mediatek/mt8192/mt8192-mt6359-rt1015-rt5682.c @@ -920,7 +920,7 @@ static struct snd_soc_dai_link mt8192_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .playback_only = 1, .ignore_suspend = 1, .be_hw_params_fixup = mt8192_i2s_hw_params_fixup, diff --git a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c index 8016bfb35015..5d025ad72263 100644 --- a/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c +++ b/sound/soc/mediatek/mt8195/mt8195-afe-pcm.c @@ -3188,15 +3188,15 @@ static const struct of_device_id mt8195_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8195_afe_pcm_dt_match); static const struct dev_pm_ops mt8195_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8195_afe_runtime_suspend, - mt8195_afe_runtime_resume, NULL) + RUNTIME_PM_OPS(mt8195_afe_runtime_suspend, + mt8195_afe_runtime_resume, NULL) }; static struct platform_driver mt8195_afe_pcm_driver = { .driver = { .name = "mt8195-audio", .of_match_table = mt8195_afe_pcm_dt_match, - .pm = &mt8195_afe_pm_ops, + .pm = pm_ptr(&mt8195_afe_pm_ops), }, .probe = mt8195_afe_pcm_dev_probe, .remove = mt8195_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8195/mt8195-mt6359.c b/sound/soc/mediatek/mt8195/mt8195-mt6359.c index 2b9cb3248795..df29a9fa5aee 100644 --- a/sound/soc/mediatek/mt8195/mt8195-mt6359.c +++ b/sound/soc/mediatek/mt8195/mt8195-mt6359.c @@ -1114,7 +1114,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .capture_only = 1, SND_SOC_DAILINK_REG(ETDM1_IN_BE), }, @@ -1123,7 +1123,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .capture_only = 1, .be_hw_params_fixup = mt8195_etdm_hw_params_fixup, SND_SOC_DAILINK_REG(ETDM2_IN_BE), @@ -1133,7 +1133,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .playback_only = 1, .be_hw_params_fixup = mt8195_etdm_hw_params_fixup, SND_SOC_DAILINK_REG(ETDM1_OUT_BE), @@ -1143,7 +1143,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .playback_only = 1, SND_SOC_DAILINK_REG(ETDM2_OUT_BE), }, @@ -1152,7 +1152,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .playback_only = 1, SND_SOC_DAILINK_REG(ETDM3_OUT_BE), }, @@ -1161,7 +1161,7 @@ static struct snd_soc_dai_link mt8195_mt6359_dai_links[] = { .no_pcm = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(PCM1_BE), }, [DAI_LINK_UL_SRC1_BE] = { diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c index 8a0af2ea8546..7078c01ba19b 100644 --- a/sound/soc/mediatek/mt8365/mt8365-afe-clk.c +++ b/sound/soc/mediatek/mt8365/mt8365-afe-clk.c @@ -49,8 +49,7 @@ int mt8365_afe_init_audio_clk(struct mtk_base_afe *afe) void mt8365_afe_disable_clk(struct mtk_base_afe *afe, struct clk *clk) { - if (clk) - clk_disable_unprepare(clk); + clk_disable_unprepare(clk); } int mt8365_afe_set_clk_rate(struct mtk_base_afe *afe, struct clk *clk, diff --git a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c index 743b46572144..10793bbe9275 100644 --- a/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c +++ b/sound/soc/mediatek/mt8365/mt8365-afe-pcm.c @@ -1957,7 +1957,7 @@ err_irq: return IRQ_HANDLED; } -static int __maybe_unused mt8365_afe_runtime_suspend(struct device *dev) +static int mt8365_afe_runtime_suspend(struct device *dev) { return 0; } @@ -1967,7 +1967,7 @@ static int mt8365_afe_runtime_resume(struct device *dev) return 0; } -static int __maybe_unused mt8365_afe_suspend(struct device *dev) +static int mt8365_afe_suspend(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); struct regmap *regmap = afe->regmap; @@ -1989,7 +1989,7 @@ static int __maybe_unused mt8365_afe_suspend(struct device *dev) return 0; } -static int __maybe_unused mt8365_afe_resume(struct device *dev) +static int mt8365_afe_resume(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); struct regmap *regmap = afe->regmap; @@ -2009,7 +2009,7 @@ static int __maybe_unused mt8365_afe_resume(struct device *dev) return 0; } -static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev) +static int mt8365_afe_dev_runtime_suspend(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); @@ -2021,7 +2021,7 @@ static int __maybe_unused mt8365_afe_dev_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused mt8365_afe_dev_runtime_resume(struct device *dev) +static int mt8365_afe_dev_runtime_resume(struct device *dev) { struct mtk_base_afe *afe = dev_get_drvdata(dev); @@ -2250,17 +2250,16 @@ static const struct of_device_id mt8365_afe_pcm_dt_match[] = { MODULE_DEVICE_TABLE(of, mt8365_afe_pcm_dt_match); static const struct dev_pm_ops mt8365_afe_pm_ops = { - SET_RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend, - mt8365_afe_dev_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend, - mt8365_afe_resume) + RUNTIME_PM_OPS(mt8365_afe_dev_runtime_suspend, + mt8365_afe_dev_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(mt8365_afe_suspend, mt8365_afe_resume) }; static struct platform_driver mt8365_afe_pcm_driver = { .driver = { .name = "mt8365-afe-pcm", .of_match_table = mt8365_afe_pcm_dt_match, - .pm = &mt8365_afe_pm_ops, + .pm = pm_ptr(&mt8365_afe_pm_ops), }, .probe = mt8365_afe_pcm_dev_probe, .remove = mt8365_afe_pcm_dev_remove, diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c index 11b9a5bc7163..cae51756cead 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-i2s.c @@ -313,7 +313,7 @@ static int mt8365_dai_set_config(struct mtk_base_afe *afe, } if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBM_CFM) { + SND_SOC_DAIFMT_CBP_CFP) { val |= AFE_I2S_CON_SRC_SLAVE; val &= ~(u32)AFE_I2S_CON_FROM_IO_MUX;//from consys } @@ -523,7 +523,7 @@ static int mt8365_dai_i2s_startup(struct snd_pcm_substream *substream, bool i2s_in_slave = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) && ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBM_CFM); + SND_SOC_DAIFMT_CBP_CFP); mt8365_afe_enable_main_clk(afe); @@ -551,7 +551,7 @@ static void mt8365_dai_i2s_shutdown(struct snd_pcm_substream *substream, bool i2s_in_slave = (substream->stream == SNDRV_PCM_STREAM_CAPTURE) && ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) == - SND_SOC_DAIFMT_CBM_CFM); + SND_SOC_DAIFMT_CBP_CFP); if (be->prepared[substream->stream]) { if (reset_i2s_out_change) @@ -613,7 +613,7 @@ static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream, if (apply_i2s_in_change) { if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) - == SND_SOC_DAIFMT_CBM_CFM) { + == SND_SOC_DAIFMT_CBP_CFP) { ret = mt8365_afe_set_2nd_i2s_asrc(afe, 32000, rate, (unsigned int)bit_width, 0, 0, 1); @@ -659,7 +659,7 @@ static int mt8365_dai_i2s_prepare(struct snd_pcm_substream *substream, mt8365_dai_set_enable(afe, i2s_data, true, true); if ((be->fmt_mode & SND_SOC_DAIFMT_MASTER_MASK) - == SND_SOC_DAIFMT_CBM_CFM) + == SND_SOC_DAIFMT_CBP_CFP) mt8365_afe_set_2nd_i2s_asrc_enable(afe, true); be->prepared[SNDRV_PCM_STREAM_CAPTURE] = true; @@ -712,7 +712,7 @@ static int mt8365_afe_2nd_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) be->fmt_mode |= (fmt & SND_SOC_DAIFMT_INV_MASK); - if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)) + if (((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBP_CFP)) be->fmt_mode |= (fmt & SND_SOC_DAIFMT_MASTER_MASK); return 0; diff --git a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c index 3373b88da28e..0ec114a566ad 100644 --- a/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c +++ b/sound/soc/mediatek/mt8365/mt8365-dai-pcm.c @@ -189,10 +189,10 @@ static int mt8365_dai_pcm1_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: pcm_priv->slave_mode = true; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: pcm_priv->slave_mode = false; break; default: diff --git a/sound/soc/mediatek/mt8365/mt8365-mt6357.c b/sound/soc/mediatek/mt8365/mt8365-mt6357.c index 9f28d6bf0323..a998fba82bfe 100644 --- a/sound/soc/mediatek/mt8365/mt8365-mt6357.c +++ b/sound/soc/mediatek/mt8365/mt8365-mt6357.c @@ -225,7 +225,7 @@ static struct snd_soc_dai_link mt8365_mt6357_dais[] = { .id = DAI_LINK_2ND_I2S_INTF, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(i2s3), }, [DAI_LINK_DMIC] = { diff --git a/sound/soc/meson/axg-tdm-interface.c b/sound/soc/meson/axg-tdm-interface.c index 09103eef2a97..421b5d719fb3 100644 --- a/sound/soc/meson/axg-tdm-interface.c +++ b/sound/soc/meson/axg-tdm-interface.c @@ -529,7 +529,6 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct snd_soc_dai_driver *dai_drv; struct axg_tdm_iface *iface; - int i; iface = devm_kzalloc(dev, sizeof(*iface), GFP_KERNEL); if (!iface) @@ -541,15 +540,11 @@ static int axg_tdm_iface_probe(struct platform_device *pdev) * We'll change the number of channel provided by DAI stream, so dpcm * channel merge can be done properly */ - dai_drv = devm_kcalloc(dev, ARRAY_SIZE(axg_tdm_iface_dai_drv), - sizeof(*dai_drv), GFP_KERNEL); + dai_drv = devm_kmemdup_array(dev, axg_tdm_iface_dai_drv, ARRAY_SIZE(axg_tdm_iface_dai_drv), + sizeof(axg_tdm_iface_dai_drv[0]), GFP_KERNEL); if (!dai_drv) return -ENOMEM; - for (i = 0; i < ARRAY_SIZE(axg_tdm_iface_dai_drv); i++) - memcpy(&dai_drv[i], &axg_tdm_iface_dai_drv[i], - sizeof(*dai_drv)); - /* Bit clock provided on the pad */ iface->sclk = devm_clk_get(dev, "sclk"); if (IS_ERR(iface->sclk)) diff --git a/sound/soc/meson/meson-card-utils.c b/sound/soc/meson/meson-card-utils.c index 1a4ef124e4e2..cfc7f6e41ab5 100644 --- a/sound/soc/meson/meson-card-utils.c +++ b/sound/soc/meson/meson-card-utils.c @@ -119,10 +119,10 @@ unsigned int meson_card_parse_daifmt(struct device_node *node, /* If no master is provided, default to cpu master */ if (!bitclkmaster || bitclkmaster == cpu_node) { daifmt |= (!framemaster || framemaster == cpu_node) ? - SND_SOC_DAIFMT_CBS_CFS : SND_SOC_DAIFMT_CBS_CFM; + SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBC_CFP; } else { daifmt |= (!framemaster || framemaster == cpu_node) ? - SND_SOC_DAIFMT_CBM_CFS : SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFC : SND_SOC_DAIFMT_CBP_CFP; } of_node_put(bitclkmaster); diff --git a/sound/soc/meson/t9015.c b/sound/soc/meson/t9015.c index 571f65788c59..a80e9c9d6288 100644 --- a/sound/soc/meson/t9015.c +++ b/sound/soc/meson/t9015.c @@ -57,11 +57,11 @@ static int t9015_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) unsigned int val; switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: + case SND_SOC_DAIFMT_CBP_CFP: val = I2S_MODE; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: val = 0; break; diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c index a41a13ae38a5..245f17411638 100644 --- a/sound/soc/mxs/mxs-sgtl5000.c +++ b/sound/soc/mxs/mxs-sgtl5000.c @@ -59,7 +59,7 @@ static const struct snd_soc_ops mxs_sgtl5000_hifi_ops = { }; #define MXS_SGTL5000_DAI_FMT (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | \ - SND_SOC_DAIFMT_CBS_CFS) + SND_SOC_DAIFMT_CBC_CFC) SND_SOC_DAILINK_DEFS(hifi_tx, diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c index 8caa1aa99bdc..6ca0a6bcd34c 100644 --- a/sound/soc/pxa/spitz.c +++ b/sound/soc/pxa/spitz.c @@ -260,7 +260,7 @@ static struct snd_soc_dai_link spitz_dai = { .name = "wm8750", .stream_name = "WM8750", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &spitz_ops, SND_SOC_DAILINK_REG(wm8750), }; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index fbead6af3d95..7c6a9b0fda89 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -160,14 +160,14 @@ static int sc7180_lpass_exit(struct platform_device *pdev) return 0; } -static int __maybe_unused sc7180_lpass_dev_resume(struct device *dev) +static int sc7180_lpass_dev_resume(struct device *dev) { struct lpass_data *drvdata = dev_get_drvdata(dev); return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); } -static int __maybe_unused sc7180_lpass_dev_suspend(struct device *dev) +static int sc7180_lpass_dev_suspend(struct device *dev) { struct lpass_data *drvdata = dev_get_drvdata(dev); @@ -176,7 +176,7 @@ static int __maybe_unused sc7180_lpass_dev_suspend(struct device *dev) } static const struct dev_pm_ops sc7180_lpass_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(sc7180_lpass_dev_suspend, sc7180_lpass_dev_resume) + SYSTEM_SLEEP_PM_OPS(sc7180_lpass_dev_suspend, sc7180_lpass_dev_resume) }; static const struct lpass_variant sc7180_data = { @@ -312,7 +312,7 @@ static struct platform_driver sc7180_lpass_cpu_platform_driver = { .driver = { .name = "sc7180-lpass-cpu", .of_match_table = of_match_ptr(sc7180_lpass_cpu_device_id), - .pm = &sc7180_lpass_pm_ops, + .pm = pm_ptr(&sc7180_lpass_pm_ops), }, .probe = asoc_qcom_lpass_cpu_platform_probe, .remove = asoc_qcom_lpass_cpu_platform_remove, diff --git a/sound/soc/qcom/lpass-sc7280.c b/sound/soc/qcom/lpass-sc7280.c index 7cd3e291382a..817c824f9179 100644 --- a/sound/soc/qcom/lpass-sc7280.c +++ b/sound/soc/qcom/lpass-sc7280.c @@ -233,14 +233,14 @@ static int sc7280_lpass_exit(struct platform_device *pdev) return 0; } -static int __maybe_unused sc7280_lpass_dev_resume(struct device *dev) +static int sc7280_lpass_dev_resume(struct device *dev) { struct lpass_data *drvdata = dev_get_drvdata(dev); return clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clks); } -static int __maybe_unused sc7280_lpass_dev_suspend(struct device *dev) +static int sc7280_lpass_dev_suspend(struct device *dev) { struct lpass_data *drvdata = dev_get_drvdata(dev); @@ -249,7 +249,7 @@ static int __maybe_unused sc7280_lpass_dev_suspend(struct device *dev) } static const struct dev_pm_ops sc7280_lpass_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(sc7280_lpass_dev_suspend, sc7280_lpass_dev_resume) + SYSTEM_SLEEP_PM_OPS(sc7280_lpass_dev_suspend, sc7280_lpass_dev_resume) }; static const struct lpass_variant sc7280_data = { @@ -442,7 +442,7 @@ static struct platform_driver sc7280_lpass_cpu_platform_driver = { .driver = { .name = "sc7280-lpass-cpu", .of_match_table = of_match_ptr(sc7280_lpass_cpu_device_id), - .pm = &sc7280_lpass_pm_ops, + .pm = pm_ptr(&sc7280_lpass_pm_ops), }, .probe = asoc_qcom_lpass_cpu_platform_probe, .remove = asoc_qcom_lpass_cpu_platform_remove, diff --git a/sound/soc/qcom/qdsp6/q6apm.c b/sound/soc/qcom/qdsp6/q6apm.c index 2a2a5bd98110..11e252a70f69 100644 --- a/sound/soc/qcom/qdsp6/q6apm.c +++ b/sound/soc/qcom/qdsp6/q6apm.c @@ -230,7 +230,7 @@ int q6apm_map_memory_regions(struct q6apm_graph *graph, unsigned int dir, phys_a return 0; } - buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_KERNEL); + buf = kcalloc(periods, sizeof(struct audio_buffer), GFP_KERNEL); if (!buf) { mutex_unlock(&graph->lock); return -ENOMEM; diff --git a/sound/soc/qcom/sc7180.c b/sound/soc/qcom/sc7180.c index d95710b1ea4e..84b6ac5d2a20 100644 --- a/sound/soc/qcom/sc7180.c +++ b/sound/soc/qcom/sc7180.c @@ -397,7 +397,7 @@ static int sc7180_adau7002_snd_startup(struct snd_pcm_substream *substream) switch (cpu_dai->id) { case MI2S_PRIMARY: snd_soc_dai_set_fmt(codec_dai, - SND_SOC_DAIFMT_CBS_CFS | + SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_I2S); runtime->hw.formats = SNDRV_PCM_FMTBIT_S32_LE; diff --git a/sound/soc/qcom/sc7280.c b/sound/soc/qcom/sc7280.c index 230af8d7b205..af412bd0c89f 100644 --- a/sound/soc/qcom/sc7280.c +++ b/sound/soc/qcom/sc7280.c @@ -342,8 +342,8 @@ static void sc7280_snd_shutdown(struct snd_pcm_substream *substream) static int sc7280_snd_startup(struct snd_pcm_substream *substream) { - unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS; - unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBS_CFS; + unsigned int fmt = SND_SOC_DAIFMT_CBC_CFC; + unsigned int codec_dai_fmt = SND_SOC_DAIFMT_CBC_CFC; struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0); diff --git a/sound/soc/qcom/sdw.c b/sound/soc/qcom/sdw.c index f2eda2ff46c0..1d01b9329e08 100644 --- a/sound/soc/qcom/sdw.c +++ b/sound/soc/qcom/sdw.c @@ -23,9 +23,11 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream) { struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0); + u32 rx_ch[SDW_MAX_PORTS], tx_ch[SDW_MAX_PORTS]; struct sdw_stream_runtime *sruntime; struct snd_soc_dai *codec_dai; - int ret, i; + u32 rx_ch_cnt = 0, tx_ch_cnt = 0; + int ret, i, j; sruntime = sdw_alloc_stream(cpu_dai->name); if (!sruntime) @@ -35,9 +37,35 @@ int qcom_snd_sdw_startup(struct snd_pcm_substream *substream) ret = snd_soc_dai_set_stream(codec_dai, sruntime, substream->stream); if (ret < 0 && ret != -ENOTSUPP) { - dev_err(rtd->dev, "Failed to set sdw stream on %s\n", - codec_dai->name); + dev_err(rtd->dev, "Failed to set sdw stream on %s\n", codec_dai->name); goto err_set_stream; + } else if (ret == -ENOTSUPP) { + /* Ignore unsupported */ + continue; + } + + ret = snd_soc_dai_get_channel_map(codec_dai, &tx_ch_cnt, tx_ch, + &rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) { + dev_err(rtd->dev, "Failed to get codec chan map %s\n", codec_dai->name); + goto err_set_stream; + } else if (ret == -ENOTSUPP) { + /* Ignore unsupported */ + continue; + } + } + + switch (cpu_dai->id) { + case RX_CODEC_DMA_RX_0: + case TX_CODEC_DMA_TX_3: + if (tx_ch_cnt || rx_ch_cnt) { + for_each_rtd_codec_dais(rtd, j, codec_dai) { + ret = snd_soc_dai_set_channel_map(codec_dai, + tx_ch_cnt, tx_ch, + rx_ch_cnt, rx_ch); + if (ret != 0 && ret != -ENOTSUPP) + goto err_set_stream; + } } } diff --git a/sound/soc/qcom/sm8250.c b/sound/soc/qcom/sm8250.c index 45e0c33fc3f3..9039107972e2 100644 --- a/sound/soc/qcom/sm8250.c +++ b/sound/soc/qcom/sm8250.c @@ -7,6 +7,7 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/pcm.h> +#include <sound/pcm_params.h> #include <linux/soundwire/sdw.h> #include <sound/jack.h> #include <linux/input-event-codes.h> @@ -39,9 +40,11 @@ static int sm8250_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, SNDRV_PCM_HW_PARAM_RATE); struct snd_interval *channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); rate->min = rate->max = 48000; channels->min = channels->max = 2; + snd_mask_set_format(fmt, SNDRV_PCM_FORMAT_S16_LE); return 0; } diff --git a/sound/soc/renesas/migor.c b/sound/soc/renesas/migor.c index 5a0bc6edac0a..45fc594d331b 100644 --- a/sound/soc/renesas/migor.c +++ b/sound/soc/renesas/migor.c @@ -132,7 +132,7 @@ static struct snd_soc_dai_link migor_dai = { .name = "wm8978", .stream_name = "WM8978", .dai_fmt = SND_SOC_DAIFMT_NB_IF | SND_SOC_DAIFMT_I2S | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &migor_dai_ops, SND_SOC_DAILINK_REG(wm8978), }; diff --git a/sound/soc/renesas/rcar/core.c b/sound/soc/renesas/rcar/core.c index f3f0c3f0bb9f..30afc942d381 100644 --- a/sound/soc/renesas/rcar/core.c +++ b/sound/soc/renesas/rcar/core.c @@ -2059,7 +2059,7 @@ static void rsnd_remove(struct platform_device *pdev) remove_func[i](priv); } -static int __maybe_unused rsnd_suspend(struct device *dev) +static int rsnd_suspend(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); @@ -2068,7 +2068,7 @@ static int __maybe_unused rsnd_suspend(struct device *dev) return 0; } -static int __maybe_unused rsnd_resume(struct device *dev) +static int rsnd_resume(struct device *dev) { struct rsnd_priv *priv = dev_get_drvdata(dev); @@ -2076,13 +2076,13 @@ static int __maybe_unused rsnd_resume(struct device *dev) } static const struct dev_pm_ops rsnd_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume) + SYSTEM_SLEEP_PM_OPS(rsnd_suspend, rsnd_resume) }; static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", - .pm = &rsnd_pm_ops, + .pm = pm_ptr(&rsnd_pm_ops), .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, diff --git a/sound/soc/rockchip/rk3288_hdmi_analog.c b/sound/soc/rockchip/rk3288_hdmi_analog.c index a65d923d94dc..ffbc5a39b493 100644 --- a/sound/soc/rockchip/rk3288_hdmi_analog.c +++ b/sound/soc/rockchip/rk3288_hdmi_analog.c @@ -148,7 +148,7 @@ static struct snd_soc_dai_link rk_dailink = { .ops = &rk_ops, /* Set codecs as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(audio), }; diff --git a/sound/soc/rockchip/rk3399_gru_sound.c b/sound/soc/rockchip/rk3399_gru_sound.c index 6c89c7331229..c8137e8883c4 100644 --- a/sound/soc/rockchip/rk3399_gru_sound.c +++ b/sound/soc/rockchip/rk3399_gru_sound.c @@ -338,7 +338,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { .stream_name = "DP PCM", .init = rockchip_sound_cdndp_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(cdndp), }, [DAILINK_DA7219] = { @@ -348,7 +348,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { .ops = &rockchip_sound_da7219_ops, /* set da7219 as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(da7219), }, [DAILINK_DMIC] = { @@ -356,7 +356,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { .stream_name = "DMIC PCM", .ops = &rockchip_sound_dmic_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(dmic), }, [DAILINK_MAX98357A] = { @@ -365,7 +365,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { .ops = &rockchip_sound_max98357a_ops, /* set max98357a as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(max98357a), }, [DAILINK_RT5514] = { @@ -374,7 +374,7 @@ static const struct snd_soc_dai_link rockchip_dais[] = { .ops = &rockchip_sound_rt5514_ops, /* set rt5514 as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(rt5514), }, /* RT5514 DSP for voice wakeup via spi bus */ diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 4315da4a47c1..0a0a95b4f520 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c @@ -860,8 +860,7 @@ static void rockchip_i2s_remove(struct platform_device *pdev) } static const struct dev_pm_ops rockchip_i2s_pm_ops = { - SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, - NULL) + RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, NULL) }; static struct platform_driver rockchip_i2s_driver = { @@ -870,7 +869,7 @@ static struct platform_driver rockchip_i2s_driver = { .driver = { .name = DRV_NAME, .of_match_table = of_match_ptr(rockchip_i2s_match), - .pm = &rockchip_i2s_pm_ops, + .pm = pm_ptr(&rockchip_i2s_pm_ops), }, }; module_platform_driver(rockchip_i2s_driver); diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 78ab88843f86..d9a1fab7f403 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -122,7 +122,7 @@ err_mclk_tx: return ret; } -static int __maybe_unused i2s_tdm_runtime_suspend(struct device *dev) +static int i2s_tdm_runtime_suspend(struct device *dev) { struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); @@ -134,7 +134,7 @@ static int __maybe_unused i2s_tdm_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused i2s_tdm_runtime_resume(struct device *dev) +static int i2s_tdm_runtime_resume(struct device *dev) { struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); int ret; @@ -1390,7 +1390,7 @@ static void rockchip_i2s_tdm_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused rockchip_i2s_tdm_suspend(struct device *dev) +static int rockchip_i2s_tdm_suspend(struct device *dev) { struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); @@ -1399,7 +1399,7 @@ static int __maybe_unused rockchip_i2s_tdm_suspend(struct device *dev) return 0; } -static int __maybe_unused rockchip_i2s_tdm_resume(struct device *dev) +static int rockchip_i2s_tdm_resume(struct device *dev) { struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); int ret; @@ -1414,10 +1414,8 @@ static int __maybe_unused rockchip_i2s_tdm_resume(struct device *dev) } static const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = { - SET_RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend, - rockchip_i2s_tdm_resume) + RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend, rockchip_i2s_tdm_resume) }; static struct platform_driver rockchip_i2s_tdm_driver = { @@ -1426,7 +1424,7 @@ static struct platform_driver rockchip_i2s_tdm_driver = { .driver = { .name = DRV_NAME, .of_match_table = rockchip_i2s_tdm_match, - .pm = &rockchip_i2s_tdm_pm_ops, + .pm = pm_ptr(&rockchip_i2s_tdm_pm_ops), }, }; module_platform_driver(rockchip_i2s_tdm_driver); diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 783956dc83b5..b8326e9143b6 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -247,7 +247,7 @@ static struct snd_soc_dai_link rk_max98090_dailinks[] = { .ops = &rk_aif1_ops, /* set max98090 as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(analog), }, }; @@ -260,7 +260,7 @@ static struct snd_soc_dai_link rk_hdmi_dailinks[] = { .init = rk_hdmi_init, .ops = &rk_aif1_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(hdmi), } }; @@ -274,7 +274,7 @@ static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = { .ops = &rk_aif1_ops, /* set max98090 as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(analog), }, [DAILINK_HDMI] = { @@ -283,7 +283,7 @@ static struct snd_soc_dai_link rk_max98090_hdmi_dailinks[] = { .init = rk_hdmi_init, .ops = &rk_aif1_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(hdmi), } }; diff --git a/sound/soc/rockchip/rockchip_pdm.c b/sound/soc/rockchip/rockchip_pdm.c index cae91108f7a8..c1ee470ec607 100644 --- a/sound/soc/rockchip/rockchip_pdm.c +++ b/sound/soc/rockchip/rockchip_pdm.c @@ -668,7 +668,6 @@ static void rockchip_pdm_remove(struct platform_device *pdev) clk_disable_unprepare(pdm->hclk); } -#ifdef CONFIG_PM_SLEEP static int rockchip_pdm_suspend(struct device *dev) { struct rk_pdm_dev *pdm = dev_get_drvdata(dev); @@ -693,12 +692,11 @@ static int rockchip_pdm_resume(struct device *dev) return ret; } -#endif static const struct dev_pm_ops rockchip_pdm_pm_ops = { - SET_RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend, - rockchip_pdm_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) + RUNTIME_PM_OPS(rockchip_pdm_runtime_suspend, + rockchip_pdm_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(rockchip_pdm_suspend, rockchip_pdm_resume) }; static struct platform_driver rockchip_pdm_driver = { @@ -707,7 +705,7 @@ static struct platform_driver rockchip_pdm_driver = { .driver = { .name = "rockchip-pdm", .of_match_table = of_match_ptr(rockchip_pdm_match), - .pm = &rockchip_pdm_pm_ops, + .pm = pm_ptr(&rockchip_pdm_pm_ops), }, }; diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index b085d80ea2e4..590b64b362f6 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -145,7 +145,7 @@ static struct snd_soc_dai_link rk_dailink = { .ops = &rk_aif1_ops, /* set rt5645 as slave */ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(pcm), }; diff --git a/sound/soc/rockchip/rockchip_spdif.c b/sound/soc/rockchip/rockchip_spdif.c index d87c0e4f6f91..d365168934dc 100644 --- a/sound/soc/rockchip/rockchip_spdif.c +++ b/sound/soc/rockchip/rockchip_spdif.c @@ -63,7 +63,7 @@ static const struct of_device_id rk_spdif_match[] __maybe_unused = { }; MODULE_DEVICE_TABLE(of, rk_spdif_match); -static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) +static int rk_spdif_runtime_suspend(struct device *dev) { struct rk_spdif_dev *spdif = dev_get_drvdata(dev); @@ -74,7 +74,7 @@ static int __maybe_unused rk_spdif_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused rk_spdif_runtime_resume(struct device *dev) +static int rk_spdif_runtime_resume(struct device *dev) { struct rk_spdif_dev *spdif = dev_get_drvdata(dev); int ret; @@ -374,8 +374,7 @@ static void rk_spdif_remove(struct platform_device *pdev) } static const struct dev_pm_ops rk_spdif_pm_ops = { - SET_RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume, - NULL) + RUNTIME_PM_OPS(rk_spdif_runtime_suspend, rk_spdif_runtime_resume, NULL) }; static struct platform_driver rk_spdif_driver = { @@ -384,7 +383,7 @@ static struct platform_driver rk_spdif_driver = { .driver = { .name = "rockchip-spdif", .of_match_table = of_match_ptr(rk_spdif_match), - .pm = &rk_spdif_pm_ops, + .pm = pm_ptr(&rk_spdif_pm_ops), }, }; module_platform_driver(rk_spdif_driver); diff --git a/sound/soc/samsung/aries_wm8994.c b/sound/soc/samsung/aries_wm8994.c index 01716df0c842..3723329b266d 100644 --- a/sound/soc/samsung/aries_wm8994.c +++ b/sound/soc/samsung/aries_wm8994.c @@ -474,7 +474,7 @@ static struct snd_soc_dai_link aries_dai[] = { .name = "WM8994 AIF1", .stream_name = "HiFi", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &aries_ops, SND_SOC_DAILINK_REG(aif1), }, @@ -510,13 +510,13 @@ static struct snd_soc_card aries_card = { }; static const struct aries_wm8994_variant fascinate4g_variant = { - .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBS_CFS + .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBC_CFC | SND_SOC_DAIFMT_IB_NF, .has_fm_radio = false, }; static const struct aries_wm8994_variant aries_variant = { - .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBM_CFM + .modem_dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_CBP_CFP | SND_SOC_DAIFMT_IB_NF, .has_fm_radio = true, }; diff --git a/sound/soc/samsung/arndale.c b/sound/soc/samsung/arndale.c index 9619f550608c..172943bb3b24 100644 --- a/sound/soc/samsung/arndale.c +++ b/sound/soc/samsung/arndale.c @@ -95,7 +95,7 @@ static struct snd_soc_dai_link arndale_rt5631_dai[] = { .stream_name = "Primary", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .ops = &arndale_rt5631_ops, SND_SOC_DAILINK_REG(rt5631_hifi), }, @@ -112,7 +112,7 @@ static struct snd_soc_dai_link arndale_wm1811_dai[] = { .stream_name = "Primary", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ops = &arndale_wm1811_ops, SND_SOC_DAILINK_REG(wm1811_hifi), }, diff --git a/sound/soc/samsung/bells.c b/sound/soc/samsung/bells.c index 365b1aca4855..8dc3b2da4c8f 100644 --- a/sound/soc/samsung/bells.c +++ b/sound/soc/samsung/bells.c @@ -7,7 +7,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include <linux/gpio.h> #include <linux/module.h> #include "../codecs/wm5102.h" @@ -256,14 +255,14 @@ static struct snd_soc_dai_link bells_dai_wm2200[] = { .name = "CPU-DSP", .stream_name = "CPU-DSP", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(wm2200_cpu_dsp), }, { .name = "DSP-CODEC", .stream_name = "DSP-CODEC", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .c2c_params = &sub_params, .num_c2c_params = 1, .ignore_suspend = 1, @@ -293,14 +292,14 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { .name = "CPU-DSP", .stream_name = "CPU-DSP", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(wm5102_cpu_dsp), }, { .name = "DSP-CODEC", .stream_name = "DSP-CODEC", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .c2c_params = &sub_params, .num_c2c_params = 1, .ignore_suspend = 1, @@ -310,7 +309,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { .name = "Baseband", .stream_name = "Baseband", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, .c2c_params = &baseband_params, .num_c2c_params = 1, @@ -320,7 +319,7 @@ static struct snd_soc_dai_link bells_dai_wm5102[] = { .name = "Sub", .stream_name = "Sub", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .ignore_suspend = 1, .c2c_params = &sub_params, .num_c2c_params = 1, @@ -351,14 +350,14 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { .name = "CPU-DSP", .stream_name = "CPU-DSP", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(wm5110_cpu_dsp), }, { .name = "DSP-CODEC", .stream_name = "DSP-CODEC", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .c2c_params = &sub_params, .num_c2c_params = 1, .ignore_suspend = 1, @@ -368,7 +367,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { .name = "Baseband", .stream_name = "Baseband", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, .c2c_params = &baseband_params, .num_c2c_params = 1, @@ -378,7 +377,7 @@ static struct snd_soc_dai_link bells_dai_wm5110[] = { .name = "Sub", .stream_name = "Sub", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBS_CFS, + | SND_SOC_DAIFMT_CBC_CFC, .ignore_suspend = 1, .c2c_params = &sub_params, .num_c2c_params = 1, diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 8f6deb06e234..e9964f0e010a 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1216,7 +1216,6 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, return 0; } -#ifdef CONFIG_PM static int i2s_runtime_suspend(struct device *dev) { struct samsung_i2s_priv *priv = dev_get_drvdata(dev); @@ -1254,7 +1253,6 @@ static int i2s_runtime_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ static void i2s_unregister_clocks(struct samsung_i2s_priv *priv) { @@ -1733,10 +1731,8 @@ MODULE_DEVICE_TABLE(of, exynos_i2s_match); #endif static const struct dev_pm_ops samsung_i2s_pm = { - SET_RUNTIME_PM_OPS(i2s_runtime_suspend, - i2s_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver samsung_i2s_driver = { @@ -1746,7 +1742,7 @@ static struct platform_driver samsung_i2s_driver = { .driver = { .name = "samsung-i2s", .of_match_table = of_match_ptr(exynos_i2s_match), - .pm = &samsung_i2s_pm, + .pm = pm_ptr(&samsung_i2s_pm), }, }; diff --git a/sound/soc/samsung/littlemill.c b/sound/soc/samsung/littlemill.c index c5260e101c2a..5a02aac9b423 100644 --- a/sound/soc/samsung/littlemill.c +++ b/sound/soc/samsung/littlemill.c @@ -7,7 +7,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include <linux/gpio.h> #include <linux/module.h> #include "../codecs/wm8994.h" @@ -157,7 +156,7 @@ static struct snd_soc_dai_link littlemill_dai[] = { .name = "CPU", .stream_name = "CPU", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ops = &littlemill_ops, SND_SOC_DAILINK_REG(cpu), }, @@ -165,7 +164,7 @@ static struct snd_soc_dai_link littlemill_dai[] = { .name = "Baseband", .stream_name = "Baseband", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, .c2c_params = &baseband_params, .num_c2c_params = 1, diff --git a/sound/soc/samsung/lowland.c b/sound/soc/samsung/lowland.c index 702cb4cc1ce9..1e95a2a435d4 100644 --- a/sound/soc/samsung/lowland.c +++ b/sound/soc/samsung/lowland.c @@ -7,7 +7,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include <linux/gpio.h> #include <linux/module.h> #include "../codecs/wm5100.h" @@ -105,7 +104,7 @@ static struct snd_soc_dai_link lowland_dai[] = { .name = "CPU", .stream_name = "CPU", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .init = lowland_wm5100_init, SND_SOC_DAILINK_REG(cpu), }, @@ -113,7 +112,7 @@ static struct snd_soc_dai_link lowland_dai[] = { .name = "Baseband", .stream_name = "Baseband", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, SND_SOC_DAILINK_REG(baseband), }, @@ -121,7 +120,7 @@ static struct snd_soc_dai_link lowland_dai[] = { .name = "Sub Speaker", .stream_name = "Sub Speaker", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, .c2c_params = &sub_params, .num_c2c_params = 1, diff --git a/sound/soc/samsung/midas_wm1811.c b/sound/soc/samsung/midas_wm1811.c index bbfe5fef59af..239e958b88d3 100644 --- a/sound/soc/samsung/midas_wm1811.c +++ b/sound/soc/samsung/midas_wm1811.c @@ -537,7 +537,7 @@ static struct snd_soc_dai_link midas_dai[] = { .stream_name = "HiFi Primary", .ops = &midas_aif1_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(wm1811_hifi), }, { .name = "WM1811 Voice", diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 40ac12c07145..ab3398f39f4a 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -180,7 +180,7 @@ static struct snd_soc_dai_link odroid_card_dais[] = { .no_pcm = 1, .playback_only = 1, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(mixer), }, { /* Secondary FE <-> BE link */ diff --git a/sound/soc/samsung/smdk_wm8994.c b/sound/soc/samsung/smdk_wm8994.c index def92cc09f9c..acb29cd785a9 100644 --- a/sound/soc/samsung/smdk_wm8994.c +++ b/sound/soc/samsung/smdk_wm8994.c @@ -106,14 +106,14 @@ static struct snd_soc_dai_link smdk_dai[] = { .stream_name = "Pri_Dai", .init = smdk_wm8994_init_paiftx, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &smdk_ops, SND_SOC_DAILINK_REG(aif1), }, { /* Sec_Fifo Playback i/f */ .name = "Sec_FIFO TX", .stream_name = "Sec_Dai", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &smdk_ops, SND_SOC_DAILINK_REG(fifo_tx), }, diff --git a/sound/soc/samsung/smdk_wm8994pcm.c b/sound/soc/samsung/smdk_wm8994pcm.c index 5802f92ab8ba..a3f539fbde5f 100644 --- a/sound/soc/samsung/smdk_wm8994pcm.c +++ b/sound/soc/samsung/smdk_wm8994pcm.c @@ -99,7 +99,7 @@ static struct snd_soc_dai_link smdk_dai[] = { .name = "WM8994 PAIF PCM", .stream_name = "Primary PCM", .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &smdk_wm8994_pcm_ops, SND_SOC_DAILINK_REG(paif_pcm), }, diff --git a/sound/soc/samsung/snow.c b/sound/soc/samsung/snow.c index 4bbe7bcdb845..66ef49dff1ba 100644 --- a/sound/soc/samsung/snow.c +++ b/sound/soc/samsung/snow.c @@ -137,7 +137,7 @@ static int snow_probe(struct platform_device *pdev) link = &priv->dai_link; link->dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS; + SND_SOC_DAIFMT_CBC_CFC; link->name = "Primary"; link->stream_name = link->name; diff --git a/sound/soc/samsung/speyside.c b/sound/soc/samsung/speyside.c index 79476e8eb680..9262e5626584 100644 --- a/sound/soc/samsung/speyside.c +++ b/sound/soc/samsung/speyside.c @@ -7,13 +7,13 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include <linux/gpio.h> +#include <linux/gpio/machine.h> +#include <linux/gpio/consumer.h> #include <linux/module.h> #include "../codecs/wm8996.h" #include "../codecs/wm9081.h" -#define WM8996_HPSEL_GPIO 214 #define MCLK_AUDIO_RATE (512 * 48000) static int speyside_set_bias_level(struct snd_soc_card *card, @@ -105,6 +105,7 @@ static struct snd_soc_jack_pin speyside_headset_pins[] = { }, }; +static struct gpio_desc *speyside_hpsel_gpio; /* Default the headphone selection to active high */ static int speyside_jack_polarity; @@ -123,7 +124,7 @@ static void speyside_set_polarity(struct snd_soc_component *component, int polarity) { speyside_jack_polarity = !polarity; - gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); + gpiod_direction_output(speyside_hpsel_gpio, speyside_jack_polarity); /* Re-run DAPM to make sure we're using the correct mic bias */ snd_soc_dapm_sync(snd_soc_component_get_dapm(component)); @@ -145,16 +146,22 @@ static int speyside_wm8996_init(struct snd_soc_pcm_runtime *rtd) { struct snd_soc_dai *dai = snd_soc_rtd_to_codec(rtd, 0); struct snd_soc_component *component = dai->component; + enum gpiod_flags flags; int ret; ret = snd_soc_dai_set_sysclk(dai, WM8996_SYSCLK_MCLK2, 32768, 0); if (ret < 0) return ret; - ret = gpio_request(WM8996_HPSEL_GPIO, "HP_SEL"); - if (ret != 0) - pr_err("Failed to request HP_SEL GPIO: %d\n", ret); - gpio_direction_output(WM8996_HPSEL_GPIO, speyside_jack_polarity); + if (speyside_jack_polarity) + flags = GPIOD_OUT_HIGH; + else + flags = GPIOD_OUT_LOW; + speyside_hpsel_gpio = devm_gpiod_get(rtd->card->dev, + "hp-sel", + flags); + if (IS_ERR(speyside_hpsel_gpio)) + return PTR_ERR(speyside_hpsel_gpio); ret = snd_soc_card_jack_new_pins(rtd->card, "Headset", SND_JACK_LINEOUT | SND_JACK_HEADSET | @@ -210,7 +217,7 @@ static struct snd_soc_dai_link speyside_dai[] = { .stream_name = "CPU-DSP", .init = speyside_wm0010_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(cpu_dsp), }, { @@ -218,7 +225,7 @@ static struct snd_soc_dai_link speyside_dai[] = { .stream_name = "DSP-CODEC", .init = speyside_wm8996_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .c2c_params = &dsp_codec_params, .num_c2c_params = 1, .ignore_suspend = 1, @@ -228,7 +235,7 @@ static struct snd_soc_dai_link speyside_dai[] = { .name = "Baseband", .stream_name = "Baseband", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, SND_SOC_DAILINK_REG(baseband), }, @@ -325,6 +332,26 @@ static struct snd_soc_card speyside = { .late_probe = speyside_late_probe, }; +static struct gpiod_lookup_table wm8996_gpiod_table = { + /* Hardcoded device name in board file mach-crag6410.c */ + .dev_id = "speyside", + .table = { + /* + * This line was hardcoded to 214 in the global GPIO + * number space, S3C GPIO macros seems top set the + * wm8996 codec GPIO start offset to 212, so this will + * be GPIO 214 - 212 = 2 on the wm8996. + */ + GPIO_LOOKUP("wm8996", 2, "hp-sel", GPIO_ACTIVE_HIGH), + { }, + }, +}; + +static void speyside_gpiod_table_action(void *data) +{ + gpiod_remove_lookup_table(&wm8996_gpiod_table); +} + static int speyside_probe(struct platform_device *pdev) { struct snd_soc_card *card = &speyside; @@ -332,6 +359,12 @@ static int speyside_probe(struct platform_device *pdev) card->dev = &pdev->dev; + gpiod_add_lookup_table(&wm8996_gpiod_table); + ret = devm_add_action_or_reset(&pdev->dev, speyside_gpiod_table_action, + NULL); + if (ret) + return ret; + ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) dev_err_probe(&pdev->dev, ret, "snd_soc_register_card() failed\n"); diff --git a/sound/soc/samsung/tm2_wm5110.c b/sound/soc/samsung/tm2_wm5110.c index 2417b91a328f..b68ce7bd44ef 100644 --- a/sound/soc/samsung/tm2_wm5110.c +++ b/sound/soc/samsung/tm2_wm5110.c @@ -6,7 +6,6 @@ // Sylwester Nawrocki <s.nawrocki@samsung.com> #include <linux/clk.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> #include <linux/module.h> #include <linux/of.h> @@ -451,21 +450,21 @@ static struct snd_soc_dai_link tm2_dai_links[] = { .stream_name = "HiFi Primary", .ops = &tm2_aif1_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(aif1), }, { .name = "WM5110 Voice", .stream_name = "Voice call", .ops = &tm2_aif2_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, SND_SOC_DAILINK_REG(voice), }, { .name = "WM5110 BT", .stream_name = "Bluetooth", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ignore_suspend = 1, SND_SOC_DAILINK_REG(bt), }, { @@ -473,7 +472,7 @@ static struct snd_soc_dai_link tm2_dai_links[] = { .stream_name = "i2s1", .ops = &tm2_hdmi_ops, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(hdmi), } }; diff --git a/sound/soc/samsung/tobermory.c b/sound/soc/samsung/tobermory.c index 2bdd81bf821a..d0f0c01365aa 100644 --- a/sound/soc/samsung/tobermory.c +++ b/sound/soc/samsung/tobermory.c @@ -7,7 +7,6 @@ #include <sound/soc.h> #include <sound/soc-dapm.h> #include <sound/jack.h> -#include <linux/gpio.h> #include <linux/module.h> #include "../codecs/wm8962.h" @@ -119,7 +118,7 @@ static struct snd_soc_dai_link tobermory_dai[] = { .name = "CPU", .stream_name = "CPU", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF - | SND_SOC_DAIFMT_CBM_CFM, + | SND_SOC_DAIFMT_CBP_CFP, .ops = &tobermory_ops, SND_SOC_DAILINK_REG(cpu), }, diff --git a/sound/soc/sdca/Makefile b/sound/soc/sdca/Makefile index 5d1ddbbfbf62..dddc3e694256 100644 --- a/sound/soc/sdca/Makefile +++ b/sound/soc/sdca/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-soc-sdca-y := sdca_functions.o sdca_device.o +snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o obj-$(CONFIG_SND_SOC_SDCA) += snd-soc-sdca.o diff --git a/sound/soc/sdca/sdca_device.c b/sound/soc/sdca/sdca_device.c index b6399b773986..0244cdcdd109 100644 --- a/sound/soc/sdca/sdca_device.c +++ b/sound/soc/sdca/sdca_device.c @@ -48,8 +48,7 @@ static bool sdca_device_quirk_rt712_vb(struct sdw_slave *slave) return false; for (i = 0; i < slave->sdca_data.num_functions; i++) { - if (slave->sdca_data.sdca_func[i].type == - SDCA_FUNCTION_TYPE_SMART_MIC) + if (slave->sdca_data.function[i].type == SDCA_FUNCTION_TYPE_SMART_MIC) return true; } diff --git a/sound/soc/sdca/sdca_functions.c b/sound/soc/sdca/sdca_functions.c index 38071bc838b9..493f390f087a 100644 --- a/sound/soc/sdca/sdca_functions.c +++ b/sound/soc/sdca/sdca_functions.c @@ -9,7 +9,10 @@ #define dev_fmt(fmt) "%s: " fmt, __func__ #include <linux/acpi.h> +#include <linux/byteorder/generic.h> +#include <linux/cleanup.h> #include <linux/device.h> +#include <linux/dev_printk.h> #include <linux/module.h> #include <linux/property.h> #include <linux/soundwire/sdw.h> @@ -17,11 +20,16 @@ #include <sound/sdca.h> #include <sound/sdca_function.h> +/* + * Should be long enough to encompass all the MIPI DisCo properties. + */ +#define SDCA_PROPERTY_LENGTH 64 + static int patch_sdca_function_type(u32 interface_revision, u32 *function_type) { /* * Unfortunately early SDCA specifications used different indices for Functions, - * for backwards compatibility we have to reorder the values found + * for backwards compatibility we have to reorder the values found. */ if (interface_revision < 0x0801) { switch (*function_type) { @@ -85,7 +93,7 @@ static int find_sdca_function(struct acpi_device *adev, void *data) struct fwnode_handle *control5; /* used to identify function type */ const char *function_name; u32 function_type; - int func_index; + int function_index; u64 addr; int ret; @@ -145,27 +153,1702 @@ static int find_sdca_function(struct acpi_device *adev, void *data) function_name, function_type, addr); /* store results */ - func_index = sdca_data->num_functions; - sdca_data->sdca_func[func_index].adr = addr; - sdca_data->sdca_func[func_index].type = function_type; - sdca_data->sdca_func[func_index].name = function_name; + function_index = sdca_data->num_functions; + sdca_data->function[function_index].adr = addr; + sdca_data->function[function_index].type = function_type; + sdca_data->function[function_index].name = function_name; + sdca_data->function[function_index].node = function_node; sdca_data->num_functions++; return 0; } +/** + * sdca_lookup_functions - Parse sdca_device_desc for each Function + * @slave: SoundWire slave device to be processed. + * + * Iterate through the available SDCA Functions and fill in a short + * descriptor (struct sdca_function_desc) for each function, this + * information is stored along with the SoundWire slave device and + * used for adding drivers and quirks before the devices have fully + * probed. + */ void sdca_lookup_functions(struct sdw_slave *slave) { struct device *dev = &slave->dev; struct acpi_device *adev = to_acpi_device_node(dev->fwnode); if (!adev) { - dev_info(dev, "No matching ACPI device found, ignoring peripheral\n"); + dev_info(dev, "no matching ACPI device found, ignoring peripheral\n"); return; } + acpi_dev_for_each_child(adev, find_sdca_function, &slave->sdca_data); } EXPORT_SYMBOL_NS(sdca_lookup_functions, "SND_SOC_SDCA"); +struct raw_init_write { + __le32 addr; + u8 val; +} __packed; + +static int find_sdca_init_table(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + struct raw_init_write *raw __free(kfree) = NULL; + struct sdca_init_write *init_write; + int i, num_init_writes; + + num_init_writes = fwnode_property_count_u8(function_node, + "mipi-sdca-function-initialization-table"); + if (!num_init_writes || num_init_writes == -EINVAL) { + return 0; + } else if (num_init_writes < 0) { + dev_err(dev, "%pfwP: failed to read initialization table: %d\n", + function_node, num_init_writes); + return num_init_writes; + } else if (num_init_writes % sizeof(*raw) != 0) { + dev_err(dev, "%pfwP: init table size invalid\n", function_node); + return -EINVAL; + } else if (num_init_writes > SDCA_MAX_INIT_COUNT) { + dev_err(dev, "%pfwP: maximum init table size exceeded\n", function_node); + return -EINVAL; + } + + raw = kzalloc(num_init_writes, GFP_KERNEL); + if (!raw) + return -ENOMEM; + + fwnode_property_read_u8_array(function_node, + "mipi-sdca-function-initialization-table", + (u8 *)raw, num_init_writes); + + num_init_writes /= sizeof(*raw); + + init_write = devm_kcalloc(dev, num_init_writes, sizeof(*init_write), GFP_KERNEL); + if (!init_write) + return -ENOMEM; + + for (i = 0; i < num_init_writes; i++) { + init_write[i].addr = le32_to_cpu(raw[i].addr); + init_write[i].val = raw[i].val; + } + + function->num_init_table = num_init_writes; + function->init_table = init_write; + + return 0; +} + +static const char *find_sdca_control_label(struct device *dev, + const struct sdca_entity *entity, + const struct sdca_control *control) +{ + switch (SDCA_CTL_TYPE(entity->type, control->sel)) { + case SDCA_CTL_TYPE_S(IT, MIC_BIAS): + return SDCA_CTL_MIC_BIAS_NAME; + case SDCA_CTL_TYPE_S(IT, USAGE): + case SDCA_CTL_TYPE_S(OT, USAGE): + return SDCA_CTL_USAGE_NAME; + case SDCA_CTL_TYPE_S(IT, LATENCY): + case SDCA_CTL_TYPE_S(OT, LATENCY): + case SDCA_CTL_TYPE_S(MU, LATENCY): + case SDCA_CTL_TYPE_S(SU, LATENCY): + case SDCA_CTL_TYPE_S(FU, LATENCY): + case SDCA_CTL_TYPE_S(XU, LATENCY): + case SDCA_CTL_TYPE_S(CRU, LATENCY): + case SDCA_CTL_TYPE_S(UDMPU, LATENCY): + case SDCA_CTL_TYPE_S(MFPU, LATENCY): + case SDCA_CTL_TYPE_S(SMPU, LATENCY): + case SDCA_CTL_TYPE_S(SAPU, LATENCY): + case SDCA_CTL_TYPE_S(PPU, LATENCY): + return SDCA_CTL_LATENCY_NAME; + case SDCA_CTL_TYPE_S(IT, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(CRU, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(UDMPU, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(MFPU, CLUSTERINDEX): + return SDCA_CTL_CLUSTERINDEX_NAME; + case SDCA_CTL_TYPE_S(IT, DATAPORT_SELECTOR): + case SDCA_CTL_TYPE_S(OT, DATAPORT_SELECTOR): + return SDCA_CTL_DATAPORT_SELECTOR_NAME; + case SDCA_CTL_TYPE_S(IT, MATCHING_GUID): + case SDCA_CTL_TYPE_S(OT, MATCHING_GUID): + case SDCA_CTL_TYPE_S(ENTITY_0, MATCHING_GUID): + return SDCA_CTL_MATCHING_GUID_NAME; + case SDCA_CTL_TYPE_S(IT, KEEP_ALIVE): + case SDCA_CTL_TYPE_S(OT, KEEP_ALIVE): + return SDCA_CTL_KEEP_ALIVE_NAME; + case SDCA_CTL_TYPE_S(IT, NDAI_STREAM): + case SDCA_CTL_TYPE_S(OT, NDAI_STREAM): + return SDCA_CTL_NDAI_STREAM_NAME; + case SDCA_CTL_TYPE_S(IT, NDAI_CATEGORY): + case SDCA_CTL_TYPE_S(OT, NDAI_CATEGORY): + return SDCA_CTL_NDAI_CATEGORY_NAME; + case SDCA_CTL_TYPE_S(IT, NDAI_CODINGTYPE): + case SDCA_CTL_TYPE_S(OT, NDAI_CODINGTYPE): + return SDCA_CTL_NDAI_CODINGTYPE_NAME; + case SDCA_CTL_TYPE_S(IT, NDAI_PACKETTYPE): + case SDCA_CTL_TYPE_S(OT, NDAI_PACKETTYPE): + return SDCA_CTL_NDAI_PACKETTYPE_NAME; + case SDCA_CTL_TYPE_S(MU, MIXER): + return SDCA_CTL_MIXER_NAME; + case SDCA_CTL_TYPE_S(SU, SELECTOR): + return SDCA_CTL_SELECTOR_NAME; + case SDCA_CTL_TYPE_S(FU, MUTE): + return SDCA_CTL_MUTE_NAME; + case SDCA_CTL_TYPE_S(FU, CHANNEL_VOLUME): + return SDCA_CTL_CHANNEL_VOLUME_NAME; + case SDCA_CTL_TYPE_S(FU, AGC): + return SDCA_CTL_AGC_NAME; + case SDCA_CTL_TYPE_S(FU, BASS_BOOST): + return SDCA_CTL_BASS_BOOST_NAME; + case SDCA_CTL_TYPE_S(FU, LOUDNESS): + return SDCA_CTL_LOUDNESS_NAME; + case SDCA_CTL_TYPE_S(FU, GAIN): + return SDCA_CTL_GAIN_NAME; + case SDCA_CTL_TYPE_S(XU, BYPASS): + case SDCA_CTL_TYPE_S(MFPU, BYPASS): + return SDCA_CTL_BYPASS_NAME; + case SDCA_CTL_TYPE_S(XU, XU_ID): + return SDCA_CTL_XU_ID_NAME; + case SDCA_CTL_TYPE_S(XU, XU_VERSION): + return SDCA_CTL_XU_VERSION_NAME; + case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER): + return SDCA_CTL_FDL_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET): + return SDCA_CTL_FDL_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH): + return SDCA_CTL_FDL_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(XU, FDL_STATUS): + return SDCA_CTL_FDL_STATUS_NAME; + case SDCA_CTL_TYPE_S(XU, FDL_SET_INDEX): + return SDCA_CTL_FDL_SET_INDEX_NAME; + case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST): + return SDCA_CTL_FDL_HOST_REQUEST_NAME; + case SDCA_CTL_TYPE_S(CS, CLOCK_VALID): + return SDCA_CTL_CLOCK_VALID_NAME; + case SDCA_CTL_TYPE_S(CS, SAMPLERATEINDEX): + return SDCA_CTL_SAMPLERATEINDEX_NAME; + case SDCA_CTL_TYPE_S(CX, CLOCK_SELECT): + return SDCA_CTL_CLOCK_SELECT_NAME; + case SDCA_CTL_TYPE_S(PDE, REQUESTED_PS): + return SDCA_CTL_REQUESTED_PS_NAME; + case SDCA_CTL_TYPE_S(PDE, ACTUAL_PS): + return SDCA_CTL_ACTUAL_PS_NAME; + case SDCA_CTL_TYPE_S(GE, SELECTED_MODE): + return SDCA_CTL_SELECTED_MODE_NAME; + case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): + return SDCA_CTL_DETECTED_MODE_NAME; + case SDCA_CTL_TYPE_S(SPE, PRIVATE): + return SDCA_CTL_PRIVATE_NAME; + case SDCA_CTL_TYPE_S(SPE, PRIVACY_POLICY): + return SDCA_CTL_PRIVACY_POLICY_NAME; + case SDCA_CTL_TYPE_S(SPE, PRIVACY_LOCKSTATE): + return SDCA_CTL_PRIVACY_LOCKSTATE_NAME; + case SDCA_CTL_TYPE_S(SPE, PRIVACY_OWNER): + return SDCA_CTL_PRIVACY_OWNER_NAME; + case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER): + return SDCA_CTL_AUTHTX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET): + return SDCA_CTL_AUTHTX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH): + return SDCA_CTL_AUTHTX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER): + return SDCA_CTL_AUTHRX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET): + return SDCA_CTL_AUTHRX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH): + return SDCA_CTL_AUTHRX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(UDMPU, ACOUSTIC_ENERGY_LEVEL_MONITOR): + return SDCA_CTL_ACOUSTIC_ENERGY_LEVEL_MONITOR_NAME; + case SDCA_CTL_TYPE_S(UDMPU, ULTRASOUND_LOOP_GAIN): + return SDCA_CTL_ULTRASOUND_LOOP_GAIN_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_0): + return SDCA_CTL_OPAQUESET_0_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_1): + return SDCA_CTL_OPAQUESET_1_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_2): + return SDCA_CTL_OPAQUESET_2_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_3): + return SDCA_CTL_OPAQUESET_3_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_4): + return SDCA_CTL_OPAQUESET_4_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_5): + return SDCA_CTL_OPAQUESET_5_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_6): + return SDCA_CTL_OPAQUESET_6_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_7): + return SDCA_CTL_OPAQUESET_7_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_8): + return SDCA_CTL_OPAQUESET_8_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_9): + return SDCA_CTL_OPAQUESET_9_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_10): + return SDCA_CTL_OPAQUESET_10_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_11): + return SDCA_CTL_OPAQUESET_11_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_12): + return SDCA_CTL_OPAQUESET_12_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_13): + return SDCA_CTL_OPAQUESET_13_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_14): + return SDCA_CTL_OPAQUESET_14_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_15): + return SDCA_CTL_OPAQUESET_15_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_16): + return SDCA_CTL_OPAQUESET_16_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_17): + return SDCA_CTL_OPAQUESET_17_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_18): + return SDCA_CTL_OPAQUESET_18_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_19): + return SDCA_CTL_OPAQUESET_19_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_20): + return SDCA_CTL_OPAQUESET_20_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_21): + return SDCA_CTL_OPAQUESET_21_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_22): + return SDCA_CTL_OPAQUESET_22_NAME; + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_23): + return SDCA_CTL_OPAQUESET_23_NAME; + case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_READY): + return SDCA_CTL_ALGORITHM_READY_NAME; + case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_ENABLE): + return SDCA_CTL_ALGORITHM_ENABLE_NAME; + case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_PREPARE): + return SDCA_CTL_ALGORITHM_PREPARE_NAME; + case SDCA_CTL_TYPE_S(MFPU, CENTER_FREQUENCY_INDEX): + return SDCA_CTL_CENTER_FREQUENCY_INDEX_NAME; + case SDCA_CTL_TYPE_S(MFPU, ULTRASOUND_LEVEL): + return SDCA_CTL_ULTRASOUND_LEVEL_NAME; + case SDCA_CTL_TYPE_S(MFPU, AE_NUMBER): + return SDCA_CTL_AE_NUMBER_NAME; + case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER): + return SDCA_CTL_AE_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET): + return SDCA_CTL_AE_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH): + return SDCA_CTL_AE_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_ENABLE): + return SDCA_CTL_TRIGGER_ENABLE_NAME; + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_STATUS): + return SDCA_CTL_TRIGGER_STATUS_NAME; + case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_MODE): + return SDCA_CTL_HIST_BUFFER_MODE_NAME; + case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_PREAMBLE): + return SDCA_CTL_HIST_BUFFER_PREAMBLE_NAME; + case SDCA_CTL_TYPE_S(SMPU, HIST_ERROR): + return SDCA_CTL_HIST_ERROR_NAME; + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_EXTENSION): + return SDCA_CTL_TRIGGER_EXTENSION_NAME; + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_READY): + return SDCA_CTL_TRIGGER_READY_NAME; + case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER): + return SDCA_CTL_HIST_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET): + return SDCA_CTL_HIST_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH): + return SDCA_CTL_HIST_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER): + return SDCA_CTL_DTODTX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET): + return SDCA_CTL_DTODTX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH): + return SDCA_CTL_DTODTX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER): + return SDCA_CTL_DTODRX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET): + return SDCA_CTL_DTODRX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH): + return SDCA_CTL_DTODRX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(SAPU, PROTECTION_MODE): + return SDCA_CTL_PROTECTION_MODE_NAME; + case SDCA_CTL_TYPE_S(SAPU, PROTECTION_STATUS): + return SDCA_CTL_PROTECTION_STATUS_NAME; + case SDCA_CTL_TYPE_S(SAPU, OPAQUESETREQ_INDEX): + return SDCA_CTL_OPAQUESETREQ_INDEX_NAME; + case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER): + return SDCA_CTL_DTODTX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET): + return SDCA_CTL_DTODTX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH): + return SDCA_CTL_DTODTX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER): + return SDCA_CTL_DTODRX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET): + return SDCA_CTL_DTODRX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH): + return SDCA_CTL_DTODRX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(PPU, POSTURENUMBER): + return SDCA_CTL_POSTURENUMBER_NAME; + case SDCA_CTL_TYPE_S(PPU, POSTUREEXTENSION): + return SDCA_CTL_POSTUREEXTENSION_NAME; + case SDCA_CTL_TYPE_S(PPU, HORIZONTALBALANCE): + return SDCA_CTL_HORIZONTALBALANCE_NAME; + case SDCA_CTL_TYPE_S(PPU, VERTICALBALANCE): + return SDCA_CTL_VERTICALBALANCE_NAME; + case SDCA_CTL_TYPE_S(TG, TONE_DIVIDER): + return SDCA_CTL_TONE_DIVIDER_NAME; + case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): + return SDCA_CTL_HIDTX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET): + return SDCA_CTL_HIDTX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH): + return SDCA_CTL_HIDTX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER): + return SDCA_CTL_HIDRX_CURRENTOWNER_NAME; + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET): + return SDCA_CTL_HIDRX_MESSAGEOFFSET_NAME; + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH): + return SDCA_CTL_HIDRX_MESSAGELENGTH_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, COMMIT_GROUP_MASK): + return SDCA_CTL_COMMIT_GROUP_MASK_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_SDCA_VERSION): + return SDCA_CTL_FUNCTION_SDCA_VERSION_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_TYPE): + return SDCA_CTL_FUNCTION_TYPE_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_MANUFACTURER_ID): + return SDCA_CTL_FUNCTION_MANUFACTURER_ID_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ID): + return SDCA_CTL_FUNCTION_ID_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_VERSION): + return SDCA_CTL_FUNCTION_VERSION_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_ID): + return SDCA_CTL_FUNCTION_EXTENSION_ID_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_VERSION): + return SDCA_CTL_FUNCTION_EXTENSION_VERSION_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS): + return SDCA_CTL_FUNCTION_STATUS_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ACTION): + return SDCA_CTL_FUNCTION_ACTION_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_MANUFACTURER_ID): + return SDCA_CTL_DEVICE_MANUFACTURER_ID_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_PART_ID): + return SDCA_CTL_DEVICE_PART_ID_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_VERSION): + return SDCA_CTL_DEVICE_VERSION_NAME; + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_SDCA_VERSION): + return SDCA_CTL_DEVICE_SDCA_VERSION_NAME; + default: + return devm_kasprintf(dev, GFP_KERNEL, "Imp-Def %#x", control->sel); + } +} + +static unsigned int find_sdca_control_bits(const struct sdca_entity *entity, + const struct sdca_control *control) +{ + switch (SDCA_CTL_TYPE(entity->type, control->sel)) { + case SDCA_CTL_TYPE_S(IT, LATENCY): + case SDCA_CTL_TYPE_S(OT, LATENCY): + case SDCA_CTL_TYPE_S(MU, LATENCY): + case SDCA_CTL_TYPE_S(SU, LATENCY): + case SDCA_CTL_TYPE_S(FU, LATENCY): + case SDCA_CTL_TYPE_S(XU, LATENCY): + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(CRU, LATENCY): + case SDCA_CTL_TYPE_S(UDMPU, LATENCY): + case SDCA_CTL_TYPE_S(MFPU, LATENCY): + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, LATENCY): + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SAPU, LATENCY): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(PPU, LATENCY): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH): + return 32; + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_MANUFACTURER_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_MANUFACTURER_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_PART_ID): + case SDCA_CTL_TYPE_S(IT, DATAPORT_SELECTOR): + case SDCA_CTL_TYPE_S(OT, DATAPORT_SELECTOR): + case SDCA_CTL_TYPE_S(MU, MIXER): + case SDCA_CTL_TYPE_S(FU, CHANNEL_VOLUME): + case SDCA_CTL_TYPE_S(FU, GAIN): + case SDCA_CTL_TYPE_S(XU, XU_ID): + case SDCA_CTL_TYPE_S(UDMPU, ACOUSTIC_ENERGY_LEVEL_MONITOR): + case SDCA_CTL_TYPE_S(UDMPU, ULTRASOUND_LOOP_GAIN): + case SDCA_CTL_TYPE_S(MFPU, ULTRASOUND_LEVEL): + case SDCA_CTL_TYPE_S(PPU, HORIZONTALBALANCE): + case SDCA_CTL_TYPE_S(PPU, VERTICALBALANCE): + return 16; + case SDCA_CTL_TYPE_S(FU, MUTE): + case SDCA_CTL_TYPE_S(FU, AGC): + case SDCA_CTL_TYPE_S(FU, BASS_BOOST): + case SDCA_CTL_TYPE_S(FU, LOUDNESS): + case SDCA_CTL_TYPE_S(XU, BYPASS): + case SDCA_CTL_TYPE_S(MFPU, BYPASS): + return 1; + default: + return 8; + } +} + +static enum sdca_control_datatype +find_sdca_control_datatype(const struct sdca_entity *entity, + const struct sdca_control *control) +{ + switch (SDCA_CTL_TYPE(entity->type, control->sel)) { + case SDCA_CTL_TYPE_S(XU, BYPASS): + case SDCA_CTL_TYPE_S(MFPU, BYPASS): + case SDCA_CTL_TYPE_S(FU, MUTE): + case SDCA_CTL_TYPE_S(FU, AGC): + case SDCA_CTL_TYPE_S(FU, BASS_BOOST): + case SDCA_CTL_TYPE_S(FU, LOUDNESS): + return SDCA_CTL_DATATYPE_ONEBIT; + case SDCA_CTL_TYPE_S(IT, LATENCY): + case SDCA_CTL_TYPE_S(OT, LATENCY): + case SDCA_CTL_TYPE_S(MU, LATENCY): + case SDCA_CTL_TYPE_S(SU, LATENCY): + case SDCA_CTL_TYPE_S(FU, LATENCY): + case SDCA_CTL_TYPE_S(XU, LATENCY): + case SDCA_CTL_TYPE_S(CRU, LATENCY): + case SDCA_CTL_TYPE_S(UDMPU, LATENCY): + case SDCA_CTL_TYPE_S(MFPU, LATENCY): + case SDCA_CTL_TYPE_S(SMPU, LATENCY): + case SDCA_CTL_TYPE_S(SAPU, LATENCY): + case SDCA_CTL_TYPE_S(PPU, LATENCY): + case SDCA_CTL_TYPE_S(SU, SELECTOR): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_0): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_1): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_2): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_3): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_4): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_5): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_6): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_7): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_8): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_9): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_10): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_11): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_12): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_13): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_14): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_15): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_16): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_17): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_18): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_19): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_20): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_21): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_22): + case SDCA_CTL_TYPE_S(UDMPU, OPAQUESET_23): + case SDCA_CTL_TYPE_S(SAPU, PROTECTION_MODE): + case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_PREAMBLE): + case SDCA_CTL_TYPE_S(XU, FDL_HOST_REQUEST): + case SDCA_CTL_TYPE_S(XU, XU_ID): + case SDCA_CTL_TYPE_S(CX, CLOCK_SELECT): + case SDCA_CTL_TYPE_S(TG, TONE_DIVIDER): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_MANUFACTURER_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_MANUFACTURER_ID): + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_PART_ID): + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(XU, FDL_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(MFPU, AE_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, HIST_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_MESSAGELENGTH): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGEOFFSET): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_MESSAGELENGTH): + return SDCA_CTL_DATATYPE_INTEGER; + case SDCA_CTL_TYPE_S(IT, MIC_BIAS): + case SDCA_CTL_TYPE_S(SMPU, HIST_BUFFER_MODE): + case SDCA_CTL_TYPE_S(PDE, REQUESTED_PS): + case SDCA_CTL_TYPE_S(PDE, ACTUAL_PS): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_TYPE): + return SDCA_CTL_DATATYPE_SPEC_ENCODED_VALUE; + case SDCA_CTL_TYPE_S(XU, XU_VERSION): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_SDCA_VERSION): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_VERSION): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_EXTENSION_VERSION): + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_VERSION): + case SDCA_CTL_TYPE_S(ENTITY_0, DEVICE_SDCA_VERSION): + return SDCA_CTL_DATATYPE_BCD; + case SDCA_CTL_TYPE_S(FU, CHANNEL_VOLUME): + case SDCA_CTL_TYPE_S(FU, GAIN): + case SDCA_CTL_TYPE_S(MU, MIXER): + case SDCA_CTL_TYPE_S(PPU, HORIZONTALBALANCE): + case SDCA_CTL_TYPE_S(PPU, VERTICALBALANCE): + case SDCA_CTL_TYPE_S(MFPU, ULTRASOUND_LEVEL): + case SDCA_CTL_TYPE_S(UDMPU, ACOUSTIC_ENERGY_LEVEL_MONITOR): + case SDCA_CTL_TYPE_S(UDMPU, ULTRASOUND_LOOP_GAIN): + return SDCA_CTL_DATATYPE_Q7P8DB; + case SDCA_CTL_TYPE_S(IT, USAGE): + case SDCA_CTL_TYPE_S(OT, USAGE): + case SDCA_CTL_TYPE_S(IT, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(CRU, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(UDMPU, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(MFPU, CLUSTERINDEX): + case SDCA_CTL_TYPE_S(MFPU, CENTER_FREQUENCY_INDEX): + case SDCA_CTL_TYPE_S(MFPU, AE_NUMBER): + case SDCA_CTL_TYPE_S(SAPU, OPAQUESETREQ_INDEX): + case SDCA_CTL_TYPE_S(XU, FDL_SET_INDEX): + case SDCA_CTL_TYPE_S(CS, SAMPLERATEINDEX): + case SDCA_CTL_TYPE_S(GE, SELECTED_MODE): + case SDCA_CTL_TYPE_S(GE, DETECTED_MODE): + return SDCA_CTL_DATATYPE_BYTEINDEX; + case SDCA_CTL_TYPE_S(PPU, POSTURENUMBER): + return SDCA_CTL_DATATYPE_POSTURENUMBER; + case SDCA_CTL_TYPE_S(IT, DATAPORT_SELECTOR): + case SDCA_CTL_TYPE_S(OT, DATAPORT_SELECTOR): + return SDCA_CTL_DATATYPE_DP_INDEX; + case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_READY): + case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_ENABLE): + case SDCA_CTL_TYPE_S(MFPU, ALGORITHM_PREPARE): + case SDCA_CTL_TYPE_S(SAPU, PROTECTION_STATUS): + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_ENABLE): + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_STATUS): + case SDCA_CTL_TYPE_S(SMPU, TRIGGER_READY): + case SDCA_CTL_TYPE_S(SPE, PRIVACY_POLICY): + case SDCA_CTL_TYPE_S(SPE, PRIVACY_OWNER): + return SDCA_CTL_DATATYPE_BITINDEX; + case SDCA_CTL_TYPE_S(IT, KEEP_ALIVE): + case SDCA_CTL_TYPE_S(OT, KEEP_ALIVE): + case SDCA_CTL_TYPE_S(IT, NDAI_STREAM): + case SDCA_CTL_TYPE_S(OT, NDAI_STREAM): + case SDCA_CTL_TYPE_S(IT, NDAI_CATEGORY): + case SDCA_CTL_TYPE_S(OT, NDAI_CATEGORY): + case SDCA_CTL_TYPE_S(IT, NDAI_CODINGTYPE): + case SDCA_CTL_TYPE_S(OT, NDAI_CODINGTYPE): + case SDCA_CTL_TYPE_S(IT, NDAI_PACKETTYPE): + case SDCA_CTL_TYPE_S(OT, NDAI_PACKETTYPE): + case SDCA_CTL_TYPE_S(SMPU, HIST_ERROR): + case SDCA_CTL_TYPE_S(XU, FDL_STATUS): + case SDCA_CTL_TYPE_S(CS, CLOCK_VALID): + case SDCA_CTL_TYPE_S(SPE, PRIVACY_LOCKSTATE): + case SDCA_CTL_TYPE_S(ENTITY_0, COMMIT_GROUP_MASK): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_STATUS): + case SDCA_CTL_TYPE_S(ENTITY_0, FUNCTION_ACTION): + case SDCA_CTL_TYPE_S(XU, FDL_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SPE, AUTHTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SPE, AUTHRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(MFPU, AE_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SMPU, HIST_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SMPU, DTODTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SMPU, DTODRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SAPU, DTODTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(SAPU, DTODRX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(HIDE, HIDTX_CURRENTOWNER): + case SDCA_CTL_TYPE_S(HIDE, HIDRX_CURRENTOWNER): + return SDCA_CTL_DATATYPE_BITMAP; + case SDCA_CTL_TYPE_S(IT, MATCHING_GUID): + case SDCA_CTL_TYPE_S(OT, MATCHING_GUID): + case SDCA_CTL_TYPE_S(ENTITY_0, MATCHING_GUID): + return SDCA_CTL_DATATYPE_GUID; + default: + return SDCA_CTL_DATATYPE_IMPDEF; + } +} + +static int find_sdca_control_range(struct device *dev, + struct fwnode_handle *control_node, + struct sdca_control_range *range) +{ + u8 *range_list; + int num_range; + u16 *limits; + int i; + + num_range = fwnode_property_count_u8(control_node, "mipi-sdca-control-range"); + if (!num_range || num_range == -EINVAL) + return 0; + else if (num_range < 0) + return num_range; + + range_list = devm_kcalloc(dev, num_range, sizeof(*range_list), GFP_KERNEL); + if (!range_list) + return -ENOMEM; + + fwnode_property_read_u8_array(control_node, "mipi-sdca-control-range", + range_list, num_range); + + limits = (u16 *)range_list; + + range->cols = le16_to_cpu(limits[0]); + range->rows = le16_to_cpu(limits[1]); + range->data = (u32 *)&limits[2]; + + num_range = (num_range - (2 * sizeof(*limits))) / sizeof(*range->data); + if (num_range != range->cols * range->rows) + return -EINVAL; + + for (i = 0; i < num_range; i++) + range->data[i] = le32_to_cpu(range->data[i]); + + return 0; +} + +/* + * TODO: Add support for -cn- properties, allowing different channels to have + * different defaults etc. + */ +static int find_sdca_entity_control(struct device *dev, struct sdca_entity *entity, + struct fwnode_handle *control_node, + struct sdca_control *control) +{ + u32 tmp; + int ret; + + ret = fwnode_property_read_u32(control_node, "mipi-sdca-control-access-mode", &tmp); + if (ret) { + dev_err(dev, "%s: control %#x: access mode missing: %d\n", + entity->label, control->sel, ret); + return ret; + } + + control->mode = tmp; + + ret = fwnode_property_read_u32(control_node, "mipi-sdca-control-access-layer", &tmp); + if (ret) { + dev_err(dev, "%s: control %#x: access layer missing: %d\n", + entity->label, control->sel, ret); + return ret; + } + + control->layers = tmp; + + switch (control->mode) { + case SDCA_ACCESS_MODE_DC: + ret = fwnode_property_read_u32(control_node, + "mipi-sdca-control-dc-value", + &tmp); + if (ret) { + dev_err(dev, "%s: control %#x: dc value missing: %d\n", + entity->label, control->sel, ret); + return ret; + } + + control->value = tmp; + control->has_fixed = true; + break; + case SDCA_ACCESS_MODE_RW: + case SDCA_ACCESS_MODE_DUAL: + ret = fwnode_property_read_u32(control_node, + "mipi-sdca-control-default-value", + &tmp); + if (!ret) { + control->value = tmp; + control->has_default = true; + } + + ret = fwnode_property_read_u32(control_node, + "mipi-sdca-control-fixed-value", + &tmp); + if (!ret) { + if (control->has_default && control->value != tmp) { + dev_err(dev, + "%s: control %#x: default and fixed value don't match\n", + entity->label, control->sel); + return -EINVAL; + } + + control->value = tmp; + control->has_fixed = true; + } + + control->deferrable = fwnode_property_read_bool(control_node, + "mipi-sdca-control-deferrable"); + break; + default: + break; + } + + ret = find_sdca_control_range(dev, control_node, &control->range); + if (ret) { + dev_err(dev, "%s: control %#x: range missing: %d\n", + entity->label, control->sel, ret); + return ret; + } + + ret = fwnode_property_read_u64(control_node, "mipi-sdca-control-cn-list", + &control->cn_list); + if (ret == -EINVAL) { + /* Spec allows not specifying cn-list if only the first number is used */ + control->cn_list = 0x1; + } else if (ret || !control->cn_list) { + dev_err(dev, "%s: control %#x: cn list missing: %d\n", + entity->label, control->sel, ret); + return ret; + } + + ret = fwnode_property_read_u32(control_node, + "mipi-sdca-control-interrupt-position", + &tmp); + if (!ret) + control->interrupt_position = tmp; + + control->label = find_sdca_control_label(dev, entity, control); + if (!control->label) + return -ENOMEM; + + control->type = find_sdca_control_datatype(entity, control); + control->nbits = find_sdca_control_bits(entity, control); + + dev_info(dev, "%s: %s: control %#x mode %#x layers %#x cn %#llx int %d value %#x %s\n", + entity->label, control->label, control->sel, + control->mode, control->layers, control->cn_list, + control->interrupt_position, control->value, + control->deferrable ? "deferrable" : ""); + + return 0; +} + +static int find_sdca_entity_controls(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_control *controls; + int num_controls; + u64 control_list; + int control_sel; + int i, ret; + + ret = fwnode_property_read_u64(entity_node, "mipi-sdca-control-list", &control_list); + if (ret == -EINVAL) { + /* Allow missing control lists, assume no controls. */ + dev_warn(dev, "%s: missing control list\n", entity->label); + return 0; + } else if (ret) { + dev_err(dev, "%s: failed to read control list: %d\n", entity->label, ret); + return ret; + } else if (!control_list) { + return 0; + } + + num_controls = hweight64(control_list); + controls = devm_kcalloc(dev, num_controls, sizeof(*controls), GFP_KERNEL); + if (!controls) + return -ENOMEM; + + i = 0; + for_each_set_bit(control_sel, (unsigned long *)&control_list, + BITS_PER_TYPE(control_list)) { + struct fwnode_handle *control_node; + char control_property[SDCA_PROPERTY_LENGTH]; + + /* DisCo uses upper-case for hex numbers */ + snprintf(control_property, sizeof(control_property), + "mipi-sdca-control-0x%X-subproperties", control_sel); + + control_node = fwnode_get_named_child_node(entity_node, control_property); + if (!control_node) { + dev_err(dev, "%s: control node %s not found\n", + entity->label, control_property); + return -EINVAL; + } + + controls[i].sel = control_sel; + + ret = find_sdca_entity_control(dev, entity, control_node, &controls[i]); + fwnode_handle_put(control_node); + if (ret) + return ret; + + i++; + } + + entity->num_controls = num_controls; + entity->controls = controls; + + return 0; +} + +static bool find_sdca_iot_dataport(struct sdca_entity_iot *terminal) +{ + switch (terminal->type) { + case SDCA_TERM_TYPE_GENERIC: + case SDCA_TERM_TYPE_ULTRASOUND: + case SDCA_TERM_TYPE_CAPTURE_DIRECT_PCM_MIC: + case SDCA_TERM_TYPE_RAW_PDM_MIC: + case SDCA_TERM_TYPE_SPEECH: + case SDCA_TERM_TYPE_VOICE: + case SDCA_TERM_TYPE_SECONDARY_PCM_MIC: + case SDCA_TERM_TYPE_ACOUSTIC_CONTEXT_AWARENESS: + case SDCA_TERM_TYPE_DTOD_STREAM: + case SDCA_TERM_TYPE_REFERENCE_STREAM: + case SDCA_TERM_TYPE_SENSE_CAPTURE: + case SDCA_TERM_TYPE_STREAMING_MIC: + case SDCA_TERM_TYPE_OPTIMIZATION_STREAM: + case SDCA_TERM_TYPE_PDM_RENDER_STREAM: + case SDCA_TERM_TYPE_COMPANION_DATA: + return true; + default: + return false; + } +} + +static int find_sdca_entity_iot(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity_iot *terminal = &entity->iot; + u32 tmp; + int ret; + + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-terminal-type", &tmp); + if (ret) { + dev_err(dev, "%s: terminal type missing: %d\n", entity->label, ret); + return ret; + } + + terminal->type = tmp; + terminal->is_dataport = find_sdca_iot_dataport(terminal); + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-terminal-reference-number", &tmp); + if (!ret) + terminal->reference = tmp; + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-terminal-connector-type", &tmp); + if (!ret) + terminal->connector = tmp; + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-terminal-transducer-count", &tmp); + if (!ret) + terminal->num_transducer = tmp; + + dev_info(dev, "%s: terminal type %#x ref %#x conn %#x count %d\n", + entity->label, terminal->type, terminal->reference, + terminal->connector, terminal->num_transducer); + + return 0; +} + +static int find_sdca_entity_cs(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity_cs *clock = &entity->cs; + u32 tmp; + int ret; + + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-cs-type", &tmp); + if (ret) { + dev_err(dev, "%s: clock type missing: %d\n", entity->label, ret); + return ret; + } + + clock->type = tmp; + + ret = fwnode_property_read_u32(entity_node, + "mipi-sdca-clock-valid-max-delay", &tmp); + if (!ret) + clock->max_delay = tmp; + + dev_info(dev, "%s: clock type %#x delay %d\n", entity->label, + clock->type, clock->max_delay); + + return 0; +} + +static int find_sdca_entity_pde(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + static const int mult_delay = 3; + struct sdca_entity_pde *power = &entity->pde; + u32 *delay_list __free(kfree) = NULL; + struct sdca_pde_delay *delays; + int num_delays; + int i, j; + + num_delays = fwnode_property_count_u32(entity_node, + "mipi-sdca-powerdomain-transition-max-delay"); + if (num_delays <= 0) { + dev_err(dev, "%s: max delay list missing: %d\n", + entity->label, num_delays); + return -EINVAL; + } else if (num_delays % mult_delay != 0) { + dev_err(dev, "%s: delays not multiple of %d\n", + entity->label, mult_delay); + return -EINVAL; + } else if (num_delays > SDCA_MAX_DELAY_COUNT) { + dev_err(dev, "%s: maximum number of transition delays exceeded\n", + entity->label); + return -EINVAL; + } + + /* There are 3 values per delay */ + delays = devm_kcalloc(dev, num_delays / mult_delay, + sizeof(*delays), GFP_KERNEL); + if (!delays) + return -ENOMEM; + + delay_list = kcalloc(num_delays, sizeof(*delay_list), GFP_KERNEL); + if (!delay_list) + return -ENOMEM; + + fwnode_property_read_u32_array(entity_node, + "mipi-sdca-powerdomain-transition-max-delay", + delay_list, num_delays); + + num_delays /= mult_delay; + + for (i = 0, j = 0; i < num_delays; i++) { + delays[i].from_ps = delay_list[j++]; + delays[i].to_ps = delay_list[j++]; + delays[i].us = delay_list[j++]; + + dev_info(dev, "%s: from %#x to %#x delay %dus\n", entity->label, + delays[i].from_ps, delays[i].to_ps, delays[i].us); + } + + power->num_max_delay = num_delays; + power->max_delay = delays; + + return 0; +} + +struct raw_ge_mode { + u8 val; + u8 num_controls; + struct { + u8 id; + u8 sel; + u8 cn; + __le32 val; + } __packed controls[] __counted_by(num_controls); +} __packed; + +static int find_sdca_entity_ge(struct device *dev, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity_ge *group = &entity->ge; + u8 *affected_list __free(kfree) = NULL; + u8 *affected_iter; + int num_affected; + int i, j; + + num_affected = fwnode_property_count_u8(entity_node, + "mipi-sdca-ge-selectedmode-controls-affected"); + if (!num_affected) { + return 0; + } else if (num_affected < 0) { + dev_err(dev, "%s: failed to read affected controls: %d\n", + entity->label, num_affected); + return num_affected; + } else if (num_affected > SDCA_MAX_AFFECTED_COUNT) { + dev_err(dev, "%s: maximum affected controls size exceeded\n", + entity->label); + return -EINVAL; + } + + affected_list = kcalloc(num_affected, sizeof(*affected_list), GFP_KERNEL); + if (!affected_list) + return -ENOMEM; + + fwnode_property_read_u8_array(entity_node, + "mipi-sdca-ge-selectedmode-controls-affected", + affected_list, num_affected); + + group->num_modes = *affected_list; + affected_iter = affected_list + 1; + + group->modes = devm_kcalloc(dev, group->num_modes, sizeof(*group->modes), + GFP_KERNEL); + if (!group->modes) + return -ENOMEM; + + for (i = 0; i < group->num_modes; i++) { + struct raw_ge_mode *raw = (struct raw_ge_mode *)affected_iter; + struct sdca_ge_mode *mode = &group->modes[i]; + + affected_iter += sizeof(*raw); + if (affected_iter > affected_list + num_affected) + goto bad_list; + + mode->val = raw->val; + mode->num_controls = raw->num_controls; + + affected_iter += mode->num_controls * sizeof(raw->controls[0]); + if (affected_iter > affected_list + num_affected) + goto bad_list; + + mode->controls = devm_kcalloc(dev, mode->num_controls, + sizeof(*mode->controls), GFP_KERNEL); + if (!mode->controls) + return -ENOMEM; + + for (j = 0; j < mode->num_controls; j++) { + mode->controls[j].id = raw->controls[j].id; + mode->controls[j].sel = raw->controls[j].sel; + mode->controls[j].cn = raw->controls[j].cn; + mode->controls[j].val = le32_to_cpu(raw->controls[j].val); + } + } + + return 0; + +bad_list: + dev_err(dev, "%s: malformed affected controls list\n", entity->label); + return -EINVAL; +} + +static int find_sdca_entity(struct device *dev, + struct fwnode_handle *function_node, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + u32 tmp; + int ret; + + ret = fwnode_property_read_string(entity_node, "mipi-sdca-entity-label", + &entity->label); + if (ret) { + dev_err(dev, "%pfwP: entity %#x: label missing: %d\n", + function_node, entity->id, ret); + return ret; + } + + ret = fwnode_property_read_u32(entity_node, "mipi-sdca-entity-type", &tmp); + if (ret) { + dev_err(dev, "%s: type missing: %d\n", entity->label, ret); + return ret; + } + + entity->type = tmp; + + dev_info(dev, "%s: entity %#x type %#x\n", + entity->label, entity->id, entity->type); + + switch (entity->type) { + case SDCA_ENTITY_TYPE_IT: + case SDCA_ENTITY_TYPE_OT: + ret = find_sdca_entity_iot(dev, entity_node, entity); + break; + case SDCA_ENTITY_TYPE_CS: + ret = find_sdca_entity_cs(dev, entity_node, entity); + break; + case SDCA_ENTITY_TYPE_PDE: + ret = find_sdca_entity_pde(dev, entity_node, entity); + break; + case SDCA_ENTITY_TYPE_GE: + ret = find_sdca_entity_ge(dev, entity_node, entity); + break; + default: + break; + } + if (ret) + return ret; + + ret = find_sdca_entity_controls(dev, entity_node, entity); + if (ret) + return ret; + + return 0; +} + +static int find_sdca_entities(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + u32 *entity_list __free(kfree) = NULL; + struct sdca_entity *entities; + int num_entities; + int i, ret; + + num_entities = fwnode_property_count_u32(function_node, + "mipi-sdca-entity-id-list"); + if (num_entities <= 0) { + dev_err(dev, "%pfwP: entity id list missing: %d\n", + function_node, num_entities); + return -EINVAL; + } else if (num_entities > SDCA_MAX_ENTITY_COUNT) { + dev_err(dev, "%pfwP: maximum number of entities exceeded\n", + function_node); + return -EINVAL; + } + + /* Add 1 to make space for Entity 0 */ + entities = devm_kcalloc(dev, num_entities + 1, sizeof(*entities), GFP_KERNEL); + if (!entities) + return -ENOMEM; + + entity_list = kcalloc(num_entities, sizeof(*entity_list), GFP_KERNEL); + if (!entity_list) + return -ENOMEM; + + fwnode_property_read_u32_array(function_node, "mipi-sdca-entity-id-list", + entity_list, num_entities); + + for (i = 0; i < num_entities; i++) + entities[i].id = entity_list[i]; + + /* now read subproperties */ + for (i = 0; i < num_entities; i++) { + char entity_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *entity_node; + + /* DisCo uses upper-case for hex numbers */ + snprintf(entity_property, sizeof(entity_property), + "mipi-sdca-entity-id-0x%X-subproperties", entities[i].id); + + entity_node = fwnode_get_named_child_node(function_node, entity_property); + if (!entity_node) { + dev_err(dev, "%pfwP: entity node %s not found\n", + function_node, entity_property); + return -EINVAL; + } + + ret = find_sdca_entity(dev, function_node, entity_node, &entities[i]); + fwnode_handle_put(entity_node); + if (ret) + return ret; + } + + /* + * Add Entity 0 at end of the array, makes it easy to skip during + * all the Entity searches involved in creating connections. + */ + entities[num_entities].label = "entity0"; + + ret = find_sdca_entity_controls(dev, function_node, &entities[num_entities]); + if (ret) + return ret; + + function->num_entities = num_entities + 1; + function->entities = entities; + + return 0; +} + +static struct sdca_entity *find_sdca_entity_by_label(struct sdca_function_data *function, + const char *entity_label) +{ + int i; + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + if (!strcmp(entity->label, entity_label)) + return entity; + } + + return NULL; +} + +static struct sdca_entity *find_sdca_entity_by_id(struct sdca_function_data *function, + const int id) +{ + int i; + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + if (entity->id == id) + return entity; + } + + return NULL; +} + +static int find_sdca_entity_connection_iot(struct device *dev, + struct sdca_function_data *function, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity_iot *terminal = &entity->iot; + struct fwnode_handle *clock_node; + struct sdca_entity *clock_entity; + const char *clock_label; + int ret; + + clock_node = fwnode_get_named_child_node(entity_node, + "mipi-sdca-terminal-clock-connection"); + if (!clock_node) + return 0; + + ret = fwnode_property_read_string(clock_node, "mipi-sdca-entity-label", + &clock_label); + if (ret) { + dev_err(dev, "%s: clock label missing: %d\n", entity->label, ret); + fwnode_handle_put(clock_node); + return ret; + } + + clock_entity = find_sdca_entity_by_label(function, clock_label); + if (!clock_entity) { + dev_err(dev, "%s: failed to find clock with label %s\n", + entity->label, clock_label); + fwnode_handle_put(clock_node); + return -EINVAL; + } + + terminal->clock = clock_entity; + + dev_info(dev, "%s -> %s\n", clock_entity->label, entity->label); + + fwnode_handle_put(clock_node); + return 0; +} + +static int find_sdca_entity_connection_pde(struct device *dev, + struct sdca_function_data *function, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity_pde *power = &entity->pde; + u32 *managed_list __free(kfree) = NULL; + struct sdca_entity **managed; + int num_managed; + int i; + + num_managed = fwnode_property_count_u32(entity_node, + "mipi-sdca-powerdomain-managed-list"); + if (!num_managed) { + return 0; + } else if (num_managed < 0) { + dev_err(dev, "%s: managed list missing: %d\n", entity->label, num_managed); + return num_managed; + } else if (num_managed > SDCA_MAX_ENTITY_COUNT) { + dev_err(dev, "%s: maximum number of managed entities exceeded\n", + entity->label); + return -EINVAL; + } + + managed = devm_kcalloc(dev, num_managed, sizeof(*managed), GFP_KERNEL); + if (!managed) + return -ENOMEM; + + managed_list = kcalloc(num_managed, sizeof(*managed_list), GFP_KERNEL); + if (!managed_list) + return -ENOMEM; + + fwnode_property_read_u32_array(entity_node, + "mipi-sdca-powerdomain-managed-list", + managed_list, num_managed); + + for (i = 0; i < num_managed; i++) { + managed[i] = find_sdca_entity_by_id(function, managed_list[i]); + if (!managed[i]) { + dev_err(dev, "%s: failed to find entity with id %#x\n", + entity->label, managed_list[i]); + return -EINVAL; + } + + dev_info(dev, "%s -> %s\n", managed[i]->label, entity->label); + } + + power->num_managed = num_managed; + power->managed = managed; + + return 0; +} + +static int find_sdca_entity_connection_ge(struct device *dev, + struct sdca_function_data *function, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + int i, j; + + for (i = 0; i < entity->ge.num_modes; i++) { + struct sdca_ge_mode *mode = &entity->ge.modes[i]; + + for (j = 0; j < mode->num_controls; j++) { + struct sdca_ge_control *affected = &mode->controls[j]; + struct sdca_entity *managed; + + managed = find_sdca_entity_by_id(function, affected->id); + if (!managed) { + dev_err(dev, "%s: failed to find entity with id %#x\n", + entity->label, affected->id); + return -EINVAL; + } + + if (managed->group && managed->group != entity) { + dev_err(dev, + "%s: entity controlled by two groups %s, %s\n", + managed->label, managed->group->label, + entity->label); + return -EINVAL; + } + + managed->group = entity; + } + } + + return 0; +} + +static int find_sdca_entity_connection(struct device *dev, + struct sdca_function_data *function, + struct fwnode_handle *entity_node, + struct sdca_entity *entity) +{ + struct sdca_entity **pins; + int num_pins, pin; + u64 pin_list; + int i, ret; + + switch (entity->type) { + case SDCA_ENTITY_TYPE_IT: + case SDCA_ENTITY_TYPE_OT: + ret = find_sdca_entity_connection_iot(dev, function, + entity_node, entity); + break; + case SDCA_ENTITY_TYPE_PDE: + ret = find_sdca_entity_connection_pde(dev, function, + entity_node, entity); + break; + case SDCA_ENTITY_TYPE_GE: + ret = find_sdca_entity_connection_ge(dev, function, + entity_node, entity); + break; + default: + ret = 0; + break; + } + if (ret) + return ret; + + ret = fwnode_property_read_u64(entity_node, "mipi-sdca-input-pin-list", &pin_list); + if (ret == -EINVAL) { + /* Allow missing pin lists, assume no pins. */ + dev_warn(dev, "%s: missing pin list\n", entity->label); + return 0; + } else if (ret) { + dev_err(dev, "%s: failed to read pin list: %d\n", entity->label, ret); + return ret; + } else if (pin_list & BIT(0)) { + /* + * Each bit set in the pin-list refers to an entity_id in this + * Function. Entity 0 is an illegal connection since it is used + * for Function-level configurations. + */ + dev_err(dev, "%s: pin 0 used as input\n", entity->label); + return -EINVAL; + } else if (!pin_list) { + return 0; + } + + num_pins = hweight64(pin_list); + pins = devm_kcalloc(dev, num_pins, sizeof(*pins), GFP_KERNEL); + if (!pins) + return -ENOMEM; + + i = 0; + for_each_set_bit(pin, (unsigned long *)&pin_list, BITS_PER_TYPE(pin_list)) { + char pin_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *connected_node; + struct sdca_entity *connected_entity; + const char *connected_label; + + snprintf(pin_property, sizeof(pin_property), "mipi-sdca-input-pin-%d", pin); + + connected_node = fwnode_get_named_child_node(entity_node, pin_property); + if (!connected_node) { + dev_err(dev, "%s: pin node %s not found\n", + entity->label, pin_property); + return -EINVAL; + } + + ret = fwnode_property_read_string(connected_node, "mipi-sdca-entity-label", + &connected_label); + if (ret) { + dev_err(dev, "%s: pin %d label missing: %d\n", + entity->label, pin, ret); + fwnode_handle_put(connected_node); + return ret; + } + + connected_entity = find_sdca_entity_by_label(function, connected_label); + if (!connected_entity) { + dev_err(dev, "%s: failed to find entity with label %s\n", + entity->label, connected_label); + fwnode_handle_put(connected_node); + return -EINVAL; + } + + pins[i] = connected_entity; + + dev_info(dev, "%s -> %s\n", connected_entity->label, entity->label); + + i++; + fwnode_handle_put(connected_node); + } + + entity->num_sources = num_pins; + entity->sources = pins; + + return 0; +} + +static int find_sdca_connections(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + int i; + + /* Entity 0 cannot have connections */ + for (i = 0; i < function->num_entities - 1; i++) { + struct sdca_entity *entity = &function->entities[i]; + char entity_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *entity_node; + int ret; + + /* DisCo uses upper-case for hex numbers */ + snprintf(entity_property, sizeof(entity_property), + "mipi-sdca-entity-id-0x%X-subproperties", + entity->id); + + entity_node = fwnode_get_named_child_node(function_node, entity_property); + if (!entity_node) { + dev_err(dev, "%pfwP: entity node %s not found\n", + function_node, entity_property); + return -EINVAL; + } + + ret = find_sdca_entity_connection(dev, function, entity_node, entity); + fwnode_handle_put(entity_node); + if (ret) + return ret; + } + + return 0; +} + +static int find_sdca_cluster_channel(struct device *dev, + struct sdca_cluster *cluster, + struct fwnode_handle *channel_node, + struct sdca_channel *channel) +{ + u32 tmp; + int ret; + + ret = fwnode_property_read_u32(channel_node, "mipi-sdca-cluster-channel-id", &tmp); + if (ret) { + dev_err(dev, "cluster %#x: missing channel id: %d\n", + cluster->id, ret); + return ret; + } + + channel->id = tmp; + + ret = fwnode_property_read_u32(channel_node, + "mipi-sdca-cluster-channel-purpose", + &tmp); + if (ret) { + dev_err(dev, "cluster %#x: channel %#x: missing purpose: %d\n", + cluster->id, channel->id, ret); + return ret; + } + + channel->purpose = tmp; + + ret = fwnode_property_read_u32(channel_node, + "mipi-sdca-cluster-channel-relationship", + &tmp); + if (ret) { + dev_err(dev, "cluster %#x: channel %#x: missing relationship: %d\n", + cluster->id, channel->id, ret); + return ret; + } + + channel->relationship = tmp; + + dev_info(dev, "cluster %#x: channel id %#x purpose %#x relationship %#x\n", + cluster->id, channel->id, channel->purpose, channel->relationship); + + return 0; +} + +static int find_sdca_cluster_channels(struct device *dev, + struct fwnode_handle *cluster_node, + struct sdca_cluster *cluster) +{ + struct sdca_channel *channels; + u32 num_channels; + int i, ret; + + ret = fwnode_property_read_u32(cluster_node, "mipi-sdca-channel-count", + &num_channels); + if (ret < 0) { + dev_err(dev, "cluster %#x: failed to read channel list: %d\n", + cluster->id, ret); + return ret; + } else if (num_channels > SDCA_MAX_CHANNEL_COUNT) { + dev_err(dev, "cluster %#x: maximum number of channels exceeded\n", + cluster->id); + return -EINVAL; + } + + channels = devm_kcalloc(dev, num_channels, sizeof(*channels), GFP_KERNEL); + if (!channels) + return -ENOMEM; + + for (i = 0; i < num_channels; i++) { + char channel_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *channel_node; + + /* DisCo uses upper-case for hex numbers */ + snprintf(channel_property, sizeof(channel_property), + "mipi-sdca-channel-%d-subproperties", i + 1); + + channel_node = fwnode_get_named_child_node(cluster_node, channel_property); + if (!channel_node) { + dev_err(dev, "cluster %#x: channel node %s not found\n", + cluster->id, channel_property); + return -EINVAL; + } + + ret = find_sdca_cluster_channel(dev, cluster, channel_node, &channels[i]); + fwnode_handle_put(channel_node); + if (ret) + return ret; + } + + cluster->num_channels = num_channels; + cluster->channels = channels; + + return 0; +} + +static int find_sdca_clusters(struct device *dev, + struct fwnode_handle *function_node, + struct sdca_function_data *function) +{ + u32 *cluster_list __free(kfree) = NULL; + struct sdca_cluster *clusters; + int num_clusters; + int i, ret; + + num_clusters = fwnode_property_count_u32(function_node, "mipi-sdca-cluster-id-list"); + if (!num_clusters || num_clusters == -EINVAL) { + return 0; + } else if (num_clusters < 0) { + dev_err(dev, "%pfwP: failed to read cluster id list: %d\n", + function_node, num_clusters); + return num_clusters; + } else if (num_clusters > SDCA_MAX_CLUSTER_COUNT) { + dev_err(dev, "%pfwP: maximum number of clusters exceeded\n", function_node); + return -EINVAL; + } + + clusters = devm_kcalloc(dev, num_clusters, sizeof(*clusters), GFP_KERNEL); + if (!clusters) + return -ENOMEM; + + cluster_list = kcalloc(num_clusters, sizeof(*cluster_list), GFP_KERNEL); + if (!cluster_list) + return -ENOMEM; + + fwnode_property_read_u32_array(function_node, "mipi-sdca-cluster-id-list", + cluster_list, num_clusters); + + for (i = 0; i < num_clusters; i++) + clusters[i].id = cluster_list[i]; + + /* now read subproperties */ + for (i = 0; i < num_clusters; i++) { + char cluster_property[SDCA_PROPERTY_LENGTH]; + struct fwnode_handle *cluster_node; + + /* DisCo uses upper-case for hex numbers */ + snprintf(cluster_property, sizeof(cluster_property), + "mipi-sdca-cluster-id-0x%X-subproperties", clusters[i].id); + + cluster_node = fwnode_get_named_child_node(function_node, cluster_property); + if (!cluster_node) { + dev_err(dev, "%pfwP: cluster node %s not found\n", + function_node, cluster_property); + return -EINVAL; + } + + ret = find_sdca_cluster_channels(dev, cluster_node, &clusters[i]); + fwnode_handle_put(cluster_node); + if (ret) + return ret; + } + + function->num_clusters = num_clusters; + function->clusters = clusters; + + return 0; +} + +/** + * sdca_parse_function - parse ACPI DisCo for a Function + * @dev: Pointer to device against which function data will be allocated. + * @function_desc: Pointer to the Function short descriptor. + * @function: Pointer to the Function information, to be populated. + * + * Return: Returns 0 for success. + */ +int sdca_parse_function(struct device *dev, + struct sdca_function_desc *function_desc, + struct sdca_function_data *function) +{ + u32 tmp; + int ret; + + function->desc = function_desc; + + ret = fwnode_property_read_u32(function_desc->node, + "mipi-sdca-function-busy-max-delay", &tmp); + if (!ret) + function->busy_max_delay = tmp; + + dev_info(dev, "%pfwP: name %s delay %dus\n", function->desc->node, + function->desc->name, function->busy_max_delay); + + ret = find_sdca_init_table(dev, function_desc->node, function); + if (ret) + return ret; + + ret = find_sdca_entities(dev, function_desc->node, function); + if (ret) + return ret; + + ret = find_sdca_connections(dev, function_desc->node, function); + if (ret) + return ret; + + ret = find_sdca_clusters(dev, function_desc->node, function); + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL_NS(sdca_parse_function, "SND_SOC_SDCA"); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SDCA library"); diff --git a/sound/soc/sdca/sdca_regmap.c b/sound/soc/sdca/sdca_regmap.c new file mode 100644 index 000000000000..4b78188cfceb --- /dev/null +++ b/sound/soc/sdca/sdca_regmap.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +/* + * The MIPI SDCA specification is available for public downloads at + * https://www.mipi.org/mipi-sdca-v1-0-download + */ + +#include <linux/bitops.h> +#include <linux/minmax.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/soundwire/sdw_registers.h> +#include <linux/types.h> +#include <sound/sdca.h> +#include <sound/sdca_function.h> +#include <sound/sdca_regmap.h> + +static struct sdca_entity * +function_find_entity(struct sdca_function_data *function, unsigned int reg) +{ + int i; + + for (i = 0; i < function->num_entities; i++) + if (SDW_SDCA_CTL_ENT(reg) == function->entities[i].id) + return &function->entities[i]; + + return NULL; +} + +static struct sdca_control * +entity_find_control(struct sdca_entity *entity, unsigned int reg) +{ + int i; + + for (i = 0; i < entity->num_controls; i++) { + if (SDW_SDCA_CTL_CSEL(reg) == entity->controls[i].sel) + return &entity->controls[i]; + } + + return NULL; +} + +static struct sdca_control * +function_find_control(struct sdca_function_data *function, unsigned int reg) +{ + struct sdca_entity *entity; + + entity = function_find_entity(function, reg); + if (!entity) + return NULL; + + return entity_find_control(entity, reg); +} + +/** + * sdca_regmap_readable - return if a given SDCA Control is readable + * @function: Pointer to the Function information. + * @reg: Register address/Control to be processed. + * + * Return: Returns true if the register is readable. + */ +bool sdca_regmap_readable(struct sdca_function_data *function, unsigned int reg) +{ + struct sdca_control *control; + + if (!SDW_SDCA_VALID_CTL(reg)) + return false; + + control = function_find_control(function, reg); + if (!control) + return false; + + switch (control->mode) { + case SDCA_ACCESS_MODE_RW: + case SDCA_ACCESS_MODE_RO: + case SDCA_ACCESS_MODE_DUAL: + case SDCA_ACCESS_MODE_RW1S: + case SDCA_ACCESS_MODE_RW1C: + /* No access to registers marked solely for device use */ + return control->layers & ~SDCA_ACCESS_LAYER_DEVICE; + default: + return false; + } +} +EXPORT_SYMBOL_NS(sdca_regmap_readable, "SND_SOC_SDCA"); + +/** + * sdca_regmap_writeable - return if a given SDCA Control is writeable + * @function: Pointer to the Function information. + * @reg: Register address/Control to be processed. + * + * Return: Returns true if the register is writeable. + */ +bool sdca_regmap_writeable(struct sdca_function_data *function, unsigned int reg) +{ + struct sdca_control *control; + + if (!SDW_SDCA_VALID_CTL(reg)) + return false; + + control = function_find_control(function, reg); + if (!control) + return false; + + switch (control->mode) { + case SDCA_ACCESS_MODE_RW: + case SDCA_ACCESS_MODE_DUAL: + case SDCA_ACCESS_MODE_RW1S: + case SDCA_ACCESS_MODE_RW1C: + /* No access to registers marked solely for device use */ + return control->layers & ~SDCA_ACCESS_LAYER_DEVICE; + default: + return false; + } +} +EXPORT_SYMBOL_NS(sdca_regmap_writeable, "SND_SOC_SDCA"); + +/** + * sdca_regmap_volatile - return if a given SDCA Control is volatile + * @function: Pointer to the Function information. + * @reg: Register address/Control to be processed. + * + * Return: Returns true if the register is volatile. + */ +bool sdca_regmap_volatile(struct sdca_function_data *function, unsigned int reg) +{ + struct sdca_control *control; + + if (!SDW_SDCA_VALID_CTL(reg)) + return false; + + control = function_find_control(function, reg); + if (!control) + return false; + + switch (control->mode) { + case SDCA_ACCESS_MODE_RO: + case SDCA_ACCESS_MODE_RW1S: + case SDCA_ACCESS_MODE_RW1C: + return true; + default: + return false; + } +} +EXPORT_SYMBOL_NS(sdca_regmap_volatile, "SND_SOC_SDCA"); + +/** + * sdca_regmap_deferrable - return if a given SDCA Control is deferrable + * @function: Pointer to the Function information. + * @reg: Register address/Control to be processed. + * + * Return: Returns true if the register is deferrable. + */ +bool sdca_regmap_deferrable(struct sdca_function_data *function, unsigned int reg) +{ + struct sdca_control *control; + + if (!SDW_SDCA_VALID_CTL(reg)) + return false; + + control = function_find_control(function, reg); + if (!control) + return false; + + return control->deferrable; +} +EXPORT_SYMBOL_NS(sdca_regmap_deferrable, "SND_SOC_SDCA"); + +/** + * sdca_regmap_mbq_size - return size in bytes of a given SDCA Control + * @function: Pointer to the Function information. + * @reg: Register address/Control to be processed. + * + * Return: Returns the size in bytes of the Control. + */ +int sdca_regmap_mbq_size(struct sdca_function_data *function, unsigned int reg) +{ + struct sdca_control *control; + + if (!SDW_SDCA_VALID_CTL(reg)) + return -EINVAL; + + control = function_find_control(function, reg); + if (!control) + return false; + + return clamp_val(control->nbits / BITS_PER_BYTE, sizeof(u8), sizeof(u32)); +} +EXPORT_SYMBOL_NS(sdca_regmap_mbq_size, "SND_SOC_SDCA"); + +/** + * sdca_regmap_count_constants - count the number of DisCo constant Controls + * @dev: Pointer to the device. + * @function: Pointer to the Function information, to be parsed. + * + * This function returns the number of DisCo constant Controls present + * in a function. Typically this information will be used to populate + * the regmap defaults array, allowing drivers to access the values of + * DisCo constants as any other physical register. + * + * Return: Returns number of DisCo constant controls, or a negative error + * code on failure. + */ +int sdca_regmap_count_constants(struct device *dev, + struct sdca_function_data *function) +{ + int nconsts = 0; + int i, j; + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + for (j = 0; j < entity->num_controls; j++) { + if (entity->controls[j].mode == SDCA_ACCESS_MODE_DC) + nconsts += hweight64(entity->controls[j].cn_list); + } + } + + return nconsts; +} +EXPORT_SYMBOL_NS(sdca_regmap_count_constants, "SND_SOC_SDCA"); + +/** + * sdca_regmap_populate_constants - fill an array with DisCo constant values + * @dev: Pointer to the device. + * @function: Pointer to the Function information, to be parsed. + * @consts: Pointer to the array which should be filled with the DisCo + * constant values. + * + * This function will populate a regmap struct reg_default array with + * the values of the DisCo constants for a given Function. This + * allows to access the values of DisCo constants the same as any + * other physical register. + * + * Return: Returns the number of constants populated on success, a negative + * error code on failure. + */ +int sdca_regmap_populate_constants(struct device *dev, + struct sdca_function_data *function, + struct reg_default *consts) +{ + int i, j, k; + + for (i = 0, k = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + for (j = 0; j < entity->num_controls; j++) { + struct sdca_control *control = &entity->controls[j]; + int cn; + + if (control->mode != SDCA_ACCESS_MODE_DC) + continue; + + for_each_set_bit(cn, (unsigned long *)&control->cn_list, + BITS_PER_TYPE(control->cn_list)) { + consts[k].reg = SDW_SDCA_CTL(function->desc->adr, + entity->id, + control->sel, cn); + consts[k].def = control->value; + k++; + } + } + } + + return k; +} +EXPORT_SYMBOL_NS(sdca_regmap_populate_constants, "SND_SOC_SDCA"); + +/** + * sdca_regmap_write_defaults - write out DisCo defaults to device + * @dev: Pointer to the device. + * @regmap: Pointer to the Function register map. + * @function: Pointer to the Function information, to be parsed. + * + * This function will write out to the hardware all the DisCo default and + * fixed value controls. This will cause them to be populated into the cache, + * and subsequent handling can be done through a cache sync. + * + * Return: Returns zero on success, and a negative error code on failure. + */ +int sdca_regmap_write_defaults(struct device *dev, struct regmap *regmap, + struct sdca_function_data *function) +{ + int i, j; + int ret; + + for (i = 0; i < function->num_entities; i++) { + struct sdca_entity *entity = &function->entities[i]; + + for (j = 0; j < entity->num_controls; j++) { + struct sdca_control *control = &entity->controls[j]; + int cn; + + if (control->mode == SDCA_ACCESS_MODE_DC) + continue; + + if (!control->has_default && !control->has_fixed) + continue; + + for_each_set_bit(cn, (unsigned long *)&control->cn_list, + BITS_PER_TYPE(control->cn_list)) { + unsigned int reg; + + reg = SDW_SDCA_CTL(function->desc->adr, entity->id, + control->sel, cn); + + ret = regmap_write(regmap, reg, control->value); + if (ret) + return ret; + } + } + } + + return 0; +} +EXPORT_SYMBOL_NS(sdca_regmap_write_defaults, "SND_SOC_SDCA"); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SDCA library"); diff --git a/sound/soc/sdw_utils/soc_sdw_utils.c b/sound/soc/sdw_utils/soc_sdw_utils.c index 6ee7d30b8ece..5175818ff2c1 100644 --- a/sound/soc/sdw_utils/soc_sdw_utils.c +++ b/sound/soc/sdw_utils/soc_sdw_utils.c @@ -586,8 +586,20 @@ struct asoc_sdw_codec_info codec_info_list[] = { .dai_type = SOC_SDW_DAI_TYPE_JACK, .dailink = {SOC_SDW_JACK_OUT_DAI_ID, SOC_SDW_JACK_IN_DAI_ID}, }, + { + .direction = {true, false}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_AMP, + .dailink = {SOC_SDW_AMP_OUT_DAI_ID, SOC_SDW_UNUSED_DAI_ID}, + }, + { + .direction = {false, true}, + .dai_name = "sdw-mockup-aif1", + .dai_type = SOC_SDW_DAI_TYPE_MIC, + .dailink = {SOC_SDW_UNUSED_DAI_ID, SOC_SDW_DMIC_DAI_ID}, + }, }, - .dai_num = 1, + .dai_num = 3, }, { .part_id = 0xaa55, /* headset codec mockup */ diff --git a/sound/soc/soc-card.c b/sound/soc/soc-card.c index e6eb71b3010a..235427d69061 100644 --- a/sound/soc/soc-card.c +++ b/sound/soc/soc-card.c @@ -15,18 +15,8 @@ static inline int _soc_card_ret(struct snd_soc_card *card, const char *func, int ret) { - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - case 0: - break; - default: - dev_err(card->dev, - "ASoC: error at %s on %s: %d\n", - func, card->name, ret); - } - - return ret; + return snd_soc_ret(card->dev, ret, + "at %s() on %s\n", func, card->name); } struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, diff --git a/sound/soc/soc-component.c b/sound/soc/soc-component.c index b67ef78f405c..25f5e543ae8d 100644 --- a/sound/soc/soc-component.c +++ b/sound/soc/soc-component.c @@ -13,32 +13,20 @@ #include <sound/soc.h> #include <linux/bitops.h> -#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret, -1) -#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret(dai, __func__, ret, reg) -static inline int _soc_component_ret(struct snd_soc_component *component, - const char *func, int ret, int reg) -{ - /* Positive/Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - if (reg == -1) - dev_err(component->dev, - "ASoC: error at %s on %s: %d\n", - func, component->name, ret); - else - dev_err(component->dev, - "ASoC: error at %s on %s for register: [0x%08x] %d\n", - func, component->name, reg, ret); - } +#define soc_component_ret(dai, ret) _soc_component_ret(dai, __func__, ret) +static inline int _soc_component_ret(struct snd_soc_component *component, const char *func, int ret) +{ + return snd_soc_ret(component->dev, ret, + "at %s() on %s\n", func, component->name); +} - return ret; +#define soc_component_ret_reg_rw(dai, ret, reg) _soc_component_ret_reg_rw(dai, __func__, ret, reg) +static inline int _soc_component_ret_reg_rw(struct snd_soc_component *component, + const char *func, int ret, int reg) +{ + return snd_soc_ret(component->dev, ret, + "at %s() on %s for register: [0x%08x]\n", + func, component->name, reg); } static inline int soc_component_field_shift(struct snd_soc_component *component, diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 563dc0767c17..01d1d6bee28c 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c @@ -148,7 +148,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) snd_soc_dpcm_mutex_lock(fe); /* calculate valid and active FE <-> BE dpcms */ - dpcm_process_paths(fe, stream, &list, 1); + dpcm_add_paths(fe, stream, &list); fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3c6d8aef4130..3f97d1f132c6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -32,6 +32,7 @@ #include <linux/of_graph.h> #include <linux/dmi.h> #include <linux/acpi.h> +#include <linux/string_choices.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> @@ -430,7 +431,7 @@ void snd_soc_close_delayed_work(struct snd_soc_pcm_runtime *rtd) codec_dai->driver->playback.stream_name, snd_soc_dai_stream_active(codec_dai, playback) ? "active" : "inactive", - rtd->pop_wait ? "yes" : "no"); + str_yes_no(rtd->pop_wait)); /* are we waiting on this codec DAI stream */ if (rtd->pop_wait == 1) { @@ -1887,7 +1888,6 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str) /** * snd_soc_set_dmi_name() - Register DMI names to card * @card: The card to register DMI names - * @flavour: The flavour "differentiator" for the card amongst its peers. * * An Intel machine driver may be used by many different devices but are * difficult for userspace to differentiate, since machine drivers usually @@ -1915,7 +1915,7 @@ static void append_dmi_string(struct snd_soc_card *card, const char *str) * * Returns 0 on success, otherwise a negative error code. */ -int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) +static int snd_soc_set_dmi_name(struct snd_soc_card *card) { const char *vendor, *product, *board; @@ -1959,16 +1959,16 @@ int snd_soc_set_dmi_name(struct snd_soc_card *card, const char *flavour) return 0; } - /* Add flavour to dmi long name */ - if (flavour) - append_dmi_string(card, flavour); - /* set the card long name */ card->long_name = card->dmi_longname; return 0; } -EXPORT_SYMBOL_GPL(snd_soc_set_dmi_name); +#else +static inline int snd_soc_set_dmi_name(struct snd_soc_card *card) +{ + return 0; +} #endif /* CONFIG_DMI */ static void soc_check_tplg_fes(struct snd_soc_card *card) @@ -2256,7 +2256,7 @@ static int snd_soc_bind_card(struct snd_soc_card *card) goto probe_end; /* try to set some sane longname if DMI is available */ - snd_soc_set_dmi_name(card, NULL); + snd_soc_set_dmi_name(card); soc_setup_card_name(card, card->snd_card->shortname, card->name, NULL); @@ -3046,7 +3046,7 @@ int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop) unsigned int i, nb_controls; int ret; - if (!of_property_read_bool(dev->of_node, prop)) + if (!of_property_present(dev->of_node, prop)) return 0; strings = devm_kcalloc(dev, nb_controls_max, @@ -3120,23 +3120,17 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, if (rx_mask) snd_soc_of_get_slot_mask(np, "dai-tdm-slot-rx-mask", rx_mask); - if (of_property_read_bool(np, "dai-tdm-slot-num")) { - ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); - if (ret) - return ret; - - if (slots) - *slots = val; - } - - if (of_property_read_bool(np, "dai-tdm-slot-width")) { - ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); - if (ret) - return ret; + ret = of_property_read_u32(np, "dai-tdm-slot-num", &val); + if (ret && ret != -EINVAL) + return ret; + if (!ret && slots) + *slots = val; - if (slot_width) - *slot_width = val; - } + ret = of_property_read_u32(np, "dai-tdm-slot-width", &val); + if (ret && ret != -EINVAL) + return ret; + if (!ret && slot_width) + *slot_width = val; return 0; } @@ -3403,12 +3397,12 @@ unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np, * check "[prefix]frame-master" */ snprintf(prop, sizeof(prop), "%sbitclock-master", prefix); - bit = of_property_read_bool(np, prop); + bit = of_property_present(np, prop); if (bit && bitclkmaster) *bitclkmaster = of_parse_phandle(np, prop, 0); snprintf(prop, sizeof(prop), "%sframe-master", prefix); - frame = of_property_read_bool(np, prop); + frame = of_property_present(np, prop); if (frame && framemaster) *framemaster = of_parse_phandle(np, prop, 0); diff --git a/sound/soc/soc-dai.c b/sound/soc/soc-dai.c index ca0308f6d41c..a210089747d0 100644 --- a/sound/soc/soc-dai.c +++ b/sound/soc/soc-dai.c @@ -14,22 +14,8 @@ static inline int _soc_dai_ret(const struct snd_soc_dai *dai, const char *func, int ret) { - /* Positive, Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - dev_err(dai->dev, - "ASoC: error at %s on %s: %d\n", - func, dai->name, ret); - } - - return ret; + return snd_soc_ret(dai->dev, ret, + "at %s() on %s\n", func, dai->name); } /* @@ -275,10 +261,11 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, if (dai->driver->ops && dai->driver->ops->xlate_tdm_slot_mask) - dai->driver->ops->xlate_tdm_slot_mask(slots, - &tx_mask, &rx_mask); + ret = dai->driver->ops->xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); else - snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + ret = snd_soc_xlate_tdm_slot_mask(slots, &tx_mask, &rx_mask); + if (ret) + goto err; for_each_pcm_streams(stream) snd_soc_dai_tdm_mask_set(dai, stream, *tdm_mask[stream]); @@ -287,6 +274,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, dai->driver->ops->set_tdm_slot) ret = dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, slots, slot_width); +err: return soc_dai_ret(dai, ret); } EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); @@ -376,6 +364,14 @@ int snd_soc_dai_prepare(struct snd_soc_dai *dai, } EXPORT_SYMBOL_GPL(snd_soc_dai_prepare); +int snd_soc_dai_mute_is_ctrled_at_trigger(struct snd_soc_dai *dai) +{ + if (dai->driver->ops) + return dai->driver->ops->mute_unmute_on_trigger; + + return 0; +} + /** * snd_soc_dai_digital_mute - configure DAI system or master clock. * @dai: DAI @@ -632,7 +628,7 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, if (ret < 0) break; - if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger) + if (snd_soc_dai_mute_is_ctrled_at_trigger(dai)) snd_soc_dai_digital_mute(dai, 0, substream->stream); soc_dai_mark_push(dai, substream, trigger); @@ -645,7 +641,7 @@ int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, if (rollback && !soc_dai_mark_match(dai, substream, trigger)) continue; - if (dai->driver->ops && dai->driver->ops->mute_unmute_on_trigger) + if (snd_soc_dai_mute_is_ctrled_at_trigger(dai)) snd_soc_dai_digital_mute(dai, 1, substream->stream); r = soc_dai_trigger(dai, substream, cmd); diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index b5116b700d73..b7818388984e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -317,7 +317,6 @@ void dapm_mark_endpoints_dirty(struct snd_soc_card *card) snd_soc_dapm_mutex_unlock(card); } -EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty); /* create a new dapm widget */ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( @@ -1744,9 +1743,8 @@ static void dapm_seq_run(struct snd_soc_card *card, soc_dapm_async_complete(d); } -static void dapm_widget_update(struct snd_soc_card *card) +static void dapm_widget_update(struct snd_soc_card *card, struct snd_soc_dapm_update *update) { - struct snd_soc_dapm_update *update = card->update; struct snd_soc_dapm_widget_list *wlist; struct snd_soc_dapm_widget *w = NULL; unsigned int wi; @@ -1952,7 +1950,8 @@ static bool dapm_idle_bias_off(struct snd_soc_dapm_context *dapm) * o Input pin to Output pin (bypass, sidetone) * o DAC to ADC (loopback). */ -static int dapm_power_widgets(struct snd_soc_card *card, int event) +static int dapm_power_widgets(struct snd_soc_card *card, int event, + struct snd_soc_dapm_update *update) { struct snd_soc_dapm_widget *w; struct snd_soc_dapm_context *d; @@ -2060,7 +2059,7 @@ static int dapm_power_widgets(struct snd_soc_card *card, int event) /* Power down widgets first; try to avoid amplifying pops. */ dapm_seq_run(card, &down_list, event, false); - dapm_widget_update(card); + dapm_widget_update(card, update); /* Now power up. */ dapm_seq_run(card, &up_list, event, true); @@ -2333,7 +2332,9 @@ static void soc_dapm_connect_path(struct snd_soc_dapm_path *path, /* test and update the power status of a mux widget */ static int soc_dapm_mux_update_power(struct snd_soc_card *card, - struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e) + struct snd_kcontrol *kcontrol, + struct snd_soc_dapm_update *update, + int mux, struct soc_enum *e) { struct snd_soc_dapm_path *path; int found = 0; @@ -2354,7 +2355,7 @@ static int soc_dapm_mux_update_power(struct snd_soc_card *card, } if (found) - dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); + dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP, update); return found; } @@ -2367,9 +2368,7 @@ int snd_soc_dapm_mux_update_power(struct snd_soc_dapm_context *dapm, int ret; snd_soc_dapm_mutex_lock(card); - card->update = update; - ret = soc_dapm_mux_update_power(card, kcontrol, mux, e); - card->update = NULL; + ret = soc_dapm_mux_update_power(card, kcontrol, update, mux, e); snd_soc_dapm_mutex_unlock(card); if (ret > 0) snd_soc_dpcm_runtime_update(card); @@ -2380,6 +2379,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_mux_update_power); /* test and update the power status of a mixer or switch widget */ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, struct snd_kcontrol *kcontrol, + struct snd_soc_dapm_update *update, int connect, int rconnect) { struct snd_soc_dapm_path *path; @@ -2419,7 +2419,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card, } if (found) - dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); + dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP, update); return found; } @@ -2432,9 +2432,7 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, int ret; snd_soc_dapm_mutex_lock(card); - card->update = update; - ret = soc_dapm_mixer_update_power(card, kcontrol, connect, -1); - card->update = NULL; + ret = soc_dapm_mixer_update_power(card, kcontrol, update, connect, -1); snd_soc_dapm_mutex_unlock(card); if (ret > 0) snd_soc_dpcm_runtime_update(card); @@ -2690,7 +2688,7 @@ int snd_soc_dapm_sync_unlocked(struct snd_soc_dapm_context *dapm) if (!snd_soc_card_is_instantiated(dapm->card)) return 0; - return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP); + return dapm_power_widgets(dapm->card, SND_SOC_DAPM_STREAM_NOP, NULL); } EXPORT_SYMBOL_GPL(snd_soc_dapm_sync_unlocked); @@ -2783,7 +2781,6 @@ int snd_soc_dapm_update_dai(struct snd_pcm_substream *substream, return ret; } -EXPORT_SYMBOL_GPL(snd_soc_dapm_update_dai); int snd_soc_dapm_widget_name_cmp(struct snd_soc_dapm_widget *widget, const char *s) { @@ -3360,7 +3357,7 @@ int snd_soc_dapm_new_widgets(struct snd_soc_card *card) dapm_debugfs_add_widget(w); } - dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP); + dapm_power_widgets(card, SND_SOC_DAPM_STREAM_NOP, NULL); snd_soc_dapm_mutex_unlock(card); return 0; } @@ -3449,6 +3446,7 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, unsigned int val, rval = 0; int connect, rconnect = -1, change, reg_change = 0; struct snd_soc_dapm_update update = {}; + struct snd_soc_dapm_update *pupdate = NULL; int ret = 0; val = (ucontrol->value.integer.value[0] & mask); @@ -3497,13 +3495,9 @@ int snd_soc_dapm_put_volsw(struct snd_kcontrol *kcontrol, update.reg = reg; update.mask = mask << shift; update.val = val; - card->update = &update; + pupdate = &update; } - - ret = soc_dapm_mixer_update_power(card, kcontrol, connect, - rconnect); - - card->update = NULL; + ret = soc_dapm_mixer_update_power(card, kcontrol, pupdate, connect, rconnect); } snd_soc_dapm_mutex_unlock(card); @@ -3570,6 +3564,7 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, unsigned int val, change, reg_change = 0; unsigned int mask; struct snd_soc_dapm_update update = {}; + struct snd_soc_dapm_update *pupdate = NULL; int ret = 0; if (item[0] >= e->items) @@ -3597,12 +3592,9 @@ int snd_soc_dapm_put_enum_double(struct snd_kcontrol *kcontrol, update.reg = e->reg; update.mask = mask; update.val = val; - card->update = &update; + pupdate = &update; } - - ret = soc_dapm_mux_update_power(card, kcontrol, item[0], e); - - card->update = NULL; + ret = soc_dapm_mux_update_power(card, kcontrol, pupdate, item[0], e); } snd_soc_dapm_mutex_unlock(card); @@ -4528,7 +4520,7 @@ static void soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, for_each_rtd_dais(rtd, i, dai) soc_dapm_dai_stream_event(dai, stream, event); - dapm_power_widgets(rtd->card, event); + dapm_power_widgets(rtd->card, event, NULL); } /** @@ -4865,7 +4857,6 @@ void snd_soc_dapm_init(struct snd_soc_dapm_context *dapm, /* see for_each_card_dapms */ list_add(&dapm->list, &card->dapm_list); } -EXPORT_SYMBOL_GPL(snd_soc_dapm_init); static void soc_dapm_shutdown_dapm(struct snd_soc_dapm_context *dapm) { diff --git a/sound/soc/soc-link.c b/sound/soc/soc-link.c index 7f1f1bc717e2..02fd68f2e702 100644 --- a/sound/soc/soc-link.c +++ b/sound/soc/soc-link.c @@ -12,22 +12,8 @@ static inline int _soc_link_ret(struct snd_soc_pcm_runtime *rtd, const char *func, int ret) { - /* Positive, Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - dev_err(rtd->dev, - "ASoC: error at %s on %s: %d\n", - func, rtd->dai_link->name, ret); - } - - return ret; + return snd_soc_ret(rtd->dev, ret, + "at %s() on %s\n", func, rtd->dai_link->name); } /* diff --git a/sound/soc/soc-ops-test.c b/sound/soc/soc-ops-test.c new file mode 100644 index 000000000000..dc1e482bba6a --- /dev/null +++ b/sound/soc/soc-ops-test.c @@ -0,0 +1,541 @@ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2025 Cirrus Logic, Inc. and +// Cirrus Logic International Semiconductor Ltd. + +#include <kunit/device.h> +#include <kunit/test.h> +#include <linux/module.h> +#include <linux/regmap.h> +#include <linux/string.h> +#include <sound/asound.h> +#include <sound/control.h> +#include <sound/soc.h> +#include <sound/soc-component.h> + +enum soc_ops_test_control_layout { + SOC_OPS_TEST_SINGLE, + SOC_OPS_TEST_DOUBLE, + SOC_OPS_TEST_DOUBLE_R, +}; + +#define TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert) \ + .mc = { \ + .min = xmin, .max = xmax, .platform_max = xpmax, \ + .reg = 0, .shift = 0, .sign_bit = xsign, .invert = xinvert, \ + .rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? 1 : 0, \ + .rshift = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? 16 : 0, \ + } + +#define TEST_UINFO(clayout, ctype, cmin, cmax) \ + .uinfo = { \ + .type = SNDRV_CTL_ELEM_TYPE_##ctype, \ + .count = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_SINGLE ? 1 : 2, \ + .value.integer.min = cmin, \ + .value.integer.max = cmax, \ + } + +#define ITEST(cname, clayout, ctype, cfunc, cmin, cmax, \ + xmin, xmax, xpmax, xsign, xinvert) \ + { \ + .name = cname, \ + .func_name = #cfunc, \ + .layout = SOC_OPS_TEST_##clayout, \ + .info = snd_soc_info_##cfunc, \ + TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \ + TEST_UINFO(clayout, ctype, cmin, cmax), \ + } + +#define ATEST(clayout, cfunc, cctl, cret, cinit, \ + xmask, xreg, xmin, xmax, xpmax, xsign, xinvert) \ + { \ + .func_name = #cfunc, \ + .layout = SOC_OPS_TEST_##clayout, \ + .put = snd_soc_put_##cfunc, \ + .get = snd_soc_get_##cfunc, \ + TEST_MC(clayout, xmin, xmax, xpmax, xsign, xinvert), \ + .lctl = cctl, .rctl = cctl, \ + .lmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \ + (xmask) | (xmask) << 16 : (xmask), \ + .rmask = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xmask) : 0, \ + .init = cinit ? 0xFFFFFFFF : 0x00000000, \ + .lreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE ? \ + (xreg) | (xreg) << 16 : (xreg), \ + .rreg = SOC_OPS_TEST_##clayout == SOC_OPS_TEST_DOUBLE_R ? (xreg) : 0, \ + .ret = cret, \ + } + +struct soc_ops_test_priv { + struct kunit *test; + + struct snd_soc_component component; +}; + +struct info_test_param { + const char * const name; + const char * const func_name; + enum soc_ops_test_control_layout layout; + struct soc_mixer_control mc; + int (*info)(struct snd_kcontrol *kctl, struct snd_ctl_elem_info *info); + + struct snd_ctl_elem_info uinfo; +}; + +struct access_test_param { + const char * const func_name; + enum soc_ops_test_control_layout layout; + struct soc_mixer_control mc; + int (*put)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value); + int (*get)(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *value); + + unsigned int init; + unsigned int lmask; + unsigned int rmask; + unsigned int lreg; + unsigned int rreg; + long lctl; + long rctl; + int ret; +}; + +static const struct info_test_param all_info_test_params[] = { + // Handling of volume control name for types + ITEST("Test Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Volume Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Control", DOUBLE_R, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Volume", DOUBLE_R, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Volume Control", DOUBLE_R, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Volume", DOUBLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Volume Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 0), + ITEST("Test Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1), + ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 1), + ITEST("Test Volume Control", SINGLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1), + ITEST("Test Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1), + ITEST("Test Volume", DOUBLE, INTEGER, volsw, 0, 1, 0, 1, 0, 0, 1), + ITEST("Test Volume Control", DOUBLE, BOOLEAN, volsw, 0, 1, 0, 1, 0, 0, 1), + ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 2, 0, 2, 0, 0, 0), + ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 2, 0, 2, 0, 0, 0), + ITEST("Test Volume Control", SINGLE, INTEGER, volsw, 0, 2, 0, 2, 0, 0, 0), + ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 1, 0, 2, 1, 0, 0), + ITEST("Test Volume", SINGLE, INTEGER, volsw, 0, 1, 0, 2, 1, 0, 0), + ITEST("Test Volume Control", SINGLE, INTEGER, volsw, 0, 1, 0, 2, 1, 0, 0), + // Negative minimums + ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 20, -10, 10, 0, 4, 0), + ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 15, -10, 10, 15, 4, 0), + ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 20, -10, 10, 0, 4, 1), + ITEST("Test Control", SINGLE, INTEGER, volsw, 0, 15, -10, 10, 15, 4, 1), + // SX control volume control naming + ITEST("Test Control", SINGLE, BOOLEAN, volsw_sx, 0, 1, 0xF, 1, 0, 0, 0), + ITEST("Test Volume", SINGLE, INTEGER, volsw_sx, 0, 1, 0xF, 1, 0, 0, 0), + ITEST("Test Volume Control", SINGLE, BOOLEAN, volsw_sx, 0, 1, 0xF, 1, 0, 0, 0), + ITEST("Test Control", SINGLE, INTEGER, volsw_sx, 0, 4, 0xE, 4, 0, 0, 0), + ITEST("Test Volume", SINGLE, INTEGER, volsw_sx, 0, 4, 0xE, 4, 0, 0, 0), + ITEST("Test Volume Control", SINGLE, INTEGER, volsw_sx, 0, 4, 0xE, 4, 0, 0, 0), + ITEST("Test Control", SINGLE, INTEGER, volsw_sx, 0, 3, 0xE, 4, 3, 0, 0), + ITEST("Test Volume", SINGLE, INTEGER, volsw_sx, 0, 3, 0xE, 4, 3, 0, 0), + ITEST("Test Volume Control", SINGLE, INTEGER, volsw_sx, 0, 3, 0xE, 4, 3, 0, 0), +}; + +static const struct access_test_param all_access_test_params[] = { + // Single positive value controls + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 0), + ATEST(SINGLE, volsw, 0, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 0), + ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 0), + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 0), + ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 0), + ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x0F, 0, 20, 15, 0, 0), + // Inverted single positive value controls + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 1), + ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 1), + ATEST(SINGLE, volsw, 20, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 1), + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 1), + ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 1), + ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x05, 0, 20, 15, 0, 1), + ATEST(SINGLE, volsw, 10, 1, true, 0x1F, 0x0A, 0, 20, 0, 0, 0), + ATEST(SINGLE, volsw, 0, 1, true, 0x1F, 0x00, 0, 20, 0, 0, 0), + ATEST(SINGLE, volsw, 20, 1, true, 0x1F, 0x14, 0, 20, 0, 0, 0), + ATEST(SINGLE, volsw, 10, 1, true, 0x1F, 0x0A, 0, 20, 15, 0, 0), + ATEST(SINGLE, volsw, 25, -22, true, 0x1F, 0x00, 0, 20, 15, 0, 0), + ATEST(SINGLE, volsw, 15, 1, true, 0x1F, 0x0F, 0, 20, 15, 0, 0), + // Single negative value controls + ATEST(SINGLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 0), + ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 0), + ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 0), + ATEST(SINGLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x05, -10, 10, 15, 4, 0), + // Single non-zero minimum positive value controls + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 0), + ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 0), + ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 0), + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 0), + ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 0), + ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x19, 10, 30, 15, 0, 0), + // Inverted single non-zero minimum positive value controls + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 1), + ATEST(SINGLE, volsw, 0, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 1), + ATEST(SINGLE, volsw, 20, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 1), + ATEST(SINGLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 1), + ATEST(SINGLE, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 1), + ATEST(SINGLE, volsw, 15, 1, false, 0x1F, 0x0F, 10, 30, 15, 0, 1), + // Double register positive value controls + ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 0), + ATEST(DOUBLE_R, volsw, 0, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 0), + ATEST(DOUBLE_R, volsw, 20, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 0), + ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 0), + ATEST(DOUBLE_R, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 0), + ATEST(DOUBLE_R, volsw, 15, 1, false, 0x1F, 0x0F, 0, 20, 15, 0, 0), + // Double register negative value controls + ATEST(DOUBLE_R, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 0), + ATEST(DOUBLE_R, volsw, 0, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 0), + ATEST(DOUBLE_R, volsw, 20, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 0), + ATEST(DOUBLE_R, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(DOUBLE_R, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(DOUBLE_R, volsw, 15, 1, false, 0x1F, 0x05, -10, 10, 15, 4, 0), + ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 0, 4, 0), + ATEST(DOUBLE_R, volsw, 0, 1, true, 0x1F, 0x16, -10, 10, 0, 4, 0), + ATEST(DOUBLE_R, volsw, 20, 1, true, 0x1F, 0x0A, -10, 10, 0, 4, 0), + ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(DOUBLE_R, volsw, 25, -22, true, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(DOUBLE_R, volsw, 15, 1, true, 0x1F, 0x05, -10, 10, 15, 4, 0), + // Inverted double register negative value controls + ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 0, 4, 1), + ATEST(DOUBLE_R, volsw, 0, 1, true, 0x1F, 0x0A, -10, 10, 0, 4, 1), + ATEST(DOUBLE_R, volsw, 20, 1, true, 0x1F, 0x16, -10, 10, 0, 4, 1), + ATEST(DOUBLE_R, volsw, 10, 1, true, 0x1F, 0x00, -10, 10, 15, 4, 1), + ATEST(DOUBLE_R, volsw, 25, -22, true, 0x1F, 0x00, -10, 10, 15, 4, 1), + ATEST(DOUBLE_R, volsw, 15, 1, true, 0x1F, 0x1B, -10, 10, 15, 4, 1), + // Double register non-zero minimum positive value controls + ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 0), + ATEST(DOUBLE_R, volsw, 0, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 0), + ATEST(DOUBLE_R, volsw, 20, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 0), + ATEST(DOUBLE_R, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 0), + ATEST(DOUBLE_R, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 0), + ATEST(DOUBLE_R, volsw, 15, 1, false, 0x1F, 0x19, 10, 30, 15, 0, 0), + // Double shift positive value controls + ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 0, 0, 0), + ATEST(DOUBLE, volsw, 0, 0, false, 0x1F, 0x00, 0, 20, 0, 0, 0), + ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x14, 0, 20, 0, 0, 0), + ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x0A, 0, 20, 15, 0, 0), + ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, 0, 20, 15, 0, 0), + ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x0F, 0, 20, 15, 0, 0), + // Double shift negative value controls + ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 0), + ATEST(DOUBLE, volsw, 0, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 0), + ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 0), + ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 0), + ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x05, -10, 10, 15, 4, 0), + // Inverted double shift negative value controls + ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 0, 4, 1), + ATEST(DOUBLE, volsw, 0, 1, false, 0x1F, 0x0A, -10, 10, 0, 4, 1), + ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x16, -10, 10, 0, 4, 1), + ATEST(DOUBLE, volsw, 10, 0, false, 0x1F, 0x00, -10, 10, 15, 4, 1), + ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, -10, 10, 15, 4, 1), + ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x1B, -10, 10, 15, 4, 1), + // Double shift non-zero minimum positive value controls + ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 0, 0, 0), + ATEST(DOUBLE, volsw, 0, 1, false, 0x1F, 0x0A, 10, 30, 0, 0, 0), + ATEST(DOUBLE, volsw, 20, 1, false, 0x1F, 0x1E, 10, 30, 0, 0, 0), + ATEST(DOUBLE, volsw, 10, 1, false, 0x1F, 0x14, 10, 30, 15, 0, 0), + ATEST(DOUBLE, volsw, 25, -22, false, 0x1F, 0x00, 10, 30, 15, 0, 0), + ATEST(DOUBLE, volsw, 15, 1, false, 0x1F, 0x19, 10, 30, 15, 0, 0), + ATEST(DOUBLE, volsw, 10, 1, true, 0x1F, 0x14, 10, 30, 0, 0, 0), + ATEST(DOUBLE, volsw, 0, 1, true, 0x1F, 0x0A, 10, 30, 0, 0, 0), + ATEST(DOUBLE, volsw, 20, 1, true, 0x1F, 0x1E, 10, 30, 0, 0, 0), + ATEST(DOUBLE, volsw, 10, 1, true, 0x1F, 0x14, 10, 30, 15, 0, 0), + ATEST(DOUBLE, volsw, 25, -22, true, 0x1F, 0x00, 10, 30, 15, 0, 0), + ATEST(DOUBLE, volsw, 15, 1, true, 0x1F, 0x19, 10, 30, 15, 0, 0), + // Single SX all values + ATEST(SINGLE, volsw_sx, 0, 1, false, 0xF, 0x0F, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 1, 0, false, 0xF, 0x00, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 2, 1, false, 0xF, 0x01, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 3, 1, false, 0xF, 0x02, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 4, 1, false, 0xF, 0x03, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 5, -22, false, 0xF, 0x00, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 0, 0, true, 0xF, 0x0F, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 1, 1, true, 0xF, 0x00, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 2, 1, true, 0xF, 0x01, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 3, 1, true, 0xF, 0x02, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 4, 1, true, 0xF, 0x03, 0x0F, 4, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 5, -22, true, 0xF, 0x00, 0x0F, 4, 0, 0, 0), + // Inverted single SX all values + ATEST(SINGLE, volsw_sx, 0, 1, false, 0x1F, 0x03, 0x0F, 4, 0, 0, 1), + ATEST(SINGLE, volsw_sx, 1, 1, false, 0x1F, 0x02, 0x0F, 4, 0, 0, 1), + ATEST(SINGLE, volsw_sx, 2, 1, false, 0x1F, 0x01, 0x0F, 4, 0, 0, 1), + ATEST(SINGLE, volsw_sx, 3, 0, false, 0x1F, 0x00, 0x0F, 4, 0, 0, 1), + ATEST(SINGLE, volsw_sx, 4, 1, false, 0x1F, 0x0F, 0x0F, 4, 0, 0, 1), + ATEST(SINGLE, volsw_sx, 5, -22, false, 0x1F, 0x00, 0x0F, 4, 0, 0, 1), + // Single SX select values + ATEST(SINGLE, volsw_sx, 0, 1, false, 0xFF, 0x88, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 1, 1, false, 0xFF, 0x89, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 119, 1, false, 0xFF, 0xFF, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 120, 0, false, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 121, 1, false, 0xFF, 0x01, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 143, 1, false, 0xFF, 0x17, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 144, 1, false, 0xFF, 0x18, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 145, -22, false, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 0, 1, true, 0xFF, 0x88, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 1, 1, true, 0xFF, 0x89, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 119, 0, true, 0xFF, 0xFF, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 120, 1, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 121, 1, true, 0xFF, 0x01, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 143, 1, true, 0xFF, 0x17, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 144, 1, true, 0xFF, 0x18, 0x88, 144, 0, 0, 0), + ATEST(SINGLE, volsw_sx, 145, -22, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + // Double shift SX select values + ATEST(DOUBLE, volsw_sx, 0, 1, true, 0xFF, 0x88, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 1, 1, true, 0xFF, 0x89, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 119, 0, true, 0xFF, 0xFF, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 120, 1, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 121, 1, true, 0xFF, 0x01, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 143, 1, true, 0xFF, 0x17, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 144, 1, true, 0xFF, 0x18, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE, volsw_sx, 145, -22, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + // Double register SX select values + ATEST(DOUBLE_R, volsw_sx, 0, 1, true, 0xFF, 0x88, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 1, 1, true, 0xFF, 0x89, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 119, 0, true, 0xFF, 0xFF, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 120, 1, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 121, 1, true, 0xFF, 0x01, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 143, 1, true, 0xFF, 0x17, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 144, 1, true, 0xFF, 0x18, 0x88, 144, 0, 0, 0), + ATEST(DOUBLE_R, volsw_sx, 145, -22, true, 0xFF, 0x00, 0x88, 144, 0, 0, 0), +}; + +static const char *control_type_str(const snd_ctl_elem_type_t type) +{ + switch (type) { + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + return "bool"; + case SNDRV_CTL_ELEM_TYPE_INTEGER: + return "int"; + default: + return "unknown"; + } +} + +static const char *control_layout_str(const enum soc_ops_test_control_layout layout) +{ + switch (layout) { + case SOC_OPS_TEST_SINGLE: + return "single"; + case SOC_OPS_TEST_DOUBLE: + return "double"; + case SOC_OPS_TEST_DOUBLE_R: + return "double_r"; + default: + return "unknown"; + } +}; + +static int mock_regmap_read(void *context, const void *reg_buf, + const size_t reg_size, void *val_buf, + size_t val_size) +{ + struct soc_ops_test_priv *priv = context; + + KUNIT_FAIL(priv->test, "Unexpected bus read"); + + return -EIO; +} + +static int mock_regmap_gather_write(void *context, + const void *reg_buf, size_t reg_size, + const void *val_buf, size_t val_size) +{ + struct soc_ops_test_priv *priv = context; + + KUNIT_FAIL(priv->test, "Unexpected bus gather_write"); + + return -EIO; +} + +static int mock_regmap_write(void *context, const void *val_buf, + size_t val_size) +{ + struct soc_ops_test_priv *priv = context; + + KUNIT_FAIL(priv->test, "Unexpected bus write"); + + return -EIO; +} + +static const struct regmap_bus mock_regmap_bus = { + .read = mock_regmap_read, + .write = mock_regmap_write, + .gather_write = mock_regmap_gather_write, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static const struct regmap_config mock_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_NATIVE, + .val_format_endian = REGMAP_ENDIAN_NATIVE, + .max_register = 0x1, + .cache_type = REGCACHE_FLAT, +}; + +static int soc_ops_test_init(struct kunit *test) +{ + struct soc_ops_test_priv *priv; + struct regmap *regmap; + struct device *dev; + + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->test = test; + + dev = kunit_device_register(test, "soc_ops_test_drv"); + if (IS_ERR(dev)) + return PTR_ERR(dev); + + regmap = devm_regmap_init(dev, &mock_regmap_bus, priv, &mock_regmap_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); + + /* No actual hardware, we just use the cache */ + regcache_cache_only(regmap, true); + + priv->component.dev = dev; + priv->component.regmap = regmap; + mutex_init(&priv->component.io_mutex); + + test->priv = priv; + + return 0; +} + +static void soc_ops_test_exit(struct kunit *test) +{ + struct soc_ops_test_priv *priv = test->priv; + + kunit_device_unregister(test, priv->component.dev); +} + +static void info_test_desc(const struct info_test_param *param, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "%s %s %s: ctl range: %ld->%ld, reg range: %d->%d(%d), sign: %d, inv: %d", + control_layout_str(param->layout), param->func_name, + control_type_str(param->uinfo.type), + param->uinfo.value.integer.min, param->uinfo.value.integer.max, + param->mc.min, param->mc.max, param->mc.platform_max, + param->mc.sign_bit, param->mc.invert); +} + +static void soc_ops_test_info(struct kunit *test) +{ + struct soc_ops_test_priv *priv = test->priv; + const struct info_test_param *param = test->param_value; + const struct snd_ctl_elem_info *target = ¶m->uinfo; + struct snd_ctl_elem_info result; + struct snd_kcontrol kctl = { + .private_data = &priv->component, + .private_value = (unsigned long)¶m->mc, + }; + int ret; + + strscpy(kctl.id.name, param->name, sizeof(kctl.id.name)); + + ret = param->info(&kctl, &result); + KUNIT_ASSERT_FALSE(test, ret); + + KUNIT_EXPECT_EQ(test, result.count, target->count); + KUNIT_EXPECT_EQ(test, result.type, target->type); + KUNIT_EXPECT_EQ(test, result.value.integer.min, target->value.integer.min); + KUNIT_EXPECT_EQ(test, result.value.integer.max, target->value.integer.max); +} + +static void access_test_desc(const struct access_test_param *param, char *desc) +{ + if (param->ret < 0) { + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> err: %d", + control_layout_str(param->layout), param->func_name, + param->lctl, param->rctl, + param->mc.min, param->mc.max, param->mc.platform_max, + param->mc.sign_bit, param->mc.invert, + param->ret); + } else { + snprintf(desc, KUNIT_PARAM_DESC_SIZE, + "%s %s: %ld,%ld -> range: %d->%d(%d), sign: %d, inv: %d -> %#x,%#x", + control_layout_str(param->layout), param->func_name, + param->lctl, param->rctl, + param->mc.min, param->mc.max, param->mc.platform_max, + param->mc.sign_bit, param->mc.invert, + param->lreg, param->rreg); + } +} + +static void soc_ops_test_access(struct kunit *test) +{ + struct soc_ops_test_priv *priv = test->priv; + const struct access_test_param *param = test->param_value; + struct snd_kcontrol kctl = { + .private_data = &priv->component, + .private_value = (unsigned long)¶m->mc, + }; + struct snd_ctl_elem_value result; + unsigned int val; + int ret; + + ret = regmap_write(priv->component.regmap, 0x0, param->init); + KUNIT_ASSERT_FALSE(test, ret); + ret = regmap_write(priv->component.regmap, 0x1, param->init); + KUNIT_ASSERT_FALSE(test, ret); + + result.value.integer.value[0] = param->lctl; + result.value.integer.value[1] = param->rctl; + + ret = param->put(&kctl, &result); + KUNIT_ASSERT_EQ(test, ret, param->ret); + if (ret < 0) + return; + + ret = regmap_read(priv->component.regmap, 0x0, &val); + KUNIT_ASSERT_FALSE(test, ret); + KUNIT_EXPECT_EQ(test, val, (param->init & ~param->lmask) | param->lreg); + + ret = regmap_read(priv->component.regmap, 0x1, &val); + KUNIT_ASSERT_FALSE(test, ret); + KUNIT_EXPECT_EQ(test, val, (param->init & ~param->rmask) | param->rreg); + + result.value.integer.value[0] = 0; + result.value.integer.value[1] = 0; + + ret = param->get(&kctl, &result); + KUNIT_ASSERT_GE(test, ret, 0); + + KUNIT_EXPECT_EQ(test, result.value.integer.value[0], param->lctl); + if (param->layout != SOC_OPS_TEST_SINGLE) + KUNIT_EXPECT_EQ(test, result.value.integer.value[1], param->rctl); + else + KUNIT_EXPECT_EQ(test, result.value.integer.value[1], 0); +} + +KUNIT_ARRAY_PARAM(all_info_tests, all_info_test_params, info_test_desc); +KUNIT_ARRAY_PARAM(all_access_tests, all_access_test_params, access_test_desc); + +static struct kunit_case soc_ops_test_cases[] = { + KUNIT_CASE_PARAM(soc_ops_test_info, all_info_tests_gen_params), + KUNIT_CASE_PARAM(soc_ops_test_access, all_access_tests_gen_params), + {} +}; + +static struct kunit_suite soc_ops_test_suite = { + .name = "soc-ops", + .init = soc_ops_test_init, + .exit = soc_ops_test_exit, + .test_cases = soc_ops_test_cases, +}; + +kunit_test_suites(&soc_ops_test_suite); + +MODULE_DESCRIPTION("ASoC soc-ops kunit test"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c index b0e4e4168f38..8d4dd11c9aef 100644 --- a/sound/soc/soc-ops.c +++ b/sound/soc/soc-ops.c @@ -24,7 +24,6 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> -#include <sound/soc-dpcm.h> #include <sound/initval.h> /** @@ -38,7 +37,7 @@ * Returns 0 for success. */ int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; @@ -57,7 +56,7 @@ EXPORT_SYMBOL_GPL(snd_soc_info_enum_double); * Returns 0 for success. */ int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; @@ -88,7 +87,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_enum_double); * Returns 0 for success. */ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; @@ -111,95 +110,183 @@ int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_GPL(snd_soc_put_enum_double); -/** - * snd_soc_read_signed - Read a codec register and interpret as signed value - * @component: component - * @reg: Register to read - * @mask: Mask to use after shifting the register value - * @shift: Right shift of register value - * @sign_bit: Bit that describes if a number is negative or not. - * @signed_val: Pointer to where the read value should be stored - * - * This functions reads a codec register. The register value is shifted right - * by 'shift' bits and masked with the given 'mask'. Afterwards it translates - * the given registervalue into a signed integer if sign_bit is non-zero. - * - * Returns 0 on sucess, otherwise an error value - */ -static int snd_soc_read_signed(struct snd_soc_component *component, - unsigned int reg, unsigned int mask, unsigned int shift, - unsigned int sign_bit, int *signed_val) +static int soc_mixer_reg_to_ctl(struct soc_mixer_control *mc, unsigned int reg_val, + unsigned int mask, unsigned int shift, int max) +{ + int val = (reg_val >> shift) & mask; + + if (mc->sign_bit) + val = sign_extend32(val, mc->sign_bit); + + val -= mc->min; + + if (mc->invert) + val = max - val; + + return val & mask; +} + +static unsigned int soc_mixer_ctl_to_reg(struct soc_mixer_control *mc, int val, + unsigned int mask, unsigned int shift, + int max) +{ + unsigned int reg_val; + + if (mc->invert) + val = max - val; + + reg_val = val + mc->min; + + return (reg_val & mask) << shift; +} + +static int soc_mixer_valid_ctl(struct soc_mixer_control *mc, long val, int max) +{ + if (val < 0) + return -EINVAL; + + if (mc->platform_max && val > mc->platform_max) + return -EINVAL; + + if (val > max) + return -EINVAL; + + return 0; +} + +static int soc_mixer_mask(struct soc_mixer_control *mc) +{ + if (mc->sign_bit) + return GENMASK(mc->sign_bit, 0); + else + return GENMASK(fls(mc->max) - 1, 0); +} + +static int soc_mixer_sx_mask(struct soc_mixer_control *mc) +{ + // min + max will take us 1-bit over the size of the mask + return GENMASK(fls(mc->min + mc->max) - 2, 0); +} + +static int soc_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + struct soc_mixer_control *mc, int max) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + + if (max == 1) { + /* Even two value controls ending in Volume should be integer */ + const char *vol_string = strstr(kcontrol->id.name, " Volume"); + + if (!vol_string || strcmp(vol_string, " Volume")) + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + } + + if (mc->platform_max && mc->platform_max < max) + max = mc->platform_max; + + uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = max; + + return 0; +} + +static int soc_put_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + struct soc_mixer_control *mc, int mask, int max) { + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + unsigned int val1, val_mask; + unsigned int val2 = 0; + bool double_r = false; int ret; - unsigned int val; - val = snd_soc_component_read(component, reg); - val = (val >> shift) & mask; + ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[0], max); + if (ret) + return ret; - if (!sign_bit) { - *signed_val = val; - return 0; + val1 = soc_mixer_ctl_to_reg(mc, ucontrol->value.integer.value[0], + mask, mc->shift, max); + val_mask = mask << mc->shift; + + if (snd_soc_volsw_is_stereo(mc)) { + ret = soc_mixer_valid_ctl(mc, ucontrol->value.integer.value[1], max); + if (ret) + return ret; + + if (mc->reg == mc->rreg) { + val1 |= soc_mixer_ctl_to_reg(mc, + ucontrol->value.integer.value[1], + mask, mc->rshift, max); + val_mask |= mask << mc->rshift; + } else { + val2 = soc_mixer_ctl_to_reg(mc, + ucontrol->value.integer.value[1], + mask, mc->shift, max); + double_r = true; + } } - /* non-negative number */ - if (!(val & BIT(sign_bit))) { - *signed_val = val; - return 0; + ret = snd_soc_component_update_bits(component, mc->reg, val_mask, val1); + if (ret < 0) + return ret; + + if (double_r) { + int err = snd_soc_component_update_bits(component, mc->rreg, + val_mask, val2); + /* Don't drop change flag */ + if (err) + return err; } - ret = val; + return ret; +} - /* - * The register most probably does not contain a full-sized int. - * Instead we have an arbitrary number of bits in a signed - * representation which has to be translated into a full-sized int. - * This is done by filling up all bits above the sign-bit. - */ - ret |= ~((int)(BIT(sign_bit) - 1)); +static int soc_get_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + struct soc_mixer_control *mc, int mask, int max) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + unsigned int reg_val; + int val; + + reg_val = snd_soc_component_read(component, mc->reg); + val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max); + + ucontrol->value.integer.value[0] = val; - *signed_val = ret; + if (snd_soc_volsw_is_stereo(mc)) { + if (mc->reg == mc->rreg) { + val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->rshift, max); + } else { + reg_val = snd_soc_component_read(component, mc->rreg); + val = soc_mixer_reg_to_ctl(mc, reg_val, mask, mc->shift, max); + } + + ucontrol->value.integer.value[1] = val; + } return 0; } /** - * snd_soc_info_volsw - single mixer info callback + * snd_soc_info_volsw - single mixer info callback with range. * @kcontrol: mixer control * @uinfo: control element information * - * Callback to provide information about a single mixer control, or a double - * mixer control that spans 2 registers. + * Callback to provide information, with a range, about a single mixer control, + * or a double mixer control that spans 2 registers. * * Returns 0 for success. */ int snd_soc_info_volsw(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - const char *vol_string = NULL; - int max; - - max = uinfo->value.integer.max = mc->max - mc->min; - if (mc->platform_max && mc->platform_max < max) - max = mc->platform_max; - - if (max == 1) { - /* Even two value controls ending in Volume should always be integer */ - vol_string = strstr(kcontrol->id.name, " Volume"); - if (vol_string && !strcmp(vol_string, " Volume")) - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - else - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - } else { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - } - - uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = max; - return 0; + return soc_info_volsw(kcontrol, uinfo, mc, mc->max - mc->min); } EXPORT_SYMBOL_GPL(snd_soc_info_volsw); @@ -221,165 +308,50 @@ int snd_soc_info_volsw_sx(struct snd_kcontrol *kcontrol, { struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int max; - if (mc->platform_max) - max = mc->platform_max; - else - max = mc->max; - - if (max == 1 && !strstr(kcontrol->id.name, " Volume")) - uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; - else - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - - uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = max; - - return 0; + return soc_info_volsw(kcontrol, uinfo, mc, mc->max); } EXPORT_SYMBOL_GPL(snd_soc_info_volsw_sx); /** - * snd_soc_get_volsw - single mixer get callback + * snd_soc_get_volsw - single mixer get callback with range * @kcontrol: mixer control * @ucontrol: control element information * - * Callback to get the value of a single mixer control, or a double mixer - * control that spans 2 registers. + * Callback to get the value, within a range, of a single mixer control, or a + * double mixer control that spans 2 registers. * * Returns 0 for success. */ int snd_soc_get_volsw(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int min = mc->min; - int sign_bit = mc->sign_bit; - unsigned int mask = (1ULL << fls(max)) - 1; - unsigned int invert = mc->invert; - int val; - int ret; - - if (sign_bit) - mask = BIT(sign_bit + 1) - 1; + unsigned int mask = soc_mixer_mask(mc); - ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val); - if (ret) - return ret; - - ucontrol->value.integer.value[0] = val - min; - if (invert) - ucontrol->value.integer.value[0] = - max - ucontrol->value.integer.value[0]; - - if (snd_soc_volsw_is_stereo(mc)) { - if (reg == reg2) - ret = snd_soc_read_signed(component, reg, mask, rshift, - sign_bit, &val); - else - ret = snd_soc_read_signed(component, reg2, mask, shift, - sign_bit, &val); - if (ret) - return ret; - - ucontrol->value.integer.value[1] = val - min; - if (invert) - ucontrol->value.integer.value[1] = - max - ucontrol->value.integer.value[1]; - } - - return 0; + return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min); } EXPORT_SYMBOL_GPL(snd_soc_get_volsw); /** - * snd_soc_put_volsw - single mixer put callback + * snd_soc_put_volsw - single mixer put callback with range * @kcontrol: mixer control * @ucontrol: control element information * - * Callback to set the value of a single mixer control, or a double mixer - * control that spans 2 registers. + * Callback to set the value , within a range, of a single mixer control, or + * a double mixer control that spans 2 registers. * * Returns 0 for success. */ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int min = mc->min; - unsigned int sign_bit = mc->sign_bit; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int invert = mc->invert; - int err, ret; - bool type_2r = false; - unsigned int val2 = 0; - unsigned int val, val_mask; - - if (sign_bit) - mask = BIT(sign_bit + 1) - 1; - - if (ucontrol->value.integer.value[0] < 0) - return -EINVAL; - val = ucontrol->value.integer.value[0]; - if (mc->platform_max && val > mc->platform_max) - return -EINVAL; - if (val > max - min) - return -EINVAL; - val = (val + min) & mask; - if (invert) - val = max - val; - val_mask = mask << shift; - val = val << shift; - if (snd_soc_volsw_is_stereo(mc)) { - if (ucontrol->value.integer.value[1] < 0) - return -EINVAL; - val2 = ucontrol->value.integer.value[1]; - if (mc->platform_max && val2 > mc->platform_max) - return -EINVAL; - if (val2 > max - min) - return -EINVAL; - val2 = (val2 + min) & mask; - if (invert) - val2 = max - val2; - if (reg == reg2) { - val_mask |= mask << rshift; - val |= val2 << rshift; - } else { - val2 = val2 << shift; - type_2r = true; - } - } - err = snd_soc_component_update_bits(component, reg, val_mask, val); - if (err < 0) - return err; - ret = err; - - if (type_2r) { - err = snd_soc_component_update_bits(component, reg2, val_mask, - val2); - /* Don't discard any error code or drop change flag */ - if (ret == 0 || err < 0) { - ret = err; - } - } + unsigned int mask = soc_mixer_mask(mc); - return ret; + return soc_put_volsw(kcontrol, ucontrol, mc, mask, mc->max - mc->min); } EXPORT_SYMBOL_GPL(snd_soc_put_volsw); @@ -394,30 +366,13 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw); * Returns 0 for success. */ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int min = mc->min; - unsigned int mask = (1U << (fls(min + max) - 1)) - 1; - unsigned int val; - - val = snd_soc_component_read(component, reg); - ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask; - - if (snd_soc_volsw_is_stereo(mc)) { - val = snd_soc_component_read(component, reg2); - val = ((val >> rshift) - min) & mask; - ucontrol->value.integer.value[1] = val; - } + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int mask = soc_mixer_sx_mask(mc); - return 0; + return soc_get_volsw(kcontrol, ucontrol, mc, mask, mc->max); } EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); @@ -433,211 +388,40 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx); int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - - unsigned int reg = mc->reg; - unsigned int reg2 = mc->rreg; - unsigned int shift = mc->shift; - unsigned int rshift = mc->rshift; - int max = mc->max; - int min = mc->min; - unsigned int mask = (1U << (fls(min + max) - 1)) - 1; - int err = 0; - int ret; - unsigned int val, val_mask; - - if (ucontrol->value.integer.value[0] < 0) - return -EINVAL; - val = ucontrol->value.integer.value[0]; - if (mc->platform_max && val > mc->platform_max) - return -EINVAL; - if (val > max) - return -EINVAL; - val_mask = mask << shift; - val = (val + min) & mask; - val = val << shift; - - err = snd_soc_component_update_bits(component, reg, val_mask, val); - if (err < 0) - return err; - ret = err; - - if (snd_soc_volsw_is_stereo(mc)) { - unsigned int val2 = ucontrol->value.integer.value[1]; - - if (mc->platform_max && val2 > mc->platform_max) - return -EINVAL; - if (val2 > max) - return -EINVAL; - - val_mask = mask << rshift; - val2 = (val2 + min) & mask; - val2 = val2 << rshift; - - err = snd_soc_component_update_bits(component, reg2, val_mask, - val2); - - /* Don't discard any error code or drop change flag */ - if (ret == 0 || err < 0) { - ret = err; - } - } - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); - -/** - * snd_soc_info_volsw_range - single mixer info callback with range. - * @kcontrol: mixer control - * @uinfo: control element information - * - * Callback to provide information, within a range, about a single - * mixer control. - * - * returns 0 for success. - */ -int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - int max; - - max = mc->max - mc->min; - if (mc->platform_max && mc->platform_max < max) - max = mc->platform_max; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = max; + unsigned int mask = soc_mixer_sx_mask(mc); - return 0; + return soc_put_volsw(kcontrol, ucontrol, mc, mask, mc->max); } -EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range); +EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx); -/** - * snd_soc_put_volsw_range - single mixer put value callback with range. - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to set the value, within a range, for a single mixer control. - * - * Returns 0 for success. - */ -int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_soc_clip_to_platform_max(struct snd_kcontrol *kctl) { - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - unsigned int reg = mc->reg; - unsigned int rreg = mc->rreg; - unsigned int shift = mc->shift; - int min = mc->min; - int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int invert = mc->invert; - unsigned int val, val_mask; - int err, ret, tmp; - - tmp = ucontrol->value.integer.value[0]; - if (tmp < 0) - return -EINVAL; - if (mc->platform_max && tmp > mc->platform_max) - return -EINVAL; - if (tmp > mc->max - mc->min) - return -EINVAL; - - if (invert) - val = (max - ucontrol->value.integer.value[0]) & mask; - else - val = ((ucontrol->value.integer.value[0] + min) & mask); - val_mask = mask << shift; - val = val << shift; - - err = snd_soc_component_update_bits(component, reg, val_mask, val); - if (err < 0) - return err; - ret = err; - - if (snd_soc_volsw_is_stereo(mc)) { - tmp = ucontrol->value.integer.value[1]; - if (tmp < 0) - return -EINVAL; - if (mc->platform_max && tmp > mc->platform_max) - return -EINVAL; - if (tmp > mc->max - mc->min) - return -EINVAL; + struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct snd_ctl_elem_value uctl; + int ret; - if (invert) - val = (max - ucontrol->value.integer.value[1]) & mask; - else - val = ((ucontrol->value.integer.value[1] + min) & mask); - val_mask = mask << shift; - val = val << shift; - - err = snd_soc_component_update_bits(component, rreg, val_mask, - val); - /* Don't discard any error code or drop change flag */ - if (ret == 0 || err < 0) { - ret = err; - } - } + if (!mc->platform_max) + return 0; - return ret; -} -EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range); + ret = kctl->get(kctl, &uctl); + if (ret < 0) + return ret; -/** - * snd_soc_get_volsw_range - single mixer get callback with range - * @kcontrol: mixer control - * @ucontrol: control element information - * - * Callback to get the value, within a range, of a single mixer control. - * - * Returns 0 for success. - */ -int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); - struct soc_mixer_control *mc = - (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int rreg = mc->rreg; - unsigned int shift = mc->shift; - int min = mc->min; - int max = mc->max; - unsigned int mask = (1 << fls(max)) - 1; - unsigned int invert = mc->invert; - unsigned int val; + if (uctl.value.integer.value[0] > mc->platform_max) + uctl.value.integer.value[0] = mc->platform_max; - val = snd_soc_component_read(component, reg); - ucontrol->value.integer.value[0] = (val >> shift) & mask; - if (invert) - ucontrol->value.integer.value[0] = - max - ucontrol->value.integer.value[0]; - else - ucontrol->value.integer.value[0] = - ucontrol->value.integer.value[0] - min; + if (snd_soc_volsw_is_stereo(mc) && + uctl.value.integer.value[1] > mc->platform_max) + uctl.value.integer.value[1] = mc->platform_max; - if (snd_soc_volsw_is_stereo(mc)) { - val = snd_soc_component_read(component, rreg); - ucontrol->value.integer.value[1] = (val >> shift) & mask; - if (invert) - ucontrol->value.integer.value[1] = - max - ucontrol->value.integer.value[1]; - else - ucontrol->value.integer.value[1] = - ucontrol->value.integer.value[1] - min; - } + ret = kctl->put(kctl, &uctl); + if (ret < 0) + return ret; return 0; } -EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); /** * snd_soc_limit_volume - Set new limit to an existing volume control. @@ -648,8 +432,7 @@ EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range); * * Return 0 for success, else error. */ -int snd_soc_limit_volume(struct snd_soc_card *card, - const char *name, int max) +int snd_soc_limit_volume(struct snd_soc_card *card, const char *name, int max) { struct snd_kcontrol *kctl; int ret = -EINVAL; @@ -660,12 +443,15 @@ int snd_soc_limit_volume(struct snd_soc_card *card, kctl = snd_soc_card_get_kcontrol(card, name); if (kctl) { - struct soc_mixer_control *mc = (struct soc_mixer_control *)kctl->private_value; + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kctl->private_value; + if (max <= mc->max - mc->min) { mc->platform_max = max; - ret = 0; + ret = snd_soc_clip_to_platform_max(kctl); } } + return ret; } EXPORT_SYMBOL_GPL(snd_soc_limit_volume); @@ -725,8 +511,8 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_bytes *params = (void *)kcontrol->private_value; - int ret, len; unsigned int val, mask; + int ret, len; if (!component->regmap || !params->num_regs) return -EINVAL; @@ -757,15 +543,13 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, break; case 2: mask = ~params->mask; - ret = regmap_parse_val(component->regmap, - &mask, &mask); + ret = regmap_parse_val(component->regmap, &mask, &mask); if (ret != 0) return ret; ((u16 *)data)[0] &= mask; - ret = regmap_parse_val(component->regmap, - &val, &val); + ret = regmap_parse_val(component->regmap, &val, &val); if (ret != 0) return ret; @@ -773,15 +557,13 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, break; case 4: mask = ~params->mask; - ret = regmap_parse_val(component->regmap, - &mask, &mask); + ret = regmap_parse_val(component->regmap, &mask, &mask); if (ret != 0) return ret; ((u32 *)data)[0] &= mask; - ret = regmap_parse_val(component->regmap, - &val, &val); + ret = regmap_parse_val(component->regmap, &val, &val); if (ret != 0) return ret; @@ -797,7 +579,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_bytes_put); int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *ucontrol) + struct snd_ctl_elem_info *ucontrol) { struct soc_bytes_ext *params = (void *)kcontrol->private_value; @@ -809,7 +591,7 @@ int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol, EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext); int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) + unsigned int size, unsigned int __user *tlv) { struct soc_bytes_ext *params = (void *)kcontrol->private_value; unsigned int count = size < params->max ? size : params->max; @@ -825,6 +607,7 @@ int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag, ret = params->put(kcontrol, tlv, count); break; } + return ret; } EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); @@ -834,17 +617,19 @@ EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback); * @kcontrol: mreg control * @uinfo: control element information * - * Callback to provide information of a control that can - * span multiple codec registers which together - * forms a single signed value in a MSB/LSB manner. + * Callback to provide information of a control that can span multiple + * codec registers which together forms a single signed value. Note + * that unlike the non-xr variant of sx controls these may or may not + * include the sign bit, depending on nbits, and there is no shift. * * Returns 0 for success. */ int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { struct soc_mreg_control *mc = (struct soc_mreg_control *)kcontrol->private_value; + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = mc->min; @@ -859,16 +644,17 @@ EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx); * @kcontrol: mreg control * @ucontrol: control element information * - * Callback to get the value of a control that can span - * multiple codec registers which together forms a single - * signed value in a MSB/LSB manner. The control supports - * specifying total no of bits used to allow for bitfields - * across the multiple codec registers. + * Callback to get the value of a control that can span multiple codec + * registers which together forms a single signed value. The control + * supports specifying total no of bits used to allow for bitfields + * across the multiple codec registers. Note that unlike the non-xr + * variant of sx controls these may or may not include the sign bit, + * depending on nbits, and there is no shift. * * Returns 0 for success. */ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mreg_control *mc = @@ -876,23 +662,21 @@ int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol, unsigned int regbase = mc->regbase; unsigned int regcount = mc->regcount; unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; - unsigned int regwmask = (1UL<<regwshift)-1; - unsigned int invert = mc->invert; - unsigned long mask = (1UL<<mc->nbits)-1; - long min = mc->min; - long max = mc->max; + unsigned int regwmask = GENMASK(regwshift - 1, 0); + unsigned long mask = GENMASK(mc->nbits - 1, 0); long val = 0; unsigned int i; for (i = 0; i < regcount; i++) { - unsigned int regval = snd_soc_component_read(component, regbase+i); - val |= (regval & regwmask) << (regwshift*(regcount-i-1)); + unsigned int regval = snd_soc_component_read(component, regbase + i); + + val |= (regval & regwmask) << (regwshift * (regcount - i - 1)); } val &= mask; - if (min < 0 && val > max) + if (mc->min < 0 && val > mc->max) val |= ~mask; - if (invert) - val = max - val; + if (mc->invert) + val = mc->max - val; ucontrol->value.integer.value[0] = val; return 0; @@ -904,16 +688,17 @@ EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx); * @kcontrol: mreg control * @ucontrol: control element information * - * Callback to set the value of a control that can span - * multiple codec registers which together forms a single - * signed value in a MSB/LSB manner. The control supports - * specifying total no of bits used to allow for bitfields - * across the multiple codec registers. + * Callback to set the value of a control that can span multiple codec + * registers which together forms a single signed value. The control + * supports specifying total no of bits used to allow for bitfields + * across the multiple codec registers. Note that unlike the non-xr + * variant of sx controls these may or may not include the sign bit, + * depending on nbits, and there is no shift. * * Returns 0 for success. */ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mreg_control *mc = @@ -921,24 +706,25 @@ int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol, unsigned int regbase = mc->regbase; unsigned int regcount = mc->regcount; unsigned int regwshift = component->val_bytes * BITS_PER_BYTE; - unsigned int regwmask = (1UL<<regwshift)-1; - unsigned int invert = mc->invert; - unsigned long mask = (1UL<<mc->nbits)-1; - long max = mc->max; + unsigned int regwmask = GENMASK(regwshift - 1, 0); + unsigned long mask = GENMASK(mc->nbits - 1, 0); long val = ucontrol->value.integer.value[0]; int ret = 0; unsigned int i; if (val < mc->min || val > mc->max) return -EINVAL; - if (invert) - val = max - val; + if (mc->invert) + val = mc->max - val; val &= mask; for (i = 0; i < regcount; i++) { - unsigned int regval = (val >> (regwshift*(regcount-i-1))) & regwmask; - unsigned int regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask; - int err = snd_soc_component_update_bits(component, regbase+i, + unsigned int regval = (val >> (regwshift * (regcount - i - 1))) & + regwmask; + unsigned int regmask = (mask >> (regwshift * (regcount - i - 1))) & + regwmask; + int err = snd_soc_component_update_bits(component, regbase + i, regmask, regval); + if (err < 0) return err; if (err > 0) @@ -959,22 +745,21 @@ EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx); * Returns 0 for success. */ int snd_soc_get_strobe(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int mask = 1 << shift; unsigned int invert = mc->invert != 0; + unsigned int mask = BIT(mc->shift); unsigned int val; - val = snd_soc_component_read(component, reg); + val = snd_soc_component_read(component, mc->reg); val &= mask; - if (shift != 0 && val != 0) - val = val >> shift; + if (mc->shift != 0 && val != 0) + val = val >> mc->shift; + ucontrol->value.enumerated.item[0] = val ^ invert; return 0; @@ -992,24 +777,22 @@ EXPORT_SYMBOL_GPL(snd_soc_get_strobe); * Returns 1 for success. */ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) + struct snd_ctl_elem_value *ucontrol) { struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value; - unsigned int reg = mc->reg; - unsigned int shift = mc->shift; - unsigned int mask = 1 << shift; - unsigned int invert = mc->invert != 0; unsigned int strobe = ucontrol->value.enumerated.item[0] != 0; + unsigned int invert = mc->invert != 0; + unsigned int mask = BIT(mc->shift); unsigned int val1 = (strobe ^ invert) ? mask : 0; unsigned int val2 = (strobe ^ invert) ? 0 : mask; - int err; + int ret; - err = snd_soc_component_update_bits(component, reg, mask, val1); - if (err < 0) - return err; + ret = snd_soc_component_update_bits(component, mc->reg, mask, val1); + if (ret < 0) + return ret; - return snd_soc_component_update_bits(component, reg, mask, val2); + return snd_soc_component_update_bits(component, mc->reg, mask, val2); } EXPORT_SYMBOL_GPL(snd_soc_put_strobe); diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 88b3ad5a2552..4308a6cbb2e6 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -30,27 +30,13 @@ static inline int _soc_pcm_ret(struct snd_soc_pcm_runtime *rtd, const char *func, int ret) { - /* Positive, Zero values are not errors */ - if (ret >= 0) - return ret; - - /* Negative values might be errors */ - switch (ret) { - case -EPROBE_DEFER: - case -ENOTSUPP: - break; - default: - dev_err(rtd->dev, - "ASoC: error at %s on %s: %d\n", - func, rtd->dai_link->name, ret); - } - - return ret; + return snd_soc_ret(rtd->dev, ret, + "at %s() on %s\n", func, rtd->dai_link->name); } /* is the current PCM operation for this FE ? */ #if 0 -static int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream) +static int snd_soc_dpcm_can_fe_update(struct snd_soc_pcm_runtime *fe, int stream) { if (fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) return 1; @@ -59,7 +45,7 @@ static int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream #endif /* is the current PCM operation for this BE ? */ -static int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe, +static int snd_soc_dpcm_can_be_update(struct snd_soc_pcm_runtime *fe, struct snd_soc_pcm_runtime *be, int stream) { if ((fe->dpcm[stream].runtime_update == SND_SOC_DPCM_UPDATE_FE) || @@ -158,7 +144,6 @@ static inline const char *soc_codec_dai_name(struct snd_soc_pcm_runtime *rtd) return (rtd)->dai_link->num_codecs == 1 ? snd_soc_rtd_to_codec(rtd, 0)->name : "multicodec"; } -#ifdef CONFIG_DEBUG_FS static const char *dpcm_state_string(enum snd_soc_dpcm_state state) { switch (state) { @@ -187,6 +172,7 @@ static const char *dpcm_state_string(enum snd_soc_dpcm_state state) return "unknown"; } +#ifdef CONFIG_DEBUG_FS static ssize_t dpcm_show_state(struct snd_soc_pcm_runtime *fe, int stream, char *buf, size_t size) { @@ -252,11 +238,9 @@ static ssize_t dpcm_state_read_file(struct file *file, char __user *user_buf, int stream; char *buf; - if (fe->dai_link->num_cpus > 1) { - dev_err(fe->dev, + if (fe->dai_link->num_cpus > 1) + return snd_soc_ret(fe->dev, -EINVAL, "%s doesn't support Multi CPU yet\n", __func__); - return -EINVAL; - } buf = kmalloc(out_count, GFP_KERNEL); if (!buf) @@ -416,8 +400,7 @@ bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) } /* DPCM stream event, send event to FE and all active BEs. */ -int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, - int event) +void dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, int event) { struct snd_soc_dpcm *dpcm; @@ -438,8 +421,6 @@ int dpcm_dapm_stream_event(struct snd_soc_pcm_runtime *fe, int dir, } snd_soc_dapm_stream_event(fe, dir, event); - - return 0; } static void soc_pcm_set_dai_params(struct snd_soc_dai *dai, @@ -474,12 +455,9 @@ static int soc_pcm_apply_symmetry(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_single(substream->runtime, \ SNDRV_PCM_HW_PARAM_##NAME,\ soc_dai->symmetric_##name); \ - if (ret < 0) { \ - dev_err(soc_dai->dev, \ - "ASoC: Unable to apply %s constraint: %d\n",\ - #name, ret); \ - return ret; \ - } \ + if (ret < 0) \ + return snd_soc_ret(soc_dai->dev, ret, \ + "Unable to apply %s constraint\n", #name); \ } __soc_pcm_apply_symmetry(rate, RATE); @@ -510,12 +488,11 @@ static int soc_pcm_params_symmetry(struct snd_pcm_substream *substream, for_each_rtd_cpu_dais(rtd, i, cpu_dai) \ if (!snd_soc_dai_is_dummy(cpu_dai) && \ cpu_dai->symmetric_##xxx && \ - cpu_dai->symmetric_##xxx != d.symmetric_##xxx) { \ - dev_err(rtd->dev, "ASoC: unmatched %s symmetry: %s:%d - %s:%d\n", \ - #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ - d.name, d.symmetric_##xxx); \ - return -EINVAL; \ - } + cpu_dai->symmetric_##xxx != d.symmetric_##xxx) \ + return snd_soc_ret(rtd->dev, -EINVAL, \ + "unmatched %s symmetry: %s:%d - %s:%d\n", \ + #xxx, cpu_dai->name, cpu_dai->symmetric_##xxx, \ + d.name, d.symmetric_##xxx); /* reject unmatched parameters when applying symmetry */ __soc_pcm_params_symmetry(rate); @@ -626,13 +603,8 @@ static void soc_pcm_hw_update_chan(struct snd_pcm_hardware *hw, static void soc_pcm_hw_update_format(struct snd_pcm_hardware *hw, const struct snd_soc_pcm_stream *p) { - hw->formats &= p->formats; -} - -static void soc_pcm_hw_update_subformat(struct snd_pcm_hardware *hw, - const struct snd_soc_pcm_stream *p) -{ - hw->subformats &= p->subformats; + hw->formats &= p->formats; + hw->subformats &= p->subformats; } /** @@ -673,7 +645,6 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, soc_pcm_hw_update_chan(hw, cpu_stream); soc_pcm_hw_update_rate(hw, cpu_stream); soc_pcm_hw_update_format(hw, cpu_stream); - soc_pcm_hw_update_subformat(hw, cpu_stream); } cpu_chan_min = hw->channels_min; cpu_chan_max = hw->channels_max; @@ -695,7 +666,6 @@ int snd_soc_runtime_calc_hw(struct snd_soc_pcm_runtime *rtd, soc_pcm_hw_update_chan(hw, codec_stream); soc_pcm_hw_update_rate(hw, codec_stream); soc_pcm_hw_update_format(hw, codec_stream); - soc_pcm_hw_update_subformat(hw, codec_stream); } /* Verify both a valid CPU DAI and a valid CODEC DAI were found */ @@ -860,9 +830,8 @@ static int soc_hw_sanity_check(struct snd_pcm_substream *substream) return 0; config_err: - dev_err(dev, "ASoC: %s <-> %s No matching %s\n", - name_codec, name_cpu, err_msg); - return -EINVAL; + return snd_soc_ret(dev, -EINVAL, + "%s <-> %s No matching %s\n", name_codec, name_cpu, err_msg); } /* @@ -980,7 +949,7 @@ static int __soc_pcm_prepare(struct snd_soc_pcm_runtime *rtd, SND_SOC_DAPM_STREAM_START); for_each_rtd_dais(rtd, i, dai) { - if (dai->driver->ops && !dai->driver->ops->mute_unmute_on_trigger) + if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai)) snd_soc_dai_digital_mute(dai, 0, substream->stream); } @@ -1038,7 +1007,7 @@ static int soc_pcm_hw_clean(struct snd_soc_pcm_runtime *rtd, soc_pcm_set_dai_params(dai, NULL); if (snd_soc_dai_stream_active(dai, substream->stream) == 1) { - if (dai->driver->ops && !dai->driver->ops->mute_unmute_on_trigger) + if (!snd_soc_dai_mute_is_ctrled_at_trigger(dai)) snd_soc_dai_digital_mute(dai, 1, substream->stream); } } @@ -1086,10 +1055,10 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) * function can also be called multiple times and can allocate buffers * (using snd_pcm_lib_* ). It's non-atomic. */ -static int __soc_pcm_hw_params(struct snd_soc_pcm_runtime *rtd, - struct snd_pcm_substream *substream, +static int __soc_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_soc_dai *cpu_dai; struct snd_soc_dai *codec_dai; struct snd_pcm_hw_params tmp_params; @@ -1195,7 +1164,7 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, int ret; snd_soc_dpcm_mutex_lock(rtd); - ret = __soc_pcm_hw_params(rtd, substream, params); + ret = __soc_pcm_hw_params(substream, params); snd_soc_dpcm_mutex_unlock(rtd); return ret; } @@ -1325,19 +1294,18 @@ static int dpcm_be_connect(struct snd_soc_pcm_runtime *fe, snd_soc_dpcm_mutex_assert_held(fe); /* only add new dpcms */ - for_each_dpcm_be(fe, stream, dpcm) { - if (dpcm->be == be && dpcm->fe == fe) + for_each_dpcm_be(fe, stream, dpcm) + if (dpcm->be == be) return 0; - } fe_substream = snd_soc_dpcm_get_substream(fe, stream); be_substream = snd_soc_dpcm_get_substream(be, stream); - if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic) { - dev_err(be->dev, "%s: FE is atomic but BE is nonatomic, invalid configuration\n", - __func__); - return -EINVAL; - } + if (!fe_substream->pcm->nonatomic && be_substream->pcm->nonatomic) + return snd_soc_ret(be->dev, -EINVAL, + "%s: %s is atomic but %s is nonatomic, invalid configuration\n", + __func__, fe->dai_link->name, be->dai_link->name); + if (fe_substream->pcm->nonatomic && !be_substream->pcm->nonatomic) { dev_dbg(be->dev, "FE is nonatomic but BE is not, forcing BE as nonatomic\n"); be_substream->pcm->nonatomic = 1; @@ -1507,11 +1475,9 @@ int dpcm_path_get(struct snd_soc_pcm_runtime *fe, struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(fe, 0); int paths; - if (fe->dai_link->num_cpus > 1) { - dev_err(fe->dev, + if (fe->dai_link->num_cpus > 1) + return snd_soc_ret(fe->dev, -EINVAL, "%s doesn't support Multi CPU yet\n", __func__); - return -EINVAL; - } /* get number of valid DAI paths and their widgets */ paths = snd_soc_dapm_dai_get_connected_widgets(cpu_dai, stream, list, @@ -1577,8 +1543,8 @@ static int dpcm_prune_paths(struct snd_soc_pcm_runtime *fe, int stream, return prune; } -static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, - struct snd_soc_dapm_widget_list **list_) +int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, + struct snd_soc_dapm_widget_list **list_) { struct snd_soc_card *card = fe->card; struct snd_soc_dapm_widget_list *list = *list_; @@ -1643,19 +1609,6 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, return new; } -/* - * Find the corresponding BE DAIs that source or sink audio to this - * FE substream. - */ -int dpcm_process_paths(struct snd_soc_pcm_runtime *fe, - int stream, struct snd_soc_dapm_widget_list **list, int new) -{ - if (new) - return dpcm_add_paths(fe, stream, list); - else - return dpcm_prune_paths(fe, stream, list); -} - void dpcm_clear_pending_state(struct snd_soc_pcm_runtime *fe, int stream) { struct snd_soc_dpcm *dpcm; @@ -1679,13 +1632,13 @@ void dpcm_be_dai_stop(struct snd_soc_pcm_runtime *fe, int stream, return; /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; if (be->dpcm[stream].users == 0) { - dev_err(be->dev, "ASoC: no users %s at close - state %d\n", + dev_err(be->dev, "ASoC: no users %s at close - state %s\n", snd_pcm_direction_name(stream), - be->dpcm[stream].state); + dpcm_state_string(be->dpcm[stream].state)); continue; } @@ -1729,14 +1682,14 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) } /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; /* first time the dpcm is open ? */ if (be->dpcm[stream].users == DPCM_MAX_BE_USERS) { - dev_err(be->dev, "ASoC: too many users %s at open %d\n", + dev_err(be->dev, "ASoC: too many users %s at open %s\n", snd_pcm_direction_name(stream), - be->dpcm[stream].state); + dpcm_state_string(be->dpcm[stream].state)); continue; } @@ -1755,9 +1708,9 @@ int dpcm_be_dai_startup(struct snd_soc_pcm_runtime *fe, int stream) if (err < 0) { be->dpcm[stream].users--; if (be->dpcm[stream].users < 0) - dev_err(be->dev, "ASoC: no users %s at unwind %d\n", + dev_err(be->dev, "ASoC: no users %s at unwind %s\n", snd_pcm_direction_name(stream), - be->dpcm[stream].state); + dpcm_state_string(be->dpcm[stream].state)); be->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE; goto unwind; @@ -1805,7 +1758,6 @@ static void dpcm_runtime_setup_fe(struct snd_pcm_substream *substream) soc_pcm_hw_update_rate(hw, cpu_stream); soc_pcm_hw_update_chan(hw, cpu_stream); soc_pcm_hw_update_format(hw, cpu_stream); - soc_pcm_hw_update_subformat(hw, cpu_stream); } } @@ -1843,7 +1795,6 @@ static void dpcm_runtime_setup_be_format(struct snd_pcm_substream *substream) codec_stream = snd_soc_dai_get_pcm_stream(dai, stream); soc_pcm_hw_update_format(hw, codec_stream); - soc_pcm_hw_update_subformat(hw, codec_stream); } } } @@ -2056,7 +2007,7 @@ void dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream) snd_soc_dpcm_get_substream(be, stream); /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; /* only free hw when no longer used - check all FEs */ @@ -2122,7 +2073,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) be_substream = snd_soc_dpcm_get_substream(be, stream); /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; /* copy params for each dpcm */ @@ -2150,7 +2101,7 @@ int dpcm_be_dai_hw_params(struct snd_soc_pcm_runtime *fe, int stream) dev_dbg(be->dev, "ASoC: hw_params BE %s\n", be->dai_link->name); - ret = __soc_pcm_hw_params(be, be_substream, &hw_params); + ret = __soc_pcm_hw_params(be_substream, &hw_params); if (ret < 0) goto unwind; @@ -2167,7 +2118,7 @@ unwind: be = dpcm->be; be_substream = snd_soc_dpcm_get_substream(be, stream); - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; /* only allow hw_free() if no connected FEs are running */ @@ -2206,7 +2157,7 @@ static int dpcm_fe_dai_hw_params(struct snd_pcm_substream *substream, params_channels(params), params_format(params)); /* call hw_params on the frontend */ - ret = __soc_pcm_hw_params(fe, substream, params); + ret = __soc_pcm_hw_params(substream, params); if (ret < 0) dpcm_be_dai_hw_free(fe, stream); else @@ -2237,7 +2188,7 @@ int dpcm_be_dai_trigger(struct snd_soc_pcm_runtime *fe, int stream, snd_pcm_stream_lock_irqsave_nested(be_substream, flags); /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) goto next; dev_dbg(be->dev, "ASoC: trigger BE %s cmd %d\n", @@ -2402,23 +2353,23 @@ static int dpcm_dai_trigger_fe_be(struct snd_pcm_substream *substream, ret = soc_pcm_trigger(substream, cmd); if (ret < 0) - return ret; + goto end; ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); - return ret; } - /* call trigger on the frontend after the backend. */ - ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); - if (ret < 0) - return ret; - - dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", - fe->dai_link->name, cmd); + else { + ret = dpcm_be_dai_trigger(fe, substream->stream, cmd); + if (ret < 0) + goto end; - ret = soc_pcm_trigger(substream, cmd); + dev_dbg(fe->dev, "ASoC: post trigger FE %s cmd %d\n", + fe->dai_link->name, cmd); - return ret; + ret = soc_pcm_trigger(substream, cmd); + } +end: + return snd_soc_ret(fe->dev, ret, "trigger FE cmd: %d failed\n", cmd); } static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) @@ -2426,46 +2377,17 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_pcm_runtime *fe = snd_soc_substream_to_rtd(substream); int stream = substream->stream; int ret = 0; + int fe_first; enum snd_soc_dpcm_trigger trigger = fe->dai_link->trigger[stream]; fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; switch (trigger) { case SND_SOC_DPCM_TRIGGER_PRE: - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_DRAIN: - ret = dpcm_dai_trigger_fe_be(substream, cmd, true); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = dpcm_dai_trigger_fe_be(substream, cmd, false); - break; - default: - ret = -EINVAL; - break; - } + fe_first = true; break; case SND_SOC_DPCM_TRIGGER_POST: - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_DRAIN: - ret = dpcm_dai_trigger_fe_be(substream, cmd, false); - break; - case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - ret = dpcm_dai_trigger_fe_be(substream, cmd, true); - break; - default: - ret = -EINVAL; - break; - } + fe_first = false; break; default: dev_err(fe->dev, "ASoC: invalid trigger cmd %d for %s\n", cmd, @@ -2474,12 +2396,26 @@ static int dpcm_fe_dai_do_trigger(struct snd_pcm_substream *substream, int cmd) goto out; } - if (ret < 0) { - dev_err(fe->dev, "ASoC: trigger FE cmd: %d failed: %d\n", - cmd, ret); - goto out; + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_DRAIN: + ret = dpcm_dai_trigger_fe_be(substream, cmd, fe_first); + break; + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + ret = dpcm_dai_trigger_fe_be(substream, cmd, !fe_first); + break; + default: + ret = -EINVAL; + break; } + if (ret < 0) + goto out; + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -2529,7 +2465,7 @@ int dpcm_be_dai_prepare(struct snd_soc_pcm_runtime *fe, int stream) snd_soc_dpcm_get_substream(be, stream); /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; if (!snd_soc_dpcm_can_be_prepared(fe, be, stream)) @@ -2636,8 +2572,8 @@ static int dpcm_run_update_startup(struct snd_soc_pcm_runtime *fe, int stream) /* Only start the BE if the FE is ready */ if (fe->dpcm[stream].state == SND_SOC_DPCM_STATE_HW_FREE || fe->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE) { - dev_err(fe->dev, "ASoC: FE %s is not ready %d\n", - fe->dai_link->name, fe->dpcm[stream].state); + dev_err(fe->dev, "ASoC: FE %s is not ready %s\n", + fe->dai_link->name, dpcm_state_string(fe->dpcm[stream].state)); ret = -EINVAL; goto disconnect; } @@ -2687,7 +2623,7 @@ disconnect: struct snd_soc_pcm_runtime *be = dpcm->be; /* is this op for this BE ? */ - if (!snd_soc_dpcm_be_can_update(fe, be, stream)) + if (!snd_soc_dpcm_can_be_update(fe, be, stream)) continue; if (be->dpcm[stream].state == SND_SOC_DPCM_STATE_CLOSE || @@ -2707,11 +2643,9 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) if (!fe->dai_link->dynamic) return 0; - if (fe->dai_link->num_cpus > 1) { - dev_err(fe->dev, + if (fe->dai_link->num_cpus > 1) + return snd_soc_ret(fe->dev, -EINVAL, "%s doesn't support Multi CPU yet\n", __func__); - return -EINVAL; - } /* only check active links */ if (!snd_soc_dai_active(snd_soc_rtd_to_cpu(fe, 0))) @@ -2738,7 +2672,14 @@ static int soc_dpcm_fe_runtime_update(struct snd_soc_pcm_runtime *fe, int new) return paths; /* update any playback/capture paths */ - count = dpcm_process_paths(fe, stream, &list, new); + /* + * Find the corresponding BE DAIs that source or sink audio to this + * FE substream. + */ + if (new) + count = dpcm_add_paths(fe, stream, &list); + else + count = dpcm_prune_paths(fe, stream, &list); if (count) { dpcm_set_fe_update_state(fe, stream, SND_SOC_DPCM_UPDATE_BE); if (new) @@ -2782,7 +2723,8 @@ int snd_soc_dpcm_runtime_update(struct snd_soc_card *card) out: snd_soc_dpcm_mutex_unlock(card); - return ret; + + return snd_soc_ret(card->dev, ret, "%s() failed\n", __func__); } EXPORT_SYMBOL_GPL(snd_soc_dpcm_runtime_update); @@ -2829,7 +2771,7 @@ static int dpcm_fe_dai_open(struct snd_pcm_substream *fe_substream) goto open_end; /* calculate valid and active FE <-> BE dpcms */ - dpcm_process_paths(fe, stream, &list, 1); + dpcm_add_paths(fe, stream, &list); ret = dpcm_fe_dai_startup(fe_substream); if (ret < 0) @@ -2856,10 +2798,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, int has_capture = 0; int i; - if (dai_link->dynamic && dai_link->num_cpus > 1) { - dev_err(rtd->dev, "DPCM doesn't support Multi CPU for Front-Ends yet\n"); - return -EINVAL; - } + if (dai_link->dynamic && dai_link->num_cpus > 1) + return snd_soc_ret(rtd->dev, -EINVAL, + "DPCM doesn't support Multi CPU for Front-Ends yet\n"); /* Adapt stream for codec2codec links */ cpu_capture = snd_soc_get_stream_cpu(dai_link, SNDRV_PCM_STREAM_CAPTURE); @@ -2901,12 +2842,9 @@ static int soc_get_playback_capture(struct snd_soc_pcm_runtime *rtd, if (dai_link->capture_only) has_playback = 0; - if (!has_playback && !has_capture) { - dev_err(rtd->dev, "substream %s has no playback, no capture\n", - dai_link->stream_name); - - return -EINVAL; - } + if (!has_playback && !has_capture) + return snd_soc_ret(rtd->dev, -EINVAL, + "substream %s has no playback, no capture\n", dai_link->stream_name); *playback = has_playback; *capture = has_capture; @@ -2946,11 +2884,10 @@ static int soc_create_pcm(struct snd_pcm **pcm, ret = snd_pcm_new(rtd->card->snd_card, new_name, rtd->id, playback, capture, pcm); } - if (ret < 0) { - dev_err(rtd->card->dev, "ASoC: can't create pcm %s for dailink %s: %d\n", - new_name, rtd->dai_link->name, ret); - return ret; - } + if (ret < 0) + return snd_soc_ret(rtd->dev, ret, + "can't create pcm %s for dailink %s\n", new_name, rtd->dai_link->name); + dev_dbg(rtd->card->dev, "ASoC: registered pcm #%d %s\n", rtd->id, new_name); return 0; diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index 9f4da061eff9..7b0b8531bb32 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -131,8 +131,8 @@ static const struct snd_soc_tplg_kcontrol_ops io_ops[] = { snd_soc_put_enum_double, NULL}, {SND_SOC_TPLG_CTL_BYTES, snd_soc_bytes_get, snd_soc_bytes_put, snd_soc_bytes_info}, - {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw_range, - snd_soc_put_volsw_range, snd_soc_info_volsw_range}, + {SND_SOC_TPLG_CTL_RANGE, snd_soc_get_volsw, + snd_soc_put_volsw, snd_soc_info_volsw}, {SND_SOC_TPLG_CTL_VOLSW_XR_SX, snd_soc_get_xr_sx, snd_soc_put_xr_sx, snd_soc_info_xr_sx}, {SND_SOC_TPLG_CTL_STROBE, snd_soc_get_strobe, @@ -220,15 +220,6 @@ static int get_widget_id(int tplg_type) return -EINVAL; } -static inline void soc_bind_err(struct soc_tplg *tplg, - struct snd_soc_tplg_ctl_hdr *hdr, int index) -{ - dev_err(tplg->dev, - "ASoC: invalid control type (g,p,i) %d:%d:%d index %d at 0x%lx\n", - hdr->ops.get, hdr->ops.put, hdr->ops.info, index, - soc_tplg_get_offset(tplg)); -} - static inline void soc_control_err(struct soc_tplg *tplg, struct snd_soc_tplg_ctl_hdr *hdr, const char *name) { @@ -678,6 +669,7 @@ static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcon sm->min = le32_to_cpu(mc->min); sm->invert = le32_to_cpu(mc->invert); sm->platform_max = le32_to_cpu(mc->platform_max); + sm->num_channels = le32_to_cpu(mc->num_channels); /* map io handlers */ err = soc_tplg_kcontrol_bind_io(&mc->hdr, kc, tplg); @@ -992,35 +984,26 @@ static int soc_tplg_kcontrol_elems_load(struct soc_tplg *tplg, return -EINVAL; } - switch (le32_to_cpu(control_hdr->ops.info)) { - case SND_SOC_TPLG_CTL_VOLSW: - case SND_SOC_TPLG_CTL_STROBE: - case SND_SOC_TPLG_CTL_VOLSW_SX: - case SND_SOC_TPLG_CTL_VOLSW_XR_SX: - case SND_SOC_TPLG_CTL_RANGE: - case SND_SOC_TPLG_DAPM_CTL_VOLSW: - case SND_SOC_TPLG_DAPM_CTL_PIN: + switch (le32_to_cpu(control_hdr->type)) { + case SND_SOC_TPLG_TYPE_MIXER: ret = soc_tplg_dmixer_create(tplg, le32_to_cpu(hdr->payload_size)); break; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + case SND_SOC_TPLG_TYPE_ENUM: ret = soc_tplg_denum_create(tplg, le32_to_cpu(hdr->payload_size)); break; - case SND_SOC_TPLG_CTL_BYTES: + case SND_SOC_TPLG_TYPE_BYTES: ret = soc_tplg_dbytes_create(tplg, le32_to_cpu(hdr->payload_size)); break; default: - soc_bind_err(tplg, control_hdr, i); - return -EINVAL; + ret = -EINVAL; + break; } + if (ret < 0) { - dev_err(tplg->dev, "ASoC: invalid control\n"); + dev_err(tplg->dev, "ASoC: invalid control type: %d, index: %d at 0x%lx\n", + control_hdr->type, i, soc_tplg_get_offset(tplg)); return ret; } - } return 0; @@ -1184,13 +1167,9 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, for (i = 0; i < le32_to_cpu(w->num_kcontrols); i++) { control_hdr = (struct snd_soc_tplg_ctl_hdr *)tplg->pos; - switch (le32_to_cpu(control_hdr->ops.info)) { - case SND_SOC_TPLG_CTL_VOLSW: - case SND_SOC_TPLG_CTL_STROBE: - case SND_SOC_TPLG_CTL_VOLSW_SX: - case SND_SOC_TPLG_CTL_VOLSW_XR_SX: - case SND_SOC_TPLG_CTL_RANGE: - case SND_SOC_TPLG_DAPM_CTL_VOLSW: + + switch (le32_to_cpu(control_hdr->type)) { + case SND_SOC_TPLG_TYPE_MIXER: /* volume mixer */ kc[i].index = mixer_count; kcontrol_type[i] = SND_SOC_TPLG_TYPE_MIXER; @@ -1199,11 +1178,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, if (ret < 0) goto hdr_err; break; - case SND_SOC_TPLG_CTL_ENUM: - case SND_SOC_TPLG_CTL_ENUM_VALUE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT: - case SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE: + case SND_SOC_TPLG_TYPE_ENUM: /* enumerated mixer */ kc[i].index = enum_count; kcontrol_type[i] = SND_SOC_TPLG_TYPE_ENUM; @@ -1212,7 +1187,7 @@ static int soc_tplg_dapm_widget_create(struct soc_tplg *tplg, if (ret < 0) goto hdr_err; break; - case SND_SOC_TPLG_CTL_BYTES: + case SND_SOC_TPLG_TYPE_BYTES: /* bytes control */ kc[i].index = bytes_count; kcontrol_type[i] = SND_SOC_TPLG_TYPE_BYTES; diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c index aa93e77ac937..5e3e4f14c392 100644 --- a/sound/soc/soc-utils.c +++ b/sound/soc/soc-utils.c @@ -7,7 +7,7 @@ // Author: Mark Brown <broonie@opensource.wolfsonmicro.com> // Liam Girdwood <lrg@slimlogic.co.uk> -#include <linux/platform_device.h> +#include <linux/device/faux.h> #include <linux/export.h> #include <linux/math.h> #include <sound/core.h> @@ -15,6 +15,33 @@ #include <sound/pcm_params.h> #include <sound/soc.h> +int snd_soc_ret(const struct device *dev, int ret, const char *fmt, ...) +{ + struct va_format vaf; + va_list args; + + /* Positive, Zero values are not errors */ + if (ret >= 0) + return ret; + + /* Negative values might be errors */ + switch (ret) { + case -EPROBE_DEFER: + case -ENOTSUPP: + case -EOPNOTSUPP: + break; + default: + va_start(args, fmt); + vaf.fmt = fmt; + vaf.va = &args; + + dev_err(dev, "ASoC error (%d): %pV", ret, &vaf); + } + + return ret; +} +EXPORT_SYMBOL_GPL(snd_soc_ret); + int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots) { return sample_size * channels * tdm_slots; @@ -235,48 +262,38 @@ struct snd_soc_dai_link_component snd_soc_dummy_dlc = { }; EXPORT_SYMBOL_GPL(snd_soc_dummy_dlc); -static int snd_soc_dummy_probe(struct platform_device *pdev) +static int snd_soc_dummy_probe(struct faux_device *fdev) { int ret; - ret = devm_snd_soc_register_component(&pdev->dev, + ret = devm_snd_soc_register_component(&fdev->dev, &dummy_codec, &dummy_dai, 1); if (ret < 0) return ret; - ret = devm_snd_soc_register_component(&pdev->dev, &dummy_platform, + ret = devm_snd_soc_register_component(&fdev->dev, &dummy_platform, NULL, 0); return ret; } -static struct platform_driver soc_dummy_driver = { - .driver = { - .name = "snd-soc-dummy", - }, +static struct faux_device_ops soc_dummy_ops = { .probe = snd_soc_dummy_probe, }; -static struct platform_device *soc_dummy_dev; +static struct faux_device *soc_dummy_dev; int __init snd_soc_util_init(void) { - int ret; - - soc_dummy_dev = - platform_device_register_simple("snd-soc-dummy", -1, NULL, 0); - if (IS_ERR(soc_dummy_dev)) - return PTR_ERR(soc_dummy_dev); + soc_dummy_dev = faux_device_create("snd-soc-dummy", NULL, + &soc_dummy_ops); + if (!soc_dummy_dev) + return -ENODEV; - ret = platform_driver_register(&soc_dummy_driver); - if (ret != 0) - platform_device_unregister(soc_dummy_dev); - - return ret; + return 0; } void snd_soc_util_exit(void) { - platform_driver_unregister(&soc_dummy_driver); - platform_device_unregister(soc_dummy_dev); + faux_device_destroy(soc_dummy_dev); } diff --git a/sound/soc/sof/amd/Kconfig b/sound/soc/sof/amd/Kconfig index f4cafe801017..3ea82fa72e35 100644 --- a/sound/soc/sof/amd/Kconfig +++ b/sound/soc/sof/amd/Kconfig @@ -32,6 +32,7 @@ config SND_SOC_SOF_AMD_COMMON config SND_SOC_SOF_AMD_RENOIR tristate "SOF support for RENOIR" depends on SND_SOC_SOF_PCI + depends on AMD_NODE select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support on AMD Renoir platform @@ -39,6 +40,7 @@ config SND_SOC_SOF_AMD_RENOIR config SND_SOC_SOF_AMD_VANGOGH tristate "SOF support for VANGOGH" depends on SND_SOC_SOF_PCI + depends on AMD_NODE select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support @@ -49,6 +51,7 @@ config SND_SOC_SOF_AMD_VANGOGH config SND_SOC_SOF_AMD_REMBRANDT tristate "SOF support for REMBRANDT" depends on SND_SOC_SOF_PCI + depends on AMD_NODE select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support on AMD Rembrandt platform @@ -81,6 +84,7 @@ config SND_SOC_SOF_AMD_SOUNDWIRE config SND_SOC_SOF_AMD_ACP63 tristate "SOF support for ACP6.3 platform" depends on SND_SOC_SOF_PCI + depends on AMD_NODE select SND_SOC_SOF_AMD_COMMON select SND_SOC_SOF_AMD_SOUNDWIRE_LINK_BASELINE help @@ -92,6 +96,7 @@ config SND_SOC_SOF_AMD_ACP63 config SND_SOC_SOF_AMD_ACP70 tristate "SOF support for ACP7.0 platform" depends on SND_SOC_SOF_PCI + depends on AMD_NODE select SND_SOC_SOF_AMD_COMMON help Select this option for SOF support on diff --git a/sound/soc/sof/amd/acp.c b/sound/soc/sof/amd/acp.c index 9e13c96528be..7c6d647fa253 100644 --- a/sound/soc/sof/amd/acp.c +++ b/sound/soc/sof/amd/acp.c @@ -16,6 +16,8 @@ #include <linux/module.h> #include <linux/pci.h> +#include <asm/amd_node.h> + #include "../ops.h" #include "acp.h" #include "acp-dsp-offset.h" @@ -43,24 +45,6 @@ const struct dmi_system_id acp_sof_quirk_table[] = { }; EXPORT_SYMBOL_GPL(acp_sof_quirk_table); -static int smn_write(struct pci_dev *dev, u32 smn_addr, u32 data) -{ - pci_write_config_dword(dev, 0x60, smn_addr); - pci_write_config_dword(dev, 0x64, data); - - return 0; -} - -static int smn_read(struct pci_dev *dev, u32 smn_addr) -{ - u32 data = 0; - - pci_write_config_dword(dev, 0x60, smn_addr); - pci_read_config_dword(dev, 0x64, &data); - - return data; -} - static void init_dma_descriptor(struct acp_dev_data *adata) { struct snd_sof_dev *sdev = adata->dev; @@ -209,11 +193,11 @@ int configure_and_run_dma(struct acp_dev_data *adata, unsigned int src_addr, static int psp_mbox_ready(struct acp_dev_data *adata, bool ack) { struct snd_sof_dev *sdev = adata->dev; - int ret; - u32 data; + int ret, data; + + ret = read_poll_timeout(smn_read_register, data, data > 0 && data & MBOX_READY_MASK, + MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_114_REG); - ret = read_poll_timeout(smn_read, data, data & MBOX_READY_MASK, MBOX_DELAY_US, - ACP_PSP_TIMEOUT_US, false, adata->smn_dev, MP0_C2PMSG_114_REG); if (!ret) return 0; @@ -241,8 +225,8 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd) return -EINVAL; /* Get a non-zero Doorbell value from PSP */ - ret = read_poll_timeout(smn_read, data, data, MBOX_DELAY_US, ACP_PSP_TIMEOUT_US, false, - adata->smn_dev, MP0_C2PMSG_73_REG); + ret = read_poll_timeout(smn_read_register, data, data > 0, MBOX_DELAY_US, + ACP_PSP_TIMEOUT_US, false, MP0_C2PMSG_73_REG); if (ret) { dev_err(sdev->dev, "Failed to get Doorbell from MBOX %x\n", MP0_C2PMSG_73_REG); @@ -254,10 +238,14 @@ static int psp_send_cmd(struct acp_dev_data *adata, int cmd) if (ret) return ret; - smn_write(adata->smn_dev, MP0_C2PMSG_114_REG, cmd); + ret = amd_smn_write(0, MP0_C2PMSG_114_REG, cmd); + if (ret) + return ret; /* Ring the Doorbell for PSP */ - smn_write(adata->smn_dev, MP0_C2PMSG_73_REG, data); + ret = amd_smn_write(0, MP0_C2PMSG_73_REG, data); + if (ret) + return ret; /* Check MBOX ready as PSP ack */ ret = psp_mbox_ready(adata, 1); @@ -771,16 +759,10 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) adata->pci_rev = pci->revision; mutex_init(&adata->acp_lock); sdev->pdata->hw_pdata = adata; - adata->smn_dev = pci_get_device(PCI_VENDOR_ID_AMD, chip->host_bridge_id, NULL); - if (!adata->smn_dev) { - dev_err(sdev->dev, "Failed to get host bridge device\n"); - ret = -ENODEV; - goto unregister_dev; - } ret = acp_init(sdev); if (ret < 0) - goto free_smn_dev; + goto unregister_dev; sdev->ipc_irq = pci->irq; ret = request_threaded_irq(sdev->ipc_irq, acp_irq_handler, acp_irq_thread, @@ -788,7 +770,7 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "failed to register IRQ %d\n", sdev->ipc_irq); - goto free_smn_dev; + goto unregister_dev; } /* scan SoundWire capabilities exposed by DSDT */ @@ -801,7 +783,6 @@ int amd_sof_acp_probe(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: SoundWire probe error\n"); free_irq(sdev->ipc_irq, sdev); - pci_dev_put(adata->smn_dev); return ret; } @@ -847,8 +828,6 @@ skip_soundwire: free_ipc_irq: free_irq(sdev->ipc_irq, sdev); -free_smn_dev: - pci_dev_put(adata->smn_dev); unregister_dev: platform_device_unregister(adata->dmic_dev); return ret; @@ -859,9 +838,6 @@ void amd_sof_acp_remove(struct snd_sof_dev *sdev) { struct acp_dev_data *adata = sdev->pdata->hw_pdata; - if (adata->smn_dev) - pci_dev_put(adata->smn_dev); - if (adata->sdw) amd_sof_sdw_exit(sdev); diff --git a/sound/soc/sof/amd/acp.h b/sound/soc/sof/amd/acp.h index 2a19d82d6200..d084db34eed8 100644 --- a/sound/soc/sof/amd/acp.h +++ b/sound/soc/sof/amd/acp.h @@ -197,7 +197,6 @@ struct acp_dsp_stream { struct sof_amd_acp_desc { const char *name; - unsigned int host_bridge_id; u32 pgfsm_base; u32 ext_intr_enb; u32 ext_intr_cntl; @@ -256,7 +255,6 @@ struct acp_dev_data { struct dma_descriptor dscr_info[ACP_MAX_DESC]; struct acp_dsp_stream stream_buf[ACP_MAX_STREAM]; struct acp_dsp_stream *dtrace_stream; - struct pci_dev *smn_dev; struct acp_dsp_stream *probe_stream; bool enable_fw_debug; bool is_dram_in_use; diff --git a/sound/soc/sof/amd/pci-acp63.c b/sound/soc/sof/amd/pci-acp63.c index ffe7c755d655..21ffdfdcf03d 100644 --- a/sound/soc/sof/amd/pci-acp63.c +++ b/sound/soc/sof/amd/pci-acp63.c @@ -28,7 +28,6 @@ #define ACP6x_REG_END 0x125C000 static const struct sof_amd_acp_desc acp63_chip_info = { - .host_bridge_id = HOST_BRIDGE_ACP63, .pgfsm_base = ACP6X_PGFSM_BASE, .ext_intr_enb = ACP6X_EXTERNAL_INTR_ENB, .ext_intr_cntl = ACP6X_EXTERNAL_INTR_CNTL, @@ -105,7 +104,7 @@ static struct pci_driver snd_sof_pci_amd_acp63_driver = { .probe = acp63_pci_probe, .remove = acp63_pci_remove, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_amd_acp63_driver); diff --git a/sound/soc/sof/amd/pci-acp70.c b/sound/soc/sof/amd/pci-acp70.c index 3647ec992e95..8fa1170a2161 100644 --- a/sound/soc/sof/amd/pci-acp70.c +++ b/sound/soc/sof/amd/pci-acp70.c @@ -28,7 +28,6 @@ #define ACP70_REG_END 0x125C000 static const struct sof_amd_acp_desc acp70_chip_info = { - .host_bridge_id = HOST_BRIDGE_ACP70, .pgfsm_base = ACP70_PGFSM_BASE, .ext_intr_enb = ACP70_EXTERNAL_INTR_ENB, .ext_intr_cntl = ACP70_EXTERNAL_INTR_CNTL, @@ -101,7 +100,7 @@ static struct pci_driver snd_sof_pci_amd_acp70_driver = { .probe = acp70_pci_probe, .remove = acp70_pci_remove, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_amd_acp70_driver); diff --git a/sound/soc/sof/amd/pci-rmb.c b/sound/soc/sof/amd/pci-rmb.c index cbb4d5282664..0233b6ba2d2e 100644 --- a/sound/soc/sof/amd/pci-rmb.c +++ b/sound/soc/sof/amd/pci-rmb.c @@ -28,7 +28,6 @@ #define ACP6X_FUTURE_REG_ACLK_0 0x1854 static const struct sof_amd_acp_desc rembrandt_chip_info = { - .host_bridge_id = HOST_BRIDGE_RMB, .pgfsm_base = ACP6X_PGFSM_BASE, .ext_intr_stat = ACP6X_EXT_INTR_STAT, .dsp_intr_base = ACP6X_DSP_SW_INTR_BASE, diff --git a/sound/soc/sof/amd/pci-rn.c b/sound/soc/sof/amd/pci-rn.c index b7d558cb1fd7..2b7fbcf11b55 100644 --- a/sound/soc/sof/amd/pci-rn.c +++ b/sound/soc/sof/amd/pci-rn.c @@ -28,7 +28,6 @@ #define ACP3X_FUTURE_REG_ACLK_0 0x1860 static const struct sof_amd_acp_desc renoir_chip_info = { - .host_bridge_id = HOST_BRIDGE_CZN, .pgfsm_base = ACP3X_PGFSM_BASE, .ext_intr_stat = ACP3X_EXT_INTR_STAT, .dsp_intr_base = ACP3X_DSP_SW_INTR_BASE, @@ -98,7 +97,7 @@ static struct pci_driver snd_sof_pci_amd_rn_driver = { .probe = acp_pci_rn_probe, .remove = acp_pci_rn_remove, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_amd_rn_driver); diff --git a/sound/soc/sof/amd/pci-vangogh.c b/sound/soc/sof/amd/pci-vangogh.c index 28f2d4050a67..6ef692becfb9 100644 --- a/sound/soc/sof/amd/pci-vangogh.c +++ b/sound/soc/sof/amd/pci-vangogh.c @@ -25,7 +25,6 @@ static const struct sof_amd_acp_desc vangogh_chip_info = { .name = "vangogh", - .host_bridge_id = HOST_BRIDGE_VGH, .pgfsm_base = ACP5X_PGFSM_BASE, .ext_intr_stat = ACP5X_EXT_INTR_STAT, .dsp_intr_base = ACP5X_DSP_SW_INTR_BASE, @@ -91,7 +90,7 @@ static struct pci_driver snd_sof_pci_amd_vgh_driver = { .probe = acp_pci_vgh_probe, .remove = acp_pci_vgh_remove, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_amd_vgh_driver); diff --git a/sound/soc/sof/imx/Kconfig b/sound/soc/sof/imx/Kconfig index 4751b04d5e6f..327e2df94a58 100644 --- a/sound/soc/sof/imx/Kconfig +++ b/sound/soc/sof/imx/Kconfig @@ -32,22 +32,13 @@ config SND_SOC_SOF_IMX8 Say Y if you have such a device. If unsure select "N". -config SND_SOC_SOF_IMX8M - tristate "SOF support for i.MX8M" +config SND_SOC_SOF_IMX9 + tristate "SOF support for i.MX9" depends on IMX_DSP select SND_SOC_SOF_IMX_COMMON help - This adds support for Sound Open Firmware for NXP i.MX8M platforms. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_SOF_IMX8ULP - tristate "SOF support for i.MX8ULP" - depends on IMX_DSP - select SND_SOC_SOF_IMX_COMMON - help - This adds support for Sound Open Firmware for NXP i.MX8ULP platforms. - Say Y if you have such a device. + This adds support for Sound Open Firmware for NXP i.MX9 platforms. + Say Y if you need such a device. If unsure select "N". endif ## SND_SOC_SOF_IMX_TOPLEVEL diff --git a/sound/soc/sof/imx/Makefile b/sound/soc/sof/imx/Makefile index be0bf0736dfa..74b5ecad8fe8 100644 --- a/sound/soc/sof/imx/Makefile +++ b/sound/soc/sof/imx/Makefile @@ -1,11 +1,9 @@ # SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) snd-sof-imx8-y := imx8.o -snd-sof-imx8m-y := imx8m.o -snd-sof-imx8ulp-y := imx8ulp.o +snd-sof-imx9-y := imx9.o snd-sof-imx-common-y := imx-common.o obj-$(CONFIG_SND_SOC_SOF_IMX8) += snd-sof-imx8.o -obj-$(CONFIG_SND_SOC_SOF_IMX8M) += snd-sof-imx8m.o -obj-$(CONFIG_SND_SOC_SOF_IMX8ULP) += snd-sof-imx8ulp.o +obj-$(CONFIG_SND_SOC_SOF_IMX9) += snd-sof-imx9.o obj-$(CONFIG_SND_SOC_SOF_IMX_COMMON) += imx-common.o diff --git a/sound/soc/sof/imx/imx-common.c b/sound/soc/sof/imx/imx-common.c index fce6d9cf6a6b..62bf707aa909 100644 --- a/sound/soc/sof/imx/imx-common.c +++ b/sound/soc/sof/imx/imx-common.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // -// Copyright 2020 NXP +// Copyright 2020-2025 NXP // // Common helpers for the audio DSP on i.MX8 +#include <linux/firmware/imx/dsp.h> #include <linux/module.h> +#include <linux/of_address.h> +#include <linux/of_reserved_mem.h> +#include <linux/pm_domain.h> #include <sound/sof/xtensa.h> + #include "../ops.h" #include "imx-common.h" @@ -74,5 +79,428 @@ void imx8_dump(struct snd_sof_dev *sdev, u32 flags) } EXPORT_SYMBOL(imx8_dump); +static void imx_handle_reply(struct imx_dsp_ipc *ipc) +{ + struct snd_sof_dev *sdev; + unsigned long flags; + + sdev = imx_dsp_get_data(ipc); + + spin_lock_irqsave(&sdev->ipc_lock, flags); + snd_sof_ipc_process_reply(sdev, 0); + spin_unlock_irqrestore(&sdev->ipc_lock, flags); +} + +static void imx_handle_request(struct imx_dsp_ipc *ipc) +{ + struct snd_sof_dev *sdev; + u32 panic_code; + + sdev = imx_dsp_get_data(ipc); + + if (get_chip_info(sdev)->ipc_info.has_panic_code) { + sof_mailbox_read(sdev, sdev->debug_box.offset + 0x4, + &panic_code, + sizeof(panic_code)); + + if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(sdev, panic_code, true); + return; + } + } + + snd_sof_ipc_msgs_rx(sdev); +} + +static struct imx_dsp_ops imx_ipc_ops = { + .handle_reply = imx_handle_reply, + .handle_request = imx_handle_request, +}; + +static int imx_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct imx_common_data *common = sdev->pdata->hw_pdata; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, msg->msg_size); + imx_dsp_ring_doorbell(common->ipc_handle, 0x0); + + return 0; +} + +static int imx_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + switch (type) { + case SOF_FW_BLK_TYPE_IRAM: + case SOF_FW_BLK_TYPE_SRAM: + return type; + default: + return -EINVAL; + } +} + +static int imx_get_mailbox_offset(struct snd_sof_dev *sdev) +{ + return get_chip_info(sdev)->ipc_info.boot_mbox_offset; +} + +static int imx_get_window_offset(struct snd_sof_dev *sdev, u32 id) +{ + return get_chip_info(sdev)->ipc_info.window_offset; +} + +static int imx_set_power_state(struct snd_sof_dev *sdev, + const struct sof_dsp_power_state *target) +{ + sdev->dsp_power_state = *target; + + return 0; +} + +static int imx_common_resume(struct snd_sof_dev *sdev) +{ + struct imx_common_data *common; + int ret, i; + + common = sdev->pdata->hw_pdata; + + ret = clk_bulk_prepare_enable(common->clk_num, common->clks); + if (ret) + dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_request_channel(common->ipc_handle, i); + + /* done. If need be, core will be started by SOF core immediately after */ + return 0; +} + +static int imx_common_suspend(struct snd_sof_dev *sdev) +{ + struct imx_common_data *common; + int i, ret; + + common = sdev->pdata->hw_pdata; + + ret = imx_chip_core_shutdown(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to shutdown core: %d\n", ret); + return ret; + } + + for (i = 0; i < DSP_MU_CHAN_NUM; i++) + imx_dsp_free_channel(common->ipc_handle, i); + + clk_bulk_disable_unprepare(common->clk_num, common->clks); + + return 0; +} + +static int imx_runtime_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + }; + int ret; + + ret = imx_common_resume(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to runtime common resume: %d\n", ret); + return ret; + } + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int imx_resume(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D0, + }; + int ret; + + ret = imx_common_resume(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to common resume: %d\n", ret); + return ret; + } + + if (pm_runtime_suspended(sdev->dev)) { + pm_runtime_disable(sdev->dev); + pm_runtime_set_active(sdev->dev); + pm_runtime_mark_last_busy(sdev->dev); + pm_runtime_enable(sdev->dev); + pm_runtime_idle(sdev->dev); + } + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int imx_runtime_suspend(struct snd_sof_dev *sdev) +{ + const struct sof_dsp_power_state target_state = { + .state = SOF_DSP_PM_D3, + }; + int ret; + + ret = imx_common_suspend(sdev); + if (ret < 0) + dev_err(sdev->dev, "failed to runtime common suspend: %d\n", ret); + + return snd_sof_dsp_set_power_state(sdev, &target_state); +} + +static int imx_suspend(struct snd_sof_dev *sdev, unsigned int target_state) +{ + const struct sof_dsp_power_state target_power_state = { + .state = target_state, + }; + int ret; + + if (!pm_runtime_suspended(sdev->dev)) { + ret = imx_common_suspend(sdev); + if (ret < 0) { + dev_err(sdev->dev, "failed to common suspend: %d\n", ret); + return ret; + } + } + + return snd_sof_dsp_set_power_state(sdev, &target_power_state); +} + +static int imx_region_name_to_blk_type(const char *region_name) +{ + if (!strcmp(region_name, "iram")) + return SOF_FW_BLK_TYPE_IRAM; + else if (!strcmp(region_name, "dram")) + return SOF_FW_BLK_TYPE_DRAM; + else if (!strcmp(region_name, "sram")) + return SOF_FW_BLK_TYPE_SRAM; + else + return -EINVAL; +} + +static int imx_parse_ioremap_memory(struct snd_sof_dev *sdev) +{ + const struct imx_chip_info *chip_info; + struct reserved_mem *reserved; + struct platform_device *pdev; + struct device_node *res_np; + phys_addr_t base, size; + struct resource *res; + int i, blk_type, ret; + + pdev = to_platform_device(sdev->dev); + chip_info = get_chip_info(sdev); + + for (i = 0; chip_info->memory[i].name; i++) { + blk_type = imx_region_name_to_blk_type(chip_info->memory[i].name); + if (blk_type < 0) + return dev_err_probe(sdev->dev, blk_type, + "no blk type for region %s\n", + chip_info->memory[i].name); + + if (!chip_info->memory[i].reserved) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + chip_info->memory[i].name); + if (!res) + return dev_err_probe(sdev->dev, -ENODEV, + "failed to fetch %s resource\n", + chip_info->memory[i].name); + + base = res->start; + size = resource_size(res); + } else { + ret = of_property_match_string(pdev->dev.of_node, + "memory-region-names", + chip_info->memory[i].name); + if (ret < 0) + return dev_err_probe(sdev->dev, ret, + "no valid index for %s\n", + chip_info->memory[i].name); + + res_np = of_parse_phandle(pdev->dev.of_node, + "memory-region", + ret); + if (!res_np) + return dev_err_probe(sdev->dev, -ENODEV, + "failed to parse phandle %s\n", + chip_info->memory[i].name); + + reserved = of_reserved_mem_lookup(res_np); + of_node_put(res_np); + if (!reserved) + return dev_err_probe(sdev->dev, -ENODEV, + "failed to get %s reserved\n", + chip_info->memory[i].name); + + base = reserved->base; + size = reserved->size; + } + + sdev->bar[blk_type] = devm_ioremap(sdev->dev, base, size); + if (!sdev->bar[blk_type]) + return dev_err_probe(sdev->dev, + -ENOMEM, + "failed to ioremap %s region\n", + chip_info->memory[i].name); + } + + return 0; +} + +static void imx_unregister_action(void *data) +{ + struct imx_common_data *common; + struct snd_sof_dev *sdev; + + sdev = data; + common = sdev->pdata->hw_pdata; + + if (get_chip_info(sdev)->has_dma_reserved) + of_reserved_mem_device_release(sdev->dev); + + platform_device_unregister(common->ipc_dev); +} + +static int imx_probe(struct snd_sof_dev *sdev) +{ + struct dev_pm_domain_attach_data domain_data = { + .pd_names = NULL, /* no filtering */ + .pd_flags = PD_FLAG_DEV_LINK_ON, + }; + struct imx_common_data *common; + struct platform_device *pdev; + int ret; + + pdev = to_platform_device(sdev->dev); + + common = devm_kzalloc(sdev->dev, sizeof(*common), GFP_KERNEL); + if (!common) + return dev_err_probe(sdev->dev, -ENOMEM, + "failed to allocate common data\n"); + sdev->pdata->hw_pdata = common; + + common->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", + PLATFORM_DEVID_NONE, + pdev, sizeof(*pdev)); + if (IS_ERR(common->ipc_dev)) + return dev_err_probe(sdev->dev, PTR_ERR(common->ipc_dev), + "failed to create IPC device\n"); + + if (get_chip_info(sdev)->has_dma_reserved) { + ret = of_reserved_mem_device_init_by_name(sdev->dev, + pdev->dev.of_node, + "dma"); + if (ret) { + platform_device_unregister(common->ipc_dev); + + return dev_err_probe(sdev->dev, ret, + "failed to bind DMA region\n"); + } + } + + /* let the devres API take care of the cleanup */ + ret = devm_add_action_or_reset(sdev->dev, + imx_unregister_action, + sdev); + if (ret) + return dev_err_probe(sdev->dev, ret, "failed to add devm action\n"); + + common->ipc_handle = dev_get_drvdata(&common->ipc_dev->dev); + if (!common->ipc_handle) + return dev_err_probe(sdev->dev, -EPROBE_DEFER, + "failed to fetch IPC handle\n"); + + ret = imx_parse_ioremap_memory(sdev); + if (ret < 0) + return dev_err_probe(sdev->dev, ret, + "failed to parse/ioremap memory regions\n"); + + if (!sdev->dev->pm_domain) { + ret = devm_pm_domain_attach_list(sdev->dev, + &domain_data, &common->pd_list); + if (ret < 0) + return dev_err_probe(sdev->dev, ret, "failed to attach PDs\n"); + } + + ret = devm_clk_bulk_get_all(sdev->dev, &common->clks); + if (ret < 0) + return dev_err_probe(sdev->dev, ret, "failed to fetch clocks\n"); + common->clk_num = ret; + + ret = clk_bulk_prepare_enable(common->clk_num, common->clks); + if (ret < 0) + return dev_err_probe(sdev->dev, ret, "failed to enable clocks\n"); + + common->ipc_handle->ops = &imx_ipc_ops; + imx_dsp_set_data(common->ipc_handle, sdev); + + sdev->num_cores = 1; + sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + sdev->dsp_box.offset = get_chip_info(sdev)->ipc_info.boot_mbox_offset; + + return imx_chip_probe(sdev); +} + +static void imx_remove(struct snd_sof_dev *sdev) +{ + struct imx_common_data *common; + int ret; + + common = sdev->pdata->hw_pdata; + + if (!pm_runtime_suspended(sdev->dev)) { + ret = imx_chip_core_shutdown(sdev); + if (ret < 0) + dev_err(sdev->dev, "failed to shutdown core: %d\n", ret); + + clk_bulk_disable_unprepare(common->clk_num, common->clks); + } +} + +const struct snd_sof_dsp_ops sof_imx_ops = { + .probe = imx_probe, + .remove = imx_remove, + + .run = imx_chip_core_kick, + .reset = imx_chip_core_reset, + + .block_read = sof_block_read, + .block_write = sof_block_write, + + .mailbox_read = sof_mailbox_read, + .mailbox_write = sof_mailbox_write, + + .send_msg = imx_send_msg, + .get_mailbox_offset = imx_get_mailbox_offset, + .get_window_offset = imx_get_window_offset, + + .ipc_msg_data = sof_ipc_msg_data, + .set_stream_data_offset = sof_set_stream_data_offset, + + .get_bar_index = imx_get_bar_index, + .load_firmware = snd_sof_load_firmware_memcpy, + + .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, + + .pcm_open = sof_stream_pcm_open, + .pcm_close = sof_stream_pcm_close, + + .runtime_suspend = imx_runtime_suspend, + .runtime_resume = imx_runtime_resume, + .suspend = imx_suspend, + .resume = imx_resume, + + .set_power_state = imx_set_power_state, + + .hw_info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_BATCH | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, +}; +EXPORT_SYMBOL(sof_imx_ops); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF helpers for IMX platforms"); diff --git a/sound/soc/sof/imx/imx-common.h b/sound/soc/sof/imx/imx-common.h index 13d7f3ef675e..9bd711dbb5d0 100644 --- a/sound/soc/sof/imx/imx-common.h +++ b/sound/soc/sof/imx/imx-common.h @@ -4,10 +4,159 @@ #define __IMX_COMMON_H__ #include <linux/clk.h> +#include <linux/of_platform.h> +#include <sound/sof/xtensa.h> + +#include "../sof-of-dev.h" +#include "../ops.h" #define EXCEPT_MAX_HDR_SIZE 0x400 #define IMX8_STACK_DUMP_SIZE 32 +/* chip_info refers to the data stored in struct sof_dev_desc's chip_info */ +#define get_chip_info(sdev)\ + ((const struct imx_chip_info *)((sdev)->pdata->desc->chip_info)) + +/* chip_pdata refers to the data stored in struct imx_common_data's chip_pdata */ +#define get_chip_pdata(sdev)\ + (((struct imx_common_data *)((sdev)->pdata->hw_pdata))->chip_pdata) + +/* can be used if: + * 1) The only supported IPC version is IPC3. + * 2) The default paths/FW name match values below. + * + * otherwise, just explicitly declare the structure + */ +#define IMX_SOF_DEV_DESC(mach_name, of_machs, \ + mach_chip_info, mach_ops, mach_ops_init) \ +static struct sof_dev_desc sof_of_##mach_name##_desc = { \ + .of_machines = of_machs, \ + .chip_info = mach_chip_info, \ + .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), \ + .ipc_default = SOF_IPC_TYPE_3, \ + .default_fw_path = { \ + [SOF_IPC_TYPE_3] = "imx/sof", \ + }, \ + .default_tplg_path = { \ + [SOF_IPC_TYPE_3] = "imx/sof-tplg", \ + }, \ + .default_fw_filename = { \ + [SOF_IPC_TYPE_3] = "sof-" #mach_name ".ri", \ + }, \ + .ops = mach_ops, \ + .ops_init = mach_ops_init, \ +} + +/* to be used alongside IMX_SOF_DEV_DESC() */ +#define IMX_SOF_DEV_DESC_NAME(mach_name) sof_of_##mach_name##_desc + +/* dai driver entry w/ playback and capture caps. If one direction is missing + * then set the channels to 0. + */ +#define IMX_SOF_DAI_DRV_ENTRY(dai_name, pb_cmin, pb_cmax, cap_cmin, cap_cmax) \ +{ \ + .name = dai_name, \ + .playback = { \ + .channels_min = pb_cmin, \ + .channels_max = pb_cmax, \ + }, \ + .capture = { \ + .channels_min = cap_cmin, \ + .channels_max = cap_cmax, \ + }, \ +} + +/* use if playback and capture have the same min/max channel count */ +#define IMX_SOF_DAI_DRV_ENTRY_BIDIR(dai_name, cmin, cmax)\ + IMX_SOF_DAI_DRV_ENTRY(dai_name, cmin, cmax, cmin, cmax) + +struct imx_ipc_info { + /* true if core is able to write a panic code to the debug box */ + bool has_panic_code; + /* offset to mailbox in which firmware initially writes FW_READY */ + int boot_mbox_offset; + /* offset to region at which the mailboxes start */ + int window_offset; +}; + +struct imx_chip_ops { + /* called after clocks and PDs are enabled */ + int (*probe)(struct snd_sof_dev *sdev); + /* used directly by the SOF core */ + int (*core_kick)(struct snd_sof_dev *sdev); + /* called during suspend()/remove() before clocks are disabled */ + int (*core_shutdown)(struct snd_sof_dev *sdev); + /* used directly by the SOF core */ + int (*core_reset)(struct snd_sof_dev *sdev); +}; + +struct imx_memory_info { + const char *name; + bool reserved; +}; + +struct imx_chip_info { + struct imx_ipc_info ipc_info; + /* does the chip have a reserved memory region for DMA? */ + bool has_dma_reserved; + struct imx_memory_info *memory; + struct snd_soc_dai_driver *drv; + int num_drv; + /* optional */ + const struct imx_chip_ops *ops; +}; + +struct imx_common_data { + struct platform_device *ipc_dev; + struct imx_dsp_ipc *ipc_handle; + /* core may have no clocks */ + struct clk_bulk_data *clks; + int clk_num; + /* core may have no PDs */ + struct dev_pm_domain_list *pd_list; + void *chip_pdata; +}; + +static inline int imx_chip_core_kick(struct snd_sof_dev *sdev) +{ + const struct imx_chip_ops *ops = get_chip_info(sdev)->ops; + + if (ops && ops->core_kick) + return ops->core_kick(sdev); + + return 0; +} + +static inline int imx_chip_core_shutdown(struct snd_sof_dev *sdev) +{ + const struct imx_chip_ops *ops = get_chip_info(sdev)->ops; + + if (ops && ops->core_shutdown) + return ops->core_shutdown(sdev); + + return 0; +} + +static inline int imx_chip_core_reset(struct snd_sof_dev *sdev) +{ + const struct imx_chip_ops *ops = get_chip_info(sdev)->ops; + + if (ops && ops->core_reset) + return ops->core_reset(sdev); + + return 0; +} + +static inline int imx_chip_probe(struct snd_sof_dev *sdev) +{ + const struct imx_chip_ops *ops = get_chip_info(sdev)->ops; + + if (ops && ops->probe) + return ops->probe(sdev); + + return 0; +} + void imx8_get_registers(struct snd_sof_dev *sdev, struct sof_ipc_dsp_oops_xtensa *xoops, struct sof_ipc_panic_info *panic_info, @@ -15,4 +164,6 @@ void imx8_get_registers(struct snd_sof_dev *sdev, void imx8_dump(struct snd_sof_dev *sdev, u32 flags); +extern const struct snd_sof_dsp_ops sof_imx_ops; + #endif diff --git a/sound/soc/sof/imx/imx8.c b/sound/soc/sof/imx/imx8.c index 1e7bf00d7c46..ab07512e511d 100644 --- a/sound/soc/sof/imx/imx8.c +++ b/sound/soc/sof/imx/imx8.c @@ -1,140 +1,72 @@ // SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) // -// Copyright 2019 NXP +// Copyright 2019-2025 NXP // // Author: Daniel Baluta <daniel.baluta@nxp.com> // // Hardware interface for audio DSP on i.MX8 -#include <linux/firmware.h> -#include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/pm_domain.h> - -#include <linux/module.h> -#include <sound/sof.h> -#include <sound/sof/xtensa.h> -#include <linux/firmware/imx/ipc.h> -#include <linux/firmware/imx/dsp.h> +#include <dt-bindings/firmware/imx/rsrc.h> +#include <linux/arm-smccc.h> #include <linux/firmware/imx/svc/misc.h> -#include <dt-bindings/firmware/imx/rsrc.h> -#include "../ops.h" -#include "../sof-of-dev.h" -#include "imx-common.h" +#include <linux/mfd/syscon.h> -/* DSP memories */ -#define IRAM_OFFSET 0x10000 -#define IRAM_SIZE (2 * 1024) -#define DRAM0_OFFSET 0x0 -#define DRAM0_SIZE (32 * 1024) -#define DRAM1_OFFSET 0x8000 -#define DRAM1_SIZE (32 * 1024) -#define SYSRAM_OFFSET 0x18000 -#define SYSRAM_SIZE (256 * 1024) -#define SYSROM_OFFSET 0x58000 -#define SYSROM_SIZE (192 * 1024) +#include "imx-common.h" +/* imx8/imx8x macros */ #define RESET_VECTOR_VADDR 0x596f8000 -#define MBOX_OFFSET 0x800000 -#define MBOX_SIZE 0x1000 - -struct imx8_priv { - struct device *dev; - struct snd_sof_dev *sdev; - - /* DSP IPC handler */ - struct imx_dsp_ipc *dsp_ipc; - struct platform_device *ipc_dev; - - /* System Controller IPC handler */ - struct imx_sc_ipc *sc_ipc; - - /* Power domain handling */ - int num_domains; - struct device **pd_dev; - struct device_link **link; - - struct clk_bulk_data *clks; - int clk_num; -}; - -static int imx8_get_mailbox_offset(struct snd_sof_dev *sdev) -{ - return MBOX_OFFSET; -} - -static int imx8_get_window_offset(struct snd_sof_dev *sdev, u32 id) -{ - return MBOX_OFFSET; -} - -static void imx8_dsp_handle_reply(struct imx_dsp_ipc *ipc) -{ - struct imx8_priv *priv = imx_dsp_get_data(ipc); - unsigned long flags; - - spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - snd_sof_ipc_process_reply(priv->sdev, 0); - spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); -} - -static void imx8_dsp_handle_request(struct imx_dsp_ipc *ipc) -{ - struct imx8_priv *priv = imx_dsp_get_data(ipc); - u32 p; /* panic code */ - - /* Read the message from the debug box. */ - sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); - - /* Check to see if the message is a panic code (0x0dead***) */ - if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) - snd_sof_dsp_panic(priv->sdev, p, true); - else - snd_sof_ipc_msgs_rx(priv->sdev); -} - -static struct imx_dsp_ops dsp_ops = { - .handle_reply = imx8_dsp_handle_reply, - .handle_request = imx8_dsp_handle_request, +/* imx8m macros */ +#define IMX8M_DAP_DEBUG 0x28800000 +#define IMX8M_DAP_DEBUG_SIZE (64 * 1024) +#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020) +#define IMX8M_PWRCTL_CORERESET BIT(16) + +#define AudioDSP_REG0 0x100 +#define AudioDSP_REG1 0x104 +#define AudioDSP_REG2 0x108 +#define AudioDSP_REG3 0x10c + +#define AudioDSP_REG2_RUNSTALL BIT(5) + +/* imx8ulp macros */ +#define FSL_SIP_HIFI_XRDC 0xc200000e +#define SYSCTRL0 0x8 +#define EXECUTE_BIT BIT(13) +#define RESET_BIT BIT(16) +#define HIFI4_CLK_BIT BIT(17) +#define PB_CLK_BIT BIT(18) +#define PLAT_CLK_BIT BIT(19) +#define DEBUG_LOGIC_BIT BIT(25) + +struct imx8m_chip_data { + void __iomem *dap; + struct regmap *regmap; }; -static int imx8_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - struct imx8_priv *priv = sdev->pdata->hw_pdata; - - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - imx_dsp_ring_doorbell(priv->dsp_ipc, 0); - - return 0; -} - /* * DSP control. */ static int imx8x_run(struct snd_sof_dev *sdev) { - struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata; int ret; - ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP, IMX_SC_C_OFS_SEL, 1); if (ret < 0) { dev_err(sdev->dev, "Error system address offset source select\n"); return ret; } - ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP, IMX_SC_C_OFS_AUDIO, 0x80); if (ret < 0) { dev_err(sdev->dev, "Error system address offset of AUDIO\n"); return ret; } - ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP, IMX_SC_C_OFS_PERIPH, 0x5A); if (ret < 0) { dev_err(sdev->dev, "Error system address offset of PERIPH %d\n", @@ -142,14 +74,14 @@ static int imx8x_run(struct snd_sof_dev *sdev) return ret; } - ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP, IMX_SC_C_OFS_IRQ, 0x51); if (ret < 0) { dev_err(sdev->dev, "Error system address offset of IRQ\n"); return ret; } - imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, + imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true, RESET_VECTOR_VADDR); return 0; @@ -157,17 +89,16 @@ static int imx8x_run(struct snd_sof_dev *sdev) static int imx8_run(struct snd_sof_dev *sdev) { - struct imx8_priv *dsp_priv = sdev->pdata->hw_pdata; int ret; - ret = imx_sc_misc_set_control(dsp_priv->sc_ipc, IMX_SC_R_DSP, + ret = imx_sc_misc_set_control(get_chip_pdata(sdev), IMX_SC_R_DSP, IMX_SC_C_OFS_SEL, 0); if (ret < 0) { dev_err(sdev->dev, "Error system address offset source select\n"); return ret; } - imx_sc_pm_cpu_start(dsp_priv->sc_ipc, IMX_SC_R_DSP, true, + imx_sc_pm_cpu_start(get_chip_pdata(sdev), IMX_SC_R_DSP, true, RESET_VECTOR_VADDR); return 0; @@ -175,428 +106,273 @@ static int imx8_run(struct snd_sof_dev *sdev) static int imx8_probe(struct snd_sof_dev *sdev) { - struct platform_device *pdev = to_platform_device(sdev->dev); - struct device_node *np = pdev->dev.of_node; - struct device_node *res_node; - struct resource *mmio; - struct imx8_priv *priv; - struct resource res; - u32 base, size; - int ret = 0; - int i; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - sdev->num_cores = 1; - sdev->pdata->hw_pdata = priv; - priv->dev = sdev->dev; - priv->sdev = sdev; - - /* power up device associated power domains */ - priv->num_domains = of_count_phandle_with_args(np, "power-domains", - "#power-domain-cells"); - if (priv->num_domains < 0) { - dev_err(sdev->dev, "no power-domains property in %pOF\n", np); - return priv->num_domains; - } - - priv->pd_dev = devm_kmalloc_array(&pdev->dev, priv->num_domains, - sizeof(*priv->pd_dev), GFP_KERNEL); - if (!priv->pd_dev) - return -ENOMEM; - - priv->link = devm_kmalloc_array(&pdev->dev, priv->num_domains, - sizeof(*priv->link), GFP_KERNEL); - if (!priv->link) - return -ENOMEM; - - for (i = 0; i < priv->num_domains; i++) { - priv->pd_dev[i] = dev_pm_domain_attach_by_id(&pdev->dev, i); - if (IS_ERR(priv->pd_dev[i])) { - ret = PTR_ERR(priv->pd_dev[i]); - goto exit_unroll_pm; - } - priv->link[i] = device_link_add(&pdev->dev, priv->pd_dev[i], - DL_FLAG_STATELESS | - DL_FLAG_PM_RUNTIME | - DL_FLAG_RPM_ACTIVE); - if (!priv->link[i]) { - ret = -ENOMEM; - dev_pm_domain_detach(priv->pd_dev[i], false); - goto exit_unroll_pm; - } - } - - ret = imx_scu_get_handle(&priv->sc_ipc); - if (ret) { - dev_err(sdev->dev, "Cannot obtain SCU handle (err = %d)\n", - ret); - goto exit_unroll_pm; - } + struct imx_sc_ipc *sc_ipc_handle; + struct imx_common_data *common; + int ret; - priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", - PLATFORM_DEVID_NONE, - pdev, sizeof(*pdev)); - if (IS_ERR(priv->ipc_dev)) { - ret = PTR_ERR(priv->ipc_dev); - goto exit_unroll_pm; - } + common = sdev->pdata->hw_pdata; - priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); - if (!priv->dsp_ipc) { - /* DSP IPC driver not probed yet, try later */ - ret = -EPROBE_DEFER; - dev_err(sdev->dev, "Failed to get drvdata\n"); - goto exit_pdev_unregister; - } + ret = imx_scu_get_handle(&sc_ipc_handle); + if (ret < 0) + return dev_err_probe(sdev->dev, ret, + "failed to fetch SC IPC handle\n"); - imx_dsp_set_data(priv->dsp_ipc, priv); - priv->dsp_ipc->ops = &dsp_ops; - - /* DSP base */ - mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); - ret = -EINVAL; - goto exit_pdev_unregister; - } + common->chip_pdata = sc_ipc_handle; - sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { - dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", - base, size); - ret = -ENODEV; - goto exit_pdev_unregister; - } - sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; + return 0; +} - res_node = of_parse_phandle(np, "memory-region", 0); - if (!res_node) { - dev_err(&pdev->dev, "failed to get memory region node\n"); - ret = -ENODEV; - goto exit_pdev_unregister; - } +static int imx8m_reset(struct snd_sof_dev *sdev) +{ + struct imx8m_chip_data *chip; + u32 pwrctl; - ret = of_address_to_resource(res_node, 0, &res); - of_node_put(res_node); - if (ret) { - dev_err(&pdev->dev, "failed to get reserved region address\n"); - goto exit_pdev_unregister; - } + chip = get_chip_pdata(sdev); - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, - resource_size(&res)); - if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { - dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", - base, size); - ret = -ENOMEM; - goto exit_pdev_unregister; - } - sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; + /* put DSP into reset and stall */ + pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL); + pwrctl |= IMX8M_PWRCTL_CORERESET; + writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL); - /* set default mailbox offset for FW ready message */ - sdev->dsp_box.offset = MBOX_OFFSET; + /* keep reset asserted for 10 cycles */ + usleep_range(1, 2); - ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret); - goto exit_pdev_unregister; - } - priv->clk_num = ret; + regmap_update_bits(chip->regmap, AudioDSP_REG2, + AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL); - ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); - goto exit_pdev_unregister; - } + /* take the DSP out of reset and keep stalled for FW loading */ + pwrctl = readl(chip->dap + IMX8M_DAP_PWRCTL); + pwrctl &= ~IMX8M_PWRCTL_CORERESET; + writel(pwrctl, chip->dap + IMX8M_DAP_PWRCTL); return 0; - -exit_pdev_unregister: - platform_device_unregister(priv->ipc_dev); -exit_unroll_pm: - while (--i >= 0) { - device_link_del(priv->link[i]); - dev_pm_domain_detach(priv->pd_dev[i], false); - } - - return ret; } -static void imx8_remove(struct snd_sof_dev *sdev) +static int imx8m_run(struct snd_sof_dev *sdev) { - struct imx8_priv *priv = sdev->pdata->hw_pdata; - int i; + struct imx8m_chip_data *chip = get_chip_pdata(sdev); - clk_bulk_disable_unprepare(priv->clk_num, priv->clks); - platform_device_unregister(priv->ipc_dev); + regmap_update_bits(chip->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0); - for (i = 0; i < priv->num_domains; i++) { - device_link_del(priv->link[i]); - dev_pm_domain_detach(priv->pd_dev[i], false); - } + return 0; } -/* on i.MX8 there is 1 to 1 match between type and BAR idx */ -static int imx8_get_bar_index(struct snd_sof_dev *sdev, u32 type) +static int imx8m_probe(struct snd_sof_dev *sdev) { - /* Only IRAM and SRAM bars are valid */ - switch (type) { - case SOF_FW_BLK_TYPE_IRAM: - case SOF_FW_BLK_TYPE_SRAM: - return type; - default: - return -EINVAL; - } -} + struct imx_common_data *common; + struct imx8m_chip_data *chip; -static void imx8_suspend(struct snd_sof_dev *sdev) -{ - int i; - struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata; + common = sdev->pdata->hw_pdata; - for (i = 0; i < DSP_MU_CHAN_NUM; i++) - imx_dsp_free_channel(priv->dsp_ipc, i); + chip = devm_kzalloc(sdev->dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return dev_err_probe(sdev->dev, -ENOMEM, + "failed to allocate chip data\n"); - clk_bulk_disable_unprepare(priv->clk_num, priv->clks); -} + chip->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE); + if (!chip->dap) + return dev_err_probe(sdev->dev, -ENODEV, + "failed to ioremap DAP\n"); -static int imx8_resume(struct snd_sof_dev *sdev) -{ - struct imx8_priv *priv = (struct imx8_priv *)sdev->pdata->hw_pdata; - int ret; - int i; + chip->regmap = syscon_regmap_lookup_by_phandle(sdev->dev->of_node, "fsl,dsp-ctrl"); + if (IS_ERR(chip->regmap)) + return dev_err_probe(sdev->dev, PTR_ERR(chip->regmap), + "failed to fetch dsp ctrl regmap\n"); - ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); - return ret; - } - - for (i = 0; i < DSP_MU_CHAN_NUM; i++) - imx_dsp_request_channel(priv->dsp_ipc, i); + common->chip_pdata = chip; return 0; } -static int imx8_dsp_runtime_resume(struct snd_sof_dev *sdev) +static int imx8ulp_run(struct snd_sof_dev *sdev) { - int ret; - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D0, - }; + struct regmap *regmap = get_chip_pdata(sdev); - ret = imx8_resume(sdev); - if (ret < 0) - return ret; - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} + /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */ + regmap_update_bits(regmap, SYSCTRL0, RESET_BIT, 0); -static int imx8_dsp_runtime_suspend(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D3, - }; + /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/ + regmap_update_bits(regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0); - imx8_suspend(sdev); + /* Stall HIFI4 DSP Execution: 1 stall, 0 run */ + regmap_update_bits(regmap, SYSCTRL0, EXECUTE_BIT, 0); - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); + return 0; } -static int imx8_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) +static int imx8ulp_reset(struct snd_sof_dev *sdev) { - const struct sof_dsp_power_state target_dsp_state = { - .state = target_state, - }; + struct arm_smccc_res smc_res; + struct regmap *regmap; - if (!pm_runtime_suspended(sdev->dev)) - imx8_suspend(sdev); + regmap = get_chip_pdata(sdev); - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} + /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */ + regmap_update_bits(regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT); -static int imx8_dsp_resume(struct snd_sof_dev *sdev) -{ - int ret; - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D0, - }; + /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */ + regmap_update_bits(regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT); - ret = imx8_resume(sdev); - if (ret < 0) - return ret; + /* HiFi4 Clock Enable: 1 enabled, 0 disabled */ + regmap_update_bits(regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT); - if (pm_runtime_suspended(sdev->dev)) { - pm_runtime_disable(sdev->dev); - pm_runtime_set_active(sdev->dev); - pm_runtime_mark_last_busy(sdev->dev); - pm_runtime_enable(sdev->dev); - pm_runtime_idle(sdev->dev); - } + regmap_update_bits(regmap, SYSCTRL0, RESET_BIT, RESET_BIT); - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} + usleep_range(1, 2); -static struct snd_soc_dai_driver imx8_dai[] = { -{ - .name = "esai0", - .playback = { - .channels_min = 1, - .channels_max = 8, - }, - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -{ - .name = "sai1", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -}; + /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */ + regmap_update_bits(regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT); + usleep_range(1, 2); -static int imx8_dsp_set_power_state(struct snd_sof_dev *sdev, - const struct sof_dsp_power_state *target_state) -{ - sdev->dsp_power_state = *target_state; + arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_res); - return 0; + return smc_res.a0; } -/* i.MX8 ops */ -static const struct snd_sof_dsp_ops sof_imx8_ops = { - /* probe and remove */ - .probe = imx8_probe, - .remove = imx8_remove, - /* DSP core boot */ - .run = imx8_run, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, +static int imx8ulp_probe(struct snd_sof_dev *sdev) +{ + struct imx_common_data *common; + struct regmap *regmap; - /* Mailbox IO */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, + common = sdev->pdata->hw_pdata; - /* ipc */ - .send_msg = imx8_send_msg, - .get_mailbox_offset = imx8_get_mailbox_offset, - .get_window_offset = imx8_get_window_offset, + regmap = syscon_regmap_lookup_by_phandle(sdev->dev->of_node, "fsl,dsp-ctrl"); + if (IS_ERR(regmap)) + return dev_err_probe(sdev->dev, PTR_ERR(regmap), + "failed to fetch dsp ctrl regmap\n"); - .ipc_msg_data = sof_ipc_msg_data, - .set_stream_data_offset = sof_set_stream_data_offset, + common->chip_pdata = regmap; - .get_bar_index = imx8_get_bar_index, + return 0; +} - /* firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, +static struct snd_soc_dai_driver imx8_dai[] = { + IMX_SOF_DAI_DRV_ENTRY_BIDIR("esai0", 1, 8), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32), +}; - /* Debug information */ - .dbg_dump = imx8_dump, - .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, +static struct snd_soc_dai_driver imx8m_dai[] = { + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai1", 1, 32), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai2", 1, 32), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai5", 1, 32), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai7", 1, 32), + IMX_SOF_DAI_DRV_ENTRY("micfil", 0, 0, 1, 8), +}; - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, +static struct snd_soc_dai_driver imx8ulp_dai[] = { + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai5", 1, 32), + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai6", 1, 32), +}; - /* Firmware ops */ - .dsp_arch_ops = &sof_xtensa_arch_ops, +static struct snd_sof_dsp_ops sof_imx8_ops; - /* DAI drivers */ - .drv = imx8_dai, - .num_drv = ARRAY_SIZE(imx8_dai), +static int imx8_ops_init(struct snd_sof_dev *sdev) +{ + /* first copy from template */ + memcpy(&sof_imx8_ops, &sof_imx_ops, sizeof(sof_imx_ops)); - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, + /* then set common imx8 ops */ + sof_imx8_ops.dbg_dump = imx8_dump; + sof_imx8_ops.dsp_arch_ops = &sof_xtensa_arch_ops; + sof_imx8_ops.debugfs_add_region_item = + snd_sof_debugfs_add_region_item_iomem; - /* PM */ - .runtime_suspend = imx8_dsp_runtime_suspend, - .runtime_resume = imx8_dsp_runtime_resume, + /* ... and finally set DAI driver */ + sof_imx8_ops.drv = get_chip_info(sdev)->drv; + sof_imx8_ops.num_drv = get_chip_info(sdev)->num_drv; - .suspend = imx8_dsp_suspend, - .resume = imx8_dsp_resume, + return 0; +} - .set_power_state = imx8_dsp_set_power_state, +static const struct imx_chip_ops imx8_chip_ops = { + .probe = imx8_probe, + .core_kick = imx8_run, }; -/* i.MX8X ops */ -static const struct snd_sof_dsp_ops sof_imx8x_ops = { - /* probe and remove */ - .probe = imx8_probe, - .remove = imx8_remove, - /* DSP core boot */ - .run = imx8x_run, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, - - /* Mailbox IO */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - - /* ipc */ - .send_msg = imx8_send_msg, - .get_mailbox_offset = imx8_get_mailbox_offset, - .get_window_offset = imx8_get_window_offset, - - .ipc_msg_data = sof_ipc_msg_data, - .set_stream_data_offset = sof_set_stream_data_offset, +static const struct imx_chip_ops imx8x_chip_ops = { + .probe = imx8_probe, + .core_kick = imx8x_run, +}; - .get_bar_index = imx8_get_bar_index, +static const struct imx_chip_ops imx8m_chip_ops = { + .probe = imx8m_probe, + .core_kick = imx8m_run, + .core_reset = imx8m_reset, +}; - /* firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, +static const struct imx_chip_ops imx8ulp_chip_ops = { + .probe = imx8ulp_probe, + .core_kick = imx8ulp_run, + .core_reset = imx8ulp_reset, +}; - /* Debug information */ - .dbg_dump = imx8_dump, - .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, +static struct imx_memory_info imx8_memory_regions[] = { + { .name = "iram", .reserved = false }, + { .name = "sram", .reserved = true }, + { } +}; - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, +static struct imx_memory_info imx8m_memory_regions[] = { + { .name = "iram", .reserved = false }, + { .name = "sram", .reserved = true }, + { } +}; - /* Firmware ops */ - .dsp_arch_ops = &sof_xtensa_arch_ops, +static struct imx_memory_info imx8ulp_memory_regions[] = { + { .name = "iram", .reserved = false }, + { .name = "sram", .reserved = true }, + { } +}; - /* DAI drivers */ +static const struct imx_chip_info imx8_chip_info = { + .ipc_info = { + .has_panic_code = true, + .boot_mbox_offset = 0x800000, + .window_offset = 0x800000, + }, + .memory = imx8_memory_regions, .drv = imx8_dai, .num_drv = ARRAY_SIZE(imx8_dai), + .ops = &imx8_chip_ops, +}; - /* PM */ - .runtime_suspend = imx8_dsp_runtime_suspend, - .runtime_resume = imx8_dsp_runtime_resume, - - .suspend = imx8_dsp_suspend, - .resume = imx8_dsp_resume, +static const struct imx_chip_info imx8x_chip_info = { + .ipc_info = { + .has_panic_code = true, + .boot_mbox_offset = 0x800000, + .window_offset = 0x800000, + }, + .memory = imx8_memory_regions, + .drv = imx8_dai, + .num_drv = ARRAY_SIZE(imx8_dai), + .ops = &imx8x_chip_ops, +}; - .set_power_state = imx8_dsp_set_power_state, +static const struct imx_chip_info imx8m_chip_info = { + .ipc_info = { + .has_panic_code = true, + .boot_mbox_offset = 0x800000, + .window_offset = 0x800000, + }, + .memory = imx8m_memory_regions, + .drv = imx8m_dai, + .num_drv = ARRAY_SIZE(imx8m_dai), + .ops = &imx8m_chip_ops, +}; - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP +static const struct imx_chip_info imx8ulp_chip_info = { + .ipc_info = { + .has_panic_code = true, + .boot_mbox_offset = 0x800000, + .window_offset = 0x800000, + }, + .has_dma_reserved = true, + .memory = imx8ulp_memory_regions, + .drv = imx8ulp_dai, + .num_drv = ARRAY_SIZE(imx8ulp_dai), + .ops = &imx8ulp_chip_ops, }; static struct snd_sof_of_mach sof_imx8_machs[] = { @@ -630,47 +406,46 @@ static struct snd_sof_of_mach sof_imx8_machs[] = { .sof_tplg_filename = "sof-imx8-cs42888.tplg", .drv_name = "asoc-audio-graph-card2", }, - - {} -}; - -static struct sof_dev_desc sof_of_imx8qxp_desc = { - .of_machines = sof_imx8_machs, - .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), - .ipc_default = SOF_IPC_TYPE_3, - .default_fw_path = { - [SOF_IPC_TYPE_3] = "imx/sof", + { + .compatible = "fsl,imx8mp-evk", + .sof_tplg_filename = "sof-imx8mp-wm8960.tplg", + .drv_name = "asoc-audio-graph-card2", }, - .default_tplg_path = { - [SOF_IPC_TYPE_3] = "imx/sof-tplg", + { + .compatible = "fsl,imx8mp-evk-revb4", + .sof_tplg_filename = "sof-imx8mp-wm8962.tplg", + .drv_name = "asoc-audio-graph-card2", }, - .default_fw_filename = { - [SOF_IPC_TYPE_3] = "sof-imx8x.ri", + { + .compatible = "fsl,imx8ulp-evk", + .sof_tplg_filename = "sof-imx8ulp-btsco.tplg", + .drv_name = "asoc-audio-graph-card2", }, - .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", - .ops = &sof_imx8x_ops, + {} }; -static struct sof_dev_desc sof_of_imx8qm_desc = { - .of_machines = sof_imx8_machs, - .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), - .ipc_default = SOF_IPC_TYPE_3, - .default_fw_path = { - [SOF_IPC_TYPE_3] = "imx/sof", +IMX_SOF_DEV_DESC(imx8, sof_imx8_machs, &imx8_chip_info, &sof_imx8_ops, imx8_ops_init); +IMX_SOF_DEV_DESC(imx8x, sof_imx8_machs, &imx8x_chip_info, &sof_imx8_ops, imx8_ops_init); +IMX_SOF_DEV_DESC(imx8m, sof_imx8_machs, &imx8m_chip_info, &sof_imx8_ops, imx8_ops_init); +IMX_SOF_DEV_DESC(imx8ulp, sof_imx8_machs, &imx8ulp_chip_info, &sof_imx8_ops, imx8_ops_init); + +static const struct of_device_id sof_of_imx8_ids[] = { + { + .compatible = "fsl,imx8qxp-dsp", + .data = &IMX_SOF_DEV_DESC_NAME(imx8x), }, - .default_tplg_path = { - [SOF_IPC_TYPE_3] = "imx/sof-tplg", + { + .compatible = "fsl,imx8qm-dsp", + .data = &IMX_SOF_DEV_DESC_NAME(imx8), }, - .default_fw_filename = { - [SOF_IPC_TYPE_3] = "sof-imx8.ri", + { + .compatible = "fsl,imx8mp-dsp", + .data = &IMX_SOF_DEV_DESC_NAME(imx8m), + }, + { + .compatible = "fsl,imx8ulp-dsp", + .data = &IMX_SOF_DEV_DESC_NAME(imx8ulp), }, - .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", - .ops = &sof_imx8_ops, -}; - -static const struct of_device_id sof_of_imx8_ids[] = { - { .compatible = "fsl,imx8qxp-dsp", .data = &sof_of_imx8qxp_desc}, - { .compatible = "fsl,imx8qm-dsp", .data = &sof_of_imx8qm_desc}, { } }; MODULE_DEVICE_TABLE(of, sof_of_imx8_ids); @@ -681,7 +456,7 @@ static struct platform_driver snd_sof_of_imx8_driver = { .remove = sof_of_remove, .driver = { .name = "sof-audio-of-imx8", - .pm = &sof_of_pm, + .pm = pm_ptr(&sof_of_pm), .of_match_table = sof_of_imx8_ids, }, }; diff --git a/sound/soc/sof/imx/imx8m.c b/sound/soc/sof/imx/imx8m.c deleted file mode 100644 index 3cabdebac558..000000000000 --- a/sound/soc/sof/imx/imx8m.c +++ /dev/null @@ -1,567 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -// -// Copyright 2020 NXP -// -// Author: Daniel Baluta <daniel.baluta@nxp.com> -// -// Hardware interface for audio DSP on i.MX8M - -#include <linux/bits.h> -#include <linux/firmware.h> -#include <linux/mfd/syscon.h> -#include <linux/of_platform.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/regmap.h> - -#include <linux/module.h> -#include <sound/sof.h> -#include <sound/sof/xtensa.h> -#include <linux/firmware/imx/dsp.h> - -#include "../ops.h" -#include "../sof-of-dev.h" -#include "imx-common.h" - -#define MBOX_OFFSET 0x800000 -#define MBOX_SIZE 0x1000 - -/* DAP registers */ -#define IMX8M_DAP_DEBUG 0x28800000 -#define IMX8M_DAP_DEBUG_SIZE (64 * 1024) -#define IMX8M_DAP_PWRCTL (0x4000 + 0x3020) -#define IMX8M_PWRCTL_CORERESET BIT(16) - -/* DSP audio mix registers */ -#define AudioDSP_REG0 0x100 -#define AudioDSP_REG1 0x104 -#define AudioDSP_REG2 0x108 -#define AudioDSP_REG3 0x10c - -#define AudioDSP_REG2_RUNSTALL BIT(5) - -struct imx8m_priv { - struct device *dev; - struct snd_sof_dev *sdev; - - /* DSP IPC handler */ - struct imx_dsp_ipc *dsp_ipc; - struct platform_device *ipc_dev; - - struct clk_bulk_data *clks; - int clk_num; - - void __iomem *dap; - struct regmap *regmap; -}; - -static int imx8m_get_mailbox_offset(struct snd_sof_dev *sdev) -{ - return MBOX_OFFSET; -} - -static int imx8m_get_window_offset(struct snd_sof_dev *sdev, u32 id) -{ - return MBOX_OFFSET; -} - -static void imx8m_dsp_handle_reply(struct imx_dsp_ipc *ipc) -{ - struct imx8m_priv *priv = imx_dsp_get_data(ipc); - unsigned long flags; - - spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - snd_sof_ipc_process_reply(priv->sdev, 0); - spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); -} - -static void imx8m_dsp_handle_request(struct imx_dsp_ipc *ipc) -{ - struct imx8m_priv *priv = imx_dsp_get_data(ipc); - u32 p; /* Panic code */ - - /* Read the message from the debug box. */ - sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); - - /* Check to see if the message is a panic code (0x0dead***) */ - if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) - snd_sof_dsp_panic(priv->sdev, p, true); - else - snd_sof_ipc_msgs_rx(priv->sdev); -} - -static struct imx_dsp_ops imx8m_dsp_ops = { - .handle_reply = imx8m_dsp_handle_reply, - .handle_request = imx8m_dsp_handle_request, -}; - -static int imx8m_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - struct imx8m_priv *priv = sdev->pdata->hw_pdata; - - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - imx_dsp_ring_doorbell(priv->dsp_ipc, 0); - - return 0; -} - -/* - * DSP control. - */ -static int imx8m_run(struct snd_sof_dev *sdev) -{ - struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; - - regmap_update_bits(priv->regmap, AudioDSP_REG2, AudioDSP_REG2_RUNSTALL, 0); - - return 0; -} - -static int imx8m_reset(struct snd_sof_dev *sdev) -{ - struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; - u32 pwrctl; - - /* put DSP into reset and stall */ - pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL); - pwrctl |= IMX8M_PWRCTL_CORERESET; - writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL); - - /* keep reset asserted for 10 cycles */ - usleep_range(1, 2); - - regmap_update_bits(priv->regmap, AudioDSP_REG2, - AudioDSP_REG2_RUNSTALL, AudioDSP_REG2_RUNSTALL); - - /* take the DSP out of reset and keep stalled for FW loading */ - pwrctl = readl(priv->dap + IMX8M_DAP_PWRCTL); - pwrctl &= ~IMX8M_PWRCTL_CORERESET; - writel(pwrctl, priv->dap + IMX8M_DAP_PWRCTL); - - return 0; -} - -static int imx8m_probe(struct snd_sof_dev *sdev) -{ - struct platform_device *pdev = to_platform_device(sdev->dev); - struct device_node *np = pdev->dev.of_node; - struct device_node *res_node; - struct resource *mmio; - struct imx8m_priv *priv; - struct resource res; - u32 base, size; - int ret = 0; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - sdev->num_cores = 1; - sdev->pdata->hw_pdata = priv; - priv->dev = sdev->dev; - priv->sdev = sdev; - - priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", - PLATFORM_DEVID_NONE, - pdev, sizeof(*pdev)); - if (IS_ERR(priv->ipc_dev)) - return PTR_ERR(priv->ipc_dev); - - priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); - if (!priv->dsp_ipc) { - /* DSP IPC driver not probed yet, try later */ - ret = -EPROBE_DEFER; - dev_err(sdev->dev, "Failed to get drvdata\n"); - goto exit_pdev_unregister; - } - - imx_dsp_set_data(priv->dsp_ipc, priv); - priv->dsp_ipc->ops = &imx8m_dsp_ops; - - /* DSP base */ - mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); - ret = -EINVAL; - goto exit_pdev_unregister; - } - - priv->dap = devm_ioremap(sdev->dev, IMX8M_DAP_DEBUG, IMX8M_DAP_DEBUG_SIZE); - if (!priv->dap) { - dev_err(sdev->dev, "error: failed to map DAP debug memory area"); - ret = -ENODEV; - goto exit_pdev_unregister; - } - - sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { - dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", - base, size); - ret = -ENODEV; - goto exit_pdev_unregister; - } - sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; - - res_node = of_parse_phandle(np, "memory-region", 0); - if (!res_node) { - dev_err(&pdev->dev, "failed to get memory region node\n"); - ret = -ENODEV; - goto exit_pdev_unregister; - } - - ret = of_address_to_resource(res_node, 0, &res); - of_node_put(res_node); - if (ret) { - dev_err(&pdev->dev, "failed to get reserved region address\n"); - goto exit_pdev_unregister; - } - - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, - resource_size(&res)); - if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { - dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", - base, size); - ret = -ENOMEM; - goto exit_pdev_unregister; - } - sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; - - /* set default mailbox offset for FW ready message */ - sdev->dsp_box.offset = MBOX_OFFSET; - - priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl"); - if (IS_ERR(priv->regmap)) { - dev_err(sdev->dev, "cannot find dsp-ctrl registers"); - ret = PTR_ERR(priv->regmap); - goto exit_pdev_unregister; - } - - ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret); - goto exit_pdev_unregister; - } - priv->clk_num = ret; - - ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); - goto exit_pdev_unregister; - } - - return 0; - -exit_pdev_unregister: - platform_device_unregister(priv->ipc_dev); - return ret; -} - -static void imx8m_remove(struct snd_sof_dev *sdev) -{ - struct imx8m_priv *priv = sdev->pdata->hw_pdata; - - clk_bulk_disable_unprepare(priv->clk_num, priv->clks); - platform_device_unregister(priv->ipc_dev); -} - -/* on i.MX8 there is 1 to 1 match between type and BAR idx */ -static int imx8m_get_bar_index(struct snd_sof_dev *sdev, u32 type) -{ - /* Only IRAM and SRAM bars are valid */ - switch (type) { - case SOF_FW_BLK_TYPE_IRAM: - case SOF_FW_BLK_TYPE_SRAM: - return type; - default: - return -EINVAL; - } -} - -static struct snd_soc_dai_driver imx8m_dai[] = { -{ - .name = "sai1", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -{ - .name = "sai2", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -{ - .name = "sai3", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -{ - .name = "sai5", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -{ - .name = "sai6", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -{ - .name = "sai7", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, -}, -{ - .name = "micfil", - .capture = { - .channels_min = 1, - .channels_max = 8, - }, -}, -}; - -static int imx8m_dsp_set_power_state(struct snd_sof_dev *sdev, - const struct sof_dsp_power_state *target_state) -{ - sdev->dsp_power_state = *target_state; - - return 0; -} - -static int imx8m_resume(struct snd_sof_dev *sdev) -{ - struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; - int ret; - int i; - - ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); - return ret; - } - - for (i = 0; i < DSP_MU_CHAN_NUM; i++) - imx_dsp_request_channel(priv->dsp_ipc, i); - - return 0; -} - -static void imx8m_suspend(struct snd_sof_dev *sdev) -{ - struct imx8m_priv *priv = (struct imx8m_priv *)sdev->pdata->hw_pdata; - int i; - - for (i = 0; i < DSP_MU_CHAN_NUM; i++) - imx_dsp_free_channel(priv->dsp_ipc, i); - - clk_bulk_disable_unprepare(priv->clk_num, priv->clks); -} - -static int imx8m_dsp_runtime_resume(struct snd_sof_dev *sdev) -{ - int ret; - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D0, - }; - - ret = imx8m_resume(sdev); - if (ret < 0) - return ret; - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int imx8m_dsp_runtime_suspend(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D3, - }; - - imx8m_suspend(sdev); - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int imx8m_dsp_resume(struct snd_sof_dev *sdev) -{ - int ret; - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D0, - }; - - ret = imx8m_resume(sdev); - if (ret < 0) - return ret; - - if (pm_runtime_suspended(sdev->dev)) { - pm_runtime_disable(sdev->dev); - pm_runtime_set_active(sdev->dev); - pm_runtime_mark_last_busy(sdev->dev); - pm_runtime_enable(sdev->dev); - pm_runtime_idle(sdev->dev); - } - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int imx8m_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = target_state, - }; - - if (!pm_runtime_suspended(sdev->dev)) - imx8m_suspend(sdev); - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -/* i.MX8 ops */ -static const struct snd_sof_dsp_ops sof_imx8m_ops = { - /* probe and remove */ - .probe = imx8m_probe, - .remove = imx8m_remove, - /* DSP core boot */ - .run = imx8m_run, - .reset = imx8m_reset, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, - - /* Mailbox IO */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - - /* ipc */ - .send_msg = imx8m_send_msg, - .get_mailbox_offset = imx8m_get_mailbox_offset, - .get_window_offset = imx8m_get_window_offset, - - .ipc_msg_data = sof_ipc_msg_data, - .set_stream_data_offset = sof_set_stream_data_offset, - - .get_bar_index = imx8m_get_bar_index, - - /* firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, - - /* Debug information */ - .dbg_dump = imx8_dump, - .debugfs_add_region_item = snd_sof_debugfs_add_region_item_iomem, - - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - /* Firmware ops */ - .dsp_arch_ops = &sof_xtensa_arch_ops, - - /* DAI drivers */ - .drv = imx8m_dai, - .num_drv = ARRAY_SIZE(imx8m_dai), - - .suspend = imx8m_dsp_suspend, - .resume = imx8m_dsp_resume, - - .runtime_suspend = imx8m_dsp_runtime_suspend, - .runtime_resume = imx8m_dsp_runtime_resume, - - .set_power_state = imx8m_dsp_set_power_state, - - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, -}; - -static struct snd_sof_of_mach sof_imx8mp_machs[] = { - { - .compatible = "fsl,imx8mp-evk-revb4", - .sof_tplg_filename = "sof-imx8mp-wm8962.tplg", - .drv_name = "asoc-audio-graph-card2", - }, - { - .compatible = "fsl,imx8mp-evk", - .sof_tplg_filename = "sof-imx8mp-wm8960.tplg", - .drv_name = "asoc-audio-graph-card2", - }, - {} -}; - -static struct sof_dev_desc sof_of_imx8mp_desc = { - .of_machines = sof_imx8mp_machs, - .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), - .ipc_default = SOF_IPC_TYPE_3, - .default_fw_path = { - [SOF_IPC_TYPE_3] = "imx/sof", - }, - .default_tplg_path = { - [SOF_IPC_TYPE_3] = "imx/sof-tplg", - }, - .default_fw_filename = { - [SOF_IPC_TYPE_3] = "sof-imx8m.ri", - }, - .nocodec_tplg_filename = "sof-imx8-nocodec.tplg", - .ops = &sof_imx8m_ops, -}; - -static const struct of_device_id sof_of_imx8m_ids[] = { - { .compatible = "fsl,imx8mp-dsp", .data = &sof_of_imx8mp_desc}, - { } -}; -MODULE_DEVICE_TABLE(of, sof_of_imx8m_ids); - -/* DT driver definition */ -static struct platform_driver snd_sof_of_imx8m_driver = { - .probe = sof_of_probe, - .remove = sof_of_remove, - .driver = { - .name = "sof-audio-of-imx8m", - .pm = &sof_of_pm, - .of_match_table = sof_of_imx8m_ids, - }, -}; -module_platform_driver(snd_sof_of_imx8m_driver); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("SOF support for IMX8M platforms"); -MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); diff --git a/sound/soc/sof/imx/imx8ulp.c b/sound/soc/sof/imx/imx8ulp.c deleted file mode 100644 index 0704da27e69d..000000000000 --- a/sound/soc/sof/imx/imx8ulp.c +++ /dev/null @@ -1,520 +0,0 @@ -// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) -// -// Copyright 2021-2022 NXP -// -// Author: Peng Zhang <peng.zhang_8@nxp.com> -// -// Hardware interface for audio DSP on i.MX8ULP - -#include <linux/arm-smccc.h> -#include <linux/clk.h> -#include <linux/firmware.h> -#include <linux/firmware/imx/dsp.h> -#include <linux/firmware/imx/ipc.h> -#include <linux/firmware/imx/svc/misc.h> -#include <linux/mfd/syscon.h> -#include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/of_platform.h> -#include <linux/of_reserved_mem.h> - -#include <sound/sof.h> -#include <sound/sof/xtensa.h> - -#include "../ops.h" -#include "../sof-of-dev.h" -#include "imx-common.h" - -#define FSL_SIP_HIFI_XRDC 0xc200000e - -/* SIM Domain register */ -#define SYSCTRL0 0x8 -#define EXECUTE_BIT BIT(13) -#define RESET_BIT BIT(16) -#define HIFI4_CLK_BIT BIT(17) -#define PB_CLK_BIT BIT(18) -#define PLAT_CLK_BIT BIT(19) -#define DEBUG_LOGIC_BIT BIT(25) - -#define MBOX_OFFSET 0x800000 -#define MBOX_SIZE 0x1000 - -struct imx8ulp_priv { - struct device *dev; - struct snd_sof_dev *sdev; - - /* DSP IPC handler */ - struct imx_dsp_ipc *dsp_ipc; - struct platform_device *ipc_dev; - - struct regmap *regmap; - struct clk_bulk_data *clks; - int clk_num; -}; - -static void imx8ulp_sim_lpav_start(struct imx8ulp_priv *priv) -{ - /* Controls the HiFi4 DSP Reset: 1 in reset, 0 out of reset */ - regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, 0); - - /* Reset HiFi4 DSP Debug logic: 1 debug reset, 0 out of reset*/ - regmap_update_bits(priv->regmap, SYSCTRL0, DEBUG_LOGIC_BIT, 0); - - /* Stall HIFI4 DSP Execution: 1 stall, 0 run */ - regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, 0); -} - -static int imx8ulp_get_mailbox_offset(struct snd_sof_dev *sdev) -{ - return MBOX_OFFSET; -} - -static int imx8ulp_get_window_offset(struct snd_sof_dev *sdev, u32 id) -{ - return MBOX_OFFSET; -} - -static void imx8ulp_dsp_handle_reply(struct imx_dsp_ipc *ipc) -{ - struct imx8ulp_priv *priv = imx_dsp_get_data(ipc); - unsigned long flags; - - spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - - snd_sof_ipc_process_reply(priv->sdev, 0); - - spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); -} - -static void imx8ulp_dsp_handle_request(struct imx_dsp_ipc *ipc) -{ - struct imx8ulp_priv *priv = imx_dsp_get_data(ipc); - u32 p; /* panic code */ - - /* Read the message from the debug box. */ - sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, &p, sizeof(p)); - - /* Check to see if the message is a panic code (0x0dead***) */ - if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) - snd_sof_dsp_panic(priv->sdev, p, true); - else - snd_sof_ipc_msgs_rx(priv->sdev); -} - -static struct imx_dsp_ops dsp_ops = { - .handle_reply = imx8ulp_dsp_handle_reply, - .handle_request = imx8ulp_dsp_handle_request, -}; - -static int imx8ulp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) -{ - struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; - - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - imx_dsp_ring_doorbell(priv->dsp_ipc, 0); - - return 0; -} - -static int imx8ulp_run(struct snd_sof_dev *sdev) -{ - struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; - - imx8ulp_sim_lpav_start(priv); - - return 0; -} - -static int imx8ulp_reset(struct snd_sof_dev *sdev) -{ - struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; - struct arm_smccc_res smc_resource; - - /* HiFi4 Platform Clock Enable: 1 enabled, 0 disabled */ - regmap_update_bits(priv->regmap, SYSCTRL0, PLAT_CLK_BIT, PLAT_CLK_BIT); - - /* HiFi4 PBCLK clock enable: 1 enabled, 0 disabled */ - regmap_update_bits(priv->regmap, SYSCTRL0, PB_CLK_BIT, PB_CLK_BIT); - - /* HiFi4 Clock Enable: 1 enabled, 0 disabled */ - regmap_update_bits(priv->regmap, SYSCTRL0, HIFI4_CLK_BIT, HIFI4_CLK_BIT); - - regmap_update_bits(priv->regmap, SYSCTRL0, RESET_BIT, RESET_BIT); - usleep_range(1, 2); - - /* Stall HIFI4 DSP Execution: 1 stall, 0 not stall */ - regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT); - usleep_range(1, 2); - - arm_smccc_smc(FSL_SIP_HIFI_XRDC, 0, 0, 0, 0, 0, 0, 0, &smc_resource); - - return 0; -} - -static int imx8ulp_probe(struct snd_sof_dev *sdev) -{ - struct platform_device *pdev = to_platform_device(sdev->dev); - struct device_node *np = pdev->dev.of_node; - struct device_node *res_node; - struct resource *mmio; - struct imx8ulp_priv *priv; - struct resource res; - u32 base, size; - int ret = 0; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - sdev->num_cores = 1; - sdev->pdata->hw_pdata = priv; - priv->dev = sdev->dev; - priv->sdev = sdev; - - /* System integration module(SIM) control dsp configuration */ - priv->regmap = syscon_regmap_lookup_by_phandle(np, "fsl,dsp-ctrl"); - if (IS_ERR(priv->regmap)) - return PTR_ERR(priv->regmap); - - priv->ipc_dev = platform_device_register_data(sdev->dev, "imx-dsp", - PLATFORM_DEVID_NONE, - pdev, sizeof(*pdev)); - if (IS_ERR(priv->ipc_dev)) - return PTR_ERR(priv->ipc_dev); - - priv->dsp_ipc = dev_get_drvdata(&priv->ipc_dev->dev); - if (!priv->dsp_ipc) { - /* DSP IPC driver not probed yet, try later */ - ret = -EPROBE_DEFER; - dev_err(sdev->dev, "Failed to get drvdata\n"); - goto exit_pdev_unregister; - } - - imx_dsp_set_data(priv->dsp_ipc, priv); - priv->dsp_ipc->ops = &dsp_ops; - - /* DSP base */ - mmio = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (mmio) { - base = mmio->start; - size = resource_size(mmio); - } else { - dev_err(sdev->dev, "error: failed to get DSP base at idx 0\n"); - ret = -EINVAL; - goto exit_pdev_unregister; - } - - sdev->bar[SOF_FW_BLK_TYPE_IRAM] = devm_ioremap(sdev->dev, base, size); - if (!sdev->bar[SOF_FW_BLK_TYPE_IRAM]) { - dev_err(sdev->dev, "failed to ioremap base 0x%x size 0x%x\n", - base, size); - ret = -ENODEV; - goto exit_pdev_unregister; - } - sdev->mmio_bar = SOF_FW_BLK_TYPE_IRAM; - - res_node = of_parse_phandle(np, "memory-reserved", 0); - if (!res_node) { - dev_err(&pdev->dev, "failed to get memory region node\n"); - ret = -ENODEV; - goto exit_pdev_unregister; - } - - ret = of_address_to_resource(res_node, 0, &res); - of_node_put(res_node); - if (ret) { - dev_err(&pdev->dev, "failed to get reserved region address\n"); - goto exit_pdev_unregister; - } - - sdev->bar[SOF_FW_BLK_TYPE_SRAM] = devm_ioremap_wc(sdev->dev, res.start, - resource_size(&res)); - if (!sdev->bar[SOF_FW_BLK_TYPE_SRAM]) { - dev_err(sdev->dev, "failed to ioremap mem 0x%x size 0x%x\n", - base, size); - ret = -ENOMEM; - goto exit_pdev_unregister; - } - sdev->mailbox_bar = SOF_FW_BLK_TYPE_SRAM; - - /* set default mailbox offset for FW ready message */ - sdev->dsp_box.offset = MBOX_OFFSET; - - ret = of_reserved_mem_device_init(sdev->dev); - if (ret) { - dev_err(&pdev->dev, "failed to init reserved memory region %d\n", ret); - goto exit_pdev_unregister; - } - - ret = devm_clk_bulk_get_all(sdev->dev, &priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to fetch clocks: %d\n", ret); - goto exit_pdev_unregister; - } - priv->clk_num = ret; - - ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); - goto exit_pdev_unregister; - } - - return 0; - -exit_pdev_unregister: - platform_device_unregister(priv->ipc_dev); - - return ret; -} - -static void imx8ulp_remove(struct snd_sof_dev *sdev) -{ - struct imx8ulp_priv *priv = sdev->pdata->hw_pdata; - - clk_bulk_disable_unprepare(priv->clk_num, priv->clks); - platform_device_unregister(priv->ipc_dev); -} - -/* on i.MX8 there is 1 to 1 match between type and BAR idx */ -static int imx8ulp_get_bar_index(struct snd_sof_dev *sdev, u32 type) -{ - return type; -} - -static int imx8ulp_suspend(struct snd_sof_dev *sdev) -{ - int i; - struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata; - - /*Stall DSP, release in .run() */ - regmap_update_bits(priv->regmap, SYSCTRL0, EXECUTE_BIT, EXECUTE_BIT); - - for (i = 0; i < DSP_MU_CHAN_NUM; i++) - imx_dsp_free_channel(priv->dsp_ipc, i); - - clk_bulk_disable_unprepare(priv->clk_num, priv->clks); - - return 0; -} - -static int imx8ulp_resume(struct snd_sof_dev *sdev) -{ - struct imx8ulp_priv *priv = (struct imx8ulp_priv *)sdev->pdata->hw_pdata; - int i, ret; - - ret = clk_bulk_prepare_enable(priv->clk_num, priv->clks); - if (ret < 0) { - dev_err(sdev->dev, "failed to enable clocks: %d\n", ret); - return ret; - } - - for (i = 0; i < DSP_MU_CHAN_NUM; i++) - imx_dsp_request_channel(priv->dsp_ipc, i); - - return 0; -} - -static int imx8ulp_dsp_runtime_resume(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D0, - .substate = 0, - }; - - imx8ulp_resume(sdev); - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int imx8ulp_dsp_runtime_suspend(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D3, - .substate = 0, - }; - - imx8ulp_suspend(sdev); - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int imx8ulp_dsp_suspend(struct snd_sof_dev *sdev, unsigned int target_state) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = target_state, - .substate = 0, - }; - - if (!pm_runtime_suspended(sdev->dev)) - imx8ulp_suspend(sdev); - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static int imx8ulp_dsp_resume(struct snd_sof_dev *sdev) -{ - const struct sof_dsp_power_state target_dsp_state = { - .state = SOF_DSP_PM_D0, - .substate = 0, - }; - - imx8ulp_resume(sdev); - - if (pm_runtime_suspended(sdev->dev)) { - pm_runtime_disable(sdev->dev); - pm_runtime_set_active(sdev->dev); - pm_runtime_mark_last_busy(sdev->dev); - pm_runtime_enable(sdev->dev); - pm_runtime_idle(sdev->dev); - } - - return snd_sof_dsp_set_power_state(sdev, &target_dsp_state); -} - -static struct snd_soc_dai_driver imx8ulp_dai[] = { - { - .name = "sai5", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, - }, - { - .name = "sai6", - .playback = { - .channels_min = 1, - .channels_max = 32, - }, - .capture = { - .channels_min = 1, - .channels_max = 32, - }, - }, -}; - -static int imx8ulp_dsp_set_power_state(struct snd_sof_dev *sdev, - const struct sof_dsp_power_state *target_state) -{ - sdev->dsp_power_state = *target_state; - - return 0; -} - -/* i.MX8 ops */ -static const struct snd_sof_dsp_ops sof_imx8ulp_ops = { - /* probe and remove */ - .probe = imx8ulp_probe, - .remove = imx8ulp_remove, - /* DSP core boot */ - .run = imx8ulp_run, - .reset = imx8ulp_reset, - - /* Block IO */ - .block_read = sof_block_read, - .block_write = sof_block_write, - - /* Module IO */ - .read64 = sof_io_read64, - - /* Mailbox IO */ - .mailbox_read = sof_mailbox_read, - .mailbox_write = sof_mailbox_write, - - /* ipc */ - .send_msg = imx8ulp_send_msg, - .get_mailbox_offset = imx8ulp_get_mailbox_offset, - .get_window_offset = imx8ulp_get_window_offset, - - .ipc_msg_data = sof_ipc_msg_data, - .set_stream_data_offset = sof_set_stream_data_offset, - - /* stream callbacks */ - .pcm_open = sof_stream_pcm_open, - .pcm_close = sof_stream_pcm_close, - - /* module loading */ - .get_bar_index = imx8ulp_get_bar_index, - /* firmware loading */ - .load_firmware = snd_sof_load_firmware_memcpy, - - /* Debug information */ - .dbg_dump = imx8_dump, - - /* Firmware ops */ - .dsp_arch_ops = &sof_xtensa_arch_ops, - - /* DAI drivers */ - .drv = imx8ulp_dai, - .num_drv = ARRAY_SIZE(imx8ulp_dai), - - /* ALSA HW info flags */ - .hw_info = SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_MMAP_VALID | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_BATCH | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP, - - /* PM */ - .runtime_suspend = imx8ulp_dsp_runtime_suspend, - .runtime_resume = imx8ulp_dsp_runtime_resume, - - .suspend = imx8ulp_dsp_suspend, - .resume = imx8ulp_dsp_resume, - - .set_power_state = imx8ulp_dsp_set_power_state, -}; - -static struct snd_sof_of_mach sof_imx8ulp_machs[] = { - { - .compatible = "fsl,imx8ulp-evk", - .sof_tplg_filename = "sof-imx8ulp-btsco.tplg", - .drv_name = "asoc-audio-graph-card2", - }, - {} -}; - -static struct sof_dev_desc sof_of_imx8ulp_desc = { - .of_machines = sof_imx8ulp_machs, - .ipc_supported_mask = BIT(SOF_IPC_TYPE_3), - .ipc_default = SOF_IPC_TYPE_3, - .default_fw_path = { - [SOF_IPC_TYPE_3] = "imx/sof", - }, - .default_tplg_path = { - [SOF_IPC_TYPE_3] = "imx/sof-tplg", - }, - .default_fw_filename = { - [SOF_IPC_TYPE_3] = "sof-imx8ulp.ri", - }, - .nocodec_tplg_filename = "sof-imx8ulp-nocodec.tplg", - .ops = &sof_imx8ulp_ops, -}; - -static const struct of_device_id sof_of_imx8ulp_ids[] = { - { .compatible = "fsl,imx8ulp-dsp", .data = &sof_of_imx8ulp_desc}, - { } -}; -MODULE_DEVICE_TABLE(of, sof_of_imx8ulp_ids); - -/* DT driver definition */ -static struct platform_driver snd_sof_of_imx8ulp_driver = { - .probe = sof_of_probe, - .remove = sof_of_remove, - .driver = { - .name = "sof-audio-of-imx8ulp", - .pm = &sof_of_pm, - .of_match_table = sof_of_imx8ulp_ids, - }, -}; -module_platform_driver(snd_sof_of_imx8ulp_driver); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_DESCRIPTION("SOF support for IMX8ULP platforms"); -MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); diff --git a/sound/soc/sof/imx/imx9.c b/sound/soc/sof/imx/imx9.c new file mode 100644 index 000000000000..853155d5990a --- /dev/null +++ b/sound/soc/sof/imx/imx9.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +/* + * Copyright 2025 NXP + */ + +#include <linux/arm-smccc.h> + +#include "imx-common.h" + +#define IMX_SIP_SRC 0xC2000005 +#define IMX_SIP_SRC_M_RESET_ADDR_SET 0x03 + +#define IMX95_CPU_VEC_FLAGS_BOOT BIT(29) + +#define IMX_SIP_LMM 0xC200000F +#define IMX_SIP_LMM_BOOT 0x0 +#define IMX_SIP_LMM_SHUTDOWN 0x1 + +#define IMX95_M7_LM_ID 0x1 + +static struct snd_soc_dai_driver imx95_dai[] = { + IMX_SOF_DAI_DRV_ENTRY_BIDIR("sai3", 1, 32), +}; + +static struct snd_sof_dsp_ops sof_imx9_ops; + +static int imx95_ops_init(struct snd_sof_dev *sdev) +{ + /* first copy from template */ + memcpy(&sof_imx9_ops, &sof_imx_ops, sizeof(sof_imx_ops)); + + /* ... and finally set DAI driver */ + sof_imx9_ops.drv = get_chip_info(sdev)->drv; + sof_imx9_ops.num_drv = get_chip_info(sdev)->num_drv; + + return 0; +} + +static int imx95_chip_probe(struct snd_sof_dev *sdev) +{ + struct arm_smccc_res smc_res; + struct platform_device *pdev; + struct resource *res; + + pdev = to_platform_device(sdev->dev); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sram"); + if (!res) + return dev_err_probe(sdev->dev, -ENODEV, + "failed to fetch SRAM region\n"); + + /* set core boot reset address */ + arm_smccc_smc(IMX_SIP_SRC, IMX_SIP_SRC_M_RESET_ADDR_SET, res->start, + IMX95_CPU_VEC_FLAGS_BOOT, 0, 0, 0, 0, &smc_res); + + return smc_res.a0; +} + +static int imx95_core_kick(struct snd_sof_dev *sdev) +{ + struct arm_smccc_res smc_res; + + arm_smccc_smc(IMX_SIP_LMM, IMX_SIP_LMM_BOOT, + IMX95_M7_LM_ID, 0, 0, 0, 0, 0, &smc_res); + + return smc_res.a0; +} + +static int imx95_core_shutdown(struct snd_sof_dev *sdev) +{ + struct arm_smccc_res smc_res; + + arm_smccc_smc(IMX_SIP_LMM, IMX_SIP_LMM_SHUTDOWN, + IMX95_M7_LM_ID, 0, 0, 0, 0, 0, &smc_res); + + return smc_res.a0; +} + +static const struct imx_chip_ops imx95_chip_ops = { + .probe = imx95_chip_probe, + .core_kick = imx95_core_kick, + .core_shutdown = imx95_core_shutdown, +}; + +static struct imx_memory_info imx95_memory_regions[] = { + { .name = "sram", .reserved = false }, + { } +}; + +static const struct imx_chip_info imx95_chip_info = { + .ipc_info = { + .boot_mbox_offset = 0x6001000, + .window_offset = 0x6000000, + }, + .has_dma_reserved = true, + .memory = imx95_memory_regions, + .drv = imx95_dai, + .num_drv = ARRAY_SIZE(imx95_dai), + .ops = &imx95_chip_ops, +}; + +static struct snd_sof_of_mach sof_imx9_machs[] = { + { + .compatible = "fsl,imx95-19x19-evk", + .sof_tplg_filename = "sof-imx95-wm8962.tplg", + .drv_name = "asoc-audio-graph-card2", + }, + { + } +}; + +IMX_SOF_DEV_DESC(imx95, sof_imx9_machs, &imx95_chip_info, &sof_imx9_ops, imx95_ops_init); + +static const struct of_device_id sof_of_imx9_ids[] = { + { + .compatible = "fsl,imx95-cm7-sof", + .data = &IMX_SOF_DEV_DESC_NAME(imx95), + }, + { + }, +}; +MODULE_DEVICE_TABLE(of, sof_of_imx9_ids); + +static struct platform_driver snd_sof_of_imx9_driver = { + .probe = sof_of_probe, + .remove = sof_of_remove, + .driver = { + .name = "sof-audio-of-imx9", + .pm = pm_ptr(&sof_of_pm), + .of_match_table = sof_of_imx9_ids, + }, +}; +module_platform_driver(snd_sof_of_imx9_driver); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("SOF driver for imx9 platforms"); +MODULE_AUTHOR("Laurentiu Mihalcea <laurentiu.mihalcea@nxp.com>"); diff --git a/sound/soc/sof/intel/Makefile b/sound/soc/sof/intel/Makefile index f40daa616803..675f9fc92dde 100644 --- a/sound/soc/sof/intel/Makefile +++ b/sound/soc/sof/intel/Makefile @@ -34,7 +34,7 @@ snd-sof-pci-intel-icl-y := pci-icl.o icl.o snd-sof-pci-intel-tgl-y := pci-tgl.o tgl.o snd-sof-pci-intel-mtl-y := pci-mtl.o mtl.o snd-sof-pci-intel-lnl-y := pci-lnl.o lnl.o -snd-sof-pci-intel-ptl-y := pci-ptl.o +snd-sof-pci-intel-ptl-y := pci-ptl.o ptl.o obj-$(CONFIG_SND_SOC_SOF_MERRIFIELD) += snd-sof-pci-intel-tng.o obj-$(CONFIG_SND_SOC_SOF_INTEL_SKL) += snd-sof-pci-intel-skl.o diff --git a/sound/soc/sof/intel/bdw.c b/sound/soc/sof/intel/bdw.c index e1f0e38c2407..f1287d509835 100644 --- a/sound/soc/sof/intel/bdw.c +++ b/sound/soc/sof/intel/bdw.c @@ -686,7 +686,7 @@ static struct platform_driver snd_sof_acpi_intel_bdw_driver = { .remove = sof_acpi_remove, .driver = { .name = "sof-audio-acpi-intel-bdw", - .pm = &sof_acpi_pm, + .pm = pm_ptr(&sof_acpi_pm), .acpi_match_table = sof_broadwell_match, }, }; @@ -694,6 +694,5 @@ module_platform_driver(snd_sof_acpi_intel_bdw_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Broadwell platforms"); -MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV"); diff --git a/sound/soc/sof/intel/byt.c b/sound/soc/sof/intel/byt.c index cae7dc0036c6..18208f77b84d 100644 --- a/sound/soc/sof/intel/byt.c +++ b/sound/soc/sof/intel/byt.c @@ -467,7 +467,7 @@ static struct platform_driver snd_sof_acpi_intel_byt_driver = { .remove = sof_acpi_remove, .driver = { .name = "sof-audio-acpi-intel-byt", - .pm = &sof_acpi_pm, + .pm = pm_ptr(&sof_acpi_pm), .acpi_match_table = sof_baytrail_match, }, }; @@ -475,7 +475,6 @@ module_platform_driver(snd_sof_acpi_intel_byt_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Baytrail/Cherrytrail"); -MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_ACPI_DEV"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/intel/hda-dai.c b/sound/soc/sof/intel/hda-dai.c index da12aabc1bb8..883d0d3bae9e 100644 --- a/sound/soc/sof/intel/hda-dai.c +++ b/sound/soc/sof/intel/hda-dai.c @@ -318,7 +318,7 @@ static int __maybe_unused hda_dai_trigger(struct snd_pcm_substream *substream, i case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: ret = hda_link_dma_cleanup(substream, hext_stream, dai, - cmd == SNDRV_PCM_TRIGGER_STOP ? false : true); + cmd != SNDRV_PCM_TRIGGER_STOP); if (ret < 0) { dev_err(sdev->dev, "%s: failed to clean up link DMA\n", __func__); return ret; diff --git a/sound/soc/sof/intel/hda-mlink.c b/sound/soc/sof/intel/hda-mlink.c index fe627bcb0531..ce561fe52bd5 100644 --- a/sound/soc/sof/intel/hda-mlink.c +++ b/sound/soc/sof/intel/hda-mlink.c @@ -16,6 +16,7 @@ #include <linux/bitfield.h> #include <linux/module.h> +#include <linux/string_choices.h> #if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_MLINK) @@ -42,6 +43,7 @@ * @shim_offset: offset to SHIM register base * @ip_offset: offset to IP register base * @shim_vs_offset: offset to vendor-specific (VS) SHIM base + * @mic_privacy_mask: bitmask of sublinks where mic privacy is applied */ struct hdac_ext2_link { struct hdac_ext_link hext_link; @@ -65,6 +67,8 @@ struct hdac_ext2_link { u32 shim_offset; u32 ip_offset; u32 shim_vs_offset; + + unsigned long mic_privacy_mask; }; #define hdac_ext_link_to_ext2(h) container_of(h, struct hdac_ext2_link, hext_link) @@ -90,6 +94,13 @@ struct hdac_ext2_link { #define AZX_REG_INTEL_UAOL_IP_OFFSET 0x100 #define AZX_REG_INTEL_UAOL_VS_SHIM_OFFSET 0xC00 +/* Microphone privacy */ +#define AZX_REG_INTEL_VS_SHIM_PVCCS 0x10 +#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE BIT(0) +#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG BIT(8) +#define AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS BIT(9) +#define AZX_REG_INTEL_VS_SHIM_PVCCS_FMDIS BIT(10) + /* HDAML section - this part follows sequences in the hardware specification, * including naming conventions and the use of the hdaml_ prefix. * The code is intentionally minimal with limited dependencies on frameworks or @@ -696,6 +707,20 @@ static int hdac_bus_eml_power_up_base(struct hdac_bus *bus, bool alt, int elid, } ret = hdaml_link_init(hlink->ml_addr + AZX_REG_ML_LCTL, sublink); + if ((h2link->mic_privacy_mask & BIT(sublink)) && !ret) { + u16 __iomem *pvccs = h2link->base_ptr + + h2link->shim_vs_offset + + sublink * h2link->instance_offset + + AZX_REG_INTEL_VS_SHIM_PVCCS; + u16 val = readw(pvccs); + + writew(val | AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs); + + if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS) + dev_dbg(bus->dev, + "sublink %d (%d:%d): Mic privacy is enabled\n", + sublink, alt, elid); + } skip_init: if (eml_lock) @@ -742,6 +767,16 @@ static int hdac_bus_eml_power_down_base(struct hdac_bus *bus, bool alt, int elid if (--h2link->sublink_ref_count[sublink] > 0) goto skip_shutdown; } + + if (h2link->mic_privacy_mask & BIT(sublink)) { + u16 __iomem *pvccs = h2link->base_ptr + + h2link->shim_vs_offset + + sublink * h2link->instance_offset + + AZX_REG_INTEL_VS_SHIM_PVCCS; + + writew(readw(pvccs) & ~AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHGIE, pvccs); + } + ret = hdaml_link_shutdown(hlink->ml_addr + AZX_REG_ML_LCTL, sublink); skip_shutdown: @@ -987,6 +1022,98 @@ int hdac_bus_eml_enable_offload(struct hdac_bus *bus, bool alt, int elid, bool e } EXPORT_SYMBOL_NS(hdac_bus_eml_enable_offload, "SND_SOC_SOF_HDA_MLINK"); +void hdac_bus_eml_set_mic_privacy_mask(struct hdac_bus *bus, bool alt, int elid, + unsigned long mask) +{ + struct hdac_ext2_link *h2link; + + if (!mask) + return; + + h2link = find_ext2_link(bus, alt, elid); + if (!h2link) + return; + + if (__fls(mask) > h2link->slcount) { + dev_warn(bus->dev, + "%s: invalid sublink mask for %d:%d, slcount %d: %#lx\n", + __func__, alt, elid, h2link->slcount, mask); + return; + } + + dev_dbg(bus->dev, "sublink mask for %d:%d, slcount %d: %#lx\n", alt, + elid, h2link->slcount, mask); + + h2link->mic_privacy_mask = mask; +} +EXPORT_SYMBOL_NS(hdac_bus_eml_set_mic_privacy_mask, "SND_SOC_SOF_HDA_MLINK"); + +bool hdac_bus_eml_is_mic_privacy_changed(struct hdac_bus *bus, bool alt, int elid) +{ + struct hdac_ext2_link *h2link; + bool changed = false; + u16 __iomem *pvccs; + int i; + + h2link = find_ext2_link(bus, alt, elid); + if (!h2link) + return false; + + /* The change in privacy state needs to be acked for each link */ + for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) { + u16 val; + + if (h2link->sublink_ref_count[i] == 0) + continue; + + pvccs = h2link->base_ptr + + h2link->shim_vs_offset + + i * h2link->instance_offset + + AZX_REG_INTEL_VS_SHIM_PVCCS; + + val = readw(pvccs); + if (val & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTSCHG) { + writew(val, pvccs); + changed = true; + } + } + + return changed; +} +EXPORT_SYMBOL_NS(hdac_bus_eml_is_mic_privacy_changed, "SND_SOC_SOF_HDA_MLINK"); + +bool hdac_bus_eml_get_mic_privacy_state(struct hdac_bus *bus, bool alt, int elid) +{ + struct hdac_ext2_link *h2link; + u16 __iomem *pvccs; + bool state; + int i; + + h2link = find_ext2_link(bus, alt, elid); + if (!h2link) + return false; + + for_each_set_bit(i, &h2link->mic_privacy_mask, h2link->slcount) { + if (h2link->sublink_ref_count[i] == 0) + continue; + + /* Return the privacy state from the first active link */ + pvccs = h2link->base_ptr + + h2link->shim_vs_offset + + i * h2link->instance_offset + + AZX_REG_INTEL_VS_SHIM_PVCCS; + + state = readw(pvccs) & AZX_REG_INTEL_VS_SHIM_PVCCS_MDSTS; + dev_dbg(bus->dev, "alt: %d, elid: %d: Mic privacy is %s\n", alt, + elid, str_enabled_disabled(state)); + + return state; + } + + return false; +} +EXPORT_SYMBOL_NS(hdac_bus_eml_get_mic_privacy_state, "SND_SOC_SOF_HDA_MLINK"); + #endif MODULE_LICENSE("Dual BSD/GPL"); diff --git a/sound/soc/sof/intel/hda.c b/sound/soc/sof/intel/hda.c index a1ccd95da8bb..6b1ada566476 100644 --- a/sound/soc/sof/intel/hda.c +++ b/sound/soc/sof/intel/hda.c @@ -352,6 +352,27 @@ void hda_sdw_process_wakeen_common(struct snd_sof_dev *sdev) } EXPORT_SYMBOL_NS(hda_sdw_process_wakeen_common, "SND_SOC_SOF_INTEL_HDA_GENERIC"); +static bool hda_dsp_sdw_check_mic_privacy_irq(struct snd_sof_dev *sdev) +{ + const struct sof_intel_dsp_desc *chip; + + chip = get_chip_info(sdev->pdata); + if (chip && chip->check_mic_privacy_irq) + return chip->check_mic_privacy_irq(sdev, true, + AZX_REG_ML_LEPTR_ID_SDW); + + return false; +} + +static void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) +{ + const struct sof_intel_dsp_desc *chip; + + chip = get_chip_info(sdev->pdata); + if (chip && chip->process_mic_privacy) + chip->process_mic_privacy(sdev, true, AZX_REG_ML_LEPTR_ID_SDW); +} + #else /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */ static inline int hda_sdw_acpi_scan(struct snd_sof_dev *sdev) { @@ -383,6 +404,13 @@ static inline bool hda_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) return false; } +static inline bool hda_dsp_sdw_check_mic_privacy_irq(struct snd_sof_dev *sdev) +{ + return false; +} + +static inline void hda_dsp_sdw_process_mic_privacy(struct snd_sof_dev *sdev) { } + #endif /* IS_ENABLED(CONFIG_SND_SOC_SOF_INTEL_SOUNDWIRE) */ /* pre fw run operations */ @@ -678,7 +706,13 @@ static irqreturn_t hda_dsp_interrupt_thread(int irq, void *context) if (hda_dsp_check_sdw_irq(sdev)) { trace_sof_intel_hda_irq(sdev, "sdw"); + hda_dsp_sdw_thread(irq, hdev->sdw); + + if (hda_dsp_sdw_check_mic_privacy_irq(sdev)) { + trace_sof_intel_hda_irq(sdev, "mic privacy"); + hda_dsp_sdw_process_mic_privacy(sdev); + } } if (hda_sdw_check_wakeen_irq(sdev)) { diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ee4ccc1a5490..76154627fc17 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -913,10 +913,6 @@ extern struct snd_sof_dsp_ops sof_tgl_ops; int sof_tgl_ops_init(struct snd_sof_dev *sdev); extern struct snd_sof_dsp_ops sof_icl_ops; int sof_icl_ops_init(struct snd_sof_dev *sdev); -extern struct snd_sof_dsp_ops sof_mtl_ops; -int sof_mtl_ops_init(struct snd_sof_dev *sdev); -extern struct snd_sof_dsp_ops sof_lnl_ops; -int sof_lnl_ops_init(struct snd_sof_dev *sdev); extern const struct sof_intel_dsp_desc skl_chip_info; extern const struct sof_intel_dsp_desc apl_chip_info; diff --git a/sound/soc/sof/intel/lnl.c b/sound/soc/sof/intel/lnl.c index 793d8539821d..2f3222040f98 100644 --- a/sound/soc/sof/intel/lnl.c +++ b/sound/soc/sof/intel/lnl.c @@ -20,17 +20,6 @@ #include "lnl.h" #include <sound/hda-mlink.h> -/* LunarLake ops */ -struct snd_sof_dsp_ops sof_lnl_ops; -EXPORT_SYMBOL_NS(sof_lnl_ops, "SND_SOC_SOF_INTEL_LNL"); - -static const struct snd_sof_debugfs_map lnl_dsp_debugfs[] = { - {"hda", HDA_DSP_HDA_BAR, 0, 0x4000, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"pp", HDA_DSP_PP_BAR, 0, 0x1000, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"dsp", HDA_DSP_BAR, 0, 0x10000, SOF_DEBUGFS_ACCESS_ALWAYS}, - {"fw_regs", HDA_DSP_BAR, MTL_SRAM_WINDOW_OFFSET(0), 0x1000, SOF_DEBUGFS_ACCESS_D0_ONLY}, -}; - /* this helps allows the DSP to setup DMIC/SSP */ static int hdac_bus_offload_dmic_ssp(struct hdac_bus *bus, bool enable) { @@ -111,94 +100,50 @@ static int lnl_dsp_post_fw_run(struct snd_sof_dev *sdev) return 0; } -int sof_lnl_ops_init(struct snd_sof_dev *sdev) +int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) { - struct sof_ipc4_fw_data *ipc4_data; + int ret; - /* common defaults */ - memcpy(&sof_lnl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + ret = sof_mtl_set_ops(sdev, dsp_ops); + if (ret) + return ret; /* probe/remove */ if (!sdev->dspless_mode_selected) { - sof_lnl_ops.probe = lnl_hda_dsp_probe; - sof_lnl_ops.remove = lnl_hda_dsp_remove; + dsp_ops->probe = lnl_hda_dsp_probe; + dsp_ops->remove = lnl_hda_dsp_remove; } - /* shutdown */ - sof_lnl_ops.shutdown = hda_dsp_shutdown; - - /* doorbell */ - sof_lnl_ops.irq_thread = mtl_ipc_irq_thread; - - /* ipc */ - sof_lnl_ops.send_msg = mtl_ipc_send_msg; - sof_lnl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; - sof_lnl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; - - /* debug */ - sof_lnl_ops.debug_map = lnl_dsp_debugfs; - sof_lnl_ops.debug_map_count = ARRAY_SIZE(lnl_dsp_debugfs); - sof_lnl_ops.dbg_dump = mtl_dsp_dump; - sof_lnl_ops.ipc_dump = mtl_ipc_dump; - - /* pre/post fw run */ - sof_lnl_ops.pre_fw_run = mtl_dsp_pre_fw_run; - sof_lnl_ops.post_fw_run = lnl_dsp_post_fw_run; - - /* parse platform specific extended manifest */ - sof_lnl_ops.parse_platform_ext_manifest = NULL; - - /* dsp core get/put */ - /* TODO: add core_get and core_put */ + /* post fw run */ + dsp_ops->post_fw_run = lnl_dsp_post_fw_run; /* PM */ if (!sdev->dspless_mode_selected) { - sof_lnl_ops.resume = lnl_hda_dsp_resume; - sof_lnl_ops.runtime_resume = lnl_hda_dsp_runtime_resume; + dsp_ops->resume = lnl_hda_dsp_resume; + dsp_ops->runtime_resume = lnl_hda_dsp_runtime_resume; } - /* dsp core get/put */ - sof_lnl_ops.core_get = mtl_dsp_core_get; - sof_lnl_ops.core_put = mtl_dsp_core_put; - - sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); - if (!sdev->private) - return -ENOMEM; - - ipc4_data = sdev->private; - ipc4_data->manifest_fw_hdr_offset = SOF_MAN4_FW_HDR_OFFSET; - - ipc4_data->mtrace_type = SOF_IPC4_MTRACE_INTEL_CAVS_2; - - ipc4_data->fw_context_save = true; - - /* External library loading support */ - ipc4_data->load_library = hda_dsp_ipc4_load_library; - - /* set DAI ops */ - hda_set_dai_drv_ops(sdev, &sof_lnl_ops); - - sof_lnl_ops.set_power_state = hda_dsp_set_power_state_ipc4; - return 0; -}; -EXPORT_SYMBOL_NS(sof_lnl_ops_init, "SND_SOC_SOF_INTEL_LNL"); +} +EXPORT_SYMBOL_NS(sof_lnl_set_ops, "SND_SOC_SOF_INTEL_LNL"); /* Check if an SDW IRQ occurred */ -static bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) +bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); return hdac_bus_eml_check_interrupt(bus, true, AZX_REG_ML_LEPTR_ID_SDW); } +EXPORT_SYMBOL_NS(lnl_dsp_check_sdw_irq, "SND_SOC_SOF_INTEL_LNL"); -static int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) +int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { mtl_disable_ipc_interrupts(sdev); return mtl_enable_interrupts(sdev, false); } +EXPORT_SYMBOL_NS(lnl_dsp_disable_interrupts, "SND_SOC_SOF_INTEL_LNL"); -static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) +bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) { struct hdac_bus *bus = sof_to_bus(sdev); u16 wake_sts; @@ -214,6 +159,7 @@ static bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev) /* filter out the range of SDIs that can be set for SoundWire */ return wake_sts & GENMASK(SDW_MAX_DEVICES, SDW_INTEL_DEV_NUM_IDA_MIN); } +EXPORT_SYMBOL_NS(lnl_sdw_check_wakeen_irq, "SND_SOC_SOF_INTEL_LNL"); const struct sof_intel_dsp_desc lnl_chip_info = { .cores_num = 5, @@ -239,26 +185,5 @@ const struct sof_intel_dsp_desc lnl_chip_info = { .hw_ip_version = SOF_INTEL_ACE_2_0, }; -const struct sof_intel_dsp_desc ptl_chip_info = { - .cores_num = 5, - .init_core_mask = BIT(0), - .host_managed_cores_mask = BIT(0), - .ipc_req = MTL_DSP_REG_HFIPCXIDR, - .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, - .ipc_ack = MTL_DSP_REG_HFIPCXIDA, - .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, - .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, - .rom_status_reg = LNL_DSP_REG_HFDSC, - .rom_init_timeout = 300, - .ssp_count = MTL_SSP_COUNT, - .d0i3_offset = MTL_HDA_VS_D0I3C, - .read_sdw_lcount = hda_sdw_check_lcount_ext, - .check_sdw_irq = lnl_dsp_check_sdw_irq, - .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, - .check_ipc_irq = mtl_dsp_check_ipc_irq, - .cl_init = mtl_dsp_cl_init, - .power_down_dsp = mtl_power_down_dsp, - .disable_interrupts = lnl_dsp_disable_interrupts, - .hw_ip_version = SOF_INTEL_ACE_3_0, -}; -EXPORT_SYMBOL_NS(ptl_chip_info, "SND_SOC_SOF_INTEL_LNL"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); diff --git a/sound/soc/sof/intel/lnl.h b/sound/soc/sof/intel/lnl.h index 79101af84b2e..2837f818ac51 100644 --- a/sound/soc/sof/intel/lnl.h +++ b/sound/soc/sof/intel/lnl.h @@ -12,4 +12,10 @@ #define LNL_DSP_REG_HFDSC 0x160200 /* DSP core0 status */ #define LNL_DSP_REG_HFDEC 0x160204 /* DSP core0 error */ +int sof_lnl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops); + +bool lnl_dsp_check_sdw_irq(struct snd_sof_dev *sdev); +int lnl_dsp_disable_interrupts(struct snd_sof_dev *sdev); +bool lnl_sdw_check_wakeen_irq(struct snd_sof_dev *sdev); + #endif /* __SOF_INTEL_LNL_H */ diff --git a/sound/soc/sof/intel/mtl.c b/sound/soc/sof/intel/mtl.c index d07c68f431ba..2242c96bfa51 100644 --- a/sound/soc/sof/intel/mtl.c +++ b/sound/soc/sof/intel/mtl.c @@ -11,6 +11,7 @@ #include <linux/debugfs.h> #include <linux/firmware.h> +#include <linux/string_choices.h> #include <sound/sof/ipc4/header.h> #include <trace/events/sof_intel.h> #include "../ipc4-priv.h" @@ -95,7 +96,7 @@ static bool mtl_dsp_check_sdw_irq(struct snd_sof_dev *sdev) return false; } -int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +static int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; struct sof_ipc4_msg *msg_data = msg->msg_data; @@ -121,7 +122,6 @@ int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) return 0; } -EXPORT_SYMBOL_NS(mtl_ipc_send_msg, "SND_SOC_SOF_INTEL_MTL"); void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev) { @@ -176,7 +176,7 @@ static void mtl_enable_sdw_irq(struct snd_sof_dev *sdev, bool enable) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) dev_err(sdev->dev, "failed to set SoundWire IPC interrupt %s\n", - enable ? "enable" : "disable"); + str_enable_disable(enable)); } int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) @@ -209,7 +209,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) { dev_err(sdev->dev, "failed to %s Host IPC and/or SOUNDWIRE\n", - enable ? "enable" : "disable"); + str_enable_disable(enable)); return ret; } @@ -228,7 +228,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) HDA_DSP_REG_POLL_INTERVAL_US, HDA_DSP_RESET_TIMEOUT_US); if (ret < 0) { dev_err(sdev->dev, "failed to set Host IPC interrupt %s\n", - enable ? "enable" : "disable"); + str_enable_disable(enable)); return ret; } @@ -237,7 +237,7 @@ int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable) EXPORT_SYMBOL_NS(mtl_enable_interrupts, "SND_SOC_SOF_INTEL_MTL"); /* pre fw run operations */ -int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) +static int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) { struct sof_intel_hda_dev *hdev = sdev->pdata->hw_pdata; u32 dsphfpwrsts; @@ -297,9 +297,8 @@ int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev) return ret; } -EXPORT_SYMBOL_NS(mtl_dsp_pre_fw_run, "SND_SOC_SOF_INTEL_MTL"); -int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) +static int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) { int ret; @@ -324,9 +323,8 @@ int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev) hda_sdw_int_enable(sdev, true); return 0; } -EXPORT_SYMBOL_NS(mtl_dsp_post_fw_run, "SND_SOC_SOF_INTEL_MTL"); -void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) +static void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) { char *level = (flags & SOF_DBG_DUMP_OPTIONAL) ? KERN_DEBUG : KERN_ERR; u32 fwsts; @@ -342,7 +340,6 @@ void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags) sof_ipc4_intel_dump_telemetry_state(sdev, flags); } -EXPORT_SYMBOL_NS(mtl_dsp_dump, "SND_SOC_SOF_INTEL_MTL"); static bool mtl_dsp_primary_core_is_enabled(struct snd_sof_dev *sdev) { @@ -558,7 +555,7 @@ err: } EXPORT_SYMBOL_NS(mtl_dsp_cl_init, "SND_SOC_SOF_INTEL_MTL"); -irqreturn_t mtl_ipc_irq_thread(int irq, void *context) +static irqreturn_t mtl_ipc_irq_thread(int irq, void *context) { struct sof_ipc4_msg notification_data = {{ 0 }}; struct snd_sof_dev *sdev = context; @@ -640,21 +637,18 @@ irqreturn_t mtl_ipc_irq_thread(int irq, void *context) return IRQ_HANDLED; } -EXPORT_SYMBOL_NS(mtl_ipc_irq_thread, "SND_SOC_SOF_INTEL_MTL"); -int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) +static int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev) { return MTL_DSP_MBOX_UPLINK_OFFSET; } -EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_mailbox_offset, "SND_SOC_SOF_INTEL_MTL"); -int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) +static int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id) { return MTL_SRAM_WINDOW_OFFSET(id); } -EXPORT_SYMBOL_NS(mtl_dsp_ipc_get_window_offset, "SND_SOC_SOF_INTEL_MTL"); -void mtl_ipc_dump(struct snd_sof_dev *sdev) +static void mtl_ipc_dump(struct snd_sof_dev *sdev) { u32 hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl; @@ -670,7 +664,6 @@ void mtl_ipc_dump(struct snd_sof_dev *sdev) "Host IPC initiator: %#x|%#x|%#x, target: %#x|%#x|%#x, ctl: %#x\n", hipcidr, hipcidd, hipcida, hipctdr, hipctdd, hipctda, hipcctl); } -EXPORT_SYMBOL_NS(mtl_ipc_dump, "SND_SOC_SOF_INTEL_MTL"); static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) { @@ -679,7 +672,7 @@ static int mtl_dsp_disable_interrupts(struct snd_sof_dev *sdev) return mtl_enable_interrupts(sdev, false); } -int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) +static int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; @@ -691,9 +684,8 @@ int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core) return 0; } -EXPORT_SYMBOL_NS(mtl_dsp_core_get, "SND_SOC_SOF_INTEL_MTL"); -int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) +static int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) { const struct sof_ipc_pm_ops *pm_ops = sdev->ipc->ops->pm; int ret; @@ -709,45 +701,41 @@ int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core) return 0; } -EXPORT_SYMBOL_NS(mtl_dsp_core_put, "SND_SOC_SOF_INTEL_MTL"); -/* Meteorlake ops */ -struct snd_sof_dsp_ops sof_mtl_ops; - -int sof_mtl_ops_init(struct snd_sof_dev *sdev) +int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) { struct sof_ipc4_fw_data *ipc4_data; /* common defaults */ - memcpy(&sof_mtl_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); + memcpy(dsp_ops, &sof_hda_common_ops, sizeof(struct snd_sof_dsp_ops)); /* shutdown */ - sof_mtl_ops.shutdown = hda_dsp_shutdown; + dsp_ops->shutdown = hda_dsp_shutdown; /* doorbell */ - sof_mtl_ops.irq_thread = mtl_ipc_irq_thread; + dsp_ops->irq_thread = mtl_ipc_irq_thread; /* ipc */ - sof_mtl_ops.send_msg = mtl_ipc_send_msg; - sof_mtl_ops.get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; - sof_mtl_ops.get_window_offset = mtl_dsp_ipc_get_window_offset; + dsp_ops->send_msg = mtl_ipc_send_msg; + dsp_ops->get_mailbox_offset = mtl_dsp_ipc_get_mailbox_offset; + dsp_ops->get_window_offset = mtl_dsp_ipc_get_window_offset; /* debug */ - sof_mtl_ops.debug_map = mtl_dsp_debugfs; - sof_mtl_ops.debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs); - sof_mtl_ops.dbg_dump = mtl_dsp_dump; - sof_mtl_ops.ipc_dump = mtl_ipc_dump; + dsp_ops->debug_map = mtl_dsp_debugfs; + dsp_ops->debug_map_count = ARRAY_SIZE(mtl_dsp_debugfs); + dsp_ops->dbg_dump = mtl_dsp_dump; + dsp_ops->ipc_dump = mtl_ipc_dump; /* pre/post fw run */ - sof_mtl_ops.pre_fw_run = mtl_dsp_pre_fw_run; - sof_mtl_ops.post_fw_run = mtl_dsp_post_fw_run; + dsp_ops->pre_fw_run = mtl_dsp_pre_fw_run; + dsp_ops->post_fw_run = mtl_dsp_post_fw_run; /* parse platform specific extended manifest */ - sof_mtl_ops.parse_platform_ext_manifest = NULL; + dsp_ops->parse_platform_ext_manifest = NULL; /* dsp core get/put */ - sof_mtl_ops.core_get = mtl_dsp_core_get; - sof_mtl_ops.core_put = mtl_dsp_core_put; + dsp_ops->core_get = mtl_dsp_core_get; + dsp_ops->core_put = mtl_dsp_core_put; sdev->private = kzalloc(sizeof(struct sof_ipc4_fw_data), GFP_KERNEL); if (!sdev->private) @@ -763,13 +751,14 @@ int sof_mtl_ops_init(struct snd_sof_dev *sdev) /* External library loading support */ ipc4_data->load_library = hda_dsp_ipc4_load_library; - /* set DAI ops */ - hda_set_dai_drv_ops(sdev, &sof_mtl_ops); + dsp_ops->set_power_state = hda_dsp_set_power_state_ipc4; - sof_mtl_ops.set_power_state = hda_dsp_set_power_state_ipc4; + /* set DAI ops */ + hda_set_dai_drv_ops(sdev, dsp_ops); return 0; -}; +} +EXPORT_SYMBOL_NS(sof_mtl_set_ops, "SND_SOC_SOF_INTEL_MTL"); const struct sof_intel_dsp_desc mtl_chip_info = { .cores_num = 3, diff --git a/sound/soc/sof/intel/mtl.h b/sound/soc/sof/intel/mtl.h index 9ab4b21c960e..e01a1536709e 100644 --- a/sound/soc/sof/intel/mtl.h +++ b/sound/soc/sof/intel/mtl.h @@ -122,26 +122,13 @@ #define MTL_DSP_REG_HfIMRIS1_IU_MASK BIT(0) bool mtl_dsp_check_ipc_irq(struct snd_sof_dev *sdev); -int mtl_ipc_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); void mtl_enable_ipc_interrupts(struct snd_sof_dev *sdev); void mtl_disable_ipc_interrupts(struct snd_sof_dev *sdev); int mtl_enable_interrupts(struct snd_sof_dev *sdev, bool enable); -int mtl_dsp_pre_fw_run(struct snd_sof_dev *sdev); -int mtl_dsp_post_fw_run(struct snd_sof_dev *sdev); -void mtl_dsp_dump(struct snd_sof_dev *sdev, u32 flags); - int mtl_power_down_dsp(struct snd_sof_dev *sdev); int mtl_dsp_cl_init(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); -irqreturn_t mtl_ipc_irq_thread(int irq, void *context); - -int mtl_dsp_ipc_get_mailbox_offset(struct snd_sof_dev *sdev); -int mtl_dsp_ipc_get_window_offset(struct snd_sof_dev *sdev, u32 id); - -void mtl_ipc_dump(struct snd_sof_dev *sdev); - -int mtl_dsp_core_get(struct snd_sof_dev *sdev, int core); -int mtl_dsp_core_put(struct snd_sof_dev *sdev, int core); +int sof_mtl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops); diff --git a/sound/soc/sof/intel/pci-apl.c b/sound/soc/sof/intel/pci-apl.c index 94ab3c61e3f7..0bf7ee753bc3 100644 --- a/sound/soc/sof/intel/pci-apl.c +++ b/sound/soc/sof/intel/pci-apl.c @@ -99,7 +99,7 @@ static struct pci_driver snd_sof_pci_intel_apl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_apl_driver); diff --git a/sound/soc/sof/intel/pci-cnl.c b/sound/soc/sof/intel/pci-cnl.c index 739c352c3860..de48640024e4 100644 --- a/sound/soc/sof/intel/pci-cnl.c +++ b/sound/soc/sof/intel/pci-cnl.c @@ -137,7 +137,7 @@ static struct pci_driver snd_sof_pci_intel_cnl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_cnl_driver); diff --git a/sound/soc/sof/intel/pci-icl.c b/sound/soc/sof/intel/pci-icl.c index 8545ab95eac8..fd219e654844 100644 --- a/sound/soc/sof/intel/pci-icl.c +++ b/sound/soc/sof/intel/pci-icl.c @@ -102,7 +102,7 @@ static struct pci_driver snd_sof_pci_intel_icl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_icl_driver); diff --git a/sound/soc/sof/intel/pci-lnl.c b/sound/soc/sof/intel/pci-lnl.c index 8d4d74ac4398..ae379c23f008 100644 --- a/sound/soc/sof/intel/pci-lnl.c +++ b/sound/soc/sof/intel/pci-lnl.c @@ -18,7 +18,15 @@ /* platform specific devices */ #include "hda.h" -#include "mtl.h" +#include "lnl.h" + +/* LunarLake ops */ +static struct snd_sof_dsp_ops sof_lnl_ops; + +static int sof_lnl_ops_init(struct snd_sof_dev *sdev) +{ + return sof_lnl_set_ops(sdev, &sof_lnl_ops); +} static const struct sof_dev_desc lnl_desc = { .use_acpi_target_states = true, @@ -64,7 +72,7 @@ static struct pci_driver snd_sof_pci_intel_lnl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_lnl_driver); @@ -73,6 +81,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for LunarLake platforms"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); -MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); -MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-mtl.c b/sound/soc/sof/intel/pci-mtl.c index 71f711cf8599..7b2533999195 100644 --- a/sound/soc/sof/intel/pci-mtl.c +++ b/sound/soc/sof/intel/pci-mtl.c @@ -20,6 +20,14 @@ #include "hda.h" #include "mtl.h" +/* Meteorlake ops */ +static struct snd_sof_dsp_ops sof_mtl_ops; + +static int sof_mtl_ops_init(struct snd_sof_dev *sdev) +{ + return sof_mtl_set_ops(sdev, &sof_mtl_ops); +} + static const struct sof_dev_desc mtl_desc = { .use_acpi_target_states = true, .machines = snd_soc_acpi_intel_mtl_machines, @@ -127,7 +135,7 @@ static struct pci_driver snd_sof_pci_intel_mtl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_mtl_driver); diff --git a/sound/soc/sof/intel/pci-ptl.c b/sound/soc/sof/intel/pci-ptl.c index c4fb6a2441b7..7d4c46f56931 100644 --- a/sound/soc/sof/intel/pci-ptl.c +++ b/sound/soc/sof/intel/pci-ptl.c @@ -16,7 +16,15 @@ /* platform specific devices */ #include "hda.h" -#include "mtl.h" +#include "ptl.h" + +/* PantherLake ops */ +static struct snd_sof_dsp_ops sof_ptl_ops; + +static int sof_ptl_ops_init(struct snd_sof_dev *sdev) +{ + return sof_ptl_set_ops(sdev, &sof_ptl_ops); +} static const struct sof_dev_desc ptl_desc = { .use_acpi_target_states = true, @@ -43,8 +51,8 @@ static const struct sof_dev_desc ptl_desc = { [SOF_IPC_TYPE_4] = "sof-ptl.ri", }, .nocodec_tplg_filename = "sof-ptl-nocodec.tplg", - .ops = &sof_lnl_ops, - .ops_init = sof_lnl_ops_init, + .ops = &sof_ptl_ops, + .ops_init = sof_ptl_ops_init, }; /* PCI IDs */ @@ -63,7 +71,7 @@ static struct pci_driver snd_sof_pci_intel_ptl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_ptl_driver); @@ -72,7 +80,4 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for PantherLake platforms"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_GENERIC"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HDA_COMMON"); -MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL"); -MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); -MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); diff --git a/sound/soc/sof/intel/pci-skl.c b/sound/soc/sof/intel/pci-skl.c index bd9daae51e4c..a16945dc35f7 100644 --- a/sound/soc/sof/intel/pci-skl.c +++ b/sound/soc/sof/intel/pci-skl.c @@ -83,7 +83,7 @@ static struct pci_driver snd_sof_pci_intel_skl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_skl_driver); diff --git a/sound/soc/sof/intel/pci-tgl.c b/sound/soc/sof/intel/pci-tgl.c index f76a7197f6ca..437c43819825 100644 --- a/sound/soc/sof/intel/pci-tgl.c +++ b/sound/soc/sof/intel/pci-tgl.c @@ -311,7 +311,7 @@ static struct pci_driver snd_sof_pci_intel_tgl_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_tgl_driver); diff --git a/sound/soc/sof/intel/pci-tng.c b/sound/soc/sof/intel/pci-tng.c index b585ac4a85c2..0c11cc1fd820 100644 --- a/sound/soc/sof/intel/pci-tng.c +++ b/sound/soc/sof/intel/pci-tng.c @@ -238,14 +238,13 @@ static struct pci_driver snd_sof_pci_intel_tng_driver = { .remove = sof_pci_remove, .shutdown = sof_pci_shutdown, .driver = { - .pm = &sof_pci_pm, + .pm = pm_ptr(&sof_pci_pm), }, }; module_pci_driver(snd_sof_pci_intel_tng_driver); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF support for Tangier platforms"); -MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_HIFI_EP_IPC"); MODULE_IMPORT_NS("SND_SOC_SOF_XTENSA"); MODULE_IMPORT_NS("SND_SOC_SOF_PCI_DEV"); MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_ATOM_HIFI_EP"); diff --git a/sound/soc/sof/intel/ptl.c b/sound/soc/sof/intel/ptl.c new file mode 100644 index 000000000000..8fa4bdceedd9 --- /dev/null +++ b/sound/soc/sof/intel/ptl.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) +// +// Copyright(c) 2025 Intel Corporation + +/* + * Hardware interface for audio DSP on PantherLake. + */ + +#include <sound/hda_register.h> +#include <sound/hda-mlink.h> +#include <sound/sof/ipc4/header.h> +#include "../ipc4-priv.h" +#include "../ops.h" +#include "hda.h" +#include "hda-ipc.h" +#include "../sof-audio.h" +#include "mtl.h" +#include "lnl.h" +#include "ptl.h" + +static bool sof_ptl_check_mic_privacy_irq(struct snd_sof_dev *sdev, bool alt, + int elid) +{ + if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW) + return false; + + return hdac_bus_eml_is_mic_privacy_changed(sof_to_bus(sdev), alt, elid); +} + +static void sof_ptl_process_mic_privacy(struct snd_sof_dev *sdev, bool alt, + int elid) +{ + bool state; + + if (!alt || elid != AZX_REG_ML_LEPTR_ID_SDW) + return; + + state = hdac_bus_eml_get_mic_privacy_state(sof_to_bus(sdev), alt, elid); + + sof_ipc4_mic_privacy_state_change(sdev, state); +} + +static void sof_ptl_set_mic_privacy(struct snd_sof_dev *sdev, + struct sof_ipc4_intel_mic_privacy_cap *caps) +{ + u32 micpvcp; + + if (!caps || !caps->capabilities_length) + return; + + micpvcp = caps->capabilities[0]; + + /* No need to set the mic privacy if it is not enabled or forced */ + if (!(micpvcp & PTL_MICPVCP_DDZE_ENABLED) || + micpvcp & PTL_MICPVCP_DDZE_FORCED) + return; + + hdac_bus_eml_set_mic_privacy_mask(sof_to_bus(sdev), true, + AZX_REG_ML_LEPTR_ID_SDW, + PTL_MICPVCP_GET_SDW_MASK(micpvcp)); +} + +int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops) +{ + struct sof_ipc4_fw_data *ipc4_data; + int ret; + + ret = sof_lnl_set_ops(sdev, dsp_ops); + if (ret) + return ret; + + ipc4_data = sdev->private; + ipc4_data->intel_configure_mic_privacy = sof_ptl_set_mic_privacy; + + return 0; +}; +EXPORT_SYMBOL_NS(sof_ptl_set_ops, "SND_SOC_SOF_INTEL_PTL"); + +const struct sof_intel_dsp_desc ptl_chip_info = { + .cores_num = 5, + .init_core_mask = BIT(0), + .host_managed_cores_mask = BIT(0), + .ipc_req = MTL_DSP_REG_HFIPCXIDR, + .ipc_req_mask = MTL_DSP_REG_HFIPCXIDR_BUSY, + .ipc_ack = MTL_DSP_REG_HFIPCXIDA, + .ipc_ack_mask = MTL_DSP_REG_HFIPCXIDA_DONE, + .ipc_ctl = MTL_DSP_REG_HFIPCXCTL, + .rom_status_reg = LNL_DSP_REG_HFDSC, + .rom_init_timeout = 300, + .ssp_count = MTL_SSP_COUNT, + .d0i3_offset = MTL_HDA_VS_D0I3C, + .read_sdw_lcount = hda_sdw_check_lcount_ext, + .check_sdw_irq = lnl_dsp_check_sdw_irq, + .check_sdw_wakeen_irq = lnl_sdw_check_wakeen_irq, + .check_ipc_irq = mtl_dsp_check_ipc_irq, + .check_mic_privacy_irq = sof_ptl_check_mic_privacy_irq, + .process_mic_privacy = sof_ptl_process_mic_privacy, + .cl_init = mtl_dsp_cl_init, + .power_down_dsp = mtl_power_down_dsp, + .disable_interrupts = lnl_dsp_disable_interrupts, + .hw_ip_version = SOF_INTEL_ACE_3_0, +}; + +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_MTL"); +MODULE_IMPORT_NS("SND_SOC_SOF_INTEL_LNL"); +MODULE_IMPORT_NS("SND_SOC_SOF_HDA_MLINK"); diff --git a/sound/soc/sof/intel/ptl.h b/sound/soc/sof/intel/ptl.h new file mode 100644 index 000000000000..6a7ef11f411e --- /dev/null +++ b/sound/soc/sof/intel/ptl.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause) */ +/* + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * Copyright(c) 2025 Intel Corporation + */ + +#ifndef __SOF_INTEL_PTL_H +#define __SOF_INTEL_PTL_H + +#define PTL_MICPVCP_DDZE_FORCED BIT(16) +#define PTL_MICPVCP_DDZE_ENABLED BIT(17) +#define PTL_MICPVCP_DDZLS_SDW GENMASK(26, 20) +#define PTL_MICPVCP_GET_SDW_MASK(x) (((x) & PTL_MICPVCP_DDZLS_SDW) >> 20) + +int sof_ptl_set_ops(struct snd_sof_dev *sdev, struct snd_sof_dsp_ops *dsp_ops); + +#endif /* __SOF_INTEL_PTL_H */ diff --git a/sound/soc/sof/intel/shim.h b/sound/soc/sof/intel/shim.h index 8709b750a11e..d4372f0bff7e 100644 --- a/sound/soc/sof/intel/shim.h +++ b/sound/soc/sof/intel/shim.h @@ -193,6 +193,8 @@ struct sof_intel_dsp_desc { bool (*check_sdw_wakeen_irq)(struct snd_sof_dev *sdev); void (*sdw_process_wakeen)(struct snd_sof_dev *sdev); bool (*check_ipc_irq)(struct snd_sof_dev *sdev); + bool (*check_mic_privacy_irq)(struct snd_sof_dev *sdev, bool alt, int elid); + void (*process_mic_privacy)(struct snd_sof_dev *sdev, bool alt, int elid); int (*power_down_dsp)(struct snd_sof_dev *sdev); int (*disable_interrupts)(struct snd_sof_dev *sdev); int (*cl_init)(struct snd_sof_dev *sdev, int stream_tag, bool imr_boot); diff --git a/sound/soc/sof/ipc3-pcm.c b/sound/soc/sof/ipc3-pcm.c index 1c1b8f595367..90ef5d99f626 100644 --- a/sound/soc/sof/ipc3-pcm.c +++ b/sound/soc/sof/ipc3-pcm.c @@ -117,22 +117,23 @@ static int sof_ipc3_pcm_hw_params(struct snd_soc_component *component, if (platform_params->cont_update_posn) pcm.params.cont_update_posn = 1; - dev_dbg(component->dev, "stream_tag %d", pcm.params.stream_tag); + spcm_dbg(spcm, substream->stream, "stream_tag %d\n", + pcm.params.stream_tag); /* send hw_params IPC to the DSP */ ret = sof_ipc_tx_message(sdev->ipc, &pcm, sizeof(pcm), &ipc_params_reply, sizeof(ipc_params_reply)); if (ret < 0) { - dev_err(component->dev, "HW params ipc failed for stream %d\n", - pcm.params.stream_tag); + spcm_err(spcm, substream->stream, + "STREAM_PCM_PARAMS ipc failed for stream_tag %d\n", + pcm.params.stream_tag); return ret; } ret = snd_sof_set_stream_data_offset(sdev, &spcm->stream[substream->stream], ipc_params_reply.posn_offset); if (ret < 0) { - dev_err(component->dev, "%s: invalid stream data offset for PCM %d\n", - __func__, spcm->pcm.pcm_id); + spcm_err(spcm, substream->stream, "invalid stream data offset\n"); return ret; } @@ -171,7 +172,7 @@ static int sof_ipc3_pcm_trigger(struct snd_soc_component *component, stream.hdr.cmd |= SOF_IPC_STREAM_TRIG_STOP; break; default: - dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd); + spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd); return -EINVAL; } diff --git a/sound/soc/sof/ipc3-topology.c b/sound/soc/sof/ipc3-topology.c index e98b53b67d12..473d416bc910 100644 --- a/sound/soc/sof/ipc3-topology.c +++ b/sound/soc/sof/ipc3-topology.c @@ -2386,28 +2386,16 @@ static int sof_ipc3_set_up_all_pipelines(struct snd_sof_dev *sdev, bool verify) static int sof_tear_down_left_over_pipelines(struct snd_sof_dev *sdev) { struct snd_sof_widget *swidget; - struct snd_sof_pcm *spcm; - int dir, ret; + int ret; /* * free all PCMs and their associated DAPM widgets if their connected DAPM widget * list is not NULL. This should only be true for paused streams at this point. * This is equivalent to the handling of FE DAI suspend trigger for running streams. */ - list_for_each_entry(spcm, &sdev->pcm_list, list) { - for_each_pcm_streams(dir) { - struct snd_pcm_substream *substream = spcm->stream[dir].substream; - - if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) - continue; - - if (spcm->stream[dir].list) { - ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); - if (ret < 0) - return ret; - } - } - } + ret = sof_pcm_free_all_streams(sdev); + if (ret) + return ret; /* * free any left over DAI widgets. This is equivalent to the handling of suspend trigger diff --git a/sound/soc/sof/ipc3.c b/sound/soc/sof/ipc3.c index 7de5e3d285e7..4a194a705ace 100644 --- a/sound/soc/sof/ipc3.c +++ b/sound/soc/sof/ipc3.c @@ -801,20 +801,16 @@ int sof_ipc3_validate_fw_version(struct snd_sof_dev *sdev) return -EINVAL; } - if (ready->flags & SOF_IPC_INFO_BUILD) { + if (ready->flags & SOF_IPC_INFO_BUILD) dev_info(sdev->dev, "Firmware debug build %d on %s-%s - options:\n" " GDB: %s\n" " lock debug: %s\n" " lock vdebug: %s\n", v->build, v->date, v->time, - (ready->flags & SOF_IPC_INFO_GDB) ? - "enabled" : "disabled", - (ready->flags & SOF_IPC_INFO_LOCKS) ? - "enabled" : "disabled", - (ready->flags & SOF_IPC_INFO_LOCKSV) ? - "enabled" : "disabled"); - } + str_enabled_disabled(ready->flags & SOF_IPC_INFO_GDB), + str_enabled_disabled(ready->flags & SOF_IPC_INFO_LOCKS), + str_enabled_disabled(ready->flags & SOF_IPC_INFO_LOCKSV)); /* copy the fw_version into debugfs at first boot */ memcpy(&sdev->fw_version, v, sizeof(*v)); diff --git a/sound/soc/sof/ipc4-loader.c b/sound/soc/sof/ipc4-loader.c index bcdb33d03682..d2f534d65edf 100644 --- a/sound/soc/sof/ipc4-loader.c +++ b/sound/soc/sof/ipc4-loader.c @@ -169,21 +169,14 @@ static size_t sof_ipc4_fw_parse_basefw_ext_man(struct snd_sof_dev *sdev) return payload_offset; } -static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, - unsigned long lib_id, const guid_t *uuid) +static int sof_ipc4_load_library(struct snd_sof_dev *sdev, unsigned long lib_id, + const char *lib_filename, bool optional) { struct sof_ipc4_fw_data *ipc4_data = sdev->private; struct sof_ipc4_fw_library *fw_lib; - const char *fw_filename; ssize_t payload_offset; int ret, i, err; - if (!sdev->pdata->fw_lib_prefix) { - dev_err(sdev->dev, - "Library loading is not supported due to not set library path\n"); - return -EINVAL; - } - if (!ipc4_data->load_library) { dev_err(sdev->dev, "Library loading is not supported on this platform\n"); return -EOPNOTSUPP; @@ -193,21 +186,26 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, if (!fw_lib) return -ENOMEM; - fw_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", - sdev->pdata->fw_lib_prefix, uuid); - if (!fw_filename) { - ret = -ENOMEM; - goto free_fw_lib; - } - - ret = request_firmware(&fw_lib->sof_fw.fw, fw_filename, sdev->dev); - if (ret < 0) { - dev_err(sdev->dev, "Library file '%s' is missing\n", fw_filename); - goto free_filename; + if (optional) { + ret = firmware_request_nowarn(&fw_lib->sof_fw.fw, lib_filename, + sdev->dev); + if (ret < 0) { + /* optional library, override the error */ + ret = 0; + goto free_fw_lib; + } } else { - dev_dbg(sdev->dev, "Library file '%s' loaded\n", fw_filename); + ret = request_firmware(&fw_lib->sof_fw.fw, lib_filename, + sdev->dev); + if (ret < 0) { + dev_err(sdev->dev, "Library file '%s' is missing\n", + lib_filename); + goto free_fw_lib; + } } + dev_dbg(sdev->dev, "Library file '%s' loaded\n", lib_filename); + payload_offset = sof_ipc4_fw_parse_ext_man(sdev, fw_lib); if (payload_offset <= 0) { if (!payload_offset) @@ -251,22 +249,117 @@ static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, if (unlikely(ret)) goto release; - kfree(fw_filename); - return 0; release: release_firmware(fw_lib->sof_fw.fw); /* Allocated within sof_ipc4_fw_parse_ext_man() */ devm_kfree(sdev->dev, fw_lib->modules); -free_filename: - kfree(fw_filename); free_fw_lib: devm_kfree(sdev->dev, fw_lib); return ret; } +/** + * sof_ipc4_complete_split_release - loads the library parts of a split firmware + * @sdev: SOF device + * + * With IPC4 the firmware can be a single binary or a split release. + * - single binary: only the basefw + * - split release: basefw and two libraries (openmodules, debug) + * + * With split firmware release it is also allowed that for example only the + * debug library is present (the openmodules content is built in the basefw). + * + * To handle the permutations try to load the openmodules then the debug + * libraries as optional ones after the basefw boot. + * + * The libraries for the split release are stored alongside the basefw on the + * filesystem. + */ +int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev) +{ + static const char * const lib_bundle[] = { "openmodules", "debug" }; + const char *fw_filename = sdev->pdata->fw_filename; + const char *lib_filename, *p; + size_t lib_name_base_size; + unsigned long lib_id = 1; + char *lib_name_base; + int i; + + p = strstr(fw_filename, ".ri"); + if (!p || strlen(p) != 3) { + dev_info(sdev->dev, + "%s: Firmware name '%s' is missing .ri extension\n", + __func__, fw_filename); + return 0; + } + + /* Space for the firmware basename + '\0', without the extension */ + lib_name_base_size = strlen(fw_filename) - 2; + lib_name_base = kzalloc(lib_name_base_size, GFP_KERNEL); + if (!lib_name_base) + return -ENOMEM; + + /* + * strscpy will 0 terminate the copied string, removing the '.ri' from + * the end of the fw_filename, for example: + * fw_filename: "sof-ptl.ri\0" + * lib_name_base: "sof-ptl\0" + */ + strscpy(lib_name_base, fw_filename, lib_name_base_size); + + for (i = 0; i < ARRAY_SIZE(lib_bundle); i++) { + int ret; + + lib_filename = kasprintf(GFP_KERNEL, "%s/%s-%s.ri", + sdev->pdata->fw_filename_prefix, + lib_name_base, lib_bundle[i]); + if (!lib_filename) { + kfree(lib_name_base); + return -ENOMEM; + } + + ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, true); + if (ret) + dev_warn(sdev->dev, "%s: Failed to load %s: %d\n", + __func__, lib_filename, ret); + else + lib_id++; + + kfree(lib_filename); + } + + kfree(lib_name_base); + + return 0; +} + +static int sof_ipc4_load_library_by_uuid(struct snd_sof_dev *sdev, + unsigned long lib_id, const guid_t *uuid) +{ + const char *lib_filename; + int ret; + + if (!sdev->pdata->fw_lib_prefix) { + dev_err(sdev->dev, + "Library loading is not supported due to not set library path\n"); + return -EINVAL; + } + + lib_filename = kasprintf(GFP_KERNEL, "%s/%pUL.bin", + sdev->pdata->fw_lib_prefix, uuid); + if (!lib_filename) + return -ENOMEM; + + ret = sof_ipc4_load_library(sdev, lib_id, lib_filename, false); + + kfree(lib_filename); + + return ret; +} + struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, const guid_t *uuid) { @@ -409,6 +502,39 @@ int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev) offset += sizeof(*tuple) + tuple->size; } + /* Get the hardware configuration */ + msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); + msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_HW_CONFIG_GET); + + msg.data_size = sdev->ipc->max_payload_size; + + ret = iops->set_get_data(sdev, &msg, msg.data_size, false); + if (ret) + goto out; + + offset = 0; + while (offset < msg.data_size) { + tuple = (struct sof_ipc4_tuple *)((u8 *)msg.data_ptr + offset); + + switch (tuple->type) { + case SOF_IPC4_HW_CFG_INTEL_MIC_PRIVACY_CAPS: + if (ipc4_data->intel_configure_mic_privacy) { + struct sof_ipc4_intel_mic_privacy_cap *caps; + + caps = (struct sof_ipc4_intel_mic_privacy_cap *)tuple->value; + ipc4_data->intel_configure_mic_privacy(sdev, caps); + } + break; + default: + break; + } + + offset += sizeof(*tuple) + tuple->size; + } + out: kfree(msg.data_ptr); diff --git a/sound/soc/sof/ipc4-pcm.c b/sound/soc/sof/ipc4-pcm.c index 18fff2df76f9..1a2841899ff5 100644 --- a/sound/soc/sof/ipc4-pcm.c +++ b/sound/soc/sof/ipc4-pcm.c @@ -313,7 +313,7 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, set_fifo_size = false; break; default: - dev_err(sdev->dev, "Unexpected state %d", state); + spcm_err(spcm, direction, "Unexpected pipeline state %d\n", state); return -EINVAL; } @@ -333,8 +333,8 @@ static int sof_ipc4_chain_dma_trigger(struct snd_sof_dev *sdev, struct sof_ipc4_pipeline *pipeline = pipe_widget->private; if (!pipeline->use_chain_dma) { - dev_err(sdev->dev, - "All pipelines in chained DMA stream should have use_chain_dma attribute set."); + spcm_err(spcm, direction, + "All pipelines in chained DMA path should have use_chain_dma attribute set."); return -EINVAL; } @@ -389,12 +389,12 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, int ret; int i; - dev_dbg(sdev->dev, "trigger cmd: %d state: %d\n", cmd, state); - spcm = snd_sof_find_spcm_dai(component, rtd); if (!spcm) return -EINVAL; + spcm_dbg(spcm, substream->stream, "cmd: %d, state: %d\n", cmd, state); + pipeline_list = &spcm->stream[substream->stream].pipeline_list; /* nothing to trigger if the list is empty */ @@ -465,7 +465,7 @@ static int sof_ipc4_trigger_pipelines(struct snd_soc_component *component, */ ret = sof_ipc4_set_multi_pipeline_state(sdev, SOF_IPC4_PIPE_PAUSED, trigger_list); if (ret < 0) { - dev_err(sdev->dev, "failed to pause all pipelines\n"); + spcm_err(spcm, substream->stream, "failed to pause all pipelines\n"); goto free; } @@ -494,7 +494,9 @@ skip_pause_transition: /* else set the RUNNING/RESET state in the DSP */ ret = sof_ipc4_set_multi_pipeline_state(sdev, state, trigger_list); if (ret < 0) { - dev_err(sdev->dev, "failed to set final state %d for all pipelines\n", state); + spcm_err(spcm, substream->stream, + "failed to set final state %d for all pipelines\n", + state); /* * workaround: if the firmware is crashed while setting the * pipelines to reset state we must ignore the error code and @@ -610,12 +612,11 @@ static int sof_ipc4_pcm_dai_link_fixup_rate(struct snd_sof_dev *sdev, * Copier does not change sampling rate, so we * need to only consider the input pin information. */ + be_rate = pin_fmts[0].audio_fmt.sampling_frequency; for (i = 0; i < num_input_formats; i++) { unsigned int val = pin_fmts[i].audio_fmt.sampling_frequency; - if (i == 0) - be_rate = val; - else if (val != be_rate) + if (val != be_rate) single_be_rate = false; if (val == fe_rate) { diff --git a/sound/soc/sof/ipc4-priv.h b/sound/soc/sof/ipc4-priv.h index ea3323b90343..58b032820683 100644 --- a/sound/soc/sof/ipc4-priv.h +++ b/sound/soc/sof/ipc4-priv.h @@ -11,6 +11,7 @@ #include <linux/idr.h> #include <sound/sof/ext_manifest4.h> +#include <sound/sof/ipc4/header.h> #include "sof-priv.h" /* The DSP window indices are fixed */ @@ -89,6 +90,8 @@ struct sof_ipc4_fw_data { int (*load_library)(struct snd_sof_dev *sdev, struct sof_ipc4_fw_library *fw_lib, bool reload); + void (*intel_configure_mic_privacy)(struct snd_sof_dev *sdev, + struct sof_ipc4_intel_mic_privacy_cap *caps); struct mutex pipeline_state_mutex; /* protect pipeline triggers, ref counts and states */ }; @@ -101,6 +104,7 @@ extern const struct sof_ipc_fw_tracing_ops ipc4_mtrace_ops; int sof_ipc4_set_pipeline_state(struct snd_sof_dev *sdev, u32 instance_id, u32 state); int sof_ipc4_mtrace_update_pos(struct snd_sof_dev *sdev, int core); +int sof_ipc4_complete_split_release(struct snd_sof_dev *sdev); int sof_ipc4_query_fw_configuration(struct snd_sof_dev *sdev); int sof_ipc4_reload_fw_libraries(struct snd_sof_dev *sdev); struct sof_ipc4_fw_module *sof_ipc4_find_module_by_uuid(struct snd_sof_dev *sdev, @@ -117,4 +121,6 @@ void sof_ipc4_update_cpc_from_manifest(struct snd_sof_dev *sdev, size_t sof_ipc4_find_debug_slot_offset_by_type(struct snd_sof_dev *sdev, u32 slot_type); +void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state); + #endif diff --git a/sound/soc/sof/ipc4-topology.c b/sound/soc/sof/ipc4-topology.c index 6d5cda813e48..540ba140e155 100644 --- a/sound/soc/sof/ipc4-topology.c +++ b/sound/soc/sof/ipc4-topology.c @@ -7,6 +7,7 @@ // // #include <linux/bitfield.h> +#include <linux/cleanup.h> #include <uapi/sound/sof/tokens.h> #include <sound/pcm_params.h> #include <sound/sof/ext_manifest4.h> @@ -1807,8 +1808,8 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_sof_dev *sdev = snd_soc_component_get_drvdata(scomp); struct sof_ipc4_copier_data *copier_data; int input_fmt_index, output_fmt_index; - struct snd_pcm_hw_params ref_params; struct sof_ipc4_copier *ipc4_copier; + struct snd_pcm_hw_params *ref_params __free(kfree) = NULL; struct snd_sof_dai *dai; u32 gtw_cfg_config_length; u32 dma_config_tlv_size = 0; @@ -1821,15 +1822,19 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, bool single_output_bitdepth; int i; - dev_dbg(sdev->dev, "copier %s, type %d", swidget->widget->name, swidget->id); - switch (swidget->id) { case snd_soc_dapm_aif_in: case snd_soc_dapm_aif_out: { + struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; + struct sof_ipc4_pipeline *pipeline = pipe_widget->private; struct sof_ipc4_gtw_attributes *gtw_attr; - struct snd_sof_widget *pipe_widget; - struct sof_ipc4_pipeline *pipeline; + + dev_dbg(sdev->dev, + "Host copier %s, type %d, ChainDMA: %s, stream_tag: %d\n", + swidget->widget->name, swidget->id, + str_yes_no(pipeline->use_chain_dma), + platform_params->stream_tag); /* parse the deep buffer dma size */ ret = sof_update_ipc_object(scomp, &deep_buffer_dma_ms, @@ -1846,9 +1851,6 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; - pipe_widget = swidget->spipe->pipe_widget; - pipeline = pipe_widget->private; - if (pipeline->use_chain_dma) { u32 host_dma_id; u32 fifo_size; @@ -1884,9 +1886,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * for capture. */ if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ref_params = *fe_params; + ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL); else - ref_params = *pipeline_params; + ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL); + if (!ref_params) + return -ENOMEM; copier_data->gtw_cfg.node_id &= ~SOF_IPC4_NODE_INDEX_MASK; copier_data->gtw_cfg.node_id |= @@ -1902,6 +1906,10 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, struct snd_sof_widget *pipe_widget = swidget->spipe->pipe_widget; struct sof_ipc4_pipeline *pipeline = pipe_widget->private; + dev_dbg(sdev->dev, "Dai copier %s, type %d, ChainDMA: %s\n", + swidget->widget->name, swidget->id, + str_yes_no(pipeline->use_chain_dma)); + if (pipeline->use_chain_dma) return 0; @@ -1919,8 +1927,11 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * In case of capture the ref_params returned will be used to * find the input configuration of the copier. */ - ref_params = *fe_params; - ret = sof_ipc4_prepare_dai_copier(sdev, dai, &ref_params, dir); + ref_params = kmemdup(fe_params, sizeof(*ref_params), GFP_KERNEL); + if (!ref_params) + return -ENOMEM; + + ret = sof_ipc4_prepare_dai_copier(sdev, dai, ref_params, dir); if (ret < 0) return ret; @@ -1929,16 +1940,22 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, * input configuration of the copier. */ if (dir == SNDRV_PCM_STREAM_PLAYBACK) - ref_params = *pipeline_params; + memcpy(ref_params, pipeline_params, sizeof(*ref_params)); break; } case snd_soc_dapm_buffer: { + dev_dbg(sdev->dev, "Module copier %s, type %d\n", + swidget->widget->name, swidget->id); + ipc4_copier = (struct sof_ipc4_copier *)swidget->private; copier_data = &ipc4_copier->data; available_fmt = &ipc4_copier->available_fmt; - ref_params = *pipeline_params; + + ref_params = kmemdup(pipeline_params, sizeof(*ref_params), GFP_KERNEL); + if (!ref_params) + return -ENOMEM; break; } @@ -1951,7 +1968,7 @@ sof_ipc4_prepare_copier_module(struct snd_sof_widget *swidget, /* set input and output audio formats */ input_fmt_index = sof_ipc4_init_input_audio_fmt(sdev, swidget, &copier_data->base_config, - &ref_params, available_fmt); + ref_params, available_fmt); if (input_fmt_index < 0) return input_fmt_index; @@ -3409,9 +3426,6 @@ static int sof_ipc4_dai_get_param(struct snd_sof_dev *sdev, struct snd_sof_dai * static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verify) { - struct snd_sof_pcm *spcm; - int dir, ret; - /* * This function is called during system suspend, we need to make sure * that all streams have been freed up. @@ -3423,21 +3437,8 @@ static int sof_ipc4_tear_down_all_pipelines(struct snd_sof_dev *sdev, bool verif * * This will also make sure that paused streams handled correctly. */ - list_for_each_entry(spcm, &sdev->pcm_list, list) { - for_each_pcm_streams(dir) { - struct snd_pcm_substream *substream = spcm->stream[dir].substream; - - if (!substream || !substream->runtime || spcm->stream[dir].suspend_ignored) - continue; - if (spcm->stream[dir].list) { - ret = sof_pcm_stream_free(sdev, substream, spcm, dir, true); - if (ret < 0) - return ret; - } - } - } - return 0; + return sof_pcm_free_all_streams(sdev); } static int sof_ipc4_link_setup(struct snd_sof_dev *sdev, struct snd_soc_dai_link *link) diff --git a/sound/soc/sof/ipc4.c b/sound/soc/sof/ipc4.c index 4386cbae16d4..37e837b22ac8 100644 --- a/sound/soc/sof/ipc4.c +++ b/sound/soc/sof/ipc4.c @@ -825,8 +825,14 @@ static void sof_ipc4_exit(struct snd_sof_dev *sdev) static int sof_ipc4_post_boot(struct snd_sof_dev *sdev) { - if (sdev->first_boot) + if (sdev->first_boot) { + int ret = sof_ipc4_complete_split_release(sdev); + + if (ret) + return ret; + return sof_ipc4_query_fw_configuration(sdev); + } return sof_ipc4_reload_fw_libraries(sdev); } @@ -845,3 +851,21 @@ const struct sof_ipc_ops ipc4_ops = { .pcm = &ipc4_pcm_ops, .fw_tracing = &ipc4_mtrace_ops, }; + +void sof_ipc4_mic_privacy_state_change(struct snd_sof_dev *sdev, bool state) +{ + struct sof_ipc4_msg msg; + u32 data = state; + + msg.primary = SOF_IPC4_MSG_TARGET(SOF_IPC4_MODULE_MSG); + msg.primary |= SOF_IPC4_MSG_DIR(SOF_IPC4_MSG_REQUEST); + msg.primary |= SOF_IPC4_MOD_ID(SOF_IPC4_MOD_INIT_BASEFW_MOD_ID); + msg.primary |= SOF_IPC4_MOD_INSTANCE(SOF_IPC4_MOD_INIT_BASEFW_INSTANCE_ID); + msg.extension = SOF_IPC4_MOD_EXT_MSG_PARAM_ID(SOF_IPC4_FW_PARAM_MIC_PRIVACY_STATE_CHANGE); + + msg.data_size = sizeof(data); + msg.data_ptr = &data; + + sof_ipc4_set_get_data(sdev, &msg, msg.data_size, true); +} +EXPORT_SYMBOL(sof_ipc4_mic_privacy_state_change); diff --git a/sound/soc/sof/mediatek/mt8186/mt8186.c b/sound/soc/sof/mediatek/mt8186/mt8186.c index 31437fdd4e92..7ff080452cbe 100644 --- a/sound/soc/sof/mediatek/mt8186/mt8186.c +++ b/sound/soc/sof/mediatek/mt8186/mt8186.c @@ -22,7 +22,6 @@ #include <sound/sof/xtensa.h> #include "../../ops.h" #include "../../sof-of-dev.h" -#include "../../sof-audio.h" #include "../adsp_helper.h" #include "../mtk-adsp-common.h" #include "mt8186.h" @@ -38,53 +37,9 @@ static int mt8186_get_window_offset(struct snd_sof_dev *sdev, u32 id) return MBOX_OFFSET; } -static int mt8186_send_msg(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) -{ - struct adsp_priv *priv = sdev->pdata->hw_pdata; - - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - - return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); -} - -static void mt8186_dsp_handle_reply(struct mtk_adsp_ipc *ipc) -{ - struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); - unsigned long flags; - - spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - snd_sof_ipc_process_reply(priv->sdev, 0); - spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); -} - -static void mt8186_dsp_handle_request(struct mtk_adsp_ipc *ipc) -{ - struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); - u32 p; /* panic code */ - int ret; - - /* Read the message from the debug box. */ - sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, - &p, sizeof(p)); - - /* Check to see if the message is a panic code 0x0dead*** */ - if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(priv->sdev, p, true); - } else { - snd_sof_ipc_msgs_rx(priv->sdev); - - /* tell DSP cmd is done */ - ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP); - if (ret) - dev_err(priv->dev, "request send ipc failed"); - } -} - static const struct mtk_adsp_ipc_ops dsp_ops = { - .handle_reply = mt8186_dsp_handle_reply, - .handle_request = mt8186_dsp_handle_request, + .handle_reply = mtk_adsp_handle_reply, + .handle_request = mtk_adsp_handle_request, }; static int platform_parse_resource(struct platform_device *pdev, void *data) @@ -381,54 +336,6 @@ static int mt8186_dsp_resume(struct snd_sof_dev *sdev) return ret; } -/* on mt8186 there is 1 to 1 match between type and BAR idx */ -static int mt8186_get_bar_index(struct snd_sof_dev *sdev, u32 type) -{ - return type; -} - -static int mt8186_pcm_hw_params(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_sof_platform_stream_params *platform_params) -{ - platform_params->cont_update_posn = 1; - - return 0; -} - -static snd_pcm_uframes_t mt8186_pcm_pointer(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream) -{ - int ret; - snd_pcm_uframes_t pos; - struct snd_sof_pcm *spcm; - struct sof_ipc_stream_posn posn; - struct snd_sof_pcm_stream *stream; - struct snd_soc_component *scomp = sdev->component; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - - spcm = snd_sof_find_spcm_dai(scomp, rtd); - if (!spcm) { - dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", - rtd->dai_link->id); - return 0; - } - - stream = &spcm->stream[substream->stream]; - ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); - if (ret < 0) { - dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); - return 0; - } - - memcpy(&stream->posn, &posn, sizeof(posn)); - pos = spcm->stream[substream->stream].posn.host_posn; - pos = bytes_to_frames(substream->runtime, pos); - - return pos; -} - static void mt8186_adsp_dump(struct snd_sof_dev *sdev, u32 flags) { u32 dbg_pc, dbg_data, dbg_inst, dbg_ls0stat, dbg_status, faultinfo; @@ -505,19 +412,19 @@ static const struct snd_sof_dsp_ops sof_mt8186_ops = { .read64 = sof_io_read64, /* ipc */ - .send_msg = mt8186_send_msg, + .send_msg = mtk_adsp_send_msg, .get_mailbox_offset = mt8186_get_mailbox_offset, .get_window_offset = mt8186_get_window_offset, .ipc_msg_data = sof_ipc_msg_data, .set_stream_data_offset = sof_set_stream_data_offset, /* misc */ - .get_bar_index = mt8186_get_bar_index, + .get_bar_index = mtk_adsp_get_bar_index, /* stream callbacks */ .pcm_open = sof_stream_pcm_open, - .pcm_hw_params = mt8186_pcm_hw_params, - .pcm_pointer = mt8186_pcm_pointer, + .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, + .pcm_pointer = mtk_adsp_stream_pcm_pointer, .pcm_close = sof_stream_pcm_close, /* firmware loading */ @@ -660,7 +567,7 @@ static struct platform_driver snd_sof_of_mt8186_driver = { .shutdown = sof_of_shutdown, .driver = { .name = "sof-audio-of-mt8186", - .pm = &sof_of_pm, + .pm = pm_ptr(&sof_of_pm), .of_match_table = sof_of_mt8186_ids, }, }; diff --git a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c index 7cffcad00f9b..2c2c4cd323fc 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195-clk.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195-clk.c @@ -8,6 +8,7 @@ #include <linux/clk.h> #include <linux/io.h> +#include <linux/string_choices.h> #include "mt8195.h" #include "mt8195-clk.h" #include "../adsp_helper.h" @@ -114,7 +115,7 @@ static int adsp_default_clk_init(struct snd_sof_dev *sdev, bool enable) struct adsp_priv *priv = sdev->pdata->hw_pdata; int ret; - dev_dbg(dev, "%s: %s\n", __func__, enable ? "on" : "off"); + dev_dbg(dev, "%s: %s\n", __func__, str_on_off(enable)); if (enable) { ret = clk_set_parent(priv->clk[CLK_TOP_ADSP], diff --git a/sound/soc/sof/mediatek/mt8195/mt8195.c b/sound/soc/sof/mediatek/mt8195/mt8195.c index 371563d7ce79..3b3582d74510 100644 --- a/sound/soc/sof/mediatek/mt8195/mt8195.c +++ b/sound/soc/sof/mediatek/mt8195/mt8195.c @@ -22,7 +22,6 @@ #include <sound/sof/xtensa.h> #include "../../ops.h" #include "../../sof-of-dev.h" -#include "../../sof-audio.h" #include "../adsp_helper.h" #include "../mtk-adsp-common.h" #include "mt8195.h" @@ -38,53 +37,9 @@ static int mt8195_get_window_offset(struct snd_sof_dev *sdev, u32 id) return MBOX_OFFSET; } -static int mt8195_send_msg(struct snd_sof_dev *sdev, - struct snd_sof_ipc_msg *msg) -{ - struct adsp_priv *priv = sdev->pdata->hw_pdata; - - sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, - msg->msg_size); - - return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); -} - -static void mt8195_dsp_handle_reply(struct mtk_adsp_ipc *ipc) -{ - struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); - unsigned long flags; - - spin_lock_irqsave(&priv->sdev->ipc_lock, flags); - snd_sof_ipc_process_reply(priv->sdev, 0); - spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); -} - -static void mt8195_dsp_handle_request(struct mtk_adsp_ipc *ipc) -{ - struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); - u32 p; /* panic code */ - int ret; - - /* Read the message from the debug box. */ - sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, - &p, sizeof(p)); - - /* Check to see if the message is a panic code 0x0dead*** */ - if ((p & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { - snd_sof_dsp_panic(priv->sdev, p, true); - } else { - snd_sof_ipc_msgs_rx(priv->sdev); - - /* tell DSP cmd is done */ - ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP); - if (ret) - dev_err(priv->dev, "request send ipc failed"); - } -} - static const struct mtk_adsp_ipc_ops dsp_ops = { - .handle_reply = mt8195_dsp_handle_reply, - .handle_request = mt8195_dsp_handle_request, + .handle_reply = mtk_adsp_handle_reply, + .handle_request = mtk_adsp_handle_request, }; static int platform_parse_resource(struct platform_device *pdev, void *data) @@ -400,54 +355,6 @@ static int mt8195_dsp_resume(struct snd_sof_dev *sdev) return ret; } -/* on mt8195 there is 1 to 1 match between type and BAR idx */ -static int mt8195_get_bar_index(struct snd_sof_dev *sdev, u32 type) -{ - return type; -} - -static int mt8195_pcm_hw_params(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params, - struct snd_sof_platform_stream_params *platform_params) -{ - platform_params->cont_update_posn = 1; - - return 0; -} - -static snd_pcm_uframes_t mt8195_pcm_pointer(struct snd_sof_dev *sdev, - struct snd_pcm_substream *substream) -{ - int ret; - snd_pcm_uframes_t pos; - struct snd_sof_pcm *spcm; - struct sof_ipc_stream_posn posn; - struct snd_sof_pcm_stream *stream; - struct snd_soc_component *scomp = sdev->component; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); - - spcm = snd_sof_find_spcm_dai(scomp, rtd); - if (!spcm) { - dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", - rtd->dai_link->id); - return 0; - } - - stream = &spcm->stream[substream->stream]; - ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); - if (ret < 0) { - dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); - return 0; - } - - memcpy(&stream->posn, &posn, sizeof(posn)); - pos = spcm->stream[substream->stream].posn.host_posn; - pos = bytes_to_frames(substream->runtime, pos); - - return pos; -} - static void mt8195_adsp_dump(struct snd_sof_dev *sdev, u32 flags) { u32 dbg_pc, dbg_data, dbg_bus0, dbg_bus1, dbg_inst; @@ -529,19 +436,19 @@ static const struct snd_sof_dsp_ops sof_mt8195_ops = { .read64 = sof_io_read64, /* ipc */ - .send_msg = mt8195_send_msg, + .send_msg = mtk_adsp_send_msg, .get_mailbox_offset = mt8195_get_mailbox_offset, .get_window_offset = mt8195_get_window_offset, .ipc_msg_data = sof_ipc_msg_data, .set_stream_data_offset = sof_set_stream_data_offset, /* misc */ - .get_bar_index = mt8195_get_bar_index, + .get_bar_index = mtk_adsp_get_bar_index, /* stream callbacks */ .pcm_open = sof_stream_pcm_open, - .pcm_hw_params = mt8195_pcm_hw_params, - .pcm_pointer = mt8195_pcm_pointer, + .pcm_hw_params = mtk_adsp_stream_pcm_hw_params, + .pcm_pointer = mtk_adsp_stream_pcm_pointer, .pcm_close = sof_stream_pcm_close, /* firmware loading */ @@ -616,7 +523,7 @@ static struct platform_driver snd_sof_of_mt8195_driver = { .shutdown = sof_of_shutdown, .driver = { .name = "sof-audio-of-mt8195", - .pm = &sof_of_pm, + .pm = pm_ptr(&sof_of_pm), .of_match_table = sof_of_mt8195_ids, }, }; diff --git a/sound/soc/sof/mediatek/mtk-adsp-common.c b/sound/soc/sof/mediatek/mtk-adsp-common.c index 20bcf5590eb8..01bbadb160ff 100644 --- a/sound/soc/sof/mediatek/mtk-adsp-common.c +++ b/sound/soc/sof/mediatek/mtk-adsp-common.c @@ -12,8 +12,11 @@ */ #include <linux/module.h> +#include <sound/asound.h> #include <sound/sof/xtensa.h> #include "../ops.h" +#include "../sof-audio.h" +#include "adsp_helper.h" #include "mtk-adsp-common.h" /** @@ -81,5 +84,132 @@ void mtk_adsp_dump(struct snd_sof_dev *sdev, u32 flags) } EXPORT_SYMBOL(mtk_adsp_dump); +/** + * mtk_adsp_send_msg - Send message to Audio DSP + * @sdev: SOF device + * @msg: SOF IPC Message to send + */ +int mtk_adsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg) +{ + struct adsp_priv *priv = sdev->pdata->hw_pdata; + + sof_mailbox_write(sdev, sdev->host_box.offset, msg->msg_data, + msg->msg_size); + + return mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_REQ, MTK_ADSP_IPC_OP_REQ); +} +EXPORT_SYMBOL(mtk_adsp_send_msg); + +/** + * mtk_adsp_handle_reply - Handle reply from the Audio DSP through Mailbox + * @ipc: ADSP IPC handle + */ +void mtk_adsp_handle_reply(struct mtk_adsp_ipc *ipc) +{ + struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); + unsigned long flags; + + spin_lock_irqsave(&priv->sdev->ipc_lock, flags); + snd_sof_ipc_process_reply(priv->sdev, 0); + spin_unlock_irqrestore(&priv->sdev->ipc_lock, flags); +} +EXPORT_SYMBOL(mtk_adsp_handle_reply); + +/** + * mtk_adsp_handle_request - Handle request from the Audio DSP through Mailbox + * @ipc: ADSP IPC handle + */ +void mtk_adsp_handle_request(struct mtk_adsp_ipc *ipc) +{ + struct adsp_priv *priv = mtk_adsp_ipc_get_data(ipc); + u32 panic_code; + int ret; + + /* Read the message from the debug box. */ + sof_mailbox_read(priv->sdev, priv->sdev->debug_box.offset + 4, + &panic_code, sizeof(panic_code)); + + /* Check to see if the message is a panic code 0x0dead*** */ + if ((panic_code & SOF_IPC_PANIC_MAGIC_MASK) == SOF_IPC_PANIC_MAGIC) { + snd_sof_dsp_panic(priv->sdev, panic_code, true); + } else { + snd_sof_ipc_msgs_rx(priv->sdev); + + /* Tell DSP cmd is done */ + ret = mtk_adsp_ipc_send(priv->dsp_ipc, MTK_ADSP_IPC_RSP, MTK_ADSP_IPC_OP_RSP); + if (ret) + dev_err(priv->dev, "request send ipc failed"); + } +} +EXPORT_SYMBOL(mtk_adsp_handle_request); + +/** + * mtk_adsp_get_bar_index - Map section type with BAR idx + * @sdev: SOF device + * @type: Section type as described by snd_sof_fw_blk_type + * + * MediaTek Audio DSPs have a 1:1 match between type and BAR idx + */ +int mtk_adsp_get_bar_index(struct snd_sof_dev *sdev, u32 type) +{ + return type; +} +EXPORT_SYMBOL(mtk_adsp_get_bar_index); + +/** + * mtk_adsp_stream_pcm_hw_params - Platform specific host stream hw params + * @sdev: SOF device + * @substream: PCM Substream + * @params: hw params + * @platform_params: Platform specific SOF stream parameters + */ +int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params) +{ + platform_params->cont_update_posn = 1; + return 0; +} +EXPORT_SYMBOL(mtk_adsp_stream_pcm_hw_params); + +/** + * mtk_adsp_stream_pcm_pointer - Get host stream pointer + * @sdev: SOF device + * @substream: PCM substream + */ +snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct snd_soc_component *scomp = sdev->component; + struct snd_sof_pcm_stream *stream; + struct sof_ipc_stream_posn posn; + struct snd_sof_pcm *spcm; + snd_pcm_uframes_t pos; + int ret; + + spcm = snd_sof_find_spcm_dai(scomp, rtd); + if (!spcm) { + dev_warn_ratelimited(sdev->dev, "warn: can't find PCM with DAI ID %d\n", + rtd->dai_link->id); + return 0; + } + + stream = &spcm->stream[substream->stream]; + ret = snd_sof_ipc_msg_data(sdev, stream, &posn, sizeof(posn)); + if (ret < 0) { + dev_warn(sdev->dev, "failed to read stream position: %d\n", ret); + return 0; + } + + memcpy(&stream->posn, &posn, sizeof(posn)); + pos = spcm->stream[substream->stream].posn.host_posn; + pos = bytes_to_frames(substream->runtime, pos); + + return pos; +} +EXPORT_SYMBOL(mtk_adsp_stream_pcm_pointer); + MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("SOF helpers for MTK ADSP platforms"); diff --git a/sound/soc/sof/mediatek/mtk-adsp-common.h b/sound/soc/sof/mediatek/mtk-adsp-common.h index 612cff1f38f7..dc36b91d6779 100644 --- a/sound/soc/sof/mediatek/mtk-adsp-common.h +++ b/sound/soc/sof/mediatek/mtk-adsp-common.h @@ -7,4 +7,14 @@ #define MTK_ADSP_STACK_DUMP_SIZE 32 void mtk_adsp_dump(struct snd_sof_dev *sdev, u32 flags); +int mtk_adsp_send_msg(struct snd_sof_dev *sdev, struct snd_sof_ipc_msg *msg); +void mtk_adsp_handle_reply(struct mtk_adsp_ipc *ipc); +void mtk_adsp_handle_request(struct mtk_adsp_ipc *ipc); +int mtk_adsp_get_bar_index(struct snd_sof_dev *sdev, u32 type); +int mtk_adsp_stream_pcm_hw_params(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_sof_platform_stream_params *platform_params); +snd_pcm_uframes_t mtk_adsp_stream_pcm_pointer(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream); #endif diff --git a/sound/soc/sof/pcm.c b/sound/soc/sof/pcm.c index c5c6353f18ce..d584a72e6f52 100644 --- a/sound/soc/sof/pcm.c +++ b/sound/soc/sof/pcm.c @@ -99,8 +99,8 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run ret = snd_soc_dapm_dai_get_connected_widgets(dai, dir, &list, dpcm_end_walk_at_be); if (ret < 0) { - dev_err(sdev->dev, "error: dai %s has no valid %s path\n", dai->name, - snd_pcm_direction_name(dir)); + spcm_err(spcm, dir, "dai %s has no valid %s path\n", + dai->name, snd_pcm_direction_name(dir)); return ret; } @@ -108,8 +108,7 @@ sof_pcm_setup_connected_widgets(struct snd_sof_dev *sdev, struct snd_soc_pcm_run ret = sof_widget_list_setup(sdev, spcm, params, platform_params, dir); if (ret < 0) { - dev_err(sdev->dev, "error: failed widget list set up for pcm %d dir %d\n", - spcm->pcm.pcm_id, dir); + spcm_err(spcm, dir, "Widget list set up failed\n"); spcm->stream[dir].list = NULL; snd_soc_dapm_dai_free_widgets(&list); return ret; @@ -139,6 +138,8 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, if (!spcm) return -EINVAL; + spcm_dbg(spcm, substream->stream, "Entry: hw_params\n"); + /* * Handle repeated calls to hw_params() without free_pcm() in * between. At least ALSA OSS emulation depends on this. @@ -151,12 +152,9 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, spcm->prepared[substream->stream] = false; } - dev_dbg(component->dev, "pcm: hw params stream %d dir %d\n", - spcm->pcm.pcm_id, substream->stream); - ret = snd_sof_pcm_platform_hw_params(sdev, substream, params, &platform_params); if (ret < 0) { - dev_err(component->dev, "platform hw params failed\n"); + spcm_err(spcm, substream->stream, "platform hw params failed\n"); return ret; } @@ -191,6 +189,84 @@ static int sof_pcm_hw_params(struct snd_soc_component *component, return 0; } +static int sof_pcm_stream_free(struct snd_sof_dev *sdev, + struct snd_pcm_substream *substream, + struct snd_sof_pcm *spcm, int dir, + bool free_widget_list) +{ + const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); + int ret; + int err = 0; + + if (spcm->prepared[substream->stream]) { + /* stop DMA first if needed */ + if (pcm_ops && pcm_ops->platform_stop_during_hw_free) + snd_sof_pcm_platform_trigger(sdev, substream, + SNDRV_PCM_TRIGGER_STOP); + + /* free PCM in the DSP */ + if (pcm_ops && pcm_ops->hw_free) { + ret = pcm_ops->hw_free(sdev->component, substream); + if (ret < 0) { + spcm_err(spcm, substream->stream, + "pcm_ops->hw_free failed %d\n", ret); + err = ret; + } + } + + spcm->prepared[substream->stream] = false; + spcm->pending_stop[substream->stream] = false; + } + + /* reset the DMA */ + ret = snd_sof_pcm_platform_hw_free(sdev, substream); + if (ret < 0) { + spcm_err(spcm, substream->stream, + "platform hw free failed %d\n", ret); + if (!err) + err = ret; + } + + /* free widget list */ + if (free_widget_list) { + ret = sof_widget_list_free(sdev, spcm, dir); + if (ret < 0) { + spcm_err(spcm, substream->stream, + "sof_widget_list_free failed %d\n", ret); + if (!err) + err = ret; + } + } + + return err; +} + +int sof_pcm_free_all_streams(struct snd_sof_dev *sdev) +{ + struct snd_pcm_substream *substream; + struct snd_sof_pcm *spcm; + int dir, ret; + + list_for_each_entry(spcm, &sdev->pcm_list, list) { + for_each_pcm_streams(dir) { + substream = spcm->stream[dir].substream; + + if (!substream || !substream->runtime || + spcm->stream[dir].suspend_ignored) + continue; + + if (spcm->stream[dir].list) { + ret = sof_pcm_stream_free(sdev, substream, spcm, + dir, true); + if (ret < 0) + return ret; + } + } + } + + return 0; +} + static int sof_pcm_hw_free(struct snd_soc_component *component, struct snd_pcm_substream *substream) { @@ -207,8 +283,7 @@ static int sof_pcm_hw_free(struct snd_soc_component *component, if (!spcm) return -EINVAL; - dev_dbg(component->dev, "pcm: free stream %d dir %d\n", - spcm->pcm.pcm_id, substream->stream); + spcm_dbg(spcm, substream->stream, "Entry: hw_free\n"); ret = sof_pcm_stream_free(sdev, substream, spcm, substream->stream, true); @@ -233,6 +308,8 @@ static int sof_pcm_prepare(struct snd_soc_component *component, if (!spcm) return -EINVAL; + spcm_dbg(spcm, substream->stream, "Entry: prepare\n"); + if (spcm->prepared[substream->stream]) { if (!spcm->pending_stop[substream->stream]) return 0; @@ -246,15 +323,12 @@ static int sof_pcm_prepare(struct snd_soc_component *component, return ret; } - dev_dbg(component->dev, "pcm: prepare stream %d dir %d\n", - spcm->pcm.pcm_id, substream->stream); - /* set hw_params */ ret = sof_pcm_hw_params(component, substream, &spcm->params[substream->stream]); if (ret < 0) { - dev_err(component->dev, - "error: set pcm hw_params after resume\n"); + spcm_err(spcm, substream->stream, + "failed to set hw_params after resume\n"); return ret; } @@ -284,8 +358,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, if (!spcm) return -EINVAL; - dev_dbg(component->dev, "pcm: trigger stream %d dir %d cmd %d\n", - spcm->pcm.pcm_id, substream->stream, cmd); + spcm_dbg(spcm, substream->stream, "Entry: trigger (cmd: %d)\n", cmd); spcm->pending_stop[substream->stream] = false; @@ -334,7 +407,7 @@ static int sof_pcm_trigger(struct snd_soc_component *component, reset_hw_params = true; break; default: - dev_err(component->dev, "Unhandled trigger cmd %d\n", cmd); + spcm_err(spcm, substream->stream, "Unhandled trigger cmd %d\n", cmd); return -EINVAL; } @@ -436,9 +509,7 @@ static int sof_pcm_open(struct snd_soc_component *component, if (!spcm) return -EINVAL; - dev_dbg(component->dev, "pcm: open stream %d dir %d\n", - spcm->pcm.pcm_id, substream->stream); - + spcm_dbg(spcm, substream->stream, "Entry: open\n"); caps = &spcm->pcm.caps[substream->stream]; @@ -458,15 +529,6 @@ static int sof_pcm_open(struct snd_soc_component *component, */ runtime->hw.buffer_bytes_max = le32_to_cpu(caps->buffer_size_max); - dev_dbg(component->dev, "period min %zd max %zd bytes\n", - runtime->hw.period_bytes_min, - runtime->hw.period_bytes_max); - dev_dbg(component->dev, "period count %d max %d\n", - runtime->hw.periods_min, - runtime->hw.periods_max); - dev_dbg(component->dev, "buffer max %zd bytes\n", - runtime->hw.buffer_bytes_max); - /* set wait time - TODO: come from topology */ substream->wait_time = 500; @@ -476,10 +538,19 @@ static int sof_pcm_open(struct snd_soc_component *component, spcm->prepared[substream->stream] = false; ret = snd_sof_pcm_platform_open(sdev, substream); - if (ret < 0) - dev_err(component->dev, "error: pcm open failed %d\n", ret); + if (ret < 0) { + spcm_err(spcm, substream->stream, + "platform pcm open failed %d\n", ret); + return ret; + } - return ret; + spcm_dbg(spcm, substream->stream, "period bytes min %zd, max %zd\n", + runtime->hw.period_bytes_min, runtime->hw.period_bytes_max); + spcm_dbg(spcm, substream->stream, "period count min %d, max %d\n", + runtime->hw.periods_min, runtime->hw.periods_max); + spcm_dbg(spcm, substream->stream, "buffer bytes max %zd\n", runtime->hw.buffer_bytes_max); + + return 0; } static int sof_pcm_close(struct snd_soc_component *component, @@ -498,13 +569,12 @@ static int sof_pcm_close(struct snd_soc_component *component, if (!spcm) return -EINVAL; - dev_dbg(component->dev, "pcm: close stream %d dir %d\n", - spcm->pcm.pcm_id, substream->stream); + spcm_dbg(spcm, substream->stream, "Entry: close\n"); err = snd_sof_pcm_platform_close(sdev, substream); if (err < 0) { - dev_err(component->dev, "error: pcm close failed %d\n", - err); + spcm_err(spcm, substream->stream, + "platform pcm close failed %d\n", err); /* * keep going, no point in preventing the close * from happening @@ -538,7 +608,8 @@ static int sof_pcm_new(struct snd_soc_component *component, return 0; } - dev_dbg(component->dev, "creating new PCM %s\n", spcm->pcm.pcm_name); + dev_dbg(spcm->scomp->dev, "pcm%u (%s): Entry: pcm_construct\n", + spcm->pcm.pcm_id, spcm->pcm.pcm_name); /* do we need to pre-allocate playback audio buffer pages */ if (!spcm->pcm.playback) @@ -546,16 +617,15 @@ static int sof_pcm_new(struct snd_soc_component *component, caps = &spcm->pcm.caps[stream]; - /* pre-allocate playback audio buffer pages */ - dev_dbg(component->dev, - "spcm: allocate %s playback DMA buffer size 0x%x max 0x%x\n", - caps->name, caps->buffer_size_min, caps->buffer_size_max); - if (!pcm->streams[stream].substream) { - dev_err(component->dev, "error: NULL playback substream!\n"); + spcm_err(spcm, stream, "NULL playback substream!\n"); return -EINVAL; } + /* pre-allocate playback audio buffer pages */ + spcm_dbg(spcm, stream, "allocate %s playback DMA buffer size 0x%x max 0x%x\n", + caps->name, caps->buffer_size_min, caps->buffer_size_max); + snd_pcm_set_managed_buffer(pcm->streams[stream].substream, SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 0, le32_to_cpu(caps->buffer_size_max)); @@ -568,16 +638,15 @@ capture: caps = &spcm->pcm.caps[stream]; - /* pre-allocate capture audio buffer pages */ - dev_dbg(component->dev, - "spcm: allocate %s capture DMA buffer size 0x%x max 0x%x\n", - caps->name, caps->buffer_size_min, caps->buffer_size_max); - if (!pcm->streams[stream].substream) { - dev_err(component->dev, "error: NULL capture substream!\n"); + spcm_err(spcm, stream, "NULL capture substream!\n"); return -EINVAL; } + /* pre-allocate capture audio buffer pages */ + spcm_dbg(spcm, stream, "allocate %s capture DMA buffer size 0x%x max 0x%x\n", + caps->name, caps->buffer_size_min, caps->buffer_size_max); + snd_pcm_set_managed_buffer(pcm->streams[stream].substream, SNDRV_DMA_TYPE_DEV_SG, sdev->dev, 0, le32_to_cpu(caps->buffer_size_max)); diff --git a/sound/soc/sof/sof-acpi-dev.c b/sound/soc/sof/sof-acpi-dev.c index 58fd5f7c7905..68bf1b57093e 100644 --- a/sound/soc/sof/sof-acpi-dev.c +++ b/sound/soc/sof/sof-acpi-dev.c @@ -36,12 +36,11 @@ MODULE_PARM_DESC(sof_acpi_debug, "SOF ACPI debug options (0x0 all off)"); #define SOF_ACPI_DISABLE_PM_RUNTIME BIT(0) -const struct dev_pm_ops sof_acpi_pm = { - SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) - SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, - snd_sof_runtime_idle) +EXPORT_NS_DEV_PM_OPS(sof_acpi_pm, SND_SOC_SOF_ACPI_DEV) = { + SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + snd_sof_runtime_idle) }; -EXPORT_SYMBOL_NS(sof_acpi_pm, "SND_SOC_SOF_ACPI_DEV"); static void sof_acpi_probe_complete(struct device *dev) { diff --git a/sound/soc/sof/sof-audio.c b/sound/soc/sof/sof-audio.c index 9a52781bf8d8..a9664b4cf43f 100644 --- a/sound/soc/sof/sof-audio.c +++ b/sound/soc/sof/sof-audio.c @@ -829,55 +829,6 @@ bool snd_sof_stream_suspend_ignored(struct snd_sof_dev *sdev) return false; } -int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, - struct snd_sof_pcm *spcm, int dir, bool free_widget_list) -{ - const struct sof_ipc_pcm_ops *pcm_ops = sof_ipc_get_ops(sdev, pcm); - int ret; - int err = 0; - - if (spcm->prepared[substream->stream]) { - /* stop DMA first if needed */ - if (pcm_ops && pcm_ops->platform_stop_during_hw_free) - snd_sof_pcm_platform_trigger(sdev, substream, SNDRV_PCM_TRIGGER_STOP); - - /* free PCM in the DSP */ - if (pcm_ops && pcm_ops->hw_free) { - ret = pcm_ops->hw_free(sdev->component, substream); - if (ret < 0) { - dev_err(sdev->dev, "%s: pcm_ops hw_free failed %d\n", - __func__, ret); - err = ret; - } - } - - spcm->prepared[substream->stream] = false; - spcm->pending_stop[substream->stream] = false; - } - - /* reset the DMA */ - ret = snd_sof_pcm_platform_hw_free(sdev, substream); - if (ret < 0) { - dev_err(sdev->dev, "%s: platform hw free failed %d\n", - __func__, ret); - if (!err) - err = ret; - } - - /* free widget list */ - if (free_widget_list) { - ret = sof_widget_list_free(sdev, spcm, dir); - if (ret < 0) { - dev_err(sdev->dev, "%s: sof_widget_list_free failed %d\n", - __func__, ret); - if (!err) - err = ret; - } - } - - return err; -} - /* * Generic object lookup APIs. */ diff --git a/sound/soc/sof/sof-audio.h b/sound/soc/sof/sof-audio.h index 62f3c11a9216..36ab75e11779 100644 --- a/sound/soc/sof/sof-audio.h +++ b/sound/soc/sof/sof-audio.h @@ -617,6 +617,20 @@ struct snd_sof_pcm *snd_sof_find_spcm_comp(struct snd_soc_component *scomp, void snd_sof_pcm_period_elapsed(struct snd_pcm_substream *substream); void snd_sof_pcm_init_elapsed_work(struct work_struct *work); +/* + * snd_sof_pcm specific wrappers for dev_dbg() and dev_err() to provide + * consistent and useful prints. + */ +#define spcm_dbg(__spcm, __dir, __fmt, ...) \ + dev_dbg((__spcm)->scomp->dev, "pcm%u (%s), dir %d: " __fmt, \ + (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \ + ##__VA_ARGS__) + +#define spcm_err(__spcm, __dir, __fmt, ...) \ + dev_err((__spcm)->scomp->dev, "%s: pcm%u (%s), dir %d: " __fmt, \ + __func__, (__spcm)->pcm.pcm_id, (__spcm)->pcm.pcm_name, __dir, \ + ##__VA_ARGS__) + #if IS_ENABLED(CONFIG_SND_SOC_SOF_COMPRESS) void snd_sof_compr_fragment_elapsed(struct snd_compr_stream *cstream); void snd_sof_compr_init_elapsed_work(struct work_struct *work); @@ -649,8 +663,7 @@ int sof_widget_list_setup(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int sof_widget_list_free(struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm, int dir); int sof_pcm_dsp_pcm_free(struct snd_pcm_substream *substream, struct snd_sof_dev *sdev, struct snd_sof_pcm *spcm); -int sof_pcm_stream_free(struct snd_sof_dev *sdev, struct snd_pcm_substream *substream, - struct snd_sof_pcm *spcm, int dir, bool free_widget_list); +int sof_pcm_free_all_streams(struct snd_sof_dev *sdev); int get_token_u32(void *elem, void *object, u32 offset); int get_token_u16(void *elem, void *object, u32 offset); int get_token_comp_format(void *elem, void *object, u32 offset); diff --git a/sound/soc/sof/sof-of-dev.c b/sound/soc/sof/sof-of-dev.c index fb8c8a14d885..3ccfcfb142b7 100644 --- a/sound/soc/sof/sof-of-dev.c +++ b/sound/soc/sof/sof-of-dev.c @@ -30,14 +30,12 @@ static char *tplg_filename; module_param(tplg_filename, charp, 0444); MODULE_PARM_DESC(tplg_filename, "deprecated - moved to snd-sof module."); -const struct dev_pm_ops sof_of_pm = { +EXPORT_DEV_PM_OPS(sof_of_pm) = { .prepare = snd_sof_prepare, .complete = snd_sof_complete, - SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) - SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, - NULL) + SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, NULL) }; -EXPORT_SYMBOL(sof_of_pm); static void sof_of_probe_complete(struct device *dev) { diff --git a/sound/soc/sof/sof-pci-dev.c b/sound/soc/sof/sof-pci-dev.c index 103377e2caaf..2fc14b9a33d4 100644 --- a/sound/soc/sof/sof-pci-dev.c +++ b/sound/soc/sof/sof-pci-dev.c @@ -155,14 +155,13 @@ static const struct dmi_system_id community_key_platforms[] = { {}, }; -const struct dev_pm_ops sof_pci_pm = { +EXPORT_NS_DEV_PM_OPS(sof_pci_pm, SND_SOC_SOF_PCI_DEV) = { .prepare = snd_sof_prepare, .complete = snd_sof_complete, - SET_SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) - SET_RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, - snd_sof_runtime_idle) + SYSTEM_SLEEP_PM_OPS(snd_sof_suspend, snd_sof_resume) + RUNTIME_PM_OPS(snd_sof_runtime_suspend, snd_sof_runtime_resume, + snd_sof_runtime_idle) }; -EXPORT_SYMBOL_NS(sof_pci_pm, "SND_SOC_SOF_PCI_DEV"); static void sof_pci_probe_complete(struct device *dev) { diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 688cc7ac1714..dc9cb8324067 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1273,8 +1273,8 @@ static int sof_widget_parse_tokens(struct snd_soc_component *scomp, struct snd_s struct snd_sof_tuple *new_tuples; num_tuples += token_list[object_token_list[i]].count * (num_sets - 1); - new_tuples = krealloc(swidget->tuples, - sizeof(*new_tuples) * num_tuples, GFP_KERNEL); + new_tuples = krealloc_array(swidget->tuples, + num_tuples, sizeof(*new_tuples), GFP_KERNEL); if (!new_tuples) { ret = -ENOMEM; goto err; diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c index 19dc61008a75..6037b7a9c97b 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c @@ -1352,7 +1352,6 @@ error: MODULE_DEVICE_TABLE(of, stm32_i2s_ids); -#ifdef CONFIG_PM_SLEEP static int stm32_i2s_suspend(struct device *dev) { struct stm32_i2s_data *i2s = dev_get_drvdata(dev); @@ -1370,17 +1369,16 @@ static int stm32_i2s_resume(struct device *dev) regcache_cache_only(i2s->regmap, false); return regcache_sync(i2s->regmap); } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops stm32_i2s_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_i2s_suspend, stm32_i2s_resume) + SYSTEM_SLEEP_PM_OPS(stm32_i2s_suspend, stm32_i2s_resume) }; static struct platform_driver stm32_i2s_driver = { .driver = { .name = "st,stm32-i2s", .of_match_table = stm32_i2s_ids, - .pm = &stm32_i2s_pm_ops, + .pm = pm_ptr(&stm32_i2s_pm_ops), }, .probe = stm32_i2s_probe, .remove = stm32_i2s_remove, diff --git a/sound/soc/stm/stm32_sai.c b/sound/soc/stm/stm32_sai.c index bc8180fc8462..504a14584765 100644 --- a/sound/soc/stm/stm32_sai.c +++ b/sound/soc/stm/stm32_sai.c @@ -270,7 +270,6 @@ static int stm32_sai_probe(struct platform_device *pdev) return devm_of_platform_populate(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP /* * When pins are shared by two sai sub instances, pins have to be defined * in sai parent node. In this case, pins state is not managed by alsa fw. @@ -305,10 +304,9 @@ static int stm32_sai_resume(struct device *dev) return pinctrl_pm_select_default_state(dev); } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops stm32_sai_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume) + SYSTEM_SLEEP_PM_OPS(stm32_sai_suspend, stm32_sai_resume) }; MODULE_DEVICE_TABLE(of, stm32_sai_ids); @@ -317,7 +315,7 @@ static struct platform_driver stm32_sai_driver = { .driver = { .name = "st,stm32-sai", .of_match_table = stm32_sai_ids, - .pm = &stm32_sai_pm_ops, + .pm = pm_ptr(&stm32_sai_pm_ops), }, .probe = stm32_sai_probe, }; diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c index 3efbf4aaf965..e8c1abf1ae0a 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1704,7 +1704,6 @@ static void stm32_sai_sub_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -#ifdef CONFIG_PM_SLEEP static int stm32_sai_sub_suspend(struct device *dev) { struct stm32_sai_sub_data *sai = dev_get_drvdata(dev); @@ -1738,17 +1737,16 @@ static int stm32_sai_sub_resume(struct device *dev) return ret; } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops stm32_sai_sub_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume) + SYSTEM_SLEEP_PM_OPS(stm32_sai_sub_suspend, stm32_sai_sub_resume) }; static struct platform_driver stm32_sai_sub_driver = { .driver = { .name = "st,stm32-sai-sub", .of_match_table = stm32_sai_sub_ids, - .pm = &stm32_sai_sub_pm_ops, + .pm = pm_ptr(&stm32_sai_sub_pm_ops), }, .probe = stm32_sai_sub_probe, .remove = stm32_sai_sub_remove, diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c index 9e30852de93c..57b711c44278 100644 --- a/sound/soc/stm/stm32_spdifrx.c +++ b/sound/soc/stm/stm32_spdifrx.c @@ -1040,7 +1040,6 @@ error: MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); -#ifdef CONFIG_PM_SLEEP static int stm32_spdifrx_suspend(struct device *dev) { struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); @@ -1059,17 +1058,16 @@ static int stm32_spdifrx_resume(struct device *dev) return regcache_sync(spdifrx->regmap); } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops stm32_spdifrx_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume) + SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume) }; static struct platform_driver stm32_spdifrx_driver = { .driver = { .name = "st,stm32-spdifrx", .of_match_table = stm32_spdifrx_ids, - .pm = &stm32_spdifrx_pm_ops, + .pm = pm_ptr(&stm32_spdifrx_pm_ops), }, .probe = stm32_spdifrx_probe, .remove = stm32_spdifrx_remove, diff --git a/sound/soc/sunxi/sun4i-codec.c b/sound/soc/sunxi/sun4i-codec.c index 886b3fa537d2..93733ff2e32a 100644 --- a/sound/soc/sunxi/sun4i-codec.c +++ b/sound/soc/sunxi/sun4i-codec.c @@ -22,6 +22,7 @@ #include <linux/gpio/consumer.h> #include <sound/core.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -331,6 +332,7 @@ struct sun4i_codec { struct clk *clk_module; struct reset_control *rst; struct gpio_desc *gpio_pa; + struct gpio_desc *gpio_hp; /* ADC_FIFOC register is at different offset on different SoCs */ struct regmap_field *reg_adc_fifoc; @@ -1583,6 +1585,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = { .ops = &dummy_dai_ops, }; +static struct snd_soc_jack sun4i_headphone_jack; + +static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = { + { .pin = "Headphone", .mask = SND_JACK_HEADPHONE }, +}; + +static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = { + .name = "hp-det", + .report = SND_JACK_HEADPHONE, + .debounce_time = 150, +}; + +static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_card *card = rtd->card; + struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card); + int ret; + + if (scodec->gpio_hp) { + ret = snd_soc_card_jack_new_pins(card, "Headphone Jack", + SND_JACK_HEADPHONE, + &sun4i_headphone_jack, + sun4i_headphone_jack_pins, + ARRAY_SIZE(sun4i_headphone_jack_pins)); + if (ret) { + dev_err(rtd->dev, + "Headphone jack creation failed: %d\n", ret); + return ret; + } + + sun4i_headphone_jack_gpio.desc = scodec->gpio_hp; + ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1, + &sun4i_headphone_jack_gpio); + + if (ret) { + dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret); + return ret; + } + } + + return 0; +} + static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, int *num_links) { @@ -1608,6 +1653,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev, link->codecs->name = dev_name(dev); link->platforms->name = dev_name(dev); link->dai_fmt = SND_SOC_DAIFMT_I2S; + link->init = sun4i_codec_machine_init; *num_links = 1; @@ -1916,10 +1962,11 @@ static const struct snd_soc_component_driver sun50i_h616_codec_codec = { }; static const struct snd_kcontrol_new sun50i_h616_card_controls[] = { - SOC_DAPM_PIN_SWITCH("LINEOUT"), + SOC_DAPM_PIN_SWITCH("Speaker"), }; static const struct snd_soc_dapm_widget sun50i_h616_codec_card_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), SND_SOC_DAPM_LINE("Line Out", NULL), SND_SOC_DAPM_SPK("Speaker", sun4i_codec_spk_event), }; @@ -1966,6 +2013,7 @@ static struct snd_soc_card *sun50i_h616_codec_create_card(struct device *dev) card->dev = dev; card->owner = THIS_MODULE; card->name = "H616 Audio Codec"; + card->long_name = "h616-audio-codec"; card->driver_name = "sun4i-codec"; card->controls = sun50i_h616_card_controls; card->num_controls = ARRAY_SIZE(sun50i_h616_card_controls); @@ -2301,6 +2349,13 @@ static int sun4i_codec_probe(struct platform_device *pdev) return ret; } + scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN); + if (IS_ERR(scodec->gpio_hp)) { + ret = PTR_ERR(scodec->gpio_hp); + dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n"); + return ret; + } + /* reg_field setup */ scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev, scodec->regmap, diff --git a/sound/soc/sunxi/sun4i-spdif.c b/sound/soc/sunxi/sun4i-spdif.c index 41caf1795d09..34e5bd94e9af 100644 --- a/sound/soc/sunxi/sun4i-spdif.c +++ b/sound/soc/sunxi/sun4i-spdif.c @@ -727,15 +727,15 @@ static void sun4i_spdif_remove(struct platform_device *pdev) } static const struct dev_pm_ops sun4i_spdif_pm = { - SET_RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend, - sun4i_spdif_runtime_resume, NULL) + RUNTIME_PM_OPS(sun4i_spdif_runtime_suspend, + sun4i_spdif_runtime_resume, NULL) }; static struct platform_driver sun4i_spdif_driver = { .driver = { .name = "sun4i-spdif", .of_match_table = sun4i_spdif_of_match, - .pm = &sun4i_spdif_pm, + .pm = pm_ptr(&sun4i_spdif_pm), }, .probe = sun4i_spdif_probe, .remove = sun4i_spdif_remove, diff --git a/sound/soc/sunxi/sun50i-dmic.c b/sound/soc/sunxi/sun50i-dmic.c index 3e751b5694fe..bab1e29c9988 100644 --- a/sound/soc/sunxi/sun50i-dmic.c +++ b/sound/soc/sunxi/sun50i-dmic.c @@ -415,15 +415,15 @@ static void sun50i_dmic_remove(struct platform_device *pdev) } static const struct dev_pm_ops sun50i_dmic_pm = { - SET_RUNTIME_PM_OPS(sun50i_dmic_runtime_suspend, - sun50i_dmic_runtime_resume, NULL) + RUNTIME_PM_OPS(sun50i_dmic_runtime_suspend, + sun50i_dmic_runtime_resume, NULL) }; static struct platform_driver sun50i_dmic_driver = { .driver = { .name = "sun50i-dmic", .of_match_table = sun50i_dmic_of_match, - .pm = &sun50i_dmic_pm, + .pm = pm_ptr(&sun50i_dmic_pm), }, .probe = sun50i_dmic_probe, .remove = sun50i_dmic_remove, diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c index 8c645e04d571..8b9eb1a202f7 100644 --- a/sound/soc/sunxi/sun8i-codec.c +++ b/sound/soc/sunxi/sun8i-codec.c @@ -1702,15 +1702,15 @@ static const struct of_device_id sun8i_codec_of_match[] = { MODULE_DEVICE_TABLE(of, sun8i_codec_of_match); static const struct dev_pm_ops sun8i_codec_pm_ops = { - SET_RUNTIME_PM_OPS(sun8i_codec_runtime_suspend, - sun8i_codec_runtime_resume, NULL) + RUNTIME_PM_OPS(sun8i_codec_runtime_suspend, + sun8i_codec_runtime_resume, NULL) }; static struct platform_driver sun8i_codec_driver = { .driver = { .name = "sun8i-codec", .of_match_table = sun8i_codec_of_match, - .pm = &sun8i_codec_pm_ops, + .pm = pm_ptr(&sun8i_codec_pm_ops), }, .probe = sun8i_codec_probe, .remove = sun8i_codec_remove, diff --git a/sound/soc/tegra/Makefile b/sound/soc/tegra/Makefile index cea4b0d54378..defea7f53f11 100644 --- a/sound/soc/tegra/Makefile +++ b/sound/soc/tegra/Makefile @@ -13,7 +13,7 @@ snd-soc-tegra210-dmic-y := tegra210_dmic.o snd-soc-tegra210-i2s-y := tegra210_i2s.o snd-soc-tegra186-asrc-y := tegra186_asrc.o snd-soc-tegra186-dspk-y := tegra186_dspk.o -snd-soc-tegra210-admaif-y := tegra210_admaif.o +snd-soc-tegra210-admaif-y := tegra210_admaif.o tegra_isomgr_bw.o snd-soc-tegra210-mvc-y := tegra210_mvc.o snd-soc-tegra210-sfc-y := tegra210_sfc.o snd-soc-tegra210-amx-y := tegra210_amx.o diff --git a/sound/soc/tegra/tegra186_asrc.c b/sound/soc/tegra/tegra186_asrc.c index d914dba56013..5c67e1f01d9b 100644 --- a/sound/soc/tegra/tegra186_asrc.c +++ b/sound/soc/tegra/tegra186_asrc.c @@ -76,7 +76,7 @@ static void tegra186_asrc_lock_stream(struct tegra186_asrc *asrc, 1); } -static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev) +static int tegra186_asrc_runtime_suspend(struct device *dev) { struct tegra186_asrc *asrc = dev_get_drvdata(dev); @@ -86,7 +86,7 @@ static int __maybe_unused tegra186_asrc_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra186_asrc_runtime_resume(struct device *dev) +static int tegra186_asrc_runtime_resume(struct device *dev) { struct tegra186_asrc *asrc = dev_get_drvdata(dev); int id; @@ -1021,17 +1021,16 @@ static void tegra186_asrc_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra186_asrc_pm_ops = { - SET_RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend, - tegra186_asrc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra186_asrc_runtime_suspend, + tegra186_asrc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra186_asrc_driver = { .driver = { .name = "tegra186-asrc", .of_match_table = tegra186_asrc_of_match, - .pm = &tegra186_asrc_pm_ops, + .pm = pm_ptr(&tegra186_asrc_pm_ops), }, .probe = tegra186_asrc_platform_probe, .remove = tegra186_asrc_platform_remove, diff --git a/sound/soc/tegra/tegra186_dspk.c b/sound/soc/tegra/tegra186_dspk.c index 1be6c09cbe1a..21fdab2a1977 100644 --- a/sound/soc/tegra/tegra186_dspk.c +++ b/sound/soc/tegra/tegra186_dspk.c @@ -181,7 +181,7 @@ static int tegra186_dspk_put_stereo_to_mono(struct snd_kcontrol *kcontrol, return 1; } -static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev) +static int tegra186_dspk_runtime_suspend(struct device *dev) { struct tegra186_dspk *dspk = dev_get_drvdata(dev); @@ -193,7 +193,7 @@ static int __maybe_unused tegra186_dspk_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra186_dspk_runtime_resume(struct device *dev) +static int tegra186_dspk_runtime_resume(struct device *dev) { struct tegra186_dspk *dspk = dev_get_drvdata(dev); int err; @@ -532,17 +532,16 @@ static void tegra186_dspk_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra186_dspk_pm_ops = { - SET_RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend, - tegra186_dspk_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra186_dspk_runtime_suspend, + tegra186_dspk_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra186_dspk_driver = { .driver = { .name = "tegra186-dspk", .of_match_table = tegra186_dspk_of_match, - .pm = &tegra186_dspk_pm_ops, + .pm = pm_ptr(&tegra186_dspk_pm_ops), }, .probe = tegra186_dspk_platform_probe, .remove = tegra186_dspk_platform_remove, diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 3b9823d1a87a..51df0835ce3e 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -34,7 +34,7 @@ #define DRV_NAME "tegra20-i2s" -static __maybe_unused int tegra20_i2s_runtime_suspend(struct device *dev) +static int tegra20_i2s_runtime_suspend(struct device *dev) { struct tegra20_i2s *i2s = dev_get_drvdata(dev); @@ -45,7 +45,7 @@ static __maybe_unused int tegra20_i2s_runtime_suspend(struct device *dev) return 0; } -static __maybe_unused int tegra20_i2s_runtime_resume(struct device *dev) +static int tegra20_i2s_runtime_resume(struct device *dev) { struct tegra20_i2s *i2s = dev_get_drvdata(dev); int ret; @@ -487,17 +487,16 @@ static const struct of_device_id tegra20_i2s_of_match[] = { }; static const struct dev_pm_ops tegra20_i2s_pm_ops = { - SET_RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend, - tegra20_i2s_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra20_i2s_runtime_suspend, + tegra20_i2s_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra20_i2s_driver = { .driver = { .name = DRV_NAME, .of_match_table = tegra20_i2s_of_match, - .pm = &tegra20_i2s_pm_ops, + .pm = pm_ptr(&tegra20_i2s_pm_ops), }, .probe = tegra20_i2s_platform_probe, .remove = tegra20_i2s_platform_remove, diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 380011233eb1..38661d9b4a7c 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -25,7 +25,7 @@ #include "tegra20_spdif.h" -static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev) +static int tegra20_spdif_runtime_suspend(struct device *dev) { struct tegra20_spdif *spdif = dev_get_drvdata(dev); @@ -36,7 +36,7 @@ static __maybe_unused int tegra20_spdif_runtime_suspend(struct device *dev) return 0; } -static __maybe_unused int tegra20_spdif_runtime_resume(struct device *dev) +static int tegra20_spdif_runtime_resume(struct device *dev) { struct tegra20_spdif *spdif = dev_get_drvdata(dev); int ret; @@ -403,10 +403,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) } static const struct dev_pm_ops tegra20_spdif_pm_ops = { - SET_RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend, - tegra20_spdif_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra20_spdif_runtime_suspend, + tegra20_spdif_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct of_device_id tegra20_spdif_of_match[] = { @@ -418,7 +417,7 @@ MODULE_DEVICE_TABLE(of, tegra20_spdif_of_match); static struct platform_driver tegra20_spdif_driver = { .driver = { .name = "tegra20-spdif", - .pm = &tegra20_spdif_pm_ops, + .pm = pm_ptr(&tegra20_spdif_pm_ops), .of_match_table = tegra20_spdif_of_match, }, .probe = tegra20_spdif_platform_probe, diff --git a/sound/soc/tegra/tegra210_admaif.c b/sound/soc/tegra/tegra210_admaif.c index 58fdb0e79954..76ff4fe40f65 100644 --- a/sound/soc/tegra/tegra210_admaif.c +++ b/sound/soc/tegra/tegra210_admaif.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (c) 2020-2024 NVIDIA CORPORATION & AFFILIATES. +// SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. // All rights reserved. // // tegra210_admaif.c - Tegra ADMAIF driver @@ -13,6 +13,7 @@ #include <linux/regmap.h> #include <sound/pcm_params.h> #include <sound/soc.h> +#include "tegra_isomgr_bw.h" #include "tegra210_admaif.h" #include "tegra_cif.h" #include "tegra_pcm.h" @@ -219,7 +220,7 @@ static const struct regmap_config tegra186_admaif_regmap_config = { .cache_type = REGCACHE_FLAT, }; -static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev) +static int tegra_admaif_runtime_suspend(struct device *dev) { struct tegra_admaif *admaif = dev_get_drvdata(dev); @@ -229,7 +230,7 @@ static int __maybe_unused tegra_admaif_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra_admaif_runtime_resume(struct device *dev) +static int tegra_admaif_runtime_resume(struct device *dev) { struct tegra_admaif *admaif = dev_get_drvdata(dev); @@ -262,6 +263,18 @@ static int tegra_admaif_set_pack_mode(struct regmap *map, unsigned int reg, return 0; } +static int tegra_admaif_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return tegra_isomgr_adma_setbw(substream, dai, true); +} + +static void tegra_admaif_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + tegra_isomgr_adma_setbw(substream, dai, false); +} + static int tegra_admaif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -554,6 +567,8 @@ static const struct snd_soc_dai_ops tegra_admaif_dai_ops = { .probe = tegra_admaif_dai_probe, .hw_params = tegra_admaif_hw_params, .trigger = tegra_admaif_trigger, + .shutdown = tegra_admaif_shutdown, + .prepare = tegra_admaif_prepare, }; #define DAI(dai_name) \ @@ -800,6 +815,12 @@ static int tegra_admaif_probe(struct platform_device *pdev) regcache_cache_only(admaif->regmap, true); + err = tegra_isomgr_adma_register(&pdev->dev); + if (err) { + dev_err(&pdev->dev, "Failed to add interconnect path\n"); + return err; + } + regmap_update_bits(admaif->regmap, admaif->soc_data->global_base + TEGRA_ADMAIF_GLOBAL_ENABLE, 1, 1); @@ -851,14 +872,14 @@ static int tegra_admaif_probe(struct platform_device *pdev) static void tegra_admaif_remove(struct platform_device *pdev) { + tegra_isomgr_adma_unregister(&pdev->dev); pm_runtime_disable(&pdev->dev); } static const struct dev_pm_ops tegra_admaif_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_admaif_runtime_suspend, - tegra_admaif_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra_admaif_runtime_suspend, + tegra_admaif_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra_admaif_driver = { @@ -867,7 +888,7 @@ static struct platform_driver tegra_admaif_driver = { .driver = { .name = "tegra210-admaif", .of_match_table = tegra_admaif_of_match, - .pm = &tegra_admaif_pm_ops, + .pm = pm_ptr(&tegra_admaif_pm_ops), }, }; module_platform_driver(tegra_admaif_driver); diff --git a/sound/soc/tegra/tegra210_admaif.h b/sound/soc/tegra/tegra210_admaif.h index 96686dc92081..748f886ee74e 100644 --- a/sound/soc/tegra/tegra210_admaif.h +++ b/sound/soc/tegra/tegra210_admaif.h @@ -1,8 +1,8 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * tegra210_admaif.h - Tegra ADMAIF registers +/* SPDX-License-Identifier: GPL-2.0-only + * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. * - * Copyright (c) 2020 NVIDIA CORPORATION. All rights reserved. + * tegra210_admaif.h - Tegra ADMAIF registers * */ @@ -157,6 +157,7 @@ struct tegra_admaif { unsigned int *mono_to_stereo[ADMAIF_PATHS]; unsigned int *stereo_to_mono[ADMAIF_PATHS]; struct regmap *regmap; + struct tegra_adma_isomgr *adma_isomgr; }; #endif diff --git a/sound/soc/tegra/tegra210_adx.c b/sound/soc/tegra/tegra210_adx.c index 0aa93b948378..b6c798baedea 100644 --- a/sound/soc/tegra/tegra210_adx.c +++ b/sound/soc/tegra/tegra210_adx.c @@ -1,5 +1,5 @@ // SPDX-License-Identifier: GPL-2.0-only -// SPDX-FileCopyrightText: Copyright (c) 2021-2024 NVIDIA CORPORATION & AFFILIATES. +// SPDX-FileCopyrightText: Copyright (c) 2021-2025 NVIDIA CORPORATION & AFFILIATES. // All rights reserved. // // tegra210_adx.c - Tegra210 ADX driver @@ -57,8 +57,8 @@ static int tegra210_adx_startup(struct snd_pcm_substream *substream, int err; /* Ensure if ADX status is disabled */ - err = regmap_read_poll_timeout_atomic(adx->regmap, TEGRA210_ADX_STATUS, - val, !(val & 0x1), 10, 10000); + err = regmap_read_poll_timeout(adx->regmap, TEGRA210_ADX_STATUS, + val, !(val & 0x1), 10, 10000); if (err < 0) { dev_err(dai->dev, "failed to stop ADX, err = %d\n", err); return err; @@ -84,7 +84,7 @@ static int tegra210_adx_startup(struct snd_pcm_substream *substream, return 0; } -static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev) +static int tegra210_adx_runtime_suspend(struct device *dev) { struct tegra210_adx *adx = dev_get_drvdata(dev); @@ -94,7 +94,7 @@ static int __maybe_unused tegra210_adx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_adx_runtime_resume(struct device *dev) +static int tegra210_adx_runtime_resume(struct device *dev) { struct tegra210_adx *adx = dev_get_drvdata(dev); @@ -524,17 +524,16 @@ static void tegra210_adx_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_adx_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_adx_runtime_suspend, - tegra210_adx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_adx_runtime_suspend, + tegra210_adx_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra210_adx_driver = { .driver = { .name = "tegra210-adx", .of_match_table = tegra210_adx_of_match, - .pm = &tegra210_adx_pm_ops, + .pm = pm_ptr(&tegra210_adx_pm_ops), }, .probe = tegra210_adx_platform_probe, .remove = tegra210_adx_platform_remove, diff --git a/sound/soc/tegra/tegra210_ahub.c b/sound/soc/tegra/tegra210_ahub.c index 1920b996e9aa..99683f292b5d 100644 --- a/sound/soc/tegra/tegra210_ahub.c +++ b/sound/soc/tegra/tegra210_ahub.c @@ -1319,7 +1319,7 @@ static const struct of_device_id tegra_ahub_of_match[] = { }; MODULE_DEVICE_TABLE(of, tegra_ahub_of_match); -static int __maybe_unused tegra_ahub_runtime_suspend(struct device *dev) +static int tegra_ahub_runtime_suspend(struct device *dev) { struct tegra_ahub *ahub = dev_get_drvdata(dev); @@ -1331,7 +1331,7 @@ static int __maybe_unused tegra_ahub_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra_ahub_runtime_resume(struct device *dev) +static int tegra_ahub_runtime_resume(struct device *dev) { struct tegra_ahub *ahub = dev_get_drvdata(dev); int err; @@ -1408,10 +1408,9 @@ static void tegra_ahub_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra_ahub_pm_ops = { - SET_RUNTIME_PM_OPS(tegra_ahub_runtime_suspend, - tegra_ahub_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra_ahub_runtime_suspend, + tegra_ahub_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra_ahub_driver = { @@ -1420,7 +1419,7 @@ static struct platform_driver tegra_ahub_driver = { .driver = { .name = "tegra210-ahub", .of_match_table = tegra_ahub_of_match, - .pm = &tegra_ahub_pm_ops, + .pm = pm_ptr(&tegra_ahub_pm_ops), }, }; module_platform_driver(tegra_ahub_driver); diff --git a/sound/soc/tegra/tegra210_amx.c b/sound/soc/tegra/tegra210_amx.c index a9ef22c19e81..1981b94009cf 100644 --- a/sound/soc/tegra/tegra210_amx.c +++ b/sound/soc/tegra/tegra210_amx.c @@ -98,7 +98,7 @@ static int tegra210_amx_startup(struct snd_pcm_substream *substream, return 0; } -static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev) +static int tegra210_amx_runtime_suspend(struct device *dev) { struct tegra210_amx *amx = dev_get_drvdata(dev); @@ -108,7 +108,7 @@ static int __maybe_unused tegra210_amx_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_amx_runtime_resume(struct device *dev) +static int tegra210_amx_runtime_resume(struct device *dev) { struct tegra210_amx *amx = dev_get_drvdata(dev); @@ -581,17 +581,16 @@ static void tegra210_amx_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_amx_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, - tegra210_amx_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_amx_runtime_suspend, + tegra210_amx_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra210_amx_driver = { .driver = { .name = "tegra210-amx", .of_match_table = tegra210_amx_of_match, - .pm = &tegra210_amx_pm_ops, + .pm = pm_ptr(&tegra210_amx_pm_ops), }, .probe = tegra210_amx_platform_probe, .remove = tegra210_amx_platform_remove, diff --git a/sound/soc/tegra/tegra210_dmic.c b/sound/soc/tegra/tegra210_dmic.c index 7986be71f43d..e4a144571265 100644 --- a/sound/soc/tegra/tegra210_dmic.c +++ b/sound/soc/tegra/tegra210_dmic.c @@ -40,7 +40,7 @@ static const struct reg_default tegra210_dmic_reg_defaults[] = { { TEGRA210_DMIC_LP_BIQUAD_1_COEF_4, 0x0 }, }; -static int __maybe_unused tegra210_dmic_runtime_suspend(struct device *dev) +static int tegra210_dmic_runtime_suspend(struct device *dev) { struct tegra210_dmic *dmic = dev_get_drvdata(dev); @@ -52,7 +52,7 @@ static int __maybe_unused tegra210_dmic_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_dmic_runtime_resume(struct device *dev) +static int tegra210_dmic_runtime_resume(struct device *dev) { struct tegra210_dmic *dmic = dev_get_drvdata(dev); int err; @@ -543,10 +543,9 @@ static void tegra210_dmic_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_dmic_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend, - tegra210_dmic_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_dmic_runtime_suspend, + tegra210_dmic_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct of_device_id tegra210_dmic_of_match[] = { @@ -559,7 +558,7 @@ static struct platform_driver tegra210_dmic_driver = { .driver = { .name = "tegra210-dmic", .of_match_table = tegra210_dmic_of_match, - .pm = &tegra210_dmic_pm_ops, + .pm = pm_ptr(&tegra210_dmic_pm_ops), }, .probe = tegra210_dmic_probe, .remove = tegra210_dmic_remove, diff --git a/sound/soc/tegra/tegra210_i2s.c b/sound/soc/tegra/tegra210_i2s.c index 07ce2dbe6c00..766cddebd5f6 100644 --- a/sound/soc/tegra/tegra210_i2s.c +++ b/sound/soc/tegra/tegra210_i2s.c @@ -166,7 +166,7 @@ static int tegra210_i2s_init(struct snd_soc_dapm_widget *w, return tegra210_i2s_sw_reset(compnt, stream); } -static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev) +static int tegra210_i2s_runtime_suspend(struct device *dev) { struct tegra210_i2s *i2s = dev_get_drvdata(dev); @@ -178,7 +178,7 @@ static int __maybe_unused tegra210_i2s_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_i2s_runtime_resume(struct device *dev) +static int tegra210_i2s_runtime_resume(struct device *dev) { struct tegra210_i2s *i2s = dev_get_drvdata(dev); int err; @@ -1010,10 +1010,9 @@ static void tegra210_i2s_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_i2s_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend, - tegra210_i2s_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_i2s_runtime_suspend, + tegra210_i2s_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct of_device_id tegra210_i2s_of_match[] = { @@ -1026,7 +1025,7 @@ static struct platform_driver tegra210_i2s_driver = { .driver = { .name = "tegra210-i2s", .of_match_table = tegra210_i2s_of_match, - .pm = &tegra210_i2s_pm_ops, + .pm = pm_ptr(&tegra210_i2s_pm_ops), }, .probe = tegra210_i2s_probe, .remove = tegra210_i2s_remove, diff --git a/sound/soc/tegra/tegra210_mixer.c b/sound/soc/tegra/tegra210_mixer.c index 410259d98dfb..95d69a7e027f 100644 --- a/sound/soc/tegra/tegra210_mixer.c +++ b/sound/soc/tegra/tegra210_mixer.c @@ -73,7 +73,7 @@ static const struct tegra210_mixer_gain_params gain_params = { { 0, 0, 0x400, 0x8000000 }, }; -static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev) +static int tegra210_mixer_runtime_suspend(struct device *dev) { struct tegra210_mixer *mixer = dev_get_drvdata(dev); @@ -83,7 +83,7 @@ static int __maybe_unused tegra210_mixer_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_mixer_runtime_resume(struct device *dev) +static int tegra210_mixer_runtime_resume(struct device *dev) { struct tegra210_mixer *mixer = dev_get_drvdata(dev); @@ -666,17 +666,16 @@ static void tegra210_mixer_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_mixer_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend, - tegra210_mixer_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_mixer_runtime_suspend, + tegra210_mixer_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra210_mixer_driver = { .driver = { .name = "tegra210_mixer", .of_match_table = tegra210_mixer_of_match, - .pm = &tegra210_mixer_pm_ops, + .pm = pm_ptr(&tegra210_mixer_pm_ops), }, .probe = tegra210_mixer_platform_probe, .remove = tegra210_mixer_platform_remove, diff --git a/sound/soc/tegra/tegra210_mvc.c b/sound/soc/tegra/tegra210_mvc.c index 119f17501478..35b14c8396f4 100644 --- a/sound/soc/tegra/tegra210_mvc.c +++ b/sound/soc/tegra/tegra210_mvc.c @@ -47,7 +47,7 @@ static const struct tegra210_mvc_gain_params gain_params = { .duration_inv = 14316558, }; -static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev) +static int tegra210_mvc_runtime_suspend(struct device *dev) { struct tegra210_mvc *mvc = dev_get_drvdata(dev); @@ -59,7 +59,7 @@ static int __maybe_unused tegra210_mvc_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_mvc_runtime_resume(struct device *dev) +static int tegra210_mvc_runtime_resume(struct device *dev) { struct tegra210_mvc *mvc = dev_get_drvdata(dev); @@ -758,17 +758,16 @@ static void tegra210_mvc_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_mvc_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend, - tegra210_mvc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_mvc_runtime_suspend, + tegra210_mvc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra210_mvc_driver = { .driver = { .name = "tegra210-mvc", .of_match_table = tegra210_mvc_of_match, - .pm = &tegra210_mvc_pm_ops, + .pm = pm_ptr(&tegra210_mvc_pm_ops), }, .probe = tegra210_mvc_platform_probe, .remove = tegra210_mvc_platform_remove, diff --git a/sound/soc/tegra/tegra210_ope.c b/sound/soc/tegra/tegra210_ope.c index c595cec9baab..5036bcfe0828 100644 --- a/sound/soc/tegra/tegra210_ope.c +++ b/sound/soc/tegra/tegra210_ope.c @@ -356,7 +356,7 @@ static void tegra210_ope_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev) +static int tegra210_ope_runtime_suspend(struct device *dev) { struct tegra210_ope *ope = dev_get_drvdata(dev); @@ -374,7 +374,7 @@ static int __maybe_unused tegra210_ope_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev) +static int tegra210_ope_runtime_resume(struct device *dev) { struct tegra210_ope *ope = dev_get_drvdata(dev); @@ -393,10 +393,9 @@ static int __maybe_unused tegra210_ope_runtime_resume(struct device *dev) } static const struct dev_pm_ops tegra210_ope_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_ope_runtime_suspend, - tegra210_ope_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_ope_runtime_suspend, + tegra210_ope_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static const struct of_device_id tegra210_ope_of_match[] = { @@ -409,7 +408,7 @@ static struct platform_driver tegra210_ope_driver = { .driver = { .name = "tegra210-ope", .of_match_table = tegra210_ope_of_match, - .pm = &tegra210_ope_pm_ops, + .pm = pm_ptr(&tegra210_ope_pm_ops), }, .probe = tegra210_ope_probe, .remove = tegra210_ope_remove, diff --git a/sound/soc/tegra/tegra210_sfc.c b/sound/soc/tegra/tegra210_sfc.c index df88708c733c..a0bd36f12c68 100644 --- a/sound/soc/tegra/tegra210_sfc.c +++ b/sound/soc/tegra/tegra210_sfc.c @@ -3056,7 +3056,7 @@ static s32 *coef_addr_table[TEGRA210_SFC_NUM_RATES][TEGRA210_SFC_NUM_RATES] = { }, }; -static int __maybe_unused tegra210_sfc_runtime_suspend(struct device *dev) +static int tegra210_sfc_runtime_suspend(struct device *dev) { struct tegra210_sfc *sfc = dev_get_drvdata(dev); @@ -3066,7 +3066,7 @@ static int __maybe_unused tegra210_sfc_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused tegra210_sfc_runtime_resume(struct device *dev) +static int tegra210_sfc_runtime_resume(struct device *dev) { struct tegra210_sfc *sfc = dev_get_drvdata(dev); @@ -3623,17 +3623,16 @@ static void tegra210_sfc_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra210_sfc_pm_ops = { - SET_RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend, - tegra210_sfc_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra210_sfc_runtime_suspend, + tegra210_sfc_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra210_sfc_driver = { .driver = { .name = "tegra210-sfc", .of_match_table = tegra210_sfc_of_match, - .pm = &tegra210_sfc_pm_ops, + .pm = pm_ptr(&tegra210_sfc_pm_ops), }, .probe = tegra210_sfc_platform_probe, .remove = tegra210_sfc_platform_remove, diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index c9b52f54cea8..51e5ab6c276b 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -40,7 +40,7 @@ static inline void tegra30_audio_write(u32 reg, u32 val) regmap_write(ahub->regmap_ahub, reg, val); } -static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev) +static int tegra30_ahub_runtime_suspend(struct device *dev) { regcache_cache_only(ahub->regmap_apbif, true); regcache_cache_only(ahub->regmap_ahub, true); @@ -61,7 +61,7 @@ static __maybe_unused int tegra30_ahub_runtime_suspend(struct device *dev) * stopping streams should dynamically adjust the clock as required. However, * this is not yet implemented. */ -static __maybe_unused int tegra30_ahub_runtime_resume(struct device *dev) +static int tegra30_ahub_runtime_resume(struct device *dev) { int ret; @@ -600,10 +600,9 @@ static void tegra30_ahub_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra30_ahub_pm_ops = { - SET_RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, - tegra30_ahub_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra30_ahub_runtime_suspend, + tegra30_ahub_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra30_ahub_driver = { @@ -612,7 +611,7 @@ static struct platform_driver tegra30_ahub_driver = { .driver = { .name = DRV_NAME, .of_match_table = tegra30_ahub_of_match, - .pm = &tegra30_ahub_pm_ops, + .pm = pm_ptr(&tegra30_ahub_pm_ops), }, }; module_platform_driver(tegra30_ahub_driver); diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index 0d3badfbe143..b121af9ef8ed 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -35,7 +35,7 @@ #define DRV_NAME "tegra30-i2s" -static __maybe_unused int tegra30_i2s_runtime_suspend(struct device *dev) +static int tegra30_i2s_runtime_suspend(struct device *dev) { struct tegra30_i2s *i2s = dev_get_drvdata(dev); @@ -46,7 +46,7 @@ static __maybe_unused int tegra30_i2s_runtime_suspend(struct device *dev) return 0; } -static __maybe_unused int tegra30_i2s_runtime_resume(struct device *dev) +static int tegra30_i2s_runtime_resume(struct device *dev) { struct tegra30_i2s *i2s = dev_get_drvdata(dev); int ret; @@ -547,17 +547,16 @@ static void tegra30_i2s_platform_remove(struct platform_device *pdev) } static const struct dev_pm_ops tegra30_i2s_pm_ops = { - SET_RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend, - tegra30_i2s_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + RUNTIME_PM_OPS(tegra30_i2s_runtime_suspend, + tegra30_i2s_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver tegra30_i2s_driver = { .driver = { .name = DRV_NAME, .of_match_table = tegra30_i2s_of_match, - .pm = &tegra30_i2s_pm_ops, + .pm = pm_ptr(&tegra30_i2s_pm_ops), }, .probe = tegra30_i2s_platform_probe, .remove = tegra30_i2s_platform_remove, diff --git a/sound/soc/tegra/tegra_asoc_machine.c b/sound/soc/tegra/tegra_asoc_machine.c index 775ce433fdbf..62f896772731 100644 --- a/sound/soc/tegra/tegra_asoc_machine.c +++ b/sound/soc/tegra/tegra_asoc_machine.c @@ -637,7 +637,7 @@ static struct snd_soc_dai_link tegra_wm8753_dai = { .stream_name = "WM8753 PCM", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(wm8753_hifi), }; @@ -701,7 +701,7 @@ static struct snd_soc_dai_link tegra_max98090_dai = { .init = tegra_asoc_machine_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(max98090_hifi), }; @@ -736,7 +736,7 @@ static struct snd_soc_dai_link tegra_max98088_dai = { .init = tegra_asoc_machine_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(max98088_hifi), }; @@ -769,7 +769,7 @@ static struct snd_soc_dai_link tegra_sgtl5000_dai = { .stream_name = "HiFi", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(sgtl5000_hifi), }; @@ -812,7 +812,7 @@ static struct snd_soc_dai_link tegra_tlv320aic23_dai = { .stream_name = "AIC23", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(tlv320aic23_hifi), }; @@ -861,7 +861,7 @@ static struct snd_soc_dai_link tegra_rt5677_dai = { .init = tegra_rt5677_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(rt5677_aif1), }; @@ -895,7 +895,7 @@ static struct snd_soc_dai_link tegra_rt5640_dai = { .init = tegra_asoc_machine_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(rt5640_aif1), }; @@ -928,7 +928,7 @@ static struct snd_soc_dai_link tegra_rt5632_dai = { .init = tegra_rt5677_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(rt5632_hifi), }; @@ -961,7 +961,7 @@ static struct snd_soc_dai_link tegra_rt5631_dai = { .init = tegra_asoc_machine_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(rt5631_hifi), }; diff --git a/sound/soc/tegra/tegra_isomgr_bw.c b/sound/soc/tegra/tegra_isomgr_bw.c new file mode 100644 index 000000000000..18e802bca6a6 --- /dev/null +++ b/sound/soc/tegra/tegra_isomgr_bw.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-only +// SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. +// All rights reserved. +// +// ADMA bandwidth calculation + +#include <linux/interconnect.h> +#include <linux/module.h> +#include <sound/pcm_params.h> +#include <sound/soc.h> +#include "tegra_isomgr_bw.h" +#include "tegra210_admaif.h" + +/* Max possible rate is 192KHz x 16channel x 4bytes */ +#define MAX_BW_PER_DEV 12288 + +int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, bool is_running) +{ + struct device *dev = dai->dev; + struct tegra_admaif *admaif = snd_soc_dai_get_drvdata(dai); + struct tegra_adma_isomgr *adma_isomgr = admaif->adma_isomgr; + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_pcm *pcm = substream->pcm; + u32 type = substream->stream, bandwidth = 0; + int sample_bytes; + + if (!adma_isomgr) + return 0; + + if (!runtime || !pcm) + return -EINVAL; + + if (pcm->device >= adma_isomgr->max_pcm_device) { + dev_err(dev, "%s: PCM device number %d is greater than %d\n", __func__, + pcm->device, adma_isomgr->max_pcm_device); + return -EINVAL; + } + + /* + * No action if stream is running and bandwidth is already set or + * stream is not running and bandwidth is already reset + */ + if ((adma_isomgr->bw_per_dev[type][pcm->device] && is_running) || + (!adma_isomgr->bw_per_dev[type][pcm->device] && !is_running)) + return 0; + + if (is_running) { + sample_bytes = snd_pcm_format_width(runtime->format) / 8; + if (sample_bytes < 0) + return sample_bytes; + + /* KB/s kilo bytes per sec */ + bandwidth = runtime->channels * (runtime->rate / 1000) * + sample_bytes; + } + + mutex_lock(&adma_isomgr->mutex); + + if (is_running) { + if (bandwidth + adma_isomgr->current_bandwidth > adma_isomgr->max_bw) + bandwidth = adma_isomgr->max_bw - adma_isomgr->current_bandwidth; + + adma_isomgr->current_bandwidth += bandwidth; + } else { + adma_isomgr->current_bandwidth -= adma_isomgr->bw_per_dev[type][pcm->device]; + } + + mutex_unlock(&adma_isomgr->mutex); + + adma_isomgr->bw_per_dev[type][pcm->device] = bandwidth; + + dev_dbg(dev, "Setting up bandwidth to %d KBps\n", adma_isomgr->current_bandwidth); + + return icc_set_bw(adma_isomgr->icc_path_handle, + adma_isomgr->current_bandwidth, adma_isomgr->max_bw); +} + +int tegra_isomgr_adma_register(struct device *dev) +{ + struct tegra_admaif *admaif = dev_get_drvdata(dev); + struct tegra_adma_isomgr *adma_isomgr; + int i; + + adma_isomgr = devm_kzalloc(dev, sizeof(struct tegra_adma_isomgr), GFP_KERNEL); + if (!adma_isomgr) + return -ENOMEM; + + adma_isomgr->icc_path_handle = devm_of_icc_get(dev, "write"); + if (IS_ERR(adma_isomgr->icc_path_handle)) + return dev_err_probe(dev, PTR_ERR(adma_isomgr->icc_path_handle), + "failed to acquire interconnect path\n"); + + /* Either INTERCONNECT config OR interconnect property is not defined */ + if (!adma_isomgr->icc_path_handle) { + devm_kfree(dev, adma_isomgr); + return 0; + } + + adma_isomgr->max_pcm_device = admaif->soc_data->num_ch; + adma_isomgr->max_bw = STREAM_TYPE * MAX_BW_PER_DEV * adma_isomgr->max_pcm_device; + + for (i = 0; i < STREAM_TYPE; i++) { + adma_isomgr->bw_per_dev[i] = devm_kzalloc(dev, adma_isomgr->max_pcm_device * + sizeof(u32), GFP_KERNEL); + if (!adma_isomgr->bw_per_dev[i]) + return -ENOMEM; + } + + adma_isomgr->current_bandwidth = 0; + mutex_init(&adma_isomgr->mutex); + admaif->adma_isomgr = adma_isomgr; + + return 0; +} + +void tegra_isomgr_adma_unregister(struct device *dev) +{ + struct tegra_admaif *admaif = dev_get_drvdata(dev); + + if (!admaif->adma_isomgr) + return; + + mutex_destroy(&admaif->adma_isomgr->mutex); +} + +MODULE_AUTHOR("Mohan Kumar <mkumard@nvidia.com>"); +MODULE_DESCRIPTION("Tegra ADMA Bandwidth Request driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/tegra/tegra_isomgr_bw.h b/sound/soc/tegra/tegra_isomgr_bw.h new file mode 100644 index 000000000000..86db3cfd4e43 --- /dev/null +++ b/sound/soc/tegra/tegra_isomgr_bw.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only + * SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. + * All rights reserved. + * + * tegra_isomgr_bw.h - Definitions for ADMA bandwidth calculation + * + */ + +#ifndef __TEGRA_ISOMGR_BW_H__ +#define __TEGRA_ISOMGR_BW_H__ + +/* Playback and Capture streams */ +#define STREAM_TYPE 2 + +struct tegra_adma_isomgr { + /* Protect pcm devices bandwidth */ + struct mutex mutex; + /* interconnect path handle */ + struct icc_path *icc_path_handle; + u32 *bw_per_dev[STREAM_TYPE]; + u32 current_bandwidth; + u32 max_pcm_device; + u32 max_bw; +}; + +int tegra_isomgr_adma_register(struct device *dev); +void tegra_isomgr_adma_unregister(struct device *dev); +int tegra_isomgr_adma_setbw(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai, bool is_running); + +#endif diff --git a/sound/soc/tegra/tegra_wm8903.c b/sound/soc/tegra/tegra_wm8903.c index 6116d2e30fca..78b02c64d95c 100644 --- a/sound/soc/tegra/tegra_wm8903.c +++ b/sound/soc/tegra/tegra_wm8903.c @@ -124,7 +124,7 @@ static struct snd_soc_dai_link tegra_wm8903_dai = { .init = tegra_wm8903_init, .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, SND_SOC_DAILINK_REG(hifi), }; diff --git a/sound/soc/ti/ams-delta.c b/sound/soc/ti/ams-delta.c index 94645f275495..8a4423646aea 100644 --- a/sound/soc/ti/ams-delta.c +++ b/sound/soc/ti/ams-delta.c @@ -532,7 +532,7 @@ static struct snd_soc_dai_link ams_delta_dai_link = { .init = ams_delta_cx20442_init, .ops = &ams_delta_ops, .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(cx20442), }; diff --git a/sound/soc/ti/davinci-evm.c b/sound/soc/ti/davinci-evm.c index 1bf333d2740d..2a2f5bc95576 100644 --- a/sound/soc/ti/davinci-evm.c +++ b/sound/soc/ti/davinci-evm.c @@ -152,7 +152,7 @@ static struct snd_soc_dai_link evm_dai_tlv320aic3x = { .stream_name = "AIC3X", .ops = &evm_ops, .init = evm_aic3x_init, - .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM | + .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBP_CFP | SND_SOC_DAIFMT_IB_NF, SND_SOC_DAILINK_REG(evm), }; diff --git a/sound/soc/ti/davinci-i2s.c b/sound/soc/ti/davinci-i2s.c index d682b98d6848..059967f0e632 100644 --- a/sound/soc/ti/davinci-i2s.c +++ b/sound/soc/ti/davinci-i2s.c @@ -892,8 +892,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) err_unregister_component: snd_soc_unregister_component(&pdev->dev); err_disable_ext_clk: - if (dev->ext_clk) - clk_disable_unprepare(dev->ext_clk); + clk_disable_unprepare(dev->ext_clk); err_disable_clk: clk_disable_unprepare(dev->clk); @@ -908,8 +907,7 @@ static void davinci_i2s_remove(struct platform_device *pdev) clk_disable_unprepare(dev->clk); - if (dev->ext_clk) - clk_disable_unprepare(dev->ext_clk); + clk_disable_unprepare(dev->ext_clk); } static const struct of_device_id davinci_i2s_match[] __maybe_unused = { diff --git a/sound/soc/ti/j721e-evm.c b/sound/soc/ti/j721e-evm.c index d9d1e021f5b2..0e7e4ff950b5 100644 --- a/sound/soc/ti/j721e-evm.c +++ b/sound/soc/ti/j721e-evm.c @@ -37,7 +37,7 @@ enum j721e_audio_domain_id { #define J721E_DAI_FMT (SND_SOC_DAIFMT_RIGHT_J | \ SND_SOC_DAIFMT_NB_NF | \ - SND_SOC_DAIFMT_CBS_CFS) + SND_SOC_DAIFMT_CBC_CFC) enum j721e_board_type { J721E_BOARD_CPB = 1, @@ -182,6 +182,8 @@ static int j721e_configure_refclk(struct j721e_priv *priv, clk_id = J721E_CLK_PARENT_48000; else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_44100]) clk_id = J721E_CLK_PARENT_44100; + else if (!(rate % 11025) && priv->pll_rates[J721E_CLK_PARENT_48000]) + clk_id = J721E_CLK_PARENT_48000; else return ret; @@ -913,8 +915,9 @@ static int j721e_soc_probe(struct platform_device *pdev) mutex_init(&priv->mutex); ret = devm_snd_soc_register_card(&pdev->dev, card); if (ret) - dev_err(&pdev->dev, "devm_snd_soc_register_card() failed: %d\n", - ret); + dev_err_probe(&pdev->dev, ret, + "devm_snd_soc_register_card() failed: %d\n", + ret); return ret; } diff --git a/sound/soc/ti/n810.c b/sound/soc/ti/n810.c index 50a8ec97cf20..345c98765380 100644 --- a/sound/soc/ti/n810.c +++ b/sound/soc/ti/n810.c @@ -258,7 +258,7 @@ static struct snd_soc_dai_link n810_dai = { .name = "TLV320AIC33", .stream_name = "AIC33", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &n810_ops, SND_SOC_DAILINK_REG(aic33), }; diff --git a/sound/soc/ti/omap-twl4030.c b/sound/soc/ti/omap-twl4030.c index a402d66e4f4d..3548b58002c4 100644 --- a/sound/soc/ti/omap-twl4030.c +++ b/sound/soc/ti/omap-twl4030.c @@ -42,12 +42,12 @@ static int omap_twl4030_hw_params(struct snd_pcm_substream *substream, case 2: /* Stereo I2S mode */ fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; break; case 4: /* Four channel TDM mode */ fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM; + SND_SOC_DAIFMT_CBP_CFP; break; default: return -EINVAL; @@ -218,7 +218,7 @@ static struct snd_soc_dai_link omap_twl4030_dai_links[] = { .name = "TWL4030 Voice", .stream_name = "TWL4030 Voice", .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, SND_SOC_DAILINK_REG(voice), }, }; diff --git a/sound/soc/ti/omap3pandora.c b/sound/soc/ti/omap3pandora.c index be69476e59d6..808fb6765c05 100644 --- a/sound/soc/ti/omap3pandora.c +++ b/sound/soc/ti/omap3pandora.c @@ -189,7 +189,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { .name = "PCM1773", .stream_name = "HiFi Out", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &omap3pandora_ops, .init = omap3pandora_out_init, SND_SOC_DAILINK_REG(out), @@ -197,7 +197,7 @@ static struct snd_soc_dai_link omap3pandora_dai[] = { .name = "TWL4030", .stream_name = "Line/Mic In", .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBS_CFS, + SND_SOC_DAIFMT_CBC_CFC, .ops = &omap3pandora_ops, .init = omap3pandora_in_init, SND_SOC_DAILINK_REG(in), diff --git a/sound/soc/ti/osk5912.c b/sound/soc/ti/osk5912.c index 98714c593496..fa5ef7814dab 100644 --- a/sound/soc/ti/osk5912.c +++ b/sound/soc/ti/osk5912.c @@ -86,7 +86,7 @@ static struct snd_soc_dai_link osk_dai = { .name = "TLV320AIC23", .stream_name = "AIC23", .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .ops = &osk_ops, SND_SOC_DAILINK_REG(aic23), }; diff --git a/sound/soc/ti/rx51.c b/sound/soc/ti/rx51.c index d9900c69e536..e969031657e9 100644 --- a/sound/soc/ti/rx51.c +++ b/sound/soc/ti/rx51.c @@ -307,7 +307,7 @@ static struct snd_soc_dai_link rx51_dai[] = { .name = "TLV320AIC34", .stream_name = "AIC34", .dai_fmt = SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF | - SND_SOC_DAIFMT_CBM_CFM, + SND_SOC_DAIFMT_CBP_CFP, .init = rx51_aic34_init, .ops = &rx51_ops, SND_SOC_DAILINK_REG(aic34), diff --git a/sound/soc/uniphier/aio-cpu.c b/sound/soc/uniphier/aio-cpu.c index 470f129166a4..3224c11a527f 100644 --- a/sound/soc/uniphier/aio-cpu.c +++ b/sound/soc/uniphier/aio-cpu.c @@ -762,14 +762,10 @@ int uniphier_aio_probe(struct platform_device *pdev) return -ENOMEM; chip->num_plls = chip->chip_spec->num_plls; - chip->plls = devm_kcalloc(dev, - chip->num_plls, - sizeof(struct uniphier_aio_pll), - GFP_KERNEL); + chip->plls = devm_kmemdup_array(dev, chip->chip_spec->plls, chip->num_plls, + sizeof(*chip->chip_spec->plls), GFP_KERNEL); if (!chip->plls) return -ENOMEM; - memcpy(chip->plls, chip->chip_spec->plls, - sizeof(struct uniphier_aio_pll) * chip->num_plls); for (i = 0; i < chip->num_aios; i++) { struct uniphier_aio *aio = &chip->aios[i]; diff --git a/sound/soc/ux500/mop500_ab8500.c b/sound/soc/ux500/mop500_ab8500.c index 710b6744e013..5246f73ef12e 100644 --- a/sound/soc/ux500/mop500_ab8500.c +++ b/sound/soc/ux500/mop500_ab8500.c @@ -275,12 +275,12 @@ static int mop500_ab8500_hw_params(struct snd_pcm_substream *substream, if (driver_mode == DRIVERMODE_NORMAL) { fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_CBP_CFP | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CONT; } else { fmt = SND_SOC_DAIFMT_DSP_A | - SND_SOC_DAIFMT_CBM_CFM | + SND_SOC_DAIFMT_CBP_CFP | SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_GATED; } diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 4eaa9011405f..678ded059b95 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -629,8 +629,8 @@ MODULE_DEVICE_TABLE(of, xtfpga_i2s_of_match); #endif static const struct dev_pm_ops xtfpga_i2s_pm_ops = { - SET_RUNTIME_PM_OPS(xtfpga_i2s_runtime_suspend, - xtfpga_i2s_runtime_resume, NULL) + RUNTIME_PM_OPS(xtfpga_i2s_runtime_suspend, + xtfpga_i2s_runtime_resume, NULL) }; static struct platform_driver xtfpga_i2s_driver = { @@ -639,7 +639,7 @@ static struct platform_driver xtfpga_i2s_driver = { .driver = { .name = "xtfpga-i2s", .of_match_table = of_match_ptr(xtfpga_i2s_of_match), - .pm = &xtfpga_i2s_pm_ops, + .pm = pm_ptr(&xtfpga_i2s_pm_ops), }, }; diff --git a/sound/usb/format.c b/sound/usb/format.c index 6049d957694c..9d32b21a5fbb 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -384,6 +384,10 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip, if (chip->usb_id == USB_ID(0x194f, 0x010c) && !s1810c_valid_sample_rate(fp, rate)) goto skip_rate; + /* Filter out invalid rates on Presonus Studio 1824c */ + if (chip->usb_id == USB_ID(0x194f, 0x010d) && + !s1810c_valid_sample_rate(fp, rate)) + goto skip_rate; /* Filter out invalid rates on Focusrite devices */ if (USB_ID_VENDOR(chip->usb_id) == 0x1235 && diff --git a/sound/usb/midi.c b/sound/usb/midi.c index 779d97d31f17..826ac870f246 100644 --- a/sound/usb/midi.c +++ b/sound/usb/midi.c @@ -489,16 +489,84 @@ static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep, /* * CME protocol: like the standard protocol, but SysEx commands are sent as a - * single USB packet preceded by a 0x0F byte. + * single USB packet preceded by a 0x0F byte, as are system realtime + * messages and MIDI Active Sensing. + * Also, multiple messages can be sent in the same packet. */ static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, uint8_t *buffer, int buffer_length) { - if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) - snd_usbmidi_standard_input(ep, buffer, buffer_length); - else - snd_usbmidi_input_data(ep, buffer[0] >> 4, - &buffer[1], buffer_length - 1); + int remaining = buffer_length; + + /* + * CME send sysex, song position pointer, system realtime + * and active sensing using CIN 0x0f, which in the standard + * is only intended for single byte unparsed data. + * So we need to interpret these here before sending them on. + * By default, we assume single byte data, which is true + * for system realtime (midi clock, start, stop and continue) + * and active sensing, and handle the other (known) cases + * separately. + * In contrast to the standard, CME does not split sysex + * into multiple 4-byte packets, but lumps everything together + * into one. In addition, CME can string multiple messages + * together in the same packet; pressing the Record button + * on an UF6 sends a sysex message directly followed + * by a song position pointer in the same packet. + * For it to have any reasonable meaning, a sysex message + * needs to be at least 3 bytes in length (0xf0, id, 0xf7), + * corresponding to a packet size of 4 bytes, and the ones sent + * by CME devices are 6 or 7 bytes, making the packet fragments + * 7 or 8 bytes long (six or seven bytes plus preceding CN+CIN byte). + * For the other types, the packet size is always 4 bytes, + * as per the standard, with the data size being 3 for SPP + * and 1 for the others. + * Thus all packet fragments are at least 4 bytes long, so we can + * skip anything that is shorter; this also conveniantly skips + * packets with size 0, which CME devices continuously send when + * they have nothing better to do. + * Another quirk is that sometimes multiple messages are sent + * in the same packet. This has been observed for midi clock + * and active sensing i.e. 0x0f 0xf8 0x00 0x00 0x0f 0xfe 0x00 0x00, + * but also multiple note ons/offs, and control change together + * with MIDI clock. Similarly, some sysex messages are followed by + * the song position pointer in the same packet, and occasionally + * additionally by a midi clock or active sensing. + * We handle this by looping over all data and parsing it along the way. + */ + while (remaining >= 4) { + int source_length = 4; /* default */ + + if ((buffer[0] & 0x0f) == 0x0f) { + int data_length = 1; /* default */ + + if (buffer[1] == 0xf0) { + /* Sysex: Find EOX and send on whole message. */ + /* To kick off the search, skip the first + * two bytes (CN+CIN and SYSEX (0xf0). + */ + uint8_t *tmp_buf = buffer + 2; + int tmp_length = remaining - 2; + + while (tmp_length > 1 && *tmp_buf != 0xf7) { + tmp_buf++; + tmp_length--; + } + data_length = tmp_buf - buffer; + source_length = data_length + 1; + } else if (buffer[1] == 0xf2) { + /* Three byte song position pointer */ + data_length = 3; + } + snd_usbmidi_input_data(ep, buffer[0] >> 4, + &buffer[1], data_length); + } else { + /* normal channel events */ + snd_usbmidi_standard_input(ep, buffer, source_length); + } + buffer += source_length; + remaining -= source_length; + } } /* diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index ed6127b0389f..a90673d43822 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -3688,8 +3688,7 @@ static const char *snd_djm_get_label(u8 device_idx, u16 wvalue, u16 windex) // common DJM capture level option values static const u16 snd_djm_opts_cap_level[] = { - 0x0000, 0x0100, 0x0200, 0x0300, 0x400, 0x500 }; - + 0x0000, 0x0100, 0x0200, 0x0300 }; // DJM-250MK2 static const u16 snd_djm_opts_250mk2_cap1[] = { @@ -3831,6 +3830,8 @@ static const struct snd_djm_ctl snd_djm_ctls_750mk2[] = { // DJM-A9 +static const u16 snd_djm_opts_a9_cap_level[] = { + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500 }; static const u16 snd_djm_opts_a9_cap1[] = { 0x0107, 0x0108, 0x0109, 0x010a, 0x010e, 0x111, 0x112, 0x113, 0x114, 0x0131, 0x132, 0x133, 0x134 }; @@ -3844,7 +3845,7 @@ static const u16 snd_djm_opts_a9_cap5[] = { 0x0501, 0x0502, 0x0503, 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x050a, 0x050e }; static const struct snd_djm_ctl snd_djm_ctls_a9[] = { - SND_DJM_CTL("Capture Level", cap_level, 0, SND_DJM_WINDEX_CAPLVL), + SND_DJM_CTL("Capture Level", a9_cap_level, 0, SND_DJM_WINDEX_CAPLVL), SND_DJM_CTL("Master Input", a9_cap1, 3, SND_DJM_WINDEX_CAP), SND_DJM_CTL("Ch1 Input", a9_cap2, 2, SND_DJM_WINDEX_CAP), SND_DJM_CTL("Ch2 Input", a9_cap3, 2, SND_DJM_WINDEX_CAP), @@ -4119,6 +4120,9 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x194f, 0x010c): /* Presonus Studio 1810c */ err = snd_sc1810_init_mixer(mixer); break; + case USB_ID(0x194f, 0x010d): /* Presonus Studio 1824c */ + err = snd_sc1810_init_mixer(mixer); + break; case USB_ID(0x2a39, 0x3fb0): /* RME Babyface Pro FS */ err = snd_bbfpro_controls_create(mixer); break; @@ -4223,6 +4227,52 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer, } } +/* + * Some Plantronics headsets have control names that don't meet ALSA naming + * standards. This function fixes nonstandard source names. By the time + * this function is called the control name should look like one of these: + * "source names Playback Volume" + * "source names Playback Switch" + * "source names Capture Volume" + * "source names Capture Switch" + * If any of the trigger words are found in the name then the name will + * be changed to: + * "Headset Playback Volume" + * "Headset Playback Switch" + * "Headset Capture Volume" + * "Headset Capture Switch" + * depending on the current suffix. + */ +static void snd_fix_plt_name(struct snd_usb_audio *chip, + struct snd_ctl_elem_id *id) +{ + /* no variant of "Sidetone" should be added to this list */ + static const char * const trigger[] = { + "Earphone", "Microphone", "Receive", "Transmit" + }; + static const char * const suffix[] = { + " Playback Volume", " Playback Switch", + " Capture Volume", " Capture Switch" + }; + int i; + + for (i = 0; i < ARRAY_SIZE(trigger); i++) + if (strstr(id->name, trigger[i])) + goto triggered; + usb_audio_dbg(chip, "no change in %s\n", id->name); + return; + +triggered: + for (i = 0; i < ARRAY_SIZE(suffix); i++) + if (strstr(id->name, suffix[i])) { + usb_audio_dbg(chip, "fixing kctl name %s\n", id->name); + snprintf(id->name, sizeof(id->name), "Headset%s", + suffix[i]); + return; + } + usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name); +} + void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, struct usb_mixer_elem_info *cval, int unitid, struct snd_kcontrol *kctl) @@ -4240,5 +4290,10 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, cval->min_mute = 1; break; } + + /* ALSA-ify some Plantronics headset control names */ + if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && + (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME)) + snd_fix_plt_name(mixer->chip, &kctl->id); } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 09210fb4ac60..9112313a9dbc 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -1599,7 +1599,9 @@ int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip, /* presonus studio 1810c: skip altsets incompatible with device_setup */ if (chip->usb_id == USB_ID(0x194f, 0x010c)) return s1810c_skip_setting_quirk(chip, iface, altno); - + /* presonus studio 1824c: skip altsets incompatible with device_setup */ + if (chip->usb_id == USB_ID(0x194f, 0x010d)) + return s1810c_skip_setting_quirk(chip, iface, altno); return 0; } diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index d41ea09ffbe5..7fcc528a0204 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c @@ -1617,7 +1617,7 @@ static int had_create_jack(struct snd_intelhad *ctx, * PM callbacks */ -static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev) +static int hdmi_lpe_audio_suspend(struct device *dev) { struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev); @@ -1626,7 +1626,7 @@ static int __maybe_unused hdmi_lpe_audio_suspend(struct device *dev) return 0; } -static int __maybe_unused hdmi_lpe_audio_resume(struct device *dev) +static int hdmi_lpe_audio_resume(struct device *dev) { struct snd_intelhad_card *card_ctx = dev_get_drvdata(dev); @@ -1833,13 +1833,13 @@ static int hdmi_lpe_audio_probe(struct platform_device *pdev) } static const struct dev_pm_ops hdmi_lpe_audio_pm = { - SET_SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume) + SYSTEM_SLEEP_PM_OPS(hdmi_lpe_audio_suspend, hdmi_lpe_audio_resume) }; static struct platform_driver hdmi_lpe_audio_driver = { .driver = { .name = "hdmi-lpe-audio", - .pm = &hdmi_lpe_audio_pm, + .pm = pm_ptr(&hdmi_lpe_audio_pm), }, .probe = hdmi_lpe_audio_probe, }; |