diff mbox series

[net-next,v4,13/12] net: lan865x: optional hardware reset

Message ID Zi68sDje4wfgftyZ@builder
State Changes Requested
Headers show
Series Add support for OPEN Alliance 10BASE-T1x MACPHY Serial Interface | expand

Checks

Context Check Description
robh/checkpatch warning total: 0 errors, 1 warnings, 0 checks, 67 lines checked
robh/patch-applied success

Commit Message

Ramón Nordin Rodriguez April 28, 2024, 9:16 p.m. UTC
From c65e42982684d5fd8b2294eb6acf755aa0fcab83 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ram=C3=B3n=20Nordin=20Rodriguez?=
 <ramon.nordin.rodriguez@ferroamp.se>
Date: Sun, 28 Apr 2024 22:25:12 +0200
Subject: [PATCH net-next v4 13/12] net: lan865x: optional hardware reset
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This commit optionally enables a hardware reset of the lan8650/1
mac-phy. These chips have a software reset that is discourage from use
in the manual since it only resets the internal phy.

Signed-off-by: Ramón Nordin Rodriguez <ramon.nordin.rodriguez@ferroamp.se>
---
 .../bindings/net/microchip,lan865x.yaml       |  4 +++
 .../net/ethernet/microchip/lan865x/lan865x.c  | 28 +++++++++++++++++++
 2 files changed, 32 insertions(+)

Comments

Andrew Lunn April 28, 2024, 11:17 p.m. UTC | #1
On Sun, Apr 28, 2024 at 11:16:32PM +0200, Ramón Nordin Rodriguez wrote:
> >From c65e42982684d5fd8b2294eb6acf755aa0fcab83 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Ram=C3=B3n=20Nordin=20Rodriguez?=
>  <ramon.nordin.rodriguez@ferroamp.se>
> Date: Sun, 28 Apr 2024 22:25:12 +0200
> Subject: [PATCH net-next v4 13/12] net: lan865x: optional hardware reset
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit

You sent this patch in an odd way. We don't normally see headers like
this. I've been using b4 recently for patch management:

https://b4.docs.kernel.org/en/latest/contributor/prep.html

Using `b4 send` is a good idea. Otherwise git format-patch; git send-email

> index 9abefa8b9d9f..bed9033574b2 100644
> --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c
> +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c
> @@ -9,6 +9,7 @@
>  #include <linux/kernel.h>
>  #include <linux/phy.h>
>  #include <linux/oa_tc6.h>
> +#include <linux/gpio/driver.h>

This is not a gpio driver, it is a gpio consumer. So you should be
using linux/gpio/consumer.h. Also, i _think_ the includes are sorted,
so it probably should go earlier.

>  
>  #define DRV_NAME			"lan865x"
>  
> @@ -33,6 +34,7 @@
>  
>  struct lan865x_priv {
>  	struct work_struct multicast_work;
> +	struct gpio_desc *reset_gpio;
>  	struct net_device *netdev;
>  	struct spi_device *spi;
>  	struct oa_tc6 *tc6;
> @@ -283,6 +285,24 @@ static int lan865x_set_zarfe(struct lan865x_priv *priv)
>  	return oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG0, regval);
>  }
>  
> +static int lan865x_probe_reset_gpio(struct lan865x_priv *priv)
> +{
> +	priv->reset_gpio = devm_gpiod_get_optional(&priv->spi->dev, "reset",
> +						   GPIOD_OUT_HIGH);
> +	if (IS_ERR(priv->reset_gpio))
> +		return PTR_ERR(priv->reset_gpio);
> +
> +	return 0;
> +}
> +
> +static void lan865x_hw_reset(struct lan865x_priv *priv)
> +{
> +	gpiod_set_value_cansleep(priv->reset_gpio, 1);
> +	// section 9.6.3 RESET_N Timing specifies a minimum hold of 5us
> +	usleep_range(5, 10);
> +	gpiod_set_value_cansleep(priv->reset_gpio, 0);
> +}

