1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Driver for the regulator based Ethernet Power Sourcing Equipment, without 4 // auto classification support. 5 // 6 // Copyright (c) 2022 Pengutronix, Oleksij Rempel <kernel@pengutronix.de> 7 // 8 9 #include <linux/module.h> 10 #include <linux/of.h> 11 #include <linux/platform_device.h> 12 #include <linux/pse-pd/pse.h> 13 #include <linux/regulator/consumer.h> 14 15 struct pse_reg_priv { 16 struct pse_controller_dev pcdev; 17 struct regulator *ps; /*power source */ 18 enum ethtool_podl_pse_admin_state admin_state; 19 }; 20 21 static struct pse_reg_priv *to_pse_reg(struct pse_controller_dev *pcdev) 22 { 23 return container_of(pcdev, struct pse_reg_priv, pcdev); 24 } 25 26 static int 27 pse_reg_pi_enable(struct pse_controller_dev *pcdev, int id) 28 { 29 struct pse_reg_priv *priv = to_pse_reg(pcdev); 30 int ret; 31 32 ret = regulator_enable(priv->ps); 33 if (ret) 34 return ret; 35 36 priv->admin_state = ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED; 37 return 0; 38 } 39 40 static int 41 pse_reg_pi_disable(struct pse_controller_dev *pcdev, int id) 42 { 43 struct pse_reg_priv *priv = to_pse_reg(pcdev); 44 int ret; 45 46 ret = regulator_disable(priv->ps); 47 if (ret) 48 return ret; 49 50 priv->admin_state = ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED; 51 return 0; 52 } 53 54 static int 55 pse_reg_pi_get_admin_state(struct pse_controller_dev *pcdev, int id, 56 struct pse_admin_state *admin_state) 57 { 58 struct pse_reg_priv *priv = to_pse_reg(pcdev); 59 60 admin_state->podl_admin_state = priv->admin_state; 61 62 return 0; 63 } 64 65 static int 66 pse_reg_pi_get_pw_status(struct pse_controller_dev *pcdev, int id, 67 struct pse_pw_status *pw_status) 68 { 69 struct pse_reg_priv *priv = to_pse_reg(pcdev); 70 int ret; 71 72 ret = regulator_is_enabled(priv->ps); 73 if (ret < 0) 74 return ret; 75 76 if (!ret) 77 pw_status->podl_pw_status = 78 ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED; 79 else 80 pw_status->podl_pw_status = 81 ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING; 82 83 return 0; 84 } 85 86 static const struct pse_controller_ops pse_reg_ops = { 87 .pi_get_admin_state = pse_reg_pi_get_admin_state, 88 .pi_get_pw_status = pse_reg_pi_get_pw_status, 89 .pi_enable = pse_reg_pi_enable, 90 .pi_disable = pse_reg_pi_disable, 91 }; 92 93 static int 94 pse_reg_probe(struct platform_device *pdev) 95 { 96 struct device *dev = &pdev->dev; 97 struct pse_reg_priv *priv; 98 int ret; 99 100 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 101 if (!priv) 102 return -ENOMEM; 103 104 if (!pdev->dev.of_node) 105 return -ENOENT; 106 107 priv->ps = devm_regulator_get_exclusive(dev, "pse"); 108 if (IS_ERR(priv->ps)) 109 return dev_err_probe(dev, PTR_ERR(priv->ps), 110 "failed to get PSE regulator.\n"); 111 112 platform_set_drvdata(pdev, priv); 113 114 ret = regulator_is_enabled(priv->ps); 115 if (ret < 0) 116 return ret; 117 118 if (ret) 119 priv->admin_state = ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED; 120 else 121 priv->admin_state = ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED; 122 123 priv->pcdev.owner = THIS_MODULE; 124 priv->pcdev.ops = &pse_reg_ops; 125 priv->pcdev.dev = dev; 126 priv->pcdev.types = ETHTOOL_PSE_PODL; 127 ret = devm_pse_controller_register(dev, &priv->pcdev); 128 if (ret) { 129 dev_err(dev, "failed to register PSE controller (%pe)\n", 130 ERR_PTR(ret)); 131 return ret; 132 } 133 134 return 0; 135 } 136 137 static const __maybe_unused struct of_device_id pse_reg_of_match[] = { 138 { .compatible = "podl-pse-regulator", }, 139 { }, 140 }; 141 MODULE_DEVICE_TABLE(of, pse_reg_of_match); 142 143 static struct platform_driver pse_reg_driver = { 144 .probe = pse_reg_probe, 145 .driver = { 146 .name = "PSE regulator", 147 .of_match_table = of_match_ptr(pse_reg_of_match), 148 }, 149 }; 150 module_platform_driver(pse_reg_driver); 151 152 MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>"); 153 MODULE_DESCRIPTION("regulator based Ethernet Power Sourcing Equipment"); 154 MODULE_LICENSE("GPL v2"); 155 MODULE_ALIAS("platform:pse-regulator"); 156