1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2024 Linaro Ltd. 4 * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 5 */ 6 7 #include <linux/clk.h> 8 #include <linux/device.h> 9 #include <linux/mod_devicetable.h> 10 #include <linux/module.h> 11 #include <linux/pci-pwrctrl.h> 12 #include <linux/platform_device.h> 13 #include <linux/regulator/consumer.h> 14 #include <linux/slab.h> 15 16 struct pci_pwrctrl_slot_data { 17 struct pci_pwrctrl ctx; 18 struct regulator_bulk_data *supplies; 19 int num_supplies; 20 }; 21 22 static void devm_pci_pwrctrl_slot_power_off(void *data) 23 { 24 struct pci_pwrctrl_slot_data *slot = data; 25 26 regulator_bulk_disable(slot->num_supplies, slot->supplies); 27 regulator_bulk_free(slot->num_supplies, slot->supplies); 28 } 29 30 static int pci_pwrctrl_slot_probe(struct platform_device *pdev) 31 { 32 struct pci_pwrctrl_slot_data *slot; 33 struct device *dev = &pdev->dev; 34 struct clk *clk; 35 int ret; 36 37 slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL); 38 if (!slot) 39 return -ENOMEM; 40 41 ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), 42 &slot->supplies); 43 if (ret < 0) { 44 dev_err_probe(dev, ret, "Failed to get slot regulators\n"); 45 return ret; 46 } 47 48 slot->num_supplies = ret; 49 ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); 50 if (ret < 0) { 51 dev_err_probe(dev, ret, "Failed to enable slot regulators\n"); 52 regulator_bulk_free(slot->num_supplies, slot->supplies); 53 return ret; 54 } 55 56 ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off, 57 slot); 58 if (ret) 59 return ret; 60 61 clk = devm_clk_get_optional_enabled(dev, NULL); 62 if (IS_ERR(clk)) { 63 return dev_err_probe(dev, PTR_ERR(clk), 64 "Failed to enable slot clock\n"); 65 } 66 67 pci_pwrctrl_init(&slot->ctx, dev); 68 69 ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->ctx); 70 if (ret) 71 return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); 72 73 return 0; 74 } 75 76 static const struct of_device_id pci_pwrctrl_slot_of_match[] = { 77 { 78 .compatible = "pciclass,0604", 79 }, 80 { } 81 }; 82 MODULE_DEVICE_TABLE(of, pci_pwrctrl_slot_of_match); 83 84 static struct platform_driver pci_pwrctrl_slot_driver = { 85 .driver = { 86 .name = "pci-pwrctrl-slot", 87 .of_match_table = pci_pwrctrl_slot_of_match, 88 }, 89 .probe = pci_pwrctrl_slot_probe, 90 }; 91 module_platform_driver(pci_pwrctrl_slot_driver); 92 93 MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 94 MODULE_DESCRIPTION("Generic PCI Power Control driver for PCI Slots"); 95 MODULE_LICENSE("GPL"); 96