2020-8-9 常见对象_05

Date类:

概述:

Date类表示特定的瞬间,精确到毫秒;

构造方法:

1.public Date():分配Date对象并初始化此对象,以分配它的时间;

2.public Date(long Date):分配Date对象并初始化此对象,以表示自从标准基准时间以来的毫秒偏移;

成员方法:

1.public long getTime():获取时间,以毫秒为单位;

2.public void setTime(long time):设置时间;

DateFormat类:

概述:

DateFormat是日期/时间格式化子类的抽象类,它以与语言无关的方式格式化并解析时间或日期;

是抽象类,所以使用其子类SimpleDateFormat;

SimpleDateFormat构造方法:

1.public SimpleDateFormat():用默认的模式和默认语言环境的日期格式符号构造SimpleDateFormat;

2.public SimpleDateFormat(String pattern):用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat;

SimpleDateFormat成员方法:

1.public final String format(Date date):将Date类型的数据格式化为String类型;

2.public final Date parse(String source):将String类型的数据解析为Date类型;

模式字母:

y:年;

M:年中的月份;

d:月份中的天数;

H:一天中的小时数;

m:小时中的分钟数;

s:分钟中的毫秒数;

注意:再把一个字符串解析为Date类型的数据时,请注意模式,必须和给定的字符串相匹配;

Calendar类:

概述:

Calendar类是一个抽象类,它为特定瞬间与值诸如YEAR,MONTH,DAY_OF_MONTH,HOUR等日历字段之间的转换提供了一些方法,并用于操作日历字段;

日历类中的每个日历字段都是静态的成员变量,并且是int类型(例 public static YEAR);

成员方法:

1.public static Calendar getInstance():返回一个Calendar对象;

2.public int get(int field):返回给定的日历字段的值;