Do you see a need to do a reset at any time other than probe? If not,
i would probably combine these two functions into one. Also, since you
pass GPIOD_OUT_HIGH, you have already put it into reset. So setting
the gpio to 1 is pointless.

Does the datasheet say anything about how long you should wait after
releasing the reset?

> +
>  static int lan865x_probe(struct spi_device *spi)
>  {
>  	struct net_device *netdev;
> @@ -297,6 +317,14 @@ static int lan865x_probe(struct spi_device *spi)
>  	priv->netdev = netdev;
>  	priv->spi = spi;
>  	spi_set_drvdata(spi, priv);
> +	if (lan865x_probe_reset_gpio(priv)) {
> +		dev_err(&spi->dev, "failed to probe reset pin");
> +		ret = -ENODEV;

It is normal that a function like lan865x_probe_reset_gpio() would
return an error code. You should then return that error code, rather
than replace it with ENODEV.

     Andrew
Parthiban Veerasooran April 29, 2024, 6:09 a.m. UTC | #2
Hi Ramon,

On 29/04/24 2:46 am, Ramón Nordin Rodriguez wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>  From c65e42982684d5fd8b2294eb6acf755aa0fcab83 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Ram=C3=B3n=20Nordin=20Rodriguez?=
>   <ramon.nordin.rodriguez@ferroamp.se>
> Date: Sun, 28 Apr 2024 22:25:12 +0200
> Subject: [PATCH net-next v4 13/12] net: lan865x: optional hardware reset
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> This commit optionally enables a hardware reset of the lan8650/1
> mac-phy. These chips have a software reset that is discourage from use
> in the manual since it only resets the internal phy.
The software reset done by the current driver is not only resetting the 
internal PHY, it resets the entire MAC-PHY including the integrated PHY.
The reset bit of the Clause 22 basic control register only will reset 
the internal PHY alone. But oa_tc6_sw_reset_macphy() function is writing 
software reset bit in the Reset Control and Status register which resets 
the entire MAC-PHY including the internal PHY.

OPEN Alliance spec says the following which is done in the 
oa_tc6_sw_reset_macphy().

9.2.4
Reset Control and Status Register (0x0003)
9.2.4.1 RSVD
Reserved for future use. Writing to these bits shall have no effect on 
the MAC-PHY.
9.2.4.2 SWRESET
MAC-PHY Software Reset. The action of writing a ‘1’ to this bit shall 
fully reset the MAC-PHY, including the integrated PHY, to an initial 
state including but not limited to resetting all state machines and 
registers to their default value. When this bit is set, the reset shall 
not occur until CSn is deasserted to allow for the control command write 
to complete. This bit is self-clearing.

LAN8650 spec says the following,

4.1.1.3 Software Reset
A software reset of the LAN8650/1 is available via the Soft Reset 
(SW_RESET) bit in the standard OA_CONFIG0 register.

Note: The SW_RESET bit of the Clause 22 Basic Control register will 
reset only the internal PHY, not the entire device. This PHY only reset 
is not recommended for use. If such a reset is detected, by reading the 
RESETC bit of the STS2 register, reset the entire device.

The above note is given in the lan8650 datasheet to let the user to know 
that clause 22 software reset will reset only internal PHY but I don't 
think they mean it for the MAC-PHY software reset done from Reset 
Control and Status register.

So in my opinion, I don't see the need of external pin reset as the 
existing oa_tc6_sw_reset_macphy() function does the software reset of 
the entire MAC-PHY.

Still if you see a need to have this external pin reset as an optional 
function then it may be needed for all the vendor specific MAC drivers. 
In that case, reset-gpios parameter value alone can be taken from the 
chip specific device tree and the remaining code for operating the reset 
gpio can be moved to oa_tc6.c and the function name can be 
oa_tc6_hw_reset_macphy().

Best regards,
Parthiban V
> 
> Signed-off-by: Ramón Nordin Rodriguez <ramon.nordin.rodriguez@ferroamp.se>
> ---
>   .../bindings/net/microchip,lan865x.yaml       |  4 +++
>   .../net/ethernet/microchip/lan865x/lan865x.c  | 28 +++++++++++++++++++
>   2 files changed, 32 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> index 4fdec0ba3532..0f11f431df06 100644
> --- a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> +++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
> @@ -44,6 +44,9 @@ properties:
>       minimum: 15000000
>       maximum: 25000000
> 
> +  reset-gpios:
> +    maxItems: 1
> +
>     "#address-cells":
>       const: 1
> 
> @@ -76,5 +79,6 @@ examples:
>           interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
>           local-mac-address = [04 05 06 01 02 03];
>           spi-max-frequency = <15000000>;
> +        reset-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
>         };
>       };
> diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c
> index 9abefa8b9d9f..bed9033574b2 100644
> --- a/drivers/net/ethernet/microchip/lan865x/lan865x.c
> +++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c
> @@ -9,6 +9,7 @@
>   #include <linux/kernel.h>
>   #include <linux/phy.h>
>   #include <linux/oa_tc6.h>
> +#include <linux/gpio/driver.h>
> 
>   #define DRV_NAME                       "lan865x"
> 
> @@ -33,6 +34,7 @@
> 
>   struct lan865x_priv {
>          struct work_struct multicast_work;
> +       struct gpio_desc *reset_gpio;
>          struct net_device *netdev;
>          struct spi_device *spi;
>          struct oa_tc6 *tc6;
> @@ -283,6 +285,24 @@ static int lan865x_set_zarfe(struct lan865x_priv *priv)
>          return oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG0, regval);
>   }
> 
> +static int lan865x_probe_reset_gpio(struct lan865x_priv *priv)
> +{
> +       priv->reset_gpio = devm_gpiod_get_optional(&priv->spi->dev, "reset",
> +                                                  GPIOD_OUT_HIGH);
> +       if (IS_ERR(priv->reset_gpio))
> +               return PTR_ERR(priv->reset_gpio);
> +
> +       return 0;
> +}
> +
> +static void lan865x_hw_reset(struct lan865x_priv *priv)
> +{
> +       gpiod_set_value_cansleep(priv->reset_gpio, 1);
> +       // section 9.6.3 RESET_N Timing specifies a minimum hold of 5us
> +       usleep_range(5, 10);
> +       gpiod_set_value_cansleep(priv->reset_gpio, 0);
> +}
> +
>   static int lan865x_probe(struct spi_device *spi)
>   {
>          struct net_device *netdev;
> @@ -297,6 +317,14 @@ static int lan865x_probe(struct spi_device *spi)
>          priv->netdev = netdev;
>          priv->spi = spi;
>          spi_set_drvdata(spi, priv);
> +       if (lan865x_probe_reset_gpio(priv)) {
> +               dev_err(&spi->dev, "failed to probe reset pin");
> +               ret = -ENODEV;
> +               goto free_netdev;
> +       }
> +
> +       if (priv->reset_gpio)
> +               lan865x_hw_reset(priv);
>          INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler);
> 
>          priv->tc6 = oa_tc6_init(spi, netdev);
> --
> 2.43.0
> 
>
Krzysztof Kozlowski April 29, 2024, 6:09 a.m. UTC | #3
On 28/04/2024 23:16, Ramón Nordin Rodriguez wrote:
> From c65e42982684d5fd8b2294eb6acf755aa0fcab83 Mon Sep 17 00:00:00 2001
> From: =?UTF-8?q?Ram=C3=B3n=20Nordin=20Rodriguez?=
>  <ramon.nordin.rodriguez@ferroamp.se>
> Date: Sun, 28 Apr 2024 22:25:12 +0200
> Subject: [PATCH net-next v4 13/12] net: lan865x: optional hardware reset
> MIME-Version: 1.0
> Content-Type: text/plain; charset=UTF-8
> Content-Transfer-Encoding: 8bit
> 
> This commit optionally enables a hardware reset of the lan8650/1
> mac-phy. These chips have a software reset that is discourage from use
> in the manual since it only resets the internal phy.
> 
> Signed-off-by: Ramón Nordin Rodriguez <ramon.nordin.rodriguez@ferroamp.se>
> ---
>  .../bindings/net/microchip,lan865x.yaml       |  4 +++
>  .../net/ethernet/microchip/lan865x/lan865x.c  | 28 +++++++++++++++++++

