1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2022 Google LLC
5 * This driver provides the ability to configure Type C muxes and retimers which are controlled by
9 #include <linux/acpi.h>
10 #include <linux/module.h>
11 #include <linux/platform_data/cros_ec_commands.h>
12 #include <linux/platform_device.h>
13 #include <linux/usb/typec_retimer.h>
15 #define DRV_NAME "cros-typec-switch"
17 /* Handles and other relevant data required for each port's switches. */
18 struct cros_typec_port {
20 struct typec_retimer *retimer;
21 struct cros_typec_switch_data *sdata;
24 /* Driver-specific data. */
25 struct cros_typec_switch_data {
27 struct cros_ec_device *ec;
28 struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
31 static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state)
36 static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata)
40 for (i = 0; i < EC_USB_PD_MAX_PORTS; i++) {
43 typec_retimer_unregister(sdata->ports[i]->retimer);
47 static int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode)
49 struct typec_retimer_desc retimer_desc = {
52 .name = fwnode_get_name(fwnode),
53 .set = cros_typec_retimer_set,
56 port->retimer = typec_retimer_register(port->sdata->dev, &retimer_desc);
57 if (IS_ERR(port->retimer))
58 return PTR_ERR(port->retimer);
63 static int cros_typec_register_switches(struct cros_typec_switch_data *sdata)
65 struct cros_typec_port *port = NULL;
66 struct device *dev = sdata->dev;
67 struct fwnode_handle *fwnode;
68 struct acpi_device *adev;
69 unsigned long long index;
73 nports = device_get_child_node_count(dev);
75 dev_err(dev, "No switch devices found.\n");
79 device_for_each_child_node(dev, fwnode) {
80 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
86 adev = to_acpi_device_node(fwnode);
88 dev_err(fwnode->dev, "Couldn't get ACPI device handle\n");
93 ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index);
94 if (ACPI_FAILURE(ret)) {
95 dev_err(fwnode->dev, "_ADR wasn't evaluated\n");
100 if (index < 0 || index >= EC_USB_PD_MAX_PORTS) {
101 dev_err(fwnode->dev, "Invalid port index number: %llu", index);
106 port->port_num = index;
107 sdata->ports[index] = port;
109 ret = cros_typec_register_retimer(port, fwnode);
111 dev_err(dev, "Retimer switch register failed\n");
115 dev_dbg(dev, "Retimer switch registered for index %llu\n", index);
120 cros_typec_unregister_switches(sdata);
124 static int cros_typec_switch_probe(struct platform_device *pdev)
126 struct device *dev = &pdev->dev;
127 struct cros_typec_switch_data *sdata;
129 sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL);
134 sdata->ec = dev_get_drvdata(pdev->dev.parent);
136 platform_set_drvdata(pdev, sdata);
138 return cros_typec_register_switches(sdata);
141 static int cros_typec_switch_remove(struct platform_device *pdev)
143 struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev);
145 cros_typec_unregister_switches(sdata);
150 static const struct acpi_device_id cros_typec_switch_acpi_id[] = {
154 MODULE_DEVICE_TABLE(acpi, cros_typec_switch_acpi_id);
157 static struct platform_driver cros_typec_switch_driver = {
160 .acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id),
162 .probe = cros_typec_switch_probe,
163 .remove = cros_typec_switch_remove,
166 module_platform_driver(cros_typec_switch_driver);
168 MODULE_AUTHOR("Prashant Malani <pmalani@chromium.org>");
169 MODULE_DESCRIPTION("Chrome OS EC Type C Switch control");
170 MODULE_LICENSE("GPL");