aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-02-22 10:53:31 -0500
committerTejun Heo <tj@kernel.org>2014-02-22 15:35:41 -0500
commit156c5887948cd191417f18026aab9ce26e5a95da (patch)
tree65100ae8c89fec69d8f949ceb9b9b413a6af3468
parent039ece38da45f5e6a94be3aa7611cf3634bc2461 (diff)
ahci-platform: Add support for devices with more then 1 clock
The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the imx AHCI controller needs 3 clocks to be enabled. tj: Minor comment formatting updates. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt1
-rw-r--r--drivers/ata/ahci.h3
-rw-r--r--drivers/ata/ahci_platform.c113
-rw-r--r--include/linux/ahci_platform.h4
4 files changed, 93 insertions, 28 deletions
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 89de1564950c..3ced07dc8f56 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -10,6 +10,7 @@ Required properties:
10 10
11Optional properties: 11Optional properties:
12- dma-coherent : Present if dma operations are coherent 12- dma-coherent : Present if dma operations are coherent
13- clocks : a list of phandle + clock specifier pairs
13 14
14Example: 15Example:
15 sata@ffe08000 { 16 sata@ffe08000 {
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 64d1a99de5e4..c12862bd48ee 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -51,6 +51,7 @@
51 51
52enum { 52enum {
53 AHCI_MAX_PORTS = 32, 53 AHCI_MAX_PORTS = 32,
54 AHCI_MAX_CLKS = 3,
54 AHCI_MAX_SG = 168, /* hardware max is 64K */ 55 AHCI_MAX_SG = 168, /* hardware max is 64K */
55 AHCI_DMA_BOUNDARY = 0xffffffff, 56 AHCI_DMA_BOUNDARY = 0xffffffff,
56 AHCI_MAX_CMDS = 32, 57 AHCI_MAX_CMDS = 32,
@@ -321,7 +322,7 @@ struct ahci_host_priv {
321 u32 em_loc; /* enclosure management location */ 322 u32 em_loc; /* enclosure management location */
322 u32 em_buf_sz; /* EM buffer size in byte */ 323 u32 em_buf_sz; /* EM buffer size in byte */
323 u32 em_msg_type; /* EM message type */ 324 u32 em_msg_type; /* EM message type */
324 struct clk *clk; /* Only for platforms supporting clk */ 325 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
325 void *plat_data; /* Other platform data */ 326 void *plat_data; /* Other platform data */
326 /* 327 /*
327 * Optional ahci_start_engine override, if not set this gets set to the 328 * Optional ahci_start_engine override, if not set this gets set to the
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 9302d8143393..8d5a9a7ce958 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -86,6 +86,60 @@ static struct scsi_host_template ahci_platform_sht = {
86 AHCI_SHT("ahci_platform"), 86 AHCI_SHT("ahci_platform"),
87}; 87};
88 88
89/**
90 * ahci_platform_enable_clks - Enable platform clocks
91 * @hpriv: host private area to store config values
92 *
93 * This function enables all the clks found in hpriv->clks, starting at
94 * index 0. If any clk fails to enable it disables all the clks already
95 * enabled in reverse order, and then returns an error.
96 *
97 * RETURNS:
98 * 0 on success otherwise a negative error code
99 */
100int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
101{
102 int c, rc;
103
104 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
105 rc = clk_prepare_enable(hpriv->clks[c]);
106 if (rc)
107 goto disable_unprepare_clk;
108 }
109 return 0;
110
111disable_unprepare_clk:
112 while (--c >= 0)
113 clk_disable_unprepare(hpriv->clks[c]);
114 return rc;
115}
116EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
117
118/**
119 * ahci_platform_disable_clks - Disable platform clocks
120 * @hpriv: host private area to store config values
121 *
122 * This function disables all the clks found in hpriv->clks, in reverse
123 * order of ahci_platform_enable_clks (starting at the end of the array).
124 */
125void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
126{
127 int c;
128
129 for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
130 if (hpriv->clks[c])
131 clk_disable_unprepare(hpriv->clks[c]);
132}
133EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
134
135static void ahci_put_clks(struct ahci_host_priv *hpriv)
136{
137 int c;
138
139 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
140 clk_put(hpriv->clks[c]);
141}
142
89static int ahci_probe(struct platform_device *pdev) 143static int ahci_probe(struct platform_device *pdev)
90{ 144{
91 struct device *dev = &pdev->dev; 145 struct device *dev = &pdev->dev;
@@ -96,6 +150,7 @@ static int ahci_probe(struct platform_device *pdev)
96 struct ahci_host_priv *hpriv; 150 struct ahci_host_priv *hpriv;
97 struct ata_host *host; 151 struct ata_host *host;
98 struct resource *mem; 152 struct resource *mem;
153 struct clk *clk;
99 int irq; 154 int irq;
100 int n_ports; 155 int n_ports;
101 int i; 156 int i;
@@ -130,17 +185,31 @@ static int ahci_probe(struct platform_device *pdev)
130 return -ENOMEM; 185 return -ENOMEM;
131 } 186 }
132 187
133 hpriv->clk = clk_get(dev, NULL); 188 for (i = 0; i < AHCI_MAX_CLKS; i++) {
134 if (IS_ERR(hpriv->clk)) { 189 /*
135 dev_err(dev, "can't get clock\n"); 190 * For now we must use clk_get(dev, NULL) for the first clock,
136 } else { 191 * because some platforms (da850, spear13xx) are not yet
137 rc = clk_prepare_enable(hpriv->clk); 192 * converted to use devicetree for clocks. For new platforms
138 if (rc) { 193 * this is equivalent to of_clk_get(dev->of_node, 0).
139 dev_err(dev, "clock prepare enable failed"); 194 */
140 goto free_clk; 195 if (i == 0)
196 clk = clk_get(dev, NULL);
197 else
198 clk = of_clk_get(dev->of_node, i);
199
200 if (IS_ERR(clk)) {
201 rc = PTR_ERR(clk);
202 if (rc == -EPROBE_DEFER)
203 goto free_clk;
204 break;
141 } 205 }
206 hpriv->clks[i] = clk;
142 } 207 }
143 208
209 rc = ahci_enable_clks(dev, hpriv);
210 if (rc)
211 goto free_clk;
212
144 /* 213 /*
145 * Some platforms might need to prepare for mmio region access, 214 * Some platforms might need to prepare for mmio region access,
146 * which could be done in the following init call. So, the mmio 215 * which could be done in the following init call. So, the mmio
@@ -221,11 +290,9 @@ pdata_exit:
221 if (pdata && pdata->exit) 290 if (pdata && pdata->exit)
222 pdata->exit(dev); 291 pdata->exit(dev);
223disable_unprepare_clk: 292disable_unprepare_clk:
224 if (!IS_ERR(hpriv->clk)) 293 ahci_disable_clks(hpriv);
225 clk_disable_unprepare(hpriv->clk);
226free_clk: 294free_clk:
227 if (!IS_ERR(hpriv->clk)) 295 ahci_put_clks(hpriv);
228 clk_put(hpriv->clk);
229 return rc; 296 return rc;
230} 297}
231 298
@@ -238,10 +305,8 @@ static void ahci_host_stop(struct ata_host *host)
238 if (pdata && pdata->exit) 305 if (pdata && pdata->exit)
239 pdata->exit(dev); 306 pdata->exit(dev);
240 307
241 if (!IS_ERR(hpriv->clk)) { 308 ahci_disable_clks(hpriv);
242 clk_disable_unprepare(hpriv->clk); 309 ahci_put_clks(hpriv);
243 clk_put(hpriv->clk);
244 }
245} 310}
246 311
247#ifdef CONFIG_PM_SLEEP 312#ifdef CONFIG_PM_SLEEP
@@ -276,8 +341,7 @@ static int ahci_suspend(struct device *dev)
276 if (pdata && pdata->suspend) 341 if (pdata && pdata->suspend)
277 return pdata->suspend(dev); 342 return pdata->suspend(dev);
278 343
279 if (!IS_ERR(hpriv->clk)) 344 ahci_disable_clks(hpriv);
280 clk_disable_unprepare(hpriv->clk);
281 345
282 return 0; 346 return 0;
283} 347}
@@ -289,13 +353,9 @@ static int ahci_resume(struct device *dev)
289 struct ahci_host_priv *hpriv = host->private_data; 353 struct ahci_host_priv *hpriv = host->private_data;
290 int rc; 354 int rc;
291 355
292 if (!IS_ERR(hpriv->clk)) { 356 rc = ahci_enable_clks(dev, hpriv);
293 rc = clk_prepare_enable(hpriv->clk); 357 if (rc)
294 if (rc) { 358 return rc;
295 dev_err(dev, "clock prepare enable failed");
296 return rc;
297 }
298 }
299 359
300 if (pdata && pdata->resume) { 360 if (pdata && pdata->resume) {
301 rc = pdata->resume(dev); 361 rc = pdata->resume(dev);
@@ -316,8 +376,7 @@ static int ahci_resume(struct device *dev)
316 return 0; 376 return 0;
317 377
318disable_unprepare_clk: 378disable_unprepare_clk:
319 if (!IS_ERR(hpriv->clk)) 379 ahci_disable_clks(hpriv);
320 clk_disable_unprepare(hpriv->clk);
321 380
322 return rc; 381 return rc;
323} 382}
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 73a25005d88a..769d06525320 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -19,6 +19,7 @@
19 19
20struct device; 20struct device;
21struct ata_port_info; 21struct ata_port_info;
22struct ahci_host_priv;
22 23
23struct ahci_platform_data { 24struct ahci_platform_data {
24 int (*init)(struct device *dev, void __iomem *addr); 25 int (*init)(struct device *dev, void __iomem *addr);
@@ -30,4 +31,7 @@ struct ahci_platform_data {
30 unsigned int mask_port_map; 31 unsigned int mask_port_map;
31}; 32};
32 33
34int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
35void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
36
33#endif /* _AHCI_PLATFORM_H */ 37#endif /* _AHCI_PLATFORM_H */