Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: host: fotg2: add silicon clock handling

When used in a system with software-controlled silicon clocks,
the FOTG210 needs to grab, prepare and enable the clock.

This is needed on for example the Cortina Gemini, where the
platform will by default gate off the clock unless the
peripheral (in this case the USB driver) grabs and enables
the clock.

If there is no clock available on the platform, we live
without it. Make sure to percolate probe deferrals.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Linus Walleij and committed by
Greg Kroah-Hartman
ffa8a31b 697fa834

+32 -4
+29 -4
drivers/usb/host/fotg210-hcd.c
··· 31 31 #include <linux/uaccess.h> 32 32 #include <linux/platform_device.h> 33 33 #include <linux/io.h> 34 + #include <linux/clk.h> 34 35 35 36 #include <asm/byteorder.h> 36 37 #include <asm/irq.h> ··· 5597 5596 hcd->regs = devm_ioremap_resource(&pdev->dev, res); 5598 5597 if (IS_ERR(hcd->regs)) { 5599 5598 retval = PTR_ERR(hcd->regs); 5600 - goto failed; 5599 + goto failed_put_hcd; 5601 5600 } 5602 5601 5603 5602 hcd->rsrc_start = res->start; ··· 5607 5606 5608 5607 fotg210->caps = hcd->regs; 5609 5608 5609 + /* It's OK not to supply this clock */ 5610 + fotg210->pclk = clk_get(dev, "PCLK"); 5611 + if (!IS_ERR(fotg210->pclk)) { 5612 + retval = clk_prepare_enable(fotg210->pclk); 5613 + if (retval) { 5614 + dev_err(dev, "failed to enable PCLK\n"); 5615 + goto failed_put_hcd; 5616 + } 5617 + } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) { 5618 + /* 5619 + * Percolate deferrals, for anything else, 5620 + * just live without the clocking. 5621 + */ 5622 + retval = PTR_ERR(fotg210->pclk); 5623 + goto failed_dis_clk; 5624 + } 5625 + 5610 5626 retval = fotg210_setup(hcd); 5611 5627 if (retval) 5612 - goto failed; 5628 + goto failed_dis_clk; 5613 5629 5614 5630 fotg210_init(fotg210); 5615 5631 5616 5632 retval = usb_add_hcd(hcd, irq, IRQF_SHARED); 5617 5633 if (retval) { 5618 5634 dev_err(dev, "failed to add hcd with err %d\n", retval); 5619 - goto failed; 5635 + goto failed_dis_clk; 5620 5636 } 5621 5637 device_wakeup_enable(hcd->self.controller); 5622 5638 5623 5639 return retval; 5624 5640 5625 - failed: 5641 + failed_dis_clk: 5642 + if (!IS_ERR(fotg210->pclk)) 5643 + clk_disable_unprepare(fotg210->pclk); 5644 + failed_put_hcd: 5626 5645 usb_put_hcd(hcd); 5627 5646 fail_create_hcd: 5628 5647 dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval); ··· 5658 5637 { 5659 5638 struct device *dev = &pdev->dev; 5660 5639 struct usb_hcd *hcd = dev_get_drvdata(dev); 5640 + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); 5641 + 5642 + if (!IS_ERR(fotg210->pclk)) 5643 + clk_disable_unprepare(fotg210->pclk); 5661 5644 5662 5645 if (!hcd) 5663 5646 return 0;
+3
drivers/usb/host/fotg210.h
··· 182 182 # define COUNT(x) 183 183 #endif 184 184 185 + /* silicon clock */ 186 + struct clk *pclk; 187 + 185 188 /* debug files */ 186 189 struct dentry *debug_dir; 187 190 };