xref: /linux/drivers/usb/isp1760/isp1760-core.c (revision 95298d63c67673c654c08952672d016212b26054)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Driver for the NXP ISP1760 chip
4  *
5  * Copyright 2014 Laurent Pinchart
6  * Copyright 2007 Sebastian Siewior
7  *
8  * Contacts:
9  *	Sebastian Siewior <bigeasy@linutronix.de>
10  *	Laurent Pinchart <laurent.pinchart@ideasonboard.com>
11  */
12 
13 #include <linux/delay.h>
14 #include <linux/gpio/consumer.h>
15 #include <linux/io.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/slab.h>
19 #include <linux/usb.h>
20 
21 #include "isp1760-core.h"
22 #include "isp1760-hcd.h"
23 #include "isp1760-regs.h"
24 #include "isp1760-udc.h"
25 
26 static void isp1760_init_core(struct isp1760_device *isp)
27 {
28 	u32 otgctrl;
29 	u32 hwmode;
30 
31 	/* Low-level chip reset */
32 	if (isp->rst_gpio) {
33 		gpiod_set_value_cansleep(isp->rst_gpio, 1);
34 		msleep(50);
35 		gpiod_set_value_cansleep(isp->rst_gpio, 0);
36 	}
37 
38 	/*
39 	 * Reset the host controller, including the CPU interface
40 	 * configuration.
41 	 */
42 	isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
43 	msleep(100);
44 
45 	/* Setup HW Mode Control: This assumes a level active-low interrupt */
46 	hwmode = HW_DATA_BUS_32BIT;
47 
48 	if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
49 		hwmode &= ~HW_DATA_BUS_32BIT;
50 	if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
51 		hwmode |= HW_ANA_DIGI_OC;
52 	if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
53 		hwmode |= HW_DACK_POL_HIGH;
54 	if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
55 		hwmode |= HW_DREQ_POL_HIGH;
56 	if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
57 		hwmode |= HW_INTR_HIGH_ACT;
58 	if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
59 		hwmode |= HW_INTR_EDGE_TRIG;
60 
61 	/*
62 	 * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
63 	 * IRQ line for both the host and device controllers. Hardcode IRQ
64 	 * sharing for now and disable the DC interrupts globally to avoid
65 	 * spurious interrupts during HCD registration.
66 	 */
67 	if (isp->devflags & ISP1760_FLAG_ISP1761) {
68 		isp1760_write32(isp->regs, DC_MODE, 0);
69 		hwmode |= HW_COMN_IRQ;
70 	}
71 
72 	/*
73 	 * We have to set this first in case we're in 16-bit mode.
74 	 * Write it twice to ensure correct upper bits if switching
75 	 * to 16-bit mode.
76 	 */
77 	isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
78 	isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
79 
80 	/*
81 	 * PORT 1 Control register of the ISP1760 is the OTG control register
82 	 * on ISP1761.
83 	 *
84 	 * TODO: Really support OTG. For now we configure port 1 in device mode
85 	 * when OTG is requested.
86 	 */
87 	if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
88 	    (isp->devflags & ISP1760_FLAG_OTG_EN))
89 		otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
90 			| HW_OTG_DISABLE;
91 	else
92 		otgctrl = (HW_SW_SEL_HC_DC << 16)
93 			| (HW_VBUS_DRV | HW_SEL_CP_EXT);
94 
95 	isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
96 
97 	dev_info(isp->dev, "bus width: %u, oc: %s\n",
98 		 isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
99 		 isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
100 }
101 
102 void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
103 {
104 	isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
105 			enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
106 }
107 
108 int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
109 		     struct device *dev, unsigned int devflags)
110 {
111 	struct isp1760_device *isp;
112 	bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
113 	int ret;
114 
115 	/*
116 	 * If neither the HCD not the UDC is enabled return an error, as no
117 	 * device would be registered.
118 	 */
119 	if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
120 	    (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
121 		return -ENODEV;
122 
123 	isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
124 	if (!isp)
125 		return -ENOMEM;
126 
127 	isp->dev = dev;
128 	isp->devflags = devflags;
129 
130 	isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
131 	if (IS_ERR(isp->rst_gpio))
132 		return PTR_ERR(isp->rst_gpio);
133 
134 	isp->regs = devm_ioremap_resource(dev, mem);
135 	if (IS_ERR(isp->regs))
136 		return PTR_ERR(isp->regs);
137 
138 	isp1760_init_core(isp);
139 
140 	if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
141 		ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
142 					   irqflags | IRQF_SHARED, dev);
143 		if (ret < 0)
144 			return ret;
145 	}
146 
147 	if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
148 		ret = isp1760_udc_register(isp, irq, irqflags);
149 		if (ret < 0) {
150 			isp1760_hcd_unregister(&isp->hcd);
151 			return ret;
152 		}
153 	}
154 
155 	dev_set_drvdata(dev, isp);
156 
157 	return 0;
158 }
159 
160 void isp1760_unregister(struct device *dev)
161 {
162 	struct isp1760_device *isp = dev_get_drvdata(dev);
163 
164 	isp1760_udc_unregister(isp);
165 	isp1760_hcd_unregister(&isp->hcd);
166 }
167 
168 MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
169 MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
170 MODULE_LICENSE("GPL v2");
171