xref: /linux/drivers/extcon/extcon-usbc-tusb320.c (revision ea49432d184a6a09f84461604b7711a4e9f5ec9c)
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");
338