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