3.public void add(int field,int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量;

4.public final void set(int year,int month,int date):设置年月日,需要注意的是,月份是从0开始的,比如设置三月,month的值应为2;

集合:

数组和集合的区别:

数组虽然也可以存储对象,但长度是固定的,集合长度是可变的,数组中可以存储基本数据类型,集合只能存储对象;

集合分类:

淦,给老子显示图片啊

Collection:

添加功能:

1.public boolean add(E e):追加一个元素;

2.public boolean addAll(Collection<? extends E>):将Collection中的所有元素添加到集合中;

删除功能:

1.public void clear():删除集合中的所有元素;

2,public boolean remove(Object o):移除集合中的指定元素;

3.public boolean removeAll(Collection<?> e):删除集合中Collection所包含的所有元素;

判断功能:

1.public boolean contains(Object o):判断集合中是否包含指定元素;

2.public boolean containsAll(Collection<?> e):判断集合是否包含Collection中的所有元素;

3.public boolean isEmpty():判断集合是否为空集合;

获取功能:

1.public Iterator <E> iterator:

返回在此Collection的元素上进行迭代的迭代器;

获取长度:

public int size():获取集合的长度;

交集功能:

public boolean retainAll(Collection c):保留集合中与Collection集合有交集的部分,并判断集合是否改变,如果元素改变,返回true,元素不变,返回false;

Iterator迭代器:

成员方法:

1.public boolean hasnext():判断是否有下一个元素可以迭代;

2.public E next():返回迭代器的下一个元素;

List的特有功能:

添加功能:

1.public void add(int index, E element):在指定位置添加元素;

2.public boolean addAll(int index,Collection<? extends E> e):在指定位置添加Collection中的所有元素;

获取功能:

1.public E get(int index):返回列表中指定位置的元素;

2.public ListIterator<E> listIterator():返回此列表元素的列表迭代器;

3.public ListIterator<E> listIterator(int index):返回从指定下标开始的列表迭代器;

删除功能:

1.public E remove(int index):移除指定位置的元素;

截取功能:

public List<E> subList(int fromindex,int offindex):截取,不解释;

ListIterator特有方法:

成员方法:

1.public boolean hasPrevious():判断是否有上一个元素;

2.public E previous:返回上一个元素;

3.public void add(E e):将指定的元素追加到列表;

注意:先正向遍历,才能逆向遍历,一般无意义,不实用;

List的子类特点:

ArrayList:

底层数据结构为数组,查询快,增删慢,因为线程不安全,效率高;

Vector:

底层数据结构为数组,查询快,增删慢,因为线程安全,效率低;

LinkedList:

底层数据结构为链表,查询慢,增删快,因为线程不安全,效率高;

Vector类特有功能(已过时):

1.public void addElement(E obj)[add]:添加;

2.public Eelement elementAt(int index)[get]:获取;

3.public Enumeration elements()[iterator]:类似迭代器;(public boolean hasMoreElement();public Object nextElement());

LinkedList类特有功能:

1.public void addFirst(E e)及addLast(E e):在指定位置添加元素;

2.public E getFirst()及getLast():获取指定位置元素;

3.public E removeFirst()及removeLast():移除指定位置元素; 		
/* * msb250x_udc.c - Sigmastar * * Copyright (c) [2019~2020] SigmaStar Technology. * * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License version 2 for more details. * */ #include <common.h> #include <linux/list.h> #include <linux/bug.h> #include <linux/delay.h> #include <linux/usb/gadget.h> #include <dm.h> #include <reset.h> #include "msb250x_udc.h" #include <dm/device-internal.h> static int msb250x_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc); static int msb250x_ep_disable(struct usb_ep *_ep); static struct usb_request *msb250x_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags); static void msb250x_ep_free_request(struct usb_ep *ep, struct usb_request *_req); static int msb250x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags); static int msb250x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req); static int msb250x_ep_set_halt(struct usb_ep *_ep, int value); static int msb250x_ep_fifo_status(struct usb_ep *_ep); static void msb250x_ep_fifo_flush(struct usb_ep *_ep); static int msb250x_usb_pullup(struct usb_gadget *_gadget, int is_active); static int msb250x_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver); static int msb250x_udc_stop(struct usb_gadget *g); static const char driver_name[] = "msb250x_udc"; static const char ep0name[] = "ep0"; static struct usb_ep_ops msb250x_ep_ops = { .enable = msb250x_ep_enable, .disable = msb250x_ep_disable, .alloc_request = msb250x_ep_alloc_request, .free_request = msb250x_ep_free_request, .queue = msb250x_ep_queue, .dequeue = msb250x_ep_dequeue, .set_halt = msb250x_ep_set_halt, .fifo_status = msb250x_ep_fifo_status, .fifo_flush = msb250x_ep_fifo_flush, }; static struct usb_gadget_ops msb250x_gadget_ops = { .pullup = msb250x_usb_pullup, .udc_start = msb250x_udc_start, .udc_stop = msb250x_udc_stop, }; static struct msb250x_udc memory = { .gadget = { .ops = &msb250x_gadget_ops, .ep0 = &memory.ep[0].ep, .max_speed = USB_SPEED_HIGH, .name = driver_name, }, MSB250X_EPS_CAP(&memory, &msb250x_ep_ops), }; static void msb250x_reset_otg(void) { sstar_writeb(sstar_readb(MSB250X_OTG0_USB_CFG0_L) & ~MSB250X_OTG0_CFG0_SRST_N, MSB250X_OTG0_USB_CFG0_L); // low active sstar_writeb(sstar_readb(MSB250X_OTG0_USB_CFG0_L) | MSB250X_OTG0_CFG0_SRST_N, MSB250X_OTG0_USB_CFG0_L); // default set as 1 } static void msb250x_request_done(struct msb250x_ep *ep, struct msb250x_request *req, int status) { if (likely(req->req.status == -EINPROGRESS)) { req->req.status = status; } else { status = req->req.status; } if (status && status != -ESHUTDOWN) { debug("complete %s req %p stat %d len %u/%u\n", ep->ep.name, &req->req, status, req->req.actual, req->req.length); } usb_gadget_giveback_request(&ep->ep, &req->req); } static void msb250x_request_nuke(struct msb250x_ep *ep, int status) { struct msb250x_request *req, *r; list_for_each_entry_safe(req, r, &ep->queue, queue) { list_del_init(&req->queue); msb250x_request_done(ep, req, status); } } int msb250x_udc_get_autoNAK_cfg(u8 ep_num) { int cfg = 0; u8 ep_bulkout = 0; for (cfg = 0; cfg < AUTONAK_COUNT; cfg++) { switch (cfg) { case 0: ep_bulkout = (sstar_readb(MSB250X_OTG0_AUTONAK0_EP_BULKOUT) & 0x0f); break; case 1: ep_bulkout = (sstar_readb(MSB250X_OTG0_AUTONAK1_EP_BULKOUT) & 0x0f); break; case 2: ep_bulkout = (sstar_readb(MSB250X_OTG0_AUTONAK2_EP_BULKOUT) & 0xf0); ep_bulkout = ep_bulkout >> 4; break; } if (0 == ep_bulkout) { return (cfg + 1); } } return 0; } int msb250x_udc_disable_autoNAK_cfg(u8 cfg) { cfg--; switch (cfg) { case 0: sstar_writeb((sstar_readb(MSB250X_OTG0_AUTONAK0_EP_BULKOUT) & 0xf0), MSB250X_OTG0_AUTONAK0_EP_BULKOUT); sstar_writew(0, MSB250X_OTG0_AUTONAK0_CTRL); break; case 1: sstar_writeb((sstar_readb(MSB250X_OTG0_AUTONAK1_EP_BULKOUT) & 0xf0), MSB250X_OTG0_AUTONAK1_EP_BULKOUT); sstar_writeb( (sstar_readb(MSB250X_OTG0_AUTONAK1_CTRL) & ~(MSB250X_OTG0_AUTONAK1_EN | MSB250X_OTG0_AUTONAK1_OK2Rcv | MSB250X_OTG0_AUTONAK1_AllowAck)), MSB250X_OTG0_AUTONAK1_CTRL); sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK1_RX_PKT_CNT) & 0xE000), MSB250X_OTG0_AUTONAK1_RX_PKT_CNT); break; case 2: sstar_writeb((sstar_readb(MSB250X_OTG0_AUTONAK2_EP_BULKOUT) & 0x0f), MSB250X_OTG0_AUTONAK2_EP_BULKOUT); sstar_writew( (sstar_readw(MSB250X_OTG0_AUTONAK2_CTRL) & ~(MSB250X_OTG0_AUTONAK2_EN | MSB250X_OTG0_AUTONAK2_OK2Rcv | MSB250X_OTG0_AUTONAK2_AllowAck)), MSB250X_OTG0_AUTONAK2_CTRL); sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK2_RX_PKT_CNT) & 0xE000), MSB250X_OTG0_AUTONAK2_RX_PKT_CNT); break; } return 0; } int msb250x_udc_init_autoNAK_cfg(void) { int cfg = 0; for (cfg = 0; cfg < AUTONAK_COUNT; cfg++) { msb250x_udc_disable_autoNAK_cfg((cfg + 1)); } // sstar_writew(0, MSB250X_OTG0_USB_CFG5); // sstar_writeb((sstar_readb(MSB250X_OTG0_USB_CFG6_H) | 0x20), MSB250X_OTG0_USB_CFG6_H);//short_mode return 0; } void msb250x_udc_enable_autoNAK(u8 ep_num, u8 cfg) { cfg--; switch (cfg) { case 0: ep_num &= 0x0f; sstar_writeb(ep_num, MSB250X_OTG0_AUTONAK0_EP_BULKOUT); { u16 ctrl = 0; ctrl |= MSB250X_OTG0_AUTONAK0_EN; sstar_writew(ctrl, MSB250X_OTG0_AUTONAK0_CTRL); } break; case 1: ep_num &= 0x0f; sstar_writeb(MSB250X_OTG0_AUTONAK1_EN | ep_num, MSB250X_OTG0_AUTONAK1_CTRL); sstar_writeb((sstar_readb(MSB250X_OTG0_AUTONAK1_CTRL) & ~(MSB250X_OTG0_AUTONAK1_OK2Rcv | MSB250X_OTG0_AUTONAK1_AllowAck)), MSB250X_OTG0_AUTONAK1_CTRL); sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK1_RX_PKT_CNT) & 0xE000), MSB250X_OTG0_AUTONAK1_RX_PKT_CNT); break; case 2: ep_num = ep_num << 4; ep_num &= 0xf0; sstar_writew(MSB250X_OTG0_AUTONAK2_EN | (u16)ep_num, MSB250X_OTG0_AUTONAK2_CTRL); sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK2_CTRL) & ~(MSB250X_OTG0_AUTONAK2_OK2Rcv | (u16)MSB250X_OTG0_AUTONAK2_AllowAck)), MSB250X_OTG0_AUTONAK2_CTRL); sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK2_RX_PKT_CNT) & 0xE000), MSB250X_OTG0_AUTONAK2_RX_PKT_CNT); break; } debug("<USB>[NAK][%d] NAK enabled.\n", cfg); } void msb250x_udc_ok2rcv_for_packets(u8 cfg, u16 pkt_num) { u16 ctrl = 0; cfg--; #if defined(GPIO_LED0_ENABLED) if (0 < pkt_num) { sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)) | BIT1, GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)); } else { sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)) & ~BIT1, GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)); } #endif switch (cfg) { case 0: ctrl |= MSB250X_OTG0_AUTONAK0_EN; ctrl |= (pkt_num & ~0xE000); if (0 < pkt_num) { ctrl |= MSB250X_OTG0_AUTONAK0_OK2Rcv; } sstar_writew(ctrl, MSB250X_OTG0_AUTONAK0_CTRL); break; case 1: sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK1_RX_PKT_CNT) & ~0xE000) | pkt_num, MSB250X_OTG0_AUTONAK1_RX_PKT_CNT); ctrl = sstar_readb(MSB250X_OTG0_AUTONAK1_CTRL); if (0 < pkt_num) { ctrl |= MSB250X_OTG0_AUTONAK1_OK2Rcv; } sstar_writeb(ctrl & 0xFF, MSB250X_OTG0_AUTONAK1_CTRL); break; case 2: sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK2_RX_PKT_CNT) & ~0xE000) | pkt_num, MSB250X_OTG0_AUTONAK2_RX_PKT_CNT); ctrl = sstar_readw(MSB250X_OTG0_AUTONAK2_CTRL); if (0 < pkt_num) { ctrl |= MSB250X_OTG0_AUTONAK2_OK2Rcv; } sstar_writew(ctrl, MSB250X_OTG0_AUTONAK2_CTRL); break; } debug("<USB>[NAK][%d] ok2rcv %d packets\n", cfg, pkt_num); } void msb250x_udc_allowAck(u8 cfg) { cfg--; switch (cfg) { case 0: sstar_writew(sstar_readw(MSB250X_OTG0_AUTONAK0_CTRL), MSB250X_OTG0_AUTONAK0_CTRL); sstar_writew((sstar_readw(MSB250X_OTG0_AUTONAK0_CTRL) | MSB250X_OTG0_AUTONAK0_AllowAck), MSB250X_OTG0_AUTONAK0_CTRL); break; case 1: sstar_writeb(sstar_readb(MSB250X_OTG0_AUTONAK1_CTRL), MSB250X_OTG0_AUTONAK1_CTRL); sstar_writeb((sstar_readb(MSB250X_OTG0_AUTONAK1_CTRL) | MSB250X_OTG0_AUTONAK1_AllowAck), MSB250X_OTG0_AUTONAK1_CTRL); break; case 2: sstar_writeb(sstar_readb(MSB250X_OTG0_AUTONAK2_CTRL), MSB250X_OTG0_AUTONAK2_CTRL); sstar_writeb((sstar_readb(MSB250X_OTG0_AUTONAK2_CTRL) | MSB250X_OTG0_AUTONAK2_AllowAck), MSB250X_OTG0_AUTONAK2_CTRL); break; } debug("<USB>[NAK][%d] allowAck\n", cfg); } u16 msb250x_udc_get_pkt_cnt(u8 cfg) { u16 count = 0; cfg--; switch (cfg) { case 0: count = sstar_readw(MSB250X_OTG0_AUTONAK0_CTRL); break; case 1: count = sstar_readw(MSB250X_OTG0_AUTONAK1_RX_PKT_CNT); break; case 2: count = sstar_readw(MSB250X_OTG0_AUTONAK2_RX_PKT_CNT); break; default: count = 0; } count &= ~0xE000; debug("<USB>[NAK][%d] %d packtes\n", cfg, count); return count; } static int msb250x_ep_read_riu(struct msb250x_ep *ep, struct msb250x_request *req) { u8 *buf = NULL; int is_last = 0; u16 count = 0; u16 bytedone = 0; u8 ep_num = 0; ep_num = ep->ep_num; if (0 == req->req.length) { return 1; } buf = req->req.buf + req->req.actual; count = sstar_readw(MSB250X_OTG0_EP_RXCOUNT_REG(ep_num)); if ((req->req.length - req->req.actual) < count) { printf( "<USB_WARN>[RX][%d] Bytes in fifo(0x%04x) is more than buffer size. " "buf/actual/length(0x%p/0x%04x/0x%04x)!\n", ep_num, count, req->req.buf, req->req.actual, req->req.length); } count = min((u16)count, (u16)(req->req.length - req->req.actual)); if (0 < count) { bytedone = count; if ((uintptr_t)buf & 1) { while (bytedone > 0) { *buf++ = sstar_readb(OTG0_EP_FIFO_ACCESS_L(ep_num)); bytedone--; } } else { while (bytedone >= 2) { *(volatile unsigned short *)buf = sstar_readw(OTG0_EP_FIFO_ACCESS_L(ep_num)); buf += 2; bytedone -= 2; } if (bytedone > 0) { *buf++ = sstar_readb(OTG0_EP_FIFO_ACCESS_L(ep_num)); bytedone--; } } req->req.actual += count; if (count != ep->ep.maxpacket || req->req.zero) { is_last = 1; } } is_last = (req->req.length == req->req.actual || 0 == count) ? 1 : is_last; if (0 != ep_num && !usb_endpoint_xfer_int(ep->desc)) { debug("<USB>[RX][%d] count/maxpacket(0x%04x/0x%04x) buff/last/actual/length(%p/%d/0x%04x/0x%04x) \n", ep_num, count, ep->ep.maxpacket, req->req.buf, is_last, req->req.actual, req->req.length); } return is_last; } static int msb250x_ep_write_riu(struct msb250x_ep *ep, struct msb250x_request *req) { u16 count = 0; u32 bytedone = 0; u8 *buf = NULL; int is_last = 0; u8 ep_num = 0; // printf("msb250x_ep_write_riu\n"); ep_num = ep->ep_num; count = min((u32)ep->ep.maxpacket, (u32)(req->req.length - req->req.actual)); buf = req->req.buf + req->req.actual; if (0 < count) { bytedone = count; if ((uintptr_t)buf & 1) { while (bytedone > 0) { sstar_writeb(*buf++, OTG0_EP_FIFO_ACCESS_L(ep_num)); bytedone--; } } else { while (bytedone >= 2) { sstar_writew(*(volatile unsigned short *)buf, OTG0_EP_FIFO_ACCESS_L(ep_num)); buf += 2; bytedone -= 2; } if (bytedone > 0) { sstar_writeb(*buf++, OTG0_EP_FIFO_ACCESS_L(ep_num)); bytedone--; } } req->req.actual += count; } /* last packet is often short (sometimes a zlp) */ if (count != ep->ep.maxpacket || req->req.length == req->req.actual) { is_last = 1; } if (0 != ep_num && !usb_endpoint_xfer_int(ep->desc)) { debug("<USB>[TX][%d] maxpacket/bytesDone(0x%04x/0x%04x) buff/last/actual/length(%p/%d/0x%04x/0x%04x) \n", ep_num, ep->ep.maxpacket, count, req->req.buf, is_last, req->req.actual, req->req.length); } return is_last; } static void msb250x_udc_pullup_i(int is_on) { u8 power = 0; struct otg0_usb_power *pst_power = (struct otg0_usb_power *)&power; power = sstar_readb(MSB250X_OTG0_PWR_REG); pst_power->bSoftConn = is_on; sstar_writeb(power, MSB250X_OTG0_PWR_REG); printf("<USB>[UDC] PULL %s D+.\n", (is_on) ? "UP" : "DOWN"); } struct msb250x_request *msb250x_ep_handle_request(struct msb250x_ep *ep, struct msb250x_request *req) { struct msb250x_udc *dev = ep->dev; #ifndef CONFIG_SSTAR_MSB250X_BULK_OUT_PATCH u16 pkt_num = 0; #endif u8 csr = 0; u8 intrusb = 0; u8 is_last = 0; u8 ep_num = 0; struct otg0_ep0_csr_l * csr_l = NULL; struct otg0_ep_rxcsr_l *rxcsr_l = NULL; struct otg0_ep_txcsr_l *txcsr_l = NULL; struct otg0_usb_intr * st_intrusb = (struct otg0_usb_intr *)&intrusb; ep_num = ep->ep_num; if (1 == st_intrusb->bReset) { return req; } if (0 == ep->halted) { // set_ep_halt(ep, 1); intrusb = sstar_readb(MSB250X_OTG0_INTRUSB_REG); if (1 == st_intrusb->bReset) { return req; } if (0 == ep_num) { csr = sstar_readb(MSB250X_OTG0_EP0_CSR0_REG); csr_l = (struct otg0_ep0_csr_l *)&csr; switch (ep->dev->ep0state) { case EP0_IDLE: if (0 < dev->delay_status) { msb250x_ep0_clear_opr(); dev->delay_status--; is_last = 1; } break; case EP0_IN_DATA_PHASE: if (0 == csr_l->bTxPktRdy) { is_last = msb250x_ep_write_riu(ep, req); if (is_last) { msb250x_ep0_set_de_in(); ep->dev->ep0state = EP0_IDLE; } else { msb250x_ep0_set_ipr(); } } break; case EP0_OUT_DATA_PHASE: if (1 == csr_l->bRxPktRdy) { is_last = msb250x_ep_read_riu(ep, req); if (is_last) { msb250x_ep0_set_de_out(); ep->dev->ep0state = EP0_IDLE; } else { msb250x_ep0_clear_opr(); } } break; default: printf("<USB>[0] Request Error !!\n"); } set_ep_halt(ep, 0); } else { if (usb_endpoint_dir_in(ep->desc)) { txcsr_l = (struct otg0_ep_txcsr_l *)&csr; csr = sstar_readb(MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); // if (0 == (txcsr_l->bTxPktRdy | txcsr_l->bFIFONotEmpty)) if (0 == txcsr_l->bTxPktRdy) { is_last = msb250x_ep_write_riu(ep, req); msb250x_ep_set_ipr(ep_num); } } else if (usb_endpoint_dir_out(ep->desc)) { csr = sstar_readb(MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); rxcsr_l = (struct otg0_ep_rxcsr_l *)&csr; /* DMA RX: */ if (!usb_endpoint_xfer_bulk(ep->desc)) { if (1 == rxcsr_l->bRxPktRdy) { is_last = msb250x_ep_read_riu(ep, req); msb250x_ep_set_ipr(ep_num); set_ep_halt(ep, 0); } } else { #ifndef CONFIG_SSTAR_MSB250X_BULK_OUT_PATCH if (0 == rxcsr_l->bRxPktRdy) { if (1 == ep->shortPkt) { udelay(125); } // msb250x_udc_allowAck(ep->autoNAK_cfg); if (ep->ep.maxpacket >= req->req.length - req->req.actual) { msb250x_udc_allowAck(ep->autoNAK_cfg); ep->shortPkt = 0; } else { pkt_num = ((req->req.length - req->req.actual) + (ep->ep.maxpacket - 1)) / ep->ep.maxpacket; msb250x_udc_ok2rcv_for_packets(ep->autoNAK_cfg, pkt_num); ep->shortPkt = 1; } } else { is_last = msb250x_ep_read_riu(ep, req); msb250x_ep_set_opr(ep_num); } #else if (0 == rxcsr_l->bRxPktRdy) { msb250x_udc_allowAck(ep->autoNAK_cfg); ep->shortPkt = 0; } if (1 == rxcsr_l->bRxPktRdy) { is_last = msb250x_ep_read_riu(ep, req); msb250x_ep_set_opr(ep_num); if (!is_last) { msb250x_udc_allowAck(ep->autoNAK_cfg); } } #endif } } } } if (1 == is_last) { list_del_init(&req->queue); msb250x_request_done(ep, req, 0); req = NULL; } return req; } static void msb250x_udc_init_MIU_sel(void) { printk("<USB> config miu select [%x] [%x] [%x] [%x].\n", USB_MIU_SEL0, USB_MIU_SEL1, USB_MIU_SEL2, USB_MIU_SEL3); sstar_writeb(USB_MIU_SEL0, GET_REG16_ADDR(USBC_BASE_ADDR, 0x0A)); // Setting MIU0 segment sstar_writeb(USB_MIU_SEL1, GET_REG16_ADDR(USBC_BASE_ADDR, 0x0B)); // Setting MIU1 segment sstar_writeb(USB_MIU_SEL2, GET_REG16_ADDR(USBC_BASE_ADDR, 0x0B) + 1); // Setting MIU2 segment sstar_writeb(USB_MIU_SEL3, GET_REG16_ADDR(USBC_BASE_ADDR, 0x0C)); // Setting MIU3 segment sstar_writeb((sstar_readb(GET_REG16_ADDR(USBC_BASE_ADDR, 0x0C) + 1) | 0x1), GET_REG16_ADDR(USBC_BASE_ADDR, 0x0C) + 1); // Enable miu partition mechanism } void msb250x_udc_init_utmi(void) { u8 ctrl_l = 0; struct usbc0_rst_ctrl_l *pst_usbc0_rst_ctrl_l; #ifndef CONFIG_USB_FPGA_VERIFICATION // UTMI sstar_writew(0x0C2F, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x04)); sstar_writew(0x040F, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x04)); // utmi0 sstar_writew(0x7F05, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x00)); sstar_writeb(0x00, GET_REG16_ADDR(USBC_BASE_ADDR, 0x29)); // Module: utmi0 (0x142100) sstar_writew(0x2084, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x01)); // Enable CLK12_SEL bit <2> for select low voltage crystal clock sstar_writew(0x0426, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x04)); // bit<7>: Power down UTMI port-0 bandgap current sstar_writew(0x6BC3, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x00)); // reg_pdn: bit<15>, bit <2> ref_pdn Turn on reference voltage and regulator sstar_writeb(0x3F, GET_REG16_ADDR(USBC_BASE_ADDR, 0x29)); // overwrite off mdelay(1); sstar_writew(0x69C3, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x00)); // Turn on UPLL, reg_pdn: bit<9> sstar_writeb(0x3F, GET_REG16_ADDR(USBC_BASE_ADDR, 0x29)); // overwrite off mdelay(1); sstar_writew(0x0001, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x00)); // Turn all (including hs_current) use override mode sstar_writeb(0x00, GET_REG16_ADDR(USBC_BASE_ADDR, 0x29)); // overwrite off mdelay(3); #ifdef UTMI2_BASE_ADDR /* * Not all chips require utmi2 for upll up. * Add this setting only to those chips has defined utmi2 bank. */ sstar_writew(0x7F05, GET_REG16_ADDR(UTMI2_BASE_ADDR, 0)); // UTMI2 #endif sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x3c)) | 0x01), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x3c)); // set CA_START as 1 mdelay(10); sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x3c)) & ~0x01), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x3c)); // release CA_START while (0 == (sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x3c)) & 0x02)) ; // polling bit <1> (CA_END) sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x06)) & 0x9F) | 0x40, GET_REG8_ADDR(UTMI_BASE_ADDR, 0x06)); // reg_tx_force_hs_current_enable sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x03)) | 0x28), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x03)); // Disconnect window select sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x03)) & 0xef), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x03)); // Disconnect window select sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x07)) & 0xfd), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x07)); // Disable improved CDR sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x09)) | 0x81), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x09)); // UTMI RX anti-dead-loc, ISI effect improvement sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x15)) | 0x20), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x15)); // Chirp signal source select sstar_writeb((sstar_readb(GET_REG8_ADDR(UTMI_BASE_ADDR, 0x0b)) | 0x80), GET_REG8_ADDR(UTMI_BASE_ADDR, 0x0b)); // set reg_ck_inv_reserved[6] to solve timing problem sstar_writeb((sstar_readb(GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16)) | 0x10), GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16)); sstar_writeb((sstar_readb(GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16) + 1) | 0x02), GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16) + 1); sstar_writeb((sstar_readb(GET_REG16_ADDR(UTMI_BASE_ADDR, 0x02)) | 0x80), GET_REG16_ADDR(UTMI_BASE_ADDR, 0x02)); // avoid glitch #else // FPGA(haps) sstar_writew((sstar_readw(GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)) & 0x7fff), GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)); // bit15 = 0 pull low reset sstar_writew((sstar_readw(GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)) & 0xffef), GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)); // bit4 = 0 pull low stp sstar_writew((sstar_readw(GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)) & 0xefff), GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)); // bit12 = 0 enable data bus for riu sstar_writew(0x6184, GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x74)); // command softreset sstar_writew((sstar_readw(GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)) & 0xfffe), GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)); // trigger command sstar_writew((sstar_readw(GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)) | ~(0xefff)), GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)); // bit12 = 1 disable data bus for riu sstar_writew((sstar_readw(GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)) & 0xfeff), GET_REG16_ADDR(CHIPTOP_BASE_ADDR, 0x73)); // bit8 = 0 enable data bus for mac #endif sstar_writeb(((sstar_readb(GET_REG8_ADDR(USBC_BASE_ADDR, 0x01 * 2)) & ~(BIT0 | BIT1)) | BIT1), GET_REG8_ADDR(USBC_BASE_ADDR, 0x01 * 2)); pst_usbc0_rst_ctrl_l = (struct usbc0_rst_ctrl_l *)&ctrl_l; ctrl_l = sstar_readb(GET_REG8_ADDR(USBC_BASE_ADDR, 0x00)); pst_usbc0_rst_ctrl_l->bOTG_RST = 1; pst_usbc0_rst_ctrl_l->bREG_SUSPEND = 1; sstar_writeb(ctrl_l, GET_REG8_ADDR(USBC_BASE_ADDR, 0x00)); ctrl_l = sstar_readb(GET_REG8_ADDR(USBC_BASE_ADDR, 0x00)); pst_usbc0_rst_ctrl_l->bOTG_RST = 0; pst_usbc0_rst_ctrl_l->bOTG_XIU_ENABLE = 1; sstar_writeb(ctrl_l, GET_REG8_ADDR(USBC_BASE_ADDR, 0x00)); // clear otg reset does not take effect after the miu clk count is executed. // Because mcm is enabled by default, the miu clk will be speed down // The patch delay is increased by 1ms. mantibt_id: 3075 mdelay(1); } /* * udc_enable - enable USB device controller */ void msb250x_udc_init_otg(void) { // u8 ep_num = 0; u8 power = 0; u8 usb_cfg_h = 0; u8 otg0_usb_intr = 0; struct otg0_usb_cfg0_h *pst_otg0_usb_cfg0_h = (struct otg0_usb_cfg0_h *)&usb_cfg_h; struct otg0_usb_cfg6_h *pst_otg0_usb_cfg6_h = NULL; struct otg0_usb_power * pst_power = (struct otg0_usb_power *)&power; struct otg0_usb_intr * pst_intr_usb = (struct otg0_usb_intr *)&otg0_usb_intr; debug("<USB> %s[+]\n", __func__); sstar_writeb( (sstar_readb(MSB250X_OTG0_USB_CFG6_H) | (CFG6_H_SHORT_MODE | CFG6_H_BUS_OP_FIX | CFG6_H_REG_MI_WDFIFO_CTRL)), MSB250X_OTG0_USB_CFG6_H); usb_cfg_h = sstar_readb(MSB250X_OTG0_USB_CFG0_H); // printf("<USB> Reset OTG\n"); pst_otg0_usb_cfg0_h->bDMPullDown = 1; sstar_writeb(usb_cfg_h, MSB250X_OTG0_USB_CFG0_H); // Enable DM pull down // printf("<USB> Enable DM pull down\n"); // Set FAddr to 0 sstar_writeb(0, MSB250X_OTG0_FADDR_REG); pst_otg0_usb_cfg6_h = (struct otg0_usb_cfg6_h *)&usb_cfg_h; usb_cfg_h = sstar_readb(MSB250X_OTG0_USB_CFG6_H); pst_otg0_usb_cfg6_h->bINT_WR_CLR_EN = 1; pst_otg0_usb_cfg6_h->bBusOPFix = 1; sstar_writeb(usb_cfg_h, MSB250X_OTG0_USB_CFG6_H); /* USB_REG_WRITE8(M_REG_CFG6_H, USB_REG_READ8(M_REG_CFG6_H) | 0x08); USB_REG_WRITE8(M_REG_CFG6_H, USB_REG_READ8(M_REG_CFG6_H) | 0x40); */ // while(0x18 != (USB_REG_READ8(M_REG_DEVCTL) & 0x18)); power = sstar_readb(MSB250X_OTG0_PWR_REG); pst_power->bSuspendMode = 0; pst_power->bSoftConn = 0; pst_power->bHSEnab = 1; sstar_writeb(power, MSB250X_OTG0_PWR_REG); sstar_writeb(0x00, MSB250X_OTG0_DEVCTL_REG); otg0_usb_intr = 0xff; pst_intr_usb->bSOF = 0; sstar_writeb(otg0_usb_intr, MSB250X_OTG0_INTRUSB_REG); sstar_readb(MSB250X_OTG0_INTRUSB_REG); // Flush the next packet to be transmitted/ read from the endpoint 0 FIFO sstar_writeb(0x00, MSB250X_OTG0_INDEX_REG); sstar_writeb(0x01, MSB250X_OTG0_CSR0_FLSH_REG); sstar_writew(0x0001, MSB250X_OTG0_INTRTXE_REG); sstar_writew(0x0001, MSB250X_OTG0_INTRRXE_REG); sstar_readw(MSB250X_OTG0_INTRTXE_REG); sstar_readw(MSB250X_OTG0_INTRRXE_REG); debug("<USB> %s[-]\n", __func__); } /* * udc_disable - disable USB device controller */ static void msb250x_udc_disable(struct msb250x_udc *dev) { /* block all irqs */ sstar_writeb(0x00, MSB250X_OTG0_INTRUSBE_REG); sstar_writeb(0x00, MSB250X_OTG0_INTRTX1E_REG); sstar_writeb(0x00, MSB250X_OTG0_INTRRX1E_REG); /* if hardware supports it, disconnect from usb */ msb250x_udc_pullup_i(0); ep0_idle(dev); dev->gadget.speed = USB_SPEED_UNKNOWN; } /*void usb_ep_set_maxpacket_limit(struct usb_ep *ep, unsigned maxpacket_limit) { ep->maxpacket = maxpacket_limit; }*/ static void msb250x_udc_reinit(struct msb250x_udc *dev) { u8 ep_num = 0; /* device/ep0 records init */ INIT_LIST_HEAD(&dev->gadget.ep_list); INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); dev->gadget.ep0 = &dev->ep[0].ep; dev->gadget.speed = USB_SPEED_UNKNOWN; for (ep_num = 0; ep_num < MSB250X_MAX_ENDPOINTS; ep_num++) { struct msb250x_ep *ep = &dev->ep[ep_num]; ep->ep_num = ep_num; ep->autoNAK_cfg = 0; list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); INIT_LIST_HEAD(&ep->queue); } usb_ep_set_maxpacket_limit(&dev->ep[0].ep, 64); list_del_init(&dev->ep[0].ep.ep_list); dev->delay_status = 0; } static int msb250x_udc_link_isr(struct msb250x_udc *dev) { u8 usb_status = 0; u8 power = 0; struct otg0_usb_intr * usb_st = (struct otg0_usb_intr *)&usb_status; struct otg0_usb_power *pst_power = (struct otg0_usb_power *)&power; power = sstar_readb(MSB250X_OTG0_PWR_REG); usb_status = sstar_readb(MSB250X_OTG0_INTRUSB_REG); sstar_writeb(usb_status, MSB250X_OTG0_INTRUSB_REG); if (1 == usb_st->bReset) { /* two kind of reset : * - reset start -> pwr reg = 8 * - reset end -> pwr reg = 0 **/ sstar_writeb(0x10, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16)); // TX-current adjust to 105%=> bit <4> set 1 sstar_writeb(0x02, (GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16) + 1)); // Pre-emphasis enable=> bit <1> set 1 // sstar_writeb(0x01, (GET_REG16_ADDR(UTMI_BASE_ADDR, 0x17) + 1)); //HS_TX common mode current enable (100mV)=> // bit <7> set 1 // sstar_writeb(0x10, (UTMI_BASE_ADDR + 0x58)); //TX-current adjust to 105%=> bit <4> set 1 // sstar_writeb(0x02, (UTMI_BASE_ADDR + 0x5A)); // Pre-emphasis enable=> bit <1> set 1 // sstar_writeb(0x01, (UTMI_BASE_ADDR + 0x5E)); //HS_TX common mode current enable (100mV)=> bit <7> // set 1 if (dev->driver && dev->driver->disconnect) { dev->driver->disconnect(&dev->gadget); } sstar_writeb(0, MSB250X_OTG0_FADDR_REG); dev->address = 0; dev->delay_status = 0; dev->ep0state = EP0_IDLE; // if (udc_read8(MSB250X_UDC_PWR_REG)&MSB250X_UDC_PWR_HS_MODE) if (1 != pst_power->bHSMode) { // printf("<USB>[LINK] Not high speed device.\r\n"); usb_gadget_disconnect(&dev->gadget); msb250x_reset_otg(); msb250x_udc_init_otg(); // mdelay(10); delay is not necessery and reset_otg + udc_init_otg work well usb_gadget_connect(&dev->gadget); return IRQ_HANDLED; } dev->gadget.speed = USB_SPEED_HIGH; printf("<USB>[LINK] High speed device.\r\n"); sstar_writew(0x0230, GET_REG16_ADDR(UTMI_BASE_ADDR, 0x16)); // B2 analog parameter msb250x_udc_init_autoNAK_cfg(); #if 0 if (1 == pst_power->bHSMode) { dev->gadget.speed = USB_SPEED_HIGH; printf("<USB>[LINK] High speed device.\r\n"); sstar_writew(0x0230, (UTMI_BASE_ADDR + 0x58)); //B2 analog parameter } else { dev->gadget.speed = USB_SPEED_FULL; printf("<USB>[LINK] Full speed device.\r\n"); sstar_writew(0x0030, (UTMI_BASE_ADDR + 0x58)); //B2 analog parameter } #endif } /* RESUME */ if (1 == usb_st->bResume) { printf("<USB>[LINK] Resume power<0x%x>.\r\n", power); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->resume) dev->driver->resume(&dev->gadget); } /* SUSPEND */ if (1 == usb_st->bSuspend) { printf("<USB>[LINK] Suspend.\r\n"); if (dev->gadget.speed != USB_SPEED_UNKNOWN && dev->driver && dev->driver->suspend) { dev->driver->suspend(&dev->gadget); dev->ep0state = EP0_IDLE; } } return IRQ_HANDLED; } static int msb250x_ep_set_halt(struct usb_ep *_ep, int value) { struct msb250x_ep *ep = container_of(_ep, struct msb250x_ep, ep); u8 csr = 0; u8 ep_num = 0; struct otg0_ep_rxcsr_l *rxcsr_l = NULL; struct otg0_ep_txcsr_l *txcsr_l = NULL; if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { printf("%s: inval 2\n", __FUNCTION__); return -EINVAL; } ep_num = ep->ep_num; ep->halted = value ? 1 : 0; if (ep_num == 0) { msb250x_ep0_set_ss(); } else { if (NULL != ep->desc) { if (usb_endpoint_dir_out(ep->desc)) { csr = sstar_readb(MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); rxcsr_l = (struct otg0_ep_rxcsr_l *)&csr; if (value) { rxcsr_l->bSendStall = 1; sstar_writeb(csr, MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); } else { rxcsr_l->bSendStall = 0; rxcsr_l->bClrDataTog = 1; sstar_writeb(csr, MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); if (1 == rxcsr_l->bRxPktRdy) { // msb250x_ep_request_continue(ep); } } } else { csr = sstar_readb(MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); txcsr_l = (struct otg0_ep_txcsr_l *)&csr; if (value) { if (1 == txcsr_l->bFIFONotEmpty) { printf("%s fifo busy, cannot halt\n", _ep->name); ep->halted = 0; // spin_unlock_irqrestore(&ep->dev->lock,flags);//local_irq_restore (flags); return -EAGAIN; } txcsr_l->bSendStall = 1; sstar_writeb(csr, MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); } else { txcsr_l->bClrDataTog = 1; sstar_writeb(csr, MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); sstar_writeb(0, MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); if (0 == txcsr_l->bTxPktRdy) { // msb250x_ep_request_continue(ep); } } } } } return 0; } static int msb250x_udc_get_status(struct msb250x_udc *dev, struct usb_ctrlrequest *crq) { u8 status = 0; u8 ep_num = crq->wIndex & 0x7F; u8 is_in = crq->wIndex & USB_DIR_IN; switch (crq->bRequestType & USB_RECIP_MASK) { case USB_RECIP_INTERFACE: break; case USB_RECIP_DEVICE: status = dev->devstatus; break; case USB_RECIP_ENDPOINT: if (MSB250X_MAX_ENDPOINTS < ep_num || crq->wLength > 2) return 1; if (ep_num == 0) { status = sstar_readb(MSB250X_OTG0_EP_TXCSR1_REG(0)); status &= MSB250X_OTG0_CSR0_SENDSTALL; } else { if (is_in) { status = sstar_readb(MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); status &= MSB250X_OTG0_TXCSR1_SENDSTALL; } else { status = sstar_readb(MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); status &= MSB250X_OTG0_RXCSR1_SENDSTALL; } } status = status ? 1 : 0; break; default: return 1; } /* Seems to be needed to get it working. ouch :( */ udelay(5); sstar_writeb(status & 0xFF, OTG0_EP_FIFO_ACCESS_L(0)); sstar_writeb(0, OTG0_EP_FIFO_ACCESS_L(0)); return 0; } static unsigned msb250x_ep0_read_ctl_req(struct usb_ctrlrequest *crq) { u8 *buf = (unsigned char *)crq; u8 bytes_read = 0; u16 count = 0; count = sstar_readw(MSB250X_OTG0_EP_RXCOUNT_REG(0)); if (count != sizeof(struct usb_ctrlrequest)) { printf("<USB>[0] wanted %u bytes got %d. Stalling out...\n", sizeof(struct usb_ctrlrequest), count); msb250x_ep0_clr_opr_set_ss(); return 0; } while (count > bytes_read) { *buf++ = sstar_readb(OTG0_EP_FIFO_ACCESS_L(0)); bytes_read++; } return count; } static void msb250x_ep0_test_mode(u8 mode) { u8 i; u8 testPacket[53] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E}; switch (mode) { case TEST_J: printf("TEST_J mode\n"); sstar_writeb(MSB250X_OTG0_TESTMODE_TEST_J, MSB250X_OTG0_TESTMODE_REG); break; case TEST_K: printf("TEST_K mode\n"); sstar_writeb(MSB250X_OTG0_TESTMODE_TEST_K, MSB250X_OTG0_TESTMODE_REG); break; case TEST_SE0_NAK: printf("TEST_SE0_NAK mode\n"); sstar_writeb(MSB250X_OTG0_TESTMODE_TEST_SE0_NAK, MSB250X_OTG0_TESTMODE_REG); break; case TEST_PACKET: printf("TEST_PACKET mode\n"); sstar_writeb(MSB250X_OTG0_TESTMODE_TEST_PACKET, MSB250X_OTG0_TESTMODE_REG); for (i = 0; i < 53; i++) { sstar_writeb(testPacket[i], OTG0_EP_FIFO_ACCESS_L(0)); } msb250x_ep0_set_de_in(); break; default: printf("UNKNOWN TEST mode\n"); break; } } static void msb250x_ep0_handle_idle(struct msb250x_udc *dev) { struct usb_ctrlrequest ctrl_req; int ret = 0; // msb250x_ep_request_nuke(dev, ep, -EPROTO); if (!msb250x_ep0_read_ctl_req(&ctrl_req)) { return; } debug("<USB>[0][SETUP][%s][%d] bRequestType/bRequest/wValue/wIndex/wlength(0x%02x/0x%02x/0x%04x/0x%04x/0x%04x)\r\n", (ctrl_req.bRequestType & USB_DIR_IN) ? "IN" : "OUT", (ctrl_req.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD, ctrl_req.bRequestType, ctrl_req.bRequest, le16_to_cpu(ctrl_req.wValue), le16_to_cpu(ctrl_req.wIndex), le16_to_cpu(ctrl_req.wLength)); /* cope with automagic for some standard requests. */ dev->req_std = (ctrl_req.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD; dev->req_config = 0; dev->req_pending = 1; if (dev->req_std) { switch (ctrl_req.bRequest) { case USB_REQ_SET_CONFIGURATION: // printf("USB_REQ_SET_CONFIGURATION ... \n"); if (ctrl_req.bRequestType == USB_RECIP_DEVICE) { dev->delay_status++; } break; case USB_REQ_SET_INTERFACE: // printf("USB_REQ_SET_INTERFACE ... \n"); if (ctrl_req.bRequestType == USB_RECIP_INTERFACE) { dev->delay_status++; } break; case USB_REQ_SET_ADDRESS: // printf("USB_REQ_SET_ADDRESS ... \n"); if (ctrl_req.bRequestType == USB_RECIP_DEVICE) { u8 address = 0; address = ctrl_req.wValue & 0x7F; dev->address = address; sstar_writeb(address, MSB250X_OTG0_FADDR_REG); msb250x_ep0_clear_opr(); return; } break; case USB_REQ_GET_STATUS: // printf("USB_REQ_GET_STATUS ... \n"); msb250x_ep0_clear_opr(); if (0 == msb250x_udc_get_status(dev, &ctrl_req)) { msb250x_ep0_set_de_in(); return; } break; case USB_REQ_CLEAR_FEATURE: printf("USB_REQ_CLEAR_FEATURE ... \n"); if (ctrl_req.bRequestType != USB_RECIP_ENDPOINT) break; if (ctrl_req.wValue != USB_ENDPOINT_HALT || ctrl_req.wLength != 0) break; msb250x_ep_set_halt(&dev->ep[ctrl_req.wIndex & 0x7f].ep, 0); msb250x_ep0_clear_opr(); return; case USB_REQ_SET_FEATURE: // printf("USB_REQ_SET_FEATURE ... \n"); msb250x_ep0_clear_opr(); if (ctrl_req.bRequestType == USB_RECIP_DEVICE) { // USB20_TEST_MODE if (ctrl_req.wValue == USB_DEVICE_TEST_MODE) { msb250x_ep0_test_mode(ctrl_req.wIndex >> 8); } } if (ctrl_req.bRequestType != USB_RECIP_ENDPOINT) break; if (ctrl_req.wValue != USB_ENDPOINT_HALT || ctrl_req.wLength != 0) break; msb250x_ep_set_halt(&dev->ep[ctrl_req.wIndex & 0x7f].ep, 1); msb250x_ep0_clear_opr(); return; default: msb250x_ep0_clear_opr(); break; } } else { msb250x_ep0_clear_opr(); } if (ctrl_req.bRequestType & USB_DIR_IN) { dev->ep0state = EP0_IN_DATA_PHASE; } else { dev->ep0state = EP0_OUT_DATA_PHASE; } if (0 == ctrl_req.wLength) { dev->ep0state = EP0_IDLE; } if (dev->driver && dev->driver->setup) { ret = dev->driver->setup(&dev->gadget, &ctrl_req); } else { ret = -EOPNOTSUPP; } if (ret < 0) { if (0 < dev->delay_status) { printf("<USB> config change %02x fail %d?\n", ctrl_req.bRequest, ret); return; } if (ret == -EOPNOTSUPP) printf("Operation not supported\n"); else printf("dev->driver->setup failed. (%d)\n", ret); msb250x_ep0_clr_opr_set_ss(); dev->ep0state = EP0_IDLE; /* deferred i/o == no response yet */ } else if (dev->req_pending) { dev->req_pending = 0; } // printf("<USB>[0] ep0state %s\n", ep0states[dev->ep0state]); } static void msb250x_ep0_isr_handler(struct msb250x_udc *dev) { u8 ep0csr = 0; struct msb250x_ep * ep = &dev->ep[0]; struct msb250x_request *req = NULL; ep0csr = sstar_readb(MSB250X_OTG0_EP0_CSR0_REG); /* clear stall status */ if (ep0csr & MSB250X_OTG0_CSR0_SENTSTALL) { printk("<USB>[0][EP] ... clear SENT_STALL ...\n"); msb250x_request_nuke(ep, -EPIPE); msb250x_ep0_clear_sst(); dev->ep0state = EP0_IDLE; return; } /* clear setup end */ if (ep0csr & MSB250X_OTG0_CSR0_SETUPEND) { // printk("... serviced SETUP_END ...\n"); msb250x_request_nuke(ep, 0); msb250x_ep0_clear_se(); dev->ep0state = EP0_IDLE; } switch (dev->ep0state) { case EP0_IDLE: if (ep0csr & MSB250X_OTG0_CSR0_RXPKTRDY) { msb250x_ep0_handle_idle(dev); } break; case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ set_ep_halt(ep, 0); if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct msb250x_request, queue); msb250x_ep_handle_request(ep, req); } break; default: dev->ep0state = EP0_IDLE; printk("EP0 status ... what now?\n"); break; } } static void msb250x_ep_isr_handler(struct msb250x_ep *ep) { struct msb250x_request *req = NULL; struct otg0_ep_rxcsr_l *rxcsr_l = NULL; struct otg0_ep_txcsr_l *txcsr_l = NULL; u8 csr1 = 0; u8 ep_num = 0; ep_num = usb_endpoint_num(ep->desc); if (!list_empty(&ep->queue)) { req = list_entry(ep->queue.next, struct msb250x_request, queue); } if (NULL != req) { if (usb_endpoint_dir_in(ep->desc)) { csr1 = sstar_readb(MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); txcsr_l = (struct otg0_ep_txcsr_l *)&csr1; if (1 == txcsr_l->bSentStall) { txcsr_l->bSentStall = 0; sstar_writeb(csr1, MSB250X_OTG0_EP_TXCSR1_REG(ep_num)); return; } } else { #ifndef CONFIG_SSTAR_MSB250X_BULK_OUT_PATCH u16 counts = 0; #endif csr1 = sstar_readb(MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); rxcsr_l = (struct otg0_ep_rxcsr_l *)&csr1; debug("<USB>[INT_RX][%d] bRxPktRdy/bSentStall/fifo(%d/%d/0x%04x).\n", ep_num, rxcsr_l->bRxPktRdy, rxcsr_l->bSentStall, sstar_readw(MSB250X_OTG0_EP_RXCOUNT_REG(ep_num))); if (1 == rxcsr_l->bSentStall) { rxcsr_l->bSentStall = 0; sstar_writeb(csr1, MSB250X_OTG0_EP_RXCSR1_REG(ep_num)); return; } if (usb_endpoint_xfer_bulk(ep->desc)) { if (1 == rxcsr_l->bRxPktRdy) { #ifndef CONFIG_SSTAR_MSB250X_BULK_OUT_PATCH if (ep->ep.maxpacket < req->req.length) { counts = sstar_readw(MSB250X_OTG0_EP_RXCOUNT_REG(ep_num)); if (ep->ep.maxpacket != counts || (ep->ep.maxpacket * msb250x_udc_get_pkt_cnt(ep->autoNAK_cfg)) == req->req.length) { msb250x_udc_ok2rcv_for_packets(ep->autoNAK_cfg, 0); if (ep->ep.maxpacket != counts) { ep->shortPkt &= 1; } } } #else if (ep->shortPkt == 1) { msb250x_udc_ok2rcv_for_packets(ep->autoNAK_cfg, 0); } #endif } } } msb250x_ep_handle_request(ep, req); } } static int msb250x_udc_ep_isr(struct msb250x_udc *dev) { u8 ep_num = 0; u8 usb_intr_rx = 0; u8 usb_intr_tx = 0; usb_intr_rx = sstar_readb(MSB250X_OTG0_INTRRX_REG); usb_intr_tx = sstar_readb(MSB250X_OTG0_INTRTX_REG); sstar_writeb(usb_intr_rx, MSB250X_OTG0_INTRRX_REG); sstar_writeb(usb_intr_tx, MSB250X_OTG0_INTRTX_REG); if (0 < (usb_intr_rx | usb_intr_tx)) { // printf("<USB>[INTR] intr_rx<0x%x> intr_tx<0x%x>\r\n", usb_intr_rx, usb_intr_tx); if (usb_intr_tx & MSB250X_OTG0_INTR_EP(0)) { msb250x_ep0_isr_handler(dev); } for (ep_num = 1; MSB250X_MAX_ENDPOINTS > ep_num; ep_num++) { if ((usb_intr_rx | usb_intr_tx) & MSB250X_OTG0_INTR_EP(ep_num)) { msb250x_ep_isr_handler(&dev->ep[ep_num]); } } } return IRQ_HANDLED; } static int msb250x_udc_isr(void) { struct msb250x_udc *dev = &memory; msb250x_udc_link_isr(dev); msb250x_udc_ep_isr(dev); return IRQ_HANDLED; } static int msb250x_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) { struct msb250x_udc *dev = NULL; struct msb250x_ep * ep = container_of(_ep, struct msb250x_ep, ep); u32 maxp = 0; u8 csr1 = 0, csr2 = 0; u8 power = 0; struct otg0_usb_power *pst_power = (struct otg0_usb_power *)&power; if (!_ep || !desc || ep->desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT) { return -EINVAL; } dev = ep->dev; if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { return -ESHUTDOWN; } maxp = usb_endpoint_maxp(desc); _ep->maxpacket = maxp & 0x7ff; ep->desc = desc; _ep->desc = desc; set_ep_halt(ep, 0); /* set type, direction, address; reset fifo counters */ if (usb_endpoint_dir_in(desc)) { csr1 = MSB250X_OTG0_TXCSR1_FLUSHFIFO | MSB250X_OTG0_TXCSR1_CLRDATAOTG; csr2 = MSB250X_OTG0_TXCSR2_MODE; power = sstar_readb(MSB250X_OTG0_PWR_REG); pst_power->bISOUpdate = 0; if (usb_endpoint_xfer_isoc(desc)) { csr2 |= MSB250X_OTG0_TXCSR2_ISOC; pst_power->bISOUpdate = 1; } sstar_writeb(power, MSB250X_OTG0_PWR_REG); sstar_writew(maxp, MSB250X_OTG0_EP_TXMAP_REG(ep->ep_num)); sstar_writeb(csr1, MSB250X_OTG0_EP_TXCSR1_REG(ep->ep_num)); sstar_writeb(csr2, MSB250X_OTG0_EP_TXCSR2_REG(ep->ep_num)); ep->fifo_size = 1 << (sstar_readb(MSB250X_OTG0_EP_FIFOSIZE_REG(ep->ep_num)) & 0xf0 >> 4); // ep->fifo_size = sstar_readb(MSB250X_UDC_FIFOSIZE_REG); /* enable irqs */ sstar_writeb((sstar_readb(MSB250X_OTG0_INTRTX1E_REG) | MSB250X_OTG0_INTR_EP(ep->ep_num)), MSB250X_OTG0_INTRTX1E_REG); } else { /* enable the enpoint direction as Rx */ csr1 = MSB250X_OTG0_RXCSR1_FLUSHFIFO | MSB250X_OTG0_RXCSR1_CLRDATATOG; csr2 = 0; if (usb_endpoint_xfer_int(desc)) { csr2 |= MSB250X_OTG0_RXCSR2_DISNYET; } if (usb_endpoint_xfer_isoc(desc)) { csr2 |= MSB250X_OTG0_RXCSR2_ISOC; } if (usb_endpoint_xfer_bulk(desc)) { ep->autoNAK_cfg = msb250x_udc_get_autoNAK_cfg(ep->ep_num); msb250x_udc_enable_autoNAK(ep->ep_num, ep->autoNAK_cfg); } sstar_writew(maxp, MSB250X_OTG0_EP_RXMAP_REG(ep->ep_num)); sstar_writeb(csr1, MSB250X_OTG0_EP_RXCSR1_REG(ep->ep_num)); sstar_writeb(csr2, MSB250X_OTG0_EP_RXCSR2_REG(ep->ep_num)); ep->fifo_size = 1 << (sstar_readb(MSB250X_OTG0_EP_FIFOSIZE_REG(ep->ep_num)) & 0x0f); /* enable irqs */ sstar_writeb((sstar_readb(MSB250X_OTG0_INTRRX1E_REG) | MSB250X_OTG0_INTR_EP(ep->ep_num)), MSB250X_OTG0_INTRRX1E_REG); } printf("<USB>[%d][EN] %s %s with maxpacket/fifo(%d/%d)\r\n", usb_endpoint_num(desc), usb_endpoint_xfer_bulk(desc) ? "bulk" : (usb_endpoint_xfer_isoc(desc) ? "isoc" : "int"), usb_endpoint_dir_in(desc) ? "in" : "out", _ep->maxpacket, ep->fifo_size); return 0; } static int msb250x_ep_disable(struct usb_ep *_ep) { struct msb250x_ep *ep = NULL; u16 int_en_reg = 0; if (!_ep) { printf("ep not enabled\n"); return -EINVAL; } ep = container_of(_ep, struct msb250x_ep, ep); if (!ep->desc) { return -EINVAL; } set_ep_halt(ep, 1); /* disable irqs */ if (usb_endpoint_dir_in(ep->desc)) { int_en_reg = sstar_readw(MSB250X_OTG0_INTRTXE_REG); sstar_writew(int_en_reg & ~(MSB250X_OTG0_INTR_EP(ep->ep_num)), MSB250X_OTG0_INTRTXE_REG); } else { if (usb_endpoint_xfer_bulk(ep->desc)) { msb250x_udc_disable_autoNAK_cfg(ep->autoNAK_cfg); ep->autoNAK_cfg = 0; } int_en_reg = sstar_readw(MSB250X_OTG0_INTRRXE_REG); sstar_writew(int_en_reg & ~(MSB250X_OTG0_INTR_EP(ep->ep_num)), MSB250X_OTG0_INTRRXE_REG); } msb250x_request_nuke(ep, -ESHUTDOWN); ep->desc = NULL; return 0; } static struct usb_request *msb250x_ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) { struct msb250x_request *req; req = kzalloc(sizeof(struct msb250x_request), gfp_flags); if (!req) return 0; memset(req, 0, sizeof *req); INIT_LIST_HEAD(&req->queue); debug("%s: %s %p req: %p\n", __func__, ep->name, ep, &req->req); return &req->req; } static void msb250x_ep_free_request(struct usb_ep *ep, struct usb_request *_req) { struct msb250x_request *req; debug("%s: %p\n", __func__, ep); req = container_of(_req, struct msb250x_request, req); WARN_ON(!list_empty(&req->queue)); kfree(req); } /** Queue one request * Kickstart transfer if needed */ static int msb250x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) { struct msb250x_request *req = container_of(_req, struct msb250x_request, req); struct msb250x_ep * ep; struct msb250x_udc * dev; if (unlikely(!_req || !_req->complete || !_req->buf || !list_empty(&req->queue))) { debug("%s: bad params\n", __func__); return -EINVAL; } ep = container_of(_ep, struct msb250x_ep, ep); if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { debug("%s: bad ep: %s, %d, %p\n", __func__, ep->ep.name, !ep->desc, _ep); return -EINVAL; } dev = ep->dev; if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { debug("%s: bogus device state %p\n", __func__, dev->driver); return -ESHUTDOWN; } _req->status = -EINPROGRESS; _req->actual = 0; if (list_empty(&ep->queue)) { req = msb250x_ep_handle_request(ep, req); } /* pio or dma irq handler advances the queue. */ if (req != 0) list_add_tail(&req->queue, &ep->queue); return 0; } /* dequeue JUST ONE request */ static int msb250x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) { struct msb250x_ep * ep; struct msb250x_request *req; debug("%s: %p\n", __func__, _ep); ep = container_of(_ep, struct msb250x_ep, ep); if (!_ep || ep->ep.name == ep0name) return -EINVAL; /* make sure it&#39;s actually queued on this endpoint */ list_for_each_entry(req, &ep->queue, queue) { if (&req->req == _req) break; } if (&req->req != _req) { return -EINVAL; } list_del_init(&req->queue); msb250x_request_done(ep, req, -ECONNRESET); return 0; } /* * Return bytes in EP FIFO */ static int msb250x_ep_fifo_status(struct usb_ep *_ep) { int count = 0; struct msb250x_ep *ep = container_of(_ep, struct msb250x_ep, ep); if (!_ep) { debug("%s: bad ep\n", __func__); return -ENODEV; } /* LPD can&#39;t report unclaimed bytes from IN fifos */ if (usb_endpoint_dir_in(ep->desc)) { return -EOPNOTSUPP; } return count; } /* * Flush EP FIFO */ static void msb250x_ep_fifo_flush(struct usb_ep *_ep) { struct msb250x_ep *ep = NULL; ep = container_of(_ep, struct msb250x_ep, ep); if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { debug("%s: bad ep\n", __func__); return; } if (0 == ep->ep_num) { sstar_writeb(sstar_readb(MSB250X_OTG0_EP0_CSR0_FLSH_REG) | MSB250X_OTG0_CSR0_FLUSHFIFO, MSB250X_OTG0_EP0_CSR0_FLSH_REG); } else { if (usb_endpoint_dir_in(ep->desc)) { sstar_writeb(sstar_readb(MSB250X_OTG0_EP_TXCSR1_REG(ep->ep_num)) | MSB250X_OTG0_TXCSR1_FLUSHFIFO, MSB250X_OTG0_EP_TXCSR1_REG(ep->ep_num)); } else { sstar_writeb(sstar_readb(MSB250X_OTG0_EP_RXCSR1_REG(ep->ep_num)) | MSB250X_OTG0_RXCSR1_FLUSHFIFO, MSB250X_OTG0_EP_RXCSR1_REG(ep->ep_num)); } } } /* drivers may have software control over D+ pullup */ static int msb250x_usb_pullup(struct usb_gadget *_gadget, int is_active) { msb250x_udc_pullup_i(is_active != 0); return 0; } static int msb250x_udc_start(struct usb_gadget *g, struct usb_gadget_driver *driver) { struct msb250x_udc *udc = NULL; if (!g) { printk("<USB_ERR>[GADGET] ENODEV!\n"); return -ENODEV; } udc = container_of(g, struct msb250x_udc, gadget); udc->driver = driver; printf("<USB>[GADGET] UDC start\n"); return 0; } static int msb250x_udc_stop(struct usb_gadget *g) { struct msb250x_udc *udc = NULL; if (!g) { printk("<USB_ERR>[GADGET] ENODEV!\n"); return -ENODEV; } udc = container_of(g, struct msb250x_udc, gadget); udc->driver = NULL; printf("<USB>[GADGET] UDC stop\n"); return 0; } #if !CONFIG_IS_ENABLED(DM_USB_GADGET) int usb_gadget_handle_interrupts(int index) { return msb250x_udc_isr(); } int usb_gadget_register_driver(struct usb_gadget_driver *driver) { struct msb250x_udc *dev = &memory; int retval = 0; if (!driver || (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH && driver->speed != USB_SPEED_SUPER) || !driver->bind || !driver->disconnect || !driver->setup) { return -EINVAL; } if (dev->driver) { return -EBUSY; } msb250x_udc_reinit(dev); msb250x_udc_init_MIU_sel(); msb250x_udc_init_utmi(); msb250x_reset_otg(); msb250x_udc_init_otg(); usb_gadget_disconnect(&dev->gadget); retval = driver->bind(&dev->gadget); if (retval) { dev->driver = 0; return retval; } #if defined(GPIO_LED0_ENABLED) sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x4E)) & ~BIT3, GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x4E)); sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x51)) & ~(BIT4 | BIT5), GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x51)); sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x50)) & ~(BIT4 | BIT5), GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x50)); sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)) & ~(BIT0 | BIT1), GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)); #endif dev->driver = driver; printk("registered gadget driver &#39;%s&#39;\n", driver_name); return 0; } int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) { struct msb250x_udc *dev = &memory; if (!dev) return -ENODEV; if (!driver || driver != dev->driver) return -EINVAL; msb250x_udc_disable(dev); driver->disconnect(&dev->gadget); driver->unbind(&dev->gadget); dev->driver = 0; printf("unregistered gadget driver &#39;%s&#39;\n", driver_name); return 0; } #else /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ int dm_usb_gadget_handle_interrupts(struct udevice *dev) { return msb250x_udc_isr(); } static const struct udevice_id msb250x_ids[] = {{.compatible = "sstar,msb250x-udc"}, {}}; static int msb250x_udc_probe(struct udevice *dev) { struct msb250x_udc *udc = &memory; struct reset_ctl_bulk *reset; reset = devm_reset_bulk_get_optional(dev); if (reset) reset_deassert_bulk(reset); #ifdef UTMI1_BASE_ADDR /*In usb boot mode, usb20 mac should use port1 utmi(utmi2), set this to switch to port1 utmi.*/ sstar_writew(sstar_readw(GET_REG16_ADDR(UTMI1_BASE_ADDR, 0x1)) | BIT7, GET_REG16_ADDR(UTMI1_BASE_ADDR, 0x1)); #endif msb250x_udc_reinit(udc); msb250x_udc_init_MIU_sel(); msb250x_udc_init_utmi(); msb250x_reset_otg(); msb250x_udc_init_otg(); usb_gadget_disconnect(&udc->gadget); #if defined(GPIO_LED0_ENABLED) sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x4E)) & ~BIT3, GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x4E)); sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x51)) & ~(BIT4 | BIT5), GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x51)); sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x50)) & ~(BIT4 | BIT5), GET_REG8_ADDR(REG_ADDR_BASE_PM_PWM, 0x50)); sstar_writeb(sstar_readb(GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)) & ~(BIT0 | BIT1), GET_REG8_ADDR(REG_ADDR_BASE_PM_GPIO, 0x94)); #endif dev_set_priv(dev, (void *)udc); usb_add_gadget_udc((struct device *)dev, &udc->gadget); return 0; } static int msb250x_udc_remove(struct udevice *dev) { struct msb250x_udc *udc = dev_get_priv(dev); usb_del_gadget_udc(&udc->gadget); msb250x_udc_disable(udc); return 0; } U_BOOT_DRIVER(sstar_msb250x_udc) = { .name = "msb250x-udc", .id = UCLASS_USB_GADGET_GENERIC, .of_match = msb250x_ids, .probe = msb250x_udc_probe, .remove = msb250x_udc_remove, }; #endif /* CONFIG_IS_ENABLED(DM_USB_GADGET) */ drivers/sstar/usb/gadget/udc/usb20/msb250x_udc.c这个文件作用是什么
最新发布
09-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值