File Index
Files and directories
Sign in
FILE

hd3ss3220.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/typec/hd3ss3220.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * TI HD3SS3220 Type-C DRP Port Controller Driver
  4 *
  5 * Copyright (C) 2019 Renesas Electronics Corp.
  6 */
  7
  8#include <linux/module.h>
  9#include <linux/i2c.h>
 10#include <linux/usb/role.h>
 11#include <linux/irqreturn.h>
 12#include <linux/interrupt.h>
 13#include <linux/regmap.h>
 14#include <linux/slab.h>
 15#include <linux/usb/typec.h>
 16#include <linux/delay.h>
 17#include <linux/workqueue.h>
 18#include <linux/gpio/consumer.h>
 19#include <linux/regulator/consumer.h>
 20#include <linux/of_graph.h>
 21
 22#define HD3SS3220_REG_CN_STAT		0x08
 23#define HD3SS3220_REG_CN_STAT_CTRL	0x09
 24#define HD3SS3220_REG_GEN_CTRL		0x0A
 25#define HD3SS3220_REG_DEV_REV		0xA0
 26
 27/* Register HD3SS3220_REG_CN_STAT */
 28#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_MASK		(BIT(7) | BIT(6))
 29#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_DEFAULT	0x00
 30#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_MID		BIT(6)
 31#define HD3SS3220_REG_CN_STAT_CURRENT_MODE_HIGH		BIT(7)
 32
 33/* Register HD3SS3220_REG_CN_STAT_CTRL*/
 34#define HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK	(BIT(7) | BIT(6))
 35#define HD3SS3220_REG_CN_STAT_CTRL_AS_DFP		BIT(6)
 36#define HD3SS3220_REG_CN_STAT_CTRL_AS_UFP		BIT(7)
 37#define HD3SS3220_REG_CN_STAT_CTRL_TO_ACCESSORY		(BIT(7) | BIT(6))
 38#define HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS		BIT(4)
 39
 40/* Register HD3SS3220_REG_GEN_CTRL*/
 41#define HD3SS3220_REG_GEN_CTRL_DISABLE_TERM		BIT(0)
 42#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK		(BIT(2) | BIT(1))
 43#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT	0x00
 44#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK	BIT(1)
 45#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC	(BIT(2) | BIT(1))
 46#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_MASK		(BIT(5) | BIT(4))
 47#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DEFAULT	0x00
 48#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DFP		BIT(5)
 49#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_UFP		BIT(4)
 50#define HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DRP		(BIT(5) | BIT(4))
 51
 52struct hd3ss3220 {
 53	struct device *dev;
 54	struct regmap *regmap;
 55	struct usb_role_switch	*role_sw;
 56	struct typec_port *port;
 57	struct delayed_work output_poll_work;
 58	enum usb_role role_state;
 59	bool poll;
 60
 61	struct gpio_desc *id_gpiod;
 62	int id_irq;
 63
 64	struct regulator *vbus;
 65};
 66
 67static int hd3ss3220_set_power_opmode(struct hd3ss3220 *hd3ss3220, int power_opmode)
 68{
 69	int current_mode;
 70
 71	switch (power_opmode) {
 72	case TYPEC_PWR_MODE_USB:
 73		current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_DEFAULT;
 74		break;
 75	case TYPEC_PWR_MODE_1_5A:
 76		current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_MID;
 77		break;
 78	case TYPEC_PWR_MODE_3_0A:
 79		current_mode = HD3SS3220_REG_CN_STAT_CURRENT_MODE_HIGH;
 80		break;
 81	case TYPEC_PWR_MODE_PD: /* Power delivery not supported */
 82	default:
 83		dev_err(hd3ss3220->dev, "bad power operation mode: %d\n", power_opmode);
 84		return -EINVAL;
 85	}
 86
 87	return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT,
 88				  HD3SS3220_REG_CN_STAT_CURRENT_MODE_MASK,
 89				  current_mode);
 90}
 91
 92static int hd3ss3220_set_port_type(struct hd3ss3220 *hd3ss3220, int type)
 93{
 94	int mode_select, err;
 95
 96	switch (type) {
 97	case TYPEC_PORT_SRC:
 98		mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DFP;
 99		break;
100	case TYPEC_PORT_SNK:
101		mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_UFP;
102		break;
103	case TYPEC_PORT_DRP:
104		mode_select = HD3SS3220_REG_GEN_CTRL_MODE_SELECT_DRP;
105		break;
106	default:
107		dev_err(hd3ss3220->dev, "bad port type: %d\n", type);
108		return -EINVAL;
109	}
110
111	/* Disable termination before changing MODE_SELECT as required by datasheet */
112	err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
113				 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM,
114				 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM);
115	if (err < 0) {
116		dev_err(hd3ss3220->dev, "Failed to disable port for mode change: %d\n", err);
117		return err;
118	}
119
120	err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
121				 HD3SS3220_REG_GEN_CTRL_MODE_SELECT_MASK,
122				 mode_select);
123	if (err < 0) {
124		dev_err(hd3ss3220->dev, "Failed to change mode: %d\n", err);
125		regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
126				   HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 0);
127		return err;
128	}
129
130	err = regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
131				 HD3SS3220_REG_GEN_CTRL_DISABLE_TERM, 0);
132	if (err < 0)
133		dev_err(hd3ss3220->dev, "Failed to re-enable port after mode change: %d\n", err);
134
135	return err;
136}
137
138static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int prefer_role)
139{
140	int src_pref;
141
142	switch (prefer_role) {
143	case TYPEC_NO_PREFERRED_ROLE:
144		src_pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT;
145		break;
146	case TYPEC_SINK:
147		src_pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK;
148		break;
149	case TYPEC_SOURCE:
150		src_pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC;
151		break;
152	default:
153		dev_err(hd3ss3220->dev, "bad role preference: %d\n", prefer_role);
154		return -EINVAL;
155	}
156
157	return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL,
158				  HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK,
159				  src_pref);
160}
161
162static enum usb_role hd3ss3220_get_attached_state(struct hd3ss3220 *hd3ss3220)
163{
164	unsigned int reg_val;
165	enum usb_role attached_state;
166	int ret;
167
168	ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL,
169			  &reg_val);
170	if (ret < 0)
171		return ret;
172
173	switch (reg_val & HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK) {
174	case HD3SS3220_REG_CN_STAT_CTRL_AS_DFP:
175		attached_state = USB_ROLE_HOST;
176		break;
177	case HD3SS3220_REG_CN_STAT_CTRL_AS_UFP:
178		attached_state = USB_ROLE_DEVICE;
179		break;
180	default:
181		attached_state = USB_ROLE_NONE;
182		break;
183	}
184
185	return attached_state;
186}
187
188static int hd3ss3220_try_role(struct typec_port *port, int role)
189{
190	struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port);
191
192	return hd3ss3220_set_source_pref(hd3ss3220, role);
193}
194
195static int hd3ss3220_port_type_set(struct typec_port *port, enum typec_port_type type)
196{
197	struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port);
198
199	return hd3ss3220_set_port_type(hd3ss3220, type);
200}
201
202static const struct typec_operations hd3ss3220_ops = {
203	.try_role = hd3ss3220_try_role,
204	.port_type_set = hd3ss3220_port_type_set,
205};
206
207static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220)
208{
209	enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220);
210
211	usb_role_switch_set_role(hd3ss3220->role_sw, role_state);
212
213	switch (role_state) {
214	case USB_ROLE_HOST:
215		typec_set_data_role(hd3ss3220->port, TYPEC_HOST);
216		break;
217	case USB_ROLE_DEVICE:
218		typec_set_data_role(hd3ss3220->port, TYPEC_DEVICE);
219		break;
220	default:
221		break;
222	}
223
224	hd3ss3220->role_state = role_state;
225}
226
227static void output_poll_execute(struct work_struct *work)
228{
229	struct delayed_work *delayed_work = to_delayed_work(work);
230	struct hd3ss3220 *hd3ss3220 = container_of(delayed_work,
231						   struct hd3ss3220,
232						   output_poll_work);
233	enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220);
234
235	if (hd3ss3220->role_state != role_state)
236		hd3ss3220_set_role(hd3ss3220);
237
238	schedule_delayed_work(&hd3ss3220->output_poll_work, HZ);
239}
240
241static irqreturn_t hd3ss3220_irq(struct hd3ss3220 *hd3ss3220)
242{
243	int err;
244
245	hd3ss3220_set_role(hd3ss3220);
246	err = regmap_write_bits(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL,
247				HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS,
248				HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS);
249	if (err < 0)
250		return IRQ_NONE;
251
252	return IRQ_HANDLED;
253}
254
255static irqreturn_t hd3ss3220_irq_handler(int irq, void *data)
256{
257	struct i2c_client *client = to_i2c_client(data);
258	struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client);
259
260	return hd3ss3220_irq(hd3ss3220);
261}
262
263static int hd3ss3220_configure_power_opmode(struct hd3ss3220 *hd3ss3220,
264					    struct fwnode_handle *connector)
265{
266	/*
267	 * Supported power operation mode can be configured through device tree
268	 */
269	const char *cap_str;
270	int ret, power_opmode;
271
272	ret = fwnode_property_read_string(connector, "typec-power-opmode", &cap_str);
273	if (ret)
274		return 0;
275
276	power_opmode = typec_find_pwr_opmode(cap_str);
277	return hd3ss3220_set_power_opmode(hd3ss3220, power_opmode);
278}
279
280static int hd3ss3220_configure_port_type(struct hd3ss3220 *hd3ss3220,
281					 struct fwnode_handle *connector,
282					 struct typec_capability *cap)
283{
284	/*
285	 * Port type can be configured through device tree
286	 */
287	const char *cap_str;
288	int ret;
289
290	ret = fwnode_property_read_string(connector, "power-role", &cap_str);
291	if (ret)
292		return 0;
293
294	ret = typec_find_port_power_role(cap_str);
295	if (ret < 0)
296		return ret;
297
298	cap->type = ret;
299	return hd3ss3220_set_port_type(hd3ss3220, cap->type);
300}
301
302static int hd3ss3220_configure_source_pref(struct hd3ss3220 *hd3ss3220,
303					   struct fwnode_handle *connector,
304					   struct typec_capability *cap)
305{
306	/*
307	 * Preferred role can be configured through device tree
308	 */
309	const char *cap_str;
310	int ret;
311
312	ret = fwnode_property_read_string(connector, "try-power-role", &cap_str);
313	if (ret)
314		return 0;
315
316	ret = typec_find_power_role(cap_str);
317	if (ret < 0)
318		return ret;
319
320	cap->prefer_role = ret;
321	return hd3ss3220_set_source_pref(hd3ss3220, cap->prefer_role);
322}
323
324static const struct regmap_config config = {
325	.reg_bits = 8,
326	.val_bits = 8,
327	.max_register = 0x0A,
328};
329
330static irqreturn_t hd3ss3220_id_isr(int irq, void *dev_id)
331{
332	struct hd3ss3220 *hd3ss3220 = dev_id;
333	int ret;
334	int id;
335
336	id = gpiod_get_value_cansleep(hd3ss3220->id_gpiod);
337	if (!id)
338		ret = regulator_enable(hd3ss3220->vbus);
339	else
340		ret = regulator_disable(hd3ss3220->vbus);
341
342	if (ret)
343		dev_err(hd3ss3220->dev,
344			"vbus regulator %s failed: %d\n", id ? "disable" : "enable", ret);
345
346	return IRQ_HANDLED;
347}
348
349static int hd3ss3220_probe(struct i2c_client *client)
350{
351	struct typec_capability typec_cap = { };
352	struct fwnode_handle *connector, *ep;
353	struct hd3ss3220 *hd3ss3220;
354	struct regulator *vbus;
355	unsigned int data;
356	int ret;
357
358	hd3ss3220 = devm_kzalloc(&client->dev, sizeof(struct hd3ss3220),
359				 GFP_KERNEL);
360	if (!hd3ss3220)
361		return -ENOMEM;
362
363	i2c_set_clientdata(client, hd3ss3220);
364
365	hd3ss3220->dev = &client->dev;
366	hd3ss3220->regmap = devm_regmap_init_i2c(client, &config);
367	if (IS_ERR(hd3ss3220->regmap))
368		return PTR_ERR(hd3ss3220->regmap);
369
370	/* For backward compatibility check the connector child node first */
371	connector = device_get_named_child_node(hd3ss3220->dev, "connector");
372	if (connector) {
373		hd3ss3220->role_sw = fwnode_usb_role_switch_get(connector);
374	} else {
375		ep = fwnode_graph_get_next_endpoint(dev_fwnode(hd3ss3220->dev), NULL);
376		if (!ep)
377			return -ENODEV;
378		connector = fwnode_graph_get_remote_port_parent(ep);
379		fwnode_handle_put(ep);
380		if (!connector)
381			return -ENODEV;
382		hd3ss3220->role_sw = usb_role_switch_get(hd3ss3220->dev);
383	}
384
385	if (IS_ERR(hd3ss3220->role_sw)) {
386		ret = PTR_ERR(hd3ss3220->role_sw);
387		goto err_put_fwnode;
388	}
389
390	vbus = devm_of_regulator_get_optional(hd3ss3220->dev,
391					      to_of_node(connector),
392					      "vbus");
393	if (IS_ERR(vbus) && vbus != ERR_PTR(-ENODEV)) {
394		ret = PTR_ERR(vbus);
395		dev_err(hd3ss3220->dev, "failed to get vbus: %d", ret);
396		goto err_put_fwnode;
397	}
398
399	hd3ss3220->vbus = (vbus == ERR_PTR(-ENODEV) ? NULL : vbus);
400
401	if (hd3ss3220->vbus) {
402		hd3ss3220->id_gpiod = devm_gpiod_get_optional(hd3ss3220->dev,
403							      "id",
404							      GPIOD_IN);
405		if (IS_ERR(hd3ss3220->id_gpiod)) {
406			ret = PTR_ERR(hd3ss3220->id_gpiod);
407			goto err_put_fwnode;
408		}
409	}
410
411	if (hd3ss3220->id_gpiod) {
412		hd3ss3220->id_irq = gpiod_to_irq(hd3ss3220->id_gpiod);
413		if (hd3ss3220->id_irq < 0) {
414			ret = hd3ss3220->id_irq;
415			dev_err(hd3ss3220->dev,
416				"failed to get ID gpio: %d\n",
417				hd3ss3220->id_irq);
418			goto err_put_fwnode;
419		}
420
421		ret = devm_request_threaded_irq(hd3ss3220->dev,
422						hd3ss3220->id_irq, NULL,
423						hd3ss3220_id_isr,
424						IRQF_TRIGGER_RISING |
425						IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
426						dev_name(hd3ss3220->dev), hd3ss3220);
427		if (ret < 0) {
428			dev_err(hd3ss3220->dev, "failed to get ID irq: %d\n", ret);
429			goto err_put_fwnode;
430		}
431	}
432
433	typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE;
434	typec_cap.driver_data = hd3ss3220;
435	typec_cap.type = TYPEC_PORT_DRP;
436	typec_cap.data = TYPEC_PORT_DRD;
437	typec_cap.ops = &hd3ss3220_ops;
438	typec_cap.fwnode = connector;
439
440	ret = hd3ss3220_configure_source_pref(hd3ss3220, connector, &typec_cap);
441	if (ret < 0)
442		goto err_put_role;
443
444	ret = hd3ss3220_configure_port_type(hd3ss3220, connector, &typec_cap);
445	if (ret < 0)
446		goto err_put_role;
447
448	hd3ss3220->port = typec_register_port(&client->dev, &typec_cap);
449	if (IS_ERR(hd3ss3220->port)) {
450		ret = PTR_ERR(hd3ss3220->port);
451		goto err_put_role;
452	}
453
454	ret = hd3ss3220_configure_power_opmode(hd3ss3220, connector);
455	if (ret < 0)
456		goto err_unreg_port;
457
458	hd3ss3220_set_role(hd3ss3220);
459	ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, &data);
460	if (ret < 0)
461		goto err_unreg_port;
462
463	if (data & HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS) {
464		ret = regmap_write(hd3ss3220->regmap,
465				HD3SS3220_REG_CN_STAT_CTRL,
466				data | HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS);
467		if (ret < 0)
468			goto err_unreg_port;
469	}
470
471	if (client->irq > 0) {
472		ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
473					hd3ss3220_irq_handler,
474					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
475					"hd3ss3220", &client->dev);
476		if (ret)
477			goto err_unreg_port;
478	} else {
479		INIT_DELAYED_WORK(&hd3ss3220->output_poll_work, output_poll_execute);
480		hd3ss3220->poll = true;
481	}
482
483	ret = i2c_smbus_read_byte_data(client, HD3SS3220_REG_DEV_REV);
484	if (ret < 0)
485		goto err_unreg_port;
486
487	fwnode_handle_put(connector);
488
489	if (hd3ss3220->poll)
490		schedule_delayed_work(&hd3ss3220->output_poll_work, HZ);
491
492	dev_info(&client->dev, "probed revision=0x%x\n", ret);
493
494	return 0;
495err_unreg_port:
496	typec_unregister_port(hd3ss3220->port);
497err_put_role:
498	usb_role_switch_put(hd3ss3220->role_sw);
499err_put_fwnode:
500	fwnode_handle_put(connector);
501
502	return ret;
503}
504
505static void hd3ss3220_remove(struct i2c_client *client)
506{
507	struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client);
508
509	if (hd3ss3220->poll)
510		cancel_delayed_work_sync(&hd3ss3220->output_poll_work);
511
512	typec_unregister_port(hd3ss3220->port);
513	usb_role_switch_put(hd3ss3220->role_sw);
514}
515
516static const struct of_device_id dev_ids[] = {
517	{ .compatible = "ti,hd3ss3220"},
518	{}
519};
520MODULE_DEVICE_TABLE(of, dev_ids);
521
522static struct i2c_driver hd3ss3220_driver = {
523	.driver = {
524		.name = "hd3ss3220",
525		.of_match_table = dev_ids,
526	},
527	.probe = hd3ss3220_probe,
528	.remove = hd3ss3220_remove,
529};
530
531module_i2c_driver(hd3ss3220_driver);
532
533MODULE_AUTHOR("Biju Das <biju.das@bp.renesas.com>");
534MODULE_DESCRIPTION("TI HD3SS3220 DRP Port Controller Driver");
535MODULE_LICENSE("GPL");
~/ Read-only file preview.