mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 18:35:42 +01:00 
			
		
		
		
	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:
		| @@ -211,6 +211,7 @@ CONFIG_SMEM=y | |||||||
| CONFIG_SANDBOX_SMEM=y | CONFIG_SANDBOX_SMEM=y | ||||||
| CONFIG_SOUND=y | CONFIG_SOUND=y | ||||||
| CONFIG_SOUND_DA7219=y | CONFIG_SOUND_DA7219=y | ||||||
|  | CONFIG_SOUND_MAX98357A=y | ||||||
| CONFIG_SOUND_SANDBOX=y | CONFIG_SOUND_SANDBOX=y | ||||||
| CONFIG_SANDBOX_SPI=y | CONFIG_SANDBOX_SPI=y | ||||||
| CONFIG_SPMI=y | CONFIG_SPMI=y | ||||||
|   | |||||||
							
								
								
									
										22
									
								
								doc/device-tree-bindings/sound/max98357a.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								doc/device-tree-bindings/sound/max98357a.txt
									
									
									
									
									
										Normal 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>; | ||||||
|  | }; | ||||||
| @@ -113,6 +113,15 @@ config SOUND_MAX98095 | |||||||
| 	  audio data and I2C for codec control. At present it only works | 	  audio data and I2C for codec control. At present it only works | ||||||
| 	  with the Samsung I2S driver. | 	  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 | config SOUND_RT5677 | ||||||
| 	bool "Support Realtek RT5677 audio codec" | 	bool "Support Realtek RT5677 audio codec" | ||||||
| 	depends on SOUND | 	depends on SOUND | ||||||
|   | |||||||
| @@ -17,6 +17,7 @@ obj-$(CONFIG_SOUND_WM8994)	+= wm8994.o | |||||||
| obj-$(CONFIG_SOUND_MAX98088)	+= max98088.o maxim_codec.o | obj-$(CONFIG_SOUND_MAX98088)	+= max98088.o maxim_codec.o | ||||||
| obj-$(CONFIG_SOUND_MAX98090)	+= max98090.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_MAX98095)	+= max98095.o maxim_codec.o | ||||||
|  | obj-$(CONFIG_SOUND_MAX98357A)	+= max98357a.o | ||||||
| obj-$(CONFIG_SOUND_INTEL_HDA)	+= hda_codec.o | obj-$(CONFIG_SOUND_INTEL_HDA)	+= hda_codec.o | ||||||
| obj-$(CONFIG_SOUND_I8254)	+= i8254_beep.o | obj-$(CONFIG_SOUND_I8254)	+= i8254_beep.o | ||||||
| obj-$(CONFIG_SOUND_RT5677)	+= rt5677.o | obj-$(CONFIG_SOUND_RT5677)	+= rt5677.o | ||||||
|   | |||||||
							
								
								
									
										161
									
								
								drivers/sound/max98357a.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								drivers/sound/max98357a.c
									
									
									
									
									
										Normal 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) | ||||||
|  | }; | ||||||
		Reference in New Issue
	
	Block a user