~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/mach-pxa/pxa3xx-ulpi.c

Version: ~ [ linux-5.4-rc7 ] ~ [ linux-5.3.11 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.84 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.154 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.201 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.201 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.77 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * linux/arch/arm/mach-pxa/pxa3xx-ulpi.c
  3  *
  4  * code specific to pxa3xx aka Monahans
  5  *
  6  * Copyright (C) 2010 CompuLab Ltd.
  7  *
  8  * 2010-13-07: Igor Grinberg <grinberg@compulab.co.il>
  9  *             initial version: pxa310 USB Host mode support
 10  *
 11  * This program is free software; you can redistribute it and/or modify
 12  * it under the terms of the GNU General Public License version 2 as
 13  * published by the Free Software Foundation.
 14  */
 15 
 16 #include <linux/module.h>
 17 #include <linux/kernel.h>
 18 #include <linux/slab.h>
 19 #include <linux/device.h>
 20 #include <linux/platform_device.h>
 21 #include <linux/err.h>
 22 #include <linux/io.h>
 23 #include <linux/delay.h>
 24 #include <linux/clk.h>
 25 #include <linux/usb.h>
 26 #include <linux/usb/otg.h>
 27 
 28 #include <mach/hardware.h>
 29 #include <mach/regs-u2d.h>
 30 #include <linux/platform_data/usb-pxa3xx-ulpi.h>
 31 
 32 struct pxa3xx_u2d_ulpi {
 33         struct clk              *clk;
 34         void __iomem            *mmio_base;
 35 
 36         struct usb_phy          *otg;
 37         unsigned int            ulpi_mode;
 38 };
 39 
 40 static struct pxa3xx_u2d_ulpi *u2d;
 41 
 42 static inline u32 u2d_readl(u32 reg)
 43 {
 44         return __raw_readl(u2d->mmio_base + reg);
 45 }
 46 
 47 static inline void u2d_writel(u32 reg, u32 val)
 48 {
 49         __raw_writel(val, u2d->mmio_base + reg);
 50 }
 51 
 52 #if defined(CONFIG_PXA310_ULPI)
 53 enum u2d_ulpi_phy_mode {
 54         SYNCH           = 0,
 55         CARKIT          = (1 << 0),
 56         SER_3PIN        = (1 << 1),
 57         SER_6PIN        = (1 << 2),
 58         LOWPOWER        = (1 << 3),
 59 };
 60 
 61 static inline enum u2d_ulpi_phy_mode pxa310_ulpi_get_phymode(void)
 62 {
 63         return (u2d_readl(U2DOTGUSR) >> 28) & 0xF;
 64 }
 65 
 66 static int pxa310_ulpi_poll(void)
 67 {
 68         int timeout = 50000;
 69 
 70         while (timeout--) {
 71                 if (!(u2d_readl(U2DOTGUCR) & U2DOTGUCR_RUN))
 72                         return 0;
 73 
 74                 cpu_relax();
 75         }
 76 
 77         pr_warning("%s: ULPI access timed out!\n", __func__);
 78 
 79         return -ETIMEDOUT;
 80 }
 81 
 82 static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
 83 {
 84         int err;
 85 
 86         if (pxa310_ulpi_get_phymode() != SYNCH) {
 87                 pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
 88                 return -EBUSY;
 89         }
 90 
 91         u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | U2DOTGUCR_RNW | (reg << 16));
 92         msleep(5);
 93 
 94         err = pxa310_ulpi_poll();
 95         if (err)
 96                 return err;
 97 
 98         return u2d_readl(U2DOTGUCR) & U2DOTGUCR_RDATA;
 99 }
