diff options
26 files changed, 2449 insertions, 158 deletions
diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt new file mode 100644 index 000000000000..7a95c651ceb3 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/dwc3.txt | |||
@@ -0,0 +1,22 @@ | |||
1 | synopsys DWC3 CORE | ||
2 | |||
3 | DWC3- USB3 CONTROLLER | ||
4 | |||
5 | Required properties: | ||
6 | - compatible: must be "synopsys,dwc3" | ||
7 | - reg : Address and length of the register set for the device | ||
8 | - interrupts: Interrupts used by the dwc3 controller. | ||
9 | - usb-phy : array of phandle for the PHY device | ||
10 | |||
11 | Optional properties: | ||
12 | - tx-fifo-resize: determines if the FIFO *has* to be reallocated. | ||
13 | |||
14 | This is usually a subnode to DWC3 glue to which it is connected. | ||
15 | |||
16 | dwc3@4a030000 { | ||
17 | compatible = "synopsys,dwc3"; | ||
18 | reg = <0x4a030000 0xcfff>; | ||
19 | interrupts = <0 92 4> | ||
20 | usb-phy = <&usb2_phy>, <&usb3,phy>; | ||
21 | tx-fifo-resize; | ||
22 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 29a043ecda52..1ef0ce71f8fa 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt | |||
@@ -1,8 +1,11 @@ | |||
1 | OMAP GLUE | 1 | OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS |
2 | 2 | ||
3 | OMAP MUSB GLUE | 3 | OMAP MUSB GLUE |
4 | - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" | 4 | - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" |
5 | - ti,hwmods : must be "usb_otg_hs" | 5 | - ti,hwmods : must be "usb_otg_hs" |
6 | - ti,has-mailbox : to specify that omap uses an external mailbox | ||
7 | (in control module) to communicate with the musb core during device connect | ||
8 | and disconnect. | ||
6 | - multipoint : Should be "1" indicating the musb controller supports | 9 | - multipoint : Should be "1" indicating the musb controller supports |
7 | multipoint. This is a MUSB configuration-specific setting. | 10 | multipoint. This is a MUSB configuration-specific setting. |
8 | - num_eps : Specifies the number of endpoints. This is also a | 11 | - num_eps : Specifies the number of endpoints. This is also a |
@@ -16,13 +19,19 @@ OMAP MUSB GLUE | |||
16 | - power : Should be "50". This signifies the controller can supply upto | 19 | - power : Should be "50". This signifies the controller can supply upto |
17 | 100mA when operating in host mode. | 20 | 100mA when operating in host mode. |
18 | 21 | ||
22 | Optional properties: | ||
23 | - ctrl-module : phandle of the control module this glue uses to write to | ||
24 | mailbox | ||
25 | |||
19 | SOC specific device node entry | 26 | SOC specific device node entry |
20 | usb_otg_hs: usb_otg_hs@4a0ab000 { | 27 | usb_otg_hs: usb_otg_hs@4a0ab000 { |
21 | compatible = "ti,omap4-musb"; | 28 | compatible = "ti,omap4-musb"; |
22 | ti,hwmods = "usb_otg_hs"; | 29 | ti,hwmods = "usb_otg_hs"; |
30 | ti,has-mailbox; | ||
23 | multipoint = <1>; | 31 | multipoint = <1>; |
24 | num_eps = <16>; | 32 | num_eps = <16>; |
25 | ram_bits = <12>; | 33 | ram_bits = <12>; |
34 | ctrl-module = <&omap_control_usb>; | ||
26 | }; | 35 | }; |
27 | 36 | ||
28 | Board specific device node entry | 37 | Board specific device node entry |
@@ -31,3 +40,26 @@ Board specific device node entry | |||
31 | mode = <3>; | 40 | mode = <3>; |
32 | power = <50>; | 41 | power = <50>; |
33 | }; | 42 | }; |
43 | |||
44 | OMAP CONTROL USB | ||
45 | |||
46 | Required properties: | ||
47 | - compatible: Should be "ti,omap-control-usb" | ||
48 | - reg : Address and length of the register set for the device. It contains | ||
49 | the address of "control_dev_conf" and "otghs_control" or "phy_power_usb" | ||
50 | depending upon omap4 or omap5. | ||
51 | - reg-names: The names of the register addresses corresponding to the registers | ||
52 | filled in "reg". | ||
53 | - ti,type: This is used to differentiate whether the control module has | ||
54 | usb mailbox or usb3 phy power. omap4 has usb mailbox in control module to | ||
55 | notify events to the musb core and omap5 has usb3 phy power register to | ||
56 | power on usb3 phy. Should be "1" if it has mailbox and "2" if it has usb3 | ||
57 | phy power. | ||
58 | |||
59 | omap_control_usb: omap-control-usb@4a002300 { | ||
60 | compatible = "ti,omap-control-usb"; | ||
61 | reg = <0x4a002300 0x4>, | ||
62 | <0x4a00233c 0x4>; | ||
63 | reg-names = "control_dev_conf", "otghs_control"; | ||
64 | ti,type = <1>; | ||
65 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/samsung-usbphy.txt b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt new file mode 100644 index 000000000000..033194934f64 --- /dev/null +++ b/Documentation/devicetree/bindings/usb/samsung-usbphy.txt | |||
@@ -0,0 +1,55 @@ | |||
1 | * Samsung's usb phy transceiver | ||
2 | |||
3 | The Samsung's phy transceiver is used for controlling usb phy for | ||
4 | s3c-hsotg as well as ehci-s5p and ohci-exynos usb controllers | ||
5 | across Samsung SOCs. | ||
6 | TODO: Adding the PHY binding with controller(s) according to the under | ||
7 | developement generic PHY driver. | ||
8 | |||
9 | Required properties: | ||
10 | |||
11 | Exynos4210: | ||
12 | - compatible : should be "samsung,exynos4210-usbphy" | ||
13 | - reg : base physical address of the phy registers and length of memory mapped | ||
14 | region. | ||
15 | |||
16 | Exynos5250: | ||
17 | - compatible : should be "samsung,exynos5250-usbphy" | ||
18 | - reg : base physical address of the phy registers and length of memory mapped | ||
19 | region. | ||
20 | |||
21 | Optional properties: | ||
22 | - #address-cells: should be '1' when usbphy node has a child node with 'reg' | ||
23 | property. | ||
24 | - #size-cells: should be '1' when usbphy node has a child node with 'reg' | ||
25 | property. | ||
26 | - ranges: allows valid translation between child's address space and parent's | ||
27 | address space. | ||
28 | |||
29 | - The child node 'usbphy-sys' to the node 'usbphy' is for the system controller | ||
30 | interface for usb-phy. It should provide the following information required by | ||
31 | usb-phy controller to control phy. | ||
32 | - reg : base physical address of PHY_CONTROL registers. | ||
33 | The size of this register is the total sum of size of all PHY_CONTROL | ||
34 | registers that the SoC has. For example, the size will be | ||
35 | '0x4' in case we have only one PHY_CONTROL register (e.g. | ||
36 | OTHERS register in S3C64XX or USB_PHY_CONTROL register in S5PV210) | ||
37 | and, '0x8' in case we have two PHY_CONTROL registers (e.g. | ||
38 | USBDEVICE_PHY_CONTROL and USBHOST_PHY_CONTROL registers in exynos4x). | ||
39 | and so on. | ||
40 | |||
41 | Example: | ||
42 | - Exynos4210 | ||
43 | |||
44 | usbphy@125B0000 { | ||
45 | #address-cells = <1>; | ||
46 | #size-cells = <1>; | ||
47 | compatible = "samsung,exynos4210-usbphy"; | ||
48 | reg = <0x125B0000 0x100>; | ||
49 | ranges; | ||
50 | |||
51 | usbphy-sys { | ||
52 | /* USB device and host PHY_CONTROL registers */ | ||
53 | reg = <0x10020704 0x8>; | ||
54 | }; | ||
55 | }; | ||
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt index 80d4148cb661..61496f5cb095 100644 --- a/Documentation/devicetree/bindings/usb/usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/usb-phy.txt | |||
@@ -4,14 +4,39 @@ OMAP USB2 PHY | |||
4 | 4 | ||
5 | Required properties: | 5 | Required properties: |
6 | - compatible: Should be "ti,omap-usb2" | 6 | - compatible: Should be "ti,omap-usb2" |
7 | - reg : Address and length of the register set for the device. Also | 7 | - reg : Address and length of the register set for the device. |
8 | add the address of control module dev conf register until a driver for | 8 | |
9 | control module is added | 9 | Optional properties: |
10 | - ctrl-module : phandle of the control module used by PHY driver to power on | ||
11 | the PHY. | ||
10 | 12 | ||
11 | This is usually a subnode of ocp2scp to which it is connected. | 13 | This is usually a subnode of ocp2scp to which it is connected. |
12 | 14 | ||
13 | usb2phy@4a0ad080 { | 15 | usb2phy@4a0ad080 { |
14 | compatible = "ti,omap-usb2"; | 16 | compatible = "ti,omap-usb2"; |
15 | reg = <0x4a0ad080 0x58>, | 17 | reg = <0x4a0ad080 0x58>; |
16 | <0x4a002300 0x4>; | 18 | ctrl-module = <&omap_control_usb>; |
19 | }; | ||
20 | |||
21 | OMAP USB3 PHY | ||
22 | |||
23 | Required properties: | ||
24 | - compatible: Should be "ti,omap-usb3" | ||
25 | - reg : Address and length of the register set for the device. | ||
26 | - reg-names: The names of the register addresses corresponding to the registers | ||
27 | filled in "reg". | ||
28 | |||
29 | Optional properties: | ||
30 | - ctrl-module : phandle of the control module used by PHY driver to power on | ||
31 | the PHY. | ||
32 | |||
33 | This is usually a subnode of ocp2scp to which it is connected. | ||
34 | |||
35 | usb3phy@4a084400 { | ||
36 | compatible = "ti,omap-usb3"; | ||
37 | reg = <0x4a084400 0x80>, | ||
38 | <0x4a084800 0x64>, | ||
39 | <0x4a084c00 0x40>; | ||
40 | reg-names = "phy_rx", "phy_tx", "pll_ctrl"; | ||
41 | ctrl-module = <&omap_control_usb>; | ||
17 | }; | 42 | }; |
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 177f4c61acab..999909451e37 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c | |||
@@ -420,13 +420,19 @@ static int dwc3_probe(struct platform_device *pdev) | |||
420 | return -ENOMEM; | 420 | return -ENOMEM; |
421 | } | 421 | } |
422 | 422 | ||
423 | dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); | 423 | if (node) { |
424 | dwc->usb2_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 0); | ||
425 | dwc->usb3_phy = devm_usb_get_phy_by_phandle(dev, "usb-phy", 1); | ||
426 | } else { | ||
427 | dwc->usb2_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); | ||
428 | dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); | ||
429 | } | ||
430 | |||
424 | if (IS_ERR_OR_NULL(dwc->usb2_phy)) { | 431 | if (IS_ERR_OR_NULL(dwc->usb2_phy)) { |
425 | dev_err(dev, "no usb2 phy configured\n"); | 432 | dev_err(dev, "no usb2 phy configured\n"); |
426 | return -EPROBE_DEFER; | 433 | return -EPROBE_DEFER; |
427 | } | 434 | } |
428 | 435 | ||
429 | dwc->usb3_phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB3); | ||
430 | if (IS_ERR_OR_NULL(dwc->usb3_phy)) { | 436 | if (IS_ERR_OR_NULL(dwc->usb3_phy)) { |
431 | dev_err(dev, "no usb3 phy configured\n"); | 437 | dev_err(dev, "no usb3 phy configured\n"); |
432 | return -EPROBE_DEFER; | 438 | return -EPROBE_DEFER; |
@@ -453,8 +459,7 @@ static int dwc3_probe(struct platform_device *pdev) | |||
453 | else | 459 | else |
454 | dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; | 460 | dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; |
455 | 461 | ||
456 | if (of_get_property(node, "tx-fifo-resize", NULL)) | 462 | dwc->needs_fifo_resize = of_property_read_bool(node, "tx-fifo-resize"); |
457 | dwc->needs_fifo_resize = true; | ||
458 | 463 | ||
459 | pm_runtime_enable(dev); | 464 | pm_runtime_enable(dev); |
460 | pm_runtime_get_sync(dev); | 465 | pm_runtime_get_sync(dev); |
@@ -583,11 +588,22 @@ static int dwc3_remove(struct platform_device *pdev) | |||
583 | return 0; | 588 | return 0; |
584 | } | 589 | } |
585 | 590 | ||
591 | #ifdef CONFIG_OF | ||
592 | static const struct of_device_id of_dwc3_match[] = { | ||
593 | { | ||
594 | .compatible = "synopsys,dwc3" | ||
595 | }, | ||
596 | { }, | ||
597 | }; | ||
598 | MODULE_DEVICE_TABLE(of, of_dwc3_match); | ||
599 | #endif | ||
600 | |||
586 | static struct platform_driver dwc3_driver = { | 601 | static struct platform_driver dwc3_driver = { |
587 | .probe = dwc3_probe, | 602 | .probe = dwc3_probe, |
588 | .remove = dwc3_remove, | 603 | .remove = dwc3_remove, |
589 | .driver = { | 604 | .driver = { |
590 | .name = "dwc3", | 605 | .name = "dwc3", |
606 | .of_match_table = of_match_ptr(of_dwc3_match), | ||
591 | }, | 607 | }, |
592 | }; | 608 | }; |
593 | 609 | ||
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index e1cd0f1adfb9..e97df1d094dd 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c | |||
@@ -32,6 +32,7 @@ | |||
32 | 32 | ||
33 | #include <linux/usb/ch9.h> | 33 | #include <linux/usb/ch9.h> |
34 | #include <linux/usb/gadget.h> | 34 | #include <linux/usb/gadget.h> |
35 | #include <linux/usb/phy.h> | ||
35 | #include <linux/platform_data/s3c-hsotg.h> | 36 | #include <linux/platform_data/s3c-hsotg.h> |
36 | 37 | ||
37 | #include <mach/map.h> | 38 | #include <mach/map.h> |
@@ -133,7 +134,9 @@ struct s3c_hsotg_ep { | |||
133 | * struct s3c_hsotg - driver state. | 134 | * struct s3c_hsotg - driver state. |
134 | * @dev: The parent device supplied to the probe function | 135 | * @dev: The parent device supplied to the probe function |
135 | * @driver: USB gadget driver | 136 | * @driver: USB gadget driver |
136 | * @plat: The platform specific configuration data. | 137 | * @phy: The otg phy transceiver structure for phy control. |
138 | * @plat: The platform specific configuration data. This can be removed once | ||
139 | * all SoCs support usb transceiver. | ||
137 | * @regs: The memory area mapped for accessing registers. | 140 | * @regs: The memory area mapped for accessing registers. |
138 | * @irq: The IRQ number we are using | 141 | * @irq: The IRQ number we are using |
139 | * @supplies: Definition of USB power supplies | 142 | * @supplies: Definition of USB power supplies |
@@ -153,6 +156,7 @@ struct s3c_hsotg_ep { | |||
153 | struct s3c_hsotg { | 156 | struct s3c_hsotg { |
154 | struct device *dev; | 157 | struct device *dev; |
155 | struct usb_gadget_driver *driver; | 158 | struct usb_gadget_driver *driver; |
159 | struct usb_phy *phy; | ||
156 | struct s3c_hsotg_plat *plat; | 160 | struct s3c_hsotg_plat *plat; |
157 | 161 | ||
158 | spinlock_t lock; | 162 | spinlock_t lock; |
@@ -2854,7 +2858,10 @@ static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) | |||
2854 | struct platform_device *pdev = to_platform_device(hsotg->dev); | 2858 | struct platform_device *pdev = to_platform_device(hsotg->dev); |
2855 | 2859 | ||
2856 | dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); | 2860 | dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); |
2857 | if (hsotg->plat->phy_init) | 2861 | |
2862 | if (hsotg->phy) | ||
2863 | usb_phy_init(hsotg->phy); | ||
2864 | else if (hsotg->plat->phy_init) | ||
2858 | hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); | 2865 | hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); |
2859 | } | 2866 | } |
2860 | 2867 | ||
@@ -2869,7 +2876,9 @@ static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) | |||
2869 | { | 2876 | { |
2870 | struct platform_device *pdev = to_platform_device(hsotg->dev); | 2877 | struct platform_device *pdev = to_platform_device(hsotg->dev); |
2871 | 2878 | ||
2872 | if (hsotg->plat->phy_exit) | 2879 | if (hsotg->phy) |
2880 | usb_phy_shutdown(hsotg->phy); | ||
2881 | else if (hsotg->plat->phy_exit) | ||
2873 | hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); | 2882 | hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); |
2874 | } | 2883 | } |
2875 | 2884 | ||
@@ -3492,6 +3501,7 @@ static void s3c_hsotg_release(struct device *dev) | |||
3492 | static int s3c_hsotg_probe(struct platform_device *pdev) | 3501 | static int s3c_hsotg_probe(struct platform_device *pdev) |
3493 | { | 3502 | { |
3494 | struct s3c_hsotg_plat *plat = pdev->dev.platform_data; | 3503 | struct s3c_hsotg_plat *plat = pdev->dev.platform_data; |
3504 | struct usb_phy *phy; | ||
3495 | struct device *dev = &pdev->dev; | 3505 | struct device *dev = &pdev->dev; |
3496 | struct s3c_hsotg_ep *eps; | 3506 | struct s3c_hsotg_ep *eps; |
3497 | struct s3c_hsotg *hsotg; | 3507 | struct s3c_hsotg *hsotg; |
@@ -3500,20 +3510,27 @@ static int s3c_hsotg_probe(struct platform_device *pdev) | |||
3500 | int ret; | 3510 | int ret; |
3501 | int i; | 3511 | int i; |
3502 | 3512 | ||
3503 | plat = pdev->dev.platform_data; | ||
3504 | if (!plat) { | ||
3505 | dev_err(&pdev->dev, "no platform data defined\n"); | ||
3506 | return -EINVAL; | ||
3507 | } | ||
3508 | |||
3509 | hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); | 3513 | hsotg = devm_kzalloc(&pdev->dev, sizeof(struct s3c_hsotg), GFP_KERNEL); |
3510 | if (!hsotg) { | 3514 | if (!hsotg) { |
3511 | dev_err(dev, "cannot get memory\n"); | 3515 | dev_err(dev, "cannot get memory\n"); |
3512 | return -ENOMEM; | 3516 | return -ENOMEM; |
3513 | } | 3517 | } |
3514 | 3518 | ||
3519 | phy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); | ||
3520 | if (IS_ERR_OR_NULL(phy)) { | ||
3521 | /* Fallback for pdata */ | ||
3522 | plat = pdev->dev.platform_data; | ||
3523 | if (!plat) { | ||
3524 | dev_err(&pdev->dev, "no platform data or transceiver defined\n"); | ||
3525 | return -EPROBE_DEFER; | ||
3526 | } else { | ||
3527 | hsotg->plat = plat; | ||
3528 | } | ||
3529 | } else { | ||
3530 | hsotg->phy = phy; | ||
3531 | } | ||
3532 | |||
3515 | hsotg->dev = dev; | 3533 | hsotg->dev = dev; |
3516 | hsotg->plat = plat; | ||
3517 | 3534 | ||
3518 | hsotg->clk = devm_clk_get(&pdev->dev, "otg"); | 3535 | hsotg->clk = devm_clk_get(&pdev->dev, "otg"); |
3519 | if (IS_ERR(hsotg->clk)) { | 3536 | if (IS_ERR(hsotg->clk)) { |
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index f18e6ac081aa..20ebf6a8b7f4 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c | |||
@@ -17,6 +17,8 @@ | |||
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/of_gpio.h> | 18 | #include <linux/of_gpio.h> |
19 | #include <linux/platform_data/usb-ehci-s5p.h> | 19 | #include <linux/platform_data/usb-ehci-s5p.h> |
20 | #include <linux/usb/phy.h> | ||
21 | #include <linux/usb/samsung_usb_phy.h> | ||
20 | #include <plat/usb-phy.h> | 22 | #include <plat/usb-phy.h> |
21 | 23 | ||
22 | #define EHCI_INSNREG00(base) (base + 0x90) | 24 | #define EHCI_INSNREG00(base) (base + 0x90) |
@@ -32,6 +34,9 @@ struct s5p_ehci_hcd { | |||
32 | struct device *dev; | 34 | struct device *dev; |
33 | struct usb_hcd *hcd; | 35 | struct usb_hcd *hcd; |
34 | struct clk *clk; | 36 | struct clk *clk; |
37 | struct usb_phy *phy; | ||
38 | struct usb_otg *otg; | ||
39 | struct s5p_ehci_platdata *pdata; | ||
35 | }; | 40 | }; |
36 | 41 | ||
37 | static const struct hc_driver s5p_ehci_hc_driver = { | 42 | static const struct hc_driver s5p_ehci_hc_driver = { |
@@ -65,6 +70,26 @@ static const struct hc_driver s5p_ehci_hc_driver = { | |||
65 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, | 70 | .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, |
66 | }; | 71 | }; |
67 | 72 | ||
73 | static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci) | ||
74 | { | ||
75 | struct platform_device *pdev = to_platform_device(s5p_ehci->dev); | ||
76 | |||
77 | if (s5p_ehci->phy) | ||
78 | usb_phy_init(s5p_ehci->phy); | ||
79 | else if (s5p_ehci->pdata->phy_init) | ||
80 | s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | ||
81 | } | ||
82 | |||
83 | static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci) | ||
84 | { | ||
85 | struct platform_device *pdev = to_platform_device(s5p_ehci->dev); | ||
86 | |||
87 | if (s5p_ehci->phy) | ||
88 | usb_phy_shutdown(s5p_ehci->phy); | ||
89 | else if (s5p_ehci->pdata->phy_exit) | ||
90 | s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | ||
91 | } | ||
92 | |||
68 | static void s5p_setup_vbus_gpio(struct platform_device *pdev) | 93 | static void s5p_setup_vbus_gpio(struct platform_device *pdev) |
69 | { | 94 | { |
70 | int err; | 95 | int err; |
@@ -87,20 +112,15 @@ static u64 ehci_s5p_dma_mask = DMA_BIT_MASK(32); | |||
87 | 112 | ||
88 | static int s5p_ehci_probe(struct platform_device *pdev) | 113 | static int s5p_ehci_probe(struct platform_device *pdev) |
89 | { | 114 | { |
90 | struct s5p_ehci_platdata *pdata; | 115 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; |
91 | struct s5p_ehci_hcd *s5p_ehci; | 116 | struct s5p_ehci_hcd *s5p_ehci; |
92 | struct usb_hcd *hcd; | 117 | struct usb_hcd *hcd; |
93 | struct ehci_hcd *ehci; | 118 | struct ehci_hcd *ehci; |
94 | struct resource *res; | 119 | struct resource *res; |
120 | struct usb_phy *phy; | ||
95 | int irq; | 121 | int irq; |
96 | int err; | 122 | int err; |
97 | 123 | ||
98 | pdata = pdev->dev.platform_data; | ||
99 | if (!pdata) { | ||
100 | dev_err(&pdev->dev, "No platform data defined\n"); | ||
101 | return -EINVAL; | ||
102 | } | ||
103 | |||
104 | /* | 124 | /* |
105 | * Right now device-tree probed devices don't get dma_mask set. | 125 | * Right now device-tree probed devices don't get dma_mask set. |
106 | * Since shared usb code relies on it, set it here for now. | 126 | * Since shared usb code relies on it, set it here for now. |
@@ -118,6 +138,20 @@ static int s5p_ehci_probe(struct platform_device *pdev) | |||
118 | if (!s5p_ehci) | 138 | if (!s5p_ehci) |
119 | return -ENOMEM; | 139 | return -ENOMEM; |
120 | 140 | ||
141 | phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); | ||
142 | if (IS_ERR_OR_NULL(phy)) { | ||
143 | /* Fallback to pdata */ | ||
144 | if (!pdata) { | ||
145 | dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); | ||
146 | return -EPROBE_DEFER; | ||
147 | } else { | ||
148 | s5p_ehci->pdata = pdata; | ||
149 | } | ||
150 | } else { | ||
151 | s5p_ehci->phy = phy; | ||
152 | s5p_ehci->otg = phy->otg; | ||
153 | } | ||
154 | |||
121 | s5p_ehci->dev = &pdev->dev; | 155 | s5p_ehci->dev = &pdev->dev; |
122 | 156 | ||
123 | hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, | 157 | hcd = usb_create_hcd(&s5p_ehci_hc_driver, &pdev->dev, |
@@ -163,8 +197,10 @@ static int s5p_ehci_probe(struct platform_device *pdev) | |||
163 | goto fail_io; | 197 | goto fail_io; |
164 | } | 198 | } |
165 | 199 | ||
166 | if (pdata->phy_init) | 200 | if (s5p_ehci->otg) |
167 | pdata->phy_init(pdev, S5P_USB_PHY_HOST); | 201 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
202 | |||
203 | s5p_ehci_phy_enable(s5p_ehci); | ||
168 | 204 | ||
169 | ehci = hcd_to_ehci(hcd); | 205 | ehci = hcd_to_ehci(hcd); |
170 | ehci->caps = hcd->regs; | 206 | ehci->caps = hcd->regs; |
@@ -175,13 +211,15 @@ static int s5p_ehci_probe(struct platform_device *pdev) | |||
175 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); | 211 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); |
176 | if (err) { | 212 | if (err) { |
177 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); | 213 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); |
178 | goto fail_io; | 214 | goto fail_add_hcd; |
179 | } | 215 | } |
180 | 216 | ||
181 | platform_set_drvdata(pdev, s5p_ehci); | 217 | platform_set_drvdata(pdev, s5p_ehci); |
182 | 218 | ||
183 | return 0; | 219 | return 0; |
184 | 220 | ||
221 | fail_add_hcd: | ||
222 | s5p_ehci_phy_disable(s5p_ehci); | ||
185 | fail_io: | 223 | fail_io: |
186 | clk_disable_unprepare(s5p_ehci->clk); | 224 | clk_disable_unprepare(s5p_ehci->clk); |
187 | fail_clk: | 225 | fail_clk: |
@@ -191,14 +229,15 @@ fail_clk: | |||
191 | 229 | ||
192 | static int s5p_ehci_remove(struct platform_device *pdev) | 230 | static int s5p_ehci_remove(struct platform_device *pdev) |
193 | { | 231 | { |
194 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; | ||
195 | struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); | 232 | struct s5p_ehci_hcd *s5p_ehci = platform_get_drvdata(pdev); |
196 | struct usb_hcd *hcd = s5p_ehci->hcd; | 233 | struct usb_hcd *hcd = s5p_ehci->hcd; |
197 | 234 | ||
198 | usb_remove_hcd(hcd); | 235 | usb_remove_hcd(hcd); |
199 | 236 | ||
200 | if (pdata && pdata->phy_exit) | 237 | if (s5p_ehci->otg) |
201 | pdata->phy_exit(pdev, S5P_USB_PHY_HOST); | 238 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
239 | |||
240 | s5p_ehci_phy_disable(s5p_ehci); | ||
202 | 241 | ||
203 | clk_disable_unprepare(s5p_ehci->clk); | 242 | clk_disable_unprepare(s5p_ehci->clk); |
204 | 243 | ||
@@ -222,14 +261,14 @@ static int s5p_ehci_suspend(struct device *dev) | |||
222 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); | 261 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); |
223 | struct usb_hcd *hcd = s5p_ehci->hcd; | 262 | struct usb_hcd *hcd = s5p_ehci->hcd; |
224 | bool do_wakeup = device_may_wakeup(dev); | 263 | bool do_wakeup = device_may_wakeup(dev); |
225 | struct platform_device *pdev = to_platform_device(dev); | ||
226 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; | ||
227 | int rc; | 264 | int rc; |
228 | 265 | ||
229 | rc = ehci_suspend(hcd, do_wakeup); | 266 | rc = ehci_suspend(hcd, do_wakeup); |
230 | 267 | ||
231 | if (pdata && pdata->phy_exit) | 268 | if (s5p_ehci->otg) |
232 | pdata->phy_exit(pdev, S5P_USB_PHY_HOST); | 269 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
270 | |||
271 | s5p_ehci_phy_disable(s5p_ehci); | ||
233 | 272 | ||
234 | clk_disable_unprepare(s5p_ehci->clk); | 273 | clk_disable_unprepare(s5p_ehci->clk); |
235 | 274 | ||
@@ -240,13 +279,13 @@ static int s5p_ehci_resume(struct device *dev) | |||
240 | { | 279 | { |
241 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); | 280 | struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev); |
242 | struct usb_hcd *hcd = s5p_ehci->hcd; | 281 | struct usb_hcd *hcd = s5p_ehci->hcd; |
243 | struct platform_device *pdev = to_platform_device(dev); | ||
244 | struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; | ||
245 | 282 | ||
246 | clk_prepare_enable(s5p_ehci->clk); | 283 | clk_prepare_enable(s5p_ehci->clk); |
247 | 284 | ||
248 | if (pdata && pdata->phy_init) | 285 | if (s5p_ehci->otg) |
249 | pdata->phy_init(pdev, S5P_USB_PHY_HOST); | 286 | s5p_ehci->otg->set_host(s5p_ehci->otg, &s5p_ehci->hcd->self); |
287 | |||
288 | s5p_ehci_phy_enable(s5p_ehci); | ||
250 | 289 | ||
251 | /* DMA burst Enable */ | 290 | /* DMA burst Enable */ |
252 | writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); | 291 | writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); |
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 77f2017c33c4..e3b7e85120e4 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c | |||
@@ -15,14 +15,39 @@ | |||
15 | #include <linux/of.h> | 15 | #include <linux/of.h> |
16 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/platform_data/usb-exynos.h> | 17 | #include <linux/platform_data/usb-exynos.h> |
18 | #include <linux/usb/phy.h> | ||
19 | #include <linux/usb/samsung_usb_phy.h> | ||
18 | #include <plat/usb-phy.h> | 20 | #include <plat/usb-phy.h> |
19 | 21 | ||
20 | struct exynos_ohci_hcd { | 22 | struct exynos_ohci_hcd { |
21 | struct device *dev; | 23 | struct device *dev; |
22 | struct usb_hcd *hcd; | 24 | struct usb_hcd *hcd; |
23 | struct clk *clk; | 25 | struct clk *clk; |
26 | struct usb_phy *phy; | ||
27 | struct usb_otg *otg; | ||
28 | struct exynos4_ohci_platdata *pdata; | ||
24 | }; | 29 | }; |
25 | 30 | ||
31 | static void exynos_ohci_phy_enable(struct exynos_ohci_hcd *exynos_ohci) | ||
32 | { | ||
33 | struct platform_device *pdev = to_platform_device(exynos_ohci->dev); | ||
34 | |||
35 | if (exynos_ohci->phy) | ||
36 | usb_phy_init(exynos_ohci->phy); | ||
37 | else if (exynos_ohci->pdata->phy_init) | ||
38 | exynos_ohci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); | ||
39 | } | ||
40 | |||
41 | static void exynos_ohci_phy_disable(struct exynos_ohci_hcd *exynos_ohci) | ||
42 | { | ||
43 | struct platform_device *pdev = to_platform_device(exynos_ohci->dev); | ||
44 | |||
45 | if (exynos_ohci->phy) | ||
46 | usb_phy_shutdown(exynos_ohci->phy); | ||
47 | else if (exynos_ohci->pdata->phy_exit) | ||
48 | exynos_ohci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); | ||
49 | } | ||
50 | |||
26 | static int ohci_exynos_reset(struct usb_hcd *hcd) | 51 | static int ohci_exynos_reset(struct usb_hcd *hcd) |
27 | { | 52 | { |
28 | return ohci_init(hcd_to_ohci(hcd)); | 53 | return ohci_init(hcd_to_ohci(hcd)); |
@@ -78,20 +103,15 @@ static u64 ohci_exynos_dma_mask = DMA_BIT_MASK(32); | |||
78 | 103 | ||
79 | static int exynos_ohci_probe(struct platform_device *pdev) | 104 | static int exynos_ohci_probe(struct platform_device *pdev) |
80 | { | 105 | { |
81 | struct exynos4_ohci_platdata *pdata; | 106 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; |
82 | struct exynos_ohci_hcd *exynos_ohci; | 107 | struct exynos_ohci_hcd *exynos_ohci; |
83 | struct usb_hcd *hcd; | 108 | struct usb_hcd *hcd; |
84 | struct ohci_hcd *ohci; | 109 | struct ohci_hcd *ohci; |
85 | struct resource *res; | 110 | struct resource *res; |
111 | struct usb_phy *phy; | ||
86 | int irq; | 112 | int irq; |
87 | int err; | 113 | int err; |
88 | 114 | ||
89 | pdata = pdev->dev.platform_data; | ||
90 | if (!pdata) { | ||
91 | dev_err(&pdev->dev, "No platform data defined\n"); | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | /* | 115 | /* |
96 | * Right now device-tree probed devices don't get dma_mask set. | 116 | * Right now device-tree probed devices don't get dma_mask set. |
97 | * Since shared usb code relies on it, set it here for now. | 117 | * Since shared usb code relies on it, set it here for now. |
@@ -107,6 +127,20 @@ static int exynos_ohci_probe(struct platform_device *pdev) | |||
107 | if (!exynos_ohci) | 127 | if (!exynos_ohci) |
108 | return -ENOMEM; | 128 | return -ENOMEM; |
109 | 129 | ||
130 | phy = devm_usb_get_phy(&pdev->dev, USB_PHY_TYPE_USB2); | ||
131 | if (IS_ERR_OR_NULL(phy)) { | ||
132 | /* Fallback to pdata */ | ||
133 | if (!pdata) { | ||
134 | dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); | ||
135 | return -EPROBE_DEFER; | ||
136 | } else { | ||
137 | exynos_ohci->pdata = pdata; | ||
138 | } | ||
139 | } else { | ||
140 | exynos_ohci->phy = phy; | ||
141 | exynos_ohci->otg = phy->otg; | ||
142 | } | ||
143 | |||
110 | exynos_ohci->dev = &pdev->dev; | 144 | exynos_ohci->dev = &pdev->dev; |
111 | 145 | ||
112 | hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, | 146 | hcd = usb_create_hcd(&exynos_ohci_hc_driver, &pdev->dev, |
@@ -152,8 +186,11 @@ static int exynos_ohci_probe(struct platform_device *pdev) | |||
152 | goto fail_io; | 186 | goto fail_io; |
153 | } | 187 | } |
154 | 188 | ||
155 | if (pdata->phy_init) | 189 | if (exynos_ohci->otg) |
156 | pdata->phy_init(pdev, S5P_USB_PHY_HOST); | 190 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
191 | &exynos_ohci->hcd->self); | ||
192 | |||
193 | exynos_ohci_phy_enable(exynos_ohci); | ||
157 | 194 | ||
158 | ohci = hcd_to_ohci(hcd); | 195 | ohci = hcd_to_ohci(hcd); |
159 | ohci_hcd_init(ohci); | 196 | ohci_hcd_init(ohci); |
@@ -161,13 +198,15 @@ static int exynos_ohci_probe(struct platform_device *pdev) | |||
161 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); | 198 | err = usb_add_hcd(hcd, irq, IRQF_SHARED); |
162 | if (err) { | 199 | if (err) { |
163 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); | 200 | dev_err(&pdev->dev, "Failed to add USB HCD\n"); |
164 | goto fail_io; | 201 | goto fail_add_hcd; |
165 | } | 202 | } |
166 | 203 | ||
167 | platform_set_drvdata(pdev, exynos_ohci); | 204 | platform_set_drvdata(pdev, exynos_ohci); |
168 | 205 | ||
169 | return 0; | 206 | return 0; |
170 | 207 | ||
208 | fail_add_hcd: | ||
209 | exynos_ohci_phy_disable(exynos_ohci); | ||
171 | fail_io: | 210 | fail_io: |
172 | clk_disable_unprepare(exynos_ohci->clk); | 211 | clk_disable_unprepare(exynos_ohci->clk); |
173 | fail_clk: | 212 | fail_clk: |
@@ -177,14 +216,16 @@ fail_clk: | |||
177 | 216 | ||
178 | static int exynos_ohci_remove(struct platform_device *pdev) | 217 | static int exynos_ohci_remove(struct platform_device *pdev) |
179 | { | 218 | { |
180 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; | ||
181 | struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); | 219 | struct exynos_ohci_hcd *exynos_ohci = platform_get_drvdata(pdev); |
182 | struct usb_hcd *hcd = exynos_ohci->hcd; | 220 | struct usb_hcd *hcd = exynos_ohci->hcd; |
183 | 221 | ||
184 | usb_remove_hcd(hcd); | 222 | usb_remove_hcd(hcd); |
185 | 223 | ||
186 | if (pdata && pdata->phy_exit) | 224 | if (exynos_ohci->otg) |
187 | pdata->phy_exit(pdev, S5P_USB_PHY_HOST); | 225 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
226 | &exynos_ohci->hcd->self); | ||
227 | |||
228 | exynos_ohci_phy_disable(exynos_ohci); | ||
188 | 229 | ||
189 | clk_disable_unprepare(exynos_ohci->clk); | 230 | clk_disable_unprepare(exynos_ohci->clk); |
190 | 231 | ||
@@ -208,8 +249,6 @@ static int exynos_ohci_suspend(struct device *dev) | |||
208 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); | 249 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); |
209 | struct usb_hcd *hcd = exynos_ohci->hcd; | 250 | struct usb_hcd *hcd = exynos_ohci->hcd; |
210 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | 251 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); |
211 | struct platform_device *pdev = to_platform_device(dev); | ||
212 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; | ||
213 | unsigned long flags; | 252 | unsigned long flags; |
214 | int rc = 0; | 253 | int rc = 0; |
215 | 254 | ||
@@ -228,8 +267,11 @@ static int exynos_ohci_suspend(struct device *dev) | |||
228 | 267 | ||
229 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); | 268 | clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); |
230 | 269 | ||
231 | if (pdata && pdata->phy_exit) | 270 | if (exynos_ohci->otg) |
232 | pdata->phy_exit(pdev, S5P_USB_PHY_HOST); | 271 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
272 | &exynos_ohci->hcd->self); | ||
273 | |||
274 | exynos_ohci_phy_disable(exynos_ohci); | ||
233 | 275 | ||
234 | clk_disable_unprepare(exynos_ohci->clk); | 276 | clk_disable_unprepare(exynos_ohci->clk); |
235 | 277 | ||
@@ -243,13 +285,14 @@ static int exynos_ohci_resume(struct device *dev) | |||
243 | { | 285 | { |
244 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); | 286 | struct exynos_ohci_hcd *exynos_ohci = dev_get_drvdata(dev); |
245 | struct usb_hcd *hcd = exynos_ohci->hcd; | 287 | struct usb_hcd *hcd = exynos_ohci->hcd; |
246 | struct platform_device *pdev = to_platform_device(dev); | ||
247 | struct exynos4_ohci_platdata *pdata = pdev->dev.platform_data; | ||
248 | 288 | ||
249 | clk_prepare_enable(exynos_ohci->clk); | 289 | clk_prepare_enable(exynos_ohci->clk); |
250 | 290 | ||
251 | if (pdata && pdata->phy_init) | 291 | if (exynos_ohci->otg) |
252 | pdata->phy_init(pdev, S5P_USB_PHY_HOST); | 292 | exynos_ohci->otg->set_host(exynos_ohci->otg, |
293 | &exynos_ohci->hcd->self); | ||
294 | |||
295 | exynos_ohci_phy_enable(exynos_ohci); | ||
253 | 296 | ||
254 | ohci_resume(hcd, false); | 297 | ohci_resume(hcd, false); |
255 | 298 | ||
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 23a0b7f0892d..de6e5ce26316 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig | |||
@@ -11,6 +11,7 @@ config USB_MUSB_HDRC | |||
11 | select NOP_USB_XCEIV if (SOC_TI81XX || SOC_AM33XX) | 11 | select NOP_USB_XCEIV if (SOC_TI81XX || SOC_AM33XX) |
12 | select TWL4030_USB if MACH_OMAP_3430SDP | 12 | select TWL4030_USB if MACH_OMAP_3430SDP |
13 | select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA | 13 | select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA |
14 | select OMAP_CONTROL_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA | ||
14 | select USB_OTG_UTILS | 15 | select USB_OTG_UTILS |
15 | help | 16 | help |
16 | Say Y here if your system has a dual role high speed USB | 17 | Say Y here if your system has a dual role high speed USB |
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index bb48796e5213..1762354fe793 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/err.h> | 37 | #include <linux/err.h> |
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <linux/usb/musb-omap.h> | 39 | #include <linux/usb/musb-omap.h> |
40 | #include <linux/usb/omap_control_usb.h> | ||
40 | 41 | ||
41 | #include "musb_core.h" | 42 | #include "musb_core.h" |
42 | #include "omap2430.h" | 43 | #include "omap2430.h" |
@@ -46,7 +47,7 @@ struct omap2430_glue { | |||
46 | struct platform_device *musb; | 47 | struct platform_device *musb; |
47 | enum omap_musb_vbus_id_status status; | 48 | enum omap_musb_vbus_id_status status; |
48 | struct work_struct omap_musb_mailbox_work; | 49 | struct work_struct omap_musb_mailbox_work; |
49 | u32 __iomem *control_otghs; | 50 | struct device *control_otghs; |
50 | }; | 51 | }; |
51 | #define glue_to_musb(g) platform_get_drvdata(g->musb) | 52 | #define glue_to_musb(g) platform_get_drvdata(g->musb) |
52 | 53 | ||
@@ -54,26 +55,6 @@ struct omap2430_glue *_glue; | |||
54 | 55 | ||
55 | static struct timer_list musb_idle_timer; | 56 | static struct timer_list musb_idle_timer; |
56 | 57 | ||
57 | /** | ||
58 | * omap4_usb_phy_mailbox - write to usb otg mailbox | ||
59 | * @glue: struct omap2430_glue * | ||
60 | * @val: the value to be written to the mailbox | ||
61 | * | ||
62 | * On detection of a device (ID pin is grounded), this API should be called | ||
63 | * to set AVALID, VBUSVALID and ID pin is grounded. | ||
64 | * | ||
65 | * When OMAP is connected to a host (OMAP in device mode), this API | ||
66 | * is called to set AVALID, VBUSVALID and ID pin in high impedance. | ||
67 | * | ||
68 | * XXX: This function will be removed once we have a seperate driver for | ||
69 | * control module | ||
70 | */ | ||
71 | static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val) | ||
72 | { | ||
73 | if (glue->control_otghs) | ||
74 | writel(val, glue->control_otghs); | ||
75 | } | ||
76 | |||
77 | static void musb_do_idle(unsigned long _musb) | 58 | static void musb_do_idle(unsigned long _musb) |
78 | { | 59 | { |
79 | struct musb *musb = (void *)_musb; | 60 | struct musb *musb = (void *)_musb; |
@@ -269,7 +250,6 @@ EXPORT_SYMBOL_GPL(omap_musb_mailbox); | |||
269 | 250 | ||
270 | static void omap_musb_set_mailbox(struct omap2430_glue *glue) | 251 | static void omap_musb_set_mailbox(struct omap2430_glue *glue) |
271 | { | 252 | { |
272 | u32 val; | ||
273 | struct musb *musb = glue_to_musb(glue); | 253 | struct musb *musb = glue_to_musb(glue); |
274 | struct device *dev = musb->controller; | 254 | struct device *dev = musb->controller; |
275 | struct musb_hdrc_platform_data *pdata = dev->platform_data; | 255 | struct musb_hdrc_platform_data *pdata = dev->platform_data; |
@@ -285,8 +265,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) | |||
285 | musb->xceiv->last_event = USB_EVENT_ID; | 265 | musb->xceiv->last_event = USB_EVENT_ID; |
286 | if (musb->gadget_driver) { | 266 | if (musb->gadget_driver) { |
287 | pm_runtime_get_sync(dev); | 267 | pm_runtime_get_sync(dev); |
288 | val = AVALID | VBUSVALID; | 268 | omap_control_usb_set_mode(glue->control_otghs, |
289 | omap4_usb_phy_mailbox(glue, val); | 269 | USB_MODE_HOST); |
290 | omap2430_musb_set_vbus(musb, 1); | 270 | omap2430_musb_set_vbus(musb, 1); |
291 | } | 271 | } |
292 | break; | 272 | break; |
@@ -299,8 +279,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) | |||
299 | musb->xceiv->last_event = USB_EVENT_VBUS; | 279 | musb->xceiv->last_event = USB_EVENT_VBUS; |
300 | if (musb->gadget_driver) | 280 | if (musb->gadget_driver) |
301 | pm_runtime_get_sync(dev); | 281 | pm_runtime_get_sync(dev); |
302 | val = IDDIG | AVALID | VBUSVALID; | 282 | omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); |
303 | omap4_usb_phy_mailbox(glue, val); | ||
304 | break; | 283 | break; |
305 | 284 | ||
306 | case OMAP_MUSB_ID_FLOAT: | 285 | case OMAP_MUSB_ID_FLOAT: |
@@ -317,8 +296,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) | |||
317 | if (musb->xceiv->otg->set_vbus) | 296 | if (musb->xceiv->otg->set_vbus) |
318 | otg_set_vbus(musb->xceiv->otg, 0); | 297 | otg_set_vbus(musb->xceiv->otg, 0); |
319 | } | 298 | } |
320 | val = SESSEND | IDDIG; | 299 | omap_control_usb_set_mode(glue->control_otghs, |
321 | omap4_usb_phy_mailbox(glue, val); | 300 | USB_MODE_DISCONNECT); |
322 | break; | 301 | break; |
323 | default: | 302 | default: |
324 | dev_dbg(dev, "ID float\n"); | 303 | dev_dbg(dev, "ID float\n"); |
@@ -366,7 +345,12 @@ static int omap2430_musb_init(struct musb *musb) | |||
366 | * up through ULPI. TWL4030-family PMICs include one, | 345 | * up through ULPI. TWL4030-family PMICs include one, |
367 | * which needs a driver, drivers aren't always needed. | 346 | * which needs a driver, drivers aren't always needed. |
368 | */ | 347 | */ |
369 | musb->xceiv = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2); | 348 | if (dev->parent->of_node) |
349 | musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, | ||
350 | "usb-phy", 0); | ||
351 | else | ||
352 | musb->xceiv = devm_usb_get_phy_dev(dev, 0); | ||
353 | |||
370 | if (IS_ERR_OR_NULL(musb->xceiv)) { | 354 | if (IS_ERR_OR_NULL(musb->xceiv)) { |
371 | pr_err("HS USB OTG: no transceiver configured\n"); | 355 | pr_err("HS USB OTG: no transceiver configured\n"); |
372 | return -EPROBE_DEFER; | 356 | return -EPROBE_DEFER; |
@@ -415,7 +399,6 @@ err1: | |||
415 | static void omap2430_musb_enable(struct musb *musb) | 399 | static void omap2430_musb_enable(struct musb *musb) |
416 | { | 400 | { |
417 | u8 devctl; | 401 | u8 devctl; |
418 | u32 val; | ||
419 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | 402 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); |
420 | struct device *dev = musb->controller; | 403 | struct device *dev = musb->controller; |
421 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | 404 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); |
@@ -425,8 +408,7 @@ static void omap2430_musb_enable(struct musb *musb) | |||
425 | switch (glue->status) { | 408 | switch (glue->status) { |
426 | 409 | ||
427 | case OMAP_MUSB_ID_GROUND: | 410 | case OMAP_MUSB_ID_GROUND: |
428 | val = AVALID | VBUSVALID; | 411 | omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); |
429 | omap4_usb_phy_mailbox(glue, val); | ||
430 | if (data->interface_type != MUSB_INTERFACE_UTMI) | 412 | if (data->interface_type != MUSB_INTERFACE_UTMI) |
431 | break; | 413 | break; |
432 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); | 414 | devctl = musb_readb(musb->mregs, MUSB_DEVCTL); |
@@ -445,8 +427,7 @@ static void omap2430_musb_enable(struct musb *musb) | |||
445 | break; | 427 | break; |
446 | 428 | ||
447 | case OMAP_MUSB_VBUS_VALID: | 429 | case OMAP_MUSB_VBUS_VALID: |
448 | val = IDDIG | AVALID | VBUSVALID; | 430 | omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); |
449 | omap4_usb_phy_mailbox(glue, val); | ||
450 | break; | 431 | break; |
451 | 432 | ||
452 | default: | 433 | default: |
@@ -456,14 +437,12 @@ static void omap2430_musb_enable(struct musb *musb) | |||
456 | 437 | ||
457 | static void omap2430_musb_disable(struct musb *musb) | 438 | static void omap2430_musb_disable(struct musb *musb) |
458 | { | 439 | { |
459 | u32 val; | ||
460 | struct device *dev = musb->controller; | 440 | struct device *dev = musb->controller; |
461 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); | 441 | struct omap2430_glue *glue = dev_get_drvdata(dev->parent); |
462 | 442 | ||
463 | if (glue->status != OMAP_MUSB_UNKNOWN) { | 443 | if (glue->status != OMAP_MUSB_UNKNOWN) |
464 | val = SESSEND | IDDIG; | 444 | omap_control_usb_set_mode(glue->control_otghs, |
465 | omap4_usb_phy_mailbox(glue, val); | 445 | USB_MODE_DISCONNECT); |
466 | } | ||
467 | } | 446 | } |
468 | 447 | ||
469 | static int omap2430_musb_exit(struct musb *musb) | 448 | static int omap2430_musb_exit(struct musb *musb) |
@@ -498,7 +477,6 @@ static int omap2430_probe(struct platform_device *pdev) | |||
498 | struct omap2430_glue *glue; | 477 | struct omap2430_glue *glue; |
499 | struct device_node *np = pdev->dev.of_node; | 478 | struct device_node *np = pdev->dev.of_node; |
500 | struct musb_hdrc_config *config; | 479 | struct musb_hdrc_config *config; |
501 | struct resource *res; | ||
502 | int ret = -ENOMEM; | 480 | int ret = -ENOMEM; |
503 | 481 | ||
504 | glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); | 482 | glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); |
@@ -521,12 +499,6 @@ static int omap2430_probe(struct platform_device *pdev) | |||
521 | glue->musb = musb; | 499 | glue->musb = musb; |
522 | glue->status = OMAP_MUSB_UNKNOWN; | 500 | glue->status = OMAP_MUSB_UNKNOWN; |
523 | 501 | ||
524 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | ||
525 | |||
526 | glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res); | ||
527 | if (glue->control_otghs == NULL) | ||
528 | dev_dbg(&pdev->dev, "Failed to obtain control memory\n"); | ||
529 | |||
530 | if (np) { | 502 | if (np) { |
531 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); | 503 | pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); |
532 | if (!pdata) { | 504 | if (!pdata) { |
@@ -556,11 +528,22 @@ static int omap2430_probe(struct platform_device *pdev) | |||
556 | of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits); | 528 | of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits); |
557 | of_property_read_u32(np, "power", (u32 *)&pdata->power); | 529 | of_property_read_u32(np, "power", (u32 *)&pdata->power); |
558 | config->multipoint = of_property_read_bool(np, "multipoint"); | 530 | config->multipoint = of_property_read_bool(np, "multipoint"); |
531 | pdata->has_mailbox = of_property_read_bool(np, | ||
532 | "ti,has-mailbox"); | ||
559 | 533 | ||
560 | pdata->board_data = data; | 534 | pdata->board_data = data; |
561 | pdata->config = config; | 535 | pdata->config = config; |
562 | } | 536 | } |
563 | 537 | ||
538 | if (pdata->has_mailbox) { | ||
539 | glue->control_otghs = omap_get_control_dev(); | ||
540 | if (IS_ERR(glue->control_otghs)) { | ||
541 | dev_vdbg(&pdev->dev, "Failed to get control device\n"); | ||
542 | return -ENODEV; | ||
543 | } | ||
544 | } else { | ||
545 | glue->control_otghs = ERR_PTR(-ENODEV); | ||
546 | } | ||
564 | pdata->platform_ops = &omap2430_ops; | 547 | pdata->platform_ops = &omap2430_ops; |
565 | 548 | ||
566 | platform_set_drvdata(pdev, glue); | 549 | platform_set_drvdata(pdev, glue); |
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h index 8ef656659fcb..1b5e83a9840e 100644 --- a/drivers/usb/musb/omap2430.h +++ b/drivers/usb/musb/omap2430.h | |||
@@ -49,13 +49,4 @@ | |||
49 | #define OTG_FORCESTDBY 0x414 | 49 | #define OTG_FORCESTDBY 0x414 |
50 | # define ENABLEFORCE (1 << 0) | 50 | # define ENABLEFORCE (1 << 0) |
51 | 51 | ||
52 | /* | ||
53 | * Control Module bit definitions | ||
54 | * XXX: Will be removed once we have a driver for control module. | ||
55 | */ | ||
56 | #define AVALID BIT(0) | ||
57 | #define BVALID BIT(1) | ||
58 | #define VBUSVALID BIT(2) | ||
59 | #define SESSEND BIT(3) | ||
60 | #define IDDIG BIT(4) | ||
61 | #endif /* __MUSB_OMAP243X_H__ */ | 52 | #endif /* __MUSB_OMAP243X_H__ */ |
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c index da2d60c06f15..b6a9be31133b 100644 --- a/drivers/usb/otg/mv_otg.c +++ b/drivers/usb/otg/mv_otg.c | |||
@@ -420,7 +420,7 @@ static void mv_otg_work(struct work_struct *work) | |||
420 | struct usb_otg *otg; | 420 | struct usb_otg *otg; |
421 | int old_state; | 421 | int old_state; |
422 | 422 | ||
423 | mvotg = container_of((struct delayed_work *)work, struct mv_otg, work); | 423 | mvotg = container_of(to_delayed_work(work), struct mv_otg, work); |
424 | 424 | ||
425 | run: | 425 | run: |
426 | /* work queue is single thread, or we need spin_lock to protect */ | 426 | /* work queue is single thread, or we need spin_lock to protect */ |
diff --git a/drivers/usb/otg/mxs-phy.c b/drivers/usb/otg/mxs-phy.c index 76302720055a..5158332522b1 100644 --- a/drivers/usb/otg/mxs-phy.c +++ b/drivers/usb/otg/mxs-phy.c | |||
@@ -76,6 +76,25 @@ static void mxs_phy_shutdown(struct usb_phy *phy) | |||
76 | clk_disable_unprepare(mxs_phy->clk); | 76 | clk_disable_unprepare(mxs_phy->clk); |
77 | } | 77 | } |
78 | 78 | ||
79 | static int mxs_phy_suspend(struct usb_phy *x, int suspend) | ||
80 | { | ||
81 | struct mxs_phy *mxs_phy = to_mxs_phy(x); | ||
82 | |||
83 | if (suspend) { | ||
84 | writel_relaxed(0xffffffff, x->io_priv + HW_USBPHY_PWD); | ||
85 | writel_relaxed(BM_USBPHY_CTRL_CLKGATE, | ||
86 | x->io_priv + HW_USBPHY_CTRL_SET); | ||
87 | clk_disable_unprepare(mxs_phy->clk); | ||
88 | } else { | ||
89 | clk_prepare_enable(mxs_phy->clk); | ||
90 | writel_relaxed(BM_USBPHY_CTRL_CLKGATE, | ||
91 | x->io_priv + HW_USBPHY_CTRL_CLR); | ||
92 | writel_relaxed(0, x->io_priv + HW_USBPHY_PWD); | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
79 | static int mxs_phy_on_connect(struct usb_phy *phy, | 98 | static int mxs_phy_on_connect(struct usb_phy *phy, |
80 | enum usb_device_speed speed) | 99 | enum usb_device_speed speed) |
81 | { | 100 | { |
@@ -137,6 +156,7 @@ static int mxs_phy_probe(struct platform_device *pdev) | |||
137 | mxs_phy->phy.label = DRIVER_NAME; | 156 | mxs_phy->phy.label = DRIVER_NAME; |
138 | mxs_phy->phy.init = mxs_phy_init; | 157 | mxs_phy->phy.init = mxs_phy_init; |
139 | mxs_phy->phy.shutdown = mxs_phy_shutdown; | 158 | mxs_phy->phy.shutdown = mxs_phy_shutdown; |
159 | mxs_phy->phy.set_suspend = mxs_phy_suspend; | ||
140 | mxs_phy->phy.notify_connect = mxs_phy_on_connect; | 160 | mxs_phy->phy.notify_connect = mxs_phy_on_connect; |
141 | mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; | 161 | mxs_phy->phy.notify_disconnect = mxs_phy_on_disconnect; |
142 | 162 | ||
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index a30c04115115..e1814397ca3a 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c | |||
@@ -13,11 +13,14 @@ | |||
13 | #include <linux/export.h> | 13 | #include <linux/export.h> |
14 | #include <linux/err.h> | 14 | #include <linux/err.h> |
15 | #include <linux/device.h> | 15 | #include <linux/device.h> |
16 | #include <linux/module.h> | ||
16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/of.h> | ||
17 | 19 | ||
18 | #include <linux/usb/otg.h> | 20 | #include <linux/usb/otg.h> |
19 | 21 | ||
20 | static LIST_HEAD(phy_list); | 22 | static LIST_HEAD(phy_list); |
23 | static LIST_HEAD(phy_bind_list); | ||
21 | static DEFINE_SPINLOCK(phy_lock); | 24 | static DEFINE_SPINLOCK(phy_lock); |
22 | 25 | ||
23 | static struct usb_phy *__usb_find_phy(struct list_head *list, | 26 | static struct usb_phy *__usb_find_phy(struct list_head *list, |
@@ -35,6 +38,38 @@ static struct usb_phy *__usb_find_phy(struct list_head *list, | |||
35 | return ERR_PTR(-ENODEV); | 38 | return ERR_PTR(-ENODEV); |
36 | } | 39 | } |
37 | 40 | ||
41 | static struct usb_phy *__usb_find_phy_dev(struct device *dev, | ||
42 | struct list_head *list, u8 index) | ||
43 | { | ||
44 | struct usb_phy_bind *phy_bind = NULL; | ||
45 | |||
46 | list_for_each_entry(phy_bind, list, list) { | ||
47 | if (!(strcmp(phy_bind->dev_name, dev_name(dev))) && | ||
48 | phy_bind->index == index) { | ||
49 | if (phy_bind->phy) | ||
50 | return phy_bind->phy; | ||
51 | else | ||
52 | return ERR_PTR(-EPROBE_DEFER); | ||
53 | } | ||
54 | } | ||
55 | |||
56 | return ERR_PTR(-ENODEV); | ||
57 | } | ||
58 | |||
59 | static struct usb_phy *__of_usb_find_phy(struct device_node *node) | ||
60 | { | ||
61 | struct usb_phy *phy; | ||
62 | |||
63 | list_for_each_entry(phy, &phy_list, head) { | ||
64 | if (node != phy->dev->of_node) | ||
65 | continue; | ||
66 | |||
67 | return phy; | ||
68 | } | ||
69 | |||
70 | return ERR_PTR(-ENODEV); | ||
71 | } | ||
72 | |||
38 | static void devm_usb_phy_release(struct device *dev, void *res) | 73 | static void devm_usb_phy_release(struct device *dev, void *res) |
39 | { | 74 | { |
40 | struct usb_phy *phy = *(struct usb_phy **)res; | 75 | struct usb_phy *phy = *(struct usb_phy **)res; |
@@ -110,6 +145,133 @@ err0: | |||
110 | } | 145 | } |
111 | EXPORT_SYMBOL(usb_get_phy); | 146 | EXPORT_SYMBOL(usb_get_phy); |
112 | 147 | ||
148 | /** | ||
149 | * devm_usb_get_phy_by_phandle - find the USB PHY by phandle | ||
150 | * @dev - device that requests this phy | ||
151 | * @phandle - name of the property holding the phy phandle value | ||
152 | * @index - the index of the phy | ||
153 | * | ||
154 | * Returns the phy driver associated with the given phandle value, | ||
155 | * after getting a refcount to it, -ENODEV if there is no such phy or | ||
156 | * -EPROBE_DEFER if there is a phandle to the phy, but the device is | ||
157 | * not yet loaded. While at that, it also associates the device with | ||
158 | * the phy using devres. On driver detach, release function is invoked | ||
159 | * on the devres data, then, devres data is freed. | ||
160 | * | ||
161 | * For use by USB host and peripheral drivers. | ||
162 | */ | ||
163 | struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | ||
164 | const char *phandle, u8 index) | ||
165 | { | ||
166 | struct usb_phy *phy = ERR_PTR(-ENOMEM), **ptr; | ||
167 | unsigned long flags; | ||
168 | struct device_node *node; | ||
169 | |||
170 | if (!dev->of_node) { | ||
171 | dev_dbg(dev, "device does not have a device node entry\n"); | ||
172 | return ERR_PTR(-EINVAL); | ||
173 | } | ||
174 | |||
175 | node = of_parse_phandle(dev->of_node, phandle, index); | ||
176 | if (!node) { | ||
177 | dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, | ||
178 | dev->of_node->full_name); | ||
179 | return ERR_PTR(-ENODEV); | ||
180 | } | ||
181 | |||
182 | ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); | ||
183 | if (!ptr) { | ||
184 | dev_dbg(dev, "failed to allocate memory for devres\n"); | ||
185 | goto err0; | ||
186 | } | ||
187 | |||
188 | spin_lock_irqsave(&phy_lock, flags); | ||
189 | |||
190 | phy = __of_usb_find_phy(node); | ||
191 | if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { | ||
192 | phy = ERR_PTR(-EPROBE_DEFER); | ||
193 | devres_free(ptr); | ||
194 | goto err1; | ||
195 | } | ||
196 | |||
197 | *ptr = phy; | ||
198 | devres_add(dev, ptr); | ||
199 | |||
200 | get_device(phy->dev); | ||
201 | |||
202 | err1: | ||
203 | spin_unlock_irqrestore(&phy_lock, flags); | ||
204 | |||
205 | err0: | ||
206 | of_node_put(node); | ||
207 | |||
208 | return phy; | ||
209 | } | ||
210 | EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); | ||
211 | |||
212 | /** | ||
213 | * usb_get_phy_dev - find the USB PHY | ||
214 | * @dev - device that requests this phy | ||
215 | * @index - the index of the phy | ||
216 | * | ||
217 | * Returns the phy driver, after getting a refcount to it; or | ||
218 | * -ENODEV if there is no such phy. The caller is responsible for | ||
219 | * calling usb_put_phy() to release that count. | ||
220 | * | ||
221 | * For use by USB host and peripheral drivers. | ||
222 | */ | ||
223 | struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) | ||
224 | { | ||
225 | struct usb_phy *phy = NULL; | ||
226 | unsigned long flags; | ||
227 | |||
228 | spin_lock_irqsave(&phy_lock, flags); | ||
229 | |||
230 | phy = __usb_find_phy_dev(dev, &phy_bind_list, index); | ||
231 | if (IS_ERR(phy)) { | ||
232 | pr_err("unable to find transceiver\n"); | ||
233 | goto err0; | ||
234 | } | ||
235 | |||
236 | get_device(phy->dev); | ||
237 | |||
238 | err0: | ||
239 | spin_unlock_irqrestore(&phy_lock, flags); | ||
240 | |||
241 | return phy; | ||
242 | } | ||
243 | EXPORT_SYMBOL(usb_get_phy_dev); | ||
244 | |||
245 | /** | ||
246 | * devm_usb_get_phy_dev - find the USB PHY using device ptr and index | ||
247 | * @dev - device that requests this phy | ||
248 | * @index - the index of the phy | ||
249 | * | ||
250 | * Gets the phy using usb_get_phy_dev(), and associates a device with it using | ||
251 | * devres. On driver detach, release function is invoked on the devres data, | ||
252 | * then, devres data is freed. | ||
253 | * | ||
254 | * For use by USB host and peripheral drivers. | ||
255 | */ | ||
256 | struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) | ||
257 | { | ||
258 | struct usb_phy **ptr, *phy; | ||
259 | |||
260 | ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); | ||
261 | if (!ptr) | ||
262 | return NULL; | ||
263 | |||
264 | phy = usb_get_phy_dev(dev, index); | ||
265 | if (!IS_ERR(phy)) { | ||
266 | *ptr = phy; | ||
267 | devres_add(dev, ptr); | ||
268 | } else | ||
269 | devres_free(ptr); | ||
270 | |||
271 | return phy; | ||
272 | } | ||
273 | EXPORT_SYMBOL(devm_usb_get_phy_dev); | ||
274 | |||
113 | /** | 275 | /** |
114 | * devm_usb_put_phy - release the USB PHY | 276 | * devm_usb_put_phy - release the USB PHY |
115 | * @dev - device that wants to release this phy | 277 | * @dev - device that wants to release this phy |
@@ -185,6 +347,36 @@ out: | |||
185 | EXPORT_SYMBOL(usb_add_phy); | 347 | EXPORT_SYMBOL(usb_add_phy); |
186 | 348 | ||
187 | /** | 349 | /** |
350 | * usb_add_phy_dev - declare the USB PHY | ||
351 | * @x: the USB phy to be used; or NULL | ||
352 | * | ||
353 | * This call is exclusively for use by phy drivers, which | ||
354 | * coordinate the activities of drivers for host and peripheral | ||
355 | * controllers, and in some cases for VBUS current regulation. | ||
356 | */ | ||
357 | int usb_add_phy_dev(struct usb_phy *x) | ||
358 | { | ||
359 | struct usb_phy_bind *phy_bind; | ||
360 | unsigned long flags; | ||
361 | |||
362 | if (!x->dev) { | ||
363 | dev_err(x->dev, "no device provided for PHY\n"); | ||
364 | return -EINVAL; | ||
365 | } | ||
366 | |||
367 | spin_lock_irqsave(&phy_lock, flags); | ||
368 | list_for_each_entry(phy_bind, &phy_bind_list, list) | ||
369 | if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev)))) | ||
370 | phy_bind->phy = x; | ||
371 | |||
372 | list_add_tail(&x->head, &phy_list); | ||
373 | |||
374 | spin_unlock_irqrestore(&phy_lock, flags); | ||
375 | return 0; | ||
376 | } | ||
377 | EXPORT_SYMBOL(usb_add_phy_dev); | ||
378 | |||
379 | /** | ||
188 | * usb_remove_phy - remove the OTG PHY | 380 | * usb_remove_phy - remove the OTG PHY |
189 | * @x: the USB OTG PHY to be removed; | 381 | * @x: the USB OTG PHY to be removed; |
190 | * | 382 | * |
@@ -193,14 +385,55 @@ EXPORT_SYMBOL(usb_add_phy); | |||
193 | void usb_remove_phy(struct usb_phy *x) | 385 | void usb_remove_phy(struct usb_phy *x) |
194 | { | 386 | { |
195 | unsigned long flags; | 387 | unsigned long flags; |
388 | struct usb_phy_bind *phy_bind; | ||
196 | 389 | ||
197 | spin_lock_irqsave(&phy_lock, flags); | 390 | spin_lock_irqsave(&phy_lock, flags); |
198 | if (x) | 391 | if (x) { |
392 | list_for_each_entry(phy_bind, &phy_bind_list, list) | ||
393 | if (phy_bind->phy == x) | ||
394 | phy_bind->phy = NULL; | ||
199 | list_del(&x->head); | 395 | list_del(&x->head); |
396 | } | ||
200 | spin_unlock_irqrestore(&phy_lock, flags); | 397 | spin_unlock_irqrestore(&phy_lock, flags); |
201 | } | 398 | } |
202 | EXPORT_SYMBOL(usb_remove_phy); | 399 | EXPORT_SYMBOL(usb_remove_phy); |
203 | 400 | ||
401 | /** | ||
402 | * usb_bind_phy - bind the phy and the controller that uses the phy | ||
403 | * @dev_name: the device name of the device that will bind to the phy | ||
404 | * @index: index to specify the port number | ||
405 | * @phy_dev_name: the device name of the phy | ||
406 | * | ||
407 | * Fills the phy_bind structure with the dev_name and phy_dev_name. This will | ||
408 | * be used when the phy driver registers the phy and when the controller | ||
409 | * requests this phy. | ||
410 | * | ||
411 | * To be used by platform specific initialization code. | ||
412 | */ | ||
413 | int __init usb_bind_phy(const char *dev_name, u8 index, | ||
414 | const char *phy_dev_name) | ||
415 | { | ||
416 | struct usb_phy_bind *phy_bind; | ||
417 | unsigned long flags; | ||
418 | |||
419 | phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL); | ||
420 | if (!phy_bind) { | ||
421 | pr_err("phy_bind(): No memory for phy_bind"); | ||
422 | return -ENOMEM; | ||
423 | } | ||
424 | |||
425 | phy_bind->dev_name = dev_name; | ||
426 | phy_bind->phy_dev_name = phy_dev_name; | ||
427 | phy_bind->index = index; | ||
428 | |||
429 | spin_lock_irqsave(&phy_lock, flags); | ||
430 | list_add_tail(&phy_bind->list, &phy_bind_list); | ||
431 | spin_unlock_irqrestore(&phy_lock, flags); | ||
432 | |||
433 | return 0; | ||
434 | } | ||
435 | EXPORT_SYMBOL_GPL(usb_bind_phy); | ||
436 | |||
204 | const char *otg_state_string(enum usb_otg_state state) | 437 | const char *otg_state_string(enum usb_otg_state state) |
205 | { | 438 | { |
206 | switch (state) { | 439 | switch (state) { |
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c index 0a701938ab53..a994715a3101 100644 --- a/drivers/usb/otg/twl4030-usb.c +++ b/drivers/usb/otg/twl4030-usb.c | |||
@@ -610,6 +610,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) | |||
610 | twl->phy.dev = twl->dev; | 610 | twl->phy.dev = twl->dev; |
611 | twl->phy.label = "twl4030"; | 611 | twl->phy.label = "twl4030"; |
612 | twl->phy.otg = otg; | 612 | twl->phy.otg = otg; |
613 | twl->phy.type = USB_PHY_TYPE_USB2; | ||
613 | twl->phy.set_suspend = twl4030_set_suspend; | 614 | twl->phy.set_suspend = twl4030_set_suspend; |
614 | 615 | ||
615 | otg->phy = &twl->phy; | 616 | otg->phy = &twl->phy; |
@@ -624,7 +625,7 @@ static int twl4030_usb_probe(struct platform_device *pdev) | |||
624 | dev_err(&pdev->dev, "ldo init failed\n"); | 625 | dev_err(&pdev->dev, "ldo init failed\n"); |
625 | return err; | 626 | return err; |
626 | } | 627 | } |
627 | usb_add_phy(&twl->phy, USB_PHY_TYPE_USB2); | 628 | usb_add_phy_dev(&twl->phy); |
628 | 629 | ||
629 | platform_set_drvdata(pdev, twl); | 630 | platform_set_drvdata(pdev, twl); |
630 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) | 631 | if (device_create_file(&pdev->dev, &dev_attr_vbus)) |
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 5de6e7f39f9c..9bbedecb3371 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig | |||
@@ -8,12 +8,33 @@ config OMAP_USB2 | |||
8 | tristate "OMAP USB2 PHY Driver" | 8 | tristate "OMAP USB2 PHY Driver" |
9 | depends on ARCH_OMAP2PLUS | 9 | depends on ARCH_OMAP2PLUS |
10 | select USB_OTG_UTILS | 10 | select USB_OTG_UTILS |
11 | select OMAP_CONTROL_USB | ||
11 | help | 12 | help |
12 | Enable this to support the transceiver that is part of SOC. This | 13 | Enable this to support the transceiver that is part of SOC. This |
13 | driver takes care of all the PHY functionality apart from comparator. | 14 | driver takes care of all the PHY functionality apart from comparator. |
14 | The USB OTG controller communicates with the comparator using this | 15 | The USB OTG controller communicates with the comparator using this |
15 | driver. | 16 | driver. |
16 | 17 | ||
18 | config OMAP_USB3 | ||
19 | tristate "OMAP USB3 PHY Driver" | ||
20 | select USB_OTG_UTILS | ||
21 | select OMAP_CONTROL_USB | ||
22 | help | ||
23 | Enable this to support the USB3 PHY that is part of SOC. This | ||
24 | driver takes care of all the PHY functionality apart from comparator. | ||
25 | This driver interacts with the "OMAP Control USB Driver" to power | ||
26 | on/off the PHY. | ||
27 | |||
28 | config OMAP_CONTROL_USB | ||
29 | tristate "OMAP CONTROL USB Driver" | ||
30 | depends on ARCH_OMAP2PLUS | ||
31 | help | ||
32 | Enable this to add support for the USB part present in the control | ||
33 | module. This driver has API to power on the USB2 PHY and to write to | ||
34 | the mailbox. The mailbox is present only in omap4 and the register to | ||
35 | power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an | ||
36 | additional register to power on USB3 PHY. | ||
37 | |||
17 | config USB_ISP1301 | 38 | config USB_ISP1301 |
18 | tristate "NXP ISP1301 USB transceiver support" | 39 | tristate "NXP ISP1301 USB transceiver support" |
19 | depends on USB || USB_GADGET | 40 | depends on USB || USB_GADGET |
@@ -45,3 +66,11 @@ config USB_RCAR_PHY | |||
45 | 66 | ||
46 | To compile this driver as a module, choose M here: the | 67 | To compile this driver as a module, choose M here: the |
47 | module will be called rcar-phy. | 68 | module will be called rcar-phy. |
69 | |||
70 | config SAMSUNG_USBPHY | ||
71 | bool "Samsung USB PHY controller Driver" | ||
72 | depends on USB_S3C_HSOTG || USB_EHCI_S5P || USB_OHCI_EXYNOS | ||
73 | select USB_OTG_UTILS | ||
74 | help | ||
75 | Enable this to support Samsung USB phy controller for samsung | ||
76 | SoCs. | ||
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index 1a579a860a03..b13faa193e0c 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile | |||
@@ -5,7 +5,10 @@ | |||
5 | ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG | 5 | ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG |
6 | 6 | ||
7 | obj-$(CONFIG_OMAP_USB2) += omap-usb2.o | 7 | obj-$(CONFIG_OMAP_USB2) += omap-usb2.o |
8 | obj-$(CONFIG_OMAP_USB3) += omap-usb3.o | ||
9 | obj-$(CONFIG_OMAP_CONTROL_USB) += omap-control-usb.o | ||
8 | obj-$(CONFIG_USB_ISP1301) += isp1301.o | 10 | obj-$(CONFIG_USB_ISP1301) += isp1301.o |
9 | obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o | 11 | obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o |
10 | obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o | 12 | obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.o |
11 | obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o | 13 | obj-$(CONFIG_USB_RCAR_PHY) += rcar-phy.o |
14 | obj-$(CONFIG_SAMSUNG_USBPHY) += samsung-usbphy.o | ||
diff --git a/drivers/usb/phy/omap-control-usb.c b/drivers/usb/phy/omap-control-usb.c new file mode 100644 index 000000000000..5323b71c3521 --- /dev/null +++ b/drivers/usb/phy/omap-control-usb.c | |||
@@ -0,0 +1,295 @@ | |||
1 | /* | ||
2 | * omap-control-usb.c - The USB part of control module. | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/of.h> | ||
23 | #include <linux/err.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/clk.h> | ||
26 | #include <linux/usb/omap_control_usb.h> | ||
27 | |||
28 | static struct omap_control_usb *control_usb; | ||
29 | |||
30 | /** | ||
31 | * omap_get_control_dev - returns the device pointer for this control device | ||
32 | * | ||
33 | * This API should be called to get the device pointer for this control | ||
34 | * module device. This device pointer should be used for called other | ||
35 | * exported API's in this driver. | ||
36 | * | ||
37 | * To be used by PHY driver and glue driver. | ||
38 | */ | ||
39 | struct device *omap_get_control_dev(void) | ||
40 | { | ||
41 | if (!control_usb) | ||
42 | return ERR_PTR(-ENODEV); | ||
43 | |||
44 | return control_usb->dev; | ||
45 | } | ||
46 | EXPORT_SYMBOL_GPL(omap_get_control_dev); | ||
47 | |||
48 | /** | ||
49 | * omap_control_usb3_phy_power - power on/off the serializer using control | ||
50 | * module | ||
51 | * @dev: the control module device | ||
52 | * @on: 0 to off and 1 to on based on powering on or off the PHY | ||
53 | * | ||
54 | * usb3 PHY driver should call this API to power on or off the PHY. | ||
55 | */ | ||
56 | void omap_control_usb3_phy_power(struct device *dev, bool on) | ||
57 | { | ||
58 | u32 val; | ||
59 | unsigned long rate; | ||
60 | struct omap_control_usb *control_usb = dev_get_drvdata(dev); | ||
61 | |||
62 | if (control_usb->type != OMAP_CTRL_DEV_TYPE2) | ||
63 | return; | ||
64 | |||
65 | rate = clk_get_rate(control_usb->sys_clk); | ||
66 | rate = rate/1000000; | ||
67 | |||
68 | val = readl(control_usb->phy_power); | ||
69 | |||
70 | if (on) { | ||
71 | val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK | | ||
72 | OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK); | ||
73 | val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON << | ||
74 | OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT; | ||
75 | val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT; | ||
76 | } else { | ||
77 | val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK; | ||
78 | val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF << | ||
79 | OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT; | ||
80 | } | ||
81 | |||
82 | writel(val, control_usb->phy_power); | ||
83 | } | ||
84 | EXPORT_SYMBOL_GPL(omap_control_usb3_phy_power); | ||
85 | |||
86 | /** | ||
87 | * omap_control_usb_phy_power - power on/off the phy using control module reg | ||
88 | * @dev: the control module device | ||
89 | * @on: 0 or 1, based on powering on or off the PHY | ||
90 | */ | ||
91 | void omap_control_usb_phy_power(struct device *dev, int on) | ||
92 | { | ||
93 | u32 val; | ||
94 | struct omap_control_usb *control_usb = dev_get_drvdata(dev); | ||
95 | |||
96 | val = readl(control_usb->dev_conf); | ||
97 | |||
98 | if (on) | ||
99 | val &= ~OMAP_CTRL_DEV_PHY_PD; | ||
100 | else | ||
101 | val |= OMAP_CTRL_DEV_PHY_PD; | ||
102 | |||
103 | writel(val, control_usb->dev_conf); | ||
104 | } | ||
105 | EXPORT_SYMBOL_GPL(omap_control_usb_phy_power); | ||
106 | |||
107 | /** | ||
108 | * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded | ||
109 | * @ctrl_usb: struct omap_control_usb * | ||
110 | * | ||
111 | * Writes to the mailbox register to notify the usb core that a usb | ||
112 | * device has been connected. | ||
113 | */ | ||
114 | static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb) | ||
115 | { | ||
116 | u32 val; | ||
117 | |||
118 | val = readl(ctrl_usb->otghs_control); | ||
119 | val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND); | ||
120 | val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID; | ||
121 | writel(val, ctrl_usb->otghs_control); | ||
122 | } | ||
123 | |||
124 | /** | ||
125 | * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high | ||
126 | * impedance | ||
127 | * @ctrl_usb: struct omap_control_usb * | ||
128 | * | ||
129 | * Writes to the mailbox register to notify the usb core that it has been | ||
130 | * connected to a usb host. | ||
131 | */ | ||
132 | static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb) | ||
133 | { | ||
134 | u32 val; | ||
135 | |||
136 | val = readl(ctrl_usb->otghs_control); | ||
137 | val &= ~OMAP_CTRL_DEV_SESSEND; | ||
138 | val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID | | ||
139 | OMAP_CTRL_DEV_VBUSVALID; | ||
140 | writel(val, ctrl_usb->otghs_control); | ||
141 | } | ||
142 | |||
143 | /** | ||
144 | * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high | ||
145 | * impedance | ||
146 | * @ctrl_usb: struct omap_control_usb * | ||
147 | * | ||
148 | * Writes to the mailbox register to notify the usb core it's now in | ||
149 | * disconnected state. | ||
150 | */ | ||
151 | static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb) | ||
152 | { | ||
153 | u32 val; | ||
154 | |||
155 | val = readl(ctrl_usb->otghs_control); | ||
156 | val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID); | ||
157 | val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND; | ||
158 | writel(val, ctrl_usb->otghs_control); | ||
159 | } | ||
160 | |||
161 | /** | ||
162 | * omap_control_usb_set_mode - Calls to functions to set USB in one of host mode | ||
163 | * or device mode or to denote disconnected state | ||
164 | * @dev: the control module device | ||
165 | * @mode: The mode to which usb should be configured | ||
166 | * | ||
167 | * This is an API to write to the mailbox register to notify the usb core that | ||
168 | * a usb device has been connected. | ||
169 | */ | ||
170 | void omap_control_usb_set_mode(struct device *dev, | ||
171 | enum omap_control_usb_mode mode) | ||
172 | { | ||
173 | struct omap_control_usb *ctrl_usb; | ||
174 | |||
175 | if (IS_ERR(dev) || control_usb->type != OMAP_CTRL_DEV_TYPE1) | ||
176 | return; | ||
177 | |||
178 | ctrl_usb = dev_get_drvdata(dev); | ||
179 | |||
180 | switch (mode) { | ||
181 | case USB_MODE_HOST: | ||
182 | omap_control_usb_host_mode(ctrl_usb); | ||
183 | break; | ||
184 | case USB_MODE_DEVICE: | ||
185 | omap_control_usb_device_mode(ctrl_usb); | ||
186 | break; | ||
187 | case USB_MODE_DISCONNECT: | ||
188 | omap_control_usb_set_sessionend(ctrl_usb); | ||
189 | break; | ||
190 | default: | ||
191 | dev_vdbg(dev, "invalid omap control usb mode\n"); | ||
192 | } | ||
193 | } | ||
194 | EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); | ||
195 | |||
196 | static int omap_control_usb_probe(struct platform_device *pdev) | ||
197 | { | ||
198 | struct resource *res; | ||
199 | struct device_node *np = pdev->dev.of_node; | ||
200 | struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data; | ||
201 | |||
202 | control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb), | ||
203 | GFP_KERNEL); | ||
204 | if (!control_usb) { | ||
205 | dev_err(&pdev->dev, "unable to alloc memory for control usb\n"); | ||
206 | return -ENOMEM; | ||
207 | } | ||
208 | |||
209 | if (np) { | ||
210 | of_property_read_u32(np, "ti,type", &control_usb->type); | ||
211 | } else if (pdata) { | ||
212 | control_usb->type = pdata->type; | ||
213 | } else { | ||
214 | dev_err(&pdev->dev, "no pdata present\n"); | ||
215 | return -EINVAL; | ||
216 | } | ||
217 | |||
218 | control_usb->dev = &pdev->dev; | ||
219 | |||
220 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
221 | "control_dev_conf"); | ||
222 | control_usb->dev_conf = devm_request_and_ioremap(&pdev->dev, res); | ||
223 | if (!control_usb->dev_conf) { | ||
224 | dev_err(&pdev->dev, "Failed to obtain io memory\n"); | ||
225 | return -EADDRNOTAVAIL; | ||
226 | } | ||
227 | |||
228 | if (control_usb->type == OMAP_CTRL_DEV_TYPE1) { | ||
229 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
230 | "otghs_control"); | ||
231 | control_usb->otghs_control = devm_request_and_ioremap( | ||
232 | &pdev->dev, res); | ||
233 | if (!control_usb->otghs_control) { | ||
234 | dev_err(&pdev->dev, "Failed to obtain io memory\n"); | ||
235 | return -EADDRNOTAVAIL; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | if (control_usb->type == OMAP_CTRL_DEV_TYPE2) { | ||
240 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, | ||
241 | "phy_power_usb"); | ||
242 | control_usb->phy_power = devm_request_and_ioremap( | ||
243 | &pdev->dev, res); | ||
244 | if (!control_usb->phy_power) { | ||
245 | dev_dbg(&pdev->dev, "Failed to obtain io memory\n"); | ||
246 | return -EADDRNOTAVAIL; | ||
247 | } | ||
248 | |||
249 | control_usb->sys_clk = devm_clk_get(control_usb->dev, | ||
250 | "sys_clkin"); | ||
251 | if (IS_ERR(control_usb->sys_clk)) { | ||
252 | pr_err("%s: unable to get sys_clkin\n", __func__); | ||
253 | return -EINVAL; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | |||
258 | dev_set_drvdata(control_usb->dev, control_usb); | ||
259 | |||
260 | return 0; | ||
261 | } | ||
262 | |||
263 | #ifdef CONFIG_OF | ||
264 | static const struct of_device_id omap_control_usb_id_table[] = { | ||
265 | { .compatible = "ti,omap-control-usb" }, | ||
266 | {} | ||
267 | }; | ||
268 | MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); | ||
269 | #endif | ||
270 | |||
271 | static struct platform_driver omap_control_usb_driver = { | ||
272 | .probe = omap_control_usb_probe, | ||
273 | .driver = { | ||
274 | .name = "omap-control-usb", | ||
275 | .owner = THIS_MODULE, | ||
276 | .of_match_table = of_match_ptr(omap_control_usb_id_table), | ||
277 | }, | ||
278 | }; | ||
279 | |||
280 | static int __init omap_control_usb_init(void) | ||
281 | { | ||
282 | return platform_driver_register(&omap_control_usb_driver); | ||
283 | } | ||
284 | subsys_initcall(omap_control_usb_init); | ||
285 | |||
286 | static void __exit omap_control_usb_exit(void) | ||
287 | { | ||
288 | platform_driver_unregister(&omap_control_usb_driver); | ||
289 | } | ||
290 | module_exit(omap_control_usb_exit); | ||
291 | |||
292 | MODULE_ALIAS("platform: omap_control_usb"); | ||
293 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
294 | MODULE_DESCRIPTION("OMAP Control Module USB Driver"); | ||
295 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c index 26ae8f49225c..844ab68f08d0 100644 --- a/drivers/usb/phy/omap-usb2.c +++ b/drivers/usb/phy/omap-usb2.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/err.h> | 27 | #include <linux/err.h> |
28 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/usb/omap_control_usb.h> | ||
30 | 31 | ||
31 | /** | 32 | /** |
32 | * omap_usb2_set_comparator - links the comparator present in the sytem with | 33 | * omap_usb2_set_comparator - links the comparator present in the sytem with |
@@ -52,29 +53,6 @@ int omap_usb2_set_comparator(struct phy_companion *comparator) | |||
52 | } | 53 | } |
53 | EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); | 54 | EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); |
54 | 55 | ||
55 | /** | ||
56 | * omap_usb_phy_power - power on/off the phy using control module reg | ||
57 | * @phy: struct omap_usb * | ||
58 | * @on: 0 or 1, based on powering on or off the PHY | ||
59 | * | ||
60 | * XXX: Remove this function once control module driver gets merged | ||
61 | */ | ||
62 | static void omap_usb_phy_power(struct omap_usb *phy, int on) | ||
63 | { | ||
64 | u32 val; | ||
65 | |||
66 | if (on) { | ||
67 | val = readl(phy->control_dev); | ||
68 | if (val & PHY_PD) { | ||
69 | writel(~PHY_PD, phy->control_dev); | ||
70 | /* XXX: add proper documentation for this delay */ | ||
71 | mdelay(200); | ||
72 | } | ||
73 | } else { | ||
74 | writel(PHY_PD, phy->control_dev); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) | 56 | static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) |
79 | { | 57 | { |
80 | struct omap_usb *phy = phy_to_omapusb(otg->phy); | 58 | struct omap_usb *phy = phy_to_omapusb(otg->phy); |
@@ -124,7 +102,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend) | |||
124 | struct omap_usb *phy = phy_to_omapusb(x); | 102 | struct omap_usb *phy = phy_to_omapusb(x); |
125 | 103 | ||
126 | if (suspend && !phy->is_suspended) { | 104 | if (suspend && !phy->is_suspended) { |
127 | omap_usb_phy_power(phy, 0); | 105 | omap_control_usb_phy_power(phy->control_dev, 0); |
128 | pm_runtime_put_sync(phy->dev); | 106 | pm_runtime_put_sync(phy->dev); |
129 | phy->is_suspended = 1; | 107 | phy->is_suspended = 1; |
130 | } else if (!suspend && phy->is_suspended) { | 108 | } else if (!suspend && phy->is_suspended) { |
@@ -134,7 +112,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend) | |||
134 | ret); | 112 | ret); |
135 | return ret; | 113 | return ret; |
136 | } | 114 | } |
137 | omap_usb_phy_power(phy, 1); | 115 | omap_control_usb_phy_power(phy->control_dev, 1); |
138 | phy->is_suspended = 0; | 116 | phy->is_suspended = 0; |
139 | } | 117 | } |
140 | 118 | ||
@@ -145,7 +123,6 @@ static int omap_usb2_probe(struct platform_device *pdev) | |||
145 | { | 123 | { |
146 | struct omap_usb *phy; | 124 | struct omap_usb *phy; |
147 | struct usb_otg *otg; | 125 | struct usb_otg *otg; |
148 | struct resource *res; | ||
149 | 126 | ||
150 | phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); | 127 | phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); |
151 | if (!phy) { | 128 | if (!phy) { |
@@ -165,17 +142,16 @@ static int omap_usb2_probe(struct platform_device *pdev) | |||
165 | phy->phy.label = "omap-usb2"; | 142 | phy->phy.label = "omap-usb2"; |
166 | phy->phy.set_suspend = omap_usb2_suspend; | 143 | phy->phy.set_suspend = omap_usb2_suspend; |
167 | phy->phy.otg = otg; | 144 | phy->phy.otg = otg; |
145 | phy->phy.type = USB_PHY_TYPE_USB2; | ||
168 | 146 | ||
169 | res = platform_get_resource(pdev, IORESOURCE_MEM, 1); | 147 | phy->control_dev = omap_get_control_dev(); |
170 | 148 | if (IS_ERR(phy->control_dev)) { | |
171 | phy->control_dev = devm_request_and_ioremap(&pdev->dev, res); | 149 | dev_dbg(&pdev->dev, "Failed to get control device\n"); |
172 | if (phy->control_dev == NULL) { | 150 | return -ENODEV; |
173 | dev_err(&pdev->dev, "Failed to obtain io memory\n"); | ||
174 | return -ENXIO; | ||
175 | } | 151 | } |
176 | 152 | ||
177 | phy->is_suspended = 1; | 153 | phy->is_suspended = 1; |
178 | omap_usb_phy_power(phy, 0); | 154 | omap_control_usb_phy_power(phy->control_dev, 0); |
179 | 155 | ||
180 | otg->set_host = omap_usb_set_host; | 156 | otg->set_host = omap_usb_set_host; |
181 | otg->set_peripheral = omap_usb_set_peripheral; | 157 | otg->set_peripheral = omap_usb_set_peripheral; |
@@ -190,7 +166,13 @@ static int omap_usb2_probe(struct platform_device *pdev) | |||
190 | } | 166 | } |
191 | clk_prepare(phy->wkupclk); | 167 | clk_prepare(phy->wkupclk); |
192 | 168 | ||
193 | usb_add_phy(&phy->phy, USB_PHY_TYPE_USB2); | 169 | phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); |
170 | if (IS_ERR(phy->optclk)) | ||
171 | dev_vdbg(&pdev->dev, "unable to get refclk960m\n"); | ||
172 | else | ||
173 | clk_prepare(phy->optclk); | ||
174 | |||
175 | usb_add_phy_dev(&phy->phy); | ||
194 | 176 | ||
195 | platform_set_drvdata(pdev, phy); | 177 | platform_set_drvdata(pdev, phy); |
196 | 178 | ||
@@ -204,6 +186,8 @@ static int omap_usb2_remove(struct platform_device *pdev) | |||
204 | struct omap_usb *phy = platform_get_drvdata(pdev); | 186 | struct omap_usb *phy = platform_get_drvdata(pdev); |
205 | 187 | ||
206 | clk_unprepare(phy->wkupclk); | 188 | clk_unprepare(phy->wkupclk); |
189 | if (!IS_ERR(phy->optclk)) | ||
190 | clk_unprepare(phy->optclk); | ||
207 | usb_remove_phy(&phy->phy); | 191 | usb_remove_phy(&phy->phy); |
208 | 192 | ||
209 | return 0; | 193 | return 0; |
@@ -217,6 +201,8 @@ static int omap_usb2_runtime_suspend(struct device *dev) | |||
217 | struct omap_usb *phy = platform_get_drvdata(pdev); | 201 | struct omap_usb *phy = platform_get_drvdata(pdev); |
218 | 202 | ||
219 | clk_disable(phy->wkupclk); | 203 | clk_disable(phy->wkupclk); |
204 | if (!IS_ERR(phy->optclk)) | ||
205 | clk_disable(phy->optclk); | ||
220 | 206 | ||
221 | return 0; | 207 | return 0; |
222 | } | 208 | } |
@@ -228,9 +214,25 @@ static int omap_usb2_runtime_resume(struct device *dev) | |||
228 | struct omap_usb *phy = platform_get_drvdata(pdev); | 214 | struct omap_usb *phy = platform_get_drvdata(pdev); |
229 | 215 | ||
230 | ret = clk_enable(phy->wkupclk); | 216 | ret = clk_enable(phy->wkupclk); |
231 | if (ret < 0) | 217 | if (ret < 0) { |
232 | dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); | 218 | dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); |
219 | goto err0; | ||
220 | } | ||
221 | |||
222 | if (!IS_ERR(phy->optclk)) { | ||
223 | ret = clk_enable(phy->optclk); | ||
224 | if (ret < 0) { | ||
225 | dev_err(phy->dev, "Failed to enable optclk %d\n", ret); | ||
226 | goto err1; | ||
227 | } | ||
228 | } | ||
229 | |||
230 | return 0; | ||
231 | |||
232 | err1: | ||
233 | clk_disable(phy->wkupclk); | ||
233 | 234 | ||
235 | err0: | ||
234 | return ret; | 236 | return ret; |
235 | } | 237 | } |
236 | 238 | ||
diff --git a/drivers/usb/phy/omap-usb3.c b/drivers/usb/phy/omap-usb3.c new file mode 100644 index 000000000000..fadc0c2b65bb --- /dev/null +++ b/drivers/usb/phy/omap-usb3.c | |||
@@ -0,0 +1,355 @@ | |||
1 | /* | ||
2 | * omap-usb3 - USB PHY, talking to dwc3 controller in OMAP. | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/usb/omap_usb.h> | ||
23 | #include <linux/of.h> | ||
24 | #include <linux/clk.h> | ||
25 | #include <linux/err.h> | ||
26 | #include <linux/pm_runtime.h> | ||
27 | #include <linux/delay.h> | ||
28 | #include <linux/usb/omap_control_usb.h> | ||
29 | |||
30 | #define NUM_SYS_CLKS 5 | ||
31 | #define PLL_STATUS 0x00000004 | ||
32 | #define PLL_GO 0x00000008 | ||
33 | #define PLL_CONFIGURATION1 0x0000000C | ||
34 | #define PLL_CONFIGURATION2 0x00000010 | ||
35 | #define PLL_CONFIGURATION3 0x00000014 | ||
36 | #define PLL_CONFIGURATION4 0x00000020 | ||
37 | |||
38 | #define PLL_REGM_MASK 0x001FFE00 | ||
39 | #define PLL_REGM_SHIFT 0x9 | ||
40 | #define PLL_REGM_F_MASK 0x0003FFFF | ||
41 | #define PLL_REGM_F_SHIFT 0x0 | ||
42 | #define PLL_REGN_MASK 0x000001FE | ||
43 | #define PLL_REGN_SHIFT 0x1 | ||
44 | #define PLL_SELFREQDCO_MASK 0x0000000E | ||
45 | #define PLL_SELFREQDCO_SHIFT 0x1 | ||
46 | #define PLL_SD_MASK 0x0003FC00 | ||
47 | #define PLL_SD_SHIFT 0x9 | ||
48 | #define SET_PLL_GO 0x1 | ||
49 | #define PLL_TICOPWDN 0x10000 | ||
50 | #define PLL_LOCK 0x2 | ||
51 | #define PLL_IDLE 0x1 | ||
52 | |||
53 | /* | ||
54 | * This is an Empirical value that works, need to confirm the actual | ||
55 | * value required for the USB3PHY_PLL_CONFIGURATION2.PLL_IDLE status | ||
56 | * to be correctly reflected in the USB3PHY_PLL_STATUS register. | ||
57 | */ | ||
58 | # define PLL_IDLE_TIME 100; | ||
59 | |||
60 | enum sys_clk_rate { | ||
61 | CLK_RATE_UNDEFINED = -1, | ||
62 | CLK_RATE_12MHZ, | ||
63 | CLK_RATE_16MHZ, | ||
64 | CLK_RATE_19MHZ, | ||
65 | CLK_RATE_26MHZ, | ||
66 | CLK_RATE_38MHZ | ||
67 | }; | ||
68 | |||
69 | static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = { | ||
70 | {1250, 5, 4, 20, 0}, /* 12 MHz */ | ||
71 | {3125, 20, 4, 20, 0}, /* 16.8 MHz */ | ||
72 | {1172, 8, 4, 20, 65537}, /* 19.2 MHz */ | ||
73 | {1250, 12, 4, 20, 0}, /* 26 MHz */ | ||
74 | {3125, 47, 4, 20, 92843}, /* 38.4 MHz */ | ||
75 | }; | ||
76 | |||
77 | static int omap_usb3_suspend(struct usb_phy *x, int suspend) | ||
78 | { | ||
79 | struct omap_usb *phy = phy_to_omapusb(x); | ||
80 | int val; | ||
81 | int timeout = PLL_IDLE_TIME; | ||
82 | |||
83 | if (suspend && !phy->is_suspended) { | ||
84 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); | ||
85 | val |= PLL_IDLE; | ||
86 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); | ||
87 | |||
88 | do { | ||
89 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); | ||
90 | if (val & PLL_TICOPWDN) | ||
91 | break; | ||
92 | udelay(1); | ||
93 | } while (--timeout); | ||
94 | |||
95 | omap_control_usb3_phy_power(phy->control_dev, 0); | ||
96 | |||
97 | phy->is_suspended = 1; | ||
98 | } else if (!suspend && phy->is_suspended) { | ||
99 | phy->is_suspended = 0; | ||
100 | |||
101 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); | ||
102 | val &= ~PLL_IDLE; | ||
103 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); | ||
104 | |||
105 | do { | ||
106 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); | ||
107 | if (!(val & PLL_TICOPWDN)) | ||
108 | break; | ||
109 | udelay(1); | ||
110 | } while (--timeout); | ||
111 | } | ||
112 | |||
113 | return 0; | ||
114 | } | ||
115 | |||
116 | static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate) | ||
117 | { | ||
118 | switch (rate) { | ||
119 | case 12000000: | ||
120 | return CLK_RATE_12MHZ; | ||
121 | case 16800000: | ||
122 | return CLK_RATE_16MHZ; | ||
123 | case 19200000: | ||
124 | return CLK_RATE_19MHZ; | ||
125 | case 26000000: | ||
126 | return CLK_RATE_26MHZ; | ||
127 | case 38400000: | ||
128 | return CLK_RATE_38MHZ; | ||
129 | default: | ||
130 | return CLK_RATE_UNDEFINED; | ||
131 | } | ||
132 | } | ||
133 | |||
134 | static void omap_usb_dpll_relock(struct omap_usb *phy) | ||
135 | { | ||
136 | u32 val; | ||
137 | unsigned long timeout; | ||
138 | |||
139 | omap_usb_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO); | ||
140 | |||
141 | timeout = jiffies + msecs_to_jiffies(20); | ||
142 | do { | ||
143 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); | ||
144 | if (val & PLL_LOCK) | ||
145 | break; | ||
146 | } while (!WARN_ON(time_after(jiffies, timeout))); | ||
147 | } | ||
148 | |||
149 | static int omap_usb_dpll_lock(struct omap_usb *phy) | ||
150 | { | ||
151 | u32 val; | ||
152 | unsigned long rate; | ||
153 | enum sys_clk_rate clk_index; | ||
154 | |||
155 | rate = clk_get_rate(phy->sys_clk); | ||
156 | clk_index = __get_sys_clk_index(rate); | ||
157 | |||
158 | if (clk_index == CLK_RATE_UNDEFINED) { | ||
159 | pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate); | ||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); | ||
164 | val &= ~PLL_REGN_MASK; | ||
165 | val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT; | ||
166 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); | ||
167 | |||
168 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); | ||
169 | val &= ~PLL_SELFREQDCO_MASK; | ||
170 | val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT; | ||
171 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); | ||
172 | |||
173 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); | ||
174 | val &= ~PLL_REGM_MASK; | ||
175 | val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT; | ||
176 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); | ||
177 | |||
178 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); | ||
179 | val &= ~PLL_REGM_F_MASK; | ||
180 | val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT; | ||
181 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); | ||
182 | |||
183 | val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); | ||
184 | val &= ~PLL_SD_MASK; | ||
185 | val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT; | ||
186 | omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); | ||
187 | |||
188 | omap_usb_dpll_relock(phy); | ||
189 | |||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int omap_usb3_init(struct usb_phy *x) | ||
194 | { | ||
195 | struct omap_usb *phy = phy_to_omapusb(x); | ||
196 | |||
197 | omap_usb_dpll_lock(phy); | ||
198 | omap_control_usb3_phy_power(phy->control_dev, 1); | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static int omap_usb3_probe(struct platform_device *pdev) | ||
204 | { | ||
205 | struct omap_usb *phy; | ||
206 | struct resource *res; | ||
207 | |||
208 | phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); | ||
209 | if (!phy) { | ||
210 | dev_err(&pdev->dev, "unable to alloc mem for OMAP USB3 PHY\n"); | ||
211 | return -ENOMEM; | ||
212 | } | ||
213 | |||
214 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); | ||
215 | phy->pll_ctrl_base = devm_request_and_ioremap(&pdev->dev, res); | ||
216 | if (!phy->pll_ctrl_base) { | ||
217 | dev_err(&pdev->dev, "ioremap of pll_ctrl failed\n"); | ||
218 | return -ENOMEM; | ||
219 | } | ||
220 | |||
221 | phy->dev = &pdev->dev; | ||
222 | |||
223 | phy->phy.dev = phy->dev; | ||
224 | phy->phy.label = "omap-usb3"; | ||
225 | phy->phy.init = omap_usb3_init; | ||
226 | phy->phy.set_suspend = omap_usb3_suspend; | ||
227 | phy->phy.type = USB_PHY_TYPE_USB3; | ||
228 | |||
229 | phy->is_suspended = 1; | ||
230 | phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); | ||
231 | if (IS_ERR(phy->wkupclk)) { | ||
232 | dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); | ||
233 | return PTR_ERR(phy->wkupclk); | ||
234 | } | ||
235 | clk_prepare(phy->wkupclk); | ||
236 | |||
237 | phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); | ||
238 | if (IS_ERR(phy->optclk)) { | ||
239 | dev_err(&pdev->dev, "unable to get usb_otg_ss_refclk960m\n"); | ||
240 | return PTR_ERR(phy->optclk); | ||
241 | } | ||
242 | clk_prepare(phy->optclk); | ||
243 | |||
244 | phy->sys_clk = devm_clk_get(phy->dev, "sys_clkin"); | ||
245 | if (IS_ERR(phy->sys_clk)) { | ||
246 | pr_err("%s: unable to get sys_clkin\n", __func__); | ||
247 | return -EINVAL; | ||
248 | } | ||
249 | |||
250 | phy->control_dev = omap_get_control_dev(); | ||
251 | if (IS_ERR(phy->control_dev)) { | ||
252 | dev_dbg(&pdev->dev, "Failed to get control device\n"); | ||
253 | return -ENODEV; | ||
254 | } | ||
255 | |||
256 | omap_control_usb3_phy_power(phy->control_dev, 0); | ||
257 | usb_add_phy_dev(&phy->phy); | ||
258 | |||
259 | platform_set_drvdata(pdev, phy); | ||
260 | |||
261 | pm_runtime_enable(phy->dev); | ||
262 | pm_runtime_get(&pdev->dev); | ||
263 | |||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int omap_usb3_remove(struct platform_device *pdev) | ||
268 | { | ||
269 | struct omap_usb *phy = platform_get_drvdata(pdev); | ||
270 | |||
271 | clk_unprepare(phy->wkupclk); | ||
272 | clk_unprepare(phy->optclk); | ||
273 | usb_remove_phy(&phy->phy); | ||
274 | if (!pm_runtime_suspended(&pdev->dev)) | ||
275 | pm_runtime_put(&pdev->dev); | ||
276 | pm_runtime_disable(&pdev->dev); | ||
277 | |||
278 | return 0; | ||
279 | } | ||
280 | |||
281 | #ifdef CONFIG_PM_RUNTIME | ||
282 | |||
283 | static int omap_usb3_runtime_suspend(struct device *dev) | ||
284 | { | ||
285 | struct platform_device *pdev = to_platform_device(dev); | ||
286 | struct omap_usb *phy = platform_get_drvdata(pdev); | ||
287 | |||
288 | clk_disable(phy->wkupclk); | ||
289 | clk_disable(phy->optclk); | ||
290 | |||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int omap_usb3_runtime_resume(struct device *dev) | ||
295 | { | ||
296 | u32 ret = 0; | ||
297 | struct platform_device *pdev = to_platform_device(dev); | ||
298 | struct omap_usb *phy = platform_get_drvdata(pdev); | ||
299 | |||
300 | ret = clk_enable(phy->optclk); | ||
301 | if (ret) { | ||
302 | dev_err(phy->dev, "Failed to enable optclk %d\n", ret); | ||
303 | goto err1; | ||
304 | } | ||
305 | |||
306 | ret = clk_enable(phy->wkupclk); | ||
307 | if (ret) { | ||
308 | dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); | ||
309 | goto err2; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | |||
314 | err2: | ||
315 | clk_disable(phy->optclk); | ||
316 | |||
317 | err1: | ||
318 | return ret; | ||
319 | } | ||
320 | |||
321 | static const struct dev_pm_ops omap_usb3_pm_ops = { | ||
322 | SET_RUNTIME_PM_OPS(omap_usb3_runtime_suspend, omap_usb3_runtime_resume, | ||
323 | NULL) | ||
324 | }; | ||
325 | |||
326 | #define DEV_PM_OPS (&omap_usb3_pm_ops) | ||
327 | #else | ||
328 | #define DEV_PM_OPS NULL | ||
329 | #endif | ||
330 | |||
331 | #ifdef CONFIG_OF | ||
332 | static const struct of_device_id omap_usb3_id_table[] = { | ||
333 | { .compatible = "ti,omap-usb3" }, | ||
334 | {} | ||
335 | }; | ||
336 | MODULE_DEVICE_TABLE(of, omap_usb3_id_table); | ||
337 | #endif | ||
338 | |||
339 | static struct platform_driver omap_usb3_driver = { | ||
340 | .probe = omap_usb3_probe, | ||
341 | .remove = omap_usb3_remove, | ||
342 | .driver = { | ||
343 | .name = "omap-usb3", | ||
344 | .owner = THIS_MODULE, | ||
345 | .pm = DEV_PM_OPS, | ||
346 | .of_match_table = of_match_ptr(omap_usb3_id_table), | ||
347 | }, | ||
348 | }; | ||
349 | |||
350 | module_platform_driver(omap_usb3_driver); | ||
351 | |||
352 | MODULE_ALIAS("platform: omap_usb3"); | ||
353 | MODULE_AUTHOR("Texas Instruments Inc."); | ||
354 | MODULE_DESCRIPTION("OMAP USB3 phy driver"); | ||
355 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/usb/phy/samsung-usbphy.c b/drivers/usb/phy/samsung-usbphy.c new file mode 100644 index 000000000000..6ea553733832 --- /dev/null +++ b/drivers/usb/phy/samsung-usbphy.c | |||
@@ -0,0 +1,930 @@ | |||
1 | /* linux/drivers/usb/phy/samsung-usbphy.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 USB2.0 PHY transceiver; talks to S3C HS OTG controller, EHCI-S5P and | ||
9 | * OHCI-EXYNOS controllers. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/device.h> | ||
26 | #include <linux/err.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <linux/of.h> | ||
29 | #include <linux/of_address.h> | ||
30 | #include <linux/usb/otg.h> | ||
31 | #include <linux/usb/samsung_usb_phy.h> | ||
32 | #include <linux/platform_data/samsung-usbphy.h> | ||
33 | |||
34 | /* Register definitions */ | ||
35 | |||
36 | #define SAMSUNG_PHYPWR (0x00) | ||
37 | |||
38 | #define PHYPWR_NORMAL_MASK (0x19 << 0) | ||
39 | #define PHYPWR_OTG_DISABLE (0x1 << 4) | ||
40 | #define PHYPWR_ANALOG_POWERDOWN (0x1 << 3) | ||
41 | #define PHYPWR_FORCE_SUSPEND (0x1 << 1) | ||
42 | /* For Exynos4 */ | ||
43 | #define PHYPWR_NORMAL_MASK_PHY0 (0x39 << 0) | ||
44 | #define PHYPWR_SLEEP_PHY0 (0x1 << 5) | ||
45 | |||
46 | #define SAMSUNG_PHYCLK (0x04) | ||
47 | |||
48 | #define PHYCLK_MODE_USB11 (0x1 << 6) | ||
49 | #define PHYCLK_EXT_OSC (0x1 << 5) | ||
50 | #define PHYCLK_COMMON_ON_N (0x1 << 4) | ||
51 | #define PHYCLK_ID_PULL (0x1 << 2) | ||
52 | #define PHYCLK_CLKSEL_MASK (0x3 << 0) | ||
53 | #define PHYCLK_CLKSEL_48M (0x0 << 0) | ||
54 | #define PHYCLK_CLKSEL_12M (0x2 << 0) | ||
55 | #define PHYCLK_CLKSEL_24M (0x3 << 0) | ||
56 | |||
57 | #define SAMSUNG_RSTCON (0x08) | ||
58 | |||
59 | #define RSTCON_PHYLINK_SWRST (0x1 << 2) | ||
60 | #define RSTCON_HLINK_SWRST (0x1 << 1) | ||
61 | #define RSTCON_SWRST (0x1 << 0) | ||
62 | |||
63 | /* EXYNOS5 */ | ||
64 | #define EXYNOS5_PHY_HOST_CTRL0 (0x00) | ||
65 | |||
66 | #define HOST_CTRL0_PHYSWRSTALL (0x1 << 31) | ||
67 | |||
68 | #define HOST_CTRL0_REFCLKSEL_MASK (0x3 << 19) | ||
69 | #define HOST_CTRL0_REFCLKSEL_XTAL (0x0 << 19) | ||
70 | #define HOST_CTRL0_REFCLKSEL_EXTL (0x1 << 19) | ||
71 | #define HOST_CTRL0_REFCLKSEL_CLKCORE (0x2 << 19) | ||
72 | |||
73 | #define HOST_CTRL0_FSEL_MASK (0x7 << 16) | ||
74 | #define HOST_CTRL0_FSEL(_x) ((_x) << 16) | ||
75 | |||
76 | #define FSEL_CLKSEL_50M (0x7) | ||
77 | #define FSEL_CLKSEL_24M (0x5) | ||
78 | #define FSEL_CLKSEL_20M (0x4) | ||
79 | #define FSEL_CLKSEL_19200K (0x3) | ||
80 | #define FSEL_CLKSEL_12M (0x2) | ||
81 | #define FSEL_CLKSEL_10M (0x1) | ||
82 | #define FSEL_CLKSEL_9600K (0x0) | ||
83 | |||
84 | #define HOST_CTRL0_TESTBURNIN (0x1 << 11) | ||
85 | #define HOST_CTRL0_RETENABLE (0x1 << 10) | ||
86 | #define HOST_CTRL0_COMMONON_N (0x1 << 9) | ||
87 | #define HOST_CTRL0_SIDDQ (0x1 << 6) | ||
88 | #define HOST_CTRL0_FORCESLEEP (0x1 << 5) | ||
89 | #define HOST_CTRL0_FORCESUSPEND (0x1 << 4) | ||
90 | #define HOST_CTRL0_WORDINTERFACE (0x1 << 3) | ||
91 | #define HOST_CTRL0_UTMISWRST (0x1 << 2) | ||
92 | #define HOST_CTRL0_LINKSWRST (0x1 << 1) | ||
93 | #define HOST_CTRL0_PHYSWRST (0x1 << 0) | ||
94 | |||
95 | #define EXYNOS5_PHY_HOST_TUNE0 (0x04) | ||
96 | |||
97 | #define EXYNOS5_PHY_HSIC_CTRL1 (0x10) | ||
98 | |||
99 | #define EXYNOS5_PHY_HSIC_TUNE1 (0x14) | ||
100 | |||
101 | #define EXYNOS5_PHY_HSIC_CTRL2 (0x20) | ||
102 | |||
103 | #define EXYNOS5_PHY_HSIC_TUNE2 (0x24) | ||
104 | |||
105 | #define HSIC_CTRL_REFCLKSEL_MASK (0x3 << 23) | ||
106 | #define HSIC_CTRL_REFCLKSEL (0x2 << 23) | ||
107 | |||
108 | #define HSIC_CTRL_REFCLKDIV_MASK (0x7f << 16) | ||
109 | #define HSIC_CTRL_REFCLKDIV(_x) ((_x) << 16) | ||
110 | #define HSIC_CTRL_REFCLKDIV_12 (0x24 << 16) | ||
111 | #define HSIC_CTRL_REFCLKDIV_15 (0x1c << 16) | ||
112 | #define HSIC_CTRL_REFCLKDIV_16 (0x1a << 16) | ||
113 | #define HSIC_CTRL_REFCLKDIV_19_2 (0x15 << 16) | ||
114 | #define HSIC_CTRL_REFCLKDIV_20 (0x14 << 16) | ||
115 | |||
116 | #define HSIC_CTRL_SIDDQ (0x1 << 6) | ||
117 | #define HSIC_CTRL_FORCESLEEP (0x1 << 5) | ||
118 | #define HSIC_CTRL_FORCESUSPEND (0x1 << 4) | ||
119 | #define HSIC_CTRL_WORDINTERFACE (0x1 << 3) | ||
120 | #define HSIC_CTRL_UTMISWRST (0x1 << 2) | ||
121 | #define HSIC_CTRL_PHYSWRST (0x1 << 0) | ||
122 | |||
123 | #define EXYNOS5_PHY_HOST_EHCICTRL (0x30) | ||
124 | |||
125 | #define HOST_EHCICTRL_ENAINCRXALIGN (0x1 << 29) | ||
126 | #define HOST_EHCICTRL_ENAINCR4 (0x1 << 28) | ||
127 | #define HOST_EHCICTRL_ENAINCR8 (0x1 << 27) | ||
128 | #define HOST_EHCICTRL_ENAINCR16 (0x1 << 26) | ||
129 | |||
130 | #define EXYNOS5_PHY_HOST_OHCICTRL (0x34) | ||
131 | |||
132 | #define HOST_OHCICTRL_SUSPLGCY (0x1 << 3) | ||
133 | #define HOST_OHCICTRL_APPSTARTCLK (0x1 << 2) | ||
134 | #define HOST_OHCICTRL_CNTSEL (0x1 << 1) | ||
135 | #define HOST_OHCICTRL_CLKCKTRST (0x1 << 0) | ||
136 | |||
137 | #define EXYNOS5_PHY_OTG_SYS (0x38) | ||
138 | |||
139 | #define OTG_SYS_PHYLINK_SWRESET (0x1 << 14) | ||
140 | #define OTG_SYS_LINKSWRST_UOTG (0x1 << 13) | ||
141 | #define OTG_SYS_PHY0_SWRST (0x1 << 12) | ||
142 | |||
143 | #define OTG_SYS_REFCLKSEL_MASK (0x3 << 9) | ||
144 | #define OTG_SYS_REFCLKSEL_XTAL (0x0 << 9) | ||
145 | #define OTG_SYS_REFCLKSEL_EXTL (0x1 << 9) | ||
146 | #define OTG_SYS_REFCLKSEL_CLKCORE (0x2 << 9) | ||
147 | |||
148 | #define OTG_SYS_IDPULLUP_UOTG (0x1 << 8) | ||
149 | #define OTG_SYS_COMMON_ON (0x1 << 7) | ||
150 | |||
151 | #define OTG_SYS_FSEL_MASK (0x7 << 4) | ||
152 | #define OTG_SYS_FSEL(_x) ((_x) << 4) | ||
153 | |||
154 | #define OTG_SYS_FORCESLEEP (0x1 << 3) | ||
155 | #define OTG_SYS_OTGDISABLE (0x1 << 2) | ||
156 | #define OTG_SYS_SIDDQ_UOTG (0x1 << 1) | ||
157 | #define OTG_SYS_FORCESUSPEND (0x1 << 0) | ||
158 | |||
159 | #define EXYNOS5_PHY_OTG_TUNE (0x40) | ||
160 | |||
161 | #ifndef MHZ | ||
162 | #define MHZ (1000*1000) | ||
163 | #endif | ||
164 | |||
165 | #ifndef KHZ | ||
166 | #define KHZ (1000) | ||
167 | #endif | ||
168 | |||
169 | #define EXYNOS_USBHOST_PHY_CTRL_OFFSET (0x4) | ||
170 | #define S3C64XX_USBPHY_ENABLE (0x1 << 16) | ||
171 | #define EXYNOS_USBPHY_ENABLE (0x1 << 0) | ||
172 | #define EXYNOS_USB20PHY_CFG_HOST_LINK (0x1 << 0) | ||
173 | |||
174 | enum samsung_cpu_type { | ||
175 | TYPE_S3C64XX, | ||
176 | TYPE_EXYNOS4210, | ||
177 | TYPE_EXYNOS5250, | ||
178 | }; | ||
179 | |||
180 | /* | ||
181 | * struct samsung_usbphy_drvdata - driver data for various SoC variants | ||
182 | * @cpu_type: machine identifier | ||
183 | * @devphy_en_mask: device phy enable mask for PHY CONTROL register | ||
184 | * @hostphy_en_mask: host phy enable mask for PHY CONTROL register | ||
185 | * @devphy_reg_offset: offset to DEVICE PHY CONTROL register from | ||
186 | * mapped address of system controller. | ||
187 | * @hostphy_reg_offset: offset to HOST PHY CONTROL register from | ||
188 | * mapped address of system controller. | ||
189 | * | ||
190 | * Here we have a separate mask for device type phy. | ||
191 | * Having different masks for host and device type phy helps | ||
192 | * in setting independent masks in case of SoCs like S5PV210, | ||
193 | * in which PHY0 and PHY1 enable bits belong to same register | ||
194 | * placed at position 0 and 1 respectively. | ||
195 | * Although for newer SoCs like exynos these bits belong to | ||
196 | * different registers altogether placed at position 0. | ||
197 | */ | ||
198 | struct samsung_usbphy_drvdata { | ||
199 | int cpu_type; | ||
200 | int devphy_en_mask; | ||
201 | int hostphy_en_mask; | ||
202 | u32 devphy_reg_offset; | ||
203 | u32 hostphy_reg_offset; | ||
204 | }; | ||
205 | |||
206 | /* | ||
207 | * struct samsung_usbphy - transceiver driver state | ||
208 | * @phy: transceiver structure | ||
209 | * @plat: platform data | ||
210 | * @dev: The parent device supplied to the probe function | ||
211 | * @clk: usb phy clock | ||
212 | * @regs: usb phy controller registers memory base | ||
213 | * @pmuregs: USB device PHY_CONTROL register memory base | ||
214 | * @sysreg: USB2.0 PHY_CFG register memory base | ||
215 | * @ref_clk_freq: reference clock frequency selection | ||
216 | * @drv_data: driver data available for different SoCs | ||
217 | * @phy_type: Samsung SoCs specific phy types: #HOST | ||
218 | * #DEVICE | ||
219 | * @phy_usage: usage count for phy | ||
220 | * @lock: lock for phy operations | ||
221 | */ | ||
222 | struct samsung_usbphy { | ||
223 | struct usb_phy phy; | ||
224 | struct samsung_usbphy_data *plat; | ||
225 | struct device *dev; | ||
226 | struct clk *clk; | ||
227 | void __iomem *regs; | ||
228 | void __iomem *pmuregs; | ||
229 | void __iomem *sysreg; | ||
230 | int ref_clk_freq; | ||
231 | const struct samsung_usbphy_drvdata *drv_data; | ||
232 | enum samsung_usb_phy_type phy_type; | ||
233 | atomic_t phy_usage; | ||
234 | spinlock_t lock; | ||
235 | }; | ||
236 | |||
237 | #define phy_to_sphy(x) container_of((x), struct samsung_usbphy, phy) | ||
238 | |||
239 | int samsung_usbphy_set_host(struct usb_otg *otg, struct usb_bus *host) | ||
240 | { | ||
241 | if (!otg) | ||
242 | return -ENODEV; | ||
243 | |||
244 | if (!otg->host) | ||
245 | otg->host = host; | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int samsung_usbphy_parse_dt(struct samsung_usbphy *sphy) | ||
251 | { | ||
252 | struct device_node *usbphy_sys; | ||
253 | |||
254 | /* Getting node for system controller interface for usb-phy */ | ||
255 | usbphy_sys = of_get_child_by_name(sphy->dev->of_node, "usbphy-sys"); | ||
256 | if (!usbphy_sys) { | ||
257 | dev_err(sphy->dev, "No sys-controller interface for usb-phy\n"); | ||
258 | return -ENODEV; | ||
259 | } | ||
260 | |||
261 | sphy->pmuregs = of_iomap(usbphy_sys, 0); | ||
262 | |||
263 | if (sphy->pmuregs == NULL) { | ||
264 | dev_err(sphy->dev, "Can't get usb-phy pmu control register\n"); | ||
265 | goto err0; | ||
266 | } | ||
267 | |||
268 | sphy->sysreg = of_iomap(usbphy_sys, 1); | ||
269 | |||
270 | /* | ||
271 | * Not returning error code here, since this situation is not fatal. | ||
272 | * Few SoCs may not have this switch available | ||
273 | */ | ||
274 | if (sphy->sysreg == NULL) | ||
275 | dev_warn(sphy->dev, "Can't get usb-phy sysreg cfg register\n"); | ||
276 | |||
277 | of_node_put(usbphy_sys); | ||
278 | |||
279 | return 0; | ||
280 | |||
281 | err0: | ||
282 | of_node_put(usbphy_sys); | ||
283 | return -ENXIO; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Set isolation here for phy. | ||
288 | * Here 'on = true' would mean USB PHY block is isolated, hence | ||
289 | * de-activated and vice-versa. | ||
290 | */ | ||
291 | static void samsung_usbphy_set_isolation(struct samsung_usbphy *sphy, bool on) | ||
292 | { | ||
293 | void __iomem *reg = NULL; | ||
294 | u32 reg_val; | ||
295 | u32 en_mask = 0; | ||
296 | |||
297 | if (!sphy->pmuregs) { | ||
298 | dev_warn(sphy->dev, "Can't set pmu isolation\n"); | ||
299 | return; | ||
300 | } | ||
301 | |||
302 | switch (sphy->drv_data->cpu_type) { | ||
303 | case TYPE_S3C64XX: | ||
304 | /* | ||
305 | * Do nothing: We will add here once S3C64xx goes for DT support | ||
306 | */ | ||
307 | break; | ||
308 | case TYPE_EXYNOS4210: | ||
309 | /* | ||
310 | * Fall through since exynos4210 and exynos5250 have similar | ||
311 | * register architecture: two separate registers for host and | ||
312 | * device phy control with enable bit at position 0. | ||
313 | */ | ||
314 | case TYPE_EXYNOS5250: | ||
315 | if (sphy->phy_type == USB_PHY_TYPE_DEVICE) { | ||
316 | reg = sphy->pmuregs + | ||
317 | sphy->drv_data->devphy_reg_offset; | ||
318 | en_mask = sphy->drv_data->devphy_en_mask; | ||
319 | } else if (sphy->phy_type == USB_PHY_TYPE_HOST) { | ||
320 | reg = sphy->pmuregs + | ||
321 | sphy->drv_data->hostphy_reg_offset; | ||
322 | en_mask = sphy->drv_data->hostphy_en_mask; | ||
323 | } | ||
324 | break; | ||
325 | default: | ||
326 | dev_err(sphy->dev, "Invalid SoC type\n"); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | reg_val = readl(reg); | ||
331 | |||
332 | if (on) | ||
333 | reg_val &= ~en_mask; | ||
334 | else | ||
335 | reg_val |= en_mask; | ||
336 | |||
337 | writel(reg_val, reg); | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * Configure the mode of working of usb-phy here: HOST/DEVICE. | ||
342 | */ | ||
343 | static void samsung_usbphy_cfg_sel(struct samsung_usbphy *sphy) | ||
344 | { | ||
345 | u32 reg; | ||
346 | |||
347 | if (!sphy->sysreg) { | ||
348 | dev_warn(sphy->dev, "Can't configure specified phy mode\n"); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | reg = readl(sphy->sysreg); | ||
353 | |||
354 | if (sphy->phy_type == USB_PHY_TYPE_DEVICE) | ||
355 | reg &= ~EXYNOS_USB20PHY_CFG_HOST_LINK; | ||
356 | else if (sphy->phy_type == USB_PHY_TYPE_HOST) | ||
357 | reg |= EXYNOS_USB20PHY_CFG_HOST_LINK; | ||
358 | |||
359 | writel(reg, sphy->sysreg); | ||
360 | } | ||
361 | |||
362 | /* | ||
363 | * PHYs are different for USB Device and USB Host. | ||
364 | * This make sure that correct PHY type is selected before | ||
365 | * any operation on PHY. | ||
366 | */ | ||
367 | static int samsung_usbphy_set_type(struct usb_phy *phy, | ||
368 | enum samsung_usb_phy_type phy_type) | ||
369 | { | ||
370 | struct samsung_usbphy *sphy = phy_to_sphy(phy); | ||
371 | |||
372 | sphy->phy_type = phy_type; | ||
373 | |||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | /* | ||
378 | * Returns reference clock frequency selection value | ||
379 | */ | ||
380 | static int samsung_usbphy_get_refclk_freq(struct samsung_usbphy *sphy) | ||
381 | { | ||
382 | struct clk *ref_clk; | ||
383 | int refclk_freq = 0; | ||
384 | |||
385 | /* | ||
386 | * In exynos5250 USB host and device PHY use | ||
387 | * external crystal clock XXTI | ||
388 | */ | ||
389 | if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) | ||
390 | ref_clk = clk_get(sphy->dev, "ext_xtal"); | ||
391 | else | ||
392 | ref_clk = clk_get(sphy->dev, "xusbxti"); | ||
393 | if (IS_ERR(ref_clk)) { | ||
394 | dev_err(sphy->dev, "Failed to get reference clock\n"); | ||
395 | return PTR_ERR(ref_clk); | ||
396 | } | ||
397 | |||
398 | if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) { | ||
399 | /* set clock frequency for PLL */ | ||
400 | switch (clk_get_rate(ref_clk)) { | ||
401 | case 9600 * KHZ: | ||
402 | refclk_freq = FSEL_CLKSEL_9600K; | ||
403 | break; | ||
404 | case 10 * MHZ: | ||
405 | refclk_freq = FSEL_CLKSEL_10M; | ||
406 | break; | ||
407 | case 12 * MHZ: | ||
408 | refclk_freq = FSEL_CLKSEL_12M; | ||
409 | break; | ||
410 | case 19200 * KHZ: | ||
411 | refclk_freq = FSEL_CLKSEL_19200K; | ||
412 | break; | ||
413 | case 20 * MHZ: | ||
414 | refclk_freq = FSEL_CLKSEL_20M; | ||
415 | break; | ||
416 | case 50 * MHZ: | ||
417 | refclk_freq = FSEL_CLKSEL_50M; | ||
418 | break; | ||
419 | case 24 * MHZ: | ||
420 | default: | ||
421 | /* default reference clock */ | ||
422 | refclk_freq = FSEL_CLKSEL_24M; | ||
423 | break; | ||
424 | } | ||
425 | } else { | ||
426 | switch (clk_get_rate(ref_clk)) { | ||
427 | case 12 * MHZ: | ||
428 | refclk_freq = PHYCLK_CLKSEL_12M; | ||
429 | break; | ||
430 | case 24 * MHZ: | ||
431 | refclk_freq = PHYCLK_CLKSEL_24M; | ||
432 | break; | ||
433 | case 48 * MHZ: | ||
434 | refclk_freq = PHYCLK_CLKSEL_48M; | ||
435 | break; | ||
436 | default: | ||
437 | if (sphy->drv_data->cpu_type == TYPE_S3C64XX) | ||
438 | refclk_freq = PHYCLK_CLKSEL_48M; | ||
439 | else | ||
440 | refclk_freq = PHYCLK_CLKSEL_24M; | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | clk_put(ref_clk); | ||
445 | |||
446 | return refclk_freq; | ||
447 | } | ||
448 | |||
449 | static bool exynos5_phyhost_is_on(void *regs) | ||
450 | { | ||
451 | u32 reg; | ||
452 | |||
453 | reg = readl(regs + EXYNOS5_PHY_HOST_CTRL0); | ||
454 | |||
455 | return !(reg & HOST_CTRL0_SIDDQ); | ||
456 | } | ||
457 | |||
458 | static void samsung_exynos5_usbphy_enable(struct samsung_usbphy *sphy) | ||
459 | { | ||
460 | void __iomem *regs = sphy->regs; | ||
461 | u32 phyclk = sphy->ref_clk_freq; | ||
462 | u32 phyhost; | ||
463 | u32 phyotg; | ||
464 | u32 phyhsic; | ||
465 | u32 ehcictrl; | ||
466 | u32 ohcictrl; | ||
467 | |||
468 | /* | ||
469 | * phy_usage helps in keeping usage count for phy | ||
470 | * so that the first consumer enabling the phy is also | ||
471 | * the last consumer to disable it. | ||
472 | */ | ||
473 | |||
474 | atomic_inc(&sphy->phy_usage); | ||
475 | |||
476 | if (exynos5_phyhost_is_on(regs)) { | ||
477 | dev_info(sphy->dev, "Already power on PHY\n"); | ||
478 | return; | ||
479 | } | ||
480 | |||
481 | /* Host configuration */ | ||
482 | phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); | ||
483 | |||
484 | /* phy reference clock configuration */ | ||
485 | phyhost &= ~HOST_CTRL0_FSEL_MASK; | ||
486 | phyhost |= HOST_CTRL0_FSEL(phyclk); | ||
487 | |||
488 | /* host phy reset */ | ||
489 | phyhost &= ~(HOST_CTRL0_PHYSWRST | | ||
490 | HOST_CTRL0_PHYSWRSTALL | | ||
491 | HOST_CTRL0_SIDDQ | | ||
492 | /* Enable normal mode of operation */ | ||
493 | HOST_CTRL0_FORCESUSPEND | | ||
494 | HOST_CTRL0_FORCESLEEP); | ||
495 | |||
496 | /* Link reset */ | ||
497 | phyhost |= (HOST_CTRL0_LINKSWRST | | ||
498 | HOST_CTRL0_UTMISWRST | | ||
499 | /* COMMON Block configuration during suspend */ | ||
500 | HOST_CTRL0_COMMONON_N); | ||
501 | writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); | ||
502 | udelay(10); | ||
503 | phyhost &= ~(HOST_CTRL0_LINKSWRST | | ||
504 | HOST_CTRL0_UTMISWRST); | ||
505 | writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); | ||
506 | |||
507 | /* OTG configuration */ | ||
508 | phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS); | ||
509 | |||
510 | /* phy reference clock configuration */ | ||
511 | phyotg &= ~OTG_SYS_FSEL_MASK; | ||
512 | phyotg |= OTG_SYS_FSEL(phyclk); | ||
513 | |||
514 | /* Enable normal mode of operation */ | ||
515 | phyotg &= ~(OTG_SYS_FORCESUSPEND | | ||
516 | OTG_SYS_SIDDQ_UOTG | | ||
517 | OTG_SYS_FORCESLEEP | | ||
518 | OTG_SYS_REFCLKSEL_MASK | | ||
519 | /* COMMON Block configuration during suspend */ | ||
520 | OTG_SYS_COMMON_ON); | ||
521 | |||
522 | /* OTG phy & link reset */ | ||
523 | phyotg |= (OTG_SYS_PHY0_SWRST | | ||
524 | OTG_SYS_LINKSWRST_UOTG | | ||
525 | OTG_SYS_PHYLINK_SWRESET | | ||
526 | OTG_SYS_OTGDISABLE | | ||
527 | /* Set phy refclk */ | ||
528 | OTG_SYS_REFCLKSEL_CLKCORE); | ||
529 | |||
530 | writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); | ||
531 | udelay(10); | ||
532 | phyotg &= ~(OTG_SYS_PHY0_SWRST | | ||
533 | OTG_SYS_LINKSWRST_UOTG | | ||
534 | OTG_SYS_PHYLINK_SWRESET); | ||
535 | writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); | ||
536 | |||
537 | /* HSIC phy configuration */ | ||
538 | phyhsic = (HSIC_CTRL_REFCLKDIV_12 | | ||
539 | HSIC_CTRL_REFCLKSEL | | ||
540 | HSIC_CTRL_PHYSWRST); | ||
541 | writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); | ||
542 | writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); | ||
543 | udelay(10); | ||
544 | phyhsic &= ~HSIC_CTRL_PHYSWRST; | ||
545 | writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); | ||
546 | writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); | ||
547 | |||
548 | udelay(80); | ||
549 | |||
550 | /* enable EHCI DMA burst */ | ||
551 | ehcictrl = readl(regs + EXYNOS5_PHY_HOST_EHCICTRL); | ||
552 | ehcictrl |= (HOST_EHCICTRL_ENAINCRXALIGN | | ||
553 | HOST_EHCICTRL_ENAINCR4 | | ||
554 | HOST_EHCICTRL_ENAINCR8 | | ||
555 | HOST_EHCICTRL_ENAINCR16); | ||
556 | writel(ehcictrl, regs + EXYNOS5_PHY_HOST_EHCICTRL); | ||
557 | |||
558 | /* set ohci_suspend_on_n */ | ||
559 | ohcictrl = readl(regs + EXYNOS5_PHY_HOST_OHCICTRL); | ||
560 | ohcictrl |= HOST_OHCICTRL_SUSPLGCY; | ||
561 | writel(ohcictrl, regs + EXYNOS5_PHY_HOST_OHCICTRL); | ||
562 | } | ||
563 | |||
564 | static void samsung_usbphy_enable(struct samsung_usbphy *sphy) | ||
565 | { | ||
566 | void __iomem *regs = sphy->regs; | ||
567 | u32 phypwr; | ||
568 | u32 phyclk; | ||
569 | u32 rstcon; | ||
570 | |||
571 | /* set clock frequency for PLL */ | ||
572 | phyclk = sphy->ref_clk_freq; | ||
573 | phypwr = readl(regs + SAMSUNG_PHYPWR); | ||
574 | rstcon = readl(regs + SAMSUNG_RSTCON); | ||
575 | |||
576 | switch (sphy->drv_data->cpu_type) { | ||
577 | case TYPE_S3C64XX: | ||
578 | phyclk &= ~PHYCLK_COMMON_ON_N; | ||
579 | phypwr &= ~PHYPWR_NORMAL_MASK; | ||
580 | rstcon |= RSTCON_SWRST; | ||
581 | break; | ||
582 | case TYPE_EXYNOS4210: | ||
583 | phypwr &= ~PHYPWR_NORMAL_MASK_PHY0; | ||
584 | rstcon |= RSTCON_SWRST; | ||
585 | default: | ||
586 | break; | ||
587 | } | ||
588 | |||
589 | writel(phyclk, regs + SAMSUNG_PHYCLK); | ||
590 | /* Configure PHY0 for normal operation*/ | ||
591 | writel(phypwr, regs + SAMSUNG_PHYPWR); | ||
592 | /* reset all ports of PHY and Link */ | ||
593 | writel(rstcon, regs + SAMSUNG_RSTCON); | ||
594 | udelay(10); | ||
595 | rstcon &= ~RSTCON_SWRST; | ||
596 | writel(rstcon, regs + SAMSUNG_RSTCON); | ||
597 | } | ||
598 | |||
599 | static void samsung_exynos5_usbphy_disable(struct samsung_usbphy *sphy) | ||
600 | { | ||
601 | void __iomem *regs = sphy->regs; | ||
602 | u32 phyhost; | ||
603 | u32 phyotg; | ||
604 | u32 phyhsic; | ||
605 | |||
606 | if (atomic_dec_return(&sphy->phy_usage) > 0) { | ||
607 | dev_info(sphy->dev, "still being used\n"); | ||
608 | return; | ||
609 | } | ||
610 | |||
611 | phyhsic = (HSIC_CTRL_REFCLKDIV_12 | | ||
612 | HSIC_CTRL_REFCLKSEL | | ||
613 | HSIC_CTRL_SIDDQ | | ||
614 | HSIC_CTRL_FORCESLEEP | | ||
615 | HSIC_CTRL_FORCESUSPEND); | ||
616 | writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL1); | ||
617 | writel(phyhsic, regs + EXYNOS5_PHY_HSIC_CTRL2); | ||
618 | |||
619 | phyhost = readl(regs + EXYNOS5_PHY_HOST_CTRL0); | ||
620 | phyhost |= (HOST_CTRL0_SIDDQ | | ||
621 | HOST_CTRL0_FORCESUSPEND | | ||
622 | HOST_CTRL0_FORCESLEEP | | ||
623 | HOST_CTRL0_PHYSWRST | | ||
624 | HOST_CTRL0_PHYSWRSTALL); | ||
625 | writel(phyhost, regs + EXYNOS5_PHY_HOST_CTRL0); | ||
626 | |||
627 | phyotg = readl(regs + EXYNOS5_PHY_OTG_SYS); | ||
628 | phyotg |= (OTG_SYS_FORCESUSPEND | | ||
629 | OTG_SYS_SIDDQ_UOTG | | ||
630 | OTG_SYS_FORCESLEEP); | ||
631 | writel(phyotg, regs + EXYNOS5_PHY_OTG_SYS); | ||
632 | } | ||
633 | |||
634 | static void samsung_usbphy_disable(struct samsung_usbphy *sphy) | ||
635 | { | ||
636 | void __iomem *regs = sphy->regs; | ||
637 | u32 phypwr; | ||
638 | |||
639 | phypwr = readl(regs + SAMSUNG_PHYPWR); | ||
640 | |||
641 | switch (sphy->drv_data->cpu_type) { | ||
642 | case TYPE_S3C64XX: | ||
643 | phypwr |= PHYPWR_NORMAL_MASK; | ||
644 | break; | ||
645 | case TYPE_EXYNOS4210: | ||
646 | phypwr |= PHYPWR_NORMAL_MASK_PHY0; | ||
647 | default: | ||
648 | break; | ||
649 | } | ||
650 | |||
651 | /* Disable analog and otg block power */ | ||
652 | writel(phypwr, regs + SAMSUNG_PHYPWR); | ||
653 | } | ||
654 | |||
655 | /* | ||
656 | * The function passed to the usb driver for phy initialization | ||
657 | */ | ||
658 | static int samsung_usbphy_init(struct usb_phy *phy) | ||
659 | { | ||
660 | struct samsung_usbphy *sphy; | ||
661 | struct usb_bus *host = NULL; | ||
662 | unsigned long flags; | ||
663 | int ret = 0; | ||
664 | |||
665 | sphy = phy_to_sphy(phy); | ||
666 | |||
667 | host = phy->otg->host; | ||
668 | |||
669 | /* Enable the phy clock */ | ||
670 | ret = clk_prepare_enable(sphy->clk); | ||
671 | if (ret) { | ||
672 | dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); | ||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | spin_lock_irqsave(&sphy->lock, flags); | ||
677 | |||
678 | if (host) { | ||
679 | /* setting default phy-type for USB 2.0 */ | ||
680 | if (!strstr(dev_name(host->controller), "ehci") || | ||
681 | !strstr(dev_name(host->controller), "ohci")) | ||
682 | samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST); | ||
683 | } else { | ||
684 | samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); | ||
685 | } | ||
686 | |||
687 | /* Disable phy isolation */ | ||
688 | if (sphy->plat && sphy->plat->pmu_isolation) | ||
689 | sphy->plat->pmu_isolation(false); | ||
690 | else | ||
691 | samsung_usbphy_set_isolation(sphy, false); | ||
692 | |||
693 | /* Selecting Host/OTG mode; After reset USB2.0PHY_CFG: HOST */ | ||
694 | samsung_usbphy_cfg_sel(sphy); | ||
695 | |||
696 | /* Initialize usb phy registers */ | ||
697 | if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) | ||
698 | samsung_exynos5_usbphy_enable(sphy); | ||
699 | else | ||
700 | samsung_usbphy_enable(sphy); | ||
701 | |||
702 | spin_unlock_irqrestore(&sphy->lock, flags); | ||
703 | |||
704 | /* Disable the phy clock */ | ||
705 | clk_disable_unprepare(sphy->clk); | ||
706 | |||
707 | return ret; | ||
708 | } | ||
709 | |||
710 | /* | ||
711 | * The function passed to the usb driver for phy shutdown | ||
712 | */ | ||
713 | static void samsung_usbphy_shutdown(struct usb_phy *phy) | ||
714 | { | ||
715 | struct samsung_usbphy *sphy; | ||
716 | struct usb_bus *host = NULL; | ||
717 | unsigned long flags; | ||
718 | |||
719 | sphy = phy_to_sphy(phy); | ||
720 | |||
721 | host = phy->otg->host; | ||
722 | |||
723 | if (clk_prepare_enable(sphy->clk)) { | ||
724 | dev_err(sphy->dev, "%s: clk_prepare_enable failed\n", __func__); | ||
725 | return; | ||
726 | } | ||
727 | |||
728 | spin_lock_irqsave(&sphy->lock, flags); | ||
729 | |||
730 | if (host) { | ||
731 | /* setting default phy-type for USB 2.0 */ | ||
732 | if (!strstr(dev_name(host->controller), "ehci") || | ||
733 | !strstr(dev_name(host->controller), "ohci")) | ||
734 | samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_HOST); | ||
735 | } else { | ||
736 | samsung_usbphy_set_type(&sphy->phy, USB_PHY_TYPE_DEVICE); | ||
737 | } | ||
738 | |||
739 | /* De-initialize usb phy registers */ | ||
740 | if (sphy->drv_data->cpu_type == TYPE_EXYNOS5250) | ||
741 | samsung_exynos5_usbphy_disable(sphy); | ||
742 | else | ||
743 | samsung_usbphy_disable(sphy); | ||
744 | |||
745 | /* Enable phy isolation */ | ||
746 | if (sphy->plat && sphy->plat->pmu_isolation) | ||
747 | sphy->plat->pmu_isolation(true); | ||
748 | else | ||
749 | samsung_usbphy_set_isolation(sphy, true); | ||
750 | |||
751 | spin_unlock_irqrestore(&sphy->lock, flags); | ||
752 | |||
753 | clk_disable_unprepare(sphy->clk); | ||
754 | } | ||
755 | |||
756 | static const struct of_device_id samsung_usbphy_dt_match[]; | ||
757 | |||
758 | static inline const struct samsung_usbphy_drvdata | ||
759 | *samsung_usbphy_get_driver_data(struct platform_device *pdev) | ||
760 | { | ||
761 | if (pdev->dev.of_node) { | ||
762 | const struct of_device_id *match; | ||
763 | match = of_match_node(samsung_usbphy_dt_match, | ||
764 | pdev->dev.of_node); | ||
765 | return match->data; | ||
766 | } | ||
767 | |||
768 | return (struct samsung_usbphy_drvdata *) | ||
769 | platform_get_device_id(pdev)->driver_data; | ||
770 | } | ||
771 | |||
772 | static int samsung_usbphy_probe(struct platform_device *pdev) | ||
773 | { | ||
774 | struct samsung_usbphy *sphy; | ||
775 | struct usb_otg *otg; | ||
776 | struct samsung_usbphy_data *pdata = pdev->dev.platform_data; | ||
777 | const struct samsung_usbphy_drvdata *drv_data; | ||
778 | struct device *dev = &pdev->dev; | ||
779 | struct resource *phy_mem; | ||
780 | void __iomem *phy_base; | ||
781 | struct clk *clk; | ||
782 | int ret; | ||
783 | |||
784 | phy_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
785 | if (!phy_mem) { | ||
786 | dev_err(dev, "%s: missing mem resource\n", __func__); | ||
787 | return -ENODEV; | ||
788 | } | ||
789 | |||
790 | phy_base = devm_request_and_ioremap(dev, phy_mem); | ||
791 | if (!phy_base) { | ||
792 | dev_err(dev, "%s: register mapping failed\n", __func__); | ||
793 | return -ENXIO; | ||
794 | } | ||
795 | |||
796 | sphy = devm_kzalloc(dev, sizeof(*sphy), GFP_KERNEL); | ||
797 | if (!sphy) | ||
798 | return -ENOMEM; | ||
799 | |||
800 | otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL); | ||
801 | if (!otg) | ||
802 | return -ENOMEM; | ||
803 | |||
804 | drv_data = samsung_usbphy_get_driver_data(pdev); | ||
805 | |||
806 | if (drv_data->cpu_type == TYPE_EXYNOS5250) | ||
807 | clk = devm_clk_get(dev, "usbhost"); | ||
808 | else | ||
809 | clk = devm_clk_get(dev, "otg"); | ||
810 | |||
811 | if (IS_ERR(clk)) { | ||
812 | dev_err(dev, "Failed to get otg clock\n"); | ||
813 | return PTR_ERR(clk); | ||
814 | } | ||
815 | |||
816 | sphy->dev = dev; | ||
817 | |||
818 | if (dev->of_node) { | ||
819 | ret = samsung_usbphy_parse_dt(sphy); | ||
820 | if (ret < 0) | ||
821 | return ret; | ||
822 | } else { | ||
823 | if (!pdata) { | ||
824 | dev_err(dev, "no platform data specified\n"); | ||
825 | return -EINVAL; | ||
826 | } | ||
827 | } | ||
828 | |||
829 | sphy->plat = pdata; | ||
830 | sphy->regs = phy_base; | ||
831 | sphy->clk = clk; | ||
832 | sphy->drv_data = drv_data; | ||
833 | sphy->phy.dev = sphy->dev; | ||
834 | sphy->phy.label = "samsung-usbphy"; | ||
835 | sphy->phy.init = samsung_usbphy_init; | ||
836 | sphy->phy.shutdown = samsung_usbphy_shutdown; | ||
837 | sphy->ref_clk_freq = samsung_usbphy_get_refclk_freq(sphy); | ||
838 | |||
839 | sphy->phy.otg = otg; | ||
840 | sphy->phy.otg->phy = &sphy->phy; | ||
841 | sphy->phy.otg->set_host = samsung_usbphy_set_host; | ||
842 | |||
843 | spin_lock_init(&sphy->lock); | ||
844 | |||
845 | platform_set_drvdata(pdev, sphy); | ||
846 | |||
847 | return usb_add_phy(&sphy->phy, USB_PHY_TYPE_USB2); | ||
848 | } | ||
849 | |||
850 | static int samsung_usbphy_remove(struct platform_device *pdev) | ||
851 | { | ||
852 | struct samsung_usbphy *sphy = platform_get_drvdata(pdev); | ||
853 | |||
854 | usb_remove_phy(&sphy->phy); | ||
855 | |||
856 | if (sphy->pmuregs) | ||
857 | iounmap(sphy->pmuregs); | ||
858 | if (sphy->sysreg) | ||
859 | iounmap(sphy->sysreg); | ||
860 | |||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static const struct samsung_usbphy_drvdata usbphy_s3c64xx = { | ||
865 | .cpu_type = TYPE_S3C64XX, | ||
866 | .devphy_en_mask = S3C64XX_USBPHY_ENABLE, | ||
867 | }; | ||
868 | |||
869 | static const struct samsung_usbphy_drvdata usbphy_exynos4 = { | ||
870 | .cpu_type = TYPE_EXYNOS4210, | ||
871 | .devphy_en_mask = EXYNOS_USBPHY_ENABLE, | ||
872 | .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, | ||
873 | }; | ||
874 | |||
875 | static struct samsung_usbphy_drvdata usbphy_exynos5 = { | ||
876 | .cpu_type = TYPE_EXYNOS5250, | ||
877 | .hostphy_en_mask = EXYNOS_USBPHY_ENABLE, | ||
878 | .hostphy_reg_offset = EXYNOS_USBHOST_PHY_CTRL_OFFSET, | ||
879 | }; | ||
880 | |||
881 | #ifdef CONFIG_OF | ||
882 | static const struct of_device_id samsung_usbphy_dt_match[] = { | ||
883 | { | ||
884 | .compatible = "samsung,s3c64xx-usbphy", | ||
885 | .data = &usbphy_s3c64xx, | ||
886 | }, { | ||
887 | .compatible = "samsung,exynos4210-usbphy", | ||
888 | .data = &usbphy_exynos4, | ||
889 | }, { | ||
890 | .compatible = "samsung,exynos5250-usbphy", | ||
891 | .data = &usbphy_exynos5 | ||
892 | }, | ||
893 | {}, | ||
894 | }; | ||
895 | MODULE_DEVICE_TABLE(of, samsung_usbphy_dt_match); | ||
896 | #endif | ||
897 | |||
898 | static struct platform_device_id samsung_usbphy_driver_ids[] = { | ||
899 | { | ||
900 | .name = "s3c64xx-usbphy", | ||
901 | .driver_data = (unsigned long)&usbphy_s3c64xx, | ||
902 | }, { | ||
903 | .name = "exynos4210-usbphy", | ||
904 | .driver_data = (unsigned long)&usbphy_exynos4, | ||
905 | }, { | ||
906 | .name = "exynos5250-usbphy", | ||
907 | .driver_data = (unsigned long)&usbphy_exynos5, | ||
908 | }, | ||
909 | {}, | ||
910 | }; | ||
911 | |||
912 | MODULE_DEVICE_TABLE(platform, samsung_usbphy_driver_ids); | ||
913 | |||
914 | static struct platform_driver samsung_usbphy_driver = { | ||
915 | .probe = samsung_usbphy_probe, | ||
916 | .remove = samsung_usbphy_remove, | ||
917 | .id_table = samsung_usbphy_driver_ids, | ||
918 | .driver = { | ||
919 | .name = "samsung-usbphy", | ||
920 | .owner = THIS_MODULE, | ||
921 | .of_match_table = of_match_ptr(samsung_usbphy_dt_match), | ||
922 | }, | ||
923 | }; | ||
924 | |||
925 | module_platform_driver(samsung_usbphy_driver); | ||
926 | |||
927 | MODULE_DESCRIPTION("Samsung USB phy controller"); | ||
928 | MODULE_AUTHOR("Praveen Paneri <p.paneri@samsung.com>"); | ||
929 | MODULE_LICENSE("GPL"); | ||
930 | MODULE_ALIAS("platform:samsung-usbphy"); | ||
diff --git a/include/linux/platform_data/samsung-usbphy.h b/include/linux/platform_data/samsung-usbphy.h new file mode 100644 index 000000000000..1bd24cba982b --- /dev/null +++ b/include/linux/platform_data/samsung-usbphy.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Samsung Electronics Co.Ltd | ||
3 | * http://www.samsung.com/ | ||
4 | * Author: Praveen Paneri <p.paneri@samsung.com> | ||
5 | * | ||
6 | * Defines platform data for samsung usb phy driver. | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License as published by the | ||
10 | * Free Software Foundation; either version 2 of the License, or (at your | ||
11 | * option) any later version. | ||
12 | */ | ||
13 | |||
14 | #ifndef __SAMSUNG_USBPHY_PLATFORM_H | ||
15 | #define __SAMSUNG_USBPHY_PLATFORM_H | ||
16 | |||
17 | /** | ||
18 | * samsung_usbphy_data - Platform data for USB PHY driver. | ||
19 | * @pmu_isolation: Function to control usb phy isolation in PMU. | ||
20 | */ | ||
21 | struct samsung_usbphy_data { | ||
22 | void (*pmu_isolation)(int on); | ||
23 | }; | ||
24 | |||
25 | extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd); | ||
26 | |||
27 | #endif /* __SAMSUNG_USBPHY_PLATFORM_H */ | ||
diff --git a/include/linux/usb/omap_control_usb.h b/include/linux/usb/omap_control_usb.h new file mode 100644 index 000000000000..f306db7149ca --- /dev/null +++ b/include/linux/usb/omap_control_usb.h | |||
@@ -0,0 +1,92 @@ | |||
1 | /* | ||
2 | * omap_control_usb.h - Header file for the USB part of control module. | ||
3 | * | ||
4 | * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * Author: Kishon Vijay Abraham I <kishon@ti.com> | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef __OMAP_CONTROL_USB_H__ | ||
20 | #define __OMAP_CONTROL_USB_H__ | ||
21 | |||
22 | struct omap_control_usb { | ||
23 | struct device *dev; | ||
24 | |||
25 | u32 __iomem *dev_conf; | ||
26 | u32 __iomem *otghs_control; | ||
27 | u32 __iomem *phy_power; | ||
28 | |||
29 | struct clk *sys_clk; | ||
30 | |||
31 | u32 type; | ||
32 | }; | ||
33 | |||
34 | struct omap_control_usb_platform_data { | ||
35 | u8 type; | ||
36 | }; | ||
37 | |||
38 | enum omap_control_usb_mode { | ||
39 | USB_MODE_UNDEFINED = 0, | ||
40 | USB_MODE_HOST, | ||
41 | USB_MODE_DEVICE, | ||
42 | USB_MODE_DISCONNECT, | ||
43 | }; | ||
44 | |||
45 | /* To differentiate ctrl module IP having either mailbox or USB3 PHY power */ | ||
46 | #define OMAP_CTRL_DEV_TYPE1 0x1 | ||
47 | #define OMAP_CTRL_DEV_TYPE2 0x2 | ||
48 | |||
49 | #define OMAP_CTRL_DEV_PHY_PD BIT(0) | ||
50 | |||
51 | #define OMAP_CTRL_DEV_AVALID BIT(0) | ||
52 | #define OMAP_CTRL_DEV_BVALID BIT(1) | ||
53 | #define OMAP_CTRL_DEV_VBUSVALID BIT(2) | ||
54 | #define OMAP_CTRL_DEV_SESSEND BIT(3) | ||
55 | #define OMAP_CTRL_DEV_IDDIG BIT(4) | ||
56 | |||
57 | #define OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK 0x003FC000 | ||
58 | #define OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT 0xE | ||
59 | |||
60 | #define OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK 0xFFC00000 | ||
61 | #define OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT 0x16 | ||
62 | |||
63 | #define OMAP_CTRL_USB3_PHY_TX_RX_POWERON 0x3 | ||
64 | #define OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF 0x0 | ||
65 | |||
66 | #if IS_ENABLED(CONFIG_OMAP_CONTROL_USB) | ||
67 | extern struct device *omap_get_control_dev(void); | ||
68 | extern void omap_control_usb_phy_power(struct device *dev, int on); | ||
69 | extern void omap_control_usb3_phy_power(struct device *dev, bool on); | ||
70 | extern void omap_control_usb_set_mode(struct device *dev, | ||
71 | enum omap_control_usb_mode mode); | ||
72 | #else | ||
73 | static inline struct device *omap_get_control_dev() | ||
74 | { | ||
75 | return ERR_PTR(-ENODEV); | ||
76 | } | ||
77 | |||
78 | static inline void omap_control_usb_phy_power(struct device *dev, int on) | ||
79 | { | ||
80 | } | ||
81 | |||
82 | static inline void omap_control_usb3_phy_power(struct device *dev, int on) | ||
83 | { | ||
84 | } | ||
85 | |||
86 | static inline void omap_control_usb_set_mode(struct device *dev, | ||
87 | enum omap_control_usb_mode mode) | ||
88 | { | ||
89 | } | ||
90 | #endif | ||
91 | |||
92 | #endif /* __OMAP_CONTROL_USB_H__ */ | ||
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h index 0ea17f8ae820..6ae29360e1d2 100644 --- a/include/linux/usb/omap_usb.h +++ b/include/linux/usb/omap_usb.h | |||
@@ -19,19 +19,29 @@ | |||
19 | #ifndef __DRIVERS_OMAP_USB2_H | 19 | #ifndef __DRIVERS_OMAP_USB2_H |
20 | #define __DRIVERS_OMAP_USB2_H | 20 | #define __DRIVERS_OMAP_USB2_H |
21 | 21 | ||
22 | #include <linux/io.h> | ||
22 | #include <linux/usb/otg.h> | 23 | #include <linux/usb/otg.h> |
23 | 24 | ||
25 | struct usb_dpll_params { | ||
26 | u16 m; | ||
27 | u8 n; | ||
28 | u8 freq:3; | ||
29 | u8 sd; | ||
30 | u32 mf; | ||
31 | }; | ||
32 | |||
24 | struct omap_usb { | 33 | struct omap_usb { |
25 | struct usb_phy phy; | 34 | struct usb_phy phy; |
26 | struct phy_companion *comparator; | 35 | struct phy_companion *comparator; |
36 | void __iomem *pll_ctrl_base; | ||
27 | struct device *dev; | 37 | struct device *dev; |
28 | u32 __iomem *control_dev; | 38 | struct device *control_dev; |
29 | struct clk *wkupclk; | 39 | struct clk *wkupclk; |
40 | struct clk *sys_clk; | ||
41 | struct clk *optclk; | ||
30 | u8 is_suspended:1; | 42 | u8 is_suspended:1; |
31 | }; | 43 | }; |
32 | 44 | ||
33 | #define PHY_PD 0x1 | ||
34 | |||
35 | #define phy_to_omapusb(x) container_of((x), struct omap_usb, phy) | 45 | #define phy_to_omapusb(x) container_of((x), struct omap_usb, phy) |
36 | 46 | ||
37 | #if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE) | 47 | #if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE) |
@@ -43,4 +53,15 @@ static inline int omap_usb2_set_comparator(struct phy_companion *comparator) | |||
43 | } | 53 | } |
44 | #endif | 54 | #endif |
45 | 55 | ||
56 | static inline u32 omap_usb_readl(void __iomem *addr, unsigned offset) | ||
57 | { | ||
58 | return __raw_readl(addr + offset); | ||
59 | } | ||
60 | |||
61 | static inline void omap_usb_writel(void __iomem *addr, unsigned offset, | ||
62 | u32 data) | ||
63 | { | ||
64 | __raw_writel(data, addr + offset); | ||
65 | } | ||
66 | |||
46 | #endif /* __DRIVERS_OMAP_USB_H */ | 67 | #endif /* __DRIVERS_OMAP_USB_H */ |
diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index a29ae1eb9346..15847cbdb512 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h | |||
@@ -106,9 +106,25 @@ struct usb_phy { | |||
106 | enum usb_device_speed speed); | 106 | enum usb_device_speed speed); |
107 | }; | 107 | }; |
108 | 108 | ||
109 | /** | ||
110 | * struct usb_phy_bind - represent the binding for the phy | ||
111 | * @dev_name: the device name of the device that will bind to the phy | ||
112 | * @phy_dev_name: the device name of the phy | ||
113 | * @index: used if a single controller uses multiple phys | ||
114 | * @phy: reference to the phy | ||
115 | * @list: to maintain a linked list of the binding information | ||
116 | */ | ||
117 | struct usb_phy_bind { | ||
118 | const char *dev_name; | ||
119 | const char *phy_dev_name; | ||
120 | u8 index; | ||
121 | struct usb_phy *phy; | ||
122 | struct list_head list; | ||
123 | }; | ||
109 | 124 | ||
110 | /* for board-specific init logic */ | 125 | /* for board-specific init logic */ |
111 | extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); | 126 | extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); |
127 | extern int usb_add_phy_dev(struct usb_phy *); | ||
112 | extern void usb_remove_phy(struct usb_phy *); | 128 | extern void usb_remove_phy(struct usb_phy *); |
113 | 129 | ||
114 | /* helpers for direct access thru low-level io interface */ | 130 | /* helpers for direct access thru low-level io interface */ |
@@ -149,8 +165,14 @@ usb_phy_shutdown(struct usb_phy *x) | |||
149 | extern struct usb_phy *usb_get_phy(enum usb_phy_type type); | 165 | extern struct usb_phy *usb_get_phy(enum usb_phy_type type); |
150 | extern struct usb_phy *devm_usb_get_phy(struct device *dev, | 166 | extern struct usb_phy *devm_usb_get_phy(struct device *dev, |
151 | enum usb_phy_type type); | 167 | enum usb_phy_type type); |
168 | extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); | ||
169 | extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); | ||
170 | extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | ||
171 | const char *phandle, u8 index); | ||
152 | extern void usb_put_phy(struct usb_phy *); | 172 | extern void usb_put_phy(struct usb_phy *); |
153 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); | 173 | extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); |
174 | extern int usb_bind_phy(const char *dev_name, u8 index, | ||
175 | const char *phy_dev_name); | ||
154 | #else | 176 | #else |
155 | static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) | 177 | static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) |
156 | { | 178 | { |
@@ -163,6 +185,22 @@ static inline struct usb_phy *devm_usb_get_phy(struct device *dev, | |||
163 | return NULL; | 185 | return NULL; |
164 | } | 186 | } |
165 | 187 | ||
188 | static inline struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) | ||
189 | { | ||
190 | return NULL; | ||
191 | } | ||
192 | |||
193 | static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) | ||
194 | { | ||
195 | return NULL; | ||
196 | } | ||
197 | |||
198 | static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, | ||
199 | const char *phandle, u8 index) | ||
200 | { | ||
201 | return NULL; | ||
202 | } | ||
203 | |||
166 | static inline void usb_put_phy(struct usb_phy *x) | 204 | static inline void usb_put_phy(struct usb_phy *x) |
167 | { | 205 | { |
168 | } | 206 | } |
@@ -171,6 +209,11 @@ static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) | |||
171 | { | 209 | { |
172 | } | 210 | } |
173 | 211 | ||
212 | static inline int usb_bind_phy(const char *dev_name, u8 index, | ||
213 | const char *phy_dev_name) | ||
214 | { | ||
215 | return -EOPNOTSUPP; | ||
216 | } | ||
174 | #endif | 217 | #endif |
175 | 218 | ||
176 | static inline int | 219 | static inline int |
diff --git a/include/linux/usb/samsung_usb_phy.h b/include/linux/usb/samsung_usb_phy.h new file mode 100644 index 000000000000..916782699f1c --- /dev/null +++ b/include/linux/usb/samsung_usb_phy.h | |||
@@ -0,0 +1,16 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2012 Samsung Electronics Co.Ltd | ||
3 | * http://www.samsung.com/ | ||
4 | * | ||
5 | * Defines phy types for samsung usb phy controllers - HOST or DEIVCE. | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | enum samsung_usb_phy_type { | ||
14 | USB_PHY_TYPE_DEVICE, | ||
15 | USB_PHY_TYPE_HOST, | ||
16 | }; | ||