Re: [RFC PATH 1/3] phy: add USB ULPI abstraction layer
Hi, On Thursday 28 November 2013 09:29 PM, Heikki Krogerus wrote: ULPI PHY is an USB2 PHY that is accessed from the USB controller. ULPI PHYs allow discovery based on vendor and product ids which allows binding the PHY to a driver. For USB controllers that are enumerated from buses such as PCI, that do not provide any information about the PHY, ULPI abstraction layer allows runtime detection. This makes it possible to take advantage of vendor specific functions of the PHYs with product specific drivers without the need for platform or device specific quirks. Signed-off-by: Heikki Krogerus heikki.kroge...@linux.intel.com --- drivers/phy/Kconfig | 2 + drivers/phy/Makefile | 1 + drivers/phy/ulpi/Kconfig | 11 ++ drivers/phy/ulpi/Makefile | 1 + drivers/phy/ulpi/ulpi.c | 273 ++ include/linux/phy/ulpi.h | 105 ++ 6 files changed, 393 insertions(+) create mode 100644 drivers/phy/ulpi/Kconfig create mode 100644 drivers/phy/ulpi/Makefile create mode 100644 drivers/phy/ulpi/ulpi.c create mode 100644 include/linux/phy/ulpi.h diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index a344f3d..6c03824 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -51,4 +51,6 @@ config PHY_EXYNOS_DP_VIDEO help Support for Display Port PHY found on Samsung EXYNOS SoCs. +source drivers/phy/ulpi/Kconfig + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index d0caae9..d6af605 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO) += phy-exynos-mipi-video.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_TWL4030_USB)+= phy-twl4030-usb.o +obj-$(CONFIG_ULPI_PHY) += ulpi/ diff --git a/drivers/phy/ulpi/Kconfig b/drivers/phy/ulpi/Kconfig new file mode 100644 index 000..3211aaa --- /dev/null +++ b/drivers/phy/ulpi/Kconfig @@ -0,0 +1,11 @@ + +config ULPI_PHY + tristate USB ULPI PHY interface support + depends on USB || USB_GADGET + select GENERIC_PHY + help + Say yes if you have ULPI PHY attached to your USB controller. If no + vendor modules are selected, the driver will act as NOP PHY driver. + + If unsure, say Y. + diff --git a/drivers/phy/ulpi/Makefile b/drivers/phy/ulpi/Makefile new file mode 100644 index 000..7ed0895 --- /dev/null +++ b/drivers/phy/ulpi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ULPI_PHY) += ulpi.o diff --git a/drivers/phy/ulpi/ulpi.c b/drivers/phy/ulpi/ulpi.c new file mode 100644 index 000..7aa2f5d --- /dev/null +++ b/drivers/phy/ulpi/ulpi.c @@ -0,0 +1,273 @@ +/** + * ulpi.c - USB ULPI PHY abstraction module + * + * Copyright (C) 2013 Intel Corporation + * + * Author: Heikki Krogerus heikki.kroge...@linux.intel.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. + */ + +#include linux/phy/ulpi.h +#include linux/phy/phy.h +#include linux/module.h +#include linux/slab.h + +/* -- */ + +static struct phy_consumer phy_consumer[] = { + { .port = ULPI_PORT_NAME, }, We had to introduce the entire phy_consumer stuff to support legacy pdata. Not sure if it is a good idea to use it here. +}; + +static struct phy_init_data phy_data = { + .num_consumers = 1, + .consumers = phy_consumer, +}; + +static int ulpi_power_on(struct phy *phy) +{ + struct ulpi_dev *ulpi = phy_get_drvdata(phy); + struct ulpi_driver *drv = to_ulpi_driver(ulpi-dev.driver); + + if (drv drv-phy_ops drv-phy_ops-power_on) + return drv-phy_ops-power_on(phy); + + return 0; +} + +static int ulpi_power_off(struct phy *phy) +{ + struct ulpi_dev *ulpi = phy_get_drvdata(phy); + struct ulpi_driver *drv = to_ulpi_driver(ulpi-dev.driver); + + if (drv drv-phy_ops drv-phy_ops-power_off) + return drv-phy_ops-power_off(phy); + + return 0; +} + +static struct phy_ops phy_ops = { + .owner = THIS_MODULE, + .power_on = ulpi_power_on, + .power_off = ulpi_power_off, +}; + +/* -- */ + +static int ulpi_match(struct device *dev, struct device_driver *driver) +{ + struct ulpi_driver *drv = to_ulpi_driver(driver); + struct ulpi_dev *ulpi = to_ulpi_dev(dev); + const struct ulpi_device_id *id; + + for (id = drv-id_table; id-vendor; id++) + if (id-vendor == ulpi-id.vendor + id-product
Re: [RFC PATH 1/3] phy: add USB ULPI abstraction layer
Hi, On Mon, Dec 02, 2013 at 04:20:51PM +0530, Kishon Vijay Abraham I wrote: Hi, On Thursday 28 November 2013 09:29 PM, Heikki Krogerus wrote: ULPI PHY is an USB2 PHY that is accessed from the USB controller. ULPI PHYs allow discovery based on vendor and product ids which allows binding the PHY to a driver. For USB controllers that are enumerated from buses such as PCI, that do not provide any information about the PHY, ULPI abstraction layer allows runtime detection. This makes it possible to take advantage of vendor specific functions of the PHYs with product specific drivers without the need for platform or device specific quirks. Signed-off-by: Heikki Krogerus heikki.kroge...@linux.intel.com --- drivers/phy/Kconfig | 2 + drivers/phy/Makefile | 1 + drivers/phy/ulpi/Kconfig | 11 ++ drivers/phy/ulpi/Makefile | 1 + drivers/phy/ulpi/ulpi.c | 273 ++ include/linux/phy/ulpi.h | 105 ++ 6 files changed, 393 insertions(+) create mode 100644 drivers/phy/ulpi/Kconfig create mode 100644 drivers/phy/ulpi/Makefile create mode 100644 drivers/phy/ulpi/ulpi.c create mode 100644 include/linux/phy/ulpi.h diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index a344f3d..6c03824 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -51,4 +51,6 @@ config PHY_EXYNOS_DP_VIDEO help Support for Display Port PHY found on Samsung EXYNOS SoCs. +source drivers/phy/ulpi/Kconfig + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index d0caae9..d6af605 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)+= phy-exynos-mipi-video.o obj-$(CONFIG_OMAP_USB2)+= phy-omap-usb2.o obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o +obj-$(CONFIG_ULPI_PHY) += ulpi/ diff --git a/drivers/phy/ulpi/Kconfig b/drivers/phy/ulpi/Kconfig new file mode 100644 index 000..3211aaa --- /dev/null +++ b/drivers/phy/ulpi/Kconfig @@ -0,0 +1,11 @@ + +config ULPI_PHY + tristate USB ULPI PHY interface support + depends on USB || USB_GADGET + select GENERIC_PHY + help + Say yes if you have ULPI PHY attached to your USB controller. If no + vendor modules are selected, the driver will act as NOP PHY driver. + + If unsure, say Y. + diff --git a/drivers/phy/ulpi/Makefile b/drivers/phy/ulpi/Makefile new file mode 100644 index 000..7ed0895 --- /dev/null +++ b/drivers/phy/ulpi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ULPI_PHY) += ulpi.o diff --git a/drivers/phy/ulpi/ulpi.c b/drivers/phy/ulpi/ulpi.c new file mode 100644 index 000..7aa2f5d --- /dev/null +++ b/drivers/phy/ulpi/ulpi.c @@ -0,0 +1,273 @@ +/** + * ulpi.c - USB ULPI PHY abstraction module + * + * Copyright (C) 2013 Intel Corporation + * + * Author: Heikki Krogerus heikki.kroge...@linux.intel.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. + */ + +#include linux/phy/ulpi.h +#include linux/phy/phy.h +#include linux/module.h +#include linux/slab.h + +/* -- */ + +static struct phy_consumer phy_consumer[] = { + { .port = ULPI_PORT_NAME, }, We had to introduce the entire phy_consumer stuff to support legacy pdata. Not sure if it is a good idea to use it here. Well, maybe we can improve it at least a bit. I don't see how it's possible to get rid of the device name matching, but at least the port name dependency could be replaced with possibility to use index instead. Check how they made the gpiod lookup to work in gpiolib. Let's get back to this one. +}; + +static struct phy_init_data phy_data = { + .num_consumers = 1, + .consumers = phy_consumer, +}; + +static int ulpi_power_on(struct phy *phy) +{ + struct ulpi_dev *ulpi = phy_get_drvdata(phy); + struct ulpi_driver *drv = to_ulpi_driver(ulpi-dev.driver); + + if (drv drv-phy_ops drv-phy_ops-power_on) + return drv-phy_ops-power_on(phy); + + return 0; +} + +static int ulpi_power_off(struct phy *phy) +{ + struct ulpi_dev *ulpi = phy_get_drvdata(phy); + struct ulpi_driver *drv = to_ulpi_driver(ulpi-dev.driver); + + if (drv drv-phy_ops drv-phy_ops-power_off) + return drv-phy_ops-power_off(phy); + + return 0; +} + +static struct phy_ops phy_ops = { + .owner = THIS_MODULE, + .power_on = ulpi_power_on, + .power_off =
[RFC PATH 1/3] phy: add USB ULPI abstraction layer
ULPI PHY is an USB2 PHY that is accessed from the USB controller. ULPI PHYs allow discovery based on vendor and product ids which allows binding the PHY to a driver. For USB controllers that are enumerated from buses such as PCI, that do not provide any information about the PHY, ULPI abstraction layer allows runtime detection. This makes it possible to take advantage of vendor specific functions of the PHYs with product specific drivers without the need for platform or device specific quirks. Signed-off-by: Heikki Krogerus heikki.kroge...@linux.intel.com --- drivers/phy/Kconfig | 2 + drivers/phy/Makefile | 1 + drivers/phy/ulpi/Kconfig | 11 ++ drivers/phy/ulpi/Makefile | 1 + drivers/phy/ulpi/ulpi.c | 273 ++ include/linux/phy/ulpi.h | 105 ++ 6 files changed, 393 insertions(+) create mode 100644 drivers/phy/ulpi/Kconfig create mode 100644 drivers/phy/ulpi/Makefile create mode 100644 drivers/phy/ulpi/ulpi.c create mode 100644 include/linux/phy/ulpi.h diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index a344f3d..6c03824 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -51,4 +51,6 @@ config PHY_EXYNOS_DP_VIDEO help Support for Display Port PHY found on Samsung EXYNOS SoCs. +source drivers/phy/ulpi/Kconfig + endmenu diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index d0caae9..d6af605 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -7,3 +7,4 @@ obj-$(CONFIG_PHY_EXYNOS_DP_VIDEO) += phy-exynos-dp-video.o obj-$(CONFIG_PHY_EXYNOS_MIPI_VIDEO)+= phy-exynos-mipi-video.o obj-$(CONFIG_OMAP_USB2)+= phy-omap-usb2.o obj-$(CONFIG_TWL4030_USB) += phy-twl4030-usb.o +obj-$(CONFIG_ULPI_PHY) += ulpi/ diff --git a/drivers/phy/ulpi/Kconfig b/drivers/phy/ulpi/Kconfig new file mode 100644 index 000..3211aaa --- /dev/null +++ b/drivers/phy/ulpi/Kconfig @@ -0,0 +1,11 @@ + +config ULPI_PHY + tristate USB ULPI PHY interface support + depends on USB || USB_GADGET + select GENERIC_PHY + help + Say yes if you have ULPI PHY attached to your USB controller. If no + vendor modules are selected, the driver will act as NOP PHY driver. + + If unsure, say Y. + diff --git a/drivers/phy/ulpi/Makefile b/drivers/phy/ulpi/Makefile new file mode 100644 index 000..7ed0895 --- /dev/null +++ b/drivers/phy/ulpi/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_ULPI_PHY) += ulpi.o diff --git a/drivers/phy/ulpi/ulpi.c b/drivers/phy/ulpi/ulpi.c new file mode 100644 index 000..7aa2f5d --- /dev/null +++ b/drivers/phy/ulpi/ulpi.c @@ -0,0 +1,273 @@ +/** + * ulpi.c - USB ULPI PHY abstraction module + * + * Copyright (C) 2013 Intel Corporation + * + * Author: Heikki Krogerus heikki.kroge...@linux.intel.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. + */ + +#include linux/phy/ulpi.h +#include linux/phy/phy.h +#include linux/module.h +#include linux/slab.h + +/* -- */ + +static struct phy_consumer phy_consumer[] = { + { .port = ULPI_PORT_NAME, }, +}; + +static struct phy_init_data phy_data = { + .num_consumers = 1, + .consumers = phy_consumer, +}; + +static int ulpi_power_on(struct phy *phy) +{ + struct ulpi_dev *ulpi = phy_get_drvdata(phy); + struct ulpi_driver *drv = to_ulpi_driver(ulpi-dev.driver); + + if (drv drv-phy_ops drv-phy_ops-power_on) + return drv-phy_ops-power_on(phy); + + return 0; +} + +static int ulpi_power_off(struct phy *phy) +{ + struct ulpi_dev *ulpi = phy_get_drvdata(phy); + struct ulpi_driver *drv = to_ulpi_driver(ulpi-dev.driver); + + if (drv drv-phy_ops drv-phy_ops-power_off) + return drv-phy_ops-power_off(phy); + + return 0; +} + +static struct phy_ops phy_ops = { + .owner = THIS_MODULE, + .power_on = ulpi_power_on, + .power_off = ulpi_power_off, +}; + +/* -- */ + +static int ulpi_match(struct device *dev, struct device_driver *driver) +{ + struct ulpi_driver *drv = to_ulpi_driver(driver); + struct ulpi_dev *ulpi = to_ulpi_dev(dev); + const struct ulpi_device_id *id; + + for (id = drv-id_table; id-vendor; id++) + if (id-vendor == ulpi-id.vendor + id-product == ulpi-id.product) + return 1; + + return 0; +} + +static int ulpi_probe(struct device *dev) +{ + struct ulpi_driver *drv = to_ulpi_driver(dev-driver); + + return drv-probe(to_ulpi_dev(dev)); +} + +static int ulpi_remove(struct device