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