xref: /OK3568_Linux_fs/kernel/drivers/phy/motorola/phy-cpcap-usb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Motorola CPCAP PMIC USB PHY driver
3*4882a593Smuzhiyun  * Copyright (C) 2017 Tony Lindgren <tony@atomide.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Some parts based on earlier Motorola Linux kernel tree code in
6*4882a593Smuzhiyun  * board-mapphone-usb.c and cpcap-usb-det.c:
7*4882a593Smuzhiyun  * Copyright (C) 2007 - 2011 Motorola, Inc.
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This program is free software; you can redistribute it and/or
10*4882a593Smuzhiyun  * modify it under the terms of the GNU General Public License as
11*4882a593Smuzhiyun  * published by the Free Software Foundation version 2.
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
14*4882a593Smuzhiyun  * kind, whether express or implied; without even the implied warranty
15*4882a593Smuzhiyun  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*4882a593Smuzhiyun  * GNU General Public License for more details.
17*4882a593Smuzhiyun  */
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #include <linux/atomic.h>
20*4882a593Smuzhiyun #include <linux/clk.h>
21*4882a593Smuzhiyun #include <linux/delay.h>
22*4882a593Smuzhiyun #include <linux/err.h>
23*4882a593Smuzhiyun #include <linux/io.h>
24*4882a593Smuzhiyun #include <linux/module.h>
25*4882a593Smuzhiyun #include <linux/of.h>
26*4882a593Smuzhiyun #include <linux/of_platform.h>
27*4882a593Smuzhiyun #include <linux/iio/consumer.h>
28*4882a593Smuzhiyun #include <linux/pinctrl/consumer.h>
29*4882a593Smuzhiyun #include <linux/platform_device.h>
30*4882a593Smuzhiyun #include <linux/regmap.h>
31*4882a593Smuzhiyun #include <linux/slab.h>
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include <linux/gpio/consumer.h>
34*4882a593Smuzhiyun #include <linux/mfd/motorola-cpcap.h>
35*4882a593Smuzhiyun #include <linux/phy/omap_usb.h>
36*4882a593Smuzhiyun #include <linux/phy/phy.h>
37*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
38*4882a593Smuzhiyun #include <linux/usb/musb.h>
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun /* CPCAP_REG_USBC1 register bits */
41*4882a593Smuzhiyun #define CPCAP_BIT_IDPULSE		BIT(15)
42*4882a593Smuzhiyun #define CPCAP_BIT_ID100KPU		BIT(14)
43*4882a593Smuzhiyun #define CPCAP_BIT_IDPUCNTRL		BIT(13)
44*4882a593Smuzhiyun #define CPCAP_BIT_IDPU			BIT(12)
45*4882a593Smuzhiyun #define CPCAP_BIT_IDPD			BIT(11)
46*4882a593Smuzhiyun #define CPCAP_BIT_VBUSCHRGTMR3		BIT(10)
47*4882a593Smuzhiyun #define CPCAP_BIT_VBUSCHRGTMR2		BIT(9)
48*4882a593Smuzhiyun #define CPCAP_BIT_VBUSCHRGTMR1		BIT(8)
49*4882a593Smuzhiyun #define CPCAP_BIT_VBUSCHRGTMR0		BIT(7)
50*4882a593Smuzhiyun #define CPCAP_BIT_VBUSPU		BIT(6)
51*4882a593Smuzhiyun #define CPCAP_BIT_VBUSPD		BIT(5)
52*4882a593Smuzhiyun #define CPCAP_BIT_DMPD			BIT(4)
53*4882a593Smuzhiyun #define CPCAP_BIT_DPPD			BIT(3)
54*4882a593Smuzhiyun #define CPCAP_BIT_DM1K5PU		BIT(2)
55*4882a593Smuzhiyun #define CPCAP_BIT_DP1K5PU		BIT(1)
56*4882a593Smuzhiyun #define CPCAP_BIT_DP150KPU		BIT(0)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun /* CPCAP_REG_USBC2 register bits */
59*4882a593Smuzhiyun #define CPCAP_BIT_ZHSDRV1		BIT(15)
60*4882a593Smuzhiyun #define CPCAP_BIT_ZHSDRV0		BIT(14)
61*4882a593Smuzhiyun #define CPCAP_BIT_DPLLCLKREQ		BIT(13)
62*4882a593Smuzhiyun #define CPCAP_BIT_SE0CONN		BIT(12)
63*4882a593Smuzhiyun #define CPCAP_BIT_UARTTXTRI		BIT(11)
64*4882a593Smuzhiyun #define CPCAP_BIT_UARTSWAP		BIT(10)
65*4882a593Smuzhiyun #define CPCAP_BIT_UARTMUX1		BIT(9)
66*4882a593Smuzhiyun #define CPCAP_BIT_UARTMUX0		BIT(8)
67*4882a593Smuzhiyun #define CPCAP_BIT_ULPISTPLOW		BIT(7)
68*4882a593Smuzhiyun #define CPCAP_BIT_TXENPOL		BIT(6)
69*4882a593Smuzhiyun #define CPCAP_BIT_USBXCVREN		BIT(5)
70*4882a593Smuzhiyun #define CPCAP_BIT_USBCNTRL		BIT(4)
71*4882a593Smuzhiyun #define CPCAP_BIT_USBSUSPEND		BIT(3)
72*4882a593Smuzhiyun #define CPCAP_BIT_EMUMODE2		BIT(2)
73*4882a593Smuzhiyun #define CPCAP_BIT_EMUMODE1		BIT(1)
74*4882a593Smuzhiyun #define CPCAP_BIT_EMUMODE0		BIT(0)
75*4882a593Smuzhiyun 
76*4882a593Smuzhiyun /* CPCAP_REG_USBC3 register bits */
77*4882a593Smuzhiyun #define CPCAP_BIT_SPARE_898_15		BIT(15)
78*4882a593Smuzhiyun #define CPCAP_BIT_IHSTX03		BIT(14)
79*4882a593Smuzhiyun #define CPCAP_BIT_IHSTX02		BIT(13)
80*4882a593Smuzhiyun #define CPCAP_BIT_IHSTX01		BIT(12)
81*4882a593Smuzhiyun #define CPCAP_BIT_IHSTX0		BIT(11)
82*4882a593Smuzhiyun #define CPCAP_BIT_IDPU_SPI		BIT(10)
83*4882a593Smuzhiyun #define CPCAP_BIT_UNUSED_898_9		BIT(9)
84*4882a593Smuzhiyun #define CPCAP_BIT_VBUSSTBY_EN		BIT(8)
85*4882a593Smuzhiyun #define CPCAP_BIT_VBUSEN_SPI		BIT(7)
86*4882a593Smuzhiyun #define CPCAP_BIT_VBUSPU_SPI		BIT(6)
87*4882a593Smuzhiyun #define CPCAP_BIT_VBUSPD_SPI		BIT(5)
88*4882a593Smuzhiyun #define CPCAP_BIT_DMPD_SPI		BIT(4)
89*4882a593Smuzhiyun #define CPCAP_BIT_DPPD_SPI		BIT(3)
90*4882a593Smuzhiyun #define CPCAP_BIT_SUSPEND_SPI		BIT(2)
91*4882a593Smuzhiyun #define CPCAP_BIT_PU_SPI		BIT(1)
92*4882a593Smuzhiyun #define CPCAP_BIT_ULPI_SPI_SEL		BIT(0)
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun struct cpcap_usb_ints_state {
95*4882a593Smuzhiyun 	bool id_ground;
96*4882a593Smuzhiyun 	bool id_float;
97*4882a593Smuzhiyun 	bool chrg_det;
98*4882a593Smuzhiyun 	bool rvrs_chrg;
99*4882a593Smuzhiyun 	bool vbusov;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	bool chrg_se1b;
102*4882a593Smuzhiyun 	bool se0conn;
103*4882a593Smuzhiyun 	bool rvrs_mode;
104*4882a593Smuzhiyun 	bool chrgcurr1;
105*4882a593Smuzhiyun 	bool vbusvld;
106*4882a593Smuzhiyun 	bool sessvld;
107*4882a593Smuzhiyun 	bool sessend;
108*4882a593Smuzhiyun 	bool se1;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	bool battdetb;
111*4882a593Smuzhiyun 	bool dm;
112*4882a593Smuzhiyun 	bool dp;
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun enum cpcap_gpio_mode {
116*4882a593Smuzhiyun 	CPCAP_DM_DP,
117*4882a593Smuzhiyun 	CPCAP_MDM_RX_TX,
118*4882a593Smuzhiyun 	CPCAP_UNKNOWN_DISABLED,	/* Seems to disable USB lines */
119*4882a593Smuzhiyun 	CPCAP_OTG_DM_DP,
120*4882a593Smuzhiyun };
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun struct cpcap_phy_ddata {
123*4882a593Smuzhiyun 	struct regmap *reg;
124*4882a593Smuzhiyun 	struct device *dev;
125*4882a593Smuzhiyun 	struct usb_phy phy;
126*4882a593Smuzhiyun 	struct delayed_work detect_work;
127*4882a593Smuzhiyun 	struct pinctrl *pins;
128*4882a593Smuzhiyun 	struct pinctrl_state *pins_ulpi;
129*4882a593Smuzhiyun 	struct pinctrl_state *pins_utmi;
130*4882a593Smuzhiyun 	struct pinctrl_state *pins_uart;
131*4882a593Smuzhiyun 	struct gpio_desc *gpio[2];
132*4882a593Smuzhiyun 	struct iio_channel *vbus;
133*4882a593Smuzhiyun 	struct iio_channel *id;
134*4882a593Smuzhiyun 	struct regulator *vusb;
135*4882a593Smuzhiyun 	atomic_t active;
136*4882a593Smuzhiyun 	unsigned int vbus_provider:1;
137*4882a593Smuzhiyun 	unsigned int docked:1;
138*4882a593Smuzhiyun };
139*4882a593Smuzhiyun 
cpcap_usb_vbus_valid(struct cpcap_phy_ddata * ddata)140*4882a593Smuzhiyun static bool cpcap_usb_vbus_valid(struct cpcap_phy_ddata *ddata)
141*4882a593Smuzhiyun {
142*4882a593Smuzhiyun 	int error, value = 0;
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun 	error = iio_read_channel_processed(ddata->vbus, &value);
145*4882a593Smuzhiyun 	if (error >= 0)
146*4882a593Smuzhiyun 		return value > 3900 ? true : false;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	dev_err(ddata->dev, "error reading VBUS: %i\n", error);
149*4882a593Smuzhiyun 
150*4882a593Smuzhiyun 	return false;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun 
cpcap_usb_phy_set_host(struct usb_otg * otg,struct usb_bus * host)153*4882a593Smuzhiyun static int cpcap_usb_phy_set_host(struct usb_otg *otg, struct usb_bus *host)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	otg->host = host;
156*4882a593Smuzhiyun 	if (!host)
157*4882a593Smuzhiyun 		otg->state = OTG_STATE_UNDEFINED;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	return 0;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun 
cpcap_usb_phy_set_peripheral(struct usb_otg * otg,struct usb_gadget * gadget)162*4882a593Smuzhiyun static int cpcap_usb_phy_set_peripheral(struct usb_otg *otg,
163*4882a593Smuzhiyun 					struct usb_gadget *gadget)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun 	otg->gadget = gadget;
166*4882a593Smuzhiyun 	if (!gadget)
167*4882a593Smuzhiyun 		otg->state = OTG_STATE_UNDEFINED;
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	return 0;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun static const struct phy_ops ops = {
173*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
174*4882a593Smuzhiyun };
175*4882a593Smuzhiyun 
cpcap_phy_get_ints_state(struct cpcap_phy_ddata * ddata,struct cpcap_usb_ints_state * s)176*4882a593Smuzhiyun static int cpcap_phy_get_ints_state(struct cpcap_phy_ddata *ddata,
177*4882a593Smuzhiyun 				    struct cpcap_usb_ints_state *s)
178*4882a593Smuzhiyun {
179*4882a593Smuzhiyun 	int val, error;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	error = regmap_read(ddata->reg, CPCAP_REG_INTS1, &val);
182*4882a593Smuzhiyun 	if (error)
183*4882a593Smuzhiyun 		return error;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	s->id_ground = val & BIT(15);
186*4882a593Smuzhiyun 	s->id_float = val & BIT(14);
187*4882a593Smuzhiyun 	s->vbusov = val & BIT(11);
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	error = regmap_read(ddata->reg, CPCAP_REG_INTS2, &val);
190*4882a593Smuzhiyun 	if (error)
191*4882a593Smuzhiyun 		return error;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	s->vbusvld = val & BIT(3);
194*4882a593Smuzhiyun 	s->sessvld = val & BIT(2);
195*4882a593Smuzhiyun 	s->sessend = val & BIT(1);
196*4882a593Smuzhiyun 	s->se1 = val & BIT(0);
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	error = regmap_read(ddata->reg, CPCAP_REG_INTS4, &val);
199*4882a593Smuzhiyun 	if (error)
200*4882a593Smuzhiyun 		return error;
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	s->dm = val & BIT(1);
203*4882a593Smuzhiyun 	s->dp = val & BIT(0);
204*4882a593Smuzhiyun 
205*4882a593Smuzhiyun 	return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata);
209*4882a593Smuzhiyun static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata);
210*4882a593Smuzhiyun 
cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata * ddata,enum musb_vbus_id_status status)211*4882a593Smuzhiyun static void cpcap_usb_try_musb_mailbox(struct cpcap_phy_ddata *ddata,
212*4882a593Smuzhiyun 				       enum musb_vbus_id_status status)
213*4882a593Smuzhiyun {
214*4882a593Smuzhiyun 	int error;
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	error = musb_mailbox(status);
217*4882a593Smuzhiyun 	if (!error)
218*4882a593Smuzhiyun 		return;
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	dev_dbg(ddata->dev, "%s: musb_mailbox failed: %i\n",
221*4882a593Smuzhiyun 		__func__, error);
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun 
cpcap_usb_detect(struct work_struct * work)224*4882a593Smuzhiyun static void cpcap_usb_detect(struct work_struct *work)
225*4882a593Smuzhiyun {
226*4882a593Smuzhiyun 	struct cpcap_phy_ddata *ddata;
227*4882a593Smuzhiyun 	struct cpcap_usb_ints_state s;
228*4882a593Smuzhiyun 	bool vbus = false;
229*4882a593Smuzhiyun 	int error;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	ddata = container_of(work, struct cpcap_phy_ddata, detect_work.work);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	error = cpcap_phy_get_ints_state(ddata, &s);
234*4882a593Smuzhiyun 	if (error)
235*4882a593Smuzhiyun 		return;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	vbus = cpcap_usb_vbus_valid(ddata);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	/* We need to kick the VBUS as USB A-host */
240*4882a593Smuzhiyun 	if (s.id_ground && ddata->vbus_provider) {
241*4882a593Smuzhiyun 		dev_dbg(ddata->dev, "still in USB A-host mode, kicking VBUS\n");
242*4882a593Smuzhiyun 
243*4882a593Smuzhiyun 		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
246*4882a593Smuzhiyun 					   CPCAP_BIT_VBUSSTBY_EN |
247*4882a593Smuzhiyun 					   CPCAP_BIT_VBUSEN_SPI,
248*4882a593Smuzhiyun 					   CPCAP_BIT_VBUSEN_SPI);
249*4882a593Smuzhiyun 		if (error)
250*4882a593Smuzhiyun 			goto out_err;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 		return;
253*4882a593Smuzhiyun 	}
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (vbus && s.id_ground && ddata->docked) {
256*4882a593Smuzhiyun 		dev_dbg(ddata->dev, "still docked as A-host, signal ID down\n");
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 		return;
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	/* No VBUS needed with docks */
264*4882a593Smuzhiyun 	if (vbus && s.id_ground && !ddata->vbus_provider) {
265*4882a593Smuzhiyun 		dev_dbg(ddata->dev, "connected to a dock\n");
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 		ddata->docked = true;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 		error = cpcap_usb_set_usb_mode(ddata);
270*4882a593Smuzhiyun 		if (error)
271*4882a593Smuzhiyun 			goto out_err;
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 		/*
276*4882a593Smuzhiyun 		 * Force check state again after musb has reoriented,
277*4882a593Smuzhiyun 		 * otherwise devices won't enumerate after loading PHY
278*4882a593Smuzhiyun 		 * driver.
279*4882a593Smuzhiyun 		 */
280*4882a593Smuzhiyun 		schedule_delayed_work(&ddata->detect_work,
281*4882a593Smuzhiyun 				      msecs_to_jiffies(1000));
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 		return;
284*4882a593Smuzhiyun 	}
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (s.id_ground && !ddata->docked) {
287*4882a593Smuzhiyun 		dev_dbg(ddata->dev, "id ground, USB host mode\n");
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 		ddata->vbus_provider = true;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 		error = cpcap_usb_set_usb_mode(ddata);
292*4882a593Smuzhiyun 		if (error)
293*4882a593Smuzhiyun 			goto out_err;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 		cpcap_usb_try_musb_mailbox(ddata, MUSB_ID_GROUND);
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun 		error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
298*4882a593Smuzhiyun 					   CPCAP_BIT_VBUSSTBY_EN |
299*4882a593Smuzhiyun 					   CPCAP_BIT_VBUSEN_SPI,
300*4882a593Smuzhiyun 					   CPCAP_BIT_VBUSEN_SPI);
301*4882a593Smuzhiyun 		if (error)
302*4882a593Smuzhiyun 			goto out_err;
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		return;
305*4882a593Smuzhiyun 	}
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
308*4882a593Smuzhiyun 				   CPCAP_BIT_VBUSSTBY_EN |
309*4882a593Smuzhiyun 				   CPCAP_BIT_VBUSEN_SPI, 0);
310*4882a593Smuzhiyun 	if (error)
311*4882a593Smuzhiyun 		goto out_err;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	vbus = cpcap_usb_vbus_valid(ddata);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/* Otherwise assume we're connected to a USB host */
316*4882a593Smuzhiyun 	if (vbus) {
317*4882a593Smuzhiyun 		dev_dbg(ddata->dev, "connected to USB host\n");
318*4882a593Smuzhiyun 		error = cpcap_usb_set_usb_mode(ddata);
319*4882a593Smuzhiyun 		if (error)
320*4882a593Smuzhiyun 			goto out_err;
321*4882a593Smuzhiyun 		cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_VALID);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 		return;
324*4882a593Smuzhiyun 	}
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	ddata->vbus_provider = false;
327*4882a593Smuzhiyun 	ddata->docked = false;
328*4882a593Smuzhiyun 	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	/* Default to debug UART mode */
331*4882a593Smuzhiyun 	error = cpcap_usb_set_uart_mode(ddata);
332*4882a593Smuzhiyun 	if (error)
333*4882a593Smuzhiyun 		goto out_err;
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 	dev_dbg(ddata->dev, "set UART mode\n");
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	return;
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun out_err:
340*4882a593Smuzhiyun 	dev_err(ddata->dev, "error setting cable state: %i\n", error);
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun 
cpcap_phy_irq_thread(int irq,void * data)343*4882a593Smuzhiyun static irqreturn_t cpcap_phy_irq_thread(int irq, void *data)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun 	struct cpcap_phy_ddata *ddata = data;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	if (!atomic_read(&ddata->active))
348*4882a593Smuzhiyun 		return IRQ_NONE;
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun 	schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	return IRQ_HANDLED;
353*4882a593Smuzhiyun }
354*4882a593Smuzhiyun 
cpcap_usb_init_irq(struct platform_device * pdev,struct cpcap_phy_ddata * ddata,const char * name)355*4882a593Smuzhiyun static int cpcap_usb_init_irq(struct platform_device *pdev,
356*4882a593Smuzhiyun 			      struct cpcap_phy_ddata *ddata,
357*4882a593Smuzhiyun 			      const char *name)
358*4882a593Smuzhiyun {
359*4882a593Smuzhiyun 	int irq, error;
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 	irq = platform_get_irq_byname(pdev, name);
362*4882a593Smuzhiyun 	if (irq < 0)
363*4882a593Smuzhiyun 		return -ENODEV;
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	error = devm_request_threaded_irq(ddata->dev, irq, NULL,
366*4882a593Smuzhiyun 					  cpcap_phy_irq_thread,
367*4882a593Smuzhiyun 					  IRQF_SHARED |
368*4882a593Smuzhiyun 					  IRQF_ONESHOT,
369*4882a593Smuzhiyun 					  name, ddata);
370*4882a593Smuzhiyun 	if (error) {
371*4882a593Smuzhiyun 		dev_err(ddata->dev, "could not get irq %s: %i\n",
372*4882a593Smuzhiyun 			name, error);
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		return error;
375*4882a593Smuzhiyun 	}
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 	return 0;
378*4882a593Smuzhiyun }
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun static const char * const cpcap_phy_irqs[] = {
381*4882a593Smuzhiyun 	/* REG_INT_0 */
382*4882a593Smuzhiyun 	"id_ground", "id_float",
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	/* REG_INT1 */
385*4882a593Smuzhiyun 	"se0conn", "vbusvld", "sessvld", "sessend", "se1",
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	/* REG_INT_3 */
388*4882a593Smuzhiyun 	"dm", "dp",
389*4882a593Smuzhiyun };
390*4882a593Smuzhiyun 
cpcap_usb_init_interrupts(struct platform_device * pdev,struct cpcap_phy_ddata * ddata)391*4882a593Smuzhiyun static int cpcap_usb_init_interrupts(struct platform_device *pdev,
392*4882a593Smuzhiyun 				     struct cpcap_phy_ddata *ddata)
393*4882a593Smuzhiyun {
394*4882a593Smuzhiyun 	int i, error;
395*4882a593Smuzhiyun 
396*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(cpcap_phy_irqs); i++) {
397*4882a593Smuzhiyun 		error = cpcap_usb_init_irq(pdev, ddata, cpcap_phy_irqs[i]);
398*4882a593Smuzhiyun 		if (error)
399*4882a593Smuzhiyun 			return error;
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	return 0;
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun /*
406*4882a593Smuzhiyun  * Optional pins and modes. At least Motorola mapphone devices
407*4882a593Smuzhiyun  * are using two GPIOs and dynamic pinctrl to multiplex PHY pins
408*4882a593Smuzhiyun  * to UART, ULPI or UTMI mode.
409*4882a593Smuzhiyun  */
410*4882a593Smuzhiyun 
cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata * ddata,enum cpcap_gpio_mode mode)411*4882a593Smuzhiyun static int cpcap_usb_gpio_set_mode(struct cpcap_phy_ddata *ddata,
412*4882a593Smuzhiyun 				   enum cpcap_gpio_mode mode)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	if (!ddata->gpio[0] || !ddata->gpio[1])
415*4882a593Smuzhiyun 		return 0;
416*4882a593Smuzhiyun 
417*4882a593Smuzhiyun 	gpiod_set_value(ddata->gpio[0], mode & 1);
418*4882a593Smuzhiyun 	gpiod_set_value(ddata->gpio[1], mode >> 1);
419*4882a593Smuzhiyun 
420*4882a593Smuzhiyun 	return 0;
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun 
cpcap_usb_set_uart_mode(struct cpcap_phy_ddata * ddata)423*4882a593Smuzhiyun static int cpcap_usb_set_uart_mode(struct cpcap_phy_ddata *ddata)
424*4882a593Smuzhiyun {
425*4882a593Smuzhiyun 	int error;
426*4882a593Smuzhiyun 
427*4882a593Smuzhiyun 	/* Disable lines to prevent glitches from waking up mdm6600 */
428*4882a593Smuzhiyun 	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
429*4882a593Smuzhiyun 	if (error)
430*4882a593Smuzhiyun 		goto out_err;
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	if (ddata->pins_uart) {
433*4882a593Smuzhiyun 		error = pinctrl_select_state(ddata->pins, ddata->pins_uart);
434*4882a593Smuzhiyun 		if (error)
435*4882a593Smuzhiyun 			goto out_err;
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,
439*4882a593Smuzhiyun 				   CPCAP_BIT_VBUSPD,
440*4882a593Smuzhiyun 				   CPCAP_BIT_VBUSPD);
441*4882a593Smuzhiyun 	if (error)
442*4882a593Smuzhiyun 		goto out_err;
443*4882a593Smuzhiyun 
444*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,
445*4882a593Smuzhiyun 				   0xffff, CPCAP_BIT_UARTMUX0 |
446*4882a593Smuzhiyun 				   CPCAP_BIT_EMUMODE0);
447*4882a593Smuzhiyun 	if (error)
448*4882a593Smuzhiyun 		goto out_err;
449*4882a593Smuzhiyun 
450*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3, 0x7fff,
451*4882a593Smuzhiyun 				   CPCAP_BIT_IDPU_SPI);
452*4882a593Smuzhiyun 	if (error)
453*4882a593Smuzhiyun 		goto out_err;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	/* Enable UART mode */
456*4882a593Smuzhiyun 	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_DM_DP);
457*4882a593Smuzhiyun 	if (error)
458*4882a593Smuzhiyun 		goto out_err;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	return 0;
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun out_err:
463*4882a593Smuzhiyun 	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	return error;
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
cpcap_usb_set_usb_mode(struct cpcap_phy_ddata * ddata)468*4882a593Smuzhiyun static int cpcap_usb_set_usb_mode(struct cpcap_phy_ddata *ddata)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun 	int error;
471*4882a593Smuzhiyun 
472*4882a593Smuzhiyun 	/* Disable lines to prevent glitches from waking up mdm6600 */
473*4882a593Smuzhiyun 	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_UNKNOWN_DISABLED);
474*4882a593Smuzhiyun 	if (error)
475*4882a593Smuzhiyun 		return error;
476*4882a593Smuzhiyun 
477*4882a593Smuzhiyun 	if (ddata->pins_utmi) {
478*4882a593Smuzhiyun 		error = pinctrl_select_state(ddata->pins, ddata->pins_utmi);
479*4882a593Smuzhiyun 		if (error) {
480*4882a593Smuzhiyun 			dev_err(ddata->dev, "could not set usb mode: %i\n",
481*4882a593Smuzhiyun 				error);
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 			return error;
484*4882a593Smuzhiyun 		}
485*4882a593Smuzhiyun 	}
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC1,
488*4882a593Smuzhiyun 				   CPCAP_BIT_VBUSPD, 0);
489*4882a593Smuzhiyun 	if (error)
490*4882a593Smuzhiyun 		goto out_err;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC3,
493*4882a593Smuzhiyun 				   CPCAP_BIT_PU_SPI |
494*4882a593Smuzhiyun 				   CPCAP_BIT_DMPD_SPI |
495*4882a593Smuzhiyun 				   CPCAP_BIT_DPPD_SPI |
496*4882a593Smuzhiyun 				   CPCAP_BIT_SUSPEND_SPI |
497*4882a593Smuzhiyun 				   CPCAP_BIT_ULPI_SPI_SEL, 0);
498*4882a593Smuzhiyun 	if (error)
499*4882a593Smuzhiyun 		goto out_err;
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	error = regmap_update_bits(ddata->reg, CPCAP_REG_USBC2,
502*4882a593Smuzhiyun 				   CPCAP_BIT_USBXCVREN,
503*4882a593Smuzhiyun 				   CPCAP_BIT_USBXCVREN);
504*4882a593Smuzhiyun 	if (error)
505*4882a593Smuzhiyun 		goto out_err;
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun 	/* Enable USB mode */
508*4882a593Smuzhiyun 	error = cpcap_usb_gpio_set_mode(ddata, CPCAP_OTG_DM_DP);
509*4882a593Smuzhiyun 	if (error)
510*4882a593Smuzhiyun 		goto out_err;
511*4882a593Smuzhiyun 
512*4882a593Smuzhiyun 	return 0;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun out_err:
515*4882a593Smuzhiyun 	dev_err(ddata->dev, "%s failed with %i\n", __func__, error);
516*4882a593Smuzhiyun 
517*4882a593Smuzhiyun 	return error;
518*4882a593Smuzhiyun }
519*4882a593Smuzhiyun 
cpcap_usb_init_optional_pins(struct cpcap_phy_ddata * ddata)520*4882a593Smuzhiyun static int cpcap_usb_init_optional_pins(struct cpcap_phy_ddata *ddata)
521*4882a593Smuzhiyun {
522*4882a593Smuzhiyun 	ddata->pins = devm_pinctrl_get(ddata->dev);
523*4882a593Smuzhiyun 	if (IS_ERR(ddata->pins)) {
524*4882a593Smuzhiyun 		dev_info(ddata->dev, "default pins not configured: %ld\n",
525*4882a593Smuzhiyun 			 PTR_ERR(ddata->pins));
526*4882a593Smuzhiyun 		ddata->pins = NULL;
527*4882a593Smuzhiyun 
528*4882a593Smuzhiyun 		return 0;
529*4882a593Smuzhiyun 	}
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	ddata->pins_ulpi = pinctrl_lookup_state(ddata->pins, "ulpi");
532*4882a593Smuzhiyun 	if (IS_ERR(ddata->pins_ulpi)) {
533*4882a593Smuzhiyun 		dev_info(ddata->dev, "ulpi pins not configured\n");
534*4882a593Smuzhiyun 		ddata->pins_ulpi = NULL;
535*4882a593Smuzhiyun 	}
536*4882a593Smuzhiyun 
537*4882a593Smuzhiyun 	ddata->pins_utmi = pinctrl_lookup_state(ddata->pins, "utmi");
538*4882a593Smuzhiyun 	if (IS_ERR(ddata->pins_utmi)) {
539*4882a593Smuzhiyun 		dev_info(ddata->dev, "utmi pins not configured\n");
540*4882a593Smuzhiyun 		ddata->pins_utmi = NULL;
541*4882a593Smuzhiyun 	}
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	ddata->pins_uart = pinctrl_lookup_state(ddata->pins, "uart");
544*4882a593Smuzhiyun 	if (IS_ERR(ddata->pins_uart)) {
545*4882a593Smuzhiyun 		dev_info(ddata->dev, "uart pins not configured\n");
546*4882a593Smuzhiyun 		ddata->pins_uart = NULL;
547*4882a593Smuzhiyun 	}
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (ddata->pins_uart)
550*4882a593Smuzhiyun 		return pinctrl_select_state(ddata->pins, ddata->pins_uart);
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	return 0;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
cpcap_usb_init_optional_gpios(struct cpcap_phy_ddata * ddata)555*4882a593Smuzhiyun static void cpcap_usb_init_optional_gpios(struct cpcap_phy_ddata *ddata)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	int i;
558*4882a593Smuzhiyun 
559*4882a593Smuzhiyun 	for (i = 0; i < 2; i++) {
560*4882a593Smuzhiyun 		ddata->gpio[i] = devm_gpiod_get_index(ddata->dev, "mode",
561*4882a593Smuzhiyun 						      i, GPIOD_OUT_HIGH);
562*4882a593Smuzhiyun 		if (IS_ERR(ddata->gpio[i])) {
563*4882a593Smuzhiyun 			dev_info(ddata->dev, "no mode change GPIO%i: %li\n",
564*4882a593Smuzhiyun 				 i, PTR_ERR(ddata->gpio[i]));
565*4882a593Smuzhiyun 			ddata->gpio[i] = NULL;
566*4882a593Smuzhiyun 		}
567*4882a593Smuzhiyun 	}
568*4882a593Smuzhiyun }
569*4882a593Smuzhiyun 
cpcap_usb_init_iio(struct cpcap_phy_ddata * ddata)570*4882a593Smuzhiyun static int cpcap_usb_init_iio(struct cpcap_phy_ddata *ddata)
571*4882a593Smuzhiyun {
572*4882a593Smuzhiyun 	enum iio_chan_type type;
573*4882a593Smuzhiyun 	int error;
574*4882a593Smuzhiyun 
575*4882a593Smuzhiyun 	ddata->vbus = devm_iio_channel_get(ddata->dev, "vbus");
576*4882a593Smuzhiyun 	if (IS_ERR(ddata->vbus)) {
577*4882a593Smuzhiyun 		error = PTR_ERR(ddata->vbus);
578*4882a593Smuzhiyun 		goto out_err;
579*4882a593Smuzhiyun 	}
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	if (!ddata->vbus->indio_dev) {
582*4882a593Smuzhiyun 		error = -ENXIO;
583*4882a593Smuzhiyun 		goto out_err;
584*4882a593Smuzhiyun 	}
585*4882a593Smuzhiyun 
586*4882a593Smuzhiyun 	error = iio_get_channel_type(ddata->vbus, &type);
587*4882a593Smuzhiyun 	if (error < 0)
588*4882a593Smuzhiyun 		goto out_err;
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun 	if (type != IIO_VOLTAGE) {
591*4882a593Smuzhiyun 		error = -EINVAL;
592*4882a593Smuzhiyun 		goto out_err;
593*4882a593Smuzhiyun 	}
594*4882a593Smuzhiyun 
595*4882a593Smuzhiyun 	return 0;
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun out_err:
598*4882a593Smuzhiyun 	dev_err(ddata->dev, "could not initialize VBUS or ID IIO: %i\n",
599*4882a593Smuzhiyun 		error);
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	return error;
602*4882a593Smuzhiyun }
603*4882a593Smuzhiyun 
604*4882a593Smuzhiyun #ifdef CONFIG_OF
605*4882a593Smuzhiyun static const struct of_device_id cpcap_usb_phy_id_table[] = {
606*4882a593Smuzhiyun 	{
607*4882a593Smuzhiyun 		.compatible = "motorola,cpcap-usb-phy",
608*4882a593Smuzhiyun 	},
609*4882a593Smuzhiyun 	{
610*4882a593Smuzhiyun 		.compatible = "motorola,mapphone-cpcap-usb-phy",
611*4882a593Smuzhiyun 	},
612*4882a593Smuzhiyun 	{},
613*4882a593Smuzhiyun };
614*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, cpcap_usb_phy_id_table);
615*4882a593Smuzhiyun #endif
616*4882a593Smuzhiyun 
cpcap_usb_phy_probe(struct platform_device * pdev)617*4882a593Smuzhiyun static int cpcap_usb_phy_probe(struct platform_device *pdev)
618*4882a593Smuzhiyun {
619*4882a593Smuzhiyun 	struct cpcap_phy_ddata *ddata;
620*4882a593Smuzhiyun 	struct phy *generic_phy;
621*4882a593Smuzhiyun 	struct phy_provider *phy_provider;
622*4882a593Smuzhiyun 	struct usb_otg *otg;
623*4882a593Smuzhiyun 	const struct of_device_id *of_id;
624*4882a593Smuzhiyun 	int error;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	of_id = of_match_device(of_match_ptr(cpcap_usb_phy_id_table),
627*4882a593Smuzhiyun 				&pdev->dev);
628*4882a593Smuzhiyun 	if (!of_id)
629*4882a593Smuzhiyun 		return -EINVAL;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
632*4882a593Smuzhiyun 	if (!ddata)
633*4882a593Smuzhiyun 		return -ENOMEM;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	ddata->reg = dev_get_regmap(pdev->dev.parent, NULL);
636*4882a593Smuzhiyun 	if (!ddata->reg)
637*4882a593Smuzhiyun 		return -ENODEV;
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL);
640*4882a593Smuzhiyun 	if (!otg)
641*4882a593Smuzhiyun 		return -ENOMEM;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	ddata->dev = &pdev->dev;
644*4882a593Smuzhiyun 	ddata->phy.dev = ddata->dev;
645*4882a593Smuzhiyun 	ddata->phy.label = "cpcap_usb_phy";
646*4882a593Smuzhiyun 	ddata->phy.otg = otg;
647*4882a593Smuzhiyun 	ddata->phy.type = USB_PHY_TYPE_USB2;
648*4882a593Smuzhiyun 	otg->set_host = cpcap_usb_phy_set_host;
649*4882a593Smuzhiyun 	otg->set_peripheral = cpcap_usb_phy_set_peripheral;
650*4882a593Smuzhiyun 	otg->usb_phy = &ddata->phy;
651*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&ddata->detect_work, cpcap_usb_detect);
652*4882a593Smuzhiyun 	platform_set_drvdata(pdev, ddata);
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun 	ddata->vusb = devm_regulator_get(&pdev->dev, "vusb");
655*4882a593Smuzhiyun 	if (IS_ERR(ddata->vusb))
656*4882a593Smuzhiyun 		return PTR_ERR(ddata->vusb);
657*4882a593Smuzhiyun 
658*4882a593Smuzhiyun 	error = regulator_enable(ddata->vusb);
659*4882a593Smuzhiyun 	if (error)
660*4882a593Smuzhiyun 		return error;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	generic_phy = devm_phy_create(ddata->dev, NULL, &ops);
663*4882a593Smuzhiyun 	if (IS_ERR(generic_phy)) {
664*4882a593Smuzhiyun 		error = PTR_ERR(generic_phy);
665*4882a593Smuzhiyun 		goto out_reg_disable;
666*4882a593Smuzhiyun 	}
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	phy_set_drvdata(generic_phy, ddata);
669*4882a593Smuzhiyun 
670*4882a593Smuzhiyun 	phy_provider = devm_of_phy_provider_register(ddata->dev,
671*4882a593Smuzhiyun 						     of_phy_simple_xlate);
672*4882a593Smuzhiyun 	if (IS_ERR(phy_provider)) {
673*4882a593Smuzhiyun 		error = PTR_ERR(phy_provider);
674*4882a593Smuzhiyun 		goto out_reg_disable;
675*4882a593Smuzhiyun 	}
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	error = cpcap_usb_init_optional_pins(ddata);
678*4882a593Smuzhiyun 	if (error)
679*4882a593Smuzhiyun 		goto out_reg_disable;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	cpcap_usb_init_optional_gpios(ddata);
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	error = cpcap_usb_init_iio(ddata);
684*4882a593Smuzhiyun 	if (error)
685*4882a593Smuzhiyun 		goto out_reg_disable;
686*4882a593Smuzhiyun 
687*4882a593Smuzhiyun 	error = cpcap_usb_init_interrupts(pdev, ddata);
688*4882a593Smuzhiyun 	if (error)
689*4882a593Smuzhiyun 		goto out_reg_disable;
690*4882a593Smuzhiyun 
691*4882a593Smuzhiyun 	usb_add_phy_dev(&ddata->phy);
692*4882a593Smuzhiyun 	atomic_set(&ddata->active, 1);
693*4882a593Smuzhiyun 	schedule_delayed_work(&ddata->detect_work, msecs_to_jiffies(1));
694*4882a593Smuzhiyun 
695*4882a593Smuzhiyun 	return 0;
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun out_reg_disable:
698*4882a593Smuzhiyun 	regulator_disable(ddata->vusb);
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	return error;
701*4882a593Smuzhiyun }
702*4882a593Smuzhiyun 
cpcap_usb_phy_remove(struct platform_device * pdev)703*4882a593Smuzhiyun static int cpcap_usb_phy_remove(struct platform_device *pdev)
704*4882a593Smuzhiyun {
705*4882a593Smuzhiyun 	struct cpcap_phy_ddata *ddata = platform_get_drvdata(pdev);
706*4882a593Smuzhiyun 	int error;
707*4882a593Smuzhiyun 
708*4882a593Smuzhiyun 	atomic_set(&ddata->active, 0);
709*4882a593Smuzhiyun 	error = cpcap_usb_set_uart_mode(ddata);
710*4882a593Smuzhiyun 	if (error)
711*4882a593Smuzhiyun 		dev_err(ddata->dev, "could not set UART mode\n");
712*4882a593Smuzhiyun 
713*4882a593Smuzhiyun 	cpcap_usb_try_musb_mailbox(ddata, MUSB_VBUS_OFF);
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	usb_remove_phy(&ddata->phy);
716*4882a593Smuzhiyun 	cancel_delayed_work_sync(&ddata->detect_work);
717*4882a593Smuzhiyun 	regulator_disable(ddata->vusb);
718*4882a593Smuzhiyun 
719*4882a593Smuzhiyun 	return 0;
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun 
722*4882a593Smuzhiyun static struct platform_driver cpcap_usb_phy_driver = {
723*4882a593Smuzhiyun 	.probe		= cpcap_usb_phy_probe,
724*4882a593Smuzhiyun 	.remove		= cpcap_usb_phy_remove,
725*4882a593Smuzhiyun 	.driver		= {
726*4882a593Smuzhiyun 		.name	= "cpcap-usb-phy",
727*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(cpcap_usb_phy_id_table),
728*4882a593Smuzhiyun 	},
729*4882a593Smuzhiyun };
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun module_platform_driver(cpcap_usb_phy_driver);
732*4882a593Smuzhiyun 
733*4882a593Smuzhiyun MODULE_ALIAS("platform:cpcap_usb");
734*4882a593Smuzhiyun MODULE_AUTHOR("Tony Lindgren <tony@atomide.com>");
735*4882a593Smuzhiyun MODULE_DESCRIPTION("CPCAP usb phy driver");
736*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
737