xref: /openbmc/linux/drivers/phy/ti/phy-tusb1210.c (revision 20e2fc42)
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 
20 struct 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 
28 static 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 
43 static 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 
53 static 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 
86 static 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 
93 static 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 
149 static 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 
158 static const struct ulpi_device_id tusb1210_ulpi_id[] = {
159 	{ TI_VENDOR_ID, 0x1507, },  /* TUSB1210 */
160 	{ TI_VENDOR_ID, 0x1508, },  /* TUSB1211 */
161 	{ },
162 };
163 MODULE_DEVICE_TABLE(ulpi, tusb1210_ulpi_id);
164 
165 static 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 
175 module_ulpi_driver(tusb1210_driver);
176 
177 MODULE_AUTHOR("Intel Corporation");
178 MODULE_LICENSE("GPL v2");
179 MODULE_DESCRIPTION("TUSB1210 ULPI PHY driver");
180