Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 #include <linux/module.h>
0003 #include <linux/netdevice.h>
0004 #include <linux/mii.h>
0005 #include <linux/usb.h>
0006 #include <linux/usb/cdc.h>
0007 #include <linux/usb/usbnet.h>
0008 #include <linux/usb/r8152.h>
0009 
0010 #define OCP_BASE        0xe86c
0011 
0012 static int pla_read_word(struct usbnet *dev, u16 index)
0013 {
0014     u16 byen = BYTE_EN_WORD;
0015     u8 shift = index & 2;
0016     __le32 tmp;
0017     int ret;
0018 
0019     if (shift)
0020         byen <<= shift;
0021 
0022     index &= ~3;
0023 
0024     ret = usbnet_read_cmd(dev, RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, index,
0025                   MCU_TYPE_PLA | byen, &tmp, sizeof(tmp));
0026     if (ret < 0)
0027         goto out;
0028 
0029     ret = __le32_to_cpu(tmp);
0030     ret >>= (shift * 8);
0031     ret &= 0xffff;
0032 
0033 out:
0034     return ret;
0035 }
0036 
0037 static int pla_write_word(struct usbnet *dev, u16 index, u32 data)
0038 {
0039     u32 mask = 0xffff;
0040     u16 byen = BYTE_EN_WORD;
0041     u8 shift = index & 2;
0042     __le32 tmp;
0043     int ret;
0044 
0045     data &= mask;
0046 
0047     if (shift) {
0048         byen <<= shift;
0049         mask <<= (shift * 8);
0050         data <<= (shift * 8);
0051     }
0052 
0053     index &= ~3;
0054 
0055     ret = usbnet_read_cmd(dev, RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, index,
0056                   MCU_TYPE_PLA | byen, &tmp, sizeof(tmp));
0057 
0058     if (ret < 0)
0059         goto out;
0060 
0061     data |= __le32_to_cpu(tmp) & ~mask;
0062     tmp = __cpu_to_le32(data);
0063 
0064     ret = usbnet_write_cmd(dev, RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, index,
0065                    MCU_TYPE_PLA | byen, &tmp, sizeof(tmp));
0066 
0067 out:
0068     return ret;
0069 }
0070 
0071 static int r8153_ecm_mdio_read(struct net_device *netdev, int phy_id, int reg)
0072 {
0073     struct usbnet *dev = netdev_priv(netdev);
0074     int ret;
0075 
0076     ret = pla_write_word(dev, OCP_BASE, 0xa000);
0077     if (ret < 0)
0078         goto out;
0079 
0080     ret = pla_read_word(dev, 0xb400 + reg * 2);
0081 
0082 out:
0083     return ret;
0084 }
0085 
0086 static void r8153_ecm_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
0087 {
0088     struct usbnet *dev = netdev_priv(netdev);
0089     int ret;
0090 
0091     ret = pla_write_word(dev, OCP_BASE, 0xa000);
0092     if (ret < 0)
0093         return;
0094 
0095     ret = pla_write_word(dev, 0xb400 + reg * 2, val);
0096 }
0097 
0098 static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
0099 {
0100     int status;
0101 
0102     status = usbnet_cdc_bind(dev, intf);
0103     if (status < 0)
0104         return status;
0105 
0106     dev->mii.dev = dev->net;
0107     dev->mii.mdio_read = r8153_ecm_mdio_read;
0108     dev->mii.mdio_write = r8153_ecm_mdio_write;
0109     dev->mii.reg_num_mask = 0x1f;
0110     dev->mii.supports_gmii = 1;
0111 
0112     return status;
0113 }
0114 
0115 static const struct driver_info r8153_info = {
0116     .description =  "RTL8153 ECM Device",
0117     .flags =    FLAG_ETHER,
0118     .bind =     r8153_bind,
0119     .unbind =   usbnet_cdc_unbind,
0120     .status =   usbnet_cdc_status,
0121     .manage_power = usbnet_manage_power,
0122 };
0123 
0124 static const struct usb_device_id products[] = {
0125 /* Realtek RTL8153 Based USB 3.0 Ethernet Adapters */
0126 {
0127     USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID_REALTEK, 0x8153, USB_CLASS_COMM,
0128                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
0129     .driver_info = (unsigned long)&r8153_info,
0130 },
0131 
0132 /* Lenovo Powered USB-C Travel Hub (4X90S92381, based on Realtek RTL8153) */
0133 {
0134     USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID_LENOVO, 0x721e, USB_CLASS_COMM,
0135                       USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
0136     .driver_info = (unsigned long)&r8153_info,
0137 },
0138 
0139     { },        /* END */
0140 };
0141 MODULE_DEVICE_TABLE(usb, products);
0142 
0143 static int rtl8153_ecm_probe(struct usb_interface *intf,
0144                  const struct usb_device_id *id)
0145 {
0146 #if IS_REACHABLE(CONFIG_USB_RTL8152)
0147     if (rtl8152_get_version(intf))
0148         return -ENODEV;
0149 #endif
0150 
0151     return usbnet_probe(intf, id);
0152 }
0153 
0154 static struct usb_driver r8153_ecm_driver = {
0155     .name =     "r8153_ecm",
0156     .id_table = products,
0157     .probe =    rtl8153_ecm_probe,
0158     .disconnect =   usbnet_disconnect,
0159     .suspend =  usbnet_suspend,
0160     .resume =   usbnet_resume,
0161     .reset_resume = usbnet_resume,
0162     .supports_autosuspend = 1,
0163     .disable_hub_initiated_lpm = 1,
0164 };
0165 
0166 module_usb_driver(r8153_ecm_driver);
0167 
0168 MODULE_AUTHOR("Hayes Wang");
0169 MODULE_DESCRIPTION("Realtek USB ECM device");
0170 MODULE_LICENSE("GPL");