xref: /OK3568_Linux_fs/kernel/drivers/usb/phy/phy-twl6030-usb.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Author: Hema HK <hemahk@ti.com>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/interrupt.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/io.h>
15*4882a593Smuzhiyun #include <linux/usb/musb.h>
16*4882a593Smuzhiyun #include <linux/usb/phy_companion.h>
17*4882a593Smuzhiyun #include <linux/phy/omap_usb.h>
18*4882a593Smuzhiyun #include <linux/mfd/twl.h>
19*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
20*4882a593Smuzhiyun #include <linux/err.h>
21*4882a593Smuzhiyun #include <linux/slab.h>
22*4882a593Smuzhiyun #include <linux/delay.h>
23*4882a593Smuzhiyun #include <linux/of.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun /* usb register definitions */
26*4882a593Smuzhiyun #define USB_VENDOR_ID_LSB		0x00
27*4882a593Smuzhiyun #define USB_VENDOR_ID_MSB		0x01
28*4882a593Smuzhiyun #define USB_PRODUCT_ID_LSB		0x02
29*4882a593Smuzhiyun #define USB_PRODUCT_ID_MSB		0x03
30*4882a593Smuzhiyun #define USB_VBUS_CTRL_SET		0x04
31*4882a593Smuzhiyun #define USB_VBUS_CTRL_CLR		0x05
32*4882a593Smuzhiyun #define USB_ID_CTRL_SET			0x06
33*4882a593Smuzhiyun #define USB_ID_CTRL_CLR			0x07
34*4882a593Smuzhiyun #define USB_VBUS_INT_SRC		0x08
35*4882a593Smuzhiyun #define USB_VBUS_INT_LATCH_SET		0x09
36*4882a593Smuzhiyun #define USB_VBUS_INT_LATCH_CLR		0x0A
37*4882a593Smuzhiyun #define USB_VBUS_INT_EN_LO_SET		0x0B
38*4882a593Smuzhiyun #define USB_VBUS_INT_EN_LO_CLR		0x0C
39*4882a593Smuzhiyun #define USB_VBUS_INT_EN_HI_SET		0x0D
40*4882a593Smuzhiyun #define USB_VBUS_INT_EN_HI_CLR		0x0E
41*4882a593Smuzhiyun #define USB_ID_INT_SRC			0x0F
42*4882a593Smuzhiyun #define USB_ID_INT_LATCH_SET		0x10
43*4882a593Smuzhiyun #define USB_ID_INT_LATCH_CLR		0x11
44*4882a593Smuzhiyun 
45*4882a593Smuzhiyun #define USB_ID_INT_EN_LO_SET		0x12
46*4882a593Smuzhiyun #define USB_ID_INT_EN_LO_CLR		0x13
47*4882a593Smuzhiyun #define USB_ID_INT_EN_HI_SET		0x14
48*4882a593Smuzhiyun #define USB_ID_INT_EN_HI_CLR		0x15
49*4882a593Smuzhiyun #define USB_OTG_ADP_CTRL		0x16
50*4882a593Smuzhiyun #define USB_OTG_ADP_HIGH		0x17
51*4882a593Smuzhiyun #define USB_OTG_ADP_LOW			0x18
52*4882a593Smuzhiyun #define USB_OTG_ADP_RISE		0x19
53*4882a593Smuzhiyun #define USB_OTG_REVISION		0x1A
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun /* to be moved to LDO */
56*4882a593Smuzhiyun #define TWL6030_MISC2			0xE5
57*4882a593Smuzhiyun #define TWL6030_CFG_LDO_PD2		0xF5
58*4882a593Smuzhiyun #define TWL6030_BACKUP_REG		0xFA
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define STS_HW_CONDITIONS		0x21
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun /* In module TWL6030_MODULE_PM_MASTER */
63*4882a593Smuzhiyun #define STS_HW_CONDITIONS		0x21
64*4882a593Smuzhiyun #define STS_USB_ID			BIT(2)
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun /* In module TWL6030_MODULE_PM_RECEIVER */
67*4882a593Smuzhiyun #define VUSB_CFG_TRANS			0x71
68*4882a593Smuzhiyun #define VUSB_CFG_STATE			0x72
69*4882a593Smuzhiyun #define VUSB_CFG_VOLTAGE		0x73
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun /* in module TWL6030_MODULE_MAIN_CHARGE */
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun #define CHARGERUSB_CTRL1		0x8
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun #define CONTROLLER_STAT1		0x03
76*4882a593Smuzhiyun #define	VBUS_DET			BIT(2)
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun struct twl6030_usb {
79*4882a593Smuzhiyun 	struct phy_companion	comparator;
80*4882a593Smuzhiyun 	struct device		*dev;
81*4882a593Smuzhiyun 
82*4882a593Smuzhiyun 	/* for vbus reporting with irqs disabled */
83*4882a593Smuzhiyun 	spinlock_t		lock;
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun 	struct regulator		*usb3v3;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	/* used to check initial cable status after probe */
88*4882a593Smuzhiyun 	struct delayed_work	get_status_work;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	/* used to set vbus, in atomic path */
91*4882a593Smuzhiyun 	struct work_struct	set_vbus_work;
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	int			irq1;
94*4882a593Smuzhiyun 	int			irq2;
95*4882a593Smuzhiyun 	enum musb_vbus_id_status linkstat;
96*4882a593Smuzhiyun 	u8			asleep;
97*4882a593Smuzhiyun 	bool			vbus_enable;
98*4882a593Smuzhiyun };
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun #define	comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun /*-------------------------------------------------------------------------*/
103*4882a593Smuzhiyun 
twl6030_writeb(struct twl6030_usb * twl,u8 module,u8 data,u8 address)104*4882a593Smuzhiyun static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
105*4882a593Smuzhiyun 						u8 data, u8 address)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	int ret = 0;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	ret = twl_i2c_write_u8(module, data, address);
110*4882a593Smuzhiyun 	if (ret < 0)
111*4882a593Smuzhiyun 		dev_err(twl->dev,
112*4882a593Smuzhiyun 			"Write[0x%x] Error %d\n", address, ret);
113*4882a593Smuzhiyun 	return ret;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun 
twl6030_readb(struct twl6030_usb * twl,u8 module,u8 address)116*4882a593Smuzhiyun static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
117*4882a593Smuzhiyun {
118*4882a593Smuzhiyun 	u8 data;
119*4882a593Smuzhiyun 	int ret;
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	ret = twl_i2c_read_u8(module, &data, address);
122*4882a593Smuzhiyun 	if (ret >= 0)
123*4882a593Smuzhiyun 		ret = data;
124*4882a593Smuzhiyun 	else
125*4882a593Smuzhiyun 		dev_err(twl->dev,
126*4882a593Smuzhiyun 			"readb[0x%x,0x%x] Error %d\n",
127*4882a593Smuzhiyun 					module, address, ret);
128*4882a593Smuzhiyun 	return ret;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
twl6030_start_srp(struct phy_companion * comparator)131*4882a593Smuzhiyun static int twl6030_start_srp(struct phy_companion *comparator)
132*4882a593Smuzhiyun {
133*4882a593Smuzhiyun 	struct twl6030_usb *twl = comparator_to_twl(comparator);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
136*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	mdelay(100);
139*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR);
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
twl6030_usb_ldo_init(struct twl6030_usb * twl)144*4882a593Smuzhiyun static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
147*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_BACKUP_REG);
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	/* Program CFG_LDO_PD2 register and set VUSB bit */
150*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_CFG_LDO_PD2);
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	/* Program MISC2 register and set bit VUSB_IN_VBAT */
153*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2);
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	twl->usb3v3 = regulator_get(twl->dev, "usb");
156*4882a593Smuzhiyun 	if (IS_ERR(twl->usb3v3))
157*4882a593Smuzhiyun 		return -ENODEV;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	/* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
160*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	/*
163*4882a593Smuzhiyun 	 * Program the USB_ID_CTRL_SET register to enable GND drive
164*4882a593Smuzhiyun 	 * and the ID comparators
165*4882a593Smuzhiyun 	 */
166*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
167*4882a593Smuzhiyun 
168*4882a593Smuzhiyun 	return 0;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun 
vbus_show(struct device * dev,struct device_attribute * attr,char * buf)171*4882a593Smuzhiyun static ssize_t vbus_show(struct device *dev,
172*4882a593Smuzhiyun 			struct device_attribute *attr, char *buf)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct twl6030_usb *twl = dev_get_drvdata(dev);
175*4882a593Smuzhiyun 	unsigned long flags;
176*4882a593Smuzhiyun 	int ret = -EINVAL;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	spin_lock_irqsave(&twl->lock, flags);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	switch (twl->linkstat) {
181*4882a593Smuzhiyun 	case MUSB_VBUS_VALID:
182*4882a593Smuzhiyun 	       ret = snprintf(buf, PAGE_SIZE, "vbus\n");
183*4882a593Smuzhiyun 	       break;
184*4882a593Smuzhiyun 	case MUSB_ID_GROUND:
185*4882a593Smuzhiyun 	       ret = snprintf(buf, PAGE_SIZE, "id\n");
186*4882a593Smuzhiyun 	       break;
187*4882a593Smuzhiyun 	case MUSB_VBUS_OFF:
188*4882a593Smuzhiyun 	       ret = snprintf(buf, PAGE_SIZE, "none\n");
189*4882a593Smuzhiyun 	       break;
190*4882a593Smuzhiyun 	default:
191*4882a593Smuzhiyun 	       ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
192*4882a593Smuzhiyun 	}
193*4882a593Smuzhiyun 	spin_unlock_irqrestore(&twl->lock, flags);
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	return ret;
196*4882a593Smuzhiyun }
197*4882a593Smuzhiyun static DEVICE_ATTR_RO(vbus);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun static struct attribute *twl6030_attrs[] = {
200*4882a593Smuzhiyun 	&dev_attr_vbus.attr,
201*4882a593Smuzhiyun 	NULL,
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun ATTRIBUTE_GROUPS(twl6030);
204*4882a593Smuzhiyun 
twl6030_usb_irq(int irq,void * _twl)205*4882a593Smuzhiyun static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun 	struct twl6030_usb *twl = _twl;
208*4882a593Smuzhiyun 	enum musb_vbus_id_status status = MUSB_UNKNOWN;
209*4882a593Smuzhiyun 	u8 vbus_state, hw_state;
210*4882a593Smuzhiyun 	int ret;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
215*4882a593Smuzhiyun 						CONTROLLER_STAT1);
216*4882a593Smuzhiyun 	if (!(hw_state & STS_USB_ID)) {
217*4882a593Smuzhiyun 		if (vbus_state & VBUS_DET) {
218*4882a593Smuzhiyun 			ret = regulator_enable(twl->usb3v3);
219*4882a593Smuzhiyun 			if (ret)
220*4882a593Smuzhiyun 				dev_err(twl->dev, "Failed to enable usb3v3\n");
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 			twl->asleep = 1;
223*4882a593Smuzhiyun 			status = MUSB_VBUS_VALID;
224*4882a593Smuzhiyun 			twl->linkstat = status;
225*4882a593Smuzhiyun 			ret = musb_mailbox(status);
226*4882a593Smuzhiyun 			if (ret)
227*4882a593Smuzhiyun 				twl->linkstat = MUSB_UNKNOWN;
228*4882a593Smuzhiyun 		} else {
229*4882a593Smuzhiyun 			if (twl->linkstat != MUSB_UNKNOWN) {
230*4882a593Smuzhiyun 				status = MUSB_VBUS_OFF;
231*4882a593Smuzhiyun 				twl->linkstat = status;
232*4882a593Smuzhiyun 				ret = musb_mailbox(status);
233*4882a593Smuzhiyun 				if (ret)
234*4882a593Smuzhiyun 					twl->linkstat = MUSB_UNKNOWN;
235*4882a593Smuzhiyun 				if (twl->asleep) {
236*4882a593Smuzhiyun 					regulator_disable(twl->usb3v3);
237*4882a593Smuzhiyun 					twl->asleep = 0;
238*4882a593Smuzhiyun 				}
239*4882a593Smuzhiyun 			}
240*4882a593Smuzhiyun 		}
241*4882a593Smuzhiyun 	}
242*4882a593Smuzhiyun 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	return IRQ_HANDLED;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun 
twl6030_usbotg_irq(int irq,void * _twl)247*4882a593Smuzhiyun static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun 	struct twl6030_usb *twl = _twl;
250*4882a593Smuzhiyun 	enum musb_vbus_id_status status = MUSB_UNKNOWN;
251*4882a593Smuzhiyun 	u8 hw_state;
252*4882a593Smuzhiyun 	int ret;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	if (hw_state & STS_USB_ID) {
257*4882a593Smuzhiyun 		ret = regulator_enable(twl->usb3v3);
258*4882a593Smuzhiyun 		if (ret)
259*4882a593Smuzhiyun 			dev_err(twl->dev, "Failed to enable usb3v3\n");
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 		twl->asleep = 1;
262*4882a593Smuzhiyun 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
263*4882a593Smuzhiyun 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
264*4882a593Smuzhiyun 		status = MUSB_ID_GROUND;
265*4882a593Smuzhiyun 		twl->linkstat = status;
266*4882a593Smuzhiyun 		ret = musb_mailbox(status);
267*4882a593Smuzhiyun 		if (ret)
268*4882a593Smuzhiyun 			twl->linkstat = MUSB_UNKNOWN;
269*4882a593Smuzhiyun 	} else  {
270*4882a593Smuzhiyun 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
271*4882a593Smuzhiyun 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
272*4882a593Smuzhiyun 	}
273*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	return IRQ_HANDLED;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
twl6030_status_work(struct work_struct * work)278*4882a593Smuzhiyun static void twl6030_status_work(struct work_struct *work)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun 	struct twl6030_usb *twl = container_of(work, struct twl6030_usb,
281*4882a593Smuzhiyun 					       get_status_work.work);
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	twl6030_usb_irq(twl->irq2, twl);
284*4882a593Smuzhiyun 	twl6030_usbotg_irq(twl->irq1, twl);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun 
twl6030_enable_irq(struct twl6030_usb * twl)287*4882a593Smuzhiyun static int twl6030_enable_irq(struct twl6030_usb *twl)
288*4882a593Smuzhiyun {
289*4882a593Smuzhiyun 	twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
290*4882a593Smuzhiyun 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
291*4882a593Smuzhiyun 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
294*4882a593Smuzhiyun 				REG_INT_MSK_LINE_C);
295*4882a593Smuzhiyun 	twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
296*4882a593Smuzhiyun 				REG_INT_MSK_STS_C);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	return 0;
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
otg_set_vbus_work(struct work_struct * data)301*4882a593Smuzhiyun static void otg_set_vbus_work(struct work_struct *data)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
304*4882a593Smuzhiyun 								set_vbus_work);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	/*
307*4882a593Smuzhiyun 	 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
308*4882a593Smuzhiyun 	 * register. This enables boost mode.
309*4882a593Smuzhiyun 	 */
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	if (twl->vbus_enable)
312*4882a593Smuzhiyun 		twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x40,
313*4882a593Smuzhiyun 							CHARGERUSB_CTRL1);
314*4882a593Smuzhiyun 	else
315*4882a593Smuzhiyun 		twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x00,
316*4882a593Smuzhiyun 							CHARGERUSB_CTRL1);
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun 
twl6030_set_vbus(struct phy_companion * comparator,bool enabled)319*4882a593Smuzhiyun static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	struct twl6030_usb *twl = comparator_to_twl(comparator);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	twl->vbus_enable = enabled;
324*4882a593Smuzhiyun 	schedule_work(&twl->set_vbus_work);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun 
twl6030_usb_probe(struct platform_device * pdev)329*4882a593Smuzhiyun static int twl6030_usb_probe(struct platform_device *pdev)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun 	u32 ret;
332*4882a593Smuzhiyun 	struct twl6030_usb	*twl;
333*4882a593Smuzhiyun 	int			status, err;
334*4882a593Smuzhiyun 	struct device_node	*np = pdev->dev.of_node;
335*4882a593Smuzhiyun 	struct device		*dev = &pdev->dev;
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	if (!np) {
338*4882a593Smuzhiyun 		dev_err(dev, "no DT info\n");
339*4882a593Smuzhiyun 		return -EINVAL;
340*4882a593Smuzhiyun 	}
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun 	twl = devm_kzalloc(dev, sizeof(*twl), GFP_KERNEL);
343*4882a593Smuzhiyun 	if (!twl)
344*4882a593Smuzhiyun 		return -ENOMEM;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	twl->dev		= &pdev->dev;
347*4882a593Smuzhiyun 	twl->irq1		= platform_get_irq(pdev, 0);
348*4882a593Smuzhiyun 	twl->irq2		= platform_get_irq(pdev, 1);
349*4882a593Smuzhiyun 	twl->linkstat		= MUSB_UNKNOWN;
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	if (twl->irq1 < 0)
352*4882a593Smuzhiyun 		return twl->irq1;
353*4882a593Smuzhiyun 	if (twl->irq2 < 0)
354*4882a593Smuzhiyun 		return twl->irq2;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	twl->comparator.set_vbus	= twl6030_set_vbus;
357*4882a593Smuzhiyun 	twl->comparator.start_srp	= twl6030_start_srp;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	ret = omap_usb2_set_comparator(&twl->comparator);
360*4882a593Smuzhiyun 	if (ret == -ENODEV) {
361*4882a593Smuzhiyun 		dev_info(&pdev->dev, "phy not ready, deferring probe");
362*4882a593Smuzhiyun 		return -EPROBE_DEFER;
363*4882a593Smuzhiyun 	}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 	/* init spinlock for workqueue */
366*4882a593Smuzhiyun 	spin_lock_init(&twl->lock);
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	err = twl6030_usb_ldo_init(twl);
369*4882a593Smuzhiyun 	if (err) {
370*4882a593Smuzhiyun 		dev_err(&pdev->dev, "ldo init failed\n");
371*4882a593Smuzhiyun 		return err;
372*4882a593Smuzhiyun 	}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 	platform_set_drvdata(pdev, twl);
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
377*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&twl->get_status_work, twl6030_status_work);
378*4882a593Smuzhiyun 
379*4882a593Smuzhiyun 	status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
380*4882a593Smuzhiyun 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
381*4882a593Smuzhiyun 			"twl6030_usb", twl);
382*4882a593Smuzhiyun 	if (status < 0) {
383*4882a593Smuzhiyun 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
384*4882a593Smuzhiyun 			twl->irq1, status);
385*4882a593Smuzhiyun 		goto err_put_regulator;
386*4882a593Smuzhiyun 	}
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
389*4882a593Smuzhiyun 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
390*4882a593Smuzhiyun 			"twl6030_usb", twl);
391*4882a593Smuzhiyun 	if (status < 0) {
392*4882a593Smuzhiyun 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
393*4882a593Smuzhiyun 			twl->irq2, status);
394*4882a593Smuzhiyun 		goto err_free_irq1;
395*4882a593Smuzhiyun 	}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 	twl->asleep = 0;
398*4882a593Smuzhiyun 	twl6030_enable_irq(twl);
399*4882a593Smuzhiyun 	schedule_delayed_work(&twl->get_status_work, HZ);
400*4882a593Smuzhiyun 	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	return 0;
403*4882a593Smuzhiyun 
404*4882a593Smuzhiyun err_free_irq1:
405*4882a593Smuzhiyun 	free_irq(twl->irq1, twl);
406*4882a593Smuzhiyun err_put_regulator:
407*4882a593Smuzhiyun 	regulator_put(twl->usb3v3);
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return status;
410*4882a593Smuzhiyun }
411*4882a593Smuzhiyun 
twl6030_usb_remove(struct platform_device * pdev)412*4882a593Smuzhiyun static int twl6030_usb_remove(struct platform_device *pdev)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun 	struct twl6030_usb *twl = platform_get_drvdata(pdev);
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	cancel_delayed_work_sync(&twl->get_status_work);
417*4882a593Smuzhiyun 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
418*4882a593Smuzhiyun 		REG_INT_MSK_LINE_C);
419*4882a593Smuzhiyun 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
420*4882a593Smuzhiyun 			REG_INT_MSK_STS_C);
421*4882a593Smuzhiyun 	free_irq(twl->irq1, twl);
422*4882a593Smuzhiyun 	free_irq(twl->irq2, twl);
423*4882a593Smuzhiyun 	regulator_put(twl->usb3v3);
424*4882a593Smuzhiyun 	cancel_work_sync(&twl->set_vbus_work);
425*4882a593Smuzhiyun 
426*4882a593Smuzhiyun 	return 0;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun static const struct of_device_id twl6030_usb_id_table[] = {
430*4882a593Smuzhiyun 	{ .compatible = "ti,twl6030-usb" },
431*4882a593Smuzhiyun 	{}
432*4882a593Smuzhiyun };
433*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun static struct platform_driver twl6030_usb_driver = {
436*4882a593Smuzhiyun 	.probe		= twl6030_usb_probe,
437*4882a593Smuzhiyun 	.remove		= twl6030_usb_remove,
438*4882a593Smuzhiyun 	.driver		= {
439*4882a593Smuzhiyun 		.name	= "twl6030_usb",
440*4882a593Smuzhiyun 		.of_match_table = of_match_ptr(twl6030_usb_id_table),
441*4882a593Smuzhiyun 		.dev_groups = twl6030_groups,
442*4882a593Smuzhiyun 	},
443*4882a593Smuzhiyun };
444*4882a593Smuzhiyun 
twl6030_usb_init(void)445*4882a593Smuzhiyun static int __init twl6030_usb_init(void)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun 	return platform_driver_register(&twl6030_usb_driver);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun subsys_initcall(twl6030_usb_init);
450*4882a593Smuzhiyun 
twl6030_usb_exit(void)451*4882a593Smuzhiyun static void __exit twl6030_usb_exit(void)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	platform_driver_unregister(&twl6030_usb_driver);
454*4882a593Smuzhiyun }
455*4882a593Smuzhiyun module_exit(twl6030_usb_exit);
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun MODULE_ALIAS("platform:twl6030_usb");
458*4882a593Smuzhiyun MODULE_AUTHOR("Hema HK <hemahk@ti.com>");
459*4882a593Smuzhiyun MODULE_DESCRIPTION("TWL6030 USB transceiver driver");
460*4882a593Smuzhiyun MODULE_LICENSE("GPL");
461