15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
294ae9843SFelipe Balbi /*
394ae9843SFelipe Balbi  * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
494ae9843SFelipe Balbi  *
536774c5aSAlexander A. Klimov  * Copyright (C) 2010 Texas Instruments Incorporated - https://www.ti.com
694ae9843SFelipe Balbi  *
794ae9843SFelipe Balbi  * Author: Hema HK <hemahk@ti.com>
894ae9843SFelipe Balbi  */
994ae9843SFelipe Balbi 
1094ae9843SFelipe Balbi #include <linux/module.h>
1194ae9843SFelipe Balbi #include <linux/init.h>
1294ae9843SFelipe Balbi #include <linux/interrupt.h>
1394ae9843SFelipe Balbi #include <linux/platform_device.h>
1494ae9843SFelipe Balbi #include <linux/io.h>
158055555fSTony Lindgren #include <linux/usb/musb.h>
1694ae9843SFelipe Balbi #include <linux/usb/phy_companion.h>
176284be23SKishon Vijay Abraham I #include <linux/phy/omap_usb.h>
18a2054256SWolfram Sang #include <linux/mfd/twl.h>
1994ae9843SFelipe Balbi #include <linux/regulator/consumer.h>
2094ae9843SFelipe Balbi #include <linux/err.h>
2194ae9843SFelipe Balbi #include <linux/slab.h>
2294ae9843SFelipe Balbi #include <linux/delay.h>
2380d7d8a7SSachin Kamat #include <linux/of.h>
2494ae9843SFelipe Balbi 
2594ae9843SFelipe Balbi /* usb register definitions */
2694ae9843SFelipe Balbi #define USB_VENDOR_ID_LSB		0x00
2794ae9843SFelipe Balbi #define USB_VENDOR_ID_MSB		0x01
2894ae9843SFelipe Balbi #define USB_PRODUCT_ID_LSB		0x02
2994ae9843SFelipe Balbi #define USB_PRODUCT_ID_MSB		0x03
3094ae9843SFelipe Balbi #define USB_VBUS_CTRL_SET		0x04
3194ae9843SFelipe Balbi #define USB_VBUS_CTRL_CLR		0x05
3294ae9843SFelipe Balbi #define USB_ID_CTRL_SET			0x06
3394ae9843SFelipe Balbi #define USB_ID_CTRL_CLR			0x07
3494ae9843SFelipe Balbi #define USB_VBUS_INT_SRC		0x08
3594ae9843SFelipe Balbi #define USB_VBUS_INT_LATCH_SET		0x09
3694ae9843SFelipe Balbi #define USB_VBUS_INT_LATCH_CLR		0x0A
3794ae9843SFelipe Balbi #define USB_VBUS_INT_EN_LO_SET		0x0B
3894ae9843SFelipe Balbi #define USB_VBUS_INT_EN_LO_CLR		0x0C
3994ae9843SFelipe Balbi #define USB_VBUS_INT_EN_HI_SET		0x0D
4094ae9843SFelipe Balbi #define USB_VBUS_INT_EN_HI_CLR		0x0E
4194ae9843SFelipe Balbi #define USB_ID_INT_SRC			0x0F
4294ae9843SFelipe Balbi #define USB_ID_INT_LATCH_SET		0x10
4394ae9843SFelipe Balbi #define USB_ID_INT_LATCH_CLR		0x11
4494ae9843SFelipe Balbi 
4594ae9843SFelipe Balbi #define USB_ID_INT_EN_LO_SET		0x12
4694ae9843SFelipe Balbi #define USB_ID_INT_EN_LO_CLR		0x13
4794ae9843SFelipe Balbi #define USB_ID_INT_EN_HI_SET		0x14
4894ae9843SFelipe Balbi #define USB_ID_INT_EN_HI_CLR		0x15
4994ae9843SFelipe Balbi #define USB_OTG_ADP_CTRL		0x16
5094ae9843SFelipe Balbi #define USB_OTG_ADP_HIGH		0x17
5194ae9843SFelipe Balbi #define USB_OTG_ADP_LOW			0x18
5294ae9843SFelipe Balbi #define USB_OTG_ADP_RISE		0x19
5394ae9843SFelipe Balbi #define USB_OTG_REVISION		0x1A
5494ae9843SFelipe Balbi 
5594ae9843SFelipe Balbi /* to be moved to LDO */
5694ae9843SFelipe Balbi #define TWL6030_MISC2			0xE5
5794ae9843SFelipe Balbi #define TWL6030_CFG_LDO_PD2		0xF5
5894ae9843SFelipe Balbi #define TWL6030_BACKUP_REG		0xFA
5994ae9843SFelipe Balbi 
6094ae9843SFelipe Balbi #define STS_HW_CONDITIONS		0x21
6194ae9843SFelipe Balbi 
6294ae9843SFelipe Balbi /* In module TWL6030_MODULE_PM_MASTER */
6394ae9843SFelipe Balbi #define STS_HW_CONDITIONS		0x21
6494ae9843SFelipe Balbi #define STS_USB_ID			BIT(2)
6594ae9843SFelipe Balbi 
6694ae9843SFelipe Balbi /* In module TWL6030_MODULE_PM_RECEIVER */
6794ae9843SFelipe Balbi #define VUSB_CFG_TRANS			0x71
6894ae9843SFelipe Balbi #define VUSB_CFG_STATE			0x72
6994ae9843SFelipe Balbi #define VUSB_CFG_VOLTAGE		0x73
7094ae9843SFelipe Balbi 
7194ae9843SFelipe Balbi /* in module TWL6030_MODULE_MAIN_CHARGE */
7294ae9843SFelipe Balbi 
7394ae9843SFelipe Balbi #define CHARGERUSB_CTRL1		0x8
7494ae9843SFelipe Balbi 
7594ae9843SFelipe Balbi #define CONTROLLER_STAT1		0x03
7694ae9843SFelipe Balbi #define	VBUS_DET			BIT(2)
7794ae9843SFelipe Balbi 
7894ae9843SFelipe Balbi struct twl6030_usb {
7994ae9843SFelipe Balbi 	struct phy_companion	comparator;
8094ae9843SFelipe Balbi 	struct device		*dev;
8194ae9843SFelipe Balbi 
8294ae9843SFelipe Balbi 	/* for vbus reporting with irqs disabled */
8394ae9843SFelipe Balbi 	spinlock_t		lock;
8494ae9843SFelipe Balbi 
8594ae9843SFelipe Balbi 	struct regulator		*usb3v3;
8694ae9843SFelipe Balbi 
87b6a619a8STony Lindgren 	/* used to check initial cable status after probe */
88b6a619a8STony Lindgren 	struct delayed_work	get_status_work;
89b6a619a8STony Lindgren 
9094ae9843SFelipe Balbi 	/* used to set vbus, in atomic path */
9194ae9843SFelipe Balbi 	struct work_struct	set_vbus_work;
9294ae9843SFelipe Balbi 
9394ae9843SFelipe Balbi 	int			irq1;
9494ae9843SFelipe Balbi 	int			irq2;
958055555fSTony Lindgren 	enum musb_vbus_id_status linkstat;
9694ae9843SFelipe Balbi 	u8			asleep;
9794ae9843SFelipe Balbi 	bool			vbus_enable;
9894ae9843SFelipe Balbi };
9994ae9843SFelipe Balbi 
10094ae9843SFelipe Balbi #define	comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
10194ae9843SFelipe Balbi 
10294ae9843SFelipe Balbi /*-------------------------------------------------------------------------*/
10394ae9843SFelipe Balbi 
twl6030_writeb(struct twl6030_usb * twl,u8 module,u8 data,u8 address)10494ae9843SFelipe Balbi static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
10594ae9843SFelipe Balbi 						u8 data, u8 address)
10694ae9843SFelipe Balbi {
10794ae9843SFelipe Balbi 	int ret = 0;
10894ae9843SFelipe Balbi 
10994ae9843SFelipe Balbi 	ret = twl_i2c_write_u8(module, data, address);
11094ae9843SFelipe Balbi 	if (ret < 0)
11194ae9843SFelipe Balbi 		dev_err(twl->dev,
11294ae9843SFelipe Balbi 			"Write[0x%x] Error %d\n", address, ret);
11394ae9843SFelipe Balbi 	return ret;
11494ae9843SFelipe Balbi }
11594ae9843SFelipe Balbi 
twl6030_readb(struct twl6030_usb * twl,u8 module,u8 address)11694ae9843SFelipe Balbi static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
11794ae9843SFelipe Balbi {
1180b551490SDan Carpenter 	u8 data;
1190b551490SDan Carpenter 	int ret;
12094ae9843SFelipe Balbi 
12194ae9843SFelipe Balbi 	ret = twl_i2c_read_u8(module, &data, address);
12294ae9843SFelipe Balbi 	if (ret >= 0)
12394ae9843SFelipe Balbi 		ret = data;
12494ae9843SFelipe Balbi 	else
12594ae9843SFelipe Balbi 		dev_err(twl->dev,
12694ae9843SFelipe Balbi 			"readb[0x%x,0x%x] Error %d\n",
12794ae9843SFelipe Balbi 					module, address, ret);
12894ae9843SFelipe Balbi 	return ret;
12994ae9843SFelipe Balbi }
13094ae9843SFelipe Balbi 
twl6030_start_srp(struct phy_companion * comparator)13194ae9843SFelipe Balbi static int twl6030_start_srp(struct phy_companion *comparator)
13294ae9843SFelipe Balbi {
13394ae9843SFelipe Balbi 	struct twl6030_usb *twl = comparator_to_twl(comparator);
13494ae9843SFelipe Balbi 
13594ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
13694ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
13794ae9843SFelipe Balbi 
13894ae9843SFelipe Balbi 	mdelay(100);
13994ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR);
14094ae9843SFelipe Balbi 
14194ae9843SFelipe Balbi 	return 0;
14294ae9843SFelipe Balbi }
14394ae9843SFelipe Balbi 
twl6030_usb_ldo_init(struct twl6030_usb * twl)14494ae9843SFelipe Balbi static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
14594ae9843SFelipe Balbi {
14694ae9843SFelipe Balbi 	/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
14794ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_BACKUP_REG);
14894ae9843SFelipe Balbi 
14994ae9843SFelipe Balbi 	/* Program CFG_LDO_PD2 register and set VUSB bit */
15094ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_CFG_LDO_PD2);
15194ae9843SFelipe Balbi 
15294ae9843SFelipe Balbi 	/* Program MISC2 register and set bit VUSB_IN_VBAT */
15394ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2);
15494ae9843SFelipe Balbi 
1551ad528dbSNicolae Rosia 	twl->usb3v3 = regulator_get(twl->dev, "usb");
15694ae9843SFelipe Balbi 	if (IS_ERR(twl->usb3v3))
15794ae9843SFelipe Balbi 		return -ENODEV;
15894ae9843SFelipe Balbi 
15994ae9843SFelipe Balbi 	/* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
16094ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
16194ae9843SFelipe Balbi 
16294ae9843SFelipe Balbi 	/*
16394ae9843SFelipe Balbi 	 * Program the USB_ID_CTRL_SET register to enable GND drive
16494ae9843SFelipe Balbi 	 * and the ID comparators
16594ae9843SFelipe Balbi 	 */
16694ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
16794ae9843SFelipe Balbi 
16894ae9843SFelipe Balbi 	return 0;
16994ae9843SFelipe Balbi }
17094ae9843SFelipe Balbi 
vbus_show(struct device * dev,struct device_attribute * attr,char * buf)1717f26ee4bSGreg Kroah-Hartman static ssize_t vbus_show(struct device *dev,
17294ae9843SFelipe Balbi 			struct device_attribute *attr, char *buf)
17394ae9843SFelipe Balbi {
17494ae9843SFelipe Balbi 	struct twl6030_usb *twl = dev_get_drvdata(dev);
17594ae9843SFelipe Balbi 	unsigned long flags;
17694ae9843SFelipe Balbi 	int ret = -EINVAL;
17794ae9843SFelipe Balbi 
17894ae9843SFelipe Balbi 	spin_lock_irqsave(&twl->lock, flags);
17994ae9843SFelipe Balbi 
18094ae9843SFelipe Balbi 	switch (twl->linkstat) {
1818055555fSTony Lindgren 	case MUSB_VBUS_VALID:
18294ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "vbus\n");
18394ae9843SFelipe Balbi 	       break;
1848055555fSTony Lindgren 	case MUSB_ID_GROUND:
18594ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "id\n");
18694ae9843SFelipe Balbi 	       break;
1878055555fSTony Lindgren 	case MUSB_VBUS_OFF:
18894ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "none\n");
18994ae9843SFelipe Balbi 	       break;
19094ae9843SFelipe Balbi 	default:
19194ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
19294ae9843SFelipe Balbi 	}
19394ae9843SFelipe Balbi 	spin_unlock_irqrestore(&twl->lock, flags);
19494ae9843SFelipe Balbi 
19594ae9843SFelipe Balbi 	return ret;
19694ae9843SFelipe Balbi }
1977f26ee4bSGreg Kroah-Hartman static DEVICE_ATTR_RO(vbus);
19894ae9843SFelipe Balbi 
199891c1da6SGreg Kroah-Hartman static struct attribute *twl6030_attrs[] = {
200891c1da6SGreg Kroah-Hartman 	&dev_attr_vbus.attr,
201891c1da6SGreg Kroah-Hartman 	NULL,
202891c1da6SGreg Kroah-Hartman };
203891c1da6SGreg Kroah-Hartman ATTRIBUTE_GROUPS(twl6030);
204891c1da6SGreg Kroah-Hartman 
twl6030_usb_irq(int irq,void * _twl)20594ae9843SFelipe Balbi static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
20694ae9843SFelipe Balbi {
20794ae9843SFelipe Balbi 	struct twl6030_usb *twl = _twl;
2088055555fSTony Lindgren 	enum musb_vbus_id_status status = MUSB_UNKNOWN;
20994ae9843SFelipe Balbi 	u8 vbus_state, hw_state;
210bb54542cSFabio Baltieri 	int ret;
21194ae9843SFelipe Balbi 
21294ae9843SFelipe Balbi 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
21394ae9843SFelipe Balbi 
21494ae9843SFelipe Balbi 	vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
21594ae9843SFelipe Balbi 						CONTROLLER_STAT1);
21694ae9843SFelipe Balbi 	if (!(hw_state & STS_USB_ID)) {
21794ae9843SFelipe Balbi 		if (vbus_state & VBUS_DET) {
218bb54542cSFabio Baltieri 			ret = regulator_enable(twl->usb3v3);
219bb54542cSFabio Baltieri 			if (ret)
220bb54542cSFabio Baltieri 				dev_err(twl->dev, "Failed to enable usb3v3\n");
221bb54542cSFabio Baltieri 
22294ae9843SFelipe Balbi 			twl->asleep = 1;
2238055555fSTony Lindgren 			status = MUSB_VBUS_VALID;
22494ae9843SFelipe Balbi 			twl->linkstat = status;
22512b7db2bSTony Lindgren 			ret = musb_mailbox(status);
22612b7db2bSTony Lindgren 			if (ret)
22712b7db2bSTony Lindgren 				twl->linkstat = MUSB_UNKNOWN;
22894ae9843SFelipe Balbi 		} else {
2298055555fSTony Lindgren 			if (twl->linkstat != MUSB_UNKNOWN) {
2308055555fSTony Lindgren 				status = MUSB_VBUS_OFF;
23194ae9843SFelipe Balbi 				twl->linkstat = status;
23212b7db2bSTony Lindgren 				ret = musb_mailbox(status);
23312b7db2bSTony Lindgren 				if (ret)
23412b7db2bSTony Lindgren 					twl->linkstat = MUSB_UNKNOWN;
23594ae9843SFelipe Balbi 				if (twl->asleep) {
23694ae9843SFelipe Balbi 					regulator_disable(twl->usb3v3);
23794ae9843SFelipe Balbi 					twl->asleep = 0;
23894ae9843SFelipe Balbi 				}
23994ae9843SFelipe Balbi 			}
24094ae9843SFelipe Balbi 		}
24194ae9843SFelipe Balbi 	}
24294ae9843SFelipe Balbi 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
24394ae9843SFelipe Balbi 
24494ae9843SFelipe Balbi 	return IRQ_HANDLED;
24594ae9843SFelipe Balbi }
24694ae9843SFelipe Balbi 
twl6030_usbotg_irq(int irq,void * _twl)24794ae9843SFelipe Balbi static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
24894ae9843SFelipe Balbi {
24994ae9843SFelipe Balbi 	struct twl6030_usb *twl = _twl;
2508055555fSTony Lindgren 	enum musb_vbus_id_status status = MUSB_UNKNOWN;
25194ae9843SFelipe Balbi 	u8 hw_state;
252bb54542cSFabio Baltieri 	int ret;
25394ae9843SFelipe Balbi 
25494ae9843SFelipe Balbi 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
25594ae9843SFelipe Balbi 
25694ae9843SFelipe Balbi 	if (hw_state & STS_USB_ID) {
257bb54542cSFabio Baltieri 		ret = regulator_enable(twl->usb3v3);
258bb54542cSFabio Baltieri 		if (ret)
259bb54542cSFabio Baltieri 			dev_err(twl->dev, "Failed to enable usb3v3\n");
26094ae9843SFelipe Balbi 
26194ae9843SFelipe Balbi 		twl->asleep = 1;
26294ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
26394ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
2648055555fSTony Lindgren 		status = MUSB_ID_GROUND;
26594ae9843SFelipe Balbi 		twl->linkstat = status;
26612b7db2bSTony Lindgren 		ret = musb_mailbox(status);
26712b7db2bSTony Lindgren 		if (ret)
26812b7db2bSTony Lindgren 			twl->linkstat = MUSB_UNKNOWN;
26994ae9843SFelipe Balbi 	} else  {
27094ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
27194ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
27294ae9843SFelipe Balbi 	}
27394ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
27494ae9843SFelipe Balbi 
27594ae9843SFelipe Balbi 	return IRQ_HANDLED;
27694ae9843SFelipe Balbi }
27794ae9843SFelipe Balbi 
twl6030_status_work(struct work_struct * work)278b6a619a8STony Lindgren static void twl6030_status_work(struct work_struct *work)
279b6a619a8STony Lindgren {
280b6a619a8STony Lindgren 	struct twl6030_usb *twl = container_of(work, struct twl6030_usb,
281b6a619a8STony Lindgren 					       get_status_work.work);
282b6a619a8STony Lindgren 
283b6a619a8STony Lindgren 	twl6030_usb_irq(twl->irq2, twl);
284b6a619a8STony Lindgren 	twl6030_usbotg_irq(twl->irq1, twl);
285b6a619a8STony Lindgren }
286b6a619a8STony Lindgren 
twl6030_enable_irq(struct twl6030_usb * twl)28794ae9843SFelipe Balbi static int twl6030_enable_irq(struct twl6030_usb *twl)
28894ae9843SFelipe Balbi {
28994ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
29094ae9843SFelipe Balbi 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
29194ae9843SFelipe Balbi 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
29294ae9843SFelipe Balbi 
29394ae9843SFelipe Balbi 	twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
29494ae9843SFelipe Balbi 				REG_INT_MSK_LINE_C);
29594ae9843SFelipe Balbi 	twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
29694ae9843SFelipe Balbi 				REG_INT_MSK_STS_C);
29794ae9843SFelipe Balbi 
29894ae9843SFelipe Balbi 	return 0;
29994ae9843SFelipe Balbi }
30094ae9843SFelipe Balbi 
otg_set_vbus_work(struct work_struct * data)30194ae9843SFelipe Balbi static void otg_set_vbus_work(struct work_struct *data)
30294ae9843SFelipe Balbi {
30394ae9843SFelipe Balbi 	struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
30494ae9843SFelipe Balbi 								set_vbus_work);
30594ae9843SFelipe Balbi 
30694ae9843SFelipe Balbi 	/*
30794ae9843SFelipe Balbi 	 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
30894ae9843SFelipe Balbi 	 * register. This enables boost mode.
30994ae9843SFelipe Balbi 	 */
31094ae9843SFelipe Balbi 
31194ae9843SFelipe Balbi 	if (twl->vbus_enable)
31294ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x40,
31394ae9843SFelipe Balbi 							CHARGERUSB_CTRL1);
31494ae9843SFelipe Balbi 	else
31594ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x00,
31694ae9843SFelipe Balbi 							CHARGERUSB_CTRL1);
31794ae9843SFelipe Balbi }
31894ae9843SFelipe Balbi 
twl6030_set_vbus(struct phy_companion * comparator,bool enabled)31994ae9843SFelipe Balbi static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
32094ae9843SFelipe Balbi {
32194ae9843SFelipe Balbi 	struct twl6030_usb *twl = comparator_to_twl(comparator);
32294ae9843SFelipe Balbi 
32394ae9843SFelipe Balbi 	twl->vbus_enable = enabled;
32494ae9843SFelipe Balbi 	schedule_work(&twl->set_vbus_work);
32594ae9843SFelipe Balbi 
32694ae9843SFelipe Balbi 	return 0;
32794ae9843SFelipe Balbi }
32894ae9843SFelipe Balbi 
twl6030_usb_probe(struct platform_device * pdev)32994ae9843SFelipe Balbi static int twl6030_usb_probe(struct platform_device *pdev)
33094ae9843SFelipe Balbi {
33194ae9843SFelipe Balbi 	u32 ret;
33294ae9843SFelipe Balbi 	struct twl6030_usb	*twl;
33394ae9843SFelipe Balbi 	int			status, err;
33494ae9843SFelipe Balbi 	struct device_node	*np = pdev->dev.of_node;
33594ae9843SFelipe Balbi 	struct device		*dev = &pdev->dev;
3361ad528dbSNicolae Rosia 
3371ad528dbSNicolae Rosia 	if (!np) {
3381ad528dbSNicolae Rosia 		dev_err(dev, "no DT info\n");
3391ad528dbSNicolae Rosia 		return -EINVAL;
3401ad528dbSNicolae Rosia 	}
34194ae9843SFelipe Balbi 
3422ee8ff30SSachin Kamat 	twl = devm_kzalloc(dev, sizeof(*twl), GFP_KERNEL);
34394ae9843SFelipe Balbi 	if (!twl)
34494ae9843SFelipe Balbi 		return -ENOMEM;
34594ae9843SFelipe Balbi 
34694ae9843SFelipe Balbi 	twl->dev		= &pdev->dev;
34794ae9843SFelipe Balbi 	twl->irq1		= platform_get_irq(pdev, 0);
34894ae9843SFelipe Balbi 	twl->irq2		= platform_get_irq(pdev, 1);
3498055555fSTony Lindgren 	twl->linkstat		= MUSB_UNKNOWN;
35094ae9843SFelipe Balbi 
3510881e22cSSergey Shtylyov 	if (twl->irq1 < 0)
3520881e22cSSergey Shtylyov 		return twl->irq1;
3530881e22cSSergey Shtylyov 	if (twl->irq2 < 0)
3540881e22cSSergey Shtylyov 		return twl->irq2;
3550881e22cSSergey Shtylyov 
35694ae9843SFelipe Balbi 	twl->comparator.set_vbus	= twl6030_set_vbus;
35794ae9843SFelipe Balbi 	twl->comparator.start_srp	= twl6030_start_srp;
35894ae9843SFelipe Balbi 
35994ae9843SFelipe Balbi 	ret = omap_usb2_set_comparator(&twl->comparator);
36094ae9843SFelipe Balbi 	if (ret == -ENODEV) {
36194ae9843SFelipe Balbi 		dev_info(&pdev->dev, "phy not ready, deferring probe");
36294ae9843SFelipe Balbi 		return -EPROBE_DEFER;
36394ae9843SFelipe Balbi 	}
36494ae9843SFelipe Balbi 
36594ae9843SFelipe Balbi 	/* init spinlock for workqueue */
36694ae9843SFelipe Balbi 	spin_lock_init(&twl->lock);
36794ae9843SFelipe Balbi 
36894ae9843SFelipe Balbi 	err = twl6030_usb_ldo_init(twl);
36994ae9843SFelipe Balbi 	if (err) {
37094ae9843SFelipe Balbi 		dev_err(&pdev->dev, "ldo init failed\n");
37194ae9843SFelipe Balbi 		return err;
37294ae9843SFelipe Balbi 	}
37394ae9843SFelipe Balbi 
37494ae9843SFelipe Balbi 	platform_set_drvdata(pdev, twl);
37594ae9843SFelipe Balbi 
37694ae9843SFelipe Balbi 	INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
377b6a619a8STony Lindgren 	INIT_DELAYED_WORK(&twl->get_status_work, twl6030_status_work);
37894ae9843SFelipe Balbi 
37994ae9843SFelipe Balbi 	status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
38094ae9843SFelipe Balbi 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
38194ae9843SFelipe Balbi 			"twl6030_usb", twl);
38294ae9843SFelipe Balbi 	if (status < 0) {
38394ae9843SFelipe Balbi 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
38494ae9843SFelipe Balbi 			twl->irq1, status);
385f058764dSChristophe JAILLET 		goto err_put_regulator;
38694ae9843SFelipe Balbi 	}
38794ae9843SFelipe Balbi 
38894ae9843SFelipe Balbi 	status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
38994ae9843SFelipe Balbi 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
39094ae9843SFelipe Balbi 			"twl6030_usb", twl);
39194ae9843SFelipe Balbi 	if (status < 0) {
39294ae9843SFelipe Balbi 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
39394ae9843SFelipe Balbi 			twl->irq2, status);
394f058764dSChristophe JAILLET 		goto err_free_irq1;
39594ae9843SFelipe Balbi 	}
39694ae9843SFelipe Balbi 
39794ae9843SFelipe Balbi 	twl->asleep = 0;
39894ae9843SFelipe Balbi 	twl6030_enable_irq(twl);
399b6a619a8STony Lindgren 	schedule_delayed_work(&twl->get_status_work, HZ);
40094ae9843SFelipe Balbi 	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
40194ae9843SFelipe Balbi 
40294ae9843SFelipe Balbi 	return 0;
403f058764dSChristophe JAILLET 
404f058764dSChristophe JAILLET err_free_irq1:
405f058764dSChristophe JAILLET 	free_irq(twl->irq1, twl);
406f058764dSChristophe JAILLET err_put_regulator:
407f058764dSChristophe JAILLET 	regulator_put(twl->usb3v3);
408f058764dSChristophe JAILLET 
409f058764dSChristophe JAILLET 	return status;
41094ae9843SFelipe Balbi }
41194ae9843SFelipe Balbi 
twl6030_usb_remove(struct platform_device * pdev)412*17eb8190SUwe Kleine-König static void twl6030_usb_remove(struct platform_device *pdev)
41394ae9843SFelipe Balbi {
41494ae9843SFelipe Balbi 	struct twl6030_usb *twl = platform_get_drvdata(pdev);
41594ae9843SFelipe Balbi 
4165895d311SSven Van Asbroeck 	cancel_delayed_work_sync(&twl->get_status_work);
41794ae9843SFelipe Balbi 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
41894ae9843SFelipe Balbi 		REG_INT_MSK_LINE_C);
41994ae9843SFelipe Balbi 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
42094ae9843SFelipe Balbi 			REG_INT_MSK_STS_C);
42194ae9843SFelipe Balbi 	free_irq(twl->irq1, twl);
42294ae9843SFelipe Balbi 	free_irq(twl->irq2, twl);
42394ae9843SFelipe Balbi 	regulator_put(twl->usb3v3);
42494ae9843SFelipe Balbi 	cancel_work_sync(&twl->set_vbus_work);
42594ae9843SFelipe Balbi }
42694ae9843SFelipe Balbi 
42794ae9843SFelipe Balbi static const struct of_device_id twl6030_usb_id_table[] = {
42894ae9843SFelipe Balbi 	{ .compatible = "ti,twl6030-usb" },
42994ae9843SFelipe Balbi 	{}
43094ae9843SFelipe Balbi };
43194ae9843SFelipe Balbi MODULE_DEVICE_TABLE(of, twl6030_usb_id_table);
43294ae9843SFelipe Balbi 
43394ae9843SFelipe Balbi static struct platform_driver twl6030_usb_driver = {
43494ae9843SFelipe Balbi 	.probe		= twl6030_usb_probe,
435*17eb8190SUwe Kleine-König 	.remove_new	= twl6030_usb_remove,
43694ae9843SFelipe Balbi 	.driver		= {
43794ae9843SFelipe Balbi 		.name	= "twl6030_usb",
43894ae9843SFelipe Balbi 		.of_match_table = of_match_ptr(twl6030_usb_id_table),
439891c1da6SGreg Kroah-Hartman 		.dev_groups = twl6030_groups,
44094ae9843SFelipe Balbi 	},
44194ae9843SFelipe Balbi };
44294ae9843SFelipe Balbi 
twl6030_usb_init(void)44394ae9843SFelipe Balbi static int __init twl6030_usb_init(void)
44494ae9843SFelipe Balbi {
44594ae9843SFelipe Balbi 	return platform_driver_register(&twl6030_usb_driver);
44694ae9843SFelipe Balbi }
44794ae9843SFelipe Balbi subsys_initcall(twl6030_usb_init);
44894ae9843SFelipe Balbi 
twl6030_usb_exit(void)44994ae9843SFelipe Balbi static void __exit twl6030_usb_exit(void)
45094ae9843SFelipe Balbi {
45194ae9843SFelipe Balbi 	platform_driver_unregister(&twl6030_usb_driver);
45294ae9843SFelipe Balbi }
45394ae9843SFelipe Balbi module_exit(twl6030_usb_exit);
45494ae9843SFelipe Balbi 
45594ae9843SFelipe Balbi MODULE_ALIAS("platform:twl6030_usb");
45694ae9843SFelipe Balbi MODULE_AUTHOR("Hema HK <hemahk@ti.com>");
45794ae9843SFelipe Balbi MODULE_DESCRIPTION("TWL6030 USB transceiver driver");
45894ae9843SFelipe Balbi MODULE_LICENSE("GPL");
459