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_DisableIdPullUp(__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_ID_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_EnableDpDmPullUp(__iomem void *base) 119 { 120 u32 reg_val; 121 122 reg_val = musb_readl(base, USBC_REG_o_ISCR); 123 reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN); 124 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 125 musb_writel(base, USBC_REG_o_ISCR, reg_val); 126 } 127 128 static void USBC_DisableDpDmPullUp(__iomem void *base) 129 { 130 u32 reg_val; 131 132 reg_val = musb_readl(base, USBC_REG_o_ISCR); 133 reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN); 134 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 135 musb_writel(base, USBC_REG_o_ISCR, reg_val); 136 } 137 138 static void USBC_ForceIdToLow(__iomem void *base) 139 { 140 u32 reg_val; 141 142 reg_val = musb_readl(base, USBC_REG_o_ISCR); 143 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 144 reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID); 145 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 146 musb_writel(base, USBC_REG_o_ISCR, reg_val); 147 } 148 149 static void USBC_ForceIdToHigh(__iomem void *base) 150 { 151 u32 reg_val; 152 153 reg_val = musb_readl(base, USBC_REG_o_ISCR); 154 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID); 155 reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID); 156 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 157 musb_writel(base, USBC_REG_o_ISCR, reg_val); 158 } 159 160 static void USBC_ForceVbusValidToHigh(__iomem void *base) 161 { 162 u32 reg_val; 163 164 reg_val = musb_readl(base, USBC_REG_o_ISCR); 165 reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 166 reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID); 167 reg_val = USBC_WakeUp_ClearChangeDetect(reg_val); 168 musb_writel(base, USBC_REG_o_ISCR, reg_val); 169 } 170 171 static void USBC_ConfigFIFO_Base(void) 172 { 173 u32 reg_value; 174 175 /* config usb fifo, 8kb mode */ 176 reg_value = readl(SUNXI_SRAMC_BASE + 0x04); 177 reg_value &= ~(0x03 << 0); 178 reg_value |= (1 << 0); 179 writel(reg_value, SUNXI_SRAMC_BASE + 0x04); 180 } 181 182 /****************************************************************************** 183 * MUSB Glue code 184 ******************************************************************************/ 185 186 static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) 187 { 188 struct musb *musb = __hci; 189 irqreturn_t retval = IRQ_NONE; 190 191 /* read and flush interrupts */ 192 musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); 193 if (musb->int_usb) 194 musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); 195 musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); 196 if (musb->int_tx) 197 musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); 198 musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); 199 if (musb->int_rx) 200 musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); 201 202 if (musb->int_usb || musb->int_tx || musb->int_rx) 203 retval |= musb_interrupt(musb); 204 205 return retval; 206 } 207 208 static void sunxi_musb_enable(struct musb *musb) 209 { 210 pr_debug("%s():\n", __func__); 211 212 /* select PIO mode */ 213 musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); 214 215 if (is_host_enabled(musb)) { 216 /* port power on */ 217 sunxi_usb_phy_power_on(0); 218 } 219 } 220 221 static void sunxi_musb_disable(struct musb *musb) 222 { 223 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 224 225 pr_debug("%s():\n", __func__); 226 227 /* Put the controller back in a pristane state for "usb reset" */ 228 if (musb->is_active) { 229 sunxi_usb_phy_exit(0); 230 #ifdef CONFIG_SUNXI_GEN_SUN6I 231 clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0); 232 #endif 233 clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0); 234 235 mdelay(10); 236 237 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0); 238 #ifdef CONFIG_SUNXI_GEN_SUN6I 239 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0); 240 #endif 241 sunxi_usb_phy_init(0); 242 musb->is_active = 0; 243 } 244 } 245 246 static int sunxi_musb_init(struct musb *musb) 247 { 248 struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; 249 int err; 250 251 pr_debug("%s():\n", __func__); 252 253 if (is_host_enabled(musb)) { 254 err = sunxi_usb_phy_vbus_detect(0); 255 if (err) { 256 eprintf("Error: A charger is plugged into the OTG\n"); 257 return -EIO; 258 } 259 } 260 261 musb->isr = sunxi_musb_interrupt; 262 263 setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0); 264 #ifdef CONFIG_SUNXI_GEN_SUN6I 265 setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0); 266 #endif 267 sunxi_usb_phy_init(0); 268 269 USBC_ConfigFIFO_Base(); 270 USBC_EnableDpDmPullUp(musb->mregs); 271 USBC_EnableIdPullUp(musb->mregs); 272 273 if (is_host_enabled(musb)) { 274 /* Host mode */ 275 USBC_ForceIdToLow(musb->mregs); 276 } else { 277 /* Peripheral mode */ 278 USBC_ForceIdToHigh(musb->mregs); 279 } 280 USBC_ForceVbusValidToHigh(musb->mregs); 281 282 return 0; 283 } 284 285 static int sunxi_musb_exit(struct musb *musb) 286 { 287 pr_debug("%s():\n", __func__); 288 289 USBC_DisableDpDmPullUp(musb->mregs); 290 USBC_DisableIdPullUp(musb->mregs); 291 sunxi_usb_phy_power_off(0); 292 sunxi_usb_phy_exit(0); 293 294 return 0; 295 } 296 297 const struct musb_platform_ops sunxi_musb_ops = { 298 .init = sunxi_musb_init, 299 .exit = sunxi_musb_exit, 300 301 .enable = sunxi_musb_enable, 302 .disable = sunxi_musb_disable, 303 }; 304