1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright 2022 Google LLC 4 * 5 * This driver provides the ability to configure Type-C muxes and retimers which are controlled by 6 * the ChromeOS EC. 7 */ 8 9#include <linux/acpi.h> 10#include <linux/delay.h> 11#include <linux/jiffies.h> 12#include <linux/module.h> 13#include <linux/platform_data/cros_ec_commands.h> 14#include <linux/platform_data/cros_ec_proto.h> 15#include <linux/platform_device.h> 16#include <linux/usb/typec_altmode.h> 17#include <linux/usb/typec_dp.h> 18#include <linux/usb/typec_mux.h> 19#include <linux/usb/typec_retimer.h> 20 21/* Handles and other relevant data required for each port's switches. */ 22struct cros_typec_port { 23 int port_num; 24 struct typec_mux_dev *mode_switch; 25 struct typec_retimer *retimer; 26 struct cros_typec_switch_data *sdata; 27}; 28 29/* Driver-specific data. */ 30struct cros_typec_switch_data { 31 struct device *dev; 32 struct cros_ec_device *ec; 33 struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS]; 34}; 35 36static int cros_typec_cmd_mux_set(struct cros_typec_switch_data *sdata, int port_num, u8 index, 37 u8 state) 38{ 39 struct ec_params_typec_control req = { 40 .port = port_num, 41 .command = TYPEC_CONTROL_COMMAND_USB_MUX_SET, 42 .mux_params = { 43 .mux_index = index, 44 .mux_flags = state, 45 }, 46 }; 47 48 return cros_ec_cmd(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req, sizeof(req), NULL, 0); 49} 50 51static int cros_typec_get_mux_state(unsigned long mode, struct typec_altmode *alt) 52{ 53 int ret = -EOPNOTSUPP; 54 u8 pin_assign; 55 56 if (mode == TYPEC_STATE_SAFE) { 57 ret = USB_PD_MUX_SAFE_MODE; 58 } else if (mode == TYPEC_STATE_USB) { 59 ret = USB_PD_MUX_USB_ENABLED; 60 } else if (alt && alt->svid == USB_TYPEC_DP_SID) { 61 ret = USB_PD_MUX_DP_ENABLED; 62 pin_assign = mode - TYPEC_STATE_MODAL; 63 if (pin_assign & DP_PIN_ASSIGN_D) 64 ret |= USB_PD_MUX_USB_ENABLED; 65 } 66 67 return ret; 68} 69 70static int cros_typec_send_clear_event(struct cros_typec_switch_data *sdata, int port_num, 71 u32 events_mask) 72{ 73 struct ec_params_typec_control req = { 74 .port = port_num, 75 .command = TYPEC_CONTROL_COMMAND_CLEAR_EVENTS, 76 .clear_events_mask = events_mask, 77 }; 78 79 return cros_ec_cmd(sdata->ec, 0, EC_CMD_TYPEC_CONTROL, &req, sizeof(req), NULL, 0); 80} 81 82static bool cros_typec_check_event(struct cros_typec_switch_data *sdata, int port_num, u32 mask) 83{ 84 struct ec_response_typec_status resp; 85 struct ec_params_typec_status req = { 86 .port = port_num, 87 }; 88 int ret; 89 90 ret = cros_ec_cmd(sdata->ec, 0, EC_CMD_TYPEC_STATUS, &req, sizeof(req), 91 &resp, sizeof(resp)); 92 if (ret < 0) { 93 dev_warn(sdata->dev, "EC_CMD_TYPEC_STATUS failed for port: %d\n", port_num); 94 return false; 95 } 96 97 if (resp.events & mask) 98 return true; 99 100 return false; 101} 102 103/* 104 * The ChromeOS EC treats both mode-switches and retimers as "muxes" for the purposes of the 105 * host command API. This common function configures and verifies the retimer/mode-switch 106 * according to the provided setting. 107 */ 108static int cros_typec_configure_mux(struct cros_typec_switch_data *sdata, int port_num, int index, 109 unsigned long mode, struct typec_altmode *alt) 110{ 111 unsigned long end; 112 u32 event_mask; 113 u8 mux_state; 114 int ret; 115 116 ret = cros_typec_get_mux_state(mode, alt); 117 if (ret < 0) 118 return ret; 119 mux_state = (u8)ret; 120 121 /* Clear any old mux set done event. */ 122 if (index == 0) 123 event_mask = PD_STATUS_EVENT_MUX_0_SET_DONE; 124 else 125 event_mask = PD_STATUS_EVENT_MUX_1_SET_DONE; 126 127 ret = cros_typec_send_clear_event(sdata, port_num, event_mask); 128 if (ret < 0) 129 return ret; 130 131 /* Send the set command. */ 132 ret = cros_typec_cmd_mux_set(sdata, port_num, index, mux_state); 133 if (ret < 0) 134 return ret; 135 136 /* Check for the mux set done event. */ 137 end = jiffies + msecs_to_jiffies(1000); 138 do { 139 if (cros_typec_check_event(sdata, port_num, event_mask)) 140 return 0; 141 142 usleep_range(500, 1000); 143 } while (time_before(jiffies, end)); 144 145 dev_err(sdata->dev, "Timed out waiting for mux set done on index: %d, state: %d\n", 146 index, mux_state); 147 148 return -ETIMEDOUT; 149} 150 151static int cros_typec_mode_switch_set(struct typec_mux_dev *mode_switch, 152 struct typec_mux_state *state) 153{ 154 struct cros_typec_port *port = typec_mux_get_drvdata(mode_switch); 155 156 /* Mode switches have index 0. */ 157 return cros_typec_configure_mux(port->sdata, port->port_num, 0, state->mode, state->alt); 158} 159 160static int cros_typec_retimer_set(struct typec_retimer *retimer, struct typec_retimer_state *state) 161{ 162 struct cros_typec_port *port = typec_retimer_get_drvdata(retimer); 163 164 /* Retimers have index 1. */ 165 return cros_typec_configure_mux(port->sdata, port->port_num, 1, state->mode, state->alt); 166} 167 168static void cros_typec_unregister_switches(struct cros_typec_switch_data *sdata) 169{ 170 int i; 171 172 for (i = 0; i < EC_USB_PD_MAX_PORTS; i++) { 173 if (!sdata->ports[i]) 174 continue; 175 typec_retimer_unregister(sdata->ports[i]->retimer); 176 typec_mux_unregister(sdata->ports[i]->mode_switch); 177 } 178} 179 180static int cros_typec_register_mode_switch(struct cros_typec_port *port, 181 struct fwnode_handle *fwnode) 182{ 183 struct typec_mux_desc mode_switch_desc = { 184 .fwnode = fwnode, 185 .drvdata = port, 186 .name = fwnode_get_name(fwnode), 187 .set = cros_typec_mode_switch_set, 188 }; 189 190 port->mode_switch = typec_mux_register(port->sdata->dev, &mode_switch_desc); 191 192 return PTR_ERR_OR_ZERO(port->mode_switch); 193} 194 195static int cros_typec_register_retimer(struct cros_typec_port *port, struct fwnode_handle *fwnode) 196{ 197 struct typec_retimer_desc retimer_desc = { 198 .fwnode = fwnode, 199 .drvdata = port, 200 .name = fwnode_get_name(fwnode), 201 .set = cros_typec_retimer_set, 202 }; 203 204 port->retimer = typec_retimer_register(port->sdata->dev, &retimer_desc); 205 206 return PTR_ERR_OR_ZERO(port->retimer); 207} 208 209static int cros_typec_register_switches(struct cros_typec_switch_data *sdata) 210{ 211 struct cros_typec_port *port; 212 struct device *dev = sdata->dev; 213 struct fwnode_handle *fwnode; 214 struct acpi_device *adev; 215 unsigned long long index; 216 int nports, ret; 217 218 nports = device_get_child_node_count(dev); 219 if (nports == 0) { 220 dev_err(dev, "No switch devices found.\n"); 221 return -ENODEV; 222 } 223 224 device_for_each_child_node(dev, fwnode) { 225 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 226 if (!port) { 227 ret = -ENOMEM; 228 goto err_switch; 229 } 230 231 adev = to_acpi_device_node(fwnode); 232 if (!adev) { 233 dev_err(fwnode->dev, "Couldn't get ACPI device handle\n"); 234 ret = -ENODEV; 235 goto err_switch; 236 } 237 238 ret = acpi_evaluate_integer(adev->handle, "_ADR", NULL, &index); 239 if (ACPI_FAILURE(ret)) { 240 dev_err(fwnode->dev, "_ADR wasn't evaluated\n"); 241 ret = -ENODATA; 242 goto err_switch; 243 } 244 245 if (index >= EC_USB_PD_MAX_PORTS) { 246 dev_err(fwnode->dev, "Invalid port index number: %llu\n", index); 247 ret = -EINVAL; 248 goto err_switch; 249 } 250 port->sdata = sdata; 251 port->port_num = index; 252 sdata->ports[index] = port; 253 254 if (fwnode_property_present(fwnode, "retimer-switch")) { 255 ret = cros_typec_register_retimer(port, fwnode); 256 if (ret) { 257 dev_err(dev, "Retimer switch register failed\n"); 258 goto err_switch; 259 } 260 261 dev_dbg(dev, "Retimer switch registered for index %llu\n", index); 262 } 263 264 if (!fwnode_property_present(fwnode, "mode-switch")) 265 continue; 266 267 ret = cros_typec_register_mode_switch(port, fwnode); 268 if (ret) { 269 dev_err(dev, "Mode switch register failed\n"); 270 goto err_switch; 271 } 272 273 dev_dbg(dev, "Mode switch registered for index %llu\n", index); 274 } 275 276 return 0; 277err_switch: 278 fwnode_handle_put(fwnode); 279 cros_typec_unregister_switches(sdata); 280 return ret; 281} 282 283static int cros_typec_switch_probe(struct platform_device *pdev) 284{ 285 struct device *dev = &pdev->dev; 286 struct cros_typec_switch_data *sdata; 287 288 sdata = devm_kzalloc(dev, sizeof(*sdata), GFP_KERNEL); 289 if (!sdata) 290 return -ENOMEM; 291 292 sdata->dev = dev; 293 sdata->ec = dev_get_drvdata(pdev->dev.parent); 294 295 platform_set_drvdata(pdev, sdata); 296 297 return cros_typec_register_switches(sdata); 298} 299 300static void cros_typec_switch_remove(struct platform_device *pdev) 301{ 302 struct cros_typec_switch_data *sdata = platform_get_drvdata(pdev); 303 304 cros_typec_unregister_switches(sdata); 305} 306 307#ifdef CONFIG_ACPI 308static const struct acpi_device_id cros_typec_switch_acpi_id[] = { 309 { "GOOG001A", 0 }, 310 {} 311}; 312MODULE_DEVICE_TABLE(acpi, cros_typec_switch_acpi_id); 313#endif 314 315static struct platform_driver cros_typec_switch_driver = { 316 .driver = { 317 .name = "cros-typec-switch", 318 .acpi_match_table = ACPI_PTR(cros_typec_switch_acpi_id), 319 }, 320 .probe = cros_typec_switch_probe, 321 .remove_new = cros_typec_switch_remove, 322}; 323 324module_platform_driver(cros_typec_switch_driver); 325 326MODULE_AUTHOR("Prashant Malani <pmalani@chromium.org>"); 327MODULE_DESCRIPTION("ChromeOS EC Type-C Switch control"); 328MODULE_LICENSE("GPL"); 329