Commit 7173e59e6b5f9cbde3ece66ae664454edcac6382
Committed by
Simon Horman
1 parent
2437b27c3a
Exists in
smarc-imx_3.14.28_1.0.0_ga
and in
1 other branch
phy-rcar-usb: handle platform data
Set the USBPCTRL0 register from the passed platform data in rcar_usb_phy_init(); don't reset it to 0 in rcar_usb_phy_shutdown() anymore as that does not make sense. Also, don't allow the driver's probe to succeed when the platform data are not supplied with a device. The patch has been tested on the Marzen and BOCK-W boards. Signed-off-by: Sergei Shtylyov <sergei.shtylyov@cogentembedded.com> Acked-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> Acked-by: Simon Horman <horms+renesas@verge.net.au> Acked-by: Felipe Balbi <balbi@ti.com> Signed-off-by: Simon Horman <horms+renesas@verge.net.au>
Showing 1 changed file with 45 additions and 6 deletions Inline Diff
drivers/usb/phy/phy-rcar-usb.c
1 | /* | 1 | /* |
2 | * Renesas R-Car USB phy driver | 2 | * Renesas R-Car USB phy driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Renesas Solutions Corp. | 4 | * Copyright (C) 2012-2013 Renesas Solutions Corp. |
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> |
6 | * Copyright (C) 2013 Cogent Embedded, Inc. | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
9 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
10 | */ | 11 | */ |
11 | 12 | ||
12 | #include <linux/delay.h> | 13 | #include <linux/delay.h> |
13 | #include <linux/io.h> | 14 | #include <linux/io.h> |
14 | #include <linux/usb/otg.h> | 15 | #include <linux/usb/otg.h> |
15 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
16 | #include <linux/spinlock.h> | 17 | #include <linux/spinlock.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/platform_data/usb-rcar-phy.h> | ||
18 | 20 | ||
19 | /* REGS block */ | 21 | /* REGS block */ |
20 | #define USBPCTRL0 0x00 | 22 | #define USBPCTRL0 0x00 |
21 | #define USBPCTRL1 0x04 | 23 | #define USBPCTRL1 0x04 |
22 | #define USBST 0x08 | 24 | #define USBST 0x08 |
23 | #define USBEH0 0x0C | 25 | #define USBEH0 0x0C |
24 | #define USBOH0 0x1C | 26 | #define USBOH0 0x1C |
25 | #define USBCTL0 0x58 | 27 | #define USBCTL0 0x58 |
26 | 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 */ | ||
27 | /* USBPCTRL1 */ | 48 | /* USBPCTRL1 */ |
28 | #define PHY_RST (1 << 2) | 49 | #define PHY_RST (1 << 2) |
29 | #define PLL_ENB (1 << 1) | 50 | #define PLL_ENB (1 << 1) |
30 | #define PHY_ENB (1 << 0) | 51 | #define PHY_ENB (1 << 0) |
31 | 52 | ||
32 | /* USBST */ | 53 | /* USBST */ |
33 | #define ST_ACT (1 << 31) | 54 | #define ST_ACT (1 << 31) |
34 | #define ST_PLL (1 << 30) | 55 | #define ST_PLL (1 << 30) |
35 | 56 | ||
36 | struct rcar_usb_phy_priv { | 57 | struct rcar_usb_phy_priv { |
37 | struct usb_phy phy; | 58 | struct usb_phy phy; |
38 | spinlock_t lock; | 59 | spinlock_t lock; |
39 | 60 | ||
40 | void __iomem *reg0; | 61 | void __iomem *reg0; |
41 | int counter; | 62 | int counter; |
42 | }; | 63 | }; |
43 | 64 | ||
44 | #define usb_phy_to_priv(p) container_of(p, struct rcar_usb_phy_priv, phy) | 65 | #define usb_phy_to_priv(p) container_of(p, struct rcar_usb_phy_priv, phy) |
45 | 66 | ||
46 | 67 | ||
47 | /* | 68 | /* |
48 | * USB initial/install operation. | 69 | * USB initial/install operation. |
49 | * | 70 | * |
50 | * This function setup USB phy. | 71 | * This function setup USB phy. |
51 | * The used value and setting order came from | 72 | * The used value and setting order came from |
52 | * [USB :: Initial setting] on datasheet. | 73 | * [USB :: Initial setting] on datasheet. |
53 | */ | 74 | */ |
54 | static int rcar_usb_phy_init(struct usb_phy *phy) | 75 | static int rcar_usb_phy_init(struct usb_phy *phy) |
55 | { | 76 | { |
56 | struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); | 77 | struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); |
57 | struct device *dev = phy->dev; | 78 | struct device *dev = phy->dev; |
79 | struct rcar_phy_platform_data *pdata = dev->platform_data; | ||
58 | void __iomem *reg0 = priv->reg0; | 80 | void __iomem *reg0 = priv->reg0; |
81 | static const u8 ovcn_act[] = { OVC0_ACT, OVC1_ACT, OVC2_ACT }; | ||
59 | int i; | 82 | int i; |
60 | u32 val; | 83 | u32 val; |
61 | unsigned long flags; | 84 | unsigned long flags; |
62 | 85 | ||
63 | spin_lock_irqsave(&priv->lock, flags); | 86 | spin_lock_irqsave(&priv->lock, flags); |
64 | if (priv->counter++ == 0) { | 87 | if (priv->counter++ == 0) { |
65 | 88 | ||
66 | /* | 89 | /* |
67 | * USB phy start-up | 90 | * USB phy start-up |
68 | */ | 91 | */ |
69 | 92 | ||
70 | /* (1) USB-PHY standby release */ | 93 | /* (1) USB-PHY standby release */ |
71 | iowrite32(PHY_ENB, (reg0 + USBPCTRL1)); | 94 | iowrite32(PHY_ENB, (reg0 + USBPCTRL1)); |
72 | 95 | ||
73 | /* (2) start USB-PHY internal PLL */ | 96 | /* (2) start USB-PHY internal PLL */ |
74 | iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1)); | 97 | iowrite32(PHY_ENB | PLL_ENB, (reg0 + USBPCTRL1)); |
75 | 98 | ||
76 | /* (3) USB module status check */ | 99 | /* (3) USB module status check */ |
77 | for (i = 0; i < 1024; i++) { | 100 | for (i = 0; i < 1024; i++) { |
78 | udelay(10); | 101 | udelay(10); |
79 | val = ioread32(reg0 + USBST); | 102 | val = ioread32(reg0 + USBST); |
80 | if (val == (ST_ACT | ST_PLL)) | 103 | if (val == (ST_ACT | ST_PLL)) |
81 | break; | 104 | break; |
82 | } | 105 | } |
83 | 106 | ||
84 | if (val != (ST_ACT | ST_PLL)) { | 107 | if (val != (ST_ACT | ST_PLL)) { |
85 | dev_err(dev, "USB phy not ready\n"); | 108 | dev_err(dev, "USB phy not ready\n"); |
86 | goto phy_init_end; | 109 | goto phy_init_end; |
87 | } | 110 | } |
88 | 111 | ||
89 | /* (4) USB-PHY reset clear */ | 112 | /* (4) USB-PHY reset clear */ |
90 | iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1)); | 113 | iowrite32(PHY_ENB | PLL_ENB | PHY_RST, (reg0 + USBPCTRL1)); |
91 | 114 | ||
92 | /* set platform specific port settings */ | 115 | /* Board specific port settings */ |
93 | iowrite32(0x00000000, (reg0 + USBPCTRL0)); | 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)); | ||
94 | 130 | ||
95 | /* | 131 | /* |
96 | * Bus alignment settings | 132 | * Bus alignment settings |
97 | */ | 133 | */ |
98 | 134 | ||
99 | /* (1) EHCI bus alignment (little endian) */ | 135 | /* (1) EHCI bus alignment (little endian) */ |
100 | iowrite32(0x00000000, (reg0 + USBEH0)); | 136 | iowrite32(0x00000000, (reg0 + USBEH0)); |
101 | 137 | ||
102 | /* (1) OHCI bus alignment (little endian) */ | 138 | /* (1) OHCI bus alignment (little endian) */ |
103 | iowrite32(0x00000000, (reg0 + USBOH0)); | 139 | iowrite32(0x00000000, (reg0 + USBOH0)); |
104 | } | 140 | } |
105 | 141 | ||
106 | phy_init_end: | 142 | phy_init_end: |
107 | spin_unlock_irqrestore(&priv->lock, flags); | 143 | spin_unlock_irqrestore(&priv->lock, flags); |
108 | 144 | ||
109 | return 0; | 145 | return 0; |
110 | } | 146 | } |
111 | 147 | ||
112 | static void rcar_usb_phy_shutdown(struct usb_phy *phy) | 148 | static void rcar_usb_phy_shutdown(struct usb_phy *phy) |
113 | { | 149 | { |
114 | struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); | 150 | struct rcar_usb_phy_priv *priv = usb_phy_to_priv(phy); |
115 | void __iomem *reg0 = priv->reg0; | 151 | void __iomem *reg0 = priv->reg0; |
116 | unsigned long flags; | 152 | unsigned long flags; |
117 | 153 | ||
118 | spin_lock_irqsave(&priv->lock, flags); | 154 | spin_lock_irqsave(&priv->lock, flags); |
119 | 155 | ||
120 | if (priv->counter-- == 1) { /* last user */ | 156 | if (priv->counter-- == 1) /* last user */ |
121 | iowrite32(0x00000000, (reg0 + USBPCTRL0)); | ||
122 | iowrite32(0x00000000, (reg0 + USBPCTRL1)); | 157 | iowrite32(0x00000000, (reg0 + USBPCTRL1)); |
123 | } | ||
124 | 158 | ||
125 | spin_unlock_irqrestore(&priv->lock, flags); | 159 | spin_unlock_irqrestore(&priv->lock, flags); |
126 | } | 160 | } |
127 | 161 | ||
128 | static int rcar_usb_phy_probe(struct platform_device *pdev) | 162 | static int rcar_usb_phy_probe(struct platform_device *pdev) |
129 | { | 163 | { |
130 | struct rcar_usb_phy_priv *priv; | 164 | struct rcar_usb_phy_priv *priv; |
131 | struct resource *res0; | 165 | struct resource *res0; |
132 | struct device *dev = &pdev->dev; | 166 | struct device *dev = &pdev->dev; |
133 | void __iomem *reg0; | 167 | void __iomem *reg0; |
134 | int ret; | 168 | int ret; |
169 | |||
170 | if (!pdev->dev.platform_data) { | ||
171 | dev_err(dev, "No platform data\n"); | ||
172 | return -EINVAL; | ||
173 | } | ||
135 | 174 | ||
136 | res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 175 | res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
137 | if (!res0) { | 176 | if (!res0) { |
138 | dev_err(dev, "Not enough platform resources\n"); | 177 | dev_err(dev, "Not enough platform resources\n"); |
139 | return -EINVAL; | 178 | return -EINVAL; |
140 | } | 179 | } |
141 | 180 | ||
142 | reg0 = devm_ioremap_resource(dev, res0); | 181 | reg0 = devm_ioremap_resource(dev, res0); |
143 | if (IS_ERR(reg0)) | 182 | if (IS_ERR(reg0)) |
144 | return PTR_ERR(reg0); | 183 | return PTR_ERR(reg0); |
145 | 184 | ||
146 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | 185 | priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); |
147 | if (!priv) { | 186 | if (!priv) { |
148 | dev_err(dev, "priv data allocation error\n"); | 187 | dev_err(dev, "priv data allocation error\n"); |
149 | return -ENOMEM; | 188 | return -ENOMEM; |
150 | } | 189 | } |
151 | 190 | ||
152 | priv->reg0 = reg0; | 191 | priv->reg0 = reg0; |
153 | priv->counter = 0; | 192 | priv->counter = 0; |
154 | priv->phy.dev = dev; | 193 | priv->phy.dev = dev; |
155 | priv->phy.label = dev_name(dev); | 194 | priv->phy.label = dev_name(dev); |
156 | priv->phy.init = rcar_usb_phy_init; | 195 | priv->phy.init = rcar_usb_phy_init; |
157 | priv->phy.shutdown = rcar_usb_phy_shutdown; | 196 | priv->phy.shutdown = rcar_usb_phy_shutdown; |
158 | spin_lock_init(&priv->lock); | 197 | spin_lock_init(&priv->lock); |
159 | 198 | ||
160 | ret = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2); | 199 | ret = usb_add_phy(&priv->phy, USB_PHY_TYPE_USB2); |
161 | if (ret < 0) { | 200 | if (ret < 0) { |
162 | dev_err(dev, "usb phy addition error\n"); | 201 | dev_err(dev, "usb phy addition error\n"); |
163 | return ret; | 202 | return ret; |
164 | } | 203 | } |
165 | 204 | ||
166 | platform_set_drvdata(pdev, priv); | 205 | platform_set_drvdata(pdev, priv); |
167 | 206 | ||
168 | return ret; | 207 | return ret; |
169 | } | 208 | } |
170 | 209 | ||
171 | static int rcar_usb_phy_remove(struct platform_device *pdev) | 210 | static int rcar_usb_phy_remove(struct platform_device *pdev) |
172 | { | 211 | { |
173 | struct rcar_usb_phy_priv *priv = platform_get_drvdata(pdev); | 212 | struct rcar_usb_phy_priv *priv = platform_get_drvdata(pdev); |
174 | 213 | ||
175 | usb_remove_phy(&priv->phy); | 214 | usb_remove_phy(&priv->phy); |
176 | 215 | ||
177 | return 0; | 216 | return 0; |
178 | } | 217 | } |
179 | 218 | ||
180 | static struct platform_driver rcar_usb_phy_driver = { | 219 | static struct platform_driver rcar_usb_phy_driver = { |
181 | .driver = { | 220 | .driver = { |
182 | .name = "rcar_usb_phy", | 221 | .name = "rcar_usb_phy", |
183 | }, | 222 | }, |
184 | .probe = rcar_usb_phy_probe, | 223 | .probe = rcar_usb_phy_probe, |
185 | .remove = rcar_usb_phy_remove, | 224 | .remove = rcar_usb_phy_remove, |
186 | }; | 225 | }; |
187 | 226 | ||
188 | module_platform_driver(rcar_usb_phy_driver); | 227 | module_platform_driver(rcar_usb_phy_driver); |
189 | 228 | ||
190 | MODULE_LICENSE("GPL v2"); | 229 | MODULE_LICENSE("GPL v2"); |
191 | MODULE_DESCRIPTION("Renesas R-Car USB phy"); | 230 | MODULE_DESCRIPTION("Renesas R-Car USB phy"); |