Please run scripts/checkpatch.pl and fix reported warnings. Then please
run `scripts/checkpatch.pl --strict` and (probably) fix more warnings.
Some warnings can be ignored, especially from --strict run, but the code
here looks like it needs a fix. Feel free to get in touch if the warning
is not clear.

Best regards,
Krzysztof
Ramón Nordin Rodriguez April 29, 2024, 10:38 a.m. UTC | #4
> > This commit optionally enables a hardware reset of the lan8650/1
> > mac-phy. These chips have a software reset that is discourage from use
> > in the manual since it only resets the internal phy.
> The software reset done by the current driver is not only resetting the 
> internal PHY, it resets the entire MAC-PHY including the integrated PHY.
> The reset bit of the Clause 22 basic control register only will reset 
> the internal PHY alone. But oa_tc6_sw_reset_macphy() function is writing 
> software reset bit in the Reset Control and Status register which resets 
> the entire MAC-PHY including the internal PHY.

All right, I did not dig deep enough obviously.

> The above note is given in the lan8650 datasheet to let the user to know 
> that clause 22 software reset will reset only internal PHY but I don't 
> think they mean it for the MAC-PHY software reset done from Reset 
> Control and Status register.

Could still be relevant to implement the .soft_reset with -EOPNOTSUPP as
Andrew has suggested in the phy driver.

