1309466Sngie// SPDX-License-Identifier: GPL-2.0+ 2272343Sngie/* 3272343Sngie * CEC driver for ChromeOS Embedded Controller 4272343Sngie * 5272343Sngie * Copyright (c) 2018 BayLibre, SAS 6272343Sngie * Author: Neil Armstrong <narmstrong@baylibre.com> 7272343Sngie */ 8272343Sngie 9272343Sngie#include <linux/kernel.h> 10272343Sngie#include <linux/module.h> 11272343Sngie#include <linux/platform_device.h> 12272343Sngie#include <linux/dmi.h> 13272343Sngie#include <linux/pci.h> 14272343Sngie#include <linux/cec.h> 15272343Sngie#include <linux/slab.h> 16272343Sngie#include <linux/interrupt.h> 17272343Sngie#include <linux/platform_data/cros_ec_commands.h> 18272343Sngie#include <linux/platform_data/cros_ec_proto.h> 19272343Sngie#include <media/cec.h> 20272343Sngie#include <media/cec-notifier.h> 21272343Sngie 22272343Sngie#define DRV_NAME "cros-ec-cec" 23272343Sngie 24272343Sngie/** 25272343Sngie * struct cros_ec_cec_port - Driver data for a single EC CEC port 26272343Sngie * 27272343Sngie * @port_num: port number 28272343Sngie * @adap: CEC adapter 29272343Sngie * @notify: CEC notifier pointer 30272343Sngie * @rx_msg: storage for a received message 31272343Sngie * @cros_ec_cec: pointer to the parent struct 32272343Sngie */ 33272343Sngiestruct cros_ec_cec_port { 34272343Sngie int port_num; 35309466Sngie struct cec_adapter *adap; 36272343Sngie struct cec_notifier *notify; 37272343Sngie struct cec_msg rx_msg; 38309466Sngie struct cros_ec_cec *cros_ec_cec; 39309466Sngie}; 40272343Sngie 41272343Sngie/** 42272343Sngie * struct cros_ec_cec - Driver data for EC CEC 43272343Sngie * 44272343Sngie * @cros_ec: Pointer to EC device 45272343Sngie * @notifier: Notifier info for responding to EC events 46272343Sngie * @write_cmd_version: Highest supported version of EC_CMD_CEC_WRITE_MSG. 47272343Sngie * @num_ports: Number of CEC ports 48272343Sngie * @ports: Array of ports 49272343Sngie */ 50272343Sngiestruct cros_ec_cec { 51272343Sngie struct cros_ec_device *cros_ec; 52272343Sngie struct notifier_block notifier; 53272343Sngie int write_cmd_version; 54274626Sngie int num_ports; 55273025Sngie struct cros_ec_cec_port *ports[EC_CEC_MAX_PORTS]; 56273025Sngie}; 57273025Sngie 58273025Sngiestatic void cros_ec_cec_received_message(struct cros_ec_cec_port *port, 59273025Sngie uint8_t *msg, uint8_t len) 60273025Sngie{ 61273025Sngie if (len > CEC_MAX_MSG_SIZE) 62273025Sngie len = CEC_MAX_MSG_SIZE; 63273025Sngie 64273025Sngie port->rx_msg.len = len; 65272343Sngie memcpy(port->rx_msg.msg, msg, len); 66272343Sngie 67272343Sngie cec_received_msg(port->adap, &port->rx_msg); 68272343Sngie} 69272343Sngie 70272343Sngiestatic void handle_cec_message(struct cros_ec_cec *cros_ec_cec) 71272343Sngie{ 72272343Sngie struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 73272343Sngie uint8_t *cec_message = cros_ec->event_data.data.cec_message; 74273025Sngie unsigned int len = cros_ec->event_size; 75272343Sngie struct cros_ec_cec_port *port; 76272343Sngie /* 77272343Sngie * There are two ways of receiving CEC messages: 78272343Sngie * 1. Old EC firmware which only supports one port sends the data in a 79272343Sngie * cec_message MKBP event. 80272343Sngie * 2. New EC firmware which supports multiple ports uses 81272343Sngie * EC_MKBP_CEC_HAVE_DATA to notify that data is ready and 82272343Sngie * EC_CMD_CEC_READ_MSG to read it. 83272343Sngie * Check that the EC only has one CEC port, and then we can assume the 84272343Sngie * message is from port 0. 85272343Sngie */ 86272343Sngie if (cros_ec_cec->num_ports != 1) { 87272343Sngie dev_err(cros_ec->dev, 88272343Sngie "received cec_message on device with %d ports\n", 89272343Sngie cros_ec_cec->num_ports); 90272343Sngie return; 91272343Sngie } 92272343Sngie port = cros_ec_cec->ports[0]; 93274626Sngie 94273025Sngie cros_ec_cec_received_message(port, cec_message, len); 95273025Sngie} 96273025Sngie 97272343Sngiestatic void cros_ec_cec_read_message(struct cros_ec_cec_port *port) 98272343Sngie{ 99273025Sngie struct cros_ec_device *cros_ec = port->cros_ec_cec->cros_ec; 100272343Sngie struct ec_params_cec_read params = { 101272343Sngie .port = port->port_num, 102309466Sngie }; 103309466Sngie struct ec_response_cec_read response; 104309466Sngie int ret; 105309466Sngie 106309466Sngie ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_READ_MSG, ¶ms, 107309466Sngie sizeof(params), &response, sizeof(response)); 108309466Sngie if (ret < 0) { 109309466Sngie dev_err(cros_ec->dev, 110309466Sngie "error reading CEC message on EC: %d\n", ret); 111309466Sngie return; 112309466Sngie } 113309466Sngie 114309466Sngie cros_ec_cec_received_message(port, response.msg, response.msg_len); 115309466Sngie} 116309466Sngie 117309466Sngiestatic void handle_cec_event(struct cros_ec_cec *cros_ec_cec) 118309466Sngie{ 119309466Sngie struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 120309466Sngie uint32_t cec_events = cros_ec->event_data.data.cec_events; 121309466Sngie uint32_t port_num = EC_MKBP_EVENT_CEC_GET_PORT(cec_events); 122309466Sngie uint32_t events = EC_MKBP_EVENT_CEC_GET_EVENTS(cec_events); 123309466Sngie struct cros_ec_cec_port *port; 124309466Sngie 125309466Sngie if (port_num >= cros_ec_cec->num_ports) { 126309466Sngie dev_err(cros_ec->dev, 127309466Sngie "received CEC event for invalid port %d\n", port_num); 128309466Sngie return; 129309466Sngie } 130309466Sngie port = cros_ec_cec->ports[port_num]; 131309466Sngie 132309466Sngie if (events & EC_MKBP_CEC_SEND_OK) 133309466Sngie cec_transmit_attempt_done(port->adap, CEC_TX_STATUS_OK); 134309466Sngie 135309466Sngie /* FW takes care of all retries, tell core to avoid more retries */ 136309466Sngie if (events & EC_MKBP_CEC_SEND_FAILED) 137309466Sngie cec_transmit_attempt_done(port->adap, 138309466Sngie CEC_TX_STATUS_MAX_RETRIES | 139309466Sngie CEC_TX_STATUS_NACK); 140309466Sngie 141309466Sngie if (events & EC_MKBP_CEC_HAVE_DATA) 142309466Sngie cros_ec_cec_read_message(port); 143309466Sngie} 144309466Sngie 145309466Sngiestatic int cros_ec_cec_event(struct notifier_block *nb, 146309466Sngie unsigned long queued_during_suspend, 147309466Sngie void *_notify) 148309466Sngie{ 149309466Sngie struct cros_ec_cec *cros_ec_cec; 150309466Sngie struct cros_ec_device *cros_ec; 151309466Sngie 152309466Sngie cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier); 153309466Sngie cros_ec = cros_ec_cec->cros_ec; 154309466Sngie 155309466Sngie if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) { 156309466Sngie handle_cec_event(cros_ec_cec); 157309466Sngie return NOTIFY_OK; 158309466Sngie } 159309466Sngie 160309466Sngie if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) { 161309466Sngie handle_cec_message(cros_ec_cec); 162309466Sngie return NOTIFY_OK; 163309466Sngie } 164309466Sngie 165309466Sngie return NOTIFY_DONE; 166309466Sngie} 167309466Sngie 168309466Sngiestatic int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) 169309466Sngie{ 170309466Sngie struct cros_ec_cec_port *port = adap->priv; 171309466Sngie struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; 172309466Sngie struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 173309466Sngie struct ec_params_cec_set params = { 174309466Sngie .cmd = CEC_CMD_LOGICAL_ADDRESS, 175309466Sngie .port = port->port_num, 176309466Sngie .val = logical_addr, 177309466Sngie }; 178309466Sngie int ret; 179309466Sngie 180309466Sngie ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), 181309466Sngie NULL, 0); 182309466Sngie if (ret < 0) { 183309466Sngie dev_err(cros_ec->dev, 184309466Sngie "error setting CEC logical address on EC: %d\n", ret); 185309466Sngie return ret; 186309466Sngie } 187309466Sngie 188309466Sngie return 0; 189309466Sngie} 190309466Sngie 191309466Sngiestatic int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, 192309466Sngie u32 signal_free_time, struct cec_msg *cec_msg) 193309466Sngie{ 194309466Sngie struct cros_ec_cec_port *port = adap->priv; 195309466Sngie struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; 196309466Sngie struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 197309466Sngie struct ec_params_cec_write params; 198309466Sngie struct ec_params_cec_write_v1 params_v1; 199309466Sngie int ret; 200309466Sngie 201309466Sngie if (cros_ec_cec->write_cmd_version == 0) { 202309466Sngie memcpy(params.msg, cec_msg->msg, cec_msg->len); 203309466Sngie ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_WRITE_MSG, ¶ms, 204309466Sngie cec_msg->len, NULL, 0); 205309466Sngie } else { 206309466Sngie params_v1.port = port->port_num; 207309466Sngie params_v1.msg_len = cec_msg->len; 208309466Sngie memcpy(params_v1.msg, cec_msg->msg, cec_msg->len); 209309466Sngie ret = cros_ec_cmd(cros_ec, cros_ec_cec->write_cmd_version, 210309466Sngie EC_CMD_CEC_WRITE_MSG, ¶ms_v1, 211309466Sngie sizeof(params_v1), NULL, 0); 212309466Sngie } 213309466Sngie 214309466Sngie if (ret < 0) { 215309466Sngie dev_err(cros_ec->dev, 216309466Sngie "error writing CEC msg on EC: %d\n", ret); 217309466Sngie return ret; 218309466Sngie } 219309466Sngie 220272343Sngie return 0; 221272343Sngie} 222272343Sngie 223272343Sngiestatic int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) 224272343Sngie{ 225272343Sngie struct cros_ec_cec_port *port = adap->priv; 226272343Sngie struct cros_ec_cec *cros_ec_cec = port->cros_ec_cec; 227272343Sngie struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 228272343Sngie struct ec_params_cec_set params = { 229272343Sngie .cmd = CEC_CMD_ENABLE, 230272343Sngie .port = port->port_num, 231274626Sngie .val = enable, 232273025Sngie }; 233273025Sngie int ret; 234273025Sngie 235272343Sngie ret = cros_ec_cmd(cros_ec, 0, EC_CMD_CEC_SET, ¶ms, sizeof(params), 236309466Sngie NULL, 0); 237272343Sngie if (ret < 0) { 238309466Sngie dev_err(cros_ec->dev, 239272343Sngie "error %sabling CEC on EC: %d\n", 240309466Sngie (enable ? "en" : "dis"), ret); 241272343Sngie return ret; 242309466Sngie } 243272343Sngie 244309466Sngie return 0; 245272343Sngie} 246309466Sngie 247272343Sngiestatic const struct cec_adap_ops cros_ec_cec_ops = { 248272343Sngie .adap_enable = cros_ec_cec_adap_enable, 249272343Sngie .adap_log_addr = cros_ec_cec_set_log_addr, 250272343Sngie .adap_transmit = cros_ec_cec_transmit, 251272343Sngie}; 252272343Sngie 253272343Sngie#ifdef CONFIG_PM_SLEEP 254309466Sngiestatic int cros_ec_cec_suspend(struct device *dev) 255309466Sngie{ 256272343Sngie struct platform_device *pdev = to_platform_device(dev); 257272343Sngie struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); 258272343Sngie 259272343Sngie if (device_may_wakeup(dev)) 260272343Sngie enable_irq_wake(cros_ec_cec->cros_ec->irq); 261272343Sngie 262272343Sngie return 0; 263272343Sngie} 264272343Sngie 265272343Sngiestatic int cros_ec_cec_resume(struct device *dev) 266272343Sngie{ 267272343Sngie struct platform_device *pdev = to_platform_device(dev); 268272343Sngie struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); 269272343Sngie 270272343Sngie if (device_may_wakeup(dev)) 271272343Sngie disable_irq_wake(cros_ec_cec->cros_ec->irq); 272272343Sngie 273272343Sngie return 0; 274272343Sngie} 275272343Sngie#endif 276272343Sngie 277272343Sngiestatic SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, 278272343Sngie cros_ec_cec_suspend, cros_ec_cec_resume); 279272343Sngie 280272343Sngie#if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) 281272343Sngie 282272343Sngie/* 283272343Sngie * Specify the DRM device name handling the HDMI output and the HDMI connector 284272343Sngie * corresponding to each CEC port. The order of connectors must match the order 285272343Sngie * in the EC (first connector is EC port 0, ...), and the number of connectors 286272343Sngie * must match the number of ports in the EC (which can be queried using the 287272343Sngie * EC_CMD_CEC_PORT_COUNT host command). 288272343Sngie */ 289272343Sngie 290272343Sngiestruct cec_dmi_match { 291272343Sngie const char *sys_vendor; 292272343Sngie const char *product_name; 293272343Sngie const char *devname; 294272343Sngie const char *const *conns; 295272343Sngie}; 296272343Sngie 297274626Sngiestatic const char *const port_b_conns[] = { "Port B", NULL }; 298272343Sngiestatic const char *const port_db_conns[] = { "Port D", "Port B", NULL }; 299273025Sngiestatic const char *const port_ba_conns[] = { "Port B", "Port A", NULL }; 300273025Sngiestatic const char *const port_d_conns[] = { "Port D", NULL }; 301273025Sngie 302272343Sngiestatic const struct cec_dmi_match cec_dmi_match_table[] = { 303274626Sngie /* Google Fizz */ 304272343Sngie { "Google", "Fizz", "0000:00:02.0", port_b_conns }, 305273025Sngie /* Google Brask */ 306273025Sngie { "Google", "Brask", "0000:00:02.0", port_b_conns }, 307273025Sngie /* Google Moli */ 308272343Sngie { "Google", "Moli", "0000:00:02.0", port_b_conns }, 309272343Sngie /* Google Kinox */ 310309466Sngie { "Google", "Kinox", "0000:00:02.0", port_b_conns }, 311309466Sngie /* Google Kuldax */ 312309466Sngie { "Google", "Kuldax", "0000:00:02.0", port_b_conns }, 313309466Sngie /* Google Aurash */ 314309466Sngie { "Google", "Aurash", "0000:00:02.0", port_b_conns }, 315309466Sngie /* Google Gladios */ 316309466Sngie { "Google", "Gladios", "0000:00:02.0", port_b_conns }, 317309466Sngie /* Google Lisbon */ 318309466Sngie { "Google", "Lisbon", "0000:00:02.0", port_b_conns }, 319309466Sngie /* Google Dibbi */ 320309466Sngie { "Google", "Dibbi", "0000:00:02.0", port_db_conns }, 321309466Sngie /* Google Constitution */ 322309466Sngie { "Google", "Constitution", "0000:00:02.0", port_ba_conns }, 323309466Sngie /* Google Boxy */ 324309466Sngie { "Google", "Boxy", "0000:00:02.0", port_d_conns }, 325309466Sngie /* Google Taranza */ 326309466Sngie { "Google", "Taranza", "0000:00:02.0", port_db_conns }, 327309466Sngie /* Google Dexi */ 328309466Sngie { "Google", "Dexi", "0000:00:02.0", port_db_conns }, 329309466Sngie /* Google Dita */ 330309466Sngie { "Google", "Dita", "0000:00:02.0", port_db_conns }, 331309466Sngie}; 332272343Sngie 333272343Sngiestatic struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, 334272343Sngie const char * const **conns) 335272343Sngie{ 336272343Sngie int i; 337309466Sngie 338309466Sngie for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) { 339272343Sngie const struct cec_dmi_match *m = &cec_dmi_match_table[i]; 340272343Sngie 341272343Sngie if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && 342272343Sngie dmi_match(DMI_PRODUCT_NAME, m->product_name)) { 343272343Sngie struct device *d; 344272343Sngie 345272343Sngie /* Find the device, bail out if not yet registered */ 346272343Sngie d = bus_find_device_by_name(&pci_bus_type, NULL, 347272343Sngie m->devname); 348272343Sngie if (!d) 349272343Sngie return ERR_PTR(-EPROBE_DEFER); 350272343Sngie put_device(d); 351272343Sngie *conns = m->conns; 352272343Sngie return d; 353272343Sngie } 354272343Sngie } 355272343Sngie 356272343Sngie /* Hardware support must be added in the cec_dmi_match_table */ 357272343Sngie dev_warn(dev, "CEC notifier not configured for this hardware\n"); 358272343Sngie 359272343Sngie return ERR_PTR(-ENODEV); 360272343Sngie} 361272343Sngie 362272343Sngie#else 363272343Sngie 364272343Sngiestatic struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, 365272343Sngie const char * const **conns) 366272343Sngie{ 367272343Sngie return ERR_PTR(-ENODEV); 368272343Sngie} 369272343Sngie 370272343Sngie#endif 371272343Sngie 372272343Sngiestatic int cros_ec_cec_get_num_ports(struct cros_ec_cec *cros_ec_cec) 373272343Sngie{ 374272343Sngie struct ec_response_cec_port_count response; 375272343Sngie int ret; 376272343Sngie 377272343Sngie ret = cros_ec_cmd(cros_ec_cec->cros_ec, 0, EC_CMD_CEC_PORT_COUNT, NULL, 378272343Sngie 0, &response, sizeof(response)); 379272343Sngie if (ret < 0) { 380272343Sngie /* 381272343Sngie * Old EC firmware only supports one port and does not support 382272343Sngie * the port count command, so fall back to assuming one port. 383272343Sngie */ 384272343Sngie cros_ec_cec->num_ports = 1; 385272343Sngie return 0; 386272343Sngie } 387272343Sngie 388272343Sngie if (response.port_count == 0) { 389272343Sngie dev_err(cros_ec_cec->cros_ec->dev, 390272343Sngie "EC reports 0 CEC ports\n"); 391272343Sngie return -ENODEV; 392272343Sngie } 393272343Sngie 394272343Sngie if (response.port_count > EC_CEC_MAX_PORTS) { 395272343Sngie dev_err(cros_ec_cec->cros_ec->dev, 396272343Sngie "EC reports too many ports: %d\n", response.port_count); 397272343Sngie return -EINVAL; 398272343Sngie } 399272343Sngie 400272343Sngie cros_ec_cec->num_ports = response.port_count; 401309466Sngie return 0; 402309466Sngie} 403309466Sngie 404309466Sngiestatic int cros_ec_cec_get_write_cmd_version(struct cros_ec_cec *cros_ec_cec) 405309466Sngie{ 406309466Sngie struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 407309466Sngie struct ec_params_get_cmd_versions_v1 params = { 408309466Sngie .cmd = EC_CMD_CEC_WRITE_MSG, 409309466Sngie }; 410309466Sngie struct ec_response_get_cmd_versions response; 411309466Sngie int ret; 412309466Sngie 413309466Sngie ret = cros_ec_cmd(cros_ec, 1, EC_CMD_GET_CMD_VERSIONS, ¶ms, 414309466Sngie sizeof(params), &response, sizeof(response)); 415309466Sngie if (ret < 0) { 416309466Sngie dev_err(cros_ec->dev, 417309466Sngie "error getting CEC write command version: %d\n", ret); 418309466Sngie return ret; 419309466Sngie } 420309466Sngie 421309466Sngie if (response.version_mask & EC_VER_MASK(1)) { 422309466Sngie cros_ec_cec->write_cmd_version = 1; 423309466Sngie } else { 424309466Sngie if (cros_ec_cec->num_ports != 1) { 425309466Sngie dev_err(cros_ec->dev, 426309466Sngie "v0 write command only supports 1 port, %d reported\n", 427309466Sngie cros_ec_cec->num_ports); 428309466Sngie return -EINVAL; 429309466Sngie } 430309466Sngie cros_ec_cec->write_cmd_version = 0; 431309466Sngie } 432309466Sngie 433309466Sngie return 0; 434309466Sngie} 435309466Sngie 436309466Sngiestatic int cros_ec_cec_init_port(struct device *dev, 437309466Sngie struct cros_ec_cec *cros_ec_cec, 438309466Sngie int port_num, struct device *hdmi_dev, 439309466Sngie const char * const *conns) 440309466Sngie{ 441309466Sngie struct cros_ec_cec_port *port; 442309466Sngie int ret; 443309466Sngie 444309466Sngie port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); 445309466Sngie if (!port) 446309466Sngie return -ENOMEM; 447309466Sngie 448309466Sngie port->cros_ec_cec = cros_ec_cec; 449309466Sngie port->port_num = port_num; 450309466Sngie 451309466Sngie port->adap = cec_allocate_adapter(&cros_ec_cec_ops, port, DRV_NAME, 452309466Sngie CEC_CAP_DEFAULTS | 453309466Sngie CEC_CAP_CONNECTOR_INFO, 1); 454309466Sngie if (IS_ERR(port->adap)) 455309466Sngie return PTR_ERR(port->adap); 456309466Sngie 457309466Sngie if (!conns[port_num]) { 458309466Sngie dev_err(dev, "no conn for port %d\n", port_num); 459309466Sngie ret = -ENODEV; 460309466Sngie goto out_probe_adapter; 461309466Sngie } 462309466Sngie 463309466Sngie port->notify = cec_notifier_cec_adap_register(hdmi_dev, conns[port_num], 464309466Sngie port->adap); 465309466Sngie if (!port->notify) { 466309466Sngie ret = -ENOMEM; 467309466Sngie goto out_probe_adapter; 468309466Sngie } 469309466Sngie 470309466Sngie ret = cec_register_adapter(port->adap, dev); 471309466Sngie if (ret < 0) 472309466Sngie goto out_probe_notify; 473272343Sngie 474272343Sngie cros_ec_cec->ports[port_num] = port; 475272343Sngie 476272343Sngie return 0; 477272343Sngie 478309466Sngieout_probe_notify: 479272343Sngie cec_notifier_cec_adap_unregister(port->notify, port->adap); 480309466Sngieout_probe_adapter: 481309466Sngie cec_delete_adapter(port->adap); 482309466Sngie return ret; 483309466Sngie} 484272343Sngie 485272343Sngiestatic int cros_ec_cec_probe(struct platform_device *pdev) 486272343Sngie{ 487 struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); 488 struct cros_ec_device *cros_ec = ec_dev->ec_dev; 489 struct cros_ec_cec *cros_ec_cec; 490 struct cros_ec_cec_port *port; 491 struct device *hdmi_dev; 492 const char * const *conns = NULL; 493 int ret; 494 495 hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conns); 496 if (IS_ERR(hdmi_dev)) 497 return PTR_ERR(hdmi_dev); 498 499 cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), 500 GFP_KERNEL); 501 if (!cros_ec_cec) 502 return -ENOMEM; 503 504 platform_set_drvdata(pdev, cros_ec_cec); 505 cros_ec_cec->cros_ec = cros_ec; 506 507 device_init_wakeup(&pdev->dev, 1); 508 509 ret = cros_ec_cec_get_num_ports(cros_ec_cec); 510 if (ret) 511 return ret; 512 513 ret = cros_ec_cec_get_write_cmd_version(cros_ec_cec); 514 if (ret) 515 return ret; 516 517 for (int i = 0; i < cros_ec_cec->num_ports; i++) { 518 ret = cros_ec_cec_init_port(&pdev->dev, cros_ec_cec, i, 519 hdmi_dev, conns); 520 if (ret) 521 goto unregister_ports; 522 } 523 524 /* Get CEC events from the EC. */ 525 cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; 526 ret = blocking_notifier_chain_register(&cros_ec->event_notifier, 527 &cros_ec_cec->notifier); 528 if (ret) { 529 dev_err(&pdev->dev, "failed to register notifier\n"); 530 goto unregister_ports; 531 } 532 533 return 0; 534 535unregister_ports: 536 /* 537 * Unregister any adapters which have been registered. We don't add the 538 * port to the array until the adapter has been registered successfully, 539 * so any non-NULL ports must have been registered. 540 */ 541 for (int i = 0; i < cros_ec_cec->num_ports; i++) { 542 port = cros_ec_cec->ports[i]; 543 if (!port) 544 break; 545 cec_notifier_cec_adap_unregister(port->notify, port->adap); 546 cec_unregister_adapter(port->adap); 547 } 548 return ret; 549} 550 551static void cros_ec_cec_remove(struct platform_device *pdev) 552{ 553 struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); 554 struct device *dev = &pdev->dev; 555 struct cros_ec_cec_port *port; 556 int ret; 557 558 /* 559 * blocking_notifier_chain_unregister() only fails if the notifier isn't 560 * in the list. We know it was added to it by .probe(), so there should 561 * be no need for error checking. Be cautious and still check. 562 */ 563 ret = blocking_notifier_chain_unregister( 564 &cros_ec_cec->cros_ec->event_notifier, 565 &cros_ec_cec->notifier); 566 if (ret) 567 dev_err(dev, "failed to unregister notifier\n"); 568 569 for (int i = 0; i < cros_ec_cec->num_ports; i++) { 570 port = cros_ec_cec->ports[i]; 571 cec_notifier_cec_adap_unregister(port->notify, port->adap); 572 cec_unregister_adapter(port->adap); 573 } 574} 575 576static struct platform_driver cros_ec_cec_driver = { 577 .probe = cros_ec_cec_probe, 578 .remove_new = cros_ec_cec_remove, 579 .driver = { 580 .name = DRV_NAME, 581 .pm = &cros_ec_cec_pm_ops, 582 }, 583}; 584 585module_platform_driver(cros_ec_cec_driver); 586 587MODULE_DESCRIPTION("CEC driver for ChromeOS ECs"); 588MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 589MODULE_LICENSE("GPL"); 590MODULE_ALIAS("platform:" DRV_NAME); 591