1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * CEC driver for ChromeOS Embedded Controller 4 * 5 * Copyright (c) 2018 BayLibre, SAS 6 * Author: Neil Armstrong <narmstrong@baylibre.com> 7 */ 8 9 #include <linux/kernel.h> 10 #include <linux/module.h> 11 #include <linux/platform_device.h> 12 #include <linux/dmi.h> 13 #include <linux/pci.h> 14 #include <linux/cec.h> 15 #include <linux/slab.h> 16 #include <linux/interrupt.h> 17 #include <linux/platform_data/cros_ec_commands.h> 18 #include <linux/platform_data/cros_ec_proto.h> 19 #include <media/cec.h> 20 #include <media/cec-notifier.h> 21 22 #define DRV_NAME "cros-ec-cec" 23 24 /* Only one port is supported for now */ 25 #define CEC_NUM_PORTS 1 26 #define CEC_PORT 0 27 28 /** 29 * struct cros_ec_cec_port - Driver data for a single EC CEC port 30 * 31 * @port_num: port number 32 * @adap: CEC adapter 33 * @notify: CEC notifier pointer 34 * @rx_msg: storage for a received message 35 * @cros_ec_cec: pointer to the parent struct 36 */ 37 struct cros_ec_cec_port { 38 int port_num; 39 struct cec_adapter *adap; 40 struct cec_notifier *notify; 41 struct cec_msg rx_msg; 42 struct cros_ec_cec *cros_ec_cec; 43 }; 44 45 /** 46 * struct cros_ec_cec - Driver data for EC CEC 47 * 48 * @cros_ec: Pointer to EC device 49 * @notifier: Notifier info for responding to EC events 50 * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG. 51 * @num_ports: Number of CEC ports 52 * @ports: Array of ports 53 */ 54 struct cros_ec_cec { 55 struct cros_ec_device *cros_ec; 56 struct notifier_block notifier; 57 int write_cmd_version; 58 int num_ports; 59 struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; 60 }; 61 62 static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) 63 { 64 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 65 uint8_t *cec_message = cros_ec->event_data.data.cec_message; 66 unsigned int len = cros_ec->event_size; 67 struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT]; 68 69 if (len > CEC_MAX_MSG_SIZE) 70 len = CEC_MAX_MSG_SIZE; 71 port->rx_msg.len = len; 72 memcpy(port->rx_msg.msg, cec_message, len); 73 74 cec_received_msg(port->adap, &port->rx_msg); 75 } 76 77 static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) 78 { 79 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 80 uint32_t events = cros_ec->event_data.data.cec_events; 81 struct cros_ec_cec_port *port = cros_ec_cec->ports[CEC_PORT]; 82 83 if (events & EC_MKBP_CEC_SEND_OK) 84 cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK); 85 86 /* FW takes care of all retries, tell core to avoid more retries */ 87 if (events & EC_MKBP_CEC_SEND_FAILED) 88 cec_transmit_attempt_done(port->adap, 89 CEC_TX_STATUS_MAX_RETRIES | 90 CEC_TX_STATUS_NACK); 91 } 92 93 static int cros_ec_cec_event(struct notifier_block *nb, 94 unsigned long queued_during_suspend, 95 void *_notify) 96 { 97 struct cros_ec_cec *cros_ec_cec; 98 struct cros_ec_device *cros_ec; 99 100 cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier); 101 cros_ec = cros_ec_cec->cros_ec; 102 103 if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) { 104 handle_cec_event(cros_ec_cec); 105 return NOTIFY_OK; 106 } 107 108 if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) { 109 handle_cec_message(cros_ec_cec); 110 return NOTIFY_OK; 111 } 112 113 return NOTIFY_DONE; 114 } 115 116 static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) 117 { 118 struct cros_ec_cec_port *port = adap->priv; 119 struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; 120 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 121 struct ec_params_cec_set params = { 122 .cmd = CEC_CMD_LOGICAL_ADDRESS, 123 .port = port->port_num, 124 .val = logical_addr, 125 }; 126 int ret; 127 128 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), 129 NULL, 0); 130 if (ret < 0) { 131 dev_err(cros_ec->dev, 132 "error setting CEC logical address on EC: %d\n", ret); 133 return ret; 134 } 135 136 return 0; 137 } 138 139 static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, 140 u32 signal_free_time, struct cec_msg *cec_msg) 141 { 142 struct cros_ec_cec_port *port = adap->priv; 143 struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; 144 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 145 struct ec_params_cec_write params; 146 struct ec_params_cec_write_v1 params_v1; 147 int ret; 148 149 if (cros_ec_cec->write_cmd_version == 0) { 150 memcpy(params.msg, cec_msg->msg, cec_msg->len); 151 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, 152 cec_msg->len, NULL, 0); 153 } else { 154 params_v1.port = port->port_num; 155 params_v1.msg_len = cec_msg->len; 156 memcpy(params_v1.msg, cec_msg->msg, cec_msg->len); 157 ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version, 158 EC_CMD_CEC_WRITE_MSG, ¶ms_v1, 159 sizeof(params_v1), NULL, 0); 160 } 161 162 if (ret < 0) { 163 dev_err(cros_ec->dev, 164 "error writing CEC msg on EC: %d\n", ret); 165 return ret; 166 } 167 168 return 0; 169 } 170 171 static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) 172 { 173 struct cros_ec_cec_port *port = adap->priv; 174 struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; 175 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 176 struct ec_params_cec_set params = { 177 .cmd = CEC_CMD_ENABLE, 178 .port = port->port_num, 179 .val = enable, 180 }; 181 int ret; 182 183 ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), 184 NULL, 0); 185 if (ret < 0) { 186 dev_err(cros_ec->dev, 187 "error %sabling CEC on EC: %d\n", 188 (enable ? "en" : "dis"), ret); 189 return ret; 190 } 191 192 return 0; 193 } 194 195 static const struct cec_adap_ops cros_ec_cec_ops = { 196 .adap_enable = cros_ec_cec_adap_enable, 197 .adap_log_addr = cros_ec_cec_set_log_addr, 198 .adap_transmit = cros_ec_cec_transmit, 199 }; 200 201 #ifdef CONFIG_PM_SLEEP 202 static int cros_ec_cec_suspend(struct device *dev) 203 { 204 struct platform_device *pdev = to_platform_device(dev); 205 struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); 206 207 if (device_may_wakeup(dev)) 208 enable_irq_wake(cros_ec_cec->cros_ec->irq); 209 210 return 0; 211 } 212 213 static int cros_ec_cec_resume(struct device *dev) 214 { 215 struct platform_device *pdev = to_platform_device(dev); 216 struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); 217 218 if (device_may_wakeup(dev)) 219 disable_irq_wake(cros_ec_cec->cros_ec->irq); 220 221 return 0; 222 } 223 #endif 224 225 static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, 226 cros_ec_cec_suspend, cros_ec_cec_resume); 227 228 #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) 229 230 /* 231 * The Firmware only handles a single CEC interface tied to a single HDMI 232 * connector we specify along with the DRM device name handling the HDMI output 233 */ 234 235 struct cec_dmi_match { 236 const char *sys_vendor; 237 const char *product_name; 238 const char *devname; 239 const char *conn; 240 }; 241 242 static const struct cec_dmi_match cec_dmi_match_table[] = { 243 /* Google Fizz */ 244 { "Google", "Fizz", "0000:00:02.0", "Port B" }, 245 /* Google Brask */ 246 { "Google", "Brask", "0000:00:02.0", "Port B" }, 247 /* Google Moli */ 248 { "Google", "Moli", "0000:00:02.0", "Port B" }, 249 /* Google Kinox */ 250 { "Google", "Kinox", "0000:00:02.0", "Port B" }, 251 /* Google Kuldax */ 252 { "Google", "Kuldax", "0000:00:02.0", "Port B" }, 253 /* Google Aurash */ 254 { "Google", "Aurash", "0000:00:02.0", "Port B" }, 255 /* Google Gladios */ 256 { "Google", "Gladios", "0000:00:02.0", "Port B" }, 257 /* Google Lisbon */ 258 { "Google", "Lisbon", "0000:00:02.0", "Port B" }, 259 }; 260 261 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, 262 const char **conn) 263 { 264 int i; 265 266 for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) { 267 const struct cec_dmi_match *m = &cec_dmi_match_table[i]; 268 269 if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && 270 dmi_match(DMI_PRODUCT_NAME, m->product_name)) { 271 struct device *d; 272 273 /* Find the device, bail out if not yet registered */ 274 d = bus_find_device_by_name(&pci_bus_type, NULL, 275 m->devname); 276 if (!d) 277 return ERR_PTR(-EPROBE_DEFER); 278 put_device(d); 279 *conn = m->conn; 280 return d; 281 } 282 } 283 284 /* Hardware support must be added in the cec_dmi_match_table */ 285 dev_warn(dev, "CEC notifier not configured for this hardware\n"); 286 287 return ERR_PTR(-ENODEV); 288 } 289 290 #else 291 292 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, 293 const char **conn) 294 { 295 return ERR_PTR(-ENODEV); 296 } 297 298 #endif 299 300 static int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) 301 { 302 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 303 struct ec_params_get_cmd_versions_v1 params = { 304 .cmd = EC_CMD_CEC_WRITE_MSG, 305 }; 306 struct ec_response_get_cmd_versions response; 307 int ret; 308 309 ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms, 310 sizeof(params), &response, sizeof(response)); 311 if (ret < 0) { 312 dev_err(cros_ec->dev, 313 "error getting CEC write command version: %d\n", ret); 314 return ret; 315 } 316 317 if (response.version_mask & EC_VER_MASK(1)) { 318 cros_ec_cec->write_cmd_version = 1; 319 } else { 320 if (cros_ec_cec->num_ports != 1) { 321 dev_err(cros_ec->dev, 322 "v0 write command only supports 1 port, %d reported\n", 323 cros_ec_cec->num_ports); 324 return -EINVAL; 325 } 326 cros_ec_cec->write_cmd_version = 0; 327 } 328 329 return 0; 330 } 331 332 static int cros_ec_cec_init_port(struct device *dev, 333 struct cros_ec_cec *cros_ec_cec, 334 int port_num, struct device *hdmi_dev, 335 const char *conn) 336 { 337 struct cros_ec_cec_port *port; 338 int ret; 339 340 port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 341 if (!port) 342 return -ENOMEM; 343 344 port->cros_ec_cec = cros_ec_cec; 345 port->port_num = port_num; 346 347 port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME, 348 CEC_CAP_DEFAULTS | 349 CEC_CAP_CONNECTOR_INFO, 1); 350 if (IS_ERR(port->adap)) 351 return PTR_ERR(port->adap); 352 353 port->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, 354 port->adap); 355 if (!port->notify) { 356 ret = -ENOMEM; 357 goto out_probe_adapter; 358 } 359 360 ret = cec_register_adapter(port->adap, dev); 361 if (ret < 0) 362 goto out_probe_notify; 363 364 cros_ec_cec->ports[port_num] = port; 365 366 return 0; 367 368 out_probe_notify: 369 cec_notifier_cec_adap_unregister(port->notify, port->adap); 370 out_probe_adapter: 371 cec_delete_adapter(port->adap); 372 return ret; 373 } 374 375 static int cros_ec_cec_probe(struct platform_device *pdev) 376 { 377 struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); 378 struct cros_ec_device *cros_ec = ec_dev->ec_dev; 379 struct cros_ec_cec *cros_ec_cec; 380 struct cros_ec_cec_port *port; 381 struct device *hdmi_dev; 382 const char *conn = NULL; 383 int ret; 384 385 hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); 386 if (IS_ERR(hdmi_dev)) 387 return PTR_ERR(hdmi_dev); 388 389 cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), 390 GFP_KERNEL); 391 if (!cros_ec_cec) 392 return -ENOMEM; 393 394 platform_set_drvdata(pdev, cros_ec_cec); 395 cros_ec_cec->cros_ec = cros_ec; 396 397 device_init_wakeup(&pdev->dev, 1); 398 399 cros_ec_cec->num_ports = CEC_NUM_PORTS; 400 401 ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec); 402 if (ret) 403 return ret; 404 405 for (int i = 0; i < cros_ec_cec->num_ports; i++) { 406 ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, 407 hdmi_dev, conn); 408 if (ret) 409 goto unregister_ports; 410 } 411 412 /* Get CEC events from the EC. */ 413 cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; 414 ret = blocking_notifier_chain_register(&cros_ec->event_notifier, 415 &cros_ec_cec->notifier); 416 if (ret) { 417 dev_err(&pdev->dev, "failed to register notifier\n"); 418 goto unregister_ports; 419 } 420 421 return 0; 422 423 unregister_ports: 424 /* 425 * Unregister any adapters which have been registered. We don't add the 426 * port to the array until the adapter has been registered successfully, 427 * so any non-NULL ports must have been registered. 428 */ 429 for (int i = 0; i < cros_ec_cec->num_ports; i++) { 430 port = cros_ec_cec->ports[i]; 431 if (!port) 432 break; 433 cec_notifier_cec_adap_unregister(port->notify, port->adap); 434 cec_unregister_adapter(port->adap); 435 } 436 return ret; 437 } 438 439 static void cros_ec_cec_remove(struct platform_device *pdev) 440 { 441 struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); 442 struct device *dev = &pdev->dev; 443 struct cros_ec_cec_port *port; 444 int ret; 445 446 /* 447 * blocking_notifier_chain_unregister() only fails if the notifier isn't 448 * in the list. We know it was added to it by .probe(), so there should 449 * be no need for error checking. Be cautious and still check. 450 */ 451 ret = blocking_notifier_chain_unregister( 452 &cros_ec_cec->cros_ec->event_notifier, 453 &cros_ec_cec->notifier); 454 if (ret) 455 dev_err(dev, "failed to unregister notifier\n"); 456 457 for (int i = 0; i < cros_ec_cec->num_ports; i++) { 458 port = cros_ec_cec->ports[i]; 459 cec_notifier_cec_adap_unregister(port->notify, port->adap); 460 cec_unregister_adapter(port->adap); 461 } 462 } 463 464 static struct platform_driver cros_ec_cec_driver = { 465 .probe = cros_ec_cec_probe, 466 .remove_new = cros_ec_cec_remove, 467 .driver = { 468 .name = DRV_NAME, 469 .pm = &cros_ec_cec_pm_ops, 470 }, 471 }; 472 473 module_platform_driver(cros_ec_cec_driver); 474 475 MODULE_DESCRIPTION("CEC driver for ChromeOS ECs"); 476 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 477 MODULE_LICENSE("GPL"); 478 MODULE_ALIAS("platform:" DRV_NAME); 479