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 23 struct 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 31 static 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 46 static 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 56 static 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 89 static 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 96 static 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 152 static 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 161 static const struct ulpi_device_id tusb1210_ulpi_id[] = { 162 { TI_VENDOR_ID, 0x1507, }, /* TUSB1210 */ 163 { TI_VENDOR_ID, 0x1508, }, /* TUSB1211 */ 164 { }, 165 }; 166 MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id); 167 168 static 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 178 module_ulpi_driver(tusb1210_driver); 179 180 MODULE_AUTHOR("Intel Corporation"); 181 MODULE_LICENSE("GPL v2"); 182 MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver"); 183