diff options
author | Fabio Baltieri <fabio.baltieri@linaro.org> | 2013-04-03 04:45:08 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-04-03 05:01:56 -0400 |
commit | 54dfbb08051c2fa666bd4ce6cb7626b9e2a80655 (patch) | |
tree | 3b67ab9b6cc9318133348e0846511e1b8a35adbf /drivers/usb | |
parent | c0ea70646ad66a83f09562621babae4700c2f322 (diff) |
usb: phy: ab8500-usb: enable/disable regulator on phy events
Add ab8500_usb_regulator_{enable,disable} functions to control USB phy
regulators on corresponding ab8500_usb_phy_{enable,disable} events.
This contains some workaround and optimization for specific AB8500
versions.
Signed-off-by: Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
Signed-off-by: Sakethram Bommisetti <sakethram.bommisetti@stericsson.com>
Signed-off-by: Praveena Nadahally <praveen.nadahally@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Fabio Baltieri <fabio.baltieri@linaro.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/phy/phy-ab8500-usb.c | 68 |
1 files changed, 66 insertions, 2 deletions
diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 58b194b72432..96b4854f25df 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c | |||
@@ -130,6 +130,7 @@ struct ab8500_usb { | |||
130 | struct regulator *v_ape; | 130 | struct regulator *v_ape; |
131 | struct regulator *v_musb; | 131 | struct regulator *v_musb; |
132 | struct regulator *v_ulpi; | 132 | struct regulator *v_ulpi; |
133 | int saved_v_ulpi; | ||
133 | int previous_link_status_state; | 134 | int previous_link_status_state; |
134 | }; | 135 | }; |
135 | 136 | ||
@@ -161,6 +162,67 @@ static void ab8500_usb_wd_workaround(struct ab8500_usb *ab) | |||
161 | 0); | 162 | 0); |
162 | } | 163 | } |
163 | 164 | ||
165 | static void ab8500_usb_regulator_enable(struct ab8500_usb *ab) | ||
166 | { | ||
167 | int ret, volt; | ||
168 | |||
169 | regulator_enable(ab->v_ape); | ||
170 | |||
171 | if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { | ||
172 | ab->saved_v_ulpi = regulator_get_voltage(ab->v_ulpi); | ||
173 | if (ab->saved_v_ulpi < 0) | ||
174 | dev_err(ab->dev, "Failed to get v_ulpi voltage\n"); | ||
175 | |||
176 | ret = regulator_set_voltage(ab->v_ulpi, 1300000, 1350000); | ||
177 | if (ret < 0) | ||
178 | dev_err(ab->dev, "Failed to set the Vintcore to 1.3V, ret=%d\n", | ||
179 | ret); | ||
180 | |||
181 | ret = regulator_set_optimum_mode(ab->v_ulpi, 28000); | ||
182 | if (ret < 0) | ||
183 | dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n", | ||
184 | ret); | ||
185 | } | ||
186 | |||
187 | regulator_enable(ab->v_ulpi); | ||
188 | |||
189 | if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { | ||
190 | volt = regulator_get_voltage(ab->v_ulpi); | ||
191 | if ((volt != 1300000) && (volt != 1350000)) | ||
192 | dev_err(ab->dev, "Vintcore is not set to 1.3V volt=%d\n", | ||
193 | volt); | ||
194 | } | ||
195 | |||
196 | regulator_enable(ab->v_musb); | ||
197 | } | ||
198 | |||
199 | static void ab8500_usb_regulator_disable(struct ab8500_usb *ab) | ||
200 | { | ||
201 | int ret; | ||
202 | |||
203 | regulator_disable(ab->v_musb); | ||
204 | |||
205 | regulator_disable(ab->v_ulpi); | ||
206 | |||
207 | /* USB is not the only consumer of Vintcore, restore old settings */ | ||
208 | if (!is_ab8500_2p0_or_earlier(ab->ab8500)) { | ||
209 | if (ab->saved_v_ulpi > 0) { | ||
210 | ret = regulator_set_voltage(ab->v_ulpi, | ||
211 | ab->saved_v_ulpi, ab->saved_v_ulpi); | ||
212 | if (ret < 0) | ||
213 | dev_err(ab->dev, "Failed to set the Vintcore to %duV, ret=%d\n", | ||
214 | ab->saved_v_ulpi, ret); | ||
215 | } | ||
216 | |||
217 | ret = regulator_set_optimum_mode(ab->v_ulpi, 0); | ||
218 | if (ret < 0) | ||
219 | dev_err(ab->dev, "Failed to set optimum mode (ret=%d)\n", | ||
220 | ret); | ||
221 | } | ||
222 | |||
223 | regulator_disable(ab->v_ape); | ||
224 | } | ||
225 | |||
164 | static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit) | 226 | static void ab8500_usb_wd_linkstatus(struct ab8500_usb *ab, u8 bit) |
165 | { | 227 | { |
166 | /* Workaround for v2.0 bug # 31952 */ | 228 | /* Workaround for v2.0 bug # 31952 */ |
@@ -178,6 +240,8 @@ static void ab8500_usb_phy_enable(struct ab8500_usb *ab, bool sel_host) | |||
178 | bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : | 240 | bit = sel_host ? AB8500_BIT_PHY_CTRL_HOST_EN : |
179 | AB8500_BIT_PHY_CTRL_DEVICE_EN; | 241 | AB8500_BIT_PHY_CTRL_DEVICE_EN; |
180 | 242 | ||
243 | ab8500_usb_regulator_enable(ab); | ||
244 | |||
181 | abx500_mask_and_set_register_interruptible(ab->dev, | 245 | abx500_mask_and_set_register_interruptible(ab->dev, |
182 | AB8500_USB, AB8500_USB_PHY_CTRL_REG, | 246 | AB8500_USB, AB8500_USB_PHY_CTRL_REG, |
183 | bit, bit); | 247 | bit, bit); |
@@ -197,6 +261,8 @@ static void ab8500_usb_phy_disable(struct ab8500_usb *ab, bool sel_host) | |||
197 | 261 | ||
198 | /* Needed to disable the phy.*/ | 262 | /* Needed to disable the phy.*/ |
199 | ab8500_usb_wd_workaround(ab); | 263 | ab8500_usb_wd_workaround(ab); |
264 | |||
265 | ab8500_usb_regulator_disable(ab); | ||
200 | } | 266 | } |
201 | 267 | ||
202 | #define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true) | 268 | #define ab8500_usb_host_phy_en(ab) ab8500_usb_phy_enable(ab, true) |
@@ -544,7 +610,6 @@ static int ab8500_usb_set_peripheral(struct usb_otg *otg, | |||
544 | */ | 610 | */ |
545 | 611 | ||
546 | if (!gadget) { | 612 | if (!gadget) { |
547 | /* TODO: Disable regulators. */ | ||
548 | otg->gadget = NULL; | 613 | otg->gadget = NULL; |
549 | schedule_work(&ab->phy_dis_work); | 614 | schedule_work(&ab->phy_dis_work); |
550 | } else { | 615 | } else { |
@@ -576,7 +641,6 @@ static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host) | |||
576 | */ | 641 | */ |
577 | 642 | ||
578 | if (!host) { | 643 | if (!host) { |
579 | /* TODO: Disable regulators. */ | ||
580 | otg->host = NULL; | 644 | otg->host = NULL; |
581 | schedule_work(&ab->phy_dis_work); | 645 | schedule_work(&ab->phy_dis_work); |
582 | } else { | 646 | } else { |