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