sound: Add an ACPI driver for Maxim MAX98357ac

This chip is used on coral and we need to generate ACPI tables for sound
to make it work. Add a driver that does just this (i.e. at present does
not actually support playing sound).

Signed-off-by: Simon Glass <sjg@chromium.org>
[bmeng: Use the correct acpi_irq_polarity enum number]
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
This commit is contained in:
Simon Glass 2020-07-07 21:32:18 -06:00 committed by Bin Meng
parent 0324b7123e
commit 54bcca2973
5 changed files with 194 additions and 0 deletions

View file

@ -211,6 +211,7 @@ CONFIG_SMEM=y
CONFIG_SANDBOX_SMEM=y
CONFIG_SOUND=y
CONFIG_SOUND_DA7219=y
CONFIG_SOUND_MAX98357A=y
CONFIG_SOUND_SANDBOX=y
CONFIG_SANDBOX_SPI=y
CONFIG_SPMI=y

View file

@ -0,0 +1,22 @@
Maxim MAX98357A audio DAC
This node models the Maxim MAX98357A DAC.
Required properties:
- compatible : "maxim,max98357a"
Optional properties:
- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin.
If this option is not specified then driver does not manage
the pin state (e.g. chip is always on).
- sdmode-delay : specify delay time for SD_MODE pin.
If this option is specified, which means it's required i2s clocks
ready before SD_MODE is unmuted in order to avoid the speaker pop noise.
It's observed that 5ms is sufficient.
Example:
max98357a {
compatible = "maxim,max98357a";
sdmode-gpios = <&qcom_pinmux 25 0>;
};

View file

@ -113,6 +113,15 @@ config SOUND_MAX98095
audio data and I2C for codec control. At present it only works
with the Samsung I2S driver.
config SOUND_MAX98357A
bool "Support Maxim max98357a audio codec"
depends on PCI
help
Enable the max98357a audio codec. This is connected on PCI for
audio data codec control. This is currently only capable of providing
ACPI information. A full driver (with sound in U-Boot) is currently
not available.
config SOUND_RT5677
bool "Support Realtek RT5677 audio codec"
depends on SOUND

View file

@ -17,6 +17,7 @@ obj-$(CONFIG_SOUND_WM8994) += wm8994.o
obj-$(CONFIG_SOUND_MAX98088) += max98088.o maxim_codec.o
obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o
obj-$(CONFIG_SOUND_MAX98095) += max98095.o maxim_codec.o
obj-$(CONFIG_SOUND_MAX98357A) += max98357a.o
obj-$(CONFIG_SOUND_INTEL_HDA) += hda_codec.o
obj-$(CONFIG_SOUND_I8254) += i8254_beep.o
obj-$(CONFIG_SOUND_RT5677) += rt5677.o

161
drivers/sound/max98357a.c Normal file
View file

