0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/device.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/usb.h>
0013
0014 #include "c67x00.h"
0015 #include "c67x00-hcd.h"
0016
0017
0018
0019
0020
0021 static __u8 c67x00_hub_des[] = {
0022 0x09,
0023 USB_DT_HUB,
0024 0x02,
0025 0x00,
0026 0x00,
0027 0x32,
0028 0x00,
0029 0x00,
0030 0xff,
0031 };
0032
0033 static void c67x00_hub_reset_host_port(struct c67x00_sie *sie, int port)
0034 {
0035 struct c67x00_hcd *c67x00 = sie->private_data;
0036 unsigned long flags;
0037
0038 c67x00_ll_husb_reset(sie, port);
0039
0040 spin_lock_irqsave(&c67x00->lock, flags);
0041 c67x00_ll_husb_reset_port(sie, port);
0042 spin_unlock_irqrestore(&c67x00->lock, flags);
0043
0044 c67x00_ll_set_husb_eot(sie->dev, DEFAULT_EOT);
0045 }
0046
0047 static int c67x00_hub_status_data(struct usb_hcd *hcd, char *buf)
0048 {
0049 struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
0050 struct c67x00_sie *sie = c67x00->sie;
0051 u16 status;
0052 int i;
0053
0054 *buf = 0;
0055 status = c67x00_ll_usb_get_status(sie);
0056 for (i = 0; i < C67X00_PORTS; i++)
0057 if (status & PORT_CONNECT_CHANGE(i))
0058 *buf |= (1 << i);
0059
0060
0061 *buf <<= 1;
0062
0063 return !!*buf;
0064 }
0065
0066 static int c67x00_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
0067 u16 wIndex, char *buf, u16 wLength)
0068 {
0069 struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
0070 struct c67x00_sie *sie = c67x00->sie;
0071 u16 status, usb_status;
0072 int len = 0;
0073 unsigned int port = wIndex-1;
0074 u16 wPortChange, wPortStatus;
0075
0076 switch (typeReq) {
0077
0078 case GetHubStatus:
0079 *(__le32 *) buf = cpu_to_le32(0);
0080 len = 4;
0081 break;
0082
0083 case GetPortStatus:
0084 if (wIndex > C67X00_PORTS)
0085 return -EPIPE;
0086
0087 status = c67x00_ll_usb_get_status(sie);
0088 usb_status = c67x00_ll_get_usb_ctl(sie);
0089
0090 wPortChange = 0;
0091 if (status & PORT_CONNECT_CHANGE(port))
0092 wPortChange |= USB_PORT_STAT_C_CONNECTION;
0093
0094 wPortStatus = USB_PORT_STAT_POWER;
0095 if (!(status & PORT_SE0_STATUS(port)))
0096 wPortStatus |= USB_PORT_STAT_CONNECTION;
0097 if (usb_status & LOW_SPEED_PORT(port)) {
0098 wPortStatus |= USB_PORT_STAT_LOW_SPEED;
0099 c67x00->low_speed_ports |= (1 << port);
0100 } else
0101 c67x00->low_speed_ports &= ~(1 << port);
0102
0103 if (usb_status & SOF_EOP_EN(port))
0104 wPortStatus |= USB_PORT_STAT_ENABLE;
0105
0106 *(__le16 *) buf = cpu_to_le16(wPortStatus);
0107 *(__le16 *) (buf + 2) = cpu_to_le16(wPortChange);
0108 len = 4;
0109 break;
0110
0111 case SetHubFeature:
0112 case ClearHubFeature:
0113 switch (wValue) {
0114 case C_HUB_OVER_CURRENT:
0115 case C_HUB_LOCAL_POWER:
0116 len = 0;
0117 break;
0118
0119 default:
0120 return -EPIPE;
0121 }
0122 break;
0123
0124 case SetPortFeature:
0125 if (wIndex > C67X00_PORTS)
0126 return -EPIPE;
0127
0128 switch (wValue) {
0129 case USB_PORT_FEAT_SUSPEND:
0130 dev_dbg(c67x00_hcd_dev(c67x00),
0131 "SetPortFeature %d (SUSPEND)\n", port);
0132 len = 0;
0133 break;
0134
0135 case USB_PORT_FEAT_RESET:
0136 c67x00_hub_reset_host_port(sie, port);
0137 len = 0;
0138 break;
0139
0140 case USB_PORT_FEAT_POWER:
0141
0142 len = 0;
0143 break;
0144
0145 default:
0146 dev_dbg(c67x00_hcd_dev(c67x00),
0147 "%s: SetPortFeature %d (0x%04x) Error!\n",
0148 __func__, port, wValue);
0149 return -EPIPE;
0150 }
0151 break;
0152
0153 case ClearPortFeature:
0154 if (wIndex > C67X00_PORTS)
0155 return -EPIPE;
0156
0157 switch (wValue) {
0158 case USB_PORT_FEAT_ENABLE:
0159
0160
0161 c67x00_hub_reset_host_port(sie, port);
0162 len = 0;
0163 break;
0164
0165 case USB_PORT_FEAT_C_ENABLE:
0166 dev_dbg(c67x00_hcd_dev(c67x00),
0167 "ClearPortFeature (%d): C_ENABLE\n", port);
0168 len = 0;
0169 break;
0170
0171 case USB_PORT_FEAT_SUSPEND:
0172 dev_dbg(c67x00_hcd_dev(c67x00),
0173 "ClearPortFeature (%d): SUSPEND\n", port);
0174 len = 0;
0175 break;
0176
0177 case USB_PORT_FEAT_C_SUSPEND:
0178 dev_dbg(c67x00_hcd_dev(c67x00),
0179 "ClearPortFeature (%d): C_SUSPEND\n", port);
0180 len = 0;
0181 break;
0182
0183 case USB_PORT_FEAT_POWER:
0184 dev_dbg(c67x00_hcd_dev(c67x00),
0185 "ClearPortFeature (%d): POWER\n", port);
0186 return -EPIPE;
0187
0188 case USB_PORT_FEAT_C_CONNECTION:
0189 c67x00_ll_usb_clear_status(sie,
0190 PORT_CONNECT_CHANGE(port));
0191 len = 0;
0192 break;
0193
0194 case USB_PORT_FEAT_C_OVER_CURRENT:
0195 dev_dbg(c67x00_hcd_dev(c67x00),
0196 "ClearPortFeature (%d): OVER_CURRENT\n", port);
0197 len = 0;
0198 break;
0199
0200 case USB_PORT_FEAT_C_RESET:
0201 dev_dbg(c67x00_hcd_dev(c67x00),
0202 "ClearPortFeature (%d): C_RESET\n", port);
0203 len = 0;
0204 break;
0205
0206 default:
0207 dev_dbg(c67x00_hcd_dev(c67x00),
0208 "%s: ClearPortFeature %d (0x%04x) Error!\n",
0209 __func__, port, wValue);
0210 return -EPIPE;
0211 }
0212 break;
0213
0214 case GetHubDescriptor:
0215 len = min_t(unsigned int, sizeof(c67x00_hub_des), wLength);
0216 memcpy(buf, c67x00_hub_des, len);
0217 break;
0218
0219 default:
0220 dev_dbg(c67x00_hcd_dev(c67x00), "%s: unknown\n", __func__);
0221 return -EPIPE;
0222 }
0223
0224 return 0;
0225 }
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
0237 {
0238 struct c67x00_hcd *c67x00 = sie->private_data;
0239 struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
0240
0241
0242 if (msg) {
0243 if (msg & HUSB_TDListDone)
0244 c67x00_sched_kick(c67x00);
0245 else
0246 dev_warn(c67x00_hcd_dev(c67x00),
0247 "Unknown SIE msg flag(s): 0x%04x\n", msg);
0248 }
0249
0250 if (unlikely(hcd->state == HC_STATE_HALT))
0251 return;
0252
0253 if (!HCD_HW_ACCESSIBLE(hcd))
0254 return;
0255
0256
0257 if (int_status & SOFEOP_FLG(sie->sie_num)) {
0258 c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
0259 c67x00_sched_kick(c67x00);
0260 }
0261 }
0262
0263
0264
0265
0266 static int c67x00_hcd_start(struct usb_hcd *hcd)
0267 {
0268 hcd->uses_new_polling = 1;
0269 hcd->state = HC_STATE_RUNNING;
0270 set_bit(HCD_FLAG_POLL_RH, &hcd->flags);
0271
0272 return 0;
0273 }
0274
0275
0276
0277
0278 static void c67x00_hcd_stop(struct usb_hcd *hcd)
0279 {
0280
0281 }
0282
0283 static int c67x00_hcd_get_frame(struct usb_hcd *hcd)
0284 {
0285 struct c67x00_hcd *c67x00 = hcd_to_c67x00_hcd(hcd);
0286 u16 temp_val;
0287
0288 dev_dbg(c67x00_hcd_dev(c67x00), "%s\n", __func__);
0289 temp_val = c67x00_ll_husb_get_frame(c67x00->sie);
0290 temp_val &= HOST_FRAME_MASK;
0291 return temp_val ? (temp_val - 1) : HOST_FRAME_MASK;
0292 }
0293
0294 static const struct hc_driver c67x00_hc_driver = {
0295 .description = "c67x00-hcd",
0296 .product_desc = "Cypress C67X00 Host Controller",
0297 .hcd_priv_size = sizeof(struct c67x00_hcd),
0298 .flags = HCD_USB11 | HCD_MEMORY,
0299
0300
0301
0302
0303 .start = c67x00_hcd_start,
0304 .stop = c67x00_hcd_stop,
0305
0306
0307
0308
0309 .urb_enqueue = c67x00_urb_enqueue,
0310 .urb_dequeue = c67x00_urb_dequeue,
0311 .endpoint_disable = c67x00_endpoint_disable,
0312
0313
0314
0315
0316 .get_frame_number = c67x00_hcd_get_frame,
0317
0318
0319
0320
0321 .hub_status_data = c67x00_hub_status_data,
0322 .hub_control = c67x00_hub_control,
0323 };
0324
0325
0326
0327
0328
0329 int c67x00_hcd_probe(struct c67x00_sie *sie)
0330 {
0331 struct c67x00_hcd *c67x00;
0332 struct usb_hcd *hcd;
0333 unsigned long flags;
0334 int retval;
0335
0336 if (usb_disabled())
0337 return -ENODEV;
0338
0339 hcd = usb_create_hcd(&c67x00_hc_driver, sie_dev(sie), "c67x00_sie");
0340 if (!hcd) {
0341 retval = -ENOMEM;
0342 goto err0;
0343 }
0344 c67x00 = hcd_to_c67x00_hcd(hcd);
0345
0346 spin_lock_init(&c67x00->lock);
0347 c67x00->sie = sie;
0348
0349 INIT_LIST_HEAD(&c67x00->list[PIPE_ISOCHRONOUS]);
0350 INIT_LIST_HEAD(&c67x00->list[PIPE_INTERRUPT]);
0351 INIT_LIST_HEAD(&c67x00->list[PIPE_CONTROL]);
0352 INIT_LIST_HEAD(&c67x00->list[PIPE_BULK]);
0353 c67x00->urb_count = 0;
0354 INIT_LIST_HEAD(&c67x00->td_list);
0355 c67x00->td_base_addr = CY_HCD_BUF_ADDR + SIE_TD_OFFSET(sie->sie_num);
0356 c67x00->buf_base_addr = CY_HCD_BUF_ADDR + SIE_BUF_OFFSET(sie->sie_num);
0357 c67x00->max_frame_bw = MAX_FRAME_BW_STD;
0358
0359 c67x00_ll_husb_init_host_port(sie);
0360
0361 init_completion(&c67x00->endpoint_disable);
0362 retval = c67x00_sched_start_scheduler(c67x00);
0363 if (retval)
0364 goto err1;
0365
0366 retval = usb_add_hcd(hcd, 0, 0);
0367 if (retval) {
0368 dev_dbg(sie_dev(sie), "%s: usb_add_hcd returned %d\n",
0369 __func__, retval);
0370 goto err2;
0371 }
0372
0373 device_wakeup_enable(hcd->self.controller);
0374
0375 spin_lock_irqsave(&sie->lock, flags);
0376 sie->private_data = c67x00;
0377 sie->irq = c67x00_hcd_irq;
0378 spin_unlock_irqrestore(&sie->lock, flags);
0379
0380 return retval;
0381
0382 err2:
0383 c67x00_sched_stop_scheduler(c67x00);
0384 err1:
0385 usb_put_hcd(hcd);
0386 err0:
0387 return retval;
0388 }
0389
0390
0391 void c67x00_hcd_remove(struct c67x00_sie *sie)
0392 {
0393 struct c67x00_hcd *c67x00 = sie->private_data;
0394 struct usb_hcd *hcd = c67x00_hcd_to_hcd(c67x00);
0395
0396 c67x00_sched_stop_scheduler(c67x00);
0397 usb_remove_hcd(hcd);
0398 usb_put_hcd(hcd);
0399 }