From 337dc3a7684cf6577b5595b9bb96e1af06baec41 Mon Sep 17 00:00:00 2001 From: Praveen Paneri Date: Fri, 23 Nov 2012 16:03:06 +0530 Subject: usb: phy: samsung: Introducing usb phy driver for hsotg This driver uses usb_phy interface to interact with s3c-hsotg. Supports phy_init and phy_shutdown functions to enable/disable usb phy. Support will be extended to host controllers and more Samsung SoCs. Signed-off-by: Praveen Paneri Acked-by: Heiko Stuebner Acked-by: Kyungmin Park Signed-off-by: Felipe Balbi --- include/linux/platform_data/samsung-usbphy.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 include/linux/platform_data/samsung-usbphy.h (limited to 'include') 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 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * http://www.samsung.com/ + * Author: Praveen Paneri + * + * Defines platform data for samsung usb phy driver. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +#ifndef __SAMSUNG_USBPHY_PLATFORM_H +#define __SAMSUNG_USBPHY_PLATFORM_H + +/** + * samsung_usbphy_data - Platform data for USB PHY driver. + * @pmu_isolation: Function to control usb phy isolation in PMU. + */ +struct samsung_usbphy_data { + void (*pmu_isolation)(int on); +}; + +extern void samsung_usbphy_set_pdata(struct samsung_usbphy_data *pd); + +#endif /* __SAMSUNG_USBPHY_PLATFORM_H */ -- cgit v1.2.3 From b506eebc504caaf863b5c5a68a1e1d304d610482 Mon Sep 17 00:00:00 2001 From: Vivek Gautam Date: Tue, 22 Jan 2013 18:30:40 +0530 Subject: ARM: EXYNOS: Update & move usb-phy types to generic include layer Updating the names of usb-phy types to more generic names: USB_PHY_TYPE_DEIVCE & USB_PHY_TYPE_HOST; and further update its dependencies. Signed-off-by: Praveen Paneri Signed-off-by: Vivek Gautam Acked-by: Kukjin Kim Signed-off-by: Felipe Balbi --- drivers/usb/host/ehci-s5p.c | 9 +++++---- drivers/usb/host/ohci-exynos.c | 9 +++++---- include/linux/usb/samsung_usb_phy.h | 16 ++++++++++++++++ 3 files changed, 26 insertions(+), 8 deletions(-) create mode 100644 include/linux/usb/samsung_usb_phy.h (limited to 'include') diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index 319dcfaa8735..46ca5efac82b 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #define EHCI_INSNREG00(base) (base + 0x90) @@ -164,7 +165,7 @@ static int s5p_ehci_probe(struct platform_device *pdev) } if (pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); + pdata->phy_init(pdev, USB_PHY_TYPE_HOST); ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; @@ -198,7 +199,7 @@ static int s5p_ehci_remove(struct platform_device *pdev) usb_remove_hcd(hcd); if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); clk_disable_unprepare(s5p_ehci->clk); @@ -229,7 +230,7 @@ static int s5p_ehci_suspend(struct device *dev) rc = ehci_suspend(hcd, do_wakeup); if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); clk_disable_unprepare(s5p_ehci->clk); @@ -246,7 +247,7 @@ static int s5p_ehci_resume(struct device *dev) clk_prepare_enable(s5p_ehci->clk); if (pdata && pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); + pdata->phy_init(pdev, USB_PHY_TYPE_HOST); /* DMA burst Enable */ 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 aa3b8844bb9f..804fb62a888c 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -15,6 +15,7 @@ #include #include #include +#include #include struct exynos_ohci_hcd { @@ -153,7 +154,7 @@ static int exynos_ohci_probe(struct platform_device *pdev) } if (pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); + pdata->phy_init(pdev, USB_PHY_TYPE_HOST); ohci = hcd_to_ohci(hcd); ohci_hcd_init(ohci); @@ -184,7 +185,7 @@ static int exynos_ohci_remove(struct platform_device *pdev) usb_remove_hcd(hcd); if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); clk_disable_unprepare(exynos_ohci->clk); @@ -229,7 +230,7 @@ static int exynos_ohci_suspend(struct device *dev) clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); if (pdata && pdata->phy_exit) - pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); clk_disable_unprepare(exynos_ohci->clk); @@ -249,7 +250,7 @@ static int exynos_ohci_resume(struct device *dev) clk_prepare_enable(exynos_ohci->clk); if (pdata && pdata->phy_init) - pdata->phy_init(pdev, S5P_USB_PHY_HOST); + pdata->phy_init(pdev, USB_PHY_TYPE_HOST); ohci_resume(hcd, false); 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 @@ +/* + * Copyright (C) 2012 Samsung Electronics Co.Ltd + * http://www.samsung.com/ + * + * Defines phy types for samsung usb phy controllers - HOST or DEIVCE. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + */ + +enum samsung_usb_phy_type { + USB_PHY_TYPE_DEVICE, + USB_PHY_TYPE_HOST, +}; -- cgit v1.2.3 From b4a83e4df1bc864e89d3bb90e97f9caab656545d Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 25 Jan 2013 08:03:21 +0530 Subject: usb: otg: add an api to bind the usb controller and phy In order to support platforms which has multiple PHY's (of same type) and which has multiple USB controllers, a new design is adopted wherin the binding information (between the PHY and the USB controller) should be passed to the PHY library from platform specific file (board file). So added a new API to pass the binding information. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/otg/otg.c | 37 +++++++++++++++++++++++++++++++++++++ include/linux/usb/phy.h | 22 ++++++++++++++++++++++ 2 files changed, 59 insertions(+) (limited to 'include') diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index a30c04115115..8e756d95a28f 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -18,6 +18,7 @@ #include static LIST_HEAD(phy_list); +static LIST_HEAD(phy_bind_list); static DEFINE_SPINLOCK(phy_lock); static struct usb_phy *__usb_find_phy(struct list_head *list, @@ -201,6 +202,42 @@ void usb_remove_phy(struct usb_phy *x) } EXPORT_SYMBOL(usb_remove_phy); +/** + * usb_bind_phy - bind the phy and the controller that uses the phy + * @dev_name: the device name of the device that will bind to the phy + * @index: index to specify the port number + * @phy_dev_name: the device name of the phy + * + * Fills the phy_bind structure with the dev_name and phy_dev_name. This will + * be used when the phy driver registers the phy and when the controller + * requests this phy. + * + * To be used by platform specific initialization code. + */ +int __init usb_bind_phy(const char *dev_name, u8 index, + const char *phy_dev_name) +{ + struct usb_phy_bind *phy_bind; + unsigned long flags; + + phy_bind = kzalloc(sizeof(*phy_bind), GFP_KERNEL); + if (!phy_bind) { + pr_err("phy_bind(): No memory for phy_bind"); + return -ENOMEM; + } + + phy_bind->dev_name = dev_name; + phy_bind->phy_dev_name = phy_dev_name; + phy_bind->index = index; + + spin_lock_irqsave(&phy_lock, flags); + list_add_tail(&phy_bind->list, &phy_bind_list); + spin_unlock_irqrestore(&phy_lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(usb_bind_phy); + const char *otg_state_string(enum usb_otg_state state) { switch (state) { diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index a29ae1eb9346..a812ed5a1691 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -106,6 +106,21 @@ struct usb_phy { enum usb_device_speed speed); }; +/** + * struct usb_phy_bind - represent the binding for the phy + * @dev_name: the device name of the device that will bind to the phy + * @phy_dev_name: the device name of the phy + * @index: used if a single controller uses multiple phys + * @phy: reference to the phy + * @list: to maintain a linked list of the binding information + */ +struct usb_phy_bind { + const char *dev_name; + const char *phy_dev_name; + u8 index; + struct usb_phy *phy; + struct list_head list; +}; /* for board-specific init logic */ extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); @@ -151,6 +166,8 @@ extern struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type); extern void usb_put_phy(struct usb_phy *); extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); +extern int usb_bind_phy(const char *dev_name, u8 index, + const char *phy_dev_name); #else static inline struct usb_phy *usb_get_phy(enum usb_phy_type type) { @@ -171,6 +188,11 @@ static inline void devm_usb_put_phy(struct device *dev, struct usb_phy *x) { } +static inline int usb_bind_phy(const char *dev_name, u8 index, + const char *phy_dev_name) +{ + return -EOPNOTSUPP; +} #endif static inline int -- cgit v1.2.3 From 0fa4fab4ee46470ccd463c83be95434936942e05 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 25 Jan 2013 08:03:22 +0530 Subject: usb: otg: utils: add facilities in phy lib to support multiple PHYs of same type In order to add support for multipe PHY's of the same type, new API's for adding PHY and getting PHY has been added. Now the binding information for the PHY and controller should be done in platform file using usb_bind_phy API. And for getting a PHY, the device pointer of the USB controller and an index should be passed. Based on the binding information that is added in the platform file, usb_get_phy_dev will return the appropriate PHY. Already existing API's to add and get phy by type is not removed. These API's are deprecated and will be removed once all the platforms start to use the new API. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/otg/otg.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++- include/linux/usb/phy.h | 13 ++++++ 2 files changed, 130 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index 8e756d95a28f..4bb4333c9653 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -36,6 +36,24 @@ static struct usb_phy *__usb_find_phy(struct list_head *list, return ERR_PTR(-ENODEV); } +static struct usb_phy *__usb_find_phy_dev(struct device *dev, + struct list_head *list, u8 index) +{ + struct usb_phy_bind *phy_bind = NULL; + + list_for_each_entry(phy_bind, list, list) { + if (!(strcmp(phy_bind->dev_name, dev_name(dev))) && + phy_bind->index == index) { + if (phy_bind->phy) + return phy_bind->phy; + else + return ERR_PTR(-EPROBE_DEFER); + } + } + + return ERR_PTR(-ENODEV); +} + static void devm_usb_phy_release(struct device *dev, void *res) { struct usb_phy *phy = *(struct usb_phy **)res; @@ -111,6 +129,69 @@ err0: } EXPORT_SYMBOL(usb_get_phy); +/** + * usb_get_phy_dev - find the USB PHY + * @dev - device that requests this phy + * @index - the index of the phy + * + * Returns the phy driver, after getting a refcount to it; or + * -ENODEV if there is no such phy. The caller is responsible for + * calling usb_put_phy() to release that count. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) +{ + struct usb_phy *phy = NULL; + unsigned long flags; + + spin_lock_irqsave(&phy_lock, flags); + + phy = __usb_find_phy_dev(dev, &phy_bind_list, index); + if (IS_ERR(phy)) { + pr_err("unable to find transceiver\n"); + goto err0; + } + + get_device(phy->dev); + +err0: + spin_unlock_irqrestore(&phy_lock, flags); + + return phy; +} +EXPORT_SYMBOL(usb_get_phy_dev); + +/** + * devm_usb_get_phy_dev - find the USB PHY using device ptr and index + * @dev - device that requests this phy + * @index - the index of the phy + * + * Gets the phy using usb_get_phy_dev(), and associates a device with it using + * devres. On driver detach, release function is invoked on the devres data, + * then, devres data is freed. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) +{ + struct usb_phy **ptr, *phy; + + ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return NULL; + + phy = usb_get_phy_dev(dev, index); + if (!IS_ERR(phy)) { + *ptr = phy; + devres_add(dev, ptr); + } else + devres_free(ptr); + + return phy; +} +EXPORT_SYMBOL(devm_usb_get_phy_dev); + /** * devm_usb_put_phy - release the USB PHY * @dev - device that wants to release this phy @@ -185,6 +266,36 @@ out: } EXPORT_SYMBOL(usb_add_phy); +/** + * usb_add_phy_dev - declare the USB PHY + * @x: the USB phy to be used; or NULL + * + * This call is exclusively for use by phy drivers, which + * coordinate the activities of drivers for host and peripheral + * controllers, and in some cases for VBUS current regulation. + */ +int usb_add_phy_dev(struct usb_phy *x) +{ + struct usb_phy_bind *phy_bind; + unsigned long flags; + + if (!x->dev) { + dev_err(x->dev, "no device provided for PHY\n"); + return -EINVAL; + } + + spin_lock_irqsave(&phy_lock, flags); + list_for_each_entry(phy_bind, &phy_bind_list, list) + if (!(strcmp(phy_bind->phy_dev_name, dev_name(x->dev)))) + phy_bind->phy = x; + + list_add_tail(&x->head, &phy_list); + + spin_unlock_irqrestore(&phy_lock, flags); + return 0; +} +EXPORT_SYMBOL(usb_add_phy_dev); + /** * usb_remove_phy - remove the OTG PHY * @x: the USB OTG PHY to be removed; @@ -194,10 +305,15 @@ EXPORT_SYMBOL(usb_add_phy); void usb_remove_phy(struct usb_phy *x) { unsigned long flags; + struct usb_phy_bind *phy_bind; spin_lock_irqsave(&phy_lock, flags); - if (x) + if (x) { + list_for_each_entry(phy_bind, &phy_bind_list, list) + if (phy_bind->phy == x) + phy_bind->phy = NULL; list_del(&x->head); + } spin_unlock_irqrestore(&phy_lock, flags); } EXPORT_SYMBOL(usb_remove_phy); diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index a812ed5a1691..359db7de61e4 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -124,6 +124,7 @@ struct usb_phy_bind { /* for board-specific init logic */ extern int usb_add_phy(struct usb_phy *, enum usb_phy_type type); +extern int usb_add_phy_dev(struct usb_phy *); extern void usb_remove_phy(struct usb_phy *); /* helpers for direct access thru low-level io interface */ @@ -164,6 +165,8 @@ usb_phy_shutdown(struct usb_phy *x) extern struct usb_phy *usb_get_phy(enum usb_phy_type type); extern struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type); +extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); +extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); extern void usb_put_phy(struct usb_phy *); extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern int usb_bind_phy(const char *dev_name, u8 index, @@ -180,6 +183,16 @@ static inline struct usb_phy *devm_usb_get_phy(struct device *dev, return NULL; } +static inline struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index) +{ + return NULL; +} + +static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) +{ + return NULL; +} + static inline void usb_put_phy(struct usb_phy *x) { } -- cgit v1.2.3 From 5d3c28b5a42df5ceaa854901ba2cccb76883c77e Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 25 Jan 2013 08:03:25 +0530 Subject: usb: otg: add device tree support to otg library Added an API devm_usb_get_phy_by_phandle(), to get usb phy by passing a device node phandle value. This function will return a pointer to the phy on success, -EPROBE_DEFER if there is a device_node for the phandle, but the phy has not been added, or a ERR_PTR() otherwise. Cc: Marc Kleine-Budde Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- drivers/usb/otg/otg.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/usb/phy.h | 8 +++++ 2 files changed, 88 insertions(+) (limited to 'include') diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c index 4bb4333c9653..e1814397ca3a 100644 --- a/drivers/usb/otg/otg.c +++ b/drivers/usb/otg/otg.c @@ -13,7 +13,9 @@ #include #include #include +#include #include +#include #include @@ -54,6 +56,20 @@ static struct usb_phy *__usb_find_phy_dev(struct device *dev, return ERR_PTR(-ENODEV); } +static struct usb_phy *__of_usb_find_phy(struct device_node *node) +{ + struct usb_phy *phy; + + list_for_each_entry(phy, &phy_list, head) { + if (node != phy->dev->of_node) + continue; + + return phy; + } + + return ERR_PTR(-ENODEV); +} + static void devm_usb_phy_release(struct device *dev, void *res) { struct usb_phy *phy = *(struct usb_phy **)res; @@ -129,6 +145,70 @@ err0: } EXPORT_SYMBOL(usb_get_phy); + /** + * devm_usb_get_phy_by_phandle - find the USB PHY by phandle + * @dev - device that requests this phy + * @phandle - name of the property holding the phy phandle value + * @index - the index of the phy + * + * Returns the phy driver associated with the given phandle value, + * after getting a refcount to it, -ENODEV if there is no such phy or + * -EPROBE_DEFER if there is a phandle to the phy, but the device is + * not yet loaded. While at that, it also associates the device with + * the phy using devres. On driver detach, release function is invoked + * on the devres data, then, devres data is freed. + * + * For use by USB host and peripheral drivers. + */ +struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle, u8 index) +{ + struct usb_phy *phy = ERR_PTR(-ENOMEM), **ptr; + unsigned long flags; + struct device_node *node; + + if (!dev->of_node) { + dev_dbg(dev, "device does not have a device node entry\n"); + return ERR_PTR(-EINVAL); + } + + node = of_parse_phandle(dev->of_node, phandle, index); + if (!node) { + dev_dbg(dev, "failed to get %s phandle in %s node\n", phandle, + dev->of_node->full_name); + return ERR_PTR(-ENODEV); + } + + ptr = devres_alloc(devm_usb_phy_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) { + dev_dbg(dev, "failed to allocate memory for devres\n"); + goto err0; + } + + spin_lock_irqsave(&phy_lock, flags); + + phy = __of_usb_find_phy(node); + if (IS_ERR(phy) || !try_module_get(phy->dev->driver->owner)) { + phy = ERR_PTR(-EPROBE_DEFER); + devres_free(ptr); + goto err1; + } + + *ptr = phy; + devres_add(dev, ptr); + + get_device(phy->dev); + +err1: + spin_unlock_irqrestore(&phy_lock, flags); + +err0: + of_node_put(node); + + return phy; +} +EXPORT_SYMBOL(devm_usb_get_phy_by_phandle); + /** * usb_get_phy_dev - find the USB PHY * @dev - device that requests this phy diff --git a/include/linux/usb/phy.h b/include/linux/usb/phy.h index 359db7de61e4..15847cbdb512 100644 --- a/include/linux/usb/phy.h +++ b/include/linux/usb/phy.h @@ -167,6 +167,8 @@ extern struct usb_phy *devm_usb_get_phy(struct device *dev, enum usb_phy_type type); extern struct usb_phy *usb_get_phy_dev(struct device *dev, u8 index); extern struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index); +extern struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle, u8 index); extern void usb_put_phy(struct usb_phy *); extern void devm_usb_put_phy(struct device *dev, struct usb_phy *x); extern int usb_bind_phy(const char *dev_name, u8 index, @@ -193,6 +195,12 @@ static inline struct usb_phy *devm_usb_get_phy_dev(struct device *dev, u8 index) return NULL; } +static inline struct usb_phy *devm_usb_get_phy_by_phandle(struct device *dev, + const char *phandle, u8 index) +{ + return NULL; +} + static inline void usb_put_phy(struct usb_phy *x) { } -- cgit v1.2.3 From 01658f0f8d1322dbf94f289aa610731d539bf888 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 25 Jan 2013 15:53:57 +0530 Subject: usb: phy: add a new driver for usb part of control module Added a new driver for the usb part of control module. This has an API to power on the USB2 phy and an API to write to the mailbox depending on whether MUSB has to act in host mode or in device mode. Writing to control module registers for doing the above task which was previously done in omap glue and in omap-usb2 phy will be removed. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/omap-usb.txt | 30 ++- Documentation/devicetree/bindings/usb/usb-phy.txt | 5 + drivers/usb/phy/Kconfig | 10 + drivers/usb/phy/Makefile | 1 + drivers/usb/phy/omap-control-usb.c | 295 +++++++++++++++++++++ include/linux/usb/omap_control_usb.h | 92 +++++++ 6 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 drivers/usb/phy/omap-control-usb.c create mode 100644 include/linux/usb/omap_control_usb.h (limited to 'include') diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 29a043ecda52..3d78cc2b486e 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -1,4 +1,4 @@ -OMAP GLUE +OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS OMAP MUSB GLUE - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" @@ -16,6 +16,10 @@ OMAP MUSB GLUE - power : Should be "50". This signifies the controller can supply upto 100mA when operating in host mode. +Optional properties: + - ctrl-module : phandle of the control module this glue uses to write to + mailbox + SOC specific device node entry usb_otg_hs: usb_otg_hs@4a0ab000 { compatible = "ti,omap4-musb"; @@ -23,6 +27,7 @@ usb_otg_hs: usb_otg_hs@4a0ab000 { multipoint = <1>; num_eps = <16>; ram_bits = <12>; + ctrl-module = <&omap_control_usb>; }; Board specific device node entry @@ -31,3 +36,26 @@ Board specific device node entry mode = <3>; power = <50>; }; + +OMAP CONTROL USB + +Required properties: + - compatible: Should be "ti,omap-control-usb" + - reg : Address and length of the register set for the device. It contains + the address of "control_dev_conf" and "otghs_control" or "phy_power_usb" + depending upon omap4 or omap5. + - reg-names: The names of the register addresses corresponding to the registers + filled in "reg". + - ti,type: This is used to differentiate whether the control module has + usb mailbox or usb3 phy power. omap4 has usb mailbox in control module to + notify events to the musb core and omap5 has usb3 phy power register to + power on usb3 phy. Should be "1" if it has mailbox and "2" if it has usb3 + phy power. + +omap_control_usb: omap-control-usb@4a002300 { + compatible = "ti,omap-control-usb"; + reg = <0x4a002300 0x4>, + <0x4a00233c 0x4>; + reg-names = "control_dev_conf", "otghs_control"; + ti,type = <1>; +}; diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt index 80d4148cb661..4234105302db 100644 --- a/Documentation/devicetree/bindings/usb/usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/usb-phy.txt @@ -8,10 +8,15 @@ Required properties: add the address of control module dev conf register until a driver for control module is added +Optional properties: + - ctrl-module : phandle of the control module used by PHY driver to power on + the PHY. + This is usually a subnode of ocp2scp to which it is connected. usb2phy@4a0ad080 { compatible = "ti,omap-usb2"; reg = <0x4a0ad080 0x58>, <0x4a002300 0x4>; + ctrl-module = <&omap_control_usb>; }; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index fae4d08c0ddd..053696a2b6ef 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -14,6 +14,16 @@ config OMAP_USB2 The USB OTG controller communicates with the comparator using this driver. +config OMAP_CONTROL_USB + tristate "OMAP CONTROL USB Driver" + depends on ARCH_OMAP2PLUS + help + Enable this to add support for the USB part present in the control + module. This driver has API to power on the USB2 PHY and to write to + the mailbox. The mailbox is present only in omap4 and the register to + power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an + additional register to power on USB3 PHY. + config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index ec304f642402..ee977671f530 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -5,6 +5,7 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG obj-$(CONFIG_OMAP_USB2) += omap-usb2.o +obj-$(CONFIG_OMAP_CONTROL_USB) += omap-control-usb.o obj-$(CONFIG_USB_ISP1301) += isp1301.o obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o obj-$(CONFIG_USB_EHCI_TEGRA) += tegra_usb_phy.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 @@ +/* + * omap-control-usb.c - The USB part of control module. + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static struct omap_control_usb *control_usb; + +/** + * omap_get_control_dev - returns the device pointer for this control device + * + * This API should be called to get the device pointer for this control + * module device. This device pointer should be used for called other + * exported API's in this driver. + * + * To be used by PHY driver and glue driver. + */ +struct device *omap_get_control_dev(void) +{ + if (!control_usb) + return ERR_PTR(-ENODEV); + + return control_usb->dev; +} +EXPORT_SYMBOL_GPL(omap_get_control_dev); + +/** + * omap_control_usb3_phy_power - power on/off the serializer using control + * module + * @dev: the control module device + * @on: 0 to off and 1 to on based on powering on or off the PHY + * + * usb3 PHY driver should call this API to power on or off the PHY. + */ +void omap_control_usb3_phy_power(struct device *dev, bool on) +{ + u32 val; + unsigned long rate; + struct omap_control_usb *control_usb = dev_get_drvdata(dev); + + if (control_usb->type != OMAP_CTRL_DEV_TYPE2) + return; + + rate = clk_get_rate(control_usb->sys_clk); + rate = rate/1000000; + + val = readl(control_usb->phy_power); + + if (on) { + val &= ~(OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK | + OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK); + val |= OMAP_CTRL_USB3_PHY_TX_RX_POWERON << + OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT; + val |= rate << OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT; + } else { + val &= ~OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK; + val |= OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF << + OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT; + } + + writel(val, control_usb->phy_power); +} +EXPORT_SYMBOL_GPL(omap_control_usb3_phy_power); + +/** + * omap_control_usb_phy_power - power on/off the phy using control module reg + * @dev: the control module device + * @on: 0 or 1, based on powering on or off the PHY + */ +void omap_control_usb_phy_power(struct device *dev, int on) +{ + u32 val; + struct omap_control_usb *control_usb = dev_get_drvdata(dev); + + val = readl(control_usb->dev_conf); + + if (on) + val &= ~OMAP_CTRL_DEV_PHY_PD; + else + val |= OMAP_CTRL_DEV_PHY_PD; + + writel(val, control_usb->dev_conf); +} +EXPORT_SYMBOL_GPL(omap_control_usb_phy_power); + +/** + * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded + * @ctrl_usb: struct omap_control_usb * + * + * Writes to the mailbox register to notify the usb core that a usb + * device has been connected. + */ +static void omap_control_usb_host_mode(struct omap_control_usb *ctrl_usb) +{ + u32 val; + + val = readl(ctrl_usb->otghs_control); + val &= ~(OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND); + val |= OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID; + writel(val, ctrl_usb->otghs_control); +} + +/** + * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high + * impedance + * @ctrl_usb: struct omap_control_usb * + * + * Writes to the mailbox register to notify the usb core that it has been + * connected to a usb host. + */ +static void omap_control_usb_device_mode(struct omap_control_usb *ctrl_usb) +{ + u32 val; + + val = readl(ctrl_usb->otghs_control); + val &= ~OMAP_CTRL_DEV_SESSEND; + val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_AVALID | + OMAP_CTRL_DEV_VBUSVALID; + writel(val, ctrl_usb->otghs_control); +} + +/** + * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high + * impedance + * @ctrl_usb: struct omap_control_usb * + * + * Writes to the mailbox register to notify the usb core it's now in + * disconnected state. + */ +static void omap_control_usb_set_sessionend(struct omap_control_usb *ctrl_usb) +{ + u32 val; + + val = readl(ctrl_usb->otghs_control); + val &= ~(OMAP_CTRL_DEV_AVALID | OMAP_CTRL_DEV_VBUSVALID); + val |= OMAP_CTRL_DEV_IDDIG | OMAP_CTRL_DEV_SESSEND; + writel(val, ctrl_usb->otghs_control); +} + +/** + * omap_control_usb_set_mode - Calls to functions to set USB in one of host mode + * or device mode or to denote disconnected state + * @dev: the control module device + * @mode: The mode to which usb should be configured + * + * This is an API to write to the mailbox register to notify the usb core that + * a usb device has been connected. + */ +void omap_control_usb_set_mode(struct device *dev, + enum omap_control_usb_mode mode) +{ + struct omap_control_usb *ctrl_usb; + + if (IS_ERR(dev) || control_usb->type != OMAP_CTRL_DEV_TYPE1) + return; + + ctrl_usb = dev_get_drvdata(dev); + + switch (mode) { + case USB_MODE_HOST: + omap_control_usb_host_mode(ctrl_usb); + break; + case USB_MODE_DEVICE: + omap_control_usb_device_mode(ctrl_usb); + break; + case USB_MODE_DISCONNECT: + omap_control_usb_set_sessionend(ctrl_usb); + break; + default: + dev_vdbg(dev, "invalid omap control usb mode\n"); + } +} +EXPORT_SYMBOL_GPL(omap_control_usb_set_mode); + +static int omap_control_usb_probe(struct platform_device *pdev) +{ + struct resource *res; + struct device_node *np = pdev->dev.of_node; + struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data; + + control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb), + GFP_KERNEL); + if (!control_usb) { + dev_err(&pdev->dev, "unable to alloc memory for control usb\n"); + return -ENOMEM; + } + + if (np) { + of_property_read_u32(np, "ti,type", &control_usb->type); + } else if (pdata) { + control_usb->type = pdata->type; + } else { + dev_err(&pdev->dev, "no pdata present\n"); + return -EINVAL; + } + + control_usb->dev = &pdev->dev; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "control_dev_conf"); + control_usb->dev_conf = devm_request_and_ioremap(&pdev->dev, res); + if (!control_usb->dev_conf) { + dev_err(&pdev->dev, "Failed to obtain io memory\n"); + return -EADDRNOTAVAIL; + } + + if (control_usb->type == OMAP_CTRL_DEV_TYPE1) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "otghs_control"); + control_usb->otghs_control = devm_request_and_ioremap( + &pdev->dev, res); + if (!control_usb->otghs_control) { + dev_err(&pdev->dev, "Failed to obtain io memory\n"); + return -EADDRNOTAVAIL; + } + } + + if (control_usb->type == OMAP_CTRL_DEV_TYPE2) { + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "phy_power_usb"); + control_usb->phy_power = devm_request_and_ioremap( + &pdev->dev, res); + if (!control_usb->phy_power) { + dev_dbg(&pdev->dev, "Failed to obtain io memory\n"); + return -EADDRNOTAVAIL; + } + + control_usb->sys_clk = devm_clk_get(control_usb->dev, + "sys_clkin"); + if (IS_ERR(control_usb->sys_clk)) { + pr_err("%s: unable to get sys_clkin\n", __func__); + return -EINVAL; + } + } + + + dev_set_drvdata(control_usb->dev, control_usb); + + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id omap_control_usb_id_table[] = { + { .compatible = "ti,omap-control-usb" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_control_usb_id_table); +#endif + +static struct platform_driver omap_control_usb_driver = { + .probe = omap_control_usb_probe, + .driver = { + .name = "omap-control-usb", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(omap_control_usb_id_table), + }, +}; + +static int __init omap_control_usb_init(void) +{ + return platform_driver_register(&omap_control_usb_driver); +} +subsys_initcall(omap_control_usb_init); + +static void __exit omap_control_usb_exit(void) +{ + platform_driver_unregister(&omap_control_usb_driver); +} +module_exit(omap_control_usb_exit); + +MODULE_ALIAS("platform: omap_control_usb"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP Control Module USB Driver"); +MODULE_LICENSE("GPL v2"); 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 @@ +/* + * omap_control_usb.h - Header file for the USB part of control module. + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef __OMAP_CONTROL_USB_H__ +#define __OMAP_CONTROL_USB_H__ + +struct omap_control_usb { + struct device *dev; + + u32 __iomem *dev_conf; + u32 __iomem *otghs_control; + u32 __iomem *phy_power; + + struct clk *sys_clk; + + u32 type; +}; + +struct omap_control_usb_platform_data { + u8 type; +}; + +enum omap_control_usb_mode { + USB_MODE_UNDEFINED = 0, + USB_MODE_HOST, + USB_MODE_DEVICE, + USB_MODE_DISCONNECT, +}; + +/* To differentiate ctrl module IP having either mailbox or USB3 PHY power */ +#define OMAP_CTRL_DEV_TYPE1 0x1 +#define OMAP_CTRL_DEV_TYPE2 0x2 + +#define OMAP_CTRL_DEV_PHY_PD BIT(0) + +#define OMAP_CTRL_DEV_AVALID BIT(0) +#define OMAP_CTRL_DEV_BVALID BIT(1) +#define OMAP_CTRL_DEV_VBUSVALID BIT(2) +#define OMAP_CTRL_DEV_SESSEND BIT(3) +#define OMAP_CTRL_DEV_IDDIG BIT(4) + +#define OMAP_CTRL_USB_PWRCTL_CLK_CMD_MASK 0x003FC000 +#define OMAP_CTRL_USB_PWRCTL_CLK_CMD_SHIFT 0xE + +#define OMAP_CTRL_USB_PWRCTL_CLK_FREQ_MASK 0xFFC00000 +#define OMAP_CTRL_USB_PWRCTL_CLK_FREQ_SHIFT 0x16 + +#define OMAP_CTRL_USB3_PHY_TX_RX_POWERON 0x3 +#define OMAP_CTRL_USB3_PHY_TX_RX_POWEROFF 0x0 + +#if IS_ENABLED(CONFIG_OMAP_CONTROL_USB) +extern struct device *omap_get_control_dev(void); +extern void omap_control_usb_phy_power(struct device *dev, int on); +extern void omap_control_usb3_phy_power(struct device *dev, bool on); +extern void omap_control_usb_set_mode(struct device *dev, + enum omap_control_usb_mode mode); +#else +static inline struct device *omap_get_control_dev() +{ + return ERR_PTR(-ENODEV); +} + +static inline void omap_control_usb_phy_power(struct device *dev, int on) +{ +} + +static inline void omap_control_usb3_phy_power(struct device *dev, int on) +{ +} + +static inline void omap_control_usb_set_mode(struct device *dev, + enum omap_control_usb_mode mode) +{ +} +#endif + +#endif /* __OMAP_CONTROL_USB_H__ */ -- cgit v1.2.3 From ca784be36cc725bca9b526eba342de7550329731 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 25 Jan 2013 15:54:00 +0530 Subject: usb: start using the control module driver Start using the control module driver for powering on the PHY and for writing to the mailbox instead of writing to the control module registers on their own. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/omap-usb.txt | 4 ++ Documentation/devicetree/bindings/usb/usb-phy.txt | 7 +-- drivers/usb/musb/Kconfig | 1 + drivers/usb/musb/omap2430.c | 68 ++++++++-------------- drivers/usb/musb/omap2430.h | 9 --- drivers/usb/phy/Kconfig | 1 + drivers/usb/phy/omap-usb2.c | 41 +++---------- include/linux/usb/omap_usb.h | 4 +- 8 files changed, 40 insertions(+), 95 deletions(-) (limited to 'include') diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt index 3d78cc2b486e..1ef0ce71f8fa 100644 --- a/Documentation/devicetree/bindings/usb/omap-usb.txt +++ b/Documentation/devicetree/bindings/usb/omap-usb.txt @@ -3,6 +3,9 @@ OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS OMAP MUSB GLUE - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb" - ti,hwmods : must be "usb_otg_hs" + - ti,has-mailbox : to specify that omap uses an external mailbox + (in control module) to communicate with the musb core during device connect + and disconnect. - multipoint : Should be "1" indicating the musb controller supports multipoint. This is a MUSB configuration-specific setting. - num_eps : Specifies the number of endpoints. This is also a @@ -24,6 +27,7 @@ SOC specific device node entry usb_otg_hs: usb_otg_hs@4a0ab000 { compatible = "ti,omap4-musb"; ti,hwmods = "usb_otg_hs"; + ti,has-mailbox; multipoint = <1>; num_eps = <16>; ram_bits = <12>; diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt index 4234105302db..b4b86bb831b2 100644 --- a/Documentation/devicetree/bindings/usb/usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/usb-phy.txt @@ -4,9 +4,7 @@ OMAP USB2 PHY Required properties: - compatible: Should be "ti,omap-usb2" - - reg : Address and length of the register set for the device. Also -add the address of control module dev conf register until a driver for -control module is added + - reg : Address and length of the register set for the device. Optional properties: - ctrl-module : phandle of the control module used by PHY driver to power on @@ -16,7 +14,6 @@ This is usually a subnode of ocp2scp to which it is connected. usb2phy@4a0ad080 { compatible = "ti,omap-usb2"; - reg = <0x4a0ad080 0x58>, - <0x4a002300 0x4>; + reg = <0x4a0ad080 0x58>; ctrl-module = <&omap_control_usb>; }; 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 select NOP_USB_XCEIV if (SOC_TI81XX || SOC_AM33XX) select TWL4030_USB if MACH_OMAP_3430SDP select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA + select OMAP_CONTROL_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA select USB_OTG_UTILS help 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 da00af460794..779862d24590 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -37,6 +37,7 @@ #include #include #include +#include #include "musb_core.h" #include "omap2430.h" @@ -46,7 +47,7 @@ struct omap2430_glue { struct platform_device *musb; enum omap_musb_vbus_id_status status; struct work_struct omap_musb_mailbox_work; - u32 __iomem *control_otghs; + struct device *control_otghs; }; #define glue_to_musb(g) platform_get_drvdata(g->musb) @@ -54,26 +55,6 @@ struct omap2430_glue *_glue; static struct timer_list musb_idle_timer; -/** - * omap4_usb_phy_mailbox - write to usb otg mailbox - * @glue: struct omap2430_glue * - * @val: the value to be written to the mailbox - * - * On detection of a device (ID pin is grounded), this API should be called - * to set AVALID, VBUSVALID and ID pin is grounded. - * - * When OMAP is connected to a host (OMAP in device mode), this API - * is called to set AVALID, VBUSVALID and ID pin in high impedance. - * - * XXX: This function will be removed once we have a seperate driver for - * control module - */ -static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val) -{ - if (glue->control_otghs) - writel(val, glue->control_otghs); -} - static void musb_do_idle(unsigned long _musb) { struct musb *musb = (void *)_musb; @@ -269,7 +250,6 @@ EXPORT_SYMBOL_GPL(omap_musb_mailbox); static void omap_musb_set_mailbox(struct omap2430_glue *glue) { - u32 val; struct musb *musb = glue_to_musb(glue); struct device *dev = musb->controller; struct musb_hdrc_platform_data *pdata = dev->platform_data; @@ -285,8 +265,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) musb->xceiv->last_event = USB_EVENT_ID; if (musb->gadget_driver) { pm_runtime_get_sync(dev); - val = AVALID | VBUSVALID; - omap4_usb_phy_mailbox(glue, val); + omap_control_usb_set_mode(glue->control_otghs, + USB_MODE_HOST); omap2430_musb_set_vbus(musb, 1); } break; @@ -299,8 +279,7 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) musb->xceiv->last_event = USB_EVENT_VBUS; if (musb->gadget_driver) pm_runtime_get_sync(dev); - val = IDDIG | AVALID | VBUSVALID; - omap4_usb_phy_mailbox(glue, val); + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); break; case OMAP_MUSB_ID_FLOAT: @@ -317,8 +296,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue) if (musb->xceiv->otg->set_vbus) otg_set_vbus(musb->xceiv->otg, 0); } - val = SESSEND | IDDIG; - omap4_usb_phy_mailbox(glue, val); + omap_control_usb_set_mode(glue->control_otghs, + USB_MODE_DISCONNECT); break; default: dev_dbg(dev, "ID float\n"); @@ -415,7 +394,6 @@ err1: static void omap2430_musb_enable(struct musb *musb) { u8 devctl; - u32 val; unsigned long timeout = jiffies + msecs_to_jiffies(1000); struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); @@ -425,8 +403,7 @@ static void omap2430_musb_enable(struct musb *musb) switch (glue->status) { case OMAP_MUSB_ID_GROUND: - val = AVALID | VBUSVALID; - omap4_usb_phy_mailbox(glue, val); + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST); if (data->interface_type != MUSB_INTERFACE_UTMI) break; devctl = musb_readb(musb->mregs, MUSB_DEVCTL); @@ -445,8 +422,7 @@ static void omap2430_musb_enable(struct musb *musb) break; case OMAP_MUSB_VBUS_VALID: - val = IDDIG | AVALID | VBUSVALID; - omap4_usb_phy_mailbox(glue, val); + omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE); break; default: @@ -456,14 +432,12 @@ static void omap2430_musb_enable(struct musb *musb) static void omap2430_musb_disable(struct musb *musb) { - u32 val; struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); - if (glue->status != OMAP_MUSB_UNKNOWN) { - val = SESSEND | IDDIG; - omap4_usb_phy_mailbox(glue, val); - } + if (glue->status != OMAP_MUSB_UNKNOWN) + omap_control_usb_set_mode(glue->control_otghs, + USB_MODE_DISCONNECT); } static int omap2430_musb_exit(struct musb *musb) @@ -498,7 +472,6 @@ static int omap2430_probe(struct platform_device *pdev) struct omap2430_glue *glue; struct device_node *np = pdev->dev.of_node; struct musb_hdrc_config *config; - struct resource *res; int ret = -ENOMEM; glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL); @@ -521,12 +494,6 @@ static int omap2430_probe(struct platform_device *pdev) glue->musb = musb; glue->status = OMAP_MUSB_UNKNOWN; - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res); - if (glue->control_otghs == NULL) - dev_dbg(&pdev->dev, "Failed to obtain control memory\n"); - if (np) { pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) { @@ -558,11 +525,22 @@ static int omap2430_probe(struct platform_device *pdev) of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits); of_property_read_u32(np, "power", (u32 *)&pdata->power); config->multipoint = of_property_read_bool(np, "multipoint"); + pdata->has_mailbox = of_property_read_bool(np, + "ti,has-mailbox"); pdata->board_data = data; pdata->config = config; } + if (pdata->has_mailbox) { + glue->control_otghs = omap_get_control_dev(); + if (IS_ERR(glue->control_otghs)) { + dev_vdbg(&pdev->dev, "Failed to get control device\n"); + return -ENODEV; + } + } else { + glue->control_otghs = ERR_PTR(-ENODEV); + } pdata->platform_ops = &omap2430_ops; 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 @@ #define OTG_FORCESTDBY 0x414 # define ENABLEFORCE (1 << 0) -/* - * Control Module bit definitions - * XXX: Will be removed once we have a driver for control module. - */ -#define AVALID BIT(0) -#define BVALID BIT(1) -#define VBUSVALID BIT(2) -#define SESSEND BIT(3) -#define IDDIG BIT(4) #endif /* __MUSB_OMAP243X_H__ */ diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 053696a2b6ef..f989511f13da 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -8,6 +8,7 @@ config OMAP_USB2 tristate "OMAP USB2 PHY Driver" depends on ARCH_OMAP2PLUS select USB_OTG_UTILS + select OMAP_CONTROL_USB help Enable this to support the transceiver that is part of SOC. This driver takes care of all the PHY functionality apart from comparator. diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c index 26ae8f49225c..c2b4c8e6f3c6 100644 --- a/drivers/usb/phy/omap-usb2.c +++ b/drivers/usb/phy/omap-usb2.c @@ -27,6 +27,7 @@ #include #include #include +#include /** * 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) } EXPORT_SYMBOL_GPL(omap_usb2_set_comparator); -/** - * omap_usb_phy_power - power on/off the phy using control module reg - * @phy: struct omap_usb * - * @on: 0 or 1, based on powering on or off the PHY - * - * XXX: Remove this function once control module driver gets merged - */ -static void omap_usb_phy_power(struct omap_usb *phy, int on) -{ - u32 val; - - if (on) { - val = readl(phy->control_dev); - if (val & PHY_PD) { - writel(~PHY_PD, phy->control_dev); - /* XXX: add proper documentation for this delay */ - mdelay(200); - } - } else { - writel(PHY_PD, phy->control_dev); - } -} - static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled) { struct omap_usb *phy = phy_to_omapusb(otg->phy); @@ -124,7 +102,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend) struct omap_usb *phy = phy_to_omapusb(x); if (suspend && !phy->is_suspended) { - omap_usb_phy_power(phy, 0); + omap_control_usb_phy_power(phy->control_dev, 0); pm_runtime_put_sync(phy->dev); phy->is_suspended = 1; } else if (!suspend && phy->is_suspended) { @@ -134,7 +112,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend) ret); return ret; } - omap_usb_phy_power(phy, 1); + omap_control_usb_phy_power(phy->control_dev, 1); phy->is_suspended = 0; } @@ -145,7 +123,6 @@ static int omap_usb2_probe(struct platform_device *pdev) { struct omap_usb *phy; struct usb_otg *otg; - struct resource *res; phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); if (!phy) { @@ -166,16 +143,14 @@ static int omap_usb2_probe(struct platform_device *pdev) phy->phy.set_suspend = omap_usb2_suspend; phy->phy.otg = otg; - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - - phy->control_dev = devm_request_and_ioremap(&pdev->dev, res); - if (phy->control_dev == NULL) { - dev_err(&pdev->dev, "Failed to obtain io memory\n"); - return -ENXIO; + phy->control_dev = omap_get_control_dev(); + if (IS_ERR(phy->control_dev)) { + dev_dbg(&pdev->dev, "Failed to get control device\n"); + return -ENODEV; } phy->is_suspended = 1; - omap_usb_phy_power(phy, 0); + omap_control_usb_phy_power(phy->control_dev, 0); otg->set_host = omap_usb_set_host; otg->set_peripheral = omap_usb_set_peripheral; diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h index 0ea17f8ae820..3db9b5316b10 100644 --- a/include/linux/usb/omap_usb.h +++ b/include/linux/usb/omap_usb.h @@ -25,13 +25,11 @@ struct omap_usb { struct usb_phy phy; struct phy_companion *comparator; struct device *dev; - u32 __iomem *control_dev; + struct device *control_dev; struct clk *wkupclk; u8 is_suspended:1; }; -#define PHY_PD 0x1 - #define phy_to_omapusb(x) container_of((x), struct omap_usb, phy) #if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE) -- cgit v1.2.3 From 57f6ce072e35770a63be0c5d5e82f90d8da7d665 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 25 Jan 2013 08:21:48 +0530 Subject: usb: phy: add a new driver for usb3 phy Added a driver for usb3 phy that handles the interaction between usb phy device and dwc3 controller. This also includes device tree support for usb3 phy driver and the documentation with device tree binding information is updated. Currently writing to control module register is taken care in this driver which will be removed once the control module driver is in place. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Felipe Balbi Signed-off-by: Moiz Sonasath Signed-off-by: Felipe Balbi --- Documentation/devicetree/bindings/usb/usb-phy.txt | 23 ++ drivers/usb/phy/Kconfig | 10 + drivers/usb/phy/Makefile | 1 + drivers/usb/phy/omap-usb3.c | 355 ++++++++++++++++++++++ include/linux/usb/omap_usb.h | 23 ++ 5 files changed, 412 insertions(+) create mode 100644 drivers/usb/phy/omap-usb3.c (limited to 'include') diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt index b4b86bb831b2..61496f5cb095 100644 --- a/Documentation/devicetree/bindings/usb/usb-phy.txt +++ b/Documentation/devicetree/bindings/usb/usb-phy.txt @@ -17,3 +17,26 @@ usb2phy@4a0ad080 { reg = <0x4a0ad080 0x58>; ctrl-module = <&omap_control_usb>; }; + +OMAP USB3 PHY + +Required properties: + - compatible: Should be "ti,omap-usb3" + - reg : Address and length of the register set for the device. + - reg-names: The names of the register addresses corresponding to the registers + filled in "reg". + +Optional properties: + - ctrl-module : phandle of the control module used by PHY driver to power on + the PHY. + +This is usually a subnode of ocp2scp to which it is connected. + +usb3phy@4a084400 { + compatible = "ti,omap-usb3"; + reg = <0x4a084400 0x80>, + <0x4a084800 0x64>, + <0x4a084c00 0x40>; + reg-names = "phy_rx", "phy_tx", "pll_ctrl"; + ctrl-module = <&omap_control_usb>; +}; diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index f989511f13da..9bbedecb3371 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -15,6 +15,16 @@ config OMAP_USB2 The USB OTG controller communicates with the comparator using this driver. +config OMAP_USB3 + tristate "OMAP USB3 PHY Driver" + select USB_OTG_UTILS + select OMAP_CONTROL_USB + help + Enable this to support the USB3 PHY that is part of SOC. This + driver takes care of all the PHY functionality apart from comparator. + This driver interacts with the "OMAP Control USB Driver" to power + on/off the PHY. + config OMAP_CONTROL_USB tristate "OMAP CONTROL USB Driver" depends on ARCH_OMAP2PLUS diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index ee977671f530..b13faa193e0c 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -5,6 +5,7 @@ ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG obj-$(CONFIG_OMAP_USB2) += omap-usb2.o +obj-$(CONFIG_OMAP_USB3) += omap-usb3.o obj-$(CONFIG_OMAP_CONTROL_USB) += omap-control-usb.o obj-$(CONFIG_USB_ISP1301) += isp1301.o obj-$(CONFIG_MV_U3D_PHY) += mv_u3d_phy.o 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 @@ +/* + * omap-usb3 - USB PHY, talking to dwc3 controller in OMAP. + * + * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Author: Kishon Vijay Abraham I + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define NUM_SYS_CLKS 5 +#define PLL_STATUS 0x00000004 +#define PLL_GO 0x00000008 +#define PLL_CONFIGURATION1 0x0000000C +#define PLL_CONFIGURATION2 0x00000010 +#define PLL_CONFIGURATION3 0x00000014 +#define PLL_CONFIGURATION4 0x00000020 + +#define PLL_REGM_MASK 0x001FFE00 +#define PLL_REGM_SHIFT 0x9 +#define PLL_REGM_F_MASK 0x0003FFFF +#define PLL_REGM_F_SHIFT 0x0 +#define PLL_REGN_MASK 0x000001FE +#define PLL_REGN_SHIFT 0x1 +#define PLL_SELFREQDCO_MASK 0x0000000E +#define PLL_SELFREQDCO_SHIFT 0x1 +#define PLL_SD_MASK 0x0003FC00 +#define PLL_SD_SHIFT 0x9 +#define SET_PLL_GO 0x1 +#define PLL_TICOPWDN 0x10000 +#define PLL_LOCK 0x2 +#define PLL_IDLE 0x1 + +/* + * This is an Empirical value that works, need to confirm the actual + * value required for the USB3PHY_PLL_CONFIGURATION2.PLL_IDLE status + * to be correctly reflected in the USB3PHY_PLL_STATUS register. + */ +# define PLL_IDLE_TIME 100; + +enum sys_clk_rate { + CLK_RATE_UNDEFINED = -1, + CLK_RATE_12MHZ, + CLK_RATE_16MHZ, + CLK_RATE_19MHZ, + CLK_RATE_26MHZ, + CLK_RATE_38MHZ +}; + +static struct usb_dpll_params omap_usb3_dpll_params[NUM_SYS_CLKS] = { + {1250, 5, 4, 20, 0}, /* 12 MHz */ + {3125, 20, 4, 20, 0}, /* 16.8 MHz */ + {1172, 8, 4, 20, 65537}, /* 19.2 MHz */ + {1250, 12, 4, 20, 0}, /* 26 MHz */ + {3125, 47, 4, 20, 92843}, /* 38.4 MHz */ +}; + +static int omap_usb3_suspend(struct usb_phy *x, int suspend) +{ + struct omap_usb *phy = phy_to_omapusb(x); + int val; + int timeout = PLL_IDLE_TIME; + + if (suspend && !phy->is_suspended) { + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); + val |= PLL_IDLE; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); + + do { + val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); + if (val & PLL_TICOPWDN) + break; + udelay(1); + } while (--timeout); + + omap_control_usb3_phy_power(phy->control_dev, 0); + + phy->is_suspended = 1; + } else if (!suspend && phy->is_suspended) { + phy->is_suspended = 0; + + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); + val &= ~PLL_IDLE; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); + + do { + val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); + if (!(val & PLL_TICOPWDN)) + break; + udelay(1); + } while (--timeout); + } + + return 0; +} + +static inline enum sys_clk_rate __get_sys_clk_index(unsigned long rate) +{ + switch (rate) { + case 12000000: + return CLK_RATE_12MHZ; + case 16800000: + return CLK_RATE_16MHZ; + case 19200000: + return CLK_RATE_19MHZ; + case 26000000: + return CLK_RATE_26MHZ; + case 38400000: + return CLK_RATE_38MHZ; + default: + return CLK_RATE_UNDEFINED; + } +} + +static void omap_usb_dpll_relock(struct omap_usb *phy) +{ + u32 val; + unsigned long timeout; + + omap_usb_writel(phy->pll_ctrl_base, PLL_GO, SET_PLL_GO); + + timeout = jiffies + msecs_to_jiffies(20); + do { + val = omap_usb_readl(phy->pll_ctrl_base, PLL_STATUS); + if (val & PLL_LOCK) + break; + } while (!WARN_ON(time_after(jiffies, timeout))); +} + +static int omap_usb_dpll_lock(struct omap_usb *phy) +{ + u32 val; + unsigned long rate; + enum sys_clk_rate clk_index; + + rate = clk_get_rate(phy->sys_clk); + clk_index = __get_sys_clk_index(rate); + + if (clk_index == CLK_RATE_UNDEFINED) { + pr_err("dpll cannot be locked for sys clk freq:%luHz\n", rate); + return -EINVAL; + } + + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); + val &= ~PLL_REGN_MASK; + val |= omap_usb3_dpll_params[clk_index].n << PLL_REGN_SHIFT; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); + + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION2); + val &= ~PLL_SELFREQDCO_MASK; + val |= omap_usb3_dpll_params[clk_index].freq << PLL_SELFREQDCO_SHIFT; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION2, val); + + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION1); + val &= ~PLL_REGM_MASK; + val |= omap_usb3_dpll_params[clk_index].m << PLL_REGM_SHIFT; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION1, val); + + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION4); + val &= ~PLL_REGM_F_MASK; + val |= omap_usb3_dpll_params[clk_index].mf << PLL_REGM_F_SHIFT; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION4, val); + + val = omap_usb_readl(phy->pll_ctrl_base, PLL_CONFIGURATION3); + val &= ~PLL_SD_MASK; + val |= omap_usb3_dpll_params[clk_index].sd << PLL_SD_SHIFT; + omap_usb_writel(phy->pll_ctrl_base, PLL_CONFIGURATION3, val); + + omap_usb_dpll_relock(phy); + + return 0; +} + +static int omap_usb3_init(struct usb_phy *x) +{ + struct omap_usb *phy = phy_to_omapusb(x); + + omap_usb_dpll_lock(phy); + omap_control_usb3_phy_power(phy->control_dev, 1); + + return 0; +} + +static int omap_usb3_probe(struct platform_device *pdev) +{ + struct omap_usb *phy; + struct resource *res; + + phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL); + if (!phy) { + dev_err(&pdev->dev, "unable to alloc mem for OMAP USB3 PHY\n"); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_ctrl"); + phy->pll_ctrl_base = devm_request_and_ioremap(&pdev->dev, res); + if (!phy->pll_ctrl_base) { + dev_err(&pdev->dev, "ioremap of pll_ctrl failed\n"); + return -ENOMEM; + } + + phy->dev = &pdev->dev; + + phy->phy.dev = phy->dev; + phy->phy.label = "omap-usb3"; + phy->phy.init = omap_usb3_init; + phy->phy.set_suspend = omap_usb3_suspend; + phy->phy.type = USB_PHY_TYPE_USB3; + + phy->is_suspended = 1; + phy->wkupclk = devm_clk_get(phy->dev, "usb_phy_cm_clk32k"); + if (IS_ERR(phy->wkupclk)) { + dev_err(&pdev->dev, "unable to get usb_phy_cm_clk32k\n"); + return PTR_ERR(phy->wkupclk); + } + clk_prepare(phy->wkupclk); + + phy->optclk = devm_clk_get(phy->dev, "usb_otg_ss_refclk960m"); + if (IS_ERR(phy->optclk)) { + dev_err(&pdev->dev, "unable to get usb_otg_ss_refclk960m\n"); + return PTR_ERR(phy->optclk); + } + clk_prepare(phy->optclk); + + phy->sys_clk = devm_clk_get(phy->dev, "sys_clkin"); + if (IS_ERR(phy->sys_clk)) { + pr_err("%s: unable to get sys_clkin\n", __func__); + return -EINVAL; + } + + phy->control_dev = omap_get_control_dev(); + if (IS_ERR(phy->control_dev)) { + dev_dbg(&pdev->dev, "Failed to get control device\n"); + return -ENODEV; + } + + omap_control_usb3_phy_power(phy->control_dev, 0); + usb_add_phy_dev(&phy->phy); + + platform_set_drvdata(pdev, phy); + + pm_runtime_enable(phy->dev); + pm_runtime_get(&pdev->dev); + + return 0; +} + +static int omap_usb3_remove(struct platform_device *pdev) +{ + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_unprepare(phy->wkupclk); + clk_unprepare(phy->optclk); + usb_remove_phy(&phy->phy); + if (!pm_runtime_suspended(&pdev->dev)) + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_PM_RUNTIME + +static int omap_usb3_runtime_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + clk_disable(phy->wkupclk); + clk_disable(phy->optclk); + + return 0; +} + +static int omap_usb3_runtime_resume(struct device *dev) +{ + u32 ret = 0; + struct platform_device *pdev = to_platform_device(dev); + struct omap_usb *phy = platform_get_drvdata(pdev); + + ret = clk_enable(phy->optclk); + if (ret) { + dev_err(phy->dev, "Failed to enable optclk %d\n", ret); + goto err1; + } + + ret = clk_enable(phy->wkupclk); + if (ret) { + dev_err(phy->dev, "Failed to enable wkupclk %d\n", ret); + goto err2; + } + + return 0; + +err2: + clk_disable(phy->optclk); + +err1: + return ret; +} + +static const struct dev_pm_ops omap_usb3_pm_ops = { + SET_RUNTIME_PM_OPS(omap_usb3_runtime_suspend, omap_usb3_runtime_resume, + NULL) +}; + +#define DEV_PM_OPS (&omap_usb3_pm_ops) +#else +#define DEV_PM_OPS NULL +#endif + +#ifdef CONFIG_OF +static const struct of_device_id omap_usb3_id_table[] = { + { .compatible = "ti,omap-usb3" }, + {} +}; +MODULE_DEVICE_TABLE(of, omap_usb3_id_table); +#endif + +static struct platform_driver omap_usb3_driver = { + .probe = omap_usb3_probe, + .remove = omap_usb3_remove, + .driver = { + .name = "omap-usb3", + .owner = THIS_MODULE, + .pm = DEV_PM_OPS, + .of_match_table = of_match_ptr(omap_usb3_id_table), + }, +}; + +module_platform_driver(omap_usb3_driver); + +MODULE_ALIAS("platform: omap_usb3"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("OMAP USB3 phy driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h index 3db9b5316b10..6ae29360e1d2 100644 --- a/include/linux/usb/omap_usb.h +++ b/include/linux/usb/omap_usb.h @@ -19,14 +19,26 @@ #ifndef __DRIVERS_OMAP_USB2_H #define __DRIVERS_OMAP_USB2_H +#include #include +struct usb_dpll_params { + u16 m; + u8 n; + u8 freq:3; + u8 sd; + u32 mf; +}; + struct omap_usb { struct usb_phy phy; struct phy_companion *comparator; + void __iomem *pll_ctrl_base; struct device *dev; struct device *control_dev; struct clk *wkupclk; + struct clk *sys_clk; + struct clk *optclk; u8 is_suspended:1; }; @@ -41,4 +53,15 @@ static inline int omap_usb2_set_comparator(struct phy_companion *comparator) } #endif +static inline u32 omap_usb_readl(void __iomem *addr, unsigned offset) +{ + return __raw_readl(addr + offset); +} + +static inline void omap_usb_writel(void __iomem *addr, unsigned offset, + u32 data) +{ + __raw_writel(data, addr + offset); +} + #endif /* __DRIVERS_OMAP_USB_H */ -- cgit v1.2.3