ssusb_sysfs.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. /*
  2. * MTK SSUSB driver sysfs support
  3. *
  4. * Copyright 2015 MediaTek
  5. * Author: chunfeng.yun <chunfeng.yun@mediatek.com>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * version 2 as published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * General Public License for more details.
  15. * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  16. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
  18. * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  19. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  21. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  22. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. *
  26. */
  27. #include <linux/module.h>
  28. #include <linux/kernel.h>
  29. #include <linux/init.h>
  30. #include <linux/uaccess.h>
  31. #include "musb_core.h"
  32. #include "ssusb_sysfs.h"
  33. #include "mu3d_hal_usb_drv.h"
  34. #include "mu3d_hal_hw.h"
  35. #include "ssusb_io.h"
  36. #include "xhci-mtk.h"
  37. #define REGS_LIMIT_XHCI 0x1000
  38. #define REGS_LIMIT_MU3D 0x3000
  39. #define REGS_LIMIT_PHYS 0x12000
  40. unsigned int cable_mode = CABLE_MODE_NORMAL;
  41. /*--FOR INSTANT POWER ON USAGE--------------------------------------------------*/
  42. const char *const usb_mode_str[CABLE_MODE_MAX] = { "CHRG_ONLY", "NORMAL", "HOST_ONLY" };
  43. ssize_t musb_cmode_show(struct device *dev, struct device_attribute *attr, char *buf)
  44. {
  45. if (!dev) {
  46. mu3d_dbg(K_ERR, "dev is null!!\n");
  47. return 0;
  48. }
  49. return sprintf(buf, "%s\n", usb_mode_str[cable_mode]);
  50. }
  51. ssize_t musb_cmode_store(struct device *dev, struct device_attribute *attr,
  52. const char *buf, size_t count)
  53. {
  54. struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
  55. struct musb *musb = ssusb->mu3di;
  56. unsigned int cmode;
  57. if (!dev) {
  58. mu3d_dbg(K_ERR, "dev is null!!\n");
  59. return count;
  60. } else if (1 == kstrtoint(buf, 0, &cmode)) {
  61. mu3d_dbg(K_INFO, "%s %s --> %s\n", __func__, usb_mode_str[cable_mode],
  62. usb_mode_str[cmode]);
  63. if (cmode >= CABLE_MODE_MAX)
  64. cmode = CABLE_MODE_NORMAL;
  65. if (cable_mode != cmode) {
  66. if (cmode == CABLE_MODE_CHRG_ONLY) { /* IPO shutdown, disable USB */
  67. if (musb) {
  68. musb->usb_mode = CABLE_MODE_CHRG_ONLY;
  69. mt_usb_disconnect();
  70. }
  71. } else if (cmode == CABLE_MODE_HOST_ONLY) {
  72. if (musb) {
  73. musb->usb_mode = CABLE_MODE_HOST_ONLY;
  74. mt_usb_disconnect();
  75. }
  76. } else { /* IPO bootup, enable USB */
  77. if (musb) {
  78. musb->usb_mode = CABLE_MODE_NORMAL;
  79. mt_usb_connect();
  80. }
  81. }
  82. cable_mode = cmode;
  83. }
  84. }
  85. return count;
  86. }
  87. static ssize_t musb_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
  88. {
  89. struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
  90. struct musb *musb = ssusb->mu3di;
  91. unsigned long flags;
  92. int ret = -EINVAL;
  93. /* TODO : judge when support DRD, other wise, shouldn't call mtk_is_host_mode() */
  94. spin_lock_irqsave(&musb->lock, flags);
  95. ret = sprintf(buf, "current: %s\n (echo 0: to device, 1: to host)\n",
  96. mtk_is_host_mode() ? "host" : "device");
  97. spin_unlock_irqrestore(&musb->lock, flags);
  98. return ret;
  99. }
  100. ssize_t musb_mode_store(struct device *dev, struct device_attribute *attr,
  101. const char *buf, size_t count)
  102. {
  103. struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
  104. struct musb *musb = ssusb->mu3di;
  105. int old_mode = !!mtk_is_host_mode();
  106. int mode;
  107. if (!dev) {
  108. mu3d_dbg(K_ERR, "dev is null!!\n");
  109. return count;
  110. } else if (1 == kstrtoint(buf, 0, &mode)) {
  111. mu3d_dbg(K_INFO, "%s() --> %s\n", __func__, mode ? "host" : "device");
  112. mode = !!mode;
  113. if (old_mode == mode) {
  114. mu3d_dbg(K_INFO, "already in %s\n", mode ? "host" : "device");
  115. return count;
  116. }
  117. if (mode) {
  118. musb_stop(musb);
  119. msleep(200); /* if not, there is something wrong with xhci's port status */
  120. ssusb_mode_switch_manual(ssusb, 1);
  121. } else {
  122. ssusb_mode_switch_manual(ssusb, 0);
  123. msleep(100);
  124. musb_start(musb);
  125. }
  126. } else {
  127. mu3d_dbg(K_INFO, "echo 0 > mode: to deice, echo 1 > mode: to host\n");
  128. }
  129. return count;
  130. }
  131. static DEVICE_ATTR(mode, 0664, musb_mode_show, musb_mode_store);
  132. static ssize_t ssusb_reg_show(struct device *dev, struct device_attribute *attr, char *buf)
  133. {
  134. /* struct ssusb_mtk *ssusb = dev_to_ssusb(dev); */
  135. int ret = -EINVAL;
  136. ret = sprintf(buf, "SSUSB register operation interface help info.\n"
  137. " rx - read xhci mac register: offset [len]\n"
  138. " wx - write xhci mac register: offset value\n"
  139. " rm - read mu3d mac register: offset [len]\n"
  140. " wm - write mu3d mac register: offset value\n"
  141. " rp - read phy register: offset [len]\n"
  142. " wp - write phy register: offset value\n"
  143. " NOTE: numbers should be HEX\n");
  144. return ret;
  145. }
  146. static void ssusb_write_reg(struct ssusb_mtk *ssusb, const char *buf)
  147. {
  148. struct musb *musb = ssusb->mu3di;
  149. void __iomem *base;
  150. u32 offset = 0;
  151. u32 value = 0;
  152. u32 old_val = 0;
  153. u32 limit = 0;
  154. u32 param;
  155. param = sscanf(buf, "%*s 0x%x 0x%x", &offset, &value);
  156. mu3d_dbg(K_INFO, "params-%d (offset: %#x, value: %#x)\n", param, offset, value);
  157. switch (buf[1]) {
  158. case 'x':
  159. base = get_xhci_base();
  160. limit = REGS_LIMIT_XHCI;
  161. mu3d_dbg(K_INFO, "write xhci's reg:\n");
  162. break;
  163. case 'm':
  164. base = musb->mac_base;
  165. limit = REGS_LIMIT_MU3D;
  166. mu3d_dbg(K_INFO, "write mu3d's reg:\n");
  167. break;
  168. case 'p':
  169. base = musb->sif_base;
  170. limit = REGS_LIMIT_PHYS;
  171. mu3d_dbg(K_INFO, "write sif's reg:\n");
  172. break;
  173. default:
  174. base = NULL;
  175. }
  176. if (!base || (param != 2)) {
  177. mu3d_dbg(K_ERR, "params are invalid!\n");
  178. return;
  179. }
  180. offset &= ~0x3; /* 4-bytes align */
  181. if (offset >= limit) {
  182. mu3d_dbg(K_ERR, "reg's offset overrun!\n");
  183. return;
  184. }
  185. old_val = mu3d_readl(base, offset);
  186. mu3d_writel(base, offset, value);
  187. mu3d_dbg(K_INFO, "0x%8.8x : 0x%8.8x --> 0x%8.8x\n", offset, old_val,
  188. mu3d_readl(base, offset));
  189. }
  190. static void read_single_reg(void __iomem *base, u32 offset, u32 limit)
  191. {
  192. u32 value;
  193. offset &= ~0x3; /* 4-bytes align */
  194. if (offset >= limit) {
  195. mu3d_dbg(K_ERR, "reg's offset overrun!\n");
  196. return;
  197. }
  198. value = mu3d_readl(base, offset);
  199. mu3d_dbg(K_INFO, "0x%8.8x : 0x%8.8x\n", offset, value);
  200. }
  201. static void read_multi_regs(void __iomem *base, u32 offset, u32 len, u32 limit)
  202. {
  203. int i;
  204. /* at least 4 ints */
  205. offset &= ~0xF;
  206. len = (len + 0x3) & ~0x3;
  207. if (offset + len > limit) {
  208. mu3d_dbg(K_ERR, "reg's offset overrun!\n");
  209. return;
  210. }
  211. len >>= 2;
  212. mu3d_dbg(K_INFO, "read regs [%#x, %#x)\n", offset, offset + (len << 4));
  213. for (i = 0; i < len; i++) {
  214. mu3d_dbg(K_INFO, "0x%8.8x : 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
  215. offset, mu3d_readl(base, offset), mu3d_readl(base, offset + 0x4),
  216. mu3d_readl(base, offset + 0x8), mu3d_readl(base, offset + 0xc));
  217. offset += 0x10;
  218. }
  219. }
  220. static void ssusb_read_regs(struct ssusb_mtk *ssusb, const char *buf)
  221. {
  222. struct musb *musb = ssusb->mu3di;
  223. void __iomem *base;
  224. u32 offset = 0;
  225. u32 len = 0;
  226. u32 limit = 0;
  227. u32 param;
  228. param = sscanf(buf, "%*s 0x%x 0x%x", &offset, &len);
  229. mu3d_dbg(K_INFO, "params-%d (offset: %#x, len: %#x)\n", param, offset, len);
  230. switch (buf[1]) {
  231. case 'x':
  232. base = get_xhci_base();
  233. limit = REGS_LIMIT_XHCI;
  234. mu3d_dbg(K_INFO, "read xhci's reg:\n");
  235. break;
  236. case 'm':
  237. base = musb->mac_base;
  238. limit = REGS_LIMIT_MU3D;
  239. mu3d_dbg(K_INFO, "read mu3d's reg:\n");
  240. break;
  241. case 'p':
  242. base = musb->sif_base;
  243. limit = REGS_LIMIT_PHYS;
  244. mu3d_dbg(K_INFO, "read sif's reg:\n");
  245. break;
  246. default:
  247. base = NULL;
  248. }
  249. if (!base || !param) {
  250. mu3d_dbg(K_ERR, "params are invalid!\n");
  251. return;
  252. }
  253. if (1 == param)
  254. read_single_reg(base, offset, limit);
  255. else
  256. read_multi_regs(base, offset, len, limit);
  257. }
  258. static ssize_t
  259. ssusb_reg_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n)
  260. {
  261. struct ssusb_mtk *ssusb = dev_to_ssusb(dev);
  262. mu3d_dbg(K_INFO, " cmd: %s\n", buf);
  263. if (!ssusb->is_power_on) {
  264. mu3d_dbg(K_INFO, "power off, so can't access regs\n");
  265. goto out;
  266. }
  267. switch (buf[0]) {
  268. case 'w':
  269. ssusb_write_reg(ssusb, buf);
  270. break;
  271. case 'r':
  272. ssusb_read_regs(ssusb, buf);
  273. break;
  274. default:
  275. mu3d_dbg(K_INFO, "No such cmd\n");
  276. }
  277. out:
  278. return n;
  279. }
  280. static DEVICE_ATTR(reg, 0664, ssusb_reg_show, ssusb_reg_store);
  281. DEVICE_ATTR(cmode, 0664, musb_cmode_show, musb_cmode_store);
  282. static struct attribute *musb_attributes[] = {
  283. &dev_attr_mode.attr,
  284. &dev_attr_reg.attr,
  285. &dev_attr_cmode.attr,
  286. NULL
  287. };
  288. static const struct attribute_group musb_attr_group = {
  289. .attrs = musb_attributes,
  290. };
  291. int ssusb_sysfs_init(struct musb *musb)
  292. {
  293. return sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
  294. }
  295. void ssusb_sysfs_exit(struct musb *musb)
  296. {
  297. sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);
  298. }