194ae9843SFelipe Balbi /*
294ae9843SFelipe Balbi  * twl6030_usb - TWL6030 USB transceiver, talking to OMAP OTG driver.
394ae9843SFelipe Balbi  *
494ae9843SFelipe Balbi  * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com
594ae9843SFelipe Balbi  * This program is free software; you can redistribute it and/or modify
694ae9843SFelipe Balbi  * it under the terms of the GNU General Public License as published by
794ae9843SFelipe Balbi  * the Free Software Foundation; either version 2 of the License, or
894ae9843SFelipe Balbi  * (at your option) any later version.
994ae9843SFelipe Balbi  *
1094ae9843SFelipe Balbi  * Author: Hema HK <hemahk@ti.com>
1194ae9843SFelipe Balbi  *
1294ae9843SFelipe Balbi  * This program is distributed in the hope that it will be useful,
1394ae9843SFelipe Balbi  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1494ae9843SFelipe Balbi  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1594ae9843SFelipe Balbi  * GNU General Public License for more details.
1694ae9843SFelipe Balbi  *
1794ae9843SFelipe Balbi  * You should have received a copy of the GNU General Public License
1894ae9843SFelipe Balbi  * along with this program; if not, write to the Free Software
1994ae9843SFelipe Balbi  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2094ae9843SFelipe Balbi  *
2194ae9843SFelipe Balbi  */
2294ae9843SFelipe Balbi 
2394ae9843SFelipe Balbi #include <linux/module.h>
2494ae9843SFelipe Balbi #include <linux/init.h>
2594ae9843SFelipe Balbi #include <linux/interrupt.h>
2694ae9843SFelipe Balbi #include <linux/platform_device.h>
2794ae9843SFelipe Balbi #include <linux/io.h>
288055555fSTony Lindgren #include <linux/usb/musb.h>
2994ae9843SFelipe Balbi #include <linux/usb/phy_companion.h>
306284be23SKishon Vijay Abraham I #include <linux/phy/omap_usb.h>
3194ae9843SFelipe Balbi #include <linux/i2c/twl.h>
3294ae9843SFelipe Balbi #include <linux/regulator/consumer.h>
3394ae9843SFelipe Balbi #include <linux/err.h>
3494ae9843SFelipe Balbi #include <linux/slab.h>
3594ae9843SFelipe Balbi #include <linux/delay.h>
3680d7d8a7SSachin Kamat #include <linux/of.h>
3794ae9843SFelipe Balbi 
3894ae9843SFelipe Balbi /* usb register definitions */
3994ae9843SFelipe Balbi #define USB_VENDOR_ID_LSB		0x00
4094ae9843SFelipe Balbi #define USB_VENDOR_ID_MSB		0x01
4194ae9843SFelipe Balbi #define USB_PRODUCT_ID_LSB		0x02
4294ae9843SFelipe Balbi #define USB_PRODUCT_ID_MSB		0x03
4394ae9843SFelipe Balbi #define USB_VBUS_CTRL_SET		0x04
4494ae9843SFelipe Balbi #define USB_VBUS_CTRL_CLR		0x05
4594ae9843SFelipe Balbi #define USB_ID_CTRL_SET			0x06
4694ae9843SFelipe Balbi #define USB_ID_CTRL_CLR			0x07
4794ae9843SFelipe Balbi #define USB_VBUS_INT_SRC		0x08
4894ae9843SFelipe Balbi #define USB_VBUS_INT_LATCH_SET		0x09
4994ae9843SFelipe Balbi #define USB_VBUS_INT_LATCH_CLR		0x0A
5094ae9843SFelipe Balbi #define USB_VBUS_INT_EN_LO_SET		0x0B
5194ae9843SFelipe Balbi #define USB_VBUS_INT_EN_LO_CLR		0x0C
5294ae9843SFelipe Balbi #define USB_VBUS_INT_EN_HI_SET		0x0D
5394ae9843SFelipe Balbi #define USB_VBUS_INT_EN_HI_CLR		0x0E
5494ae9843SFelipe Balbi #define USB_ID_INT_SRC			0x0F
5594ae9843SFelipe Balbi #define USB_ID_INT_LATCH_SET		0x10
5694ae9843SFelipe Balbi #define USB_ID_INT_LATCH_CLR		0x11
5794ae9843SFelipe Balbi 
5894ae9843SFelipe Balbi #define USB_ID_INT_EN_LO_SET		0x12
5994ae9843SFelipe Balbi #define USB_ID_INT_EN_LO_CLR		0x13
6094ae9843SFelipe Balbi #define USB_ID_INT_EN_HI_SET		0x14
6194ae9843SFelipe Balbi #define USB_ID_INT_EN_HI_CLR		0x15
6294ae9843SFelipe Balbi #define USB_OTG_ADP_CTRL		0x16
6394ae9843SFelipe Balbi #define USB_OTG_ADP_HIGH		0x17
6494ae9843SFelipe Balbi #define USB_OTG_ADP_LOW			0x18
6594ae9843SFelipe Balbi #define USB_OTG_ADP_RISE		0x19
6694ae9843SFelipe Balbi #define USB_OTG_REVISION		0x1A
6794ae9843SFelipe Balbi 
6894ae9843SFelipe Balbi /* to be moved to LDO */
6994ae9843SFelipe Balbi #define TWL6030_MISC2			0xE5
7094ae9843SFelipe Balbi #define TWL6030_CFG_LDO_PD2		0xF5
7194ae9843SFelipe Balbi #define TWL6030_BACKUP_REG		0xFA
7294ae9843SFelipe Balbi 
7394ae9843SFelipe Balbi #define STS_HW_CONDITIONS		0x21
7494ae9843SFelipe Balbi 
7594ae9843SFelipe Balbi /* In module TWL6030_MODULE_PM_MASTER */
7694ae9843SFelipe Balbi #define STS_HW_CONDITIONS		0x21
7794ae9843SFelipe Balbi #define STS_USB_ID			BIT(2)
7894ae9843SFelipe Balbi 
7994ae9843SFelipe Balbi /* In module TWL6030_MODULE_PM_RECEIVER */
8094ae9843SFelipe Balbi #define VUSB_CFG_TRANS			0x71
8194ae9843SFelipe Balbi #define VUSB_CFG_STATE			0x72
8294ae9843SFelipe Balbi #define VUSB_CFG_VOLTAGE		0x73
8394ae9843SFelipe Balbi 
8494ae9843SFelipe Balbi /* in module TWL6030_MODULE_MAIN_CHARGE */
8594ae9843SFelipe Balbi 
8694ae9843SFelipe Balbi #define CHARGERUSB_CTRL1		0x8
8794ae9843SFelipe Balbi 
8894ae9843SFelipe Balbi #define CONTROLLER_STAT1		0x03
8994ae9843SFelipe Balbi #define	VBUS_DET			BIT(2)
9094ae9843SFelipe Balbi 
9194ae9843SFelipe Balbi struct twl6030_usb {
9294ae9843SFelipe Balbi 	struct phy_companion	comparator;
9394ae9843SFelipe Balbi 	struct device		*dev;
9494ae9843SFelipe Balbi 
9594ae9843SFelipe Balbi 	/* for vbus reporting with irqs disabled */
9694ae9843SFelipe Balbi 	spinlock_t		lock;
9794ae9843SFelipe Balbi 
9894ae9843SFelipe Balbi 	struct regulator		*usb3v3;
9994ae9843SFelipe Balbi 
10094ae9843SFelipe Balbi 	/* used to set vbus, in atomic path */
10194ae9843SFelipe Balbi 	struct work_struct	set_vbus_work;
10294ae9843SFelipe Balbi 
10394ae9843SFelipe Balbi 	int			irq1;
10494ae9843SFelipe Balbi 	int			irq2;
1058055555fSTony Lindgren 	enum musb_vbus_id_status linkstat;
10694ae9843SFelipe Balbi 	u8			asleep;
10794ae9843SFelipe Balbi 	bool			vbus_enable;
10894ae9843SFelipe Balbi 	const char		*regulator;
10994ae9843SFelipe Balbi };
11094ae9843SFelipe Balbi 
11194ae9843SFelipe Balbi #define	comparator_to_twl(x) container_of((x), struct twl6030_usb, comparator)
11294ae9843SFelipe Balbi 
11394ae9843SFelipe Balbi /*-------------------------------------------------------------------------*/
11494ae9843SFelipe Balbi 
11594ae9843SFelipe Balbi static inline int twl6030_writeb(struct twl6030_usb *twl, u8 module,
11694ae9843SFelipe Balbi 						u8 data, u8 address)
11794ae9843SFelipe Balbi {
11894ae9843SFelipe Balbi 	int ret = 0;
11994ae9843SFelipe Balbi 
12094ae9843SFelipe Balbi 	ret = twl_i2c_write_u8(module, data, address);
12194ae9843SFelipe Balbi 	if (ret < 0)
12294ae9843SFelipe Balbi 		dev_err(twl->dev,
12394ae9843SFelipe Balbi 			"Write[0x%x] Error %d\n", address, ret);
12494ae9843SFelipe Balbi 	return ret;
12594ae9843SFelipe Balbi }
12694ae9843SFelipe Balbi 
12794ae9843SFelipe Balbi static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
12894ae9843SFelipe Balbi {
1290b551490SDan Carpenter 	u8 data;
1300b551490SDan Carpenter 	int ret;
13194ae9843SFelipe Balbi 
13294ae9843SFelipe Balbi 	ret = twl_i2c_read_u8(module, &data, address);
13394ae9843SFelipe Balbi 	if (ret >= 0)
13494ae9843SFelipe Balbi 		ret = data;
13594ae9843SFelipe Balbi 	else
13694ae9843SFelipe Balbi 		dev_err(twl->dev,
13794ae9843SFelipe Balbi 			"readb[0x%x,0x%x] Error %d\n",
13894ae9843SFelipe Balbi 					module, address, ret);
13994ae9843SFelipe Balbi 	return ret;
14094ae9843SFelipe Balbi }
14194ae9843SFelipe Balbi 
14294ae9843SFelipe Balbi static int twl6030_start_srp(struct phy_companion *comparator)
14394ae9843SFelipe Balbi {
14494ae9843SFelipe Balbi 	struct twl6030_usb *twl = comparator_to_twl(comparator);
14594ae9843SFelipe Balbi 
14694ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
14794ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
14894ae9843SFelipe Balbi 
14994ae9843SFelipe Balbi 	mdelay(100);
15094ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0xa0, USB_VBUS_CTRL_CLR);
15194ae9843SFelipe Balbi 
15294ae9843SFelipe Balbi 	return 0;
15394ae9843SFelipe Balbi }
15494ae9843SFelipe Balbi 
15594ae9843SFelipe Balbi static int twl6030_usb_ldo_init(struct twl6030_usb *twl)
15694ae9843SFelipe Balbi {
15794ae9843SFelipe Balbi 	/* Set to OTG_REV 1.3 and turn on the ID_WAKEUP_COMP */
15894ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_BACKUP_REG);
15994ae9843SFelipe Balbi 
16094ae9843SFelipe Balbi 	/* Program CFG_LDO_PD2 register and set VUSB bit */
16194ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x1, TWL6030_CFG_LDO_PD2);
16294ae9843SFelipe Balbi 
16394ae9843SFelipe Balbi 	/* Program MISC2 register and set bit VUSB_IN_VBAT */
16494ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL6030_MODULE_ID0, 0x10, TWL6030_MISC2);
16594ae9843SFelipe Balbi 
16694ae9843SFelipe Balbi 	twl->usb3v3 = regulator_get(twl->dev, twl->regulator);
16794ae9843SFelipe Balbi 	if (IS_ERR(twl->usb3v3))
16894ae9843SFelipe Balbi 		return -ENODEV;
16994ae9843SFelipe Balbi 
17094ae9843SFelipe Balbi 	/* Program the USB_VBUS_CTRL_SET and set VBUS_ACT_COMP bit */
17194ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x4, USB_VBUS_CTRL_SET);
17294ae9843SFelipe Balbi 
17394ae9843SFelipe Balbi 	/*
17494ae9843SFelipe Balbi 	 * Program the USB_ID_CTRL_SET register to enable GND drive
17594ae9843SFelipe Balbi 	 * and the ID comparators
17694ae9843SFelipe Balbi 	 */
17794ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x14, USB_ID_CTRL_SET);
17894ae9843SFelipe Balbi 
17994ae9843SFelipe Balbi 	return 0;
18094ae9843SFelipe Balbi }
18194ae9843SFelipe Balbi 
18294ae9843SFelipe Balbi static ssize_t twl6030_usb_vbus_show(struct device *dev,
18394ae9843SFelipe Balbi 			struct device_attribute *attr, char *buf)
18494ae9843SFelipe Balbi {
18594ae9843SFelipe Balbi 	struct twl6030_usb *twl = dev_get_drvdata(dev);
18694ae9843SFelipe Balbi 	unsigned long flags;
18794ae9843SFelipe Balbi 	int ret = -EINVAL;
18894ae9843SFelipe Balbi 
18994ae9843SFelipe Balbi 	spin_lock_irqsave(&twl->lock, flags);
19094ae9843SFelipe Balbi 
19194ae9843SFelipe Balbi 	switch (twl->linkstat) {
1928055555fSTony Lindgren 	case MUSB_VBUS_VALID:
19394ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "vbus\n");
19494ae9843SFelipe Balbi 	       break;
1958055555fSTony Lindgren 	case MUSB_ID_GROUND:
19694ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "id\n");
19794ae9843SFelipe Balbi 	       break;
1988055555fSTony Lindgren 	case MUSB_VBUS_OFF:
19994ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "none\n");
20094ae9843SFelipe Balbi 	       break;
20194ae9843SFelipe Balbi 	default:
20294ae9843SFelipe Balbi 	       ret = snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
20394ae9843SFelipe Balbi 	}
20494ae9843SFelipe Balbi 	spin_unlock_irqrestore(&twl->lock, flags);
20594ae9843SFelipe Balbi 
20694ae9843SFelipe Balbi 	return ret;
20794ae9843SFelipe Balbi }
20894ae9843SFelipe Balbi static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
20994ae9843SFelipe Balbi 
21094ae9843SFelipe Balbi static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
21194ae9843SFelipe Balbi {
21294ae9843SFelipe Balbi 	struct twl6030_usb *twl = _twl;
2138055555fSTony Lindgren 	enum musb_vbus_id_status status = MUSB_UNKNOWN;
21494ae9843SFelipe Balbi 	u8 vbus_state, hw_state;
215bb54542cSFabio Baltieri 	int ret;
21694ae9843SFelipe Balbi 
21794ae9843SFelipe Balbi 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
21894ae9843SFelipe Balbi 
21994ae9843SFelipe Balbi 	vbus_state = twl6030_readb(twl, TWL_MODULE_MAIN_CHARGE,
22094ae9843SFelipe Balbi 						CONTROLLER_STAT1);
22194ae9843SFelipe Balbi 	if (!(hw_state & STS_USB_ID)) {
22294ae9843SFelipe Balbi 		if (vbus_state & VBUS_DET) {
223bb54542cSFabio Baltieri 			ret = regulator_enable(twl->usb3v3);
224bb54542cSFabio Baltieri 			if (ret)
225bb54542cSFabio Baltieri 				dev_err(twl->dev, "Failed to enable usb3v3\n");
226bb54542cSFabio Baltieri 
22794ae9843SFelipe Balbi 			twl->asleep = 1;
2288055555fSTony Lindgren 			status = MUSB_VBUS_VALID;
22994ae9843SFelipe Balbi 			twl->linkstat = status;
23012b7db2bSTony Lindgren 			ret = musb_mailbox(status);
23112b7db2bSTony Lindgren 			if (ret)
23212b7db2bSTony Lindgren 				twl->linkstat = MUSB_UNKNOWN;
23394ae9843SFelipe Balbi 		} else {
2348055555fSTony Lindgren 			if (twl->linkstat != MUSB_UNKNOWN) {
2358055555fSTony Lindgren 				status = MUSB_VBUS_OFF;
23694ae9843SFelipe Balbi 				twl->linkstat = status;
23712b7db2bSTony Lindgren 				ret = musb_mailbox(status);
23812b7db2bSTony Lindgren 				if (ret)
23912b7db2bSTony Lindgren 					twl->linkstat = MUSB_UNKNOWN;
24094ae9843SFelipe Balbi 				if (twl->asleep) {
24194ae9843SFelipe Balbi 					regulator_disable(twl->usb3v3);
24294ae9843SFelipe Balbi 					twl->asleep = 0;
24394ae9843SFelipe Balbi 				}
24494ae9843SFelipe Balbi 			}
24594ae9843SFelipe Balbi 		}
24694ae9843SFelipe Balbi 	}
24794ae9843SFelipe Balbi 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
24894ae9843SFelipe Balbi 
24994ae9843SFelipe Balbi 	return IRQ_HANDLED;
25094ae9843SFelipe Balbi }
25194ae9843SFelipe Balbi 
25294ae9843SFelipe Balbi static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
25394ae9843SFelipe Balbi {
25494ae9843SFelipe Balbi 	struct twl6030_usb *twl = _twl;
2558055555fSTony Lindgren 	enum musb_vbus_id_status status = MUSB_UNKNOWN;
25694ae9843SFelipe Balbi 	u8 hw_state;
257bb54542cSFabio Baltieri 	int ret;
25894ae9843SFelipe Balbi 
25994ae9843SFelipe Balbi 	hw_state = twl6030_readb(twl, TWL6030_MODULE_ID0, STS_HW_CONDITIONS);
26094ae9843SFelipe Balbi 
26194ae9843SFelipe Balbi 	if (hw_state & STS_USB_ID) {
262bb54542cSFabio Baltieri 		ret = regulator_enable(twl->usb3v3);
263bb54542cSFabio Baltieri 		if (ret)
264bb54542cSFabio Baltieri 			dev_err(twl->dev, "Failed to enable usb3v3\n");
26594ae9843SFelipe Balbi 
26694ae9843SFelipe Balbi 		twl->asleep = 1;
26794ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_CLR);
26894ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_SET);
2698055555fSTony Lindgren 		status = MUSB_ID_GROUND;
27094ae9843SFelipe Balbi 		twl->linkstat = status;
27112b7db2bSTony Lindgren 		ret = musb_mailbox(status);
27212b7db2bSTony Lindgren 		if (ret)
27312b7db2bSTony Lindgren 			twl->linkstat = MUSB_UNKNOWN;
27494ae9843SFelipe Balbi 	} else  {
27594ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x10, USB_ID_INT_EN_HI_CLR);
27694ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
27794ae9843SFelipe Balbi 	}
27894ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, status, USB_ID_INT_LATCH_CLR);
27994ae9843SFelipe Balbi 
28094ae9843SFelipe Balbi 	return IRQ_HANDLED;
28194ae9843SFelipe Balbi }
28294ae9843SFelipe Balbi 
28394ae9843SFelipe Balbi static int twl6030_enable_irq(struct twl6030_usb *twl)
28494ae9843SFelipe Balbi {
28594ae9843SFelipe Balbi 	twl6030_writeb(twl, TWL_MODULE_USB, 0x1, USB_ID_INT_EN_HI_SET);
28694ae9843SFelipe Balbi 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
28794ae9843SFelipe Balbi 	twl6030_interrupt_unmask(0x05, REG_INT_MSK_STS_C);
28894ae9843SFelipe Balbi 
28994ae9843SFelipe Balbi 	twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
29094ae9843SFelipe Balbi 				REG_INT_MSK_LINE_C);
29194ae9843SFelipe Balbi 	twl6030_interrupt_unmask(TWL6030_CHARGER_CTRL_INT_MASK,
29294ae9843SFelipe Balbi 				REG_INT_MSK_STS_C);
29394ae9843SFelipe Balbi 	twl6030_usb_irq(twl->irq2, twl);
29494ae9843SFelipe Balbi 	twl6030_usbotg_irq(twl->irq1, twl);
29594ae9843SFelipe Balbi 
29694ae9843SFelipe Balbi 	return 0;
29794ae9843SFelipe Balbi }
29894ae9843SFelipe Balbi 
29994ae9843SFelipe Balbi static void otg_set_vbus_work(struct work_struct *data)
30094ae9843SFelipe Balbi {
30194ae9843SFelipe Balbi 	struct twl6030_usb *twl = container_of(data, struct twl6030_usb,
30294ae9843SFelipe Balbi 								set_vbus_work);
30394ae9843SFelipe Balbi 
30494ae9843SFelipe Balbi 	/*
30594ae9843SFelipe Balbi 	 * Start driving VBUS. Set OPA_MODE bit in CHARGERUSB_CTRL1
30694ae9843SFelipe Balbi 	 * register. This enables boost mode.
30794ae9843SFelipe Balbi 	 */
30894ae9843SFelipe Balbi 
30994ae9843SFelipe Balbi 	if (twl->vbus_enable)
31094ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x40,
31194ae9843SFelipe Balbi 							CHARGERUSB_CTRL1);
31294ae9843SFelipe Balbi 	else
31394ae9843SFelipe Balbi 		twl6030_writeb(twl, TWL_MODULE_MAIN_CHARGE, 0x00,
31494ae9843SFelipe Balbi 							CHARGERUSB_CTRL1);
31594ae9843SFelipe Balbi }
31694ae9843SFelipe Balbi 
31794ae9843SFelipe Balbi static int twl6030_set_vbus(struct phy_companion *comparator, bool enabled)
31894ae9843SFelipe Balbi {
31994ae9843SFelipe Balbi 	struct twl6030_usb *twl = comparator_to_twl(comparator);
32094ae9843SFelipe Balbi 
32194ae9843SFelipe Balbi 	twl->vbus_enable = enabled;
32294ae9843SFelipe Balbi 	schedule_work(&twl->set_vbus_work);
32394ae9843SFelipe Balbi 
32494ae9843SFelipe Balbi 	return 0;
32594ae9843SFelipe Balbi }
32694ae9843SFelipe Balbi 
32794ae9843SFelipe Balbi static int twl6030_usb_probe(struct platform_device *pdev)
32894ae9843SFelipe Balbi {
32994ae9843SFelipe Balbi 	u32 ret;
33094ae9843SFelipe Balbi 	struct twl6030_usb	*twl;
33194ae9843SFelipe Balbi 	int			status, err;
33294ae9843SFelipe Balbi 	struct device_node	*np = pdev->dev.of_node;
33394ae9843SFelipe Balbi 	struct device		*dev = &pdev->dev;
33419f9e188SJingoo Han 	struct twl4030_usb_data	*pdata = dev_get_platdata(dev);
33594ae9843SFelipe Balbi 
3362ee8ff30SSachin Kamat 	twl = devm_kzalloc(dev, sizeof(*twl), GFP_KERNEL);
33794ae9843SFelipe Balbi 	if (!twl)
33894ae9843SFelipe Balbi 		return -ENOMEM;
33994ae9843SFelipe Balbi 
34094ae9843SFelipe Balbi 	twl->dev		= &pdev->dev;
34194ae9843SFelipe Balbi 	twl->irq1		= platform_get_irq(pdev, 0);
34294ae9843SFelipe Balbi 	twl->irq2		= platform_get_irq(pdev, 1);
3438055555fSTony Lindgren 	twl->linkstat		= MUSB_UNKNOWN;
34494ae9843SFelipe Balbi 
34594ae9843SFelipe Balbi 	twl->comparator.set_vbus	= twl6030_set_vbus;
34694ae9843SFelipe Balbi 	twl->comparator.start_srp	= twl6030_start_srp;
34794ae9843SFelipe Balbi 
34894ae9843SFelipe Balbi 	ret = omap_usb2_set_comparator(&twl->comparator);
34994ae9843SFelipe Balbi 	if (ret == -ENODEV) {
35094ae9843SFelipe Balbi 		dev_info(&pdev->dev, "phy not ready, deferring probe");
35194ae9843SFelipe Balbi 		return -EPROBE_DEFER;
35294ae9843SFelipe Balbi 	}
35394ae9843SFelipe Balbi 
35494ae9843SFelipe Balbi 	if (np) {
35594ae9843SFelipe Balbi 		twl->regulator = "usb";
35694ae9843SFelipe Balbi 	} else if (pdata) {
35789ce43fbSGraeme Gregory 		if (pdata->features & TWL6032_SUBCLASS)
35894ae9843SFelipe Balbi 			twl->regulator = "ldousb";
35994ae9843SFelipe Balbi 		else
36094ae9843SFelipe Balbi 			twl->regulator = "vusb";
36194ae9843SFelipe Balbi 	} else {
36294ae9843SFelipe Balbi 		dev_err(&pdev->dev, "twl6030 initialized without pdata\n");
36394ae9843SFelipe Balbi 		return -EINVAL;
36494ae9843SFelipe Balbi 	}
36594ae9843SFelipe Balbi 
36694ae9843SFelipe Balbi 	/* init spinlock for workqueue */
36794ae9843SFelipe Balbi 	spin_lock_init(&twl->lock);
36894ae9843SFelipe Balbi 
36994ae9843SFelipe Balbi 	err = twl6030_usb_ldo_init(twl);
37094ae9843SFelipe Balbi 	if (err) {
37194ae9843SFelipe Balbi 		dev_err(&pdev->dev, "ldo init failed\n");
37294ae9843SFelipe Balbi 		return err;
37394ae9843SFelipe Balbi 	}
37494ae9843SFelipe Balbi 
37594ae9843SFelipe Balbi 	platform_set_drvdata(pdev, twl);
37694ae9843SFelipe Balbi 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
37794ae9843SFelipe Balbi 		dev_warn(&pdev->dev, "could not create sysfs file\n");
37894ae9843SFelipe Balbi 
37994ae9843SFelipe Balbi 	INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
38094ae9843SFelipe Balbi 
38194ae9843SFelipe Balbi 	status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq,
38294ae9843SFelipe Balbi 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
38394ae9843SFelipe Balbi 			"twl6030_usb", twl);
38494ae9843SFelipe Balbi 	if (status < 0) {
38594ae9843SFelipe Balbi 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
38694ae9843SFelipe Balbi 			twl->irq1, status);
38794ae9843SFelipe Balbi 		device_remove_file(twl->dev, &dev_attr_vbus);
38894ae9843SFelipe Balbi 		return status;
38994ae9843SFelipe Balbi 	}
39094ae9843SFelipe Balbi 
39194ae9843SFelipe Balbi 	status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq,
39294ae9843SFelipe Balbi 			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
39394ae9843SFelipe Balbi 			"twl6030_usb", twl);
39494ae9843SFelipe Balbi 	if (status < 0) {
39594ae9843SFelipe Balbi 		dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
39694ae9843SFelipe Balbi 			twl->irq2, status);
39794ae9843SFelipe Balbi 		free_irq(twl->irq1, twl);
39894ae9843SFelipe Balbi 		device_remove_file(twl->dev, &dev_attr_vbus);
39994ae9843SFelipe Balbi 		return status;
40094ae9843SFelipe Balbi 	}
40194ae9843SFelipe Balbi 
40294ae9843SFelipe Balbi 	twl->asleep = 0;
40394ae9843SFelipe Balbi 	twl6030_enable_irq(twl);
40494ae9843SFelipe Balbi 	dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
40594ae9843SFelipe Balbi 
40694ae9843SFelipe Balbi 	return 0;
40794ae9843SFelipe Balbi }
40894ae9843SFelipe Balbi 
40964dc9e2eSGreg Kroah-Hartman static int twl6030_usb_remove(struct platform_device *pdev)
41094ae9843SFelipe Balbi {
41194ae9843SFelipe Balbi 	struct twl6030_usb *twl = platform_get_drvdata(pdev);
41294ae9843SFelipe Balbi 
41394ae9843SFelipe Balbi 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
41494ae9843SFelipe Balbi 		REG_INT_MSK_LINE_C);
41594ae9843SFelipe Balbi 	twl6030_interrupt_mask(TWL6030_USBOTG_INT_MASK,
41694ae9843SFelipe Balbi 			REG_INT_MSK_STS_C);
41794ae9843SFelipe Balbi 	free_irq(twl->irq1, twl);
41894ae9843SFelipe Balbi 	free_irq(twl->irq2, twl);
41994ae9843SFelipe Balbi 	regulator_put(twl->usb3v3);
42094ae9843SFelipe Balbi 	device_remove_file(twl->dev, &dev_attr_vbus);
42194ae9843SFelipe Balbi 	cancel_work_sync(&twl->set_vbus_work);
42294ae9843SFelipe Balbi 
42394ae9843SFelipe Balbi 	return 0;
42494ae9843SFelipe Balbi }
42594ae9843SFelipe Balbi 
42694ae9843SFelipe Balbi #ifdef CONFIG_OF
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 #endif
43394ae9843SFelipe Balbi 
43494ae9843SFelipe Balbi static struct platform_driver twl6030_usb_driver = {
43594ae9843SFelipe Balbi 	.probe		= twl6030_usb_probe,
43664dc9e2eSGreg Kroah-Hartman 	.remove		= twl6030_usb_remove,
43794ae9843SFelipe Balbi 	.driver		= {
43894ae9843SFelipe Balbi 		.name	= "twl6030_usb",
43994ae9843SFelipe Balbi 		.of_match_table = of_match_ptr(twl6030_usb_id_table),
44094ae9843SFelipe Balbi 	},
44194ae9843SFelipe Balbi };
44294ae9843SFelipe Balbi 
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 
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