Merge branch 'net-dsa-microchip-add-strap-description-to-set-spi-as-interface-bus'

Bastien Curutchet says:

====================
net: dsa: microchip: Add strap description to set SPI as interface bus

At reset, the KSZ8463 uses a strap-based configuration to set SPI as
interface bus. If the required pull-ups/pull-downs are missing
(by mistake or by design to save power) the pins may float and the
configuration can go wrong preventing any communication with the switch.

This small series aims to allow to configure the KSZ8463 switch at
reset when the hardware straps are missing.

PATCH 0 and 1 add a new property to the bindings that describes the GPIOs
to be set during reset in order to configure the switch properly.

PATCH 2 implements the use of these properties in the driver.
====================

Link: https://patch.msgid.link/20250918-ksz-strap-pins-v3-0-16662e881728@bootlin.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2025-09-22 16:31:21 -07:00
2 changed files with 98 additions and 34 deletions

View File

@@ -10,9 +10,6 @@ maintainers:
- Marek Vasut <marex@denx.de>
- Woojung Huh <Woojung.Huh@microchip.com>
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
# See Documentation/devicetree/bindings/net/dsa/dsa.yaml for a list of additional
# required and optional properties.
@@ -37,6 +34,13 @@ properties:
- microchip,ksz8567
- microchip,lan9646
pinctrl-names:
items:
- const: default
- const: reset
description:
Used during reset for strap configuration.
reset-gpios:
description:
Should be a gpio specifier for a reset line.
@@ -107,38 +111,53 @@ required:
- compatible
- reg
if:
not:
properties:
compatible:
enum:
- microchip,ksz8863
- microchip,ksz8873
then:
$ref: dsa.yaml#/$defs/ethernet-ports
else:
patternProperties:
"^(ethernet-)?ports$":
allOf:
- $ref: /schemas/spi/spi-peripheral-props.yaml#
- if:
not:
properties:
compatible:
enum:
- microchip,ksz8863
- microchip,ksz8873
then:
$ref: dsa.yaml#/$defs/ethernet-ports
else:
patternProperties:
"^(ethernet-)?port@[0-2]$":
$ref: dsa-port.yaml#
unevaluatedProperties: false
properties:
microchip,rmii-clk-internal:
$ref: /schemas/types.yaml#/definitions/flag
description:
When ksz88x3 is acting as clock provier (via REFCLKO) it
can select between internal and external RMII reference
clock. Internal reference clock means that the clock for
the RMII of ksz88x3 is provided by the ksz88x3 internally
and the REFCLKI pin is unconnected. For the external
reference clock, the clock needs to be fed back to ksz88x3
via REFCLKI.
If microchip,rmii-clk-internal is set, ksz88x3 will provide
rmii reference clock internally, otherwise reference clock
should be provided externally.
dependencies:
microchip,rmii-clk-internal: [ethernet]
"^(ethernet-)?ports$":
patternProperties:
"^(ethernet-)?port@[0-2]$":
$ref: dsa-port.yaml#
unevaluatedProperties: false
properties:
microchip,rmii-clk-internal:
$ref: /schemas/types.yaml#/definitions/flag
description:
When ksz88x3 is acting as clock provier (via REFCLKO) it
can select between internal and external RMII reference
clock. Internal reference clock means that the clock for
the RMII of ksz88x3 is provided by the ksz88x3 internally
and the REFCLKI pin is unconnected. For the external
reference clock, the clock needs to be fed back to ksz88x3
via REFCLKI.
If microchip,rmii-clk-internal is set, ksz88x3 will provide
rmii reference clock internally, otherwise reference clock
should be provided externally.
dependencies:
microchip,rmii-clk-internal: [ethernet]
- if:
properties:
compatible:
contains:
const: microchip,ksz8463
then:
properties:
straps-rxd-gpios:
description:
RXD0 and RXD1 pins, used to select SPI as bus interface.
minItems: 2
maxItems: 2
unevaluatedProperties: false

View File

@@ -23,6 +23,7 @@
#include <linux/of_mdio.h>
#include <linux/of_net.h>
#include <linux/micrel_phy.h>
#include <linux/pinctrl/consumer.h>
#include <net/dsa.h>
#include <net/ieee8021q.h>
#include <net/pkt_cls.h>
@@ -5345,6 +5346,38 @@ static int ksz_parse_drive_strength(struct ksz_device *dev)
return 0;
}
static int ksz8463_configure_straps_spi(struct ksz_device *dev)
{
struct pinctrl *pinctrl;
struct gpio_desc *rxd0;
struct gpio_desc *rxd1;
rxd0 = devm_gpiod_get_index_optional(dev->dev, "straps-rxd", 0, GPIOD_OUT_LOW);
if (IS_ERR(rxd0))
return PTR_ERR(rxd0);
rxd1 = devm_gpiod_get_index_optional(dev->dev, "straps-rxd", 1, GPIOD_OUT_HIGH);
if (IS_ERR(rxd1))
return PTR_ERR(rxd1);
if (!rxd0 && !rxd1)
return 0;
if ((rxd0 && !rxd1) || (rxd1 && !rxd0))
return -EINVAL;
pinctrl = devm_pinctrl_get_select(dev->dev, "reset");
if (IS_ERR(pinctrl))
return PTR_ERR(pinctrl);
return 0;
}
static int ksz8463_release_straps_spi(struct ksz_device *dev)
{
return pinctrl_select_default_state(dev->dev);
}
int ksz_switch_register(struct ksz_device *dev)
{
const struct ksz_chip_data *info;
@@ -5360,10 +5393,22 @@ int ksz_switch_register(struct ksz_device *dev)
return PTR_ERR(dev->reset_gpio);
if (dev->reset_gpio) {
if (of_device_is_compatible(dev->dev->of_node, "microchip,ksz8463")) {
ret = ksz8463_configure_straps_spi(dev);
if (ret)
return ret;
}
gpiod_set_value_cansleep(dev->reset_gpio, 1);
usleep_range(10000, 12000);
gpiod_set_value_cansleep(dev->reset_gpio, 0);
msleep(100);
if (of_device_is_compatible(dev->dev->of_node, "microchip,ksz8463")) {
ret = ksz8463_release_straps_spi(dev);
if (ret)
return ret;
}
}
mutex_init(&dev->dev_mutex);