162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Support for Digigram Lola PCI-e boards 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <sound/core.h> 1262306a36Sopenharmony_ci#include <sound/info.h> 1362306a36Sopenharmony_ci#include <sound/pcm.h> 1462306a36Sopenharmony_ci#include "lola.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic void print_audio_widget(struct snd_info_buffer *buffer, 1762306a36Sopenharmony_ci struct lola *chip, int nid, const char *name) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci unsigned int val; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 2262306a36Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); 2362306a36Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); 2462306a36Sopenharmony_ci snd_iprintf(buffer, " Formats: 0x%x\n", val); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic void print_pin_widget(struct snd_info_buffer *buffer, 2862306a36Sopenharmony_ci struct lola *chip, int nid, unsigned int ampcap, 2962306a36Sopenharmony_ci const char *name) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci unsigned int val; 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 3462306a36Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x %s wcaps 0x%x\n", nid, name, val); 3562306a36Sopenharmony_ci if (val == 0x00400200) 3662306a36Sopenharmony_ci return; 3762306a36Sopenharmony_ci lola_read_param(chip, nid, ampcap, &val); 3862306a36Sopenharmony_ci snd_iprintf(buffer, " Amp-Caps: 0x%x\n", val); 3962306a36Sopenharmony_ci snd_iprintf(buffer, " mute=%d, step-size=%d, steps=%d, ofs=%d\n", 4062306a36Sopenharmony_ci LOLA_AMP_MUTE_CAPABLE(val), 4162306a36Sopenharmony_ci LOLA_AMP_STEP_SIZE(val), 4262306a36Sopenharmony_ci LOLA_AMP_NUM_STEPS(val), 4362306a36Sopenharmony_ci LOLA_AMP_OFFSET(val)); 4462306a36Sopenharmony_ci lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL); 4562306a36Sopenharmony_ci snd_iprintf(buffer, " Max-level: 0x%x\n", val); 4662306a36Sopenharmony_ci} 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic void print_clock_widget(struct snd_info_buffer *buffer, 4962306a36Sopenharmony_ci struct lola *chip, int nid) 5062306a36Sopenharmony_ci{ 5162306a36Sopenharmony_ci int i, j, num_clocks; 5262306a36Sopenharmony_ci unsigned int val; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 5562306a36Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x [Clock] wcaps 0x%x\n", nid, val); 5662306a36Sopenharmony_ci num_clocks = val & 0xff; 5762306a36Sopenharmony_ci for (i = 0; i < num_clocks; i += 4) { 5862306a36Sopenharmony_ci unsigned int res_ex; 5962306a36Sopenharmony_ci unsigned short items[4]; 6062306a36Sopenharmony_ci const char *name; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, 6362306a36Sopenharmony_ci i, 0, &val, &res_ex); 6462306a36Sopenharmony_ci items[0] = val & 0xfff; 6562306a36Sopenharmony_ci items[1] = (val >> 16) & 0xfff; 6662306a36Sopenharmony_ci items[2] = res_ex & 0xfff; 6762306a36Sopenharmony_ci items[3] = (res_ex >> 16) & 0xfff; 6862306a36Sopenharmony_ci for (j = 0; j < 4; j++) { 6962306a36Sopenharmony_ci unsigned char type = items[j] >> 8; 7062306a36Sopenharmony_ci unsigned int freq = items[j] & 0xff; 7162306a36Sopenharmony_ci if (i + j >= num_clocks) 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci if (type == LOLA_CLOCK_TYPE_INTERNAL) { 7462306a36Sopenharmony_ci name = "Internal"; 7562306a36Sopenharmony_ci freq = lola_sample_rate_convert(freq); 7662306a36Sopenharmony_ci } else if (type == LOLA_CLOCK_TYPE_VIDEO) { 7762306a36Sopenharmony_ci name = "Video"; 7862306a36Sopenharmony_ci freq = lola_sample_rate_convert(freq); 7962306a36Sopenharmony_ci } else { 8062306a36Sopenharmony_ci name = "Other"; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci snd_iprintf(buffer, " Clock %d: Type %d:%s, freq=%d\n", 8362306a36Sopenharmony_ci i + j, type, name, freq); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci } 8662306a36Sopenharmony_ci} 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistatic void print_mixer_widget(struct snd_info_buffer *buffer, 8962306a36Sopenharmony_ci struct lola *chip, int nid) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci unsigned int val; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); 9462306a36Sopenharmony_ci snd_iprintf(buffer, "Node 0x%02x [Mixer] wcaps 0x%x\n", nid, val); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic void lola_proc_codec_read(struct snd_info_entry *entry, 9862306a36Sopenharmony_ci struct snd_info_buffer *buffer) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci struct lola *chip = entry->private_data; 10162306a36Sopenharmony_ci unsigned int val; 10262306a36Sopenharmony_ci int i, nid; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); 10562306a36Sopenharmony_ci snd_iprintf(buffer, "Vendor: 0x%08x\n", val); 10662306a36Sopenharmony_ci lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); 10762306a36Sopenharmony_ci snd_iprintf(buffer, "Function Type: %d\n", val); 10862306a36Sopenharmony_ci lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); 10962306a36Sopenharmony_ci snd_iprintf(buffer, "Specific-Caps: 0x%08x\n", val); 11062306a36Sopenharmony_ci snd_iprintf(buffer, " Pins-In %d, Pins-Out %d\n", 11162306a36Sopenharmony_ci chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); 11262306a36Sopenharmony_ci nid = 2; 11362306a36Sopenharmony_ci for (i = 0; i < chip->pcm[CAPT].num_streams; i++, nid++) 11462306a36Sopenharmony_ci print_audio_widget(buffer, chip, nid, "[Audio-In]"); 11562306a36Sopenharmony_ci for (i = 0; i < chip->pcm[PLAY].num_streams; i++, nid++) 11662306a36Sopenharmony_ci print_audio_widget(buffer, chip, nid, "[Audio-Out]"); 11762306a36Sopenharmony_ci for (i = 0; i < chip->pin[CAPT].num_pins; i++, nid++) 11862306a36Sopenharmony_ci print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_IN_CAP, 11962306a36Sopenharmony_ci "[Pin-In]"); 12062306a36Sopenharmony_ci for (i = 0; i < chip->pin[PLAY].num_pins; i++, nid++) 12162306a36Sopenharmony_ci print_pin_widget(buffer, chip, nid, LOLA_PAR_AMP_OUT_CAP, 12262306a36Sopenharmony_ci "[Pin-Out]"); 12362306a36Sopenharmony_ci if (LOLA_AFG_CLOCK_WIDGET_PRESENT(chip->lola_caps)) { 12462306a36Sopenharmony_ci print_clock_widget(buffer, chip, nid); 12562306a36Sopenharmony_ci nid++; 12662306a36Sopenharmony_ci } 12762306a36Sopenharmony_ci if (LOLA_AFG_MIXER_WIDGET_PRESENT(chip->lola_caps)) { 12862306a36Sopenharmony_ci print_mixer_widget(buffer, chip, nid); 12962306a36Sopenharmony_ci nid++; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* direct codec access for debugging */ 13462306a36Sopenharmony_cistatic void lola_proc_codec_rw_write(struct snd_info_entry *entry, 13562306a36Sopenharmony_ci struct snd_info_buffer *buffer) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct lola *chip = entry->private_data; 13862306a36Sopenharmony_ci char line[64]; 13962306a36Sopenharmony_ci unsigned int id, verb, data, extdata; 14062306a36Sopenharmony_ci while (!snd_info_get_line(buffer, line, sizeof(line))) { 14162306a36Sopenharmony_ci if (sscanf(line, "%u %u %u %u", &id, &verb, &data, &extdata) != 4) 14262306a36Sopenharmony_ci continue; 14362306a36Sopenharmony_ci lola_codec_read(chip, id, verb, data, extdata, 14462306a36Sopenharmony_ci &chip->debug_res, 14562306a36Sopenharmony_ci &chip->debug_res_ex); 14662306a36Sopenharmony_ci } 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic void lola_proc_codec_rw_read(struct snd_info_entry *entry, 15062306a36Sopenharmony_ci struct snd_info_buffer *buffer) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct lola *chip = entry->private_data; 15362306a36Sopenharmony_ci snd_iprintf(buffer, "0x%x 0x%x\n", chip->debug_res, chip->debug_res_ex); 15462306a36Sopenharmony_ci} 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * dump some registers 15862306a36Sopenharmony_ci */ 15962306a36Sopenharmony_cistatic void lola_proc_regs_read(struct snd_info_entry *entry, 16062306a36Sopenharmony_ci struct snd_info_buffer *buffer) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci struct lola *chip = entry->private_data; 16362306a36Sopenharmony_ci int i; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci for (i = 0; i < 0x40; i += 4) { 16662306a36Sopenharmony_ci snd_iprintf(buffer, "BAR0 %02x: %08x\n", i, 16762306a36Sopenharmony_ci readl(chip->bar[BAR0].remap_addr + i)); 16862306a36Sopenharmony_ci } 16962306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 17062306a36Sopenharmony_ci for (i = 0; i < 0x30; i += 4) { 17162306a36Sopenharmony_ci snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, 17262306a36Sopenharmony_ci readl(chip->bar[BAR1].remap_addr + i)); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 17562306a36Sopenharmony_ci for (i = 0x80; i < 0xa0; i += 4) { 17662306a36Sopenharmony_ci snd_iprintf(buffer, "BAR1 %02x: %08x\n", i, 17762306a36Sopenharmony_ci readl(chip->bar[BAR1].remap_addr + i)); 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci snd_iprintf(buffer, "\n"); 18062306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 18162306a36Sopenharmony_ci snd_iprintf(buffer, "DSD %02x STS %08x\n", i, 18262306a36Sopenharmony_ci lola_dsd_read(chip, i, STS)); 18362306a36Sopenharmony_ci snd_iprintf(buffer, "DSD %02x LPIB %08x\n", i, 18462306a36Sopenharmony_ci lola_dsd_read(chip, i, LPIB)); 18562306a36Sopenharmony_ci snd_iprintf(buffer, "DSD %02x CTL %08x\n", i, 18662306a36Sopenharmony_ci lola_dsd_read(chip, i, CTL)); 18762306a36Sopenharmony_ci snd_iprintf(buffer, "DSD %02x LVIL %08x\n", i, 18862306a36Sopenharmony_ci lola_dsd_read(chip, i, LVI)); 18962306a36Sopenharmony_ci snd_iprintf(buffer, "DSD %02x BDPL %08x\n", i, 19062306a36Sopenharmony_ci lola_dsd_read(chip, i, BDPL)); 19162306a36Sopenharmony_ci snd_iprintf(buffer, "DSD %02x BDPU %08x\n", i, 19262306a36Sopenharmony_ci lola_dsd_read(chip, i, BDPU)); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_civoid lola_proc_debug_new(struct lola *chip) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci snd_card_ro_proc_new(chip->card, "codec", chip, lola_proc_codec_read); 19962306a36Sopenharmony_ci snd_card_rw_proc_new(chip->card, "codec_rw", chip, 20062306a36Sopenharmony_ci lola_proc_codec_rw_read, 20162306a36Sopenharmony_ci lola_proc_codec_rw_write); 20262306a36Sopenharmony_ci snd_card_ro_proc_new(chip->card, "regs", chip, lola_proc_regs_read); 20362306a36Sopenharmony_ci} 204