aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-02-22 10:53:34 -0500
committerTejun Heo <tj@kernel.org>2014-02-22 15:35:42 -0500
commit23b07d4cb3c0c850055cf968af44019b8da185fb (patch)
tree0af2a4e9dfdaa99a566ca51198369b09704c14b7
parent96a01ba52c60fdd74dd6e8cf06645d06515b1396 (diff)
ahci-platform: "Library-ise" ahci_probe functionality
ahci_probe consists of 3 steps: 1) Get resources (get mmio, clks, regulator) 2) Enable resources, handled by ahci_platform_enable_resouces 3) The more or less standard ahci-host controller init sequence This commit refactors step 1 and 3 into separate functions, so the platform drivers for AHCI implementations which need a specific order in step 2, and / or need to do some custom register poking at some time, can re-use ahci-platform.c code without needing to copy and paste it. Note that ahci_platform_init_host's prototype takes the 3 non function members of ahci_platform_data as arguments, the idea is that drivers using the new exported utility functions will not use ahci_platform_data at all, and hopefully in the future ahci_platform_data can go away entirely. 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--drivers/ata/ahci_platform.c188
-rw-r--r--include/linux/ahci_platform.h14
2 files changed, 137 insertions, 65 deletions
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index a32df31013cb..19e9eaafb1f2 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -188,64 +188,60 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
188} 188}
189EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); 189EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
190 190
191static void ahci_put_clks(struct ahci_host_priv *hpriv) 191static void ahci_platform_put_resources(struct device *dev, void *res)
192{ 192{
193 struct ahci_host_priv *hpriv = res;
193 int c; 194 int c;
194 195
195 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) 196 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
196 clk_put(hpriv->clks[c]); 197 clk_put(hpriv->clks[c]);
197} 198}
198 199
199static int ahci_probe(struct platform_device *pdev) 200/**
201 * ahci_platform_get_resources - Get platform resources
202 * @pdev: platform device to get resources for
203 *
204 * This function allocates an ahci_host_priv struct, and gets the following
205 * resources, storing a reference to them inside the returned struct:
206 *
207 * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
208 * 2) regulator for controlling the targets power (optional)
209 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
210 * or for non devicetree enabled platforms a single clock
211 *
212 * RETURNS:
213 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
214 */
215struct ahci_host_priv *ahci_platform_get_resources(
216 struct platform_device *pdev)
200{ 217{
201 struct device *dev = &pdev->dev; 218 struct device *dev = &pdev->dev;
202 struct ahci_platform_data *pdata = dev_get_platdata(dev);
203 const struct platform_device_id *id = platform_get_device_id(pdev);
204 struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
205 const struct ata_port_info *ppi[] = { &pi, NULL };
206 struct ahci_host_priv *hpriv; 219 struct ahci_host_priv *hpriv;
207 struct ata_host *host;
208 struct resource *mem;
209 struct clk *clk; 220 struct clk *clk;
210 int irq; 221 int i, rc = -ENOMEM;
211 int n_ports;
212 int i;
213 int rc;
214 222
215 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 223 if (!devres_open_group(dev, NULL, GFP_KERNEL))
216 if (!mem) { 224 return ERR_PTR(-ENOMEM);
217 dev_err(dev, "no mmio space\n");
218 return -EINVAL;
219 }
220
221 irq = platform_get_irq(pdev, 0);
222 if (irq <= 0) {
223 dev_err(dev, "no irq\n");
224 return -EINVAL;
225 }
226 225
227 if (pdata && pdata->ata_port_info) 226 hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
228 pi = *pdata->ata_port_info; 227 GFP_KERNEL);
229 228 if (!hpriv)
230 hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL); 229 goto err_out;
231 if (!hpriv) {
232 dev_err(dev, "can't alloc ahci_host_priv\n");
233 return -ENOMEM;
234 }
235 230
236 hpriv->flags |= (unsigned long)pi.private_data; 231 devres_add(dev, hpriv);
237 232
238 hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem)); 233 hpriv->mmio = devm_ioremap_resource(dev,
234 platform_get_resource(pdev, IORESOURCE_MEM, 0));
239 if (!hpriv->mmio) { 235 if (!hpriv->mmio) {
240 dev_err(dev, "can't map %pR\n", mem); 236 dev_err(dev, "no mmio space\n");
241 return -ENOMEM; 237 goto err_out;
242 } 238 }
243 239
244 hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); 240 hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
245 if (IS_ERR(hpriv->target_pwr)) { 241 if (IS_ERR(hpriv->target_pwr)) {
246 rc = PTR_ERR(hpriv->target_pwr); 242 rc = PTR_ERR(hpriv->target_pwr);
247 if (rc == -EPROBE_DEFER) 243 if (rc == -EPROBE_DEFER)
248 return -EPROBE_DEFER; 244 goto err_out;
249 hpriv->target_pwr = NULL; 245 hpriv->target_pwr = NULL;
250 } 246 }
251 247
@@ -264,33 +260,59 @@ static int ahci_probe(struct platform_device *pdev)
264 if (IS_ERR(clk)) { 260 if (IS_ERR(clk)) {
265 rc = PTR_ERR(clk); 261 rc = PTR_ERR(clk);
266 if (rc == -EPROBE_DEFER) 262 if (rc == -EPROBE_DEFER)
267 goto free_clk; 263 goto err_out;
268 break; 264 break;
269 } 265 }
270 hpriv->clks[i] = clk; 266 hpriv->clks[i] = clk;
271 } 267 }
272 268
273 rc = ahci_platform_enable_resources(hpriv); 269 devres_remove_group(dev, NULL);
274 if (rc) 270 return hpriv;
275 goto free_clk;
276 271
277 /* 272err_out:
278 * Some platforms might need to prepare for mmio region access, 273 devres_release_group(dev, NULL);
279 * which could be done in the following init call. So, the mmio 274 return ERR_PTR(rc);
280 * region shouldn't be accessed before init (if provided) has 275}
281 * returned successfully. 276EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
282 */ 277
283 if (pdata && pdata->init) { 278/**
284 rc = pdata->init(dev, hpriv->mmio); 279 * ahci_platform_init_host - Bring up an ahci-platform host
285 if (rc) 280 * @pdev: platform device pointer for the host
286 goto disable_resources; 281 * @hpriv: ahci-host private data for the host
287 } 282 * @pi_template: template for the ata_port_info to use
283 * @force_port_map: param passed to ahci_save_initial_config
284 * @mask_port_map: param passed to ahci_save_initial_config
285 *
286 * This function does all the usual steps needed to bring up an
287 * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
288 * must be initialized / enabled before calling this.
289 *
290 * RETURNS:
291 * 0 on success otherwise a negative error code
292 */
293int ahci_platform_init_host(struct platform_device *pdev,
294 struct ahci_host_priv *hpriv,
295 const struct ata_port_info *pi_template,
296 unsigned int force_port_map,
297 unsigned int mask_port_map)
298{
299 struct device *dev = &pdev->dev;
300 struct ata_port_info pi = *pi_template;
301 const struct ata_port_info *ppi[] = { &pi, NULL };
302 struct ata_host *host;
303 int i, irq, n_ports, rc;
288 304
289 ahci_save_initial_config(dev, hpriv, 305 irq = platform_get_irq(pdev, 0);
290 pdata ? pdata->force_port_map : 0, 306 if (irq <= 0) {
291 pdata ? pdata->mask_port_map : 0); 307 dev_err(dev, "no irq\n");
308 return -EINVAL;
309 }
292 310
293 /* prepare host */ 311 /* prepare host */
312 hpriv->flags |= (unsigned long)pi.private_data;
313
314 ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
315
294 if (hpriv->cap & HOST_CAP_NCQ) 316 if (hpriv->cap & HOST_CAP_NCQ)
295 pi.flags |= ATA_FLAG_NCQ; 317 pi.flags |= ATA_FLAG_NCQ;
296 318
@@ -307,10 +329,8 @@ static int ahci_probe(struct platform_device *pdev)
307 n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 329 n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
308 330
309 host = ata_host_alloc_pinfo(dev, ppi, n_ports); 331 host = ata_host_alloc_pinfo(dev, ppi, n_ports);
310 if (!host) { 332 if (!host)
311 rc = -ENOMEM; 333 return -ENOMEM;
312 goto pdata_exit;
313 }
314 334
315 host->private_data = hpriv; 335 host->private_data = hpriv;
316 336
@@ -325,7 +345,8 @@ static int ahci_probe(struct platform_device *pdev)
325 for (i = 0; i < host->n_ports; i++) { 345 for (i = 0; i < host->n_ports; i++) {
326 struct ata_port *ap = host->ports[i]; 346 struct ata_port *ap = host->ports[i];
327 347
328 ata_port_desc(ap, "mmio %pR", mem); 348 ata_port_desc(ap, "mmio %pR",
349 platform_get_resource(pdev, IORESOURCE_MEM, 0));
329 ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); 350 ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
330 351
331 /* set enclosure management message type */ 352 /* set enclosure management message type */
@@ -339,13 +360,53 @@ static int ahci_probe(struct platform_device *pdev)
339 360
340 rc = ahci_reset_controller(host); 361 rc = ahci_reset_controller(host);
341 if (rc) 362 if (rc)
342 goto pdata_exit; 363 return rc;
343 364
344 ahci_init_controller(host); 365 ahci_init_controller(host);
345 ahci_print_info(host, "platform"); 366 ahci_print_info(host, "platform");
346 367
347 rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, 368 return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
348 &ahci_platform_sht); 369 &ahci_platform_sht);
370}
371EXPORT_SYMBOL_GPL(ahci_platform_init_host);
372
373static int ahci_probe(struct platform_device *pdev)
374{
375 struct device *dev = &pdev->dev;
376 struct ahci_platform_data *pdata = dev_get_platdata(dev);
377 const struct platform_device_id *id = platform_get_device_id(pdev);
378 const struct ata_port_info *pi_template;
379 struct ahci_host_priv *hpriv;
380 int rc;
381
382 hpriv = ahci_platform_get_resources(pdev);
383 if (IS_ERR(hpriv))
384 return PTR_ERR(hpriv);
385
386 rc = ahci_platform_enable_resources(hpriv);
387 if (rc)
388 return rc;
389
390 /*
391 * Some platforms might need to prepare for mmio region access,
392 * which could be done in the following init call. So, the mmio
393 * region shouldn't be accessed before init (if provided) has
394 * returned successfully.
395 */
396 if (pdata && pdata->init) {
397 rc = pdata->init(dev, hpriv->mmio);
398 if (rc)
399 goto disable_resources;
400 }
401
402 if (pdata && pdata->ata_port_info)
403 pi_template = pdata->ata_port_info;
404 else
405 pi_template = &ahci_port_info[id ? id->driver_data : 0];
406
407 rc = ahci_platform_init_host(pdev, hpriv, pi_template,
408 pdata ? pdata->force_port_map : 0,
409 pdata ? pdata->mask_port_map : 0);
349 if (rc) 410 if (rc)
350 goto pdata_exit; 411 goto pdata_exit;
351 412
@@ -355,8 +416,6 @@ pdata_exit:
355 pdata->exit(dev); 416 pdata->exit(dev);
356disable_resources: 417disable_resources:
357 ahci_platform_disable_resources(hpriv); 418 ahci_platform_disable_resources(hpriv);
358free_clk:
359 ahci_put_clks(hpriv);
360 return rc; 419 return rc;
361} 420}
362 421
@@ -370,7 +429,6 @@ static void ahci_host_stop(struct ata_host *host)
370 pdata->exit(dev); 429 pdata->exit(dev);
371 430
372 ahci_platform_disable_resources(hpriv); 431 ahci_platform_disable_resources(hpriv);
373 ahci_put_clks(hpriv);
374} 432}
375 433
376#ifdef CONFIG_PM_SLEEP 434#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index b674b01ce9bc..b80c51c20f76 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -20,7 +20,14 @@
20struct device; 20struct device;
21struct ata_port_info; 21struct ata_port_info;
22struct ahci_host_priv; 22struct ahci_host_priv;
23struct platform_device;
23 24
25/*
26 * Note ahci_platform_data is deprecated, it is only kept around for use
27 * by the old da850 and spear13xx ahci code.
28 * New drivers should instead declare their own platform_driver struct, and
29 * use ahci_platform* functions in their own probe, suspend and resume methods.
30 */
24struct ahci_platform_data { 31struct ahci_platform_data {
25 int (*init)(struct device *dev, void __iomem *addr); 32 int (*init)(struct device *dev, void __iomem *addr);
26 void (*exit)(struct device *dev); 33 void (*exit)(struct device *dev);
@@ -35,5 +42,12 @@ int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
35void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); 42void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
36int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); 43int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
37void ahci_platform_disable_resources(struct ahci_host_priv *hpriv); 44void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
45struct ahci_host_priv *ahci_platform_get_resources(
46 struct platform_device *pdev);
47int ahci_platform_init_host(struct platform_device *pdev,
48 struct ahci_host_priv *hpriv,
49 const struct ata_port_info *pi_template,
50 unsigned int force_port_map,
51 unsigned int mask_port_map);
38 52
39#endif /* _AHCI_PLATFORM_H */ 53#endif /* _AHCI_PLATFORM_H */