diff options
author | Roger Quadros <rogerq@ti.com> | 2012-11-08 06:07:09 -0500 |
---|---|---|
committer | Roger Quadros <rogerq@ti.com> | 2013-02-13 06:22:39 -0500 |
commit | 0bde3e9fee74b668857b1664a70998d02807fb5b (patch) | |
tree | 77e948b1f22841e559be2e1c2d0cb6cdd392466d /drivers/mfd/omap-usb-tll.c | |
parent | 1a7a8d70cddcf4f6847e42b414da1c3113675873 (diff) |
mfd: omap-usb-tll: Clean up clock handling
Every channel has a functional clock that is similarly named.
It makes sense to use a for loop to manage these clocks as OMAPs
can come with up to 3 channels.
Dynamically allocate and get channel clocks depending on the
number of clocks avaiable on the platform.
Signed-off-by: Roger Quadros <rogerq@ti.com>
Reviewed-by: Felipe Balbi <balbi@ti.com>
Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/mfd/omap-usb-tll.c')
-rw-r--r-- | drivers/mfd/omap-usb-tll.c | 87 |
1 files changed, 54 insertions, 33 deletions
diff --git a/drivers/mfd/omap-usb-tll.c b/drivers/mfd/omap-usb-tll.c index 9a19cc722c76..bf7355e1126d 100644 --- a/drivers/mfd/omap-usb-tll.c +++ b/drivers/mfd/omap-usb-tll.c | |||
@@ -96,10 +96,9 @@ | |||
96 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) | 96 | #define is_ehci_tll_mode(x) (x == OMAP_EHCI_PORT_MODE_TLL) |
97 | 97 | ||
98 | struct usbtll_omap { | 98 | struct usbtll_omap { |
99 | struct clk *usbtll_p1_fck; | ||
100 | struct clk *usbtll_p2_fck; | ||
101 | int nch; /* num. of channels */ | 99 | int nch; /* num. of channels */ |
102 | struct usbhs_omap_platform_data *pdata; | 100 | struct usbhs_omap_platform_data *pdata; |
101 | struct clk **ch_clk; | ||
103 | /* secure the register updates */ | 102 | /* secure the register updates */ |
104 | spinlock_t lock; | 103 | spinlock_t lock; |
105 | }; | 104 | }; |
@@ -225,26 +224,12 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
225 | 224 | ||
226 | tll->pdata = pdata; | 225 | tll->pdata = pdata; |
227 | 226 | ||
228 | tll->usbtll_p1_fck = clk_get(dev, "usb_tll_hs_usb_ch0_clk"); | ||
229 | if (IS_ERR(tll->usbtll_p1_fck)) { | ||
230 | ret = PTR_ERR(tll->usbtll_p1_fck); | ||
231 | dev_err(dev, "usbtll_p1_fck failed error:%d\n", ret); | ||
232 | return ret; | ||
233 | } | ||
234 | |||
235 | tll->usbtll_p2_fck = clk_get(dev, "usb_tll_hs_usb_ch1_clk"); | ||
236 | if (IS_ERR(tll->usbtll_p2_fck)) { | ||
237 | ret = PTR_ERR(tll->usbtll_p2_fck); | ||
238 | dev_err(dev, "usbtll_p2_fck failed error:%d\n", ret); | ||
239 | goto err_p2_fck; | ||
240 | } | ||
241 | |||
242 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 227 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
243 | base = devm_request_and_ioremap(dev, res); | 228 | base = devm_request_and_ioremap(dev, res); |
244 | if (!base) { | 229 | if (!base) { |
245 | ret = -EADDRNOTAVAIL; | 230 | ret = -EADDRNOTAVAIL; |
246 | dev_err(dev, "Resource request/ioremap failed:%d\n", ret); | 231 | dev_err(dev, "Resource request/ioremap failed:%d\n", ret); |
247 | goto err_res; | 232 | return ret; |
248 | } | 233 | } |
249 | 234 | ||
250 | platform_set_drvdata(pdev, tll); | 235 | platform_set_drvdata(pdev, tll); |
@@ -270,6 +255,29 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
270 | break; | 255 | break; |
271 | } | 256 | } |
272 | 257 | ||
258 | spin_unlock_irqrestore(&tll->lock, flags); | ||
259 | |||
260 | tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]), | ||
261 | GFP_KERNEL); | ||
262 | if (!tll->ch_clk) { | ||
263 | ret = -ENOMEM; | ||
264 | dev_err(dev, "Couldn't allocate memory for channel clocks\n"); | ||
265 | goto err_clk_alloc; | ||
266 | } | ||
267 | |||
268 | for (i = 0; i < tll->nch; i++) { | ||
269 | char clkname[] = "usb_tll_hs_usb_chx_clk"; | ||
270 | |||
271 | snprintf(clkname, sizeof(clkname), | ||
272 | "usb_tll_hs_usb_ch%d_clk", i); | ||
273 | tll->ch_clk[i] = clk_get(dev, clkname); | ||
274 | |||
275 | if (IS_ERR(tll->ch_clk[i])) | ||
276 | dev_dbg(dev, "can't get clock : %s\n", clkname); | ||
277 | } | ||
278 | |||
279 | spin_lock_irqsave(&tll->lock, flags); | ||
280 | |||
273 | if (is_ehci_tll_mode(pdata->port_mode[0]) || | 281 | if (is_ehci_tll_mode(pdata->port_mode[0]) || |
274 | is_ehci_tll_mode(pdata->port_mode[1]) || | 282 | is_ehci_tll_mode(pdata->port_mode[1]) || |
275 | is_ehci_tll_mode(pdata->port_mode[2]) || | 283 | is_ehci_tll_mode(pdata->port_mode[2]) || |
@@ -321,11 +329,9 @@ static int usbtll_omap_probe(struct platform_device *pdev) | |||
321 | 329 | ||
322 | return 0; | 330 | return 0; |
323 | 331 | ||
324 | err_res: | 332 | err_clk_alloc: |
325 | clk_put(tll->usbtll_p2_fck); | 333 | pm_runtime_put_sync(dev); |
326 | 334 | pm_runtime_disable(dev); | |
327 | err_p2_fck: | ||
328 | clk_put(tll->usbtll_p1_fck); | ||
329 | 335 | ||
330 | return ret; | 336 | return ret; |
331 | } | 337 | } |
@@ -339,9 +345,12 @@ err_p2_fck: | |||
339 | static int usbtll_omap_remove(struct platform_device *pdev) | 345 | static int usbtll_omap_remove(struct platform_device *pdev) |
340 | { | 346 | { |
341 | struct usbtll_omap *tll = platform_get_drvdata(pdev); | 347 | struct usbtll_omap *tll = platform_get_drvdata(pdev); |
348 | int i; | ||
349 | |||
350 | for (i = 0; i < tll->nch; i++) | ||
351 | if (!IS_ERR(tll->ch_clk[i])) | ||
352 | clk_put(tll->ch_clk[i]); | ||
342 | 353 | ||
343 | clk_put(tll->usbtll_p2_fck); | ||
344 | clk_put(tll->usbtll_p1_fck); | ||
345 | pm_runtime_disable(&pdev->dev); | 354 | pm_runtime_disable(&pdev->dev); |
346 | return 0; | 355 | return 0; |
347 | } | 356 | } |
@@ -351,6 +360,7 @@ static int usbtll_runtime_resume(struct device *dev) | |||
351 | struct usbtll_omap *tll = dev_get_drvdata(dev); | 360 | struct usbtll_omap *tll = dev_get_drvdata(dev); |
352 | struct usbhs_omap_platform_data *pdata = tll->pdata; | 361 | struct usbhs_omap_platform_data *pdata = tll->pdata; |
353 | unsigned long flags; | 362 | unsigned long flags; |
363 | int i; | ||
354 | 364 | ||
355 | dev_dbg(dev, "usbtll_runtime_resume\n"); | 365 | dev_dbg(dev, "usbtll_runtime_resume\n"); |
356 | 366 | ||
@@ -361,11 +371,20 @@ static int usbtll_runtime_resume(struct device *dev) | |||
361 | 371 | ||
362 | spin_lock_irqsave(&tll->lock, flags); | 372 | spin_lock_irqsave(&tll->lock, flags); |
363 | 373 | ||
364 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 374 | for (i = 0; i < tll->nch; i++) { |
365 | clk_enable(tll->usbtll_p1_fck); | 375 | if (is_ehci_tll_mode(pdata->port_mode[i])) { |
376 | int r; | ||
366 | 377 | ||
367 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 378 | if (IS_ERR(tll->ch_clk[i])) |
368 | clk_enable(tll->usbtll_p2_fck); | 379 | continue; |
380 | |||
381 | r = clk_enable(tll->ch_clk[i]); | ||
382 | if (r) { | ||
383 | dev_err(dev, | ||
384 | "Error enabling ch %d clock: %d\n", i, r); | ||
385 | } | ||
386 | } | ||
387 | } | ||
369 | 388 | ||
370 | spin_unlock_irqrestore(&tll->lock, flags); | 389 | spin_unlock_irqrestore(&tll->lock, flags); |
371 | 390 | ||
@@ -377,6 +396,7 @@ static int usbtll_runtime_suspend(struct device *dev) | |||
377 | struct usbtll_omap *tll = dev_get_drvdata(dev); | 396 | struct usbtll_omap *tll = dev_get_drvdata(dev); |
378 | struct usbhs_omap_platform_data *pdata = tll->pdata; | 397 | struct usbhs_omap_platform_data *pdata = tll->pdata; |
379 | unsigned long flags; | 398 | unsigned long flags; |
399 | int i; | ||
380 | 400 | ||
381 | dev_dbg(dev, "usbtll_runtime_suspend\n"); | 401 | dev_dbg(dev, "usbtll_runtime_suspend\n"); |
382 | 402 | ||
@@ -387,11 +407,12 @@ static int usbtll_runtime_suspend(struct device *dev) | |||
387 | 407 | ||
388 | spin_lock_irqsave(&tll->lock, flags); | 408 | spin_lock_irqsave(&tll->lock, flags); |
389 | 409 | ||
390 | if (is_ehci_tll_mode(pdata->port_mode[0])) | 410 | for (i = 0; i < tll->nch; i++) { |
391 | clk_disable(tll->usbtll_p1_fck); | 411 | if (is_ehci_tll_mode(pdata->port_mode[i])) { |
392 | 412 | if (!IS_ERR(tll->ch_clk[i])) | |
393 | if (is_ehci_tll_mode(pdata->port_mode[1])) | 413 | clk_disable(tll->ch_clk[i]); |
394 | clk_disable(tll->usbtll_p2_fck); | 414 | } |
415 | } | ||
395 | 416 | ||
396 | spin_unlock_irqrestore(&tll->lock, flags); | 417 | spin_unlock_irqrestore(&tll->lock, flags); |
397 | 418 | ||