1 /* 2 * Allwinner SUNXI "glue layer" 3 * 4 * Copyright © 2015 Hans de Goede <hdegoede@redhat.com> 5 * Copyright © 2013 Jussi Kivilinna <jussi.kivilinna@iki.fi> 6 * 7 * Based on the sw_usb "Allwinner OTG Dual Role Controller" code. 8 * Copyright 2007-2012 (C) Allwinner Technology Co., Ltd. 9 * javen <javen@allwinnertech.com> 10 * 11 * Based on the DA8xx "glue layer" code. 12 * Copyright (c) 2008-2009 MontaVista Software, Inc. <source@mvista.com> 13 * Copyright (C) 2005-2006 by Texas Instruments 14 * 15 * This file is part of the Inventra Controller Driver for Linux. 16 * 17 * The Inventra Controller Driver for Linux is free software; you 18 * can redistribute it and/or modify it under the terms of the GNU 19 * General Public License version 2 as published by the Free Software 20 * Foundation. 21 * 22 */ 23 #include <common.h> 24 #include <asm/arch/cpu.h> 25 #include <asm/arch/clock.h> 26 #include <asm/arch/gpio.h> 27 #include <asm/arch/usb_phy.h> 28 #include <asm-generic/gpio.h> 29 #include "linux-compat.h" 30 #include "musb_core.h" 31 #ifdef CONFIG_AXP152_POWER 32 #include <axp152.h> 33 #endif 34 #ifdef CONFIG_AXP209_POWER 35 #include <axp209.h> 36 #endif 37 #ifdef CONFIG_AXP221_POWER 38 #include <axp221.h> 39 #endif 40 41 /****************************************************************************** 42 ****************************************************************************** 43 * From the Allwinner driver 44 ****************************************************************************** 45 ******************************************************************************/ 46 47 /****************************************************************************** 48 * From include/sunxi_usb_bsp.h 49 ******************************************************************************/ 50 51 /* reg offsets */ 52 #define USBC_REG_o_ISCR 0x0400 53 #define USBC_REG_o_PHYCTL 0x0404 54 #define USBC_REG_o_PHYBIST 0x0408 55 #define USBC_REG_o_PHYTUNE 0x040c 56 57 #define USBC_REG_o_VEND0 0x0043 58 59 /* Interface Status and Control */ 60 #define USBC_BP_ISCR_VBUS_VALID_FROM_DATA 30 61 #define USBC_BP_ISCR_VBUS_VALID_FROM_VBUS 29 62 #define USBC_BP_ISCR_EXT_ID_STATUS 28 63 #define USBC_BP_ISCR_EXT_DM_STATUS 27 64 #define USBC_BP_ISCR_EXT_DP_STATUS 26 65 #define USBC_BP_ISCR_MERGED_VBUS_STATUS 25 66 #define USBC_BP_ISCR_MERGED_ID_STATUS 24 67 68 #define USBC_BP_ISCR_ID_PULLUP_EN 17 69 #define USBC_BP_ISCR_DPDM_PULLUP_EN 16 70 #define USBC_BP_ISCR_FORCE_ID 14 71 #define USBC_BP_ISCR_FORCE_VBUS_VALID 12 72 #define USBC_BP_ISCR_VBUS_VALID_SRC 10 73 74 #define USBC_BP_ISCR_HOSC_EN 7 75 #define USBC_BP_ISCR_VBUS_CHANGE_DETECT 6 76 #define USBC_BP_ISCR_ID_CHANGE_DETECT 5 77 #define USBC_BP_ISCR_DPDM_CHANGE_DETECT 4 78 #define USBC_BP_ISCR_IRQ_ENABLE 3 79 #define USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN 2 80 #define USBC_BP_ISCR_ID_CHANGE_DETECT_EN 1 81 #define USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN 0 82 83 /****************************************************************************** 84 * From usbc/usbc.c 85 ******************************************************************************/ 86 87 static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val) 88 { 89 u32 temp = reg_val; 90 91 temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT); 92 temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT); 93 temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT); 94 95 return temp; 96 } 97 98 static void USBC_EnableIdPullUp(__iomem void *base) 99 { 100 u32 reg_val; 101 102 reg_val = musb_readl(base, USBC_REG_o_ISCR); 103 reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN); 104 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 105 musb_writel(base, USBC_REG_o_ISCR, reg_val); 106 } 107 108 static void USBC_EnableDpDmPullUp(__iomem void *base) 109 { 110 u32 reg_val; 111 112 reg_val = musb_readl(base, USBC_REG_o_ISCR); 113 reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN); 114 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 115 musb_writel(base, USBC_REG_o_ISCR, reg_val); 116 } 117 118 static void USBC_ForceIdToLow(__iomem void *base) 119 { 120 u32 reg_val; 121 122 reg_val = musb_readl(base, USBC_REG_o_ISCR); 123 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 124 reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); 125 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 126 musb_writel(base, USBC_REG_o_ISCR, reg_val); 127 } 128 129 static void USBC_ForceIdToHigh(__iomem void *base) 130 { 131 u32 reg_val; 132 133 reg_val = musb_readl(base, USBC_REG_o_ISCR); 134 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 135 reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); 136 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 137 musb_writel(base, USBC_REG_o_ISCR, reg_val); 138 } 139 140 static void USBC_ForceVbusValidToLow(__iomem void *base) 141 { 142 u32 reg_val; 143 144 reg_val = musb_readl(base, USBC_REG_o_ISCR); 145 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 146 reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID); 147 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 148 musb_writel(base, USBC_REG_o_ISCR, reg_val); 149 } 150 151 static void USBC_ForceVbusValidToHigh(__iomem void *base) 152 { 153 u32 reg_val; 154 155 reg_val = musb_readl(base, USBC_REG_o_ISCR); 156 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 157 reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 158 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 159 musb_writel(base, USBC_REG_o_ISCR, reg_val); 160 } 161 162 static void USBC_ConfigFIFO_Base(void) 163 { 164 u32 reg_value; 165 166 /* config usb fifo, 8kb mode */ 167 reg_value = readl(SUNXI_SRAMC_BASE + 0x04); 168 reg_value &= ~(0x03 << 0); 169 reg_value |= (1 << 0); 170 writel(reg_value, SUNXI_SRAMC_BASE + 0x04); 171 } 172 173 /****************************************************************************** 174 * MUSB Glue code 175 ******************************************************************************/ 176 177 static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) 178 { 179 struct musb *musb = __hci; 180 irqreturn_t retval = IRQ_NONE; 181 182 /* read and flush interrupts */ 183 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); 184 if (musb->int_usb) 185 musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); 186 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); 187 if (musb->int_tx) 188 musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); 189 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); 190 if (musb->int_rx) 191 musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); 192 193 if (musb->int_usb || musb->int_tx || musb->int_rx) 194 retval |= musb_interrupt(musb); 195 196 return retval; 197 } 198 199 /* musb_core does not call enable / disable in a balanced manner <sigh> */ 200 static bool enabled = false; 201 202 static void sunxi_musb_enable(struct musb *musb) 203 { 204 pr_debug("%s():\n", __func__); 205 206 if (enabled) 207 return; 208 209 /* select PIO mode */ 210 musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); 211 212 if (is_host_enabled(musb)) 213 sunxi_usb_phy_power_on(0); /* port power on */ 214 215 USBC_ForceVbusValidToHigh(musb->mregs); 216 217 enabled = true; 218 } 219 220 static void sunxi_musb_disable(struct musb *musb) 221 { 222 pr_debug("%s():\n", __func__); 223 224 if (!enabled) 225 return; 226 227 if (is_host_enabled(musb)) 228 sunxi_usb_phy_power_off(0); /* port power off */ 229 230 USBC_ForceVbusValidToLow(musb->mregs); 231 mdelay(200); /* Wait for the current session to timeout */ 232 233 enabled = false; 234 } 235 236 static int sunxi_musb_init(struct musb *musb) 237 { 238 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 239 int err; 240 241 pr_debug("%s():\n", __func__); 242 243 if (is_host_enabled(musb)) { 244 err = sunxi_usb_phy_vbus_detect(0); 245 if (err) { 246 eprintf("Error: A charger is plugged into the OTG\n"); 247 return -EIO; 248 } 249 } 250 251 musb->isr = sunxi_musb_interrupt; 252 253 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0); 254 #ifdef CONFIG_SUNXI_GEN_SUN6I 255 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0); 256 #endif 257 sunxi_usb_phy_init(0); 258 259 USBC_ConfigFIFO_Base(); 260 USBC_EnableDpDmPullUp(musb->mregs); 261 USBC_EnableIdPullUp(musb->mregs); 262 263 if (is_host_enabled(musb)) { 264 /* Host mode */ 265 USBC_ForceIdToLow(musb->mregs); 266 } else { 267 /* Peripheral mode */ 268 USBC_ForceIdToHigh(musb->mregs); 269 } 270 USBC_ForceVbusValidToHigh(musb->mregs); 271 272 return 0; 273 } 274 275 const struct musb_platform_ops sunxi_musb_ops = { 276 .init = sunxi_musb_init, 277 .enable = sunxi_musb_enable, 278 .disable = sunxi_musb_disable, 279 }; 280