> 
> So in my opinion, I don't see the need of external pin reset as the 
> existing oa_tc6_sw_reset_macphy() function does the software reset of 
> the entire MAC-PHY.

I agree with your assesment that this invalidates the problem I was
aiming at solving.

Additionally I figured out why my setup did not work without the HW
reset, I had missed a pull resistor in the schematic that held the IC in
reset.

To me it seems more feature complete to have a driver option for the
physical capabilities of the chip, but if it doesn't actually solve a
problem it might just be bloat.

> 
> Still if you see a need to have this external pin reset as an optional 
> function then it may be needed for all the vendor specific MAC drivers. 
> In that case, reset-gpios parameter value alone can be taken from the 
> chip specific device tree and the remaining code for operating the reset 
> gpio can be moved to oa_tc6.c and the function name can be 
> oa_tc6_hw_reset_macphy().
> 

If the consensus is to keep a HW reset I do like this suggestion.

I won't push for this to be included, if it is, I'm happy to address the
feedback of patch 13.

R
Ramón Nordin Rodriguez April 29, 2024, 10:42 a.m. UTC | #5
> You sent this patch in an odd way. We don't normally see headers like
> this. I've been using b4 recently for patch management:

Sorry about that, I appreciate the suggestion!

You left good comments on the implementation side as well, I'll wait
with addressing these. Parthibans feedback does invalidate the core of
the problem I set out to solve with this patch.

If the patch is not dropped I'll ofc address these points!

R
Ramón Nordin Rodriguez April 29, 2024, 10:44 a.m. UTC | #6
> Please run scripts/checkpatch.pl and fix reported warnings. Then please
> run `scripts/checkpatch.pl --strict` and (probably) fix more warnings.
> Some warnings can be ignored, especially from --strict run, but the code
> here looks like it needs a fix. Feel free to get in touch if the warning
> is not clear.
> 

Very much appreciated! I'll hold off on any further submissions for this
patch until it's clear that it's desriable to include.

R
Andrew Lunn April 29, 2024, 12:19 p.m. UTC | #7
> Additionally I figured out why my setup did not work without the HW
> reset, I had missed a pull resistor in the schematic that held the IC in
> reset.

