core.c 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * soundbus
  4. *
  5. * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
  6. */
  7. #include <linux/module.h>
  8. #include <linux/of.h>
  9. #include <linux/of_platform.h>
  10. #include "soundbus.h"
  11. MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
  12. MODULE_LICENSE("GPL");
  13. MODULE_DESCRIPTION("Apple Soundbus");
  14. struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev)
  15. {
  16. struct device *tmp;
  17. if (!dev)
  18. return NULL;
  19. tmp = get_device(&dev->ofdev.dev);
  20. if (tmp)
  21. return to_soundbus_device(tmp);
  22. else
  23. return NULL;
  24. }
  25. EXPORT_SYMBOL_GPL(soundbus_dev_get);
  26. void soundbus_dev_put(struct soundbus_dev *dev)
  27. {
  28. if (dev)
  29. put_device(&dev->ofdev.dev);
  30. }
  31. EXPORT_SYMBOL_GPL(soundbus_dev_put);
  32. static int soundbus_probe(struct device *dev)
  33. {
  34. int error = -ENODEV;
  35. struct soundbus_driver *drv;
  36. struct soundbus_dev *soundbus_dev;
  37. drv = to_soundbus_driver(dev->driver);
  38. soundbus_dev = to_soundbus_device(dev);
  39. if (!drv->probe)
  40. return error;
  41. soundbus_dev_get(soundbus_dev);
  42. error = drv->probe(soundbus_dev);
  43. if (error)
  44. soundbus_dev_put(soundbus_dev);
  45. return error;
  46. }
  47. static int soundbus_uevent(const struct device *dev, struct kobj_uevent_env *env)
  48. {
  49. const struct soundbus_dev * soundbus_dev;
  50. const struct platform_device * of;
  51. const char *compat;
  52. int retval = 0;
  53. int cplen, seen = 0;
  54. if (!dev)
  55. return -ENODEV;
  56. soundbus_dev = to_soundbus_device(dev);
  57. if (!soundbus_dev)
  58. return -ENODEV;
  59. of = &soundbus_dev->ofdev;
  60. /* stuff we want to pass to /sbin/hotplug */
  61. retval = add_uevent_var(env, "OF_NAME=%pOFn", of->dev.of_node);
  62. if (retval)
  63. return retval;
  64. retval = add_uevent_var(env, "OF_TYPE=%s", of_node_get_device_type(of->dev.of_node));
  65. if (retval)
  66. return retval;
  67. /* Since the compatible field can contain pretty much anything
  68. * it's not really legal to split it out with commas. We split it
  69. * up using a number of environment variables instead. */
  70. compat = of_get_property(of->dev.of_node, "compatible", &cplen);
  71. while (compat && cplen > 0) {
  72. int tmp = env->buflen;
  73. retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
  74. if (retval)
  75. return retval;
  76. compat += env->buflen - tmp;
  77. cplen -= env->buflen - tmp;
  78. seen += 1;
  79. }
  80. retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
  81. if (retval)
  82. return retval;
  83. retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias);
  84. return retval;
  85. }
  86. static void soundbus_device_remove(struct device *dev)
  87. {
  88. struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
  89. struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
  90. if (dev->driver && drv->remove)
  91. drv->remove(soundbus_dev);
  92. soundbus_dev_put(soundbus_dev);
  93. }
  94. static void soundbus_device_shutdown(struct device *dev)
  95. {
  96. struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
  97. struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
  98. if (dev->driver && drv->shutdown)
  99. drv->shutdown(soundbus_dev);
  100. }
  101. /* soundbus_dev_attrs is declared in sysfs.c */
  102. ATTRIBUTE_GROUPS(soundbus_dev);
  103. static const struct bus_type soundbus_bus_type = {
  104. .name = "aoa-soundbus",
  105. .probe = soundbus_probe,
  106. .uevent = soundbus_uevent,
  107. .remove = soundbus_device_remove,
  108. .shutdown = soundbus_device_shutdown,
  109. .dev_groups = soundbus_dev_groups,
  110. };
  111. int soundbus_add_one(struct soundbus_dev *dev)
  112. {
  113. static int devcount;
  114. /* sanity checks */
  115. if (!dev->attach_codec ||
  116. !dev->ofdev.dev.of_node ||
  117. dev->pcmname ||
  118. dev->pcmid != -1) {
  119. printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
  120. return -EINVAL;
  121. }
  122. dev_set_name(&dev->ofdev.dev, "soundbus:%x", ++devcount);
  123. dev->ofdev.dev.bus = &soundbus_bus_type;
  124. return of_device_register(&dev->ofdev);
  125. }
  126. EXPORT_SYMBOL_GPL(soundbus_add_one);
  127. void soundbus_remove_one(struct soundbus_dev *dev)
  128. {
  129. of_device_unregister(&dev->ofdev);
  130. }
  131. EXPORT_SYMBOL_GPL(soundbus_remove_one);
  132. int soundbus_register_driver(struct soundbus_driver *drv)
  133. {
  134. /* initialize common driver fields */
  135. drv->driver.name = drv->name;
  136. drv->driver.bus = &soundbus_bus_type;
  137. /* register with core */
  138. return driver_register(&drv->driver);
  139. }
  140. EXPORT_SYMBOL_GPL(soundbus_register_driver);
  141. void soundbus_unregister_driver(struct soundbus_driver *drv)
  142. {
  143. driver_unregister(&drv->driver);
  144. }
  145. EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
  146. static int __init soundbus_init(void)
  147. {
  148. return bus_register(&soundbus_bus_type);
  149. }
  150. static void __exit soundbus_exit(void)
  151. {
  152. bus_unregister(&soundbus_bus_type);
  153. }
  154. subsys_initcall(soundbus_init);
  155. module_exit(soundbus_exit);