]> rtime.felk.cvut.cz Git - linux-imx.git/blob - drivers/net/usb/r815x.c
Merge branch 'slab/for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/penber...
[linux-imx.git] / drivers / net / usb / r815x.c
1 #include <linux/module.h>
2 #include <linux/netdevice.h>
3 #include <linux/mii.h>
4 #include <linux/usb.h>
5 #include <linux/usb/cdc.h>
6 #include <linux/usb/usbnet.h>
7
8 #define RTL815x_REQT_READ       0xc0
9 #define RTL815x_REQT_WRITE      0x40
10 #define RTL815x_REQ_GET_REGS    0x05
11 #define RTL815x_REQ_SET_REGS    0x05
12
13 #define MCU_TYPE_PLA            0x0100
14 #define OCP_BASE                0xe86c
15 #define BASE_MII                0xa400
16
17 #define BYTE_EN_DWORD           0xff
18 #define BYTE_EN_WORD            0x33
19 #define BYTE_EN_BYTE            0x11
20
21 #define R815x_PHY_ID            32
22 #define REALTEK_VENDOR_ID       0x0bda
23
24
25 static int pla_read_word(struct usb_device *udev, u16 index)
26 {
27         int data, ret;
28         u8 shift = index & 2;
29         __le32 ocp_data;
30
31         index &= ~3;
32
33         ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
34                               RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
35                               index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
36                               500);
37         if (ret < 0)
38                 return ret;
39
40         data = __le32_to_cpu(ocp_data);
41         data >>= (shift * 8);
42         data &= 0xffff;
43
44         return data;
45 }
46
47 static int pla_write_word(struct usb_device *udev, u16 index, u32 data)
48 {
49         __le32 ocp_data;
50         u32 mask = 0xffff;
51         u16 byen = BYTE_EN_WORD;
52         u8 shift = index & 2;
53         int ret;
54
55         data &= mask;
56
57         if (shift) {
58                 byen <<= shift;
59                 mask <<= (shift * 8);
60                 data <<= (shift * 8);
61                 index &= ~3;
62         }
63
64         ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
65                               RTL815x_REQ_GET_REGS, RTL815x_REQT_READ,
66                               index, MCU_TYPE_PLA, &ocp_data, sizeof(ocp_data),
67                               500);
68         if (ret < 0)
69                 return ret;
70
71         data |= __le32_to_cpu(ocp_data) & ~mask;
72         ocp_data = __cpu_to_le32(data);
73
74         ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
75                               RTL815x_REQ_SET_REGS, RTL815x_REQT_WRITE,
76                               index, MCU_TYPE_PLA | byen, &ocp_data,
77                               sizeof(ocp_data), 500);
78
79         return ret;
80 }
81
82 static int ocp_reg_read(struct usbnet *dev, u16 addr)
83 {
84         u16 ocp_base, ocp_index;
85         int ret;
86
87         ocp_base = addr & 0xf000;
88         ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
89         if (ret < 0)
90                 goto out;
91
92         ocp_index = (addr & 0x0fff) | 0xb000;
93         ret = pla_read_word(dev->udev, ocp_index);
94
95 out:
96         return ret;
97 }
98
99 static int ocp_reg_write(struct usbnet *dev, u16 addr, u16 data)
100 {
101         u16 ocp_base, ocp_index;
102         int ret;
103
104         ocp_base = addr & 0xf000;
105         ret = pla_write_word(dev->udev, OCP_BASE, ocp_base);
106         if (ret < 0)
107                 goto out1;
108
109         ocp_index = (addr & 0x0fff) | 0xb000;
110         ret = pla_write_word(dev->udev, ocp_index, data);
111
112 out1:
113         return ret;
114 }
115
116 static int r815x_mdio_read(struct net_device *netdev, int phy_id, int reg)
117 {
118         struct usbnet *dev = netdev_priv(netdev);
119
120         if (phy_id != R815x_PHY_ID)
121                 return -EINVAL;
122
123         return ocp_reg_read(dev, BASE_MII + reg * 2);
124 }
125
126 static
127 void r815x_mdio_write(struct net_device *netdev, int phy_id, int reg, int val)
128 {
129         struct usbnet *dev = netdev_priv(netdev);
130
131         if (phy_id != R815x_PHY_ID)
132                 return;
133
134         ocp_reg_write(dev, BASE_MII + reg * 2, val);
135 }
136
137 static int r8153_bind(struct usbnet *dev, struct usb_interface *intf)
138 {
139         int status;
140
141         status = usbnet_cdc_bind(dev, intf);
142         if (status < 0)
143                 return status;
144
145         dev->mii.dev = dev->net;
146         dev->mii.mdio_read = r815x_mdio_read;
147         dev->mii.mdio_write = r815x_mdio_write;
148         dev->mii.phy_id_mask = 0x3f;
149         dev->mii.reg_num_mask = 0x1f;
150         dev->mii.phy_id = R815x_PHY_ID;
151         dev->mii.supports_gmii = 1;
152
153         return 0;
154 }
155
156 static int r8152_bind(struct usbnet *dev, struct usb_interface *intf)
157 {
158         int status;
159
160         status = usbnet_cdc_bind(dev, intf);
161         if (status < 0)
162                 return status;
163
164         dev->mii.dev = dev->net;
165         dev->mii.mdio_read = r815x_mdio_read;
166         dev->mii.mdio_write = r815x_mdio_write;
167         dev->mii.phy_id_mask = 0x3f;
168         dev->mii.reg_num_mask = 0x1f;
169         dev->mii.phy_id = R815x_PHY_ID;
170         dev->mii.supports_gmii = 0;
171
172         return 0;
173 }
174
175 static const struct driver_info r8152_info = {
176         .description =  "RTL8152 ECM Device",
177         .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
178         .bind =         r8152_bind,
179         .unbind =       usbnet_cdc_unbind,
180         .status =       usbnet_cdc_status,
181         .manage_power = usbnet_manage_power,
182 };
183
184 static const struct driver_info r8153_info = {
185         .description =  "RTL8153 ECM Device",
186         .flags =        FLAG_ETHER | FLAG_POINTTOPOINT,
187         .bind =         r8153_bind,
188         .unbind =       usbnet_cdc_unbind,
189         .status =       usbnet_cdc_status,
190         .manage_power = usbnet_manage_power,
191 };
192
193 static const struct usb_device_id products[] = {
194 {
195         USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM,
196                         USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
197 #if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE)
198         .driver_info = 0,
199 #else
200         .driver_info = (unsigned long) &r8152_info,
201 #endif
202 },
203
204 {
205         USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM,
206                         USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE),
207 #if defined(CONFIG_USB_RTL8153) || defined(CONFIG_USB_RTL8153_MODULE)
208         .driver_info = 0,
209 #else
210         .driver_info = (unsigned long) &r8153_info,
211 #endif
212 },
213
214         { },            /* END */
215 };
216 MODULE_DEVICE_TABLE(usb, products);
217
218 static struct usb_driver r815x_driver = {
219         .name =         "r815x",
220         .id_table =     products,
221         .probe =        usbnet_probe,
222         .disconnect =   usbnet_disconnect,
223         .suspend =      usbnet_suspend,
224         .resume =       usbnet_resume,
225         .reset_resume = usbnet_resume,
226         .supports_autosuspend = 1,
227         .disable_hub_initiated_lpm = 1,
228 };
229
230 module_usb_driver(r815x_driver);
231
232 MODULE_AUTHOR("Hayes Wang");
233 MODULE_DESCRIPTION("Realtek USB ECM device");
234 MODULE_LICENSE("GPL");