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