Skip to content

Commit

Permalink
Merge branch 'net-phy-marvell-usb-to-mdio-controller'
Browse files Browse the repository at this point in the history
Tobias Waldekranz says:

====================
net: phy: marvell usb to mdio controller

Support for an MDIO controller present on development boards for
Marvell switches from the Link Street (88E6xxx) family.

v3->v4:
- Remove unnecessary dependency on OF_MDIO.

v2->v3:
- Rename driver smi2usb -> mvusb.
- Clean up unused USB references.

v1->v2:
- Reverse christmas tree ordering of local variables.
====================

Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
davem330 committed Mar 27, 2020
2 parents 1698350 + 04e37d9 commit 6a86473
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 0 deletions.
65 changes: 65 additions & 0 deletions Documentation/devicetree/bindings/net/marvell,mvusb.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/net/marvell,mvusb.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: Marvell USB to MDIO Controller

maintainers:
- Tobias Waldekranz <[email protected]>

description: |+
This controller is mounted on development boards for Marvell's Link Street
family of Ethernet switches. It allows you to configure the switch's registers
using the standard MDIO interface.
Since the device is connected over USB, there is no strict requirement of
having a device tree representation of the device. But in order to use it with
the mv88e6xxx driver, you need a device tree node in which to place the switch
definition.
allOf:
- $ref: "mdio.yaml#"

properties:
compatible:
const: usb1286,1fa4
reg:
maxItems: 1
description: The USB port number on the host controller

required:
- compatible
- reg
- "#address-cells"
- "#size-cells"

examples:
- |
/* USB host controller */
&usb1 {
mvusb: mdio@1 {
compatible = "usb1286,1fa4";
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
};
};
/* MV88E6390X devboard */
&mvusb {
switch@0 {
compatible = "marvell,mv88e6190";
status = "ok";
reg = <0x0>;
ports {
/* Port definitions */
};
mdio {
/* PHY definitions */
};
};
};
7 changes: 7 additions & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -10106,6 +10106,13 @@ M: Nicolas Pitre <[email protected]>
S: Odd Fixes
F: drivers/mmc/host/mvsdio.*

MARVELL USB MDIO CONTROLLER DRIVER
M: Tobias Waldekranz <[email protected]>
L: [email protected]
S: Maintained
F: drivers/net/phy/mdio-mvusb.c
F: Documentation/devicetree/bindings/net/marvell,mvusb.yaml

MARVELL XENON MMC/SD/SDIO HOST CONTROLLER DRIVER
M: Hu Ziji <[email protected]>
L: [email protected]
Expand Down
7 changes: 7 additions & 0 deletions drivers/net/phy/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,13 @@ config MDIO_MSCC_MIIM
This driver supports the MIIM (MDIO) interface found in the network
switches of the Microsemi SoCs

config MDIO_MVUSB
tristate "Marvell USB to MDIO Adapter"
depends on USB
help
A USB to MDIO converter present on development boards for
Marvell's Link Street family of Ethernet switches.

config MDIO_OCTEON
tristate "Octeon and some ThunderX SOCs MDIO buses"
depends on (64BIT && OF_MDIO) || COMPILE_TEST
Expand Down
1 change: 1 addition & 0 deletions drivers/net/phy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ obj-$(CONFIG_MDIO_I2C) += mdio-i2c.o
obj-$(CONFIG_MDIO_IPQ8064) += mdio-ipq8064.o
obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
obj-$(CONFIG_MDIO_MSCC_MIIM) += mdio-mscc-miim.o
obj-$(CONFIG_MDIO_MVUSB) += mdio-mvusb.o
obj-$(CONFIG_MDIO_OCTEON) += mdio-octeon.o
obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o
obj-$(CONFIG_MDIO_THUNDER) += mdio-thunder.o
Expand Down
120 changes: 120 additions & 0 deletions drivers/net/phy/mdio-mvusb.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// SPDX-License-Identifier: GPL-2.0

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/usb.h>

#define USB_MARVELL_VID 0x1286

static const struct usb_device_id mvusb_mdio_table[] = {
{ USB_DEVICE(USB_MARVELL_VID, 0x1fa4) },

{}
};
MODULE_DEVICE_TABLE(usb, mvusb_mdio_table);

enum {
MVUSB_CMD_PREAMBLE0,
MVUSB_CMD_PREAMBLE1,
MVUSB_CMD_ADDR,
MVUSB_CMD_VAL,
};

struct mvusb_mdio {
struct usb_device *udev;
struct mii_bus *mdio;

__le16 buf[4];
};

static int mvusb_mdio_read(struct mii_bus *mdio, int dev, int reg)
{
struct mvusb_mdio *mvusb = mdio->priv;
int err, alen;

if (dev & MII_ADDR_C45)
return -EOPNOTSUPP;

mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0xa400 | (dev << 5) | reg);

err = usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2),
mvusb->buf, 6, &alen, 100);
if (err)
return err;

err = usb_bulk_msg(mvusb->udev, usb_rcvbulkpipe(mvusb->udev, 6),
&mvusb->buf[MVUSB_CMD_VAL], 2, &alen, 100);
if (err)
return err;

return le16_to_cpu(mvusb->buf[MVUSB_CMD_VAL]);
}

static int mvusb_mdio_write(struct mii_bus *mdio, int dev, int reg, u16 val)
{
struct mvusb_mdio *mvusb = mdio->priv;
int alen;

if (dev & MII_ADDR_C45)
return -EOPNOTSUPP;

mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0x8000 | (dev << 5) | reg);
mvusb->buf[MVUSB_CMD_VAL] = cpu_to_le16(val);

return usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2),
mvusb->buf, 8, &alen, 100);
}

static int mvusb_mdio_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct device *dev = &interface->dev;
struct mvusb_mdio *mvusb;
struct mii_bus *mdio;

mdio = devm_mdiobus_alloc_size(dev, sizeof(*mvusb));
if (!mdio)
return -ENOMEM;

mvusb = mdio->priv;
mvusb->mdio = mdio;
mvusb->udev = usb_get_dev(interface_to_usbdev(interface));

/* Reversed from USB PCAPs, no idea what these mean. */
mvusb->buf[MVUSB_CMD_PREAMBLE0] = cpu_to_le16(0xe800);
mvusb->buf[MVUSB_CMD_PREAMBLE1] = cpu_to_le16(0x0001);

snprintf(mdio->id, MII_BUS_ID_SIZE, "mvusb-%s", dev_name(dev));
mdio->name = mdio->id;
mdio->parent = dev;
mdio->read = mvusb_mdio_read;
mdio->write = mvusb_mdio_write;

usb_set_intfdata(interface, mvusb);
return of_mdiobus_register(mdio, dev->of_node);
}

static void mvusb_mdio_disconnect(struct usb_interface *interface)
{
struct mvusb_mdio *mvusb = usb_get_intfdata(interface);
struct usb_device *udev = mvusb->udev;

mdiobus_unregister(mvusb->mdio);
usb_set_intfdata(interface, NULL);
usb_put_dev(udev);
}

static struct usb_driver mvusb_mdio_driver = {
.name = "mvusb_mdio",
.id_table = mvusb_mdio_table,
.probe = mvusb_mdio_probe,
.disconnect = mvusb_mdio_disconnect,
};

module_usb_driver(mvusb_mdio_driver);

MODULE_AUTHOR("Tobias Waldekranz <[email protected]>");
MODULE_DESCRIPTION("Marvell USB MDIO Adapter");
MODULE_LICENSE("GPL");

0 comments on commit 6a86473

Please sign in to comment.