diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-03-16 21:39:14 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2015-05-15 15:40:55 +0200 |
commit | 278bc93a59d77cd302e59357ed89ed566519bb71 (patch) | |
tree | 9cdb4bfe8612da9e07638bdf9678c0af97018546 | |
parent | Makefile: Regenerate (diff) | |
download | rtems-libbsd-278bc93a59d77cd302e59357ed89ed566519bb71.tar.bz2 |
usb: Import USB support from libusb
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | freebsd/sys/dev/usb/controller/ehci.c | 8 | ||||
-rw-r--r-- | freebsd/sys/dev/usb/controller/ehci.h | 4 | ||||
-rwxr-xr-x | libbsd.py | 5 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c | 43 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/controller/ohci_lpc.c | 656 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/controller/ohci_lpc24xx.c | 228 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c | 607 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c | 306 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver_dump.c | 122 | ||||
-rw-r--r-- | rtemsbsd/sys/dev/usb/usb_otg_transceiver.h | 131 |
11 files changed, 1274 insertions, 841 deletions
@@ -660,8 +660,9 @@ LIB_C_FILES += rtemsbsd/pppd/sys-rtems.c LIB_C_FILES += rtemsbsd/pppd/upap.c LIB_C_FILES += rtemsbsd/pppd/utils.c LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c -LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ohci_lpc24xx.c -LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c +LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/ohci_lpc.c +LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c +LIB_C_FILES += rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver_dump.c LIB_C_FILES += rtemsbsd/sys/dev/smc/if_smc_nexus.c LIB_C_FILES += rtemsbsd/sys/dev/ffec/if_ffec_mcf548x.c LIB_C_FILES += rtemsbsd/sys/dev/dw_mmc/dw_mmc.c diff --git a/freebsd/sys/dev/usb/controller/ehci.c b/freebsd/sys/dev/usb/controller/ehci.c index 528e4a02..730fd666 100644 --- a/freebsd/sys/dev/usb/controller/ehci.c +++ b/freebsd/sys/dev/usb/controller/ehci.c @@ -591,7 +591,11 @@ ehci_detach(ehci_softc_t *sc) usb_callout_drain(&sc->sc_tmo_poll); } +#ifndef __rtems__ static void +#else /* __rtems__ */ +void +#endif /* __rtems__ */ ehci_suspend(ehci_softc_t *sc) { DPRINTF("stopping the HC\n"); @@ -600,7 +604,11 @@ ehci_suspend(ehci_softc_t *sc) ehci_hcreset(sc); } +#ifndef __rtems__ static void +#else /* __rtems__ */ +void +#endif /* __rtems__ */ ehci_resume(ehci_softc_t *sc) { /* reset HC */ diff --git a/freebsd/sys/dev/usb/controller/ehci.h b/freebsd/sys/dev/usb/controller/ehci.h index f718a8a7..76ac75f6 100644 --- a/freebsd/sys/dev/usb/controller/ehci.h +++ b/freebsd/sys/dev/usb/controller/ehci.h @@ -472,5 +472,9 @@ usb_error_t ehci_reset(ehci_softc_t *sc); usb_error_t ehci_init(ehci_softc_t *sc); void ehci_detach(struct ehci_softc *sc); void ehci_interrupt(ehci_softc_t *sc); +#ifdef __rtems__ +void ehci_suspend(ehci_softc_t *sc); +void ehci_resume(ehci_softc_t *sc); +#endif /* __rtems__ */ #endif /* _EHCI_H_ */ @@ -117,8 +117,9 @@ def rtems(mm): 'pppd/upap.c', 'pppd/utils.c', 'sys/dev/usb/controller/ehci_mpc83xx.c', - 'sys/dev/usb/controller/ohci_lpc24xx.c', - 'sys/dev/usb/controller/ohci_lpc32xx.c', + 'sys/dev/usb/controller/ohci_lpc.c', + 'sys/dev/usb/controller/usb_otg_transceiver.c', + 'sys/dev/usb/controller/usb_otg_transceiver_dump.c', 'sys/dev/smc/if_smc_nexus.c', 'sys/dev/ffec/if_ffec_mcf548x.c', 'sys/dev/dw_mmc/dw_mmc.c', diff --git a/rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c b/rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c index e82e6a56..10127db0 100644 --- a/rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c +++ b/rtemsbsd/sys/dev/usb/controller/ehci_mpc83xx.c @@ -87,6 +87,36 @@ static device_probe_t ehci_mpc83xx_probe; static device_attach_t ehci_mpc83xx_attach; static device_detach_t ehci_mpc83xx_detach; +static device_suspend_t ehci_mpc83xx_suspend; +static device_resume_t ehci_mpc83xx_resume; + +static int +ehci_mpc83xx_suspend(device_t self) +{ + ehci_softc_t *e = device_get_softc(self); + int eno = bus_generic_suspend(self); + + if (eno != 0) { + return (eno); + } + + ehci_suspend(e); + + return (0); +} + +static int +ehci_mpc83xx_resume(device_t self) +{ + ehci_softc_t *e = device_get_softc(self); + + ehci_resume(e); + + bus_generic_resume(self); + + return (0); +} + static int ehci_mpc83xx_probe(device_t self) @@ -116,8 +146,12 @@ ehci_mpc83xx_phy_init(void) #ifdef __GEN83xx_BSP_h volatile uint32_t *control = &mpc83xx.usb_dr.control; +#ifdef BSP_USB_EHCI_MPC83XX_HAS_ULPI + *control = CONTROL_PHY_CLOCK_SEL; +#else *control = CONTROL_PLL_RESET | CONTROL_REFSEL(0x2U); *control = CONTROL_UTMI_PHY_EN | CONTROL_REFSEL(0x2U); +#endif while ((*control & CONTROL_PHY_CLK_VALID) == 0) { /* Wait for PLL */ @@ -146,8 +180,13 @@ ehci_mpc83xx_host_init(void) #ifdef __GEN83xx_BSP_h mpc83xx.usb_dr.snoop1 = SNOOP_ADDR(0x0) | SNOOP_SIZE_2GB; mpc83xx.usb_dr.snoop2 = SNOOP_ADDR(0x80000) | SNOOP_SIZE_2GB; +#ifdef BSP_USB_EHCI_MPC83XX_HAS_ULPI + mpc83xx.usb_dr.control = CONTROL_PHY_CLOCK_SEL | CONTROL_USB_EN; + mpc83xx.usb_dr.portsc1 = htole32(PORTSC_PTS_ULPI); +#else mpc83xx.usb_dr.control = CONTROL_UTMI_PHY_EN | CONTROL_REFSEL(0x2) | CONTROL_USB_EN; mpc83xx.usb_dr.portsc1 = htole32(PORTSC_PTS_UTMI); +#endif #if 0 mpc83xx.usb_dr.pri_ctrl = 0xcU; mpc83xx.usb_dr.age_cnt_thresh = 0x40U; @@ -250,8 +289,8 @@ static device_method_t ehci_methods [] = { DEVMETHOD(device_probe, ehci_mpc83xx_probe), DEVMETHOD(device_attach, ehci_mpc83xx_attach), DEVMETHOD(device_detach, ehci_mpc83xx_detach), - DEVMETHOD(device_suspend,bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_suspend, ehci_mpc83xx_suspend), + DEVMETHOD(device_resume, ehci_mpc83xx_resume), DEVMETHOD(device_shutdown, bus_generic_shutdown), /* Bus interface */ diff --git a/rtemsbsd/sys/dev/usb/controller/ohci_lpc.c b/rtemsbsd/sys/dev/usb/controller/ohci_lpc.c new file mode 100644 index 00000000..527561c3 --- /dev/null +++ b/rtemsbsd/sys/dev/usb/controller/ohci_lpc.c @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2009, 2013 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <machine/rtems-bsd-kernel-space.h> +#include <machine/rtems-bsd-support.h> + +#include <bsp.h> + +#if defined(LIBBSP_ARM_LPC24XX_BSP_H) || defined(LIBBSP_ARM_LPC32XX_BSP_H) + +#include <bsp/irq.h> + +#ifdef LIBBSP_ARM_LPC24XX_BSP_H + +#include <bsp/io.h> +#include <bsp/lpc24xx.h> + +#define LPC_USB_OHCI_BASE USBHC_BASE_ADDR + +#define LPC_USB_I2C_BASE USBOTG_I2C_BASE_ADDR + +#define LPC_OTG_CLK_CTRL OTG_CLK_CTRL + +#define LPC_OTG_CLK_STAT OTG_CLK_STAT + +#define LPC_USB_OHCI_IRQ LPC24XX_IRQ_USB + +static void lpc_usb_module_enable(void) +{ + rtems_status_code sc; + + sc = lpc24xx_module_enable( + LPC24XX_MODULE_USB, + LPC24XX_MODULE_PCLK_DEFAULT + ); + BSD_ASSERT_SC(sc); +} + +static void lpc_usb_module_disable(void) +{ + rtems_status_code sc; + + sc = lpc24xx_module_disable(LPC24XX_MODULE_USB); + BSD_ASSERT_SC(sc); +} + +static void lpc_usb_pin_config(void) +{ + static const lpc24xx_pin_range pins [] = { + LPC24XX_PIN_USB_D_PLUS_1, + LPC24XX_PIN_USB_D_MINUS_1, + LPC24XX_PIN_USB_PPWR_1, + LPC24XX_PIN_USB_SCL_1, + LPC24XX_PIN_USB_SDA_1, + LPC24XX_PIN_TERMINAL + }; + + rtems_status_code sc; + + sc = lpc24xx_pin_config(&pins [0], LPC24XX_PIN_SET_FUNCTION); + BSD_ASSERT_SC(sc); +} + +static void lpc_usb_host_clock_enable(void) +{ + /* Nothing to do */ +} + +static void lpc_otg_status_and_control(void) +{ + OTG_STAT_CTRL = 0x3; +} + +#endif /* LIBBSP_ARM_LPC24XX_BSP_H */ + +#ifdef LIBBSP_ARM_LPC32XX_BSP_H + +#include <bsp/lpc32xx.h> + +#define LPC_USB_OHCI_BASE LPC32XX_BASE_USB + +#define LPC_USB_I2C_BASE (&LPC32XX_I2C_RX) + +#define LPC_OTG_CLK_CTRL LPC32XX_OTG_CLK_CTRL + +#define LPC_OTG_CLK_STAT LPC32XX_OTG_CLK_STAT + +#define LPC_USB_OHCI_IRQ LPC32XX_IRQ_USB_HOST + +#define USB_CTRL_SLAVE_HCLK_EN (1U << 24) +#define USB_CTRL_I2C_EN (1U << 23) +#define USB_CTRL_DEV_NEED_CLK_EN (1U << 22) +#define USB_CTRL_HOST_NEED_CLK_EN (1U << 21) +#define USB_CTRL_PC_MASK (0x3U << 19) +#define USB_CTRL_PC_PULL_UP (0x0U << 19) +#define USB_CTRL_PC_BUS_KEEPER (0x1U << 19) +#define USB_CTRL_PC_NONE (0x2U << 19) +#define USB_CTRL_PC_PULL_DOWN (0x3U << 19) +#define USB_CTRL_CLKEN2 (1U << 18) +#define USB_CTRL_CLKEN1 (1U << 17) +#define USB_CTRL_POWER_UP (1U << 16) +#define USB_CTRL_BYPASS (1U << 15) +#define USB_CTRL_DIRECT (1U << 14) +#define USB_CTRL_FEEDBACK (1U << 13) +#define USB_CTRL_P_SHIFT 11 +#define USB_CTRL_P_MASK (0x3U << USB_CTRL_P_SHIFT) +#define USB_CTRL_P_1 (0x0U << USB_CTRL_P_SHIFT) +#define USB_CTRL_P_2 (0x1U << USB_CTRL_P_SHIFT) +#define USB_CTRL_P_4 (0x2U << USB_CTRL_P_SHIFT) +#define USB_CTRL_P_8 (0x3U << USB_CTRL_P_SHIFT) +#define USB_CTRL_N_SHIFT 9 +#define USB_CTRL_N_MASK (0x3U << USB_CTRL_N_SHIFT) +#define USB_CTRL_N_1 (0x0U << USB_CTRL_N_SHIFT) +#define USB_CTRL_N_2 (0x1U << USB_CTRL_N_SHIFT) +#define USB_CTRL_N_3 (0x2U << USB_CTRL_N_SHIFT) +#define USB_CTRL_N_4 (0x3U << USB_CTRL_N_SHIFT) +#define USB_CTRL_M_SHIFT 1 +#define USB_CTRL_M_MASK (0xffU << USB_CTRL_M_SHIFT) +#define USB_CTRL_PLL_LOCK (1U << 0) + +static void lpc_usb_module_enable(void) +{ + LPC32XX_USB_DIV = 0xc; + LPC32XX_USB_CTRL = USB_CTRL_SLAVE_HCLK_EN + | USB_CTRL_PC_BUS_KEEPER + | USB_CTRL_CLKEN1 + | USB_CTRL_POWER_UP + | USB_CTRL_P_2 + | USB_CTRL_N_1 + | (191U << USB_CTRL_M_SHIFT); + while ((LPC32XX_USB_CTRL & USB_CTRL_PLL_LOCK) == 0) { + /* Wait */ + } + LPC32XX_USB_CTRL |= USB_CTRL_CLKEN2; +} + +static void lpc_usb_module_disable(void) +{ + LPC32XX_OTG_CLK_CTRL = 0; + LPC32XX_USB_CTRL = USB_CTRL_PC_BUS_KEEPER; +} + +static void lpc_usb_pin_config(void) +{ + /* Nothing to do */ +} + +static void lpc_usb_host_clock_enable(void) +{ + LPC32XX_USB_CTRL |= USB_CTRL_HOST_NEED_CLK_EN; +} + +static void lpc_otg_status_and_control(void) +{ + LPC32XX_OTG_STAT_CTRL = 0x1; +} + +#endif /* LIBBSP_ARM_LPC32XX_BSP_H */ + +static rtems_interval lpc_usb_timeout_init(void) +{ + return rtems_clock_get_ticks_since_boot(); +} + +static bool lpc_usb_timeout_not_expired(rtems_interval start) +{ + rtems_interval elapsed = rtems_clock_get_ticks_since_boot() - start; + + return elapsed < rtems_clock_get_ticks_per_second() / 10; +} + +#define LPC_OTG_CLK_HOST BSP_BIT32(0) +#define LPC_OTG_CLK_DEV BSP_BIT32(1) +#define LPC_OTG_CLK_I2C BSP_BIT32(2) +#define LPC_OTG_CLK_OTG BSP_BIT32(3) +#define LPC_OTG_CLK_AHB BSP_BIT32(4) + +static int lpc_otg_clk_ctrl(uint32_t otg_clk_ctrl) +{ + rtems_interval start; + bool not_ok; + + LPC_OTG_CLK_CTRL = otg_clk_ctrl; + + start = lpc_usb_timeout_init(); + while ( + (not_ok = (LPC_OTG_CLK_STAT & otg_clk_ctrl) != otg_clk_ctrl) + && lpc_usb_timeout_not_expired(start) + ) { + /* Wait */ + } + + return not_ok ? EIO : 0; +} + +#include <sys/cdefs.h> +#include <sys/stdint.h> +#include <sys/stddef.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/linker_set.h> +#include <sys/module.h> +#include <sys/lock.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/sysctl.h> +#include <sys/sx.h> +#include <sys/unistd.h> +#include <sys/callout.h> +#include <sys/malloc.h> +#include <sys/priv.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> + +#include <dev/usb/usb_core.h> +#include <dev/usb/usb_busdma.h> +#include <dev/usb/usb_process.h> +#include <dev/usb/usb_util.h> + +#include <dev/usb/usb_controller.h> +#include <dev/usb/usb_bus.h> +#include <dev/usb/controller/ohci.h> + +#ifdef BSP_USB_OTG_TRANSCEIVER_I2C_ADDR + +#define I2C_CTL_SRST (1U << 8) + +#define I2C_TX_DATA_MASK 0xffU +#define I2C_TX_ADDR_SHIFT 1 +#define I2C_TX_ADDR_MASK 0x7fU +#define I2C_TX_READ (1U << 0) +#define I2C_TX_START (1U << 8) +#define I2C_TX_STOP (1U << 9) + +#define I2C_STS_TDI (1U << 0) +#define I2C_STS_AFI (1U << 1) +#define I2C_STS_NAI (1U << 2) +#define I2C_STS_RFE (1U << 9) + +typedef struct { + uint32_t rx_tx; + uint32_t sts; + uint32_t ctl; + uint32_t clkhi; + uint32_t clklo; +} i2c_regs; + +static volatile i2c_regs *i2c = + (volatile i2c_regs *) LPC_USB_I2C_BASE; + +static int i2c_wait_for_receive_fifo_not_empty(void) +{ + rtems_interval start; + bool not_ok; + + start = lpc_usb_timeout_init(); + while ( + (not_ok = (i2c->sts & I2C_STS_RFE) != 0) + && lpc_usb_timeout_not_expired(start) + ) { + /* Wait */ + } + + return not_ok ? EIO : 0; +} + +static int i2c_wait_for_transaction_done(void) +{ + rtems_interval start; + bool not_ok; + + start = lpc_usb_timeout_init(); + while ( + (not_ok = (i2c->sts & I2C_STS_TDI) == 0) + && lpc_usb_timeout_not_expired(start) + ) { + /* Wait */ + } + + return not_ok ? EIO : 0; +} + +static int i2c_read( + const struct usb_otg_transceiver *self, + uint8_t reg_addr, + uint8_t *value +) +{ + int eno; + + i2c->ctl = I2C_CTL_SRST; + + i2c->rx_tx = self->i2c_addr | I2C_TX_START; + i2c->rx_tx = reg_addr; + i2c->rx_tx = self->i2c_addr | I2C_TX_READ | I2C_TX_START; + i2c->rx_tx = I2C_TX_STOP; + + eno = i2c_wait_for_receive_fifo_not_empty(); + + if (eno == 0) { + *value = (int) i2c->rx_tx; + } + + return eno; +} + +static int i2c_write( + const struct usb_otg_transceiver *self, + uint8_t reg_addr, + uint8_t value +) +{ + int eno; + + i2c->ctl = I2C_CTL_SRST; + i2c->sts = I2C_STS_TDI; + + i2c->rx_tx = self->i2c_addr | I2C_TX_START; + i2c->rx_tx = reg_addr; + i2c->rx_tx = value | I2C_TX_STOP; + + eno = i2c_wait_for_transaction_done(); + + return eno; +} + +#endif /* BSP_USB_OTG_TRANSCEIVER_I2C_ADDR */ + +static device_probe_t ohci_lpc_probe; +static device_attach_t ohci_lpc_attach; +static device_detach_t ohci_lpc_detach; +static device_suspend_t ohci_lpc_suspend; +static device_resume_t ohci_lpc_resume; + +static int +ohci_lpc_otg_transceiver_suspend(ohci_softc_t *e) +{ + int eno = 0; + +#ifdef BSP_USB_OTG_TRANSCEIVER_I2C_ADDR + if (eno == 0) { + eno = lpc_otg_clk_ctrl( + LPC_OTG_CLK_AHB | LPC_OTG_CLK_HOST | LPC_OTG_CLK_I2C + ); + } + + if (eno == 0) { + eno = usb_otg_transceiver_suspend(&e->sc_otg_trans); + } + +#ifdef BSP_USB_OTG_TRANSCEIVER_DUMP + usb_otg_transceiver_dump(&e->sc_otg_trans); +#endif /* BSP_USB_OTG_TRANSCEIVER_DUMP */ + + if (eno == 0) { + eno = lpc_otg_clk_ctrl(LPC_OTG_CLK_AHB | LPC_OTG_CLK_HOST); + } +#endif /* BSP_USB_OTG_TRANSCEIVER_I2C_ADDR */ + + return eno; +} + +static int +ohci_lpc_suspend(device_t self) +{ + ohci_softc_t *e = device_get_softc(self); + int eno = bus_generic_suspend(self); + + if (eno == 0) { + ohci_suspend(e); + } + + return (eno); +} + +static int +ohci_lpc_resume(device_t self) +{ + ohci_softc_t *e = device_get_softc(self); + int eno = 0; + +#ifdef BSP_USB_OTG_TRANSCEIVER_I2C_ADDR + if (eno == 0) { + eno = lpc_otg_clk_ctrl( + LPC_OTG_CLK_AHB | LPC_OTG_CLK_HOST | LPC_OTG_CLK_I2C + ); + } + + if (eno == 0) { + eno = usb_otg_transceiver_resume(&e->sc_otg_trans); + } + +#ifdef BSP_USB_OTG_TRANSCEIVER_VBUS + if (eno == 0) { + eno = usb_otg_transceiver_set_vbus( + &e->sc_otg_trans, + BSP_USB_OTG_TRANSCEIVER_VBUS + ); + } +#endif /* BSP_USB_OTG_TRANSCEIVER_VBUS */ + +#ifdef BSP_USB_OTG_TRANSCEIVER_DUMP + usb_otg_transceiver_dump(&e->sc_otg_trans); +#endif /* BSP_USB_OTG_TRANSCEIVER_DUMP */ + + if (eno == 0) { + eno = lpc_otg_clk_ctrl(LPC_OTG_CLK_AHB | LPC_OTG_CLK_HOST); + } +#endif /* BSP_USB_OTG_TRANSCEIVER_I2C_ADDR */ + + if (eno == 0) { + ohci_resume(e); + + eno = bus_generic_resume(self); + } + + return (eno); +} + +static int +ohci_lpc_probe(device_t self) +{ + device_set_desc(self, "LPC OHCI controller"); + + return (0); +} + +static int +ohci_lpc_attach(device_t self) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + ohci_softc_t *e = device_get_softc(self); + usb_error_t ue = USB_ERR_NORMAL_COMPLETION; + int eno = 0; + + memset(e, 0, sizeof(*e)); + + /* Initialize some bus fields */ + e->sc_bus.parent = self; + e->sc_bus.devices = e->sc_devices; + e->sc_bus.devices_max = OHCI_MAX_DEVICES; + + /* Get all DMA memory */ + if (usb_bus_mem_alloc_all(&e->sc_bus, USB_GET_DMA_TAG(self), &ohci_iterate_hw_softc)) { + return (ENOMEM); + } + e->sc_dev = self; + + /* Child device */ + e->sc_bus.bdev = device_add_child(self, "usbus", -1); + if (e->sc_bus.bdev == NULL) { + device_printf(self, "Could not add USB device\n"); + goto error; + } + device_set_ivars(e->sc_bus.bdev, &e->sc_bus); + device_set_desc(e->sc_bus.bdev, "LPC OHCI bus"); + snprintf(e->sc_vendor, sizeof(e->sc_vendor), "NXP"); + + /* Register space */ + e->sc_io_tag = 0U; + e->sc_io_hdl = LPC_USB_OHCI_BASE; + e->sc_io_size = 0x5cU; + + lpc_usb_module_enable(); + + eno = lpc_otg_clk_ctrl(LPC_OTG_CLK_AHB | LPC_OTG_CLK_I2C); + if (eno != 0) { + goto error; + } + + lpc_usb_pin_config(); + +#ifdef BSP_USB_OTG_TRANSCEIVER_I2C_ADDR + e->sc_otg_trans.read = i2c_read; + e->sc_otg_trans.write = i2c_write; + e->sc_otg_trans.i2c_addr = BSP_USB_OTG_TRANSCEIVER_I2C_ADDR; + eno = usb_otg_transceiver_init(&e->sc_otg_trans); + if (eno != 0) { + goto error; + } + +#ifdef BSP_USB_OTG_TRANSCEIVER_DUMP + usb_otg_transceiver_dump(&e->sc_otg_trans); +#endif /* BSP_USB_OTG_TRANSCEIVER_DUMP */ + + eno = usb_otg_transceiver_resume(&e->sc_otg_trans); + if (eno != 0) { + goto error; + } +#endif /* BSP_USB_OTG_TRANSCEIVER_I2C_ADDR */ + + lpc_usb_host_clock_enable(); + + eno = lpc_otg_clk_ctrl( + LPC_OTG_CLK_AHB | LPC_OTG_CLK_HOST + | LPC_OTG_CLK_I2C | LPC_OTG_CLK_OTG + ); + if (eno != 0) { + goto error; + } + + lpc_otg_status_and_control(); + +#if defined(BSP_USB_OTG_TRANSCEIVER_I2C_ADDR) \ + && defined(BSP_USB_OTG_TRANSCEIVER_VBUS) + eno = usb_otg_transceiver_set_vbus( + &e->sc_otg_trans, + BSP_USB_OTG_TRANSCEIVER_VBUS + ); + if (eno != 0) { + goto error; + } +#endif /* defined(BSP_USB_OTG_TRANSCEIVER_I2C_ADDR) + && defined(BSP_USB_OTG_TRANSCEIVER_VBUS) */ + +#if defined(BSP_USB_OTG_TRANSCEIVER_I2C_ADDR) \ + && defined(BSP_USB_OTG_TRANSCEIVER_DUMP) + usb_otg_transceiver_dump(&e->sc_otg_trans); +#endif /* defined(BSP_USB_OTG_TRANSCEIVER_I2C_ADDR) + && defined(BSP_USB_OTG_TRANSCEIVER_DUMP) */ + + eno = lpc_otg_clk_ctrl(LPC_OTG_CLK_AHB | LPC_OTG_CLK_HOST); + if (eno != 0) { + goto error; + } + + /* Install interrupt handler */ + sc = rtems_interrupt_server_handler_install( + RTEMS_ID_NONE, + LPC_USB_OHCI_IRQ, + "USB", + RTEMS_INTERRUPT_UNIQUE, + (rtems_interrupt_handler) ohci_interrupt, + e + ); + BSD_ASSERT_SC(sc); + + /* OHCI intitialization */ + ue = ohci_init(e); + if (ue != USB_ERR_NORMAL_COMPLETION) { + goto error; + } + e->sc_init_done = 1; + + /* Probe and attach child */ + eno = device_probe_and_attach(e->sc_bus.bdev); + if (eno != 0) { + goto error; + } + + return (0); + +error: + ohci_lpc_detach(self); + + return (ENXIO); +} + +static int +ohci_lpc_detach(device_t self) +{ + rtems_status_code sc = RTEMS_SUCCESSFUL; + ohci_softc_t *e = device_get_softc(self); + + if (e->sc_bus.bdev) { + device_t bdev = e->sc_bus.bdev; + + device_detach(bdev); + device_delete_child(self, bdev); + } + + device_delete_all_children(self); + + if (e->sc_init_done) { + ohci_detach(e); + } + + sc = rtems_interrupt_server_handler_remove( + RTEMS_ID_NONE, + LPC_USB_OHCI_IRQ, + (rtems_interrupt_handler) ohci_interrupt, + e + ); + BSD_ASSERT_SC(sc); + + ohci_lpc_otg_transceiver_suspend(e); + + lpc_otg_clk_ctrl(0); + + lpc_usb_module_disable(); + + usb_bus_mem_free_all(&e->sc_bus, &ohci_iterate_hw_softc); + + return (0); +} + +static device_method_t ohci_methods [] = { + /* Device interface */ + DEVMETHOD(device_probe, ohci_lpc_probe), + DEVMETHOD(device_attach, ohci_lpc_attach), + DEVMETHOD(device_detach, ohci_lpc_detach), + DEVMETHOD(device_suspend, ohci_lpc_suspend), + DEVMETHOD(device_resume, ohci_lpc_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + {0, 0} +}; + +static driver_t ohci_driver = { + .name = "ohci", + .methods = ohci_methods, + .size = sizeof(struct ohci_softc) +}; + +static devclass_t ohci_devclass; + +DRIVER_MODULE(ohci, nexus, ohci_driver, ohci_devclass, 0, 0); +MODULE_DEPEND(ohci, usb, 1, 1, 1); + +#endif /* defined(LIBBSP_ARM_LPC24XX_BSP_H) || defined(LIBBSP_ARM_LPC32XX_BSP_H) */ diff --git a/rtemsbsd/sys/dev/usb/controller/ohci_lpc24xx.c b/rtemsbsd/sys/dev/usb/controller/ohci_lpc24xx.c deleted file mode 100644 index bfb3c8c7..00000000 --- a/rtemsbsd/sys/dev/usb/controller/ohci_lpc24xx.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. - */ - -#include <machine/rtems-bsd-kernel-space.h> - -#include <bsp.h> - -#ifdef LIBBSP_ARM_LPC24XX_BSP_H - -#include <bsp/irq.h> -#include <bsp/io.h> -#include <bsp/lpc24xx.h> - -#include <sys/cdefs.h> -#include <sys/stdint.h> -#include <sys/stddef.h> -#include <rtems/bsd/sys/param.h> -#include <sys/queue.h> -#include <rtems/bsd/sys/types.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/bus.h> -#include <sys/linker_set.h> -#include <sys/module.h> -#include <rtems/bsd/sys/lock.h> -#include <sys/mutex.h> -#include <sys/condvar.h> -#include <sys/sysctl.h> -#include <sys/sx.h> -#include <rtems/bsd/sys/unistd.h> -#include <sys/callout.h> -#include <sys/malloc.h> -#include <sys/priv.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> - -#include <dev/usb/usb_core.h> -#include <dev/usb/usb_busdma.h> -#include <dev/usb/usb_process.h> -#include <dev/usb/usb_util.h> - -#include <dev/usb/usb_controller.h> -#include <dev/usb/usb_bus.h> -#include <dev/usb/controller/ohci.h> - -static device_probe_t ohci_lpc24xx_probe; -static device_attach_t ohci_lpc24xx_attach; -static device_detach_t ohci_lpc24xx_detach; -static device_suspend_t ohci_lpc24xx_suspend; -static device_resume_t ohci_lpc24xx_resume; - -static int -ohci_lpc24xx_suspend(device_t self) -{ - ohci_softc_t *e = device_get_softc(self); - int eno = bus_generic_suspend(self); - - if (eno != 0) { - return (eno); - } - - ohci_suspend(e); - - return (0); -} - -static int -ohci_lpc24xx_resume(device_t self) -{ - ohci_softc_t *e = device_get_softc(self); - - ohci_resume(e); - - bus_generic_resume(self); - - return (0); -} - - -static int -ohci_lpc24xx_probe(device_t self) -{ - device_set_desc(self, "LPC24XX OHCI controller"); - - return (0); -} - -static int -ohci_lpc24xx_attach(device_t self) -{ - static const lpc24xx_pin_range pins [] = { - LPC24XX_PIN_USB_D_PLUS_1, - LPC24XX_PIN_USB_D_MINUS_1, - LPC24XX_PIN_USB_PPWR_1, - LPC24XX_PIN_TERMINAL - }; - - rtems_status_code sc = RTEMS_SUCCESSFUL; - ohci_softc_t *e = device_get_softc(self); - usb_error_t ue = USB_ERR_NORMAL_COMPLETION; - int eno = 0; - - memset(e, 0, sizeof(*e)); - - BSD_PRINTF("XXX\n"); - - /* Initialize some bus fields */ - e->sc_bus.parent = self; - e->sc_bus.devices = e->sc_devices; - e->sc_bus.devices_max = OHCI_MAX_DEVICES; - - /* Get all DMA memory */ - if (usb_bus_mem_alloc_all(&e->sc_bus, USB_GET_DMA_TAG(self), &ohci_iterate_hw_softc)) { - return (ENOMEM); - } - e->sc_dev = self; - - /* Child device */ - e->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (e->sc_bus.bdev == NULL) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(e->sc_bus.bdev, &e->sc_bus); - device_set_desc(e->sc_bus.bdev, "LPC24XX OHCI bus"); - snprintf(e->sc_vendor, sizeof(e->sc_vendor), "NXP"); - - /* Register space */ - e->sc_io_tag = 0U; - e->sc_io_hdl = USBHC_BASE_ADDR; - e->sc_io_size = 0x5cU; - - /* Enable USB module */ - sc = lpc24xx_module_enable(LPC24XX_MODULE_USB, LPC24XX_MODULE_PCLK_DEFAULT); - BSD_ASSERT_SC(sc); - - /* Enable USB host and AHB clocks */ - OTG_CLK_CTRL = 0x19; - while ((OTG_CLK_STAT & 0x19) != 0x19) { - /* Wait */ - } - - /* Set OTG Status and Control Register */ - OTG_STAT_CTRL = 0x3; - - /* Configure IO pins */ - sc = lpc24xx_pin_config(&pins [0], LPC24XX_PIN_SET_FUNCTION); - BSD_ASSERT_SC(sc); - - /* Install interrupt handler */ - sc = rtems_interrupt_server_handler_install( - RTEMS_ID_NONE, - LPC24XX_IRQ_USB, - "USB", - RTEMS_INTERRUPT_UNIQUE, - (rtems_interrupt_handler) ohci_interrupt, - e - ); - BSD_ASSERT_SC(sc); - - /* OHCI intitialization */ - ue = ohci_init(e); - if (ue != USB_ERR_NORMAL_COMPLETION) { - goto error; - } - - /* Probe and attach child */ - eno = device_probe_and_attach(e->sc_bus.bdev); - if (eno != 0) { - goto error; - } - - return (0); - -error: - ohci_lpc24xx_detach(self); - return (ENXIO); -} - -static int -ohci_lpc24xx_detach(device_t self) -{ - ohci_softc_t *e = device_get_softc(self); - - BSD_PRINTF("XXX\n"); - - return (0); -} - -static device_method_t ohci_methods [] = { - /* Device interface */ - DEVMETHOD(device_probe, ohci_lpc24xx_probe), - DEVMETHOD(device_attach, ohci_lpc24xx_attach), - DEVMETHOD(device_detach, ohci_lpc24xx_detach), - DEVMETHOD(device_suspend, ohci_lpc24xx_suspend), - DEVMETHOD(device_resume, ohci_lpc24xx_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t ohci_driver = { - .name = "ohci", - .methods = ohci_methods, - .size = sizeof(struct ohci_softc) -}; - -static devclass_t ohci_devclass; - -DRIVER_MODULE(ohci, nexus, ohci_driver, ohci_devclass, 0, 0); -MODULE_DEPEND(ohci, usb, 1, 1, 1); - -#endif /* LIBBSP_ARM_LPC24XX_BSP_H */ diff --git a/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c b/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c deleted file mode 100644 index 264f9619..00000000 --- a/rtemsbsd/sys/dev/usb/controller/ohci_lpc32xx.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright (c) 2009-2012 embedded brains GmbH. All rights reserved. - * - * embedded brains GmbH - * Obere Lagerstr. 30 - * 82178 Puchheim - * Germany - * <rtems@embedded-brains.de> - * - * The license and distribution terms for this file may be - * found in the file LICENSE in this distribution or at - * http://www.rtems.com/license/LICENSE. - */ - -#include <machine/rtems-bsd-kernel-space.h> - -#include <bsp.h> - -#ifdef LIBBSP_ARM_LPC32XX_BSP_H - -#include <bsp/irq.h> -#include <bsp/lpc32xx.h> - -#include <sys/cdefs.h> -#include <sys/stdint.h> -#include <sys/stddef.h> -#include <rtems/bsd/sys/param.h> -#include <sys/queue.h> -#include <rtems/bsd/sys/types.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/bus.h> -#include <sys/linker_set.h> -#include <sys/module.h> -#include <rtems/bsd/sys/lock.h> -#include <sys/mutex.h> -#include <sys/condvar.h> -#include <sys/sysctl.h> -#include <sys/sx.h> -#include <rtems/bsd/sys/unistd.h> -#include <sys/callout.h> -#include <sys/malloc.h> -#include <sys/priv.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> - -#include <dev/usb/usb_core.h> -#include <dev/usb/usb_busdma.h> -#include <dev/usb/usb_process.h> -#include <dev/usb/usb_util.h> - -#include <dev/usb/usb_controller.h> -#include <dev/usb/usb_bus.h> -#include <dev/usb/controller/ohci.h> - -#define USB_CTRL_SLAVE_HCLK_EN (1U << 24) -#define USB_CTRL_I2C_EN (1U << 23) -#define USB_CTRL_DEV_NEED_CLK_EN (1U << 22) -#define USB_CTRL_HOST_NEED_CLK_EN (1U << 21) -#define USB_CTRL_PC_MASK (0x3U << 19) -#define USB_CTRL_PC_PULL_UP (0x0U << 19) -#define USB_CTRL_PC_BUS_KEEPER (0x1U << 19) -#define USB_CTRL_PC_NONE (0x2U << 19) -#define USB_CTRL_PC_PULL_DOWN (0x3U << 19) -#define USB_CTRL_CLKEN2 (1U << 18) -#define USB_CTRL_CLKEN1 (1U << 17) -#define USB_CTRL_POWER_UP (1U << 16) -#define USB_CTRL_BYPASS (1U << 15) -#define USB_CTRL_DIRECT (1U << 14) -#define USB_CTRL_FEEDBACK (1U << 13) -#define USB_CTRL_P_SHIFT 11 -#define USB_CTRL_P_MASK (0x3U << USB_CTRL_P_SHIFT) -#define USB_CTRL_P_1 (0x0U << USB_CTRL_P_SHIFT) -#define USB_CTRL_P_2 (0x1U << USB_CTRL_P_SHIFT) -#define USB_CTRL_P_4 (0x2U << USB_CTRL_P_SHIFT) -#define USB_CTRL_P_8 (0x3U << USB_CTRL_P_SHIFT) -#define USB_CTRL_N_SHIFT 9 -#define USB_CTRL_N_MASK (0x3U << USB_CTRL_N_SHIFT) -#define USB_CTRL_N_1 (0x0U << USB_CTRL_N_SHIFT) -#define USB_CTRL_N_2 (0x1U << USB_CTRL_N_SHIFT) -#define USB_CTRL_N_3 (0x2U << USB_CTRL_N_SHIFT) -#define USB_CTRL_N_4 (0x3U << USB_CTRL_N_SHIFT) -#define USB_CTRL_M_SHIFT 1 -#define USB_CTRL_M_MASK (0xffU << USB_CTRL_M_SHIFT) -#define USB_CTRL_PLL_LOCK (1U << 0) - -#define I2C_CTL_SRST (1U << 8) - -#define I2C_TX_DATA_MASK 0xffU -#define I2C_TX_ADDR_SHIFT 1 -#define I2C_TX_ADDR_MASK 0x7fU -#define I2C_TX_READ (1U << 0) -#define I2C_TX_START (1U << 8) -#define I2C_TX_STOP (1U << 9) - -#define I2C_STS_TDI (1U << 0) -#define I2C_STS_AFI (1U << 1) -#define I2C_STS_NAI (1U << 2) -#define I2C_STS_RFE (1U << 9) - -#define PHY_VENDOR_ID_LOW 0x0U -#define PHY_VENDOR_ID_HIGH 0x1U -#define PHY_PRODUCT_ID_LOW 0x2U -#define PHY_PRODUCT_ID_HIGH 0x3U -#define PHY_MODE_CONTROL_1 0x4U -#define PHY_MODE_CONTROL_1_SET 0x4U -#define PHY_MODE_CONTROL_1_CLEAR 0x5U -#define PHY_MODE_CONTROL_X 0x12U -#define PHY_MODE_CONTROL_X_SET 0x12U -#define PHY_MODE_CONTROL_X_CLEAR 0x13U -#define PHY_OTG_CONTROL 0x6U -#define PHY_OTG_CONTROL_SET 0x6U -#define PHY_OTG_CONTROL_CLEAR 0x7U -#define PHY_INTERRUPT_SOURCE 0x8U -#define PHY_INTERRUPT_LATCH 0xaU -#define PHY_INTERRUPT_LATCH_SET 0xaU -#define PHY_INTERRUPT_LATCH_CLEAR 0xbU -#define PHY_INTERRUPT_ENABLE_LOW 0xcU -#define PHY_INTERRUPT_ENABLE_LOW_SET 0xcU -#define PHY_INTERRUPT_ENABLE_LOW_CLEAR 0xdU -#define PHY_INTERRUPT_ENABLE_HIGH 0xeU -#define PHY_INTERRUPT_ENABLE_HIGH_SET 0xeU -#define PHY_INTERRUPT_ENABLE_HIGH_CLEAR 0xfU - -// ISP130x Specific... -#define ISP130x_VERSION_ID_LOW 0x14U -#define ISP130x_VERSION_ID_HIGH 0x15U -#define ISP130x_OTG_STATUS 0x10U - -// ISP1302 Specific... -#define ISP1302_MISC_CONTROL_SET 0x18U -#define ISP1302_MISC_CONTROL_CLEAR 0x19U - - -#define PHY_MODE_CONTROL_1_SPEED_REG (1U << 0) -#define PHY_MODE_CONTROL_1_SUSPEND_REG (1U << 1) -#define PHY_MODE_CONTROL_1_DAT_SE0 (1U << 2) -#define PHY_MODE_CONTROL_1_TRANSP_EN (1U << 3) -#define PHY_MODE_CONTROL_1_BDIS_ACON_EN (1U << 4) -#define PHY_MODE_CONTROL_1_OE_INT_EN (1U << 5) -#define PHY_MODE_CONTROL_1_UART_EN (1U << 6) - -// MODE CONTROL 'X' -// -// On ISP130x this is register MODE CONTROL 2 -// On STOTG04E this is register CONTROL 3 -// -// 'rsrvd' = not available reserved bit. -// 'diff' = different functionality . -// -// Bit Function ISP1301 ISP1302 STOTG04E -// -------------------------------------------------------------- -// 0 PWR_DN Y Y rsrvd -// 1 SPD_SUSP_CTRL Y rsrvd diff -// 2 BI_DI Y rsrvd Y -// 3 TRANSP_BDIR[0] Y Y Y -// 4 TRANSP_BDIR[1] Y Y Y -// 5 AUDIO_EN Y Y Y -// 6 PSW_OE Y Y Y -// 7 EN2V7 Y rsrvd Y - - -//ISP1301 & ISP1302 (Reserved on STOTG04E) -#define ISP130x_MODE_CONTROL_X_GLOBAL_PWR_DN (1U << 0) -//ISP1301 (ISP1302 reserved bit!) -#define ISP1301_MODE_CONTROL_X_SPD_SUSP_CTRL (1U << 1) -//STOTG04E (Different functionality!) -#define STOTG04E_MODE_CONTROL_X_RX_BIAS_EN ISP1301_MODE_CONTROL_X_SPD_SUSP_CTRL -//ISP1301 (ISP1302 reserved bit!) -#define ISP1301_MODE_CONTROL_X_BI_DI (1U << 2) -//STOTG04E -#define STOTG04E_MODE_CONTROL_X_BI_DI ISP1301_MODE_CONTROL_X_BI_DI -//ISP1301, ISP1302 & STOTG04E common definitions. -#define PHY_MODE_CONTROL_X_TRANSP_BDIR0 (1U << 3) -#define PHY_MODE_CONTROL_X_TRANSP_BDIR1 (1U << 4) -#define PHY_MODE_CONTROL_X_AUDIO_EN (1U << 5) -#define PHY_MODE_CONTROL_X_PSW_OE (1U << 6) -//ISP1301 (ISP1302 reserved bit.) -#define ISP1301_MODE_CONTROL_X_EN2V7 (1U << 7) -//STOTG04E -#define STOTG04E_MODE_CONTROL_X_EN2V7 ISP1301_MODE_CONTROL_X_EN2V7 - - -// Note: STOTG04E Control register 2 = ISP130x OTG Control register -#define PHY_OTG_CONTROL_DP_PULLUP (1U << 0) -#define PHY_OTG_CONTROL_DM_PULLUP (1U << 1) -#define PHY_OTG_CONTROL_DP_PULLDOWN (1U << 2) -#define PHY_OTG_CONTROL_DM_PULLDOWN (1U << 3) -#define PHY_OTG_CONTROL_ID_PULLDOWN (1U << 4) -#define PHY_OTG_CONTROL_VBUS_DRV (1U << 5) -#define PHY_OTG_CONTROL_VBUS_DISCHRG (1U << 6) -#define PHY_OTG_CONTROL_VBUS_CHRG (1U << 7) - -#define PHY_ADDR (0x2cU << I2C_TX_ADDR_SHIFT) - -// ISP1302 Specific... -#define ISP1302_MISC_CONTROL_REG_BYPASS_DIS (1U << 0) -#define ISP1302_MISC_CONTROL_SRP_INIT (1U << 1) -#define ISP1302_MISC_CONTROL_DP_WKPU_EN (1U << 2) -#define ISP1302_MISC_CONTROL_IDPU_DIS (1U << 3) -#define ISP1302_MISC_CONTROL_UART_2V8_EN (1U << 4) -#define ISP1302_MISC_CONTROL_FORCE_DP_LOW (1U << 6) -#define ISP1302_MISC_CONTROL_FORCE_DP_HIGH (1U << 7) - -// Product Indentifers. -#define ISP1301_PRODUCT_ID 0x1301 -#define ISP1302_PRODUCT_ID 0x1302 -#define STOTG04E_PRODUCT_ID 0xA0C4 - - - -typedef struct -{ - uint16_t VendorID; - uint16_t ProductID; - uint16_t VersionID; -} phy_Details_Typ; - -static void -i2c_wait_for_receive_fifo_not_empty(void) -{ - while ((LPC32XX_I2C_STS & I2C_STS_RFE) != 0) { - /* Wait */ - } -} - -static uint8_t -phy_read(uint8_t reg) -{ - LPC32XX_I2C_CTL = I2C_CTL_SRST; - - LPC32XX_I2C_TX = PHY_ADDR | I2C_TX_START; - - LPC32XX_I2C_TX = reg; - - LPC32XX_I2C_TX = PHY_ADDR | I2C_TX_READ | I2C_TX_START; - - LPC32XX_I2C_TX = I2C_TX_STOP; - - i2c_wait_for_receive_fifo_not_empty(); - - return (uint8_t) LPC32XX_I2C_RX; -} - -static void -i2c_wait_for_transaction_done(void) -{ - while ((LPC32XX_I2C_STS & I2C_STS_TDI) == 0) { - /* Wait */ - } - - LPC32XX_I2C_STS = I2C_STS_TDI; -} - -static void -phy_write(uint8_t reg, uint8_t val) -{ - - LPC32XX_I2C_CTL = I2C_CTL_SRST; - - LPC32XX_I2C_TX = PHY_ADDR | I2C_TX_START; - - LPC32XX_I2C_TX = reg; - - LPC32XX_I2C_TX = val | I2C_TX_STOP; - - i2c_wait_for_transaction_done(); -} - -static phy_Details_Typ - phy_GetDetails(void) -{ - phy_Details_Typ PhyDetails; - - PhyDetails.VendorID = (uint16_t)((phy_read(PHY_VENDOR_ID_HIGH) << 8) | - phy_read(PHY_VENDOR_ID_LOW)); - - PhyDetails.ProductID = (uint16_t)((phy_read(PHY_PRODUCT_ID_HIGH) << 8) | - phy_read(PHY_PRODUCT_ID_LOW)); - - if (PhyDetails.ProductID == STOTG04E_PRODUCT_ID) - { - // STOTG04E - Does not support 'Version' thus default it here to 'zero' - PhyDetails.VersionID = 0; - } - else - { - PhyDetails.VersionID = (uint16_t)((phy_read(ISP130x_VERSION_ID_HIGH) << 8) | - phy_read(ISP130x_VERSION_ID_LOW)); - } - - return PhyDetails; -} - -static char const * -get_PhyNameString(uint16_t ProductID) -{ - static char const * const ISP1301 = "ISP1301"; - static char const * const ISP1302 = "ISP1302"; - static char const * const STOTG04E = "STOTG04E"; - static char const * const UNKNOWN = "Unknown!"; - - char const * String_Ptr = ISP1301; - - switch (ProductID) { - case ISP1301_PRODUCT_ID: - String_Ptr = ISP1301; - break; - - case ISP1302_PRODUCT_ID: - String_Ptr = ISP1302; - break; - - case STOTG04E_PRODUCT_ID: - String_Ptr = STOTG04E; - break; - - default: - String_Ptr = UNKNOWN; - break; - } - - return String_Ptr; -} - -static void -phy_dump(void) -{ - phy_Details_Typ PhyDetails = phy_GetDetails(); - - switch (PhyDetails.ProductID) { - case ISP1301_PRODUCT_ID: - case ISP1302_PRODUCT_ID: - // ISP130x has extra OTG status register. - BSD_PRINTF( - "Registers: mc1 %02x, mc2 %02x, otgctrl %02x, otgsts %02x, isrc %02x, iltch %02x, ienl %02x, ienh %02x\n", - phy_read(PHY_MODE_CONTROL_1), - phy_read(PHY_MODE_CONTROL_X), - phy_read(PHY_OTG_CONTROL), - phy_read(ISP130x_OTG_STATUS), - phy_read(PHY_INTERRUPT_SOURCE), - phy_read(PHY_INTERRUPT_LATCH), - phy_read(PHY_INTERRUPT_ENABLE_LOW), - phy_read(PHY_INTERRUPT_ENABLE_HIGH) - ); - break; - - case STOTG04E_PRODUCT_ID: - // Control register 2 is 'otgctrl', control register 3 is equivalent ISP130x control register 2. - BSD_PRINTF( - "Registers: mc1 %02x, mc3 %02x, otgctrl %02x, isrc %02x, iltch %02x, ienl %02x, ienh %02x\n", - phy_read(PHY_MODE_CONTROL_1), - phy_read(PHY_MODE_CONTROL_X), - phy_read(PHY_OTG_CONTROL), - phy_read(PHY_INTERRUPT_SOURCE), - phy_read(PHY_INTERRUPT_LATCH), - phy_read(PHY_INTERRUPT_ENABLE_LOW), - phy_read(PHY_INTERRUPT_ENABLE_HIGH) - ); - break; - - default: - BSD_ASSERT_SC(RTEMS_UNSATISFIED); - break; - } -} - -static void -phy_configure(void) -{ - phy_Details_Typ PhyDetails = phy_GetDetails(); - - BSD_PRINTF( - "USB-PHY: %s (vendor 0x%04x, product 0x%04x, version 0x%04x)\n", - get_PhyNameString(PhyDetails.ProductID), - PhyDetails.VendorID, - PhyDetails.ProductID, - PhyDetails.VersionID - ); - - phy_write(PHY_MODE_CONTROL_1_CLEAR, 0xff); - phy_write(PHY_MODE_CONTROL_1_SET, PHY_MODE_CONTROL_1_SPEED_REG); - phy_write(PHY_MODE_CONTROL_X_CLEAR, 0xff); - - switch (PhyDetails.ProductID) { - case ISP1301_PRODUCT_ID: - phy_write( - PHY_MODE_CONTROL_X_SET, - ISP1301_MODE_CONTROL_X_BI_DI - | PHY_MODE_CONTROL_X_PSW_OE - | ISP1301_MODE_CONTROL_X_SPD_SUSP_CTRL - ); - break; - - case ISP1302_PRODUCT_ID: - // Do not set 'SPD_SUSP_CTRL' bit as per ISP1301 this bit is reserved in - // ISP1302, setting it will cause problems. - // also as we have cleared Control register 2 (above) we must reset the - // reserved BI_DI bit otherwise it will not work. - phy_write( - PHY_MODE_CONTROL_X_SET, - ISP1301_MODE_CONTROL_X_BI_DI | PHY_MODE_CONTROL_X_PSW_OE - ); - - // ISP1302 has an additonal register we should initialise it.. - phy_write(ISP1302_MISC_CONTROL_CLEAR, 0xff); - phy_write(ISP1302_MISC_CONTROL_SET, ISP1302_MISC_CONTROL_UART_2V8_EN); - break; - - case STOTG04E_PRODUCT_ID: - phy_write( - PHY_MODE_CONTROL_X_SET, - STOTG04E_MODE_CONTROL_X_BI_DI | PHY_MODE_CONTROL_X_PSW_OE - ); - break; - - default: - BSD_ASSERT_SC(RTEMS_UNSATISFIED); - break; - } - - phy_write(PHY_OTG_CONTROL_CLEAR, 0xff); - phy_write(PHY_MODE_CONTROL_1_SET, PHY_MODE_CONTROL_1_DAT_SE0); - phy_write(PHY_OTG_CONTROL_SET, PHY_OTG_CONTROL_DM_PULLDOWN | PHY_OTG_CONTROL_DP_PULLDOWN); - phy_write(PHY_INTERRUPT_LATCH_CLEAR, 0xff); - phy_write(PHY_INTERRUPT_ENABLE_LOW_CLEAR, 0xff); - phy_write(PHY_INTERRUPT_ENABLE_HIGH_CLEAR, 0xff); -} - -static void -phy_vbus_on(void) -{ - phy_write(PHY_OTG_CONTROL_SET, PHY_OTG_CONTROL_VBUS_DRV); -} - -static int -ohci_lpc32xx_suspend(device_t self) -{ - ohci_softc_t *e = device_get_softc(self); - int eno = bus_generic_suspend(self); - - if (eno != 0) { - return (eno); - } - - ohci_suspend(e); - - return (0); -} - -static int -ohci_lpc32xx_resume(device_t self) -{ - ohci_softc_t *e = device_get_softc(self); - - ohci_resume(e); - - bus_generic_resume(self); - - return (0); -} - - -static int -ohci_lpc32xx_probe(device_t self) -{ - device_set_desc(self, "LPC32XX OHCI controller"); - - return (0); -} - -static int -ohci_lpc32xx_detach(device_t self) -{ - BSD_PRINTF("FIXME\n"); - - return (0); -} - -static int -ohci_lpc32xx_attach(device_t self) -{ - rtems_status_code sc = RTEMS_SUCCESSFUL; - ohci_softc_t *e = device_get_softc(self); - usb_error_t ue = USB_ERR_NORMAL_COMPLETION; - int eno = 0; - - memset(e, 0, sizeof(*e)); - - /* Initialize some bus fields */ - e->sc_bus.parent = self; - e->sc_bus.devices = e->sc_devices; - e->sc_bus.devices_max = OHCI_MAX_DEVICES; - - /* Get all DMA memory */ - if (usb_bus_mem_alloc_all(&e->sc_bus, USB_GET_DMA_TAG(self), &ohci_iterate_hw_softc)) { - return (ENOMEM); - } - e->sc_dev = self; - - /* Child device */ - e->sc_bus.bdev = device_add_child(self, "usbus", -1); - if (e->sc_bus.bdev == NULL) { - device_printf(self, "Could not add USB device\n"); - goto error; - } - device_set_ivars(e->sc_bus.bdev, &e->sc_bus); - device_set_desc(e->sc_bus.bdev, "LPC32XX OHCI bus"); - snprintf(e->sc_vendor, sizeof(e->sc_vendor), "NXP"); - - /* Register space */ - e->sc_io_tag = 0U; - e->sc_io_hdl = LPC32XX_BASE_USB; - e->sc_io_size = 0x5cU; - - /* Enable USB PLL */ - LPC32XX_USB_DIV = 0xc; - LPC32XX_USB_CTRL = USB_CTRL_SLAVE_HCLK_EN - | USB_CTRL_PC_BUS_KEEPER - | USB_CTRL_CLKEN1 - | USB_CTRL_POWER_UP - | USB_CTRL_P_2 - | USB_CTRL_N_1 - | (191U << USB_CTRL_M_SHIFT); - while ((LPC32XX_USB_CTRL & USB_CTRL_PLL_LOCK) == 0) { - /* Wait */ - } - LPC32XX_USB_CTRL |= USB_CTRL_CLKEN2; - - /* Enable USB host and AHB clocks */ - LPC32XX_OTG_CLK_CTRL = 0x1c; - while ((LPC32XX_OTG_CLK_STAT & 0x1c) != 0x1c) { - /* Wait */ - } - - phy_configure(); - - LPC32XX_USB_CTRL |= USB_CTRL_HOST_NEED_CLK_EN; - - LPC32XX_OTG_CLK_CTRL = 0x1d; - while ((LPC32XX_OTG_CLK_STAT & 0x1d) != 0x1d) { - /* Wait */ - } - - /* Set OTG Status and Control Register */ - LPC32XX_OTG_STAT_CTRL = 0x1; - - phy_vbus_on(); - - /* Install interrupt handler */ - sc = rtems_interrupt_server_handler_install( - RTEMS_ID_NONE, - LPC32XX_IRQ_USB_HOST, - "USB", - RTEMS_INTERRUPT_UNIQUE, - (rtems_interrupt_handler) ohci_interrupt, - e - ); - BSD_ASSERT_SC(sc); - - /* OHCI intitialization */ - ue = ohci_init(e); - if (ue != USB_ERR_NORMAL_COMPLETION) { - goto error; - } - - /* Probe and attach child */ - eno = device_probe_and_attach(e->sc_bus.bdev); - if (eno != 0) { - goto error; - } - - return (0); - -error: - ohci_lpc32xx_detach(self); - return (ENXIO); -} - -static device_method_t ohci_methods [] = { - /* Device interface */ - DEVMETHOD(device_probe, ohci_lpc32xx_probe), - DEVMETHOD(device_attach, ohci_lpc32xx_attach), - DEVMETHOD(device_detach, ohci_lpc32xx_detach), - DEVMETHOD(device_suspend, ohci_lpc32xx_suspend), - DEVMETHOD(device_resume, ohci_lpc32xx_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - /* Bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - {0, 0} -}; - -static driver_t ohci_driver = { - .name = "ohci", - .methods = ohci_methods, - .size = sizeof(struct ohci_softc) -}; - -static devclass_t ohci_devclass; - -DRIVER_MODULE(ohci, nexus, ohci_driver, ohci_devclass, 0, 0); -MODULE_DEPEND(ohci, usb, 1, 1, 1); - -#endif /* LIBBSP_ARM_LPC32XX_BSP_H */ diff --git a/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c b/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c new file mode 100644 index 00000000..688291d4 --- /dev/null +++ b/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <info@embedded-brains.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <dev/usb/usb_otg_transceiver.h> + +#define COUNT(array) (sizeof(array) / sizeof(array [0])) + +#define USB_OTG_CONTROL_1_SPEED_REG (1 << 0) +#define USB_OTG_CONTROL_1_SUSPEND_REG (1 << 1) +#define USB_OTG_CONTROL_1_DAT_SE0 (1 << 2) +#define USB_OTG_CONTROL_1_TRANSP_EN (1 << 3) +#define USB_OTG_CONTROL_1_BDIS_ACON_EN (1 << 4) +#define USB_OTG_CONTROL_1_OE_INT_EN (1 << 5) +#define USB_OTG_CONTROL_1_UART_EN (1 << 6) + +/* + * USB_OTG_CONTROL_3 + * + * On ISP130x this is register MODE CONTROL 2 + * On STOTG04E this is register CONTROL 3 + * + * 'rsrvd' = not available reserved bit. + * 'diff' = different functionality. + * + * Bit Function ISP1301 ISP1302 STOTG04E + * -------------------------------------------------------------- + * 0 PWR_DN Y Y rsrvd + * 1 SPD_SUSP_CTRL Y rsrvd diff + * 2 BI_DI Y rsrvd Y + * 3 TRANSP_BDIR[0] Y Y Y + * 4 TRANSP_BDIR[1] Y Y Y + * 5 AUDIO_EN Y Y Y + * 6 PSW_OE Y Y Y + * 7 EN2V7 Y rsrvd Y + */ + +/* ISP1301 & ISP1302 (Reserved on STOTG04E) */ +#define ISP130x_CONTROL_3_GLOBAL_PWR_DN (1 << 0) +/* ISP1301 (ISP1302 reserved bit!) */ +#define ISP1301_CONTROL_3_SPD_SUSP_CTRL (1 << 1) +/* STOTG04E (Different functionality!) */ +#define STOTG04E_CONTROL_3_RX_BIAS_EN ISP1301_CONTROL_3_SPD_SUSP_CTRL +/* ISP1301 (ISP1302 reserved bit!) */ +#define ISP1301_CONTROL_3_BI_DI (1 << 2) +/* STOTG04E */ +#define STOTG04E_CONTROL_3_RC_BIAS_EN (1 << 1) +#define STOTG04E_CONTROL_3_BIDI_EN ISP1301_CONTROL_3_BI_DI +/* ISP1301, ISP1302 & STOTG04E common definitions. */ +#define USB_OTG_CONTROL_3_TRANSP_BDIR0 (1 << 3) +#define USB_OTG_CONTROL_3_TRANSP_BDIR1 (1 << 4) +#define USB_OTG_CONTROL_3_AUDIO_EN (1 << 5) +#define USB_OTG_CONTROL_3_PSW_OE (1 << 6) +/* ISP1301 (ISP1302 reserved bit.) */ +#define ISP1301_CONTROL_3_EN2V7 (1 << 7) +/* STOTG04E */ +#define STOTG04E_CONTROL_3_2V7_EN ISP1301_CONTROL_3_EN2V7 + +/* Note: STOTG04E Control register 2 = ISP130x OTG Control register */ +#define USB_OTG_CONTROL_2_DP_PULLUP (1 << 0) +#define USB_OTG_CONTROL_2_DM_PULLUP (1 << 1) +#define USB_OTG_CONTROL_2_DP_PULLDOWN (1 << 2) +#define USB_OTG_CONTROL_2_DM_PULLDOWN (1 << 3) +#define USB_OTG_CONTROL_2_ID_PULLDOWN (1 << 4) +#define USB_OTG_CONTROL_2_VBUS_DRV (1 << 5) +#define USB_OTG_CONTROL_2_VBUS_DISCHRG (1 << 6) +#define USB_OTG_CONTROL_2_VBUS_CHRG (1 << 7) + +/* ISP1302 specific */ +#define ISP1302_MISC_CONTROL_REG_BYPASS_DIS (1 << 0) +#define ISP1302_MISC_CONTROL_SRP_INIT (1 << 1) +#define ISP1302_MISC_CONTROL_DP_WKPU_EN (1 << 2) +#define ISP1302_MISC_CONTROL_IDPU_DIS (1 << 3) +#define ISP1302_MISC_CONTROL_UART_2V8_EN (1 << 4) +#define ISP1302_MISC_CONTROL_FORCE_DP_LOW (1 << 6) +#define ISP1302_MISC_CONTROL_FORCE_DP_HIGH (1 << 7) + +int usb_otg_transceiver_read( + const struct usb_otg_transceiver *self, + const uint8_t *reg_addrs, + uint8_t *values, + size_t count +) +{ + int eno = 0; + size_t i; + + for (i = 0; eno == 0 && i < count; ++i) { + eno = (*self->read)(self, reg_addrs [i], &values [i]); + } + + return eno; +} + +int usb_otg_transceiver_write( + const struct usb_otg_transceiver *self, + const struct usb_otg_transceiver_write_request *requests, + size_t count +) +{ + int eno = 0; + size_t i; + + for (i = 0; eno == 0 && i < count; ++i) { + const struct usb_otg_transceiver_write_request *request = &requests [i]; + + eno = (*self->write)(self, request->reg_addr, request->value); + } + + return eno; +} + +int usb_otg_transceiver_init(struct usb_otg_transceiver *self) +{ + static const uint8_t reg_addrs [4] = { + USB_OTG_VENDOR_ID_LOW, + USB_OTG_VENDOR_ID_HIGH, + USB_OTG_PRODUCT_ID_LOW, + USB_OTG_PRODUCT_ID_HIGH + }; + + int eno; + uint8_t values [4]; + + eno = usb_otg_transceiver_read(self, reg_addrs, values, 4); + if (eno == 0) { + self->vendor_id = (uint16_t) ((values [1] << 8) | values [0]); + self->product_id = (uint16_t) ((values [3] << 8) | values [2]); + } + + return eno; +} + +#define RESUME_SETUP_REQUESTS \ + { USB_OTG_CONTROL_1_CLEAR, 0xff }, \ + { USB_OTG_CONTROL_1_SET, USB_OTG_CONTROL_1_SPEED_REG }, \ + { USB_OTG_CONTROL_3_CLEAR, 0xff } + +#define RESUME_FINALIZE_REQUESTS \ + { USB_OTG_CONTROL_2_CLEAR, 0xff }, \ + { USB_OTG_CONTROL_1_SET, USB_OTG_CONTROL_1_DAT_SE0 }, \ + { \ + USB_OTG_CONTROL_2_SET, \ + USB_OTG_CONTROL_2_DM_PULLDOWN | USB_OTG_CONTROL_2_DP_PULLDOWN \ + }, \ + { USB_OTG_INT_LATCH_CLEAR, 0xff }, \ + { USB_OTG_INT_ENABLE_LOW_CLEAR, 0xff }, \ + { USB_OTG_INT_ENABLE_HIGH_CLEAR, 0xff } + +int usb_otg_transceiver_resume(const struct usb_otg_transceiver *self) +{ + static const struct usb_otg_transceiver_write_request + default_requests [] = { + RESUME_SETUP_REQUESTS, + RESUME_FINALIZE_REQUESTS + }; + + static const struct usb_otg_transceiver_write_request + isp1301_requests [] = { + RESUME_SETUP_REQUESTS, + { + USB_OTG_CONTROL_3_SET, + ISP1301_CONTROL_3_BI_DI + | USB_OTG_CONTROL_3_PSW_OE + | ISP1301_CONTROL_3_SPD_SUSP_CTRL + }, + RESUME_FINALIZE_REQUESTS + }; + + static const struct usb_otg_transceiver_write_request + isp1302_requests [] = { + RESUME_SETUP_REQUESTS, + { + USB_OTG_CONTROL_3_SET, + ISP1301_CONTROL_3_BI_DI | USB_OTG_CONTROL_3_PSW_OE + }, { + ISP1302_MISC_CONTROL_CLEAR, + 0xff + }, { + ISP1302_MISC_CONTROL_SET, + ISP1302_MISC_CONTROL_UART_2V8_EN + }, + RESUME_FINALIZE_REQUESTS + }; + + static const struct usb_otg_transceiver_write_request + stotg04e_requests [] = { + RESUME_SETUP_REQUESTS, + { + USB_OTG_CONTROL_3_SET, + STOTG04E_CONTROL_3_BIDI_EN | USB_OTG_CONTROL_3_PSW_OE, + }, + RESUME_FINALIZE_REQUESTS + }; + + int eno; + const struct usb_otg_transceiver_write_request *requests; + size_t count; + + switch (self->product_id) { + case USB_OTG_PRODUCT_ID_ISP1301: + requests = isp1301_requests; + count = COUNT(isp1301_requests); + break; + case USB_OTG_PRODUCT_ID_ISP1302: + requests = isp1302_requests; + count = COUNT(isp1302_requests); + break; + case USB_OTG_PRODUCT_ID_STOTG04E: + requests = stotg04e_requests; + count = COUNT(stotg04e_requests); + break; + default: + requests = default_requests; + count = COUNT(default_requests); + break; + } + + eno = usb_otg_transceiver_write(self, requests, count); + + return eno; +} + +int usb_otg_transceiver_suspend(const struct usb_otg_transceiver *self) +{ + static const struct usb_otg_transceiver_write_request + default_requests [] = { + { + USB_OTG_CONTROL_1_SET, + USB_OTG_CONTROL_1_SUSPEND_REG + }, { + USB_OTG_CONTROL_1_CLEAR, + USB_OTG_CONTROL_1_TRANSP_EN | USB_OTG_CONTROL_1_UART_EN + }, { + USB_OTG_CONTROL_2_CLEAR, + USB_OTG_CONTROL_2_DP_PULLUP + | USB_OTG_CONTROL_2_DM_PULLUP + | USB_OTG_CONTROL_2_ID_PULLDOWN + | USB_OTG_CONTROL_2_VBUS_DRV + | USB_OTG_CONTROL_2_VBUS_CHRG + }, { + USB_OTG_CONTROL_3_SET, + USB_OTG_CONTROL_3_PSW_OE + }, { + USB_OTG_CONTROL_3_CLEAR, + USB_OTG_CONTROL_3_AUDIO_EN + } + }; + + int eno; + const struct usb_otg_transceiver_write_request *requests; + size_t count; + + requests = default_requests; + count = COUNT(default_requests); + + eno = usb_otg_transceiver_write(self, requests, count); + + return eno; +} + +int usb_otg_transceiver_set_vbus( + const struct usb_otg_transceiver *self, + enum usb_otg_transceiver_vbus vbus +) +{ + int eno; + int all = USB_OTG_VBUS_POWER_WITH_CHARGE_PUMP + | USB_OTG_VBUS_DISCHARGE_VIA_RESISTOR + | USB_OTG_VBUS_CHARGE_VIA_RESISTOR; + struct usb_otg_transceiver_write_request requests [] = { + { USB_OTG_CONTROL_2_CLEAR, (uint8_t) (all & ~vbus) }, + { USB_OTG_CONTROL_2_SET, (uint8_t) (all & vbus) } + }; + + eno = usb_otg_transceiver_write(self, &requests [0], COUNT(requests)); + + return eno; +} diff --git a/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver_dump.c b/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver_dump.c new file mode 100644 index 00000000..f125c603 --- /dev/null +++ b/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver_dump.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <info@embedded-brains.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <machine/rtems-bsd-kernel-space.h> + +#include <rtems/bsd/sys/param.h> +#include <sys/systm.h> +#include <dev/usb/usb_otg_transceiver.h> + +int usb_otg_transceiver_dump(const struct usb_otg_transceiver *self) +{ + static const uint8_t reg_addrs [] = { + USB_OTG_CONTROL_1, + USB_OTG_CONTROL_2, + USB_OTG_CONTROL_3, + USB_OTG_INT_SOURCE, + USB_OTG_INT_LATCH, + USB_OTG_INT_ENABLE_LOW, + USB_OTG_INT_ENABLE_HIGH, + ISP130X_OTG_STATUS, + ISP130X_VERSION_ID_LOW, + ISP130X_VERSION_ID_HIGH + }; + + int eno; + uint8_t values [sizeof(reg_addrs) / sizeof(reg_addrs [0])]; + size_t reg_count = 7; + const char *product = "unknown"; + + switch (self->product_id) { + case USB_OTG_PRODUCT_ID_ISP1301: + product = "ISP1301"; + reg_count = 10; + break; + case USB_OTG_PRODUCT_ID_ISP1302: + product = "ISP1302"; + reg_count = 10; + break; + case USB_OTG_PRODUCT_ID_STOTG04E: + product = "STOTG04E"; + break; + case USB_OTG_PRODUCT_ID_MIC2555: + product = "MIC2555"; + break; + default: + break; + } + + printf("USB OTG transceiver <%s>", product); + + eno = usb_otg_transceiver_read(self, reg_addrs, values, reg_count); + if (eno == 0) { + switch (self->product_id) { + case USB_OTG_PRODUCT_ID_ISP1301: + case USB_OTG_PRODUCT_ID_ISP1302: + printf( + ": mctl1 %02x, mctl2 %02x, otgctl %02x" + ", isrc %02x, iltch %02x" + ", ienl %02x, ienh %02x" + ", otgsts %02x" + ", verl %02x, verh %02x\n", + values [0], + values [2], + values [1], + values [3], + values [4], + values [5], + values [6], + values [7], + values [8], + values [9] + ); + break; + default: + printf( + ": ctl1 %02x, ctl2 %02x, ctl3 %02x" + ", isrc %02x, iltch %02x" + ", ienl %02x, ienh %02x\n", + values [0], + values [1], + values [2], + values [3], + values [4], + values [5], + values [6] + ); + break; + } + } else { + printf("\n"); + } + + return eno; +} diff --git a/rtemsbsd/sys/dev/usb/usb_otg_transceiver.h b/rtemsbsd/sys/dev/usb/usb_otg_transceiver.h new file mode 100644 index 00000000..1e6b738d --- /dev/null +++ b/rtemsbsd/sys/dev/usb/usb_otg_transceiver.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <info@embedded-brains.de> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _USB_OTG_TRANSCEIVER_HH_ +#define _USB_OTG_TRANSCEIVER_HH_ + +#include <sys/stdint.h> + +/* USB OTG transceiver standard registers */ +#define USB_OTG_VENDOR_ID_LOW 0x0 +#define USB_OTG_VENDOR_ID_HIGH 0x1 +#define USB_OTG_PRODUCT_ID_LOW 0x2 +#define USB_OTG_PRODUCT_ID_HIGH 0x3 +#define USB_OTG_CONTROL_1 0x4 +#define USB_OTG_CONTROL_1_SET 0x4 +#define USB_OTG_CONTROL_1_CLEAR 0x5 +#define USB_OTG_CONTROL_2 0x6 +#define USB_OTG_CONTROL_2_SET 0x6 +#define USB_OTG_CONTROL_2_CLEAR 0x7 +#define USB_OTG_CONTROL_3 0x12 +#define USB_OTG_CONTROL_3_SET 0x12 +#define USB_OTG_CONTROL_3_CLEAR 0x13 +#define USB_OTG_INT_SOURCE 0x8 +#define USB_OTG_INT_LATCH 0xa +#define USB_OTG_INT_LATCH_SET 0xa +#define USB_OTG_INT_LATCH_CLEAR 0xb +#define USB_OTG_INT_ENABLE_LOW 0xc +#define USB_OTG_INT_ENABLE_LOW_SET 0xc +#define USB_OTG_INT_ENABLE_LOW_CLEAR 0xd +#define USB_OTG_INT_ENABLE_HIGH 0xe +#define USB_OTG_INT_ENABLE_HIGH_SET 0xe +#define USB_OTG_INT_ENABLE_HIGH_CLEAR 0xf + +/* ISP130X specific registers */ +#define ISP130X_OTG_STATUS 0x10 +#define ISP130X_VERSION_ID_LOW 0x14 +#define ISP130X_VERSION_ID_HIGH 0x15 + +/* ISP1302 specific registers */ +#define ISP1302_MISC_CONTROL_SET 0x18 +#define ISP1302_MISC_CONTROL_CLEAR 0x19 + +/* Product identifiers */ +#define USB_OTG_PRODUCT_ID_ISP1301 0x1301 +#define USB_OTG_PRODUCT_ID_ISP1302 0x1302 +#define USB_OTG_PRODUCT_ID_STOTG04E 0xa0c4 +#define USB_OTG_PRODUCT_ID_MIC2555 0x55b0 + +struct usb_otg_transceiver { + int (*read)( + const struct usb_otg_transceiver *self, + uint8_t reg_addr, + uint8_t *value + ); + int (*write)( + const struct usb_otg_transceiver *self, + uint8_t reg_addr, + uint8_t value + ); + uint16_t vendor_id; + uint16_t product_id; + uint8_t i2c_addr; +}; + +int usb_otg_transceiver_read( + const struct usb_otg_transceiver *self, + const uint8_t *reg_addrs, + uint8_t *values, + size_t count +); + +struct usb_otg_transceiver_write_request { + uint8_t reg_addr; + uint8_t value; +}; + +int usb_otg_transceiver_write( + const struct usb_otg_transceiver *self, + const struct usb_otg_transceiver_write_request *requests, + size_t count +); + +int usb_otg_transceiver_init(struct usb_otg_transceiver *self); + +int usb_otg_transceiver_dump(const struct usb_otg_transceiver *self); + +int usb_otg_transceiver_resume(const struct usb_otg_transceiver *self); + +int usb_otg_transceiver_suspend(const struct usb_otg_transceiver *self); + +enum usb_otg_transceiver_vbus { + USB_OTG_VBUS_NOTHING, + USB_OTG_VBUS_POWER_WITH_CHARGE_PUMP = 1 << 5, + USB_OTG_VBUS_DISCHARGE_VIA_RESISTOR = 1 << 6, + USB_OTG_VBUS_CHARGE_VIA_RESISTOR = 1 << 7 +}; + +int usb_otg_transceiver_set_vbus( + const struct usb_otg_transceiver *self, + enum usb_otg_transceiver_vbus vbus +); + +#endif/* _USB_OTG_TRANSCEIVER_HH_ */ |