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 /** 25 * struct cros_ec_cec - Driver data for EC CEC 26 * 27 * @cros_ec: Pointer to EC device 28 * @notifier: Notifier info for responding to EC events 29 * @adap: CEC adapter 30 * @notify: CEC notifier pointer 31 * @rx_msg: storage for a received message 32 */ 33 struct cros_ec_cec { 34 struct cros_ec_device *cros_ec; 35 struct notifier_block notifier; 36 struct cec_adapter *adap; 37 struct cec_notifier *notify; 38 struct cec_msg rx_msg; 39 }; 40 41 static void handle_cec_message(struct cros_ec_cec *cros_ec_cec) 42 { 43 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 44 uint8_t *cec_message = cros_ec->event_data.data.cec_message; 45 unsigned int len = cros_ec->event_size; 46 47 cros_ec_cec->rx_msg.len = len; 48 memcpy(cros_ec_cec->rx_msg.msg, cec_message, len); 49 50 cec_received_msg(cros_ec_cec->adap, &cros_ec_cec->rx_msg); 51 } 52 53 static void handle_cec_event(struct cros_ec_cec *cros_ec_cec) 54 { 55 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 56 uint32_t events = cros_ec->event_data.data.cec_events; 57 58 if (events & EC_MKBP_CEC_SEND_OK) 59 cec_transmit_attempt_done(cros_ec_cec->adap, 60 CEC_TX_STATUS_OK); 61 62 /* FW takes care of all retries, tell core to avoid more retries */ 63 if (events & EC_MKBP_CEC_SEND_FAILED) 64 cec_transmit_attempt_done(cros_ec_cec->adap, 65 CEC_TX_STATUS_MAX_RETRIES | 66 CEC_TX_STATUS_NACK); 67 } 68 69 static int cros_ec_cec_event(struct notifier_block *nb, 70 unsigned long queued_during_suspend, 71 void *_notify) 72 { 73 struct cros_ec_cec *cros_ec_cec; 74 struct cros_ec_device *cros_ec; 75 76 cros_ec_cec = container_of(nb, struct cros_ec_cec, notifier); 77 cros_ec = cros_ec_cec->cros_ec; 78 79 if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_EVENT) { 80 handle_cec_event(cros_ec_cec); 81 return NOTIFY_OK; 82 } 83 84 if (cros_ec->event_data.event_type == EC_MKBP_EVENT_CEC_MESSAGE) { 85 handle_cec_message(cros_ec_cec); 86 return NOTIFY_OK; 87 } 88 89 return NOTIFY_DONE; 90 } 91 92 static int cros_ec_cec_set_log_addr(struct cec_adapter *adap, u8 logical_addr) 93 { 94 struct cros_ec_cec *cros_ec_cec = adap->priv; 95 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 96 struct { 97 struct cros_ec_command msg; 98 struct ec_params_cec_set data; 99 } __packed msg = {}; 100 int ret; 101 102 msg.msg.command = EC_CMD_CEC_SET; 103 msg.msg.outsize = sizeof(msg.data); 104 msg.data.cmd = CEC_CMD_LOGICAL_ADDRESS; 105 msg.data.val = logical_addr; 106 107 ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); 108 if (ret < 0) { 109 dev_err(cros_ec->dev, 110 "error setting CEC logical address on EC: %d\n", ret); 111 return ret; 112 } 113 114 return 0; 115 } 116 117 static int cros_ec_cec_transmit(struct cec_adapter *adap, u8 attempts, 118 u32 signal_free_time, struct cec_msg *cec_msg) 119 { 120 struct cros_ec_cec *cros_ec_cec = adap->priv; 121 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 122 struct { 123 struct cros_ec_command msg; 124 struct ec_params_cec_write data; 125 } __packed msg = {}; 126 int ret; 127 128 msg.msg.command = EC_CMD_CEC_WRITE_MSG; 129 msg.msg.outsize = cec_msg->len; 130 memcpy(msg.data.msg, cec_msg->msg, cec_msg->len); 131 132 ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); 133 if (ret < 0) { 134 dev_err(cros_ec->dev, 135 "error writing CEC msg on EC: %d\n", ret); 136 return ret; 137 } 138 139 return 0; 140 } 141 142 static int cros_ec_cec_adap_enable(struct cec_adapter *adap, bool enable) 143 { 144 struct cros_ec_cec *cros_ec_cec = adap->priv; 145 struct cros_ec_device *cros_ec = cros_ec_cec->cros_ec; 146 struct { 147 struct cros_ec_command msg; 148 struct ec_params_cec_set data; 149 } __packed msg = {}; 150 int ret; 151 152 msg.msg.command = EC_CMD_CEC_SET; 153 msg.msg.outsize = sizeof(msg.data); 154 msg.data.cmd = CEC_CMD_ENABLE; 155 msg.data.val = enable; 156 157 ret = cros_ec_cmd_xfer_status(cros_ec, &msg.msg); 158 if (ret < 0) { 159 dev_err(cros_ec->dev, 160 "error %sabling CEC on EC: %d\n", 161 (enable ? "en" : "dis"), ret); 162 return ret; 163 } 164 165 return 0; 166 } 167 168 static const struct cec_adap_ops cros_ec_cec_ops = { 169 .adap_enable = cros_ec_cec_adap_enable, 170 .adap_log_addr = cros_ec_cec_set_log_addr, 171 .adap_transmit = cros_ec_cec_transmit, 172 }; 173 174 #ifdef CONFIG_PM_SLEEP 175 static int cros_ec_cec_suspend(struct device *dev) 176 { 177 struct platform_device *pdev = to_platform_device(dev); 178 struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); 179 180 if (device_may_wakeup(dev)) 181 enable_irq_wake(cros_ec_cec->cros_ec->irq); 182 183 return 0; 184 } 185 186 static int cros_ec_cec_resume(struct device *dev) 187 { 188 struct platform_device *pdev = to_platform_device(dev); 189 struct cros_ec_cec *cros_ec_cec = dev_get_drvdata(&pdev->dev); 190 191 if (device_may_wakeup(dev)) 192 disable_irq_wake(cros_ec_cec->cros_ec->irq); 193 194 return 0; 195 } 196 #endif 197 198 static SIMPLE_DEV_PM_OPS(cros_ec_cec_pm_ops, 199 cros_ec_cec_suspend, cros_ec_cec_resume); 200 201 #if IS_ENABLED(CONFIG_PCI) && IS_ENABLED(CONFIG_DMI) 202 203 /* 204 * The Firmware only handles a single CEC interface tied to a single HDMI 205 * connector we specify along with the DRM device name handling the HDMI output 206 */ 207 208 struct cec_dmi_match { 209 const char *sys_vendor; 210 const char *product_name; 211 const char *devname; 212 const char *conn; 213 }; 214 215 static const struct cec_dmi_match cec_dmi_match_table[] = { 216 /* Google Fizz */ 217 { "Google", "Fizz", "0000:00:02.0", "Port B" }, 218 /* Google Brask */ 219 { "Google", "Brask", "0000:00:02.0", "Port B" }, 220 /* Google Moli */ 221 { "Google", "Moli", "0000:00:02.0", "Port B" }, 222 /* Google Kinox */ 223 { "Google", "Kinox", "0000:00:02.0", "Port B" }, 224 }; 225 226 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, 227 const char **conn) 228 { 229 int i; 230 231 for (i = 0 ; i < ARRAY_SIZE(cec_dmi_match_table) ; ++i) { 232 const struct cec_dmi_match *m = &cec_dmi_match_table[i]; 233 234 if (dmi_match(DMI_SYS_VENDOR, m->sys_vendor) && 235 dmi_match(DMI_PRODUCT_NAME, m->product_name)) { 236 struct device *d; 237 238 /* Find the device, bail out if not yet registered */ 239 d = bus_find_device_by_name(&pci_bus_type, NULL, 240 m->devname); 241 if (!d) 242 return ERR_PTR(-EPROBE_DEFER); 243 put_device(d); 244 *conn = m->conn; 245 return d; 246 } 247 } 248 249 /* Hardware support must be added in the cec_dmi_match_table */ 250 dev_warn(dev, "CEC notifier not configured for this hardware\n"); 251 252 return ERR_PTR(-ENODEV); 253 } 254 255 #else 256 257 static struct device *cros_ec_cec_find_hdmi_dev(struct device *dev, 258 const char **conn) 259 { 260 return ERR_PTR(-ENODEV); 261 } 262 263 #endif 264 265 static int cros_ec_cec_probe(struct platform_device *pdev) 266 { 267 struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); 268 struct cros_ec_device *cros_ec = ec_dev->ec_dev; 269 struct cros_ec_cec *cros_ec_cec; 270 struct device *hdmi_dev; 271 const char *conn = NULL; 272 int ret; 273 274 hdmi_dev = cros_ec_cec_find_hdmi_dev(&pdev->dev, &conn); 275 if (IS_ERR(hdmi_dev)) 276 return PTR_ERR(hdmi_dev); 277 278 cros_ec_cec = devm_kzalloc(&pdev->dev, sizeof(*cros_ec_cec), 279 GFP_KERNEL); 280 if (!cros_ec_cec) 281 return -ENOMEM; 282 283 platform_set_drvdata(pdev, cros_ec_cec); 284 cros_ec_cec->cros_ec = cros_ec; 285 286 device_init_wakeup(&pdev->dev, 1); 287 288 cros_ec_cec->adap = cec_allocate_adapter(&cros_ec_cec_ops, cros_ec_cec, 289 DRV_NAME, 290 CEC_CAP_DEFAULTS | 291 CEC_CAP_CONNECTOR_INFO, 1); 292 if (IS_ERR(cros_ec_cec->adap)) 293 return PTR_ERR(cros_ec_cec->adap); 294 295 cros_ec_cec->notify = cec_notifier_cec_adap_register(hdmi_dev, conn, 296 cros_ec_cec->adap); 297 if (!cros_ec_cec->notify) { 298 ret = -ENOMEM; 299 goto out_probe_adapter; 300 } 301 302 /* Get CEC events from the EC. */ 303 cros_ec_cec->notifier.notifier_call = cros_ec_cec_event; 304 ret = blocking_notifier_chain_register(&cros_ec->event_notifier, 305 &cros_ec_cec->notifier); 306 if (ret) { 307 dev_err(&pdev->dev, "failed to register notifier\n"); 308 goto out_probe_notify; 309 } 310 311 ret = cec_register_adapter(cros_ec_cec->adap, &pdev->dev); 312 if (ret < 0) 313 goto out_probe_notify; 314 315 return 0; 316 317 out_probe_notify: 318 cec_notifier_cec_adap_unregister(cros_ec_cec->notify, 319 cros_ec_cec->adap); 320 out_probe_adapter: 321 cec_delete_adapter(cros_ec_cec->adap); 322 return ret; 323 } 324 325 static int cros_ec_cec_remove(struct platform_device *pdev) 326 { 327 struct cros_ec_cec *cros_ec_cec = platform_get_drvdata(pdev); 328 struct device *dev = &pdev->dev; 329 int ret; 330 331 ret = blocking_notifier_chain_unregister( 332 &cros_ec_cec->cros_ec->event_notifier, 333 &cros_ec_cec->notifier); 334 335 if (ret) { 336 dev_err(dev, "failed to unregister notifier\n"); 337 return ret; 338 } 339 340 cec_notifier_cec_adap_unregister(cros_ec_cec->notify, 341 cros_ec_cec->adap); 342 cec_unregister_adapter(cros_ec_cec->adap); 343 344 return 0; 345 } 346 347 static struct platform_driver cros_ec_cec_driver = { 348 .probe = cros_ec_cec_probe, 349 .remove = cros_ec_cec_remove, 350 .driver = { 351 .name = DRV_NAME, 352 .pm = &cros_ec_cec_pm_ops, 353 }, 354 }; 355 356 module_platform_driver(cros_ec_cec_driver); 357 358 MODULE_DESCRIPTION("CEC driver for ChromeOS ECs"); 359 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); 360 MODULE_LICENSE("GPL"); 361 MODULE_ALIAS("platform:" DRV_NAME); 362