diff options
author | Roger Quadros <rogerq@ti.com> | 2013-03-12 07:24:21 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2013-03-18 05:14:40 -0400 |
commit | 2319fb88e16e56c64d4f3ab50af69ed6dadbc7b5 (patch) | |
tree | ca4b7f2c7223f46054c301911465b35e585d5cfb | |
parent | e4d7dc6674efd798792adbd689986cde5422aa62 (diff) |
usb: phy: nop: Manage PHY clock
If the PHY has a clock associated to it then manage the clock.
We just enable the clock in .init() and disable it in .shutdown().
Add clk_rate parameter in platform data and configure the
clock rate during probe if supplied.
Signed-off-by: Roger Quadros <rogerq@ti.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/otg/nop-usb-xceiv.c | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c index af52870788ec..17c174f18da7 100644 --- a/drivers/usb/otg/nop-usb-xceiv.c +++ b/drivers/usb/otg/nop-usb-xceiv.c | |||
@@ -32,10 +32,12 @@ | |||
32 | #include <linux/usb/otg.h> | 32 | #include <linux/usb/otg.h> |
33 | #include <linux/usb/nop-usb-xceiv.h> | 33 | #include <linux/usb/nop-usb-xceiv.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/clk.h> | ||
35 | 36 | ||
36 | struct nop_usb_xceiv { | 37 | struct nop_usb_xceiv { |
37 | struct usb_phy phy; | 38 | struct usb_phy phy; |
38 | struct device *dev; | 39 | struct device *dev; |
40 | struct clk *clk; | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | static struct platform_device *pd; | 43 | static struct platform_device *pd; |
@@ -64,6 +66,24 @@ static int nop_set_suspend(struct usb_phy *x, int suspend) | |||
64 | return 0; | 66 | return 0; |
65 | } | 67 | } |
66 | 68 | ||
69 | static int nop_init(struct usb_phy *phy) | ||
70 | { | ||
71 | struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); | ||
72 | |||
73 | if (!IS_ERR(nop->clk)) | ||
74 | clk_enable(nop->clk); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static void nop_shutdown(struct usb_phy *phy) | ||
80 | { | ||
81 | struct nop_usb_xceiv *nop = dev_get_drvdata(phy->dev); | ||
82 | |||
83 | if (!IS_ERR(nop->clk)) | ||
84 | clk_disable(nop->clk); | ||
85 | } | ||
86 | |||
67 | static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) | 87 | static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget) |
68 | { | 88 | { |
69 | if (!otg) | 89 | if (!otg) |
@@ -112,10 +132,34 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) | |||
112 | if (pdata) | 132 | if (pdata) |
113 | type = pdata->type; | 133 | type = pdata->type; |
114 | 134 | ||
135 | nop->clk = devm_clk_get(&pdev->dev, "main_clk"); | ||
136 | if (IS_ERR(nop->clk)) { | ||
137 | dev_dbg(&pdev->dev, "Can't get phy clock: %ld\n", | ||
138 | PTR_ERR(nop->clk)); | ||
139 | } | ||
140 | |||
141 | if (!IS_ERR(nop->clk) && pdata && pdata->clk_rate) { | ||
142 | err = clk_set_rate(nop->clk, pdata->clk_rate); | ||
143 | if (err) { | ||
144 | dev_err(&pdev->dev, "Error setting clock rate\n"); | ||
145 | return err; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (!IS_ERR(nop->clk)) { | ||
150 | err = clk_prepare(nop->clk); | ||
151 | if (err) { | ||
152 | dev_err(&pdev->dev, "Error preparing clock\n"); | ||
153 | return err; | ||
154 | } | ||
155 | } | ||
156 | |||
115 | nop->dev = &pdev->dev; | 157 | nop->dev = &pdev->dev; |
116 | nop->phy.dev = nop->dev; | 158 | nop->phy.dev = nop->dev; |
117 | nop->phy.label = "nop-xceiv"; | 159 | nop->phy.label = "nop-xceiv"; |
118 | nop->phy.set_suspend = nop_set_suspend; | 160 | nop->phy.set_suspend = nop_set_suspend; |
161 | nop->phy.init = nop_init; | ||
162 | nop->phy.shutdown = nop_shutdown; | ||
119 | nop->phy.state = OTG_STATE_UNDEFINED; | 163 | nop->phy.state = OTG_STATE_UNDEFINED; |
120 | 164 | ||
121 | nop->phy.otg->phy = &nop->phy; | 165 | nop->phy.otg->phy = &nop->phy; |
@@ -126,7 +170,7 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) | |||
126 | if (err) { | 170 | if (err) { |
127 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n", | 171 | dev_err(&pdev->dev, "can't register transceiver, err: %d\n", |
128 | err); | 172 | err); |
129 | return err; | 173 | goto err_add; |
130 | } | 174 | } |
131 | 175 | ||
132 | platform_set_drvdata(pdev, nop); | 176 | platform_set_drvdata(pdev, nop); |
@@ -134,12 +178,20 @@ static int nop_usb_xceiv_probe(struct platform_device *pdev) | |||
134 | ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); | 178 | ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier); |
135 | 179 | ||
136 | return 0; | 180 | return 0; |
181 | |||
182 | err_add: | ||
183 | if (!IS_ERR(nop->clk)) | ||
184 | clk_unprepare(nop->clk); | ||
185 | return err; | ||
137 | } | 186 | } |
138 | 187 | ||
139 | static int nop_usb_xceiv_remove(struct platform_device *pdev) | 188 | static int nop_usb_xceiv_remove(struct platform_device *pdev) |
140 | { | 189 | { |
141 | struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); | 190 | struct nop_usb_xceiv *nop = platform_get_drvdata(pdev); |
142 | 191 | ||
192 | if (!IS_ERR(nop->clk)) | ||
193 | clk_unprepare(nop->clk); | ||
194 | |||
143 | usb_remove_phy(&nop->phy); | 195 | usb_remove_phy(&nop->phy); |
144 | 196 | ||
145 | platform_set_drvdata(pdev, NULL); | 197 | platform_set_drvdata(pdev, NULL); |