1ff124bbbSNeil Armstrong // SPDX-License-Identifier: GPL-2.0-only 2ff124bbbSNeil Armstrong /* 3ff124bbbSNeil Armstrong * Copyright (C) 2024 Linaro Ltd. 4ff124bbbSNeil Armstrong * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> 5ff124bbbSNeil Armstrong */ 6ff124bbbSNeil Armstrong 7ff124bbbSNeil Armstrong #include <linux/clk.h> 8ff124bbbSNeil Armstrong #include <linux/device.h> 9ff124bbbSNeil Armstrong #include <linux/mod_devicetable.h> 10ff124bbbSNeil Armstrong #include <linux/module.h> 11ff124bbbSNeil Armstrong #include <linux/of_graph.h> 12ff124bbbSNeil Armstrong #include <linux/pci-pwrctrl.h> 13ff124bbbSNeil Armstrong #include <linux/platform_device.h> 14ff124bbbSNeil Armstrong #include <linux/pwrseq/consumer.h> 15ff124bbbSNeil Armstrong #include <linux/regulator/consumer.h> 16ff124bbbSNeil Armstrong #include <linux/slab.h> 17ff124bbbSNeil Armstrong 18ff124bbbSNeil Armstrong struct slot_pwrctrl { 19ff124bbbSNeil Armstrong struct pci_pwrctrl pwrctrl; 20ff124bbbSNeil Armstrong struct regulator_bulk_data *supplies; 21ff124bbbSNeil Armstrong int num_supplies; 22ff124bbbSNeil Armstrong struct clk *clk; 23ff124bbbSNeil Armstrong struct pwrseq_desc *pwrseq; 24ff124bbbSNeil Armstrong }; 25ff124bbbSNeil Armstrong 26ff124bbbSNeil Armstrong static int slot_pwrctrl_power_on(struct pci_pwrctrl *pwrctrl) 27ff124bbbSNeil Armstrong { 28ff124bbbSNeil Armstrong struct slot_pwrctrl *slot = container_of(pwrctrl, 29ff124bbbSNeil Armstrong struct slot_pwrctrl, pwrctrl); 30ff124bbbSNeil Armstrong int ret; 31ff124bbbSNeil Armstrong 32ff124bbbSNeil Armstrong if (slot->pwrseq) { 33ff124bbbSNeil Armstrong pwrseq_power_on(slot->pwrseq); 34ff124bbbSNeil Armstrong return 0; 35ff124bbbSNeil Armstrong } 36ff124bbbSNeil Armstrong 37ff124bbbSNeil Armstrong ret = regulator_bulk_enable(slot->num_supplies, slot->supplies); 38ff124bbbSNeil Armstrong if (ret < 0) { 39ff124bbbSNeil Armstrong dev_err(slot->pwrctrl.dev, "Failed to enable slot regulators\n"); 40ff124bbbSNeil Armstrong return ret; 41ff124bbbSNeil Armstrong } 42ff124bbbSNeil Armstrong 43ff124bbbSNeil Armstrong return clk_prepare_enable(slot->clk); 44ff124bbbSNeil Armstrong } 45ff124bbbSNeil Armstrong 46ff124bbbSNeil Armstrong static int slot_pwrctrl_power_off(struct pci_pwrctrl *pwrctrl) 47ff124bbbSNeil Armstrong { 48ff124bbbSNeil Armstrong struct slot_pwrctrl *slot = container_of(pwrctrl, 49ff124bbbSNeil Armstrong struct slot_pwrctrl, pwrctrl); 50ff124bbbSNeil Armstrong 51ff124bbbSNeil Armstrong if (slot->pwrseq) { 52ff124bbbSNeil Armstrong pwrseq_power_off(slot->pwrseq); 53ff124bbbSNeil Armstrong return 0; 54ff124bbbSNeil Armstrong } 55ff124bbbSNeil Armstrong 56ff124bbbSNeil Armstrong regulator_bulk_disable(slot->num_supplies, slot->supplies); 57ff124bbbSNeil Armstrong clk_disable_unprepare(slot->clk); 58ff124bbbSNeil Armstrong 59ff124bbbSNeil Armstrong return 0; 60ff124bbbSNeil Armstrong } 61ff124bbbSNeil Armstrong 62ff124bbbSNeil Armstrong static void devm_slot_pwrctrl_release(void *data) 63ff124bbbSNeil Armstrong { 64ff124bbbSNeil Armstrong struct slot_pwrctrl *slot = data; 65ff124bbbSNeil Armstrong 66ff124bbbSNeil Armstrong regulator_bulk_free(slot->num_supplies, slot->supplies); 67ff124bbbSNeil Armstrong } 68ff124bbbSNeil Armstrong 69ff124bbbSNeil Armstrong static int slot_pwrctrl_probe(struct platform_device *pdev) 70ff124bbbSNeil Armstrong { 71ff124bbbSNeil Armstrong struct slot_pwrctrl *slot; 72ff124bbbSNeil Armstrong struct device *dev = &pdev->dev; 73ff124bbbSNeil Armstrong int ret; 74ff124bbbSNeil Armstrong 75ff124bbbSNeil Armstrong slot = devm_kzalloc(dev, sizeof(*slot), GFP_KERNEL); 76ff124bbbSNeil Armstrong if (!slot) 77ff124bbbSNeil Armstrong return -ENOMEM; 78ff124bbbSNeil Armstrong 79ff124bbbSNeil Armstrong if (of_graph_is_present(dev_of_node(dev))) { 80ff124bbbSNeil Armstrong slot->pwrseq = devm_pwrseq_get(dev, "pcie"); 81ff124bbbSNeil Armstrong if (IS_ERR(slot->pwrseq)) 82ff124bbbSNeil Armstrong return dev_err_probe(dev, PTR_ERR(slot->pwrseq), 83ff124bbbSNeil Armstrong "Failed to get the power sequencer\n"); 84ff124bbbSNeil Armstrong 85ff124bbbSNeil Armstrong goto skip_resources; 86ff124bbbSNeil Armstrong } 87ff124bbbSNeil Armstrong 88ff124bbbSNeil Armstrong ret = of_regulator_bulk_get_all(dev, dev_of_node(dev), 89ff124bbbSNeil Armstrong &slot->supplies); 900862e2b0SNeil Armstrong if (ret < 0) 910862e2b0SNeil Armstrong return dev_err_probe(dev, ret, "Failed to get slot regulators\n"); 92ff124bbbSNeil Armstrong 93ff124bbbSNeil Armstrong slot->num_supplies = ret; 94ff124bbbSNeil Armstrong 95ff124bbbSNeil Armstrong slot->clk = devm_clk_get_optional(dev, NULL); 960862e2b0SNeil Armstrong if (IS_ERR(slot->clk)) 97ff124bbbSNeil Armstrong return dev_err_probe(dev, PTR_ERR(slot->clk), 98ff124bbbSNeil Armstrong "Failed to enable slot clock\n"); 99ff124bbbSNeil Armstrong 100ff124bbbSNeil Armstrong skip_resources: 101ff124bbbSNeil Armstrong slot->pwrctrl.power_on = slot_pwrctrl_power_on; 102ff124bbbSNeil Armstrong slot->pwrctrl.power_off = slot_pwrctrl_power_off; 103ff124bbbSNeil Armstrong 104ff124bbbSNeil Armstrong ret = devm_add_action_or_reset(dev, devm_slot_pwrctrl_release, slot); 105ff124bbbSNeil Armstrong if (ret) 106ff124bbbSNeil Armstrong return ret; 107ff124bbbSNeil Armstrong 108ff124bbbSNeil Armstrong pci_pwrctrl_init(&slot->pwrctrl, dev); 109ff124bbbSNeil Armstrong 110ff124bbbSNeil Armstrong ret = devm_pci_pwrctrl_device_set_ready(dev, &slot->pwrctrl); 111ff124bbbSNeil Armstrong if (ret) 112ff124bbbSNeil Armstrong return dev_err_probe(dev, ret, "Failed to register pwrctrl driver\n"); 113ff124bbbSNeil Armstrong 114ff124bbbSNeil Armstrong return 0; 115ff124bbbSNeil Armstrong } 116ff124bbbSNeil Armstrong 117ff124bbbSNeil Armstrong static const struct of_device_id slot_pwrctrl_of_match[] = { 118ff124bbbSNeil Armstrong { 119ff124bbbSNeil Armstrong .compatible = "pciclass,0604", 120ff124bbbSNeil Armstrong }, 121*bd3622e5SNeil Armstrong /* Renesas UPD720201/UPD720202 USB 3.0 xHCI Host Controller */ 122*bd3622e5SNeil Armstrong { 123*bd3622e5SNeil Armstrong .compatible = "pci1912,0014", 124*bd3622e5SNeil Armstrong }, 125ff124bbbSNeil Armstrong { } 126ff124bbbSNeil Armstrong }; 127ff124bbbSNeil Armstrong MODULE_DEVICE_TABLE(of, slot_pwrctrl_of_match); 128ff124bbbSNeil Armstrong 129ff124bbbSNeil Armstrong static struct platform_driver slot_pwrctrl_driver = { 130ff124bbbSNeil Armstrong .driver = { 131ff124bbbSNeil Armstrong .name = "pci-pwrctrl-slot", 132ff124bbbSNeil Armstrong .of_match_table = slot_pwrctrl_of_match, 133ff124bbbSNeil Armstrong }, 134ff124bbbSNeil Armstrong .probe = slot_pwrctrl_probe, 135ff124bbbSNeil Armstrong }; 136ff124bbbSNeil Armstrong module_platform_driver(slot_pwrctrl_driver); 137ff124bbbSNeil Armstrong 138ff124bbbSNeil Armstrong MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); 139ff124bbbSNeil Armstrong MODULE_DESCRIPTION("Generic PCI Power Control driver for PCI Slots"); 140ff124bbbSNeil Armstrong MODULE_LICENSE("GPL"); 141