1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright 2020 Google LLC 4 * 5 * This driver serves as the receiver of cros_ec PD host events. 6 */ 7 8 #include <linux/acpi.h> 9 #include <linux/fwnode.h> 10 #include <linux/module.h> 11 #include <linux/platform_data/cros_ec_proto.h> 12 #include <linux/platform_data/cros_usbpd_notify.h> 13 #include <linux/platform_device.h> 14 15 #define DRV_NAME "cros-usbpd-notify" 16 #define DRV_NAME_PLAT_ACPI "cros-usbpd-notify-acpi" 17 #define ACPI_DRV_NAME "GOOG0003" 18 #define CREC_DRV_NAME "GOOG0004" 19 20 static BLOCKING_NOTIFIER_HEAD(cros_usbpd_notifier_list); 21 22 struct cros_usbpd_notify_data { 23 struct device *dev; 24 struct cros_ec_device *ec; 25 struct notifier_block nb; 26 }; 27 28 /** 29 * cros_usbpd_register_notify - Register a notifier callback for PD events. 30 * @nb: Notifier block pointer to register 31 * 32 * On ACPI platforms this corresponds to host events on the ECPD 33 * "GOOG0003" ACPI device. On non-ACPI platforms this will filter mkbp events 34 * for USB PD events. 35 * 36 * Return: 0 on success or negative error code. 37 */ 38 int cros_usbpd_register_notify(struct notifier_block *nb) 39 { 40 return blocking_notifier_chain_register(&cros_usbpd_notifier_list, 41 nb); 42 } 43 EXPORT_SYMBOL_GPL(cros_usbpd_register_notify); 44 45 /** 46 * cros_usbpd_unregister_notify - Unregister notifier callback for PD events. 47 * @nb: Notifier block pointer to unregister 48 * 49 * Unregister a notifier callback that was previously registered with 50 * cros_usbpd_register_notify(). 51 */ 52 void cros_usbpd_unregister_notify(struct notifier_block *nb) 53 { 54 blocking_notifier_chain_unregister(&cros_usbpd_notifier_list, nb); 55 } 56 EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify); 57 58 static void cros_usbpd_get_event_and_notify(struct device *dev, 59 struct cros_ec_device *ec_dev) 60 { 61 struct ec_response_host_event_status host_event_status; 62 u32 event = 0; 63 int ret; 64 65 /* 66 * We still send a 0 event out to older devices which don't 67 * have the updated device heirarchy. 68 */ 69 if (!ec_dev) { 70 dev_dbg(dev, 71 "EC device inaccessible; sending 0 event status.\n"); 72 goto send_notify; 73 } 74 75 /* Check for PD host events on EC. */ 76 ret = cros_ec_cmd(ec_dev, 0, EC_CMD_PD_HOST_EVENT_STATUS, 77 NULL, 0, &host_event_status, sizeof(host_event_status)); 78 if (ret < 0) { 79 dev_warn(dev, "Can't get host event status (err: %d)\n", ret); 80 goto send_notify; 81 } 82 83 event = host_event_status.status; 84 85 send_notify: 86 blocking_notifier_call_chain(&cros_usbpd_notifier_list, event, NULL); 87 } 88 89 #ifdef CONFIG_ACPI 90 91 static void cros_usbpd_notify_acpi(acpi_handle device, u32 event, void *data) 92 { 93 struct cros_usbpd_notify_data *pdnotify = data; 94 95 cros_usbpd_get_event_and_notify(pdnotify->dev, pdnotify->ec); 96 } 97 98 static int cros_usbpd_notify_probe_acpi(struct platform_device *pdev) 99 { 100 struct cros_usbpd_notify_data *pdnotify; 101 struct device *dev = &pdev->dev; 102 struct acpi_device *adev, *parent_adev; 103 struct cros_ec_device *ec_dev; 104 struct fwnode_handle *parent_fwnode; 105 acpi_status status; 106 107 adev = ACPI_COMPANION(dev); 108 109 pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL); 110 if (!pdnotify) 111 return -ENOMEM; 112 113 /* Get the EC device pointer needed to talk to the EC. */ 114 ec_dev = dev_get_drvdata(dev->parent); 115 if (!ec_dev) { 116 /* 117 * We continue even for older devices which don't have the 118 * correct device heirarchy, namely, GOOG0003 is a child 119 * of GOOG0004. If GOOG0003 is a child of GOOG0004 and we 120 * can't get a pointer to the Chrome EC device, defer the 121 * probe function. 122 */ 123 parent_fwnode = fwnode_get_parent(dev->fwnode); 124 if (parent_fwnode) { 125 parent_adev = to_acpi_device_node(parent_fwnode); 126 if (parent_adev && 127 acpi_dev_hid_match(parent_adev, CREC_DRV_NAME)) { 128 return -EPROBE_DEFER; 129 } 130 } 131 dev_warn(dev, "Couldn't get Chrome EC device pointer.\n"); 132 } 133 134 pdnotify->dev = dev; 135 pdnotify->ec = ec_dev; 136 137 status = acpi_install_notify_handler(adev->handle, 138 ACPI_ALL_NOTIFY, 139 cros_usbpd_notify_acpi, 140 pdnotify); 141 if (ACPI_FAILURE(status)) { 142 dev_warn(dev, "Failed to register notify handler %08x\n", 143 status); 144 return -EINVAL; 145 } 146 147 return 0; 148 } 149 150 static void cros_usbpd_notify_remove_acpi(struct platform_device *pdev) 151 { 152 struct device *dev = &pdev->dev; 153 struct acpi_device *adev = ACPI_COMPANION(dev); 154 155 acpi_remove_notify_handler(adev->handle, ACPI_ALL_NOTIFY, 156 cros_usbpd_notify_acpi); 157 } 158 159 static const struct acpi_device_id cros_usbpd_notify_acpi_device_ids[] = { 160 { ACPI_DRV_NAME, 0 }, 161 { } 162 }; 163 MODULE_DEVICE_TABLE(acpi, cros_usbpd_notify_acpi_device_ids); 164 165 static struct platform_driver cros_usbpd_notify_acpi_driver = { 166 .driver = { 167 .name = DRV_NAME_PLAT_ACPI, 168 .acpi_match_table = cros_usbpd_notify_acpi_device_ids, 169 }, 170 .probe = cros_usbpd_notify_probe_acpi, 171 .remove = cros_usbpd_notify_remove_acpi, 172 }; 173 174 #endif /* CONFIG_ACPI */ 175 176 static int cros_usbpd_notify_plat(struct notifier_block *nb, 177 unsigned long queued_during_suspend, 178 void *data) 179 { 180 struct cros_usbpd_notify_data *pdnotify = container_of(nb, 181 struct cros_usbpd_notify_data, nb); 182 struct cros_ec_device *ec_dev = (struct cros_ec_device *)data; 183 u32 host_event = cros_ec_get_host_event(ec_dev); 184 185 if (!host_event) 186 return NOTIFY_DONE; 187 188 if (host_event & (EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU) | 189 EC_HOST_EVENT_MASK(EC_HOST_EVENT_USB_MUX))) { 190 cros_usbpd_get_event_and_notify(pdnotify->dev, ec_dev); 191 return NOTIFY_OK; 192 } 193 return NOTIFY_DONE; 194 } 195 196 static int cros_usbpd_notify_probe_plat(struct platform_device *pdev) 197 { 198 struct device *dev = &pdev->dev; 199 struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent); 200 struct cros_usbpd_notify_data *pdnotify; 201 int ret; 202 203 pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL); 204 if (!pdnotify) 205 return -ENOMEM; 206 207 pdnotify->dev = dev; 208 pdnotify->ec = ecdev->ec_dev; 209 pdnotify->nb.notifier_call = cros_usbpd_notify_plat; 210 211 dev_set_drvdata(dev, pdnotify); 212 213 ret = blocking_notifier_chain_register(&ecdev->ec_dev->event_notifier, 214 &pdnotify->nb); 215 if (ret < 0) { 216 dev_err(dev, "Failed to register notifier\n"); 217 return ret; 218 } 219 220 return 0; 221 } 222 223 static void cros_usbpd_notify_remove_plat(struct platform_device *pdev) 224 { 225 struct device *dev = &pdev->dev; 226 struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent); 227 struct cros_usbpd_notify_data *pdnotify = 228 (struct cros_usbpd_notify_data *)dev_get_drvdata(dev); 229 230 blocking_notifier_chain_unregister(&ecdev->ec_dev->event_notifier, 231 &pdnotify->nb); 232 } 233 234 static const struct platform_device_id cros_usbpd_notify_id[] = { 235 { .name = DRV_NAME }, 236 { } 237 }; 238 MODULE_DEVICE_TABLE(platform, cros_usbpd_notify_id); 239 240 static struct platform_driver cros_usbpd_notify_plat_driver = { 241 .driver = { 242 .name = DRV_NAME, 243 }, 244 .probe = cros_usbpd_notify_probe_plat, 245 .remove = cros_usbpd_notify_remove_plat, 246 .id_table = cros_usbpd_notify_id, 247 }; 248 249 static int __init cros_usbpd_notify_init(void) 250 { 251 int ret; 252 253 ret = platform_driver_register(&cros_usbpd_notify_plat_driver); 254 if (ret < 0) 255 return ret; 256 257 #ifdef CONFIG_ACPI 258 ret = platform_driver_register(&cros_usbpd_notify_acpi_driver); 259 if (ret) { 260 platform_driver_unregister(&cros_usbpd_notify_plat_driver); 261 return ret; 262 } 263 #endif 264 return 0; 265 } 266 267 static void __exit cros_usbpd_notify_exit(void) 268 { 269 #ifdef CONFIG_ACPI 270 platform_driver_unregister(&cros_usbpd_notify_acpi_driver); 271 #endif 272 platform_driver_unregister(&cros_usbpd_notify_plat_driver); 273 } 274 275 module_init(cros_usbpd_notify_init); 276 module_exit(cros_usbpd_notify_exit); 277 278 MODULE_LICENSE("GPL"); 279 MODULE_DESCRIPTION("ChromeOS power delivery notifier device"); 280 MODULE_AUTHOR("Jon Flatley <jflat@chromium.org>"); 281