mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
sound fixes for 7.4-rc1
A collection of fixes across the sound subsystem since the initial
7.4 PR. Nothing particularly stands out, mostly driver- and
device-specific fixes along with a few race / UAF fixes and cleanups.
Here are some highlights:
* ALSA core:
- Fix potential race in PCM proc handling at disconnection
- Fix potential race in UMP sequencer callback at releasing
* HD-audio:
- Reject codec reset/reconfig on ASoC buses to prevent deadlock
- Force MSI for Hygon H34M51A board
- Usual Realtek quirks for ASUS and HP laptops/AiO
* USB-audio:
- Bound packet copies by PCM buffer size in generic and ua101 drivers
- Rate-limit URB submission errors at stream start
- Skip redundant probe-time interface setup on MSI ALC4080
- Device quirks for Novation UltraNova, MOTU MicroBook II, and RYDZ
Headphone
* ASoC:
- Fixes for runtime PM and IRQ handling in hdac_hda and SDCA
- SOF: Fix potential UAF at release, fix for Kconfig dependency
- Qualcomm: Fixes for sm8250 and q6apm/q6afe
- NXP / i.MX: Fix for pending work in hw_free
- Xilinx: Fix read-modify-write of AUD_CTRL in formatter_pcm
- Intel: Arrow Lake SoundWire match table additions (RT712, RT713 +
dual RT1320)
- AMD: DMI quirk for HP Laptop 14-em0xxx and memory leak fix in Raven
DMA close
- Various codec fixes for midas_wm1811, wm8994, cs35l56, cs42l56,
WSA881x/883x/884x, es8326/es8375/es9356, rt721/rt722, and
tlv320aic32x4
* Misc:
- OPL3: Fix races in timer initialization, shutdown, and voice cleanup
- Bounds checks and string helpers for AC97 and emu10k1
- Fix spu_memset() stride in legacy SH AICA driver
- Parameter handling fixes in pcmtest virtual driver
-----BEGIN PGP SIGNATURE-----
iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmrmFsAOHHRpd2FpQHN1
c2UuZGUACgkQLtJE4w1nLE8DzA//WKBXzuHaYoQCel0Ky0qbTjOsLJaI63D1+w6r
2SeeEjKIRhRVSGSuGvtMLKQ2IEFq9njhVCjnv9FK+bY2x4jrc6auSixOmXZNgplj
f39DlJjy4ZZ6N1M9LclbiHFPR7UuRlbgXqS6UR83ijapHGqTf5eWcL1RIHmiUZ3k
Xr6Yd2Q58u7sMRdwLIoXYum7VD/46iSTS/SQT5Iq8eQij7YVlVTglxUPTouCVWI7
rNm9TZe5VggJ77ADI2Fo3VRI+QhQU/BohZ7R155fpqroCvGKLmWppypkCqpxtc/u
DnVGI7Cq/TDoBh2u4GrtBhx+voyt84X2N1epJ6vZzp5VZc6cjBnKFynvsxuGH4ox
0hb9Syu70rUAtulJwefRuftXv/gl0coZJCS1NoPsoKy3pEBGHExjgBoCZv7oCNH9
chk4n7XFEb7yktN5bd6MG7yhdF1U6jwkpFyDphBTb992eaB0KTylx/JcmOzwxSun
MKcAq8jsigvoxfvjGhE1OugtOg0qgdNgW9vCD1xXwSaNRXFEGNoBHWE33Y4nq3GW
e5PqUkYI6k2cAVyosxS3N9h9H/5FfCQynC1VZECl7gdFKvhNgHVAFuVLzbQ/Hn8K
vYitKNrVdC07EubPuOyOiDqEMCqvtAv7acH11ABMkKdnqwbbi0MzZB15s1lt1vzh
er1a04E=
=zbju
-----END PGP SIGNATURE-----
Merge tag 'sound-fix-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound fixes from Takashi Iwai:
"A collection of fixes across the sound subsystem. Nothing particularly
stands out, mostly driver- and device-specific fixes along with a few
race / UAF fixes and cleanups. Here are some highlights:
ALSA core:
- Fix potential race in PCM proc handling at disconnection
- Fix potential race in UMP sequencer callback at releasing
HD-audio:
- Reject codec reset/reconfig on ASoC buses to prevent deadlock
- Force MSI for Hygon H34M51A board
- Usual Realtek quirks for ASUS and HP laptops/AiO
USB-audio:
- Bound packet copies by PCM buffer size in generic and ua101 drivers
- Rate-limit URB submission errors at stream start
- Skip redundant probe-time interface setup on MSI ALC4080
- Device quirks for Novation UltraNova, MOTU MicroBook II, and RYDZ
Headphone
ASoC:
- Fixes for runtime PM and IRQ handling in hdac_hda and SDCA
- SOF: Fix potential UAF at release, fix for Kconfig dependency
- Qualcomm: Fixes for sm8250 and q6apm/q6afe
- NXP / i.MX: Fix for pending work in hw_free
- Xilinx: Fix read-modify-write of AUD_CTRL in formatter_pcm
- Intel: Arrow Lake SoundWire match table additions (RT712, RT713 +
dual RT1320)
- AMD: DMI quirk for HP Laptop 14-em0xxx and memory leak fix in Raven
DMA close
- Various codec fixes for midas_wm1811, wm8994, cs35l56, cs42l56,
WSA881x/883x/884x, es8326/es8375/es9356, rt721/rt722, and
tlv320aic32x4
Misc:
- OPL3: Fix races in timer initialization, shutdown, and voice
cleanup
- Bounds checks and string helpers for AC97 and emu10k1
- Fix spu_memset() stride in legacy SH AICA driver
- Parameter handling fixes in pcmtest virtual driver"
* tag 'sound-fix-7.4-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (71 commits)
ASoC: SOF: Intel: hda: Stop the controller before freeing its DMA buffers
ASoC: imx-pcm-rpmsg: Flush pending work in hw_free
ASoC: xilinx: formatter_pcm: Fix read-modify-write of AUD_CTRL in hw_params
ASoC: hdac_hda: Keep runtime PM state in sync across codec remove/probe
ASoC: rt721: Remove invalid register defaults
ASoC: hdac_hda: Balance the runtime PM disable in codec remove
ASoC: hdac_hda: Restore the codec device type on unbind
ASoC: hdac_hda: Allocate the private data at codec driver bind
ASoC: qcom: sm8250: Limit RX digital gain to 0 dB
ALSA: hda: Reject codec reset on ASoC (ext_ops) buses
ALSA: usb-audio: add quirk for Novation UltraNova (1235:0011)
ALSA: usb-audio: Add correct datainterval in the quirks-table for Microbook II
ALSA: usb-audio: Skip probe-time interface setup for MSI MAG X570S ALC4080
ALSA: hda/realtek: Extend quirk for HP Pavilion All-in-One 27-ca1xxx
ALSA: pcmtest: Honor the enable parameter
ALSA: ua101: Bound packet copies by the PCM buffer size
ALSA: usb-audio: Bound packet copies by the PCM buffer size
ASoC: SDCA: re-enable IRQ on pm_runtime_force_suspend failure
ASoC: SDCA: drop pm_runtime reference on probe failure path
ASoC: SDCA: propagate sdw_slave_read_prop() failure in class_read_prop
...
This commit is contained in:
commit
e9954f3fbd
|
|
@ -209,6 +209,9 @@ struct snd_ctl_elem_value;
|
|||
|
||||
#define CS35L56_GPIO_FN_GPIO 0x00000001
|
||||
|
||||
/* DSP1_FW_VER */
|
||||
#define CS35L56_FW_MAIN_VERSION_MASK GENMASK(19, 0)
|
||||
|
||||
/* Mixer input sources */
|
||||
#define CS35L56_INPUT_SRC_NONE 0x00
|
||||
#define CS35L56_INPUT_SRC_ASP1RX1 0x08
|
||||
|
|
@ -446,6 +449,7 @@ int cs35l56_cal_set_status_get(struct cs35l56_base *cs35l56_base,
|
|||
int cs35l56_read_prot_status(struct cs35l56_base *cs35l56_base,
|
||||
bool *fw_missing, unsigned int *fw_version);
|
||||
void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base);
|
||||
bool cs35l56_needs_wait_for_firmware_timer_expiry(struct cs35l56_base *cs35l56_base);
|
||||
void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp);
|
||||
int cs35l56_hw_init(struct cs35l56_base *cs35l56_base);
|
||||
int cs35l56_get_speaker_id(struct cs35l56_base *cs35l56_base);
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ struct snd_info_entry *snd_info_create_module_entry(struct module *module,
|
|||
struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
|
||||
const char *name,
|
||||
struct snd_info_entry *parent);
|
||||
void snd_info_disconnect_entry(struct snd_info_entry *entry);
|
||||
void snd_info_free_entry(struct snd_info_entry *entry);
|
||||
|
||||
int snd_info_card_create(struct snd_card *card);
|
||||
|
|
@ -164,6 +165,7 @@ static inline int snd_info_get_line(struct snd_info_buffer *buffer, char *line,
|
|||
static inline char *snd_info_get_str(char *dest, char *src, int len) { return NULL; }
|
||||
static inline struct snd_info_entry *snd_info_create_module_entry(struct module *module, const char *name, struct snd_info_entry *parent) { return NULL; }
|
||||
static inline struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry *parent) { return NULL; }
|
||||
static inline void snd_info_disconnect_entry(struct snd_info_entry *entry) { }
|
||||
static inline void snd_info_free_entry(struct snd_info_entry *entry) { ; }
|
||||
|
||||
static inline int snd_info_card_create(struct snd_card *card) { return 0; }
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ struct snd_ump_endpoint {
|
|||
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
struct snd_seq_device *seq_dev;
|
||||
/* Published after seq_client; calls are covered by UMP core SRCU. */
|
||||
const struct snd_seq_ump_ops *seq_ops;
|
||||
void *seq_client;
|
||||
#endif
|
||||
|
|
@ -126,6 +127,10 @@ int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val);
|
|||
int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol);
|
||||
void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump);
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
void snd_ump_detach_seq(struct snd_ump_endpoint *ump);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some definitions for UMP
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -737,6 +737,23 @@ static void snd_info_clear_entries(struct snd_info_entry *entry)
|
|||
entry->p = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_info_disconnect_entry - remove proc nodes and drain their callbacks
|
||||
* @entry: root of the info entry subtree
|
||||
*
|
||||
* Retains the info entries for snd_info_free_entry(). Callers must serialize
|
||||
* registration and destruction, and must not hold locks needed by callbacks.
|
||||
*/
|
||||
void snd_info_disconnect_entry(struct snd_info_entry *entry)
|
||||
{
|
||||
if (entry && entry->p) {
|
||||
proc_remove(entry->p);
|
||||
guard(mutex)(&info_mutex);
|
||||
snd_info_clear_entries(entry);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(snd_info_disconnect_entry);
|
||||
|
||||
/**
|
||||
* snd_info_free_entry - release the info entry
|
||||
* @entry: the info entry
|
||||
|
|
@ -749,11 +766,7 @@ void snd_info_free_entry(struct snd_info_entry * entry)
|
|||
|
||||
if (!entry)
|
||||
return;
|
||||
if (entry->p) {
|
||||
proc_remove(entry->p);
|
||||
guard(mutex)(&info_mutex);
|
||||
snd_info_clear_entries(entry);
|
||||
}
|
||||
snd_info_disconnect_entry(entry);
|
||||
|
||||
/* free all children at first */
|
||||
list_for_each_entry_safe(p, n, &entry->children, list)
|
||||
|
|
|
|||
|
|
@ -520,6 +520,11 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void snd_pcm_stream_proc_disconnect(struct snd_pcm_str *pstr)
|
||||
{
|
||||
snd_info_disconnect_entry(pstr->proc_root);
|
||||
}
|
||||
|
||||
static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
|
||||
{
|
||||
snd_info_free_entry(pstr->proc_root);
|
||||
|
|
@ -580,6 +585,7 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
|
|||
|
||||
#else /* !CONFIG_SND_VERBOSE_PROCFS */
|
||||
static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; }
|
||||
static inline void snd_pcm_stream_proc_disconnect(struct snd_pcm_str *pstr) { }
|
||||
static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; }
|
||||
static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; }
|
||||
#endif /* CONFIG_SND_VERBOSE_PROCFS */
|
||||
|
|
@ -1094,33 +1100,37 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
|
|||
int cidx;
|
||||
|
||||
guard(mutex)(®ister_mutex);
|
||||
guard(mutex)(&pcm->open_mutex);
|
||||
wake_up(&pcm->open_wait);
|
||||
list_del_init(&pcm->list);
|
||||
scoped_guard(mutex, &pcm->open_mutex) {
|
||||
wake_up(&pcm->open_wait);
|
||||
list_del_init(&pcm->list);
|
||||
|
||||
for_each_pcm_substream(pcm, cidx, substream) {
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (substream->runtime) {
|
||||
if (snd_pcm_running(substream))
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
||||
/* to be sure, set the state unconditionally */
|
||||
__snd_pcm_set_state(substream->runtime,
|
||||
SNDRV_PCM_STATE_DISCONNECTED);
|
||||
wake_up(&substream->runtime->sleep);
|
||||
wake_up(&substream->runtime->tsleep);
|
||||
for_each_pcm_substream(pcm, cidx, substream) {
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
if (substream->runtime) {
|
||||
if (snd_pcm_running(substream))
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
||||
/* to be sure, set the state unconditionally */
|
||||
__snd_pcm_set_state(substream->runtime,
|
||||
SNDRV_PCM_STATE_DISCONNECTED);
|
||||
wake_up(&substream->runtime->sleep);
|
||||
wake_up(&substream->runtime->tsleep);
|
||||
}
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
|
||||
for_each_pcm_substream(pcm, cidx, substream)
|
||||
snd_pcm_sync_stop(substream, false);
|
||||
for_each_pcm_substream(pcm, cidx, substream)
|
||||
snd_pcm_sync_stop(substream, false);
|
||||
|
||||
pcm_call_notify(pcm, n_disconnect);
|
||||
for (cidx = 0; cidx < 2; cidx++) {
|
||||
if (pcm->streams[cidx].dev)
|
||||
snd_unregister_device(pcm->streams[cidx].dev);
|
||||
free_chmap(&pcm->streams[cidx]);
|
||||
pcm_call_notify(pcm, n_disconnect);
|
||||
for (cidx = 0; cidx < 2; cidx++) {
|
||||
if (pcm->streams[cidx].dev)
|
||||
snd_unregister_device(pcm->streams[cidx].dev);
|
||||
free_chmap(&pcm->streams[cidx]);
|
||||
}
|
||||
}
|
||||
/* Proc rundown can run release callbacks which take open_mutex. */
|
||||
for (cidx = 0; cidx < 2; cidx++)
|
||||
snd_pcm_stream_proc_disconnect(&pcm->streams[cidx]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -353,12 +353,12 @@ static int create_ump_endpoint_port(struct seq_ump_client *client)
|
|||
/* release the client resources */
|
||||
static void seq_ump_client_free(struct seq_ump_client *client)
|
||||
{
|
||||
snd_ump_detach_seq(client->ump);
|
||||
cancel_work_sync(&client->group_notify_work);
|
||||
|
||||
if (client->seq_client >= 0)
|
||||
snd_seq_delete_kernel_client(client->seq_client);
|
||||
|
||||
client->ump->seq_ops = NULL;
|
||||
client->ump->seq_client = NULL;
|
||||
|
||||
kfree(client);
|
||||
|
|
@ -523,7 +523,8 @@ static int snd_seq_ump_probe(struct snd_seq_device *dev)
|
|||
snd_seq_kernel_client_put(cptr);
|
||||
|
||||
ump->seq_client = client;
|
||||
ump->seq_ops = &seq_ump_ops;
|
||||
/* Publish the initialized client before callbacks can observe seq_ops. */
|
||||
smp_store_release(&ump->seq_ops, &seq_ump_ops);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/srcu.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/rawmidi.h>
|
||||
#include <sound/ump.h>
|
||||
|
|
@ -18,6 +19,31 @@
|
|||
#define ump_info(ump, fmt, args...) dev_info((ump)->core.dev, fmt, ##args)
|
||||
#define ump_dbg(ump, fmt, args...) dev_dbg((ump)->core.dev, fmt, ##args)
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
DEFINE_STATIC_SRCU(ump_seq_srcu);
|
||||
|
||||
static const struct snd_seq_ump_ops *seq_ops_load(struct snd_ump_endpoint *ump)
|
||||
{
|
||||
/* Pair with publication after seq_client has been initialized. */
|
||||
return smp_load_acquire(&ump->seq_ops);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_ump_detach_seq - stop callbacks to a sequencer binding
|
||||
* @ump: UMP endpoint
|
||||
*
|
||||
* Withdraw the binding and wait for all callbacks already in progress.
|
||||
* The caller can then drain binding work and free the sequencer client.
|
||||
* Must not be called from one of the binding callbacks.
|
||||
*/
|
||||
void snd_ump_detach_seq(struct snd_ump_endpoint *ump)
|
||||
{
|
||||
WRITE_ONCE(ump->seq_ops, NULL);
|
||||
synchronize_srcu(&ump_seq_srcu);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_ump_detach_seq);
|
||||
#endif
|
||||
|
||||
static int snd_ump_dev_register(struct snd_rawmidi *rmidi);
|
||||
static int snd_ump_dev_unregister(struct snd_rawmidi *rmidi);
|
||||
static long snd_ump_ioctl(struct snd_rawmidi *rmidi, unsigned int cmd,
|
||||
|
|
@ -348,8 +374,13 @@ int snd_ump_receive(struct snd_ump_endpoint *ump, const u32 *buffer, int count)
|
|||
continue;
|
||||
ump_handle_stream_msg(ump, ump->input_buf, n);
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
if (ump->seq_ops)
|
||||
ump->seq_ops->input_receive(ump, ump->input_buf, n);
|
||||
scoped_guard(srcu, &ump_seq_srcu) {
|
||||
const struct snd_seq_ump_ops *ops;
|
||||
|
||||
ops = seq_ops_load(ump);
|
||||
if (ops)
|
||||
ops->input_receive(ump, ump->input_buf, n);
|
||||
}
|
||||
#endif
|
||||
process_legacy_input(ump, ump->input_buf, n);
|
||||
}
|
||||
|
|
@ -559,6 +590,7 @@ static void snd_ump_proc_read(struct snd_info_entry *entry,
|
|||
/* update dir_bits and active flag for all groups in the client */
|
||||
void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
|
||||
{
|
||||
static const char separator[] = ", ";
|
||||
struct snd_ump_block *fb;
|
||||
struct snd_ump_group *group;
|
||||
int i;
|
||||
|
|
@ -598,7 +630,8 @@ void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
|
|||
if (!*fb->info.name)
|
||||
continue;
|
||||
if (*group->name)
|
||||
strlcat(group->name, ", ", sizeof(group->name));
|
||||
safe_append_string(group->name, sizeof(group->name),
|
||||
separator, sizeof(separator));
|
||||
safe_append_string(group->name, sizeof(group->name),
|
||||
fb->info.name, sizeof(fb->info.name));
|
||||
}
|
||||
|
|
@ -699,8 +732,12 @@ static void choose_default_protocol(struct snd_ump_endpoint *ump)
|
|||
static void seq_notify_ep_change(struct snd_ump_endpoint *ump)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
if (ump->parsed && ump->seq_ops && ump->seq_ops->notify_ep_change)
|
||||
ump->seq_ops->notify_ep_change(ump);
|
||||
const struct snd_seq_ump_ops *ops;
|
||||
|
||||
guard(srcu)(&ump_seq_srcu);
|
||||
ops = seq_ops_load(ump);
|
||||
if (ump->parsed && ops && ops->notify_ep_change)
|
||||
ops->notify_ep_change(ump);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -797,8 +834,12 @@ static int ump_handle_product_id_msg(struct snd_ump_endpoint *ump,
|
|||
static void seq_notify_protocol(struct snd_ump_endpoint *ump)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
if (ump->seq_ops && ump->seq_ops->switch_protocol)
|
||||
ump->seq_ops->switch_protocol(ump);
|
||||
const struct snd_seq_ump_ops *ops;
|
||||
|
||||
guard(srcu)(&ump_seq_srcu);
|
||||
ops = seq_ops_load(ump);
|
||||
if (ops && ops->switch_protocol)
|
||||
ops->switch_protocol(ump);
|
||||
#endif /* CONFIG_SND_SEQUENCER */
|
||||
}
|
||||
|
||||
|
|
@ -893,8 +934,12 @@ static void seq_notify_fb_change(struct snd_ump_endpoint *ump,
|
|||
struct snd_ump_block *fb)
|
||||
{
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER)
|
||||
if (ump->seq_ops && ump->seq_ops->notify_fb_change)
|
||||
ump->seq_ops->notify_fb_change(ump, fb);
|
||||
const struct snd_seq_ump_ops *ops;
|
||||
|
||||
guard(srcu)(&ump_seq_srcu);
|
||||
ops = seq_ops_load(ump);
|
||||
if (ops && ops->notify_fb_change)
|
||||
ops->notify_fb_change(ump, fb);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -632,6 +632,21 @@ static void snd_opl3_kill_voice(struct snd_opl3 *opl3, int voice)
|
|||
|
||||
}
|
||||
|
||||
void snd_opl3_clear_voices(struct snd_opl3 *opl3)
|
||||
{
|
||||
int i;
|
||||
|
||||
guard(spinlock_irqsave)(&opl3->voice_lock);
|
||||
/* A 4-op primary clears its higher-numbered partner's state. */
|
||||
for (i = MAX_OPL3_VOICES - 1; i >= 0; i--) {
|
||||
if (opl3->voices[i].state > 0)
|
||||
snd_opl3_kill_voice(opl3, i);
|
||||
opl3->voices[i].chan = NULL;
|
||||
opl3->voices[i].note_off_check = 0;
|
||||
opl3->voices[i].state = SNDRV_OPL3_ST_OFF;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a note in response to a midi note off.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ static void snd_opl3_oss_free_port(void *private_data)
|
|||
{
|
||||
struct snd_opl3 *opl3 = private_data;
|
||||
|
||||
snd_opl3_clear_voices(opl3);
|
||||
snd_midi_channel_free_set(opl3->oss_chset);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ static void snd_opl3_synth_free_port(void *private_data)
|
|||
{
|
||||
struct snd_opl3 *opl3 = private_data;
|
||||
|
||||
snd_opl3_clear_voices(opl3);
|
||||
snd_midi_channel_free_set(opl3->chset);
|
||||
}
|
||||
|
||||
|
|
@ -214,6 +215,11 @@ static int snd_opl3_seq_probe(struct snd_seq_device *dev)
|
|||
|
||||
spin_lock_init(&opl3->voice_lock);
|
||||
|
||||
/* Initialize the timer before an attached port can receive events. */
|
||||
timer_setup(&opl3->tlist, snd_opl3_timer_func, 0);
|
||||
spin_lock_init(&opl3->sys_timer_lock);
|
||||
opl3->sys_timer_status = 0;
|
||||
|
||||
opl3->seq_client = -1;
|
||||
|
||||
/* allocate new client */
|
||||
|
|
@ -232,11 +238,6 @@ static int snd_opl3_seq_probe(struct snd_seq_device *dev)
|
|||
return err;
|
||||
}
|
||||
|
||||
/* setup system timer */
|
||||
timer_setup(&opl3->tlist, snd_opl3_timer_func, 0);
|
||||
spin_lock_init(&opl3->sys_timer_lock);
|
||||
opl3->sys_timer_status = 0;
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SEQUENCER_OSS)
|
||||
snd_opl3_init_seq_oss(opl3, name);
|
||||
#endif
|
||||
|
|
@ -258,6 +259,8 @@ static void snd_opl3_seq_remove(struct snd_seq_device *dev)
|
|||
snd_seq_delete_kernel_client(opl3->seq_client);
|
||||
opl3->seq_client = -1;
|
||||
}
|
||||
/* Stop the shared timer after all event callbacks have been drained. */
|
||||
timer_shutdown_sync(&opl3->tlist);
|
||||
}
|
||||
|
||||
static struct snd_seq_driver opl3_seq_driver = {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ int snd_opl3_synth_use_inc(struct snd_opl3 * opl3);
|
|||
void snd_opl3_synth_use_dec(struct snd_opl3 * opl3);
|
||||
int snd_opl3_synth_setup(struct snd_opl3 * opl3);
|
||||
void snd_opl3_synth_cleanup(struct snd_opl3 * opl3);
|
||||
void snd_opl3_clear_voices(struct snd_opl3 *opl3);
|
||||
|
||||
/* Prototypes for opl3_midi.c */
|
||||
void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan);
|
||||
|
|
|
|||
|
|
@ -72,13 +72,32 @@ static u8 playback_capture_test;
|
|||
static u8 ioctl_reset_test;
|
||||
static struct dentry *driver_debug_dir;
|
||||
|
||||
static int fill_mode_set(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
short mode;
|
||||
int err;
|
||||
|
||||
err = kstrtos16(val, 0, &mode);
|
||||
if (err)
|
||||
return err;
|
||||
if (mode != FILL_MODE_RAND && mode != FILL_MODE_PAT)
|
||||
return -EINVAL;
|
||||
fill_mode = mode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops fill_mode_ops = {
|
||||
.set = fill_mode_set,
|
||||
.get = param_get_short,
|
||||
};
|
||||
|
||||
module_param(index, int, 0444);
|
||||
MODULE_PARM_DESC(index, "Index value for pcmtest soundcard");
|
||||
module_param(id, charp, 0444);
|
||||
MODULE_PARM_DESC(id, "ID string for pcmtest soundcard");
|
||||
module_param(enable, bool, 0444);
|
||||
MODULE_PARM_DESC(enable, "Enable pcmtest soundcard.");
|
||||
module_param(fill_mode, short, 0600);
|
||||
module_param_cb(fill_mode, &fill_mode_ops, &fill_mode, 0600);
|
||||
MODULE_PARM_DESC(fill_mode, "Buffer fill mode: rand(0) or pattern(1)");
|
||||
module_param(inject_delay, int, 0600);
|
||||
MODULE_PARM_DESC(inject_delay, "Inject delays during playback/capture (in jiffies)");
|
||||
|
|
@ -693,6 +712,9 @@ static int __init mod_init(void)
|
|||
{
|
||||
int err = 0;
|
||||
|
||||
if (!enable)
|
||||
return -ENODEV;
|
||||
|
||||
buf_allocated = setup_patt_bufs();
|
||||
if (!buf_allocated)
|
||||
return -ENOMEM;
|
||||
|
|
|
|||
|
|
@ -4492,6 +4492,7 @@ enum {
|
|||
ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT,
|
||||
ALC245_FIXUP_HP_MUTE_LED_V2_COEFBIT,
|
||||
ALC245_FIXUP_HP_X360_MUTE_LEDS,
|
||||
ALC245_FIXUP_HP_PAVILION_14_EW1XXX_LEDS,
|
||||
ALC287_FIXUP_THINKPAD_I2S_SPK,
|
||||
ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
|
||||
ALC287_FIXUP_CS35L41_I2C_4_THINKPAD_ACPI,
|
||||
|
|
@ -7113,6 +7114,12 @@ static const struct hda_fixup alc269_fixups[] = {
|
|||
.chained = true,
|
||||
.chain_id = ALC245_FIXUP_HP_GPIO_LED
|
||||
},
|
||||
[ALC245_FIXUP_HP_PAVILION_14_EW1XXX_LEDS] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc245_fixup_hp_mute_led_v2_coefbit,
|
||||
.chained = true,
|
||||
.chain_id = ALC245_FIXUP_HP_GPIO_LED
|
||||
},
|
||||
[ALC287_FIXUP_THINKPAD_I2S_SPK] = {
|
||||
.type = HDA_FIXUP_FUNC,
|
||||
.v.func = alc287_fixup_bind_dacs,
|
||||
|
|
@ -7869,6 +7876,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8a4f, "HP Victus 15-fa0xxx (MB 8A4F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8a50, "HP Victus 15-fa0xxx (MB 8A50)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8a6b, "HP Pavilion All-in-One Desktop 27-ca1xxx", ALC274_FIXUP_HP_VERBS),
|
||||
SND_PCI_QUIRK(0x103c, 0x89e9, "HP Pavilion All-in-One Desktop 27-ca1xxx", ALC274_FIXUP_HP_VERBS),
|
||||
SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
|
||||
SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8a75, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
|
||||
|
|
@ -7951,6 +7959,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8c2d, "HP Victus 15-fa1xxx (MB 8C2D)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8c2f, "HP Victus 15-fb2xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8c31, "HP Pavilion Plus Laptop 14-ew1xxx", ALC245_FIXUP_HP_PAVILION_14_EW1XXX_LEDS),
|
||||
SND_PCI_QUIRK(0x103c, 0x8c3f, "HP Victus 15-fa1xxx (MB 8C3F)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
|
||||
SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
|
||||
|
|
@ -8060,6 +8069,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e43, "HP Laptop 15-fd2xxx", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_GPIO),
|
||||
HDA_CODEC_QUIRK(0x103c, 0x84ee, "HP Pavilion AiO 24", ALC225_FIXUP_HP_AIO_SPK),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e60, "HP OmniBook 7 Laptop 16-bh0xxx", ALC245_FIXUP_CS35L41_I2C_2_MUTE_LED),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
|
|
@ -8214,6 +8224,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
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, 0x1e03, "ASUS ExpertBook B3402FVA", ALC256_FIXUP_ASUS_HPE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e3e, "ASUS VivoBook M515DA/X515DAP", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
|
||||
|
|
@ -8226,6 +8237,7 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
|
|||
SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
|
||||
SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
|
||||
SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RC72LA", ALC287_FIXUP_ASUS_ALLY_X),
|
||||
SND_PCI_QUIRK(0x1043, 0x1ec1, "ASUS X509JB", ALC2XX_FIXUP_HEADSET_MIC),
|
||||
SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
|
||||
SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1),
|
||||
SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
|
||||
|
|
|
|||
|
|
@ -1807,6 +1807,12 @@ int snd_hda_codec_reset(struct hda_codec *codec)
|
|||
{
|
||||
struct hda_bus *bus = codec->bus;
|
||||
|
||||
/* ASoC: driver unbind frees the card, incl. the hwdep issuing the reset */
|
||||
if (bus->core.ext_ops) {
|
||||
codec_err(codec, "Codec reset is not supported with ASoC\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (snd_hda_lock_devices(bus) < 0)
|
||||
return -EBUSY;
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,8 @@ static int clear_codec(struct hda_codec *codec)
|
|||
int err;
|
||||
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err == -EOPNOTSUPP)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
codec_err(codec, "The codec is being used, can't free.\n");
|
||||
return err;
|
||||
|
|
@ -132,6 +134,8 @@ static int reconfig_codec(struct hda_codec *codec)
|
|||
CLASS(snd_hda_power, pm)(codec);
|
||||
codec_info(codec, "hda-codec: reconfiguring\n");
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err == -EOPNOTSUPP)
|
||||
return err;
|
||||
if (err < 0) {
|
||||
codec_err(codec,
|
||||
"The codec is being used, can't reconfigure.\n");
|
||||
|
|
|
|||
|
|
@ -1668,6 +1668,7 @@ static const struct snd_pci_quirk msi_deny_list[] = {
|
|||
SND_PCI_QUIRK(0x1179, 0xfb44, "Toshiba Satellite C870", 0), /* AMD Hudson */
|
||||
SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
|
||||
SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */
|
||||
SND_PCI_QUIRK(0x1d94, 0xc950, "Hygon H34M51A", 1), /* INTx broken */
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
@ -2329,6 +2330,7 @@ static const struct snd_pci_quirk power_save_denylist[] = {
|
|||
SND_PCI_QUIRK(0x17aa, 0x5079, "Lenovo Thinkpad E15", 0),
|
||||
/* https://bugzilla.kernel.org/show_bug.cgi?id=220694 */
|
||||
SND_PCI_QUIRK(0x103c, 0x8a6b, "HP 89E9", 0),
|
||||
SND_PCI_QUIRK(0x103c, 0x89e9, "HP 89E9", 0),
|
||||
{}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1832,36 +1832,39 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name,
|
|||
size_t maxlen, int modem)
|
||||
{
|
||||
const struct ac97_codec_id *pid;
|
||||
size_t len;
|
||||
|
||||
sprintf(name, "0x%x %c%c%c", id,
|
||||
printable(id >> 24),
|
||||
printable(id >> 16),
|
||||
printable(id >> 8));
|
||||
pid = look_for_codec_id(snd_ac97_codec_id_vendors, id);
|
||||
if (! pid)
|
||||
if (!pid) {
|
||||
snprintf(name, maxlen, "0x%x %c%c%c", id,
|
||||
printable(id >> 24),
|
||||
printable(id >> 16),
|
||||
printable(id >> 8));
|
||||
return;
|
||||
}
|
||||
|
||||
strscpy(name, pid->name, maxlen);
|
||||
if (ac97 && pid->patch) {
|
||||
if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||
|
||||
(! modem && ! (pid->flags & AC97_MODEM_PATCH)))
|
||||
(!modem && !(pid->flags & AC97_MODEM_PATCH)))
|
||||
pid->patch(ac97);
|
||||
}
|
||||
}
|
||||
|
||||
len = strnlen(name, maxlen);
|
||||
pid = look_for_codec_id(snd_ac97_codec_ids, id);
|
||||
if (pid) {
|
||||
strlcat(name, " ", maxlen);
|
||||
strlcat(name, pid->name, maxlen);
|
||||
if (pid->mask != 0xffffffff)
|
||||
sprintf(name + strlen(name), " rev %u", id & ~pid->mask);
|
||||
snprintf(name + len, maxlen - len, " %s rev %u",
|
||||
pid->name, id & ~pid->mask);
|
||||
else
|
||||
snprintf(name + len, maxlen - len, " %s", pid->name);
|
||||
if (ac97 && pid->patch) {
|
||||
if ((modem && (pid->flags & AC97_MODEM_PATCH)) ||
|
||||
(! modem && ! (pid->flags & AC97_MODEM_PATCH)))
|
||||
(!modem && !(pid->flags & AC97_MODEM_PATCH)))
|
||||
pid->patch(ac97);
|
||||
}
|
||||
} else {
|
||||
int l = strlen(name);
|
||||
snprintf(name + l, maxlen - l, " id %x", id & 0xff);
|
||||
snprintf(name + len, maxlen - len, " id %x", id & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2423,12 +2423,12 @@ static int snd_emu10k1_fx8010_open(struct snd_hwdep * hw, struct file *file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void copy_string(char *dst, const char *src, const char *null, int idx)
|
||||
static void copy_string(char *dst, size_t size, const char *src, const char *null, int idx)
|
||||
{
|
||||
if (src == NULL)
|
||||
sprintf(dst, "%s %02X", null, idx);
|
||||
snprintf(dst, size, "%s %02X", null, idx);
|
||||
else
|
||||
strcpy(dst, src);
|
||||
strscpy(dst, src, size);
|
||||
}
|
||||
|
||||
static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
|
||||
|
|
@ -2446,12 +2446,16 @@ static void snd_emu10k1_fx8010_info(struct snd_emu10k1 *emu,
|
|||
extin_mask = emu->audigy ? ~0 : emu->fx8010.extin_mask;
|
||||
extout_mask = emu->audigy ? ~0 : emu->fx8010.extout_mask;
|
||||
for (res = 0; res < 16; res++, fxbus++, extin++, extout++) {
|
||||
copy_string(info->fxbus_names[res], *fxbus, "FXBUS", res);
|
||||
copy_string(info->extin_names[res], extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
|
||||
copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
|
||||
copy_string(info->fxbus_names[res], sizeof(info->fxbus_names[res]),
|
||||
*fxbus, "FXBUS", res);
|
||||
copy_string(info->extin_names[res], sizeof(info->extin_names[res]),
|
||||
extin_mask & (1 << res) ? *extin : NULL, "Unused", res);
|
||||
copy_string(info->extout_names[res], sizeof(info->extout_names[res]),
|
||||
extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
|
||||
}
|
||||
for (res = 16; res < 32; res++, extout++)
|
||||
copy_string(info->extout_names[res], extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
|
||||
copy_string(info->extout_names[res], sizeof(info->extout_names[res]),
|
||||
extout_mask & (1 << res) ? *extout : NULL, "Unused", res);
|
||||
info->gpr_controls = emu->fx8010.gpr_count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ static void spu_memset(u32 toi, u32 what, int length)
|
|||
local_irq_save(flags);
|
||||
writel(what, toi + SPU_MEMORY_BASE);
|
||||
local_irq_restore(flags);
|
||||
toi++;
|
||||
toi += sizeof(what);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -360,6 +360,8 @@ static int acp3x_dma_close(struct snd_soc_component *component,
|
|||
}
|
||||
}
|
||||
|
||||
kfree(ins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -759,6 +759,13 @@ static const struct dmi_system_id yc_acp_quirk_table[] = {
|
|||
DMI_MATCH(DMI_BOARD_NAME, "8BD6"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "HP"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "8DC2"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.driver_data = &acp6x_card,
|
||||
.matches = {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/device.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/soundwire/sdw.h>
|
||||
|
|
@ -36,6 +37,9 @@
|
|||
#define CS35L56_LATE_READ_POLL_US 10
|
||||
#define CS35L56_LATE_READ_TIMEOUT_US 1000
|
||||
|
||||
static DEFINE_MUTEX(cs35l56_fw_idle_wait_lock);
|
||||
static bool cs35l56_fw_idle_wait_pending;
|
||||
|
||||
static int cs35l56_sdw_poll_mem_status(struct sdw_slave *peripheral,
|
||||
unsigned int mask,
|
||||
unsigned int match)
|
||||
|
|
@ -387,14 +391,34 @@ static int __maybe_unused cs35l56_sdw_runtime_resume(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int cs35l56_sdw_system_suspend_prepare(struct device *dev)
|
||||
{
|
||||
cs35l56_fw_idle_wait_pending = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused cs35l56_sdw_system_suspend(struct device *dev)
|
||||
{
|
||||
struct cs35l56_private *cs35l56 = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
if (cs35l56->sdw_attached)
|
||||
cs35l56_mask_soundwire_interrupts(cs35l56);
|
||||
|
||||
return cs35l56_system_suspend(dev);
|
||||
ret = cs35l56_system_suspend(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
scoped_guard(mutex, &cs35l56_fw_idle_wait_lock) {
|
||||
if (cs35l56_fw_idle_wait_pending && cs35l56->needs_wait_for_fw_idle) {
|
||||
dev_dbg(cs35l56->base.dev, "Wait for FW timer expiry\n");
|
||||
msleep(CS35L56_FW_REQ_ACTIVE_TIMEOUT_MS + 10);
|
||||
cs35l56_fw_idle_wait_pending = false;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cs35l56_sdw_probe(struct sdw_slave *peripheral, const struct sdw_device_id *id)
|
||||
|
|
@ -460,6 +484,7 @@ static void cs35l56_sdw_remove(struct sdw_slave *peripheral)
|
|||
}
|
||||
|
||||
static const struct dev_pm_ops cs35l56_sdw_pm = {
|
||||
.prepare = cs35l56_sdw_system_suspend_prepare,
|
||||
SET_RUNTIME_PM_OPS(cs35l56_sdw_runtime_suspend, cs35l56_sdw_runtime_resume, NULL)
|
||||
SYSTEM_SLEEP_PM_OPS(cs35l56_sdw_system_suspend, cs35l56_system_resume)
|
||||
LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_system_suspend_late, cs35l56_system_resume_early)
|
||||
|
|
|
|||
|
|
@ -1379,6 +1379,44 @@ void cs35l56_warn_if_firmware_missing(struct cs35l56_base *cs35l56_base)
|
|||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cs35l56_warn_if_firmware_missing, "SND_SOC_CS35L56_SHARED");
|
||||
|
||||
bool cs35l56_needs_wait_for_firmware_timer_expiry(struct cs35l56_base *cs35l56_base)
|
||||
{
|
||||
unsigned int fw_ver;
|
||||
bool prot_sts;
|
||||
int ret;
|
||||
|
||||
switch (cs35l56_base->type) {
|
||||
case 0x54:
|
||||
case 0x56:
|
||||
case 0x57:
|
||||
switch (cs35l56_base->rev) {
|
||||
case 0xb0:
|
||||
ret = cs35l56_read_prot_status(cs35l56_base, &prot_sts, &fw_ver);
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
if ((fw_ver & CS35L56_FW_MAIN_VERSION_MASK) < 0x30d07)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
case 0xb2:
|
||||
ret = cs35l56_read_prot_status(cs35l56_base, &prot_sts, &fw_ver);
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
if ((fw_ver & CS35L56_FW_MAIN_VERSION_MASK) < 0x40710)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(cs35l56_needs_wait_for_firmware_timer_expiry, "SND_SOC_CS35L56_SHARED");
|
||||
|
||||
void cs35l56_log_tuning(struct cs35l56_base *cs35l56_base, struct cs_dsp *cs_dsp)
|
||||
{
|
||||
__be32 pid, sid, tid;
|
||||
|
|
|
|||
|
|
@ -1703,6 +1703,10 @@ int cs35l56_system_resume(struct device *dev)
|
|||
|
||||
dev_dbg(dev, "system_resume\n");
|
||||
|
||||
/* Assume the firmware reset to default until we can check it */
|
||||
if (cs35l56->base.init_done)
|
||||
cs35l56->needs_wait_for_fw_idle = true;
|
||||
|
||||
/*
|
||||
* We might have done a hard reset or the CS35L56 was power-cycled
|
||||
* so wait for control port to be ready.
|
||||
|
|
@ -1717,6 +1721,16 @@ int cs35l56_system_resume(struct device *dev)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cs35l56->sdw_peripheral && cs35l56->base.init_done) {
|
||||
ret = pm_runtime_resume_and_get(cs35l56->base.dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
cs35l56->needs_wait_for_fw_idle =
|
||||
cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base);
|
||||
pm_runtime_put_autosuspend(cs35l56->base.dev);
|
||||
}
|
||||
|
||||
/* Firmware won't have been loaded if the component hasn't probed */
|
||||
if (!cs35l56->component)
|
||||
return 0;
|
||||
|
|
@ -2241,6 +2255,9 @@ int cs35l56_init(struct cs35l56_private *cs35l56)
|
|||
if (ret)
|
||||
return dev_err_probe(cs35l56->base.dev, ret, "Failed to write ASP1_CONTROL3\n");
|
||||
|
||||
cs35l56->needs_wait_for_fw_idle =
|
||||
cs35l56_needs_wait_for_firmware_timer_expiry(&cs35l56->base);
|
||||
|
||||
cs35l56->base.init_done = true;
|
||||
complete_all(&cs35l56->init_completion);
|
||||
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ struct cs35l56_private {
|
|||
bool soft_resetting;
|
||||
bool sdw_attached;
|
||||
bool component_registered;
|
||||
bool needs_wait_for_fw_idle;
|
||||
struct completion init_completion;
|
||||
|
||||
int speaker_id;
|
||||
|
|
|
|||
|
|
@ -419,7 +419,6 @@ static const struct snd_kcontrol_new cs42l56_snd_controls[] = {
|
|||
CS42L56_PGAB_MUX_VOLUME, 0, 0x34, 0x24, pga_tlv),
|
||||
SOC_DOUBLE_R_TLV("ADC Volume", CS42L56_ADCA_ATTENUATOR,
|
||||
CS42L56_ADCB_ATTENUATOR, 0, 0x00, 1, adc_tlv),
|
||||
SOC_DOUBLE("ADC Mute Switch", CS42L56_MISC_ADC_CTL, 2, 3, 1, 1),
|
||||
SOC_DOUBLE("ADC Boost Switch", CS42L56_GAIN_BIAS_CTL, 3, 2, 1, 1),
|
||||
|
||||
SOC_DOUBLE_R_SX_TLV("Headphone Volume", CS42L56_HPA_VOLUME,
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ static const struct snd_kcontrol_new es8326_snd_controls[] = {
|
|||
SOC_SINGLE_TLV("DRE Gate Volume", ES8326_ADC_DRE_GATE,
|
||||
4, 0x07, 0, dre_gate_tlv),
|
||||
SOC_SINGLE("ALC Capture Switch", ES8326_ALC_RECOVERY, 3, 1, 0),
|
||||
SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_LEVEL,
|
||||
SOC_SINGLE_TLV("ALC Capture Recovery Level", ES8326_ALC_RECOVERY,
|
||||
0, 4, 0, drc_recovery_tlv),
|
||||
SOC_ENUM("ALC Capture Winsize", alc_winsize),
|
||||
SOC_SINGLE_TLV("ALC Capture Target Level", ES8326_ALC_LEVEL,
|
||||
|
|
|
|||
|
|
@ -199,68 +199,68 @@ struct _coeff_div {
|
|||
|
||||
static const struct _coeff_div coeff_div[] = {
|
||||
{32, 256000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{32, 512000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
|
||||
{32, 1536000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
|
||||
{32, 512000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{32, 1536000, 48000, 0x05, 0xB3, 0xD5, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{36, 288000, 8000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{36, 576000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
|
||||
{36, 1728000, 48000, 0x05, 0x33, 0xD5, 0x55, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
|
||||
{48, 384000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
|
||||
{48, 768000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x94, 0x00, 0x28, 2, 2},
|
||||
{48, 2304000, 48000, 0x05, 0x11, 0x53, 0x55, 0x17, 0x20, 0x92, 0x00, 0x28, 2, 2},
|
||||
{50, 400000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
|
||||
{50, 800000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
|
||||
{50, 2400000, 48000, 0x05, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
|
||||
{64, 512000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
|
||||
{64, 1024000, 16000, 0x05, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
|
||||
{64, 3072000, 48000, 0x05, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
|
||||
{72, 576000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x23, 0x08, 0x94, 0x00, 0x1F, 2, 2},
|
||||
{72, 1152000, 16000, 0x05, 0x13, 0x55, 0x33, 0x23, 0x08, 0x93, 0x00, 0x1F, 2, 2},
|
||||
{72, 3456000, 48000, 0x05, 0x11, 0x53, 0x33, 0x23, 0x08, 0x92, 0x00, 0x1F, 2, 2},
|
||||
{96, 768000, 8000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x94, 0x00, 0x1F, 2, 2},
|
||||
{96, 1536000, 16000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x93, 0x00, 0x1F, 2, 2},
|
||||
{96, 4608000, 48000, 0x15, 0x33, 0xD5, 0x55, 0x1F, 0x00, 0x92, 0x00, 0x1F, 2, 2},
|
||||
{100, 800000, 8000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x94, 0x00, 0x27, 2, 2},
|
||||
{100, 1600000, 16000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x93, 0x00, 0x27, 2, 2},
|
||||
{100, 4800000, 48000, 0x03, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x00, 0x27, 2, 2},
|
||||
{128, 1024000, 8000, 0x05, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x93, 0x01, 0x1F, 2, 2},
|
||||
{128, 2048000, 16000, 0x03, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
|
||||
{128, 6144000, 48000, 0x03, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x01, 0x1F, 2, 2},
|
||||
{144, 1152000, 8000, 0x05, 0x03, 0x35, 0x11, 0x23, 0x08, 0x93, 0x01, 0x1F, 2, 2},
|
||||
{144, 2304000, 16000, 0x03, 0x01, 0x33, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
|
||||
{144, 6912000, 48000, 0x03, 0x00, 0x31, 0x11, 0x23, 0x08, 0x92, 0x01, 0x1F, 2, 2},
|
||||
{192, 1536000, 8000, 0x15, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x93, 0x02, 0x1F, 2, 2},
|
||||
{192, 3072000, 16000, 0x15, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
|
||||
{192, 9216000, 48000, 0x15, 0x11, 0x53, 0x33, 0x1F, 0x00, 0x92, 0x02, 0x1F, 2, 2},
|
||||
{250, 12000000, 48000, 0x25, 0x11, 0x53, 0x55, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
|
||||
{256, 2048000, 8000, 0x0D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
|
||||
{256, 4096000, 16000, 0x0B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
|
||||
{256, 12288000, 48000, 0x0B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x03, 0x1F, 2, 2},
|
||||
{384, 3072000, 8000, 0x15, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
|
||||
{384, 6144000, 16000, 0x13, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
|
||||
{384, 18432000, 48000, 0x13, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x05, 0x1F, 2, 2},
|
||||
{400, 19200000, 48000, 0x1B, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
|
||||
{500, 24000000, 48000, 0x23, 0x00, 0x31, 0x33, 0x18, 0x24, 0x92, 0x04, 0x27, 2, 2},
|
||||
{512, 4096000, 8000, 0x1D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
|
||||
{512, 8192000, 16000, 0x1B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
|
||||
{512, 24576000, 48000, 0x1B, 0x00, 0x31, 0x11, 0x1F, 0x00, 0x92, 0x07, 0x1F, 2, 2},
|
||||
{768, 6144000, 8000, 0x2D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
|
||||
{768, 12288000, 16000, 0x2B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0B, 0x1F, 2, 2},
|
||||
{1024, 8192000, 8000, 0x3D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
|
||||
{1024, 16384000, 16000, 0x3B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
|
||||
{1152, 9216000, 8000, 0x45, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
|
||||
{1152, 18432000, 16000, 0x43, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x0F, 0x1F, 2, 2},
|
||||
{1200, 9600000, 8000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
|
||||
{1200, 19200000, 16000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x11, 0x27, 2, 2},
|
||||
{1536, 12288000, 8000, 0x5D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
|
||||
{1536, 24576000, 16000, 0x5B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x92, 0x17, 0x1F, 2, 2},
|
||||
{2048, 16384000, 8000, 0x7D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x1F, 0x1F, 2, 2},
|
||||
{2304, 18432000, 8000, 0x8D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x23, 0x1F, 2, 2},
|
||||
{2400, 19200000, 8000, 0xBD, 0x03, 0x35, 0x33, 0x18, 0x24, 0x92, 0x25, 0x27, 2, 2},
|
||||
{3072, 24576000, 8000, 0xBD, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x92, 0x2F, 0x1F, 2, 2},
|
||||
{32, 3072000, 96000, 0x05, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
|
||||
{64, 6144000, 96000, 0x03, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
|
||||
{96, 9216000, 96000, 0x15, 0x11, 0x53, 0x55, 0x0F, 0x00, 0x92, 0x00, 0x37, 2, 2},
|
||||
{128, 12288000, 96000, 0x0B, 0x00, 0x31, 0x33, 0x0F, 0x00, 0x92, 0x01, 0x37, 2, 2},
|
||||
{36, 576000, 16000, 0x05, 0x34, 0xDD, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{36, 1728000, 48000, 0x05, 0xB3, 0xD5, 0x55, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{48, 384000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x95, 0x00, 0x28, 2, 2},
|
||||
{48, 768000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x17, 0x20, 0x95, 0x00, 0x28, 2, 2},
|
||||
{48, 2304000, 48000, 0x05, 0x91, 0x53, 0x55, 0x17, 0x20, 0x95, 0x00, 0x28, 2, 2},
|
||||
{50, 400000, 8000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
|
||||
{50, 800000, 16000, 0x05, 0x14, 0x5D, 0x55, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
|
||||
{50, 2400000, 48000, 0x05, 0x91, 0x53, 0x55, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
|
||||
{64, 512000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{64, 1024000, 16000, 0x05, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{64, 3072000, 48000, 0x05, 0x91, 0x53, 0x33, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{72, 576000, 8000, 0x05, 0x14, 0x5D, 0x33, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{72, 1152000, 16000, 0x05, 0x13, 0x55, 0x33, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{72, 3456000, 48000, 0x05, 0x91, 0x53, 0x33, 0x23, 0x08, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{96, 768000, 8000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{96, 1536000, 16000, 0x15, 0x34, 0xDD, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{96, 4608000, 48000, 0x15, 0xB3, 0xD5, 0x55, 0x1F, 0x00, 0x95, 0x00, 0x1F, 2, 2},
|
||||
{100, 800000, 8000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
|
||||
{100, 1600000, 16000, 0x05, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
|
||||
{100, 4800000, 48000, 0x03, 0x80, 0x31, 0x33, 0x18, 0x24, 0x95, 0x00, 0x27, 2, 2},
|
||||
{128, 1024000, 8000, 0x05, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x01, 0x1F, 2, 2},
|
||||
{128, 2048000, 16000, 0x03, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x01, 0x1F, 2, 2},
|
||||
{128, 6144000, 48000, 0x03, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x01, 0x1F, 2, 2},
|
||||
{144, 1152000, 8000, 0x05, 0x03, 0x35, 0x11, 0x23, 0x08, 0x95, 0x01, 0x1F, 2, 2},
|
||||
{144, 2304000, 16000, 0x03, 0x01, 0x33, 0x11, 0x23, 0x08, 0x95, 0x01, 0x1F, 2, 2},
|
||||
{144, 6912000, 48000, 0x03, 0x80, 0x31, 0x11, 0x23, 0x08, 0x95, 0x01, 0x1F, 2, 2},
|
||||
{192, 1536000, 8000, 0x15, 0x14, 0x5D, 0x33, 0x1F, 0x00, 0x95, 0x02, 0x1F, 2, 2},
|
||||
{192, 3072000, 16000, 0x15, 0x13, 0x55, 0x33, 0x1F, 0x00, 0x95, 0x02, 0x1F, 2, 2},
|
||||
{192, 9216000, 48000, 0x15, 0x91, 0x53, 0x33, 0x1F, 0x00, 0x95, 0x02, 0x1F, 2, 2},
|
||||
{250, 12000000, 48000, 0x25, 0x91, 0x53, 0x55, 0x18, 0x24, 0x95, 0x04, 0x27, 2, 2},
|
||||
{256, 2048000, 8000, 0x0D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x03, 0x1F, 2, 2},
|
||||
{256, 4096000, 16000, 0x0B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x03, 0x1F, 2, 2},
|
||||
{256, 12288000, 48000, 0x0B, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x03, 0x1F, 2, 2},
|
||||
{384, 3072000, 8000, 0x15, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x05, 0x1F, 2, 2},
|
||||
{384, 6144000, 16000, 0x13, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x05, 0x1F, 2, 2},
|
||||
{384, 18432000, 48000, 0x13, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x05, 0x1F, 2, 2},
|
||||
{400, 19200000, 48000, 0x1B, 0x80, 0x31, 0x33, 0x18, 0x24, 0x95, 0x04, 0x27, 2, 2},
|
||||
{500, 24000000, 48000, 0x23, 0x80, 0x31, 0x33, 0x18, 0x24, 0x95, 0x04, 0x27, 2, 2},
|
||||
{512, 4096000, 8000, 0x1D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x07, 0x1F, 2, 2},
|
||||
{512, 8192000, 16000, 0x1B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x07, 0x1F, 2, 2},
|
||||
{512, 24576000, 48000, 0x1B, 0x80, 0x31, 0x11, 0x1F, 0x00, 0x95, 0x07, 0x1F, 2, 2},
|
||||
{768, 6144000, 8000, 0x2D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x0B, 0x1F, 2, 2},
|
||||
{768, 12288000, 16000, 0x2B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x0B, 0x1F, 2, 2},
|
||||
{1024, 8192000, 8000, 0x3D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
|
||||
{1024, 16384000, 16000, 0x3B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
|
||||
{1152, 9216000, 8000, 0x45, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
|
||||
{1152, 18432000, 16000, 0x43, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x0F, 0x1F, 2, 2},
|
||||
{1200, 9600000, 8000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x11, 0x27, 2, 2},
|
||||
{1200, 19200000, 16000, 0x5D, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x11, 0x27, 2, 2},
|
||||
{1536, 12288000, 8000, 0x5D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x17, 0x1F, 2, 2},
|
||||
{1536, 24576000, 16000, 0x5B, 0x01, 0x33, 0x11, 0x1F, 0x00, 0x95, 0x17, 0x1F, 2, 2},
|
||||
{2048, 16384000, 8000, 0x7D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x1F, 0x1F, 2, 2},
|
||||
{2304, 18432000, 8000, 0x8D, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x23, 0x1F, 2, 2},
|
||||
{2400, 19200000, 8000, 0xBD, 0x03, 0x35, 0x33, 0x18, 0x24, 0x95, 0x25, 0x27, 2, 2},
|
||||
{3072, 24576000, 8000, 0xBD, 0x03, 0x35, 0x11, 0x1F, 0x00, 0x95, 0x2F, 0x1F, 2, 2},
|
||||
{32, 3072000, 96000, 0x05, 0x91, 0x53, 0x55, 0x0F, 0x00, 0x95, 0x00, 0x37, 2, 2},
|
||||
{64, 6144000, 96000, 0x03, 0x80, 0x31, 0x33, 0x0F, 0x00, 0x95, 0x00, 0x37, 2, 2},
|
||||
{96, 9216000, 96000, 0x15, 0x91, 0x53, 0x55, 0x0F, 0x00, 0x95, 0x00, 0x37, 2, 2},
|
||||
{128, 12288000, 96000, 0x0B, 0x80, 0x31, 0x33, 0x0F, 0x00, 0x95, 0x01, 0x37, 2, 2},
|
||||
};
|
||||
|
||||
static inline int get_coeff(u8 vddd, u8 dmic, int mclk, int rate)
|
||||
|
|
@ -543,18 +543,20 @@ static void es8375_init(struct snd_soc_component *component)
|
|||
regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x02);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x05);
|
||||
regmap_write(es8375->regmap, ES8375_CSM1, 0x82);
|
||||
regmap_write(es8375->regmap, ES8375_VMID_CHARGE2, 0x20);
|
||||
regmap_write(es8375->regmap, ES8375_VMID_CHARGE3, 0x20);
|
||||
regmap_write(es8375->regmap, ES8375_DAC_CAL, 0x28);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG_SPK1, 0xFC);
|
||||
regmap_write(es8375->regmap, ES8375_VMID_CHARGE2, 0x10);
|
||||
regmap_write(es8375->regmap, ES8375_VMID_CHARGE3, 0x10);
|
||||
regmap_write(es8375->regmap, ES8375_DAC_CAL, 0x2F);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG_SPK1, 0xEC);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE0);
|
||||
regmap_write(es8375->regmap, ES8375_VMID_SEL, 0xFE);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG1, 0xB8);
|
||||
regmap_write(es8375->regmap, ES8375_VSEL2, 0x05);
|
||||
regmap_write(es8375->regmap, ES8375_LP_DAC, 0xCC);
|
||||
regmap_write(es8375->regmap, ES8375_SYS_CTRL2, 0x03);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0x16);
|
||||
regmap_write(es8375->regmap, ES8375_RESET1, 0x00);
|
||||
msleep(80);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x00);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR3, 0x08);
|
||||
regmap_write(es8375->regmap, ES8375_CSM1, 0x86);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR4, 0x0B);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR5, 0x00);
|
||||
|
|
@ -566,7 +568,7 @@ static void es8375_init(struct snd_soc_component *component)
|
|||
regmap_write(es8375->regmap, ES8375_ADC2, 0x00);
|
||||
regmap_write(es8375->regmap, ES8375_DAC2, 0x00);
|
||||
regmap_write(es8375->regmap, ES8375_DAC_OTP, 0x88);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE7);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG_SPK2, 0xE3);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG2, 0xF0);
|
||||
regmap_write(es8375->regmap, ES8375_ANALOG3, 0x40);
|
||||
regmap_write(es8375->regmap, ES8375_CLK_MGR2, 0xFE);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@
|
|||
#define ES8375_ANALOG_SPK2 0x29
|
||||
#define ES8375_VMID_SEL 0x2D
|
||||
#define ES8375_ANALOG1 0x2E
|
||||
#define ES8375_VSEL1 0x2F
|
||||
#define ES8375_VSEL2 0x30
|
||||
#define ES8375_LP_DAC 0x31
|
||||
#define ES8375_ANALOG2 0x32
|
||||
#define ES8375_ANALOG3 0x37
|
||||
#define ES8375_ADC2DAC_CLKTRI 0xF8
|
||||
|
|
@ -91,7 +94,7 @@
|
|||
|
||||
// Function values
|
||||
#define ES8375_ADC_OSR_GAIN_MAX 0x3F
|
||||
#define ES8375_DMIC_GAIN_MAX 0x04
|
||||
#define ES8375_DMIC_GAIN_MAX 0x03
|
||||
#define ES8375_ADC_AUTOMUTE_ATTN_MAX 0x1F
|
||||
#define ES8375_AUTOMUTE_NG_MAX 0x07
|
||||
#define ES8375_ADC_VOLUME_MAX 0xFF
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ static int es9356_sdca_headset_detect(struct es9356_sdw_priv *es9356)
|
|||
if (reg) {
|
||||
regmap_write(es9356->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_GE35, ES9356_SDCA_CTL_SELECTED_MODE, 0), reg);
|
||||
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0x75);
|
||||
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0x74);
|
||||
} else {
|
||||
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
|
||||
}
|
||||
|
|
@ -403,7 +403,7 @@ static void es9356_interrupt_handler(struct work_struct *work)
|
|||
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
|
||||
SND_JACK_BTN_4);
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&es9356->button_detect_work, msecs_to_jiffies(280));
|
||||
&es9356->button_detect_work, msecs_to_jiffies(50));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -450,7 +450,7 @@ static void es9356_button_detect_handler(struct work_struct *work)
|
|||
SND_JACK_BTN_2 | SND_JACK_BTN_3 |
|
||||
SND_JACK_BTN_4);
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&es9356->button_detect_work, msecs_to_jiffies(280));
|
||||
&es9356->button_detect_work, msecs_to_jiffies(50));
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
@ -724,68 +724,122 @@ static bool es9356_sdca_volatile_register(struct device *dev, unsigned int reg)
|
|||
}
|
||||
}
|
||||
|
||||
static bool es9356_writeable_register(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case ES9356_VERSION:
|
||||
case ES9356_BUF_ADDR_HID:
|
||||
case ES9356_HID_BYTE2:
|
||||
case ES9356_HID_BYTE3:
|
||||
case ES9356_HID_BYTE4:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct regmap_config es9356_sdca_regmap = {
|
||||
.reg_bits = 32,
|
||||
.val_bits = 16,
|
||||
.volatile_reg = es9356_sdca_volatile_register,
|
||||
.writeable_reg = es9356_writeable_register,
|
||||
.max_register = 0x45ffffff,
|
||||
.cache_type = REGCACHE_MAPLE,
|
||||
.use_single_read = true,
|
||||
.use_single_write = true,
|
||||
};
|
||||
|
||||
static void es9356_register_init(struct es9356_sdw_priv *es9356)
|
||||
static int es9356_register_init(struct es9356_sdw_priv *es9356)
|
||||
{
|
||||
unsigned int version;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(es9356->regmap, ES9356_VERSION, &version);
|
||||
if (ret < 0) {
|
||||
pr_err_ratelimited("IO error in %s, ret %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x2c);
|
||||
if (!(version >> 1))
|
||||
regmap_write(es9356->regmap, ES9356_HP_VOLUME, 0x11);
|
||||
else
|
||||
regmap_write(es9356->regmap, ES9356_HP_VOLUME, 0x00);
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_SPKCLK_CTL, 0xc3);
|
||||
regmap_write(es9356->regmap, ES9356_STATE, 0x02);
|
||||
regmap_write(es9356->regmap, ES9356_ENDPOINT_MODE, 0x24);
|
||||
regmap_write(es9356->regmap, ES9356_PRE_DIV_CTL, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_OSR, 0x18);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_OSRGAIN, 0x13);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_OSRGAIN, 0x11);
|
||||
regmap_write(es9356->regmap, ES9356_DAC_OSR, 0x16);
|
||||
regmap_write(es9356->regmap, ES9356_CLK_CTL, 0x0f);
|
||||
regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x01);
|
||||
regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x30);
|
||||
|
||||
if (!(version >> 1))
|
||||
regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x30);
|
||||
else
|
||||
regmap_write(es9356->regmap, ES9356_CLK_SEL, 0x10);
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x01);
|
||||
regmap_write(es9356->regmap, ES9356_DETCLK_CTL, 0x51);
|
||||
regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x10);
|
||||
regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_MICBIAS_CTL, 0x10);
|
||||
regmap_write(es9356->regmap, ES9356_HPDETECT_CTL, 0x07);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_ANA, 0x30);
|
||||
regmap_write(es9356->regmap, ES9356_PGA_CTL, 0xa8);
|
||||
regmap_write(es9356->regmap, ES9356_PGA_CTL, 0xaa);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_INT, 0xaa);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_LP, 0x19);
|
||||
regmap_write(es9356->regmap, ES9356_VMID1SEL, 0xbc);
|
||||
regmap_write(es9356->regmap, ES9356_VMID_TIME, 0x0b);
|
||||
regmap_write(es9356->regmap, ES9356_STATE_TIME, 0xbb);
|
||||
regmap_write(es9356->regmap, ES9356_HP_SPK_TIME, 0x77);
|
||||
regmap_write(es9356->regmap, ES9356_HP_SPK_TIME, 0x7a);
|
||||
regmap_write(es9356->regmap, ES9356_HP_DETECTTIME, 0xa4);
|
||||
regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x15);
|
||||
|
||||
if ((version & GENMASK(1, 0)) == 0x03)
|
||||
regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x15);
|
||||
else
|
||||
regmap_write(es9356->regmap, ES9356_MICBIAS_SEL, 0x25);
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_SPARE_REGISTER3, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_KEY_PRESS_TIME, 0xff);
|
||||
regmap_write(es9356->regmap, ES9356_KEY_RELEASE_TIME, 0xff);
|
||||
regmap_write(es9356->regmap, ES9356_KEY_HOLD_TIME, 0x0f);
|
||||
regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x00);
|
||||
|
||||
if ((version & GENMASK(1, 0)) == 0x03)
|
||||
regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x04);
|
||||
else
|
||||
regmap_write(es9356->regmap, ES9356_BTSEL_REF, 0x00);
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_KEYD_DETECT, 0x18);
|
||||
regmap_write(es9356->regmap, ES9356_MICBIAS_RES, 0x03);
|
||||
regmap_write(es9356->regmap, ES9356_BUTTON_CHARGE, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_CALIBRATION_TIME, 0x13);
|
||||
regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xf4);
|
||||
regmap_write(es9356->regmap, ES9356_CALIBRATION_TIME, 0x1a);
|
||||
|
||||
if (!(version >> 1)) {
|
||||
regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xc3);
|
||||
} else {
|
||||
regmap_write(es9356->regmap, ES9356_CALIBRATION_SETTING, 0xf4);
|
||||
regmap_write(es9356->regmap, ES9356_SPK_SCP, 0x55);
|
||||
}
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_SPK_VOLUME, 0x33);
|
||||
regmap_write(es9356->regmap, ES9356_DAC_VROI, 0x01);
|
||||
regmap_write(es9356->regmap, ES9356_DAC_LP, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_HP_IBIAS, 0x04);
|
||||
regmap_write(es9356->regmap, ES9356_HP_LP, 0x03);
|
||||
regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x65);
|
||||
regmap_write(es9356->regmap, ES9356_SPKLDO_CTL, 0x6c);
|
||||
regmap_write(es9356->regmap, ES9356_SPKBIAS_COMP, 0x09);
|
||||
regmap_write(es9356->regmap, ES9356_VMID1STL, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_VMID1STL, 0x01);
|
||||
regmap_write(es9356->regmap, ES9356_VMID2STL, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_VSEL, 0xfc);
|
||||
|
||||
regmap_write(es9356->regmap, ES9356_IBIASGEN, 0x10);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_AMIC_CTL, 0x0d);
|
||||
regmap_write(es9356->regmap, ES9356_ADC_AMIC_CTL, 0x05);
|
||||
regmap_write(es9356->regmap, ES9356_STATE, 0x0e);
|
||||
regmap_write(es9356->regmap, ES9356_CSM_RESET, 0x00);
|
||||
regmap_write(es9356->regmap, ES9356_HP_TYPE, 0x08);
|
||||
regmap_write(es9356->regmap, ES9356_DAC_AUTOMUTE, 0x31);
|
||||
regmap_write(es9356->regmap, ES9356_DAC_AUTOMUTE_WINSIZE, 0x3D);
|
||||
regmap_write(es9356->regmap, ES9356_DAC_AUTOMUTE_RESULT1, 0x80);
|
||||
|
||||
regmap_write(es9356->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_MIC, ES9356_SDCA_ENT_FU113, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
|
||||
|
|
@ -806,11 +860,14 @@ static void es9356_register_init(struct es9356_sdw_priv *es9356)
|
|||
SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_L), ES9356_DEFAULT_VOLUME);
|
||||
regmap_write(es9356->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_UAJ, ES9356_SDCA_ENT_FU36, ES9356_SDCA_CTL_FU_VOLUME, CH_R), ES9356_DEFAULT_VOLUME);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
||||
{
|
||||
struct es9356_sdw_priv *es9356 = dev_get_drvdata(&slave->dev);
|
||||
int ret = 0;
|
||||
|
||||
if (es9356->hw_init)
|
||||
return 0;
|
||||
|
|
@ -825,7 +882,11 @@ static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
|||
/* update count of parent 'active' children */
|
||||
pm_runtime_set_active(&slave->dev);
|
||||
|
||||
es9356_register_init(es9356);
|
||||
ret = es9356_register_init(es9356);
|
||||
if (ret < 0) {
|
||||
regcache_cache_only(es9356->regmap, true);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
pm_runtime_get_noresume(&slave->dev);
|
||||
|
||||
|
|
@ -852,10 +913,11 @@ static int es9356_sdca_io_init(struct device *dev, struct sdw_slave *slave)
|
|||
|
||||
es9356->hw_init = true;
|
||||
|
||||
err_out:
|
||||
pm_runtime_mark_last_busy(&slave->dev);
|
||||
pm_runtime_put_autosuspend(&slave->dev);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int es9356_sdw_update_status(struct sdw_slave *slave,
|
||||
|
|
@ -1000,10 +1062,10 @@ static int es9356_sdw_interrupt_callback(struct sdw_slave *slave,
|
|||
count++;
|
||||
} while (stat != 0 && count < retry);
|
||||
|
||||
/* The 280 ms figure was determined through testing */
|
||||
/* The 50 ms figure was determined through testing */
|
||||
if (status->sdca_cascade && !es9356->disable_irq)
|
||||
mod_delayed_work(system_power_efficient_wq,
|
||||
&es9356->interrupt_handle_work, msecs_to_jiffies(280));
|
||||
&es9356->interrupt_handle_work, msecs_to_jiffies(50));
|
||||
|
||||
mutex_unlock(&es9356->disable_irq_lock);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#define __ES9356_H__
|
||||
|
||||
/*ES9356 Implementation-define*/
|
||||
#define ES9356_VERSION 0x2000
|
||||
#define ES9356_FLAGS_HP 0x2003
|
||||
#define ES9356_CSM_RESET 0x2020
|
||||
#define ES9356_FUC_RESET 0x2021
|
||||
|
|
@ -37,6 +38,7 @@
|
|||
#define ES9356_MICBIAS_CTL 0x2047
|
||||
#define ES9356_HPDETECT_CTL 0x2048
|
||||
#define ES9356_MICBIAS_RES 0x2049
|
||||
#define ES9356_SPARE_REGISTER3 0x204a
|
||||
|
||||
/*CLK*/
|
||||
#define ES9356_CLK_SEL 0x2050
|
||||
|
|
@ -81,6 +83,9 @@
|
|||
#define ES9356_DAC_RAMP 0x2093
|
||||
#define ES9356_DAC_VPPSCALE 0x2094
|
||||
#define ES9356_DAC_SWAP 0x2097
|
||||
#define ES9356_DAC_AUTOMUTE 0x2098
|
||||
#define ES9356_DAC_AUTOMUTE_WINSIZE 0x2099
|
||||
#define ES9356_DAC_AUTOMUTE_RESULT1 0x209B
|
||||
#define ES9356_SPKCMP_VPPSC 0x20A0
|
||||
#define ES9356_CALIBRATION_TIME 0x20A1
|
||||
#define ES9356_CALIBRATION_SETTING 0x20A2
|
||||
|
|
|
|||
|
|
@ -514,6 +514,9 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component)
|
|||
snd_hdac_display_power(hdev->bus,
|
||||
HDA_CODEC_IDX_CONTROLLER, false);
|
||||
|
||||
/* The codec is in D0, the status is RPM_SUSPENDED after a previous unbind */
|
||||
pm_runtime_set_active(&hdev->dev);
|
||||
|
||||
/* match for forbid call in snd_hda_codec_device_new() */
|
||||
pm_runtime_allow(&hdev->dev);
|
||||
|
||||
|
|
@ -554,6 +557,13 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
|
|||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resume the codec to have its link reference (dropped below) and
|
||||
* codec_powered bit in the same state as after the probe.
|
||||
*/
|
||||
pm_runtime_get_sync(&hdev->dev);
|
||||
|
||||
/* prevent runtime PM callbacks while the link and the codec are torn down */
|
||||
pm_runtime_disable(&hdev->dev);
|
||||
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
|
||||
|
||||
|
|
@ -561,6 +571,12 @@ static void hdac_hda_codec_remove(struct snd_soc_component *component)
|
|||
driver->ops->remove(codec);
|
||||
|
||||
snd_hda_codec_cleanup_for_unbind(codec);
|
||||
|
||||
/* Balances the disable above, cleanup_for_unbind keeps runtime PM disabled */
|
||||
pm_runtime_enable(&hdev->dev);
|
||||
pm_runtime_put_noidle(&hdev->dev);
|
||||
/* The codec is cleaned up, system suspend must skip it from now on */
|
||||
pm_runtime_set_suspended(&hdev->dev);
|
||||
}
|
||||
|
||||
static const struct snd_soc_dapm_route hdac_hda_dapm_routes[] = {
|
||||
|
|
@ -617,12 +633,35 @@ static const struct snd_soc_component_driver hdac_hda_hdmi_codec = {
|
|||
.endianness = 1,
|
||||
};
|
||||
|
||||
static void hdac_hda_restore_dev_type(void *data)
|
||||
{
|
||||
struct hdac_device *hdev = data;
|
||||
|
||||
hdev->type = HDA_DEV_LEGACY;
|
||||
}
|
||||
|
||||
static int hdac_hda_dev_probe(struct hdac_device *hdev)
|
||||
{
|
||||
struct hdac_hda_priv *hda_pvt = dev_get_drvdata(&hdev->dev);
|
||||
struct hdac_hda_priv *hda_pvt;
|
||||
struct hdac_ext_link *hlink;
|
||||
int ret;
|
||||
|
||||
hda_pvt = devm_kzalloc(&hdev->dev, sizeof(*hda_pvt), GFP_KERNEL);
|
||||
if (!hda_pvt)
|
||||
return -ENOMEM;
|
||||
|
||||
hda_pvt->codec = dev_to_hda_codec(&hdev->dev);
|
||||
hda_pvt->dev_index = hdev->addr;
|
||||
/* Intel iDisp (HDMI/DP) codec */
|
||||
if (((hdev->vendor_id >> 16) & 0xFFFF) == 0x8086)
|
||||
hda_pvt->need_display_power = true;
|
||||
dev_set_drvdata(&hdev->dev, hda_pvt);
|
||||
|
||||
/* Allow the legacy codec driver to match again after unbind */
|
||||
ret = devm_add_action(&hdev->dev, hdac_hda_restore_dev_type, hdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* hold the ref while we probe */
|
||||
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev));
|
||||
if (!hlink) {
|
||||
|
|
|
|||
|
|
@ -92,7 +92,6 @@ static bool rt721_sdca_mbq_readable_register(struct device *dev, unsigned int re
|
|||
case 0x2000026:
|
||||
case 0x200002c:
|
||||
case 0x200003c:
|
||||
case 0x2000046:
|
||||
case 0x5810000:
|
||||
case 0x5810033:
|
||||
case 0x5810036:
|
||||
|
|
@ -174,7 +173,6 @@ static bool rt721_sdca_mbq_volatile_register(struct device *dev, unsigned int re
|
|||
case 0x2000026:
|
||||
case 0x200002c:
|
||||
case 0x2000030:
|
||||
case 0x2000046:
|
||||
case 0x2000067:
|
||||
case 0x2000084:
|
||||
case 0x2000086:
|
||||
|
|
|
|||
|
|
@ -63,8 +63,6 @@ static const struct reg_default rt721_sdca_reg_defaults[] = {
|
|||
RT721_SDCA_CTL_FU_MUTE, CH_L), 0x01 },
|
||||
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_USER_FU06,
|
||||
RT721_SDCA_CTL_FU_MUTE, CH_R), 0x01 },
|
||||
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
|
||||
RT721_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
|
||||
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
|
||||
RT721_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
|
||||
{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT721_SDCA_ENT_PDE23,
|
||||
|
|
@ -91,13 +89,11 @@ static const struct reg_default rt721_sdca_mbq_defaults[] = {
|
|||
{ 0x2000003, 0x0000 },
|
||||
{ 0x2000013, 0x8001 },
|
||||
{ 0x200003c, 0x0000 },
|
||||
{ 0x2000046, 0x3400 },
|
||||
{ 0x5b10017, 0x1b07 },
|
||||
{ 0x5f00044, 0x6040 },
|
||||
{ 0x5f00045, 0x3333 },
|
||||
{ 0x5f00048, 0x0000 },
|
||||
{ 0x6100005, 0x0005 },
|
||||
{ 0x6100006, 0x0000 },
|
||||
{ 0x6100007, 0x0007 },
|
||||
{ 0x610000d, 0x0051 },
|
||||
{ 0x6100010, 0x0180 },
|
||||
|
|
|
|||
|
|
@ -1652,6 +1652,17 @@ int rt722_sdca_init(struct device *dev, struct regmap *regmap, struct sdw_slave
|
|||
&soc_sdca_dev_rt722, rt722_sdca_dai, ARRAY_SIZE(rt722_sdca_dai));
|
||||
}
|
||||
|
||||
static const struct dmi_system_id dmi_dell_mono_spk_quirk_table[] = {
|
||||
{
|
||||
.ident = "Dell Pro 5 Micro P5M1270",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "0EBA"),
|
||||
}
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static void rt722_sdca_dmic_preset(struct rt722_sdca_priv *rt722)
|
||||
{
|
||||
unsigned int mic_func_status;
|
||||
|
|
@ -1741,6 +1752,13 @@ static void rt722_sdca_amp_preset(struct rt722_sdca_priv *rt722)
|
|||
if (rt722->hw_vid == RT722_VB)
|
||||
regmap_write(rt722->regmap, 0x2f54, 0x00);
|
||||
|
||||
/* This Dell machine only uses the mono speaker */
|
||||
if (dmi_check_system(dmi_dell_mono_spk_quirk_table)) {
|
||||
rt722_sdca_index_write(rt722, RT722_VENDOR_REG, RT722_CLSD_CTRL2, 0x391a);
|
||||
rt722_sdca_index_update_bits(rt722, RT722_VENDOR_REG,
|
||||
RT722_MISC_CTRL2, 0x0010, 0x0010);
|
||||
}
|
||||
|
||||
/* clear flag */
|
||||
regmap_write(rt722->regmap,
|
||||
SDW_SDCA_CTL(FUNC_NUM_AMP, RT722_SDCA_ENT0, RT722_SDCA_CTL_FUNC_STATUS, 0),
|
||||
|
|
|
|||
|
|
@ -68,9 +68,11 @@ struct rt722_sdca_dmic_kctrl_priv {
|
|||
#define RT722_ANALOG_BIAS_CTL3 0x04
|
||||
#define RT722_MISC_CTRL1 0x07
|
||||
#define RT722_JD_CTRL1 0x09
|
||||
#define RT722_MISC_CTRL2 0x0d
|
||||
#define RT722_LDO2_3_CTL1 0x0e
|
||||
#define RT722_LDO1_CTL 0x1a
|
||||
#define RT722_HP_JD_CTRL 0x24
|
||||
#define RT722_CLSD_CTRL2 0x38
|
||||
#define RT722_CLSD_CTRL6 0x3c
|
||||
#define RT722_COMBO_JACK_AUTO_CTL1 0x45
|
||||
#define RT722_COMBO_JACK_AUTO_CTL2 0x46
|
||||
|
|
|
|||
|
|
@ -318,6 +318,9 @@ static int clk_aic32x4_div_set_rate(struct clk_hw *hw, unsigned long rate,
|
|||
struct clk_aic32x4 *div = to_clk_aic32x4(hw);
|
||||
u8 divisor;
|
||||
|
||||
if (!rate)
|
||||
return -EINVAL;
|
||||
|
||||
divisor = DIV_ROUND_UP(parent_rate, rate);
|
||||
if (divisor > AIC32X4_DIV_MAX)
|
||||
return -EINVAL;
|
||||
|
|
@ -331,8 +334,11 @@ static int clk_aic32x4_div_determine_rate(struct clk_hw *hw,
|
|||
{
|
||||
unsigned long divisor;
|
||||
|
||||
if (!req->rate)
|
||||
return -EINVAL;
|
||||
|
||||
divisor = DIV_ROUND_UP(req->best_parent_rate, req->rate);
|
||||
if (divisor > AIC32X4_DIV_MAX)
|
||||
if (!divisor || divisor > AIC32X4_DIV_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
req->rate = DIV_ROUND_UP(req->best_parent_rate, divisor);
|
||||
|
|
|
|||
|
|
@ -163,9 +163,12 @@ static void wm8958_micd_set_rate(struct snd_soc_component *component)
|
|||
static int configure_aif_clock(struct snd_soc_component *component, int aif)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
|
||||
struct clk *mclk = NULL;
|
||||
bool switch_mclk;
|
||||
int rate;
|
||||
int reg1 = 0;
|
||||
int offset;
|
||||
int ret;
|
||||
|
||||
if (aif)
|
||||
offset = 4;
|
||||
|
|
@ -174,11 +177,13 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
|
|||
|
||||
switch (wm8994->sysclk[aif]) {
|
||||
case WM8994_SYSCLK_MCLK1:
|
||||
mclk = wm8994->mclk[WM8994_MCLK1].clk;
|
||||
rate = wm8994->mclk_rate[0];
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_MCLK2:
|
||||
reg1 |= 0x8;
|
||||
mclk = wm8994->mclk[WM8994_MCLK2].clk;
|
||||
rate = wm8994->mclk_rate[1];
|
||||
break;
|
||||
|
||||
|
|
@ -196,6 +201,20 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the AIF clock is running, enable the new MCLK before switching
|
||||
* to it and release the previous one afterwards.
|
||||
*/
|
||||
switch_mclk = wm8994->aif_clk_on[aif] && mclk != wm8994->aif_mclk[aif];
|
||||
if (switch_mclk) {
|
||||
ret = clk_prepare_enable(mclk);
|
||||
if (ret < 0) {
|
||||
dev_err(component->dev,
|
||||
"Failed to enable MCLK for AIF%d\n", aif + 1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (rate >= 13500000) {
|
||||
rate /= 2;
|
||||
reg1 |= WM8994_AIF1CLK_DIV;
|
||||
|
|
@ -210,6 +229,11 @@ static int configure_aif_clock(struct snd_soc_component *component, int aif)
|
|||
WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
|
||||
reg1);
|
||||
|
||||
if (switch_mclk) {
|
||||
clk_disable_unprepare(wm8994->aif_mclk[aif]);
|
||||
wm8994->aif_mclk[aif] = mclk;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1059,13 +1083,25 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
|
|||
unsigned int offset, val, clk_idx;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* The AIF clock source may be changed while the AIF clock is
|
||||
* running, so release the MCLK which has been enabled for it
|
||||
* instead of the one currently selected.
|
||||
*/
|
||||
if (!enable) {
|
||||
clk_disable_unprepare(wm8994->aif_mclk[aif]);
|
||||
wm8994->aif_mclk[aif] = NULL;
|
||||
wm8994->aif_clk_on[aif] = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (aif)
|
||||
offset = 4;
|
||||
else
|
||||
offset = 0;
|
||||
|
||||
val = snd_soc_component_read(component, WM8994_AIF1_CLOCKING_1 + offset);
|
||||
val &= WM8994_AIF1CLK_SRC_MASK;
|
||||
val = (val & WM8994_AIF1CLK_SRC_MASK) >> WM8994_AIF1CLK_SRC_SHIFT;
|
||||
|
||||
switch (val) {
|
||||
case 0:
|
||||
|
|
@ -1075,19 +1111,18 @@ static int aif_mclk_set(struct snd_soc_component *component, int aif, bool enabl
|
|||
clk_idx = WM8994_MCLK2;
|
||||
break;
|
||||
default:
|
||||
wm8994->aif_clk_on[aif] = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
|
||||
if (ret < 0) {
|
||||
dev_err(component->dev, "Failed to enable MCLK%d\n",
|
||||
clk_idx);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
clk_disable_unprepare(wm8994->mclk[clk_idx].clk);
|
||||
ret = clk_prepare_enable(wm8994->mclk[clk_idx].clk);
|
||||
if (ret < 0) {
|
||||
dev_err(component->dev, "Failed to enable MCLK%d\n",
|
||||
clk_idx + 1);
|
||||
return ret;
|
||||
}
|
||||
wm8994->aif_mclk[aif] = wm8994->mclk[clk_idx].clk;
|
||||
wm8994->aif_clk_on[aif] = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2199,6 +2234,44 @@ static int wm8994_get_fll_config(struct wm8994 *control, struct fll_div *fll,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If SYSCLK is less than 50kHz adjust AIFnCLK dividers for detection,
|
||||
* restoring the original ones once SYSCLK is fast enough again.
|
||||
*/
|
||||
static void wm8994_update_aif_clk_rate(struct snd_soc_component *component)
|
||||
{
|
||||
struct wm8994_priv *wm8994 = snd_soc_component_get_drvdata(component);
|
||||
|
||||
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
|
||||
/* Don't overwrite the saved dividers with the 128fs ones */
|
||||
if (!wm8994->aifdiv[0]) {
|
||||
dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
|
||||
|
||||
wm8994->aifdiv[0] = snd_soc_component_read(component,
|
||||
WM8994_AIF1_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
wm8994->aifdiv[1] = snd_soc_component_read(component,
|
||||
WM8994_AIF2_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
}
|
||||
|
||||
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK, 0x1);
|
||||
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK, 0x1);
|
||||
} else if (wm8994->aifdiv[0]) {
|
||||
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK,
|
||||
wm8994->aifdiv[0]);
|
||||
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK,
|
||||
wm8994->aifdiv[1]);
|
||||
|
||||
wm8994->aifdiv[0] = 0;
|
||||
wm8994->aifdiv[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
|
||||
unsigned int freq_in, unsigned int freq_out)
|
||||
{
|
||||
|
|
@ -2433,33 +2506,7 @@ static int _wm8994_set_fll(struct snd_soc_component *component, int id, int src,
|
|||
|
||||
configure_clock(component);
|
||||
|
||||
/*
|
||||
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
|
||||
* for detection.
|
||||
*/
|
||||
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
|
||||
dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
|
||||
|
||||
wm8994->aifdiv[0] = snd_soc_component_read(component, WM8994_AIF1_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
wm8994->aifdiv[1] = snd_soc_component_read(component, WM8994_AIF2_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
|
||||
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK, 0x1);
|
||||
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK, 0x1);
|
||||
} else if (wm8994->aifdiv[0]) {
|
||||
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK,
|
||||
wm8994->aifdiv[0]);
|
||||
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK,
|
||||
wm8994->aifdiv[1]);
|
||||
|
||||
wm8994->aifdiv[0] = 0;
|
||||
wm8994->aifdiv[1] = 0;
|
||||
}
|
||||
wm8994_update_aif_clk_rate(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -2519,7 +2566,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
case WM8994_SYSCLK_MCLK1:
|
||||
wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK1;
|
||||
|
||||
ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
|
||||
ret = wm8994_set_mclk_rate(wm8994, WM8994_MCLK1, &freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2532,7 +2579,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
/* TODO: Set GPIO AF */
|
||||
wm8994->sysclk[dai->id - 1] = WM8994_SYSCLK_MCLK2;
|
||||
|
||||
ret = wm8994_set_mclk_rate(wm8994, dai->id - 1, &freq);
|
||||
ret = wm8994_set_mclk_rate(wm8994, WM8994_MCLK2, &freq);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
|
@ -2577,33 +2624,7 @@ static int wm8994_set_dai_sysclk(struct snd_soc_dai *dai,
|
|||
|
||||
configure_clock(component);
|
||||
|
||||
/*
|
||||
* If SYSCLK will be less than 50kHz adjust AIFnCLK dividers
|
||||
* for detection.
|
||||
*/
|
||||
if (max(wm8994->aifclk[0], wm8994->aifclk[1]) < 50000) {
|
||||
dev_dbg(component->dev, "Configuring AIFs for 128fs\n");
|
||||
|
||||
wm8994->aifdiv[0] = snd_soc_component_read(component, WM8994_AIF1_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
wm8994->aifdiv[1] = snd_soc_component_read(component, WM8994_AIF2_RATE)
|
||||
& WM8994_AIF1CLK_RATE_MASK;
|
||||
|
||||
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK, 0x1);
|
||||
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK, 0x1);
|
||||
} else if (wm8994->aifdiv[0]) {
|
||||
snd_soc_component_update_bits(component, WM8994_AIF1_RATE,
|
||||
WM8994_AIF1CLK_RATE_MASK,
|
||||
wm8994->aifdiv[0]);
|
||||
snd_soc_component_update_bits(component, WM8994_AIF2_RATE,
|
||||
WM8994_AIF2CLK_RATE_MASK,
|
||||
wm8994->aifdiv[1]);
|
||||
|
||||
wm8994->aifdiv[0] = 0;
|
||||
wm8994->aifdiv[1] = 0;
|
||||
}
|
||||
wm8994_update_aif_clk_rate(component);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ struct wm8994_priv {
|
|||
struct wm_hubs_data hubs;
|
||||
struct wm8994 *wm8994;
|
||||
struct clk_bulk_data mclk[WM8994_NUM_MCLK];
|
||||
struct clk *aif_mclk[2];
|
||||
bool aif_clk_on[2];
|
||||
int sysclk[2];
|
||||
int sysclk_rate[2];
|
||||
int mclk_rate[2];
|
||||
|
|
|
|||
|
|
@ -1115,11 +1115,19 @@ static int wsa881x_probe(struct sdw_slave *pdev,
|
|||
if (!wsa881x)
|
||||
return -ENOMEM;
|
||||
|
||||
wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_LOW);
|
||||
/*
|
||||
* The powerdown GPIO may be shared between several amplifiers. Request
|
||||
* it asserted, so the shared GPIO proxy treats powerdown as the default
|
||||
* state and keeps the line de-asserted as long as any amplifier needs
|
||||
* it, then power up this amplifier.
|
||||
*/
|
||||
wsa881x->sd_n = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(wsa881x->sd_n))
|
||||
return dev_err_probe(dev, PTR_ERR(wsa881x->sd_n),
|
||||
"Shutdown Control GPIO not found\n");
|
||||
|
||||
gpiod_set_value_cansleep(wsa881x->sd_n, 0);
|
||||
|
||||
dev_set_drvdata(dev, wsa881x);
|
||||
wsa881x->slave = pdev;
|
||||
wsa881x->dev = dev;
|
||||
|
|
@ -1154,7 +1162,7 @@ static int wsa881x_runtime_suspend(struct device *dev)
|
|||
struct regmap *regmap = dev_get_regmap(dev, NULL);
|
||||
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
|
||||
|
||||
gpiod_direction_output(wsa881x->sd_n, 1);
|
||||
gpiod_set_value_cansleep(wsa881x->sd_n, 1);
|
||||
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
|
|
@ -1169,11 +1177,11 @@ static int wsa881x_runtime_resume(struct device *dev)
|
|||
struct wsa881x_priv *wsa881x = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
gpiod_direction_output(wsa881x->sd_n, 0);
|
||||
gpiod_set_value_cansleep(wsa881x->sd_n, 0);
|
||||
|
||||
ret = sdw_slave_wait_for_init(slave, WSA881X_PROBE_TIMEOUT);
|
||||
if (ret) {
|
||||
gpiod_direction_output(wsa881x->sd_n, 1);
|
||||
gpiod_set_value_cansleep(wsa881x->sd_n, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1182,7 +1190,7 @@ static int wsa881x_runtime_resume(struct device *dev)
|
|||
if (ret) {
|
||||
regcache_cache_only(regmap, true);
|
||||
regcache_mark_dirty(regmap);
|
||||
gpiod_direction_output(wsa881x->sd_n, 1);
|
||||
gpiod_set_value_cansleep(wsa881x->sd_n, 1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -456,10 +456,11 @@
|
|||
|
||||
/*
|
||||
* Device will report senseless data in many cases, so discard any measurements
|
||||
* outside of valid range.
|
||||
* outside of the two-point trim range. Do not narrow this to ambient: a
|
||||
* speaker that has been playing easily runs well above 45 degC.
|
||||
*/
|
||||
#define WSA883X_LOW_TEMP_THRESHOLD 5
|
||||
#define WSA883X_HIGH_TEMP_THRESHOLD 45
|
||||
#define WSA883X_LOW_TEMP_THRESHOLD WSA883X_T1_TEMP
|
||||
#define WSA883X_HIGH_TEMP_THRESHOLD WSA883X_T2_TEMP
|
||||
|
||||
struct wsa883x_priv {
|
||||
struct regmap *regmap;
|
||||
|
|
@ -551,7 +552,7 @@ static struct sdw_dpn_prop wsa_sink_dpn_prop[WSA883X_MAX_SWR_PORTS] = {
|
|||
.num = WSA883X_PORT_VISENSE + 1,
|
||||
.type = SDW_DPN_SIMPLE,
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.max_ch = 2,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
}
|
||||
|
|
@ -572,7 +573,7 @@ static const struct sdw_port_config wsa883x_pconfig[WSA883X_MAX_SWR_PORTS] = {
|
|||
},
|
||||
[WSA883X_PORT_VISENSE] = {
|
||||
.num = WSA883X_PORT_VISENSE + 1,
|
||||
.ch_mask = 0x1,
|
||||
.ch_mask = 0x3,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -1430,7 +1431,7 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
|
|||
unsigned int dmeas_msb = 0, dmeas_lsb = 0;
|
||||
int d1, d2, dmeas;
|
||||
unsigned int mask;
|
||||
int ret, range;
|
||||
int ret;
|
||||
long val;
|
||||
|
||||
guard(mutex)(&wsa883x->sp_lock);
|
||||
|
|
@ -1493,8 +1494,8 @@ static int wsa883x_get_temp(struct wsa883x_priv *wsa883x, long *temp)
|
|||
}
|
||||
|
||||
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)) {
|
||||
if (val >= WSA883X_LOW_TEMP_THRESHOLD &&
|
||||
val <= WSA883X_HIGH_TEMP_THRESHOLD) {
|
||||
wsa883x->temperature = val;
|
||||
*temp = val * 1000;
|
||||
ret = 0;
|
||||
|
|
@ -1668,7 +1669,9 @@ static int wsa883x_probe(struct sdw_slave *pdev,
|
|||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = devm_snd_soc_register_component(dev,
|
||||
&wsa883x_component_drv,
|
||||
|
|
|
|||
|
|
@ -720,10 +720,11 @@
|
|||
|
||||
/*
|
||||
* Device will report senseless data in many cases, so discard any measurements
|
||||
* outside of valid range.
|
||||
* outside of the two-point trim range. Do not narrow this to ambient: a
|
||||
* speaker that has been playing easily runs well above 45 degC.
|
||||
*/
|
||||
#define WSA884X_LOW_TEMP_THRESHOLD 5
|
||||
#define WSA884X_HIGH_TEMP_THRESHOLD 45
|
||||
#define WSA884X_LOW_TEMP_THRESHOLD WSA884X_T1_TEMP
|
||||
#define WSA884X_HIGH_TEMP_THRESHOLD WSA884X_T2_TEMP
|
||||
|
||||
struct wsa884x_priv {
|
||||
struct regmap *regmap;
|
||||
|
|
@ -858,7 +859,7 @@ static struct sdw_dpn_prop wsa884x_sink_dpn_prop[WSA884X_MAX_SWR_PORTS] = {
|
|||
.num = WSA884X_PORT_VISENSE + 1,
|
||||
.type = SDW_DPN_SIMPLE,
|
||||
.min_ch = 1,
|
||||
.max_ch = 1,
|
||||
.max_ch = 2,
|
||||
.simple_ch_prep_sm = true,
|
||||
.read_only_wordlength = true,
|
||||
},
|
||||
|
|
@ -891,7 +892,7 @@ static const struct sdw_port_config wsa884x_pconfig[WSA884X_MAX_SWR_PORTS] = {
|
|||
},
|
||||
[WSA884X_PORT_VISENSE] = {
|
||||
.num = WSA884X_PORT_VISENSE + 1,
|
||||
.ch_mask = 0x1,
|
||||
.ch_mask = 0x3,
|
||||
},
|
||||
[WSA884X_PORT_CPS] = {
|
||||
.num = WSA884X_PORT_CPS + 1,
|
||||
|
|
@ -1929,8 +1930,8 @@ static int wsa884x_get_temp(struct wsa884x_priv *wsa884x, long *temp)
|
|||
dev_dbg(wsa884x->dev, "Measured temp %ld (dmeas=%d, d1=%d, d2=%d)\n",
|
||||
val, dmeas, d1, d2);
|
||||
|
||||
if ((val > WSA884X_LOW_TEMP_THRESHOLD) &&
|
||||
(val < WSA884X_HIGH_TEMP_THRESHOLD)) {
|
||||
if (val >= WSA884X_LOW_TEMP_THRESHOLD &&
|
||||
val <= WSA884X_HIGH_TEMP_THRESHOLD) {
|
||||
wsa884x->temperature = val;
|
||||
*temp = val * 1000;
|
||||
ret = 0;
|
||||
|
|
@ -2124,7 +2125,9 @@ static int wsa884x_probe(struct sdw_slave *pdev,
|
|||
pm_runtime_use_autosuspend(dev);
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_snd_soc_register_component(dev,
|
||||
&wsa884x_component_drv,
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@ void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
|
|||
}
|
||||
EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks);
|
||||
|
||||
/* Fractional audio PLLs may sit a few Hz off nominal */
|
||||
#define FSL_RATE_CONSTR_TOL_HZ 100
|
||||
|
||||
/**
|
||||
* fsl_asoc_constrain_rates - constrain rates according to clocks
|
||||
*
|
||||
|
|
@ -172,6 +175,7 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
|
|||
{
|
||||
int i, j, k = 0;
|
||||
u64 clk_rate[3];
|
||||
u32 rate, rem;
|
||||
|
||||
*target_constr = *original_constr;
|
||||
if (pll8k_clk || pll11k_clk || ext_clk) {
|
||||
|
|
@ -181,10 +185,25 @@ void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
|
|||
clk_rate[0] = clk_get_rate(pll8k_clk);
|
||||
clk_rate[1] = clk_get_rate(pll11k_clk);
|
||||
clk_rate[2] = clk_get_rate(ext_clk);
|
||||
rate = original_constr->list[i];
|
||||
for (j = 0; j < 3; j++) {
|
||||
if (clk_rate[j] != 0 &&
|
||||
do_div(clk_rate[j], original_constr->list[i]) == 0) {
|
||||
target_rates[k++] = original_constr->list[i];
|
||||
if (clk_rate[j] == 0)
|
||||
continue;
|
||||
rem = do_div(clk_rate[j], rate);
|
||||
/*
|
||||
* The audio PLLs are fractional and cannot
|
||||
* always reproduce their nominal rate: after
|
||||
* any clk_set_rate() they may sit a few Hz
|
||||
* off (observed on i.MX8M Plus: audio_pll1
|
||||
* reads 393215997 after restoring 393216000),
|
||||
* which must not disqualify the entire rate
|
||||
* family. Accept near-integer ratios; the
|
||||
* other family misses by tens of kHz, so a
|
||||
* small tolerance cannot mix families.
|
||||
*/
|
||||
if (rem <= FSL_RATE_CONSTR_TOL_HZ ||
|
||||
rem >= rate - FSL_RATE_CONSTR_TOL_HZ) {
|
||||
target_rates[k++] = rate;
|
||||
target_constr->count++;
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -178,6 +178,16 @@ static int imx_rpmsg_pcm_hw_params(struct snd_soc_component *component,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int imx_rpmsg_pcm_hw_free(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct rpmsg_info *info = dev_get_drvdata(component->dev);
|
||||
|
||||
flush_workqueue(info->rpmsg_wq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t imx_rpmsg_pcm_pointer(struct snd_soc_component *component,
|
||||
struct snd_pcm_substream *substream)
|
||||
{
|
||||
|
|
@ -285,9 +295,6 @@ static int imx_rpmsg_pcm_close(struct snd_soc_component *component,
|
|||
struct rpmsg_info *info = dev_get_drvdata(component->dev);
|
||||
struct rpmsg_msg *msg;
|
||||
|
||||
/* Flush work in workqueue to make TX_CLOSE is the last message */
|
||||
flush_workqueue(info->rpmsg_wq);
|
||||
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
|
||||
msg = &info->msg[TX_CLOSE];
|
||||
msg->s_msg.header.cmd = TX_CLOSE;
|
||||
|
|
@ -624,6 +631,7 @@ static const struct snd_soc_component_driver imx_rpmsg_soc_component = {
|
|||
.open = imx_rpmsg_pcm_open,
|
||||
.close = imx_rpmsg_pcm_close,
|
||||
.hw_params = imx_rpmsg_pcm_hw_params,
|
||||
.hw_free = imx_rpmsg_pcm_hw_free,
|
||||
.trigger = imx_rpmsg_pcm_trigger,
|
||||
.pointer = imx_rpmsg_pcm_pointer,
|
||||
.ack = imx_rpmsg_pcm_ack,
|
||||
|
|
|
|||
|
|
@ -70,6 +70,23 @@ static const struct snd_soc_acpi_endpoint jack_amp_g1_dmic_endpoints[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_endpoint jack_dmic_endpoints[] = {
|
||||
/* Jack Endpoint */
|
||||
{
|
||||
.num = 0,
|
||||
.aggregated = 0,
|
||||
.group_position = 0,
|
||||
.group_id = 0,
|
||||
},
|
||||
/* DMIC Endpoint */
|
||||
{
|
||||
.num = 1,
|
||||
.aggregated = 0,
|
||||
.group_position = 0,
|
||||
.group_id = 0,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device cs35l56_2_lr_adr[] = {
|
||||
{
|
||||
.adr = 0x00023001FA355601ull,
|
||||
|
|
@ -301,6 +318,35 @@ static const struct snd_soc_acpi_adr_device rt1320_2_single_adr[] = {
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* MSI Raider 16 Max HX B2WI (MS-2651): RT713 (jack/dmic, "VB" SDCA variant)
|
||||
* on link 0, two RT1320 speaker amps sharing link 2 (unique_id 0 = left,
|
||||
* unique_id 1 = right).
|
||||
*/
|
||||
static const struct snd_soc_acpi_adr_device rt713_vb_0_adr[] = {
|
||||
{
|
||||
.adr = 0x000030025D071301ull,
|
||||
.num_endpoints = ARRAY_SIZE(jack_dmic_endpoints),
|
||||
.endpoints = jack_dmic_endpoints,
|
||||
.name_prefix = "rt713"
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_adr_device rt1320_2_lr_adr[] = {
|
||||
{
|
||||
.adr = 0x000230025D132001ull,
|
||||
.num_endpoints = 1,
|
||||
.endpoints = &spk_l_endpoint,
|
||||
.name_prefix = "rt1320-1"
|
||||
},
|
||||
{
|
||||
.adr = 0x000231025D132001ull,
|
||||
.num_endpoints = 1,
|
||||
.endpoints = &spk_r_endpoint,
|
||||
.name_prefix = "rt1320-2"
|
||||
}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr arl_n_mrd_es9356_link1[] = {
|
||||
{
|
||||
.mask = BIT(1),
|
||||
|
|
@ -454,6 +500,20 @@ static const struct snd_soc_acpi_link_adr arl_rt711_l0_rt1316_l3[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr arl_rt713_vb_l0_rt1320_l2[] = {
|
||||
{
|
||||
.mask = BIT(0),
|
||||
.num_adr = ARRAY_SIZE(rt713_vb_0_adr),
|
||||
.adr_d = rt713_vb_0_adr,
|
||||
},
|
||||
{
|
||||
.mask = BIT(2),
|
||||
.num_adr = ARRAY_SIZE(rt1320_2_lr_adr),
|
||||
.adr_d = rt1320_2_lr_adr,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr arl_rt722_l0_rt1320_l2[] = {
|
||||
{
|
||||
.mask = BIT(0),
|
||||
|
|
@ -482,6 +542,15 @@ static const struct snd_soc_acpi_link_adr arl_rt712_l0_rt1320_l3[] = {
|
|||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_link_adr arl_rt712_l0[] = {
|
||||
{
|
||||
.mask = BIT(0),
|
||||
.num_adr = ARRAY_SIZE(rt712_0_agg_adr),
|
||||
.adr_d = rt712_0_agg_adr,
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static const struct snd_soc_acpi_codecs arl_essx_83x6 = {
|
||||
.num_codecs = 3,
|
||||
.codecs = { "ESSX8316", "ESSX8326", "ESSX8336"},
|
||||
|
|
@ -617,6 +686,14 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
|
|||
.sof_tplg_filename = "sof-arl-cs42l43-l0-cs35l56-l2.tplg",
|
||||
.get_function_tplg_files = sof_sdw_get_tplg_files,
|
||||
},
|
||||
{
|
||||
.link_mask = BIT(0) | BIT(2),
|
||||
.links = arl_rt713_vb_l0_rt1320_l2,
|
||||
.drv_name = "sof_sdw",
|
||||
.machine_check = snd_soc_acpi_intel_sdca_is_device_rt712_vb,
|
||||
.sof_tplg_filename = "sof-arl-dummy.tplg",
|
||||
.get_function_tplg_files = sof_sdw_get_tplg_files,
|
||||
},
|
||||
{
|
||||
.link_mask = BIT(0) | BIT(2),
|
||||
.links = arl_rt722_l0_rt1320_l2,
|
||||
|
|
@ -646,6 +723,13 @@ struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[] = {
|
|||
.sof_tplg_filename = "sof-arl-cs42l43-l2-cs35l56-l3.tplg",
|
||||
.get_function_tplg_files = sof_sdw_get_tplg_files,
|
||||
},
|
||||
{
|
||||
.link_mask = BIT(0),
|
||||
.links = arl_rt712_l0,
|
||||
.drv_name = "sof_sdw",
|
||||
.sof_tplg_filename = "sof-arl-dummy.tplg",
|
||||
.get_function_tplg_files = sof_sdw_get_tplg_files,
|
||||
},
|
||||
{
|
||||
.link_mask = BIT(0),
|
||||
.links = arl_cs42l43_l0,
|
||||
|
|
|
|||
|
|
@ -393,6 +393,7 @@ struct q6afe {
|
|||
struct q6core_svc_api_info ainfo;
|
||||
struct mutex lock;
|
||||
struct aprv2_ibasic_rsp_result_t result;
|
||||
uint32_t vote_result;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head port_list;
|
||||
spinlock_t port_list_lock;
|
||||
|
|
@ -1010,13 +1011,14 @@ static int q6afe_callback(struct apr_device *adev, const struct apr_resp_pkt *da
|
|||
const struct aprv2_ibasic_rsp_result_t *res;
|
||||
const struct apr_hdr *hdr = &data->hdr;
|
||||
struct q6afe_port *port;
|
||||
uint32_t *vote_res;
|
||||
|
||||
if (!data->payload_size)
|
||||
return 0;
|
||||
|
||||
res = data->payload;
|
||||
switch (hdr->opcode) {
|
||||
case APR_BASIC_RSP_RESULT: {
|
||||
res = data->payload;
|
||||
if (res->status) {
|
||||
dev_err(afe->dev, "cmd = 0x%x returned error = 0x%x\n",
|
||||
res->opcode, res->status);
|
||||
|
|
@ -1043,8 +1045,10 @@ static int q6afe_callback(struct apr_device *adev, const struct apr_resp_pkt *da
|
|||
}
|
||||
break;
|
||||
case AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST:
|
||||
vote_res = data->payload;
|
||||
afe->result.opcode = hdr->opcode;
|
||||
afe->result.status = res->status;
|
||||
afe->result.status = 0;
|
||||
afe->vote_result = *vote_res;
|
||||
wake_up(&afe->wait);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -1955,6 +1959,8 @@ int q6afe_vote_lpass_core_hw(struct device *dev, uint32_t hw_block_id,
|
|||
AFE_CMD_RSP_REMOTE_LPASS_CORE_HW_VOTE_REQUEST);
|
||||
if (ret)
|
||||
dev_err(afe->dev, "AFE failed to vote (%d)\n", hw_block_id);
|
||||
else
|
||||
*client_handle = afe->vote_result;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -322,15 +322,15 @@ int q6apm_alloc_fragments(struct q6apm_graph *graph, unsigned int dir, phys_addr
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(q6apm_alloc_fragments);
|
||||
|
||||
static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id,
|
||||
static int __q6apm_unmap_memory_fixed_region(struct q6apm *apm, unsigned int graph_id,
|
||||
bool is_pos_buf)
|
||||
{
|
||||
struct apm_cmd_shared_mem_unmap_regions *cmd;
|
||||
struct q6apm *apm = dev_get_drvdata(dev->parent);
|
||||
struct audioreach_graph_info *info;
|
||||
uint32_t mem_map_handle;
|
||||
uint32_t pos_mask = is_pos_buf ? APM_MMAP_TOKEN_MAP_TYPE_POS_BUF : 0;
|
||||
struct gpr_pkt *pkt __free(kfree) = audioreach_alloc_apm_cmd_pkt(sizeof(*cmd),
|
||||
APM_CMD_SHARED_MEM_UNMAP_REGIONS, graph_id);
|
||||
APM_CMD_SHARED_MEM_UNMAP_REGIONS, (graph_id | pos_mask));
|
||||
if (IS_ERR(pkt))
|
||||
return PTR_ERR(pkt);
|
||||
|
||||
|
|
@ -357,13 +357,15 @@ static int __q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int gr
|
|||
|
||||
int q6apm_unmap_memory_fixed_region(struct device *dev, unsigned int graph_id)
|
||||
{
|
||||
return __q6apm_unmap_memory_fixed_region(dev, graph_id, false);
|
||||
return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent),
|
||||
graph_id, false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(q6apm_unmap_memory_fixed_region);
|
||||
|
||||
int q6apm_unmap_pos_buffer(struct device *dev, unsigned int graph_id)
|
||||
{
|
||||
return __q6apm_unmap_memory_fixed_region(dev, graph_id, true);
|
||||
return __q6apm_unmap_memory_fixed_region(dev_get_drvdata(dev->parent),
|
||||
graph_id, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(q6apm_unmap_pos_buffer);
|
||||
|
||||
|
|
@ -850,6 +852,21 @@ static int q6apm_audio_probe(struct snd_soc_component *component)
|
|||
|
||||
static void q6apm_audio_remove(struct snd_soc_component *component)
|
||||
{
|
||||
struct q6apm *apm = dev_get_drvdata(component->dev);
|
||||
struct audioreach_graph_info *info;
|
||||
int id;
|
||||
|
||||
/*
|
||||
* The card core removes components before freeing the PCMs, so
|
||||
* q6apm-dai's pcm_free() runs after the topology (and graph_info)
|
||||
* is gone and can no longer unmap. Release the DSP mappings here,
|
||||
* otherwise the next pcm_new() fails to map the same buffer again.
|
||||
*/
|
||||
idr_for_each_entry(&apm->graph_info_idr, info, id) {
|
||||
__q6apm_unmap_memory_fixed_region(apm, id, false);
|
||||
__q6apm_unmap_memory_fixed_region(apm, id, true);
|
||||
}
|
||||
|
||||
/* remove topology */
|
||||
snd_soc_tplg_component_remove(component);
|
||||
}
|
||||
|
|
@ -960,17 +977,23 @@ static int apm_callback(const struct gpr_resp_pkt *data, void *priv, int op)
|
|||
wake_up(&apm->wait);
|
||||
break;
|
||||
case APM_CMD_SHARED_MEM_UNMAP_REGIONS:
|
||||
apm->result.opcode = hdr->opcode;
|
||||
apm->result.status = 0;
|
||||
rsp = data->payload;
|
||||
|
||||
info = idr_find(&apm->graph_info_idr, hdr->token);
|
||||
if (info)
|
||||
info->mem_map_handle = 0;
|
||||
else
|
||||
apm->result.opcode = result->opcode;
|
||||
apm->result.status = result->status;
|
||||
if (result->status)
|
||||
dev_err(dev, "Error (%d) Processing 0x%08x cmd\n", result->status,
|
||||
result->opcode);
|
||||
|
||||
graph_id = hdr->token & APM_MMAP_TOKEN_GID_MASK;
|
||||
is_pos_buf = hdr->token & APM_MMAP_TOKEN_MAP_TYPE_POS_BUF;
|
||||
|
||||
info = idr_find(&apm->graph_info_idr, graph_id);
|
||||
if (info && !result->status) {
|
||||
if (is_pos_buf)
|
||||
info->pos_buf_mem_map_handle = 0;
|
||||
else
|
||||
info->mem_map_handle = 0;
|
||||
}
|
||||
|
||||
wake_up(&apm->wait);
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -312,22 +312,37 @@ audioreach_get_module_priv_data(const struct snd_soc_tplg_private *private)
|
|||
|
||||
for (sz = 0; sz < le32_to_cpu(private->size); ) {
|
||||
const struct snd_soc_tplg_vendor_array *mod_array;
|
||||
u32 array_size;
|
||||
|
||||
mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
|
||||
array_size = le32_to_cpu(mod_array->size);
|
||||
|
||||
if (le32_to_cpu(mod_array->type) == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) {
|
||||
struct audioreach_module_priv_data *pdata;
|
||||
u32 nwords;
|
||||
|
||||
pdata = kzalloc_flex(*pdata, data,
|
||||
le32_to_cpu(mod_array->size));
|
||||
/* size is the byte count of the __le32 data[] */
|
||||
nwords = array_size / sizeof(__le32);
|
||||
|
||||
/* the blob must lie within the private data */
|
||||
if (sizeof(*pdata) + (u64)array_size >
|
||||
le32_to_cpu(private->size) - sz)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pdata = kzalloc_flex(*pdata, data, nwords);
|
||||
if (!pdata)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
memcpy(pdata, ((u8 *)private->data + sz), struct_size(pdata, data,
|
||||
le32_to_cpu(mod_array->size)));
|
||||
memcpy(pdata, ((u8 *)private->data + sz),
|
||||
struct_size(pdata, data, nwords));
|
||||
return pdata;
|
||||
}
|
||||
|
||||
sz = sz + le32_to_cpu(mod_array->size);
|
||||
/* a zero size would never advance the walk */
|
||||
if (!array_size)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
sz = sz + array_size;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
@ -611,6 +626,12 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon
|
|||
return mod ? PTR_ERR(mod) : -ENODEV;
|
||||
|
||||
mod->data = audioreach_get_module_priv_data(&tplg_w->priv);
|
||||
if (IS_ERR(mod->data)) {
|
||||
int rc = PTR_ERR(mod->data);
|
||||
|
||||
mod->data = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
dobj = &w->dobj;
|
||||
dobj->private = mod;
|
||||
|
|
|
|||
|
|
@ -39,6 +39,16 @@ static int sm8250_snd_init(struct snd_soc_pcm_runtime *rtd)
|
|||
case USB_RX:
|
||||
return qcom_snd_usb_offload_jack_setup(rtd, &data->usb_offload_jack,
|
||||
&data->usb_offload_jack_setup);
|
||||
case RX_CODEC_DMA_RX_0:
|
||||
/*
|
||||
* The RX macro digital gain goes up to +40 dB. Userspace that
|
||||
* maps full volume to the top of the range (PipeWire, PulseAudio)
|
||||
* would clip there, so stop the interpolator gains at 0 dB.
|
||||
*/
|
||||
snd_soc_limit_volume(rtd->card, "RX_RX0 Digital Volume", 84);
|
||||
snd_soc_limit_volume(rtd->card, "RX_RX1 Digital Volume", 84);
|
||||
snd_soc_limit_volume(rtd->card, "RX_RX2 Digital Volume", 84);
|
||||
fallthrough;
|
||||
default:
|
||||
return qcom_snd_wcd_jack_setup(rtd, &data->jack, &data->jack_setup);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@
|
|||
*/
|
||||
#define MCLK1_RATE 24000000U
|
||||
#define MCLK2_RATE 32768U
|
||||
#define DEFAULT_FLL1_RATE 11289600U
|
||||
/* Matches the codec's default AIF1 configuration: 48kHz, 256fs */
|
||||
#define DEFAULT_FLL1_RATE 12288000U
|
||||
|
||||
struct midas_priv {
|
||||
struct gpio_desc *gpio_fm_sel;
|
||||
|
|
@ -34,6 +35,7 @@ struct midas_priv {
|
|||
struct gpio_desc *gpio_headset_key;
|
||||
struct iio_channel *adc_headset_detect;
|
||||
unsigned int fll1_rate;
|
||||
unsigned int aif1clk_rate;
|
||||
|
||||
struct snd_soc_jack headset_jack;
|
||||
};
|
||||
|
|
@ -171,11 +173,12 @@ static int midas_start_fll1(struct snd_soc_pcm_runtime *rtd, unsigned int rate)
|
|||
if (!rate)
|
||||
rate = priv->fll1_rate;
|
||||
/*
|
||||
* If no new rate is requested, set FLL1 to a sane default for jack
|
||||
* detection.
|
||||
* If no new rate is requested, set FLL1 to the rate the codec's AIF1
|
||||
* is currently configured for, as its digital paths can be powered
|
||||
* up without an active stream.
|
||||
*/
|
||||
if (!rate)
|
||||
rate = DEFAULT_FLL1_RATE;
|
||||
rate = priv->aif1clk_rate ?: DEFAULT_FLL1_RATE;
|
||||
|
||||
if (rate != priv->fll1_rate && priv->fll1_rate) {
|
||||
/* while reconfiguring, switch to MCLK2 for SYSCLK */
|
||||
|
|
@ -241,6 +244,7 @@ static int midas_aif1_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 midas_priv *priv = snd_soc_card_get_drvdata(rtd->card);
|
||||
unsigned int pll_out;
|
||||
|
||||
/* AIF1CLK should be at least 3MHz for "optimal performance" */
|
||||
|
|
@ -249,6 +253,8 @@ static int midas_aif1_hw_params(struct snd_pcm_substream *substream,
|
|||
else
|
||||
pll_out = params_rate(params) * 256;
|
||||
|
||||
priv->aif1clk_rate = pll_out;
|
||||
|
||||
return midas_start_fll1(rtd, pll_out);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,11 @@
|
|||
static int class_read_prop(struct sdw_slave *sdw)
|
||||
{
|
||||
struct sdw_slave_prop *prop = &sdw->prop;
|
||||
int ret;
|
||||
|
||||
sdw_slave_read_prop(sdw);
|
||||
ret = sdw_slave_read_prop(sdw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
prop->use_domain_irq = true;
|
||||
prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY |
|
||||
|
|
@ -194,8 +197,10 @@ int sdca_class_probe(struct sdw_slave *sdw,
|
|||
pm_runtime_get_noresume(dev);
|
||||
|
||||
ret = devm_pm_runtime_enable(dev);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pm_runtime_put_sync(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
queue_work(system_long_wq, &drv->boot_work);
|
||||
|
||||
|
|
@ -260,6 +265,7 @@ int sdca_class_system_suspend(struct sdca_class_drv *drv)
|
|||
ret = pm_runtime_force_suspend(drv->dev);
|
||||
if (ret) {
|
||||
dev_err(drv->dev, "failed to force suspend: %d\n", ret);
|
||||
enable_irq(drv->sdw->irq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
config SND_SOC_SOF_AMD_TOPLEVEL
|
||||
tristate "SOF support for AMD audio DSPs"
|
||||
depends on SOUNDWIRE_AMD || !SOUNDWIRE_AMD
|
||||
depends on ACPI
|
||||
depends on X86 || COMPILE_TEST
|
||||
help
|
||||
This adds support for Sound Open Firmware for AMD platforms.
|
||||
|
|
|
|||
|
|
@ -15,8 +15,6 @@
|
|||
#include "hda.h"
|
||||
|
||||
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
|
||||
#include "../../codecs/hdac_hda.h"
|
||||
|
||||
#define CODEC_PROBE_RETRIES 3
|
||||
|
||||
#define IDISP_VID_INTEL 0x80860000
|
||||
|
|
@ -148,7 +146,6 @@ static struct hda_codec *hda_codec_device_init(struct hdac_bus *bus, int addr, i
|
|||
/* probe individual codec */
|
||||
static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
|
||||
{
|
||||
struct hdac_hda_priv *hda_priv;
|
||||
struct hda_bus *hbus = sof_to_hbus(sdev);
|
||||
struct hda_codec *codec;
|
||||
u32 hda_cmd = (address << 28) | (AC_NODE_ROOT << 20) |
|
||||
|
|
@ -168,27 +165,15 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address)
|
|||
dev_dbg(sdev->dev, "HDA codec #%d probed OK: response: %x\n",
|
||||
address, resp);
|
||||
|
||||
hda_priv = devm_kzalloc(sdev->dev, sizeof(*hda_priv), GFP_KERNEL);
|
||||
if (!hda_priv)
|
||||
return -ENOMEM;
|
||||
|
||||
codec = hda_codec_device_init(&hbus->core, address, HDA_DEV_LEGACY);
|
||||
ret = PTR_ERR_OR_ZERO(codec);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
hda_priv->codec = codec;
|
||||
hda_priv->dev_index = address;
|
||||
dev_set_drvdata(&codec->core.dev, hda_priv);
|
||||
|
||||
if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) {
|
||||
if (!hbus->core.audio_component) {
|
||||
dev_dbg(sdev->dev,
|
||||
"iDisp hw present but no driver\n");
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
hda_priv->need_display_power = true;
|
||||
if ((resp & 0xFFFF0000) == IDISP_VID_INTEL && !hbus->core.audio_component) {
|
||||
dev_dbg(sdev->dev, "iDisp hw present but no driver\n");
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (is_generic_config(hbus))
|
||||
|
|
|
|||
|
|
@ -349,6 +349,7 @@ void hda_dsp_ctrl_stop_chip(struct snd_sof_dev *sdev)
|
|||
|
||||
bus->chip_init = false;
|
||||
}
|
||||
EXPORT_SYMBOL_NS(hda_dsp_ctrl_stop_chip, "SND_SOC_SOF_INTEL_HDA_COMMON");
|
||||
|
||||
MODULE_LICENSE("Dual BSD/GPL");
|
||||
MODULE_DESCRIPTION("SOF helpers for HDaudio platforms");
|
||||
|
|
|
|||
|
|
@ -939,6 +939,7 @@ int hda_dsp_probe(struct snd_sof_dev *sdev)
|
|||
hda_dsp_ctrl_ppcap_enable(sdev, false);
|
||||
}
|
||||
free_ipc_irq:
|
||||
hda_dsp_ctrl_stop_chip(sdev);
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
free_irq_vector:
|
||||
if (sdev->msi_enabled)
|
||||
|
|
@ -1006,6 +1007,9 @@ void hda_dsp_remove(struct snd_sof_dev *sdev)
|
|||
snd_dma_free_pages(&hda->iccmax_dmab);
|
||||
|
||||
skip_disable_dsp:
|
||||
/* stop CORB/RIRB and position buffer DMA before the buffers are freed */
|
||||
hda_dsp_ctrl_stop_chip(sdev);
|
||||
|
||||
free_irq(sdev->ipc_irq, sdev);
|
||||
if (sdev->msi_enabled)
|
||||
pci_free_irq_vectors(pci);
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
// Author: Maruthi Srinivas Bayyavarapu <maruthis@xilinx.com>
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -55,8 +56,8 @@
|
|||
#define CFG_S2MM_XFER_SHIFT 29
|
||||
#define CFG_S2MM_PKG_MASK BIT(28)
|
||||
|
||||
#define AUD_CTRL_DATA_WIDTH_SHIFT 16
|
||||
#define AUD_CTRL_ACTIVE_CH_SHIFT 19
|
||||
#define AUD_CTRL_DATA_WIDTH_MASK GENMASK(18, 16)
|
||||
#define AUD_CTRL_ACTIVE_CH_MASK GENMASK(22, 19)
|
||||
#define PERIOD_CFG_PERIODS_SHIFT 16
|
||||
|
||||
#define PERIODS_MIN 2
|
||||
|
|
@ -506,28 +507,29 @@ static int xlnx_formatter_pcm_hw_params(struct snd_soc_component *component,
|
|||
writel(high, stream_data->mmio + XLNX_AUD_BUFF_ADDR_MSB);
|
||||
|
||||
val = readl(stream_data->mmio + XLNX_AUD_CTRL);
|
||||
val &= ~(AUD_CTRL_DATA_WIDTH_MASK | AUD_CTRL_ACTIVE_CH_MASK);
|
||||
bits_per_sample = params_width(params);
|
||||
switch (bits_per_sample) {
|
||||
case 8:
|
||||
val |= (BIT_DEPTH_8 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_8);
|
||||
break;
|
||||
case 16:
|
||||
val |= (BIT_DEPTH_16 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_16);
|
||||
break;
|
||||
case 20:
|
||||
val |= (BIT_DEPTH_20 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_20);
|
||||
break;
|
||||
case 24:
|
||||
val |= (BIT_DEPTH_24 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_24);
|
||||
break;
|
||||
case 32:
|
||||
val |= (BIT_DEPTH_32 << AUD_CTRL_DATA_WIDTH_SHIFT);
|
||||
val |= FIELD_PREP(AUD_CTRL_DATA_WIDTH_MASK, BIT_DEPTH_32);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
val |= active_ch << AUD_CTRL_ACTIVE_CH_SHIFT;
|
||||
val |= FIELD_PREP(AUD_CTRL_ACTIVE_CH_MASK, active_ch);
|
||||
writel(val, stream_data->mmio + XLNX_AUD_CTRL);
|
||||
|
||||
val = (params_periods(params) << PERIOD_CFG_PERIODS_SHIFT)
|
||||
|
|
|
|||
|
|
@ -1642,9 +1642,9 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep)
|
|||
err = -ENODEV;
|
||||
if (err < 0) {
|
||||
if (!atomic_read(&ep->chip->shutdown))
|
||||
usb_audio_err(ep->chip,
|
||||
"cannot submit urb %d, error %d: %s\n",
|
||||
i, err, usb_error_string(err));
|
||||
usb_audio_err_ratelimited(ep->chip,
|
||||
"cannot submit urb %d, error %d: %s\n",
|
||||
i, err, usb_error_string(err));
|
||||
goto __error;
|
||||
}
|
||||
set_bit(i, &ep->active_mask);
|
||||
|
|
|
|||
|
|
@ -285,13 +285,29 @@ static void playback_work(struct work_struct *work)
|
|||
/* fill packet with data or silence */
|
||||
urb->iso_frame_desc[0].length =
|
||||
frames * ua->playback.frame_bytes;
|
||||
if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
|
||||
if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
|
||||
/*
|
||||
* The packet size comes from the capture stream,
|
||||
* i.e. from the device, while the ring buffer can
|
||||
* be as small as two tiny periods. The single wrap
|
||||
* in copy_playback_data() is only valid for
|
||||
* frames <= buffer_size, so copy at most one
|
||||
* buffer and send silence for the rest.
|
||||
*/
|
||||
unsigned int copy_frames = min(frames,
|
||||
ua->playback.substream->runtime->buffer_size);
|
||||
|
||||
do_period_elapsed |= copy_playback_data(&ua->playback,
|
||||
urb,
|
||||
frames);
|
||||
else
|
||||
copy_frames);
|
||||
memset(urb->transfer_buffer +
|
||||
copy_frames * ua->playback.frame_bytes, 0,
|
||||
(frames - copy_frames) *
|
||||
ua->playback.frame_bytes);
|
||||
} else {
|
||||
memset(urb->transfer_buffer, 0,
|
||||
urb->iso_frame_desc[0].length);
|
||||
}
|
||||
|
||||
/* and off you go ... */
|
||||
err = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
|
|
@ -320,6 +336,13 @@ static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb,
|
|||
|
||||
runtime = stream->substream->runtime;
|
||||
frame_bytes = stream->frame_bytes;
|
||||
/*
|
||||
* A packet can carry up to max_packet_bytes, the device's
|
||||
* wMaxPacketSize, which may exceed the whole ring buffer; keep what
|
||||
* fits so the single wrap below stays valid.
|
||||
*/
|
||||
if (unlikely(frames > runtime->buffer_size))
|
||||
frames = runtime->buffer_size;
|
||||
dest = runtime->dma_area + stream->buffer_pos * frame_bytes;
|
||||
if (stream->buffer_pos + frames <= runtime->buffer_size) {
|
||||
memcpy(dest, urb->transfer_buffer, frames * frame_bytes);
|
||||
|
|
|
|||
|
|
@ -1343,6 +1343,18 @@ static void retire_capture_urb(struct snd_usb_substream *subs,
|
|||
bytes -= adj;
|
||||
subs->stream_offset_adj -= adj;
|
||||
}
|
||||
/*
|
||||
* A packet can be as large as the endpoint's maxpacksize, which
|
||||
* the device chooses, while the ring buffer can be as small as
|
||||
* two 64-byte periods. The hwptr_done wrap below handles one
|
||||
* wrap only, so never take more than one buffer from a packet.
|
||||
*/
|
||||
if (unlikely(bytes > subs->buffer_bytes)) {
|
||||
dev_warn_ratelimited(&subs->dev->dev,
|
||||
"%u-byte packet exceeds %u-byte buffer, truncating\n",
|
||||
bytes, subs->buffer_bytes);
|
||||
bytes = subs->buffer_bytes;
|
||||
}
|
||||
frames = bytes / stride;
|
||||
if (!subs->txfr_quirk)
|
||||
bytes = frames * stride;
|
||||
|
|
@ -1553,8 +1565,14 @@ static int prepare_playback_urb(struct snd_usb_substream *subs,
|
|||
|
||||
for (i = 0; i < ctx->packets; i++) {
|
||||
counts = snd_usb_endpoint_next_packet_size(ep, ctx, i, avail);
|
||||
/*
|
||||
* Bound by the ring buffer as well as by the URB:
|
||||
* copy_to_urb() wraps hwptr_done once, so one URB must
|
||||
* never carry more than the whole buffer.
|
||||
*/
|
||||
if (counts < 0 ||
|
||||
(frames + counts) * stride > ctx->buffer_size)
|
||||
(frames + counts) * stride > ctx->buffer_size ||
|
||||
(frames + counts) * stride > subs->buffer_bytes)
|
||||
break;
|
||||
/* set up descriptor */
|
||||
urb->iso_frame_desc[i].offset = frames * stride;
|
||||
|
|
|
|||
|
|
@ -2359,6 +2359,69 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Novation UltraNova: vendor-specific class descriptors, fixed
|
||||
* audio and MIDI layouts. Only the audio and MIDI interfaces
|
||||
* (0 and 1) are grabbed; the vendor control interfaces (2/3)
|
||||
* are left unbound for userspace access.
|
||||
*/
|
||||
USB_DEVICE_INTERFACE_NUMBER(0x1235, 0x0011, 0),
|
||||
QUIRK_DRIVER_INFO {
|
||||
.vendor_name = "Novation",
|
||||
.product_name = "UltraNova",
|
||||
QUIRK_DATA_COMPOSITE {
|
||||
{
|
||||
QUIRK_DATA_AUDIOFORMAT(0) {
|
||||
/* playback */
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels = 4,
|
||||
.iface = 0,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
|
||||
.endpoint = 0x01,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_SYNC,
|
||||
.maxpacksize = 392,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 48000,
|
||||
.nr_rates = 2,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
QUIRK_DATA_AUDIOFORMAT(0) {
|
||||
/* capture */
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.channels = 2,
|
||||
.iface = 0,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
|
||||
.endpoint = 0x82,
|
||||
.ep_idx = 1,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC,
|
||||
.maxpacksize = 294,
|
||||
.rates = SNDRV_PCM_RATE_44100 |
|
||||
SNDRV_PCM_RATE_48000,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 48000,
|
||||
.nr_rates = 2,
|
||||
.rate_table = (unsigned int[]) {
|
||||
44100, 48000
|
||||
}
|
||||
}
|
||||
},
|
||||
{ QUIRK_DATA_RAW_BYTES(1) },
|
||||
QUIRK_COMPOSITE_END
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x1235, 0x001e),
|
||||
QUIRK_DRIVER_INFO {
|
||||
|
|
@ -3005,6 +3068,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
.rates = SNDRV_PCM_RATE_96000,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC,
|
||||
.datainterval = 1,
|
||||
.rate_min = 96000,
|
||||
.rate_max = 96000,
|
||||
.nr_rates = 1,
|
||||
|
|
@ -3027,6 +3091,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
|||
.rates = SNDRV_PCM_RATE_96000,
|
||||
.ep_attr = USB_ENDPOINT_XFER_ISOC |
|
||||
USB_ENDPOINT_SYNC_ASYNC,
|
||||
.datainterval = 1,
|
||||
.rate_min = 96000,
|
||||
.rate_max = 96000,
|
||||
.nr_rates = 1,
|
||||
|
|
|
|||
|
|
@ -1794,7 +1794,7 @@ int snd_usb_apply_boot_quirk_once(struct usb_device *dev,
|
|||
/* the quirk seems breaking on some Behringer devices */
|
||||
switch (id) {
|
||||
case USB_ID(0x1397, 0x0508): /* UMC204HD */
|
||||
case USB_ID(0x1397, 0x0509): /* UMC204HD */
|
||||
case USB_ID(0x1397, 0x0509): /* UMC404HD */
|
||||
return 0;
|
||||
}
|
||||
return snd_usb_cm1a_boot_quirk(dev);
|
||||
|
|
@ -2496,6 +2496,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|||
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
|
||||
DEVICE_FLG(0x0124, 0x0c21, /* Generic USB Headphone */
|
||||
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
|
||||
DEVICE_FLG(0x0124, 0x0c36, /* RYDZ Technology USB Headphone */
|
||||
QUIRK_FLAG_FORCE_IFACE_RESET | QUIRK_FLAG_IFACE_DELAY),
|
||||
DEVICE_FLG(0x03f0, 0x0c56, /* HP Elite x3 Lap Dock */
|
||||
QUIRK_FLAG_FIXED_RATE),
|
||||
DEVICE_FLG(0x03f0, 0x654a, /* HP 320 FHD Webcam */
|
||||
|
|
@ -2659,6 +2661,8 @@ static const struct usb_audio_quirk_flags_table quirk_flags_table[] = {
|
|||
QUIRK_FLAG_CTL_MSG_DELAY_1M | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
|
||||
DEVICE_FLG(0x0d8c, 0x0102, /* C-Media CM6206 */
|
||||
QUIRK_FLAG_GET_SAMPLE_RATE),
|
||||
DEVICE_FLG(0x0db0, 0xa073, /* MSI MAG X570S Tomahawk/Torpedo Max (ALC4080) */
|
||||
QUIRK_FLAG_SKIP_IFACE_SETUP),
|
||||
DEVICE_FLG(0x0e0b, 0xfa01, /* Feaulle Rainbow */
|
||||
QUIRK_FLAG_GET_SAMPLE_RATE | QUIRK_FLAG_MIXER_PLAYBACK_MIN_MUTE),
|
||||
DEVICE_FLG(0x0ecb, 0x205c, /* JBL Quantum610 Wireless */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user