1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | // |
3 | // Copyright (C) 2011 Samsung Electronics Co.Ltd |
4 | // Author: Joonyoung Shim <jy0922.shim@samsung.com> |
5 | |
6 | #include <linux/clk.h> |
7 | #include <linux/delay.h> |
8 | #include <linux/err.h> |
9 | #include <linux/io.h> |
10 | #include <linux/platform_device.h> |
11 | #include "map.h" |
12 | #include "cpu.h" |
13 | #include "usb-phy.h" |
14 | |
15 | #include "regs-sys-s3c64xx.h" |
16 | #include "regs-usb-hsotg-phy-s3c64xx.h" |
17 | |
18 | enum samsung_usb_phy_type { |
19 | USB_PHY_TYPE_DEVICE, |
20 | USB_PHY_TYPE_HOST, |
21 | }; |
22 | |
23 | static int s3c_usb_otgphy_init(struct platform_device *pdev) |
24 | { |
25 | struct clk *xusbxti; |
26 | u32 phyclk; |
27 | |
28 | writel(readl(S3C64XX_OTHERS) | S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS); |
29 | |
30 | /* set clock frequency for PLL */ |
31 | phyclk = readl(S3C_PHYCLK) & ~S3C_PHYCLK_CLKSEL_MASK; |
32 | |
33 | xusbxti = clk_get(dev: &pdev->dev, id: "xusbxti" ); |
34 | if (!IS_ERR(ptr: xusbxti)) { |
35 | switch (clk_get_rate(clk: xusbxti)) { |
36 | case 12 * MHZ: |
37 | phyclk |= S3C_PHYCLK_CLKSEL_12M; |
38 | break; |
39 | case 24 * MHZ: |
40 | phyclk |= S3C_PHYCLK_CLKSEL_24M; |
41 | break; |
42 | default: |
43 | case 48 * MHZ: |
44 | /* default reference clock */ |
45 | break; |
46 | } |
47 | clk_put(clk: xusbxti); |
48 | } |
49 | |
50 | /* TODO: select external clock/oscillator */ |
51 | writel(val: phyclk | S3C_PHYCLK_CLK_FORCE, S3C_PHYCLK); |
52 | |
53 | /* set to normal OTG PHY */ |
54 | writel(val: (readl(S3C_PHYPWR) & ~S3C_PHYPWR_NORMAL_MASK), S3C_PHYPWR); |
55 | mdelay(1); |
56 | |
57 | /* reset OTG PHY and Link */ |
58 | writel(S3C_RSTCON_PHY | S3C_RSTCON_HCLK | S3C_RSTCON_PHYCLK, |
59 | S3C_RSTCON); |
60 | udelay(20); /* at-least 10uS */ |
61 | writel(val: 0, S3C_RSTCON); |
62 | |
63 | return 0; |
64 | } |
65 | |
66 | static int s3c_usb_otgphy_exit(struct platform_device *pdev) |
67 | { |
68 | writel(val: (readl(S3C_PHYPWR) | S3C_PHYPWR_ANALOG_POWERDOWN | |
69 | S3C_PHYPWR_OTG_DISABLE), S3C_PHYPWR); |
70 | |
71 | writel(readl(S3C64XX_OTHERS) & ~S3C64XX_OTHERS_USBMASK, S3C64XX_OTHERS); |
72 | |
73 | return 0; |
74 | } |
75 | |
76 | int s3c_usb_phy_init(struct platform_device *pdev, int type) |
77 | { |
78 | if (type == USB_PHY_TYPE_DEVICE) |
79 | return s3c_usb_otgphy_init(pdev); |
80 | |
81 | return -EINVAL; |
82 | } |
83 | |
84 | int s3c_usb_phy_exit(struct platform_device *pdev, int type) |
85 | { |
86 | if (type == USB_PHY_TYPE_DEVICE) |
87 | return s3c_usb_otgphy_exit(pdev); |
88 | |
89 | return -EINVAL; |
90 | } |
91 | |