debugfs.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Cadence USBSS DRD Controller DebugFS filer.
  4. *
  5. * Copyright (C) 2018-2019 Cadence.
  6. *
  7. * Author: Pawel Laszczak <pawell@cadence.com>
  8. */
  9. #include <linux/types.h>
  10. #include <linux/debugfs.h>
  11. #include <linux/seq_file.h>
  12. #include <linux/uaccess.h>
  13. #include "core.h"
  14. #include "gadget.h"
  15. #include "drd.h"
  16. static int cdns3_mode_show(struct seq_file *s, void *unused)
  17. {
  18. struct cdns3 *cdns = s->private;
  19. switch (cdns->current_dr_mode) {
  20. case USB_DR_MODE_HOST:
  21. seq_puts(s, "host\n");
  22. break;
  23. case USB_DR_MODE_PERIPHERAL:
  24. seq_puts(s, "device\n");
  25. break;
  26. case USB_DR_MODE_OTG:
  27. seq_puts(s, "otg\n");
  28. break;
  29. default:
  30. seq_puts(s, "UNKNOWN mode\n");
  31. }
  32. return 0;
  33. }
  34. static int cdns3_mode_open(struct inode *inode, struct file *file)
  35. {
  36. return single_open(file, cdns3_mode_show, inode->i_private);
  37. }
  38. static ssize_t cdns3_mode_write(struct file *file,
  39. const char __user *ubuf,
  40. size_t count, loff_t *ppos)
  41. {
  42. struct seq_file *s = file->private_data;
  43. struct cdns3 *cdns = s->private;
  44. u32 mode = USB_DR_MODE_UNKNOWN;
  45. char buf[32];
  46. int ret = 0;
  47. if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
  48. return -EFAULT;
  49. if (cdns->debug_disable) {
  50. dev_err(cdns->dev,
  51. "Mode can't be changed when disable is set\n");
  52. return -EFAULT;
  53. }
  54. if (!strncmp(buf, "host", 4)) {
  55. if (cdns->dr_mode == USB_DR_MODE_HOST ||
  56. cdns->dr_mode == USB_DR_MODE_OTG) {
  57. mode = USB_DR_MODE_HOST;
  58. }
  59. }
  60. if (!strncmp(buf, "device", 6))
  61. if (cdns->dr_mode == USB_DR_MODE_PERIPHERAL ||
  62. cdns->dr_mode == USB_DR_MODE_OTG)
  63. mode = USB_DR_MODE_PERIPHERAL;
  64. if (!strncmp(buf, "otg", 3) && cdns->dr_mode == USB_DR_MODE_OTG)
  65. mode = USB_DR_MODE_OTG;
  66. if (mode == USB_DR_MODE_UNKNOWN) {
  67. dev_err(cdns->dev, "Failed: incorrect mode setting\n");
  68. return -EFAULT;
  69. }
  70. if (cdns->current_dr_mode != mode) {
  71. cdns->desired_dr_mode = mode;
  72. cdns3_role_stop(cdns);
  73. ret = cdns3_drd_update_mode(cdns);
  74. if (ret)
  75. return ret;
  76. queue_work(system_freezable_wq, &cdns->role_switch_wq);
  77. }
  78. return count;
  79. }
  80. static const struct file_operations cdns3_mode_fops = {
  81. .open = cdns3_mode_open,
  82. .write = cdns3_mode_write,
  83. .read = seq_read,
  84. .llseek = seq_lseek,
  85. .release = single_release,
  86. };
  87. static int cdns3_disable_show(struct seq_file *s, void *unused)
  88. {
  89. struct cdns3 *cdns = s->private;
  90. if (!cdns->debug_disable)
  91. seq_puts(s, "0\n");
  92. else
  93. seq_puts(s, "1\n");
  94. return 0;
  95. }
  96. static ssize_t cdns3_disable_write(struct file *file,
  97. const char __user *ubuf,
  98. size_t count, loff_t *ppos)
  99. {
  100. struct seq_file *s = file->private_data;
  101. struct cdns3 *cdns = s->private;
  102. bool disable;
  103. char buf[16];
  104. if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
  105. return -EFAULT;
  106. if (kstrtobool(buf, &disable)) {
  107. dev_err(cdns->dev, "wrong setting\n");
  108. return -EINVAL;
  109. }
  110. if (disable != cdns->debug_disable) {
  111. cdns->debug_disable = disable;
  112. queue_work(system_freezable_wq, &cdns->role_switch_wq);
  113. }
  114. return count;
  115. }
  116. static int cdns3_disable_open(struct inode *inode, struct file *file)
  117. {
  118. return single_open(file, cdns3_disable_show, inode->i_private);
  119. }
  120. static const struct file_operations cdns3_disable_fops = {
  121. .open = cdns3_disable_open,
  122. .write = cdns3_disable_write,
  123. .read = seq_read,
  124. .llseek = seq_lseek,
  125. .release = single_release,
  126. };
  127. void cdns3_debugfs_init(struct cdns3 *cdns)
  128. {
  129. struct dentry *root;
  130. root = debugfs_create_dir(dev_name(cdns->dev), NULL);
  131. cdns->root = root;
  132. if (IS_ENABLED(CONFIG_USB_CDNS3_GADGET) &&
  133. IS_ENABLED(CONFIG_USB_CDNS3_HOST))
  134. debugfs_create_file("mode", 0644, root, cdns,
  135. &cdns3_mode_fops);
  136. debugfs_create_file("disable", 0644, root, cdns,
  137. &cdns3_disable_fops);
  138. }
  139. void cdns3_debugfs_exit(struct cdns3 *cdns)
  140. {
  141. debugfs_remove_recursive(cdns->root);
  142. }