usbmisc_imx.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. /*
  2. * Copyright 2012 Freescale Semiconductor, Inc.
  3. *
  4. * The code contained herein is licensed under the GNU General Public
  5. * License. You may obtain a copy of the GNU General Public License
  6. * Version 2 or later at the following locations:
  7. *
  8. * http://www.opensource.org/licenses/gpl-license.html
  9. * http://www.gnu.org/copyleft/gpl.html
  10. */
  11. #include <linux/module.h>
  12. #include <linux/of_platform.h>
  13. #include <linux/clk.h>
  14. #include <linux/err.h>
  15. #include <linux/io.h>
  16. #include <linux/delay.h>
  17. #include "ci_hdrc_imx.h"
  18. #define MX25_USB_PHY_CTRL_OFFSET 0x08
  19. #define MX25_BM_EXTERNAL_VBUS_DIVIDER BIT(23)
  20. #define MX25_EHCI_INTERFACE_SINGLE_UNI (2 << 0)
  21. #define MX25_EHCI_INTERFACE_DIFF_UNI (0 << 0)
  22. #define MX25_EHCI_INTERFACE_MASK (0xf)
  23. #define MX25_OTG_SIC_SHIFT 29
  24. #define MX25_OTG_SIC_MASK (0x3 << MX25_OTG_SIC_SHIFT)
  25. #define MX25_OTG_PM_BIT BIT(24)
  26. #define MX25_OTG_PP_BIT BIT(11)
  27. #define MX25_OTG_OCPOL_BIT BIT(3)
  28. #define MX25_H1_SIC_SHIFT 21
  29. #define MX25_H1_SIC_MASK (0x3 << MX25_H1_SIC_SHIFT)
  30. #define MX25_H1_PP_BIT BIT(18)
  31. #define MX25_H1_PM_BIT BIT(16)
  32. #define MX25_H1_IPPUE_UP_BIT BIT(7)
  33. #define MX25_H1_IPPUE_DOWN_BIT BIT(6)
  34. #define MX25_H1_TLL_BIT BIT(5)
  35. #define MX25_H1_USBTE_BIT BIT(4)
  36. #define MX25_H1_OCPOL_BIT BIT(2)
  37. #define MX27_H1_PM_BIT BIT(8)
  38. #define MX27_H2_PM_BIT BIT(16)
  39. #define MX27_OTG_PM_BIT BIT(24)
  40. #define MX53_USB_OTG_PHY_CTRL_0_OFFSET 0x08
  41. #define MX53_USB_OTG_PHY_CTRL_1_OFFSET 0x0c
  42. #define MX53_USB_UH2_CTRL_OFFSET 0x14
  43. #define MX53_USB_UH3_CTRL_OFFSET 0x18
  44. #define MX53_BM_OVER_CUR_DIS_H1 BIT(5)
  45. #define MX53_BM_OVER_CUR_DIS_OTG BIT(8)
  46. #define MX53_BM_OVER_CUR_DIS_UHx BIT(30)
  47. #define MX53_USB_PHYCTRL1_PLLDIV_MASK 0x3
  48. #define MX53_USB_PLL_DIV_24_MHZ 0x01
  49. #define MX6_BM_OVER_CUR_DIS BIT(7)
  50. struct usbmisc_ops {
  51. /* It's called once when probe a usb device */
  52. int (*init)(struct imx_usbmisc_data *data);
  53. /* It's called once after adding a usb device */
  54. int (*post)(struct imx_usbmisc_data *data);
  55. };
  56. struct imx_usbmisc {
  57. void __iomem *base;
  58. spinlock_t lock;
  59. struct clk *clk;
  60. const struct usbmisc_ops *ops;
  61. };
  62. static struct imx_usbmisc *usbmisc;
  63. static int usbmisc_imx25_init(struct imx_usbmisc_data *data)
  64. {
  65. unsigned long flags;
  66. u32 val = 0;
  67. if (data->index > 1)
  68. return -EINVAL;
  69. spin_lock_irqsave(&usbmisc->lock, flags);
  70. switch (data->index) {
  71. case 0:
  72. val = readl(usbmisc->base);
  73. val &= ~(MX25_OTG_SIC_MASK | MX25_OTG_PP_BIT);
  74. val |= (MX25_EHCI_INTERFACE_DIFF_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_OTG_SIC_SHIFT;
  75. val |= (MX25_OTG_PM_BIT | MX25_OTG_OCPOL_BIT);
  76. writel(val, usbmisc->base);
  77. break;
  78. case 1:
  79. val = readl(usbmisc->base);
  80. val &= ~(MX25_H1_SIC_MASK | MX25_H1_PP_BIT | MX25_H1_IPPUE_UP_BIT);
  81. val |= (MX25_EHCI_INTERFACE_SINGLE_UNI & MX25_EHCI_INTERFACE_MASK) << MX25_H1_SIC_SHIFT;
  82. val |= (MX25_H1_PM_BIT | MX25_H1_OCPOL_BIT | MX25_H1_TLL_BIT |
  83. MX25_H1_USBTE_BIT | MX25_H1_IPPUE_DOWN_BIT);
  84. writel(val, usbmisc->base);
  85. break;
  86. }
  87. spin_unlock_irqrestore(&usbmisc->lock, flags);
  88. return 0;
  89. }
  90. static int usbmisc_imx25_post(struct imx_usbmisc_data *data)
  91. {
  92. void __iomem *reg;
  93. unsigned long flags;
  94. u32 val;
  95. if (data->index > 2)
  96. return -EINVAL;
  97. reg = usbmisc->base + MX25_USB_PHY_CTRL_OFFSET;
  98. if (data->evdo) {
  99. spin_lock_irqsave(&usbmisc->lock, flags);
  100. val = readl(reg);
  101. writel(val | MX25_BM_EXTERNAL_VBUS_DIVIDER, reg);
  102. spin_unlock_irqrestore(&usbmisc->lock, flags);
  103. usleep_range(5000, 10000); /* needed to stabilize voltage */
  104. }
  105. return 0;
  106. }
  107. static int usbmisc_imx27_init(struct imx_usbmisc_data *data)
  108. {
  109. unsigned long flags;
  110. u32 val;
  111. switch (data->index) {
  112. case 0:
  113. val = MX27_OTG_PM_BIT;
  114. break;
  115. case 1:
  116. val = MX27_H1_PM_BIT;
  117. break;
  118. case 2:
  119. val = MX27_H2_PM_BIT;
  120. break;
  121. default:
  122. return -EINVAL;
  123. };
  124. spin_lock_irqsave(&usbmisc->lock, flags);
  125. if (data->disable_oc)
  126. val = readl(usbmisc->base) | val;
  127. else
  128. val = readl(usbmisc->base) & ~val;
  129. writel(val, usbmisc->base);
  130. spin_unlock_irqrestore(&usbmisc->lock, flags);
  131. return 0;
  132. }
  133. static int usbmisc_imx53_init(struct imx_usbmisc_data *data)
  134. {
  135. void __iomem *reg = NULL;
  136. unsigned long flags;
  137. u32 val = 0;
  138. if (data->index > 3)
  139. return -EINVAL;
  140. /* Select a 24 MHz reference clock for the PHY */
  141. reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET;
  142. val = readl(reg);
  143. val &= ~MX53_USB_PHYCTRL1_PLLDIV_MASK;
  144. val |= MX53_USB_PLL_DIV_24_MHZ;
  145. writel(val, usbmisc->base + MX53_USB_OTG_PHY_CTRL_1_OFFSET);
  146. if (data->disable_oc) {
  147. spin_lock_irqsave(&usbmisc->lock, flags);
  148. switch (data->index) {
  149. case 0:
  150. reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
  151. val = readl(reg) | MX53_BM_OVER_CUR_DIS_OTG;
  152. break;
  153. case 1:
  154. reg = usbmisc->base + MX53_USB_OTG_PHY_CTRL_0_OFFSET;
  155. val = readl(reg) | MX53_BM_OVER_CUR_DIS_H1;
  156. break;
  157. case 2:
  158. reg = usbmisc->base + MX53_USB_UH2_CTRL_OFFSET;
  159. val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
  160. break;
  161. case 3:
  162. reg = usbmisc->base + MX53_USB_UH3_CTRL_OFFSET;
  163. val = readl(reg) | MX53_BM_OVER_CUR_DIS_UHx;
  164. break;
  165. }
  166. if (reg && val)
  167. writel(val, reg);
  168. spin_unlock_irqrestore(&usbmisc->lock, flags);
  169. }
  170. return 0;
  171. }
  172. static int usbmisc_imx6q_init(struct imx_usbmisc_data *data)
  173. {
  174. unsigned long flags;
  175. u32 reg;
  176. if (data->index > 3)
  177. return -EINVAL;
  178. if (data->disable_oc) {
  179. spin_lock_irqsave(&usbmisc->lock, flags);
  180. reg = readl(usbmisc->base + data->index * 4);
  181. writel(reg | MX6_BM_OVER_CUR_DIS,
  182. usbmisc->base + data->index * 4);
  183. spin_unlock_irqrestore(&usbmisc->lock, flags);
  184. }
  185. return 0;
  186. }
  187. static const struct usbmisc_ops imx25_usbmisc_ops = {
  188. .init = usbmisc_imx25_init,
  189. .post = usbmisc_imx25_post,
  190. };
  191. static const struct usbmisc_ops imx27_usbmisc_ops = {
  192. .init = usbmisc_imx27_init,
  193. };
  194. static const struct usbmisc_ops imx53_usbmisc_ops = {
  195. .init = usbmisc_imx53_init,
  196. };
  197. static const struct usbmisc_ops imx6q_usbmisc_ops = {
  198. .init = usbmisc_imx6q_init,
  199. };
  200. int imx_usbmisc_init(struct imx_usbmisc_data *data)
  201. {
  202. if (!usbmisc)
  203. return -EPROBE_DEFER;
  204. if (!usbmisc->ops->init)
  205. return 0;
  206. return usbmisc->ops->init(data);
  207. }
  208. EXPORT_SYMBOL_GPL(imx_usbmisc_init);
  209. int imx_usbmisc_init_post(struct imx_usbmisc_data *data)
  210. {
  211. if (!usbmisc)
  212. return -EPROBE_DEFER;
  213. if (!usbmisc->ops->post)
  214. return 0;
  215. return usbmisc->ops->post(data);
  216. }
  217. EXPORT_SYMBOL_GPL(imx_usbmisc_init_post);
  218. static const struct of_device_id usbmisc_imx_dt_ids[] = {
  219. {
  220. .compatible = "fsl,imx25-usbmisc",
  221. .data = &imx25_usbmisc_ops,
  222. },
  223. {
  224. .compatible = "fsl,imx35-usbmisc",
  225. .data = &imx25_usbmisc_ops,
  226. },
  227. {
  228. .compatible = "fsl,imx27-usbmisc",
  229. .data = &imx27_usbmisc_ops,
  230. },
  231. {
  232. .compatible = "fsl,imx51-usbmisc",
  233. .data = &imx53_usbmisc_ops,
  234. },
  235. {
  236. .compatible = "fsl,imx53-usbmisc",
  237. .data = &imx53_usbmisc_ops,
  238. },
  239. {
  240. .compatible = "fsl,imx6q-usbmisc",
  241. .data = &imx6q_usbmisc_ops,
  242. },
  243. { /* sentinel */ }
  244. };
  245. MODULE_DEVICE_TABLE(of, usbmisc_imx_dt_ids);
  246. static int usbmisc_imx_probe(struct platform_device *pdev)
  247. {
  248. struct resource *res;
  249. struct imx_usbmisc *data;
  250. int ret;
  251. struct of_device_id *tmp_dev;
  252. if (usbmisc)
  253. return -EBUSY;
  254. data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
  255. if (!data)
  256. return -ENOMEM;
  257. spin_lock_init(&data->lock);
  258. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  259. data->base = devm_ioremap_resource(&pdev->dev, res);
  260. if (IS_ERR(data->base))
  261. return PTR_ERR(data->base);
  262. data->clk = devm_clk_get(&pdev->dev, NULL);
  263. if (IS_ERR(data->clk)) {
  264. dev_err(&pdev->dev,
  265. "failed to get clock, err=%ld\n", PTR_ERR(data->clk));
  266. return PTR_ERR(data->clk);
  267. }
  268. ret = clk_prepare_enable(data->clk);
  269. if (ret) {
  270. dev_err(&pdev->dev,
  271. "clk_prepare_enable failed, err=%d\n", ret);
  272. return ret;
  273. }
  274. tmp_dev = (struct of_device_id *)
  275. of_match_device(usbmisc_imx_dt_ids, &pdev->dev);
  276. data->ops = (const struct usbmisc_ops *)tmp_dev->data;
  277. usbmisc = data;
  278. return 0;
  279. }
  280. static int usbmisc_imx_remove(struct platform_device *pdev)
  281. {
  282. clk_disable_unprepare(usbmisc->clk);
  283. usbmisc = NULL;
  284. return 0;
  285. }
  286. static struct platform_driver usbmisc_imx_driver = {
  287. .probe = usbmisc_imx_probe,
  288. .remove = usbmisc_imx_remove,
  289. .driver = {
  290. .name = "usbmisc_imx",
  291. .owner = THIS_MODULE,
  292. .of_match_table = usbmisc_imx_dt_ids,
  293. },
  294. };
  295. module_platform_driver(usbmisc_imx_driver);
  296. MODULE_ALIAS("platform:usbmisc-imx");
  297. MODULE_LICENSE("GPL v2");
  298. MODULE_DESCRIPTION("driver for imx usb non-core registers");
  299. MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");