summaryrefslogtreecommitdiffstats
path: root/rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c
diff options
context:
space:
mode:
Diffstat (limited to 'rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c')
-rw-r--r--rtemsbsd/sys/dev/usb/controller/usb_otg_transceiver.c306
1 files changed, 306 insertions, 0 deletions
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;
+}