brintos

brintos / linux-shallow public Read only

0
0
Text · 2.9 KiB · 554837c Raw
124 lines · c
1// SPDX-License-Identifier: GPL-2.02 3#include <linux/kernel.h>4#include <linux/module.h>5#include <linux/of_mdio.h>6#include <linux/phy.h>7#include <linux/usb.h>8 9#define USB_MARVELL_VID	0x128610 11static const struct usb_device_id mvusb_mdio_table[] = {12	{ USB_DEVICE(USB_MARVELL_VID, 0x1fa4) },13 14	{}15};16MODULE_DEVICE_TABLE(usb, mvusb_mdio_table);17 18enum {19	MVUSB_CMD_PREAMBLE0,20	MVUSB_CMD_PREAMBLE1,21	MVUSB_CMD_ADDR,22	MVUSB_CMD_VAL,23};24 25struct mvusb_mdio {26	struct usb_device *udev;27	struct mii_bus *mdio;28 29	__le16 buf[4];30};31 32static int mvusb_mdio_read(struct mii_bus *mdio, int dev, int reg)33{34	struct mvusb_mdio *mvusb = mdio->priv;35	int err, alen;36 37	mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0xa400 | (dev << 5) | reg);38 39	err = usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2),40			   mvusb->buf, 6, &alen, 100);41	if (err)42		return err;43 44	err = usb_bulk_msg(mvusb->udev, usb_rcvbulkpipe(mvusb->udev, 6),45			   &mvusb->buf[MVUSB_CMD_VAL], 2, &alen, 100);46	if (err)47		return err;48 49	return le16_to_cpu(mvusb->buf[MVUSB_CMD_VAL]);50}51 52static int mvusb_mdio_write(struct mii_bus *mdio, int dev, int reg, u16 val)53{54	struct mvusb_mdio *mvusb = mdio->priv;55	int alen;56 57	mvusb->buf[MVUSB_CMD_ADDR] = cpu_to_le16(0x8000 | (dev << 5) | reg);58	mvusb->buf[MVUSB_CMD_VAL]  = cpu_to_le16(val);59 60	return usb_bulk_msg(mvusb->udev, usb_sndbulkpipe(mvusb->udev, 2),61			    mvusb->buf, 8, &alen, 100);62}63 64static int mvusb_mdio_probe(struct usb_interface *interface,65			    const struct usb_device_id *id)66{67	struct device *dev = &interface->dev;68	struct mvusb_mdio *mvusb;69	struct mii_bus *mdio;70	int ret;71 72	mdio = devm_mdiobus_alloc_size(dev, sizeof(*mvusb));73	if (!mdio)74		return -ENOMEM;75 76	mvusb = mdio->priv;77	mvusb->mdio = mdio;78	mvusb->udev = usb_get_dev(interface_to_usbdev(interface));79 80	/* Reversed from USB PCAPs, no idea what these mean. */81	mvusb->buf[MVUSB_CMD_PREAMBLE0] = cpu_to_le16(0xe800);82	mvusb->buf[MVUSB_CMD_PREAMBLE1] = cpu_to_le16(0x0001);83 84	snprintf(mdio->id, MII_BUS_ID_SIZE, "mvusb-%s", dev_name(dev));85	mdio->name = mdio->id;86	mdio->parent = dev;87	mdio->read = mvusb_mdio_read;88	mdio->write = mvusb_mdio_write;89 90	usb_set_intfdata(interface, mvusb);91	ret = of_mdiobus_register(mdio, dev->of_node);92	if (ret)93		goto put_dev;94 95	return 0;96 97put_dev:98	usb_put_dev(mvusb->udev);99	return ret;100}101 102static void mvusb_mdio_disconnect(struct usb_interface *interface)103{104	struct mvusb_mdio *mvusb = usb_get_intfdata(interface);105	struct usb_device *udev = mvusb->udev;106 107	mdiobus_unregister(mvusb->mdio);108	usb_set_intfdata(interface, NULL);109	usb_put_dev(udev);110}111 112static struct usb_driver mvusb_mdio_driver = {113	.name       = "mvusb_mdio",114	.id_table   = mvusb_mdio_table,115	.probe      = mvusb_mdio_probe,116	.disconnect = mvusb_mdio_disconnect,117};118 119module_usb_driver(mvusb_mdio_driver);120 121MODULE_AUTHOR("Tobias Waldekranz <tobias@waldekranz.com>");122MODULE_DESCRIPTION("Marvell USB MDIO Adapter");123MODULE_LICENSE("GPL");124