Messages in this thread | | | Date | Fri, 8 May 2015 11:03:08 +0530 | From | Kishon Vijay Abraham I <> | Subject | Re: [̈́PATCHv4 12/12] phy: add driver for TI TUSB1210 ULPI PHY |
| |
On Thursday 07 May 2015 11:49 AM, Heikki Krogerus wrote: > TUSB1210 ULPI PHY has vendor specific register for eye > diagram tuning. On some platforms the system firmware has > set optimized value to it. In order to not loose the > optimized value, the driver stores it during probe and > restores it every time the PHY is powered back on. > > Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> > Acked-by: David Cohen <david.a.cohen@linux.intel.com> > Cc: Kishon Vijay Abraham I <kishon@ti.com>
Acked-by: Kishon Vijay Abraham I <kishon@ti.com> > --- > drivers/phy/Kconfig | 7 +++ > drivers/phy/Makefile | 1 + > drivers/phy/phy-tusb1210.c | 153 +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 161 insertions(+) > create mode 100644 drivers/phy/phy-tusb1210.c > > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig > index a53bd5b..fceac96 100644 > --- a/drivers/phy/Kconfig > +++ b/drivers/phy/Kconfig > @@ -309,4 +309,11 @@ config PHY_QCOM_UFS > help > Support for UFS PHY on QCOM chipsets. > > +config PHY_TUSB1210 > + tristate "TI TUSB1210 ULPI PHY module" > + depends on USB_ULPI_BUS > + select GENERIC_PHY > + help > + Support for TI TUSB1210 USB ULPI PHY. > + > endmenu > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index f126251..0a20418 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -40,3 +40,4 @@ obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o > obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o > obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o > obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o > +obj-$(CONFIG_PHY_TUSB1210) += phy-tusb1210.o > diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/phy-tusb1210.c > new file mode 100644 > index 0000000..07efdd3 > --- /dev/null > +++ b/drivers/phy/phy-tusb1210.c > @@ -0,0 +1,153 @@ > +/** > + * tusb1210.c - TUSB1210 USB ULPI PHY driver > + * > + * Copyright (C) 2015 Intel Corporation > + * > + * Author: Heikki Krogerus <heikki.krogerus@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 version 2 as > + * published by the Free Software Foundation. > + */ > +#include <linux/module.h> > +#include <linux/ulpi/driver.h> > +#include <linux/gpio/consumer.h> > + > +#include "ulpi_phy.h" > + > +#define TUSB1210_VENDOR_SPECIFIC2 0x80 > +#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT 0 > +#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT 4 > +#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT 6 > + > +struct tusb1210 { > + struct ulpi *ulpi; > + struct phy *phy; > + struct gpio_desc *gpio_reset; > + struct gpio_desc *gpio_cs; > + u8 vendor_specific2; > +}; > + > +static int tusb1210_power_on(struct phy *phy) > +{ > + struct tusb1210 *tusb = phy_get_drvdata(phy); > + > + gpiod_set_value_cansleep(tusb->gpio_reset, 1); > + gpiod_set_value_cansleep(tusb->gpio_cs, 1); > + > + /* Restore the optional eye diagram optimization value */ > + if (tusb->vendor_specific2) > + ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2, > + tusb->vendor_specific2); > + > + return 0; > +} > + > +static int tusb1210_power_off(struct phy *phy) > +{ > + struct tusb1210 *tusb = phy_get_drvdata(phy); > + > + gpiod_set_value_cansleep(tusb->gpio_reset, 0); > + gpiod_set_value_cansleep(tusb->gpio_cs, 0); > + > + return 0; > +} > + > +static struct phy_ops phy_ops = { > + .power_on = tusb1210_power_on, > + .power_off = tusb1210_power_off, > + .owner = THIS_MODULE, > +}; > + > +static int tusb1210_probe(struct ulpi *ulpi) > +{ > + struct gpio_desc *gpio; > + struct tusb1210 *tusb; > + u8 val, reg; > + int ret; > + > + tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL); > + if (!tusb) > + return -ENOMEM; > + > + gpio = devm_gpiod_get(&ulpi->dev, "reset"); > + if (!IS_ERR(gpio)) { > + ret = gpiod_direction_output(gpio, 0); > + if (ret) > + return ret; > + gpiod_set_value_cansleep(gpio, 1); > + tusb->gpio_reset = gpio; > + } > + > + gpio = devm_gpiod_get(&ulpi->dev, "cs"); > + if (!IS_ERR(gpio)) { > + ret = gpiod_direction_output(gpio, 0); > + if (ret) > + return ret; > + gpiod_set_value_cansleep(gpio, 1); > + tusb->gpio_cs = gpio; > + } > + > + /* > + * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye > + * diagram optimization and DP/DM swap. > + */ > + > + /* High speed output drive strength configuration */ > + device_property_read_u8(&ulpi->dev, "ihstx", &val); > + reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT; > + > + /* High speed output impedance configuration */ > + device_property_read_u8(&ulpi->dev, "zhsdrv", &val); > + reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT; > + > + /* DP/DM swap control */ > + device_property_read_u8(&ulpi->dev, "datapolarity", &val); > + reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT; > + > + if (reg) { > + ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg); > + tusb->vendor_specific2 = reg; > + } > + > + tusb->phy = ulpi_phy_create(ulpi, &phy_ops); > + if (IS_ERR(tusb->phy)) > + return PTR_ERR(tusb->phy); > + > + tusb->ulpi = ulpi; > + > + phy_set_drvdata(tusb->phy, tusb); > + ulpi_set_drvdata(ulpi, tusb); > + return 0; > +} > + > +static void tusb1210_remove(struct ulpi *ulpi) > +{ > + struct tusb1210 *tusb = ulpi_get_drvdata(ulpi); > + > + ulpi_phy_destroy(ulpi, tusb->phy); > +} > + > +#define TI_VENDOR_ID 0x0451 > + > +static const struct ulpi_device_id tusb1210_ulpi_id[] = { > + { TI_VENDOR_ID, 0x1507, }, > + { }, > +}; > +MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id); > + > +static struct ulpi_driver tusb1210_driver = { > + .id_table = tusb1210_ulpi_id, > + .probe = tusb1210_probe, > + .remove = tusb1210_remove, > + .driver = { > + .name = "tusb1210", > + .owner = THIS_MODULE, > + }, > +}; > + > +module_ulpi_driver(tusb1210_driver); > + > +MODULE_AUTHOR("Intel Corporation"); > +MODULE_LICENSE("GPL v2"); > +MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver"); >
| |