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