lkml.org 
[lkml]   [2023]   [Sep]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
SubjectRe: [PATCH 3/4] net: phy: Add GPIO and DT support to NCN26000
From
On 18/09/2023 07:59, Jay Monkman wrote:
>
> This adds GPIO support and devicetree configuration for
> the NCN26000 PHY.
>
> Signed-off-by: Jay Monkman <jtm@lopingdog.com>
> ---
> drivers/net/phy/ncn26000.c | 467 ++++++++++++++++++++++++++++++++++++-
> 1 file changed, 459 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/net/phy/ncn26000.c b/drivers/net/phy/ncn26000.c
> index 5680584f659e..d89cbac6f8e3 100644
> --- a/drivers/net/phy/ncn26000.c
> +++ b/drivers/net/phy/ncn26000.c
> @@ -7,17 +7,32 @@
> #include <linux/kernel.h>
> #include <linux/bitfield.h>
> #include <linux/errno.h>
> +#include <linux/gpio/driver.h>
> #include <linux/init.h>
> #include <linux/module.h>
> #include <linux/mii.h>
> #include <linux/phy.h>
> +#include <linux/property.h>
>
> #include "mdio-open-alliance.h"
>
> #define PHY_ID_NCN26000 0x180FF5A1
>
> +#define TO_TMR_DEFAULT 32
> +
> #define NCN26000_REG_IRQ_CTL 16
> #define NCN26000_REG_IRQ_STATUS 17
> +#define NCN26000_REG_DIO_CONFIG 18
> +
> +// clause 45 vendor specific registers
> +#define NCN26000_REG_PHYCFG1_MMD MDIO_MMD_VEND2
> +#define NCN26000_REG_PHYCFG1 0x8001
> +
> +#define NCN26000_REG_PLCAEXT_MMD MDIO_MMD_VEND2
> +#define NCN26000_REG_PLCAEXT 0x8002
> +
> +#define NCN26000_REG_TWEAKS_MMD MDIO_MMD_VEND1
> +#define NCN26000_REG_TWEAKS 0x1001
>
> // the NCN26000 maps link_ctrl to BMCR_ANENABLE
> #define NCN26000_BCMR_LINK_CTRL_BIT BMCR_ANENABLE
> @@ -33,17 +48,392 @@
> #define NCN26000_IRQ_PHYSCOL_BIT BIT(5)
> #define NCN26000_IRQ_RESET_BIT BIT(15)
>
> -#define TO_TMR_DEFAULT 32
> +#define NCN26000_DIO_FN_DISABLE 0x0
> +#define NCN26000_DIO_FN_GPIO 0x1
> +#define NCN26000_DIO_FN_SFD_TX 0x2
> +#define NCN26000_DIO_FN_SFD_RX 0x3
> +#define NCN26000_DIO_FN_LED_LINK 0x4
> +#define NCN26000_DIO_FN_LED_PLCA 0x5
> +#define NCN26000_DIO_FN_LED_TX 0x6
> +#define NCN26000_DIO_FN_LED_RX 0x7
> +#define NCN26000_DIO_FN_CLK25M 0x8
> +#define NCN26000_DIO_FN_SFD_RXTX 0xb
> +#define NCN26000_DIO_FN_LED_RXTX 0xf
> +
> +#define NCN26000_DIO_CFG_SLEW_RATE1 BIT(15)
> +#define NCN26000_DIO_CFG_PULL_EN1 BIT(14)
> +#define NCN26000_DIO_CFG_PULL_DIR1 BIT(13)
> +#define NCN26000_DIO_CFG_FN1(x) ((x) << 9)
> +#define NCN26000_DIO_CFG_VAL1 BIT(8)
> +#define NCN26000_DIO_CFG_SLEW_RATE0 BIT(7)
> +#define NCN26000_DIO_CFG_PULL_EN0 BIT(6)
> +#define NCN26000_DIO_CFG_PULL_DIR0 BIT(5)
> +#define NCN26000_DIO_CFG_FN0(x) ((x) << 1)
> +#define NCN26000_DIO_CFG_VAL0 BIT(0)
> +
> +#define NCN26000_PHYCFG1_PKT_LOOP BIT(15)
> +#define NCN26000_PHYCFG1_ENI BIT(7)
> +#define NCN26000_PHYCFG1_UNJAB_TMR BIT(6)
> +#define NCN26000_PHYCFG1_NO_COL_MASK BIT(1)
> +#define NCN26000_PHYCFG1_RX_DLY BIT(0)
> +
> +#define NCN26000_PLCAEXT_PRECEDENCE BIT(15)
> +#define NCN26000_PLCAEXT_MIIEXTDIS BIT(11)
> +
> +#define NCN26000_TWEAKS_TX_GAIN(x) ((x) << 14)
> +#define NCN26000_TWEAKS_CD_THRESH(x) ((x) << 10)
> +#define NCN26000_TWEAKS_ED_THRESH(x) ((x) << 6)
> +#define NCN26000_TWEAKS_DIG_SLEW BIT(5)
> +#define NCN26000_TWEAKS_CMC_COMP(x) ((x) << 3)
> +#define NCN26000_TWEAKS_TX_SLEW BIT(2)
> +
> +#define NCN26000_TX_GAIN_1V0 0
> +#define NCN26000_TX_GAIN_1V1 1
> +#define NCN26000_TX_GAIN_0V9 2
> +#define NCN26000_TX_GAIN_0V8 3
> +#define NCN26000_CD_THRESH_DEFAULT 11
> +#define NCN26000_ED_THRESH_DEFAULT 2
> +#define NCN26000_DIG_SLEW_FAST 1
> +#define NCN26000_DIG_SLEW_SLOW 0
> +#define NCN26000_CMC_COMP_0P25 0
> +#define NCN26000_CMC_COMP_1P37 1
> +#define NCN26000_CMC_COMP_3P00 2
> +#define NCN26000_CMC_COMP_4P37 3
> +#define NCN26000_TX_SLEW_FAST 1
> +#define NCN26000_TX_SLEW_SLOW 0
> +
> +struct ncn26000_priv {
> + struct device *dev;
> + struct phy_device *phydev;
> + struct gpio_chip gpio_chip;
> + unsigned int gpiomask;
> + u16 diocfg;
> + u16 phycfg0;
> + u16 plcaext;
> + u16 tweaks;
> +
> + enum {
> + ENI_AUTO = 0,
> + ENI_FORCE_ON = 1,
> + ENI_FORCE_OFF = 2
> + } eni_mode;
> +};
> +
> +static int ncn26000_gpio_request(struct gpio_chip *gc, unsigned int offset)
> +{
> + struct ncn26000_priv *priv = gpiochip_get_data(gc);
> +
> + if (offset > 2)
> + return -ENODEV;
> +
> + if (priv->gpiomask & (1 << offset))

it's better to use BIT(offset) here

> + return 0;
> +
> + return -EBUSY;
> +}
> +
> +static void ncn26000_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
> +{
> + struct ncn26000_priv *priv = gpiochip_get_data(gc);
> + u32 dio_reg;
> +
> + dio_reg = phy_read(priv->phydev, NCN26000_REG_DIO_CONFIG);
> +
> + switch (offset) {
> + case 0:
> + if (!val == !(priv->diocfg & NCN26000_DIO_CFG_VAL0))

val == !!(priv->diocfg & NCN26000_DIO_CFG_VAL0)

> + dio_reg |= NCN26000_DIO_CFG_VAL0;
> + else
> + dio_reg &= ~NCN26000_DIO_CFG_VAL0;
> + break;
> +
> + case 1:
> + if (!val == !(priv->diocfg & NCN26000_DIO_CFG_VAL1))

val == !!(priv->diocfg & NCN26000_DIO_CFG_VAL1)

> + dio_reg |= NCN26000_DIO_CFG_VAL1;
> + else
> + dio_reg &= ~NCN26000_DIO_CFG_VAL1;
> + break;
> +
> + default:
> + dev_err(priv->dev, "invalid GPIO offset: %d\n", offset);
> + return;
> + }
> +
> + phy_write(priv->phydev, NCN26000_REG_DIO_CONFIG, dio_reg);
> +}
> +
> +static int ncn26000_gpio_get_dir(struct gpio_chip *gc, unsigned int offset)
> +{
> + return GPIO_LINE_DIRECTION_OUT;
> +}
> +
> +static int ncn26000_gpio_dir_out(struct gpio_chip *gc, unsigned int offset,
> + int val)
> +{
> + ncn26000_gpio_set(gc, offset, val);
> + return 0;
> +}
> +
> +static int ncn26000_gpio_setup(struct ncn26000_priv *priv)
> +{
> + struct gpio_chip *gc = &priv->gpio_chip;
> +
> + gc->request = ncn26000_gpio_request;
> + gc->get_direction = ncn26000_gpio_get_dir;
> + gc->direction_output = ncn26000_gpio_dir_out;
> + gc->set = ncn26000_gpio_set;
> + gc->label = "ncn26000-gpio";
> + gc->base = -1;
> + gc->ngpio = 2;
> + gc->parent = priv->dev;
> + gc->owner = THIS_MODULE;
> +
> + return devm_gpiochip_add_data(priv->dev, gc, priv);
> +}
> +
> +static void ncn26000_tweaks_config(struct ncn26000_priv *priv)
> +{
> + u16 val = NCN26000_TWEAKS_CD_THRESH(NCN26000_CD_THRESH_DEFAULT) |
> + NCN26000_TWEAKS_ED_THRESH(NCN26000_ED_THRESH_DEFAULT) |
> + NCN26000_DIG_SLEW_FAST;
> +
> + struct device *dev = &priv->phydev->mdio.dev;
> + const char *s;
> + int ret;
> +
> + ret = device_property_read_string(dev, "tx-gain", &s);
> + if (!ret) {
> + dev_info(dev, "tx-gain = %s\n", s);
> + if (strcmp(s, "1v1") == 0)
> + val |= NCN26000_TWEAKS_TX_GAIN(NCN26000_TX_GAIN_1V1);
> + else if (strcmp(s, "0v9") == 0)
> + val |= NCN26000_TWEAKS_TX_GAIN(NCN26000_TX_GAIN_0V9);
> + else if (strcmp(s, "0v8") == 0)
> + val |= NCN26000_TWEAKS_TX_GAIN(NCN26000_TX_GAIN_0V8);
> + else if (strcmp(s, "1v0") != 0)
> + dev_err(dev, "tx-gain is invalid: %s\n", s);
> + }
> +
> + ret = device_property_read_string(dev, "tx-slew", &s);
> + if (!ret) {
> + dev_info(dev, "tx-slew = %s\n", s);
> + if (strcmp(s, "fast") == 0)
> + val |= NCN26000_TX_SLEW_FAST;
> + else if (strcmp(s, "slow") != 0)
> + dev_err(dev, "tx-slew is invalid: %s\n", s);
> + }
> +
> + ret = device_property_read_string(dev, "dig-slew", &s);
> + if (!ret) {
> + dev_info(dev, "dig-slew = %s\n", s);
> + if (strcmp(s, "slow") == 0)
> + val &= ~NCN26000_DIG_SLEW_FAST;
> + else if (strcmp(s, "fast") != 0)
> + dev_err(dev, "dig-slew is invalid: %s\n", s);
> + }
> +
> + ret = device_property_read_string(dev, "cmc-comp", &s);
> + if (!ret) {
> + dev_info(dev, "cmc-comp = %s\n", s);
> + if (strcmp(s, "1p37") == 0)
> + val |= NCN26000_TWEAKS_CMC_COMP(NCN26000_CMC_COMP_1P37);
> + else if (strcmp(s, "3p00") == 0)
> + val |= NCN26000_TWEAKS_CMC_COMP(NCN26000_CMC_COMP_3P00);
> + else if (strcmp(s, "4p37") == 0)
> + val |= NCN26000_TWEAKS_CMC_COMP(NCN26000_CMC_COMP_4P37);
> + else if (strcmp(s, "0p25") != 0)
> + dev_err(dev, "cmc-comp is invalid: %s\n", s);
> + }
> +
> + priv->tweaks = val;
> +}
> +
> +static void ncn26000_plcaext_config(struct ncn26000_priv *priv)
> +{
> + u16 val = NCN26000_PLCAEXT_MIIEXTDIS;
> +
> + if (device_property_read_bool(priv->dev, "plca-precedence")) {
> + dev_info(priv->dev, "PLCA precedence mode enabled\n");
> + val |= NCN26000_PLCAEXT_PRECEDENCE;
> + }
> +
> + priv->plcaext = val;
> +}
> +
> +static void ncn26000_phycfg0_config(struct ncn26000_priv *priv)
> +{
> + u16 val = NCN26000_PHYCFG1_RX_DLY | NCN26000_PHYCFG1_NO_COL_MASK |
> + NCN26000_PHYCFG1_UNJAB_TMR;
> +
> + struct device *dev = &priv->phydev->mdio.dev;
> + const char *s;
> + int ret;
> +
> + priv->eni_mode = ENI_AUTO;
> + ret = device_property_read_string(dev, "eni-mode", &s);
> + if (!ret) {
> + dev_info(dev, "eni-mode = %s\n", s);
> + if (strcmp(s, "force-on") == 0) {
> + priv->eni_mode = ENI_FORCE_ON;
> + val |= NCN26000_PHYCFG1_ENI;
> + } else if (strcmp(s, "force-off") == 0) {
> + priv->eni_mode = ENI_FORCE_OFF;
> + } else if (strcmp(s, "auto") != 0) {
> + dev_err(dev, "eni-mode is invalid: %s\n", s);
> + }
> + }
> +
> + if (device_property_read_bool(priv->dev, "tx-pkt-loop")) {
> + dev_info(priv->dev, "TX packet loop enabled\n");
> + val |= NCN26000_PHYCFG1_PKT_LOOP;
> + }
> +
> + if (device_property_read_bool(priv->dev, "unjab-tmr-disable")) {
> + dev_info(priv->dev, "unjab timer disabled\n");
> + val &= ~NCN26000_PHYCFG1_UNJAB_TMR;
> + }
> +
> + if (device_property_read_bool(priv->dev, "col-disable")) {
> + dev_info(priv->dev, "ENI collision detect disabled\n");
> + val &= ~NCN26000_PHYCFG1_NO_COL_MASK;
> + }
> +
> + if (device_property_read_bool(priv->dev, "no-rx-delay")) {
> + dev_info(priv->dev, "RX delay disabled\n");
> + val &= ~NCN26000_PHYCFG1_RX_DLY;
> + }
> +
> + priv->phycfg0 = val;
> +}
> +
> +static void ncn26000_dio_config(struct ncn26000_priv *priv)
> +{
> + struct device *dev = &priv->phydev->mdio.dev;
> + const char *s;
> + u16 val = 0;
> + int ret;
> +
> + ret = device_property_read_string(dev, "dio0-fn", &s);
> + if (!ret) {
> + dev_info(dev, "dio0-fn = %s\n", s);
> + if (strcmp(s, "sfd-tx") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_SFD_TX);
> + else if (strcmp(s, "sfd-rx") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_SFD_RX);
> + else if (strcmp(s, "sfd-rxtx") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_SFD_RXTX);
> + else if (strcmp(s, "led-link") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_LED_LINK);
> + else if (strcmp(s, "led-plca") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_LED_PLCA);
> + else if (strcmp(s, "led-tx") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_LED_TX);
> + else if (strcmp(s, "led-rx") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_LED_RX);
> + else if (strcmp(s, "led-rxtx") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_LED_RXTX);
> + else if (strcmp(s, "clk25m") == 0)
> + val |= NCN26000_DIO_CFG_FN0(NCN26000_DIO_FN_CLK25M);
> + else
> + dev_err(dev, "dio0-fn is invalid: %s\n", s);
> + }
> +
> + if (device_property_read_bool(dev, "dio0-pullup"))
> + val |= NCN26000_DIO_CFG_PULL_EN0;
> +
> + if (device_property_read_bool(dev, "dio0-active-high"))
> + val |= NCN26000_DIO_CFG_VAL0;
> +
> + ret = device_property_read_string(dev, "dio0-slew", &s);
> + if (!ret) {
> + dev_info(dev, "dio0-slew = %s\n", s);
> + if (strcmp(s, "slow") == 0)
> + val |= NCN26000_DIO_CFG_SLEW_RATE0;
> + else if (strcmp(s, "fast") != 0)
> + dev_err(dev, "dio0-slew is invalid: %s\n", s);
> + }
> +
> + ret = device_property_read_string(dev, "dio1-fn", &s);
> + if (!ret) {
> + dev_info(dev, "dio1-fn = %s\n", s);
> + if (strcmp(s, "sfd-tx") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_SFD_TX);
> + else if (strcmp(s, "sfd-rx") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_SFD_RX);
> + else if (strcmp(s, "sfd-rxtx") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_SFD_RXTX);
> + else if (strcmp(s, "led-link") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_LED_LINK);
> + else if (strcmp(s, "led-plca") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_LED_PLCA);
> + else if (strcmp(s, "led-tx") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_LED_TX);
> + else if (strcmp(s, "led-rx") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_LED_RX);
> + else if (strcmp(s, "led-rxtx") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_LED_RXTX);
> + else if (strcmp(s, "clk25m") == 0)
> + val |= NCN26000_DIO_CFG_FN1(NCN26000_DIO_FN_CLK25M);
> + else
> + dev_err(dev, "dio1-fn is invalid: %s\n", s);
> + }
> +
> + if (device_property_read_bool(dev, "dio1-pullup"))
> + val |= NCN26000_DIO_CFG_PULL_EN1;
> +
> + if (device_property_read_bool(dev, "dio1-active-high"))
> + val |= NCN26000_DIO_CFG_VAL1;
> +
> + ret = device_property_read_string(dev, "dio1-slew", &s);
> + if (!ret) {
> + dev_info(dev, "dio1-slew = %s\n", s);
> + if (strcmp(s, "slow") == 0)
> + val |= NCN26000_DIO_CFG_SLEW_RATE1;
> + else if (strcmp(s, "fast") != 0)
> + dev_err(dev, "dio1-slew is invalid: %s\n", s);
> + }
> +
> + priv->diocfg = val;
> +}
>
> static int ncn26000_config_init(struct phy_device *phydev)
> {
> + struct ncn26000_priv *priv = phydev->priv;
> + int ret;
> +
> + // configure the DIOx function
> + ret = phy_write(phydev, NCN26000_REG_DIO_CONFIG, priv->diocfg);
> + if (ret)
> + goto out;
> +
> + // configure proprietary PHY features
> + ret = phy_write_mmd(phydev, NCN26000_REG_PHYCFG1_MMD,
> + NCN26000_REG_PHYCFG1, priv->phycfg0);
> + if (ret)
> + goto out;
> +
> + // configure the PLCA extensions
> + ret = phy_write_mmd(phydev, NCN26000_REG_PLCAEXT_MMD,
> + NCN26000_REG_PLCAEXT, priv->plcaext);
> + if (ret)
> + goto out;
> +
> + // configure additional PHY tweaks
> + ret = phy_write_mmd(phydev, NCN26000_REG_TWEAKS_MMD,
> + NCN26000_REG_TWEAKS, priv->tweaks);
> + if (ret)
> + goto out;
> +
> /* HW bug workaround: the default value of the PLCA TO_TIMER should be
> * 32, where the current version of NCN26000 reports 24. This will be
> * fixed in future PHY versions. For the time being, we force the
> * correct default here.
> */
> - return phy_write_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR,
> - TO_TMR_DEFAULT);
> + ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MDIO_OATC14_PLCA_TOTMR,
> + TO_TMR_DEFAULT);
> +
> +out:
> + return ret;
> }
>
> static int ncn26000_config_aneg(struct phy_device *phydev)
> @@ -100,6 +490,36 @@ static int ncn26000_read_status(struct phy_device *phydev)
> return 0;
> }
>
> +static int ncn26000_plca_set_cfg(struct phy_device *phydev,
> + const struct phy_plca_cfg *plca_cfg)
> +{
> + struct ncn26000_priv *priv = phydev->priv;
> + int ret;
> +
> + /* We capture calls to PLCA set config to intercept PLCA enable/disable
> + * requests and set the proprietary ENI mode accordingly
> + */
> + ret = genphy_c45_plca_set_cfg(phydev, plca_cfg);
> + if (ret || plca_cfg->enabled < 0 || priv->eni_mode != ENI_AUTO)
> + goto out;
> +
> + ret = phy_read_mmd(phydev, NCN26000_REG_PHYCFG1_MMD,
> + NCN26000_REG_PHYCFG1);
> +
> + if (ret < 0)
> + goto out;
> +
> + if (plca_cfg->enabled)
> + ret |= NCN26000_PHYCFG1_ENI;
> + else
> + ret &= ~NCN26000_PHYCFG1_ENI;
> +
> + ret = phy_write_mmd(phydev, NCN26000_REG_PHYCFG1_MMD,
> + NCN26000_REG_PHYCFG1, ret);
> +out:
> + return ret;
> +}
> +
> static irqreturn_t ncn26000_handle_interrupt(struct phy_device *phydev)
> {
> int ret;
> @@ -140,20 +560,51 @@ static int ncn26000_config_intr(struct phy_device *phydev)
> return 0;
> }
>
> +static int ncn26000_probe(struct phy_device *phydev)
> +{
> + struct device *dev = &phydev->mdio.dev;
> + struct ncn26000_priv *priv;
> +
> + priv = kzalloc(sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + priv->dev = dev;
> + priv->phydev = phydev;
> + phydev->priv = priv;
> +
> + ncn26000_dio_config(priv);
> + if (priv->gpiomask)
> + ncn26000_gpio_setup(priv);
> +
> + ncn26000_phycfg0_config(priv);
> + ncn26000_plcaext_config(priv);
> + ncn26000_tweaks_config(priv);
> +
> + return 0;
> +}
> +
> +static void ncn26000_remove(struct phy_device *phydev)
> +{
> + kfree(phydev->priv);
> +}
> +
> static struct phy_driver ncn26000_driver[] = {
> {
> PHY_ID_MATCH_MODEL(PHY_ID_NCN26000),
> .name = "NCN26000",
> .features = PHY_BASIC_T1S_P2MP_FEATURES,
> - .config_init = ncn26000_config_init,
> - .config_intr = ncn26000_config_intr,
> + .probe = ncn26000_probe,
> + .remove = ncn26000_remove,
> + .config_init = ncn26000_config_init,
> + .config_intr = ncn26000_config_intr,
> .config_aneg = ncn26000_config_aneg,
> .read_status = ncn26000_read_status,
> - .handle_interrupt = ncn26000_handle_interrupt,
> + .handle_interrupt = ncn26000_handle_interrupt,
> + .set_plca_cfg = ncn26000_plca_set_cfg,
> .get_plca_cfg = genphy_c45_plca_get_cfg,
> - .set_plca_cfg = genphy_c45_plca_set_cfg,
> .get_plca_status = genphy_c45_plca_get_status,
> - .soft_reset = genphy_soft_reset,
> + .soft_reset = genphy_soft_reset,
> },
> };
>

\
 
 \ /
  Last update: 2023-09-18 12:43    [W:0.044 / U:0.816 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site