54f84ee0720772ba70394351470a256d6b6ba6cc
[15.05/openwrt.git] / target / linux / ipq806x / patches / 0110-ahci-platform-Add-support-for-devices-with-more-then.patch
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
5  then 1 clock
6
7 The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
8 imx AHCI controller needs 3 clocks to be enabled.
9
10 tj: Minor comment formatting updates.
11
12 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
13 Signed-off-by: Tejun Heo <tj@kernel.org>
14 ---
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(-)
20
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:
24  
25  Optional properties:
26  - dma-coherent      : Present if dma operations are coherent
27 +- clocks            : a list of phandle + clock specifier pairs
28  
29  Example:
30          sata@ffe08000 {
31 --- a/drivers/ata/ahci.h
32 +++ b/drivers/ata/ahci.h
33 @@ -51,6 +51,7 @@
34  
35  enum {
36         AHCI_MAX_PORTS          = 32,
37 +       AHCI_MAX_CLKS           = 3,
38         AHCI_MAX_SG             = 168, /* hardware max is 64K */
39         AHCI_DMA_BOUNDARY       = 0xffffffff,
40         AHCI_MAX_CMDS           = 32,
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 */
48         /*
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"),
54  };
55  
56 +/**
57 + * ahci_platform_enable_clks - Enable platform clocks
58 + * @hpriv: host private area to store config values
59 + *
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.
63 + *
64 + * RETURNS:
65 + * 0 on success otherwise a negative error code
66 + */
67 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
68 +{
69 +       int c, rc;
70 +
71 +       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
72 +               rc = clk_prepare_enable(hpriv->clks[c]);
73 +               if (rc)
74 +                       goto disable_unprepare_clk;
75 +       }
76 +       return 0;
77 +
78 +disable_unprepare_clk:
79 +       while (--c >= 0)
80 +               clk_disable_unprepare(hpriv->clks[c]);
81 +       return rc;
82 +}
83 +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
84 +
85 +/**
86 + * ahci_platform_disable_clks - Disable platform clocks
87 + * @hpriv: host private area to store config values
88 + *
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).
91 + */
92 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
93 +{
94 +       int c;
95 +
96 +       for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
97 +               if (hpriv->clks[c])
98 +                       clk_disable_unprepare(hpriv->clks[c]);
99 +}
100 +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
101 +
102 +static void ahci_put_clks(struct ahci_host_priv *hpriv)
103 +{
104 +       int c;
105 +
106 +       for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
107 +               clk_put(hpriv->clks[c]);
108 +}
109 +
110  static int ahci_probe(struct platform_device *pdev)
111  {
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;
117 +       struct clk *clk;
118         int irq;
119         int n_ports;
120         int i;
121 @@ -131,17 +186,31 @@ static int ahci_probe(struct platform_de
122                 return -ENOMEM;
123         }
124  
125 -       hpriv->clk = clk_get(dev, NULL);
126 -       if (IS_ERR(hpriv->clk)) {
127 -               dev_err(dev, "can't get clock\n");
128 -       } else {
129 -               rc = clk_prepare_enable(hpriv->clk);
130 -               if (rc) {
131 -                       dev_err(dev, "clock prepare enable failed");
132 -                       goto free_clk;
133 +       for (i = 0; i < AHCI_MAX_CLKS; i++) {
134 +               /*
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).
139 +                */
140 +               if (i == 0)
141 +                       clk = clk_get(dev, NULL);
142 +               else
143 +                       clk = of_clk_get(dev->of_node, i);
144 +
145 +               if (IS_ERR(clk)) {
146 +                       rc = PTR_ERR(clk);
147 +                       if (rc == -EPROBE_DEFER)
148 +                               goto free_clk;
149 +                       break;
150                 }
151 +               hpriv->clks[i] = clk;
152         }
153  
154 +       rc = ahci_enable_clks(dev, hpriv);
155 +       if (rc)
156 +               goto free_clk;
157 +
158         /*
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)
163                 pdata->exit(dev);
164  disable_unprepare_clk:
165 -       if (!IS_ERR(hpriv->clk))
166 -               clk_disable_unprepare(hpriv->clk);
167 +       ahci_disable_clks(hpriv);
168  free_clk:
169 -       if (!IS_ERR(hpriv->clk))
170 -               clk_put(hpriv->clk);
171 +       ahci_put_clks(hpriv);
172         return rc;
173  }
174  
175 @@ -239,10 +306,8 @@ static void ahci_host_stop(struct ata_ho
176         if (pdata && pdata->exit)
177                 pdata->exit(dev);
178  
179 -       if (!IS_ERR(hpriv->clk)) {
180 -               clk_disable_unprepare(hpriv->clk);
181 -               clk_put(hpriv->clk);
182 -       }
183 +       ahci_disable_clks(hpriv);
184 +       ahci_put_clks(hpriv);
185  }
186  
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);
191  
192 -       if (!IS_ERR(hpriv->clk))
193 -               clk_disable_unprepare(hpriv->clk);
194 +       ahci_disable_clks(hpriv);
195  
196         return 0;
197  }
198 @@ -290,13 +354,9 @@ static int ahci_resume(struct device *de
199         struct ahci_host_priv *hpriv = host->private_data;
200         int rc;
201  
202 -       if (!IS_ERR(hpriv->clk)) {
203 -               rc = clk_prepare_enable(hpriv->clk);
204 -               if (rc) {
205 -                       dev_err(dev, "clock prepare enable failed");
206 -                       return rc;
207 -               }
208 -       }
209 +       rc = ahci_enable_clks(dev, hpriv);
210 +       if (rc)
211 +               return rc;
212  
213         if (pdata && pdata->resume) {
214                 rc = pdata->resume(dev);
215 @@ -317,8 +377,7 @@ static int ahci_resume(struct device *de
216         return 0;
217  
218  disable_unprepare_clk:
219 -       if (!IS_ERR(hpriv->clk))
220 -               clk_disable_unprepare(hpriv->clk);
221 +       ahci_disable_clks(hpriv);
222  
223         return rc;
224  }
225 --- a/include/linux/ahci_platform.h
226 +++ b/include/linux/ahci_platform.h
227 @@ -19,6 +19,7 @@
228  
229  struct device;
230  struct ata_port_info;
231 +struct ahci_host_priv;
232  
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;
237  };
238  
239 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
240 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
241 +
242  #endif /* _AHCI_PLATFORM_H */