xref: /openbmc/linux/drivers/usb/phy/phy-ulpi.c (revision 8dd06ef34b6e2f41b29fbf5fc1663780f2524285)
15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
294ae9843SFelipe Balbi /*
394ae9843SFelipe Balbi  * Generic ULPI USB transceiver support
494ae9843SFelipe Balbi  *
594ae9843SFelipe Balbi  * Copyright (C) 2009 Daniel Mack <daniel@caiaq.de>
694ae9843SFelipe Balbi  *
794ae9843SFelipe Balbi  * Based on sources from
894ae9843SFelipe Balbi  *
994ae9843SFelipe Balbi  *   Sascha Hauer <s.hauer@pengutronix.de>
1094ae9843SFelipe Balbi  *   Freescale Semiconductors
1194ae9843SFelipe Balbi  */
1294ae9843SFelipe Balbi 
1394ae9843SFelipe Balbi #include <linux/kernel.h>
1494ae9843SFelipe Balbi #include <linux/slab.h>
1594ae9843SFelipe Balbi #include <linux/export.h>
1694ae9843SFelipe Balbi #include <linux/usb.h>
1794ae9843SFelipe Balbi #include <linux/usb/otg.h>
1894ae9843SFelipe Balbi #include <linux/usb/ulpi.h>
1994ae9843SFelipe Balbi 
2094ae9843SFelipe Balbi 
2194ae9843SFelipe Balbi struct ulpi_info {
2294ae9843SFelipe Balbi 	unsigned int	id;
2394ae9843SFelipe Balbi 	char		*name;
2494ae9843SFelipe Balbi };
2594ae9843SFelipe Balbi 
2694ae9843SFelipe Balbi #define ULPI_ID(vendor, product) (((vendor) << 16) | (product))
2794ae9843SFelipe Balbi #define ULPI_INFO(_id, _name)		\
2894ae9843SFelipe Balbi 	{				\
2994ae9843SFelipe Balbi 		.id	= (_id),	\
3094ae9843SFelipe Balbi 		.name	= (_name),	\
3194ae9843SFelipe Balbi 	}
3294ae9843SFelipe Balbi 
3394ae9843SFelipe Balbi /* ULPI hardcoded IDs, used for probing */
3494ae9843SFelipe Balbi static struct ulpi_info ulpi_ids[] = {
3594ae9843SFelipe Balbi 	ULPI_INFO(ULPI_ID(0x04cc, 0x1504), "NXP ISP1504"),
3694ae9843SFelipe Balbi 	ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
37ead5178bSMichal Simek 	ULPI_INFO(ULPI_ID(0x0424, 0x0007), "SMSC USB3320"),
3879cb5b53SLiviu Dudau 	ULPI_INFO(ULPI_ID(0x0424, 0x0009), "SMSC USB334x"),
39ead5178bSMichal Simek 	ULPI_INFO(ULPI_ID(0x0451, 0x1507), "TI TUSB1210"),
4094ae9843SFelipe Balbi };
4194ae9843SFelipe Balbi 
ulpi_set_otg_flags(struct usb_phy * phy)4294ae9843SFelipe Balbi static int ulpi_set_otg_flags(struct usb_phy *phy)
4394ae9843SFelipe Balbi {
4494ae9843SFelipe Balbi 	unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
4594ae9843SFelipe Balbi 			     ULPI_OTG_CTRL_DM_PULLDOWN;
4694ae9843SFelipe Balbi 
4794ae9843SFelipe Balbi 	if (phy->flags & ULPI_OTG_ID_PULLUP)
4894ae9843SFelipe Balbi 		flags |= ULPI_OTG_CTRL_ID_PULLUP;
4994ae9843SFelipe Balbi 
5094ae9843SFelipe Balbi 	/*
5194ae9843SFelipe Balbi 	 * ULPI Specification rev.1.1 default
5294ae9843SFelipe Balbi 	 * for Dp/DmPulldown is enabled.
5394ae9843SFelipe Balbi 	 */
5494ae9843SFelipe Balbi 	if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
5594ae9843SFelipe Balbi 		flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;
5694ae9843SFelipe Balbi 
5794ae9843SFelipe Balbi 	if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
5894ae9843SFelipe Balbi 		flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;
5994ae9843SFelipe Balbi 
6094ae9843SFelipe Balbi 	if (phy->flags & ULPI_OTG_EXTVBUSIND)
6194ae9843SFelipe Balbi 		flags |= ULPI_OTG_CTRL_EXTVBUSIND;
6294ae9843SFelipe Balbi 
6394ae9843SFelipe Balbi 	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
6494ae9843SFelipe Balbi }
6594ae9843SFelipe Balbi 
ulpi_set_fc_flags(struct usb_phy * phy)6694ae9843SFelipe Balbi static int ulpi_set_fc_flags(struct usb_phy *phy)
6794ae9843SFelipe Balbi {
6894ae9843SFelipe Balbi 	unsigned int flags = 0;
6994ae9843SFelipe Balbi 
7094ae9843SFelipe Balbi 	/*
7194ae9843SFelipe Balbi 	 * ULPI Specification rev.1.1 default
7294ae9843SFelipe Balbi 	 * for XcvrSelect is Full Speed.
7394ae9843SFelipe Balbi 	 */
7494ae9843SFelipe Balbi 	if (phy->flags & ULPI_FC_HS)
7594ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
7694ae9843SFelipe Balbi 	else if (phy->flags & ULPI_FC_LS)
7794ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_LOW_SPEED;
7894ae9843SFelipe Balbi 	else if (phy->flags & ULPI_FC_FS4LS)
7994ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_FS4LS;
8094ae9843SFelipe Balbi 	else
8194ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_FULL_SPEED;
8294ae9843SFelipe Balbi 
8394ae9843SFelipe Balbi 	if (phy->flags & ULPI_FC_TERMSEL)
8494ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_TERMSELECT;
8594ae9843SFelipe Balbi 
8694ae9843SFelipe Balbi 	/*
8794ae9843SFelipe Balbi 	 * ULPI Specification rev.1.1 default
8894ae9843SFelipe Balbi 	 * for OpMode is Normal Operation.
8994ae9843SFelipe Balbi 	 */
9094ae9843SFelipe Balbi 	if (phy->flags & ULPI_FC_OP_NODRV)
9194ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
9294ae9843SFelipe Balbi 	else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
9394ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
9494ae9843SFelipe Balbi 	else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
9594ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
9694ae9843SFelipe Balbi 	else
9794ae9843SFelipe Balbi 		flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
9894ae9843SFelipe Balbi 
9994ae9843SFelipe Balbi 	/*
10094ae9843SFelipe Balbi 	 * ULPI Specification rev.1.1 default
10194ae9843SFelipe Balbi 	 * for SuspendM is Powered.
10294ae9843SFelipe Balbi 	 */
10394ae9843SFelipe Balbi 	flags |= ULPI_FUNC_CTRL_SUSPENDM;
10494ae9843SFelipe Balbi 
10594ae9843SFelipe Balbi 	return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
10694ae9843SFelipe Balbi }
10794ae9843SFelipe Balbi 
ulpi_set_ic_flags(struct usb_phy * phy)10894ae9843SFelipe Balbi static int ulpi_set_ic_flags(struct usb_phy *phy)
10994ae9843SFelipe Balbi {
11094ae9843SFelipe Balbi 	unsigned int flags = 0;
11194ae9843SFelipe Balbi 
11294ae9843SFelipe Balbi 	if (phy->flags & ULPI_IC_AUTORESUME)
11394ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_AUTORESUME;
11494ae9843SFelipe Balbi 
11594ae9843SFelipe Balbi 	if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
11694ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;
11794ae9843SFelipe Balbi 
11894ae9843SFelipe Balbi 	if (phy->flags & ULPI_IC_IND_PASSTHRU)
11994ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_PASSTHRU;
12094ae9843SFelipe Balbi 
12194ae9843SFelipe Balbi 	if (phy->flags & ULPI_IC_PROTECT_DIS)
12294ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;
12394ae9843SFelipe Balbi 
12494ae9843SFelipe Balbi 	return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
12594ae9843SFelipe Balbi }
12694ae9843SFelipe Balbi 
ulpi_set_flags(struct usb_phy * phy)12794ae9843SFelipe Balbi static int ulpi_set_flags(struct usb_phy *phy)
12894ae9843SFelipe Balbi {
12994ae9843SFelipe Balbi 	int ret;
13094ae9843SFelipe Balbi 
13194ae9843SFelipe Balbi 	ret = ulpi_set_otg_flags(phy);
13294ae9843SFelipe Balbi 	if (ret)
13394ae9843SFelipe Balbi 		return ret;
13494ae9843SFelipe Balbi 
13594ae9843SFelipe Balbi 	ret = ulpi_set_ic_flags(phy);
13694ae9843SFelipe Balbi 	if (ret)
13794ae9843SFelipe Balbi 		return ret;
13894ae9843SFelipe Balbi 
13994ae9843SFelipe Balbi 	return ulpi_set_fc_flags(phy);
14094ae9843SFelipe Balbi }
14194ae9843SFelipe Balbi 
ulpi_check_integrity(struct usb_phy * phy)14294ae9843SFelipe Balbi static int ulpi_check_integrity(struct usb_phy *phy)
14394ae9843SFelipe Balbi {
14494ae9843SFelipe Balbi 	int ret, i;
14594ae9843SFelipe Balbi 	unsigned int val = 0x55;
14694ae9843SFelipe Balbi 
14794ae9843SFelipe Balbi 	for (i = 0; i < 2; i++) {
14894ae9843SFelipe Balbi 		ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
14994ae9843SFelipe Balbi 		if (ret < 0)
15094ae9843SFelipe Balbi 			return ret;
15194ae9843SFelipe Balbi 
15294ae9843SFelipe Balbi 		ret = usb_phy_io_read(phy, ULPI_SCRATCH);
15394ae9843SFelipe Balbi 		if (ret < 0)
15494ae9843SFelipe Balbi 			return ret;
15594ae9843SFelipe Balbi 
15694ae9843SFelipe Balbi 		if (ret != val) {
15794ae9843SFelipe Balbi 			pr_err("ULPI integrity check: failed!");
15894ae9843SFelipe Balbi 			return -ENODEV;
15994ae9843SFelipe Balbi 		}
16094ae9843SFelipe Balbi 		val = val << 1;
16194ae9843SFelipe Balbi 	}
16294ae9843SFelipe Balbi 
16394ae9843SFelipe Balbi 	pr_info("ULPI integrity check: passed.\n");
16494ae9843SFelipe Balbi 
16594ae9843SFelipe Balbi 	return 0;
16694ae9843SFelipe Balbi }
16794ae9843SFelipe Balbi 
ulpi_init(struct usb_phy * phy)16894ae9843SFelipe Balbi static int ulpi_init(struct usb_phy *phy)
16994ae9843SFelipe Balbi {
17094ae9843SFelipe Balbi 	int i, vid, pid, ret;
17194ae9843SFelipe Balbi 	u32 ulpi_id = 0;
17294ae9843SFelipe Balbi 
17394ae9843SFelipe Balbi 	for (i = 0; i < 4; i++) {
17494ae9843SFelipe Balbi 		ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
17594ae9843SFelipe Balbi 		if (ret < 0)
17694ae9843SFelipe Balbi 			return ret;
17794ae9843SFelipe Balbi 		ulpi_id = (ulpi_id << 8) | ret;
17894ae9843SFelipe Balbi 	}
17994ae9843SFelipe Balbi 	vid = ulpi_id & 0xffff;
18094ae9843SFelipe Balbi 	pid = ulpi_id >> 16;
18194ae9843SFelipe Balbi 
18294ae9843SFelipe Balbi 	pr_info("ULPI transceiver vendor/product ID 0x%04x/0x%04x\n", vid, pid);
18394ae9843SFelipe Balbi 
18494ae9843SFelipe Balbi 	for (i = 0; i < ARRAY_SIZE(ulpi_ids); i++) {
18594ae9843SFelipe Balbi 		if (ulpi_ids[i].id == ULPI_ID(vid, pid)) {
18694ae9843SFelipe Balbi 			pr_info("Found %s ULPI transceiver.\n",
18794ae9843SFelipe Balbi 				ulpi_ids[i].name);
18894ae9843SFelipe Balbi 			break;
18994ae9843SFelipe Balbi 		}
19094ae9843SFelipe Balbi 	}
19194ae9843SFelipe Balbi 
19294ae9843SFelipe Balbi 	ret = ulpi_check_integrity(phy);
19394ae9843SFelipe Balbi 	if (ret)
19494ae9843SFelipe Balbi 		return ret;
19594ae9843SFelipe Balbi 
19694ae9843SFelipe Balbi 	return ulpi_set_flags(phy);
19794ae9843SFelipe Balbi }
19894ae9843SFelipe Balbi 
ulpi_set_host(struct usb_otg * otg,struct usb_bus * host)19994ae9843SFelipe Balbi static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
20094ae9843SFelipe Balbi {
20119c1eac2SAntoine Tenart 	struct usb_phy *phy = otg->usb_phy;
20294ae9843SFelipe Balbi 	unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
20394ae9843SFelipe Balbi 
20494ae9843SFelipe Balbi 	if (!host) {
20594ae9843SFelipe Balbi 		otg->host = NULL;
20694ae9843SFelipe Balbi 		return 0;
20794ae9843SFelipe Balbi 	}
20894ae9843SFelipe Balbi 
20994ae9843SFelipe Balbi 	otg->host = host;
21094ae9843SFelipe Balbi 
21194ae9843SFelipe Balbi 	flags &= ~(ULPI_IFC_CTRL_6_PIN_SERIAL_MODE |
21294ae9843SFelipe Balbi 		   ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
21394ae9843SFelipe Balbi 		   ULPI_IFC_CTRL_CARKITMODE);
21494ae9843SFelipe Balbi 
21594ae9843SFelipe Balbi 	if (phy->flags & ULPI_IC_6PIN_SERIAL)
21694ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
21794ae9843SFelipe Balbi 	else if (phy->flags & ULPI_IC_3PIN_SERIAL)
21894ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
21994ae9843SFelipe Balbi 	else if (phy->flags & ULPI_IC_CARKIT)
22094ae9843SFelipe Balbi 		flags |= ULPI_IFC_CTRL_CARKITMODE;
22194ae9843SFelipe Balbi 
22294ae9843SFelipe Balbi 	return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
22394ae9843SFelipe Balbi }
22494ae9843SFelipe Balbi 
ulpi_set_vbus(struct usb_otg * otg,bool on)22594ae9843SFelipe Balbi static int ulpi_set_vbus(struct usb_otg *otg, bool on)
22694ae9843SFelipe Balbi {
22719c1eac2SAntoine Tenart 	struct usb_phy *phy = otg->usb_phy;
22894ae9843SFelipe Balbi 	unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
22994ae9843SFelipe Balbi 
23094ae9843SFelipe Balbi 	flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
23194ae9843SFelipe Balbi 
23294ae9843SFelipe Balbi 	if (on) {
23394ae9843SFelipe Balbi 		if (phy->flags & ULPI_OTG_DRVVBUS)
23494ae9843SFelipe Balbi 			flags |= ULPI_OTG_CTRL_DRVVBUS;
23594ae9843SFelipe Balbi 
23694ae9843SFelipe Balbi 		if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
23794ae9843SFelipe Balbi 			flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
23894ae9843SFelipe Balbi 	}
23994ae9843SFelipe Balbi 
24094ae9843SFelipe Balbi 	return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
24194ae9843SFelipe Balbi }
24294ae9843SFelipe Balbi 
otg_ulpi_init(struct usb_phy * phy,struct usb_otg * otg,struct usb_phy_io_ops * ops,unsigned int flags)243*dea75ee6SDmitry Osipenko static void otg_ulpi_init(struct usb_phy *phy, struct usb_otg *otg,
244*dea75ee6SDmitry Osipenko 			  struct usb_phy_io_ops *ops,
245*dea75ee6SDmitry Osipenko 			  unsigned int flags)
246*dea75ee6SDmitry Osipenko {
247*dea75ee6SDmitry Osipenko 	phy->label	= "ULPI";
248*dea75ee6SDmitry Osipenko 	phy->flags	= flags;
249*dea75ee6SDmitry Osipenko 	phy->io_ops	= ops;
250*dea75ee6SDmitry Osipenko 	phy->otg	= otg;
251*dea75ee6SDmitry Osipenko 	phy->init	= ulpi_init;
252*dea75ee6SDmitry Osipenko 
253*dea75ee6SDmitry Osipenko 	otg->usb_phy	= phy;
254*dea75ee6SDmitry Osipenko 	otg->set_host	= ulpi_set_host;
255*dea75ee6SDmitry Osipenko 	otg->set_vbus	= ulpi_set_vbus;
256*dea75ee6SDmitry Osipenko }
257*dea75ee6SDmitry Osipenko 
25894ae9843SFelipe Balbi struct usb_phy *
otg_ulpi_create(struct usb_phy_io_ops * ops,unsigned int flags)25994ae9843SFelipe Balbi otg_ulpi_create(struct usb_phy_io_ops *ops,
26094ae9843SFelipe Balbi 		unsigned int flags)
26194ae9843SFelipe Balbi {
26294ae9843SFelipe Balbi 	struct usb_phy *phy;
26394ae9843SFelipe Balbi 	struct usb_otg *otg;
26494ae9843SFelipe Balbi 
26594ae9843SFelipe Balbi 	phy = kzalloc(sizeof(*phy), GFP_KERNEL);
26694ae9843SFelipe Balbi 	if (!phy)
26794ae9843SFelipe Balbi 		return NULL;
26894ae9843SFelipe Balbi 
26994ae9843SFelipe Balbi 	otg = kzalloc(sizeof(*otg), GFP_KERNEL);
27094ae9843SFelipe Balbi 	if (!otg) {
27194ae9843SFelipe Balbi 		kfree(phy);
27294ae9843SFelipe Balbi 		return NULL;
27394ae9843SFelipe Balbi 	}
27494ae9843SFelipe Balbi 
275*dea75ee6SDmitry Osipenko 	otg_ulpi_init(phy, otg, ops, flags);
27694ae9843SFelipe Balbi 
27794ae9843SFelipe Balbi 	return phy;
27894ae9843SFelipe Balbi }
27994ae9843SFelipe Balbi EXPORT_SYMBOL_GPL(otg_ulpi_create);
28094ae9843SFelipe Balbi 
281*dea75ee6SDmitry Osipenko struct usb_phy *
devm_otg_ulpi_create(struct device * dev,struct usb_phy_io_ops * ops,unsigned int flags)282*dea75ee6SDmitry Osipenko devm_otg_ulpi_create(struct device *dev,
283*dea75ee6SDmitry Osipenko 		     struct usb_phy_io_ops *ops,
284*dea75ee6SDmitry Osipenko 		     unsigned int flags)
285*dea75ee6SDmitry Osipenko {
286*dea75ee6SDmitry Osipenko 	struct usb_phy *phy;
287*dea75ee6SDmitry Osipenko 	struct usb_otg *otg;
288*dea75ee6SDmitry Osipenko 
289*dea75ee6SDmitry Osipenko 	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
290*dea75ee6SDmitry Osipenko 	if (!phy)
291*dea75ee6SDmitry Osipenko 		return NULL;
292*dea75ee6SDmitry Osipenko 
293*dea75ee6SDmitry Osipenko 	otg = devm_kzalloc(dev, sizeof(*otg), GFP_KERNEL);
294*dea75ee6SDmitry Osipenko 	if (!otg) {
295*dea75ee6SDmitry Osipenko 		devm_kfree(dev, phy);
296*dea75ee6SDmitry Osipenko 		return NULL;
297*dea75ee6SDmitry Osipenko 	}
298*dea75ee6SDmitry Osipenko 
299*dea75ee6SDmitry Osipenko 	otg_ulpi_init(phy, otg, ops, flags);
300*dea75ee6SDmitry Osipenko 
301*dea75ee6SDmitry Osipenko 	return phy;
302*dea75ee6SDmitry Osipenko }
303*dea75ee6SDmitry Osipenko EXPORT_SYMBOL_GPL(devm_otg_ulpi_create);
304