18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Support for Digigram Lola PCI-e boards 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <sound/core.h> 128c2ecf20Sopenharmony_ci#include <sound/info.h> 138c2ecf20Sopenharmony_ci#include <sound/pcm.h> 148c2ecf20Sopenharmony_ci#include "lola.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic void print_audio_widget(struct snd_info_buffer *buffer, 178c2ecf20Sopenharmony_ci struct lola *chip, int nid, const char *name) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci unsigned int val; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 228c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); 238c2ecf20Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); 248c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Formats: 0x%x\n", val); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic void print_pin_widget(struct snd_info_buffer *buffer, 288c2ecf20Sopenharmony_ci struct lola *chip, int nid, unsigned int ampcap, 298c2ecf20Sopenharmony_ci const char *name) 308c2ecf20Sopenharmony_ci{ 318c2ecf20Sopenharmony_ci unsigned int val; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 348c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); 358c2ecf20Sopenharmony_ci if (val == 0x00400200) 368c2ecf20Sopenharmony_ci return; 378c2ecf20Sopenharmony_ci lola_read_param(chip, nid, ampcap, &val); 388c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Amp-Caps: 0x%x\n", val); 398c2ecf20Sopenharmony_ci snd_iprintf(buffer, " mute=%d, step-size=%d, steps=%d, ofs=%d\n", 408c2ecf20Sopenharmony_ci LOLA_AMP_MUTE_CAPABLE(val), 418c2ecf20Sopenharmony_ci LOLA_AMP_STEP_SIZE(val), 428c2ecf20Sopenharmony_ci LOLA_AMP_NUM_STEPS(val), 438c2ecf20Sopenharmony_ci LOLA_AMP_OFFSET(val)); 448c2ecf20Sopenharmony_ci lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL); 458c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Max-level: 0x%x\n", val); 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic void print_clock_widget(struct snd_info_buffer *buffer, 498c2ecf20Sopenharmony_ci struct lola *chip, int nid) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci int i, j, num_clocks; 528c2ecf20Sopenharmony_ci unsigned int val; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 558c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val); 568c2ecf20Sopenharmony_ci num_clocks = val & 0xff; 578c2ecf20Sopenharmony_ci for (i = 0; i < num_clocks; i += 4) { 588c2ecf20Sopenharmony_ci unsigned int res_ex; 598c2ecf20Sopenharmony_ci unsigned short items[4]; 608c2ecf20Sopenharmony_ci const char *name; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, 638c2ecf20Sopenharmony_ci i, 0, &val, &res_ex); 648c2ecf20Sopenharmony_ci items[0] = val & 0xfff; 658c2ecf20Sopenharmony_ci items[1] = (val >> 16) & 0xfff; 668c2ecf20Sopenharmony_ci items[2] = res_ex & 0xfff; 678c2ecf20Sopenharmony_ci items[3] = (res_ex >> 16) & 0xfff; 688c2ecf20Sopenharmony_ci for (j = 0; j < 4; j++) { 698c2ecf20Sopenharmony_ci unsigned char type = items[j] >> 8; 708c2ecf20Sopenharmony_ci unsigned int freq = items[j] & 0xff; 718c2ecf20Sopenharmony_ci if (i + j >= num_clocks) 728c2ecf20Sopenharmony_ci break; 738c2ecf20Sopenharmony_ci if (type == LOLA_CLOCK_TYPE_INTERNAL) { 748c2ecf20Sopenharmony_ci name = "Internal"; 758c2ecf20Sopenharmony_ci freq = lola_sample_rate_convert(freq); 768c2ecf20Sopenharmony_ci } else if (type == LOLA_CLOCK_TYPE_VIDEO) { 778c2ecf20Sopenharmony_ci name = "Video"; 788c2ecf20Sopenharmony_ci freq = lola_sample_rate_convert(freq); 798c2ecf20Sopenharmony_ci } else { 808c2ecf20Sopenharmony_ci name = "Other"; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Clock %d: Type %d:%s, freq=%d\n", 838c2ecf20Sopenharmony_ci i + j, type, name, freq); 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void print_mixer_widget(struct snd_info_buffer *buffer, 898c2ecf20Sopenharmony_ci struct lola *chip, int nid) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci unsigned int val; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 948c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void lola_proc_codec_read(struct snd_info_entry *entry, 988c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci struct lola *chip = entry->private_data; 1018c2ecf20Sopenharmony_ci unsigned int val; 1028c2ecf20Sopenharmony_ci int i, nid; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); 1058c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Vendor: 0x%08x\n", val); 1068c2ecf20Sopenharmony_ci lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); 1078c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Function Type: %d\n", val); 1088c2ecf20Sopenharmony_ci lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); 1098c2ecf20Sopenharmony_ci snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val); 1108c2ecf20Sopenharmony_ci snd_iprintf(buffer, " Pins-In %d, Pins-Out %d\n", 1118c2ecf20Sopenharmony_ci chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); 1128c2ecf20Sopenharmony_ci nid = 2; 1138c2ecf20Sopenharmony_ci for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++) 1148c2ecf20Sopenharmony_ci print_audio_widget(buffer, chip, nid, "[Audio-In]"); 1158c2ecf20Sopenharmony_ci for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++) 1168c2ecf20Sopenharmony_ci print_audio_widget(buffer, chip, nid, "[Audio-Out]"); 1178c2ecf20Sopenharmony_ci for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++) 1188c2ecf20Sopenharmony_ci print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP, 1198c2ecf20Sopenharmony_ci "[Pin-In]"); 1208c2ecf20Sopenharmony_ci for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++) 1218c2ecf20Sopenharmony_ci print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP, 1228c2ecf20Sopenharmony_ci "[Pin-Out]"); 1238c2ecf20Sopenharmony_ci if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { 1248c2ecf20Sopenharmony_ci print_clock_widget(buffer, chip, nid); 1258c2ecf20Sopenharmony_ci nid++; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { 1288c2ecf20Sopenharmony_ci print_mixer_widget(buffer, chip, nid); 1298c2ecf20Sopenharmony_ci nid++; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* direct codec access for debugging */ 1348c2ecf20Sopenharmony_cistatic void lola_proc_codec_rw_write(struct snd_info_entry *entry, 1358c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct lola *chip = entry->private_data; 1388c2ecf20Sopenharmony_ci char line[64]; 1398c2ecf20Sopenharmony_ci unsigned int id, verb, data, extdata; 1408c2ecf20Sopenharmony_ci while (!snd_info_get_line(buffer, line, sizeof(line))) { 1418c2ecf20Sopenharmony_ci if (sscanf(line, "%u %u %u %u", &id, &verb, &data, &extdata) != 4) 1428c2ecf20Sopenharmony_ci continue; 1438c2ecf20Sopenharmony_ci lola_codec_read(chip, id, verb, data, extdata, 1448c2ecf20Sopenharmony_ci &chip->debug_res, 1458c2ecf20Sopenharmony_ci &chip->debug_res_ex); 1468c2ecf20Sopenharmony_ci } 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic void lola_proc_codec_rw_read(struct snd_info_entry *entry, 1508c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct lola *chip = entry->private_data; 1538c2ecf20Sopenharmony_ci snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci/* 1578c2ecf20Sopenharmony_ci * dump some registers 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_cistatic void lola_proc_regs_read(struct snd_info_entry *entry, 1608c2ecf20Sopenharmony_ci struct snd_info_buffer *buffer) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci struct lola *chip = entry->private_data; 1638c2ecf20Sopenharmony_ci int i; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci for (i = 0; i < 0x40; i += 4) { 1668c2ecf20Sopenharmony_ci snd_iprintf(buffer, "BAR0 %02x: %08x\n", i, 1678c2ecf20Sopenharmony_ci readl(chip->bar[BAR0].remap_addr + i)); 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 1708c2ecf20Sopenharmony_ci for (i = 0; i < 0x30; i += 4) { 1718c2ecf20Sopenharmony_ci snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, 1728c2ecf20Sopenharmony_ci readl(chip->bar[BAR1].remap_addr + i)); 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 1758c2ecf20Sopenharmony_ci for (i = 0x80; i < 0xa0; i += 4) { 1768c2ecf20Sopenharmony_ci snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, 1778c2ecf20Sopenharmony_ci readl(chip->bar[BAR1].remap_addr + i)); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci snd_iprintf(buffer, "\n"); 1808c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) { 1818c2ecf20Sopenharmony_ci snd_iprintf(buffer, "DSD %02x STS %08x\n", i, 1828c2ecf20Sopenharmony_ci lola_dsd_read(chip, i, STS)); 1838c2ecf20Sopenharmony_ci snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i, 1848c2ecf20Sopenharmony_ci lola_dsd_read(chip, i, LPIB)); 1858c2ecf20Sopenharmony_ci snd_iprintf(buffer, "DSD %02x CTL %08x\n", i, 1868c2ecf20Sopenharmony_ci lola_dsd_read(chip, i, CTL)); 1878c2ecf20Sopenharmony_ci snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i, 1888c2ecf20Sopenharmony_ci lola_dsd_read(chip, i, LVI)); 1898c2ecf20Sopenharmony_ci snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i, 1908c2ecf20Sopenharmony_ci lola_dsd_read(chip, i, BDPL)); 1918c2ecf20Sopenharmony_ci snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i, 1928c2ecf20Sopenharmony_ci lola_dsd_read(chip, i, BDPU)); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_civoid lola_proc_debug_new(struct lola *chip) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci snd_card_ro_proc_new(chip->card, "codec", chip, lola_proc_codec_read); 1998c2ecf20Sopenharmony_ci snd_card_rw_proc_new(chip->card, "codec_rw", chip, 2008c2ecf20Sopenharmony_ci lola_proc_codec_rw_read, 2018c2ecf20Sopenharmony_ci lola_proc_codec_rw_write); 2028c2ecf20Sopenharmony_ci snd_card_ro_proc_new(chip->card, "regs", chip, lola_proc_regs_read); 2038c2ecf20Sopenharmony_ci} 204