Having a reset controlled by software is a pretty common
design. Something needs to ensure the device is out of reset. It could
be the bootloader, but i don't particularly like that, hiding away
critical things where they are hard to see. So i think having it in
the Linux driver is better.

There is an open question of does the driver need to actually reset
the device, or is it sufficient to ensure it is out of reset? The
wording of the standard suggests a hardware reset cycle is probably
not required, but why did Microchip provide a reset pin?

	Andrew
Ramón Nordin Rodriguez April 30, 2024, 8:04 a.m. UTC | #8
> > Additionally I figured out why my setup did not work without the HW
> > reset, I had missed a pull resistor in the schematic that held the IC in
> > reset.
> 
> Having a reset controlled by software is a pretty common
> design. Something needs to ensure the device is out of reset. It could
> be the bootloader, but i don't particularly like that, hiding away
> critical things where they are hard to see. So i think having it in
> the Linux driver is better.

Wholeheartedly agree, beyond the basics of bringing up ram, cores etc.
it becomes really weird when/if the bootloaders behaviour defines kernel
functionality.

In this case the oa_tc6 module does a soft reset and waits for a status
reg to signal ready.

What seems to be missing here is that the chip signals ready/out of
reset by asserting the irq pin and setting the RESETC bit of ther OA_STATUS0
reg (which is defined behaviour in the OA spec as I understand it).

Neither the lan865x_probe or oa_tc6_init checks for the initial
condition, but I'm guessing it's a fair assumption that the chip is out
of reset by the point when the oa_tc6_sw_reset_machphy function is
invoked.

Far as I can tell no timing information is given in the datasheet.

Might be unecessary but the setup could be made more explicit/clear
with a func such as:

int oa_tc6_out_of_reset(struct oa_tc*);

Which should be invoked before any reg access/modification code in
either oa_tc6 or the mac driver.
If this fails my (opinionated) preferred style would be to do one hw
reset, recheck, and on subsequent failure bail.

Such a change would probably lead to the HW reset being invoked on
reboots (if there is enough capacitors to keep the IC powered) and
definetly as a result of kexec calls.

> 
> There is an open question of does the driver need to actually reset
> the device, or is it sufficient to ensure it is out of reset? The
> wording of the standard suggests a hardware reset cycle is probably
> not required, but why did Microchip provide a reset pin?
> 

This has me tripped up. The lan8650/1 has a configuration write
protection mechanism with an unlock sequence, described in "4.6.3
Configuration Protection" of the datasheet.
The unlocking can be bypassed/simplified with a HW reset, still does
not seem like an explanation for the functionality.

I can't define one scenario where the HW reset is definetly necessary,
but will probably do it anyways on the systems I work on.

Ramón
Parthiban Veerasooran April 30, 2024, 1:30 p.m. UTC | #9
On 29/04/24 5:49 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> Additionally I figured out why my setup did not work without the HW
>> reset, I had missed a pull resistor in the schematic that held the IC in
>> reset.
> 
> Having a reset controlled by software is a pretty common
> design. Something needs to ensure the device is out of reset. It could
> be the bootloader, but i don't particularly like that, hiding away
> critical things where they are hard to see. So i think having it in
> the Linux driver is better.
> 
> There is an open question of does the driver need to actually reset
> the device, or is it sufficient to ensure it is out of reset? The
> wording of the standard suggests a hardware reset cycle is probably
> not required, but why did Microchip provide a reset pin?
There are three resets mentioned,

1. Power ON reset - A Power-On Reset occurs when power is initially 
applied to the device. Once the reset completes, the IRQ_N pin will be 
asserted and the RESETC (Reset Completed) bit of the OA_STATUS0 Register 
will be set to 1, as specified by the Open Alliance. This indicates to 
the driver that the device has been reset and ready to configure. For a 
pre configured system this is enough to start the configuration.

2. Software reset - This reset can be done from software. In the driver, 
it is done as part of initialization. Actually it may not be needed if 
we are not going to reload the driver, as the Power ON reset does the 
same job for us. But if we compiled the driver as a loadable module and 
out of tree then it is needed for each time when we reload the driver 
without power reset.

