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 goto err_regulator_free; 53 } 54 55 ret = devm_add_action_or_reset(dev, devm_pci_pwrctrl_slot_power_off, 56 slot); 57 if (ret) 58 goto err_regulator_disable; 59 60 clk = devm_clk_get_optional_enabled(dev, NULL); 61 if (IS_ERR(clk)) { 62 return dev_err_probe(dev, PTR_ERR(clk), 63 "Failed to enable slot clock\n"); 64 } 65 66 pci_pwrctrl_init(&slot->ctx, dev); 67 68 ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->ctx); 69 if (ret) 70 return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); 71 72 return 0; 73 74 err_regulator_disable: 75 regulator_bulk_disable(slot->num_supplies, slot->supplies); 76 err_regulator_free: 77 regulator_bulk_free(slot->num_supplies, slot->supplies); 78 79 return ret; 80 } 81 82 static const struct of_device_id pci_pwrctrl_slot_of_match[] = { 83 { 84 .compatible = "pciclass,0604", 85 }, 86 { } 87 }; 88 MODULE_DEVICE_TABLE(of, pci_pwrctrl_slot_of_match); 89 90 static struct platform_driver pci_pwrctrl_slot_driver = { 91 .driver = { 92 .name = "pci-pwrctrl-slot", 93 .of_match_table = pci_pwrctrl_slot_of_match, 94 }, 95 .probe = pci_pwrctrl_slot_probe, 96 }; 97 module_platform_driver(pci_pwrctrl_slot_driver); 98 99 MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 100 MODULE_DESCRIPTION("Generic PCI Power Control driver for PCI Slots"); 101 MODULE_LICENSE("GPL"); 102