lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <b279bee8-1613-23ea-a339-9d3fdde9d0eb@linux.dev>
Date:   Mon, 18 Sep 2023 11:40:36 +0100
From:   Vadim Fedorenko <vadim.fedorenko@...ux.dev>
To:     Jay Monkman <jtm@...ingdog.com>, devicetree@...r.kernel.org,
        netdev@...r.kernel.org, linux-kernel@...r.kernel.org,
        Piergiorgio Beruto <piergiorgio.beruto@...il.com>,
        Arndt Schuebel <Arndt.Schuebel@...emi.com>
Subject: Re: [PATCH 3/4] net: phy: Add GPIO and DT support to NCN26000

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@...ingdog.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,
>   	},
>   };
>   

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