Merge tag 'nfs-for-5.6-1' of git://git.linux-nfs.org/projects/anna/linux-nfs
[linux-2.6-microblaze.git] / drivers / phy / ti / phy-tusb1210.c
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");