linux/drivers/phy/ti/phy-tusb1210.c
<<
>>
Prefs
   1/**
   2 * tusb1210.c - TUSB1210 USB ULPI PHY driver
   3 *
   4 * Copyright (C) 2015 Intel Corporation
   5 *
   6 * Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12#include <linux/module.h>
  13#include <linux/ulpi/driver.h>
  14#include <linux/ulpi/regs.h>
  15#include <linux/gpio/consumer.h>
  16#include <linux/phy/ulpi_phy.h>
  17
  18#define TUSB1210_VENDOR_SPECIFIC2               0x80
  19#define TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT   0
  20#define TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT  4
  21#define TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT      6
  22
  23struct tusb1210 {
  24        struct ulpi *ulpi;
  25        struct phy *phy;
  26        struct gpio_desc *gpio_reset;
  27        struct gpio_desc *gpio_cs;
  28        u8 vendor_specific2;
  29};
  30
  31static int tusb1210_power_on(struct phy *phy)
  32{
  33        struct tusb1210 *tusb = phy_get_drvdata(phy);
  34
  35        gpiod_set_value_cansleep(tusb->gpio_reset, 1);
  36        gpiod_set_value_cansleep(tusb->gpio_cs, 1);
  37
  38        /* Restore the optional eye diagram optimization value */
  39        if (tusb->vendor_specific2)
  40                ulpi_write(tusb->ulpi, TUSB1210_VENDOR_SPECIFIC2,
  41                           tusb->vendor_specific2);
  42
  43        return 0;
  44}
  45
  46static int tusb1210_power_off(struct phy *phy)
  47{
  48        struct tusb1210 *tusb = phy_get_drvdata(phy);
  49
  50        gpiod_set_value_cansleep(tusb->gpio_reset, 0);
  51        gpiod_set_value_cansleep(tusb->gpio_cs, 0);
  52
  53        return 0;
  54}
  55
  56static int tusb1210_set_mode(struct phy *phy, enum phy_mode mode)
  57{
  58        struct tusb1210 *tusb = phy_get_drvdata(phy);
  59        int ret;
  60
  61        ret = ulpi_read(tusb->ulpi, ULPI_OTG_CTRL);
  62        if (ret < 0)
  63                return ret;
  64
  65        switch (mode) {
  66        case PHY_MODE_USB_HOST:
  67                ret |= (ULPI_OTG_CTRL_DRVVBUS_EXT
  68                        | ULPI_OTG_CTRL_ID_PULLUP
  69                        | ULPI_OTG_CTRL_DP_PULLDOWN
  70                        | ULPI_OTG_CTRL_DM_PULLDOWN);
  71                ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
  72                ret |= ULPI_OTG_CTRL_DRVVBUS;
  73                break;
  74        case PHY_MODE_USB_DEVICE:
  75                ret &= ~(ULPI_OTG_CTRL_DRVVBUS
  76                         | ULPI_OTG_CTRL_DP_PULLDOWN
  77                         | ULPI_OTG_CTRL_DM_PULLDOWN);
  78                ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
  79                ret &= ~ULPI_OTG_CTRL_DRVVBUS_EXT;
  80                break;
  81        default:
  82                /* nothing */
  83                return 0;
  84        }
  85
  86        return ulpi_write(tusb->ulpi, ULPI_OTG_CTRL, ret);
  87}
  88
  89static const struct phy_ops phy_ops = {
  90        .power_on = tusb1210_power_on,
  91        .power_off = tusb1210_power_off,
  92        .set_mode = tusb1210_set_mode,
  93        .owner = THIS_MODULE,
  94};
  95
  96static int tusb1210_probe(struct ulpi *ulpi)
  97{
  98        struct tusb1210 *tusb;
  99        u8 val, reg;
 100
 101        tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL);
 102        if (!tusb)
 103                return -ENOMEM;
 104
 105        tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset",
 106                                                   GPIOD_OUT_LOW);
 107        if (IS_ERR(tusb->gpio_reset))
 108                return PTR_ERR(tusb->gpio_reset);
 109
 110        gpiod_set_value_cansleep(tusb->gpio_reset, 1);
 111
 112        tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs",
 113                                                GPIOD_OUT_LOW);
 114        if (IS_ERR(tusb->gpio_cs))
 115                return PTR_ERR(tusb->gpio_cs);
 116
 117        gpiod_set_value_cansleep(tusb->gpio_cs, 1);
 118
 119        /*
 120         * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye
 121         * diagram optimization and DP/DM swap.
 122         */
 123
 124        /* High speed output drive strength configuration */
 125        device_property_read_u8(&ulpi->dev, "ihstx", &val);
 126        reg = val << TUSB1210_VENDOR_SPECIFIC2_IHSTX_SHIFT;
 127
 128        /* High speed output impedance configuration */
 129        device_property_read_u8(&ulpi->dev, "zhsdrv", &val);
 130        reg |= val << TUSB1210_VENDOR_SPECIFIC2_ZHSDRV_SHIFT;
 131
 132        /* DP/DM swap control */
 133        device_property_read_u8(&ulpi->dev, "datapolarity", &val);
 134        reg |= val << TUSB1210_VENDOR_SPECIFIC2_DP_SHIFT;
 135
 136        if (reg) {
 137                ulpi_write(ulpi, TUSB1210_VENDOR_SPECIFIC2, reg);
 138                tusb->vendor_specific2 = reg;
 139        }
 140
 141        tusb->phy = ulpi_phy_create(ulpi, &phy_ops);
 142        if (IS_ERR(tusb->phy))
 143                return PTR_ERR(tusb->phy);
 144
 145        tusb->ulpi = ulpi;
 146
 147        phy_set_drvdata(tusb->phy, tusb);
 148        ulpi_set_drvdata(ulpi, tusb);
 149        return 0;
 150}
 151
 152static void tusb1210_remove(struct ulpi *ulpi)
 153{
 154        struct tusb1210 *tusb = ulpi_get_drvdata(ulpi);
 155
 156        ulpi_phy_destroy(ulpi, tusb->phy);
 157}
 158
 159#define TI_VENDOR_ID 0x0451
 160
 161static const struct ulpi_device_id tusb1210_ulpi_id[] = {
 162        { TI_VENDOR_ID, 0x1507, },  /* TUSB1210 */
 163        { TI_VENDOR_ID, 0x1508, },  /* TUSB1211 */
 164        { },
 165};
 166MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
 167
 168static struct ulpi_driver tusb1210_driver = {
 169        .id_table = tusb1210_ulpi_id,
 170        .probe = tusb1210_probe,
 171        .remove = tusb1210_remove,
 172        .driver = {
 173                .name = "tusb1210",
 174                .owner = THIS_MODULE,
 175        },
 176};
 177
 178module_ulpi_driver(tusb1210_driver);
 179
 180MODULE_AUTHOR("Intel Corporation");
 181MODULE_LICENSE("GPL v2");
 182MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
 183