/src/u-boot/drivers/sound/da7219.c
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0+ |
2 | | /* |
3 | | * ACPI driver for DA7219 codec |
4 | | * |
5 | | * Copyright 2019 Google LLC |
6 | | * Parts taken from coreboot |
7 | | */ |
8 | | |
9 | | #include <dm.h> |
10 | | #include <i2c.h> |
11 | | #include <irq.h> |
12 | | #include <log.h> |
13 | | #include <acpi/acpigen.h> |
14 | | #include <acpi/acpi_device.h> |
15 | | #include <acpi/acpi_dp.h> |
16 | | #ifdef CONFIG_X86 |
17 | | #include <asm/acpi_nhlt.h> |
18 | | #endif |
19 | | #include <asm-generic/gpio.h> |
20 | | #include <dt-bindings/sound/nhlt.h> |
21 | | #include <dm/acpi.h> |
22 | | |
23 | 0 | #define DA7219_ACPI_HID "DLGS7219" |
24 | | |
25 | | __maybe_unused |
26 | | static int da7219_acpi_fill_ssdt(const struct udevice *dev, |
27 | | struct acpi_ctx *ctx) |
28 | 0 | { |
29 | 0 | char scope[ACPI_PATH_MAX]; |
30 | 0 | char name[ACPI_NAME_MAX]; |
31 | 0 | struct acpi_dp *dsd, *aad; |
32 | 0 | ofnode node; |
33 | 0 | u32 val; |
34 | 0 | int ret; |
35 | |
|
36 | 0 | ret = acpi_device_scope(dev, scope, sizeof(scope)); |
37 | 0 | if (ret) |
38 | 0 | return log_msg_ret("scope", ret); |
39 | 0 | ret = acpi_get_name(dev, name); |
40 | 0 | if (ret) |
41 | 0 | return log_msg_ret("name", ret); |
42 | | |
43 | | /* Device */ |
44 | 0 | acpigen_write_scope(ctx, scope); |
45 | 0 | acpigen_write_device(ctx, name); |
46 | 0 | acpigen_write_name_string(ctx, "_HID", DA7219_ACPI_HID); |
47 | 0 | acpigen_write_name_integer(ctx, "_UID", 1); |
48 | 0 | acpigen_write_name_string(ctx, "_DDN", |
49 | 0 | dev_read_string(dev, "acpi,ddn")); |
50 | 0 | acpigen_write_name_integer(ctx, "_S0W", 4); |
51 | 0 | acpigen_write_sta(ctx, acpi_device_status(dev)); |
52 | | |
53 | | /* Resources */ |
54 | 0 | acpigen_write_name(ctx, "_CRS"); |
55 | 0 | acpigen_write_resourcetemplate_header(ctx); |
56 | 0 | ret = acpi_device_write_i2c_dev(ctx, dev); |
57 | 0 | if (ret < 0) |
58 | 0 | return log_msg_ret("i2c", ret); |
59 | | |
60 | | /* Use either Interrupt() or GpioInt() */ |
61 | 0 | ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev, |
62 | 0 | "req-gpios"); |
63 | 0 | if (ret < 0) |
64 | 0 | return log_msg_ret("irq_gpio", ret); |
65 | 0 | acpigen_write_resourcetemplate_footer(ctx); |
66 | | |
67 | | /* AAD Child Device Properties */ |
68 | 0 | aad = acpi_dp_new_table("DAAD"); |
69 | 0 | if (!aad) |
70 | 0 | return log_msg_ret("aad", -ENOMEM); |
71 | | |
72 | 0 | node = ofnode_find_subnode(dev_ofnode(dev), "da7219_aad"); |
73 | 0 | if (!ofnode_valid(node)) |
74 | 0 | return log_msg_ret("da7219_aad", -EINVAL); |
75 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,btn-cfg"); |
76 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,mic-det-thr"); |
77 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,jack-ins-deb"); |
78 | 0 | acpi_dp_ofnode_copy_str(node, aad, "dlg,jack-det-rate"); |
79 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,jack-rem-deb"); |
80 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,a-d-btn-thr"); |
81 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,d-b-btn-thr"); |
82 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,b-c-btn-thr"); |
83 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,c-mic-btn-thr"); |
84 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,btn-avg"); |
85 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,adc-1bit-rpt"); |
86 | 0 | if (!ofnode_read_u32(node, "dlg,micbias-pulse-lvl", &val)) { |
87 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,micbias-pulse-lvl"); |
88 | 0 | acpi_dp_ofnode_copy_int(node, aad, "dlg,micbias-pulse-time"); |
89 | 0 | } |
90 | | |
91 | | /* DA7219 Properties */ |
92 | 0 | dsd = acpi_dp_new_table("_DSD"); |
93 | 0 | if (!dsd) |
94 | 0 | return log_msg_ret("dsd", -ENOMEM); |
95 | 0 | acpi_dp_dev_copy_int(dev, dsd, "dlg,micbias-lvl"); |
96 | 0 | acpi_dp_dev_copy_str(dev, dsd, "dlg,mic-amp-in-sel"); |
97 | 0 | acpi_dp_dev_copy_str(dev, dsd, "dlg,mclk-name"); |
98 | 0 | acpi_dp_add_child(dsd, "da7219_aad", aad); |
99 | | |
100 | | /* Write Device Property Hierarchy */ |
101 | 0 | acpi_dp_write(ctx, dsd); |
102 | |
|
103 | 0 | acpigen_pop_len(ctx); /* Device */ |
104 | 0 | acpigen_pop_len(ctx); /* Scope */ |
105 | |
|
106 | 0 | return 0; |
107 | 0 | } |
108 | | |
109 | | /* For now only X86 boards support NHLT */ |
110 | | #ifdef CONFIG_X86 |
111 | | static const struct nhlt_format_config da7219_formats[] = { |
112 | | /* 48 KHz 24-bits per sample. */ |
113 | | { |
114 | | .num_channels = 2, |
115 | | .sample_freq_khz = 48, |
116 | | .container_bits_per_sample = 32, |
117 | | .valid_bits_per_sample = 24, |
118 | | .settings_file = "dialog-2ch-48khz-24b.dat", |
119 | | }, |
120 | | }; |
121 | | |
122 | | static const struct nhlt_tdm_config tdm_config = { |
123 | | .virtual_slot = 0, |
124 | | .config_type = NHLT_TDM_BASIC, |
125 | | }; |
126 | | |
127 | | static const struct nhlt_endp_descriptor da7219_descriptors[] = { |
128 | | /* Render Endpoint */ |
129 | | { |
130 | | .link = NHLT_LINK_SSP, |
131 | | .device = NHLT_SSP_DEV_I2S, |
132 | | .direction = NHLT_DIR_RENDER, |
133 | | .vid = NHLT_VID, |
134 | | .did = NHLT_DID_SSP, |
135 | | .cfg = &tdm_config, |
136 | | .cfg_size = sizeof(tdm_config), |
137 | | .formats = da7219_formats, |
138 | | .num_formats = ARRAY_SIZE(da7219_formats), |
139 | | }, |
140 | | /* Capture Endpoint */ |
141 | | { |
142 | | .link = NHLT_LINK_SSP, |
143 | | .device = NHLT_SSP_DEV_I2S, |
144 | | .direction = NHLT_DIR_CAPTURE, |
145 | | .vid = NHLT_VID, |
146 | | .did = NHLT_DID_SSP, |
147 | | .cfg = &tdm_config, |
148 | | .cfg_size = sizeof(tdm_config), |
149 | | .formats = da7219_formats, |
150 | | .num_formats = ARRAY_SIZE(da7219_formats), |
151 | | }, |
152 | | }; |
153 | | |
154 | | static int da7219_acpi_setup_nhlt(const struct udevice *dev, |
155 | | struct acpi_ctx *ctx) |
156 | | { |
157 | | u32 hwlink; |
158 | | int ret; |
159 | | |
160 | | if (dev_read_u32(dev, "acpi,audio-link", &hwlink)) |
161 | | return log_msg_ret("link", -EINVAL); |
162 | | |
163 | | /* Virtual bus id of SSP links are the hardware port ids proper. */ |
164 | | ret = nhlt_add_ssp_endpoints(ctx->nhlt, hwlink, da7219_descriptors, |
165 | | ARRAY_SIZE(da7219_descriptors)); |
166 | | if (ret) |
167 | | return log_msg_ret("add", ret); |
168 | | |
169 | | return 0; |
170 | | } |
171 | | #endif |
172 | | |
173 | | struct acpi_ops da7219_acpi_ops = { |
174 | | #ifdef CONFIG_ACPIGEN |
175 | | .fill_ssdt = da7219_acpi_fill_ssdt, |
176 | | #ifdef CONFIG_X86 |
177 | | .setup_nhlt = da7219_acpi_setup_nhlt, |
178 | | #endif |
179 | | #endif |
180 | | }; |
181 | | |
182 | | static const struct udevice_id da7219_ids[] = { |
183 | | { .compatible = "dlg,da7219" }, |
184 | | { } |
185 | | }; |
186 | | |
187 | | U_BOOT_DRIVER(da7219) = { |
188 | | .name = "da7219", |
189 | | .id = UCLASS_MISC, |
190 | | .of_match = da7219_ids, |
191 | | ACPI_OPS_PTR(&da7219_acpi_ops) |
192 | | }; |