1ec2daf6eSJon Flatley // SPDX-License-Identifier: GPL-2.0-only 2ec2daf6eSJon Flatley /* 3ec2daf6eSJon Flatley * Copyright 2020 Google LLC 4ec2daf6eSJon Flatley * 5ec2daf6eSJon Flatley * This driver serves as the receiver of cros_ec PD host events. 6ec2daf6eSJon Flatley */ 7ec2daf6eSJon Flatley 8ec2daf6eSJon Flatley #include <linux/acpi.h> 9ec2daf6eSJon Flatley #include <linux/module.h> 10ec2daf6eSJon Flatley #include <linux/platform_data/cros_ec_proto.h> 11ec2daf6eSJon Flatley #include <linux/platform_data/cros_usbpd_notify.h> 12ec2daf6eSJon Flatley #include <linux/platform_device.h> 13ec2daf6eSJon Flatley 14ec2daf6eSJon Flatley #define DRV_NAME "cros-usbpd-notify" 15ec2daf6eSJon Flatley #define ACPI_DRV_NAME "GOOG0003" 16ec2daf6eSJon Flatley 17ec2daf6eSJon Flatley static BLOCKING_NOTIFIER_HEAD(cros_usbpd_notifier_list); 18ec2daf6eSJon Flatley 19f5d84a21SPrashant Malani struct cros_usbpd_notify_data { 20f5d84a21SPrashant Malani struct device *dev; 21f5d84a21SPrashant Malani struct cros_ec_device *ec; 22f5d84a21SPrashant Malani struct notifier_block nb; 23f5d84a21SPrashant Malani }; 24f5d84a21SPrashant Malani 25ec2daf6eSJon Flatley /** 26ec2daf6eSJon Flatley * cros_usbpd_register_notify - Register a notifier callback for PD events. 27ec2daf6eSJon Flatley * @nb: Notifier block pointer to register 28ec2daf6eSJon Flatley * 29ec2daf6eSJon Flatley * On ACPI platforms this corresponds to host events on the ECPD 30ec2daf6eSJon Flatley * "GOOG0003" ACPI device. On non-ACPI platforms this will filter mkbp events 31ec2daf6eSJon Flatley * for USB PD events. 32ec2daf6eSJon Flatley * 33ec2daf6eSJon Flatley * Return: 0 on success or negative error code. 34ec2daf6eSJon Flatley */ 35ec2daf6eSJon Flatley int cros_usbpd_register_notify(struct notifier_block *nb) 36ec2daf6eSJon Flatley { 37ec2daf6eSJon Flatley return blocking_notifier_chain_register(&cros_usbpd_notifier_list, 38ec2daf6eSJon Flatley nb); 39ec2daf6eSJon Flatley } 40ec2daf6eSJon Flatley EXPORT_SYMBOL_GPL(cros_usbpd_register_notify); 41ec2daf6eSJon Flatley 42ec2daf6eSJon Flatley /** 43ec2daf6eSJon Flatley * cros_usbpd_unregister_notify - Unregister notifier callback for PD events. 44ec2daf6eSJon Flatley * @nb: Notifier block pointer to unregister 45ec2daf6eSJon Flatley * 46ec2daf6eSJon Flatley * Unregister a notifier callback that was previously registered with 47ec2daf6eSJon Flatley * cros_usbpd_register_notify(). 48ec2daf6eSJon Flatley */ 49ec2daf6eSJon Flatley void cros_usbpd_unregister_notify(struct notifier_block *nb) 50ec2daf6eSJon Flatley { 51ec2daf6eSJon Flatley blocking_notifier_chain_unregister(&cros_usbpd_notifier_list, nb); 52ec2daf6eSJon Flatley } 53ec2daf6eSJon Flatley EXPORT_SYMBOL_GPL(cros_usbpd_unregister_notify); 54ec2daf6eSJon Flatley 55ec2daf6eSJon Flatley #ifdef CONFIG_ACPI 56ec2daf6eSJon Flatley 57ec2daf6eSJon Flatley static int cros_usbpd_notify_add_acpi(struct acpi_device *adev) 58ec2daf6eSJon Flatley { 59ec2daf6eSJon Flatley return 0; 60ec2daf6eSJon Flatley } 61ec2daf6eSJon Flatley 62ec2daf6eSJon Flatley static void cros_usbpd_notify_acpi(struct acpi_device *adev, u32 event) 63ec2daf6eSJon Flatley { 64ec2daf6eSJon Flatley blocking_notifier_call_chain(&cros_usbpd_notifier_list, event, NULL); 65ec2daf6eSJon Flatley } 66ec2daf6eSJon Flatley 67ec2daf6eSJon Flatley static const struct acpi_device_id cros_usbpd_notify_acpi_device_ids[] = { 68ec2daf6eSJon Flatley { ACPI_DRV_NAME, 0 }, 69ec2daf6eSJon Flatley { } 70ec2daf6eSJon Flatley }; 71ec2daf6eSJon Flatley MODULE_DEVICE_TABLE(acpi, cros_usbpd_notify_acpi_device_ids); 72ec2daf6eSJon Flatley 73ec2daf6eSJon Flatley static struct acpi_driver cros_usbpd_notify_acpi_driver = { 74ec2daf6eSJon Flatley .name = DRV_NAME, 75ec2daf6eSJon Flatley .class = DRV_NAME, 76ec2daf6eSJon Flatley .ids = cros_usbpd_notify_acpi_device_ids, 77ec2daf6eSJon Flatley .ops = { 78ec2daf6eSJon Flatley .add = cros_usbpd_notify_add_acpi, 79ec2daf6eSJon Flatley .notify = cros_usbpd_notify_acpi, 80ec2daf6eSJon Flatley }, 81ec2daf6eSJon Flatley }; 82ec2daf6eSJon Flatley 83ec2daf6eSJon Flatley #endif /* CONFIG_ACPI */ 84ec2daf6eSJon Flatley 85ec2daf6eSJon Flatley static int cros_usbpd_notify_plat(struct notifier_block *nb, 86ec2daf6eSJon Flatley unsigned long queued_during_suspend, 87ec2daf6eSJon Flatley void *data) 88ec2daf6eSJon Flatley { 89ec2daf6eSJon Flatley struct cros_ec_device *ec_dev = (struct cros_ec_device *)data; 90ec2daf6eSJon Flatley u32 host_event = cros_ec_get_host_event(ec_dev); 91ec2daf6eSJon Flatley 92ec2daf6eSJon Flatley if (!host_event) 9392e399c0SGwendal Grignou return NOTIFY_DONE; 94ec2daf6eSJon Flatley 95ec2daf6eSJon Flatley if (host_event & EC_HOST_EVENT_MASK(EC_HOST_EVENT_PD_MCU)) { 96ec2daf6eSJon Flatley blocking_notifier_call_chain(&cros_usbpd_notifier_list, 97ec2daf6eSJon Flatley host_event, NULL); 98ec2daf6eSJon Flatley return NOTIFY_OK; 99ec2daf6eSJon Flatley } 100ec2daf6eSJon Flatley return NOTIFY_DONE; 101ec2daf6eSJon Flatley } 102ec2daf6eSJon Flatley 103ec2daf6eSJon Flatley static int cros_usbpd_notify_probe_plat(struct platform_device *pdev) 104ec2daf6eSJon Flatley { 105ec2daf6eSJon Flatley struct device *dev = &pdev->dev; 106ec2daf6eSJon Flatley struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent); 107f5d84a21SPrashant Malani struct cros_usbpd_notify_data *pdnotify; 108ec2daf6eSJon Flatley int ret; 109ec2daf6eSJon Flatley 110f5d84a21SPrashant Malani pdnotify = devm_kzalloc(dev, sizeof(*pdnotify), GFP_KERNEL); 111f5d84a21SPrashant Malani if (!pdnotify) 112ec2daf6eSJon Flatley return -ENOMEM; 113ec2daf6eSJon Flatley 114f5d84a21SPrashant Malani pdnotify->dev = dev; 115f5d84a21SPrashant Malani pdnotify->ec = ecdev->ec_dev; 116f5d84a21SPrashant Malani pdnotify->nb.notifier_call = cros_usbpd_notify_plat; 117f5d84a21SPrashant Malani 118f5d84a21SPrashant Malani dev_set_drvdata(dev, pdnotify); 119ec2daf6eSJon Flatley 120ec2daf6eSJon Flatley ret = blocking_notifier_chain_register(&ecdev->ec_dev->event_notifier, 121f5d84a21SPrashant Malani &pdnotify->nb); 122ec2daf6eSJon Flatley if (ret < 0) { 123ec2daf6eSJon Flatley dev_err(dev, "Failed to register notifier\n"); 124ec2daf6eSJon Flatley return ret; 125ec2daf6eSJon Flatley } 126ec2daf6eSJon Flatley 127ec2daf6eSJon Flatley return 0; 128ec2daf6eSJon Flatley } 129ec2daf6eSJon Flatley 130ec2daf6eSJon Flatley static int cros_usbpd_notify_remove_plat(struct platform_device *pdev) 131ec2daf6eSJon Flatley { 132ec2daf6eSJon Flatley struct device *dev = &pdev->dev; 133ec2daf6eSJon Flatley struct cros_ec_dev *ecdev = dev_get_drvdata(dev->parent); 134f5d84a21SPrashant Malani struct cros_usbpd_notify_data *pdnotify = 135f5d84a21SPrashant Malani (struct cros_usbpd_notify_data *)dev_get_drvdata(dev); 136ec2daf6eSJon Flatley 137f5d84a21SPrashant Malani blocking_notifier_chain_unregister(&ecdev->ec_dev->event_notifier, 138f5d84a21SPrashant Malani &pdnotify->nb); 139ec2daf6eSJon Flatley 140ec2daf6eSJon Flatley return 0; 141ec2daf6eSJon Flatley } 142ec2daf6eSJon Flatley 143ec2daf6eSJon Flatley static struct platform_driver cros_usbpd_notify_plat_driver = { 144ec2daf6eSJon Flatley .driver = { 145ec2daf6eSJon Flatley .name = DRV_NAME, 146ec2daf6eSJon Flatley }, 147ec2daf6eSJon Flatley .probe = cros_usbpd_notify_probe_plat, 148ec2daf6eSJon Flatley .remove = cros_usbpd_notify_remove_plat, 149ec2daf6eSJon Flatley }; 150ec2daf6eSJon Flatley 151ec2daf6eSJon Flatley static int __init cros_usbpd_notify_init(void) 152ec2daf6eSJon Flatley { 153ec2daf6eSJon Flatley int ret; 154ec2daf6eSJon Flatley 155ec2daf6eSJon Flatley ret = platform_driver_register(&cros_usbpd_notify_plat_driver); 156ec2daf6eSJon Flatley if (ret < 0) 157ec2daf6eSJon Flatley return ret; 158ec2daf6eSJon Flatley 159ec2daf6eSJon Flatley #ifdef CONFIG_ACPI 160ec2daf6eSJon Flatley acpi_bus_register_driver(&cros_usbpd_notify_acpi_driver); 161ec2daf6eSJon Flatley #endif 162ec2daf6eSJon Flatley return 0; 163ec2daf6eSJon Flatley } 164ec2daf6eSJon Flatley 165ec2daf6eSJon Flatley static void __exit cros_usbpd_notify_exit(void) 166ec2daf6eSJon Flatley { 167ec2daf6eSJon Flatley #ifdef CONFIG_ACPI 168ec2daf6eSJon Flatley acpi_bus_unregister_driver(&cros_usbpd_notify_acpi_driver); 169ec2daf6eSJon Flatley #endif 170ec2daf6eSJon Flatley platform_driver_unregister(&cros_usbpd_notify_plat_driver); 171ec2daf6eSJon Flatley } 172ec2daf6eSJon Flatley 173ec2daf6eSJon Flatley module_init(cros_usbpd_notify_init); 174ec2daf6eSJon Flatley module_exit(cros_usbpd_notify_exit); 175ec2daf6eSJon Flatley 176ec2daf6eSJon Flatley MODULE_LICENSE("GPL"); 177ec2daf6eSJon Flatley MODULE_DESCRIPTION("ChromeOS power delivery notifier device"); 178ec2daf6eSJon Flatley MODULE_AUTHOR("Jon Flatley <jflat@chromium.org>"); 179ec2daf6eSJon Flatley MODULE_ALIAS("platform:" DRV_NAME); 180