1 // SPDX-License-Identifier: GPL-2.0-only OR BSD-3-Clause 2 3 /* 4 * Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES. 5 */ 6 7 #include <linux/acpi.h> 8 #include <linux/device.h> 9 #include <linux/devm-helpers.h> 10 #include <linux/interrupt.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/platform_device.h> 14 #include <linux/pm.h> 15 #include <linux/reboot.h> 16 #include <linux/types.h> 17 18 struct pwr_mlxbf { 19 struct work_struct reboot_work; 20 const char *hid; 21 }; 22 23 static void pwr_mlxbf_reboot_work(struct work_struct *work) 24 { 25 acpi_bus_generate_netlink_event("button/reboot.*", "Reboot Button", 0x80, 1); 26 } 27 28 static irqreturn_t pwr_mlxbf_irq(int irq, void *ptr) 29 { 30 const char *rst_pwr_hid = "MLNXBF24"; 31 const char *shutdown_hid = "MLNXBF29"; 32 struct pwr_mlxbf *priv = ptr; 33 34 if (!strncmp(priv->hid, rst_pwr_hid, 8)) 35 schedule_work(&priv->reboot_work); 36 37 if (!strncmp(priv->hid, shutdown_hid, 8)) 38 orderly_poweroff(true); 39 40 return IRQ_HANDLED; 41 } 42 43 static int pwr_mlxbf_probe(struct platform_device *pdev) 44 { 45 struct device *dev = &pdev->dev; 46 struct acpi_device *adev; 47 struct pwr_mlxbf *priv; 48 const char *hid; 49 int irq, err; 50 51 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 52 if (!priv) 53 return -ENOMEM; 54 55 adev = ACPI_COMPANION(dev); 56 if (!adev) 57 return -ENXIO; 58 59 hid = acpi_device_hid(adev); 60 priv->hid = hid; 61 62 irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); 63 if (irq < 0) 64 return dev_err_probe(dev, irq, "Error getting %s irq.\n", priv->hid); 65 66 err = devm_work_autocancel(dev, &priv->reboot_work, pwr_mlxbf_reboot_work); 67 if (err) 68 return err; 69 70 err = devm_request_irq(dev, irq, pwr_mlxbf_irq, 0, hid, priv); 71 72 return err; 73 } 74 75 static const struct acpi_device_id __maybe_unused pwr_mlxbf_acpi_match[] = { 76 { "MLNXBF24", 0 }, 77 { "MLNXBF29", 0 }, 78 {}, 79 }; 80 MODULE_DEVICE_TABLE(acpi, pwr_mlxbf_acpi_match); 81 82 static struct platform_driver pwr_mlxbf_driver = { 83 .driver = { 84 .name = "pwr_mlxbf", 85 .acpi_match_table = pwr_mlxbf_acpi_match, 86 }, 87 .probe = pwr_mlxbf_probe, 88 }; 89 90 module_platform_driver(pwr_mlxbf_driver); 91 92 MODULE_DESCRIPTION("Mellanox BlueField power driver"); 93 MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>"); 94 MODULE_LICENSE("Dual BSD/GPL"); 95