at v6.19 155 lines 3.7 kB view raw
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 15struct 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 21static 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 26static int 27pse_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 40static int 41pse_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 54static int 55pse_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 65static int 66pse_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 86static 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 93static int 94pse_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 137static const __maybe_unused struct of_device_id pse_reg_of_match[] = { 138 { .compatible = "podl-pse-regulator", }, 139 { }, 140}; 141MODULE_DEVICE_TABLE(of, pse_reg_of_match); 142 143static 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}; 150module_platform_driver(pse_reg_driver); 151 152MODULE_AUTHOR("Oleksij Rempel <kernel@pengutronix.de>"); 153MODULE_DESCRIPTION("regulator based Ethernet Power Sourcing Equipment"); 154MODULE_LICENSE("GPL v2"); 155MODULE_ALIAS("platform:pse-regulator");