diff options
author | Viresh Kumar <viresh.kumar@linaro.com> | 2012-08-27 01:07:19 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2012-09-13 01:10:18 -0400 |
commit | f1e70c2c535923de253eea2021376a936eb8d478 (patch) | |
tree | 74a55422cfd07ade3f711f8143272b47e6a577b8 /drivers | |
parent | 26fdaa7453db49de80cc216cb696233b23d0b9d1 (diff) |
ata/ahci_platform: Add clock framework support
On many architectures, drivers are supposed to prepare/unprepare &
enable/disable functional clock of device. This patch adds clock support for
ahci_platform.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/ata/ahci.h | 2 | ||||
-rw-r--r-- | drivers/ata/ahci_platform.c | 57 |
2 files changed, 52 insertions, 7 deletions
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h index 6441cbecfa1d..9be471200a07 100644 --- a/drivers/ata/ahci.h +++ b/drivers/ata/ahci.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #ifndef _AHCI_H | 35 | #ifndef _AHCI_H |
36 | #define _AHCI_H | 36 | #define _AHCI_H |
37 | 37 | ||
38 | #include <linux/clk.h> | ||
38 | #include <linux/libata.h> | 39 | #include <linux/libata.h> |
39 | 40 | ||
40 | /* Enclosure Management Control */ | 41 | /* Enclosure Management Control */ |
@@ -316,6 +317,7 @@ struct ahci_host_priv { | |||
316 | u32 em_loc; /* enclosure management location */ | 317 | u32 em_loc; /* enclosure management location */ |
317 | u32 em_buf_sz; /* EM buffer size in byte */ | 318 | u32 em_buf_sz; /* EM buffer size in byte */ |
318 | u32 em_msg_type; /* EM message type */ | 319 | u32 em_msg_type; /* EM message type */ |
320 | struct clk *clk; /* Only for platforms supporting clk */ | ||
319 | }; | 321 | }; |
320 | 322 | ||
321 | extern int ahci_ignore_sss; | 323 | extern int ahci_ignore_sss; |
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c index dc187c746649..b1ae48054dc5 100644 --- a/drivers/ata/ahci_platform.c +++ b/drivers/ata/ahci_platform.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * any later version. | 12 | * any later version. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/clk.h> | ||
15 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
16 | #include <linux/gfp.h> | 17 | #include <linux/gfp.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
@@ -118,6 +119,17 @@ static int __init ahci_probe(struct platform_device *pdev) | |||
118 | return -ENOMEM; | 119 | return -ENOMEM; |
119 | } | 120 | } |
120 | 121 | ||
122 | hpriv->clk = clk_get(dev, NULL); | ||
123 | if (IS_ERR(hpriv->clk)) { | ||
124 | dev_err(dev, "can't get clock\n"); | ||
125 | } else { | ||
126 | rc = clk_prepare_enable(hpriv->clk); | ||
127 | if (rc) { | ||
128 | dev_err(dev, "clock prepare enable failed"); | ||
129 | goto free_clk; | ||
130 | } | ||
131 | } | ||
132 | |||
121 | /* | 133 | /* |
122 | * Some platforms might need to prepare for mmio region access, | 134 | * Some platforms might need to prepare for mmio region access, |
123 | * which could be done in the following init call. So, the mmio | 135 | * which could be done in the following init call. So, the mmio |
@@ -127,7 +139,7 @@ static int __init ahci_probe(struct platform_device *pdev) | |||
127 | if (pdata && pdata->init) { | 139 | if (pdata && pdata->init) { |
128 | rc = pdata->init(dev, hpriv->mmio); | 140 | rc = pdata->init(dev, hpriv->mmio); |
129 | if (rc) | 141 | if (rc) |
130 | return rc; | 142 | goto disable_unprepare_clk; |
131 | } | 143 | } |
132 | 144 | ||
133 | ahci_save_initial_config(dev, hpriv, | 145 | ahci_save_initial_config(dev, hpriv, |
@@ -153,7 +165,7 @@ static int __init ahci_probe(struct platform_device *pdev) | |||
153 | host = ata_host_alloc_pinfo(dev, ppi, n_ports); | 165 | host = ata_host_alloc_pinfo(dev, ppi, n_ports); |
154 | if (!host) { | 166 | if (!host) { |
155 | rc = -ENOMEM; | 167 | rc = -ENOMEM; |
156 | goto err0; | 168 | goto pdata_exit; |
157 | } | 169 | } |
158 | 170 | ||
159 | host->private_data = hpriv; | 171 | host->private_data = hpriv; |
@@ -183,7 +195,7 @@ static int __init ahci_probe(struct platform_device *pdev) | |||
183 | 195 | ||
184 | rc = ahci_reset_controller(host); | 196 | rc = ahci_reset_controller(host); |
185 | if (rc) | 197 | if (rc) |
186 | goto err0; | 198 | goto pdata_exit; |
187 | 199 | ||
188 | ahci_init_controller(host); | 200 | ahci_init_controller(host); |
189 | ahci_print_info(host, "platform"); | 201 | ahci_print_info(host, "platform"); |
@@ -191,12 +203,18 @@ static int __init ahci_probe(struct platform_device *pdev) | |||
191 | rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, | 203 | rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, |
192 | &ahci_platform_sht); | 204 | &ahci_platform_sht); |
193 | if (rc) | 205 | if (rc) |
194 | goto err0; | 206 | goto pdata_exit; |
195 | 207 | ||
196 | return 0; | 208 | return 0; |
197 | err0: | 209 | pdata_exit: |
198 | if (pdata && pdata->exit) | 210 | if (pdata && pdata->exit) |
199 | pdata->exit(dev); | 211 | pdata->exit(dev); |
212 | disable_unprepare_clk: | ||
213 | if (!IS_ERR(hpriv->clk)) | ||
214 | clk_disable_unprepare(hpriv->clk); | ||
215 | free_clk: | ||
216 | if (!IS_ERR(hpriv->clk)) | ||
217 | clk_put(hpriv->clk); | ||
200 | return rc; | 218 | return rc; |
201 | } | 219 | } |
202 | 220 | ||
@@ -205,12 +223,18 @@ static int __devexit ahci_remove(struct platform_device *pdev) | |||
205 | struct device *dev = &pdev->dev; | 223 | struct device *dev = &pdev->dev; |
206 | struct ahci_platform_data *pdata = dev_get_platdata(dev); | 224 | struct ahci_platform_data *pdata = dev_get_platdata(dev); |
207 | struct ata_host *host = dev_get_drvdata(dev); | 225 | struct ata_host *host = dev_get_drvdata(dev); |
226 | struct ahci_host_priv *hpriv = host->private_data; | ||
208 | 227 | ||
209 | ata_host_detach(host); | 228 | ata_host_detach(host); |
210 | 229 | ||
211 | if (pdata && pdata->exit) | 230 | if (pdata && pdata->exit) |
212 | pdata->exit(dev); | 231 | pdata->exit(dev); |
213 | 232 | ||
233 | if (!IS_ERR(hpriv->clk)) { | ||
234 | clk_disable_unprepare(hpriv->clk); | ||
235 | clk_put(hpriv->clk); | ||
236 | } | ||
237 | |||
214 | return 0; | 238 | return 0; |
215 | } | 239 | } |
216 | 240 | ||
@@ -245,6 +269,10 @@ static int ahci_suspend(struct device *dev) | |||
245 | 269 | ||
246 | if (pdata && pdata->suspend) | 270 | if (pdata && pdata->suspend) |
247 | return pdata->suspend(dev); | 271 | return pdata->suspend(dev); |
272 | |||
273 | if (!IS_ERR(hpriv->clk)) | ||
274 | clk_disable_unprepare(hpriv->clk); | ||
275 | |||
248 | return 0; | 276 | return 0; |
249 | } | 277 | } |
250 | 278 | ||
@@ -252,18 +280,27 @@ static int ahci_resume(struct device *dev) | |||
252 | { | 280 | { |
253 | struct ahci_platform_data *pdata = dev_get_platdata(dev); | 281 | struct ahci_platform_data *pdata = dev_get_platdata(dev); |
254 | struct ata_host *host = dev_get_drvdata(dev); | 282 | struct ata_host *host = dev_get_drvdata(dev); |
283 | struct ahci_host_priv *hpriv = host->private_data; | ||
255 | int rc; | 284 | int rc; |
256 | 285 | ||
286 | if (!IS_ERR(hpriv->clk)) { | ||
287 | rc = clk_prepare_enable(hpriv->clk); | ||
288 | if (rc) { | ||
289 | dev_err(dev, "clock prepare enable failed"); | ||
290 | return rc; | ||
291 | } | ||
292 | } | ||
293 | |||
257 | if (pdata && pdata->resume) { | 294 | if (pdata && pdata->resume) { |
258 | rc = pdata->resume(dev); | 295 | rc = pdata->resume(dev); |
259 | if (rc) | 296 | if (rc) |
260 | return rc; | 297 | goto disable_unprepare_clk; |
261 | } | 298 | } |
262 | 299 | ||
263 | if (dev->power.power_state.event == PM_EVENT_SUSPEND) { | 300 | if (dev->power.power_state.event == PM_EVENT_SUSPEND) { |
264 | rc = ahci_reset_controller(host); | 301 | rc = ahci_reset_controller(host); |
265 | if (rc) | 302 | if (rc) |
266 | return rc; | 303 | goto disable_unprepare_clk; |
267 | 304 | ||
268 | ahci_init_controller(host); | 305 | ahci_init_controller(host); |
269 | } | 306 | } |
@@ -271,6 +308,12 @@ static int ahci_resume(struct device *dev) | |||
271 | ata_host_resume(host); | 308 | ata_host_resume(host); |
272 | 309 | ||
273 | return 0; | 310 | return 0; |
311 | |||
312 | disable_unprepare_clk: | ||
313 | if (!IS_ERR(hpriv->clk)) | ||
314 | clk_disable_unprepare(hpriv->clk); | ||
315 | |||
316 | return rc; | ||
274 | } | 317 | } |
275 | #endif | 318 | #endif |
276 | 319 | ||