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/ata | |
| 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/ata')
| -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 | ||
