-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net/usb/r8153_ecm: support ECM mode for RTL8153
Support ECM mode based on cdc_ether with relative mii functions, when CONFIG_USB_RTL8152 is not set, or the device is not supported by r8152 driver. Both r8152 and r8153_ecm would check the return value of rtl8152_get_version() in porbe(). If rtl8152_get_version() return none zero value, the r8152 is used for the device with vendor mode. Otherwise, the r8153_ecm is used for the device with ECM mode. Signed-off-by: Hayes Wang <hayeswang@realtek.com> Link: https://lore.kernel.org/r/1394712342-15778-392-Taiwan-albertk@realtek.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
- Loading branch information
Hayes Wang
authored and
Jakub Kicinski
committed
Nov 6, 2020
1 parent
3ffec6a
commit c1aedf0
Showing
4 changed files
with
204 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// SPDX-License-Identifier: GPL-2.0-or-later | ||
#include <linux/module.h> | ||
#include <linux/netdevice.h> | ||
#include <linux/mii.h> | ||
#include <linux/usb.h> | ||
#include <linux/usb/cdc.h> | ||
#include <linux/usb/usbnet.h> | ||
#include <linux/usb/r8152.h> | ||
|
||
#define OCP_BASE 0xe86c | ||
|
||
static int pla_read_word(struct usbnet *dev, u16 index) | ||
{ | ||
u16 byen = BYTE_EN_WORD; | ||
u8 shift = index & 2; | ||
__le32 tmp; | ||
int ret; | ||
|
||
if (shift) | ||
byen <<= shift; | ||
|
||
index &= ~3; | ||
|
||
ret = usbnet_read_cmd(dev, RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, index, | ||
MCU_TYPE_PLA | byen, &tmp, sizeof(tmp)); | ||
if (ret < 0) | ||
goto out; | ||
|
||
ret = __le32_to_cpu(tmp); | ||
ret >>= (shift * 8); | ||
ret &= 0xffff; | ||
|
||
out: | ||
return ret; | ||
} | ||
|
||
static int pla_write_word(struct usbnet *dev, u16 index, u32 data) | ||
{ | ||
u32 mask = 0xffff; | ||
u16 byen = BYTE_EN_WORD; | ||
u8 shift = index & 2; | ||
__le32 tmp; | ||
int ret; | ||
|
||
data &= mask; | ||
|
||
if (shift) { | ||
byen <<= shift; | ||
mask <<= (shift * 8); | ||
data <<= (shift * 8); | ||
} | ||
|
||
index &= ~3; | ||
|
||
ret = usbnet_read_cmd(dev, RTL8152_REQ_GET_REGS, RTL8152_REQT_READ, index, | ||
MCU_TYPE_PLA | byen, &tmp, sizeof(tmp)); | ||
|
||
if (ret < 0) | ||
goto out; | ||
|
||
data |= __le32_to_cpu(tmp) & ~mask; | ||
tmp = __cpu_to_le32(data); | ||
|
||
ret = usbnet_write_cmd(dev, RTL8152_REQ_SET_REGS, RTL8152_REQT_WRITE, index, | ||
MCU_TYPE_PLA | byen, &tmp, sizeof(tmp)); | ||
|
||
out: | ||
return ret; | ||
} | ||
|
||
static int r8153_ecm_mdio_read(struct net_device *netdev, int phy_id, int reg) | ||
{ | ||
struct usbnet *dev = netdev_priv(netdev); | ||
int ret; | ||
|
||
ret = pla_write_word(dev, OCP_BASE, 0xa000); | ||
if (ret < 0) | ||
goto out; | ||
|
||
ret = pla_read_word(dev, 0xb400 + reg * 2); | ||
|
||
out: | ||
return ret; | ||
} | ||
|
||
static void r8153_ecm_mdio_write(struct net_device *netdev, int phy_id, int reg, int val) | ||
{ | ||
struct usbnet *dev = netdev_priv(netdev); | ||
int ret; | ||
|
||
ret = pla_write_word(dev, OCP_BASE, 0xa000); | ||
if (ret < 0) | ||
return; | ||
|
||
ret = pla_write_word(dev, 0xb400 + reg * 2, val); | ||
} | ||
|
||
static int r8153_bind(struct usbnet *dev, struct usb_interface *intf) | ||
{ | ||
int status; | ||
|
||
status = usbnet_cdc_bind(dev, intf); | ||
if (status < 0) | ||
return status; | ||
|
||
dev->mii.dev = dev->net; | ||
dev->mii.mdio_read = r8153_ecm_mdio_read; | ||
dev->mii.mdio_write = r8153_ecm_mdio_write; | ||
dev->mii.reg_num_mask = 0x1f; | ||
dev->mii.supports_gmii = 1; | ||
|
||
return status; | ||
} | ||
|
||
static const struct driver_info r8153_info = { | ||
.description = "RTL8153 ECM Device", | ||
.flags = FLAG_ETHER, | ||
.bind = r8153_bind, | ||
.unbind = usbnet_cdc_unbind, | ||
.status = usbnet_cdc_status, | ||
.manage_power = usbnet_manage_power, | ||
}; | ||
|
||
static const struct usb_device_id products[] = { | ||
{ | ||
USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID_REALTEK, 0x8153, USB_CLASS_COMM, | ||
USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), | ||
.driver_info = (unsigned long)&r8153_info, | ||
}, | ||
|
||
{ }, /* END */ | ||
}; | ||
MODULE_DEVICE_TABLE(usb, products); | ||
|
||
static int rtl8153_ecm_probe(struct usb_interface *intf, | ||
const struct usb_device_id *id) | ||
{ | ||
#if IS_REACHABLE(CONFIG_USB_RTL8152) | ||
if (rtl8152_get_version(intf)) | ||
return -ENODEV; | ||
#endif | ||
|
||
return usbnet_probe(intf, id); | ||
} | ||
|
||
static struct usb_driver r8153_ecm_driver = { | ||
.name = "r8153_ecm", | ||
.id_table = products, | ||
.probe = rtl8153_ecm_probe, | ||
.disconnect = usbnet_disconnect, | ||
.suspend = usbnet_suspend, | ||
.resume = usbnet_resume, | ||
.reset_resume = usbnet_resume, | ||
.supports_autosuspend = 1, | ||
.disable_hub_initiated_lpm = 1, | ||
}; | ||
|
||
module_usb_driver(r8153_ecm_driver); | ||
|
||
MODULE_AUTHOR("Hayes Wang"); | ||
MODULE_DESCRIPTION("Realtek USB ECM device"); | ||
MODULE_LICENSE("GPL"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
/* SPDX-License-Identifier: GPL-2.0-only */ | ||
/* | ||
* Copyright (c) 2020 Realtek Semiconductor Corp. All rights reserved. | ||
*/ | ||
|
||
#ifndef __LINUX_R8152_H | ||
#define __LINUX_R8152_H | ||
|
||
#define RTL8152_REQT_READ 0xc0 | ||
#define RTL8152_REQT_WRITE 0x40 | ||
#define RTL8152_REQ_GET_REGS 0x05 | ||
#define RTL8152_REQ_SET_REGS 0x05 | ||
|
||
#define BYTE_EN_DWORD 0xff | ||
#define BYTE_EN_WORD 0x33 | ||
#define BYTE_EN_BYTE 0x11 | ||
#define BYTE_EN_SIX_BYTES 0x3f | ||
#define BYTE_EN_START_MASK 0x0f | ||
#define BYTE_EN_END_MASK 0xf0 | ||
|
||
#define MCU_TYPE_PLA 0x0100 | ||
#define MCU_TYPE_USB 0x0000 | ||
|
||
/* Define these values to match your device */ | ||
#define VENDOR_ID_REALTEK 0x0bda | ||
#define VENDOR_ID_MICROSOFT 0x045e | ||
#define VENDOR_ID_SAMSUNG 0x04e8 | ||
#define VENDOR_ID_LENOVO 0x17ef | ||
#define VENDOR_ID_LINKSYS 0x13b1 | ||
#define VENDOR_ID_NVIDIA 0x0955 | ||
#define VENDOR_ID_TPLINK 0x2357 | ||
|
||
#if IS_REACHABLE(CONFIG_USB_RTL8152) | ||
extern u8 rtl8152_get_version(struct usb_interface *intf); | ||
#endif | ||
|
||
#endif /* __LINUX_R8152_H */ |