mirror of
				https://xff.cz/git/u-boot/
				synced 2025-10-31 10:26:10 +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_SOUND=y | ||||
| CONFIG_SOUND_DA7219=y | ||||
| CONFIG_SOUND_MAX98357A=y | ||||
| CONFIG_SOUND_SANDBOX=y | ||||
| CONFIG_SANDBOX_SPI=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 | ||||
| 	  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 | ||||
|   | ||||
| @@ -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
									
								
							
							
						
						
									
										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