1// SPDX-License-Identifier: GPL-2.0 2/* 3 * max98357a.c -- MAX98357A Audio driver 4 * 5 * Copyright 2019 Google LLC 6 * Parts taken from coreboot 7 */ 8 9#include <common.h> 10#include <audio_codec.h> 11#include <dm.h> 12#include <log.h> 13#include <sound.h> 14#include <acpi/acpigen.h> 15#include <acpi/acpi_device.h> 16#include <acpi/acpi_dp.h> 17#include <asm-generic/gpio.h> 18#ifdef CONFIG_X86 19#include <asm/acpi_nhlt.h> 20#endif 21#include <dt-bindings/sound/nhlt.h> 22#include <dm/acpi.h> 23 24struct max98357a_priv { 25 struct gpio_desc sdmode_gpio; 26}; 27 28static int max98357a_of_to_plat(struct udevice *dev) 29{ 30 struct max98357a_priv *priv = dev_get_priv(dev); 31 int ret; 32 33 ret = gpio_request_by_name(dev, "sdmode-gpios", 0, &priv->sdmode_gpio, 34 GPIOD_IS_IN); 35 if (ret) 36 return log_msg_ret("gpio", ret); 37 38 return 0; 39} 40 41__maybe_unused 42static int max98357a_acpi_fill_ssdt(const struct udevice *dev, 43 struct acpi_ctx *ctx) 44{ 45 struct max98357a_priv *priv = dev_get_priv(dev); 46 char scope[ACPI_PATH_MAX]; 47 char name[ACPI_NAME_MAX]; 48 char path[ACPI_PATH_MAX]; 49 struct acpi_dp *dp; 50 int ret; 51 52 ret = acpi_device_scope(dev, scope, sizeof(scope)); 53 if (ret) 54 return log_msg_ret("scope", ret); 55 ret = acpi_get_name(dev, name); 56 if (ret) 57 return log_msg_ret("name", ret); 58 59 /* Device */ 60 acpigen_write_scope(ctx, scope); 61 acpigen_write_device(ctx, name); 62 acpigen_write_name_string(ctx, "_HID", 63 dev_read_string(dev, "acpi,hid")); 64 acpigen_write_name_integer(ctx, "_UID", 0); 65 acpigen_write_name_string(ctx, "_DDN", 66 dev_read_string(dev, "acpi,ddn")); 67 acpigen_write_sta(ctx, acpi_device_status(dev)); 68 69 /* Resources */ 70 acpigen_write_name(ctx, "_CRS"); 71 acpigen_write_resourcetemplate_header(ctx); 72 ret = acpi_device_write_gpio_desc(ctx, &priv->sdmode_gpio); 73 if (ret < 0) 74 return log_msg_ret("gpio", ret); 75 acpigen_write_resourcetemplate_footer(ctx); 76 77 /* _DSD for devicetree properties */ 78 /* This points to the first pin in the first gpio entry in _CRS */ 79 ret = acpi_device_path(dev, path, sizeof(path)); 80 if (ret) 81 return log_msg_ret("path", ret); 82 dp = acpi_dp_new_table("_DSD"); 83 acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0, 84 priv->sdmode_gpio.flags & GPIOD_ACTIVE_LOW ? 85 ACPI_GPIO_ACTIVE_LOW : ACPI_GPIO_ACTIVE_HIGH); 86 acpi_dp_add_integer(dp, "sdmode-delay", 87 dev_read_u32_default(dev, "sdmode-delay", 0)); 88 acpi_dp_write(ctx, dp); 89 90 acpigen_pop_len(ctx); /* Device */ 91 acpigen_pop_len(ctx); /* Scope */ 92 93 return 0; 94} 95 96/* For now only X86 boards support NHLT */ 97#ifdef CONFIG_X86 98static const struct nhlt_format_config max98357a_formats[] = { 99 /* 48 KHz 24-bits per sample. */ 100 { 101 .num_channels = 2, 102 .sample_freq_khz = 48, 103 .container_bits_per_sample = 32, 104 .valid_bits_per_sample = 24, 105 .settings_file = "max98357-render-2ch-48khz-24b.dat", 106 }, 107}; 108 109static const struct nhlt_endp_descriptor max98357a_descriptors[] = { 110 { 111 .link = NHLT_LINK_SSP, 112 .device = NHLT_SSP_DEV_I2S, 113 .direction = NHLT_DIR_RENDER, 114 .vid = NHLT_VID, 115 .did = NHLT_DID_SSP, 116 .formats = max98357a_formats, 117 .num_formats = ARRAY_SIZE(max98357a_formats), 118 }, 119}; 120 121static int max98357a_acpi_setup_nhlt(const struct udevice *dev, 122 struct acpi_ctx *ctx) 123{ 124 u32 hwlink; 125 int ret; 126 127 if (dev_read_u32(dev, "acpi,audio-link", &hwlink)) 128 return log_msg_ret("link", -EINVAL); 129 130 /* Virtual bus id of SSP links are the hardware port ids proper. */ 131 ret = nhlt_add_ssp_endpoints(ctx->nhlt, hwlink, max98357a_descriptors, 132 ARRAY_SIZE(max98357a_descriptors)); 133 if (ret) 134 return log_msg_ret("add", ret); 135 136 return 0; 137} 138#endif 139 140struct acpi_ops max98357a_acpi_ops = { 141#ifdef CONFIG_ACPIGEN 142 .fill_ssdt = max98357a_acpi_fill_ssdt, 143#ifdef CONFIG_X86 144 .setup_nhlt = max98357a_acpi_setup_nhlt, 145#endif 146#endif 147}; 148 149static const struct audio_codec_ops max98357a_ops = { 150}; 151 152static const struct udevice_id max98357a_ids[] = { 153 { .compatible = "maxim,max98357a" }, 154 { } 155}; 156 157U_BOOT_DRIVER(max98357a) = { 158 .name = "max98357a", 159 .id = UCLASS_AUDIO_CODEC, 160 .of_match = max98357a_ids, 161 .of_to_plat = max98357a_of_to_plat, 162 .ops = &max98357a_ops, 163 ACPI_OPS_PTR(&max98357a_acpi_ops) 164}; 165