]>
Commit | Line | Data |
---|---|---|
54bcca29 SG |
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 | ||
d678a59d | 9 | #include <common.h> |
54bcca29 SG |
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 | ||
24 | struct max98357a_priv { | |
25 | struct gpio_desc sdmode_gpio; | |
26 | }; | |
27 | ||
d1998a9f | 28 | static int max98357a_of_to_plat(struct udevice *dev) |
54bcca29 SG |
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 | ||
3ca32c80 | 41 | __maybe_unused |
54bcca29 SG |
42 | static 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); | |
dd30c5bb | 73 | if (ret < 0) |
54bcca29 SG |
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 ? | |
23dd0ea4 | 85 | ACPI_GPIO_ACTIVE_LOW : ACPI_GPIO_ACTIVE_HIGH); |
54bcca29 SG |
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 | |
98 | static 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 | ||
109 | static 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 | ||
121 | static 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 | ||
140 | struct acpi_ops max98357a_acpi_ops = { | |
3ca32c80 | 141 | #ifdef CONFIG_ACPIGEN |
54bcca29 SG |
142 | .fill_ssdt = max98357a_acpi_fill_ssdt, |
143 | #ifdef CONFIG_X86 | |
144 | .setup_nhlt = max98357a_acpi_setup_nhlt, | |
145 | #endif | |
3ca32c80 | 146 | #endif |
54bcca29 SG |
147 | }; |
148 | ||
149 | static const struct audio_codec_ops max98357a_ops = { | |
150 | }; | |
151 | ||
152 | static const struct udevice_id max98357a_ids[] = { | |
153 | { .compatible = "maxim,max98357a" }, | |
154 | { } | |
155 | }; | |
156 | ||
157 | U_BOOT_DRIVER(max98357a) = { | |
158 | .name = "max98357a", | |
159 | .id = UCLASS_AUDIO_CODEC, | |
160 | .of_match = max98357a_ids, | |
d1998a9f | 161 | .of_to_plat = max98357a_of_to_plat, |
54bcca29 SG |
162 | .ops = &max98357a_ops, |
163 | ACPI_OPS_PTR(&max98357a_acpi_ops) | |
164 | }; |