3. Ext pin reset - A hardware reset will occur when the RESET_N pin is 
asserted. Once the RESET_N input is deasserted, the LAN8650/1 will 
restart operation. The device will indicate to the station's controller
that it has been reset and must be configured in the same way as if a 
Power-On Reset had occurred: the IRQ_N pin will be asserted and the 
RESETC (Reset Completed) bit of the OA_STATUS Register will be set to 1.

This is also basically does the same job but it may be useful when the 
chip gets into a situation where it can't perform SPI anymore to do a 
software reset. This may be needed in the initial phase testing. But 
once the development is completed and the chip is ready to use then 
there will not be any possibility to get into the above situation unless 
there is a permanent hardware failure where this reset also will not 
make any sense.

OPEN Alliance spec says the following in the section 8.2 Variables

reset
	This variable reflects the logical-OR of all reset sources of the 
MAC-PHY and is TRUE when any of the reset sources are asserted. Reset 
sources include power-on reset (POR), software reset (see Section 
9.2.4.2), and an external RESET pin (if implemented).

In the spec, external RESET pin is mentioned as "if implemented", in my 
understanding it is MAC-PHY vendors choice of implementing it where 
Microchip is implemented it. Using this reset, can be a application 
requirement/decision. It can be controlled from an external application 
where it is not needed SPI to operate.

Best regards,
Parthiban V
> 
>          Andrew
Andrew Lunn April 30, 2024, 2:14 p.m. UTC | #10
> In the spec, external RESET pin is mentioned as "if implemented", in my 
> understanding it is MAC-PHY vendors choice of implementing it where 
> Microchip is implemented it. Using this reset, can be a application 
> requirement/decision. It can be controlled from an external application 
> where it is not needed SPI to operate.

Since it is optional, controlling the reset pin is clearly not
something for the TC6 core.

However, i doubt having an external application controlling the reset
is a good idea. You don't want to reset during operation. So to me,
this reset should be controlled by the driver. I tend to agree, that
actually performing a reset is optional, but i would expect the driver
to ensure the device is taken out of reset during probe, if the power
on default of the board is to hold it in reset.

   Andrew
Parthiban Veerasooran May 2, 2024, 10:10 a.m. UTC | #11
Hi Andrew,

On 30/04/24 7:44 pm, Andrew Lunn wrote:
> EXTERNAL EMAIL: Do not click links or open attachments unless you know the content is safe
> 
>> In the spec, external RESET pin is mentioned as "if implemented", in my
>> understanding it is MAC-PHY vendors choice of implementing it where
>> Microchip is implemented it. Using this reset, can be a application
>> requirement/decision. It can be controlled from an external application
>> where it is not needed SPI to operate.
> 
> Since it is optional, controlling the reset pin is clearly not
> something for the TC6 core.
> 
> However, i doubt having an external application controlling the reset
> is a good idea. You don't want to reset during operation. So to me,
> this reset should be controlled by the driver. I tend to agree, that
> actually performing a reset is optional, but i would expect the driver
> to ensure the device is taken out of reset during probe, if the power
> on default of the board is to hold it in reset.
POR - Power ON Reset.

If I understand you correctly, we need to ensure that whether the 
MAC-PHY is out of POR before doing any SPI operation right? so you 
expect oa_tc6_sw_reset_macphy() also may fail as the SWRESET bit write 
may fail if the device is still in POR.

Basically oa_tc6_sw_reset_macphy() does the following,
  - Writes 1 to SWRESET bit in the Reset Control and Status Register to 
trigger software reset.
  - Polls for software reset complete for every 1ms until 1s timeout.
  - Clears reset status complete status.

Can we rename the function like oa_tc6_check_power_on_reset_complete()
and the definition like below?
  - Poll for software reset complete for every 1ms until 1s timeout. The 
return value of oa_tc6_read_register() may not be needed to check for 
error as it might fail if the POR is taking place right?
  - Clear reset complete status.

