diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/ibmebus.c | 404 |
1 files changed, 400 insertions, 4 deletions
diff --git a/arch/powerpc/kernel/ibmebus.c b/arch/powerpc/kernel/ibmebus.c index f62efdfd1769..c00d4ca1ee15 100644 --- a/arch/powerpc/kernel/ibmebus.c +++ b/arch/powerpc/kernel/ibmebus.c | |||
@@ -201,13 +201,14 @@ int ibmebus_register_driver(struct of_platform_driver *drv) | |||
201 | /* If the driver uses devices that ibmebus doesn't know, add them */ | 201 | /* If the driver uses devices that ibmebus doesn't know, add them */ |
202 | ibmebus_create_devices(drv->driver.of_match_table); | 202 | ibmebus_create_devices(drv->driver.of_match_table); |
203 | 203 | ||
204 | return of_register_driver(drv, &ibmebus_bus_type); | 204 | drv->driver.bus = &ibmebus_bus_type; |
205 | return driver_register(&drv->driver); | ||
205 | } | 206 | } |
206 | EXPORT_SYMBOL(ibmebus_register_driver); | 207 | EXPORT_SYMBOL(ibmebus_register_driver); |
207 | 208 | ||
208 | void ibmebus_unregister_driver(struct of_platform_driver *drv) | 209 | void ibmebus_unregister_driver(struct of_platform_driver *drv) |
209 | { | 210 | { |
210 | of_unregister_driver(drv); | 211 | driver_unregister(&drv->driver); |
211 | } | 212 | } |
212 | EXPORT_SYMBOL(ibmebus_unregister_driver); | 213 | EXPORT_SYMBOL(ibmebus_unregister_driver); |
213 | 214 | ||
@@ -308,15 +309,410 @@ static ssize_t ibmebus_store_remove(struct bus_type *bus, | |||
308 | } | 309 | } |
309 | } | 310 | } |
310 | 311 | ||
312 | |||
311 | static struct bus_attribute ibmebus_bus_attrs[] = { | 313 | static struct bus_attribute ibmebus_bus_attrs[] = { |
312 | __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe), | 314 | __ATTR(probe, S_IWUSR, NULL, ibmebus_store_probe), |
313 | __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove), | 315 | __ATTR(remove, S_IWUSR, NULL, ibmebus_store_remove), |
314 | __ATTR_NULL | 316 | __ATTR_NULL |
315 | }; | 317 | }; |
316 | 318 | ||
319 | static int ibmebus_bus_bus_match(struct device *dev, struct device_driver *drv) | ||
320 | { | ||
321 | const struct of_device_id *matches = drv->of_match_table; | ||
322 | |||
323 | if (!matches) | ||
324 | return 0; | ||
325 | |||
326 | return of_match_device(matches, dev) != NULL; | ||
327 | } | ||
328 | |||
329 | static int ibmebus_bus_device_probe(struct device *dev) | ||
330 | { | ||
331 | int error = -ENODEV; | ||
332 | struct of_platform_driver *drv; | ||
333 | struct platform_device *of_dev; | ||
334 | const struct of_device_id *match; | ||
335 | |||
336 | drv = to_of_platform_driver(dev->driver); | ||
337 | of_dev = to_platform_device(dev); | ||
338 | |||
339 | if (!drv->probe) | ||
340 | return error; | ||
341 | |||
342 | of_dev_get(of_dev); | ||
343 | |||
344 | match = of_match_device(drv->driver.of_match_table, dev); | ||
345 | if (match) | ||
346 | error = drv->probe(of_dev, match); | ||
347 | if (error) | ||
348 | of_dev_put(of_dev); | ||
349 | |||
350 | return error; | ||
351 | } | ||
352 | |||
353 | static int ibmebus_bus_device_remove(struct device *dev) | ||
354 | { | ||
355 | struct platform_device *of_dev = to_platform_device(dev); | ||
356 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
357 | |||
358 | if (dev->driver && drv->remove) | ||
359 | drv->remove(of_dev); | ||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static void ibmebus_bus_device_shutdown(struct device *dev) | ||
364 | { | ||
365 | struct platform_device *of_dev = to_platform_device(dev); | ||
366 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
367 | |||
368 | if (dev->driver && drv->shutdown) | ||
369 | drv->shutdown(of_dev); | ||
370 | } | ||
371 | |||
372 | /* | ||
373 | * ibmebus_bus_device_attrs | ||
374 | */ | ||
375 | static ssize_t devspec_show(struct device *dev, | ||
376 | struct device_attribute *attr, char *buf) | ||
377 | { | ||
378 | struct platform_device *ofdev; | ||
379 | |||
380 | ofdev = to_platform_device(dev); | ||
381 | return sprintf(buf, "%s\n", ofdev->dev.of_node->full_name); | ||
382 | } | ||
383 | |||
384 | static ssize_t name_show(struct device *dev, | ||
385 | struct device_attribute *attr, char *buf) | ||
386 | { | ||
387 | struct platform_device *ofdev; | ||
388 | |||
389 | ofdev = to_platform_device(dev); | ||
390 | return sprintf(buf, "%s\n", ofdev->dev.of_node->name); | ||
391 | } | ||
392 | |||
393 | static ssize_t modalias_show(struct device *dev, | ||
394 | struct device_attribute *attr, char *buf) | ||
395 | { | ||
396 | ssize_t len = of_device_get_modalias(dev, buf, PAGE_SIZE - 2); | ||
397 | buf[len] = '\n'; | ||
398 | buf[len+1] = 0; | ||
399 | return len+1; | ||
400 | } | ||
401 | |||
402 | struct device_attribute ibmebus_bus_device_attrs[] = { | ||
403 | __ATTR_RO(devspec), | ||
404 | __ATTR_RO(name), | ||
405 | __ATTR_RO(modalias), | ||
406 | __ATTR_NULL | ||
407 | }; | ||
408 | |||
409 | #ifdef CONFIG_PM_SLEEP | ||
410 | static int ibmebus_bus_legacy_suspend(struct device *dev, pm_message_t mesg) | ||
411 | { | ||
412 | struct platform_device *of_dev = to_platform_device(dev); | ||
413 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
414 | int ret = 0; | ||
415 | |||
416 | if (dev->driver && drv->suspend) | ||
417 | ret = drv->suspend(of_dev, mesg); | ||
418 | return ret; | ||
419 | } | ||
420 | |||
421 | static int ibmebus_bus_legacy_resume(struct device *dev) | ||
422 | { | ||
423 | struct platform_device *of_dev = to_platform_device(dev); | ||
424 | struct of_platform_driver *drv = to_of_platform_driver(dev->driver); | ||
425 | int ret = 0; | ||
426 | |||
427 | if (dev->driver && drv->resume) | ||
428 | ret = drv->resume(of_dev); | ||
429 | return ret; | ||
430 | } | ||
431 | |||
432 | static int ibmebus_bus_pm_prepare(struct device *dev) | ||
433 | { | ||
434 | struct device_driver *drv = dev->driver; | ||
435 | int ret = 0; | ||
436 | |||
437 | if (drv && drv->pm && drv->pm->prepare) | ||
438 | ret = drv->pm->prepare(dev); | ||
439 | |||
440 | return ret; | ||
441 | } | ||
442 | |||
443 | static void ibmebus_bus_pm_complete(struct device *dev) | ||
444 | { | ||
445 | struct device_driver *drv = dev->driver; | ||
446 | |||
447 | if (drv && drv->pm && drv->pm->complete) | ||
448 | drv->pm->complete(dev); | ||
449 | } | ||
450 | |||
451 | #ifdef CONFIG_SUSPEND | ||
452 | |||
453 | static int ibmebus_bus_pm_suspend(struct device *dev) | ||
454 | { | ||
455 | struct device_driver *drv = dev->driver; | ||
456 | int ret = 0; | ||
457 | |||
458 | if (!drv) | ||
459 | return 0; | ||
460 | |||
461 | if (drv->pm) { | ||
462 | if (drv->pm->suspend) | ||
463 | ret = drv->pm->suspend(dev); | ||
464 | } else { | ||
465 | ret = ibmebus_bus_legacy_suspend(dev, PMSG_SUSPEND); | ||
466 | } | ||
467 | |||
468 | return ret; | ||
469 | } | ||
470 | |||
471 | static int ibmebus_bus_pm_suspend_noirq(struct device *dev) | ||
472 | { | ||
473 | struct device_driver *drv = dev->driver; | ||
474 | int ret = 0; | ||
475 | |||
476 | if (!drv) | ||
477 | return 0; | ||
478 | |||
479 | if (drv->pm) { | ||
480 | if (drv->pm->suspend_noirq) | ||
481 | ret = drv->pm->suspend_noirq(dev); | ||
482 | } | ||
483 | |||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | static int ibmebus_bus_pm_resume(struct device *dev) | ||
488 | { | ||
489 | struct device_driver *drv = dev->driver; | ||
490 | int ret = 0; | ||
491 | |||
492 | if (!drv) | ||
493 | return 0; | ||
494 | |||
495 | if (drv->pm) { | ||
496 | if (drv->pm->resume) | ||
497 | ret = drv->pm->resume(dev); | ||
498 | } else { | ||
499 | ret = ibmebus_bus_legacy_resume(dev); | ||
500 | } | ||
501 | |||
502 | return ret; | ||
503 | } | ||
504 | |||
505 | static int ibmebus_bus_pm_resume_noirq(struct device *dev) | ||
506 | { | ||
507 | struct device_driver *drv = dev->driver; | ||
508 | int ret = 0; | ||
509 | |||
510 | if (!drv) | ||
511 | return 0; | ||
512 | |||
513 | if (drv->pm) { | ||
514 | if (drv->pm->resume_noirq) | ||
515 | ret = drv->pm->resume_noirq(dev); | ||
516 | } | ||
517 | |||
518 | return ret; | ||
519 | } | ||
520 | |||
521 | #else /* !CONFIG_SUSPEND */ | ||
522 | |||
523 | #define ibmebus_bus_pm_suspend NULL | ||
524 | #define ibmebus_bus_pm_resume NULL | ||
525 | #define ibmebus_bus_pm_suspend_noirq NULL | ||
526 | #define ibmebus_bus_pm_resume_noirq NULL | ||
527 | |||
528 | #endif /* !CONFIG_SUSPEND */ | ||
529 | |||
530 | #ifdef CONFIG_HIBERNATION | ||
531 | |||
532 | static int ibmebus_bus_pm_freeze(struct device *dev) | ||
533 | { | ||
534 | struct device_driver *drv = dev->driver; | ||
535 | int ret = 0; | ||
536 | |||
537 | if (!drv) | ||
538 | return 0; | ||
539 | |||
540 | if (drv->pm) { | ||
541 | if (drv->pm->freeze) | ||
542 | ret = drv->pm->freeze(dev); | ||
543 | } else { | ||
544 | ret = ibmebus_bus_legacy_suspend(dev, PMSG_FREEZE); | ||
545 | } | ||
546 | |||
547 | return ret; | ||
548 | } | ||
549 | |||
550 | static int ibmebus_bus_pm_freeze_noirq(struct device *dev) | ||
551 | { | ||
552 | struct device_driver *drv = dev->driver; | ||
553 | int ret = 0; | ||
554 | |||
555 | if (!drv) | ||
556 | return 0; | ||
557 | |||
558 | if (drv->pm) { | ||
559 | if (drv->pm->freeze_noirq) | ||
560 | ret = drv->pm->freeze_noirq(dev); | ||
561 | } | ||
562 | |||
563 | return ret; | ||
564 | } | ||
565 | |||
566 | static int ibmebus_bus_pm_thaw(struct device *dev) | ||
567 | { | ||
568 | struct device_driver *drv = dev->driver; | ||
569 | int ret = 0; | ||
570 | |||
571 | if (!drv) | ||
572 | return 0; | ||
573 | |||
574 | if (drv->pm) { | ||
575 | if (drv->pm->thaw) | ||
576 | ret = drv->pm->thaw(dev); | ||
577 | } else { | ||
578 | ret = ibmebus_bus_legacy_resume(dev); | ||
579 | } | ||
580 | |||
581 | return ret; | ||
582 | } | ||
583 | |||
584 | static int ibmebus_bus_pm_thaw_noirq(struct device *dev) | ||
585 | { | ||
586 | struct device_driver *drv = dev->driver; | ||
587 | int ret = 0; | ||
588 | |||
589 | if (!drv) | ||
590 | return 0; | ||
591 | |||
592 | if (drv->pm) { | ||
593 | if (drv->pm->thaw_noirq) | ||
594 | ret = drv->pm->thaw_noirq(dev); | ||
595 | } | ||
596 | |||
597 | return ret; | ||
598 | } | ||
599 | |||
600 | static int ibmebus_bus_pm_poweroff(struct device *dev) | ||
601 | { | ||
602 | struct device_driver *drv = dev->driver; | ||
603 | int ret = 0; | ||
604 | |||
605 | if (!drv) | ||
606 | return 0; | ||
607 | |||
608 | if (drv->pm) { | ||
609 | if (drv->pm->poweroff) | ||
610 | ret = drv->pm->poweroff(dev); | ||
611 | } else { | ||
612 | ret = ibmebus_bus_legacy_suspend(dev, PMSG_HIBERNATE); | ||
613 | } | ||
614 | |||
615 | return ret; | ||
616 | } | ||
617 | |||
618 | static int ibmebus_bus_pm_poweroff_noirq(struct device *dev) | ||
619 | { | ||
620 | struct device_driver *drv = dev->driver; | ||
621 | int ret = 0; | ||
622 | |||
623 | if (!drv) | ||
624 | return 0; | ||
625 | |||
626 | if (drv->pm) { | ||
627 | if (drv->pm->poweroff_noirq) | ||
628 | ret = drv->pm->poweroff_noirq(dev); | ||
629 | } | ||
630 | |||
631 | return ret; | ||
632 | } | ||
633 | |||
634 | static int ibmebus_bus_pm_restore(struct device *dev) | ||
635 | { | ||
636 | struct device_driver *drv = dev->driver; | ||
637 | int ret = 0; | ||
638 | |||
639 | if (!drv) | ||
640 | return 0; | ||
641 | |||
642 | if (drv->pm) { | ||
643 | if (drv->pm->restore) | ||
644 | ret = drv->pm->restore(dev); | ||
645 | } else { | ||
646 | ret = ibmebus_bus_legacy_resume(dev); | ||
647 | } | ||
648 | |||
649 | return ret; | ||
650 | } | ||
651 | |||
652 | static int ibmebus_bus_pm_restore_noirq(struct device *dev) | ||
653 | { | ||
654 | struct device_driver *drv = dev->driver; | ||
655 | int ret = 0; | ||
656 | |||
657 | if (!drv) | ||
658 | return 0; | ||
659 | |||
660 | if (drv->pm) { | ||
661 | if (drv->pm->restore_noirq) | ||
662 | ret = drv->pm->restore_noirq(dev); | ||
663 | } | ||
664 | |||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | #else /* !CONFIG_HIBERNATION */ | ||
669 | |||
670 | #define ibmebus_bus_pm_freeze NULL | ||
671 | #define ibmebus_bus_pm_thaw NULL | ||
672 | #define ibmebus_bus_pm_poweroff NULL | ||
673 | #define ibmebus_bus_pm_restore NULL | ||
674 | #define ibmebus_bus_pm_freeze_noirq NULL | ||
675 | #define ibmebus_bus_pm_thaw_noirq NULL | ||
676 | #define ibmebus_bus_pm_poweroff_noirq NULL | ||
677 | #define ibmebus_bus_pm_restore_noirq NULL | ||
678 | |||
679 | #endif /* !CONFIG_HIBERNATION */ | ||
680 | |||
681 | static struct dev_pm_ops ibmebus_bus_dev_pm_ops = { | ||
682 | .prepare = ibmebus_bus_pm_prepare, | ||
683 | .complete = ibmebus_bus_pm_complete, | ||
684 | .suspend = ibmebus_bus_pm_suspend, | ||
685 | .resume = ibmebus_bus_pm_resume, | ||
686 | .freeze = ibmebus_bus_pm_freeze, | ||
687 | .thaw = ibmebus_bus_pm_thaw, | ||
688 | .poweroff = ibmebus_bus_pm_poweroff, | ||
689 | .restore = ibmebus_bus_pm_restore, | ||
690 | .suspend_noirq = ibmebus_bus_pm_suspend_noirq, | ||
691 | .resume_noirq = ibmebus_bus_pm_resume_noirq, | ||
692 | .freeze_noirq = ibmebus_bus_pm_freeze_noirq, | ||
693 | .thaw_noirq = ibmebus_bus_pm_thaw_noirq, | ||
694 | .poweroff_noirq = ibmebus_bus_pm_poweroff_noirq, | ||
695 | .restore_noirq = ibmebus_bus_pm_restore_noirq, | ||
696 | }; | ||
697 | |||
698 | #define IBMEBUS_BUS_PM_OPS_PTR (&ibmebus_bus_dev_pm_ops) | ||
699 | |||
700 | #else /* !CONFIG_PM_SLEEP */ | ||
701 | |||
702 | #define IBMEBUS_BUS_PM_OPS_PTR NULL | ||
703 | |||
704 | #endif /* !CONFIG_PM_SLEEP */ | ||
705 | |||
317 | struct bus_type ibmebus_bus_type = { | 706 | struct bus_type ibmebus_bus_type = { |
707 | .name = "ibmebus", | ||
318 | .uevent = of_device_uevent, | 708 | .uevent = of_device_uevent, |
319 | .bus_attrs = ibmebus_bus_attrs | 709 | .bus_attrs = ibmebus_bus_attrs, |
710 | .match = ibmebus_bus_bus_match, | ||
711 | .probe = ibmebus_bus_device_probe, | ||
712 | .remove = ibmebus_bus_device_remove, | ||
713 | .shutdown = ibmebus_bus_device_shutdown, | ||
714 | .dev_attrs = ibmebus_bus_device_attrs, | ||
715 | .pm = IBMEBUS_BUS_PM_OPS_PTR, | ||
320 | }; | 716 | }; |
321 | EXPORT_SYMBOL(ibmebus_bus_type); | 717 | EXPORT_SYMBOL(ibmebus_bus_type); |
322 | 718 | ||
@@ -326,7 +722,7 @@ static int __init ibmebus_bus_init(void) | |||
326 | 722 | ||
327 | printk(KERN_INFO "IBM eBus Device Driver\n"); | 723 | printk(KERN_INFO "IBM eBus Device Driver\n"); |
328 | 724 | ||
329 | err = of_bus_type_init(&ibmebus_bus_type, "ibmebus"); | 725 | err = bus_register(&ibmebus_bus_type); |
330 | if (err) { | 726 | if (err) { |
331 | printk(KERN_ERR "%s: failed to register IBM eBus.\n", | 727 | printk(KERN_ERR "%s: failed to register IBM eBus.\n", |
332 | __func__); | 728 | __func__); |