100 
101 static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
102 {
103         if (pxa310_ulpi_get_phymode() != SYNCH) {
104                 pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
105                 return -EBUSY;
106         }
107 
108         u2d_writel(U2DOTGUCR, U2DOTGUCR_RUN | (reg << 16) | (val << 8));
109         msleep(5);
110 
111         return pxa310_ulpi_poll();
112 }
113 
114 struct usb_phy_io_ops pxa310_ulpi_access_ops = {
115         .read   = pxa310_ulpi_read,
116         .write  = pxa310_ulpi_write,
117 };
118 
119 static void pxa310_otg_transceiver_rtsm(void)
120 {
121         u32 u2dotgcr;
122 
123         /* put PHY to sync mode */
124         u2dotgcr = u2d_readl(U2DOTGCR);
125         u2dotgcr |=  U2DOTGCR_RTSM | U2DOTGCR_UTMID;
126         u2d_writel(U2DOTGCR, u2dotgcr);
127         msleep(10);
128 
129         /* setup OTG sync mode */
130         u2dotgcr = u2d_readl(U2DOTGCR);
131         u2dotgcr |= U2DOTGCR_ULAF;
132         u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
133         u2d_writel(U2DOTGCR, u2dotgcr);
134 }
135 
136 static int pxa310_start_otg_host_transcvr(struct usb_bus *host)
137 {
138         int err;
139 
140         pxa310_otg_transceiver_rtsm();
141 
142         err = usb_phy_init(u2d->otg);
143         if (err) {
144                 pr_err("OTG transceiver init failed");
145                 return err;
146         }
147 
148         err = otg_set_vbus(u2d->otg->otg, 1);
149         if (err) {
150                 pr_err("OTG transceiver VBUS set failed");
151                 return err;
152         }
153 
154         err = otg_set_host(u2d->otg->otg, host);
155         if (err)
156                 pr_err("OTG transceiver Host mode set failed");
157 
158         return err;
159 }
160 
161 static int pxa310_start_otg_hc(struct usb_bus *host)
162 {
163         u32 u2dotgcr;
164         int err;
165 
166         /* disable USB device controller */
167         u2d_writel(U2DCR, u2d_readl(U2DCR) & ~U2DCR_UDE);
168         u2d_writel(U2DOTGCR, u2d_readl(U2DOTGCR) | U2DOTGCR_UTMID);
169         u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
170 
171         err = pxa310_start_otg_host_transcvr(host);
172         if (err)
173                 return err;
174 
175         /* set xceiver mode */
176         if (u2d->ulpi_mode & ULPI_IC_6PIN_SERIAL)
177                 u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) & ~U2DP3CR_P2SS);
178         else if (u2d->ulpi_mode & ULPI_IC_3PIN_SERIAL)
179                 u2d_writel(U2DP3CR, u2d_readl(U2DP3CR) | U2DP3CR_P2SS);
180 
181         /* start OTG host controller */
182         u2dotgcr = u2d_readl(U2DOTGCR) | U2DOTGCR_SMAF;
183         u2d_writel(U2DOTGCR, u2dotgcr & ~(U2DOTGCR_ULAF | U2DOTGCR_CKAF));
184 
185         return 0;
186 }
187 
188 static void pxa310_stop_otg_hc(void)
189 {
190         pxa310_otg_transceiver_rtsm();
191 
192         otg_set_host(u2d->otg->otg, NULL);
193         otg_set_vbus(u2d->otg->otg, 0);
194         usb_phy_shutdown(u2d->otg);
195 }
196 
197 static void pxa310_u2d_setup_otg_hc(void)
198 {
199         u32 u2dotgcr;
200 
201         u2dotgcr = u2d_readl(U2DOTGCR);
202         u2dotgcr |= U2DOTGCR_ULAF | U2DOTGCR_UTMID;
203         u2dotgcr &= ~(U2DOTGCR_SMAF | U2DOTGCR_CKAF);
204         u2d_writel(U2DOTGCR, u2dotgcr);
205         msleep(5);
206         u2d_writel(U2DOTGCR, u2dotgcr | U2DOTGCR_ULE);
207         msleep(5);
208         u2d_writel(U2DOTGICR, u2d_readl(U2DOTGICR) & ~0x37F7F);
209 }
210 
211 static int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
212 {
213         unsigned int ulpi_mode = ULPI_OTG_DRVVBUS;
214 
215         if (pdata) {
216                 if (pdata->ulpi_mode & ULPI_SER_6PIN)
217                         ulpi_mode |= ULPI_IC_6PIN_SERIAL;
218                 else if (pdata->ulpi_mode & ULPI_SER_3PIN)
219                         ulpi_mode |= ULPI_IC_3PIN_SERIAL;
220         }
221 
222         u2d->ulpi_mode = ulpi_mode;
223 
224         u2d->otg = otg_ulpi_create(&pxa310_ulpi_access_ops, ulpi_mode);
225         if (!u2d->otg)
226                 return -ENOMEM;
227 
228         u2d->otg->io_priv = u2d->mmio_base;
229 
230         return 0;
231 }
232 
233 static void pxa310_otg_exit(void)
234 {
235         kfree(u2d->otg);
236 }
237 #else
238 static inline void pxa310_u2d_setup_otg_hc(void) {}
239 static inline int pxa310_start_otg_hc(struct usb_bus *host)
240 {
241         return 0;
242 }
243 static inline void pxa310_stop_otg_hc(void) {}
244 static inline int pxa310_otg_init(struct pxa3xx_u2d_platform_data *pdata)
245 {
246         return 0;
247 }
248 static inline void pxa310_otg_exit(void) {}
249 #endif /* CONFIG_PXA310_ULPI */
250 
251 int pxa3xx_u2d_start_hc(struct usb_bus *host)
252 {
253         int err = 0;
254 
255         /* In case the PXA3xx ULPI isn't used, do nothing. */
256         if (!u2d)
257                 return 0;
258 
259         clk_enable(u2d->clk);
260 
261         if (cpu_is_pxa310()) {
262                 pxa310_u2d_setup_otg_hc();
263                 err = pxa310_start_otg_hc(host);
264         }
265 
266         return err;
267 }
268 EXPORT_SYMBOL_GPL(pxa3xx_u2d_start_hc);
269 
270 void pxa3xx_u2d_stop_hc(struct usb_bus *host)
271 {
272         /* In case the PXA3xx ULPI isn't used, do nothing. */
273         if (!u2d)
274                 return;
275 
276         if (cpu_is_pxa310())
277                 pxa310_stop_otg_hc();
278 
279         clk_disable(u2d->clk);
280 }
281 EXPORT_SYMBOL_GPL(pxa3xx_u2d_stop_hc);
282 
283 static int pxa3xx_u2d_probe(struct platform_device *pdev)
284 {
285         struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
286         struct resource *r;
287         int err;
288 
289         u2d = kzalloc(sizeof(struct pxa3xx_u2d_ulpi), GFP_KERNEL);
290         if (!u2d) {
291                 dev_err(&pdev->dev, "failed to allocate memory\n");
292                 return -ENOMEM;
293         }
294 
295         u2d->clk = clk_get(&pdev->dev, NULL);
296         if (IS_ERR(u2d->clk)) {
297                 dev_err(&pdev->dev, "failed to get u2d clock\n");
298                 err = PTR_ERR(u2d->clk);
299                 goto err_free_mem;
300         }
301 
302         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
303         if (!r) {
304                 dev_err(&pdev->dev, "no IO memory resource defined\n");
305                 err = -ENODEV;
306                 goto err_put_clk;
307         }
308 
309         r = request_mem_region(r->start, resource_size(r), pdev->name);
310         if (!r) {
311                 dev_err(&pdev->dev, "failed to request memory resource\n");
312                 err = -EBUSY;
313                 goto err_put_clk;
314         }
315 
316         u2d->mmio_base = ioremap(r->start, resource_size(r));
317         if (!u2d->mmio_base) {
318                 dev_err(&pdev->dev, "ioremap() failed\n");
319                 err = -ENODEV;
320                 goto err_free_res;
321         }
322 
323         if (pdata->init) {
324                 err = pdata->init(&pdev->dev);
325                 if (err)
326                         goto err_free_io;
327         }
328 
329         /* Only PXA310 U2D has OTG functionality */
330         if (cpu_is_pxa310()) {
331                 err = pxa310_otg_init(pdata);
332                 if (err)
333                         goto err_free_plat;
334         }
335 
336         platform_set_drvdata(pdev, &u2d);
337 
338         return 0;
339 
340 err_free_plat:
341         if (pdata->exit)
342                 pdata->exit(&pdev->dev);
343 err_free_io:
344         iounmap(u2d->mmio_base);
345 err_free_res:
346         release_mem_region(r->start, resource_size(r));
347 err_put_clk:
348         clk_put(u2d->clk);
349 err_free_mem:
350         kfree(u2d);
351         return err;
352 }
353 
354 static int pxa3xx_u2d_remove(struct platform_device *pdev)
355 {
356         struct pxa3xx_u2d_platform_data *pdata = pdev->dev.platform_data;
357         struct resource *r;
358 
359         if (cpu_is_pxa310()) {
360                 pxa310_stop_otg_hc();
361                 pxa310_otg_exit();
362         }
363 
364         if (pdata->exit)
365                 pdata->exit(&pdev->dev);
366 
367         platform_set_drvdata(pdev, NULL);
368         iounmap(u2d->mmio_base);
369         r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
370         release_mem_region(r->start, resource_size(r));
371 
372         clk_put(u2d->clk);
373 
374         kfree(u2d);
375 
376         return 0;
377 }
378 
379 static struct platform_driver pxa3xx_u2d_ulpi_driver = {
380         .driver         = {
381                 .name   = "pxa3xx-u2d",
382                 .owner  = THIS_MODULE,
383         },
384         .probe          = pxa3xx_u2d_probe,
385         .remove         = pxa3xx_u2d_remove,
386 };
387 module_platform_driver(pxa3xx_u2d_ulpi_driver);
388 
389 MODULE_DESCRIPTION("PXA3xx U2D ULPI driver");
390 MODULE_AUTHOR("Igor Grinberg");
391 MODULE_LICENSE("GPL v2");
392 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp