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 <common.h>
10 #include <dm.h>
11 #include <i2c.h>
12 #include <irq.h>
13 #include <log.h>
14 #include <acpi/acpigen.h>
15 #include <acpi/acpi_device.h>
16 #include <acpi/acpi_dp.h>
17 #ifdef CONFIG_X86
18 #include <asm/acpi_nhlt.h>
19 #endif
20 #include <asm-generic/gpio.h>
21 #include <dt-bindings/sound/nhlt.h>
22 #include <dm/acpi.h>
23 
24 #define DA7219_ACPI_HID		"DLGS7219"
25 
da7219_acpi_fill_ssdt(const struct udevice * dev,struct acpi_ctx * ctx)26 static int da7219_acpi_fill_ssdt(const struct udevice *dev,
27 				 struct acpi_ctx *ctx)
28 {
29 	char scope[ACPI_PATH_MAX];
30 	char name[ACPI_NAME_MAX];
31 	struct acpi_dp *dsd, *aad;
32 	ofnode node;
33 	u32 val;
34 	int ret;
35 
36 	ret = acpi_device_scope(dev, scope, sizeof(scope));
37 	if (ret)
38 		return log_msg_ret("scope", ret);
39 	ret = acpi_get_name(dev, name);
40 	if (ret)
41 		return log_msg_ret("name", ret);
42 
43 	/* Device */
44 	acpigen_write_scope(ctx, scope);
45 	acpigen_write_device(ctx, name);
46 	acpigen_write_name_string(ctx, "_HID", DA7219_ACPI_HID);
47 	acpigen_write_name_integer(ctx, "_UID", 1);
48 	acpigen_write_name_string(ctx, "_DDN",
49 				  dev_read_string(dev, "acpi,ddn"));
50 	acpigen_write_name_integer(ctx, "_S0W", 4);
51 	acpigen_write_sta(ctx, acpi_device_status(dev));
52 
53 	/* Resources */
54 	acpigen_write_name(ctx, "_CRS");
55 	acpigen_write_resourcetemplate_header(ctx);
56 	ret = acpi_device_write_i2c_dev(ctx, dev);
57 	if (ret < 0)
58 		return log_msg_ret("i2c", ret);
59 
60 	/* Use either Interrupt() or GpioInt() */
61 	ret = acpi_device_write_interrupt_or_gpio(ctx, (struct udevice *)dev,
62 						  "req-gpios");
63 	if (ret < 0)
64 		return log_msg_ret("irq_gpio", ret);
65 	acpigen_write_resourcetemplate_footer(ctx);
66 
67 	/* AAD Child Device Properties */
68 	aad = acpi_dp_new_table("DAAD");
69 	if (!aad)
70 		return log_msg_ret("aad", -ENOMEM);
71 
72 	node = ofnode_find_subnode(dev_ofnode(dev), "da7219_aad");
73 	if (!ofnode_valid(node))
74 		return log_msg_ret("da7219_aad", -EINVAL);
75 	acpi_dp_ofnode_copy_int(node, aad, "dlg,btn-cfg");
76 	acpi_dp_ofnode_copy_int(node, aad, "dlg,mic-det-thr");
77 	acpi_dp_ofnode_copy_int(node, aad, "dlg,jack-ins-deb");
78 	acpi_dp_ofnode_copy_str(node, aad, "dlg,jack-det-rate");
79 	acpi_dp_ofnode_copy_int(node, aad, "dlg,jack-rem-deb");
80 	acpi_dp_ofnode_copy_int(node, aad, "dlg,a-d-btn-thr");
81 	acpi_dp_ofnode_copy_int(node, aad, "dlg,d-b-btn-thr");
82 	acpi_dp_ofnode_copy_int(node, aad, "dlg,b-c-btn-thr");
83 	acpi_dp_ofnode_copy_int(node, aad, "dlg,c-mic-btn-thr");
84 	acpi_dp_ofnode_copy_int(node, aad, "dlg,btn-avg");
85 	acpi_dp_ofnode_copy_int(node, aad, "dlg,adc-1bit-rpt");
86 	if (!ofnode_read_u32(node, "dlg,micbias-pulse-lvl", &val)) {
87 		acpi_dp_ofnode_copy_int(node, aad, "dlg,micbias-pulse-lvl");
88 		acpi_dp_ofnode_copy_int(node, aad, "dlg,micbias-pulse-time");
89 	}
90 
91 	/* DA7219 Properties */
92 	dsd = acpi_dp_new_table("_DSD");
93 	if (!dsd)
94 		return log_msg_ret("dsd", -ENOMEM);
95 	acpi_dp_dev_copy_int(dev, dsd, "dlg,micbias-lvl");
96 	acpi_dp_dev_copy_str(dev, dsd, "dlg,mic-amp-in-sel");
97 	acpi_dp_dev_copy_str(dev, dsd, "dlg,mclk-name");
98 	acpi_dp_add_child(dsd, "da7219_aad", aad);
99 
100 	/* Write Device Property Hierarchy */
101 	acpi_dp_write(ctx, dsd);
102 
103 	acpigen_pop_len(ctx); /* Device */
104 	acpigen_pop_len(ctx); /* Scope */
105 
106 	return 0;
107 }
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 
da7219_acpi_setup_nhlt(const struct udevice * dev,struct acpi_ctx * ctx)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 	.fill_ssdt	= da7219_acpi_fill_ssdt,
175 #ifdef CONFIG_X86
176 	.setup_nhlt	= da7219_acpi_setup_nhlt,
177 #endif
178 };
179 
180 static const struct udevice_id da7219_ids[] = {
181 	{ .compatible = "dlg,da7219" },
182 	{ }
183 };
184 
185 U_BOOT_DRIVER(da7219) = {
186 	.name		= "da7219",
187 	.id		= UCLASS_MISC,
188 	.of_match	= da7219_ids,
189 	ACPI_OPS_PTR(&da7219_acpi_ops)
190 };
191