twl4030-usb.c revision 8f20960cd772fe42a9cdd36312b2247bc2800ffb
19ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* 29ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller 39ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 49ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * Copyright (C) 2004-2007 Texas Instruments 59ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * Copyright (C) 2008 Nokia Corporation 69ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * Contact: Felipe Balbi <felipe.balbi@nokia.com> 79ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 89ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * This program is free software; you can redistribute it and/or modify 99ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * it under the terms of the GNU General Public License as published by 109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * the Free Software Foundation; either version 2 of the License, or 119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * (at your option) any later version. 129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * This program is distributed in the hope that it will be useful, 149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * but WITHOUT ANY WARRANTY; without even the implied warranty of 159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * GNU General Public License for more details. 179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * You should have received a copy of the GNU General Public License 199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * along with this program; if not, write to the Free Software 209ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * Current status: 239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * - HS USB ULPI mode works. 249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * - 3-pin mode support may be added in future. 259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell */ 269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/module.h> 289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/init.h> 299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/interrupt.h> 309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/platform_device.h> 319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/spinlock.h> 329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/workqueue.h> 339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/io.h> 349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/delay.h> 359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#include <linux/usb/otg.h> 36b07682b6056eb6701f8cb86aa5800e6f2ea7919bSantosh Shilimkar#include <linux/i2c/twl.h> 3766760169492445395c530c812443f58e2cfdb3dcJouni Hogander#include <linux/regulator/consumer.h> 3866760169492445395c530c812443f58e2cfdb3dcJouni Hogander#include <linux/err.h> 39d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi#include <linux/notifier.h> 409ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 419ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* Register defines */ 429ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 439ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VENDOR_ID_LO 0x00 449ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VENDOR_ID_HI 0x01 459ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PRODUCT_ID_LO 0x02 469ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PRODUCT_ID_HI 0x03 479ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 489ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL 0x04 499ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_SET 0x05 509ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_CLR 0x06 519ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_SUSPENDM (1 << 6) 529ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_RESET (1 << 5) 539ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_OPMODE_MASK (3 << 3) /* bits 3 and 4 */ 549ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_OPMODE_NORMAL (0 << 3) 559ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_OPMODE_NONDRIVING (1 << 3) 569ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_OPMODE_DISABLE_BIT_NRZI (2 << 3) 579ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_TERMSELECT (1 << 2) 589ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_XCVRSELECT_MASK (3 << 0) /* bits 0 and 1 */ 599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_XCVRSELECT_HS (0 << 0) 609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_XCVRSELECT_FS (1 << 0) 619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_XCVRSELECT_LS (2 << 0) 629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define FUNC_CTRL_XCVRSELECT_FS4LS (3 << 0) 639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL 0x07 659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_SET 0x08 669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_CLR 0x09 679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_INTERFACE_PROTECT_DISABLE (1 << 7) 689ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_AUTORESUME (1 << 4) 699ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_CLOCKSUSPENDM (1 << 3) 709ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_CARKITMODE (1 << 2) 719ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define IFC_CTRL_FSLSSERIALMODE_3PIN (1 << 1) 729ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL 0x0A 749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_SET 0x0B 759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_CLR 0x0C 769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_DRVVBUS (1 << 5) 779ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_CHRGVBUS (1 << 4) 789ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_DISCHRGVBUS (1 << 3) 799ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_DMPULLDOWN (1 << 2) 809ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_DPPULLDOWN (1 << 1) 819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define TWL4030_OTG_CTRL_IDPULLUP (1 << 0) 829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 839ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_EN_RISE 0x0D 849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_EN_RISE_SET 0x0E 859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_EN_RISE_CLR 0x0F 869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_EN_FALL 0x10 879ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_EN_FALL_SET 0x11 889ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_EN_FALL_CLR 0x12 899ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_STS 0x13 909ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_LATCH 0x14 919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_IDGND (1 << 4) 929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_SESSEND (1 << 3) 939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_SESSVALID (1 << 2) 949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_VBUSVALID (1 << 1) 959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define USB_INT_HOSTDISCONNECT (1 << 0) 969ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 979ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL 0x19 989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_SET 0x1A 999ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_CLR 0x1B 1009ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_MICEN (1 << 6) 1019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_SPKRIGHTEN (1 << 5) 1029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_SPKLEFTEN (1 << 4) 1039ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_RXDEN (1 << 3) 1049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_TXDEN (1 << 2) 1059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_IDGNDDRV (1 << 1) 1069ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_CTRL_CARKITPWR (1 << 0) 1079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL 0x22 1089ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL_SET 0x23 1099ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL_CLR 0x24 1109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL_SPKRRIGHT_BIASEN (1 << 3) 1119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL_SPKRLEFT_BIASEN (1 << 2) 1129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL_RXPLSEN (1 << 1) 1139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define CARKIT_PLS_CTRL_TXPLSEN (1 << 0) 1149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL 0x30 1169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_SET 0x31 1179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_CLR 0x32 1189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_RTSOL (1 << 7) 1199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_EXTSWR (1 << 6) 1209ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_EXTSWC (1 << 5) 1219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_VOICESW (1 << 4) 1229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_OUT64K (1 << 3) 1239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_RTSCTSSW (1 << 2) 1249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL_HS_UART (1 << 0) 1259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL 0x33 1279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_SET 0x34 1289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_CLR 0x35 1299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_MICBIASEN (1 << 5) 1309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_CTS_NPU (1 << 4) 1319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_RXD_PU (1 << 3) 1329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_TXDTYP (1 << 2) 1339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_CTSTYP (1 << 1) 1349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_IO_CTRL_RTSTYP (1 << 0) 1359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1369ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL2 0x36 1379ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL2_SET 0x37 1389ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL2_CLR 0x38 1399ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define MCPC_CTRL2_MCPC_CK_EN (1 << 0) 1409ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1419ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL 0x80 1429ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL_SET 0x81 1439ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL_CLR 0x82 1449ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL_BDIS_ACON_EN (1 << 4) 1459ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL_FIVEWIRE_MODE (1 << 2) 1469ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1479ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL 0x83 1489ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_SET 0x84 1499ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_CLR 0x85 1509ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_OE_INT_EN (1 << 6) 1519ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_CEA2011_MODE (1 << 5) 1529ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_FSLSSERIALMODE_4PIN (1 << 4) 1539ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_HIZ_ULPI_60MHZ_OUT (1 << 3) 1549ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_HIZ_ULPI (1 << 2) 1559ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL_ALT_INT_REROUTE (1 << 0) 1569ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1579ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_EN_RISE 0x86 1589ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_EN_RISE_SET 0x87 1599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_EN_RISE_CLR 0x88 1609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_EN_FALL 0x89 1619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_EN_FALL_SET 0x8A 1629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_EN_FALL_CLR 0x8B 1639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_STS 0x8C 1649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_LATCH 0x8D 1659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_VB_SESS_VLD (1 << 7) 1669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_DM_HI (1 << 6) /* not valid for "latch" reg */ 1679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_DP_HI (1 << 5) /* not valid for "latch" reg */ 1689ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_BDIS_ACON (1 << 3) /* not valid for "fall" regs */ 1699ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_MANU (1 << 1) 1709ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_INT_ABNORMAL_STRESS (1 << 0) 1719ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1729ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_STATUS 0x96 1739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_RES_FLOAT (1 << 4) 1749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_RES_440K (1 << 3) 1759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_RES_200K (1 << 2) 1769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_RES_102K (1 << 1) 1779ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_RES_GND (1 << 0) 1789ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1799ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define POWER_CTRL 0xAC 1809ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define POWER_CTRL_SET 0xAD 1819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define POWER_CTRL_CLR 0xAE 1829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define POWER_CTRL_OTG_ENAB (1 << 5) 1839ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2 0xAF 1859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_SET 0xB0 1869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_CLR 0xB1 1879ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_ULPI_STP_LOW (1 << 4) 1889ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_ULPI_TXEN_POL (1 << 3) 1899ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_ULPI_4PIN_2430 (1 << 2) 1909ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_MASK (3 << 0) /* bits 0 and 1 */ 1919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT1N (0 << 0) 1929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_IFC_CTRL2_USB_INT_OUTSEL_INT2N (1 << 0) 1939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define REG_CTRL_EN 0xB2 1959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define REG_CTRL_EN_SET 0xB3 1969ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define REG_CTRL_EN_CLR 0xB4 1979ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define REG_CTRL_ERROR 0xB5 1989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ULPI_I2C_CONFLICT_INTEN (1 << 0) 1999ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2009ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL2 0xB8 2019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL2_SET 0xB9 2029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL2_CLR 0xBA 2039ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define OTHER_FUNC_CTRL2_VBAT_TIMER_EN (1 << 0) 2049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* following registers do not have separate _clr and _set registers */ 2069ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VBUS_DEBOUNCE 0xC0 2079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define ID_DEBOUNCE 0xC1 2089ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VBAT_TIMER 0xD3 2099ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_PWR_CTRL 0xFD 2109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_PWR_PHYPWD (1 << 0) 2119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_CLK_CTRL 0xFE 2129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_CLK_CTRL_CLOCKGATING_EN (1 << 2) 2139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_CLK_CTRL_CLK32K_EN (1 << 1) 2149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define REQ_PHY_DPLL_CLK (1 << 0) 2159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_CLK_CTRL_STS 0xFF 2169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PHY_DPLL_CLK (1 << 0) 2179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* In module TWL4030_MODULE_PM_MASTER */ 2199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PROTECT_KEY 0x0E 220def6f8b978618d50daaddb92331d398da9e141f1David Brownell#define STS_HW_CONDITIONS 0x0F 2219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* In module TWL4030_MODULE_PM_RECEIVER */ 2239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB_DEDICATED1 0x7D 2249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB_DEDICATED2 0x7E 2259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB1V5_DEV_GRP 0x71 2269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB1V5_TYPE 0x72 2279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB1V5_REMAP 0x73 2289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB1V8_DEV_GRP 0x74 2299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB1V8_TYPE 0x75 2309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB1V8_REMAP 0x76 2319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB3V1_DEV_GRP 0x77 2329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB3V1_TYPE 0x78 2339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define VUSB3V1_REMAP 0x79 2349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* In module TWL4030_MODULE_INTBR */ 2369ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define PMBR1 0x0D 2379ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define GPIO_USB_4PIN_ULPI_2430C (3 << 0) 2389ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2399ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstruct twl4030_usb { 2409ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct otg_transceiver otg; 2419ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct device *dev; 2429ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 24366760169492445395c530c812443f58e2cfdb3dcJouni Hogander /* TWL4030 internal USB regulator supplies */ 24466760169492445395c530c812443f58e2cfdb3dcJouni Hogander struct regulator *usb1v5; 24566760169492445395c530c812443f58e2cfdb3dcJouni Hogander struct regulator *usb1v8; 24666760169492445395c530c812443f58e2cfdb3dcJouni Hogander struct regulator *usb3v1; 24766760169492445395c530c812443f58e2cfdb3dcJouni Hogander 2489ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* for vbus reporting with irqs disabled */ 2499ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell spinlock_t lock; 2509ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2519ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* pin configuration */ 2529ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell enum twl4030_usb_mode usb_mode; 2539ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2549ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int irq; 2559ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 linkstat; 2569ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 asleep; 2579ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell bool irq_enabled; 2589ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell}; 2599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/* internal define on top of container_of */ 2619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define xceiv_to_twl(x) container_of((x), struct twl4030_usb, otg); 2629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/*-------------------------------------------------------------------------*/ 2649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl, 2669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 module, u8 data, u8 address) 2679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 2689ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 check; 2699ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 270fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K if ((twl_i2c_write_u8(module, data, address) >= 0) && 271fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K (twl_i2c_read_u8(module, &check, address) >= 0) && 2729ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell (check == data)) 2739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 2749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", 2759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 1, module, address, check, data); 2769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2779ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* Failed once: Try again */ 278fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K if ((twl_i2c_write_u8(module, data, address) >= 0) && 279fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K (twl_i2c_read_u8(module, &check, address) >= 0) && 2809ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell (check == data)) 2819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 2829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(twl->dev, "Write%d[%d,0x%x] wrote %02x but read %02x\n", 2839ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2, module, address, check, data); 2849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* Failed again: Return error */ 2869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return -EBUSY; 2879ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 2889ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2899ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell#define twl4030_usb_write_verify(twl, address, data) \ 2909ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_USB, (data), (address)) 2919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 2929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic inline int twl4030_usb_write(struct twl4030_usb *twl, 2939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 address, u8 data) 2949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 2959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int ret = 0; 2969ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 297fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K ret = twl_i2c_write_u8(TWL4030_MODULE_USB, data, address); 2989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (ret < 0) 2999ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(twl->dev, 3009ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell "TWL4030:USB:Write[0x%x] Error %d\n", address, ret); 3019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return ret; 3029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 3039ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic inline int twl4030_readb(struct twl4030_usb *twl, u8 module, u8 address) 3059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 3069ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 data; 3079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int ret = 0; 3089ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 309fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K ret = twl_i2c_read_u8(module, &data, address); 3109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (ret >= 0) 3119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell ret = data; 3129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell else 3139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(twl->dev, 3149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell "TWL4030:readb[0x%x,0x%x] Error %d\n", 3159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell module, address, ret); 3169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return ret; 3189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 3199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3209ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address) 3219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 3229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return twl4030_readb(twl, TWL4030_MODULE_USB, address); 3239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 3249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/*-------------------------------------------------------------------------*/ 3269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic inline int 3289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownelltwl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits) 3299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 3309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return twl4030_usb_write(twl, reg + 1, bits); 3319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 3329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic inline int 3349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownelltwl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits) 3359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 3369ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return twl4030_usb_write(twl, reg + 2, bits); 3379ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 3389ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3399ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell/*-------------------------------------------------------------------------*/ 3409ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 341d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbistatic enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl) 3429ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 3439ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int status; 344d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi int linkstat = USB_EVENT_NONE; 3459ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 346def6f8b978618d50daaddb92331d398da9e141f1David Brownell /* 347def6f8b978618d50daaddb92331d398da9e141f1David Brownell * For ID/VBUS sensing, see manual section 15.4.8 ... 348def6f8b978618d50daaddb92331d398da9e141f1David Brownell * except when using only battery backup power, two 349def6f8b978618d50daaddb92331d398da9e141f1David Brownell * comparators produce VBUS_PRES and ID_PRES signals, 350def6f8b978618d50daaddb92331d398da9e141f1David Brownell * which don't match docs elsewhere. But ... BIT(7) 351def6f8b978618d50daaddb92331d398da9e141f1David Brownell * and BIT(2) of STS_HW_CONDITIONS, respectively, do 352def6f8b978618d50daaddb92331d398da9e141f1David Brownell * seem to match up. If either is true the USB_PRES 353def6f8b978618d50daaddb92331d398da9e141f1David Brownell * signal is active, the OTG module is activated, and 354def6f8b978618d50daaddb92331d398da9e141f1David Brownell * its interrupt may be raised (may wake the system). 355def6f8b978618d50daaddb92331d398da9e141f1David Brownell */ 356def6f8b978618d50daaddb92331d398da9e141f1David Brownell status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 357def6f8b978618d50daaddb92331d398da9e141f1David Brownell STS_HW_CONDITIONS); 3589ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (status < 0) 3599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_err(twl->dev, "USB link status err %d\n", status); 360def6f8b978618d50daaddb92331d398da9e141f1David Brownell else if (status & (BIT(7) | BIT(2))) { 361def6f8b978618d50daaddb92331d398da9e141f1David Brownell if (status & BIT(2)) 362d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi linkstat = USB_EVENT_ID; 363def6f8b978618d50daaddb92331d398da9e141f1David Brownell else 364d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi linkstat = USB_EVENT_VBUS; 365def6f8b978618d50daaddb92331d398da9e141f1David Brownell } else 366d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi linkstat = USB_EVENT_NONE; 3679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3689ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n", 3699ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell status, status, linkstat); 3709ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3719ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* REVISIT this assumes host and peripheral controllers 3729ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * are registered, and that both are active... 3739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell */ 3749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell spin_lock_irq(&twl->lock); 3769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->linkstat = linkstat; 377d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi if (linkstat == USB_EVENT_ID) { 3789ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.default_a = true; 3799ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.state = OTG_STATE_A_IDLE; 3809ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } else { 3819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.default_a = false; 3829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.state = OTG_STATE_B_IDLE; 3839ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 3849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell spin_unlock_irq(&twl->lock); 3859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return linkstat; 3879ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 3889ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3899ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode) 3909ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 3919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->usb_mode = mode; 3929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 3939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell switch (mode) { 3949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell case T2_USB_MODE_ULPI: 3959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_clear_bits(twl, IFC_CTRL, IFC_CTRL_CARKITMODE); 3969ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_set_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); 3979ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_clear_bits(twl, FUNC_CTRL, 3989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell FUNC_CTRL_XCVRSELECT_MASK | 3999ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell FUNC_CTRL_OPMODE_MASK); 4009ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell break; 4019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell case -1: 4029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* FIXME: power on defaults */ 4039ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell break; 4049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell default: 4059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_err(twl->dev, "unsupported T2 transceiver mode %d\n", 4069ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell mode); 4079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell break; 4089ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell }; 4099ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 4109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic void twl4030_i2c_access(struct twl4030_usb *twl, int on) 4129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 4139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell unsigned long timeout; 4149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int val = twl4030_usb_read(twl, PHY_CLK_CTRL); 4159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (val >= 0) { 4179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (on) { 4189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* enable DPLL to access PHY registers over I2C */ 4199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell val |= REQ_PHY_DPLL_CLK; 4209ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL, 4219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell (u8)val) < 0); 4229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell timeout = jiffies + HZ; 4249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) & 4259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell PHY_DPLL_CLK) 4269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell && time_before(jiffies, timeout)) 4279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell udelay(10); 4289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) & 4299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell PHY_DPLL_CLK)) 4309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_err(twl->dev, "Timeout setting T2 HSUSB " 4319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell "PHY DPLL clock\n"); 4329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } else { 4339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* let ULPI control the DPLL clock */ 4349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell val &= ~REQ_PHY_DPLL_CLK; 4359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL, 4369ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell (u8)val) < 0); 4379ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 4389ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 4399ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 4409ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4419ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic void twl4030_phy_power(struct twl4030_usb *twl, int on) 4429ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 4439ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell u8 pwr; 4449ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4459ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell pwr = twl4030_usb_read(twl, PHY_PWR_CTRL); 4469ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (on) { 44766760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_enable(twl->usb3v1); 44866760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_enable(twl->usb1v8); 44966760169492445395c530c812443f58e2cfdb3dcJouni Hogander /* 45066760169492445395c530c812443f58e2cfdb3dcJouni Hogander * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP 45166760169492445395c530c812443f58e2cfdb3dcJouni Hogander * in twl4030) resets the VUSB_DEDICATED2 register. This reset 45266760169492445395c530c812443f58e2cfdb3dcJouni Hogander * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to 45366760169492445395c530c812443f58e2cfdb3dcJouni Hogander * SLEEP. We work around this by clearing the bit after usv3v1 45466760169492445395c530c812443f58e2cfdb3dcJouni Hogander * is re-activated. This ensures that VUSB3V1 is really active. 45566760169492445395c530c812443f58e2cfdb3dcJouni Hogander */ 456fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, 45766760169492445395c530c812443f58e2cfdb3dcJouni Hogander VUSB_DEDICATED2); 45866760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_enable(twl->usb1v5); 4599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell pwr &= ~PHY_PWR_PHYPWD; 4609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); 4619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_write(twl, PHY_CLK_CTRL, 4629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_read(twl, PHY_CLK_CTRL) | 4639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell (PHY_CLK_CTRL_CLOCKGATING_EN | 4649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell PHY_CLK_CTRL_CLK32K_EN)); 4659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } else { 4669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell pwr |= PHY_PWR_PHYPWD; 4679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0); 46866760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_disable(twl->usb1v5); 46966760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_disable(twl->usb1v8); 47066760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_disable(twl->usb3v1); 4719ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 4729ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 4739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off) 4759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 4769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (twl->asleep) 4779ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return; 4789ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4799ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_power(twl, 0); 4809ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->asleep = 1; 4819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 4829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4839ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic void twl4030_phy_resume(struct twl4030_usb *twl) 4849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 4859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!twl->asleep) 4869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return; 4879ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 4889ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_power(twl, 1); 4899ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_i2c_access(twl, 1); 4909ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_set_mode(twl, twl->usb_mode); 4919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (twl->usb_mode == T2_USB_MODE_ULPI) 4929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_i2c_access(twl, 0); 4939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->asleep = 0; 4949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 4959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 49666760169492445395c530c812443f58e2cfdb3dcJouni Hoganderstatic int twl4030_usb_ldo_init(struct twl4030_usb *twl) 4979ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 4989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* Enable writing to power configuration registers */ 499fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY); 500fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0x0C, PROTECT_KEY); 5019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* put VUSB3V1 LDO in active state */ 503fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB_DEDICATED2); 5049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* input to VUSB3V1 LDO is from VBAT, not VBUS */ 506fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1); 5079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 50866760169492445395c530c812443f58e2cfdb3dcJouni Hogander /* Initialize 3.1V regulator */ 509fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP); 51066760169492445395c530c812443f58e2cfdb3dcJouni Hogander 51166760169492445395c530c812443f58e2cfdb3dcJouni Hogander twl->usb3v1 = regulator_get(twl->dev, "usb3v1"); 51266760169492445395c530c812443f58e2cfdb3dcJouni Hogander if (IS_ERR(twl->usb3v1)) 51366760169492445395c530c812443f58e2cfdb3dcJouni Hogander return -ENODEV; 51466760169492445395c530c812443f58e2cfdb3dcJouni Hogander 515fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE); 5169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 51766760169492445395c530c812443f58e2cfdb3dcJouni Hogander /* Initialize 1.5V regulator */ 518fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP); 51966760169492445395c530c812443f58e2cfdb3dcJouni Hogander 52066760169492445395c530c812443f58e2cfdb3dcJouni Hogander twl->usb1v5 = regulator_get(twl->dev, "usb1v5"); 52166760169492445395c530c812443f58e2cfdb3dcJouni Hogander if (IS_ERR(twl->usb1v5)) 52266760169492445395c530c812443f58e2cfdb3dcJouni Hogander goto fail1; 52366760169492445395c530c812443f58e2cfdb3dcJouni Hogander 524fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE); 5259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 52666760169492445395c530c812443f58e2cfdb3dcJouni Hogander /* Initialize 1.8V regulator */ 527fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP); 52866760169492445395c530c812443f58e2cfdb3dcJouni Hogander 52966760169492445395c530c812443f58e2cfdb3dcJouni Hogander twl->usb1v8 = regulator_get(twl->dev, "usb1v8"); 53066760169492445395c530c812443f58e2cfdb3dcJouni Hogander if (IS_ERR(twl->usb1v8)) 53166760169492445395c530c812443f58e2cfdb3dcJouni Hogander goto fail2; 53266760169492445395c530c812443f58e2cfdb3dcJouni Hogander 533fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE); 5349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* disable access to power configuration registers */ 536fc7b92fca4e546184557f1c53f84ad57c66b7695Balaji T K twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY); 53766760169492445395c530c812443f58e2cfdb3dcJouni Hogander 53866760169492445395c530c812443f58e2cfdb3dcJouni Hogander return 0; 53966760169492445395c530c812443f58e2cfdb3dcJouni Hogander 54066760169492445395c530c812443f58e2cfdb3dcJouni Hoganderfail2: 54166760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_put(twl->usb1v5); 54266760169492445395c530c812443f58e2cfdb3dcJouni Hogander twl->usb1v5 = NULL; 54366760169492445395c530c812443f58e2cfdb3dcJouni Hoganderfail1: 54466760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_put(twl->usb3v1); 54566760169492445395c530c812443f58e2cfdb3dcJouni Hogander twl->usb3v1 = NULL; 54666760169492445395c530c812443f58e2cfdb3dcJouni Hogander return -ENODEV; 5479ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 5489ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5499ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic ssize_t twl4030_usb_vbus_show(struct device *dev, 5509ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct device_attribute *attr, char *buf) 5519ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 5529ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl = dev_get_drvdata(dev); 5539ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell unsigned long flags; 5549ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int ret = -EINVAL; 5559ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5569ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell spin_lock_irqsave(&twl->lock, flags); 5579ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell ret = sprintf(buf, "%s\n", 558d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi (twl->linkstat == USB_EVENT_VBUS) ? "on" : "off"); 5599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell spin_unlock_irqrestore(&twl->lock, flags); 5609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return ret; 5629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 5639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL); 5649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic irqreturn_t twl4030_usb_irq(int irq, void *_twl) 5669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 5679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl = _twl; 5689ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int status; 5699ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5709ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell status = twl4030_usb_linkstat(twl); 571d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi if (status >= 0) { 5729ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* FIXME add a set_power() method so that B-devices can 5739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * configure the charger appropriately. It's not always 5749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * correct to consume VBUS power, and how much current to 5759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * consume is a function of the USB configuration chosen 5769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * by the host. 5779ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 5789ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * REVISIT usb_gadget_vbus_connect(...) as needed, ditto 5799ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * its disconnect() sibling, when changing to/from the 5809ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * USB_LINK_VBUS state. musb_hdrc won't care until it 5819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * starts to handle softconnect right. 5829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell */ 583d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi if (status == USB_EVENT_NONE) 5849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_suspend(twl, 0); 5859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell else 5869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_resume(twl); 587be30fc4b650acb85549fd0a9c42fe042366de009Aguilar Pena, Leed 588d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi blocking_notifier_call_chain(&twl->otg.notifier, status, 589d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi twl->otg.gadget); 5909ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 5919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell sysfs_notify(&twl->dev->kobj, NULL, "vbus"); 5929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return IRQ_HANDLED; 5949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 5959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 5969ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic int twl4030_set_suspend(struct otg_transceiver *x, int suspend) 5979ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 5989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl = xceiv_to_twl(x); 5999ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6009ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (suspend) 6019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_suspend(twl, 1); 6029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell else 6039ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_resume(twl); 6049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 6069ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 6079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6089ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic int twl4030_set_peripheral(struct otg_transceiver *x, 6099ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct usb_gadget *gadget) 6109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 6119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl; 6129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!x) 6149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return -ENODEV; 6159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl = xceiv_to_twl(x); 6179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.gadget = gadget; 6189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!gadget) 6199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.state = OTG_STATE_UNDEFINED; 6209ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 6229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 6239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host) 6259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 6269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl; 6279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!x) 6299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return -ENODEV; 6309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl = xceiv_to_twl(x); 6329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.host = host; 6339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!host) 6349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.state = OTG_STATE_UNDEFINED; 6359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6369ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 6379ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 6389ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 639d8b175e78b9debdacd31fa74da5dedd6a6285f94Uwe Kleine-Königstatic int __devinit twl4030_usb_probe(struct platform_device *pdev) 6409ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 6419ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb_data *pdata = pdev->dev.platform_data; 6429ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl; 64366760169492445395c530c812443f58e2cfdb3dcJouni Hogander int status, err; 6449ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6459ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!pdata) { 6469ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(&pdev->dev, "platform_data not available\n"); 6479ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return -EINVAL; 6489ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 6499ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6509ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl = kzalloc(sizeof *twl, GFP_KERNEL); 6519ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (!twl) 6529ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return -ENOMEM; 6539ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6549ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->dev = &pdev->dev; 6559ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->irq = platform_get_irq(pdev, 0); 6569ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.dev = twl->dev; 6579ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.label = "twl4030"; 6589ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.set_host = twl4030_set_host; 6599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.set_peripheral = twl4030_set_peripheral; 6609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->otg.set_suspend = twl4030_set_suspend; 6619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->usb_mode = pdata->usb_mode; 6629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->asleep = 1; 6639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* init spinlock for workqueue */ 6659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell spin_lock_init(&twl->lock); 6669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 66766760169492445395c530c812443f58e2cfdb3dcJouni Hogander err = twl4030_usb_ldo_init(twl); 66866760169492445395c530c812443f58e2cfdb3dcJouni Hogander if (err) { 66966760169492445395c530c812443f58e2cfdb3dcJouni Hogander dev_err(&pdev->dev, "ldo init failed\n"); 67066760169492445395c530c812443f58e2cfdb3dcJouni Hogander kfree(twl); 67166760169492445395c530c812443f58e2cfdb3dcJouni Hogander return err; 67266760169492445395c530c812443f58e2cfdb3dcJouni Hogander } 6739ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell otg_set_transceiver(&twl->otg); 6749ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 6759ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell platform_set_drvdata(pdev, twl); 6769ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (device_create_file(&pdev->dev, &dev_attr_vbus)) 6779ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_warn(&pdev->dev, "could not create sysfs file\n"); 6789ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 679d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier); 680d1b5b5c0a8a8204f0c51d5eb99736ecfb2fd5b4eFelipe Balbi 6819ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* Our job is to use irqs and status from the power module 6829ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * to keep the transceiver disabled when nothing's connected. 6839ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 6849ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * FIXME we actually shouldn't start enabling it until the 6859ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * USB controller drivers have said they're ready, by calling 6869ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * set_host() and/or set_peripheral() ... OTG_capable boards 6879ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * need both handles, otherwise just one suffices. 6889ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell */ 6899ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->irq_enabled = true; 6908f20960cd772fe42a9cdd36312b2247bc2800ffbFelipe Balbi status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq, 6919ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, 6929ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell "twl4030_usb", twl); 6939ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (status < 0) { 6949ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n", 6959ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl->irq, status); 6969ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell kfree(twl); 6979ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return status; 6989ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 6999ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7009ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* The IRQ handler just handles changes from the previous states 7019ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * of the ID and VBUS pins ... in probe() we must initialize that 7029ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * previous state. The easy way: fake an IRQ. 7039ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * 7049ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * REVISIT: a real IRQ might have happened already, if PREEMPT is 7059ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * enabled. Else the IRQ may not yet be configured or enabled, 7069ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * because of scheduling delays. 7079ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell */ 7089ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_irq(twl->irq, twl); 7099ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7109ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell dev_info(&pdev->dev, "Initialized TWL4030 USB module\n"); 7119ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 7129ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 7139ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7149ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic int __exit twl4030_usb_remove(struct platform_device *pdev) 7159ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 7169ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell struct twl4030_usb *twl = platform_get_drvdata(pdev); 7179ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell int val; 7189ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7199ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell free_irq(twl->irq, twl); 7209ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell device_remove_file(twl->dev, &dev_attr_vbus); 7219ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7229ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* set transceiver mode to power on defaults */ 7239ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_set_mode(twl, -1); 7249ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7259ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* autogate 60MHz ULPI clock, 7269ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * clear dpll clock request for i2c access, 7279ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell * disable 32KHz 7289ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell */ 7299ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell val = twl4030_usb_read(twl, PHY_CLK_CTRL); 7309ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell if (val >= 0) { 7319ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell val |= PHY_CLK_CTRL_CLOCKGATING_EN; 7329ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK); 7339ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val); 7349ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell } 7359ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7369ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell /* disable complete OTG block */ 7379ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB); 7389ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7399ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell twl4030_phy_power(twl, 0); 74066760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_put(twl->usb1v5); 74166760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_put(twl->usb1v8); 74266760169492445395c530c812443f58e2cfdb3dcJouni Hogander regulator_put(twl->usb3v1); 7439ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7449ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell kfree(twl); 7459ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7469ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return 0; 7479ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 7489ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7499ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic struct platform_driver twl4030_usb_driver = { 7509ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell .probe = twl4030_usb_probe, 7519ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell .remove = __exit_p(twl4030_usb_remove), 7529ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell .driver = { 7539ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell .name = "twl4030_usb", 7549ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell .owner = THIS_MODULE, 7559ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell }, 7569ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell}; 7579ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7589ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic int __init twl4030_usb_init(void) 7599ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 7609ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell return platform_driver_register(&twl4030_usb_driver); 7619ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 7629ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellsubsys_initcall(twl4030_usb_init); 7639ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7649ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellstatic void __exit twl4030_usb_exit(void) 7659ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell{ 7669ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell platform_driver_unregister(&twl4030_usb_driver); 7679ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell} 7689ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownellmodule_exit(twl4030_usb_exit); 7699ebd9616648bc0e47e7f8e1898c919305f1e6347David Brownell 7709ebd9616648bc0e47e7f8e1898c919305f1e6347David BrownellMODULE_ALIAS("platform:twl4030_usb"); 7719ebd9616648bc0e47e7f8e1898c919305f1e6347David BrownellMODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation"); 7729ebd9616648bc0e47e7f8e1898c919305f1e6347David BrownellMODULE_DESCRIPTION("TWL4030 USB transceiver driver"); 7739ebd9616648bc0e47e7f8e1898c919305f1e6347David BrownellMODULE_LICENSE("GPL"); 774