]>
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 | ||
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 | ||
24 | struct max98357a_priv { | |
25 | struct gpio_desc sdmode_gpio; | |
26 | }; | |
27 | ||
28 | static int max98357a_ofdata_to_platdata(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 | static int max98357a_acpi_fill_ssdt(const struct udevice *dev, | |
42 | struct acpi_ctx *ctx) | |
43 | { | |
44 | struct max98357a_priv *priv = dev_get_priv(dev); | |
45 | char scope[ACPI_PATH_MAX]; | |
46 | char name[ACPI_NAME_MAX]; | |
47 | char path[ACPI_PATH_MAX]; | |
48 | struct acpi_dp *dp; | |
49 | int ret; | |
50 | ||
51 | ret = acpi_device_scope(dev, scope, sizeof(scope)); | |
52 | if (ret) | |
53 | return log_msg_ret("scope", ret); | |
54 | ret = acpi_get_name(dev, name); | |
55 | if (ret) | |
56 | return log_msg_ret("name", ret); | |
57 | ||
58 | /* Device */ | |
59 | acpigen_write_scope(ctx, scope); | |
60 | acpigen_write_device(ctx, name); | |
61 | acpigen_write_name_string(ctx, "_HID", | |
62 | dev_read_string(dev, "acpi,hid")); | |
63 | acpigen_write_name_integer(ctx, "_UID", 0); | |
64 | acpigen_write_name_string(ctx, "_DDN", | |
65 | dev_read_string(dev, "acpi,ddn")); | |
66 | acpigen_write_sta(ctx, acpi_device_status(dev)); | |
67 | ||
68 | /* Resources */ | |
69 | acpigen_write_name(ctx, "_CRS"); | |
70 | acpigen_write_resourcetemplate_header(ctx); | |
71 | ret = acpi_device_write_gpio_desc(ctx, &priv->sdmode_gpio); | |
72 | if (ret) | |
73 | return log_msg_ret("gpio", ret); | |
74 | acpigen_write_resourcetemplate_footer(ctx); | |
75 | ||
76 | /* _DSD for devicetree properties */ | |
77 | /* This points to the first pin in the first gpio entry in _CRS */ | |
78 | ret = acpi_device_path(dev, path, sizeof(path)); | |
79 | if (ret) | |
80 | return log_msg_ret("path", ret); | |
81 | dp = acpi_dp_new_table("_DSD"); | |
82 | acpi_dp_add_gpio(dp, "sdmode-gpio", path, 0, 0, | |
83 | priv->sdmode_gpio.flags & GPIOD_ACTIVE_LOW ? | |
23dd0ea4 | 84 | ACPI_GPIO_ACTIVE_LOW : ACPI_GPIO_ACTIVE_HIGH); |
54bcca29 SG |
85 | acpi_dp_add_integer(dp, "sdmode-delay", |
86 | dev_read_u32_default(dev, "sdmode-delay", 0)); | |
87 | acpi_dp_write(ctx, dp); | |
88 | ||
89 | acpigen_pop_len(ctx); /* Device */ | |
90 | acpigen_pop_len(ctx); /* Scope */ | |
91 | ||
92 | return 0; | |
93 | } | |
94 | ||
95 | /* For now only X86 boards support NHLT */ | |
96 | #ifdef CONFIG_X86 | |
97 | static const struct nhlt_format_config max98357a_formats[] = { | |
98 | /* 48 KHz 24-bits per sample. */ | |
99 | { | |
100 | .num_channels = 2, | |
101 | .sample_freq_khz = 48, | |
102 | .container_bits_per_sample = 32, | |
103 | .valid_bits_per_sample = 24, | |
104 | .settings_file = "max98357-render-2ch-48khz-24b.dat", | |
105 | }, | |
106 | }; | |
107 | ||
108 | static const struct nhlt_endp_descriptor max98357a_descriptors[] = { | |
109 | { | |
110 | .link = NHLT_LINK_SSP, | |
111 | .device = NHLT_SSP_DEV_I2S, | |
112 | .direction = NHLT_DIR_RENDER, | |
113 | .vid = NHLT_VID, | |
114 | .did = NHLT_DID_SSP, | |
115 | .formats = max98357a_formats, | |
116 | .num_formats = ARRAY_SIZE(max98357a_formats), | |
117 | }, | |
118 | }; | |
119 | ||
120 | static int max98357a_acpi_setup_nhlt(const struct udevice *dev, | |
121 | struct acpi_ctx *ctx) | |
122 | { | |
123 | u32 hwlink; | |
124 | int ret; | |
125 | ||
126 | if (dev_read_u32(dev, "acpi,audio-link", &hwlink)) | |
127 | return log_msg_ret("link", -EINVAL); | |
128 | ||
129 | /* Virtual bus id of SSP links are the hardware port ids proper. */ | |
130 | ret = nhlt_add_ssp_endpoints(ctx->nhlt, hwlink, max98357a_descriptors, | |
131 | ARRAY_SIZE(max98357a_descriptors)); | |
132 | if (ret) | |
133 | return log_msg_ret("add", ret); | |
134 | ||
135 | return 0; | |
136 | } | |
137 | #endif | |
138 | ||
139 | struct acpi_ops max98357a_acpi_ops = { | |
140 | .fill_ssdt = max98357a_acpi_fill_ssdt, | |
141 | #ifdef CONFIG_X86 | |
142 | .setup_nhlt = max98357a_acpi_setup_nhlt, | |
143 | #endif | |
144 | }; | |
145 | ||
146 | static const struct audio_codec_ops max98357a_ops = { | |
147 | }; | |
148 | ||
149 | static const struct udevice_id max98357a_ids[] = { | |
150 | { .compatible = "maxim,max98357a" }, | |
151 | { } | |
152 | }; | |
153 | ||
154 | U_BOOT_DRIVER(max98357a) = { | |
155 | .name = "max98357a", | |
156 | .id = UCLASS_AUDIO_CODEC, | |
157 | .of_match = max98357a_ids, | |
158 | .ofdata_to_platdata = max98357a_ofdata_to_platdata, | |
159 | .ops = &max98357a_ops, | |
160 | ACPI_OPS_PTR(&max98357a_acpi_ops) | |
161 | }; |