00001
00052 #include <assert.h>
00053 #include <debug.h>
00054 #include <irq_handler.h>
00055 #include <physmem.h>
00056 #include <stdbool.h>
00057 #include <chip/clk.h>
00058 #include <chip/memory-map.h>
00059 #include <chip/irq-map.h>
00060 #include <chip/portmux.h>
00061 #include <chip/usbb.h>
00062 #include <usb/udc.h>
00063
00064 #include <app/config_dmapool.h>
00065 #include <app/config_usb.h>
00066
00067 #include "usbb_internal.h"
00068 #include "usbb_regs.h"
00069
00070
00071 #if defined(CONFIG_USBB_UDC) && !defined(CHIP_USBB_HAS_DEVICE)
00072 # error USBB: This chip does not have a Device Controller
00073 #endif
00074 #if defined(CONFIG_USBB_HOST) && !defined(CHIP_USBB_HAS_HOST)
00075 # error USBB: This chip does not have a Host Controller
00076 #endif
00077 #if defined(CONFIG_USBB_OTG) && !defined(CHIP_USBB_HAS_OTG)
00078 # error USBB: This chip does not support USB On-The-Go
00079 #endif
00080
00081 #ifndef usbb_desc_physmem_pool
00082 # define usbb_desc_physmem_pool hsb_sram_pool
00083 #endif
00084
00085 #define USBB_DMA_DESC_ALIGN 4
00086
00087 struct dma_pool usbb_desc_pool;
00088
00089 static inline struct usbb_udc *usbb_get_udc(struct usbb_controller *usbb)
00090 {
00091 #ifdef CONFIG_USBB_UDC
00092 return usbb->udc;
00093 #else
00094 return NULL;
00095 #endif
00096 }
00097
00098 static inline struct usbb_host *usbb_get_host(struct usbb_controller *usbb)
00099 {
00100 #ifdef CONFIG_USBB_HOST
00101 return usbb->host;
00102 #else
00103 return NULL;
00104 #endif
00105 }
00106
00107 static inline bool usbb_is_otg(struct usbb_controller *usbb)
00108 {
00109 #ifdef CONFIG_USBB_OTG
00110 return true;
00111 #else
00112 return false;
00113 #endif
00114 }
00115
00116 static void usbb_check_vbus(struct usbb_controller *usbb)
00117 {
00118 struct usbb_udc *udcb = usbb_get_udc(usbb);
00119
00120 if (usbb_read_reg(USBSTA) & USBB_USBSTA_VBUS)
00121 usbb_udc_vbus_on(udcb);
00122 else
00123 usbb_udc_vbus_off(udcb);
00124 }
00125
00132 static void usbb_enter_device_mode(struct usbb_controller *usbb)
00133 {
00134 struct usbb_host *host = usbb_get_host(usbb);
00135 struct usbb_udc *udc = usbb_get_udc(usbb);
00136 uint32_t usbcon;
00137
00138 dbg_printf("USBB: Entering device mode...\n");
00139
00140 if (usbb_host_is_enabled(host))
00141 usbb_host_disable(host);
00142 if (!usbb_udc_is_enabled(udc))
00143 usbb_udc_enable(udc);
00144
00145 usbb_write_reg(USBSTACLR, USBB_VBUSTI);
00146 usbb_check_vbus(usbb);
00147
00148 usbcon = usbb_read_reg(USBCON);
00149 usbcon |= USBB_VBUSTI;
00150 usbb_write_reg(USBCON, usbcon);
00151
00152 dbg_printf("USBB: USBCON=%08x\n", usbb_read_reg(USBCON));
00153 }
00154
00155 static void usbb_enter_host_mode(struct usbb_controller *usbb)
00156 {
00157 struct usbb_host *host = usbb_get_host(usbb);
00158 struct usbb_udc *udc = usbb_get_udc(usbb);
00159
00160 if (host) {
00161 if (usbb_udc_is_enabled(udc))
00162 usbb_udc_disable(udc);
00163 if (!usbb_host_is_enabled(host))
00164 usbb_host_enable(host);
00165 }
00166 }
00167
00175 static void usbb_check_id(struct usbb_controller *usbb)
00176 {
00177 if (usbb_read_reg(USBSTA) & USBB_USBSTA_ID)
00178 usbb_enter_device_mode(usbb);
00179 else
00180 usbb_enter_host_mode(usbb);
00181 }
00182
00193 static void usbb_interrupt(void *data)
00194 {
00195 struct usbb_controller *usbb = data;
00196 struct usbb_udc *udcb;
00197 struct usbb_host *hostb;
00198 uint32_t usbsta;
00199
00200 usbsta = usbb_read_reg(USBSTA);
00201
00202 if (usbb_is_otg(usbb)) {
00203 if (usbsta & USBB_IDTI) {
00204 usbb_write_reg(USBSTACLR, USBB_IDTI);
00205 usbb_check_id(usbb);
00206 }
00207
00208
00209 }
00210
00211 udcb = usbb_get_udc(usbb);
00212 if (usbb_udc_is_enabled(udcb)) {
00213 if (usbsta & USBB_VBUSTI) {
00214 usbb_write_reg(USBSTACLR, USBB_VBUSTI);
00215 usbb_check_vbus(usbb);
00216 }
00217
00218 usbb_udc_interrupt(udcb);
00219 }
00220
00221 hostb = usbb_get_host(usbb);
00222 if (usbb_host_is_enabled(hostb)) {
00223
00224 }
00225 }
00226 DEFINE_IRQ_HANDLER(usbb, usbb_interrupt, 0);
00227
00228 static void usbb_init_desc_pool(void)
00229 {
00230 phys_addr_t addr;
00231 phys_size_t size;
00232
00233 size = round_up(sizeof(struct usbb_sw_dma_desc), USBB_DMA_DESC_ALIGN);
00234 size *= CONFIG_USBB_NR_DMA_DESCRIPTORS;
00235
00236 addr = physmem_alloc(&usbb_desc_physmem_pool, size,
00237 USBB_DMA_DESC_ALIGN);
00238 assert(addr != PHYSMEM_ALLOC_ERR);
00239
00240 dma_pool_init_coherent(&usbb_desc_pool, addr, size,
00241 sizeof(struct usbb_sw_dma_desc), USBB_DMA_DESC_ALIGN);
00242 }
00243
00244 static struct usbb_controller the_usbb_controller;
00245
00262 static struct usbb_controller *usbb_init(void)
00263 {
00264 struct usbb_controller *usbb = &the_usbb_controller;
00265 uint32_t usbcon;
00266
00267
00268
00269
00270
00271 if (usbb_get_host(usbb) || usbb_get_udc(usbb))
00272 return usbb;
00273
00274 usbb_init_desc_pool();
00275
00276 usbcon = USBB_USBCON_USBE | USBB_USBCON_OTGPADE;
00277
00278 if (clk_enable_usbb())
00279 return NULL;
00280
00281 setup_irq_handler(USBB_IRQ, usbb, 0, usbb);
00282
00283 #ifdef CONFIG_USBB_UDC
00284 usbb->udc = usbb_udc_init();
00285 if (!usbb->udc)
00286 goto err_udc;
00287 #endif
00288 #ifdef CONFIG_USBB_HOST
00289 usbb->host = usbb_host_init();
00290 if (!usbb->host)
00291 goto err_host;
00292 #endif
00293
00294 if (usbb_is_otg(usbb)) {
00295
00296 usbcon |= USBB_USBCON_UIDE;
00297 usbb_write_reg(USBCON, usbcon);
00298 usbb_write_reg(USBSTACLR, USBB_IDTI);
00299 usbb_check_id(usbb);
00300 usbcon |= USBB_IDTI;
00301 usbb_write_reg(USBCON, usbcon);
00302
00303
00304 } else if (usbb_get_udc(usbb)) {
00305
00306 usbcon |= USBB_USBCON_UIMOD_DEVICE;
00307 usbb_write_reg(USBCON, usbcon);
00308 usbb_enter_device_mode(usbb);
00309 } else if (usbb_get_host(usbb)) {
00310
00311 usbcon |= USBB_USBCON_UIMOD_HOST;
00312 usbb_write_reg(USBCON, usbcon);
00313 usbb_enter_host_mode(usbb);
00314 }
00315
00316 return usbb;
00317
00318 #ifdef CONFIG_USBB_HOST
00319 usbb_host_shutdown(usbb_get_host(usbb));
00320 err_host:
00321 #endif
00322 #ifdef CONFIG_USBB_UDC
00323 usbb_udc_shutdown(usbb_get_udc(usbb));
00324 err_udc:
00325 #endif
00326 return NULL;
00327 }
00328
00342 struct udc *udc_init(void)
00343 {
00344 struct usbb_controller *usbb;
00345
00346 usbb = usbb_init();
00347 if (!usbb)
00348 return NULL;
00349
00350 return &usbb_get_udc(usbb)->udc;
00351 }