Commit | Line | Data |
---|---|---|
f4f8bda2 DM |
1 | /* |
2 | * Copyright 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de> | |
3 | * Copyright 2009 Daniel Mack <daniel@caiaq.de> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License | |
7 | * as published by the Free Software Foundation; either version 2 | |
8 | * of the License, or (at your option) any later version. | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | |
17 | * MA 02110-1301, USA. | |
18 | */ | |
19 | ||
20 | #include <linux/module.h> | |
21 | #include <linux/kernel.h> | |
22 | #include <linux/io.h> | |
23 | #include <linux/delay.h> | |
24 | #include <linux/usb/otg.h> | |
25 | ||
26 | #include <mach/ulpi.h> | |
27 | ||
28 | /* ULPIVIEW register bits */ | |
29 | #define ULPIVW_WU (1 << 31) /* Wakeup */ | |
30 | #define ULPIVW_RUN (1 << 30) /* read/write run */ | |
31 | #define ULPIVW_WRITE (1 << 29) /* 0 = read 1 = write */ | |
32 | #define ULPIVW_SS (1 << 27) /* SyncState */ | |
33 | #define ULPIVW_PORT_MASK 0x07 /* Port field */ | |
34 | #define ULPIVW_PORT_SHIFT 24 | |
35 | #define ULPIVW_ADDR_MASK 0xff /* data address field */ | |
36 | #define ULPIVW_ADDR_SHIFT 16 | |
37 | #define ULPIVW_RDATA_MASK 0xff /* read data field */ | |
38 | #define ULPIVW_RDATA_SHIFT 8 | |
39 | #define ULPIVW_WDATA_MASK 0xff /* write data field */ | |
40 | #define ULPIVW_WDATA_SHIFT 0 | |
41 | ||
42 | static int ulpi_poll(void __iomem *view, u32 bit) | |
43 | { | |
44 | int timeout = 10000; | |
45 | ||
46 | while (timeout--) { | |
47 | u32 data = __raw_readl(view); | |
48 | ||
49 | if (!(data & bit)) | |
50 | return 0; | |
51 | ||
52 | cpu_relax(); | |
53 | }; | |
54 | ||
55 | printk(KERN_WARNING "timeout polling for ULPI device\n"); | |
56 | ||
57 | return -ETIMEDOUT; | |
58 | } | |
59 | ||
60 | static int ulpi_read(struct otg_transceiver *otg, u32 reg) | |
61 | { | |
62 | int ret; | |
63 | void __iomem *view = otg->io_priv; | |
64 | ||
65 | /* make sure interface is running */ | |
66 | if (!(__raw_readl(view) & ULPIVW_SS)) { | |
67 | __raw_writel(ULPIVW_WU, view); | |
68 | ||
69 | /* wait for wakeup */ | |
70 | ret = ulpi_poll(view, ULPIVW_WU); | |
71 | if (ret) | |
72 | return ret; | |
73 | } | |
74 | ||
75 | /* read the register */ | |
76 | __raw_writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view); | |
77 | ||
78 | /* wait for completion */ | |
79 | ret = ulpi_poll(view, ULPIVW_RUN); | |
80 | if (ret) | |
81 | return ret; | |
82 | ||
83 | return (__raw_readl(view) >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK; | |
84 | } | |
85 | ||
86 | static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg) | |
87 | { | |
88 | int ret; | |
89 | void __iomem *view = otg->io_priv; | |
90 | ||
91 | /* make sure the interface is running */ | |
92 | if (!(__raw_readl(view) & ULPIVW_SS)) { | |
93 | __raw_writel(ULPIVW_WU, view); | |
94 | /* wait for wakeup */ | |
95 | ret = ulpi_poll(view, ULPIVW_WU); | |
96 | if (ret) | |
97 | return ret; | |
98 | } | |
99 | ||
100 | __raw_writel((ULPIVW_RUN | ULPIVW_WRITE | | |
101 | (reg << ULPIVW_ADDR_SHIFT) | | |
102 | ((val & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)), view); | |
103 | ||
104 | /* wait for completion */ | |
105 | return ulpi_poll(view, ULPIVW_RUN); | |
106 | } | |
107 | ||
108 | struct otg_io_access_ops mxc_ulpi_access_ops = { | |
109 | .read = ulpi_read, | |
110 | .write = ulpi_write, | |
111 | }; | |
112 | EXPORT_SYMBOL_GPL(mxc_ulpi_access_ops); | |
113 |