]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/usb/phy/phy-rcar-usb.c
phy-rcar-usb: handle platform data
[karo-tx-linux.git] / drivers / usb / phy / phy-rcar-usb.c
1 /*
2  * Renesas R-Car USB phy driver
3  *
4  * Copyright (C) 2012-2013 Renesas Solutions Corp.
5  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
6  * Copyright (C) 2013 Cogent Embedded, Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/delay.h>
14 #include <linux/io.h>
15 #include <linux/usb/otg.h>
16 #include <linux/platform_device.h>
17 #include <linux/spinlock.h>
18 #include <linux/module.h>
19 #include <linux/platform_data/usb-rcar-phy.h>
20
21 /* REGS block */
22 #define USBPCTRL0       0x00
23 #define USBPCTRL1       0x04
24 #define USBST           0x08
25 #define USBEH0          0x0C
26 #define USBOH0          0x1C
27 #define USBCTL0         0x58
28
29 /* USBPCTRL0 */
30 #define OVC2            (1 << 10) /* Switches the OVC input pin for port 2: */
31                                 /* 1: USB_OVC2, 0: OVC2                 */
32 #define OVC1_VBUS1      (1 << 9) /* Switches the OVC input pin for port 1: */
33                                 /* 1: USB_OVC1, 0: OVC1/VBUS1           */
34                                 /* Function mode: set to 0              */
35 #define OVC0            (1 << 8) /* Switches the OVC input pin for port 0: */
36                                 /* 1: USB_OVC0 pin, 0: OVC0             */
37 #define OVC2_ACT        (1 << 6) /* Host mode: OVC2 polarity:           */
38                                 /* 1: active-high, 0: active-low        */
39 #define PENC            (1 << 4) /* Function mode: output level of PENC1 pin: */
40                                 /* 1: high, 0: low                      */
41 #define OVC0_ACT        (1 << 3) /* Host mode: OVC0 polarity:           */
42                                 /* 1: active-high, 0: active-low        */
43 #define OVC1_ACT        (1 << 1) /* Host mode: OVC1 polarity:           */
44                                 /* 1: active-high, 0: active-low        */
45                                 /* Function mode: be sure to set to 1   */
46 #define PORT1           (1 << 0) /* Selects port 1 mode:                */
47                                 /* 1: function, 0: host                 */
48 /* USBPCTRL1 */
49 #define PHY_RST         (1 << 2)
50 #define PLL_ENB         (1 << 1)
51 #define PHY_ENB         (1 << 0)
52
53 /* USBST */
54 #define ST_ACT          (1 << 31)
55 #define ST_PLL          (1 << 30)
56
57 struct rcar_usb_phy_priv {
58         struct usb_phy phy;
59         spinlock_t lock;
60
61         void __iomem *reg0;
62         int counter;
63 };
64
65 #define usb_phy_to_priv(p) container_of(p, struct rcar_usb_phy_priv, phy)
66
67
68 /*
69  * USB initial/install operation.
70  *
71  * This function setup USB phy.
72  * The used value and setting order came from
73  * [USB :: Initial setting] on datasheet.
74  */
75 static int rcar_usb_phy_init(struct usb_phy *phy)
76 {
77         struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
78         struct device *dev = phy->dev;
79         struct rcar_phy_platform_data *pdata = dev->platform_data;
80         void __iomem *reg0 = priv->reg0;
81         static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT };
82         int i;
83         u32 val;
84         unsigned long flags;
85
86         spin_lock_irqsave(&priv->lock, flags);
87         if (priv->counter++ == 0) {
88
89                 /*
90                  * USB phy start-up
91                  */
92
93                 /* (1) USB-PHY standby release */
94                 iowrite32(PHY_ENB, (reg0 + USBPCTRL1));
95
96                 /* (2) start USB-PHY internal PLL */
97                 iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1));
98
99                 /* (3) USB module status check */
100                 for (i = 0; i < 1024; i++) {
101                         udelay(10);
102                         val = ioread32(reg0 + USBST);
103                         if (val == (ST_ACT | ST_PLL))
104                                 break;
105                 }
106
107                 if (val != (ST_ACT | ST_PLL)) {
108                         dev_err(dev, "USB phy not ready\n");
109                         goto phy_init_end;
110                 }
111
112                 /* (4) USB-PHY reset clear */
113                 iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1));
114
115                 /* Board specific port settings */
116                 val = 0;
117                 if (pdata->port1_func)
118                         val |= PORT1;
119                 if (pdata->penc1)
120                         val |= PENC;
121                 for (i = 0; i < 3; i++) {
122                         /* OVCn bits follow each other in the right order */
123                         if (pdata->ovc_pin[i].select_3_3v)
124                                 val |= OVC0 << i;
125                         /* OVCn_ACT bits are spaced by irregular intervals */
126                         if (pdata->ovc_pin[i].active_high)
127                                 val |= ovcn_act[i];
128                 }
129                 iowrite32(val, (reg0 + USBPCTRL0));
130
131                 /*
132                  * Bus alignment settings
133                  */
134
135                 /* (1) EHCI bus alignment (little endian) */
136                 iowrite32(0x00000000, (reg0 + USBEH0));
137
138                 /* (1) OHCI bus alignment (little endian) */
139                 iowrite32(0x00000000, (reg0 + USBOH0));
140         }
141
142 phy_init_end:
143         spin_unlock_irqrestore(&priv->lock, flags);
144
145         return 0;
146 }
147
148 static void rcar_usb_phy_shutdown(struct usb_phy *phy)
149 {
150         struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy);
151         void __iomem *reg0 = priv->reg0;
152         unsigned long flags;
153
154         spin_lock_irqsave(&priv->lock, flags);
155
156         if (priv->counter-- == 1)       /* last user */
157                 iowrite32(0x00000000, (reg0 + USBPCTRL1));
158
159         spin_unlock_irqrestore(&priv->lock, flags);
160 }
161
162 static int rcar_usb_phy_probe(struct platform_device *pdev)
163 {
164         struct rcar_usb_phy_priv *priv;
165         struct resource *res0;
166         struct device *dev = &pdev->dev;
167         void __iomem *reg0;
168         int ret;
169
170         if (!pdev->dev.platform_data) {
171                 dev_err(dev, "No platform data\n");
172                 return -EINVAL;
173         }
174
175         res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
176         if (!res0) {
177                 dev_err(dev, "Not enough platform resources\n");
178                 return -EINVAL;
179         }
180
181         reg0 = devm_ioremap_resource(dev, res0);
182         if (IS_ERR(reg0))
183                 return PTR_ERR(reg0);
184
185         priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
186         if (!priv) {
187                 dev_err(dev, "priv data allocation error\n");
188                 return -ENOMEM;
189         }
190
191         priv->reg0              = reg0;
192         priv->counter           = 0;
193         priv->phy.dev           = dev;
194         priv->phy.label         = dev_name(dev);
195         priv->phy.init          = rcar_usb_phy_init;
196         priv->phy.shutdown      = rcar_usb_phy_shutdown;
197         spin_lock_init(&priv->lock);
198
199         ret = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2);
200         if (ret < 0) {
201                 dev_err(dev, "usb phy addition error\n");
202                 return ret;
203         }
204
205         platform_set_drvdata(pdev, priv);
206
207         return ret;
208 }
209
210 static int rcar_usb_phy_remove(struct platform_device *pdev)
211 {
212         struct rcar_usb_phy_priv *priv = platform_get_drvdata(pdev);
213
214         usb_remove_phy(&priv->phy);
215
216         return 0;
217 }
218
219 static struct platform_driver rcar_usb_phy_driver = {
220         .driver         = {
221                 .name   = "rcar_usb_phy",
222         },
223         .probe          = rcar_usb_phy_probe,
224         .remove         = rcar_usb_phy_remove,
225 };
226
227 module_platform_driver(rcar_usb_phy_driver);
228
229 MODULE_LICENSE("GPL v2");
230 MODULE_DESCRIPTION("Renesas R-Car USB phy");
231 MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");