phy-samsung-usb.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. /* linux/drivers/usb/phy/phy-samsung-usb.c
  2. *
  3. * Copyright (c) 2012 Samsung Electronics Co., Ltd.
  4. * http://www.samsung.com
  5. *
  6. * Author: Praveen Paneri <p.paneri@samsung.com>
  7. *
  8. * Samsung USB-PHY helper driver with common function calls;
  9. * interacts with Samsung USB 2.0 PHY controller driver and later
  10. * with Samsung USB 3.0 PHY driver.
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License version 2 as
  14. * published by the Free Software Foundation.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. */
  21. #include <linux/module.h>
  22. #include <linux/platform_device.h>
  23. #include <linux/clk.h>
  24. #include <linux/device.h>
  25. #include <linux/err.h>
  26. #include <linux/io.h>
  27. #include <linux/of.h>
  28. #include <linux/of_address.h>
  29. #include <linux/usb/samsung_usb_phy.h>
  30. #include "phy-samsung-usb.h"
  31. int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy)
  32. {
  33. struct device_node *usbphy_sys;
  34. /* Getting node for system controller interface for usb-phy */
  35. usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys");
  36. if (!usbphy_sys) {
  37. dev_err(sphy->dev, "No sys-controller interface for usb-phy\n");
  38. return -ENODEV;
  39. }
  40. sphy->pmuregs = of_iomap(usbphy_sys, 0);
  41. if (sphy->pmuregs == NULL) {
  42. dev_err(sphy->dev, "Can't get usb-phy pmu control register\n");
  43. goto err0;
  44. }
  45. sphy->sysreg = of_iomap(usbphy_sys, 1);
  46. /*
  47. * Not returning error code here, since this situation is not fatal.
  48. * Few SoCs may not have this switch available
  49. */
  50. if (sphy->sysreg == NULL)
  51. dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n");
  52. of_node_put(usbphy_sys);
  53. return 0;
  54. err0:
  55. of_node_put(usbphy_sys);
  56. return -ENXIO;
  57. }
  58. EXPORT_SYMBOL_GPL(samsung_usbphy_parse_dt);
  59. /*
  60. * Set isolation here for phy.
  61. * Here 'on = true' would mean USB PHY block is isolated, hence
  62. * de-activated and vice-versa.
  63. */
  64. void samsung_usbphy_set_isolation_4210(struct samsung_usbphy *sphy, bool on)
  65. {
  66. void __iomem *reg = NULL;
  67. u32 reg_val;
  68. u32 en_mask = 0;
  69. if (!sphy->pmuregs) {
  70. dev_warn(sphy->dev, "Can't set pmu isolation\n");
  71. return;
  72. }
  73. if (sphy->phy_type == USB_PHY_TYPE_DEVICE) {
  74. reg = sphy->pmuregs + sphy->drv_data->devphy_reg_offset;
  75. en_mask = sphy->drv_data->devphy_en_mask;
  76. } else if (sphy->phy_type == USB_PHY_TYPE_HOST) {
  77. reg = sphy->pmuregs + sphy->drv_data->hostphy_reg_offset;
  78. en_mask = sphy->drv_data->hostphy_en_mask;
  79. }
  80. reg_val = readl(reg);
  81. if (on)
  82. reg_val &= ~en_mask;
  83. else
  84. reg_val |= en_mask;
  85. writel(reg_val, reg);
  86. if (sphy->drv_data->cpu_type == TYPE_EXYNOS4X12) {
  87. writel(reg_val, sphy->pmuregs + EXYNOS4X12_PHY_HSIC_CTRL0);
  88. writel(reg_val, sphy->pmuregs + EXYNOS4X12_PHY_HSIC_CTRL1);
  89. }
  90. }
  91. EXPORT_SYMBOL_GPL(samsung_usbphy_set_isolation_4210);
  92. /*
  93. * Configure the mode of working of usb-phy here: HOST/DEVICE.
  94. */
  95. void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy)
  96. {
  97. u32 reg;
  98. if (!sphy->sysreg) {
  99. dev_warn(sphy->dev, "Can't configure specified phy mode\n");
  100. return;
  101. }
  102. reg = readl(sphy->sysreg);
  103. if (sphy->phy_type == USB_PHY_TYPE_DEVICE)
  104. reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK;
  105. else if (sphy->phy_type == USB_PHY_TYPE_HOST)
  106. reg |= EXYNOS_USB20PHY_CFG_HOST_LINK;
  107. writel(reg, sphy->sysreg);
  108. }
  109. EXPORT_SYMBOL_GPL(samsung_usbphy_cfg_sel);
  110. /*
  111. * PHYs are different for USB Device and USB Host.
  112. * This make sure that correct PHY type is selected before
  113. * any operation on PHY.
  114. */
  115. int samsung_usbphy_set_type(struct usb_phy *phy,
  116. enum samsung_usb_phy_type phy_type)
  117. {
  118. struct samsung_usbphy *sphy = phy_to_sphy(phy);
  119. sphy->phy_type = phy_type;
  120. return 0;
  121. }
  122. EXPORT_SYMBOL_GPL(samsung_usbphy_set_type);
  123. int samsung_usbphy_rate_to_clksel_64xx(struct samsung_usbphy *sphy,
  124. unsigned long rate)
  125. {
  126. unsigned int clksel;
  127. switch (rate) {
  128. case 12 * MHZ:
  129. clksel = PHYCLK_CLKSEL_12M;
  130. break;
  131. case 24 * MHZ:
  132. clksel = PHYCLK_CLKSEL_24M;
  133. break;
  134. case 48 * MHZ:
  135. clksel = PHYCLK_CLKSEL_48M;
  136. break;
  137. default:
  138. dev_err(sphy->dev,
  139. "Invalid reference clock frequency: %lu\n", rate);
  140. return -EINVAL;
  141. }
  142. return clksel;
  143. }
  144. EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_64xx);
  145. int samsung_usbphy_rate_to_clksel_4x12(struct samsung_usbphy *sphy,
  146. unsigned long rate)
  147. {
  148. unsigned int clksel;
  149. switch (rate) {
  150. case 9600 * KHZ:
  151. clksel = FSEL_CLKSEL_9600K;
  152. break;
  153. case 10 * MHZ:
  154. clksel = FSEL_CLKSEL_10M;
  155. break;
  156. case 12 * MHZ:
  157. clksel = FSEL_CLKSEL_12M;
  158. break;
  159. case 19200 * KHZ:
  160. clksel = FSEL_CLKSEL_19200K;
  161. break;
  162. case 20 * MHZ:
  163. clksel = FSEL_CLKSEL_20M;
  164. break;
  165. case 24 * MHZ:
  166. clksel = FSEL_CLKSEL_24M;
  167. break;
  168. case 50 * MHZ:
  169. clksel = FSEL_CLKSEL_50M;
  170. break;
  171. default:
  172. dev_err(sphy->dev,
  173. "Invalid reference clock frequency: %lu\n", rate);
  174. return -EINVAL;
  175. }
  176. return clksel;
  177. }
  178. EXPORT_SYMBOL_GPL(samsung_usbphy_rate_to_clksel_4x12);
  179. /*
  180. * Returns reference clock frequency selection value
  181. */
  182. int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy)
  183. {
  184. struct clk *ref_clk;
  185. unsigned long rate;
  186. int refclk_freq;
  187. /*
  188. * In exynos5250 USB host and device PHY use
  189. * external crystal clock XXTI
  190. */
  191. if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250)
  192. ref_clk = clk_get(sphy->dev, "ext_xtal");
  193. else
  194. ref_clk = clk_get(sphy->dev, "xusbxti");
  195. if (IS_ERR(ref_clk)) {
  196. dev_err(sphy->dev, "Failed to get reference clock\n");
  197. return PTR_ERR(ref_clk);
  198. }
  199. rate = clk_get_rate(ref_clk);
  200. refclk_freq = sphy->drv_data->rate_to_clksel(sphy, rate);
  201. clk_put(ref_clk);
  202. return refclk_freq;
  203. }
  204. EXPORT_SYMBOL_GPL(samsung_usbphy_get_refclk_freq);