But this case will work fine with initial power ON but after that if we 
are only reloading the driver for next time without powering OFF and ON 
then it will fail.

I am just thinking from TC6 framework point of view. Controlling from 
ext reset pin will not be an option as it is mentioned like an optional 
implementation in the OPEN Alliance. So some MAC-PHY vendors might not 
implement this.

Just an open question, after powering ON the Linux system, there are 
different stages are involved in the booting sequence of a system before 
kernel driver loads. A device like MAC-PHY which takes hardly around 5 
to 10us will complete the POR before that? OR is my understanding here 
is wrong?

Best regards,
Parthiban V
> 
>     Andrew
diff mbox series

Patch

diff --git a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
index 4fdec0ba3532..0f11f431df06 100644
--- a/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
+++ b/Documentation/devicetree/bindings/net/microchip,lan865x.yaml
@@ -44,6 +44,9 @@  properties:
     minimum: 15000000
     maximum: 25000000
 
+  reset-gpios:
+    maxItems: 1
+
   "#address-cells":
     const: 1
 
@@ -76,5 +79,6 @@  examples:
         interrupts = <6 IRQ_TYPE_EDGE_FALLING>;
         local-mac-address = [04 05 06 01 02 03];
         spi-max-frequency = <15000000>;
+        reset-gpios = <&gpio2 8 GPIO_ACTIVE_HIGH>;
       };
     };
diff --git a/drivers/net/ethernet/microchip/lan865x/lan865x.c b/drivers/net/ethernet/microchip/lan865x/lan865x.c
index 9abefa8b9d9f..bed9033574b2 100644
--- a/drivers/net/ethernet/microchip/lan865x/lan865x.c
+++ b/drivers/net/ethernet/microchip/lan865x/lan865x.c
@@ -9,6 +9,7 @@ 
 #include <linux/kernel.h>
 #include <linux/phy.h>
 #include <linux/oa_tc6.h>
+#include <linux/gpio/driver.h>
 
 #define DRV_NAME			"lan865x"
 
@@ -33,6 +34,7 @@ 
 
 struct lan865x_priv {
 	struct work_struct multicast_work;
+	struct gpio_desc *reset_gpio;
 	struct net_device *netdev;
 	struct spi_device *spi;
 	struct oa_tc6 *tc6;
@@ -283,6 +285,24 @@  static int lan865x_set_zarfe(struct lan865x_priv *priv)
 	return oa_tc6_write_register(priv->tc6, OA_TC6_REG_CONFIG0, regval);
 }
 
+static int lan865x_probe_reset_gpio(struct lan865x_priv *priv)
+{
+	priv->reset_gpio = devm_gpiod_get_optional(&priv->spi->dev, "reset",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(priv->reset_gpio))
+		return PTR_ERR(priv->reset_gpio);
+
+	return 0;
+}
+
+static void lan865x_hw_reset(struct lan865x_priv *priv)
+{
+	gpiod_set_value_cansleep(priv->reset_gpio, 1);
+	// section 9.6.3 RESET_N Timing specifies a minimum hold of 5us
+	usleep_range(5, 10);
+	gpiod_set_value_cansleep(priv->reset_gpio, 0);
+}
+
 static int lan865x_probe(struct spi_device *spi)
 {
 	struct net_device *netdev;
@@ -297,6 +317,14 @@  static int lan865x_probe(struct spi_device *spi)
 	priv->netdev = netdev;
 	priv->spi = spi;
 	spi_set_drvdata(spi, priv);
+	if (lan865x_probe_reset_gpio(priv)) {
+		dev_err(&spi->dev, "failed to probe reset pin");
+		ret = -ENODEV;
+		goto free_netdev;
+	}
+
+	if (priv->reset_gpio)
+		lan865x_hw_reset(priv);
 	INIT_WORK(&priv->multicast_work, lan865x_multicast_work_handler);
 
 	priv->tc6 = oa_tc6_init(spi, netdev);