1 /* SPDX-License-Identifier: GPL-2.0-or-later */
3 * In some cases UART attached devices which require an in kernel driver,
4 * e.g. UART attached Bluetooth HCIs are described in the ACPI tables
5 * by an ACPI device with a broken or missing UartSerialBusV2() resource.
7 * This causes the kernel to create a /dev/ttyS# char-device for the UART
8 * instead of creating an in kernel serdev-controller + serdev-device pair
9 * for the in kernel driver.
11 * The quirk handling in acpi_quirk_skip_serdev_enumeration() makes the kernel
12 * create a serdev-controller device for these UARTs instead of a /dev/ttyS#.
14 * Instantiating the actual serdev-device to bind to is up to pdx86 code,
15 * this header provides a helper for getting the serdev-controller device.
17 #include <linux/acpi.h>
18 #include <linux/device.h>
19 #include <linux/err.h>
20 #include <linux/printk.h>
21 #include <linux/sprintf.h>
22 #include <linux/string.h>
24 static inline struct device
*
25 get_serdev_controller(const char *serial_ctrl_hid
,
26 const char *serial_ctrl_uid
,
28 const char *serdev_ctrl_name
)
30 struct device
*ctrl_dev
, *child
;
31 struct acpi_device
*ctrl_adev
;
35 ctrl_adev
= acpi_dev_get_first_match_dev(serial_ctrl_hid
, serial_ctrl_uid
, -1);
37 pr_err("error could not get %s/%s serial-ctrl adev\n",
38 serial_ctrl_hid
, serial_ctrl_uid
);
39 return ERR_PTR(-ENODEV
);
42 /* get_first_physical_node() returns a weak ref */
43 ctrl_dev
= get_device(acpi_get_first_physical_node(ctrl_adev
));
45 pr_err("error could not get %s/%s serial-ctrl physical node\n",
46 serial_ctrl_hid
, serial_ctrl_uid
);
47 ctrl_dev
= ERR_PTR(-ENODEV
);
51 /* Walk host -> uart-ctrl -> port -> serdev-ctrl */
52 for (i
= 0; i
< 3; i
++) {
55 snprintf(name
, sizeof(name
), "%s:0", dev_name(ctrl_dev
));
58 snprintf(name
, sizeof(name
), "%s.%d",
59 dev_name(ctrl_dev
), serial_ctrl_port
);
62 strscpy(name
, serdev_ctrl_name
, sizeof(name
));
66 child
= device_find_child_by_name(ctrl_dev
, name
);
69 pr_err("error could not find '%s' device\n", name
);
70 ctrl_dev
= ERR_PTR(-ENODEV
);
78 acpi_dev_put(ctrl_adev
);