^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * helper functions for HDMI models (Xonar HDAV1.3/HDAV1.3 Slim)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/pci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <sound/asoundef.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <sound/control.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <sound/core.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <sound/pcm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sound/pcm_params.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <sound/tlv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "xonar.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static void hdmi_write_command(struct oxygen *chip, u8 command,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned int count, const u8 *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) u8 checksum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) oxygen_write_uart(chip, 0xfb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) oxygen_write_uart(chip, 0xef);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) oxygen_write_uart(chip, command);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) oxygen_write_uart(chip, count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) for (i = 0; i < count; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) oxygen_write_uart(chip, params[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) checksum = 0xfb + 0xef + command + count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) for (i = 0; i < count; ++i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) checksum += params[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) oxygen_write_uart(chip, checksum);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static void xonar_hdmi_init_commands(struct oxygen *chip,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct xonar_hdmi *hdmi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) u8 param;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) oxygen_reset_uart(chip);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) param = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) hdmi_write_command(chip, 0x61, 1, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) param = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) hdmi_write_command(chip, 0x74, 1, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) hdmi_write_command(chip, 0x54, 5, hdmi->params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *hdmi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) hdmi->params[1] = IEC958_AES3_CON_FS_48000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) hdmi->params[4] = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) xonar_hdmi_init_commands(chip, hdmi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) void xonar_hdmi_cleanup(struct oxygen *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) u8 param = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) hdmi_write_command(chip, 0x74, 1, ¶m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) xonar_hdmi_init_commands(chip, hdmi);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) void xonar_hdmi_pcm_hardware_filter(unsigned int channel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct snd_pcm_hardware *hardware)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) if (channel == PCM_MULTICH) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) hardware->rates = SNDRV_PCM_RATE_44100 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) SNDRV_PCM_RATE_48000 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) SNDRV_PCM_RATE_96000 |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) SNDRV_PCM_RATE_192000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) hardware->rate_min = 44100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct snd_pcm_hw_params *params)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) hdmi->params[0] = 0; /* 1 = non-audio */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) switch (params_rate(params)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) case 44100:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) hdmi->params[1] = IEC958_AES3_CON_FS_44100;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) case 48000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) hdmi->params[1] = IEC958_AES3_CON_FS_48000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) default: /* 96000 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) hdmi->params[1] = IEC958_AES3_CON_FS_96000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) case 192000:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) hdmi->params[1] = IEC958_AES3_CON_FS_192000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) hdmi->params[2] = params_channels(params) / 2 - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) hdmi->params[3] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) hdmi->params[3] = 0xc0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) hdmi->params[4] = 1; /* ? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) hdmi_write_command(chip, 0x54, 5, hdmi->params);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) void xonar_hdmi_uart_input(struct oxygen *chip)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) if (chip->uart_input_count >= 2 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) chip->uart_input[chip->uart_input_count - 2] == 'O' &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) chip->uart_input[chip->uart_input_count - 1] == 'K') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) dev_dbg(chip->card->dev, "message from HDMI chip received:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) chip->uart_input, chip->uart_input_count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) chip->uart_input_count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) }