master.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. // Copyright(c) 2019-2020 Intel Corporation.
  3. #include <linux/device.h>
  4. #include <linux/acpi.h>
  5. #include <linux/pm_runtime.h>
  6. #include <linux/soundwire/sdw.h>
  7. #include <linux/soundwire/sdw_type.h>
  8. #include "bus.h"
  9. /*
  10. * The 3s value for autosuspend will only be used if there are no
  11. * devices physically attached on a bus segment. In practice enabling
  12. * the bus operation will result in children devices become active and
  13. * the master device will only suspend when all its children are no
  14. * longer active.
  15. */
  16. #define SDW_MASTER_SUSPEND_DELAY_MS 3000
  17. /*
  18. * The sysfs for properties reflects the MIPI description as given
  19. * in the MIPI DisCo spec
  20. *
  21. * Base file is:
  22. * sdw-master-N
  23. * |---- revision
  24. * |---- clk_stop_modes
  25. * |---- max_clk_freq
  26. * |---- clk_freq
  27. * |---- clk_gears
  28. * |---- default_row
  29. * |---- default_col
  30. * |---- dynamic_shape
  31. * |---- err_threshold
  32. */
  33. #define sdw_master_attr(field, format_string) \
  34. static ssize_t field##_show(struct device *dev, \
  35. struct device_attribute *attr, \
  36. char *buf) \
  37. { \
  38. struct sdw_master_device *md = dev_to_sdw_master_device(dev); \
  39. return sprintf(buf, format_string, md->bus->prop.field); \
  40. } \
  41. static DEVICE_ATTR_RO(field)
  42. sdw_master_attr(revision, "0x%x\n");
  43. sdw_master_attr(clk_stop_modes, "0x%x\n");
  44. sdw_master_attr(max_clk_freq, "%d\n");
  45. sdw_master_attr(default_row, "%d\n");
  46. sdw_master_attr(default_col, "%d\n");
  47. sdw_master_attr(default_frame_rate, "%d\n");
  48. sdw_master_attr(dynamic_frame, "%d\n");
  49. sdw_master_attr(err_threshold, "%d\n");
  50. static ssize_t clock_frequencies_show(struct device *dev,
  51. struct device_attribute *attr, char *buf)
  52. {
  53. struct sdw_master_device *md = dev_to_sdw_master_device(dev);
  54. ssize_t size = 0;
  55. int i;
  56. for (i = 0; i < md->bus->prop.num_clk_freq; i++)
  57. size += sprintf(buf + size, "%8d ",
  58. md->bus->prop.clk_freq[i]);
  59. size += sprintf(buf + size, "\n");
  60. return size;
  61. }
  62. static DEVICE_ATTR_RO(clock_frequencies);
  63. static ssize_t clock_gears_show(struct device *dev,
  64. struct device_attribute *attr, char *buf)
  65. {
  66. struct sdw_master_device *md = dev_to_sdw_master_device(dev);
  67. ssize_t size = 0;
  68. int i;
  69. for (i = 0; i < md->bus->prop.num_clk_gears; i++)
  70. size += sprintf(buf + size, "%8d ",
  71. md->bus->prop.clk_gears[i]);
  72. size += sprintf(buf + size, "\n");
  73. return size;
  74. }
  75. static DEVICE_ATTR_RO(clock_gears);
  76. static struct attribute *master_node_attrs[] = {
  77. &dev_attr_revision.attr,
  78. &dev_attr_clk_stop_modes.attr,
  79. &dev_attr_max_clk_freq.attr,
  80. &dev_attr_default_row.attr,
  81. &dev_attr_default_col.attr,
  82. &dev_attr_default_frame_rate.attr,
  83. &dev_attr_dynamic_frame.attr,
  84. &dev_attr_err_threshold.attr,
  85. &dev_attr_clock_frequencies.attr,
  86. &dev_attr_clock_gears.attr,
  87. NULL,
  88. };
  89. ATTRIBUTE_GROUPS(master_node);
  90. static void sdw_master_device_release(struct device *dev)
  91. {
  92. struct sdw_master_device *md = dev_to_sdw_master_device(dev);
  93. kfree(md);
  94. }
  95. static const struct dev_pm_ops master_dev_pm = {
  96. SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend,
  97. pm_generic_runtime_resume, NULL)
  98. };
  99. struct device_type sdw_master_type = {
  100. .name = "soundwire_master",
  101. .release = sdw_master_device_release,
  102. .pm = &master_dev_pm,
  103. };
  104. /**
  105. * sdw_master_device_add() - create a Linux Master Device representation.
  106. * @bus: SDW bus instance
  107. * @parent: parent device
  108. * @fwnode: firmware node handle
  109. */
  110. int sdw_master_device_add(struct sdw_bus *bus, struct device *parent,
  111. struct fwnode_handle *fwnode)
  112. {
  113. struct sdw_master_device *md;
  114. int ret;
  115. if (!parent)
  116. return -EINVAL;
  117. md = kzalloc(sizeof(*md), GFP_KERNEL);
  118. if (!md)
  119. return -ENOMEM;
  120. md->dev.bus = &sdw_bus_type;
  121. md->dev.type = &sdw_master_type;
  122. md->dev.parent = parent;
  123. md->dev.groups = master_node_groups;
  124. md->dev.of_node = parent->of_node;
  125. md->dev.fwnode = fwnode;
  126. md->dev.dma_mask = parent->dma_mask;
  127. dev_set_name(&md->dev, "sdw-master-%d", bus->id);
  128. ret = device_register(&md->dev);
  129. if (ret) {
  130. dev_err(parent, "Failed to add master: ret %d\n", ret);
  131. /*
  132. * On err, don't free but drop ref as this will be freed
  133. * when release method is invoked.
  134. */
  135. put_device(&md->dev);
  136. goto device_register_err;
  137. }
  138. /* add shortcuts to improve code readability/compactness */
  139. md->bus = bus;
  140. bus->dev = &md->dev;
  141. bus->md = md;
  142. pm_runtime_set_autosuspend_delay(&bus->md->dev, SDW_MASTER_SUSPEND_DELAY_MS);
  143. pm_runtime_use_autosuspend(&bus->md->dev);
  144. pm_runtime_mark_last_busy(&bus->md->dev);
  145. pm_runtime_set_active(&bus->md->dev);
  146. pm_runtime_enable(&bus->md->dev);
  147. pm_runtime_idle(&bus->md->dev);
  148. device_register_err:
  149. return ret;
  150. }
  151. /**
  152. * sdw_master_device_del() - delete a Linux Master Device representation.
  153. * @bus: bus handle
  154. *
  155. * This function is the dual of sdw_master_device_add()
  156. */
  157. int sdw_master_device_del(struct sdw_bus *bus)
  158. {
  159. pm_runtime_disable(&bus->md->dev);
  160. device_unregister(bus->dev);
  161. return 0;
  162. }