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 | }; | ||
