Merge branch '100GbE' of git://git.kernel.org/pub/scm/linux/kernel/git/tnguy/next...
[linux-2.6-microblaze.git] / drivers / extcon / extcon-usbc-tusb320.c
1 // SPDX-License-Identifier: GPL-2.0
2 /**
3  * drivers/extcon/extcon-tusb320.c - TUSB320 extcon driver
4  *
5  * Copyright (C) 2020 National Instruments Corporation
6  * Author: Michael Auchter <michael.auchter@ni.com>
7  */
8
9 #include <linux/extcon-provider.h>
10 #include <linux/i2c.h>
11 #include <linux/init.h>
12 #include <linux/interrupt.h>
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/regmap.h>
16
17 #define TUSB320_REG9                            0x9
18 #define TUSB320_REG9_ATTACHED_STATE_SHIFT       6
19 #define TUSB320_REG9_ATTACHED_STATE_MASK        0x3
20 #define TUSB320_REG9_CABLE_DIRECTION            BIT(5)
21 #define TUSB320_REG9_INTERRUPT_STATUS           BIT(4)
22
23 #define TUSB320_REGA                            0xa
24 #define TUSB320L_REGA_DISABLE_TERM              BIT(0)
25 #define TUSB320_REGA_I2C_SOFT_RESET             BIT(3)
26 #define TUSB320_REGA_MODE_SELECT_SHIFT          4
27 #define TUSB320_REGA_MODE_SELECT_MASK           0x3
28
29 #define TUSB320L_REGA0_REVISION                 0xa0
30
31 enum tusb320_attached_state {
32         TUSB320_ATTACHED_STATE_NONE,
33         TUSB320_ATTACHED_STATE_DFP,
34         TUSB320_ATTACHED_STATE_UFP,
35         TUSB320_ATTACHED_STATE_ACC,
36 };
37
38 enum tusb320_mode {
39         TUSB320_MODE_PORT,
40         TUSB320_MODE_UFP,
41         TUSB320_MODE_DFP,
42         TUSB320_MODE_DRP,
43 };
44
45 struct tusb320_priv;
46
47 struct tusb320_ops {
48         int (*set_mode)(struct tusb320_priv *priv, enum tusb320_mode mode);
49         int (*get_revision)(struct tusb320_priv *priv, unsigned int *revision);
50 };
51
52 struct tusb320_priv {
53         struct device *dev;
54         struct regmap *regmap;
55         struct extcon_dev *edev;
56         struct tusb320_ops *ops;
57         enum tusb320_attached_state state;
58 };
59
60 static const char * const tusb_attached_states[] = {
61         [TUSB320_ATTACHED_STATE_NONE] = "not attached",
62         [TUSB320_ATTACHED_STATE_DFP]  = "downstream facing port",
63         [TUSB320_ATTACHED_STATE_UFP]  = "upstream facing port",
64         [TUSB320_ATTACHED_STATE_ACC]  = "accessory",
65 };
66
67 static const unsigned int tusb320_extcon_cable[] = {
68         EXTCON_USB,
69         EXTCON_USB_HOST,
70         EXTCON_NONE,
71 };
72
73 static int tusb320_check_signature(struct tusb320_priv *priv)
74 {
75         static const char sig[] = { '\0', 'T', 'U', 'S', 'B', '3', '2', '0' };
76         unsigned val;
77         int i, ret;
78
79         for (i = 0; i < sizeof(sig); i++) {
80                 ret = regmap_read(priv->regmap, sizeof(sig) - 1 - i, &val);
81                 if (ret < 0)
82                         return ret;
83                 if (val != sig[i]) {
84                         dev_err(priv->dev, "signature mismatch!\n");
85                         return -ENODEV;
86                 }
87         }
88
89         return 0;
90 }
91
92 static int tusb320_set_mode(struct tusb320_priv *priv, enum tusb320_mode mode)
93 {
94         int ret;
95
96         /* Mode cannot be changed while cable is attached */
97         if (priv->state != TUSB320_ATTACHED_STATE_NONE)
98                 return -EBUSY;
99
100         /* Write mode */
101         ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
102                 TUSB320_REGA_MODE_SELECT_MASK << TUSB320_REGA_MODE_SELECT_SHIFT,
103                 mode << TUSB320_REGA_MODE_SELECT_SHIFT);
104         if (ret) {
105                 dev_err(priv->dev, "failed to write mode: %d\n", ret);
106                 return ret;
107         }
108
109         return 0;
110 }
111
112 static int tusb320l_set_mode(struct tusb320_priv *priv, enum tusb320_mode mode)
113 {
114         int ret;
115
116         /* Disable CC state machine */
117         ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
118                 TUSB320L_REGA_DISABLE_TERM, 1);
119         if (ret) {
120                 dev_err(priv->dev,
121                         "failed to disable CC state machine: %d\n", ret);
122                 return ret;
123         }
124
125         /* Write mode */
126         ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
127                 TUSB320_REGA_MODE_SELECT_MASK << TUSB320_REGA_MODE_SELECT_SHIFT,
128                 mode << TUSB320_REGA_MODE_SELECT_SHIFT);
129         if (ret) {
130                 dev_err(priv->dev, "failed to write mode: %d\n", ret);
131                 goto err;
132         }
133
134         msleep(5);
135 err:
136         /* Re-enable CC state machine */
137         ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
138                 TUSB320L_REGA_DISABLE_TERM, 0);
139         if (ret)
140                 dev_err(priv->dev,
141                         "failed to re-enable CC state machine: %d\n", ret);
142
143         return ret;
144 }
145
146 static int tusb320_reset(struct tusb320_priv *priv)
147 {
148         int ret;
149
150         /* Set mode to default (follow PORT pin) */
151         ret = priv->ops->set_mode(priv, TUSB320_MODE_PORT);
152         if (ret && ret != -EBUSY) {
153                 dev_err(priv->dev,
154                         "failed to set mode to PORT: %d\n", ret);
155                 return ret;
156         }
157
158         /* Perform soft reset */
159         ret = regmap_write_bits(priv->regmap, TUSB320_REGA,
160                         TUSB320_REGA_I2C_SOFT_RESET, 1);
161         if (ret) {
162                 dev_err(priv->dev,
163                         "failed to write soft reset bit: %d\n", ret);
164                 return ret;
165         }
166
167         /* Wait for chip to go through reset */
168         msleep(95);
169
170         return 0;
171 }
172
173 static int tusb320l_get_revision(struct tusb320_priv *priv, unsigned int *revision)
174 {
175         return regmap_read(priv->regmap, TUSB320L_REGA0_REVISION, revision);
176 }
177
178 static struct tusb320_ops tusb320_ops = {
179         .set_mode = tusb320_set_mode,
180 };
181
182 static struct tusb320_ops tusb320l_ops = {
183         .set_mode = tusb320l_set_mode,
184         .get_revision = tusb320l_get_revision,
185 };
186
187 static irqreturn_t tusb320_irq_handler(int irq, void *dev_id)
188 {
189         struct tusb320_priv *priv = dev_id;
190         int state, polarity;
191         unsigned reg;
192
193         if (regmap_read(priv->regmap, TUSB320_REG9, &reg)) {
194                 dev_err(priv->dev, "error during i2c read!\n");
195                 return IRQ_NONE;
196         }
197
198         if (!(reg & TUSB320_REG9_INTERRUPT_STATUS))
199                 return IRQ_NONE;
200
201         state = (reg >> TUSB320_REG9_ATTACHED_STATE_SHIFT) &
202                 TUSB320_REG9_ATTACHED_STATE_MASK;
203         polarity = !!(reg & TUSB320_REG9_CABLE_DIRECTION);
204
205         dev_dbg(priv->dev, "attached state: %s, polarity: %d\n",
206                 tusb_attached_states[state], polarity);
207
208         extcon_set_state(priv->edev, EXTCON_USB,
209                          state == TUSB320_ATTACHED_STATE_UFP);
210         extcon_set_state(priv->edev, EXTCON_USB_HOST,
211                          state == TUSB320_ATTACHED_STATE_DFP);
212         extcon_set_property(priv->edev, EXTCON_USB,
213                             EXTCON_PROP_USB_TYPEC_POLARITY,
214                             (union extcon_property_value)polarity);
215         extcon_set_property(priv->edev, EXTCON_USB_HOST,
216                             EXTCON_PROP_USB_TYPEC_POLARITY,
217                             (union extcon_property_value)polarity);
218         extcon_sync(priv->edev, EXTCON_USB);
219         extcon_sync(priv->edev, EXTCON_USB_HOST);
220
221         priv->state = state;
222
223         regmap_write(priv->regmap, TUSB320_REG9, reg);
224
225         return IRQ_HANDLED;
226 }
227
228 static const struct regmap_config tusb320_regmap_config = {
229         .reg_bits = 8,
230         .val_bits = 8,
231 };
232
233 static int tusb320_extcon_probe(struct i2c_client *client,
234                                 const struct i2c_device_id *id)
235 {
236         struct tusb320_priv *priv;
237         const void *match_data;
238         unsigned int revision;
239         int ret;
240
241         priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
242         if (!priv)
243                 return -ENOMEM;
244         priv->dev = &client->dev;
245
246         priv->regmap = devm_regmap_init_i2c(client, &tusb320_regmap_config);
247         if (IS_ERR(priv->regmap))
248                 return PTR_ERR(priv->regmap);
249
250         ret = tusb320_check_signature(priv);
251         if (ret)
252                 return ret;
253
254         match_data = device_get_match_data(&client->dev);
255         if (!match_data)
256                 return -EINVAL;
257
258         priv->ops = (struct tusb320_ops*)match_data;
259
260         priv->edev = devm_extcon_dev_allocate(priv->dev, tusb320_extcon_cable);
261         if (IS_ERR(priv->edev)) {
262                 dev_err(priv->dev, "failed to allocate extcon device\n");
263                 return PTR_ERR(priv->edev);
264         }
265
266         if (priv->ops->get_revision) {
267                 ret = priv->ops->get_revision(priv, &revision);
268                 if (ret)
269                         dev_warn(priv->dev,
270                                 "failed to read revision register: %d\n", ret);
271                 else
272                         dev_info(priv->dev, "chip revision %d\n", revision);
273         }
274
275         ret = devm_extcon_dev_register(priv->dev, priv->edev);
276         if (ret < 0) {
277                 dev_err(priv->dev, "failed to register extcon device\n");
278                 return ret;
279         }
280
281         extcon_set_property_capability(priv->edev, EXTCON_USB,
282                                        EXTCON_PROP_USB_TYPEC_POLARITY);
283         extcon_set_property_capability(priv->edev, EXTCON_USB_HOST,
284                                        EXTCON_PROP_USB_TYPEC_POLARITY);
285
286         /* update initial state */
287         tusb320_irq_handler(client->irq, priv);
288
289         /* Reset chip to its default state */
290         ret = tusb320_reset(priv);
291         if (ret)
292                 dev_warn(priv->dev, "failed to reset chip: %d\n", ret);
293         else
294                 /*
295                  * State and polarity might change after a reset, so update
296                  * them again and make sure the interrupt status bit is cleared.
297                  */
298                 tusb320_irq_handler(client->irq, priv);
299
300         ret = devm_request_threaded_irq(priv->dev, client->irq, NULL,
301                                         tusb320_irq_handler,
302                                         IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
303                                         client->name, priv);
304
305         return ret;
306 }
307
308 static const struct of_device_id tusb320_extcon_dt_match[] = {
309         { .compatible = "ti,tusb320", .data = &tusb320_ops, },
310         { .compatible = "ti,tusb320l", .data = &tusb320l_ops, },
311         { }
312 };
313 MODULE_DEVICE_TABLE(of, tusb320_extcon_dt_match);
314
315 static struct i2c_driver tusb320_extcon_driver = {
316         .probe          = tusb320_extcon_probe,
317         .driver         = {
318                 .name   = "extcon-tusb320",
319                 .of_match_table = tusb320_extcon_dt_match,
320         },
321 };
322
323 static int __init tusb320_init(void)
324 {
325         return i2c_add_driver(&tusb320_extcon_driver);
326 }
327 subsys_initcall(tusb320_init);
328
329 static void __exit tusb320_exit(void)
330 {
331         i2c_del_driver(&tusb320_extcon_driver);
332 }
333 module_exit(tusb320_exit);
334
335 MODULE_AUTHOR("Michael Auchter <michael.auchter@ni.com>");
336 MODULE_DESCRIPTION("TI TUSB320 extcon driver");
337 MODULE_LICENSE("GPL v2");