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_ethtool_set_config(struct pse_controller_dev *pcdev, unsigned long id, 28 struct netlink_ext_ack *extack, 29 const struct pse_control_config *config) 30 { 31 struct pse_reg_priv *priv = to_pse_reg(pcdev); 32 int ret; 33 34 if (priv->admin_state == config->podl_admin_control) 35 return 0; 36 37 switch (config->podl_admin_control) { 38 case ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED: 39 ret = regulator_enable(priv->ps); 40 break; 41 case ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED: 42 ret = regulator_disable(priv->ps); 43 break; 44 default: 45 dev_err(pcdev->dev, "Unknown admin state %i\n", 46 config->podl_admin_control); 47 ret = -ENOTSUPP; 48 } 49 50 if (ret) 51 return ret; 52 53 priv->admin_state = config->podl_admin_control; 54 55 return 0; 56 } 57 58 static int 59 pse_reg_ethtool_get_status(struct pse_controller_dev *pcdev, unsigned long id, 60 struct netlink_ext_ack *extack, 61 struct pse_control_status *status) 62 { 63 struct pse_reg_priv *priv = to_pse_reg(pcdev); 64 int ret; 65 66 ret = regulator_is_enabled(priv->ps); 67 if (ret < 0) 68 return ret; 69 70 if (!ret) 71 status->podl_pw_status = ETHTOOL_PODL_PSE_PW_D_STATUS_DISABLED; 72 else 73 status->podl_pw_status = 74 ETHTOOL_PODL_PSE_PW_D_STATUS_DELIVERING; 75 76 status->podl_admin_state = priv->admin_state; 77 78 return 0; 79 } 80 81 static const struct pse_controller_ops pse_reg_ops = { 82 .ethtool_get_status = pse_reg_ethtool_get_status, 83 .ethtool_set_config = pse_reg_ethtool_set_config, 84 }; 85 86 static int 87 pse_reg_probe(struct platform_device *pdev) 88 { 89 struct device *dev = &pdev->dev; 90 struct pse_reg_priv *priv; 91 int ret; 92 93 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 94 if (!priv) 95 return -ENOMEM; 96 97 if (!pdev->dev.of_node) 98 return -ENOENT; 99 100 priv->ps = devm_regulator_get_exclusive(dev, "pse"); 101 if (IS_ERR(priv->ps)) 102 return dev_err_probe(dev, PTR_ERR(priv->ps), 103 "failed to get PSE regulator.\n"); 104 105 platform_set_drvdata(pdev, priv); 106 107 ret = regulator_is_enabled(priv->ps); 108 if (ret < 0) 109 return ret; 110 111 if (ret) 112 priv->admin_state = ETHTOOL_PODL_PSE_ADMIN_STATE_ENABLED; 113 else 114 priv->admin_state = ETHTOOL_PODL_PSE_ADMIN_STATE_DISABLED; 115 116 priv->pcdev.owner = THIS_MODULE; 117 priv->pcdev.ops = &pse_reg_ops; 118 priv->pcdev.dev = dev; 119 priv->pcdev.types = ETHTOOL_PSE_PODL; 120 ret = devm_pse_controller_register(dev, &priv->pcdev); 121 if (ret) { 122 dev_err(dev, "failed to register PSE controller (%pe)\n", 123 ERR_PTR(ret)); 124 return ret; 125 } 126 127 return 0; 128 } 129 130 static const __maybe_unused struct of_device_id pse_reg_of_match[] = { 131 { .compatible = "podl-pse-regulator", }, 132 { }, 133 }; 134 MODULE_DEVICE_TABLE(of, pse_reg_of_match); 135 136 static struct platform_driver pse_reg_driver = { 137 .probe = pse_reg_probe, 138 .driver = { 139 .name = "PSE regulator", 140 .of_match_table = of_match_ptr(pse_reg_of_match), 141 }, 142 }; 143 module_platform_driver(pse_reg_driver); 144 145 MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>"); 146 MODULE_DESCRIPTION("regulator based Ethernet Power Sourcing Equipment"); 147 MODULE_LICENSE("GPL v2"); 148 MODULE_ALIAS("platform:pse-regulator"); 149