Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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