xref: /openbmc/u-boot/drivers/usb/musb-new/sunxi.c (revision f82a7840)
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/gpio.h>
26 #include <asm/arch/usbc.h>
27 #include <asm-generic/gpio.h>
28 #include "linux-compat.h"
29 #include "musb_core.h"
30 #ifdef CONFIG_AXP152_POWER
31 #include <axp152.h>
32 #endif
33 #ifdef CONFIG_AXP209_POWER
34 #include <axp209.h>
35 #endif
36 #ifdef CONFIG_AXP221_POWER
37 #include <axp221.h>
38 #endif
39 
40 /******************************************************************************
41  ******************************************************************************
42  * From the Allwinner driver
43  ******************************************************************************
44  ******************************************************************************/
45 
46 /******************************************************************************
47  * From include/sunxi_usb_bsp.h
48  ******************************************************************************/
49 
50 /* reg offsets */
51 #define  USBC_REG_o_ISCR	0x0400
52 #define  USBC_REG_o_PHYCTL	0x0404
53 #define  USBC_REG_o_PHYBIST	0x0408
54 #define  USBC_REG_o_PHYTUNE	0x040c
55 
56 #define  USBC_REG_o_VEND0	0x0043
57 
58 /* Interface Status and Control */
59 #define  USBC_BP_ISCR_VBUS_VALID_FROM_DATA	30
60 #define  USBC_BP_ISCR_VBUS_VALID_FROM_VBUS	29
61 #define  USBC_BP_ISCR_EXT_ID_STATUS		28
62 #define  USBC_BP_ISCR_EXT_DM_STATUS		27
63 #define  USBC_BP_ISCR_EXT_DP_STATUS		26
64 #define  USBC_BP_ISCR_MERGED_VBUS_STATUS	25
65 #define  USBC_BP_ISCR_MERGED_ID_STATUS		24
66 
67 #define  USBC_BP_ISCR_ID_PULLUP_EN		17
68 #define  USBC_BP_ISCR_DPDM_PULLUP_EN		16
69 #define  USBC_BP_ISCR_FORCE_ID			14
70 #define  USBC_BP_ISCR_FORCE_VBUS_VALID		12
71 #define  USBC_BP_ISCR_VBUS_VALID_SRC		10
72 
73 #define  USBC_BP_ISCR_HOSC_EN			7
74 #define  USBC_BP_ISCR_VBUS_CHANGE_DETECT	6
75 #define  USBC_BP_ISCR_ID_CHANGE_DETECT		5
76 #define  USBC_BP_ISCR_DPDM_CHANGE_DETECT	4
77 #define  USBC_BP_ISCR_IRQ_ENABLE		3
78 #define  USBC_BP_ISCR_VBUS_CHANGE_DETECT_EN	2
79 #define  USBC_BP_ISCR_ID_CHANGE_DETECT_EN	1
80 #define  USBC_BP_ISCR_DPDM_CHANGE_DETECT_EN	0
81 
82 /******************************************************************************
83  * From usbc/usbc.c
84  ******************************************************************************/
85 
86 static u32 USBC_WakeUp_ClearChangeDetect(u32 reg_val)
87 {
88 	u32 temp = reg_val;
89 
90 	temp &= ~(1 << USBC_BP_ISCR_VBUS_CHANGE_DETECT);
91 	temp &= ~(1 << USBC_BP_ISCR_ID_CHANGE_DETECT);
92 	temp &= ~(1 << USBC_BP_ISCR_DPDM_CHANGE_DETECT);
93 
94 	return temp;
95 }
96 
97 static void USBC_EnableIdPullUp(__iomem void *base)
98 {
99 	u32 reg_val;
100 
101 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
102 	reg_val |= (1 << USBC_BP_ISCR_ID_PULLUP_EN);
103 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
104 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
105 }
106 
107 static void USBC_DisableIdPullUp(__iomem void *base)
108 {
109 	u32 reg_val;
110 
111 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
112 	reg_val &= ~(1 << USBC_BP_ISCR_ID_PULLUP_EN);
113 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
114 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
115 }
116 
117 static void USBC_EnableDpDmPullUp(__iomem void *base)
118 {
119 	u32 reg_val;
120 
121 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
122 	reg_val |= (1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
123 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
124 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
125 }
126 
127 static void USBC_DisableDpDmPullUp(__iomem void *base)
128 {
129 	u32 reg_val;
130 
131 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
132 	reg_val &= ~(1 << USBC_BP_ISCR_DPDM_PULLUP_EN);
133 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
134 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
135 }
136 
137 static void USBC_ForceIdToLow(__iomem void *base)
138 {
139 	u32 reg_val;
140 
141 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
142 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
143 	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_ID);
144 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
145 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
146 }
147 
148 static void USBC_ForceIdToHigh(__iomem void *base)
149 {
150 	u32 reg_val;
151 
152 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
153 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_ID);
154 	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_ID);
155 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
156 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
157 }
158 
159 static void USBC_ForceVbusValidToHigh(__iomem void *base)
160 {
161 	u32 reg_val;
162 
163 	reg_val = musb_readl(base, USBC_REG_o_ISCR);
164 	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
165 	reg_val |= (0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
166 	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
167 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
168 }
169 
170 static void USBC_ConfigFIFO_Base(void)
171 {
172 	u32 reg_value;
173 
174 	/* config usb fifo, 8kb mode */
175 	reg_value = readl(SUNXI_SRAMC_BASE + 0x04);
176 	reg_value &= ~(0x03 << 0);
177 	reg_value |= (1 << 0);
178 	writel(reg_value, SUNXI_SRAMC_BASE + 0x04);
179 }
180 
181 /******************************************************************************
182  * MUSB Glue code
183  ******************************************************************************/
184 
185 static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
186 {
187 	struct musb		*musb = __hci;
188 	irqreturn_t		retval = IRQ_NONE;
189 
190 	/* read and flush interrupts */
191 	musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
192 	if (musb->int_usb)
193 		musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb);
194 	musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
195 	if (musb->int_tx)
196 		musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx);
197 	musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
198 	if (musb->int_rx)
199 		musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx);
200 
201 	if (musb->int_usb || musb->int_tx || musb->int_rx)
202 		retval |= musb_interrupt(musb);
203 
204 	return retval;
205 }
206 
207 static void sunxi_musb_enable(struct musb *musb)
208 {
209 	pr_debug("%s():\n", __func__);
210 
211 	/* select PIO mode */
212 	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
213 
214 	if (is_host_enabled(musb)) {
215 		/* port power on */
216 		sunxi_usbc_vbus_enable(0);
217 	}
218 }
219 
220 static void sunxi_musb_disable(struct musb *musb)
221 {
222 	pr_debug("%s():\n", __func__);
223 
224 	/* Put the controller back in a pristane state for "usb reset" */
225 	if (musb->is_active) {
226 		sunxi_usbc_disable(0);
227 		sunxi_usbc_enable(0);
228 		musb->is_active = 0;
229 	}
230 }
231 
232 static int sunxi_musb_init(struct musb *musb)
233 {
234 	int err;
235 
236 	pr_debug("%s():\n", __func__);
237 
238 	err = sunxi_usbc_request_resources(0);
239 	if (err)
240 		return err;
241 
242 	if (is_host_enabled(musb)) {
243 		err = sunxi_usbc_vbus_detect(0);
244 		if (err) {
245 			eprintf("Error: A charger is plugged into the OTG\n");
246 			sunxi_usbc_free_resources(0);
247 			return -EIO;
248 		}
249 	}
250 
251 	musb->isr = sunxi_musb_interrupt;
252 	sunxi_usbc_enable(0);
253 
254 	USBC_ConfigFIFO_Base();
255 	USBC_EnableDpDmPullUp(musb->mregs);
256 	USBC_EnableIdPullUp(musb->mregs);
257 
258 	if (is_host_enabled(musb)) {
259 		/* Host mode */
260 		USBC_ForceIdToLow(musb->mregs);
261 	} else {
262 		/* Peripheral mode */
263 		USBC_ForceIdToHigh(musb->mregs);
264 	}
265 	USBC_ForceVbusValidToHigh(musb->mregs);
266 
267 	return 0;
268 }
269 
270 static int sunxi_musb_exit(struct musb *musb)
271 {
272 	pr_debug("%s():\n", __func__);
273 
274 	USBC_DisableDpDmPullUp(musb->mregs);
275 	USBC_DisableIdPullUp(musb->mregs);
276 	sunxi_usbc_vbus_disable(0);
277 	sunxi_usbc_disable(0);
278 
279 	return sunxi_usbc_free_resources(0);
280 }
281 
282 const struct musb_platform_ops sunxi_musb_ops = {
283 	.init		= sunxi_musb_init,
284 	.exit		= sunxi_musb_exit,
285 
286 	.enable		= sunxi_musb_enable,
287 	.disable	= sunxi_musb_disable,
288 };
289