@ -0,0 +1,161 @@
// SPDX-License-Identifier: GPL-2.0
/*
* max98357a.c -- MAX98357A Audio driver
*
* Copyright 2019 Google LLC
* Parts taken from coreboot
*/
#include <common.h>
#include <audio_codec.h>
#include <dm.h>
#include <log.h>
#include <sound.h>
#include <acpi/acpigen.h>
#include <acpi/acpi_device.h>
#include <acpi/acpi_dp.h>
#include <asm-generic/gpio.h>
#ifdef CONFIG_X86
#include <asm/acpi_nhlt.h>
#endif
#include <dt-bindings/sound/nhlt.h>
#include <dm/acpi.h>
struct max98357a_priv {
struct gpio_desc sdmode_gpio;
};
static int max98357a_ofdata_to_platdata(struct udevice *dev)
{
struct max98357a_priv *priv = dev_get_priv(dev);
int ret;
ret = gpio_request_by_name(dev, "sdmode-gpios", 0, &priv->sdmode_gpio,
GPIOD_IS_IN);
if (ret)
return log_msg_ret("gpio", ret);
return 0;
}
static int max98357a_acpi_fill_ssdt(const struct udevice *dev,
struct acpi_ctx *ctx)
{
struct max98357a_priv *priv = dev_get_priv(dev);
char scope[ACPI_PATH_MAX];
char name[ACPI_NAME_MAX];
char path[ACPI_PATH_MAX];
struct acpi_dp *dp;
int ret;
ret = acpi_device_scope(dev, scope, sizeof(scope));
if (ret)
return log_msg_ret("scope", ret);
ret = acpi_get_name(dev, name);
if (ret)
return log_msg_ret("name", ret);
/* Device */
acpigen_write_scope(ctx, scope);
acpigen_write_device(ctx, name);
acpigen_write_name_string(ctx, "_HID",
dev_read_string(dev, "acpi,hid"));
acpigen_write_name_integer(ctx, "_UID", 0);
acpigen_write_name_string(ctx, "_DDN",
dev_read_string(dev, "acpi,ddn"));
acpigen_write_sta(ctx, acpi_device_status(dev));
/* Resources */
acpigen_write_name(ctx, "_CRS");
acpigen_write_resourcetemplate_header(ctx);
ret = acpi_device_write_gpio_desc(ctx, &priv->sdmode_gpio);
if (ret)
return log_msg_ret("gpio", ret);
acpigen_write_resourcetemplate_footer(ctx);
/* _DSD for devicetree properties */
/* This points to the first pin in the first gpio entry in _CRS */
ret = acpi_device_path(dev, path, sizeof(path));
if (ret)
return log_msg_ret("path", ret);
dp = acpi_dp_new_table("_DSD");
acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0,
priv->sdmode_gpio.flags & GPIOD_ACTIVE_LOW ?
ACPI_IRQ_ACTIVE_LOW : ACPI_IRQ_ACTIVE_HIGH);
acpi_dp_add_integer(dp, "sdmode-delay",
dev_read_u32_default(dev, "sdmode-delay", 0));
acpi_dp_write(ctx, dp);
acpigen_pop_len(ctx); /* Device */
acpigen_pop_len(ctx); /* Scope */
return 0;
}
/* For now only X86 boards support NHLT */
#ifdef CONFIG_X86
static const struct nhlt_format_config max98357a_formats[] = {
/* 48 KHz 24-bits per sample. */
{
.num_channels = 2,
.sample_freq_khz = 48,
.container_bits_per_sample = 32,
.valid_bits_per_sample = 24,
.settings_file = "max98357-render-2ch-48khz-24b.dat",
},
};
static const struct nhlt_endp_descriptor max98357a_descriptors[] = {
{
.link = NHLT_LINK_SSP,
.device = NHLT_SSP_DEV_I2S,
.direction = NHLT_DIR_RENDER,
.vid = NHLT_VID,
.did = NHLT_DID_SSP,
.formats = max98357a_formats,
.num_formats = ARRAY_SIZE(max98357a_formats),
},
};
static int max98357a_acpi_setup_nhlt(const struct udevice *dev,
struct acpi_ctx *ctx)
{
u32 hwlink;
int ret;
if (dev_read_u32(dev, "acpi,audio-link", &hwlink))
return log_msg_ret("link", -EINVAL);
/* Virtual bus id of SSP links are the hardware port ids proper. */
ret = nhlt_add_ssp_endpoints(ctx->nhlt, hwlink, max98357a_descriptors,
ARRAY_SIZE(max98357a_descriptors));
if (ret)
return log_msg_ret("add", ret);
return 0;
}
#endif
struct acpi_ops max98357a_acpi_ops = {
.fill_ssdt = max98357a_acpi_fill_ssdt,
#ifdef CONFIG_X86
.setup_nhlt = max98357a_acpi_setup_nhlt,
#endif
};
static const struct audio_codec_ops max98357a_ops = {
};
static const struct udevice_id max98357a_ids[] = {
{ .compatible = "maxim,max98357a" },
{ }
};
U_BOOT_DRIVER(max98357a) = {
.name = "max98357a",
.id = UCLASS_AUDIO_CODEC,
.of_match = max98357a_ids,
.ofdata_to_platdata = max98357a_ofdata_to_platdata,
.ops = &max98357a_ops,
ACPI_OPS_PTR(&max98357a_acpi_ops)
};