1 From b7ad421c184b827806c7f65be3a980cfc855b589 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Sat, 22 Feb 2014 16:53:31 +0100
4 Subject: [PATCH 110/182] ahci-platform: Add support for devices with more
7 The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
8 imx AHCI controller needs 3 clocks to be enabled.
10 tj: Minor comment formatting updates.
12 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
13 Signed-off-by: Tejun Heo <tj@kernel.org>
15 .../devicetree/bindings/ata/ahci-platform.txt | 1 +
16 drivers/ata/ahci.h | 3 +-
17 drivers/ata/ahci_platform.c | 113 +++++++++++++++-----
18 include/linux/ahci_platform.h | 4 +
19 4 files changed, 93 insertions(+), 28 deletions(-)
21 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
22 +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
23 @@ -10,6 +10,7 @@ Required properties:
26 - dma-coherent : Present if dma operations are coherent
27 +- clocks : a list of phandle + clock specifier pairs
31 --- a/drivers/ata/ahci.h
32 +++ b/drivers/ata/ahci.h
38 AHCI_MAX_SG = 168, /* hardware max is 64K */
39 AHCI_DMA_BOUNDARY = 0xffffffff,
41 @@ -322,7 +323,7 @@ struct ahci_host_priv {
42 u32 em_loc; /* enclosure management location */
43 u32 em_buf_sz; /* EM buffer size in byte */
44 u32 em_msg_type; /* EM message type */
45 - struct clk *clk; /* Only for platforms supporting clk */
46 + struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
47 void *plat_data; /* Other platform data */
49 * Optional ahci_start_engine override, if not set this gets set to the
50 --- a/drivers/ata/ahci_platform.c
51 +++ b/drivers/ata/ahci_platform.c
52 @@ -87,6 +87,60 @@ static struct scsi_host_template ahci_pl
53 AHCI_SHT("ahci_platform"),
57 + * ahci_platform_enable_clks - Enable platform clocks
58 + * @hpriv: host private area to store config values
60 + * This function enables all the clks found in hpriv->clks, starting at
61 + * index 0. If any clk fails to enable it disables all the clks already
62 + * enabled in reverse order, and then returns an error.
65 + * 0 on success otherwise a negative error code
67 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
71 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
72 + rc = clk_prepare_enable(hpriv->clks[c]);
74 + goto disable_unprepare_clk;
78 +disable_unprepare_clk:
80 + clk_disable_unprepare(hpriv->clks[c]);
83 +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
86 + * ahci_platform_disable_clks - Disable platform clocks
87 + * @hpriv: host private area to store config values
89 + * This function disables all the clks found in hpriv->clks, in reverse
90 + * order of ahci_platform_enable_clks (starting at the end of the array).
92 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
96 + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
98 + clk_disable_unprepare(hpriv->clks[c]);
100 +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
102 +static void ahci_put_clks(struct ahci_host_priv *hpriv)
106 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
107 + clk_put(hpriv->clks[c]);
110 static int ahci_probe(struct platform_device *pdev)
112 struct device *dev = &pdev->dev;
113 @@ -97,6 +151,7 @@ static int ahci_probe(struct platform_de
114 struct ahci_host_priv *hpriv;
115 struct ata_host *host;
116 struct resource *mem;
121 @@ -131,17 +186,31 @@ static int ahci_probe(struct platform_de
125 - hpriv->clk = clk_get(dev, NULL);
126 - if (IS_ERR(hpriv->clk)) {
127 - dev_err(dev, "can't get clock\n");
129 - rc = clk_prepare_enable(hpriv->clk);
131 - dev_err(dev, "clock prepare enable failed");
133 + for (i = 0; i < AHCI_MAX_CLKS; i++) {
135 + * For now we must use clk_get(dev, NULL) for the first clock,
136 + * because some platforms (da850, spear13xx) are not yet
137 + * converted to use devicetree for clocks. For new platforms
138 + * this is equivalent to of_clk_get(dev->of_node, 0).
141 + clk = clk_get(dev, NULL);
143 + clk = of_clk_get(dev->of_node, i);
147 + if (rc == -EPROBE_DEFER)
151 + hpriv->clks[i] = clk;
154 + rc = ahci_enable_clks(dev, hpriv);
159 * Some platforms might need to prepare for mmio region access,
160 * which could be done in the following init call. So, the mmio
161 @@ -222,11 +291,9 @@ pdata_exit:
162 if (pdata && pdata->exit)
164 disable_unprepare_clk:
165 - if (!IS_ERR(hpriv->clk))
166 - clk_disable_unprepare(hpriv->clk);
167 + ahci_disable_clks(hpriv);
169 - if (!IS_ERR(hpriv->clk))
170 - clk_put(hpriv->clk);
171 + ahci_put_clks(hpriv);
175 @@ -239,10 +306,8 @@ static void ahci_host_stop(struct ata_ho
176 if (pdata && pdata->exit)
179 - if (!IS_ERR(hpriv->clk)) {
180 - clk_disable_unprepare(hpriv->clk);
181 - clk_put(hpriv->clk);
183 + ahci_disable_clks(hpriv);
184 + ahci_put_clks(hpriv);
187 #ifdef CONFIG_PM_SLEEP
188 @@ -277,8 +342,7 @@ static int ahci_suspend(struct device *d
189 if (pdata && pdata->suspend)
190 return pdata->suspend(dev);
192 - if (!IS_ERR(hpriv->clk))
193 - clk_disable_unprepare(hpriv->clk);
194 + ahci_disable_clks(hpriv);
198 @@ -290,13 +354,9 @@ static int ahci_resume(struct device *de
199 struct ahci_host_priv *hpriv = host->private_data;
202 - if (!IS_ERR(hpriv->clk)) {
203 - rc = clk_prepare_enable(hpriv->clk);
205 - dev_err(dev, "clock prepare enable failed");
209 + rc = ahci_enable_clks(dev, hpriv);
213 if (pdata && pdata->resume) {
214 rc = pdata->resume(dev);
215 @@ -317,8 +377,7 @@ static int ahci_resume(struct device *de
218 disable_unprepare_clk:
219 - if (!IS_ERR(hpriv->clk))
220 - clk_disable_unprepare(hpriv->clk);
221 + ahci_disable_clks(hpriv);
225 --- a/include/linux/ahci_platform.h
226 +++ b/include/linux/ahci_platform.h
230 struct ata_port_info;
231 +struct ahci_host_priv;
233 struct ahci_platform_data {
234 int (*init)(struct device *dev, void __iomem *addr);
235 @@ -30,4 +31,7 @@ struct ahci_platform_data {
236 unsigned int mask_port_map;
239 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
240 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
242 #endif /* _AHCI_PLATFORM_H */